reaction_rule.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. /******************************************************************************
  2. *
  3. * Copyright (C) 2020 by
  4. * The Salk Institute for Biological Studies
  5. *
  6. * Use of this source code is governed by an MIT-style
  7. * license that can be found in the LICENSE file or at
  8. * https://opensource.org/licenses/MIT.
  9. *
  10. ******************************************************************************/
  11. #include "api/complex.h"
  12. #include "api/reaction_rule.h"
  13. #include "bng/bngl_names.h"
  14. #include "world.h"
  15. #include <set>
  16. using namespace std;
  17. namespace MCell {
  18. namespace API {
  19. bool ReactionRule::__eq__(const ReactionRule& other) const {
  20. // ignore name when comparing
  21. if (!eq_nonarray_attributes(other, true)) {
  22. return false;
  23. }
  24. if (variable_rate != other.variable_rate) {
  25. return false;
  26. }
  27. string n1 = get_canonical_name();
  28. string n2 = other.get_canonical_name();
  29. return n1 == n2;
  30. }
  31. static std::string get_rxn_side_str(
  32. const std::vector<std::shared_ptr<Complex>>& cplxs,
  33. const bool canonical) {
  34. string res;
  35. if (!cplxs.empty()) {
  36. for (size_t i = 0; i < cplxs.size(); i++) {
  37. if (!canonical) {
  38. res += cplxs[i]->to_bngl_str();
  39. }
  40. else {
  41. res += cplxs[i]->get_canonical_name();
  42. }
  43. if (i + 1 != cplxs.size()) {
  44. res += " + ";
  45. }
  46. }
  47. }
  48. else {
  49. res = BNG::COMPLEX_ZERO;
  50. }
  51. return res;
  52. }
  53. static std::string get_rxn_str(
  54. const std::vector<std::shared_ptr<Complex>>& reactants,
  55. const std::vector<std::shared_ptr<Complex>>& products,
  56. const double rev_rate,
  57. bool canonical) {
  58. string res;
  59. res = get_rxn_side_str(reactants, canonical);
  60. if (is_set(rev_rate)) {
  61. res += " <-> ";
  62. }
  63. else {
  64. res += " -> ";
  65. }
  66. res += get_rxn_side_str(products, canonical);
  67. return res;
  68. }
  69. std::string ReactionRule::to_bngl_str_w_orientation(
  70. bool replace_orientation_w_up_down_compartments) const {
  71. return get_rxn_str(reactants, products, rev_rate, replace_orientation_w_up_down_compartments);
  72. }
  73. static void sort_by_canonical_name(std::vector<std::shared_ptr<Complex>>& vec) {
  74. std::sort(vec.begin(), vec.end(),
  75. [](const std::shared_ptr<Complex>& a, const std::shared_ptr<Complex>& b) -> bool {
  76. return a->get_canonical_name() < b->get_canonical_name();
  77. });
  78. }
  79. std::string ReactionRule::get_canonical_name() const {
  80. std::vector<std::shared_ptr<Complex>> r_sorted = reactants;
  81. sort_by_canonical_name(r_sorted);
  82. std::vector<std::shared_ptr<Complex>> p_sorted = products;
  83. sort_by_canonical_name(p_sorted);
  84. return get_rxn_str(r_sorted, p_sorted, rev_rate, true);
  85. }
  86. void ReactionRule::update_reaction_rate(const BNG::rxn_rule_id_t rxn_rule_id, const double new_rate) {
  87. assert(is_initialized());
  88. if (world->scheduler.get_event_being_executed() != nullptr) {
  89. throw ValueError("Reaction rates cannot be changed in callbacks or in between of iterations.");
  90. }
  91. BNG::RxnRule* rxn = world->get_all_rxns().get(rxn_rule_id);
  92. bool updated = rxn->update_rxn_rate(new_rate);
  93. if (updated && rxn->is_unimol()) {
  94. world->reset_unimol_rxn_times(rxn_rule_id);
  95. }
  96. }
  97. void ReactionRule::set_fwd_rate(const double new_fwd_rate_) {
  98. if (!is_set(new_fwd_rate_)) {
  99. throw ValueError(S("Attribute ") + NAME_FWD_RATE + " must be set to a different value than " +
  100. NAME_CV_FLT_UNSET + ".");
  101. }
  102. if (is_initialized()) {
  103. update_reaction_rate(fwd_rxn_rule_id, new_fwd_rate_);
  104. cached_data_are_uptodate = false;
  105. fwd_rate = new_fwd_rate_;
  106. }
  107. else {
  108. cached_data_are_uptodate = false;
  109. fwd_rate = new_fwd_rate_;
  110. }
  111. }
  112. void ReactionRule::set_rev_rate(const double new_rev_rate_) {
  113. if (is_initialized()) {
  114. // TODO: add test
  115. if (is_set(rev_rate) && !is_set(new_rev_rate_)) {
  116. throw ValueError(S("Attribute ") + NAME_REV_RATE + " must be set to a different value than " +
  117. NAME_CV_FLT_UNSET + " is this " + NAME_CLASS_REACTION_RULE + " was initialized as a reversible reaction.");
  118. }
  119. // update the existing rule
  120. release_assert(rev_rxn_rule_id != BNG::RXN_RULE_ID_INVALID);
  121. update_reaction_rate(rev_rxn_rule_id, new_rev_rate_);
  122. cached_data_are_uptodate = false;
  123. rev_rate = new_rev_rate_;
  124. }
  125. else {
  126. cached_data_are_uptodate = false;
  127. rev_rate = new_rev_rate_;
  128. }
  129. }
  130. void ReactionRule::set_variable_rate(const std::vector<std::vector<double>> new_variable_rate_) {
  131. if (initialized) {
  132. throw RuntimeError("Value 'variable_rate' of object with name " + name + " (class " + class_name + ") "
  133. "cannot be set after model was initialized.");
  134. }
  135. if (is_reversible()) {
  136. throw RuntimeError(S("Cannot set ") + NAME_VARIABLE_RATE + " for a reversible reaction.");
  137. }
  138. cached_data_are_uptodate = false;
  139. variable_rate = new_variable_rate_;
  140. check_variable_rate();
  141. // reset fwd rate so that the variable rate is used
  142. fwd_rate = FLT_UNSET;
  143. }
  144. } // namespace API
  145. } // namespace MCell