11"""
22 hard_dependencies(models; verbose::Bool=true)
33 hard_dependencies(mapping::ModelMapping; verbose::Bool=true)
4- hard_dependencies(mapping::AbstractDict{String ,T}; verbose::Bool=true)
4+ hard_dependencies(mapping::AbstractDict{Symbol ,T}; verbose::Bool=true)
55
66Compute the hard dependencies between models.
77"""
8- function hard_dependencies (models; scale= " " , verbose:: Bool = true )
8+ function _normalize_hard_dependency_scales (scales, process:: Symbol , dependency_process:: Symbol )
9+ if scales isa Symbol || scales isa AbstractString
10+ return [Symbol (scales)]
11+ elseif scales isa Tuple || scales isa AbstractVector
12+ normalized = Symbol[]
13+ for s in scales
14+ if s isa Symbol || s isa AbstractString
15+ push! (normalized, Symbol (s))
16+ else
17+ error (
18+ " Invalid hard dependency scale declaration for process `$(process) ` dependency `$(dependency_process) `: " ,
19+ " expected Symbol or String scales, got `$(typeof (s)) `."
20+ )
21+ end
22+ end
23+ isempty (normalized) && error (
24+ " Invalid hard dependency scale declaration for process `$(process) ` dependency `$(dependency_process) `: " ,
25+ " at least one target scale must be provided."
26+ )
27+ return normalized
28+ end
29+
30+ error (
31+ " Invalid hard dependency scale declaration for process `$(process) ` dependency `$(dependency_process) `: " ,
32+ " expected Symbol/String or a tuple/vector of them, got `$(typeof (scales)) `."
33+ )
34+ end
35+
36+ function hard_dependencies (models; scale= nothing , verbose:: Bool = true )
937 dep_graph = initialise_all_as_hard_dependency_node (models, scale)
1038 dep_not_found = Dict {Symbol,Any} ()
1139 for (process, i) in pairs (models) # for each model in the model list. process=:state; i=pairs(models)[process]
@@ -17,9 +45,10 @@ function hard_dependencies(models; scale="", verbose::Bool=true)
1745 # This means we should search this model in another scale. This is not done here, but after the call to this
1846 # function in the other method for `hard_dependencies` below.
1947 if isa (depend, Pair)
20- if scale != " "
48+ if ! isnothing (scale)
2149 # We skip this hard-dependency if it is multiscale, we compute this afterwards in this case
22- push! (dep_not_found, p => (parent_process= process, type= first (depend), scales= last (depend)))
50+ target_scales = _normalize_hard_dependency_scales (last (depend), process, p)
51+ push! (dep_not_found, p => (parent_process= process, type= first (depend), scales= target_scales))
2352 continue
2453 else
2554 # If we are not in a multi-scale setup e.g. in a ModelList, we shouldn't use a multiscale model.
@@ -40,7 +69,7 @@ function hard_dependencies(models; scale="", verbose::Bool=true)
4069 if verbose
4170 @info string (
4271 " Model " , typeof (i). name. name, " from process " , process,
43- scale == " " ? " " : " at scale $scale " ,
72+ isnothing ( scale) ? " " : " at scale $scale " ,
4473 " needs a model that is a subtype of " , depend, " in process " ,
4574 p
4675 )
@@ -58,7 +87,7 @@ function hard_dependencies(models; scale="", verbose::Bool=true)
5887 if verbose
5988 @info string (
6089 " Model " , typeof (i). name. name, " from process " , process,
61- scale == " " ? " " : " at scale $scale " ,
90+ isnothing (scale) ? " " : " at scale $scale " ,
6291 " needs a model that is a subtype of " , depend, " in process " ,
6392 p, " , but the process is not parameterized in the ModelList."
6493 )
@@ -94,13 +123,14 @@ Take a set of models and initialise them all as a hard dependency node, and
94123return a dictionary of `:process => HardDependencyNode`.
95124"""
96125function initialise_all_as_hard_dependency_node (models, scale)
126+ node_scale = isnothing (scale) ? :Default : Symbol (scale)
97127 dep_graph = Dict (
98128 p => HardDependencyNode (
99129 i,
100130 p,
101131 NamedTuple (),
102132 Int[],
103- scale ,
133+ node_scale ,
104134 inputs_ (i),
105135 outputs_ (i),
106136 nothing ,
113143
114144
115145# When we use a mapping (multiscale), we return the set of soft-dependencies (we put the hard-dependencies as their children):
116- function hard_dependencies (mapping:: AbstractDict{String ,T} ; verbose:: Bool = true ) where {T}
146+ function hard_dependencies (mapping:: AbstractDict{Symbol ,T} ; verbose:: Bool = true ) where {T}
117147 full_vars_mapping = Dict (first (mod) => Dict (get_mapped_variables (last (mod))) for mod in mapping)
118- soft_dep_graphs = Dict {String ,Any} ()
148+ soft_dep_graphs = Dict {Symbol ,Any} ()
119149 not_found = Dict {Symbol,DataType} ()
120150
121151 mods = Dict (organ => parse_models (get_models (model)) for (organ, model) in mapping)
@@ -125,7 +155,7 @@ function hard_dependencies(mapping::AbstractDict{String,T}; verbose::Bool=true)
125155 # Since the hard dependencies are inserted into the soft dependency graph as children and aren't referenced elsewhere
126156 # it becomes harder to keep track of them as needed without traversing the graph
127157 # so keep tabs on them during initialisation until they're no longer needed
128- hard_dependency_dict = Dict {Pair{Symbol, String }, HardDependencyNode} ()
158+ hard_dependency_dict = Dict {Pair{Symbol,Symbol }, HardDependencyNode} ()
129159
130160 hard_deps = Dict (organ => hard_dependencies (mods_scale, scale= organ, verbose= false ) for (organ, mods_scale) in mods)
131161
@@ -135,8 +165,8 @@ function hard_dependencies(mapping::AbstractDict{String,T}; verbose::Bool=true)
135165 # * Note that we compute this before computing the multiscale hard dependencies because the inputs/outputs
136166 # * of hard-dependency models should remain in their own scale. Note that the variables from the hard
137167 # * dependency may not appear in its own scale, but this is treated in the soft-dependency computation
138- inputs_process = Dict {String ,Dict{Symbol,Vector}} ()
139- outputs_process = Dict {String ,Dict{Symbol,Vector}} ()
168+ inputs_process = Dict {Symbol ,Dict{Symbol,Vector}} ()
169+ outputs_process = Dict {Symbol ,Dict{Symbol,Vector}} ()
140170 for (organ, model) in mapping
141171 # Get the status given by the user, that is used to set the default values of the variables in the mapping:
142172 st_scale_user = get_status (model)
0 commit comments