Skip to content

Commit cba965c

Browse files
committed
More changes, the new approach now works in some cases, more to investigate. More tests to implement, and other tests to fix, etc.
1 parent b608126 commit cba965c

14 files changed

Lines changed: 521 additions & 310 deletions

src/PlantSimEngine.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ export PreviousTimeStep
108108
export AbstractModel
109109
export ModelList, MultiScaleModel, TimestepMappedVariable
110110
export MultiScaleMapping
111-
export Orchestrator2, TimestepRange, Var_to, Var_from, ModelTimestepMapping
111+
export Orchestrator, TimestepRange, ModelTimestepMapping
112112
export RMSE, NRMSE, EF, dr
113113
export Status, TimeStepTable, status
114114
export init_status!

src/dependencies/dependency_graph.jl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,16 @@ mutable struct HardDependencyNode{T} <: AbstractDependencyNode
66
dependency::NamedTuple
77
missing_dependency::Vector{Int}
88
scale::String
9-
inputs
10-
outputs
9+
#inputs
10+
#outputs
1111
parent::Union{Nothing,<:AbstractDependencyNode}
1212
children::Vector{HardDependencyNode}
1313
end
1414

1515
mutable struct TimestepMapping
1616
variable_from::Symbol
1717
variable_to::Symbol
18-
node_to # SoftDependencyNode causes a circular reference, removing it as a shortcut TODO
18+
timestep_to::Period
1919
mapping_function::Function
2020
mapping_data_template
2121
mapping_data::Dict{Int, Any} # TODO fix type stability : Int is the node id, Any is a vector of n elements of the variable's type, n being the # of required timesteps
@@ -26,8 +26,8 @@ mutable struct SoftDependencyNode{T} <: AbstractDependencyNode
2626
value::T
2727
process::Symbol
2828
scale::String
29-
inputs
30-
outputs
29+
#inputs
30+
#outputs
3131
hard_dependency::Vector{HardDependencyNode}
3232
parent::Union{Nothing,Vector{SoftDependencyNode}}
3333
parent_vars::Union{Nothing,NamedTuple}

src/dependencies/hard_dependencies.jl

Lines changed: 24 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,8 @@ function initialise_all_as_hard_dependency_node(models, scale)
100100
NamedTuple(),
101101
Int[],
102102
scale,
103-
inputs_(i),
104-
outputs_(i),
103+
#inputs_(i),
104+
#outputs_(i),
105105
nothing,
106106
HardDependencyNode[]
107107
) for (p, i) in pairs(models)
@@ -134,7 +134,7 @@ Return a NamedTuple with the variables and their default values.
134134
The `vars_mapping` is a dictionary with the organ type as key and a dictionary as value. It is
135135
computed from the user mapping like so:
136136
"""
137-
function variables_multiscale(node, organ, vars_mapping, st=NamedTuple(), orchestrator::Orchestrator2=Orchestrator2())
137+
function variables_multiscale(node, organ, vars_mapping, st=NamedTuple(), orchestrator::Orchestrator=Orchestrator())
138138
node_vars = variables(node) # e.g. (inputs = (:var1=-Inf, :var2=-Inf), outputs = (:var3=-Inf,))
139139
ins = node_vars.inputs
140140
ins_variables = keys(ins)
@@ -154,36 +154,22 @@ function variables_multiscale(node, organ, vars_mapping, st=NamedTuple(), orches
154154
# If the variable is an output, we use the default value given by the model:
155155
default = defaults[var]
156156
end
157-
158-
# TODO no idea how this meshes with refvector situations or previoustimestep
159-
# if is_timestep_mapped(organ => var, orchestrator, search_inputs_only=true)
160-
# push!(vars_, var => default)
161-
# if haskey(vars_mapping[organ], PreviousTimeStep(var, node.process))
162-
# organ_mapped, organ_mapped_var = _node_mapping(vars_mapping[organ][PreviousTimeStep(var, node.process)])
163-
# push!(vars_, var => MappedVar(organ_mapped, PreviousTimeStep(var, node.process), organ_mapped_var, default))
164-
# end
165-
# else
166-
if is_timestep_mapped(organ => var, orchestrator, search_inputs_only=true)
167-
168-
push!(vars_, var => default)
169-
else
170-
if haskey(vars_mapping[organ], var)
171-
organ_mapped, organ_mapped_var = _node_mapping(vars_mapping[organ][var])
172-
push!(vars_, var => MappedVar(organ_mapped, var, organ_mapped_var, default))
173-
#* We still check if the variable also exists wrapped in PreviousTimeStep, because one model could use the current
174-
#* values, and another one the previous values.
175-
if haskey(vars_mapping[organ], PreviousTimeStep(var, node.process))
176-
organ_mapped, organ_mapped_var = _node_mapping(vars_mapping[organ][PreviousTimeStep(var, node.process)])
177-
push!(vars_, var => MappedVar(organ_mapped, PreviousTimeStep(var, node.process), organ_mapped_var, default))
178-
end
179-
elseif haskey(vars_mapping[organ], PreviousTimeStep(var, node.process))
180-
# If not found in the current time step, we check if the variable is mapped to the previous time step:
157+
if haskey(vars_mapping[organ], var)
158+
organ_mapped, organ_mapped_var = _node_mapping(vars_mapping[organ][var])
159+
push!(vars_, var => MappedVar(organ_mapped, var, organ_mapped_var, default))
160+
#* We still check if the variable also exists wrapped in PreviousTimeStep, because one model could use the current
161+
#* values, and another one the previous values.
162+
if haskey(vars_mapping[organ], PreviousTimeStep(var, node.process))
181163
organ_mapped, organ_mapped_var = _node_mapping(vars_mapping[organ][PreviousTimeStep(var, node.process)])
182164
push!(vars_, var => MappedVar(organ_mapped, PreviousTimeStep(var, node.process), organ_mapped_var, default))
183-
else
184-
# Else we take the default value:
185-
push!(vars_, var => default)
186165
end
166+
elseif haskey(vars_mapping[organ], PreviousTimeStep(var, node.process))
167+
# If not found in the current time step, we check if the variable is mapped to the previous time step:
168+
organ_mapped, organ_mapped_var = _node_mapping(vars_mapping[organ][PreviousTimeStep(var, node.process)])
169+
push!(vars_, var => MappedVar(organ_mapped, PreviousTimeStep(var, node.process), organ_mapped_var, default))
170+
else
171+
# Else we take the default value:
172+
push!(vars_, var => default)
187173
end
188174
end
189175
# end
@@ -210,12 +196,12 @@ function extract_timestep_mapped_outputs(m::MultiScaleModel, organ::String, outp
210196
key = process(m.model)
211197
extra_outputs = timestep_mapped_outputs_(m)
212198
#ind = findfirst(x -> first(x) == key, outputs_process[organ][key])
213-
timestep_mapped_outputs_process[organ][key] = (; extra_outputs...) #TODO
199+
timestep_mapped_outputs_process[organ][key] = extra_outputs #TODO
214200
end
215201
end
216202

217203
# When we use a mapping (multiscale), we return the set of soft-dependencies (we put the hard-dependencies as their children):
218-
function hard_dependencies(mapping::Dict{String,T}; verbose::Bool=true, orchestrator::Orchestrator2=Orchestrator2()) where {T}
204+
function hard_dependencies(mapping::Dict{String,T}; verbose::Bool=true, orchestrator::Orchestrator=Orchestrator()) where {T}
219205
full_vars_mapping = Dict(first(mod) => Dict(get_mapped_variables(last(mod))) for mod in mapping)
220206
soft_dep_graphs = Dict{String,Any}()
221207
not_found = Dict{Symbol,DataType}()
@@ -239,7 +225,7 @@ function hard_dependencies(mapping::Dict{String,T}; verbose::Bool=true, orchestr
239225
#* dependency may not appear in its own scale, but this is treated in the soft-dependency computation
240226
inputs_process = Dict{String,Dict{Symbol,Vector}}()
241227
outputs_process = Dict{String,Dict{Symbol,Vector}}()
242-
timestep_mapped_outputs_process = Dict{String,Dict{Symbol,NamedTuple}}()
228+
timestep_mapped_outputs_process = Dict{String,Dict{Symbol,Vector}}()
243229
for (organ, model) in mapping
244230
# Get the status given by the user, that is used to set the default values of the variables in the mapping:
245231
st_scale_user = get_status(model)
@@ -324,8 +310,8 @@ function hard_dependencies(mapping::Dict{String,T}; verbose::Bool=true, orchestr
324310
dep_node_model.dependency,
325311
dep_node_model.missing_dependency,
326312
dep_node_model.scale,
327-
dep_node_model.inputs,
328-
dep_node_model.outputs,
313+
#dep_node_model.inputs,
314+
#dep_node_model.outputs,
329315
parent_node,
330316
dep_node_model.children
331317
)
@@ -398,8 +384,8 @@ function hard_dependencies(mapping::Dict{String,T}; verbose::Bool=true, orchestr
398384
soft_dep_vars.value,
399385
process_, # process name
400386
organ, # scale
401-
inputs_process[organ][process_], # These are the inputs, potentially multiscale
402-
outputs_process[organ][process_], # Same for outputs
387+
#inputs_process[organ][process_], # These are the inputs, potentially multiscale
388+
#outputs_process[organ][process_], # Same for outputs
403389
AbstractTrees.children(soft_dep_vars), # hard dependencies
404390
nothing,
405391
nothing,
@@ -430,7 +416,7 @@ function hard_dependencies(mapping::Dict{String,T}; verbose::Bool=true, orchestr
430416
end
431417
end
432418

433-
soft_dep_graphs[organ] = (soft_dep_graph=soft_dep_graph, inputs=inputs_process[organ], outputs=outputs_process[organ], timestep_mapped_outputs=haskey(timestep_mapped_outputs_process,organ) ? timestep_mapped_outputs_process[organ] : Dict{Symbol,NamedTuple}())
419+
soft_dep_graphs[organ] = (soft_dep_graph=soft_dep_graph, inputs=inputs_process[organ], outputs=outputs_process[organ], timestep_mapped_outputs=haskey(timestep_mapped_outputs_process,organ) ? timestep_mapped_outputs_process[organ] : Dict{Symbol,Vector}())
434420
not_found = merge(not_found, hard_deps[organ].not_found)
435421
end
436422

src/dependencies/soft_dependencies.jl

Lines changed: 23 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ function soft_dependencies(d::DependencyGraph{Dict{Symbol,HardDependencyNode}},
6464
soft_dep_vars.value,
6565
process_, # process name
6666
"",
67-
inputs_(soft_dep_vars.value),
68-
outputs_(soft_dep_vars.value),
67+
#inputs_(soft_dep_vars.value),
68+
#outputs_(soft_dep_vars.value),
6969
AbstractTrees.children(soft_dep_vars), # hard dependencies
7070
nothing,
7171
nothing,
@@ -323,156 +323,32 @@ function soft_dependencies_multiscale(soft_dep_graphs_roots::DependencyGraph{Dic
323323
end
324324

325325
if haskey(timestep_mapped_outs, proc)
326-
CreateTimeStepMapping(i, reverse_multiscale_mapping, organ, proc)
326+
create_timestep_mapping(i, timestep_mapped_outs, proc)
327327
end
328328

329329
end
330330
end
331331

332332
dep_graph = DependencyGraph(independant_process_root, soft_dep_graphs_roots.not_found)
333333

334-
# TODO move these into the loop to directly act on the ndoe, use the provided timestep mappings
335-
# Don't provide parents, and then change the run! function to apply from the node to itself
336-
#traverse_dependency_graph!(x -> set_non_default_timestep_in_node(x, orchestrator), dependency_graph, visit_hard_dep=false)
337-
#traverse_dependency_graph!(x -> add_timestep_data_to_node(x, orchestrator), dep_graph, visit_hard_dep=false)
338-
339-
340334
return dep_graph
341335
end
342336

343-
# # set the timestep for everyone first, else we might not use the correct timestep when looking at the parents later
344-
function set_non_default_timestep_in_node(soft_dependency_node, orchestrator::Orchestrator2)
345-
for mtsm in orchestrator.non_default_timestep_mapping
346-
if mtsm.scale == soft_dependency_node.scale && (mtsm.model) == typeof(model_(soft_dependency_node.value))
347-
soft_dependency_node.timestep = mtsm.timestep
348-
end
349-
end
350-
end
351-
352-
function add_timestep_data_to_node(soft_dependency_node, orchestrator::Orchestrator2)
353-
354-
# now we can create the mapping
355-
for mtsm in orchestrator.non_default_timestep_mapping
356-
if mtsm.scale == soft_dependency_node.scale && (mtsm.model) == typeof(model_(soft_dependency_node.value))
357-
for (var_from, var_to) in mtsm.var_to_var
358-
if !isnothing(soft_dependency_node.parent)
359-
parent = nothing
360-
variable_mapping = nothing
361-
for parent_node in soft_dependency_node.parent
362-
if typeof(parent_node.value) == var_from.model && parent_node.scale == var_from.scale
363-
parent = parent_node
364-
variable_mapping = create_timestep_mapping(soft_dependency_node, parent, var_to, var_from)
365-
break
366-
end
367-
end
368-
if isnothing(parent)
369-
#error
370-
end
371-
if isnothing(parent.timestep_mapping_data)
372-
parent.timestep_mapping_data = Vector{TimestepMapping}()
373-
end
374-
push!(parent.timestep_mapping_data, variable_mapping)
375-
else
376-
# Error
377-
end
378-
end
379-
end
380-
end
381-
end
382-
383-
# Create the structure to attach to the softdependencynode, (not to be confused with the user-declared timestep-mapping structure)
384-
function create_timestep_mapping(node::SoftDependencyNode, parent::SoftDependencyNode, var_to::Var_to, var_from::Var_from)
385-
386-
@assert parent.timestep != 0 "Error : node timestep internally set to 0"
387-
388-
timestep_ratio = node.timestep / parent.timestep
389-
390-
# Keeping things simple for now, only integers allowed
391-
@assert timestep_ratio == trunc(timestep_ratio) "Error : non-integer timestep ratio"
392-
393-
# TODO ensure type compatibility between var_to and var_from
394-
# Simplification probably possible by doing the check earlier
395-
396-
# TODO test previoustimestep
397-
var_type = DataType
398-
399-
for (symbol, var_dump) in node.inputs
400-
for var in var_dump
401-
if isa(var, MappedVar)
402-
# check the source variable, because the sink one might be a vector...?
403-
# TODO multinode mapping
404-
if isa(var.source_organ, MultiNodeMapping)
405-
if var.source_variable[1] == var_from.name
406-
# This should be a fixed size array, ideally
407-
var_type = eltype(eltype(mapped_default(var)))
408-
break
409-
end
410-
else
411-
if var.source_variable == var_from.name
412-
# This should be a fixed size array, ideally
413-
var_type = eltype(mapped_default(var))
414-
break
415-
end
416-
end
417-
else
418-
if var.symbol == var_from.name
419-
@assert "untested"
420-
var_type = eltype(mapped_default(var))
421-
break
422-
end
423-
end
424-
end
425-
end
426-
427-
# TODO : type shouldn't be Any but Vector{var_type}
428-
return TimestepMapping(var_from.name, var_to.name, node, var_from.mapping_function, mapping_data_template, Dict{MultiScaleTreeGraph.NodeMTG, Any}())
429-
end
430-
431-
432-
function CreateTimeStepMapping(soft_dependency_node, reverse_multiscale_mapping, scale, proc)
433-
434-
for mapping_entry in reverse_multiscale_mapping[scale]
435-
if isa(mapping_entry, MultiScaleModel)
436-
if process(mapping_entry.model) == proc
437-
for timestep_mapped_var_data in mapping_entry.timestep_mapped_variables
438-
timestep_ratio = timestep_mapped_var_data.timestep_to / soft_dependency_node.timestep
439-
if timestep_ratio > 1 # todo assert it's an int or a rational ?
440-
@assert timestep_ratio == trunc(timestep_ratio) "Error : non-integer timestep ratio"
337+
function create_timestep_mapping(soft_dependency_node, timestep_mapped_outs, proc)
441338

442-
tmvd = timestep_mapped_var_data
339+
for (proc_mapped, mapping_entries) in timestep_mapped_outs
443340

444-
var_type = DataType
341+
if proc_mapped == proc
342+
for (var_to, (timestep_mapped_var_data, default_value)) in mapping_entries
343+
timestep_ratio = timestep_mapped_var_data.timestep_to / soft_dependency_node.timestep
344+
if timestep_ratio > 1 # todo assert it's an int or a rational ?
345+
@assert timestep_ratio == trunc(timestep_ratio) "Error : non-integer timestep ratio"
445346

446-
for (symbol, var_dump) in soft_dependency_node.outputs
447-
for var in var_dump
448-
if isa(var, MappedVar)
449-
# check the source variable, because the sink one might be a vector...?
450-
# TODO multinode mapping
451-
if isa(var.source_organ, MultiNodeMapping)
452-
if var.source_variable[1] == tmvd.name_from
453-
# This should be a fixed size array, ideally
454-
var_type = eltype(eltype(mapped_default(var)))
455-
break
456-
end
457-
else
458-
if var.source_variable == tmvd.name_from
459-
# This should be a fixed size array, ideally
460-
var_type = eltype(mapped_default(var))
461-
break
462-
end
463-
end
464-
else
465-
if var.symbol == tmvd.name_from
466-
@assert "untested"
467-
var_type = eltype(mapped_default(var))
468-
break
469-
end
470-
end
471-
end
472-
end
347+
tmvd = timestep_mapped_var_data
348+
var_type = typeof(default_value)
473349

474-
mapping_data_template = Vector{var_type}(undef, convert(Int64, timestep_ratio))
475-
tsm = TimestepMapping(tmvd.name_from, tmvd.name_to, soft_dependency_node, tmvd.aggregation_function, mapping_data_template, Dict{MultiScaleTreeGraph.NodeMTG,Any}())
350+
mapping_data_template = Vector{var_type}(undef, convert(Int64, timestep_ratio))
351+
tsm = TimestepMapping(tmvd.name_from, tmvd.name_to, timestep_mapped_var_data.timestep_to, tmvd.aggregation_function, mapping_data_template, Dict{MultiScaleTreeGraph.NodeMTG,Any}())
476352

477353
if isnothing(soft_dependency_node.timestep_mapping_data)
478354
soft_dependency_node.timestep_mapping_data = Vector{TimestepMapping}()
@@ -483,10 +359,9 @@ function CreateTimeStepMapping(soft_dependency_node, reverse_multiscale_mapping,
483359
end
484360
end
485361
end
486-
end
487362

488363

489-
"""
364+
"""
490365
drop_process(proc_vars, process)
491366
492367
Return a new `NamedTuple` with the process `process` removed from the `NamedTuple` `proc_vars`.
@@ -674,6 +549,13 @@ function search_inputs_in_multiscale_output(process, organ, inputs, soft_dep_gra
674549
return inputs_as_output_of_other_scale
675550
end
676551

552+
function extract_mapped_outputs(timestep_mapped_outputs)
553+
extracted = Pair[]
554+
for pair in timestep_mapped_outputs
555+
push!(extracted, Pair(first(last(pair)).name_to, last(last(pair))))
556+
end
557+
return extracted
558+
end
677559

678560
function add_input_as_output!(inputs_as_output_of_other_scale, soft_dep_graphs, organ_source, variable, value)
679561

@@ -684,7 +566,7 @@ function add_input_as_output!(inputs_as_output_of_other_scale, soft_dep_graphs,
684566
vars_all_outputs = vars_output
685567

686568
if haskey(timestep_mapped_outputs, proc_output)
687-
vars_all_outputs = (; vars_output..., flatten_vars(timestep_mapped_outputs)...)
569+
vars_all_outputs = (; vars_output..., extract_mapped_outputs(timestep_mapped_outputs[proc_output])...)
688570
end
689571

690572
# If the variable is found in the outputs of the process at the other scale:

0 commit comments

Comments
 (0)