12 #ifndef CD_KMCSolverImplem_H
13 #define CD_KMCSolverImplem_H
17 #include <unordered_set>
25 #include <CD_NamespaceHeader.H>
27 template <
typename R,
typename State,
typename T>
31 template <
typename R,
typename State,
typename T>
34 CH_TIME(
"KMCSolver::KMCSolver");
36 this->define(a_reactions);
39 template <
typename R,
typename State,
typename T>
42 CH_TIME(
"KMCSolver::~KMCSolver");
45 template <
typename R,
typename State,
typename T>
49 CH_TIME(
"KMCSolver::define");
51 m_reactions = a_reactions;
57 template <
typename R,
typename State,
typename T>
62 const Real a_SSAlim) noexcept
64 CH_TIME(
"KMCSolver::setSolverParameters");
72 template <
typename R,
typename State,
typename T>
73 inline std::vector<Real>
76 CH_TIME(
"KMCSolver::propensities(State)");
78 return this->propensities(a_state, m_reactions);
81 template <
typename R,
typename State,
typename T>
82 inline std::vector<Real>
85 CH_TIME(
"KMCSolver::propensities(State, ReactionList)");
87 std::vector<Real> A(a_reactions.size());
89 const size_t numReactions = a_reactions.size();
91 for (
size_t i = 0; i < numReactions; i++) {
92 A[i] = a_reactions[i]->propensity(a_state);
98 template <
typename R,
typename State,
typename T>
102 CH_TIME(
"KMCSolver::totalPropensity(State)");
104 return this->totalPropensity(a_state, m_reactions);
107 template <
typename R,
typename State,
typename T>
111 CH_TIME(
"KMCSolver::totalPropensity(State, ReactionList)");
115 const size_t numReactions = a_reactions.size();
117 for (
size_t i = 0; i < numReactions; i++) {
118 A += a_reactions[i]->propensity(a_state);
124 template <
typename R,
typename State,
typename T>
125 inline std::pair<typename KMCSolver<R, State, T>::ReactionList,
typename KMCSolver<R, State, T>::ReactionList>
128 CH_TIME(
"KMCSolver::partitionReactions(State)");
130 return this->partitionReactions(a_state, m_reactions);
133 template <
typename R,
typename State,
typename T>
134 inline std::pair<typename KMCSolver<R, State, T>::ReactionList,
typename KMCSolver<R, State, T>::ReactionList>
137 CH_TIME(
"KMCSolver::partitionReactions(State, ReactionList)");
139 ReactionList criticalReactions;
140 ReactionList nonCriticalReactions;
142 const size_t numReactions = a_reactions.size();
144 for (
size_t i = 0; i < numReactions; i++) {
145 const T Lj = a_reactions[i]->computeCriticalNumberOfReactions(a_state);
148 criticalReactions.emplace_back(a_reactions[i]);
151 nonCriticalReactions.emplace_back(a_reactions[i]);
155 return std::make_pair(criticalReactions, nonCriticalReactions);
158 template <
typename R,
typename State,
typename T>
163 return this->getCriticalTimeStep(a_state, m_reactions);
166 template <
typename R,
typename State,
typename T>
169 const ReactionList& a_criticalReactions)
const noexcept
171 CH_TIME(
"KMCSolver::getCriticalTimeStep");
177 if (a_criticalReactions.size() > 0) {
181 dt = this->getCriticalTimeStep(A);
187 template <
typename R,
typename State,
typename T>
191 CH_TIME(
"KineticMonteCarlo::getCriticalTimeStep(std::vector<Real>)");
196 for (
const auto& p : a_propensities) {
200 return this->getCriticalTimeStep(A);
203 template <
typename R,
typename State,
typename T>
207 CH_TIME(
"KineticMonteCarlo::getCriticalTimeStep(Real)");
211 return log(1.0 / u) / a_totalPropensity;
214 template <
typename R,
typename State,
typename T>
218 CH_TIME(
"KMCSolver::getNonCriticalTimeStep(State");
220 const auto& partitionedReactions = this->partitionReactions(a_state, m_reactions);
222 return this->getNonCriticalTimeStep(a_state, partitionedReactions.second);
225 template <
typename R,
typename State,
typename T>
229 CH_TIME(
"KMCSolver::getNonCriticalTimeStep(State, ReactionList");
231 const std::vector<Real> propensities = this->propensities(a_state, a_reactions);
233 return this->getNonCriticalTimeStep(a_state, a_reactions, propensities);
236 template <
typename R,
typename State,
typename T>
239 const ReactionList& a_nonCriticalReactions,
240 const std::vector<Real>& a_nonCriticalPropensities)
const noexcept
242 CH_TIME(
"KMCSolver::getNonCriticalTimeStep(State, ReactionList, std::vector<Real>");
244 CH_assert(a_nonCriticalReactions.size() == a_nonCriticalPropensities.size());
246 constexpr Real one = 1.0;
250 const size_t numReactions = a_nonCriticalReactions.size();
252 if (numReactions > 0) {
255 auto allReactants = a_nonCriticalReactions[0]->getReactants();
256 for (
size_t i = 1; i < numReactions; i++) {
257 const auto& curReactants = a_nonCriticalReactions[i]->getReactants();
259 allReactants.insert(allReactants.end(), curReactants.begin(), curReactants.end());
263 const auto ip = std::unique(allReactants.begin(), allReactants.end());
264 allReactants.resize(std::distance(allReactants.begin(), ip));
267 for (
const auto& reactant : allReactants) {
274 const T Xi = a_nonCriticalReactions[0]->population(reactant, a_state);
283 constexpr Real gi = 4.0;
285 for (
size_t i = 0; i < numReactions; i++) {
286 const Real& p = a_nonCriticalPropensities[i];
287 const auto& muIJ = a_nonCriticalReactions[i]->getStateChange(reactant);
289 mu += std::abs(muIJ * p);
290 sigma2 += std::abs(muIJ * muIJ * p);
296 const Real f =
std::max(m_eps * Xi / gi, one);
302 dt2 = (f * f) / sigma2;
313 template <
typename R,
typename State,
typename T>
317 CH_TIME(
"KMCSolver::stepTauPlain(State, Real)");
319 this->stepTauPlain(a_state, m_reactions, a_dt);
322 template <
typename R,
typename State,
typename T>
326 CH_TIME(
"KMCSolver::stepTauPlain(State, ReactionList, Real)");
328 const std::vector<Real> propensities = this->propensities(a_state, a_reactions);
330 this->stepTauPlain(a_state, a_reactions, propensities, a_dt);
333 template <
typename R,
typename State,
typename T>
336 const ReactionList& a_reactions,
337 const std::vector<Real>& a_propensities,
338 const Real a_dt)
const noexcept
340 CH_TIME(
"KMCSolver::stepTauPlain(State, ReactionList, std::vector<Real>, Real)");
342 CH_assert(a_reactions.size() == a_propensities.size());
344 if (a_reactions.size() > 0) {
345 for (
size_t i = 0; i < a_reactions.size(); i++) {
349 const T numReactions = (T)Random::getPoisson<long long>(a_propensities[i] * a_dt);
351 a_reactions[i]->advanceState(a_state, numReactions);
356 template <
typename R,
typename State,
typename T>
360 CH_TIME(
"KMCSolver::advanceTauPlain(State, ReactionList)");
362 this->advanceTauPlain(a_state, m_reactions, a_dt);
365 template <
typename R,
typename State,
typename T>
369 CH_TIME(
"KMCSolver::advanceTauPlain(State, ReactionList, Real)");
371 if (a_reactions.size() > 0) {
375 while (curTime < a_dt) {
378 curDt = a_dt - curTime;
385 State state = a_state;
388 this->stepTauPlain(state, a_reactions, curDt);
391 valid = state.isValidState();
406 template <
typename R,
typename State,
typename T>
410 CH_TIME(
"KMCSolver::stepTauMidpoint(State&, const Real)");
412 this->stepTauMidpoint(a_state, m_reactions, a_dt);
415 template <
typename R,
typename State,
typename T>
419 CH_TIME(
"KMCSolver::stepTauMidpoint(State&, const ReactionList&, const Real)");
421 const int numReactions = a_reactions.size();
423 if (numReactions > 0) {
425 std::vector<Real> propensities = this->propensities(a_state, a_reactions);
427 State Xdagger = a_state;
428 for (
size_t i = 0; i < numReactions; i++) {
431 a_reactions[i]->advanceState(Xdagger, (T)std::ceil(0.5 * propensities[i] * a_dt));
434 propensities = this->propensities(Xdagger, a_reactions);
435 for (
size_t i = 0; i < numReactions; i++) {
436 const T curReactions = (T)Random::getPoisson<long long>(propensities[i] * a_dt);
438 a_reactions[i]->advanceState(a_state, curReactions);
443 template <
typename R,
typename State,
typename T>
447 CH_TIME(
"KMCSolver::advanceTauMidpoint(State&, const Real)");
449 this->advanceTauMidpoint(a_state, m_reactions, a_dt);
452 template <
typename R,
typename State,
typename T>
455 const ReactionList& a_reactions,
456 const Real a_dt)
const noexcept
458 CH_TIME(
"KMCSolver::advanceTauMidpoint(State&, const ReactionList&, const Real)");
460 if (a_reactions.size() > 0) {
464 while (curTime < a_dt) {
467 curDt = a_dt - curTime;
474 State state = a_state;
477 this->stepTauMidpoint(state, a_reactions, curDt);
480 valid = state.isValidState();
495 template <
typename R,
typename State,
typename T>
499 CH_TIME(
"KMCSolver::stepSSA(State, Real)");
501 this->stepSSA(a_state, m_reactions);
504 template <
typename R,
typename State,
typename T>
508 CH_TIME(
"KMCSolver::stepSSA(State, ReactionList, Real)");
510 if (a_reactions.size() > 0) {
513 const std::vector<Real> propensities = this->propensities(a_state, a_reactions);
515 this->stepSSA(a_state, a_reactions, propensities);
519 template <
typename R,
typename State,
typename T>
522 const ReactionList& a_reactions,
523 const std::vector<Real>& a_propensities)
const noexcept
525 CH_TIME(
"KMCSolver::stepSSA(State, ReactionList, std::vector<Real>)");
527 CH_assert(a_reactions.size() == a_propensities.size());
529 const size_t numReactions = a_reactions.size();
531 if (numReactions > 0) {
532 constexpr T one = (T)1;
536 for (
size_t i = 0; i < numReactions; i++) {
537 A += a_propensities[i];
545 for (
size_t i = 0; i < a_reactions.size(); i++) {
546 sumProp += a_propensities[i];
548 if (sumProp >= u * A) {
556 a_reactions[r]->advanceState(a_state, one);
560 template <
typename R,
typename State,
typename T>
564 CH_TIME(
"KMCSolver::advanceSSA(State, Real)");
566 this->advanceSSA(a_state, m_reactions, a_dt);
569 template <
typename R,
typename State,
typename T>
573 CH_TIME(
"KMCSolver::advanceSSA(State, ReactionList, Real)");
575 const size_t numReactions = a_reactions.size();
577 if (numReactions > 0) {
582 while (curDt <= a_dt) {
585 const std::vector<Real> propensities = this->propensities(a_state, a_reactions);
587 const Real nextDt = this->getCriticalTimeStep(propensities);
590 if (curDt + nextDt <= a_dt) {
591 this->stepSSA(a_state, a_reactions, propensities);
599 template <
typename R,
typename State,
typename T>
605 CH_TIME(
"KMCSolver::advanceHybrid(State, Real, KMCLeapPropagator)");
607 this->advanceHybrid(a_state, m_reactions, a_dt, a_leapPropagator);
610 template <
typename R,
typename State,
typename T>
613 const ReactionList& a_reactions,
617 CH_TIME(
"KMCSolver::advanceHybrid(State, ReactionList, Real, KMCLeapPropagator)");
619 switch (a_leapPropagator) {
620 case KMCLeapPropagator::TauPlain: {
621 this->advanceHybrid(a_state, a_reactions, a_dt, [
this](State& s,
const ReactionList& r,
const Real dt) {
622 this->stepTauPlain(s, r, dt);
627 case KMCLeapPropagator::TauMidpoint: {
628 this->advanceHybrid(a_state, a_reactions, a_dt, [
this](State& s,
const ReactionList& r,
const Real dt) {
629 this->stepTauMidpoint(s, r, dt);
635 MayDay::Error(
"KMCSolver::advanceHybrid - unknown leap propagator requested");
640 template <
typename R,
typename State,
typename T>
644 const ReactionList& a_reactions,
646 const std::function<
void(State&,
const ReactionList& a_reactions,
const Real a_dt)>& a_propagator)
const noexcept
648 CH_TIME(
"KMCSolver::advanceHybrid(State, ReactionList, Real, std::function)");
650 constexpr T one = (T)1;
656 while (curTime < a_dt) {
659 const std::pair<ReactionList, ReactionList> partitionedReactions = this->partitionReactions(a_state, a_reactions);
661 const ReactionList& criticalReactions = partitionedReactions.first;
662 const ReactionList& nonCriticalReactions = partitionedReactions.second;
664 const std::vector<Real> propensitiesCrit = this->propensities(a_state, criticalReactions);
665 const std::vector<Real> propensitiesNonCrit = this->propensities(a_state, nonCriticalReactions);
667 Real dtCrit = this->getCriticalTimeStep(propensitiesCrit);
668 Real dtNonCrit = this->getNonCriticalTimeStep(a_state, nonCriticalReactions, propensitiesNonCrit);
672 bool validStep =
false;
679 State state = a_state;
685 const bool nonCriticalOnly = (dtNonCrit < dtCrit) || (criticalReactions.size() == 0) ||
686 (dtCrit > (a_dt - curTime));
688 if (nonCriticalOnly) {
691 Real A = this->totalPropensity(state, a_reactions);
693 if (A * curDt < m_SSAlim) {
701 while (dtSSA < curDt && numSSA < m_numSSA) {
704 std::vector<Real> propensities = this->propensities(a_state, a_reactions);
707 for (
size_t i = 0; i < propensities.size(); i++) {
708 A += propensities[i];
712 const Real dtReact = this->getCriticalTimeStep(A);
714 if (dtSSA + dtReact < curDt) {
715 this->stepSSA(a_state, a_reactions, propensities);
732 a_propagator(state, nonCriticalReactions, curDt);
735 validStep = state.isValidState();
750 this->stepSSA(state, criticalReactions, propensitiesCrit);
753 a_propagator(state, nonCriticalReactions, curDt);
756 validStep = state.isValidState();
771 #include <CD_NamespaceFooter.H>
Class for running Kinetic Monte Carlo functionality.
KMCLeapPropagator
Supported propagators for hybrid tau leaping.
Definition: CD_KMCSolver.H:29
File containing some useful static methods related to random number generation.
void setSolverParameters(const T a_numCrit, const T a_numSSA, const Real a_eps, const Real a_SSAlim) noexcept
Set solver parameters.
Definition: CD_KMCSolverImplem.H:59
virtual ~KMCSolver() noexcept
Destructor.
Definition: CD_KMCSolverImplem.H:40
void advanceTauMidpoint(State &a_state, const Real a_dt) const noexcept
Perform one leaping step using the midpoint method all reactions over a time step a_dt.
Definition: CD_KMCSolverImplem.H:445
void define(const ReactionList &a_reactions) noexcept
Define function. Sets the reactions.
Definition: CD_KMCSolverImplem.H:47
KMCSolver() noexcept
Default constructor – must subsequently define the object.
Definition: CD_KMCSolverImplem.H:28
Real getCriticalTimeStep(const State &a_state) const noexcept
Get the time to the next critical reaction.
Definition: CD_KMCSolverImplem.H:160
void stepTauMidpoint(State &a_state, const Real a_dt) const noexcept
Perform one leaping step using the midpoint method for ALL reactions over a time step a_dt.
Definition: CD_KMCSolverImplem.H:408
void stepTauPlain(State &a_state, const Real a_dt) const noexcept
Perform one plain tau-leaping step using ALL reactions.
Definition: CD_KMCSolverImplem.H:315
void advanceSSA(State &a_state, const Real a_dt) const noexcept
Advance with the SSA over the input time. This can end up using substepping.
Definition: CD_KMCSolverImplem.H:562
std::pair< ReactionList, ReactionList > partitionReactions(const State &a_state) const noexcept
Partition reactions into critical and non-critical reactions.
Definition: CD_KMCSolverImplem.H:126
void advanceTauPlain(State &a_state, const Real a_dt) const noexcept
Advance with plain tau-leaping step over the input time. This can end up using substepping.
Definition: CD_KMCSolverImplem.H:358
void stepSSA(State &a_state) const noexcept
Perform a single SSA step.
Definition: CD_KMCSolverImplem.H:497
Real getNonCriticalTimeStep(const State &a_state) const noexcept
Get the non-critical time step.
Definition: CD_KMCSolverImplem.H:216
void advanceHybrid(State &a_state, const Real a_dt, const KMCLeapPropagator &a_leapPropagator=KMCLeapPropagator::TauPlain) const noexcept
Advance using Cao et. al. hybrid algorithm over the input time. This can end up using substepping.
Definition: CD_KMCSolverImplem.H:601
Real totalPropensity(const State &a_state) const noexcept
Compute the total propensity for ALL reactions.
Definition: CD_KMCSolverImplem.H:100
std::vector< Real > propensities(const State &a_state) const noexcept
Compute propensities for ALL reactions.
Definition: CD_KMCSolverImplem.H:74
static Real getUniformReal01()
Get a uniform real number on the interval [0,1].
Definition: CD_RandomImplem.H:147
Real max(const Real &a_input) noexcept
Get the maximum of the input, reduced over MPI ranks (in the Chombo communicator)
Definition: CD_ParallelOpsImplem.H:176
Real min(const Real &a_input) noexcept
Get the minimum of the input, reduced over MPI ranks (in the Chombo communicator)
Definition: CD_ParallelOpsImplem.H:58