Sharing args/Arrays among different modules written in different MyFiles.jl as FORTRAN

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.

FUNCTION(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7 etc…)

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:

MODULE VEGETATION
      IMPLICIT NONE
      INTEGER          :: Max_Cell_Evaporation,Max_Cell_Root,Key_RDD
      DOUBLE PRECISION :: cum_qroot,q_root,cum_qevap      
      DOUBLE PRECISION :: Rooting_Depth,Root_Density_Func_Param,Root_Density_Func_0,Root_Density_Func_1
END MODULE

Perhaps I misunderstand the difficulty, but this can be done as

module Constants
  export a
  a = 1
end

module DoStuff
  using Constants
  b = a + 1
end

You just need the modules in different files so that Constants can used anywhere.

2 Likes

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?

One simple solution is to put all your variables in a struct and pass that around, rather than a bunch of individual variables. For example

module Vegetation
    export VegStruct
    Struct VegStruct
        Max_Cell_Evaporation::Int
        Max_Cell_Root::Int
        Key_RDD::Int 
    end
end

Then you can write functions like

function foo(veg::VegStruct, args...)
    a = 2*veg.Max_Cell_Evaporation
end
2 Likes

Parameters.jl seems aimed at model parameters

1 Like

My solution to this kind of thing is roughly the following:

  1. 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.

  2. Define a Case object that collects all the switches / settings that vary across cases that I want to run.

  3. Write an init_model function that takes a Case and returns a Model with the right settings.

  4. 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.

2 Likes

Great, lets assume that we have 2 structures, 1 vegetation and an other Hydraulic:

module Hydraulic
    export HydroStruct
    Struct HydroStruct
        Sat::Int
        Residual:Int
    end
end

Now we want to combine all the parameters:

module Parameters:
     export Param
    Struct Param
         HydroStruct
         VegStruct
    end
 end

When I want to use a parameter than I have to type:

Param.VegStruct.Max_Cell_Root

Would there be a way to omit Param when I call it in a Module?

There is Setfield.jl.

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

max_cell_root(p) = p.VegStruct.Max_Cell_Root

Thanks hendri you answered beautifully my question.

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).

I wrote https://github.com/rafaqz/FieldMetadata.jl/ for adding bounds or priors to each parameter in all the model structs, and https://github.com/rafaqz/FieldDefaults.jl/ to add defaults with keyword argument constructors as in parameters.jl, but available through methods.

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.