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 diff --git a/docs/src/userguide.md b/docs/src/userguide.md index 790c6267a..948b26d02 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 @@ -270,7 +288,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 ``` diff --git a/src/core/defcomp.jl b/src/core/defcomp.jl index f78ae0da5..3cd117ecd 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,16 @@ 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__)) + 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 # 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 +269,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 795b7f29e..2e28a0b24 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..00a6ac7b2 100644 --- a/test/test_parametertypes.jl +++ b/test/test_parametertypes.jl @@ -28,6 +28,19 @@ 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 +) +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 a = Parameter(index=[time, regions], default=ones(101,3)) @@ -35,16 +48,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 +67,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