From 79eb50002b45beaba77c95b5d7dd41851017f157 Mon Sep 17 00:00:00 2001 From: Cora Kingdon Date: Tue, 10 Dec 2019 15:59:31 -0500 Subject: [PATCH 1/6] Implement new datum type parameterization syntax in @defcomp --- src/core/defcomp.jl | 20 +++++++------ test/test_explorer_model.jl | 2 +- test/test_main.jl | 4 +-- test/test_main_variabletimestep.jl | 4 +-- test/test_model_structure.jl | 16 +++++------ test/test_model_structure_variabletimestep.jl | 10 +++---- test/test_parametertypes.jl | 28 ++++++++++--------- test/test_replace_comp.jl | 2 +- 8 files changed, 46 insertions(+), 40 deletions(-) diff --git a/src/core/defcomp.jl b/src/core/defcomp.jl index f78ae0da5..96aef5968 100644 --- a/src/core/defcomp.jl +++ b/src/core/defcomp.jl @@ -105,7 +105,7 @@ function _generate_var_or_param(elt_type, name, datatype, dimensions, dflt, desc return expr end -function _generate_dims_expr(name, args, vartype) +function _generate_dims_expr(name, args, datum_type) @debug " Index $name" # Args are not permitted; we attempt capture only to check syntax @@ -114,8 +114,8 @@ function _generate_dims_expr(name, args, vartype) end # Ditto types for Index, e.g., region::Foo = Index() - if vartype !== nothing - error("Index $name: Type specification ($vartype) is not supported") + if datum_type !== nothing + error("Index $name: Type specification ($datum_type) is not supported") end name_expr = (name isa Symbol) ? :($(QuoteNode(name))) : name @@ -195,13 +195,17 @@ macro defcomp(comp_name, ex) continue end - if ! @capture(elt, (name_::vartype_ | name_) = elt_type_(args__)) - error("Element syntax error: $elt") + if @capture(elt, name_::datum_type_ = elt_type_(args__)) + error("Deprecated type syntax: \"$name::$datum_type = $elt_type(...)\". Use curly bracket syntax instead: \"$name = $elt_type{$datum_type}(...)\"") + end + + if ! @capture(elt, name_ = (elt_type_{datum_type_}(args__) | elt_type_(args__))) + error("Element syntax error: $elt") end # elt_type is one of {:Variable, :Parameter, :Index} if elt_type == :Index - expr = _generate_dims_expr(name, args, vartype) + expr = _generate_dims_expr(name, args, datum_type) push!(known_dims, name) addexpr(expr) @@ -266,8 +270,8 @@ macro defcomp(comp_name, ex) end end - vartype = (vartype === nothing ? Number : Main.eval(vartype)) - addexpr(_generate_var_or_param(elt_type, name, vartype, dimensions, dflt, desc, unit)) + datum_type = (datum_type === nothing ? Number : Main.eval(datum_type)) + addexpr(_generate_var_or_param(elt_type, name, datum_type, dimensions, dflt, desc, unit)) else error("Unrecognized element type: $elt_type") diff --git a/test/test_explorer_model.jl b/test/test_explorer_model.jl index 16f209879..fc06f1f20 100644 --- a/test/test_explorer_model.jl +++ b/test/test_explorer_model.jl @@ -13,7 +13,7 @@ import Mimi: c = Parameter(index=[regions]) d = Parameter() e = Parameter(index=[four]) - f::Array{Float64, 2} = Parameter() + f = Parameter{Array{Float64, 2}}() x = Variable(index=[time, regions]) diff --git a/test/test_main.jl b/test/test_main.jl index 74fcef462..b33a00493 100644 --- a/test/test_main.jl +++ b/test/test_main.jl @@ -12,7 +12,7 @@ import Mimi: index1 = Index() par1 = Parameter() - par2::Bool = Parameter(index=[time,index1], description="description par 1") + par2 = Parameter{Bool}(index=[time,index1], description="description par 1") par3 = Parameter(index=[time]) var1 = Variable() @@ -21,7 +21,7 @@ import Mimi: idx3 = Index() idx4 = Index() - var4::Bool = Variable(index=[idx3]) + var4 = Variable{Bool}(index=[idx3]) var5 = Variable(index=[index1, idx4]) end diff --git a/test/test_main_variabletimestep.jl b/test/test_main_variabletimestep.jl index 6e6d4c42b..77da9b47d 100644 --- a/test/test_main_variabletimestep.jl +++ b/test/test_main_variabletimestep.jl @@ -12,7 +12,7 @@ import Mimi: index1 = Index() par1 = Parameter() - par2::Bool = Parameter(index=[time,index1], description="description par 1") + par2 = Parameter{Bool}(index=[time,index1], description="description par 1") par3 = Parameter(index=[time]) var1 = Variable() @@ -21,7 +21,7 @@ import Mimi: idx3 = Index() idx4 = Index() - var4::Bool = Variable(index=[idx3]) + var4 = Variable{Bool}(index=[idx3]) var5 = Variable(index=[index1, idx4]) end diff --git a/test/test_model_structure.jl b/test/test_model_structure.jl index 98c14d35b..012840465 100644 --- a/test/test_model_structure.jl +++ b/test/test_model_structure.jl @@ -11,8 +11,8 @@ import Mimi: modeldef, modelinstance, compdef, getproperty, setproperty!, dimension, compdefs @defcomp A begin - varA::Int = Variable(index=[time]) - parA::Int = Parameter() + varA = Variable{Int}(index=[time]) + parA = Parameter{Int}() function run_timestep(p, v, d, t) v.varA[t] = p.parA @@ -20,7 +20,7 @@ import Mimi: end @defcomp B begin - varB::Int = Variable() + varB = Variable{Int}() function run_timestep(p, v, d, t) if t.t < 10 @@ -32,8 +32,8 @@ end end @defcomp C begin - varC::Int = Variable() - parC::Int = Parameter() + varC = Variable{Int}() + parC = Parameter{Int}() function run_timestep(p, v, d, t) v.varC = p.parC @@ -140,9 +140,9 @@ add_comp!(m, D) ########################################## @defcomp E begin - varE::Int = Variable() - parE1::Int = Parameter() - parE2::Int = Parameter() + varE = Variable{Int}() + parE1 = Parameter{Int}() + parE2 = Parameter{Int}() function init(p, v, d) v.varE = p.parE1 diff --git a/test/test_model_structure_variabletimestep.jl b/test/test_model_structure_variabletimestep.jl index bad489be4..a079f41a5 100644 --- a/test/test_model_structure_variabletimestep.jl +++ b/test/test_model_structure_variabletimestep.jl @@ -11,8 +11,8 @@ import Mimi: dim_names, compdef, getproperty, setproperty!, dimension, compdefs @defcomp A begin - varA::Int = Variable(index=[time]) - parA::Int = Parameter() + varA = Variable{Int}(index=[time]) + parA = Parameter{Int}() function run_timestep(p, v, d, t) v.varA[t] = p.parA @@ -20,7 +20,7 @@ import Mimi: end @defcomp B begin - varB::Int = Variable() + varB = Variable{Int}() function run_timestep(p, v, d, t) if t.t < 10 @@ -32,8 +32,8 @@ end end @defcomp C begin - varC::Int = Variable() - parC::Int = Parameter() + varC = Variable{Int}() + parC = Parameter{Int}() function run_timestep(p, v, d, t) v.varC = p.parC diff --git a/test/test_parametertypes.jl b/test/test_parametertypes.jl index 3f77a5469..a0dac4763 100644 --- a/test/test_parametertypes.jl +++ b/test/test_parametertypes.jl @@ -28,6 +28,18 @@ expr = :( ) @test_throws LoadError eval(expr) +# +# Test that the old type parameterization syntax errors +# +expr = :( + @defcomp BadComp3 begin + a::Int = Parameter() + function run_timestep(p, v, d, t) + end + end +) +@test_throws LoadError eval(expr) + @defcomp MyComp begin a = Parameter(index=[time, regions], default=ones(101,3)) @@ -35,16 +47,11 @@ expr = :( c = Parameter(index=[regions]) d = Parameter() e = Parameter(index=[four]) - f::Array{Float64, 2} = Parameter() - g::Int = Parameter(default=10.0) # value should be Int despite Float64 default + f = Parameter{Array{Float64, 2}}() + g = Parameter{Int}(default=10.0) # value should be Int despite Float64 default h = Parameter(default=10) # should be "numtype", despite Int default - - x = Variable(index=[time, regions]) function run_timestep(p, v, d, t) - for r in d.regions - v.x[t, r] = 0 - end end end @@ -59,15 +66,10 @@ set_dimension!(m, :regions, 3) set_dimension!(m, :four, 4) add_comp!(m, MyComp) -# set_param!(m, :MyComp, :a, ones(101,3)) -# set_param!(m, :MyComp, :b, 1:101) set_param!(m, :MyComp, :c, [4,5,6]) set_param!(m, :MyComp, :d, 0.5) # 32-bit float constant set_param!(m, :MyComp, :e, [1,2,3,4]) -set_param!(m, :MyComp, :f, [1.0 2.0; 3.0 4.0]) - -# THIS FAILS: Base.ReshapedArray{Int64,2,UnitRange{Int64},Tuple{}} != Array{Float64,2} -# set_param!(m, :MyComp, :f, reshape(1:16, 4, 4)) +set_param!(m, :MyComp, :f, reshape(1:16, 4, 4)) extpars = external_params(m) diff --git a/test/test_replace_comp.jl b/test/test_replace_comp.jl index 5010a4de5..df3a8a3f7 100644 --- a/test/test_replace_comp.jl +++ b/test/test_replace_comp.jl @@ -37,7 +37,7 @@ end end @defcomp bad4 begin - x::Symbol = Parameter(index = [time]) # different datatype + x = Parameter{Symbol}(index = [time]) # different datatype y = Variable() # different variable dimensions end From 5417ee8a469f362df583771168ba64a30252531b Mon Sep 17 00:00:00 2001 From: Cora Date: Tue, 24 Dec 2019 15:48:48 -0500 Subject: [PATCH 2/6] Make old syntax into a deprecation warning instead of an error --- src/core/defcomp.jl | 7 +++---- test/test_parametertypes.jl | 3 ++- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/core/defcomp.jl b/src/core/defcomp.jl index 96aef5968..3cd117ecd 100644 --- a/src/core/defcomp.jl +++ b/src/core/defcomp.jl @@ -196,10 +196,9 @@ macro defcomp(comp_name, ex) end if @capture(elt, name_::datum_type_ = elt_type_(args__)) - error("Deprecated type syntax: \"$name::$datum_type = $elt_type(...)\". Use curly bracket syntax instead: \"$name = $elt_type{$datum_type}(...)\"") - end - - if ! @capture(elt, name_ = (elt_type_{datum_type_}(args__) | elt_type_(args__))) + msg = "The following syntax has been deprecated in @defcomp: \"$name::$datum_type = $elt_type(...)\". Use curly bracket syntax instead: \"$name = $elt_type{$datum_type}(...)\"" + Base.depwarn("$msg\n$(reduce((x,y) -> "$x\n$y", stacktrace()))", :defcomp) + elseif ! @capture(elt, name_ = (elt_type_{datum_type_}(args__) | elt_type_(args__))) error("Element syntax error: $elt") end diff --git a/test/test_parametertypes.jl b/test/test_parametertypes.jl index a0dac4763..00a6ac7b2 100644 --- a/test/test_parametertypes.jl +++ b/test/test_parametertypes.jl @@ -38,7 +38,8 @@ expr = :( end end ) -@test_throws LoadError eval(expr) +eval(expr) # Just a deprecation warning for v0.10, then will change to error in v1.0 +# @test_throws LoadError eval(expr) @defcomp MyComp begin From e756fc6f145c1b620d7614fed58c4bba66340c49 Mon Sep 17 00:00:00 2001 From: Cora Date: Tue, 24 Dec 2019 16:10:12 -0500 Subject: [PATCH 3/6] fix doctest --- docs/src/tutorials/tutorial_1.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/tutorials/tutorial_1.md b/docs/src/tutorials/tutorial_1.md index 2756cf945..82262f150 100644 --- a/docs/src/tutorials/tutorial_1.md +++ b/docs/src/tutorials/tutorial_1.md @@ -28,7 +28,7 @@ The next step is to run FUND. If you wish to first get more acquainted with the Now open a julia REPL and type the following command to load the MimiFUND package into the current environment: -```jldoctest tutorial1; output = false +```jldoctest tutorial1; output = false, filter = r".*"s using MimiFUND # output From 7c14b07cbf92b6510dd29edbbd6499800f718ef9 Mon Sep 17 00:00:00 2001 From: Cora Date: Thu, 23 Jan 2020 12:04:30 -0500 Subject: [PATCH 4/6] fix syntax in docs --- docs/src/userguide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/userguide.md b/docs/src/userguide.md index 8dd3d9fd0..2386ebe06 100644 --- a/docs/src/userguide.md +++ b/docs/src/userguide.md @@ -261,7 +261,7 @@ As mentioned above, a parameter can have no index (a scalar), or one or multiple ```julia @defcomp MyComponent begin p1 = Parameter(index=[4]) # an array of length 4 - p2::Array{Float64, 2} = Parameter() # a two dimensional array of unspecified length + p2 = Parameter{Array{Float64, 2}}() # a two dimensional array of unspecified length end ``` From 04b5f8c7cce9f82701ad326cea1af268cf3a969a Mon Sep 17 00:00:00 2001 From: Cora Date: Thu, 23 Jan 2020 14:59:41 -0500 Subject: [PATCH 5/6] Add description of type parameterization to the userguide --- docs/src/userguide.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/src/userguide.md b/docs/src/userguide.md index 696c533de..aee439c58 100644 --- a/docs/src/userguide.md +++ b/docs/src/userguide.md @@ -56,6 +56,8 @@ The API for using the fourth argument, represented as `t` in this explanation, i To access the data in a parameter or to assign a value to a variable, you must use the appropriate index or indices (in this example, either the Timestep or region or both). +By default, all parameters and variables defined in the `@defcomp` will be allocated storage as scalars or Arrays of type `Float64.` For a description of other data type options, see **Advanced Topics: DataType specification of Parameters and Variables**. + ## Constructing a Model The first step in constructing a model is to set the values for each index of the model. Below is an example for setting the 'time' and 'regions' indexes. The time index expects either a numerical range or an array of numbers. If a single value is provided, say '100', then that index will be set from 1 to 100. Other indexes can have values of any type. @@ -248,6 +250,22 @@ TimestepIndex(1):2:TimestepIndex(10) # explicit step of type Int Both `TimestepIndex` and `TimestepArray` have methods to support addition and subtraction of integers. Note that the addition or subtraction is relative to the definition of the `time` dimension, so while `TimestepIndex(1) + 1 == TimestepIndex(2)`, `TimestepValue(2000) + 1` could be equivalent to `TimestepValue(2001)` **if** 2001 is the next year in the time dimension, or `TimestepValue(2005)` if the array has a step size of 5. Hence adding or subtracting is relative to the definition of the `time` dimension. +### DataType specification of Parameters and Variables + +By default, the Parameters and Variables defined by a user will be allocated storage arrays of type `Float64` when a model is constructed. This default "number_type" can be overriden when a model is created, with the following syntax: +``` +m = Model(Int64) # creates a model with default number type Int64 +``` +But you can also specify individual Parameters or Variables to have different data types with the following syntax in a `@defcomp` macro: +``` +@defcomp example begin + p1 = Parameter{Bool}() # ScalarModelParameter that is a Bool + p2 = Parameter{Bool}(index = [regions]) # ArrayModelParameter with one dimension whose eltype is Bool + p3 = Parameter{Matrix{Int64}}() # ScalarModelParameter that is a Matrix of Integers + p4 = Parameter{Int64}(index = [time, regions]) # ArrayModelParameter with two dimensions whose eltype is Int64 +end +``` +If there are "index"s listed in the Parameter definition, then it will be an ArrayModelParameter whose eltype is the type specified in the curly brackets. If there are no "index"s listed, then the type specified in the curly brackets is the actual type of the parameter value, and it will be represent by Mimi as a ScalarModelParameter. ### Parameter connections between different length components From 0ff0cb94a867bee55dac10ff85507c3fe91bf0f9 Mon Sep 17 00:00:00 2001 From: Lisa Rennels <31779240+lrennels@users.noreply.github.com> Date: Thu, 23 Jan 2020 16:23:41 -0800 Subject: [PATCH 6/6] Add code backpacks to documentation --- docs/src/userguide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/userguide.md b/docs/src/userguide.md index aee439c58..948b26d02 100644 --- a/docs/src/userguide.md +++ b/docs/src/userguide.md @@ -265,7 +265,7 @@ But you can also specify individual Parameters or Variables to have different da p4 = Parameter{Int64}(index = [time, regions]) # ArrayModelParameter with two dimensions whose eltype is Int64 end ``` -If there are "index"s listed in the Parameter definition, then it will be an ArrayModelParameter whose eltype is the type specified in the curly brackets. If there are no "index"s listed, then the type specified in the curly brackets is the actual type of the parameter value, and it will be represent by Mimi as a ScalarModelParameter. +If there are "index"s listed in the Parameter definition, then it will be an `ArrayModelParameter` whose `eltype` is the type specified in the curly brackets. If there are no "index"s listed, then the type specified in the curly brackets is the actual type of the parameter value, and it will be represent by Mimi as a `ScalarModelParameter`. ### Parameter connections between different length components