I am writing large hydrological models. After computing for e.g. Arrays/args depicting for e.g. the different vegetaion, I would like to make available all these constants Arrays within all the modules written in different MyFiles.jl . I understand that one should avoid using global variables as it slows down the model.
An other solution is to pass variables as arguments to functions which is not very readable e.g.
I am wandering if one can use the concept of MODULE in Fortran.90 which stores all variables in one MODULE . To get access to these variables one just calls e.g. USE VEGETATION . This syntax is clean and fast . I would pass variables as arguments only the variables which are dynamic.
e.g. Fortran code which stores the variables and to get the values in a module just call USE VEGETATION:
Thanks Hendricks. I use your solution when I know the values of the parameters before running the model. The challenge of this question is that we do not know in advance the values of the parameters, which will be computed at the very beginning of the code. Then these Arrays will be used as constant in different modules of the program. So the question is how to pass in a clean ways these parameters to all the modules build in separate files?
My solution to this kind of thing is roughly the following:
Define a Model object that contains everything there is to know about the model. Typically with child objects that can be swapped out to try different model versions.
Define a Case object that collects all the switches / settings that vary across cases that I want to run.
Write an init_model function that takes a Case and returns a Model with the right settings.
Everything else uses Model as one input argument to keep track of all settings etc.
… Which is really just the long way of saying pretty much what Pbellive already said.
But in my applications I don’t mind writing out the nested access. It keeps things organized and I don’t have to worry about name conflicts (did I want to access field N for object A or B?).
What often happens (for me) is that I pass an entire object to a function. So I don’t have to write out deeply nested fields very often. If it turns out that I do, I just write a little convenience access function as in
Julia can do this so much better than fortran, if you are prepared to explore some different approaches.
You will easily be able to organise your models so that components can be swapped out and compared (as Clark and Mendoza etc have been pushing in Hydrology).
https://github.com/rafaqz/Flatten.jl/ will turn your composite model into a flat tuple of parameters with very good performance, which is good for sending models to an optimiser or diffeq. It will also flatten the parameter bounds, names and anything else you need to attach to the structs into flat tuples for the whole model.
Most of my modelling packages are structured like this, the Photosynthesis packages is a good example, but also see https://github.com/cesaraustralia/Dispersal.jl and all the packages in the cesaraustralia org.
I have also taken a crack at the problem of keeping track of model parameters and passing them to optimizers. My approach is a bit more involved (see https://github.com/hendri54/ModelParams).
The basic idea is to build a model out of nested objects that keep track of their parameters (and their bounds, descriptions, whether they are calibrated etc). Then there are methods that traverse the model hierarchy and collect all those parameters to either pass them to optimizers or to report them etc. I give each object a unique name, so I can put parameters back into objects, even if several objects have parameters of the same name.
Finally, there are methods for keeping track of data moments and their model counterparts. This is used automatically report model fit and construct the scalar deviation for the optimizer.
The setup is complicated (perhaps too complicated) but relatively easy to use.
Interesting we’ve been solving similar problems. Try Flatten.jl… its generic and very fast at walking the struct, and also does bounds or custom fields with very little fuss using FieldMetadata.jl. The total SLoC is only a few hundred lines so also pretty easy to maintain (if not understand, the @generated are pretty wild).
You can also use Setfield.jl to update specific parameters.
The problem is non-unique parameter names. I have models where an object contains a vector of child objects that all contain the same parameters. Something that essentially says: “set field beta somewhere in a nested struct” won’t work for me.
But the idea of FieldMetaData is certainly interesting. Thanks for pointing that out.