LCOV - code coverage report
Current view: top level - models/d_abm - simulation.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 43 43 100.0 %
Date: 2025-02-17 13:46:44 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /* 
       2             : * Copyright (C) 2020-2025 German Aerospace Center (DLR-SC)
       3             : *
       4             : * Authors: René Schmieding, Julia Bicker
       5             : *
       6             : * Contact: Martin J. Kuehn <Martin.Kuehn@DLR.de>
       7             : *
       8             : * Licensed under the Apache License, Version 2.0 (the "License");
       9             : * you may not use this file except in compliance with the License.
      10             : * You may obtain a copy of the License at
      11             : *
      12             : *     http://www.apache.org/licenses/LICENSE-2.0
      13             : *
      14             : * Unless required by applicable law or agreed to in writing, software
      15             : * distributed under the License is distributed on an "AS IS" BASIS,
      16             : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      17             : * See the License for the specific language governing permissions and
      18             : * limitations under the License.
      19             : */
      20             : 
      21             : #ifndef MIO_D_ABM_SIMULATION_H
      22             : #define MIO_D_ABM_SIMULATION_H
      23             : 
      24             : #include "d_abm/model.h"
      25             : #include "memilio/config.h"
      26             : #include "memilio/compartments/simulation.h"
      27             : #include "memilio/utils/random_number_generator.h"
      28             : 
      29             : namespace mio
      30             : {
      31             : 
      32             : namespace dabm
      33             : {
      34             : 
      35             : /**
      36             :  * @brief A specialized Simulation for mio::dabm::Model.
      37             :  * @tparam Implementation A class implementing all functions and types marked with the using keyword in Model, see dabm::Model.
      38             :  */
      39             : template <class Implementation>
      40             : class Simulation
      41             : {
      42             :     using Status = typename Implementation::Status;
      43             : 
      44             : public:
      45             :     using Model = dabm::Model<Implementation>;
      46             : 
      47             :     /**
      48             :      * @brief Set up the simulation for a diffusive ABM.
      49             :      * @param[in] model An instance of mio::dabm::Model.
      50             :      * @param[in] t0 Start time.
      51             :      * @param[in] dt Step size of integration.
      52             :      */
      53           7 :     Simulation(const Model& model, ScalarType t0 = 0, ScalarType dt = 0.1)
      54           7 :         : m_t0(t0)
      55           7 :         , m_dt(dt)
      56           7 :         , m_model(std::make_unique<Model>(model))
      57           7 :         , m_result(t0, m_model->time_point())
      58             :     {
      59           7 :         assert(dt > 0);
      60           7 :         m_current_rates.reserve(m_model->populations.size());
      61           7 :         m_current_events.reserve(m_model->populations.size());
      62           7 :     }
      63             : 
      64             :     /**
      65             :      * @brief Advance simulation to tmax.
      66             :      * This function performs a temporal Gillespie.
      67             :      * @param tmax Next stopping point of simulation.
      68             :      */
      69           7 :     void advance(const ScalarType t_max)
      70             :     {
      71             :         // draw time until an adoption takes place
      72           7 :         ScalarType waiting_time = mio::ExponentialDistribution<ScalarType>::get_instance()(m_model->get_rng(), 1.0);
      73        2107 :         while (m_t0 < t_max) {
      74        2100 :             ScalarType dt             = std::min({m_dt, t_max - m_t0});
      75        2100 :             ScalarType remaining_time = dt;
      76        2107 :             while (remaining_time > 0) {
      77        2107 :                 compute_current_rates_and_events(); // lambda_k (aka f-hat(N))
      78             :                 ScalarType cumulative_adoption_rate =
      79        2107 :                     std::accumulate(m_current_rates.begin(), m_current_rates.end(), 0.0); // Lambda
      80             :                 // status update
      81        2107 :                 if (waiting_time < cumulative_adoption_rate * remaining_time) {
      82             :                     // draw which adoption takes place
      83             :                     const size_t event_id =
      84           7 :                         mio::DiscreteDistribution<size_t>::get_instance()(m_model->get_rng(), m_current_rates);
      85           7 :                     Event& event = m_current_events[event_id];
      86             :                     // perform adoption
      87           7 :                     m_model->adopt(event.agent, event.new_status);
      88             :                     // draw new waiting time
      89           7 :                     remaining_time -= waiting_time / cumulative_adoption_rate;
      90           7 :                     waiting_time = mio::ExponentialDistribution<ScalarType>::get_instance()(m_model->get_rng(), 1.0);
      91             :                 }
      92             :                 else {
      93             :                     // no event, decrease waiting time
      94        2100 :                     waiting_time -= cumulative_adoption_rate * remaining_time;
      95        2100 :                     break;
      96             :                 }
      97             :             }
      98             :             // position update
      99        8400 :             for (auto& agent : m_model->populations) {
     100        6300 :                 m_model->move(m_t0, dt, agent);
     101             :             }
     102        2100 :             m_t0 += dt;
     103             :             // store result
     104        2100 :             m_result.add_time_point(m_t0, m_model->time_point());
     105             :         }
     106           7 :     }
     107             : 
     108             :     /**
     109             :      * @brief Returns the final simulation result.
     110             :      * @return A TimeSeries to represent the final simulation result.
     111             :      */
     112          70 :     TimeSeries<ScalarType>& get_result()
     113             :     {
     114          70 :         return m_result;
     115             :     }
     116             :     const TimeSeries<ScalarType>& get_result() const
     117             :     {
     118             :         return m_result;
     119             :     }
     120             : 
     121             :     /**
     122             :      * @brief Returns the model used in the simulation.
     123             :      */
     124             :     const Model& get_model() const
     125             :     {
     126             :         return *m_model;
     127             :     }
     128             :     Model& get_model()
     129             :     {
     130             :         return *m_model;
     131             :     }
     132             : 
     133             : private:
     134             :     /**
     135             :      * @brief Struct defining an adoption event for an agent and target infection state.
     136             :      */
     137             :     struct Event {
     138             :         typename Model::Agent& agent;
     139             :         Status new_status;
     140             :     };
     141             : 
     142             :     /**
     143             :      * @brief Calculate current values for m_current_rates and m_current_events.
     144             :      */
     145        2107 :     inline void compute_current_rates_and_events()
     146             :     {
     147        2107 :         m_current_rates.clear();
     148        2107 :         m_current_events.clear();
     149             :         // compute rate for each (agent, status) combination
     150        8428 :         for (auto& agent : m_model->populations) {
     151       44247 :             for (int s = 0; s < static_cast<int>(Status::Count); s++) {
     152       37926 :                 Status new_status = static_cast<Status>(s);
     153             :                 // check if an adoption from the agents status is possible
     154       37926 :                 auto adoption_rate = m_model->adoption_rate(agent, new_status);
     155       37926 :                 if (adoption_rate > 0) {
     156             :                     // add rate and corresponding event
     157          42 :                     m_current_rates.push_back(adoption_rate);
     158          42 :                     m_current_events.push_back({agent, new_status});
     159             :                 }
     160             :             }
     161             :         }
     162        2107 :     }
     163             : 
     164             :     ScalarType m_t0, m_dt; ///< Start time of the simulation and integration step size.
     165             :     std::unique_ptr<Model> m_model; ///< Pointer to the model used in the simulation.
     166             :     std::vector<ScalarType> m_current_rates; ///< Current adoption rates.
     167             :     std::vector<Event> m_current_events; ///< Contains an event corresponding to each rate in m_current_rates.
     168             :     mio::TimeSeries<ScalarType> m_result; ///< Result time series.
     169             : };
     170             : } //namespace dabm
     171             : } // namespace mio
     172             : 
     173             : #endif

Generated by: LCOV version 1.14