Skip to content

Commit 7595212

Browse files
authored
Merge pull request #149 from VirtualPlantLab/add-dependency-graph-into-ModelList
Add dependency graph into model list
2 parents 55f3f94 + 6449e6f commit 7595212

6 files changed

Lines changed: 47 additions & 27 deletions

File tree

src/PlantSimEngine.jl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ include("component_models/RefVector.jl")
4343
# Simulation table (time-step table, from PlantMeteo):
4444
include("component_models/TimeStepTable.jl")
4545

46+
# Declaring the dependency graph
47+
include("dependencies/dependency_graph.jl")
48+
4649
# List of models:
4750
include("component_models/ModelList.jl")
4851
include("mtg/MultiScaleModel.jl")
@@ -53,8 +56,7 @@ include("component_models/get_status.jl")
5356
# Transform into a dataframe:
5457
include("dataframe.jl")
5558

56-
# Model dependencies:
57-
include("dependencies/dependency_graph.jl")
59+
# Computing model dependencies:
5860
include("dependencies/soft_dependencies.jl")
5961
include("dependencies/hard_dependencies.jl")
6062
include("dependencies/traversal.jl")

src/component_models/ModelList.jl

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,8 @@ julia> [typeof(models[i][1]) for i in keys(status(models))]
147147
struct ModelList{M<:NamedTuple,S}
148148
models::M
149149
status::S
150-
type_promotion::Union{Nothing, Dict}
150+
type_promotion::Union{Nothing,Dict}
151+
dependency_graph::DependencyGraph
151152
end
152153

153154
#=function ModelList(models::M, status::Status) where {M<:NamedTuple{names,T} where {names,T<:NTuple{N,<:AbstractModel} where {N}}}
@@ -160,7 +161,6 @@ function ModelList(
160161
status=nothing,
161162
type_promotion::Union{Nothing,Dict}=nothing,
162163
variables_check::Bool=true,
163-
nsteps=nothing,
164164
kwargs...
165165
)
166166

@@ -187,10 +187,13 @@ function ModelList(
187187
ts_kwargs = homogeneous_ts_kwargs(status)
188188
ts_kwargs = add_model_vars(ts_kwargs, mods, type_promotion)
189189

190+
191+
190192
model_list = ModelList(
191193
mods,
192194
ts_kwargs,
193-
type_promotion
195+
type_promotion,
196+
dep(; verbose=true, mods...)
194197
)
195198
variables_check && !is_initialized(model_list)
196199

@@ -219,8 +222,8 @@ function add_model_vars(x, models, type_promotion)
219222

220223
# If the user gave a status, we check if all the variables are already initialized:
221224
vars_in_x = status_keys(x)
222-
status_x =
223-
all([k in vars_in_x for k in keys(ref_vars)]) && return isa(x, Status) ? x : Status(x) # If so, we return the input
225+
status_x =
226+
all([k in vars_in_x for k in keys(ref_vars)]) && return isa(x, Status) ? x : Status(x) # If so, we return the input
224227

225228
# Else, we add the variables by making a new object (carefull, this is a copy so it takes more time):
226229

@@ -229,15 +232,15 @@ function add_model_vars(x, models, type_promotion)
229232

230233
# If the user gave an empty status, we initialize all variables to their default values:
231234
if x === nothing
232-
return Status(ref_vars)
235+
return Status(ref_vars)
233236
end
234-
237+
235238
if Tables.istable(x)
236239
# This situation only occurs if the user provided a table instead of a status
237240
# Meaning we have a status of vector values, all initialized up to a certain point
238241
# Unsure this is desirable, as that means run! does nothing or overwrites everything
239242
# Anyway, we wish to create a NamedTuple() of Vectors here
240-
x_full = (;zip(propertynames(x), Tables.columns(x))...)
243+
x_full = (; zip(propertynames(x), Tables.columns(x))...)
241244
x_full = merge(ref_vars, x_full)
242245

243246
else
@@ -286,7 +289,7 @@ PlantSimEngine.homogeneous_ts_kwargs((Tₗ=[25.0, 26.0], aPPFD=1000.0))
286289
function homogeneous_ts_kwargs(kwargs::NamedTuple{N,T}) where {N,T}
287290
length(kwargs) == 0 && return kwargs
288291
vars_vals = collect(Any, values(kwargs))
289-
292+
290293
vars_array = NamedTuple{keys(kwargs)}(j for j in vars_vals)
291294

292295
return vars_array
@@ -325,15 +328,17 @@ function Base.copy(m::T) where {T<:ModelList}
325328
ModelList(
326329
m.models,
327330
deepcopy(m.status),
328-
deepcopy(m.type_promotion)
331+
deepcopy(m.type_promotion),
332+
deepcopy(m.dependency_graph)
329333
)
330334
end
331335

332336
function Base.copy(m::T, status) where {T<:ModelList}
333337
ModelList(
334338
m.models,
335339
status,
336-
deepcopy(m.type_promotion)
340+
deepcopy(m.type_promotion),
341+
deepcopy(m.dependency_graph)
337342
)
338343
end
339344

@@ -465,7 +470,7 @@ function convert_vars!(mapped_vars::Dict{String,Dict{Symbol,Any}}, type_promotio
465470
end
466471

467472
function Base.show(io::IO, ::MIME"text/plain", t::ModelList)
468-
print(io, dep(t, verbose=false))
473+
print(io, dep(t))
469474
print(io, status(t))
470475
end
471476

src/dependencies/dependencies.jl

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
dep(::T, nsteps=1) where {T<:AbstractModel} = NamedTuple()
22

33
"""
4-
dep(m::ModelList, nsteps=1; verbose::Bool=true)
4+
dep(m::ModelList)
55
dep(mapping::Dict{String,T}; verbose=true)
6+
dep!(m::ModelList, nsteps=1)
67
78
Get the model dependency graph given a ModelList or a multiscale model mapping. If one graph is returned,
89
then all models are coupled. If several graphs are returned, then only the models inside each graph are coupled, and
@@ -34,7 +35,12 @@ to other scales if needed. Then we transform all these nodes into soft dependenc
3435
Then we traverse all these and we set nodes that need outputs from other nodes as inputs as children/parents.
3536
If a node has no dependency, it is set as a root node and pushed into a new Dict (independant_process_root). This Dict is the returned dependency graph. And
3637
it presents root nodes as independent starting points for the sub-graphs, which are the models that are coupled together. We can then traverse each of
37-
these graphs independently to retrieve the models that are coupled together, in the right order of execution.
38+
these graphs independently to r
39+
40+
# Notes
41+
42+
The difference between `dep(m::ModelList)` and `dep!(m::ModelList, nsteps)` is that the first one returns the dependency graph found in the model list, while the
43+
second one returns the dependency graph with the specified number of steps, modifying the simulation IDs of each node in the graph (`simulation_id=fill(0, nsteps)`).
3844
3945
# Examples
4046
@@ -75,8 +81,18 @@ function dep(nsteps=1; verbose::Bool=true, vars...)
7581
return deps
7682
end
7783

78-
function dep(m::ModelList, nsteps=1; verbose::Bool=true)
79-
dep(nsteps; verbose=verbose, m.models...)
84+
function dep(m::ModelList)
85+
m.dependency_graph
86+
end
87+
88+
function dep!(m::ModelList, nsteps=1)
89+
traverse_dependency_graph!(m.dependency_graph; visit_hard_dep=false) do node
90+
if length(node.simulation_id) != nsteps
91+
node.simulation_id = fill(0, nsteps)
92+
end
93+
end
94+
95+
return m.dependency_graph
8096
end
8197

8298

src/processes/model_initialisation.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ mapping = Dict(
6565
to_initialize(mapping)
6666
```
6767
"""
68-
function to_initialize(m::ModelList; verbose::Bool=true)
69-
needed_variables = to_initialize(dep(m; verbose=verbose))
68+
function to_initialize(m::ModelList)
69+
needed_variables = to_initialize(dep(m))
7070
to_init = Dict{Symbol,Tuple}()
7171
for (process, vars) in needed_variables
7272
# default_values = needed_variables[:process1]
@@ -245,7 +245,7 @@ function init_variables(model::T; verbose::Bool=true) where {T<:AbstractModel}
245245
end
246246

247247
function init_variables(m::ModelList; verbose::Bool=true)
248-
init_variables(dep(m; verbose=verbose))
248+
init_variables(dep(m))
249249
end
250250

251251
function init_variables(m::DependencyGraph)
@@ -300,7 +300,7 @@ is_initialized(models)
300300
```
301301
"""
302302
function is_initialized(m::T; verbose=true) where {T<:ModelList}
303-
var_names = to_initialize(m; verbose=verbose)
303+
var_names = to_initialize(m)
304304

305305
if any([length(to_init) > 0 for (process, to_init) in pairs(var_names)])
306306
verbose && @info "Some variables must be initialized before simulation: $var_names (see `to_initialize()`)" maxlog = 1

src/run.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ function run!(
187187
meteo_adjusted = adjust_weather_timesteps_to_given_length(get_status_vector_max_length(object.status), meteo)
188188
nsteps = get_nsteps(meteo_adjusted)
189189

190-
dep_graph = dep(object, nsteps)
190+
dep_graph = dep!(object, nsteps)
191191

192192
if check
193193
# Check if the meteo data and the status have the same length (or length 1)

test/test-ModelList.jl

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
leaf = ModelList(
1919
process1=Process1Model(1.0),
2020
process2=Process2Model(),
21-
nsteps=3
2221
)
2322

2423
@test length(status(leaf)) == 5
@@ -81,7 +80,6 @@ end;
8180
process1=Process1Model(1.0),
8281
process2=Process2Model(),
8382
status=(var1=15.0,),
84-
nsteps=3
8583
)
8684

8785
@test length(status(leaf)) == 5
@@ -123,8 +121,7 @@ end;
123121
inits = init_variables(leaf)
124122
sorted_vars = sort([keys(inits.process3)...])
125123

126-
@test [getfield(inits.process3, i) for i in sorted_vars] ==
127-
fill(-Inf, 3)
124+
@test [getfield(inits.process3, i) for i in sorted_vars] == fill(-Inf, 3)
128125
end;
129126

130127
@testset "Copy a ModelList" begin

0 commit comments

Comments
 (0)