subsystem.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  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/component.h>
  12. #include "subsystem.h"
  13. #include "bng/bng.h"
  14. #include "api/component_type.h"
  15. #include "api/elementary_molecule_type.h"
  16. #include "api/elementary_molecule.h"
  17. #include "api/complex.h"
  18. #include "api/api_utils.h"
  19. using namespace std;
  20. namespace MCell {
  21. namespace API {
  22. void Subsystem::dump() const {
  23. std::cout << to_str() << "\n";
  24. }
  25. std::shared_ptr<Species> Subsystem::get_species_with_id(const species_id_t id) {
  26. // not very efficient, we may need some caching/map later
  27. for (auto& s: species) {
  28. if (s->species_id == id) {
  29. return s;
  30. }
  31. }
  32. return std::shared_ptr<Species>(nullptr);
  33. }
  34. void Subsystem::unify_and_register_elementary_molecule_types() {
  35. // then go through Species
  36. for (std::shared_ptr<Species> s: species) {
  37. for (size_t i = 0; i < s->elementary_molecules.size(); i++) {
  38. // note the reference, we might be changing this spared ptr
  39. std::shared_ptr<ElementaryMoleculeType>& emt = s->elementary_molecules[i]->elementary_molecule_type;
  40. // do we have this exact object already?
  41. auto it_ptr_eq = std::find_if(
  42. elementary_molecule_types.begin(), elementary_molecule_types.end(),
  43. [&emt] (const std::shared_ptr<ElementaryMoleculeType> emt_existing) {
  44. return emt_existing.get() == emt.get(); // comparing pointers
  45. }
  46. );
  47. if (it_ptr_eq != elementary_molecule_types.end()) {
  48. // same object exists
  49. continue;
  50. }
  51. // do we have an object with the same contents already?
  52. auto it_contents_eq = std::find_if(
  53. elementary_molecule_types.begin(), elementary_molecule_types.end(),
  54. [&emt] (const std::shared_ptr<ElementaryMoleculeType> emt_existing) {
  55. return *emt_existing == *emt; // comparing contents
  56. }
  57. );
  58. if (it_contents_eq != elementary_molecule_types.end()) {
  59. // same object exists, we must use this one and let shared_ptr ref counting
  60. // destroy the previous one (creation of the EMT object to be destroyed
  61. // occurs mainly when defining simple species, so the link from species to this emt
  62. // is internal and not visible to the user)
  63. emt = *it_contents_eq;
  64. continue;
  65. }
  66. // one more option is that some of the elementary molecule types that we encounter are not
  67. // fully initialized, for now expecting that the the fully initialized one is already present
  68. auto it_name_eq = std::find_if(
  69. elementary_molecule_types.begin(), elementary_molecule_types.end(),
  70. [&emt] (const std::shared_ptr<ElementaryMoleculeType> emt_existing) {
  71. return emt_existing->name == emt->name; // comparing contents
  72. }
  73. );
  74. if (it_name_eq != elementary_molecule_types.end()) {
  75. // use the one that is initialized
  76. if (!(*it_name_eq)->all_numerical_attributes_are_unset() &&
  77. emt->all_numerical_attributes_are_unset()
  78. ) {
  79. // update the pointer used in the Species object
  80. emt = *it_name_eq;
  81. continue;
  82. }
  83. if ((*it_name_eq)->all_numerical_attributes_are_unset() &&
  84. !emt->all_numerical_attributes_are_unset()
  85. ) {
  86. // update the one in elementary_molecule_types using the Species object
  87. *it_name_eq = emt;
  88. continue;
  89. }
  90. // other cases are error and will be reported in add_elementary_molecule_type
  91. }
  92. // no such object is in the emt list, add it (reports error if such object already exists)
  93. add_elementary_molecule_type(emt);
  94. }
  95. }
  96. }
  97. void Subsystem::load_bngl_molecule_types_and_reaction_rules(
  98. const std::string& file_name,
  99. const std::map<std::string, double>& parameter_overrides) {
  100. BNG::BNGData bng_data;
  101. int num_errors = BNG::parse_bngl_file(file_name, bng_data, parameter_overrides);
  102. if (num_errors != 0) {
  103. throw RuntimeError("Could not parse BNGL file " + file_name + ".");
  104. }
  105. // now convert everything we parsed into the API classes so that the user can
  106. // inspect or manipulate it if needed
  107. convert_bng_data_to_subsystem_data(bng_data);
  108. }
  109. void Subsystem::convert_bng_data_to_subsystem_data(const BNG::BNGData& bng_data) {
  110. // elementary molecules
  111. for (const BNG::ElemMolType& mt: bng_data.get_elem_mol_types()) {
  112. auto res_mt = ElementaryMoleculeType::construct_from_bng_elem_mol_type(bng_data, mt);
  113. append_to_vec_canonical_name(elementary_molecule_types, res_mt);
  114. }
  115. // reaction rules
  116. for (const BNG::RxnRule& rr: bng_data.get_rxn_rules()) {
  117. convert_reaction_rule(bng_data, rr);
  118. }
  119. }
  120. void Subsystem::convert_reaction_rule(const BNG::BNGData& bng_data, const BNG::RxnRule& bng_rr) {
  121. // always a standard rxn
  122. if (bng_rr.type != BNG::RxnType::Standard) {
  123. throw RuntimeError("Unexpected type of reaction from BNGL file for reaction " + bng_rr.name + ".");
  124. }
  125. auto res_rr = make_shared<API::ReactionRule>(DefaultCtorArgType());
  126. if (bng_rr.name != "") {
  127. res_rr->name = bng_rr.name;
  128. }
  129. // RxnRule
  130. res_rr->fwd_rate = bng_rr.base_rate_constant;
  131. for (const BNG::Cplx& inst: bng_rr.reactants) {
  132. // MCell3R accepts reactants with any orientation
  133. res_rr->reactants.push_back(
  134. Complex::construct_from_bng_cplx_w_orientation(bng_data, inst, Orientation::ANY));
  135. }
  136. for (const BNG::Cplx& inst: bng_rr.products) {
  137. // MCell3R always creates products with the orientation up
  138. res_rr->products.push_back(
  139. Complex::construct_from_bng_cplx_w_orientation(bng_data, inst, Orientation::UP));
  140. }
  141. // allow reactions with identical names
  142. append_to_vec_canonical_name(reaction_rules, res_rr);
  143. }
  144. } // namespace API
  145. } // namespace MCell