diff --git a/docs/src/internals/structures_3_instances.md b/docs/src/internals/structures_3_instances.md index 61f7a132b..0f46ac883 100644 --- a/docs/src/internals/structures_3_instances.md +++ b/docs/src/internals/structures_3_instances.md @@ -18,8 +18,8 @@ run_timestep::Union{Nothing, Function} # CompositeComponentInstance <: ComponentInstance comps_dict::OrderedDict{Symbol, ComponentInstance} -pars_dict::OrderedDict{Symbol, Any} # not currently being used but, probably should for better datum access -vars_dict::OrderedDict{Symbol, Any} # ^ same +parameters::NamedTuple +variables::NamedTuple # ModelInstance <: CompositeComponentInstance md::ModelDef diff --git a/src/core/build.jl b/src/core/build.jl index c6693f756..fcc7d4efe 100644 --- a/src/core/build.jl +++ b/src/core/build.jl @@ -77,14 +77,6 @@ function _instantiate_component_vars(md::ModelDef, comp_def::ComponentDef) return ComponentInstanceVariables(names, types, values, paths) end -function _combine_exported_pars(comp_def::AbstractCompositeComponentDef) - names = Symbol[] - values = Any[] - paths = repeat(Any[comp_def.comp_path], length(names)) - types = DataType[typeof(val) for val in values] - return ComponentInstanceParameters(names, types, values, paths) -end - # Creates the top-level vars for the model function _instantiate_vars(md::ModelDef) vdict = Dict{ComponentPath, Any}() @@ -241,10 +233,6 @@ function _instantiate_params(comp_def::ComponentDef, par_dict::Dict{Tuple{Compon return ComponentInstanceParameters(names, types, vals, paths) end -function _instantiate_params(comp_def::AbstractCompositeComponentDef, par_dict::Dict{Tuple{ComponentPath, Symbol}, Any}) - _combine_exported_pars(comp_def) -end - # Return a built leaf or composite LeafComponentInstance function _build(comp_def::ComponentDef, var_dict::Dict{ComponentPath, Any}, @@ -269,7 +257,35 @@ function _build(comp_def::AbstractCompositeComponentDef, # @info " par_dict $(par_dict)" comps = [_build(cd, var_dict, par_dict, time_bounds) for cd in compdefs(comp_def)] - return CompositeComponentInstance(comps, comp_def, time_bounds) + + variables = _get_variables(comp_def) + parameters = _get_parameters(comp_def) + + return CompositeComponentInstance(comps, comp_def, time_bounds, variables, parameters) +end + +# helper functions for to create the variables and parameters NamedTuples for a +# CompositeComponentInstance +function _get_variables(comp_def::AbstractCompositeComponentDef) + + namespace = comp_def.namespace + var_defs = filter(namespace -> isa(namespace.second, CompositeVariableDef), namespace) + names = [k for (k,v) in var_defs] + vals = [v.ref for (k,v) in var_defs] + variables = (; zip(names, vals)...) + + return variables +end + +function _get_parameters(comp_def::AbstractCompositeComponentDef) + + namespace = comp_def.namespace + par_defs = filter(namespace -> isa(namespace.second, CompositeParameterDef), namespace) + names = [k for (k,v) in par_defs] + vals = [v.refs[1] for (k,v) in par_defs] + parameters = (; zip(names, vals)...) + + return parameters end """ diff --git a/src/core/instances.jl b/src/core/instances.jl index b5fa810de..3fc1dc326 100644 --- a/src/core/instances.jl +++ b/src/core/instances.jl @@ -168,10 +168,32 @@ function Base.getindex(obj::AbstractCompositeComponentInstance, comp_name::Symbo return compinstance(obj, comp_name) end -function _get_datum(ci::AbstractComponentInstance, datum_name::Symbol) +# TBD we could probably combine the two _get_datum methods into one that takes a +# ci::AbstractComponentInstance, but for now it seems there are enough differences +# that keeping them separate is cleaner +function _get_datum(ci::CompositeComponentInstance, datum_name::Symbol) vars = variables(ci) - if datum_name in names(vars) + if datum_name in keys(vars) # could merge with method below if made names(NamedTuple) = keys(NamedTuple) + which = vars + else + pars = parameters(ci) + if datum_name in keys(pars) # could merge with method below if made names(NamedTuple) = keys(NamedTuple) + which = pars + else + error("$datum_name is not a parameter or a variable in component $(ci.comp_path).") + end + end + + ref = getproperty(which, datum_name) + + return _get_datum(ci.comps_dict[ref.comp_name], ref.datum_name) +end + +function _get_datum(ci::LeafComponentInstance, datum_name::Symbol) + vars = variables(ci) + + if datum_name in names(vars) which = vars else pars = parameters(ci) @@ -196,6 +218,8 @@ function Base.getindex(obj::AbstractCompositeComponentInstance, comp_name::Symbo return _get_datum(ci, datum) end + + """ dim_count(mi::ModelInstance, dim_name::Symbol) diff --git a/src/core/types/instances.jl b/src/core/types/instances.jl index 5e5c58ef0..559e1330e 100644 --- a/src/core/types/instances.jl +++ b/src/core/types/instances.jl @@ -189,13 +189,15 @@ end @class mutable CompositeComponentInstance <: ComponentInstance begin comps_dict::OrderedDict{Symbol, AbstractComponentInstance} - var_dict::OrderedDict{Symbol, Any} - par_dict::OrderedDict{Symbol, Any} + variables::NamedTuple + parameters::NamedTuple function CompositeComponentInstance(self::AbstractCompositeComponentInstance, comps::Vector{<: AbstractComponentInstance}, comp_def::AbstractCompositeComponentDef, time_bounds::Tuple{Int,Int}, + variables::NamedTuple, + parameters::NamedTuple, name::Symbol=nameof(comp_def)) comps_dict = OrderedDict{Symbol, AbstractComponentInstance}() @@ -203,11 +205,8 @@ end comps_dict[ci.comp_name] = ci end - var_dict = OrderedDict{Symbol, Any}() - par_dict = OrderedDict{Symbol, Any}() - ComponentInstance(self, comp_def, time_bounds, name) - CompositeComponentInstance(self, comps_dict, var_dict, par_dict) + CompositeComponentInstance(self, comps_dict, variables, parameters) return self end @@ -215,8 +214,10 @@ end function CompositeComponentInstance(comps::Vector{<: AbstractComponentInstance}, comp_def::AbstractCompositeComponentDef, time_bounds::Tuple{Int,Int}, + variables::NamedTuple, + parameters::NamedTuple, name::Symbol=nameof(comp_def)) - CompositeComponentInstance(new(), comps, comp_def, time_bounds, name) + CompositeComponentInstance(new(), comps, comp_def, time_bounds, variables, parameters, name) end end diff --git a/test/test_composite.jl b/test/test_composite.jl index 7279399ac..49e39c23b 100644 --- a/test/test_composite.jl +++ b/test/test_composite.jl @@ -6,7 +6,7 @@ using Mimi import Mimi: ComponentId, ComponentPath, ComponentDef, AbstractComponentDef, CompositeComponentDef, ModelDef, build, time_labels, compdef, find_comp, - import_params! + import_params!, CompositeVariableDef, CompositeParameterDef @defcomp Comp1 begin par_1_1 = Parameter(index=[time]) # external input @@ -88,7 +88,7 @@ end foo3 = Parameter(B.foo3) foo4 = Parameter(B.foo4) - var_3_1 = Variable(B.Comp3.var_3_1) + var_3_1 = Variable(B.var_3_1) connect(B.par_3_1, A.var_2_1) connect(B.par_4_1, B.var_3_1) @@ -138,6 +138,18 @@ run(m) mi = m.mi +# test parameters and variables fields of CompositeComponentInstance +top_var_keys = keys(mi[:top].variables) +top_par_keys = keys(mi[:top].parameters) +for item in md[:top].namespace + if isa(item.second, CompositeVariableDef) + @test in(item.first, top_var_keys) + elseif isa(item.second, CompositeParameterDef) + @test in(item.first, top_par_keys) + end +end + +# test access methods @test mi[:top][:A][:Comp2, :par_2_2] == collect(1.0:16.0) @test mi["/top/A/Comp2", :par_2_2] == collect(1.0:16.0) @@ -145,7 +157,10 @@ mi = m.mi @test mi["/top/A/Comp1", :var_1_1] == collect(1.0:16.0) @test mi["/top/B/Comp4", :par_4_1] == collect(6.0:6:96.0) -# +@test m[:top, :fooA1] == 1 +@test m[:top, :foo3] == 10 +@test m[:top, :var_3_1] == collect(6.0:6:96.0) + # Test joining external params. # m2 = Model()