instantiation.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  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/instantiation.h"
  12. #include <algorithm>
  13. #include "bng/bng.h"
  14. #include "api/subsystem.h"
  15. #include "api/geometry_object.h"
  16. #include "api/surface_region.h"
  17. #include "api/region.h"
  18. #include "api/complex.h"
  19. #include "generated/gen_geometry_utils.h"
  20. using namespace std;
  21. namespace MCell {
  22. namespace API {
  23. const char* const RELEASE_SITE_PREFIX = "rel_";
  24. void Instantiation::dump() const {
  25. std::cout << to_str() << "\n";
  26. }
  27. std::shared_ptr<GeometryObject> Instantiation::find_volume_compartment_object(const std::string& name) {
  28. for (auto o: geometry_objects) {
  29. if (o->is_bngl_compartment) {
  30. if (o->name == name) {
  31. return o;
  32. }
  33. }
  34. }
  35. return std::shared_ptr<GeometryObject>(nullptr);
  36. }
  37. std::shared_ptr<GeometryObject> Instantiation::find_surface_compartment_object(const std::string& name) {
  38. for (auto o: geometry_objects) {
  39. if (o->is_bngl_compartment) {
  40. if (is_set(o->surface_compartment_name) && o->surface_compartment_name == name) {
  41. return o;
  42. }
  43. }
  44. }
  45. return std::shared_ptr<GeometryObject>(nullptr);
  46. }
  47. void Instantiation::load_bngl_compartments_and_seed_species(
  48. const std::string& file_name,
  49. std::shared_ptr<Region> default_release_region,
  50. const std::map<std::string, double>& parameter_overrides) {
  51. BNG::BNGData bng_data;
  52. int num_errors = BNG::parse_bngl_file(file_name, bng_data, parameter_overrides);
  53. if (num_errors != 0) {
  54. throw RuntimeError("Could not parse BNGL file " + file_name + ".");
  55. }
  56. // now convert everything we parsed into the API classes so that the user can
  57. // inspect or manipulate it if needed
  58. convert_bng_data_to_instantiation(bng_data, default_release_region);
  59. }
  60. void Instantiation::convert_bng_data_to_instantiation(
  61. const BNG::BNGData& bng_data,
  62. std::shared_ptr<Region> default_release_region) {
  63. convert_compartments(bng_data);
  64. for (const BNG::SeedSpecies& bng_ss: bng_data.get_seed_species()) {
  65. convert_single_seed_species_to_release_site(bng_data, bng_ss, default_release_region);
  66. }
  67. }
  68. void Instantiation::convert_compartments(const BNG::BNGData& bng_data) {
  69. if (bng_data.get_compartments().empty()) {
  70. return;
  71. }
  72. // create objects and assign 2d release regions
  73. for (const BNG::Compartment& bng_comp: bng_data.get_compartments()) {
  74. if (bng_comp.children_compartments.size() > 2) {
  75. throw RuntimeError("Automatic creation of compartments with more than one child compartment "
  76. "is not supported yet, error for '" + bng_comp.name + ".");
  77. }
  78. if (bng_comp.is_3d) {
  79. std::shared_ptr<GeometryObject> existing_obj = find_geometry_object(bng_comp.name);
  80. if (is_set(existing_obj)) {
  81. // object with this name already exists, we will use it instead
  82. existing_obj->is_bngl_compartment = true;
  83. continue;
  84. }
  85. // compute volume using children volumes - all volumes must have been provided
  86. // for geometry object size - we won't include the volume of surface compartments
  87. double volume = bng_comp.get_volume_including_children(bng_data, false);
  88. double side = pow_f(volume, 1.0/3.0);
  89. // create box for the given compartment
  90. shared_ptr<GeometryObject> box = geometry_utils::create_box(bng_comp.name, side);
  91. box->is_bngl_compartment = true;
  92. // set its 2d name
  93. if (bng_comp.has_parent()) {
  94. box->surface_compartment_name = bng_data.get_compartment(bng_comp.parent_compartment_id).name;
  95. }
  96. add_geometry_object(box);
  97. }
  98. // TODO: assign names of 2D compartments when 3D compartment already exists
  99. }
  100. }
  101. void Instantiation::convert_single_seed_species_to_release_site(
  102. const BNG::BNGData& bng_data,
  103. const BNG::SeedSpecies& bng_ss,
  104. std::shared_ptr<Region> default_release_region) {
  105. auto rel_site = make_shared<API::ReleaseSite>(DefaultCtorArgType());
  106. // we need to create API representation for the cplx instance we got
  107. rel_site->complex =
  108. Complex::construct_from_bng_cplx(bng_data, bng_ss.cplx);
  109. // releases from BNGL always used the default orientation
  110. rel_site->complex->orientation = Orientation::DEFAULT;
  111. if (bng_ss.cplx.has_compartment()) {
  112. // we might not know the types of elementary molecules at this point so we cannot check
  113. // that molecule and compartment are of the same type (vol or surf)
  114. const BNG::Compartment& c = bng_data.get_compartment(bng_ss.cplx.get_primary_compartment_id(true));
  115. rel_site->complex->set_compartment_name(c.name);
  116. rel_site->shape = Shape::COMPARTMENT;
  117. rel_site->name =
  118. "Release of " + rel_site->complex->to_bngl_str();
  119. if (is_set(rel_site->complex->compartment_name)) {
  120. rel_site->name += " at " + rel_site->complex->compartment_name;
  121. }
  122. }
  123. else {
  124. if (!is_set(default_release_region)) {
  125. throw ValueError(S("Seed species specification for complex instance ") +
  126. rel_site->complex->to_bngl_str() + " does not have a compartment and " +
  127. NAME_DEFAULT_RELEASE_REGION + " was not set, don't know where to release.\n"
  128. );
  129. }
  130. rel_site->region = default_release_region;
  131. rel_site->shape = Shape::REGION_EXPR;
  132. rel_site->name =
  133. "Release of " + rel_site->complex->to_bngl_str() +
  134. " at " + rel_site->region->name;
  135. }
  136. if (bng_ss.count > (double)UINT32_MAX) {
  137. throw ValueError(S("Value ") + to_string(bng_ss.count) + " for " +
  138. NAME_NUMBER_TO_RELEASE + " of a " + NAME_CLASS_RELEASE_SITE + " '" + rel_site->name +
  139. "' created from 'seed species' BNGL section is too high, the maximum allowed is " + to_string(UINT32_MAX) + ".");
  140. }
  141. uint truncated_count = BNG::floor_f(bng_ss.count);
  142. if (bng_ss.count != truncated_count) {
  143. cout << "Warning: Release count of complex instance created from loaded BNGL file '" +
  144. rel_site->name + "' was truncated from " << bng_ss.count << " to " << truncated_count << ".\n";
  145. }
  146. rel_site->number_to_release = truncated_count;
  147. rel_site->check_semantics(); // only for internal checks
  148. rel_site->postprocess_in_ctor(); // sets shape
  149. release_sites.push_back(rel_site);
  150. }
  151. std::shared_ptr<Region> Instantiation::get_compartment_region(const std::string& name) {
  152. std::shared_ptr<GeometryObject> obj;
  153. // first try if it is a volume compartment
  154. obj = find_volume_compartment_object(name);
  155. if (is_set(obj)) {
  156. std::shared_ptr<Region> res = std::dynamic_pointer_cast<Region>(obj);
  157. for (auto child: obj->child_compartments) {
  158. res = res->__sub__(std::dynamic_pointer_cast<Region>(child));
  159. }
  160. return res;
  161. }
  162. // then a surface compartment
  163. obj = find_surface_compartment_object(name);
  164. if (is_set(obj)) {
  165. return std::dynamic_pointer_cast<Region>(obj);
  166. }
  167. // no compartment found
  168. return std::shared_ptr<Region>(nullptr);
  169. }
  170. }
  171. // namespace API
  172. } // namespace MCell