BioDynaMo  v1.05.159-3be850bb
regulatory_network.h
Go to the documentation of this file.
1 // -----------------------------------------------------------------------------
2 //
3 // Copyright (C) 2021 CERN & University of Surrey for the benefit of the
4 // BioDynaMo collaboration. All Rights Reserved.
5 //
6 // Licensed under the Apache License, Version 2.0 (the "License");
7 // you may not use this file except in compliance with the License.
8 //
9 // See the LICENSE file distributed with this work for details.
10 // See the NOTICE file distributed with this work for additional information
11 // regarding copyright ownership.
12 //
13 // -----------------------------------------------------------------------------
14 
15 #ifndef CORE_BEHAVIOR_REGULATORY_NETWORK_H_
16 #define CORE_BEHAVIOR_REGULATORY_NETWORK_H_
17 
18 #ifdef USE_BOOST
19 
20 #include "core/behavior/behavior.h"
21 
22 #ifndef __ROOTCLING__
23 #include "boost/numeric/odeint.hpp"
24 #include "boost/phoenix/core.hpp"
25 #include "boost/phoenix/operator.hpp"
26 #endif
27 
28 #ifndef __ROOTCLING__
29 typedef boost::numeric::ublas::vector<double> b_vector_t;
30 typedef boost::numeric::ublas::matrix<double> b_matrix_t;
31 #endif
32 
33 namespace bdm {
34 
35 enum class ODE_solver { Euler, Rosenbrock, RungeKutta };
36 
37 class RegulatoryNetwork : public Behavior {
38  BDM_BEHAVIOR_HEADER(RegulatoryNetwork, Behavior, 1);
39 
40  public:
41  RegulatoryNetwork() { AlwaysCopyToNew(); }
42 #ifndef __ROOTCLING__
43  RegulatoryNetwork(
44  real_t dt, int n_dt, const std::vector<real_t>& x, ODE_solver m,
45  const std::function<void(const b_vector_t&, b_vector_t&, real_t, Agent*)>&
46  rhs,
47  const std::function<void(const b_vector_t&, b_matrix_t&, real_t,
48  b_vector_t&, Agent*)>& jacob,
49  const std::function<void(const b_vector_t&, real_t, Agent*)>& out) {
50  AlwaysCopyToNew();
51  SetInitialSpecies(x);
52  //
53  time_step_ = dt;
54  time_subdivision_ = n_dt;
55  //
56  rhs_ = rhs;
57  jacob_ = jacob;
58  out_ = out;
59  method_ = m;
60  }
61 #endif
62  virtual ~RegulatoryNetwork() = default;
63 
64  void Initialize(const NewAgentEvent& event) override {
65  Base::Initialize(event);
66 
67  if (auto* other =
68  dynamic_cast<RegulatoryNetwork*>(event.existing_behavior)) {
69 #ifndef __ROOTCLING__
70  current_time_ = other->current_time_;
71  current_species_ = other->current_species_;
72  previous_species_ = other->previous_species_;
73 #endif
74 
75  time_step_ = other->time_step_;
76  time_subdivision_ = other->time_subdivision_;
77 
78 #ifndef __ROOTCLING__
79  rhs_ = other->rhs_;
80  jacob_ = other->jacob_;
81  out_ = other->out_;
82  method_ = other->method_;
83 #endif
84  } else {
85  Log::Fatal("RegulatoryNetwork::EventConstructor",
86  "other was not of type RegulatoryNetwork");
87  }
88  }
89 
90 #ifndef __ROOTCLING__
91  const size_t GetNumberOfSpecies() const { return current_species_.size(); }
92  const b_vector_t& GetSpecies() const { return current_species_; }
93  const real_t& GetSpecie(size_t i) const { return current_species_[i]; }
94 #endif
95 
96  void Run(Agent* agent) override {
97 #ifndef __ROOTCLING__
98  // update the previous solution
99  previous_species_ = current_species_;
100 
101  auto ode_rhs_ = [&](const b_vector_t& x, b_vector_t& dxdt, real_t t) {
102  rhs_(x, dxdt, t, agent);
103  };
104  auto ode_jacob_ = [&](const b_vector_t& x, b_matrix_t& jac, real_t t,
105  b_vector_t& dfdt) { jacob_(x, jac, t, dfdt, agent); };
106 
107  // initialize the time-integration scheme
108  if (ODE_solver::Euler == method_) {
109  // define the fixed time increment
110  const real_t dt = time_step_ / time_subdivision_;
111 
112  // explicit Euler time-integration
113  for (int i = 0; i < time_subdivision_; i++) {
114  const real_t t = current_time_ + dt * (1 + i);
115 
116  // calculate the rate of change of all species
117  b_vector_t dxdt(current_species_.size());
118  ode_rhs_(current_species_, dxdt, t);
119 
120  // update the species
121  current_species_ += dxdt * dt;
122  }
123  } else if (ODE_solver::Rosenbrock == method_) {
124  typedef boost::numeric::odeint::rosenbrock4<double> ode_int;
125 
126  // set-up the Rosenbrock integrator
127  auto stepper =
128  boost::numeric::odeint::make_dense_output<ode_int>(1e-6, 1e-6);
129 
130  // perform the time-integration
131  integrate_const(stepper, std::make_pair(ode_rhs_, ode_jacob_),
132  current_species_, current_time_,
133  (current_time_ + time_step_),
134  (time_step_ / time_subdivision_));
135  } else if (ODE_solver::RungeKutta == method_) {
136  typedef boost::numeric::odeint::runge_kutta_dopri5<b_vector_t> ode_int;
137 
138  // set-up the Runge-Kutta integrator
139  auto stepper =
140  boost::numeric::odeint::make_dense_output<ode_int>(1e-6, 1e-6);
141 
142  // perform the time-integration
143  integrate_const(stepper, ode_rhs_, current_species_, current_time_,
144  (current_time_ + time_step_),
145  (time_step_ / time_subdivision_));
146  } else {
147  Log::Fatal("RegulatoryNetwork::Run",
148  "invalid type of ODE solution method indicated");
149  }
150 
151  // update the time of the regulatory network
152  current_time_ += time_step_;
153 
154  // print-out the results
155  out_(current_species_, current_time_, agent);
156 #else
157  Log::Fatal("RegulatoryNetwork::Run",
158  "this behavior is supported only with \"boost\" installed");
159 #endif
160  };
161 
162  protected:
163 #ifndef __ROOTCLING__
164  void SetInitialSpecies(const std::vector<real_t>& x) {
165  const size_t n_species = x.size();
166 
167  current_species_.resize(n_species);
168  previous_species_.resize(n_species);
169  for (size_t i = 0; i < n_species; i++)
170  current_species_[i] = previous_species_[i] = x[i];
171  }
172 #endif
173 
174  private:
176  real_t current_time_ = 0.0;
178  real_t time_step_ = 1.0;
179  int time_subdivision_ = 100;
180 #ifndef __ROOTCLING__
182  b_vector_t current_species_ = {};
184  b_vector_t previous_species_ = {};
186  ODE_solver method_;
187 #endif
188 
189 #ifndef __ROOTCLING__
190  std::function<void(const b_vector_t&, b_vector_t&, real_t, Agent*)> rhs_;
191  std::function<void(const b_vector_t&, b_matrix_t&, real_t, b_vector_t&,
192  Agent*)>
193  jacob_;
194  std::function<void(const b_vector_t&, real_t, Agent*)> out_;
195 #endif
196 };
197 
198 } // namespace bdm
199 
200 #endif // USE_BOOST
201 
202 #endif // CORE_BEHAVIOR_REGULATORY_NETWORK_H_
#define BDM_BEHAVIOR_HEADER(class_name, base_class, class_version_id)
Inserts boilerplate code for behaviors with state.
Definition: behavior.h:130
static void Fatal(const std::string &location, const Args &... parts)
Prints fatal error message.
Definition: log.h:115
Definition: agent.cc:39
double real_t
Definition: real_t.h:21