diff --git a/docs/src/internals/structure.md b/docs/src/internals/structure.md index 658626c9d..966bd1f68 100644 --- a/docs/src/internals/structure.md +++ b/docs/src/internals/structure.md @@ -78,53 +78,6 @@ In the new version, all component definitions are represented by one type, `Comp ![Object structure](figs/MimiModelArchitecture-v1.png) -## 3. New macro `@defmodel` - -The `@defmodel` macro provides simplified syntax for model creation, eliminating many redundant parameters. For example, you can write: - -``` -@defmodel mymodel begin - - index[time] = 2015:5:2110 - - component(grosseconomy) - component(emissions) - - # Set parameters for the grosseconomy component - grosseconomy.l = [(1. + 0.015)^t *6404 for t in 1:20] - grosseconomy.tfp = [(1 + 0.065)^t * 3.57 for t in 1:20] - grosseconomy.s = ones(20).* 0.22 - grosseconomy.depk = 0.1 - grosseconomy.k0 = 130.0 - grosseconomy.share = 0.3 - - # Set parameters for the emissions component - emissions.sigma = [(1. - 0.05)^t *0.58 for t in 1:20] - - # Connect pararameters (source_variable => destination_parameter) - grosseconomy.YGROSS => emissions.YGROSS -end -``` - -which produces these function calls: - -``` -quote - mymodel = Model() - set_dimension!(mymodel, :time, 2015:5:2110) - add_comp!(mymodel, Main.grosseconomy, :grosseconomy) - add_comp!(mymodel, Main.emissions, :emissions) - set_param!(mymodel, :grosseconomy, :l, [(1.0 + 0.015) ^ t * 6404 for t = 1:20]) - set_param!(mymodel, :grosseconomy, :tfp, [(1 + 0.065) ^ t * 3.57 for t = 1:20]) - set_param!(mymodel, :grosseconomy, :s, ones(20) * 0.22) - set_param!(mymodel, :grosseconomy, :depk, 0.1) - set_param!(mymodel, :grosseconomy, :k0, 130.0) - set_param!(mymodel, :grosseconomy, :share, 0.3) - set_param!(mymodel, :emissions, :sigma, [(1.0 - 0.05) ^ t * 0.58 for t = 1:20]) - connect_param!(mymodel, :emissions, :YGROSS, :grosseconomy, :YGROSS) -end -``` - -## 4. Pre-compilation and built-in components +## 3. Pre-compilation and built-in components To get `__precompile__()` to work required moving the creation of "helper" components to an `__init__()` method in Mimi.jl, which is run automatically after Mimi loads. It defines the two "built-in" components, from `adder.jl` and `connector.jl` in the `components` subdirectory. diff --git a/docs/src/ref/ref_API.md b/docs/src/ref/ref_API.md index c485abea9..0098a7246 100644 --- a/docs/src/ref/ref_API.md +++ b/docs/src/ref/ref_API.md @@ -19,13 +19,11 @@ get_var_value hasvalue is_first is_last -is_time -is_timestep modeldef parameter_names parameter_dimensions plot_comp_graph -replace_comp! +replace! set_dimension! set_leftover_params! set_param! diff --git a/docs/src/tutorials/tutorial_2.md b/docs/src/tutorials/tutorial_2.md index 455d91fe0..1d9de52d8 100644 --- a/docs/src/tutorials/tutorial_2.md +++ b/docs/src/tutorials/tutorial_2.md @@ -32,7 +32,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, filter = r".*"s +```jldoctest tutorial2; output = false, filter = r".*"s using MimiFUND # output @@ -40,7 +40,7 @@ using MimiFUND ``` Now we can access the public API of FUND, including the function `MimiFUND.get_model`. This function returns a copy of the default FUND model. Here we will first get the model, and then use the `run` function to run it. -```jldoctest tutorial1; output = false, filter = r".*"s +```jldoctest tutorial2; output = false, filter = r".*"s m = MimiFUND.get_model() run(m) @@ -58,7 +58,7 @@ get_model(; nsteps = default_nsteps, datadir = default_datadir, params = default Thus there are no required arguments, although the user can input `nsteps` to define the number of timesteps (years in this case) the model runs for, `datadir` to define the location of the input data, and `params`, a dictionary definining the parameters of the model. For example, if you wish to run only the first 200 timesteps, you may use: -```jldoctest tutorial1; output = false, filter = r".*"s +```jldoctest tutorial2; output = false, filter = r".*"s using MimiFUND m = MimiFUND.get_model(nsteps = 200) run(m) @@ -72,7 +72,7 @@ After the model has been run, you may access the results (the calculated variabl Start off by importing the Mimi package to your space with -```jldoctest tutorial1; output = false +```jldoctest tutorial2; output = false using Mimi # output @@ -89,7 +89,7 @@ m[:ComponentName, :VariableName][100] # returns just the 100th value Indexing into a model with the name of the component and variable will return an array with values from each timestep. You may index into this array to get one value (as in the second line, which returns just the 100th value). Note that if the requested variable is two-dimensional, then a 2-D array will be returned. For example, try taking a look at the `income` variable of the `socioeconomic` component of FUND using the code below: -```jldoctest tutorial1; output = false +```jldoctest tutorial2; output = false m[:socioeconomic, :income] m[:socioeconomic, :income][100] @@ -108,7 +108,7 @@ getdataframe(m, :Component1=>:Var1, :Component2=>:Var2) # request variables from Try doing this for the `income` variable of the `socioeconomic` component using: -```jldoctest tutorial1; output = false, filter = r".*"s +```jldoctest tutorial2; output = false, filter = r".*"s getdataframe(m, :socioeconomic=>:income) # request one variable from one component getdataframe(m, :socioeconomic=>:income)[1:16,:] # results for all regions in first year (1950) diff --git a/docs/src/tutorials/tutorial_3.md b/docs/src/tutorials/tutorial_3.md index fb3269f22..18d832de0 100644 --- a/docs/src/tutorials/tutorial_3.md +++ b/docs/src/tutorials/tutorial_3.md @@ -130,7 +130,7 @@ Note that here we use the `update_timesteps` flag and set it to `true`, because ## Component and Structural Modifications: The API -Most model modifications will include not only parametric updates, but also strutural changes and component modification, addition, replacement, and deletion along with the required re-wiring of parameters etc. The most useful functions of the common API, in these cases are likely **[`replace_comp!`](@ref), [`add_comp!`](@ref)** along with **`Mimi.delete!`** and the requisite functions for parameter setting and connecting. For detail on the public API functions look at the API reference. +Most model modifications will include not only parametric updates, but also structural changes and component modification, addition, replacement, and deletion along with the required re-wiring of parameters etc. The most useful functions of the common API, in these cases are likely **[`replace!`](@ref), [`add_comp!`](@ref)** along with **`delete!`** and the requisite functions for parameter setting and connecting. For detail on the public API functions look at the API reference. If you wish to modify the component structure we recommend you also look into the **built-in helper components `adder`, `ConnectorCompVector`, and `ConnectorCompMatrix`** in the `src/components` folder, as these can prove quite useful. diff --git a/docs/src/tutorials/tutorial_4.md b/docs/src/tutorials/tutorial_4.md index cf9fd1f9d..5174edbfb 100644 --- a/docs/src/tutorials/tutorial_4.md +++ b/docs/src/tutorials/tutorial_4.md @@ -28,7 +28,7 @@ Next, the `run_timestep` function must be defined along with the various equatio It is important to note that `t` below is an `AbstractTimestep`, and the specific API for using this argument are described in detail in the how to guide How-to Guide 4: Work with Timesteps, Parameters, and Variables -```jldoctest tutorial3; output = false +```jldoctest tutorial4; output = false using Mimi # start by importing the Mimi package to your space @defcomp grosseconomy begin @@ -61,7 +61,7 @@ end Next, the component for greenhouse gas emissions must be created. Although the steps are the same as for the `grosseconomy` component, there is one minor difference. While `YGROSS` was a variable in the `grosseconomy` component, it now enters the `emissions` component as a parameter. This will be true for any variable that becomes a parameter for another component in the model. -```jldoctest tutorial3; output = false +```jldoctest tutorial4; output = false @defcomp emissions begin E = Variable(index=[time]) # Total greenhouse gas emissions sigma = Parameter(index=[time]) # Emissions output ratio @@ -88,7 +88,7 @@ We can now use Mimi to construct a model that binds the `grosseconomy` and `emis * To access model results, use `model_name[:component, :variable_name]`. * To observe model results in a graphical form , [`explore`](@ref) as either `explore(model_name)` to open the UI window, or use `Mimi.plot(model_name, :component_name, :variable_name)` or `Mimi.plot(model_name, :component_name, :parameter_name)` to plot a specific parameter or variable. -```jldoctest tutorial3; output = false +```jldoctest tutorial4; output = false using Mimi @@ -128,7 +128,7 @@ Note that as an alternative to using many of the `set_param!` calls above, one m Now we can run the model and examine the results: -```jldoctest tutorial3; output = false, filter = r".*"s +```jldoctest tutorial4; output = false, filter = r".*"s # Run model m = construct_model() run(m) @@ -162,7 +162,7 @@ To create a three-regional model, we will again start by constructing the grosse As this model is also more complex and spread across several files, we will also take this as a chance to introduce the custom of using [Modules](https://docs.julialang.org/en/v1/manual/modules/index.html) to package Mimi models, as shown below. -```jldoctest tutorial3; output = false +```jldoctest tutorial4; output = false using Mimi @defcomp grosseconomy begin @@ -202,7 +202,7 @@ end Save this component as **`gross_economy.jl`** -```jldoctest tutorial3; output = false, filter = r".*"s +```jldoctest tutorial4; output = false, filter = r".*"s using Mimi #Make sure to call Mimi again @defcomp emissions begin @@ -238,7 +238,7 @@ Save this component as **`emissions.jl`** Let's create a file with all of our parameters that we can call into our model. This will help keep things organized as the number of components and regions increases. Each column refers to parameter values for a region, reflecting differences in initial parameter values and growth rates between the three regions. -```jldoctest tutorial3; output = false +```jldoctest tutorial4; output = false l = Array{Float64}(undef, 20, 3) for t in 1:20 l[t,1] = (1. + 0.015)^t *2000 @@ -288,7 +288,7 @@ include("emissions.jl") export construct_MyModel ``` -```jldoctest tutorial3; output = false +```jldoctest tutorial4; output = false function construct_MyModel() m = Model() @@ -332,7 +332,7 @@ using Mimi include("MyModel.jl") using .MyModel ``` -```jldoctest tutorial3; output = false, filter = r".*"s +```jldoctest tutorial4; output = false, filter = r".*"s m = construct_MyModel() run(m) diff --git a/docs/src/tutorials/tutorial_5.md b/docs/src/tutorials/tutorial_5.md index d77f9e720..314831bf6 100644 --- a/docs/src/tutorials/tutorial_5.md +++ b/docs/src/tutorials/tutorial_5.md @@ -28,7 +28,7 @@ You should have `Mimi` installed by now, and if you do not have the `Distributio As a reminder, the following code is the multi-region model that was constructed in the second half of tutorial 3. You can either load the `MyModel` module from tutorial 3, or run the following code which defines the same `construct_Mymodel` function that we will use. -```jldoctest tutorial4; output = false +```jldoctest tutorial5; output = false using Mimi # Define the grosseconomy component @@ -155,7 +155,7 @@ construct_MyModel (generic function with 1 method) Then, we obtain a copy of the model: -```jldoctest tutorial4; output = false +```jldoctest tutorial5; output = false m = construct_MyModel() # output @@ -172,7 +172,7 @@ Mimi.Model The `@defsim` macro is the first step in the process, and returns a `SimulationDef`. The following syntax allows users to define random variables (RVs) as distributions, and associate model parameters with the defined random variables. There are two ways of assigning random variables to model parameters in the `@defsim` macro. Notice that both of the following syntaxes are used in the following example. - + The first is the following: ```julia rv(rv1) = Normal(0, 0.8) # create a random variable called "rv1" with the specified distribution @@ -187,7 +187,7 @@ param1 = Normal(0, 0.8) The `@defsim` macro also selects the sampling method. Simple random sampling (also called Monte Carlo sampling) is the default. Other options include Latin Hypercube sampling and Sobol sampling. -```jldoctest tutorial4; output = false, filter = r".*"s +```jldoctest tutorial5; output = false, filter = r".*"s using Mimi using Distributions @@ -235,7 +235,7 @@ Next, use the `run` function to run the simulation for the specified simulation In its simplest use, the `run` function generates and iterates over a sample of trial data from the distributions of the random variables defined in the `SimulationDef`, perturbing the subset of Mimi's "external parameters" that have been assigned random variables, and then runs the given Mimi model(s) for each set of trial data. The function returns a `SimulationInstance`, which holds a copy of the original `SimulationDef` in addition to trials information (`trials`, `current_trial`, and `current_data`), the model list `models`, and results information in `results`. Optionally, trial values and/or model results are saved to CSV files. Note that if there is concern about in-memory storage space for the results, use the `results_in_memory` flag set to `false` to incrementally clear the results from memory. -```jldoctest tutorial4; output = false, filter = r".*"s +```jldoctest tutorial5; output = false, filter = r".*"s # Run 100 trials, and optionally save results to the indicated directories si = run(sd, m, 100; trials_output_filename = "/tmp/trialdata.csv", results_output_dir="/tmp/tutorial4") @@ -279,11 +279,11 @@ save("MyFigure.png", p) This example will discuss the more advanced SA capabilities of post-trial functions and payload objects. -Case: We want to do an SCC calculation with `MimiDICE2010`, which consists of running both a `base` and `marginal` model (the latter being a model including an additional emissions pulse, see the [`create_marginal_model`](@ref) function or create your own two models). We then take the difference between the consumption level in these two models and obtain the discounted net present value to get the SCC. +Case: We want to do an SCC calculation with `MimiDICE2010`, which consists of running both a `base` and `modified` model (the latter being a model including an additional emissions pulse, see the [`create_marginal_model`](@ref) function or create your own two models). We then take the difference between the consumption level in these two models and obtain the discounted net present value to get the SCC. The beginning steps for this case are identical to those above. We first define the typical variables for a simulation, including the number of trials `N` and the simulation definition `sd`. In this case we only define one random variable, `t2xco2`, but note there could be any number of random variables defined here. -```jldoctest tutorial4; output = false +```jldoctest tutorial5; output = false using Mimi using MimiDICE2010 using Distributions @@ -304,7 +304,7 @@ MCSData() #### Payload object Simulation definitions can hold a user-defined payload object which is not used or modified by Mimi. In this example, we will use the payload to hold an array of pre-computed discount factors that we will use in the SCC calculation, as well as a storage array for saving the SCC values. -```jldoctest tutorial4; output = false, filter = r".*"s +```jldoctest tutorial5; output = false, filter = r".*"s # Choose what year to calculate the SCC for scc_year = 2015 year_idx = findfirst(isequal(scc_year), MimiDICE2010.model_years) @@ -331,7 +331,7 @@ In the simple multi-region simulation example, the only values that were saved d Here we define a `post_trial_function` called `my_scc_calculation` which will calculate the SCC for each trial of the simulation. Notice that this function retrieves and uses the payload object that was previously stored in the `SimulationDef`. -```jldoctest tutorial4; output = false +```jldoctest tutorial5; output = false function my_scc_calculation(sim_inst::SimulationInstance, trialnum::Int, ntimesteps::Int, tup::Nothing) mm = sim_inst.models[1] discount_factors, scc_results = Mimi.payload(sim_inst) # Unpack the payload object @@ -351,7 +351,7 @@ my_scc_calculation (generic function with 1 method) Now that we have our post-trial function, we can proceed to obtain our two models and run the simulation. Note that we are using a Mimi MarginalModel `mm` from MimiDICE2010, which is a Mimi object that holds both the base model and the model with the additional pulse of emissions. -```jldoctest tutorial4; output = false, filter = r".*"s +```julia # Build the marginal model mm = MimiDICE2010.get_marginal_model(year = scc_year) # The additional emissions pulse will be added in the specified year @@ -361,8 +361,6 @@ si = run(sd, mm, N; trials_output_filename = "ecs_sample.csv", post_trial_func = # View the scc_results by retrieving them from the payload object scc_results = Mimi.payload(si)[2] # Recall that the SCC array was the second of two arrays we stored in the payload tuple -# output - ``` #### Simulation Modification Functions diff --git a/src/Mimi.jl b/src/Mimi.jl index 55645a0a7..eab87c535 100644 --- a/src/Mimi.jl +++ b/src/Mimi.jl @@ -31,7 +31,7 @@ export hasvalue, is_first, is_last, - is_time, + is_time, is_timestep, modeldef, name, @@ -60,7 +60,6 @@ include("core/build.jl") include("core/connections.jl") include("core/defs.jl") include("core/defcomp.jl") -include("core/defmodel.jl") include("core/defcomposite.jl") include("core/dimensions.jl") include("core/instances.jl") diff --git a/src/core/defcomp.jl b/src/core/defcomp.jl index 3cd117ecd..2c6edbad3 100644 --- a/src/core/defcomp.jl +++ b/src/core/defcomp.jl @@ -195,13 +195,13 @@ macro defcomp(comp_name, ex) continue end + # DEPRECATION - EVENTUALLY REMOVE 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) + error("$msg\n$(reduce((x,y) -> "$x\n$y", stacktrace()))") 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, datum_type) diff --git a/src/core/defmodel.jl b/src/core/defmodel.jl deleted file mode 100644 index 87eebcf54..000000000 --- a/src/core/defmodel.jl +++ /dev/null @@ -1,82 +0,0 @@ -# -# @defmodel and supporting functions -# -using MacroTools - -""" - defmodel(model_name::Symbol, ex::Expr) - -Define a Mimi model. The following types of expressions are supported: - -1. `component(name)` # add comp to model -2. `dst_component.name = ex::Expr` # provide a value for a parameter -3. `src_component.name => dst_component.name` # connect a variable to a parameter -4. `index[name] = iterable-of-values` # define values for an index -""" -macro defmodel(model_name, ex) - - @warn("@defmodel is deprecated.") - - # @capture(ex, elements__) - - # # @__MODULE__ is evaluated in calling module when macro is interpreted - # result = :( - # let calling_module = @__MODULE__, comp_mod_name = nothing, comp_mod_obj = nothing - # global $model_name = Model() - # end - # ) - - # # helper function used in loop below - # function addexpr(expr) - # let_block = result.args[end].args - # push!(let_block, expr) - # end - - # for elt in elements - # offset = 0 - - # if @capture(elt, component(comp_mod_name_.comp_name_) | component(comp_name_) | - # component(comp_mod_name_.comp_name_, alias_) | component(comp_name_, alias_)) - - # # set local copy of comp_mod_name to the stated or default component module - # expr = (comp_mod_name === nothing ? :(comp_mod_obj = calling_module) # nameof(calling_module)) - # # TBD: This may still not be right: - # : :(comp_mod_obj = getfield(calling_module, $(QuoteNode(comp_mod_name))))) - # addexpr(expr) - - # name = (alias === nothing ? comp_name : alias) - # expr = :(add_comp!($model_name, Mimi.ComponentId(comp_mod_obj, $(QuoteNode(comp_name))), $(QuoteNode(name)))) - - - # # TBD: extend comp.var syntax to allow module name, e.g., FUND.economy.ygross - # elseif (@capture(elt, src_comp_.src_name_[arg_] => dst_comp_.dst_name_) || - # @capture(elt, src_comp_.src_name_ => dst_comp_.dst_name_)) - # if (arg !== nothing && (! @capture(arg, t - offset_) || offset <= 0)) - # error("Subscripted connection source must have subscript [t - x] where x is an integer > 0") - # end - - # expr = :(Mimi.connect_param!($model_name, - # $(QuoteNode(dst_comp)), $(QuoteNode(dst_name)), - # $(QuoteNode(src_comp)), $(QuoteNode(src_name)), - # offset=$offset)) - - # elseif @capture(elt, index[idx_name_] = rhs_) - # expr = :(Mimi.set_dimension!($model_name, $(QuoteNode(idx_name)), $rhs)) - - # elseif @capture(elt, lhs_ = rhs_) && @capture(lhs, comp_.name_) - # (path, param_name) = parse_dotted_symbols(lhs) - # expr = :(Mimi.set_param!($model_name, $path, $(QuoteNode(param_name)), $rhs)) - - # else - # # Pass through anything else to allow the user to define intermediate vars, etc. - # @info "Passing through: $elt" - # expr = elt - # end - - # addexpr(expr) - # end - - # # addexpr(:($model_name)) # return this or nothing? - # addexpr(:(nothing)) - # return esc(result) -end diff --git a/src/core/model.jl b/src/core/model.jl index bf8356d1c..1b9359fb8 100644 --- a/src/core/model.jl +++ b/src/core/model.jl @@ -154,6 +154,7 @@ function add_comp!(m::Model, comp_def::AbstractComponentDef, comp_name::Symbol=c return add_comp!(m, comp_def.comp_id, comp_name; kwargs...) end +# DEPRECATION - EVENTUALLY REMOVE """ replace_comp!( m::Model, comp_id::ComponentId, comp_name::Symbol=comp_id.comp_name; @@ -173,10 +174,10 @@ function replace_comp!(m::Model, comp_id::ComponentId, comp_name::Symbol=comp_id msg = "Function `replace_comp!(m, comp_id, comp_name; kwargs...)` has been deprecated. Use `replace!(m, comp_name => Mimi.compdef(comp_id); kwargs...)` instead." st = _get_stacktrace_string() full_msg = string(msg, " \n", st) - Base.depwarn(full_msg, :replace_comp!) - return replace!(m, comp_name => compdef(comp_id); kwargs...) + error(full_msg) end +# DEPRECATION - EVENTUALLY REMOVE """ replace_comp!( m::Model, comp_def::ComponentDef, comp_name::Symbol=comp_id.comp_name; @@ -196,8 +197,7 @@ function replace_comp!(m::Model, comp_def::ComponentDef, comp_name::Symbol=comp_ msg = "Function `replace_comp!(m, comp_def, comp_name; kwargs...)` has been deprecated. Use `replace!(m, comp_name => comp_def; kwargs...)` instead." st = _get_stacktrace_string() full_msg = string(msg, " \n", st) - Base.depwarn(full_msg, :replace_comp!) - return replace!(m, comp_name => comp_def; kwargs...) + error(full_msg) end """ diff --git a/src/core/time.jl b/src/core/time.jl index dba24f471..6689a441c 100644 --- a/src/core/time.jl +++ b/src/core/time.jl @@ -20,15 +20,15 @@ function gettime(ts::VariableTimestep) return ts.current end +# DEPRECATION - EVENTUALLY REMOVE """ - is_time(ts::AbstractTimestep, t::Int) + is_time(ts::AbstractTimestep, t::Int) -Return true or false, true if the current time (year) for `ts` is `t` -""" -function is_time(ts::AbstractTimestep, t::Int) - Base.depwarn("`is_time(ts, t)` is deprecated. Use comparison operators with TimestepValue objects instead: `ts == TimestepValue(t)` \n$(stacktrace())", :is_time) - return gettime(ts) == t -end +Deprecated fucntion to return true or false, true if the current time (year) for `ts` is `t` + """ + function is_time(ts::AbstractTimestep, t::Int) + error("`is_time(ts, t)` is deprecated. Use comparison operators with TimestepValue objects instead: `ts == TimestepValue(t)` \n$(stacktrace())", :is_time) + end """ is_first(ts::AbstractTimestep) @@ -39,15 +39,15 @@ function is_first(ts::AbstractTimestep) return ts.t == 1 end +# DEPRECATION - EVENTUALLY REMOVE """ - is_timestep(ts::AbstractTimestep, t::Int) + is_timestep(ts::AbstractTimestep, t::Int) -Return true or false, true if `ts` timestep is step `t`. -""" -function is_timestep(ts::AbstractTimestep, t::Int) - Base.depwarn("`is_timestep(ts, t)` is deprecated. Use comparison operators with TimestepIndex objects instead: `ts == TimestepIndex(t)` \n$(stacktrace())", :is_timestep) - return ts.t == t -end +Deprecated function to return true or false, true if `ts` timestep is step `t`. + """ + function is_timestep(ts::AbstractTimestep, t::Int) + error("`is_timestep(ts, t)` is deprecated. Use comparison operators with TimestepIndex objects instead: `ts == TimestepIndex(t)` \n$(stacktrace())", :is_timestep) + end """ is_last(ts::FixedTimestep) diff --git a/src/core/time_arrays.jl b/src/core/time_arrays.jl index bf6843be7..9e611924e 100644 --- a/src/core/time_arrays.jl +++ b/src/core/time_arrays.jl @@ -27,6 +27,7 @@ function get_time_index_position(obj::AbstractCompositeComponentDef, comp_name:: end const AnyIndex = Union{Int, Vector{Int}, Tuple, Colon, OrdinalRange} +# DEPRECATION - EVENTUALLY REMOVE const AnyIndex_NonColon = Union{Int, Vector{Int}, Tuple, OrdinalRange} # Helper function for getindex; throws a MissingException if data is missing, otherwise returns data @@ -56,7 +57,8 @@ function _single_index_check(data, idxs) end end -# Helper to print stacktrace for the integer indexing deprecatino warning +# DEPRECATION - EVENTUALLY REMOVE +# Helper to print stacktrace for the integer indexing errors function _get_stacktrace_string() s = "" for line in stacktrace() @@ -69,20 +71,22 @@ function _get_stacktrace_string() return s end -# Helper functionfor getindex; throws an error if one indexes into a TimestepArray with an integer -function _throw_int_getindex_depwarning() +# DEPRECATION - EVENTUALLY REMOVE +# Helper function for getindex; throws an error if one indexes into a TimestepArray with an integer +function _throw_int_getindex_error() msg = "Indexing with getindex into a TimestepArray with Integer(s) is deprecated, please index with a TimestepIndex(index::Int) instead ie. instead of t[2] use t[TimestepIndex(2)]\n" st = _get_stacktrace_string() full_msg = string(msg, " \n", st) - Base.depwarn(full_msg, :getindex) + error(full_msg) end -# Helper function for setindex; throws an deprecation warning if one indexes into a TimestepArray with an integer -function _throw_int_setindex_depwarning() - msg = "Indexing with setindex into a TimestepArray with Integer(s) is deprecated, please index with a TimestepIndex(index::Int) instead ie. instead of t[2] use t[TimestepIndec(2)]" +# DEPRECATION - EVENTUALLY REMOVE +# Helper function for setindex; throws an error if one indexes into a TimestepArray with an integer +function _throw_int_setindex_error() + msg = "Indexing with setindex into a TimestepArray with Integer(s) is deprecated, please index with a TimestepIndex(index::Int) instead ie. instead of t[2] use t[TimestepIndex(2)]" st = _get_stacktrace_string() full_msg = string(msg, " \n", st) - Base.depwarn(full_msg, :setindex!) + error(full_msg) end # Helper macro used by connector @@ -258,28 +262,25 @@ end function Base.setindex!(v::TimestepVector, val, ts::TimestepIndex) setindex!(v.data, val, ts.index) end - + +# DEPRECATION - EVENTUALLY REMOVE # int indexing version supports old-style components and internal functions, not # part of the public API -function Base.getindex(v::TimestepVector{FixedTimestep{FIRST, STEP}, T}, i::AnyIndex_NonColon) where {T, FIRST, STEP} - _throw_int_getindex_depwarning() - return v.data[i] + function Base.getindex(v::TimestepVector{FixedTimestep{FIRST, STEP}, T}, i::AnyIndex_NonColon) where {T, FIRST, STEP} + _throw_int_getindex_error() end function Base.getindex(v::TimestepVector{VariableTimestep{TIMES}, T}, i::AnyIndex_NonColon) where {T, TIMES} - _throw_int_getindex_depwarning() - return v.data[i] + _throw_int_getindex_error() end function Base.setindex!(v::TimestepVector{FixedTimestep{Start, STEP}, T}, val, i::AnyIndex_NonColon) where {T, Start, STEP} - _throw_int_setindex_depwarning() - setindex!(v.data, val, i) + _throw_int_setindex_error() end function Base.setindex!(v::TimestepVector{VariableTimestep{TIMES}, T}, val, i::AnyIndex_NonColon) where {T, TIMES} - _throw_int_setindex_depwarning() - setindex!(v.data, val, i) + _throw_int_setindex_error() end function Base.length(v::TimestepVector) @@ -440,37 +441,32 @@ function Base.setindex!(mat::TimestepMatrix, val, ts::TimestepIndex, idx::AnyInd setindex!(mat.data, val, ts.index, idx) end +# DEPRECATION - EVENTUALLY REMOVE # int indexing version supports old-style components and internal functions, not # part of the public API function Base.getindex(mat::TimestepMatrix{FixedTimestep{FIRST, STEP}, T, ti}, idx1::AnyIndex_NonColon, idx2::AnyIndex_NonColon) where {T, FIRST, STEP, ti} - _throw_int_getindex_depwarning() - return mat.data[idx1, idx2] + _throw_int_getindex_error() end function Base.getindex(mat::TimestepMatrix{VariableTimestep{TIMES}, T, ti}, idx1::AnyIndex_NonColon, idx2::AnyIndex_NonColon) where {T, TIMES, ti} - _throw_int_getindex_depwarning() - return mat.data[idx1, idx2] + _throw_int_getindex_error() end function Base.setindex!(mat::TimestepMatrix{FixedTimestep{FIRST, STEP}, T, ti}, val, idx1::Int, idx2::Int) where {T, FIRST, STEP, ti} - _throw_int_setindex_depwarning() - setindex!(mat.data, val, idx1, idx2) + _throw_int_setindex_error() end function Base.setindex!(mat::TimestepMatrix{FixedTimestep{FIRST, STEP}, T, ti}, val, idx1::AnyIndex_NonColon, idx2::AnyIndex_NonColon) where {T, FIRST, STEP, ti} - _throw_int_setindex_depwarning() - mat.data[idx1, idx2] .= val + _throw_int_setindex_error() end function Base.setindex!(mat::TimestepMatrix{VariableTimestep{TIMES}, T, ti}, val, idx1::Int, idx2::Int) where {T, TIMES, ti} - _throw_int_setindex_depwarning() - setindex!(mat.data, val, idx1, idx2) + _throw_int_setindex_error() end function Base.setindex!(mat::TimestepMatrix{VariableTimestep{TIMES}, T, ti}, val, idx1::AnyIndex_NonColon, idx2::AnyIndex_NonColon) where {T, TIMES, ti} - _throw_int_setindex_depwarning() - mat.data[idx1, idx2] .= val + _throw_int_setindex_error() end # @@ -605,27 +601,26 @@ function Base.setindex!(arr::TimestepArray{VariableTimestep{TIMES}, T, N, ti}, v setindex!(arr.data, val, idxs1..., t, idxs2...) end -# Colon support - this allows the time dimension to be indexed with a colon, and -# the deprecation warning will become an error when integer indexing is fully deprecated - -function Base.getindex(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T, N, ti}, idxs::AnyIndex...) where {FIRST, STEP, T, N, ti} - isa(idxs[ti], AnyIndex_NonColon) ? _throw_int_getindex_depwarning() : nothing - return arr.data[idxs...] +# DEPRECATION - EVENTUALLY REMOVE +# Colon support - this allows the time dimension to be indexed with a colon + function Base.getindex(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T, N, ti}, idxs::AnyIndex...) where {FIRST, STEP, T, N, ti} + isa(idxs[ti], AnyIndex_NonColon) ? _throw_int_getindex_error() : nothing + return arr.data[idxs...] end function Base.getindex(arr::TimestepArray{VariableTimestep{TIMES}, T, N, ti}, idxs::AnyIndex...) where {TIMES, T, N, ti} - isa(idxs[ti], AnyIndex_NonColon) ? _throw_int_getindex_depwarning() : nothing - return arr.data[idxs...] + isa(idxs[ti], AnyIndex_NonColon) ? _throw_int_getindex_error() : nothing + return arr.data[idxs...] end function Base.setindex!(arr::TimestepArray{FixedTimestep{FIRST, STEP}, T, N, ti}, val, idxs::AnyIndex...) where {FIRST, STEP, T, N, ti} - isa(idxs[ti], AnyIndex_NonColon) ? _throw_int_setindex_depwarning() : nothing - setindex!(arr.data, val, idxs...) + isa(idxs[ti], AnyIndex_NonColon) ? _throw_int_setindex_error() : nothing + setindex!(arr.data, val, idxs...) end function Base.setindex!(arr::TimestepArray{VariableTimestep{TIMES}, T, N, ti}, val, idxs::AnyIndex...) where {TIMES, T, N, ti} - isa(idxs[ti], AnyIndex_NonColon) ? _throw_int_setindex_depwarning() : nothing - setindex!(arr.data, val, idxs...) + isa(idxs[ti], AnyIndex_NonColon) ? _throw_int_setindex_error() : nothing + setindex!(arr.data, val, idxs...) end # Indexing with arrays of TimestepIndexes or TimestepValues diff --git a/src/core/types/model.jl b/src/core/types/model.jl index a31f6ee19..953513308 100644 --- a/src/core/types/model.jl +++ b/src/core/types/model.jl @@ -46,10 +46,10 @@ function Base.getindex(mm::MarginalModel, comp_name::Symbol, name::Symbol) return (mm.modified[comp_name, name] .- mm.base[comp_name, name]) ./ mm.delta end +# DEPRECATION - EVENTUALLY REMOVE (and go back to default getproperty behavior) function Base.getproperty(base::MarginalModel, s::Symbol) if (s == :marginal) - @warn("Use of 'MarginalModel.marginal' will be deprecated, in favor of 'MarginalModel.modified'"); - return getfield(base, :modified); + error("Use of `MarginalModel.marginal` is deprecated in favor of `MarginalModel.modified`.") end return getfield(base, s); end diff --git a/test/test_marginal_models.jl b/test/test_marginal_models.jl index 08dacb942..0d9d423e7 100644 --- a/test/test_marginal_models.jl +++ b/test/test_marginal_models.jl @@ -32,9 +32,10 @@ for i in collect(1:10) end mm2 = create_marginal_model(model1, 0.5) +@test_throws ErrorException mm2_modified = mm2.marginal # test that trying to access by the old field name, "marginal", now errors +mm2_modified = mm2.modified -mm2_marginal = @test_logs (:warn, "Use of 'MarginalModel.marginal' will be deprecated, in favor of 'MarginalModel.modified'") mm2.marginal -update_param!(mm2_marginal, :parA, x2) +update_param!(mm2_modified, :parA, x2) run(mm2) diff --git a/test/test_parametertypes.jl b/test/test_parametertypes.jl index c66beb46e..46284c8ce 100644 --- a/test/test_parametertypes.jl +++ b/test/test_parametertypes.jl @@ -38,8 +38,7 @@ expr = :( end end ) -eval(expr) # Just a deprecation warning for v0.10, then will change to error in v1.0 -# @test_throws LoadError eval(expr) +@test_throws LoadError eval(expr) @defcomp MyComp begin diff --git a/test/test_replace_comp.jl b/test/test_replace_comp.jl index 6b3e49658..7e967ea8e 100644 --- a/test/test_replace_comp.jl +++ b/test/test_replace_comp.jl @@ -47,9 +47,8 @@ m = Model() set_dimension!(m, :time, 2000:2005) add_comp!(m, X) # Original component X set_param!(m, :X, :x, zeros(6)) -# The following `replace_comp!` function name will be deprecated in v1.0.0. -# This one remains to test the preserved version with warning for v0.10.0. -replace_comp!(m, X_repl, :X) # Replace X with X_repl +@test_throws ErrorException replace_comp!(m, X_repl, :X) # test that the old function name now errors +replace!(m, :X => X_repl) # Replace X with X_repl run(m) @test length(components(m)) == 1 # Only one component exists in the model @test m[:X, :y] == 2 * ones(6) # Successfully ran the run_timestep function from X_repl @@ -63,10 +62,8 @@ add_comp!(m, X, :first) # Add two components add_comp!(m, X, :second) connect_param!(m, :second => :x, :first => :y) # Make an internal connection with a parameter with a time dimension @test_throws ErrorException replace!(m, :second => bad1) # Cannot make reconnections because :x in bad1 has different dimensions -# The following `replace_comp!` function name will be deprecated in v1.0.0. -# This one remains to test the preserved version with warning for v0.10.0. -# Every other use in this test file has been switched to `replace!` instead. -replace_comp!(m, bad1.comp_id, :second, reconnect = false) # Can replace without reconnecting +@test_throws ErrorException replace_comp!(m, bad1.comp_id, :second, reconnect = false) # Test that the old function name now errors +replace!(m, :second => bad1, reconnect = false) # Can replace without reconnecting second = compdef(m, :second) @test second.comp_id.comp_name == :bad1 # Successfully replaced diff --git a/test/test_timesteparrays.jl b/test/test_timesteparrays.jl index 888e4f3e6..c620f9da7 100644 --- a/test/test_timesteparrays.jl +++ b/test/test_timesteparrays.jl @@ -97,11 +97,9 @@ x[t3] = temp_dim_val[1] @test x[t3] == temp_dim_val[1] reset_time_val(x, time_dim_val) -# Deprecated int indexing should still run -@test x[3] == time_dim_val[3] -x[TimestepIndex(3)] = temp_dim_val[3] -@test x[TimestepIndex(3)] == temp_dim_val[3] -reset_time_val(x, time_dim_val) +# Deprecated int indexing now errors +@test_throws ErrorException x[3] == time_dim_val[3] +@test_throws ErrorException x[3] = temp_dim_val[3] #------------------------------------------------------------------------------ # 2. Test TimestepVector - Variable Timestep diff --git a/test/test_tmp.jl b/test/test_tmp.jl deleted file mode 100644 index 7bc25a9d6..000000000 --- a/test/test_tmp.jl +++ /dev/null @@ -1,44 +0,0 @@ -module Tmp - -using Test -using Mimi -import Mimi: - compdefs, compdef, external_param_conns - -@defcomp X begin - x = Parameter(index = [time]) - y = Variable(index = [time]) - function run_timestep(p, v, d, t) - v.y[t] = 1 - end -end - -@defcomp X_repl begin - x = Parameter(index = [time]) - y = Variable(index = [time]) - function run_timestep(p, v, d, t) - v.y[t] = 2 - end -end - -m = Model() -set_dimension!(m, :time, 2000:2005) -add_comp!(m, X, exports=[:x => :z]) # Original component X -add_comp!(m, X_repl) -set_param!(m, :X, :x, zeros(6)) - -if false - run(m) - @test m[:X, :y] == ones(6) - - replace_comp!(m, X_repl, :X) - run(m) - - @test length(components(m)) == 1 # Only one component exists in the model - @test m[:X, :y] == 2 * ones(6) # Successfully ran the run_timestep function from X_repl -end - -end # module - -using Mimi -m = Tmp.m