Open alex-robinson opened 2 months ago
Going along your suggestion, I think it would be very beneficial if the output routine would loop over the variables specified in a (separate) namelist. This would make the code much shorter, easier to maintain and we wouldn't need to recompile the code each time we change the output structure. A pseudo-code example:
vars = [u, v, H, z]
varnames = [...]
varlongnames = [...]
units = [...]
fortranname = [ylmo%u, ylmo%v, ylmo%H, ylmo%z]
selectvars = [1, 2, 3]
for i in selectvars
write(filename, varnames[i], parse(fortranname[i]), units = units[j], long_name = varlongnames[i], ...)
end
In the example above, this would only write out u, v, H
based on selectvars
, which can be easily modified by the user. The main issue I face here is that I don't know how to perform the parse(fortranname[i])
step. Do you know that @alex-robinson? And do you agree with the basic idea?
Yes, what you propose would be a great solution. But it exposes one of Fortran's fatal flaws in this instance. As far as I know, it is not possible to make a "list" of variables. They can only be defined in derived types with specific names (as with the Yelmo derived types themselves). Then, there is no way to call a variable within a derived type from a string name, or to "parse" it. The only way to access ylmo%dyn%now%ux
is to explicitly write it like that.
The only way I've thought of doing it before, is a brute force method, which is probably why I never got around to implementing it:
Psuedo-code:
vanames = ["ux","uy",...\ ! Passed as an argument to routine
for varnm in varnames
select case(trim(varnm))
case("ux")
call nc_write(filename,varnm,ylmo%dyn%now%ux,...)
case("uy")
call nc_write(filename,varnm,ylmo%dyn%now%ux,...)
...
case DEFAULT
! Throw error - variable name not recognized
end select
end
And have one writing case for every possible Yelmo variable with case DEFAULT
throwing an error if the variable name does not exist).
The resulting functionality would be the same as what you propose, but the code would be much more verbose of course. It might be a good solution, and a number of common variables could be quickly built in. Then we could fill it in as we go.
Makes sense, parsing strings to code should only be possible in dynamic programming languages. Looks like we are aiming at a more "brute force" solution then!
Currently there are a few output routines defined in
src/yelmo_io.f90
and insrc/yelmo_regions.f90
. The output routine insrc/yelmo_regions.f90
is used for writing integrated/averaged quantities over a specific regional domain defined by a mask. This is not the topic here.The issue is that
src/yelmo_io.f90
does not contain a general routine to output model data for the whole domain or a subset. I think ideally, such a routine would have the following features:It should be noted that such a writing routine needs an accompanying write initialization routine. Usually the latter is called at the start of a program and the former is called several times during timestepping. An initialization routine already exists and is pretty general, but may need to be adapted to allow feature 1 above.
Any other features needed for this to work well and be general?