Skip to content
4 changes: 2 additions & 2 deletions docs/src/internals/structures_3_instances.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
42 changes: 29 additions & 13 deletions src/core/build.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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}()
Expand Down Expand Up @@ -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},
Expand All @@ -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

"""
Expand Down
28 changes: 26 additions & 2 deletions src/core/instances.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)

Expand Down
15 changes: 8 additions & 7 deletions src/core/types/instances.jl
Original file line number Diff line number Diff line change
Expand Up @@ -189,34 +189,35 @@ 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}()
for ci in comps
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

# TBD: Construct vars and params from sub-components
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

Expand Down
21 changes: 18 additions & 3 deletions test/test_composite.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -138,14 +138,29 @@ 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)

@test mi["/top/A/Comp2", :var_2_1] == collect(3.0:3:48.0)
@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()
Expand Down