introspection.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  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/introspection.h"
  12. #include "api/model.h"
  13. #include "api/api_utils.h"
  14. #include "api/molecule.h"
  15. #include "api/wall.h"
  16. #include "api/geometry_object.h"
  17. #include "api/color.h"
  18. #include "api/bng_converter.h"
  19. #include "world.h"
  20. #include "src4/geometry_utils.h" // TODO: we should rename the src4 directory
  21. #include "bng/cplx.h"
  22. using namespace std;
  23. namespace MCell {
  24. namespace API {
  25. static void object_is_set_and_initialized(std::shared_ptr<GeometryObject> object) {
  26. if (!is_set(object)) {
  27. throw ValueError(S("Argument passed as ") + NAME_CLASS_GEOMETRY_OBJECT + " must not be None.");
  28. }
  29. object->check_is_initialized();
  30. }
  31. void Introspection::initialize_introspection(Model* model_) {
  32. model_inst = model_;
  33. world = model_inst->get_world();
  34. assert(world != nullptr);
  35. }
  36. std::vector<int> Introspection::get_molecule_ids(std::shared_ptr<Complex> pattern) {
  37. std::vector<int> res;
  38. // NOTE: some caching might be useful here if this function is called often
  39. uint_set<species_id_t> matching_species, not_matching_species;
  40. BNG::Cplx bng_pattern(&world->bng_engine.get_data());
  41. BNG::compartment_id_t primary_compartment_id = BNG::COMPARTMENT_ID_NONE;
  42. if (is_set(pattern)) {
  43. // convert to its BNG representation for matching
  44. BNGConverter converter(world->bng_engine.get_data(), world->bng_engine.get_config());
  45. bng_pattern = converter.convert_complex(*pattern, true);
  46. if (bng_pattern.has_compartment()) {
  47. // remove primary compartment were set, better explanation is in
  48. // MCell4Converter::convert_count_term_leaf_and_init_counting_flags
  49. primary_compartment_id = bng_pattern.get_primary_compartment_id();
  50. bng_pattern.remove_compartment_from_elem_mols(primary_compartment_id);
  51. }
  52. }
  53. Partition& p = world->get_partition(PARTITION_ID_INITIAL);
  54. std::vector<MCell::Molecule>& molecules = p.get_molecules();
  55. for (MCell::Molecule& m: molecules) {
  56. if (m.is_defunct()) {
  57. continue;
  58. }
  59. if (is_set(pattern)) {
  60. // include only molecules that match the pattern
  61. if (matching_species.count(m.species_id) != 0) {
  62. res.push_back(m.id);
  63. }
  64. else if (not_matching_species.count(m.species_id) != 0) {
  65. // nothing to do
  66. }
  67. else {
  68. // not seen species
  69. const BNG::Species& species = world->get_all_species().get(m.species_id);
  70. BNG::compartment_id_t species_compartment = species.get_primary_compartment_id();
  71. bool match = species.matches_pattern(bng_pattern, true) &&
  72. (primary_compartment_id == BNG::COMPARTMENT_ID_NONE || primary_compartment_id == species_compartment);
  73. if (match) {
  74. matching_species.insert(m.species_id);
  75. res.push_back(m.id);
  76. }
  77. else {
  78. not_matching_species.insert(m.species_id);
  79. }
  80. }
  81. }
  82. else {
  83. res.push_back(m.id);
  84. }
  85. }
  86. return res;
  87. }
  88. std::shared_ptr<API::Molecule> Introspection::get_molecule(const int id) {
  89. std::shared_ptr<API::Molecule> res;
  90. Partition& p = world->get_partition(PARTITION_ID_INITIAL);
  91. if (!p.does_molecule_exist(id)) {
  92. throw RuntimeError("Molecule with id " + to_string(id) + " does not exist.");
  93. }
  94. MCell::Molecule& m = p.get_m(id);
  95. assert(!m.is_defunct() && "is_defunct is checked already by does_molecule_exist()");
  96. res = make_shared<API::Molecule>(DefaultCtorArgType());
  97. res->id = m.id;
  98. res->species_id = m.species_id;
  99. if (m.is_surf()) {
  100. const MCell::Wall& w = p.get_wall(m.s.wall_index);
  101. const Vec3& w_vert0 = p.get_wall_vertex(w, 0);
  102. res->type = MoleculeType::SURFACE;
  103. res->pos2d = Vec2(m.s.pos * Vec2(world->config.length_unit)).to_vec();
  104. res->pos3d = Vec3(GeometryUtils::uv2xyz(m.s.pos, w, w_vert0) * Vec3(world->config.length_unit)).to_vec();
  105. res->orientation = convert_mcell_orientation(m.s.orientation);
  106. res->geometry_object = model_inst->get_geometry_object_with_id(w.object_id);
  107. assert(is_set(res->geometry_object));
  108. res->wall_index = m.s.wall_index - res->geometry_object->first_wall_index;
  109. }
  110. else {
  111. res->type = MoleculeType::VOLUME;
  112. res->pos3d = Vec3(m.v.pos * Vec3(world->config.length_unit)).to_vec();
  113. res->orientation = Orientation::NONE;
  114. }
  115. res->world = world;
  116. res->set_initialized();
  117. return res;
  118. }
  119. std::string Introspection::get_species_name(const int species_id) {
  120. if (!world->get_all_species().is_valid_id(species_id)) {
  121. throw RuntimeError("Species with id " + to_string(species_id) + " does not exist.");
  122. }
  123. return world->get_all_species().get(species_id).name;
  124. }
  125. std::vector<double> Introspection::get_vertex(std::shared_ptr<GeometryObject> object, const int vertex_index) {
  126. const MCell::Partition& p = world->get_partition(PARTITION_ID_INITIAL);
  127. return
  128. Vec3(
  129. p.get_geometry_vertex(object->get_partition_vertex_index(vertex_index)) * Vec3(world->config.length_unit)
  130. ).to_vec();
  131. }
  132. std::shared_ptr<Wall> Introspection::get_wall(std::shared_ptr<GeometryObject> object, const int wall_index) {
  133. object_is_set_and_initialized(object);
  134. const MCell::Partition& p = world->get_partition(PARTITION_ID_INITIAL);
  135. const MCell::Wall& w = p.get_wall(object->get_partition_wall_index(wall_index));
  136. auto res = make_shared<Wall>(DefaultCtorArgType());
  137. res->geometry_object = object;
  138. res->wall_index = wall_index;
  139. for (uint i = 0; i < VERTICES_IN_TRIANGLE; i++) {
  140. res->vertices.push_back(Vec3(p.get_geometry_vertex(w.vertex_indices[i]) * Vec3(world->config.length_unit)).to_vec());
  141. }
  142. res->area = w.area * world->config.length_unit * world->config.length_unit;
  143. assert(cmp_eq(len3(w.normal), (pos_t)1));
  144. res->unit_normal = w.normal.to_vec();
  145. res->is_movable = w.is_movable;
  146. res->world = world;
  147. return res;
  148. }
  149. std::vector<double> Introspection::get_vertex_unit_normal(std::shared_ptr<GeometryObject> object, const int vertex_index) {
  150. object_is_set_and_initialized(object);
  151. const MCell::Partition& p = world->get_partition(PARTITION_ID_INITIAL);
  152. const std::vector<wall_index_t>& walls = p.get_walls_using_vertex(object->get_partition_vertex_index(vertex_index));
  153. if (walls.empty()) {
  154. throw RuntimeError("Internal error: there are no walls that use vertex with index " +
  155. to_string(vertex_index) + " of object " + object->name + ".");
  156. }
  157. Vec3 normals_sum = Vec3(0);
  158. for (wall_index_t wi: walls) {
  159. const MCell::Wall& w = p.get_wall(wi);
  160. // wall normals are already unit vectors so we can just sum them
  161. normals_sum = normals_sum + w.normal;
  162. }
  163. return Vec3(normals_sum / Vec3(len3(normals_sum))).to_vec();
  164. }
  165. std::vector<double> Introspection::get_wall_unit_normal(std::shared_ptr<GeometryObject> object, const int wall_index) {
  166. object_is_set_and_initialized(object);
  167. const MCell::Partition& p = world->get_partition(PARTITION_ID_INITIAL);
  168. const MCell::Wall& w = p.get_wall(object->get_partition_wall_index(wall_index));
  169. // the value is is already normalized
  170. assert(cmp_eq(len3(w.normal), (pos_t)1));
  171. return w.normal.to_vec();
  172. }
  173. std::shared_ptr<Color> Introspection::get_wall_color(std::shared_ptr<GeometryObject> object, const int wall_index) {
  174. object_is_set_and_initialized(object);
  175. wall_index_t wi = object->get_partition_wall_index(wall_index);
  176. const MCell::GeometryObject& obj = world->get_geometry_object(object->geometry_object_id);
  177. rgba_t color = obj.get_wall_color(wi);
  178. std::shared_ptr<Color> res = make_shared<Color>(DefaultCtorArgType());
  179. res->set_rgba(color); // must use setter - initializes also other attributes
  180. return res;
  181. }
  182. void Introspection::set_wall_color(
  183. std::shared_ptr<GeometryObject> object, const int wall_index, std::shared_ptr<Color> color) {
  184. object_is_set_and_initialized(object);
  185. object_is_set_and_initialized(object);
  186. wall_index_t wi = object->get_partition_wall_index(wall_index);
  187. MCell::GeometryObject& obj = world->get_geometry_object(object->geometry_object_id);
  188. obj.set_wall_color(wi, color->get_rgba());
  189. }
  190. } // namespace API
  191. } // namespace MCell