Skip to content

Commit 24e61f5

Browse files
authored
Merge pull request #780 from mimiframework/broadcast
Broadcast
2 parents 1b8672a + 205cd85 commit 24e61f5

File tree

3 files changed

+68
-17
lines changed

3 files changed

+68
-17
lines changed

docs/src/tutorials/tutorial_3.md

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,10 @@ You have now successfully downloaded MimiDICE2010 to your local machine.
5454

5555
The next step is to run DICE using the provided API for the package:
5656

57-
```jldoctest tutorial2; output = false, filter = r".*"s
57+
```julia
5858
using MimiDICE2010
5959
m = MimiDICE2010.get_model()
6060
run(m)
61-
62-
# output
63-
6461
```
6562

6663
These steps should be relatively consistent across models, where a repository for `ModelX` should contain a primary file `ModelX.jl` which exports, at minimum, a function named something like `get_model` or `construct_model` which returns a version of the model, and can allow for model customization within the call.
@@ -77,35 +74,26 @@ Thus there are no required arguments, although the user can input `params`, a di
7774

7875
In the case that you wish to alter an exogenous parameter, you may use the [`update_param!`](@ref) function. Per usual, you will start by importing the Mimi package to your space with
7976

80-
```jldoctest tutorial2; output = false
77+
```julia
8178
using Mimi
82-
83-
# output
84-
8579
```
8680

8781
In DICE the parameter `fco22x` is the forcings of equilibrium CO2 doubling in watts per square meter, and exists in the components `climatedynamics` and `radiativeforcing`. We can change this value from its default value of `3.200` to `3.000` in both components, using the following code:
8882

89-
```jldoctest tutorial2; output = false, filter = r".*"s
83+
```julia
9084
update_param!(m, :fco22x, 3.000)
9185
run(m)
92-
93-
# output
94-
9586
```
9687

9788
A more complex example may be a situation where you want to update several parameters, including some with a `:time` dimension, in conjunction with altering the time index of the model itself. DICE uses a default time horizon of 2005 to 2595 with 10 year increment timesteps. If you wish to change this, say, to 2000 to 2500 by 10 year increment timesteps and use parameters that match this time, you could use the following code:
9889

9990
First you upate the `time` dimension of the model as follows:
10091

101-
```jldoctest tutorial2; output = false, filter = r".*"s
92+
```julia
10293
const ts = 10
10394
const years = collect(2000:ts:2500)
10495
nyears = length(years)
10596
set_dimension!(m, :time, years)
106-
107-
# output
108-
10997
```
11098

11199
Now that you have changed the time dimension, you have a mismatch between the time labels attached to your parameters and the time labels used by the model. Thus, **you must update at least all parameters with a `:time`** dimension and use the explicit `update_timesteps=true` flag to get the time labels on the parameters to match those in the model. This is required even in cases where you do not want to change the parameter values themselves (see the forum question [here](https://forum.mimiframework.org/t/update-time-index/134/5)) for an in-depth explanation of this case. You may of course also update parameters without a `:time` dimension as desired.

src/mcs/montecarlo.jl

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,8 +326,11 @@ function _perturb_param!(param::ScalarModelParameter{T}, md::ModelDef, trans::Tr
326326
end
327327
end
328328

329+
# rvalue is an Array so we expect the dims to match and don't need to worry about
330+
# broadcasting
329331
function _perturb_param!(param::ArrayModelParameter{T}, md::ModelDef,
330-
trans::TransformSpec, rvalue::Union{Number, Array{<: Number, N}}) where {T, N}
332+
trans::TransformSpec, rvalue::Array{<: Number, N}) where {T, N}
333+
331334
op = trans.op
332335
pvalue = value(param)
333336
indices = _param_indices(param, md, trans)
@@ -340,6 +343,49 @@ function _perturb_param!(param::ArrayModelParameter{T}, md::ModelDef,
340343

341344
else
342345
pvalue[indices...] += rvalue
346+
347+
end
348+
end
349+
350+
# rvalue is a Number so we might need to deal with broadcasting
351+
function _perturb_param!(param::ArrayModelParameter{T}, md::ModelDef,
352+
trans::TransformSpec, rvalue::Number) where {T, N}
353+
op = trans.op
354+
pvalue = value(param)
355+
indices = _param_indices(param, md, trans)
356+
357+
if op == :(=)
358+
359+
# first we check for a time index
360+
ti = get_time_index_position(param)
361+
362+
# If there is no time index we have all methods needed to broadcast normally
363+
if isnothing(ti)
364+
broadcast_flag = sum(map(x -> length(x) > 1, indices)) > 0
365+
broadcast_flag ? pvalue[indices...] .= rvalue : pvalue[indices...] = rvalue
366+
367+
else
368+
indices1, ts, indices2 = split_indices(indices, ti)
369+
non_ts_indices = [indices1..., indices2...]
370+
broadcast_flag = isempty(non_ts_indices) ? false : sum(map(x -> length(x) > 1, non_ts_indices)) > 0
371+
372+
# Loop over the Array of TimestepIndex
373+
if isa(ts, Array)
374+
for el in ts
375+
broadcast_flag ? pvalue[indices1..., el, indices2...] .= rvalue : pvalue[indices1..., el, indices2...] = rvalue
376+
end
377+
378+
# The time is just a single TimestepIndex and we can proceed with broadcast
379+
else
380+
broadcast_flag ? pvalue[indices...] .= rvalue : pvalue[indices...] = rvalue
381+
end
382+
end
383+
384+
elseif op == :(*=)
385+
pvalue[indices...] *= rvalue
386+
387+
else
388+
pvalue[indices...] += rvalue
343389
end
344390
end
345391

test/mcs/test_defmcs.jl

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,3 +269,20 @@ trial2 = copy(si2.sim_def.rvdict[:name1].dist.values)
269269

270270
@test length(trial1) == length(trial2)
271271
@test trial1 != trial2
272+
273+
# test broadcasting examples
274+
sd3 = @defsim begin
275+
276+
# 1 dimension
277+
depk[:] = Uniform(0.1, 0.2)
278+
k0[(Region2, Region3)] = Uniform(20, 30)
279+
280+
# 2 dimensions
281+
tfp[:, Region1] = Uniform(0.75, 1.25)
282+
sigma[2020:5:2050, (Region2, Region3)] = Uniform(0.8, 1.2)
283+
s[2020, Region1] = Uniform(0.2, 0.3)
284+
285+
end
286+
287+
N = 5
288+
si3 = run(sd3, m, N)

0 commit comments

Comments
 (0)