generator_utils.h 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  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. /**
  12. * This file is directly included because it contains templates and also to avoid the
  13. * need to have two declarations (in .h + in .cpp) for each function.
  14. */
  15. #ifndef SRC4_PYMCELLCONVERTER_GENERATOR_UTILS_H_
  16. #define SRC4_PYMCELLCONVERTER_GENERATOR_UTILS_H_
  17. #include <iostream>
  18. #include <string>
  19. #include <cassert>
  20. #include <regex>
  21. #include "libmcell/generated/gen_names.h"
  22. #include "include/datamodel_defines.h"
  23. #include "libmcell/api/api_utils.h"
  24. #include "libmcell/api/python_export_constants.h"
  25. #include "libmcell/api/python_export_utils.h"
  26. #include "libmcell/api/api_common.h"
  27. using namespace std;
  28. namespace MCell {
  29. using namespace API;
  30. using Json::Value;
  31. struct SharedGenData;
  32. const uint TESTING_RXN_CLASS_CLEANUP_PERIODICITY = 100;
  33. const uint TESTING_SPECIES_CLEANUP_PERIODICITY = 500;
  34. const char* const NAME_PARAMETER = "parameter";
  35. // using exception catching to recover from errors
  36. #define CHECK(stmt, failed) \
  37. do { \
  38. try { \
  39. (stmt); \
  40. } \
  41. catch (exception& e) { \
  42. cerr << e.what() << "\n"; \
  43. cerr << "Exception caught in '" << __FUNCTION__ << "' after conversion error.\n"; \
  44. failed = true; \
  45. } \
  46. } while (0)
  47. #define CHECK_PROPERTY(cond) \
  48. do { \
  49. if(!(cond)) { \
  50. throw ConversionError(S("Error: Expected '") + #cond + "' is false. (" + __FUNCTION__ + " - " + __FILE__ + ":" + to_string(__LINE__) + ")"); \
  51. } \
  52. } while (0)
  53. #define ERROR(msg) throw ConversionError(S("Error: ") + msg + " (function " + __FUNCTION__ + ")")
  54. // key - MDL name, used in data model, value.first - Python name, value.second - BNGL name
  55. const std::map<const std::string, std::pair<const std::string, const std::string>> mdl_functions_to_py_bngl_map {
  56. { "SQRT", {"math.sqrt", "sqrt"} },
  57. { "EXP", {"math.exp", "exp"} },
  58. { "LOG", {"math.log", "ln"} },
  59. { "LOG10", {"math.log10", "log10"} },
  60. { "SIN", {"math.sin", "sin"} },
  61. { "COS", {"math.cos", "cos"} },
  62. { "TAN", {"math.tan", "tan"} },
  63. { "ASIN", {"math.asin", "asin"} },
  64. { "ACOS", {"math.acos", "acos"} },
  65. { "ATAN", {"math.atan", "atan"} },
  66. { "ABS", {"abs", "abs"} },
  67. { "CEIL", {"math.ceil", "ceil"} },
  68. { "FLOOR", {"math.floor", "floor"} },
  69. { "MAX", {"max", "max"} },
  70. { "MIN", {"min", "min"} }
  71. };
  72. // TODO: use also in other places where it may be useful, currently just for release site quantity
  73. void check_not_empty(const Value& parent, const char* key, const std::string& msg_location);
  74. // when use_python_functions is true, function calls are replaced with Python function names
  75. // when False, they are replaced with BNGL function names
  76. std::string replace_function_calls_in_expr(const std::string& data_model_expr, const bool use_python_functions);
  77. std::string get_module_name_w_prefix(const std::string& output_files_prefix, const std::string file_suffix);
  78. void parse_rxn_rule_side(
  79. Json::Value& substances_node,
  80. std::vector<std::string>& substances,
  81. std::vector<std::string>& orientations);
  82. // throws exception when the member is member is there
  83. static Value& get_node(const string parent_name, Value& parent, const string name) {
  84. if (!parent.isMember(name)) {
  85. throw ConversionError("Error: Node '" + parent_name + "' does not contain expected node '" + name + "'.");
  86. }
  87. return parent[name];
  88. }
  89. // used when we know that the member is there
  90. static Value& get_node(Value& parent, const string name) {
  91. assert(parent.isMember(name));
  92. return parent[name];
  93. }
  94. static string fix_dots_in_simple_species(const string& s) {
  95. string res = s;
  96. if (API::is_simple_species(s)) {
  97. replace(res.begin(), res.end(), '.', '_');
  98. }
  99. return res;
  100. }
  101. string remove_compartments(const std::string& species_name);
  102. string get_single_compartment(const std::string& name, bool* has_multiple_compartments = nullptr);
  103. string make_species_or_cplx(
  104. const SharedGenData& data,
  105. const std::string& name,
  106. const std::string& orient = "",
  107. const std::string& compartment = "");
  108. static string make_species(const string bngl_str) {
  109. return S(MDOT) + API::NAME_CLASS_SPECIES + "('" + fix_dots_in_simple_species(bngl_str) + "')";
  110. }
  111. static void check_versions(
  112. const string node_name, Json::Value& node,
  113. const char* const version1, const char* const version2) {
  114. if (node[KEY_DATA_MODEL_VERSION].asString() != version1 &&
  115. node[KEY_DATA_MODEL_VERSION].asString() != version2) {
  116. throw ConversionError(
  117. "Error: version for " + node_name + " is " + node[KEY_DATA_MODEL_VERSION].asString() +
  118. ", expected " + version1 + " or " + version2 + ".");
  119. }
  120. }
  121. static void check_version(const string node_name, Json::Value& node, const char* const version) {
  122. if (!node.isMember(KEY_DATA_MODEL_VERSION) || node[KEY_DATA_MODEL_VERSION].asString() == "") {
  123. cout << "Warning: data model node " + node_name + " does not have its version specified, not checking the version.\n";
  124. }
  125. else if (node[KEY_DATA_MODEL_VERSION].asString() != version) {
  126. throw ConversionError(
  127. "Error: version for " + node_name + " is " + node[KEY_DATA_MODEL_VERSION].asString() +
  128. ", expected " + version + ".");
  129. }
  130. }
  131. static string convert_orientation(const string s, const bool return_any_orientation = false) {
  132. if (s == "\'") {
  133. return API::NAME_EV_UP;
  134. }
  135. else if (s == ",") {
  136. return API::NAME_EV_DOWN;
  137. }
  138. else if (s == ";" || s == "") {
  139. if (return_any_orientation && s == ";") {
  140. return API::NAME_EV_ANY;
  141. }
  142. else {
  143. return "";
  144. }
  145. }
  146. else {
  147. ERROR("Invalid orientation '" + s + "'.");
  148. return "INVALID_ORIENTATION";
  149. }
  150. }
  151. // NOTE: the same code is in mcell3_world_converter.cpp
  152. static bool ends_with(std::string const & value, std::string const & ending)
  153. {
  154. if (ending.size() > value.size()) {
  155. return false;
  156. }
  157. return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
  158. }
  159. static string trim(const string& str)
  160. {
  161. size_t first = str.find_first_not_of(' ');
  162. if (string::npos == first)
  163. {
  164. return str;
  165. }
  166. size_t last = str.find_last_not_of(' ');
  167. return str.substr(first, (last - first + 1));
  168. }
  169. string get_rxn_id(Json::Value& reaction_list_item, uint& unnamed_rxn_counter);
  170. string create_count_name(
  171. const string& what_to_count, const string& where_to_count, const bool molecules_not_species);
  172. uint get_num_counts_in_mdl_string(const string& mdl_string);
  173. string remove_c_comment(const string& str);
  174. string remove_whitespace(const string& str);
  175. size_t find_end_brace_pos(const string& str, const size_t start);
  176. void process_single_count_term(
  177. const SharedGenData& data,
  178. const string& mdl_string,
  179. bool& rxn_not_mol,
  180. bool& molecules_not_species,
  181. string& what_to_count,
  182. string& where_to_count,
  183. string& orientation);
  184. // sets val if the name_or_value is a floating point value,
  185. // if not, tries to find the parameter and reads its value
  186. // returns true on success
  187. // parameters are not evaluated and only one level is tried,
  188. // returns false if value was not obtained
  189. bool get_parameter_value(Json::Value& mcell, const string& name_or_value, double& val);
  190. bool is_volume_species(Json::Value& mcell, const std::string& species_name);
  191. } // namespace MCell
  192. #endif // SRC4_PYMCELLCONVERTER_GENERATOR_UTILS_H_