bng_converter.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. /******************************************************************************
  2. *
  3. * Copyright (C) 2020-2021 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/bng_converter.h"
  12. #include "api/component_type.h"
  13. #include "api/elementary_molecule_type.h"
  14. #include "api/complex.h"
  15. #include "api/api_utils.h"
  16. #include "bng/bng.h"
  17. using namespace std;
  18. namespace MCell {
  19. namespace API {
  20. BNG::component_type_id_t BNGConverter::convert_component_type(
  21. const std::string& elem_mol_type_name, API::ComponentType& api_ct) {
  22. // component types are identified by their name and set of allowed states, not just by their name
  23. BNG::ComponentType bng_ct;
  24. bng_ct.name = api_ct.name;
  25. bng_ct.elem_mol_type_name = elem_mol_type_name;
  26. for (string& s: api_ct.states) {
  27. bng_ct.allowed_state_ids.insert( bng_data.find_or_add_state_name(s) );
  28. }
  29. BNG::component_type_id_t ct_id = bng_data.find_or_add_component_type(bng_ct);
  30. if (ct_id == BNG::COMPONENT_TYPE_ID_INVALID) {
  31. throw ValueError("Conflicting component type " + api_ct.to_bngl_str() + ", " +
  32. " component with the same name already exists but has different allowed states.");
  33. }
  34. return ct_id;
  35. }
  36. BNG::Component BNGConverter::convert_component_instance(
  37. const std::string& elem_mol_type_name, API::Component& api_ci) {
  38. BNG::Component res(convert_component_type(elem_mol_type_name, *api_ci.component_type));
  39. if (api_ci.state == STATE_UNSET) {
  40. res.state_id = BNG::STATE_ID_DONT_CARE;
  41. }
  42. else {
  43. res.state_id = bng_data.find_state_id(api_ci.state);
  44. assert(res.state_id != BNG::STATE_ID_INVALID);
  45. }
  46. if (api_ci.bond == BOND_BOUND) {
  47. res.bond_value = BNG::BOND_VALUE_BOUND;
  48. }
  49. else if (api_ci.bond == BOND_UNBOUND) {
  50. res.bond_value = BNG::BOND_VALUE_UNBOUND;
  51. }
  52. else if (api_ci.bond == BOND_ANY) {
  53. res.bond_value = BNG::BOND_VALUE_ANY;
  54. }
  55. else {
  56. res.bond_value = api_ci.bond;
  57. assert(res.bond_value != BNG::BOND_VALUE_INVALID);
  58. }
  59. return res;
  60. }
  61. BNG::ElemMol BNGConverter::convert_molecule_instance(API::ElementaryMolecule& mi, const bool in_rxn_or_observables) {
  62. BNG::ElemMol res;
  63. res.elem_mol_type_id = convert_elementary_molecule_type(*mi.elementary_molecule_type, in_rxn_or_observables);
  64. for (std::shared_ptr<API::Component>& api_ci: mi.components) {
  65. res.components.push_back(convert_component_instance(mi.elementary_molecule_type->name, *api_ci));
  66. }
  67. if (is_set(mi.compartment_name)) {
  68. BNG::compartment_id_t comp_id = bng_data.find_compartment_id(mi.compartment_name);
  69. if (comp_id == BNG::COMPARTMENT_ID_INVALID) {
  70. throw ValueError("Elementary molecule " + mi.to_bngl_str() + " uses unknown compartment " + mi.compartment_name + ".");
  71. }
  72. res.compartment_id = comp_id;
  73. }
  74. else {
  75. res.compartment_id = BNG::COMPARTMENT_ID_NONE;
  76. }
  77. // we must also copy flags from the mol type
  78. res.finalize_flags_and_sort_components(bng_data);
  79. return res;
  80. }
  81. BNG::elem_mol_type_id_t BNGConverter::convert_elementary_molecule_type(
  82. API::ElementaryMoleculeType& api_mt, const bool in_rxn_or_observables) {
  83. if (api_mt.mol_type_id != BNG::ELEM_MOL_TYPE_ID_INVALID) {
  84. // already converted
  85. return api_mt.mol_type_id;
  86. }
  87. BNG::ElemMolType bng_mt;
  88. bng_mt.name = api_mt.name;
  89. if (!in_rxn_or_observables) {
  90. if (is_set(api_mt.diffusion_constant_2d)) {
  91. bng_mt.set_is_surf();
  92. bng_mt.D = api_mt.diffusion_constant_2d;
  93. }
  94. else if (is_set(api_mt.diffusion_constant_3d)) {
  95. bng_mt.set_is_vol();
  96. bng_mt.D = api_mt.diffusion_constant_3d;
  97. }
  98. else {
  99. throw RuntimeError(S("Diffusion constant for ") + NAME_CLASS_ELEMENTARY_MOLECULE_TYPE +
  100. " '" + bng_mt.name + "' was not set.");
  101. }
  102. if (is_set(api_mt.custom_time_step)) {
  103. bng_mt.custom_time_step = api_mt.custom_time_step;
  104. }
  105. else if (is_set(api_mt.custom_space_step)) {
  106. bng_mt.custom_space_step = api_mt.custom_space_step;
  107. }
  108. bng_mt.set_flag(BNG::SPECIES_MOL_FLAG_TARGET_ONLY, api_mt.target_only);
  109. }
  110. // components
  111. for (std::shared_ptr<API::ComponentType> api_ct: api_mt.components) {
  112. BNG::ComponentType bng_ct;
  113. bng_ct.name = api_ct->name;
  114. bng_ct.elem_mol_type_name = bng_mt.name;
  115. for (const string& state: api_ct->states) {
  116. bng_ct.allowed_state_ids.insert_unique(bng_data.find_or_add_state_name(state));
  117. }
  118. BNG::component_type_id_t ct_id = bng_data.find_or_add_component_type(bng_ct);
  119. if (ct_id == BNG::COMPONENT_TYPE_ID_INVALID) {
  120. throw ValueError("Conflicting component type " + api_ct->to_bngl_str() + ", " +
  121. " component with the same name already exists but has different allowed states.");
  122. }
  123. bng_mt.component_type_ids.push_back(ct_id);
  124. }
  125. if (!in_rxn_or_observables) {
  126. // we can convert only definitions
  127. bng_mt.compute_space_and_time_step(bng_config);
  128. }
  129. return bng_data.find_or_add_elem_mol_type(bng_mt);
  130. }
  131. BNG::Cplx BNGConverter::convert_complex(API::Complex& api_cplx, const bool in_observables, const bool in_rxn) {
  132. // create a temporary cplx instance that we will use for search
  133. BNG::Cplx bng_cplx(&bng_data);
  134. if (is_set(api_cplx.elementary_molecules)) {
  135. for (std::shared_ptr<API::ElementaryMolecule>& m: api_cplx.elementary_molecules) {
  136. BNG::ElemMol mi = convert_molecule_instance(*m, in_observables || in_rxn);
  137. bng_cplx.elem_mols.push_back(mi);
  138. }
  139. }
  140. else {
  141. throw ValueError(
  142. "Complex with name " + api_cplx.name + " does not have its " + NAME_ELEMENTARY_MOLECULES + " set. "
  143. "It should be always set because initialization of " + NAME_CLASS_COMPLEX + " from " + NAME_NAME + " is done "
  144. "in this class' constructor."
  145. );
  146. }
  147. // orientation or compartment does not have to be set for finalization,
  148. // this sets whether this is a surf or vol cplx
  149. bng_cplx.finalize_cplx();
  150. // BNG compartments were already created, they were also set for individual molecules
  151. if (is_set(api_cplx.compartment_name)) {
  152. // override all used compartments that were not set (are NONE)
  153. BNG::compartment_id_t in_out_id = BNG::get_in_or_out_compartment_id(api_cplx.compartment_name);
  154. if (in_out_id != BNG::COMPARTMENT_ID_INVALID) {
  155. bng_cplx.set_compartment_id(in_out_id, true);
  156. }
  157. else {
  158. const BNG::Compartment* bng_comp = bng_data.find_compartment(api_cplx.compartment_name);
  159. if (bng_cplx.is_vol() && (bng_comp == nullptr || !bng_comp->is_3d)) {
  160. throw ValueError("Did not find volume compartment " + api_cplx.compartment_name +
  161. " for a volume complex " + bng_cplx.to_str() + ".");
  162. }
  163. if (bng_cplx.is_surf() && (bng_comp == nullptr || bng_comp->is_3d)) {
  164. throw ValueError("Did not find surface compartment " + api_cplx.compartment_name +
  165. " for a surface complex " + bng_cplx.to_str() + ".");
  166. }
  167. bng_cplx.set_compartment_id(bng_comp->id, true);
  168. }
  169. }
  170. else {
  171. // main compartment was not set, do not change them
  172. if (!in_rxn && bng_cplx.is_vol() && api_cplx.orientation != Orientation::NONE && api_cplx.orientation != Orientation::DEFAULT) {
  173. throw ValueError("Orientation for a volume complex " + bng_cplx.to_str() +
  174. " must be set either to " + NAME_ENUM_ORIENTATION + "." + NAME_EV_NONE + " or " +
  175. NAME_ENUM_ORIENTATION + "." + NAME_EV_DEFAULT + ".");
  176. }
  177. else if (bng_cplx.is_surf() && api_cplx.orientation == Orientation::NONE) {
  178. throw ValueError("Orientation for a surface complex " + bng_cplx.to_str() +
  179. " must be set to a value other than " + NAME_ENUM_ORIENTATION + "." + NAME_EV_NONE +
  180. " when " + NAME_COMPARTMENT_NAME + " is not specified.");
  181. }
  182. orientation_t orient = convert_api_orientation(api_cplx.orientation, true, bng_cplx.is_vol());
  183. bng_cplx.set_orientation(orient);
  184. }
  185. return bng_cplx;
  186. }
  187. } // namespace API
  188. } // namespace MCell