diff --git a/include/respond/model.hpp b/include/respond/model.hpp index 2e90c26e..096b8fd7 100644 --- a/include/respond/model.hpp +++ b/include/respond/model.hpp @@ -4,7 +4,7 @@ // Created Date: 2026-02-05 // // Author: Matthew Carroll // // ----- // -// Last Modified: 2026-02-09 // +// Last Modified: 2026-02-12 // // Modified By: Matthew Carroll // // ----- // // Copyright (c) 2026 Syndemics Lab at Boston Medical Center // @@ -42,6 +42,8 @@ class Model { // History, but let that be the History's responsibility virtual std::map GetHistories() const = 0; + virtual void CreateDefaultHistories() = 0; + virtual void SetHistories(const std::map &h) = 0; // getter for model name virtual std::string GetModelName() const = 0; diff --git a/include/respond/simulation.hpp b/include/respond/simulation.hpp index 6e4e41eb..79b4e8f8 100644 --- a/include/respond/simulation.hpp +++ b/include/respond/simulation.hpp @@ -4,7 +4,7 @@ // Created Date: 2026-02-05 // // Author: Matthew Carroll // // ----- // -// Last Modified: 2026-02-10 // +// Last Modified: 2026-02-12 // // Modified By: Matthew Carroll // // ----- // // Copyright (c) 2026 Syndemics Lab at Boston Medical Center // @@ -33,11 +33,9 @@ class Simulation { /// @brief The core function to run the simulation. Runs all models /// associated with the simulation. /// @param duration The number of steps to take for each model. - void Run(const int &duration) { - for (int i = 0; i < duration; ++i) { - for (const auto &model : _models) { - model->RunTransitions(); - } + void Run() { + for (const auto &model : _models) { + model->RunTransitions(); } } @@ -89,27 +87,6 @@ class Simulation { return ret; } - /// @brief The default histories are: - /// 1. State - /// 2. Total Overdoses - /// 3. Fatal Overdoses - /// 4. Intervention Admissions - /// 5. Background Mortality - /// @return A vector of the default history objects. - static std::map - CreateDefaultHistories(const std::string &log_name) { - std::vector names = { - "state", "total_overdose", "fatal_overdose", - "intervention_admission", "background_death"}; - - std::map ret; - for (const auto &n : names) { - History h(n, log_name); - ret[n] = h; - } - return ret; - } - std::string GetLogName() const { return _log_name; } // Copying object diff --git a/src/background.cpp b/src/background.cpp index ca8346d0..dcf679ea 100644 --- a/src/background.cpp +++ b/src/background.cpp @@ -4,7 +4,7 @@ // Created Date: 2026-02-05 // // Author: Matthew Carroll // // ----- // -// Last Modified: 2026-02-05 // +// Last Modified: 2026-02-12 // // Modified By: Matthew Carroll // // ----- // // Copyright (c) 2026 Syndemics Lab at Boston Medical Center // @@ -28,7 +28,15 @@ BackgroundDeath::Execute(const Eigen::VectorXd &state, if (h.find("background_death") != h.end()) { h["background_death"].AddState(deaths); } + if (!(state.array() >= deaths.array()).all()) { + std::runtime_error( + "The state is not larger than the estimated background deaths!"); + } auto new_state = state - deaths; // remove deaths from state + + if (h.find("background_death") != h.end()) { + h["state"].AddState(new_state); + } return new_state; } diff --git a/src/internals/markov.hpp b/src/internals/markov.hpp index fbe879ae..f827de5f 100644 --- a/src/internals/markov.hpp +++ b/src/internals/markov.hpp @@ -4,7 +4,7 @@ // Created Date: 2026-02-05 // // Author: Matthew Carroll // // ----- // -// Last Modified: 2026-02-10 // +// Last Modified: 2026-02-12 // // Modified By: Matthew Carroll // // ----- // // Copyright (c) 2026 Syndemics Lab at Boston Medical Center // @@ -78,15 +78,33 @@ class Markov : public virtual Model { return _transition_vector; } + /// @brief The default histories are: + /// 1. State + /// 2. Total Overdoses + /// 3. Fatal Overdoses + /// 4. Intervention Admissions + /// 5. Background Mortality + /// @return A vector of the default history objects. + void CreateDefaultHistories() override { + std::vector names = { + "state", "total_overdose", "fatal_overdose", + "intervention_admission", "background_death"}; + + std::map ret; + for (const auto &n : names) { + History h(n, GetLogName()); + ret[n] = h; + } + SetHistories(ret); + } + // manipulate the state vector void RunTransitions() override { + SetupHistory(); auto histories = GetHistories(); for (const auto &t : _transition_vector) { SetState(t->Execute(GetState(), histories)); } - if (histories.find("state") != histories.end()) { - histories["state"].AddState(GetState()); - } SetHistories(histories); } // assume ownership of the Transition @@ -123,6 +141,23 @@ class Markov : public virtual Model { std::string _name; std::string _log_name; std::map _histories; + + void SetupHistory() { + auto histories = GetHistories(); + if (histories.empty()) { + CreateDefaultHistories(); + histories = GetHistories(); + } + histories["state"].AddState(GetState()); + auto size = GetState().size(); + + histories["intervention_admission"].AddState( + Eigen::VectorXd::Zero(size)); + histories["total_overdose"].AddState(Eigen::VectorXd::Zero(size)); + histories["fatal_overdose"].AddState(Eigen::VectorXd::Zero(size)); + histories["background_death"].AddState(Eigen::VectorXd::Zero(size)); + SetHistories(histories); + } }; } // namespace respond diff --git a/src/migration.cpp b/src/migration.cpp index e2070ff3..5a1cab55 100644 --- a/src/migration.cpp +++ b/src/migration.cpp @@ -4,7 +4,7 @@ // Created Date: 2026-02-05 // // Author: Matthew Carroll // // ----- // -// Last Modified: 2026-02-05 // +// Last Modified: 2026-02-12 // // Modified By: Matthew Carroll // // ----- // // Copyright (c) 2026 Syndemics Lab at Boston Medical Center // @@ -26,8 +26,10 @@ Eigen::VectorXd Migration::Execute(const Eigen::VectorXd &state, throw std::runtime_error("Unable to add Migration Transition Vector to " "State Vector, mismatched sizes."); } - auto new_state = state + GetTransitionMatrices()[0]; - return new_state; + auto subtracted = state + GetTransitionMatrices()[0]; + auto zero_stop = subtracted.array().max( + Eigen::VectorXd::Zero(subtracted.size()).array()); + return zero_stop; } std::unique_ptr Migration::Create(const std::string &name, diff --git a/src/overdose.cpp b/src/overdose.cpp index 5b667b97..1bd3c802 100644 --- a/src/overdose.cpp +++ b/src/overdose.cpp @@ -4,7 +4,7 @@ // Created Date: 2026-02-05 // // Author: Matthew Carroll // // ----- // -// Last Modified: 2026-02-05 // +// Last Modified: 2026-02-12 // // Modified By: Matthew Carroll // // ----- // // Copyright (c) 2026 Syndemics Lab at Boston Medical Center // @@ -42,6 +42,10 @@ Eigen::VectorXd Overdose::Execute(const Eigen::VectorXd &state, if (h.find("fatal_overdose") != h.end()) { h["fatal_overdose"].AddState(fods); } + if (!(state.array() >= fods.array()).all()) { + std::runtime_error( + "The state is not larger than the estimated fatal overdoses!"); + } auto new_state = state - fods; // remove fods from state return new_state; } diff --git a/tests/integration/respond_test.cpp b/tests/integration/respond_test.cpp index ab296a3a..ce576615 100644 --- a/tests/integration/respond_test.cpp +++ b/tests/integration/respond_test.cpp @@ -4,7 +4,7 @@ // Created Date: 2026-02-06 // // Author: Matthew Carroll // // ----- // -// Last Modified: 2026-02-10 // +// Last Modified: 2026-02-13 // // Modified By: Matthew Carroll // // ----- // // Copyright (c) 2026 Syndemics Lab at Boston Medical Center // @@ -86,7 +86,7 @@ TEST_F(RespondTest, RunTransitionsInModel) { } TEST_F(RespondTest, RunSimulationOneStep) { - markov->SetHistories(Simulation::CreateDefaultHistories("test_logger")); + markov->CreateDefaultHistories(); markov->SetState(init_state); @@ -108,7 +108,7 @@ TEST_F(RespondTest, RunSimulationOneStep) { Simulation sim("test_logger"); sim.AddModel(markov); - sim.Run(1); + sim.Run(); auto histories = sim.GetModelHistories(); ASSERT_EQ(histories.size(), 1); @@ -119,11 +119,28 @@ TEST_F(RespondTest, RunSimulationOneStep) { } auto state_history = mm_histories.at("state"); - ASSERT_EQ(state_history.size(), 1); + // 2 because it carries the initial state and 1 step + ASSERT_EQ(state_history.size(), 2); Eigen::Vector3d final_state; + ASSERT_TRUE(state_history[0].isApprox(init_state)); final_state << 0.76715528791564891, 0.72320370216816077, 1.037712429738102; - ASSERT_TRUE(state_history[0].isApprox(final_state)); + ASSERT_TRUE(state_history[1].isApprox(final_state)); +} + +TEST_F(RespondTest, CreateDefaultHistories) { + std::vector expected = { + "state", "total_overdose", "fatal_overdose", "intervention_admission", + "background_death"}; + + std::sort(expected.begin(), expected.end()); + + markov->CreateDefaultHistories(); + std::vector results; + for (const auto &kv : markov->GetHistories()) { + results.push_back(kv.first); + } + ASSERT_EQ(results, expected); } } // namespace testing diff --git a/tests/mocks/model_mock.hpp b/tests/mocks/model_mock.hpp index b27edba3..417d35c0 100644 --- a/tests/mocks/model_mock.hpp +++ b/tests/mocks/model_mock.hpp @@ -4,7 +4,7 @@ // Created Date: 2025-08-01 // // Author: Matthew Carroll // // ----- // -// Last Modified: 2026-02-09 // +// Last Modified: 2026-02-12 // // Modified By: Matthew Carroll // // ----- // // Copyright (c) 2025-2026 Syndemics Lab at Boston Medical Center // @@ -45,6 +45,7 @@ class MockModel : public virtual Model { MOCK_METHOD(std::string, GetModelName, (), (const, override)); MOCK_METHOD(std::string, GetLogName, (), (const, override)); MOCK_METHOD((std::unique_ptr), clone, (), (const, override)); + MOCK_METHOD(void, CreateDefaultHistories, (), (override)); }; } // namespace testing } // namespace respond diff --git a/tests/unit/simulation_test.cpp b/tests/unit/simulation_test.cpp index f4f45f50..56ff3928 100644 --- a/tests/unit/simulation_test.cpp +++ b/tests/unit/simulation_test.cpp @@ -4,7 +4,7 @@ // Created Date: 2026-02-09 // // Author: Matthew Carroll // // ----- // -// Last Modified: 2026-02-10 // +// Last Modified: 2026-02-12 // // Modified By: Matthew Carroll // // ----- // // Copyright (c) 2026 Syndemics Lab at Boston Medical Center // @@ -133,20 +133,5 @@ TEST_F(SimulationTest, GetHistoryNames) { ASSERT_EQ(s.GetModelHistoryNames(), expected); } -TEST_F(SimulationTest, CreateDefaultHistories) { - std::vector expected = { - "state", "total_overdose", "fatal_overdose", "intervention_admission", - "background_death"}; - - std::sort(expected.begin(), expected.end()); - - Simulation s; - auto defaults = s.CreateDefaultHistories("test_logger"); - std::vector results; - for (const auto &kv : defaults) { - results.push_back(kv.first); - } - ASSERT_EQ(results, expected); -} } // namespace testing } // namespace respond \ No newline at end of file