@jrising @hbenveniste @BerBastien @FrankErrickson @AlexandrePavlov This is another PSA for users of the Simulation API. We have been working to simplify the API a bit from a user-perspective, so there are some small changes coming in the next tagged release of Mimi that you will want to be aware of. I will update all models we are responsible for as well. In most uses cases, all you will have to do is (1) remove calls to set_models! and generate_trials! (2) rewrite your run_sim! functions as run functions and add a few arguments to that call.
The basic API now looks like this:
#samplesize
N = 1000
# get simulation definition
sim_definition = @defsim ...
end
# get whatever model you are using
m = get_model()
# run simulation and save results to the results_output_dir
sim_instance = run(sim_definition, m, 1000; results_output_dir = "./out")
# view in-memory results for a variable
results = sim_instance[:comp_name, :variable_name]
All changes are documented in docs and tutorials. Lots of details can be found in the notes here: https://github.com/mimiframework/Mimi.jl/pull/522.
Main Changes:
-
Types: Mirroring work with models, there are now two types
SimulationDefinitionandSimulationInstance. The former is what you get from@defsim, the latter is returned byrunand holds a (mutated) copy of theSimulationDefinitionit’srunfunction had as an argument. -
Run Function: The functions
set_models!andgenerate_trials!have been absorbed into therun_simfunction, which has been renamed to simplyrunwith the full signature:
function Base.run(sim_def::SimulationDef{T}, models::Union{Vector{Model}, Model}, samplesize::Int;
ntimesteps::Int=typemax(Int),
trials_output_filename::Union{Nothing, AbstractString}=nothing,
results_output_dir::Union{Nothing, AbstractString}=nothing,
pre_trial_func::Union{Nothing, Function}=nothing,
post_trial_func::Union{Nothing, Function}=nothing,
scenario_func::Union{Nothing, Function}=nothing,
scenario_placement::ScenarioLoopPlacement=OUTER,
scenario_args=nothing,
results_in_memory::Bool=true) where T <: AbstractSimulationData
Thus, in its simplest form, you may define a SimulationDefinition with @defsim, and then call run(sim_def, model, 100) to run sim_def on model with sample size of 100. You will notice that the output filename for the trial data is thus moved to run as trials_output_filename, and if set your trial data will be saved to disk at that location.
run(sim_def ...) will return a SimulationInstance which contains a mutated copy of the SimulationDefinition argument, a vector of models, and a vector of results. These can be accessed with regular dot syntax:
sim_instance = `run(sim_def, model, 1000)
models = sim_instance.models
results = sim_instance.results
The results are organized as a vector, one item per model, and each item is a dictionary with keys for each saved variable and values are DataFrames. It is easiest to access results with getindex, for example you may get the DataFrame for component comp_name and variable var_name with:
results = sim_def[:comp, :var_name] # returns a DataFrame
If there are scenarios, results will have a field with :scen holding the scenario name.
-
Results Saving: If you specify a
results_output_dir, your results will be saved both in that directory in a folder structure as well as in memory in theresultsarray. This folder structure is organized asscenario folder => model folder => comp_var.csv files. Only if you set theresults_in_memoryflag tofalsewill memory be cleared after each trial. We have also fixed a bug that did not properly save results (to disk or memory) when multiple scenarios were involved. -
Callback Functions: Extra functions like
post_trial_funcandpre_trial_funcnow have aSimulationInstancein their signature instead of aSimulation.
Please do not hesitate to ask any questions here. This will be the next tagged version of Mimi but I wanted to post this now in case you have questions and don’t get taken by surprise!