libpspm
Solver Class Reference

#include <solver.h>

Collaboration diagram for Solver:
[legend]

Public Member Functions

 Solver (PSPM_SolverType _method, std::string ode_method="rk45ck")
 
void addSystemVariables (int _s)
 
void addSpecies (int _J, double _xb, double _xm, bool log_breaks, Species_Base *_mod, int n_extra_vars, double input_birth_flux=-1)
 
void addSpecies (std::vector< double > xbreaks, Species_Base *_mod, int n_extra_vars, double input_birth_flux=-1)
 
int n_species ()
 
void setEnvironment (EnvironmentBase *_env)
 
void resetState (double t0=0)
 
void resizeStateFromSpecies ()
 
void initialize ()
 
void copyStateToCohorts (std::vector< double >::iterator state_begin)
 
void copyCohortsToState ()
 
double maxSize ()
 
void updateEnv (double t, std::vector< double >::iterator S, std::vector< double >::iterator dSdt)
 
void calcRates_FMU (double t, std::vector< double >::iterator S, std::vector< double >::iterator dSdt)
 
void calcRates_iFMU (double t, std::vector< double >::iterator S, std::vector< double >::iterator dSdt)
 
void stepU_iFMU (double t, std::vector< double > &S, std::vector< double > &dSdt, double dt)
 
void calcRates_EBT (double t, std::vector< double >::iterator S, std::vector< double >::iterator dSdt)
 
void addCohort_EBT ()
 
void removeDeadCohorts_EBT ()
 
void calcRates_CM (double t, std::vector< double >::iterator S, std::vector< double >::iterator dSdt)
 
void addCohort_CM ()
 
void removeCohort_CM ()
 
template<typename AfterStepFunc >
void step_to (double tstop, AfterStepFunc &afterStep_user)
 
void step_to (double tstop)
 
double calcSpeciesBirthFlux (int k, double t)
 
std::vector< double > newborns_out (double t)
 
std::vector< double > u0_out (double t)
 
void print ()
 
template<typename wFunc >
double integrate_x (wFunc w, double t, int species_id)
 Computes the integral

\[I = \int_{x_b}^{x_m} w(z,t)u(z)dz\]

for the specified species. For details, see integrate_wudx_above. More...

 
template<typename wFunc >
double integrate_wudx_above (wFunc w, double t, double xlow, int species_id)
 Computes the partial integral

\[I = \int_{x_{low}}^{x_m} w(z,t)u(z)dz\]

for the specified species. More...

 
std::vector< double > getDensitySpecies_EBT (int k, std::vector< double > breaks)
 

Public Attributes

OdeSolver odeStepper
 
EnvironmentBaseenv
 
double current_time
 
std::vector< double > state
 
std::vector< double > rates
 
std::vector< Species_Base * > species_vec
 
struct {
   double   ode_eps = 1e-6
 
   double   ode_initial_step_size = 1e-6
 
   double   convergence_eps = 1e-6
 
   double   cm_grad_dx = 1e-6
 
   bool   update_cohorts = true
 
   int   max_cohorts = 500
 
   double   ebt_ucut = 1e-10
 
   double   ebt_grad_dx = 1e-6
 
   double   ode_rk4_stepsize = 0.1
 
   double   ode_ifmu_stepsize = 0.1
 
   bool   ifmu_centered_grids = true
 
   bool   integral_interpolate = true
 
control
 
bool use_log_densities = true
 

Private Attributes

PSPM_SolverType method
 
int n_statevars_internal = 0
 
int n_statevars_system = 0
 

Detailed Description

Definition at line 15 of file solver.h.

Constructor & Destructor Documentation

◆ Solver()

Solver::Solver ( PSPM_SolverType  _method,
std::string  ode_method = "rk45ck" 
)

Definition at line 37 of file solver.cpp.

37  : odeStepper(ode_method, 0, 1e-6, 1e-6) {
38  method = _method;
39 }
OdeSolver odeStepper
Definition: solver.h:23
PSPM_SolverType method
Definition: solver.h:17

Member Function Documentation

◆ addCohort_CM()

void Solver::addCohort_CM ( )

Definition at line 58 of file cm.cpp.

58  {
59  cout << ".......... add cohorts ...............\n";
60  updateEnv(current_time, state.begin(), rates.begin());
61 
62  for (int s = 0; s< species_vec.size(); ++s){
63  auto spp = species_vec[s];
64 
65  // calculate u for boundary cohort
66  double gb = spp->growthRate(-1, spp->xb, current_time, env);
67  double pe = spp->establishmentProbability(current_time, env);
68  if (spp->birth_flux_in < 0){
69  double birthFlux = calcSpeciesBirthFlux(s,current_time) * pe;
70  spp->set_ub(birthFlux/(gb+1e-20));
71  }
72  else{
73  spp->calc_boundary_u(gb, pe); // init density of boundary cohort
74  }
75 
76  spp->initBoundaryCohort(current_time, env); // init extra state variables and birth time of the boundary cohort
77  spp->addCohort(); // introduce copy of boundary cohort in system
78  }
79 
82 }
std::vector< double > state
Definition: solver.h:28
double current_time
Definition: solver.h:27
EnvironmentBase * env
Definition: solver.h:24
std::vector< double > rates
Definition: solver.h:29
void copyCohortsToState()
Definition: solver.cpp:297
void updateEnv(double t, std::vector< double >::iterator S, std::vector< double >::iterator dSdt)
Definition: solver.cpp:344
void resizeStateFromSpecies()
Definition: solver.cpp:132
std::vector< Species_Base * > species_vec
Definition: solver.h:31
double calcSpeciesBirthFlux(int k, double t)
Definition: solver.cpp:352
Here is the caller graph for this function:

◆ addCohort_EBT()

void Solver::addCohort_EBT ( )

Definition at line 70 of file ebt.cpp.

70  {
71 
72  for (auto spp : species_vec){
73  // 1. internalize the pi0-cohort (this cohort's birth time would have been already set when it was inserted)
74  // - get pi0, N0 from last cohort
75  double pi0 = spp->getX(spp->J-1);
76  double N0 = spp->getU(spp->J-1);
77 
78  // - update the recently internalized pi0-cohort with actual x0 value
79  double x0 = spp->xb + pi0/(N0+1e-12);
80  spp->setX(spp->J-1, x0);
81  spp->setU(spp->J-1, N0);
82 
83  // 2. insert a new cohort (copy of boundary cohort, to be the new pi0-cohort)
84  spp->initBoundaryCohort(current_time, env); // update initial extra state and birth-time of boundary cohort
85  spp->addCohort(); // introduce copy of boundary cohort into species
86 
87  // 3. set x,u of the new cohort to 0,0, thus marking it as the new pi0-cohort
88  spp->setX(spp->J-1, 0);
89  spp->setU(spp->J-1, 0);
90  }
91 
92  // 4. reset state from cohorts
95 
96 }
double current_time
Definition: solver.h:27
EnvironmentBase * env
Definition: solver.h:24
void copyCohortsToState()
Definition: solver.cpp:297
void resizeStateFromSpecies()
Definition: solver.cpp:132
std::vector< Species_Base * > species_vec
Definition: solver.h:31
Here is the caller graph for this function:

◆ addSpecies() [1/2]

void Solver::addSpecies ( int  _J,
double  _xb,
double  _xm,
bool  log_breaks,
Species_Base _mod,
int  n_extra_vars,
double  input_birth_flux = -1 
)

Definition at line 106 of file solver.cpp.

107  {
108  vector<double> xbreaks;
109  if (log_breaks) xbreaks = logseq(_xb, _xm, _J+1);
110  else xbreaks = seq(_xb, _xm, _J+1);
111 
112  addSpecies(xbreaks, s, n_extra_vars, input_birth_flux);
113 }
std::vector< double > logseq(double from, double to, int len)
Definition: solver.cpp:21
void addSpecies(int _J, double _xb, double _xm, bool log_breaks, Species_Base *_mod, int n_extra_vars, double input_birth_flux=-1)
Definition: solver.cpp:106
std::vector< double > seq(double from, double to, int len)
Definition: solver.cpp:15
Here is the call graph for this function:

◆ addSpecies() [2/2]

void Solver::addSpecies ( std::vector< double >  xbreaks,
Species_Base _mod,
int  n_extra_vars,
double  input_birth_flux = -1 
)

Definition at line 42 of file solver.cpp.

42  {
43  s->set_inputBirthFlux(input_birth_flux);
44  s->n_extra_statevars = n_extra_vars;
45 
46  if (method == SOLVER_FMU || method == SOLVER_IFMU){
47  std::sort(xbreaks.begin(), xbreaks.end(), std::less<double>()); // sort cohorts ascending for FMU
48  s->xb = *xbreaks.begin();
49  }
50  else {
51  std::sort(xbreaks.begin(), xbreaks.end(), std::greater<double>()); // sort cohorts descending for CM, EBT
52  s->xb = *xbreaks.rbegin();
53  }
54 
55  int J;
56  if (method == SOLVER_FMU) J = xbreaks.size()-1;
57  else if (method == SOLVER_IFMU) J = xbreaks.size()-1;
58  else if (method == SOLVER_MMU) J = xbreaks.size()-1;
59  else if (method == SOLVER_CM ) J = xbreaks.size();
60  else if (method == SOLVER_EBT) J = xbreaks.size();
61  else throw std::runtime_error("Unsupported method");
62 
63  s->x = xbreaks;
64  s->resize(J);
65 
66  // FMU has only 1 internal state variable (x), reset have 2 (x,u)
67  bool cond = (method == SOLVER_FMU || method == SOLVER_IFMU);
68  n_statevars_internal = (cond)? 1:2;
69 
70  int state_size = s->J*(n_statevars_internal + n_extra_vars); // x/u and extra vars
71 
72  //s->start_index = state.size(); // New species will be appended to the end of state vector
73  state.resize(state.size()+state_size); // This will resize state for all species additions, but this in only initialization so its okay.
74  rates.resize(rates.size()+state_size);
75 
76  species_vec.push_back(s);
77 
78  if (method == SOLVER_FMU){
79  s->X.resize(s->J);
80  for (size_t i=0; i<s->J; ++i) s->X[i] = (s->x[i]+s->x[i+1])/2.0;
81 
82  s->h.resize(s->J); // This will be used only by FMU
83  for (size_t i=0; i<s->J; ++i) s->h[i] = s->x[i+1] - s->x[i];
84  }
85 
86  if (method == SOLVER_IFMU){
87  s->X.resize(s->J);
88  s->h.resize(s->J); // This will be used only by FMU
89 
90  if (control.ifmu_centered_grids){ // grids are labelled by the grid center
91  for (size_t i=0; i<s->J; ++i) s->X[i] = (s->x[i]+s->x[i+1])/2.0;
92  for (size_t i=0; i<s->J; ++i) s->h[i] = s->x[i+1] - s->x[i];
93  // for centered grids, also set xb to X[0] rather than x[0].
94  s->xb = s->X[0];
95  }
96  else{ // grids are labelled by the lower edge (this ensures that recruitment happens exactly at xb)
97  for (size_t i=0; i<s->J; ++i) s->X[i] = s->x[i];
98  for (size_t i=0; i<s->J; ++i) s->h[i] = s->x[i+1] - s->x[i];
99  s->xb = s->X[0];
100  }
101  }
102 
103 }
std::vector< double > state
Definition: solver.h:28
int n_statevars_internal
Definition: solver.h:19
std::vector< double > rates
Definition: solver.h:29
PSPM_SolverType method
Definition: solver.h:17
std::vector< Species_Base * > species_vec
Definition: solver.h:31
struct Solver::@1 control
Here is the call graph for this function:

◆ addSystemVariables()

void Solver::addSystemVariables ( int  _s)

Definition at line 116 of file solver.cpp.

116  {
117  n_statevars_system = _s;
118  state.resize(state.size() + _s);
119  rates.resize(state.size() + _s);
120 }
std::vector< double > state
Definition: solver.h:28
int n_statevars_system
Definition: solver.h:20
std::vector< double > rates
Definition: solver.h:29

◆ calcRates_CM()

void Solver::calcRates_CM ( double  t,
std::vector< double >::iterator  S,
std::vector< double >::iterator  dSdt 
)

Definition at line 9 of file cm.cpp.

9  {
10 
11  //auto ss = species_vec[0];
12  //cout << "svec: " << t << " " << S[0] << " " << S[1] << " " << S[2] << " " << S[3] << "\n";
13  //cout << "coho: " << t << " " << ss->getX(0) << " " << ss->getU(0) << " " << ss->getX(1) << " " << ss->getU(1) << "\n";
14 
15  vector<double>::iterator its = S + n_statevars_system; // Skip system variables
16  vector<double>::iterator itr = dSdt + n_statevars_system;
17 
18  for (int s = 0; s<species_vec.size(); ++s){
19  Species_Base* spp = species_vec[s];
20  cout << "calcRates(species = " << s << ")\n";
21 
22  double pe = spp->establishmentProbability(t, env);
23  double gb = spp->growthRate(-1, spp->xb, t, env);
24  if (spp->birth_flux_in < 0){
25  double birthFlux = calcSpeciesBirthFlux(s,t) * pe;
26  spp->set_ub(birthFlux/(gb+1e-20));
27  }
28  else{
29  spp->calc_boundary_u(gb, pe); // this will set u in boundary cohort
30  }
31 
32 
33  for (int i=0; i<spp->J; ++i){
34  double x = spp->getX(i);
35  vector<double> g_gx = spp->growthRateGradient(i, x, t, env, control.cm_grad_dx); // FIXME: x can go
36  double dx = g_gx[0];
37  double du = -(spp->mortalityRate(i, x, t, env) + g_gx[1]);
38  if (!use_log_densities) du *= spp->getU(i);
39 
40  *itr++ = dx;
41  *itr++ = du;
42 
43  its+=2;
44  }
45 
46 
47  if (spp->n_extra_statevars > 0){
48  auto itr_prev = itr;
49  spp->getExtraRates(itr);
50  assert(distance(itr_prev, itr) == spp->n_extra_statevars*spp->J);
51  its += spp->n_extra_statevars*spp->J;
52  }
53  //cout << "---\n";
54  }
55 }
virtual double growthRate(int i, double x, double t, void *env)=0
virtual double getU(int i)=0
virtual void set_ub(double _ub)=0
int n_extra_statevars
Definition: species.h:21
virtual double getX(int i)=0
int n_statevars_system
Definition: solver.h:20
virtual void getExtraRates(std::vector< double >::iterator &it)=0
virtual double establishmentProbability(double t, void *env)=0
EnvironmentBase * env
Definition: solver.h:24
virtual double mortalityRate(int i, double x, double t, void *env)=0
bool use_log_densities
Definition: solver.h:49
double birth_flux_in
Definition: species.h:34
double xb
Definition: species.h:41
virtual double calc_boundary_u(double gb, double pe)=0
std::vector< Species_Base * > species_vec
Definition: solver.h:31
virtual std::vector< double > growthRateGradient(int i, double x, double t, void *env, double grad_dx)=0
struct Solver::@1 control
double calcSpeciesBirthFlux(int k, double t)
Definition: solver.cpp:352
Here is the call graph for this function:
Here is the caller graph for this function:

◆ calcRates_EBT()

void Solver::calcRates_EBT ( double  t,
std::vector< double >::iterator  S,
std::vector< double >::iterator  dSdt 
)

Definition at line 8 of file ebt.cpp.

8  {
9 
10  vector<double>::iterator its = S + n_statevars_system; // Skip system variables
11  vector<double>::iterator itr = dSdt + n_statevars_system;
12 
13  for (int s = 0; s < species_vec.size(); ++s){
14  Species_Base * spp = species_vec[s];
15 
16  double pi0 = spp->getX(spp->J-1); // last cohort is pi0, N0
17  double N0 = spp->getU(spp->J-1);
18  //std::cout << "pi = " << pi0 << ", N0 = " << N0 << "\n";
19 
20  std::vector<double> g_gx = spp->growthRateGradient(-1, spp->xb, t, env, control.ebt_grad_dx);
21  std::vector<double> m_mx = spp->mortalityRateGradient(-1, spp->xb, t, env, control.ebt_grad_dx);
22  //std::cout << "g = " << g_gx[0] << ", gx = " << g_gx[1] << "\n";
23  //std::cout << "m = " << m_mx[0] << ", mx = " << m_mx[1] << "\n";
24 
25  double mb = m_mx[0], mortGrad = m_mx[1], gb = g_gx[0], growthGrad = g_gx[1];
26 
27  double birthFlux;
28  double pe = spp->establishmentProbability(t, env);
29  if (spp->birth_flux_in < 0){
30  birthFlux = calcSpeciesBirthFlux(s,t) * pe;
31  }
32  else{
33  double u0 = spp->calc_boundary_u(gb, pe);
34  birthFlux = u0*gb;
35  }
36 
37  for (int i=0; i<spp->J-1; ++i){ // go down to the second last cohort (exclude boundary cohort)
38  double dx = spp->growthRate(i, spp->getX(i), t, env); // dx/dt
39  double du = -spp->mortalityRate(i, spp->getX(i), t, env) * spp->getU(i); // du/dt
40  //std::cout << "S/C = " << s << "/" << i << " " << spp->getX(i) << " " << dx << " " << du << "\n";
41  *itr++ = dx;
42  *itr++ = du;
43  its += 2;
44  }
45 
46  // dpi0/dt and dN0/dt
47  //std::cout << "S/C = " << s << "/" << "b" << " | pi0/N0 = " << pi0 << " " << N0;
48  //if (pi0 <= 0) pi0 = 1e-40;
49  //if (N0 <= 0) N0 = 1e-40;
50  double dN0 = -mb*N0 - mortGrad*pi0 + birthFlux;
51  double dpi0 = gb*N0 + growthGrad*pi0 - mb*pi0;
52  //std::cout << " | dpi0/dN0 = " << dpi0 << " " << dN0 << " | mx/gx/mb/gb = " << m_mx[1] << " " << g_gx[1] << " " << m_mx[0] << " " << g_gx[0] << "\n";
53  *itr++ = dpi0;
54  *itr++ = dN0;
55  its += 2;
56 
57  if (spp->n_extra_statevars > 0){
58  auto itr_prev = itr;
59  spp->getExtraRates(itr);
60  assert(distance(itr_prev, itr) == spp->n_extra_statevars*spp->J);
61  its += spp->n_extra_statevars*spp->J;
62  }
63 
64  }
65 
66 }
virtual double growthRate(int i, double x, double t, void *env)=0
virtual double getU(int i)=0
int n_extra_statevars
Definition: species.h:21
virtual double getX(int i)=0
virtual std::vector< double > mortalityRateGradient(int i, double x, double t, void *env, double grad_dx)=0
int n_statevars_system
Definition: solver.h:20
virtual void getExtraRates(std::vector< double >::iterator &it)=0
virtual double establishmentProbability(double t, void *env)=0
EnvironmentBase * env
Definition: solver.h:24
virtual double mortalityRate(int i, double x, double t, void *env)=0
double birth_flux_in
Definition: species.h:34
double xb
Definition: species.h:41
virtual double calc_boundary_u(double gb, double pe)=0
std::vector< Species_Base * > species_vec
Definition: solver.h:31
virtual std::vector< double > growthRateGradient(int i, double x, double t, void *env, double grad_dx)=0
struct Solver::@1 control
double calcSpeciesBirthFlux(int k, double t)
Definition: solver.cpp:352
Here is the call graph for this function:
Here is the caller graph for this function:

◆ calcRates_FMU()

void Solver::calcRates_FMU ( double  t,
std::vector< double >::iterator  S,
std::vector< double >::iterator  dSdt 
)

Definition at line 11 of file fmu.cpp.

11  {
12 
13  vector<double>::iterator its = S + n_statevars_system; // Skip system variables
14  vector<double>::iterator itr = dSdt + n_statevars_system;
15 
16  for (int s = 0; s<species_vec.size(); ++s){
17  Species_Base* spp = species_vec[s];
18 
19  // [S S S u u u u u a b c a b c a b c a b c a b c] <--- full SV for species is this
20  // ^ its, itr
21  double *U = &(*its); // Since FMU only has U in state, start of species is actually U
22  double *dUdt = &(*itr);
23  int J = spp->J; // xsize of species.
24  vector<double> &x = spp->x;
25  vector<double> &X = spp->X;
26  vector<double> &h = spp->h;
27 
28  vector <double> growthArray(J+1);
29  growthArray[0] = spp->growthRate(-1, x[0], t, env); // growth rate of boundary cohort
30  for (int i=1; i<J+1; ++i) growthArray[i] = spp->growthRateOffset(i-1, x[i], t, env);
31 
32  vector <double> u(J+1);
33 
34  // i=0
35  double pe = spp->establishmentProbability(t, env);
36  if (spp->birth_flux_in < 0){
37  double birthFlux = calcSpeciesBirthFlux(s,t) * pe;
38  u[0] = birthFlux/(growthArray[0]+1e-12); // Q: is this correct? or g(X0,env)? - A: It is g(xb,env) - growthArray[] indexes x, so (0) is xb. Hence correct.
39  }
40  else{
41  u[0] = spp->calc_boundary_u(growthArray[0], pe);
42  }
43 
44  // i=1 (calc u1 assuming linear u(x) in first interval)
45  u[1] = 2*U[0]-u[0]; // NOTE: for g(x) < 0 this can be calculated with upwind scheme
46 
47  for (int i=2; i<J-1; ++i){ // dU[i] ~ u[i+1] <-- U[i],U[i-1], u[i] <-- U[i-1],U[i-2]
48  if(growthArray[i] >=0){
49  double rMinus = ((U[i]-U[i-1])/(x[i]-x[i-1]))/((U[i-1]-U[i-2]+1e-12)/(x[i-1]-x[i-2]));
50  u[i] = U[i-1] + phi(rMinus)*(U[i-1]-U[i-2])*(x[i]-x[i-1])/(x[i+1]-x[i-1]);
51  }
52  else{
53  double rPlus = ((U[i]-U[i-1])/(x[i]-x[i-1]))/((U[i+1]-U[i]+1e-12)/(x[i+1]-x[i]));
54  u[i] = U[i] - phi(rPlus)*(U[i+1]-U[i])*(x[i+1]-x[i])/(x[i+2]-x[i]);
55  }
56  }
57 
58  u[J-1] = 2*U[J-2] - u[J-2]; // NOTE: for g(x) > 0 This can be calc with upwind scheme
59  u[J] = 2*U[J-1] - u[J-1];
60 
61  // [S S S u u u u u a b c a b c a b c a b c a b c] <--- full SV for species is this
62  // ^ itr, its. Therefore, advance 1 at a time while setting dUdt, and advance its by 3*5 after.
63  for (int i=0; i<spp->J; ++i){ // dU[i] ~ u[i+1] <-- U[i],U[i-1], u[i] <-- U[i-1],U[i-2]
64  dUdt[i] = -spp->mortalityRate(i,X[i], t, env)*U[i] - (growthArray[i+1]*u[i+1] - growthArray[i]*u[i])/h[i];
65  ++itr; ++its;
66  }
67  if (spp->n_extra_statevars > 0){
68  auto itr_prev = itr;
69  spp->getExtraRates(itr);
70  assert(distance(itr_prev, itr) == spp->n_extra_statevars*spp->J);
71  its += spp->n_extra_statevars*spp->J;
72  }
73 
74 
75  }
76 }
virtual double growthRate(int i, double x, double t, void *env)=0
double phi(double r)
Definition: fmu.cpp:6
std::vector< double > h
Definition: species.h:30
int n_extra_statevars
Definition: species.h:21
int n_statevars_system
Definition: solver.h:20
virtual void getExtraRates(std::vector< double >::iterator &it)=0
virtual double establishmentProbability(double t, void *env)=0
virtual double growthRateOffset(int i, double x, double t, void *env)=0
EnvironmentBase * env
Definition: solver.h:24
std::vector< double > x
Definition: species.h:29
virtual double mortalityRate(int i, double x, double t, void *env)=0
double birth_flux_in
Definition: species.h:34
virtual double calc_boundary_u(double gb, double pe)=0
std::vector< Species_Base * > species_vec
Definition: solver.h:31
std::vector< double > X
Definition: species.h:28
double calcSpeciesBirthFlux(int k, double t)
Definition: solver.cpp:352
Here is the call graph for this function:
Here is the caller graph for this function:

◆ calcRates_iFMU()

void Solver::calcRates_iFMU ( double  t,
std::vector< double >::iterator  S,
std::vector< double >::iterator  dSdt 
)

Definition at line 5 of file ifmu.cpp.

5  {
6  vector<double>::iterator its = S + n_statevars_system; // Skip system variables
7  vector<double>::iterator itr = dSdt + n_statevars_system;
8 
9  for (int s = 0; s<species_vec.size(); ++s){
10  auto spp = species_vec[s];
11 
12  its += spp->J;// skip u
13  for (int i=0; i<spp->J; ++i) *itr++ = 0; // set du/dt to 0
14 
15  if (spp->n_extra_statevars > 0){
16  auto itr_prev = itr;
17  spp->getExtraRates(itr); // TODO/FIXME: Does calc of extra rates need t and env?
18  assert(distance(itr_prev, itr) == spp->n_extra_statevars*spp->J);
19  its += spp->n_extra_statevars*spp->J;
20  }
21  }
22 
23 }
int n_statevars_system
Definition: solver.h:20
std::vector< Species_Base * > species_vec
Definition: solver.h:31
Here is the caller graph for this function:

◆ calcSpeciesBirthFlux()

double Solver::calcSpeciesBirthFlux ( int  k,
double  t 
)

Definition at line 352 of file solver.cpp.

352  {
353  std::cout << "calc birthFlux...\n";
354  auto spp = species_vec[k];
355  auto newborns_production = [this, spp](int i, double _t){
356  double b1 = spp->birthRate(i, spp->getX(i), _t, env);
357  return b1;
358  };
359  double birthFlux = integrate_x(newborns_production, t, k);
360  return birthFlux;
361 }
EnvironmentBase * env
Definition: solver.h:24
double integrate_x(wFunc w, double t, int species_id)
Computes the integral for the specified species. For details, see integrate_wudx_above.
std::vector< Species_Base * > species_vec
Definition: solver.h:31
Here is the call graph for this function:
Here is the caller graph for this function:

◆ copyCohortsToState()

void Solver::copyCohortsToState ( )

Definition at line 297 of file solver.cpp.

297  {
298  std::cout << "state <--- cohorts\n";
299  vector<double>::iterator it = state.begin() + n_statevars_system; // no need to copy system state
300 
301  for (int k=0; k<species_vec.size(); ++k){
302  Species_Base* s = species_vec[k];
303 
304  if (method == SOLVER_FMU || method == SOLVER_IFMU){
305  for (size_t i=0; i<s->J; ++i){
306  *it++ = s->getU(i);
307  }
308  }
309  if (method == SOLVER_CM){
310  for (size_t i=0; i<s->J; ++i){
311  double X = s->getX(i);
312  double U = s->getU(i);
313  U = (use_log_densities)? log(U) : U; // log(u) in state
314  *it++ = X; // set x to state
315  *it++ = U; // set u to state
316  }
317  }
318  if (method == SOLVER_EBT){
319  // x, u for boundary and internal cohorts
320  for (size_t i=0; i<s->J; ++i){
321  double X = s->getX(i);
322  double U = s->getU(i);
323  *it++ = X;
324  *it++ = U;
325  }
326  }
327 
328  if (s->n_extra_statevars > 0){ // If extra state variables have been requested, initialize them
329  auto it_prev = it;
331  assert(distance(it_prev, it) == s->n_extra_statevars*s->J);
332  }
333  }
334 }
std::vector< double > state
Definition: solver.h:28
virtual double getU(int i)=0
int n_extra_statevars
Definition: species.h:21
virtual double getX(int i)=0
int n_statevars_system
Definition: solver.h:20
virtual void copyCohortsExtraToState(std::vector< double >::iterator &it)=0
PSPM_SolverType method
Definition: solver.h:17
bool use_log_densities
Definition: solver.h:49
std::vector< Species_Base * > species_vec
Definition: solver.h:31
Here is the call graph for this function:

◆ copyStateToCohorts()

void Solver::copyStateToCohorts ( std::vector< double >::iterator  state_begin)

Definition at line 256 of file solver.cpp.

256  {
257  std::cout << "state ---> cohorts\n";
258  std::vector<double>::iterator it = state_begin + n_statevars_system; // no need to copy system state
259 
260  for (int k=0; k<species_vec.size(); ++k){
261  Species_Base* s = species_vec[k];
262 
263  s->set_xb(s->xb); // Important: "touch" boundary cohort to trigger a precompute. Note that setSize() triggers it.
264  if (method == SOLVER_FMU || method == SOLVER_IFMU){
265  for (size_t i=0; i<s->J; ++i){
266  s->setU(i,*it++);
267  }
268  }
269  if (method == SOLVER_CM){
270  for (size_t i=0; i<s->J; ++i){
271  double X = *it++; // get x from state
272  double U = *it++; // get u from state
273  U = (use_log_densities)? exp(U) : U; // u in cohorts
274  s->setX(i,X);
275  s->setU(i,U);
276  }
277  }
278  if (method == SOLVER_EBT){
279  // x, u for boundary and internal cohorts
280  for (size_t i=0; i<s->J; ++i){
281  double X = *it++;
282  double U = *it++;
283  s->setX(i,X);
284  s->setU(i,U);
285  }
286  }
287 
288  if (s->n_extra_statevars > 0){ // If extra state variables have been requested, initialize them
289  auto it_prev = it;
291  assert(distance(it_prev, it) == s->n_extra_statevars*s->J);
292  }
293  }
294 }
int n_extra_statevars
Definition: species.h:21
virtual void set_xb(double _xb)=0
int n_statevars_system
Definition: solver.h:20
PSPM_SolverType method
Definition: solver.h:17
bool use_log_densities
Definition: solver.h:49
virtual void setU(int i, double _u)=0
double xb
Definition: species.h:41
std::vector< Species_Base * > species_vec
Definition: solver.h:31
virtual void copyExtraStateToCohorts(std::vector< double >::iterator &it)=0
virtual void setX(int i, double _x)=0
Here is the call graph for this function:
Here is the caller graph for this function:

◆ getDensitySpecies_EBT()

std::vector< double > Solver::getDensitySpecies_EBT ( int  k,
std::vector< double >  breaks 
)

Definition at line 430 of file solver.cpp.

430  {
431  auto spp = species_vec[k];
432 
433  if (method == SOLVER_EBT){
434  double xm = spp->getX(0)+1e-6;
435 
436  vector<point> points(breaks.size()-1);
437 
438  // assuming breaks are sorted ascending
439  // cohorts are sorted descending
440  int current_interval = breaks.size()-2;
441  for (int i=0; i<spp->J; ++i){ // loop over all cohorts except boundary cohort
442  double x = spp->getX(i);
443  double N = spp->getU(i);
444  if (i == spp->J-1) x = spp->xb + x/(N+1e-12); // real-ize x if it's boundary cohort
445 
446  while(breaks[current_interval]>x) --current_interval; // decrement interval until x fits
447  //cout << current_interval << ", x = " << x << "(" << N << ") in [" << breaks[current_interval] << ", " << breaks[current_interval+1] << "]\n"; cout.flush();
448  if (N>0){
449  points[current_interval].abund += N;
450  points[current_interval].count += 1;
451  points[current_interval].xmean += N*x;
452  }
453  }
454 
455 
456  for (int i=0; i<points.size(); ++i) if (points[i].count>0) points[i].xmean /= points[i].abund;
457 
458  // remove 0-count points
459  auto pred = [this](const point& p) -> bool {
460  return p.count == 0;
461  };
462 
463  auto pend = std::remove_if(points.begin(), points.end(), pred);
464  points.erase(pend, points.end());
465 
466  //cout << "mean x and abund (removed):\n";
467  //for (int i=0; i<points.size(); ++i) cout << i << "\t" << points[i].count << "\t" << points[i].xmean << "\t" << points[i].abund << "\n";
468  //cout << "--\n";
469 
470  if (points.size() > 2){
471  vector<double> h(points.size());
472  h[0] = (points[1].xmean+points[0].xmean)/2 - spp->xb;
473  for (int i=1; i<h.size()-1; ++i) h[i] = (points[i+1].xmean - points[i-1].xmean)/2;
474  h[h.size()-1] = xm - (points[h.size()-1].xmean+points[h.size()-2].xmean)/2;
475 
476  vector <double> xx, uu;
477  xx.reserve(points.size());
478  uu.reserve(points.size());
479  for (int i=0; i<points.size(); ++i){
480  xx.push_back(points[i].xmean);
481  uu.push_back(points[i].abund / h[i]);
482  }
483 
484  Spline spl;
485  spl.splineType = Spline::LINEAR; //Spline::CONSTRAINED_CUBIC;
487  spl.set_points(xx, uu);
488 
489  vector <double> dens;
490  dens.reserve(points.size());
491  for (int i=0; i<breaks.size(); ++i){
492  dens.push_back(spl.eval(breaks[i]));
493  }
494 
495  return dens;
496  }
497  else return vector<double>(breaks.size(), 0);
498  }
499  else {
500  throw std::runtime_error("This function can only be called for the EBT solver");
501  }
502 
503 }
void set_points(const Container &x, const Container &y)
Definition: cubic_spline.h:139
Extr extrapolate
Definition: cubic_spline.h:128
Float eval(Float x) const
Definition: cubic_spline.h:268
PSPM_SolverType method
Definition: solver.h:17
Type splineType
Definition: cubic_spline.h:126
std::vector< Species_Base * > species_vec
Definition: solver.h:31
Here is the call graph for this function:

◆ initialize()

void Solver::initialize ( )

Definition at line 194 of file solver.cpp.

194  {
195 
196  vector<double>::iterator it = state.begin() + n_statevars_system; // TODO: replace with init_sState()
197 
198  for (int k=0; k<species_vec.size(); ++k){
199  Species_Base* s = species_vec[k];
200 
201  // Boundary cohort is not in state, but used as a reference.
202  s->set_xb(s->xb); // set x of boundary cohort
203  s->set_ub(0); // set initial density of boundary cohort to 0.
204 
205  // set birth time for each cohort to current_time
206  for (int i=0; i<s->J; ++i) s->set_birthTime(i, current_time);
207 
208  // set x, u for all cohorts
209  if (method == SOLVER_FMU || method == SOLVER_IFMU){
210  for (size_t i=0; i<s->J; ++i){
211  double X = s->X[i]; // for FMU, X is the midpoint of the cell edges
212  double U = s->init_density(i, X, env);
213  s->setX(i,X);
214  s->setU(i,U);
215  *it++ = U; // u in state (only)
216  }
217  }
218  if (method == SOLVER_CM){
219  for (size_t i=0; i<s->J; ++i){
220  double X = s->x[i];
221  double U = s->init_density(i, X, env);
222  s->setX(i,X);
223  s->setU(i,U);
224  *it++ = X; // x in state
225  *it++ = (use_log_densities)? log(U) : U; // u in state
226  }
227  }
228  if (method == SOLVER_EBT){
229  // x, u for internal cohorts in state and it cohorts
230  for (size_t i=0; i<s->J-1; ++i){
231  double X = (s->x[i]+s->x[i+1])/2.0;
232  double U = s->init_density(i, X, env)*(s->x[i]-s->x[i+1]);
233  s->setX(i,X);
234  s->setU(i,U);
235  *it++ = X; // x in state
236  *it++ = U; // u in state
237  }
238  // set pi0, N0 as x, u for the last cohort. This scheme allows using this last cohort with xb+pi0 in integrals etc
239  *it++ = 0; *it++ = 0;
240  s->setX(s->J-1,0); // TODO: should this be set to xb for init_state and set to 0 again later? maybe not, as init_state is not expected to be x dependent
241  s->setU(s->J-1,0);
242  }
243 
244  // initialize extra state for each cohort and copy it to state
246  //if (s->n_extra_statevars > 0){ // FIXME: maybe redundant
247  //auto it_prev = it;
248  //s->init_ExtraState(it); // this also inits the extra state of boundary cohort, but without advancing the iterator
249  //assert(distance(it_prev, it) == s->n_extra_statevars*s->J);
250  //}
251 
252  }
253 }
virtual double init_density(int i, double x, void *env)=0
std::vector< double > state
Definition: solver.h:28
virtual void set_ub(double _ub)=0
virtual void set_xb(double _xb)=0
double current_time
Definition: solver.h:27
int n_statevars_system
Definition: solver.h:20
virtual void initAndCopyExtraState(double t, void *env, std::vector< double >::iterator &it)=0
EnvironmentBase * env
Definition: solver.h:24
std::vector< double > x
Definition: species.h:29
virtual void set_birthTime(int i, double t0)=0
PSPM_SolverType method
Definition: solver.h:17
bool use_log_densities
Definition: solver.h:49
virtual void setU(int i, double _u)=0
double xb
Definition: species.h:41
std::vector< Species_Base * > species_vec
Definition: solver.h:31
virtual void setX(int i, double _x)=0
std::vector< double > X
Definition: species.h:28
Here is the call graph for this function:

◆ integrate_wudx_above()

template<typename wFunc >
double Solver::integrate_wudx_above ( wFunc  w,
double  t,
double  xlow,
int  species_id 
)

Computes the partial integral

\[I = \int_{x_{low}}^{x_m} w(z,t)u(z)dz\]

for the specified species.

Parameters
wA function or function-object of the form w(int i, double t) that returns a double. It can be a lambda. This function should access the 'i'th cohort and compute the weight from the cohort's properties. The function w should be able access to the Solver in order to access cohorts.
tThe current time (corresponding to the current physiological state). This will be passed to w to allow the weights to be a direct function of time.
xlowThe lower limit of the integral
species_idThe id of the species for which the integral should be computed
size_integral.png

the computation of this integral depends on the solver method. For different solvers, the integral is defined as follows:

FMU: \(\quad I = \sum_{i=i_0}^J h_i w_i u_i\)

EBT: \(\quad I = \sum_{i=i_0}^J w_i N_i\), with \(x_0 = x_b + \pi_0/N_0\)

CM : \(\quad I = \sum_{i=i_0}^J h_i (w_{i+1}u_{i+1}+w_i u_i)/2\)

where \(i_0 = \text{argmax}(x_i \le x_{low})\), \(h_i = x_{i+1}-x_i\), and \(w_i = w(x_i)\).

If interpolation is turned on, \(h_{i_0}=x_{i_0+1}-x_{low}\), whereas \(u(x_{low})\) is set to \(u(x_{i_0})\) in FMU and calculated by bilinear interpolation in CM (See Figure). Interpolation does not play a role in EBT.

In the CM method, the density of the boundary cohort is obtained from the boundary condition of the PDE: \(u_b=B/g(x_b)\), where \(B\) is the input flux of newborns. In the current implementation of the CM method, \(B\) must be set to a constant. In future implementations which may allow real-time calculation of \(B\), \(u_b\) must be calculated recurvisely by solving \(u_b = B(u_b)/g(x_b)\), where \(B(u_b) = \int_{x_b}^{x_m} f(x)u(x)dx\).

Definition at line 44 of file size_integrals.tpp.

44  {
45 
46  Species_Base* spp = species_vec[species_id];
47 
48  // cohorts are inserted at the end, hence sorted in descending order
49  // FIXME: should there be an optional "sort_cohorts" control parameter? Maybe some freak models are such that cohorts dont remain in sorted order?
50  if (method == SOLVER_CM){
51  // integrate using trapezoidal rule
52  // Note, new cohorts are inserted at the end, so x will be descending
53  bool integration_completed = false;
54  double I = 0;
55  double u_hi = spp->getU(0);
56  double x_hi = spp->getX(0);
57  double f_hi = w(0, t)*u_hi;
58 
59  for (int i=1; i<spp->J; ++i){ // going from high ----> low
60  double u_lo = spp->getU(i);
61  double x_lo = spp->getX(i);
62  double f_lo = w(i, t)*u_lo;
63 
64  if (x_lo <= xlow){ // check if xlow falls within the current interval.
65  // * if interpolation is on, stop exactly at xlow, else take the full interval
66  double f = (control.integral_interpolate)? f_lo + (f_hi-f_lo)/(x_hi-x_lo)*(xlow - x_lo) : f_lo;
67  double x = (control.integral_interpolate)? xlow : x_lo;
68  I += (x_hi - x) * (f_hi + f);
69  integration_completed = true;
70  }
71  else{
72  I += (x_hi - x_lo) * (f_hi + f_lo);
73  }
74 
75  x_hi = x_lo;
76  f_hi = f_lo;
77  if (integration_completed) break;
78  }
79 
80  //if (integration_completed) assert(x_hi < xlow);
81  //if (!integration_completed) assert(x_hi >= xlow || spp.J == 1);
82 
83  // if integration has not completed, continue to the boundary interval
84  if (spp->J == 1 || !integration_completed){
85  // boundary at xb
86  double u0 = spp->get_boundary_u();
87  double x_lo = spp->xb;
88  if (x_hi > x_lo){
89  double f_lo = w(-1, t)*u0; // -1 is boundary cohort
90  double f = (control.integral_interpolate)? f_lo + (f_hi-f_lo)/(x_hi-x_lo)*(xlow - x_lo) : f_lo;
91  double x = (control.integral_interpolate)? xlow : x_lo;
92  I += (x_hi-x)*(f_hi+f);
93  }
94  }
95 
96  return I*0.5;
97  }
98 
99  else if (method == SOLVER_FMU || method == SOLVER_IFMU){
100  //if (xlow < spp->xb) throw std::runtime_error("integral lower bound must be >= xb");
101  if (xlow > spp->x[spp->J]) return 0; // if xlow is above the maximum size, integral is 0
102 
103  // integrate using midpoint quadrature rule
104  double I=0;
105  for (int i=spp->J-1; i>=0; --i){ // in FMU, cohorts are sorted ascending
106  if (spp->x[i] <= xlow){ // check if last interval is reached
107  double h = (control.integral_interpolate)? spp->x[i+1]-xlow : spp->h[i];
108  I += h * w(i,t) * spp->getU(i);
109  break;
110  }
111  else{
112  I += spp->h[i] * w(i,t) * spp->getU(i);
113  }
114  }
115 
116  return I;
117  }
118 
119  else if (method == SOLVER_EBT){
120  // set up cohorts to integrate
121  // backup pi0, N0 from last (youngest) cohort <-- cohorts are sorted descending
122  double pi0 = spp->getX(spp->J-1);
123  double N0 = spp->getU(spp->J-1);
124 
125  // real-ize pi0-cohort with actual x0 value
126  double x0 = spp->xb + pi0/(N0+1e-12);
127  spp->setX(spp->J-1, x0);
128 
129  // calculate integral
130  double I = 0;
131  for (int i=0; i<spp->J; ++i){ // in EBT, cohorts are sorted descending
132  if (spp->getX(i) < xlow) break; // if X == xlow, we still include it in the intgral
133  else I += w(i, t)*spp->getU(i);
134  }
135 
136  // restore the original pi0-cohort
137  spp->setX(spp->J-1, pi0);
138 
139  return I;
140  }
141 
142  else{
143  throw std::runtime_error("Unsupported solver method");
144  }
145 }
virtual double get_boundary_u()=0
std::vector< double > h
Definition: species.h:30
virtual double getU(int i)=0
virtual double getX(int i)=0
std::vector< double > x
Definition: species.h:29
PSPM_SolverType method
Definition: solver.h:17
double xb
Definition: species.h:41
std::vector< Species_Base * > species_vec
Definition: solver.h:31
virtual void setX(int i, double _x)=0
struct Solver::@1 control
Here is the call graph for this function:

◆ integrate_x()

template<typename wFunc >
double Solver::integrate_x ( wFunc  w,
double  t,
int  species_id 
)

Computes the integral

\[I = \int_{x_b}^{x_m} w(z,t)u(z)dz\]

for the specified species. For details, see integrate_wudx_above.

Definition at line 156 of file size_integrals.tpp.

156  {
157  Species_Base* spp = species_vec[species_id];
158 
159  if (method == SOLVER_FMU || method == SOLVER_IFMU){
160  // integrate using midpoint quadrature rule
161  double I=0;
162  for (unsigned int i=0; i<spp->J; ++i){
163  I += spp->h[i]*w(i, t)*spp->getU(i); // TODO: Replace with std::transform after profiling
164  }
165  return I;
166  }
167 
168  else if (method == SOLVER_EBT){
169  // integrate using EBT rule (sum over cohorts)
170 
171  // backup pi0, N0 from last cohort
172  double pi0 = spp->getX(spp->J-1);
173  double N0 = spp->getU(spp->J-1);
174 
175  // real-ize pi0-cohort with actual x0 value
176  double x0 = spp->xb + pi0/(N0+1e-12);
177  spp->setX(spp->J-1, x0);
178 
179  // calculate integral
180  double I = 0;
181  for (int i=0; i<spp->J; ++i) I += w(i, t)*spp->getU(i);
182 
183  // restore the original pi0-cohort
184  spp->setX(spp->J-1, pi0);
185 
186  return I;
187  }
188 
189  if (method == SOLVER_CM){
190  // integrate using trapezoidal rule
191  // Note, new cohorts are inserted at the beginning, so x will be ascending
192  double I = 0;
193  double u_hi = spp->getU(0);
194  double x_hi = spp->getX(0);
195  double f_hi = w(0, t)*u_hi;
196 
197  for (int i=1; i<spp->J; ++i){
198  double u_lo = spp->getU(i);
199  double x_lo = spp->getX(i);
200  double f_lo = w(i, t)*u_lo;
201 
202  I += (x_hi - x_lo) * (f_hi + f_lo);
203  x_hi = x_lo;
204  f_hi = f_lo;
205  }
206 
207  // boundary at xb
208  double u0 = spp->get_boundary_u();
209  double x_lo = spp->xb;
210  double f_lo = w(-1, t)*u0; // -1 is boundary cohort
211  I += (x_hi-x_lo)*(f_hi+f_lo);
212 
213  return I*0.5;
214  }
215 
216  else{
217  throw std::runtime_error("Unsupported solver method");
218  }
219 }
virtual double get_boundary_u()=0
std::vector< double > h
Definition: species.h:30
virtual double getU(int i)=0
virtual double getX(int i)=0
PSPM_SolverType method
Definition: solver.h:17
double xb
Definition: species.h:41
std::vector< Species_Base * > species_vec
Definition: solver.h:31
virtual void setX(int i, double _x)=0
Here is the call graph for this function:
Here is the caller graph for this function:

◆ maxSize()

double Solver::maxSize ( )

Definition at line 158 of file solver.cpp.

158  {
159  double maxsize = 0;
160  for (auto spp : species_vec) maxsize = std::max(maxsize, spp->get_maxSize());
161  return maxsize;
162 }
std::vector< Species_Base * > species_vec
Definition: solver.h:31

◆ n_species()

int Solver::n_species ( )

Definition at line 153 of file solver.cpp.

153  {
154  return species_vec.size();
155 }
std::vector< Species_Base * > species_vec
Definition: solver.h:31

◆ newborns_out()

vector< double > Solver::newborns_out ( double  t)

Definition at line 364 of file solver.cpp.

364  { // TODO: make recompute env optional
365  // update Environment from latest state
366  //copyStateToCohorts(state.begin()); // not needed here because this is done in afterStep or upon cohorts update
367  //env->computeEnv(t, this, state.begin(), rates.begin());
368  updateEnv(t, state.begin(), rates.begin()); // this will trigger a precompute
369 // for (int k = 0; k<species_vec.size(); ++k) preComputeSpecies(k,t);
370 
371  vector<double> b_out;
372  for (int k=0; k<species_vec.size(); ++k){
373  // calculate birthflux
374  // [solved] wudx doesnt work here. Why?? - works now, no idea why it was not working earlier!
375  //auto newborns_production = [this, k](int i, double t){
376  //double z = species_vec[k]->getX(i);
378  //double b = species_vec[k]->birthRate(i,z,t,env);
380  //return b;
381  //};
382  //double birthFlux = integrate_x(newborns_production, t, k);
383  //double birthFlux = integrate_wudx_above(newborns_production, t, 0, k);
384  double birthFlux = calcSpeciesBirthFlux(k, t);
385  b_out.push_back(birthFlux);
386  }
387  return b_out;
388 }
std::vector< double > state
Definition: solver.h:28
std::vector< double > rates
Definition: solver.h:29
void updateEnv(double t, std::vector< double >::iterator S, std::vector< double >::iterator dSdt)
Definition: solver.cpp:344
std::vector< Species_Base * > species_vec
Definition: solver.h:31
double calcSpeciesBirthFlux(int k, double t)
Definition: solver.cpp:352
Here is the call graph for this function:
Here is the caller graph for this function:

◆ print()

void Solver::print ( )

Definition at line 167 of file solver.cpp.

167  {
168  std::cout << ">> SOLVER \n";
169  string types[] = {"FMU", "MMU", "CM", "EBT", "Implicit FMU"};
170  std::cout << "+ Type: " << types[method] << std::endl;
171 
172  std::cout << "+ State size = " << state.size() << "\n";
173  std::cout << "+ Rates size = " << rates.size() << "\n";
174  std::cout << "+ Species:\n";
175  std::cout.flush();
176  for (int i=0; i<species_vec.size(); ++i) {
177  std::cout << "Sp (" << i << "):\n";
178  species_vec[i]->print();
179  }
180 
181 }
std::vector< double > state
Definition: solver.h:28
std::vector< double > rates
Definition: solver.h:29
PSPM_SolverType method
Definition: solver.h:17
std::vector< Species_Base * > species_vec
Definition: solver.h:31

◆ removeCohort_CM()

void Solver::removeCohort_CM ( )

Definition at line 85 of file cm.cpp.

85  {
86 
87  for (auto& spp : species_vec){
88  if (spp->J > control.max_cohorts) // remove a cohort if number of cohorts in the species exceeds a threshold
89  spp->removeDensestCohort();
90  }
91 
94  cout << "........................................\n";
95 
96 }
void copyCohortsToState()
Definition: solver.cpp:297
void resizeStateFromSpecies()
Definition: solver.cpp:132
std::vector< Species_Base * > species_vec
Definition: solver.h:31
struct Solver::@1 control
Here is the caller graph for this function:

◆ removeDeadCohorts_EBT()

void Solver::removeDeadCohorts_EBT ( )

Definition at line 99 of file ebt.cpp.

99  {
100 
101  for (auto spp : species_vec){
102  spp->removeDeadCohorts(control.ebt_ucut);
103  }
104 
107 
108 }
void copyCohortsToState()
Definition: solver.cpp:297
void resizeStateFromSpecies()
Definition: solver.cpp:132
std::vector< Species_Base * > species_vec
Definition: solver.h:31
struct Solver::@1 control
Here is the caller graph for this function:

◆ resetState()

void Solver::resetState ( double  t0 = 0)

Definition at line 123 of file solver.cpp.

123  { // FIXME: This is currently redundant, and needs to be improved with reset of both state and cohorts for a true reset of state
124  current_time = t0;
125  odeStepper.reset(t0, control.ode_eps, control.ode_eps); // = RKCK45<vector<double>> (0, control.ode_eps, control.ode_initial_step_size); // this is a cheap operation, but this will empty the internal containers, which will then be (automatically) resized at next 1st ODE step. Maybe add a reset function to the ODE stepper?
126 
127  std::fill(state.begin(), state.end(), 0);
128  std::fill(rates.begin(), rates.end(), -999); // DEBUG
129 }
std::vector< double > state
Definition: solver.h:28
void reset(double t_start, double rtol, double atol)
Definition: ode_solver.h:42
double current_time
Definition: solver.h:27
std::vector< double > rates
Definition: solver.h:29
OdeSolver odeStepper
Definition: solver.h:23
struct Solver::@1 control
Here is the call graph for this function:

◆ resizeStateFromSpecies()

void Solver::resizeStateFromSpecies ( )

Definition at line 132 of file solver.cpp.

132  {
133  int state_size_new = n_statevars_system;
134  for (auto& spp : species_vec){
135  state_size_new += spp->J*(n_statevars_internal + spp->n_extra_statevars);
136  }
137 
138  state.resize(state_size_new, -999);
139  rates.resize(state_size_new, -999);
140 }
std::vector< double > state
Definition: solver.h:28
int n_statevars_internal
Definition: solver.h:19
int n_statevars_system
Definition: solver.h:20
std::vector< double > rates
Definition: solver.h:29
std::vector< Species_Base * > species_vec
Definition: solver.h:31

◆ setEnvironment()

void Solver::setEnvironment ( EnvironmentBase _env)

Definition at line 143 of file solver.cpp.

143  {
144  env = _env;
145 }
EnvironmentBase * env
Definition: solver.h:24

◆ step_to() [1/2]

template<typename AfterStepFunc >
void Solver::step_to ( double  tstop,
AfterStepFunc &  afterStep_user 
)
Parameters
tstopThe time until which the ODE solver should be stepped. The stepper will stop exactly at tstop, for which the final step size is truncated if necessary.
afterStep_userA function of the form f(double t) to be called after every successful ODE step.
ode_flow.png
Note
1. current_time is updated by the ODE solver at every (internal) step
2. After the last ODE step, the state vector is updated but cohorts still hold an intenal ODE state (y+k5*h etc). normally, this will not be a problem because state will be copied to cohorts before rates call of the next timestep. But since add/remove cohort after step_to will rewrite the state from cohorts, the updated state vector will be lost. To avoid this, we should ensure that the state is copied to cohorts after every successful ODE step (or at least after completion of step_to). This is achieved by the afterStep function

Definition at line 15 of file solver.tpp.

15  {
16  // do nothing if tstop is <= current_time
17  if (tstop <= current_time) return;
18 
19  auto after_step = [this, afterStep_user](double t, std::vector<double>::iterator S){
20  std::cout << "After step: t = " << t << "\n";
22  afterStep_user(t);
23  };
24 
25 
26  if (method == SOLVER_FMU){
27  auto derivs = [this](double t, std::vector<double>::iterator S, std::vector<double>::iterator dSdt, void* params){
29  updateEnv(t, S, dSdt);
30  calcRates_FMU(t, S, dSdt);
31  };
32 
33  // integrate
34  odeStepper.step_to(tstop, current_time, state, derivs, after_step); // rk4_stepsize is only used if method is "rk4"
35  }
36 
37 
38  if (method == SOLVER_IFMU){
39  while (current_time < tstop){
40  double dt = std::min(control.ode_ifmu_stepsize, tstop-current_time);
41 
42  //copyStateToCohorts(state.begin()); // not needed here because it is called by the odestepper below
43  updateEnv(current_time, state.begin(), rates.begin());
44  std::vector<double> rates_prev(rates.begin(), rates.begin()+n_statevars_system); // save system variable rates
45 
46  // use implicit stepper to advance u
48  // current_time += dt; // not needed here, as current time is advanced by the ODE stepper below.
49 
50  if (n_statevars_system > 0){
51  copyStateToCohorts(state.begin()); // copy updated u to cohorts
52  updateEnv(current_time, state.begin(), rates.begin()); // recompute env with updated u
53  // FIXME: use fully implicit stepper here?
54  for (int i=0; i<n_statevars_system; ++i){
55  state[i] += (rates_prev[i]+rates[i])/2*dt; // use average of old and updated rates for stepping system vars
56  }
57  }
58 
59  // use the ODE-stepper for other state variables
60  // this stepper is called even if there are no extra state variables, so copyStateToCohorts is accomplished here
61  auto derivs = [this](double t, std::vector<double>::iterator S, std::vector<double>::iterator dSdt, void* params){
63  // precompute and env computation is not needed here, because it depends on x and u, which are not updated by the solver.
64  calcRates_iFMU(t,S,dSdt);
65  };
66  // this step below will do afterstep. FIXME: But what if there are no extra state variables?
67  odeStepper.step_to(current_time+dt, current_time, state, derivs, after_step); // rk4_stepsize is only used if method is "rk4"
68 
69  }
70 
71  }
72 
73  if (method == SOLVER_EBT){
74  auto derivs = [this](double t, std::vector<double>::iterator S, std::vector<double>::iterator dSdt, void* params){
76  updateEnv(t, S, dSdt);
77  calcRates_EBT(t, S, dSdt);
78  };
79 
80  // integrate
81  odeStepper.step_to(tstop, current_time, state, derivs, after_step); // rk4_stepsize is only used if method is "rk4"
82 
83  // update cohorts
85  addCohort_EBT(); // Add new cohort if N0 > 0. Add after removing dead ones otherwise this will also be removed.
86  }
87 
88 
89  if (method == SOLVER_CM){
90  auto derivs = [this](double t, std::vector<double>::iterator S, std::vector<double>::iterator dSdt, void* params){
91  std::cout << "derivs()\n";
92  copyStateToCohorts(S); // this triggers precompute
93  updateEnv(t, S, dSdt);
94  calcRates_CM(t, S, dSdt);
95  };
96 
97  // integrate
98  odeStepper.step_to(tstop, current_time, state, derivs, after_step); // rk4_stepsize is only used if method is "rk4"
99 
100  // update cohorts
101  if (control.update_cohorts){
102  addCohort_CM(); // add before so that it becomes boundary cohort and first internal cohort can be (potentially) removed
103  removeCohort_CM();
104  }
105  //env->computeEnv(current_time, this); // is required here IF rescaleEnv is used in derivs
106  }
107 }
void calcRates_FMU(double t, std::vector< double >::iterator S, std::vector< double >::iterator dSdt)
Definition: fmu.cpp:11
void removeCohort_CM()
Definition: cm.cpp:85
std::vector< double > state
Definition: solver.h:28
void removeDeadCohorts_EBT()
Definition: ebt.cpp:99
void stepU_iFMU(double t, std::vector< double > &S, std::vector< double > &dSdt, double dt)
Definition: ifmu.cpp:25
double current_time
Definition: solver.h:27
int n_statevars_system
Definition: solver.h:20
void copyStateToCohorts(std::vector< double >::iterator state_begin)
Definition: solver.cpp:256
void calcRates_iFMU(double t, std::vector< double >::iterator S, std::vector< double >::iterator dSdt)
Definition: ifmu.cpp:5
std::vector< double > rates
Definition: solver.h:29
OdeSolver odeStepper
Definition: solver.h:23
PSPM_SolverType method
Definition: solver.h:17
void updateEnv(double t, std::vector< double >::iterator S, std::vector< double >::iterator dSdt)
Definition: solver.cpp:344
void calcRates_EBT(double t, std::vector< double >::iterator S, std::vector< double >::iterator dSdt)
Definition: ebt.cpp:8
void addCohort_EBT()
Definition: ebt.cpp:70
void step_to(double t_stop, double &t, std::vector< double > &y, Functor &derivs, AfterStep &after_step)
Definition: ode_solver.h:60
void calcRates_CM(double t, std::vector< double >::iterator S, std::vector< double >::iterator dSdt)
Definition: cm.cpp:9
struct Solver::@1 control
void addCohort_CM()
Definition: cm.cpp:58
Here is the call graph for this function:
Here is the caller graph for this function:

◆ step_to() [2/2]

void Solver::step_to ( double  tstop)

Definition at line 338 of file solver.cpp.

338  {
339  auto func = [](double t){};
340  step_to(tstop, func);
341 }
void step_to(double tstop, AfterStepFunc &afterStep_user)
Definition: solver.tpp:15
Here is the call graph for this function:

◆ stepU_iFMU()

void Solver::stepU_iFMU ( double  t,
std::vector< double > &  S,
std::vector< double > &  dSdt,
double  dt 
)

Definition at line 25 of file ifmu.cpp.

25  {
26 
27  vector<double>::iterator its = S.begin() + n_statevars_system; // Skip system variables
28 
29  // 1. Take implicit step for U
30  for (int s = 0; s<species_vec.size(); ++s){
31  Species_Base* spp = species_vec[s];
32 
33  // [S S S u u u u u a b c a b c a b c a b c a b c] <--- full SV for species is this
34  // ^ its, itr
35  double *U = &(*its); // Since FMU only has U in state, start of species is actually U
36  int J = spp->J; // xsize of species.
37  vector<double> &h = spp->h;
38 
39  vector <double> growthArray(J);
40  for (int i=0; i<J; ++i) growthArray[i] = spp->growthRate(i, spp->getX(i), t, env);
41 
42  double birthFlux;
43  double pe = spp->establishmentProbability(t, env);
44  if (spp->birth_flux_in < 0){
45  birthFlux = calcSpeciesBirthFlux(s,t) * pe;
46  }
47  else{
48  birthFlux = spp->calc_boundary_u(growthArray[0], pe)*growthArray[0];
49  }
50 
51  //cout << t << "\t" << birthFlux/growthArray[0] << " -> " << calcSpeciesBirthFlux(s,t)/growthArray[0] << "\n";
52  double B0 = 1 + dt/h[0]*growthArray[0] + dt*spp->mortalityRate(0, spp->getX(0), t, env);
53 // std::cout << "B0 = " << B0 << endl;
54  double C0 = spp->getU(0) + dt/h[0]*birthFlux;
55  U[0] = C0/B0;
56 // std::cout << "U0 = " << U[0] << endl;
57 
58  for (int w = 1; w < J; ++w){
59  double Aw = -growthArray[w-1]*dt/h[w];
60  double Bw = 1 + dt/h[w]*growthArray[w] + dt*spp->mortalityRate(w, spp->getX(w), t, env);
61  double Cw = spp->getU(w);
62 
63  U[w] = (Cw - Aw*U[w-1])/Bw;
64  }
65 
66  its += J*(1+spp->n_extra_statevars);
67 
68  }
69 
70 }
virtual double growthRate(int i, double x, double t, void *env)=0
std::vector< double > h
Definition: species.h:30
virtual double getU(int i)=0
int n_extra_statevars
Definition: species.h:21
virtual double getX(int i)=0
int n_statevars_system
Definition: solver.h:20
virtual double establishmentProbability(double t, void *env)=0
EnvironmentBase * env
Definition: solver.h:24
virtual double mortalityRate(int i, double x, double t, void *env)=0
double birth_flux_in
Definition: species.h:34
virtual double calc_boundary_u(double gb, double pe)=0
std::vector< Species_Base * > species_vec
Definition: solver.h:31
double calcSpeciesBirthFlux(int k, double t)
Definition: solver.cpp:352
Here is the call graph for this function:
Here is the caller graph for this function:

◆ u0_out()

vector< double > Solver::u0_out ( double  t)

Definition at line 391 of file solver.cpp.

391  {
392  vector <double> u0out;
393  vector <double> newbornsout = newborns_out(t);
394  for (int k=0; k < species_vec.size(); ++k){
395  //species_vec[k]->preCompute(-1, t, env); // not req because precomputeAllCohorts called in newborns_out() precomputes BC too.
396  u0out.push_back(newbornsout[k]/species_vec[k]->growthRate(-1, species_vec[k]->xb, t, env));
397  }
398  return u0out;
399 }
EnvironmentBase * env
Definition: solver.h:24
std::vector< double > newborns_out(double t)
Definition: solver.cpp:364
std::vector< Species_Base * > species_vec
Definition: solver.h:31
Here is the call graph for this function:

◆ updateEnv()

void Solver::updateEnv ( double  t,
std::vector< double >::iterator  S,
std::vector< double >::iterator  dSdt 
)

Definition at line 344 of file solver.cpp.

344  {
345  std::cout << "update Env...\n";
346  for (auto spp : species_vec) spp->triggerPreCompute();
347  env->computeEnv(t, this, S, dSdt);
348 }
virtual void computeEnv(double t, Solver *sol, std::vector< double >::iterator S, std::vector< double >::iterator dSdt)=0
EnvironmentBase * env
Definition: solver.h:24
std::vector< Species_Base * > species_vec
Definition: solver.h:31
Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ cm_grad_dx

double Solver::cm_grad_dx = 1e-6

Definition at line 37 of file solver.h.

◆ control

struct { ... } Solver::control

◆ convergence_eps

double Solver::convergence_eps = 1e-6

Definition at line 36 of file solver.h.

◆ current_time

double Solver::current_time

Definition at line 27 of file solver.h.

◆ ebt_grad_dx

double Solver::ebt_grad_dx = 1e-6

Definition at line 41 of file solver.h.

◆ ebt_ucut

double Solver::ebt_ucut = 1e-10

Definition at line 40 of file solver.h.

◆ env

EnvironmentBase* Solver::env

Definition at line 24 of file solver.h.

◆ ifmu_centered_grids

bool Solver::ifmu_centered_grids = true

Definition at line 45 of file solver.h.

◆ integral_interpolate

bool Solver::integral_interpolate = true

Definition at line 46 of file solver.h.

◆ max_cohorts

int Solver::max_cohorts = 500

Definition at line 39 of file solver.h.

◆ method

PSPM_SolverType Solver::method
private

Definition at line 17 of file solver.h.

◆ n_statevars_internal

int Solver::n_statevars_internal = 0
private

Definition at line 19 of file solver.h.

◆ n_statevars_system

int Solver::n_statevars_system = 0
private

Definition at line 20 of file solver.h.

◆ ode_eps

double Solver::ode_eps = 1e-6

Definition at line 34 of file solver.h.

◆ ode_ifmu_stepsize

double Solver::ode_ifmu_stepsize = 0.1

Definition at line 44 of file solver.h.

◆ ode_initial_step_size

double Solver::ode_initial_step_size = 1e-6

Definition at line 35 of file solver.h.

◆ ode_rk4_stepsize

double Solver::ode_rk4_stepsize = 0.1

Definition at line 43 of file solver.h.

◆ odeStepper

OdeSolver Solver::odeStepper

Definition at line 23 of file solver.h.

◆ rates

std::vector<double> Solver::rates

Definition at line 29 of file solver.h.

◆ species_vec

std::vector<Species_Base*> Solver::species_vec

Definition at line 31 of file solver.h.

◆ state

std::vector<double> Solver::state

Definition at line 28 of file solver.h.

◆ update_cohorts

bool Solver::update_cohorts = true

Definition at line 38 of file solver.h.

◆ use_log_densities

bool Solver::use_log_densities = true

Definition at line 49 of file solver.h.


The documentation for this class was generated from the following files: