|
1 |
| -# How-to Guide 6: Port to Mimi v1.0.0 |
| 1 | +# How-to Guide 6: Port from (>=) Mimi v0.5.0 to Mimi v1.0.0 |
2 | 2 |
|
3 |
| -The release of Mimi v1.0.0 is a breaking release, necessitating the adaptation of existing models' syntax and structure in order for those models to run on this new version. This guide provides an overview of the steps required to get most models using the v0.9.5 API working with v1.0.0. It is **not** a comprehensive review of all changes and new functionalities, but a guide to the minimum steps required to port old models between versions. For complete information on the new version and its functionalities, see the full documentation. |
| 3 | +The release of Mimi v1.0.0 is a breaking release, necessitating the adaptation of existing models' syntax and structure in order for those models to run on this new version. We have worked hard to keep these changes clear and as minimal as possible. |
4 | 4 |
|
5 |
| -To port your model, we recommend you update to **Mimi v0.10.0**, which is identical to Mimi v1.0.0 **except** that it includes deprecation warnings for (most) breaking changes, instead of errors. This means that models written using Mimi v0.9.5 will, in most cases, run successfully under Mimi v0.10.0 although things that will cause errors in v1.0.0 will throw deprecation warnings. Thus a good workflow would be: |
| 5 | +This guide provides an overview of the steps required to get most models using the v0.9.5 API working with v1.0.0. It is **not** a comprehensive review of all changes and new functionalities, but a guide to the minimum steps required to port old models between versions. For complete information on the new version and its additional functionalities, see the full documentation. |
6 | 6 |
|
7 |
| -1) update to Mimi v0.10.0 |
8 |
| -2) read through this guide to get a sense for what has changed |
9 |
| -3) run your code and incrementally update it, using the deprecation warnings as guides and the instructions in this guide as explanations, until no warnings are thrown |
10 |
| -4) double check for any of the cases in this guide |
11 |
| -5) update to Mimi v1.0.0 and run your model! |
| 7 | +To port your model, we recommend you update to **Mimi v0.10.0**, which is identical to Mimi v1.0.0 **except** that it includes deprecation warnings for most breaking changes, instead of errors. This means that models written using Mimi v0.9.5 will, in most cases, run successfully under Mimi v0.10.0 and things that will cause errors in v1.0.0 will throw deprecation warnings. your changes. These can guide Thus a good workflow would be: |
12 | 8 |
|
13 |
| -This guide is organized into five main sections, each descripting an independent set of changes that can be undertaken in any order desired. |
| 9 | +1) Update your environment to use Mimi v0.10.0 with |
| 10 | +```julia |
| 11 | +pkg> add Mimi#v0.10.0 |
| 12 | +``` |
| 13 | +2) Read through this guide to get a sense for what has changed |
| 14 | +3) Run your code and incrementally update it, using the deprecation warnings as guides for what to change and the instructions in this guide as explanations, until no warnings are thrown and you have changed anything relevant to your code that is explained in this gude. |
| 15 | +5) Update to Mimi v1.0.0 with the following code, which will update Mimi to it's latest version, v1.0.0 |
| 16 | +```julia |
| 17 | +pkg> free Mimi |
| 18 | +``` |
| 19 | +6) Run your model! Things should run smoothly now. If not double check the guide, and feel free to reach out on the forum with any questions. Also, if you are curious about the reasons behind a change, just ask! |
14 | 20 |
|
15 |
| -1) Syntax within @defcomp |
16 |
| -2) The set_param! function |
17 |
| -3) Different-length components |
18 |
| -4) Simulation syntax |
19 |
| -5) Composite components (this should probably have it's own guide, but should get a brief mention here) |
| 21 | +This guide is organized into a few main sections, each descripting an independent set of changes that can be undertaken in any order desired. |
20 | 22 |
|
21 |
| -## Syntax within @defcomp |
| 23 | +- Syntax Within the @defcomp Macro |
| 24 | +- The set_param! Function |
| 25 | +- The replace_comp! Function |
| 26 | +- Different-length Components |
| 27 | +- Marginal Models |
| 28 | +- Simulation Syntax |
| 29 | +- Composite Components (optional) |
22 | 30 |
|
23 |
| -- Parameter data type specification |
24 |
| -- no more integer indexing (use TimetsepIndex(2) or TimestepValue(1990) instead, available comparison functions, d.time returns AbstractTimesteps) |
| 31 | +## Syntax Within the @defcomp Macro |
25 | 32 |
|
26 |
| -## The set_param! function |
| 33 | +#### Type-parameterization for Parameters |
27 | 34 |
|
28 |
| -- explain new function (now has five arguments) |
29 |
| -- explain the shortcuts |
30 |
| -- explain when it errors |
| 35 | +*The Mimi Change:* |
| 36 | +To be consistent with julia syntax, Mimi now uses bracketing syntax to type-parameterize `Parameter`s inside the `@defcomp` macro instead of double-colon syntax. h |
31 | 37 |
|
32 |
| -## Different-length components |
33 |
| -(either the functionality will be gone, or implemented differently) |
| 38 | +*The User Change:* |
| 39 | +Where you previously indicated that the parameter `a` should be an `Int` with |
| 40 | +```julia |
| 41 | +@defcomp my_comp begin |
| 42 | + a::Int = Parameter() |
| 43 | + function run_timestep(p, v, d, t) |
| 44 | + end |
| 45 | +end |
| 46 | +``` |
| 47 | +you should now use |
| 48 | +```julia |
| 49 | +@defcomp my_comp begin |
| 50 | + a = Parameter{Int}() |
| 51 | + function run_timestep(p, v, d, t) |
| 52 | + end |
| 53 | +end |
| 54 | +``` |
34 | 55 |
|
35 |
| -## Changes to simulation syntax |
| 56 | +#### Integer Indexing |
36 | 57 |
|
37 |
| -- Delete getindex (with square bracket shortcut) for getting values from a simulation instance; use getdataframe instead |
38 |
| -- rename some functions without camelCase |
| 58 | +*The Mimi Change:* |
| 59 | +For safety, Mimi no longer allows indexing into `Parameter`s or `Varaible`s with the `run_timestep` function of the `@defcomp` macro with integers. Instead, this functionality is supported with two new types: `TimestepIndex` and `TimestepValue`. Complete details on indexing options can be found in How-to Guide 4: Work with Timesteps, Parameters, and Variables, but below we will describe the minimum steps to get your models working. |
39 | 60 |
|
40 |
| -## Integer indexing |
41 |
| -- cannot index with integers |
42 |
| -- removed `is_time` and `is_timestep` |
| 61 | +*The User Change:* |
| 62 | +Where you previously used integers to index into a `Parameter` or `Variable`, you should now use the `TimestepIndex` type. For example, the code |
| 63 | +```julia |
| 64 | +function run_timestep(p, v, d, t) |
| 65 | + v.my_var[t] = p.my_param[10] |
| 66 | +end |
| 67 | +``` |
| 68 | +should now read |
| 69 | +```julia |
| 70 | +function run_timestep(p, v, d, t) |
| 71 | + v.my_var[t] = p.my_param[TimestepIndex(10)] |
| 72 | +end |
| 73 | +``` |
| 74 | +Also, if you previously used logic to determine which integer index pertained to a specific year, and then used that integer for indexing, you should now use the `TimestepValue` type. For example, if you previously knew that the index 2 referred to the year 2012, and added that value to a parameter with |
| 75 | +```julia |
| 76 | +function run_timestep(p, v, d, t) |
| 77 | + v.my_var[t] = p.my_param[t] + p.my_other_param[2] |
| 78 | +end |
| 79 | +``` |
| 80 | +you should now use |
| 81 | +```julia |
| 82 | +function run_timestep(p, v, d, t) |
| 83 | + v.my_var[t] = p.my_param[t] + p.my_other_param[TimestepValue(2012)] |
| 84 | +end |
| 85 | +``` |
43 | 86 |
|
44 |
| -## Composite components |
| 87 | +#### is_timestep and is_time |
45 | 88 |
|
46 |
| -This should also have it's own comprehensive guide, but should get a brief description here. |
| 89 | +*The Mimi Change:* |
| 90 | +For simplicity and consistency with the change above, Mimi no longer supports the `is_timestep` or `is_time` functions and has replaced this functionality with comparison operators combined with the afformentioned `TimestepValue` and `TimestepIndex` types. |
| 91 | + |
| 92 | +*The User Change:* |
| 93 | +Any instance of the `is_timestep` function should be replaced with simple comparison with a `TimestepIndex` object ie. replace the logic `if is_timestep(t, 10) ...` with `if t == TimestepIndex(10) ...`. |
| 94 | + |
| 95 | +Any instance of the `is_time` function should be repalced with simple comparison with a `TimestepValue` object ie. replace the logic `if is_time(t, 2010) ...` with `if t == TimestepValue(2010) ...`. |
| 96 | + |
| 97 | +## The set_param! Function |
| 98 | + |
| 99 | +*The Mimi Change:* |
| 100 | +The `set_param!` method for setting a parameter value in a component now has the following signature: |
| 101 | +``` |
| 102 | +set_param!(m::Model, comp_name::Symbol, param_name::Symbol, ext_param_name::Symbol, val::Any) |
| 103 | +``` |
| 104 | +This function creates an external parameter called `ext_param_name` with value `val` in the model `m`'s list of external parameters, and connects the parameter `param_name` in component `comp_name` to this newly created external parameter. If there is already a parameter called `ext_param_name` in the model's list of external parameters, it errors. |
| 105 | + |
| 106 | +There are two available shortcuts: |
| 107 | +``` |
| 108 | +# Shortcut 1 |
| 109 | +set_param!(m::Model, param_name::Symbol, val::Any) |
| 110 | +``` |
| 111 | +This method creates an external parameter in the model called `param_name`, sets its value to `val`, looks at all the components in the model `m`, finds all the unbound parameters named `param_name`, and creates connections from all the unbound parameters that are named `param_name` to the newly created external parameter. If there is already a parameter called `param_name` in the external parameter list, it errors. |
| 112 | + |
| 113 | +``` |
| 114 | +# Shortcut 2 |
| 115 | +set_param!(m::Model, comp_name::Symbol, param_name::Symbol, val::Any) |
| 116 | +``` |
| 117 | +This method creates a new external parameter called `param_name` in the model `m` (if that already exists, it errors), sets its value to `val`, and then connects the parameter `param_name` in component `comp_name` to this newly created external parameter. |
| 118 | + |
| 119 | +*The User Change:* |
| 120 | +Any old code that uses the `set_param!` method with only 4 arguments (shortcut #2 shown above) will still work for setting parameters **if they are found in only one component** ... but if you have multiple components that have parameters with the same name, using the old 4-argument version of `set_param!` multiple times will cause an error. Instead, you need to determine what behavior you want across multiple components with parameters of the same name: |
| 121 | +- If you want parameters with the same name that are found in multiple components to have the _same_ value, use the 3-argument method: `set_param!(m, :param_name, val)`. You only have to call this once and it will set the same value for all components with an unconnected parameter called `param_name`. |
| 122 | +- If you want different components that have parameters with the same name to have _different_ values, then you need to call the 5-argument version of `set_param!` individually for each parameter value, such as: |
| 123 | +``` |
| 124 | +set_param!(m, :comp1, :foo, :foo1, 25) # creates an external parameter called :foo1 with value 25, and connects just comp1/foo to that value |
| 125 | +set_param!(m, :comp2, :foo, :foo2, 30) # creates an external parameter called :foo2 with value 30, and connects just comp2/foo to that value |
| 126 | +``` |
| 127 | + |
| 128 | +Also, you can no longer call `set_param!` to change the value of a parameter that has already been set in the model. If the parameter has already been set, you must use the following to change it: |
| 129 | +``` |
| 130 | +update_param!(m, ext_param_name, new_val) |
| 131 | +``` |
| 132 | +This updates the value of the external parameter called `ext_param_name` in the model `m`'s list of external parameters. Any component that have parameters connected to this external parameter will now be connected to this new value. |
| 133 | + |
| 134 | +## The replace_comp! Function |
| 135 | + |
| 136 | +*The Mimi Change:* |
| 137 | +For simplicity, the `replace_comp!` function has been replaced with a method augmenting the julia Base `replace!` function. |
| 138 | + |
| 139 | +*The User Change:* |
| 140 | +Where you previously used |
| 141 | +```julia |
| 142 | +replace_comp!(m, new, old) |
| 143 | +``` |
| 144 | +to replace the `old` component with `new`, they should now use |
| 145 | +```julia |
| 146 | +replace!(m, old => new) |
| 147 | +``` |
| 148 | + |
| 149 | +## Different-length Components |
| 150 | + |
| 151 | +*The Mimi Change:* |
| 152 | +Through Mimi v0.9.4, the optional keyword arguments `first` and `last` could be used to specify times for components that do not run for the full length of the model, like this: `add_comp!(mymodel, ComponentC; first=2010, last=2100)`. This functionality is still disabled, as it was starting in v0.9.5, and all components must run for the full length of the model's time dimension. This functionality may be re-implemented in a later version of Mimi. |
| 153 | + |
| 154 | +*The User Change:* |
| 155 | +Refactor your model so that all components are the same length. You may use the `run_timestep` function within each component to dictate it's behavior in different timesteps, including doing no calculations for a portion of the full model runtime. |
| 156 | + |
| 157 | +## Marginal Models |
| 158 | + |
| 159 | +*The Mimi Change:* |
| 160 | +For clarity, the previously named `marginal` attribute of a Mimi `MarginalModel` has been renamed to `modified`. Hence a `MarginalModel` is now described as a Mimi `Model` whose results are obtained by subtracting results of one `base` Model from those of another `marginal` Model that has a difference of `delta` with the signature: |
| 161 | + |
| 162 | +*The User Change:* |
| 163 | +Any previous access to the `marginal` attribute of a `MarginalModel`, `mm` below, should be changed from |
| 164 | +```julia |
| 165 | +model = mm.marginal |
| 166 | +``` |
| 167 | +to |
| 168 | +```julia |
| 169 | +model = mm.modified |
| 170 | +``` |
| 171 | +## Simulation Syntax |
| 172 | + |
| 173 | +#### Results Access |
| 174 | + |
| 175 | +*The Mimi Change:* |
| 176 | +For clarity of return types, Mimi no longer supports use of square brackets (a shortcut for julia Base `getindex`) to access the results of a Monte Carlo analysis, which are stored in the `SimulationInstance`. Instead, access to resulst is supported with the `getdataframe` function, which will return the results in the same type and format as the square bracket method used to return. |
| 177 | + |
| 178 | +*The User Change:* |
| 179 | +Results previously obtained with |
| 180 | +```julia |
| 181 | +results = si[:grosseconomy, :K] |
| 182 | +``` |
| 183 | +should now be obtained with |
| 184 | +```julia |
| 185 | +results = getdataframe(si, :grosseconomy, :K) |
| 186 | +``` |
| 187 | +#### Simulation Definition Modification Functions |
| 188 | + |
| 189 | +*The Mimi Change:* |
| 190 | +For consistency with julia syntax rules, the small set of unexported functions available to modify an existing `SimulationDefinition` have been renamed, moving from a camel case format to an underscore-based format as follows. |
| 191 | + |
| 192 | +*The User Change:* |
| 193 | +Replace your functions as follows. |
| 194 | + |
| 195 | +- `deleteRV!` --> `delete_RV!` |
| 196 | +- `addRV!` --> `add_RV!` |
| 197 | +- `replaceRV!` --> `replace_RV!` |
| 198 | +- `deleteTransform!` --> `delete_transform!` |
| 199 | +- `addTransform!` --> `add_transform!` |
| 200 | +- `deleteSave!` --> `delete_save!` |
| 201 | +- `addSave!` --> `add_save!` |
| 202 | + |
| 203 | +## Composite Components (optional) |
| 204 | + |
| 205 | +*The Mimi Change:* |
| 206 | +The biggest functionality **addition** of Mimi v1.0.0 is the inclusion of composite components. Prior versions of Mimi supported only "flat" models, i.e., with one level of components. This new version supports mulitple layers of components, with some components being "final" or leaf components, and others being "composite" components which themselves contain other leaf or composite components. This approach allows for a cleaner organization of complex models, and allows the construction of building blocks that can be re-used in multiple models. |
| 207 | + |
| 208 | +*The User Change:* |
| 209 | +All previous models are considered "flat" models, i.e. they have only one level of components, and do **not** need to be converted into multiple layer models to run. Thus this addition does not mean users need to alter their models, but we encourage you to check out the other documentation on composite components to learn how you can enhance your current models and built better onces in the future! |
0 commit comments