RESPOND 2.5.1
Researching Effective Strategies to Prevent Opioid Death
Loading...
Searching...
No Matches
simulation.hpp
1
2// File: simulation.hpp //
3// Project: respond //
4// Created Date: 2026-02-05 //
5// Author: Matthew Carroll //
6// ----- //
7// Last Modified: 2026-07-22 //
8// Modified By: Matthew Carroll //
9// ----- //
10// Copyright (c) 2026 Syndemics Lab at Boston Medical Center //
12#ifndef RESPOND_SIMULATION_HPP_
13#define RESPOND_SIMULATION_HPP_
14
15#include <respond/constants.hpp>
16#include <respond/history.hpp>
17#include <respond/logging.hpp>
18#include <respond/model.hpp>
19
20#include <map>
21#include <memory>
22#include <string>
23#include <utility>
24#include <vector>
25
26#include <Eigen/Dense>
27
28namespace respond {
33public:
36 public:
37 ModelSlotProxy(Simulation &owner, size_t idx)
38 : _owner(&owner), _idx(idx) {}
39
41 Model *operator->() { return &_owner->GetModelRefOrThrow(_idx); }
42
44 Model &operator*() { return _owner->GetModelRefOrThrow(_idx); }
45
47 operator Model &() { return _owner->GetModelRefOrThrow(_idx); }
48
51 return *this = static_cast<const Model &>(
52 other._owner->GetModelRefOrThrow(other._idx));
53 }
54
57 _owner->GetModelRefOrThrow(_idx);
58 _owner->_models[_idx] = model.clone();
59 return *this;
60 }
61
64 ModelSlotProxy &operator=(const std::unique_ptr<Model> &model) {
65 if (!model) {
66 LogError(_owner->_log_name,
67 "Cannot assign null model pointer to simulation "
68 "slot.");
69 throw std::invalid_argument(
70 "Error attempting to assign null model pointer.");
71 }
72 _owner->GetModelRefOrThrow(_idx);
73 _owner->_models[_idx] = model->clone();
74 return *this;
75 }
76
77 private:
78 Simulation *_owner;
79 size_t _idx;
80 };
81
83 //
84 // Rule of Five: Copy and Move Semantics
85 //
87
90 Simulation() : Simulation(RESPOND_DEFAULT_LOG) {}
91
94 Simulation(const std::string &log_name)
95 : Simulation(log_name, RESPOND_DEFAULT_LOG_FILE) {}
96
100 Simulation(const std::string &log_name, const std::string &log_filepath)
101 : _log_name(log_name) {
102 CreateFileLogger(log_name, log_filepath);
103 }
104
106 ~Simulation() = default;
107
112 Simulation(const Simulation &other) {
113 _log_name = other._log_name;
114 for (const auto &m : other._models) {
115 _models.push_back(m->clone());
116 }
117 _duration = other._duration;
118 _parameter_change_times = other._parameter_change_times;
119 _stratify_entering_cohort = other._stratify_entering_cohort;
120 _build_summary_stats = other._build_summary_stats;
121 _save_state_history = other._save_state_history;
122 _timesteps_to_report = other._timesteps_to_report;
123 _pivot_long = other._pivot_long;
124 }
125
130 if (this != &other) {
131 _log_name = other._log_name;
132 _models.clear();
133 for (const auto &m : other._models) {
134 _models.push_back(m->clone());
135 }
136 _duration = other._duration;
137 _parameter_change_times = other._parameter_change_times;
138 _stratify_entering_cohort = other._stratify_entering_cohort;
139 _build_summary_stats = other._build_summary_stats;
140 _save_state_history = other._save_state_history;
141 _timesteps_to_report = other._timesteps_to_report;
142 _pivot_long = other._pivot_long;
143 }
144 return *this;
145 }
146
149 Simulation(Simulation &&other) noexcept
150 : _log_name(std::move(other._log_name)), _duration(other._duration),
151 _parameter_change_times(std::move(other._parameter_change_times)),
152 _stratify_entering_cohort(other._stratify_entering_cohort),
153 _build_summary_stats(other._build_summary_stats),
154 _save_state_history(other._save_state_history),
155 _timesteps_to_report(std::move(other._timesteps_to_report)),
156 _pivot_long(other._pivot_long) {
157 for (const auto &m : other._models) {
158 _models.push_back(m->clone());
159 }
160 other._models.clear();
161 }
162
166 Simulation &operator=(Simulation &&other) noexcept {
167 if (this != &other) {
168 _log_name = std::move(other._log_name);
169 _duration = other._duration;
170 _parameter_change_times = std::move(other._parameter_change_times);
171 _stratify_entering_cohort = other._stratify_entering_cohort;
172 _build_summary_stats = other._build_summary_stats;
173 _save_state_history = other._save_state_history;
174 _timesteps_to_report = std::move(other._timesteps_to_report);
175 _pivot_long = other._pivot_long;
176
177 for (const auto &m : other._models) {
178 _models.push_back(m->clone());
179 }
180 other._models.clear();
181 }
182 return *this;
183 }
184
186 //
187 // Simulation Behavior Methods: Model Management
188 //
190
196 std::unique_ptr<Model> CreateNewModel(const std::string &model_name) {
197 _models.push_back(Model::Create(model_name, _log_name));
198 return _models.back()->clone();
199 }
200
202 void ClearModels() { _models.clear(); }
203
207 void AddModel(const std::unique_ptr<Model> &model) {
208 _models.push_back(model->clone());
209 }
210
213 void Run(int duration = -1) {
214 if (duration > 0) {
215 _duration = duration;
216 }
217 LogInfo(_log_name, "Running simulation for duration of " +
218 std::to_string(_duration) + " timesteps.");
219 for (const auto &model : _models) {
220 model->SetFinalTimestep(_duration);
221 model->RunTimesteps();
222 }
223 }
224
226 //
227 // Getters and Setters for Transitions and Metadata
228 //
230
233 std::vector<std::unique_ptr<Model>> GetModels() const {
234 std::vector<std::unique_ptr<Model>> _models_copy;
235 for (const auto &model : _models) {
236 _models_copy.push_back(model->clone());
237 }
238 return _models_copy;
239 }
240
248 GetModelRefOrThrow(idx);
249 return ModelSlotProxy(*this, idx);
250 }
251
256 const Model &operator[](size_t idx) const {
257 return GetModelRefOrThrow(idx);
258 }
259
267 std::map<size_t, std::string> GetModelIndexNameMap() const {
268 std::map<size_t, std::string> ret;
269 for (size_t i = 0; i < _models.size(); ++i) {
270 ret[i] = _models[i]->GetName();
271 }
272 return ret;
273 }
274
280 std::unique_ptr<Model> GetModel(int idx) const {
281 if (_models.empty()) {
282 LogError(_log_name, "No models available in GetModel.");
283 throw std::out_of_range("Error attempting to GetModel: no models.");
284 }
285 if (idx < -1 || idx >= static_cast<int>(_models.size())) {
286 LogError(_log_name,
287 "Index out of range in GetModel: " + std::to_string(idx));
288 throw std::out_of_range("Error attempting to GetModel by index.");
289 }
290 // Return the last model if idx is -1
291 if (idx == -1) {
292 return _models.back()->clone();
293 }
294 return _models[idx]->clone();
295 }
296
299 std::vector<std::string> GetModelNames() const {
300 std::vector<std::string> ret;
301 for (auto &m : _models) {
302 ret.push_back(m->GetName());
303 }
304 return ret;
305 }
306
311 const std::map<std::string, History> &GetModelHistory(size_t idx) const {
312 if (idx >= _models.size()) {
313 LogError(_log_name, "Index out of range in GetModelHistory: " +
314 std::to_string(idx));
315 throw std::out_of_range(
316 "Error attempting to GetModelHistory by index.");
317 }
318 return _models[idx]->GetHistories();
319 }
320
324 const std::vector<std::string> GetModelHistoryNames(size_t idx) const {
325 if (idx >= _models.size()) {
326 LogError(_log_name, "Index out of range in GetModelHistoryNames: " +
327 std::to_string(idx));
328 throw std::out_of_range(
329 "Error attempting to GetModelHistoryNames by index.");
330 }
331 std::vector<std::string> ret;
332 for (const auto &kv : _models[idx]->GetHistories()) {
333 ret.push_back(kv.first);
334 }
335 return ret;
336 }
337
338 void SetDuration(int duration) { _duration = duration; }
339
340private:
341 Model &GetModelRefOrThrow(size_t idx) {
342 if (idx >= _models.size()) {
343 LogError(_log_name, "Index out of range in model access: " +
344 std::to_string(idx));
345 throw std::out_of_range("Error attempting to access model by "
346 "index.");
347 }
348 return *_models[idx];
349 }
350
351 const Model &GetModelRefOrThrow(size_t idx) const {
352 if (idx >= _models.size()) {
353 LogError(_log_name, "Index out of range in model access: " +
354 std::to_string(idx));
355 throw std::out_of_range("Error attempting to access model by "
356 "index.");
357 }
358 return *_models[idx];
359 }
360
361 std::string _log_name;
362 std::vector<std::unique_ptr<Model>> _models;
363
364 int _duration = 1; // Default simulation duration in timesteps
365 std::vector<int> _parameter_change_times;
366 bool _stratify_entering_cohort;
367
368 bool _build_summary_stats;
369 bool _save_state_history;
370 std::vector<int> _timesteps_to_report;
371 bool _pivot_long;
372};
373} // namespace respond
374
375#endif // RESPOND_SIMULATION_HPP_
Abstract base class representing a state transition model. Models manage a state vector,...
Definition: model.hpp:30
virtual std::unique_ptr< Model > clone() const =0
Creates a deep copy of this model.
static std::unique_ptr< Model > Create(const std::string &name, const std::string &log_name=RESPOND_DEFAULT_LOG, const std::string &log_filepath=RESPOND_DEFAULT_LOG_FILE)
Factory method to create a Model instance.
Proxy for mutable model slot access with clone-based assignment.
Definition: simulation.hpp:35
Model * operator->()
Access the underlying model pointer for member access.
Definition: simulation.hpp:41
Model & operator*()
Dereference to the underlying model.
Definition: simulation.hpp:44
ModelSlotProxy & operator=(const ModelSlotProxy &other)
Replace this slot by cloning from another proxy's model.
Definition: simulation.hpp:50
ModelSlotProxy & operator=(const Model &model)
Replace this slot by cloning from a model reference.
Definition: simulation.hpp:56
ModelSlotProxy & operator=(const std::unique_ptr< Model > &model)
Replace this slot by cloning from a model unique_ptr.
Definition: simulation.hpp:64
Manages and executes multiple models in a coordinated simulation. A Simulation aggregates Model insta...
Definition: simulation.hpp:32
std::vector< std::string > GetModelNames() const
Retrieves the names of all models in the simulation.
Definition: simulation.hpp:299
Simulation(Simulation &&other) noexcept
Move constructor for transferring simulation ownership.
Definition: simulation.hpp:149
std::vector< std::unique_ptr< Model > > GetModels() const
Retrieves all models in the simulation.
Definition: simulation.hpp:233
~Simulation()=default
Virtual destructor for polymorphic cleanup.
std::map< size_t, std::string > GetModelIndexNameMap() const
Provide a mapping of model indices to their names for all models in the simulation.
Definition: simulation.hpp:267
void Run(int duration=-1)
Executes one step of the simulation for all models. Calls RunTransitions() on each registered model i...
Definition: simulation.hpp:213
Simulation(const std::string &log_name)
Constructs a Simulation with a specified logger.
Definition: simulation.hpp:94
void ClearModels()
Removes all models from the simulation.
Definition: simulation.hpp:202
const std::map< std::string, History > & GetModelHistory(size_t idx) const
Retrieves the complete state histories for the model at the index.
Definition: simulation.hpp:311
Simulation(const Simulation &other)
Copy constructor creating an independent deep copy of the simulation. All models are cloned; modifica...
Definition: simulation.hpp:112
std::unique_ptr< Model > GetModel(int idx) const
Retrieves a specific model by index in the simulation.
Definition: simulation.hpp:280
std::unique_ptr< Model > CreateNewModel(const std::string &model_name)
Creates a new model instance and adds it to the simulation.
Definition: simulation.hpp:196
Simulation()
Default constructor for a Simulation instance. Initializes the simulation with the default logger.
Definition: simulation.hpp:90
Simulation & operator=(const Simulation &other)
Copy assignment operator for deep copying simulation state.
Definition: simulation.hpp:129
const Model & operator[](size_t idx) const
Const index-based model access.
Definition: simulation.hpp:256
Simulation(const std::string &log_name, const std::string &log_filepath)
Constructs a Simulation with a specified logger and log file.
Definition: simulation.hpp:100
Simulation & operator=(Simulation &&other) noexcept
Move assignment operator for transferring simulation ownership.
Definition: simulation.hpp:166
void AddModel(const std::unique_ptr< Model > &model)
Adds a model to the simulation. The model is cloned and managed by the simulation.
Definition: simulation.hpp:207
const std::vector< std::string > GetModelHistoryNames(size_t idx) const
Retrieves history names for the model at the specified index.
Definition: simulation.hpp:324
ModelSlotProxy operator[](size_t idx)
Mutable index-based model access.
Definition: simulation.hpp:247