Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 98 additions & 0 deletions examples/compositecomp-model.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
using Mimi

# components
@defcomp Comp1 begin
par_1_1 = Parameter(index=[time]) # external input
var_1_1 = Variable(index=[time]) # computed
foo = Parameter()

function run_timestep(p, v, d, t)
v.var_1_1[t] = p.par_1_1[t]
end
end

@defcomp Comp2 begin
par_2_1 = Parameter(index=[time]) # connected to Comp1.var_1_1
par_2_2 = Parameter(index=[time]) # external input
var_2_1 = Variable(index=[time]) # computed
foo = Parameter()

function run_timestep(p, v, d, t)
v.var_2_1[t] = p.par_2_1[t] + p.foo * p.par_2_2[t]
end
end

@defcomp Comp3 begin
par_3_1 = Parameter(index=[time]) # connected to Comp2.var_2_1
var_3_1 = Variable(index=[time]) # external output
foo = Parameter(default=30)

function run_timestep(p, v, d, t)
# @info "Comp3 run_timestep"
v.var_3_1[t] = p.par_3_1[t] * 2
end
end

@defcomp Comp4 begin
par_4_1 = Parameter(index=[time]) # connected to Comp2.var_2_1
var_4_1 = Variable(index=[time]) # external output
foo = Parameter(default=300)

function run_timestep(p, v, d, t)
# @info "Comp4 run_timestep"
v.var_4_1[t] = p.par_4_1[t] * 2
end
end

@defcomposite A begin
Component(Comp1)
Component(Comp2)

foo1 = Parameter(Comp1.foo)
foo2 = Parameter(Comp2.foo)

var_2_1 = Variable(Comp2.var_2_1)

connect(Comp2.par_2_1, Comp1.var_1_1)
connect(Comp2.par_2_2, Comp1.var_1_1)
end

@defcomposite B begin
Component(Comp3)
Component(Comp4)

foo3 = Parameter(Comp3.foo)
foo4 = Parameter(Comp4.foo)

var_3_1 = Variable(Comp3.var_3_1)
end

@defcomposite top begin
Component(A)

fooA1 = Parameter(A.foo1)
fooA2 = Parameter(A.foo2)

# TBD: component B isn't getting added to mi
Component(B)
foo3 = Parameter(B.foo3)
foo4 = Parameter(B.foo4)

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)
end

# model
m = Model()
md = m.md
set_dimension!(m, :time, 2005:2020)
add_comp!(m, top, nameof(top))

set_param!(m, :fooA1, 1)
set_param!(m, :fooA2, 2)
set_param!(m, :foo3, 10)
set_param!(m, :foo4, 20)
set_param!(m, :par_1_1, collect(1:length(time_labels(md))))
run(m)
2 changes: 1 addition & 1 deletion src/core/model.jl
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ Return an iterator on the components in a model's model instance.

Return a DatumDef for `item` in the given component `comp_def`.
"""
function datumdef(comp_def::ComponentDef, item::Symbol)
function datumdef(comp_def::AbstractComponentDef, item::Symbol)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ckingdon95 do you see a downside to doing it this way (generalizing to one signature for all AbstractComponentDef types instead of making a separate method for a CompositeComponentDef? All tests pass, but you have a better sense of the theory behind this so I want to make sure I'm not breaking something.

if has_variable(comp_def, item)
return variable(comp_def, item)

Expand Down
3 changes: 3 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ Electron.prep_test_env()
@info("test_explorer_sim.jl")
@time include("test_explorer_sim.jl")

@info("test_explorer_compositecomp.jl")
@time include("test_explorer_compositecomp.jl")

@info("test_plotting.jl")
@time include("test_plotting.jl")

Expand Down
59 changes: 59 additions & 0 deletions test/test_explorer_compositecomp.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using Mimi
using Test
using DataFrames
using VegaLite
using Electron

import Mimi:
dataframe_or_scalar, _spec_for_item, menu_item_list, getdataframe, dim_names, time_labels

# Helper function returns true if VegaLite is verison 3 or above, and false otherwise
function _is_VegaLite_v3()
return isdefined(VegaLite, :vlplot) ? true : false
end

include("../examples/compositecomp-model.jl") # constructs and runs model
# m's structure is as follows:
#
# top
# / \
# A B
# / \ / \
# 1 2 3 4


# 1. dataframe helper functions
@test typeof(dataframe_or_scalar(m, :top, :fooA1)) == Float64 # same for fooA2, foo3, foo4
@test typeof(dataframe_or_scalar(m, :top, :var_3_1)) == DataFrame
@test typeof(dataframe_or_scalar(m, :top, :par_1_1)) == DataFrame

#2. Specs and menu
items = [:fooA1, :fooA2, :foo3, :foo4, :var_3_1, :par_1_1]
for item in items
static_spec = _spec_for_item(m, :top, item; interactive = false)
interactive_spec = _spec_for_item(m, :top, item)
if length(dim_names(m, :top, item)) == 0
name = string(:top, " : ", item, " = ", m[:top, item])
else
name = string(:top, " : ", item)
end
@test static_spec["name"] == interactive_spec["name"] == name
end

s = menu_item_list(m)
@test typeof(s) == Array{Any, 1}
@test length(s) == 6

#3. explore(m::Model, title = "Electron")
w = explore(m, title = "Testing Window")
@test typeof(w) == Electron.Window
close(w)

#4. Mim.plot(m::Model, comp_name::Symbol, datum_name::Symbol;
# dim_name::Union{Nothing, Symbol} = nothing)
items = [:fooA1, :fooA2, :foo3, :foo4, :var_3_1, :par_1_1]
for item in items
p = Mimi.plot(m, :top, item)
p_type = _is_VegaLite_v3() ? VegaLite.VLSpec : VegaLite.VLSpec{:plot}
@test typeof(p) == p_type
end