From 23468561521b414f5e802797ddc7ffd024b98af6 Mon Sep 17 00:00:00 2001 From: Dimitri Baptiste <55843498+ddbaptiste@users.noreply.github.com> Date: Mon, 14 Sep 2026 14:06:32 -0400 Subject: [PATCH 1/5] Add `processor_count` as an argument to the Markov model --- src/internals/markov.hpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/internals/markov.hpp b/src/internals/markov.hpp index 08e63993..331feaea 100644 --- a/src/internals/markov.hpp +++ b/src/internals/markov.hpp @@ -4,8 +4,8 @@ // Created Date: 2026-02-05 // // Author: Matthew Carroll // // ----- // -// Last Modified: 2026-07-14 // -// Modified By: Matthew Carroll // +// Last Modified: 2026-09-14 // +// Modified By: Dimitri Baptiste // // ----- // // Copyright (c) 2026 Syndemics Lab at Boston Medical Center // //////////////////////////////////////////////////////////////////////////////// @@ -48,13 +48,16 @@ class Markov : public virtual Model { /// @param log_name The logger name for error reporting. /// @param log_filepath The file path for the log file to be used by this /// model. + /// @param processor_count The number of threads to use when running this + /// model. Markov(const std::string &name, const std::string &log_name, - const std::string &log_filepath) + const std::string &log_filepath, + const unsigned int processor_count = + std::thread::hardware_concurrency()) : _name(name), _log_name(log_name), _current_timestep(0), _history_capture_interval(1), _final_timestep(-1), _initial_history_recorded(false) { CreateFileLogger(log_name, log_filepath); - const auto processor_count = std::thread::hardware_concurrency(); Eigen::setNbThreads(processor_count); } @@ -361,4 +364,4 @@ class Markov : public virtual Model { }; } // namespace respond -#endif // RESPOND_INTERNALS_MARKOV_HPP_ \ No newline at end of file +#endif // RESPOND_INTERNALS_MARKOV_HPP_ From d540a9948adbfcee1c207cb16e7eae0fed93d5f5 Mon Sep 17 00:00:00 2001 From: Dimitri Baptiste <55843498+ddbaptiste@users.noreply.github.com> Date: Wed, 16 Sep 2026 11:15:15 -0400 Subject: [PATCH 2/5] Add capacity for processor count to be specified by users --- include/respond/model.hpp | 22 +++++++++++++++++++--- src/internals/markov.hpp | 8 ++++++-- src/model_factory.cpp | 12 ++++++++++-- tests/unit/markov_test.cpp | 16 ++++++++++++++-- 4 files changed, 49 insertions(+), 9 deletions(-) diff --git a/include/respond/model.hpp b/include/respond/model.hpp index 6be742b7..1376a154 100644 --- a/include/respond/model.hpp +++ b/include/respond/model.hpp @@ -4,8 +4,8 @@ // Created Date: 2026-02-05 // // Author: Matthew Carroll // // ----- // -// Last Modified: 2026-07-14 // -// Modified By: Matthew Carroll // +// Last Modified: 2026-09-14 // +// Modified By: Dimitri Baptiste // // ----- // // Copyright (c) 2026 Syndemics Lab at Boston Medical Center // //////////////////////////////////////////////////////////////////////////////// @@ -49,6 +49,22 @@ class Model { const std::string &log_name = RESPOND_DEFAULT_LOG, const std::string &log_filepath = RESPOND_DEFAULT_LOG_FILE); + /// @brief Alternate factory method to create a Model instance. + /// @details This method creates a new instance of a Model subclass based on + /// the provided name. It sets the number of threads to be used by the + /// model, initializes logging for the model, and returns a unique_ptr to + /// the created instance. Throws an exception if the model name is + /// unsupported. + /// @param name The name identifier for the model to create. + /// @param processor_count The number of threads to be used by the model. + /// @param log_name Name of the logger for this model (default: "console"). + /// @param log_filepath File path for the log file (default: "respond.log"). + /// @return A unique_ptr to the newly created Model instance. + static std::unique_ptr + Create(const std::string &name, const unsigned int processor_count, + const std::string &log_name = RESPOND_DEFAULT_LOG, + const std::string &log_filepath = RESPOND_DEFAULT_LOG_FILE); + /// @brief Virtual destructor for proper polymorphic cleanup. virtual ~Model() = default; @@ -188,4 +204,4 @@ inline std::ostream &operator<<(std::ostream &os, const Model &model) { } // namespace respond -#endif // RESPOND_MODEL_HPP_ \ No newline at end of file +#endif // RESPOND_MODEL_HPP_ diff --git a/src/internals/markov.hpp b/src/internals/markov.hpp index 331feaea..3073e172 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-09-14 // +// Last Modified: 2026-09-16 // // Modified By: Dimitri Baptiste // // ----- // // Copyright (c) 2026 Syndemics Lab at Boston Medical Center // @@ -58,7 +58,11 @@ class Markov : public virtual Model { _history_capture_interval(1), _final_timestep(-1), _initial_history_recorded(false) { CreateFileLogger(log_name, log_filepath); - Eigen::setNbThreads(processor_count); + // ensure that the number of threads cannot exceed the hardware capacity + const unsigned int thread_limit = std::thread::hardware_concurrency(); + const unsigned int threads = + processor_count > thread_limit ? thread_limit : processor_count; + Eigen::setNbThreads(threads); } /// @brief Destructor for Markov model. Default implementation. diff --git a/src/model_factory.cpp b/src/model_factory.cpp index d2a57d35..9d882f7b 100644 --- a/src/model_factory.cpp +++ b/src/model_factory.cpp @@ -4,8 +4,8 @@ // Created Date: 2025-07-07 // // Author: Matthew Carroll // // ----- // -// Last Modified: 2026-07-07 // -// Modified By: Matthew Carroll // +// Last Modified: 2026-09-14 // +// Modified By: Dimitri Baptiste // // ----- // // Copyright (c) 2025-2026 Syndemics Lab at Boston Medical Center // //////////////////////////////////////////////////////////////////////////////// @@ -25,4 +25,12 @@ std::unique_ptr Model::Create(const std::string &name, const std::string &log_filepath) { return std::make_unique(name, log_name, log_filepath); } + +std::unique_ptr Model::Create(const std::string &name, + const unsigned int processor_count, + const std::string &log_name, + const std::string &log_filepath) { + return std::make_unique(name, log_name, log_filepath, + processor_count); +} } // namespace respond diff --git a/tests/unit/markov_test.cpp b/tests/unit/markov_test.cpp index 02619a26..5e754b97 100644 --- a/tests/unit/markov_test.cpp +++ b/tests/unit/markov_test.cpp @@ -4,8 +4,8 @@ // Created Date: 2025-06-06 // // Author: Matthew Carroll // // ----- // -// Last Modified: 2026-07-09 // -// Modified By: Matthew Carroll // +// Last Modified: 2026-09-14 // +// Modified By: Dimitri Baptiste // // ----- // // Copyright (c) 2025-2026 Syndemics Lab at Boston Medical Center // //////////////////////////////////////////////////////////////////////////////// @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -88,6 +89,17 @@ TEST_F(MarkovTest, CreateMarkovModel) { CreationStatus::kExists); } +TEST_F(MarkovTest, CreateMarkovModelProcessorCount) { + unsigned int processor_count = + std::thread::hardware_concurrency() > 1 + ? (std::thread::hardware_concurrency() / 2) + : 1; + auto markov = Model::Create("markov", processor_count); + ASSERT_NE(markov, nullptr); + ASSERT_EQ(CreateFileLogger(RESPOND_DEFAULT_LOG, ""), + CreationStatus::kExists); +} + TEST_F(MarkovTest, MoveConstructor) { Markov markov("markov_source", RESPOND_DEFAULT_LOG); markov.SetState(state); From e8631358957567653ef0723aa6940f245b5d3641 Mon Sep 17 00:00:00 2001 From: Dimitri Baptiste <55843498+ddbaptiste@users.noreply.github.com> Date: Wed, 16 Sep 2026 16:25:44 -0400 Subject: [PATCH 3/5] Add a print statement to make it clear how many processors are used --- src/internals/markov.hpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/internals/markov.hpp b/src/internals/markov.hpp index 3073e172..97b90671 100644 --- a/src/internals/markov.hpp +++ b/src/internals/markov.hpp @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -240,6 +241,12 @@ class Markov : public virtual Model { duration = static_cast(_final_timestep); } + // specify the number of processors/threads being used before execution + std::string warning = + "Running the model with " + std::to_string(Eigen::nbThreads()) + << " computing threads"; + LogWarning(_log_name, warning); + for (size_t i = 0; i < duration; ++i) { RunTimestep(); RecordHistoryAtCurrentTimestep(); From 154a173af8c7fe4f2bea43cdeb93b9a09d43ec4d Mon Sep 17 00:00:00 2001 From: Dimitri Baptiste <55843498+ddbaptiste@users.noreply.github.com> Date: Wed, 16 Sep 2026 16:32:55 -0400 Subject: [PATCH 4/5] Fix operator typo --- src/internals/markov.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/internals/markov.hpp b/src/internals/markov.hpp index 97b90671..f92b8c67 100644 --- a/src/internals/markov.hpp +++ b/src/internals/markov.hpp @@ -242,9 +242,9 @@ class Markov : public virtual Model { } // specify the number of processors/threads being used before execution - std::string warning = - "Running the model with " + std::to_string(Eigen::nbThreads()) - << " computing threads"; + std::string warning = "Running the model with " + + std::to_string(Eigen::nbThreads()) + + " computing threads"; LogWarning(_log_name, warning); for (size_t i = 0; i < duration; ++i) { From 809f882591eae4e3a6bbf87fcc5a4350cc06d642 Mon Sep 17 00:00:00 2001 From: Dimitri Baptiste <55843498+ddbaptiste@users.noreply.github.com> Date: Fri, 18 Sep 2026 09:46:19 -0400 Subject: [PATCH 5/5] Remove printf debugging from `markov` --- src/internals/markov.hpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/internals/markov.hpp b/src/internals/markov.hpp index f92b8c67..ad5f1781 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-09-16 // +// Last Modified: 2026-09-18 // // Modified By: Dimitri Baptiste // // ----- // // Copyright (c) 2026 Syndemics Lab at Boston Medical Center // @@ -241,12 +241,6 @@ class Markov : public virtual Model { duration = static_cast(_final_timestep); } - // specify the number of processors/threads being used before execution - std::string warning = "Running the model with " + - std::to_string(Eigen::nbThreads()) + - " computing threads"; - LogWarning(_log_name, warning); - for (size_t i = 0; i < duration; ++i) { RunTimestep(); RecordHistoryAtCurrentTimestep();