gen_complex.cpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. /******************************************************************************
  2. *
  3. * Copyright (C) 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 <sstream>
  12. #include "api/pybind11_stl_include.h"
  13. #include "api/python_export_utils.h"
  14. #include "gen_complex.h"
  15. #include "api/complex.h"
  16. #include "api/elementary_molecule.h"
  17. #include "api/species.h"
  18. namespace MCell {
  19. namespace API {
  20. void GenComplex::check_semantics() const {
  21. }
  22. void GenComplex::set_initialized() {
  23. vec_set_initialized(elementary_molecules);
  24. initialized = true;
  25. }
  26. void GenComplex::set_all_attributes_as_default_or_unset() {
  27. class_name = "Complex";
  28. name = STR_UNSET;
  29. elementary_molecules = std::vector<std::shared_ptr<ElementaryMolecule>>();
  30. orientation = Orientation::DEFAULT;
  31. compartment_name = STR_UNSET;
  32. }
  33. std::shared_ptr<Complex> GenComplex::copy_complex() const {
  34. std::shared_ptr<Complex> res = std::make_shared<Complex>(DefaultCtorArgType());
  35. res->class_name = class_name;
  36. res->name = name;
  37. res->elementary_molecules = elementary_molecules;
  38. res->orientation = orientation;
  39. res->compartment_name = compartment_name;
  40. return res;
  41. }
  42. std::shared_ptr<Complex> GenComplex::deepcopy_complex(py::dict) const {
  43. std::shared_ptr<Complex> res = std::make_shared<Complex>(DefaultCtorArgType());
  44. res->class_name = class_name;
  45. res->name = name;
  46. for (const auto& item: elementary_molecules) {
  47. res->elementary_molecules.push_back((is_set(item)) ? item->deepcopy_elementary_molecule() : nullptr);
  48. }
  49. res->orientation = orientation;
  50. res->compartment_name = compartment_name;
  51. return res;
  52. }
  53. bool GenComplex::__eq__(const Complex& other) const {
  54. return
  55. name == other.name &&
  56. vec_ptr_eq(elementary_molecules, other.elementary_molecules) &&
  57. orientation == other.orientation &&
  58. compartment_name == other.compartment_name;
  59. }
  60. bool GenComplex::eq_nonarray_attributes(const Complex& other, const bool ignore_name) const {
  61. return
  62. (ignore_name || name == other.name) &&
  63. true /*elementary_molecules*/ &&
  64. orientation == other.orientation &&
  65. compartment_name == other.compartment_name;
  66. }
  67. std::string GenComplex::to_str(const bool all_details, const std::string ind) const {
  68. std::stringstream ss;
  69. ss << get_object_name() << ": " <<
  70. "name=" << name << ", " <<
  71. "\n" << ind + " " << "elementary_molecules=" << vec_ptr_to_str(elementary_molecules, all_details, ind + " ") << ", " << "\n" << ind + " " <<
  72. "orientation=" << orientation << ", " <<
  73. "compartment_name=" << compartment_name;
  74. return ss.str();
  75. }
  76. py::class_<Complex> define_pybinding_Complex(py::module& m) {
  77. return py::class_<Complex, std::shared_ptr<Complex>>(m, "Complex", "This class represents a complex molecule composed of molecule instances.\nIt is either defined using a BNGL string or using a list of elementary molecule instances.\nOn top of that, orientation may be defined.\nThis class is most often by calling its constructor as m.Complex(bngl_string) in cases where a \nfully qualified instance (such as for molecule releases) or a pattern (in observable counts) is needed. \nComparison operator __eq__ first converts complexes to their canonical representation and \nthen does comparison so for instance m.Complex('A(b!1).B(a!1)') == m.Complex('B(a!2).A(b!2)').\n")
  78. .def(
  79. py::init<
  80. const std::string&,
  81. const std::vector<std::shared_ptr<ElementaryMolecule>>,
  82. const Orientation,
  83. const std::string&
  84. >(),
  85. py::arg("name") = STR_UNSET,
  86. py::arg("elementary_molecules") = std::vector<std::shared_ptr<ElementaryMolecule>>(),
  87. py::arg("orientation") = Orientation::DEFAULT,
  88. py::arg("compartment_name") = STR_UNSET
  89. )
  90. .def("check_semantics", &Complex::check_semantics)
  91. .def("__copy__", &Complex::copy_complex)
  92. .def("__deepcopy__", &Complex::deepcopy_complex, py::arg("memo"))
  93. .def("__str__", &Complex::to_str, py::arg("all_details") = false, py::arg("ind") = std::string(""))
  94. .def("__eq__", &Complex::__eq__, py::arg("other"))
  95. .def("to_bngl_str", &Complex::to_bngl_str, "Creates a string that corresponds to its BNGL representation including compartments.")
  96. .def("as_species", &Complex::as_species, "Returns a Species object based on this Complex. All species-specific \nattributes are set to their default values and 'name' is set to value returned by \n'to_bngl_str()'.\n")
  97. .def("dump", &Complex::dump)
  98. .def_property("name", &Complex::get_name, &Complex::set_name, "When set, this complex instance is initialized from a BNGL string passed as this argument, \nthe string is parsed and elementary_molecules and compartment are initialized.\nOnly one of name or elementary_molecules can be set. \n")
  99. .def_property("elementary_molecules", &Complex::get_elementary_molecules, &Complex::set_elementary_molecules, py::return_value_policy::reference, "Individual molecule instances contained in the complex.\nOnly one of name or elementary_molecules can be set.\n")
  100. .def_property("orientation", &Complex::get_orientation, &Complex::set_orientation, "Specifies orientation of a molecule. \nWhen Orientation.DEFAULT if kept then during model initialization is\n'orientation' set to Orientation.NONE for volume complexes and to \nOrientation.UP for surface complexes.\nIgnored by derived class Species.\n")
  101. .def_property("compartment_name", &Complex::get_compartment_name, &Complex::set_compartment_name, "Specifies compartment name of this Complex.\nOnly one of 'orientation' and 'compartment_name' can be set. \nCorresponds to BNGL specification of a compartment for the whole complex '@COMP:'.\nIf a 2D/surface compartment is specified, the complex must be a surface complex and \norientation is set to Orientation.UP.\nIf a 3D/volume compartment is specified, the complex must be a volume complex and\norientation is set to Orientation.NONE.\nSets compartment to all elementary molecules whose compartment is unset. Does not override \nspecific compartments of elementary molecules that were already set.\nIf this is a volume complex (all elementary molecules have their diffusion_constant_3d set), \nall compartments of elementary molecules must be the same volume compartment.\nIf this is a surface complex (at least one elementary molecule has its their diffusion_constant_2d \nset), all compartments of surface elementary molecules must be the same, and\nall compartments of volume elementary molecules must be from the two neighboring \nvolume compartments.\n")
  102. ;
  103. }
  104. std::string GenComplex::export_to_python(std::ostream& out, PythonExportContext& ctx) {
  105. if (!export_even_if_already_exported() && ctx.already_exported(this)) {
  106. return ctx.get_exported_name(this);
  107. }
  108. std::string exported_name = std::string("complex") + "_" + (is_set(name) ? fix_id(name) : std::to_string(ctx.postinc_counter("complex")));
  109. if (!export_even_if_already_exported()) {
  110. ctx.add_exported(this, exported_name);
  111. }
  112. bool str_export = export_as_string_without_newlines();
  113. std::string nl = "";
  114. std::string ind = " ";
  115. std::stringstream ss;
  116. if (!str_export) {
  117. nl = "\n";
  118. ind = " ";
  119. ss << exported_name << " = ";
  120. }
  121. ss << "m.Complex(" << nl;
  122. if (name != STR_UNSET) {
  123. ss << ind << "name = " << "'" << name << "'" << "," << nl;
  124. }
  125. if (elementary_molecules != std::vector<std::shared_ptr<ElementaryMolecule>>() && !skip_vectors_export()) {
  126. ss << ind << "elementary_molecules = " << export_vec_elementary_molecules(out, ctx, exported_name) << "," << nl;
  127. }
  128. if (orientation != Orientation::DEFAULT) {
  129. ss << ind << "orientation = " << orientation << "," << nl;
  130. }
  131. if (compartment_name != STR_UNSET) {
  132. ss << ind << "compartment_name = " << "'" << compartment_name << "'" << "," << nl;
  133. }
  134. ss << ")" << nl << nl;
  135. if (!str_export) {
  136. out << ss.str();
  137. return exported_name;
  138. }
  139. else {
  140. return ss.str();
  141. }
  142. }
  143. std::string GenComplex::export_vec_elementary_molecules(std::ostream& out, PythonExportContext& ctx, const std::string& parent_name) {
  144. // does not print the array itself to 'out' and returns the whole list
  145. std::stringstream ss;
  146. ss << "[";
  147. for (size_t i = 0; i < elementary_molecules.size(); i++) {
  148. const auto& item = elementary_molecules[i];
  149. if (i == 0) {
  150. ss << " ";
  151. }
  152. else if (i % 16 == 0) {
  153. ss << "\n ";
  154. }
  155. if (!item->skip_python_export()) {
  156. std::string name = item->export_to_python(out, ctx);
  157. ss << name << ", ";
  158. }
  159. }
  160. ss << "]";
  161. return ss.str();
  162. }
  163. } // namespace API
  164. } // namespace MCell