diffuse_react_event.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. /******************************************************************************
  2. *
  3. * Copyright (C) 2019,2020 by
  4. * The Salk Institute for Biological Studies and
  5. * Pittsburgh Supercomputing Center, Carnegie Mellon University
  6. *
  7. * Use of this source code is governed by an MIT-style
  8. * license that can be found in the LICENSE file or at
  9. * https://opensource.org/licenses/MIT.
  10. *
  11. ******************************************************************************/
  12. #ifndef SRC4_DIFFUSE_REACT_EVENT_H_
  13. #define SRC4_DIFFUSE_REACT_EVENT_H_
  14. #include <vector>
  15. #include <deque>
  16. #include "../libs/boost/container/small_vector.hpp"
  17. #include "base_event.h"
  18. #include "partition.h"
  19. #include "collision_structs.h"
  20. namespace MCell {
  21. class World;
  22. class Partition;
  23. class Molecule;
  24. // we are executing diffusion every iteration, do not change this constant
  25. const double DIFFUSE_REACT_EVENT_PERIODICITY = 1.0;
  26. // this is an arbitrary value but let's say that we do now want to
  27. // simulate more than 100 iterations at once, this is used in scheduler
  28. // to find the next barrier
  29. const double DIFFUSION_TIME_UPPER_LIMIT = 100.0;
  30. enum class RayTraceState {
  31. UNDEFINED,
  32. HIT_SUBPARTITION,
  33. RAY_TRACE_HIT_WALL,
  34. FINISHED
  35. };
  36. enum class WallRxnResult {
  37. INVALID,
  38. TRANSPARENT,
  39. REFLECT,
  40. DESTROYED
  41. };
  42. class TileNeighborVector: public std::deque<WallTileIndexPair> {
  43. public:
  44. void dump(const std::string extra_comment, const std::string ind) {
  45. std::cout << ind << extra_comment << "\n";
  46. for (uint i = 0; i < size(); i++) {
  47. std::cout << ind << i << ": " << at(i).tile_index << "\n";
  48. }
  49. }
  50. };
  51. /**
  52. * Used as a pair molecule id, remaining timestep for molecules newly created in diffusion.
  53. * Using name action instead of event because events are handled by scheduler and are ordered by time.
  54. * These actions are simply processes in a queue (FIFO) manner.
  55. *
  56. * Used in diffuse_react _event_t and in partition_t.
  57. */
  58. class DiffuseAction {
  59. public:
  60. // position where this mol was created is
  61. // used to avoid rebinding for surf+vol->surf+vol reactions
  62. DiffuseAction(
  63. const molecule_id_t id_,
  64. const WallTileIndexPair& where_created_this_iteration_)
  65. :
  66. id(id_),
  67. where_created_this_iteration(where_created_this_iteration_) {
  68. }
  69. // position where the molecule was created may be unset when it was not a result of surface reaction
  70. DiffuseAction(const molecule_id_t id_)
  71. : id(id_) {
  72. }
  73. // defined because of usage in calendar_t
  74. const DiffuseAction& operator->() const { // TODO: remove
  75. return *this;
  76. }
  77. molecule_id_t id;
  78. // used to avoid rebinding for surf+vol->surf+vol reactions
  79. // TODO: can be removed and replaced with Molecule::previous_wall_index?
  80. WallTileIndexPair where_created_this_iteration;
  81. };
  82. /**
  83. * Diffuse all molecules with a given time step.
  84. * When a molecule is diffused, it is checked for collisions and reactions
  85. * are evaluated. Molecules newly created in reactions and diffused with their
  86. * remaining time.
  87. */
  88. class DiffuseReactEvent : public BaseEvent {
  89. public:
  90. DiffuseReactEvent(World* world_) :
  91. BaseEvent(EVENT_TYPE_INDEX_DIFFUSE_REACT),
  92. world(world_), time_up_to_next_barrier(FLT_INVALID) {
  93. // repeat this event each iteration
  94. periodicity_interval = DIFFUSE_REACT_EVENT_PERIODICITY;
  95. }
  96. void step() override;
  97. void dump(const std::string ind = "") const override;
  98. bool update_event_time_for_next_scheduled_time() override {
  99. assert(time_up_to_next_barrier != FLT_INVALID);
  100. // the next time to schedule
  101. if (time_up_to_next_barrier < periodicity_interval) {
  102. event_time = event_time + time_up_to_next_barrier;
  103. }
  104. else {
  105. event_time = event_time + periodicity_interval;
  106. }
  107. return true;
  108. }
  109. bool may_be_blocked_by_barrier_and_needs_set_time_step() const override {
  110. // DiffuseReactEvent must execute only up to a barrier such as CountEvent
  111. return true;
  112. }
  113. double get_max_time_up_to_next_barrier() const override {
  114. return DIFFUSION_TIME_UPPER_LIMIT;
  115. }
  116. void set_barrier_time_for_next_execution(const double time_up_to_next_barrier_) override {
  117. // scheduler says to this event for how long it can execute
  118. // either the maximum time step (periodicity_interval) or time up to the
  119. // first barrier
  120. release_assert(time_up_to_next_barrier_ > 0 && "Diffusion must advance even if a little bit");
  121. assert(cmp_eq(time_up_to_next_barrier_, round_f(time_up_to_next_barrier_)) &&
  122. "Time up to the next barrier is expected to be a whole number");
  123. time_up_to_next_barrier = time_up_to_next_barrier_;
  124. }
  125. void add_diffuse_action(const DiffuseAction& action) {
  126. new_diffuse_actions.push_back(action);
  127. }
  128. bool before_this_iterations_end(const double time) const {
  129. // must be lt to make sure that we don't simulate molecules with max_time close to 0
  130. return cmp_lt(time, event_time + periodicity_interval, EPS);
  131. }
  132. // used also directly from MCell API
  133. // returns true if molecule survived
  134. bool outcome_unimolecular(
  135. Partition& p,
  136. Molecule& vm,
  137. const double scheduled_time,
  138. BNG::RxnClass* rxn_class,
  139. const BNG::rxn_class_pathway_index_t pathway_index,
  140. MoleculeIdsVector* optional_product_ids = nullptr
  141. );
  142. // returns true if molecule survived
  143. bool cross_transparent_wall(
  144. Partition& p,
  145. const Collision& collision,
  146. Molecule& vm, // moves vm to the reflection point
  147. Vec3& remaining_displacement,
  148. double& t_steps,
  149. double& elapsed_molecule_time,
  150. wall_index_t& last_hit_wall_index
  151. );
  152. World* world;
  153. // this event diffuses all molecules that have this diffusion time_step
  154. double time_up_to_next_barrier;
  155. private:
  156. // auxiliary array used to store result from Partition::get_molecules_ready_for_diffusion
  157. // using the same array every iteration in order not to reallocate it every iteration
  158. MoleculeIdsVector molecules_ready_array;
  159. // internal event's schedule of molecules newly created in reactions that must be diffused
  160. std::vector<DiffuseAction> new_diffuse_actions;
  161. double get_max_time(Partition& p, Molecule& m);
  162. void diffuse_molecules(Partition& p, const MoleculeIdsVector& indices);
  163. void diffuse_single_molecule(
  164. Partition& p,
  165. const molecule_id_t vm_id,
  166. WallTileIndexPair where_created_this_iteration
  167. );
  168. // ---------------------------------- volume molecules ----------------------------------
  169. void diffuse_vol_molecule(
  170. Partition& p,
  171. Molecule& vm,
  172. double& max_time,
  173. const double diffusion_start_time,
  174. WallTileIndexPair& where_created_this_iteration
  175. );
  176. bool collide_and_react_with_vol_mol(
  177. Partition& p,
  178. const Collision& collision,
  179. Vec3& displacement,
  180. const double t_steps,
  181. const double r_rate_factor,
  182. const double elapsed_molecule_time
  183. );
  184. int collide_and_react_with_surf_mol(
  185. Partition& p,
  186. const Collision& collision,
  187. const double r_rate_factor,
  188. WallTileIndexPair& where_created_this_iteration,
  189. wall_index_t& last_hit_wall_index,
  190. Vec3& remaining_displacement,
  191. double& t_steps,
  192. double& elapsed_molecule_time
  193. );
  194. WallRxnResult collide_and_react_with_walls(
  195. Partition& p,
  196. Collision& collision,
  197. const double r_rate_factor,
  198. const double elapsed_molecule_time,
  199. const double t_steps
  200. );
  201. // ---------------------------------- surface molecules ----------------------------------
  202. void diffuse_surf_molecule(
  203. Partition& p,
  204. Molecule& sm,
  205. double& max_time,
  206. const double diffusion_start_time
  207. );
  208. wall_index_t ray_trace_surf(
  209. Partition& p,
  210. const BNG::Species& species,
  211. const molecule_id_t sm_id,
  212. Vec2& remaining_displacement,
  213. Vec2& new_pos,
  214. BNG::RxnClass*& absorb_now_rxn_class // set to non-null is molecule has to be absorbed
  215. );
  216. bool react_2D_all_neighbors(
  217. Partition& p,
  218. Molecule& sm,
  219. const double time, // same argument as t passed in mcell3 (come up with a better name)
  220. const double diffusion_start_time // diffusion_start_time + elapsed_molecule_time should be the time when reaction occurred
  221. );
  222. bool react_2D_intermembrane(
  223. Partition& p, Molecule& sm,
  224. const double t_steps, const double diffusion_start_time
  225. );
  226. // ---------------------------------- reactions ----------------------------------
  227. int find_surf_product_positions(
  228. Partition& p,
  229. const Collision& collision,
  230. const BNG::RxnRule* rxn,
  231. const Molecule* reacA, const bool keep_reacA,
  232. const Molecule* reacB, const bool keep_reacB,
  233. const Molecule* surf_reac,
  234. const BNG::RxnProductsVector& actual_products,
  235. GridPosVector& assigned_surf_product_positions,
  236. uint& num_surface_products,
  237. bool& surf_pos_reacA_is_used
  238. );
  239. int outcome_bimolecular(
  240. Partition& p,
  241. const Collision& collision,
  242. const int path,
  243. const double remaining_time_step
  244. );
  245. int outcome_intersect(
  246. Partition& p,
  247. BNG::RxnClass* rxn_class,
  248. const BNG::rxn_class_pathway_index_t pathway_index,
  249. Collision& collision,
  250. const double time
  251. );
  252. void handle_rxn_callback(
  253. Partition& p,
  254. const Collision& collision,
  255. const double time,
  256. const BNG::RxnRule* rxn,
  257. const Molecule* reac1,
  258. const Molecule* reac2,
  259. const MoleculeIdsVector& product_ids,
  260. bool& cancel_reaction
  261. );
  262. orientation_t determine_orientation_depending_on_surf_comp(
  263. const species_id_t prod_species_id,
  264. const Molecule* surf_reac
  265. );
  266. int outcome_products_random(
  267. Partition& p,
  268. const Collision& collision,
  269. const double remaining_time_step,
  270. const BNG::rxn_class_pathway_index_t pathway_index,
  271. bool& keep_reacA,
  272. bool& keep_reacB,
  273. MoleculeIdsVector* optional_product_ids = nullptr
  274. );
  275. void pick_unimol_rxn_class_and_set_rxn_time(
  276. Partition& p,
  277. const double remaining_time_step,
  278. Molecule& vm
  279. );
  280. bool react_unimol_single_molecule(
  281. Partition& p,
  282. const molecule_id_t vm_id
  283. );
  284. };
  285. RayTraceState ray_trace_vol(
  286. Partition& p,
  287. rng_state& rng,
  288. const molecule_id_t vm_id, // molecule that we are diffusing, we are changing its pos and possibly also subvolume
  289. const bool can_vol_react,
  290. const wall_index_t previous_reflected_wall, // is WALL_INDEX_INVALID when our molecule did not replect from anything this iddfusion step yet
  291. Vec3& remaining_displacement, // in/out - recomputed if there was a reflection
  292. CollisionsVector& molecule_collisions // possible reactions in this part of way marching, ordered by time
  293. );
  294. void sort_collisions_by_time(CollisionsVector& molecule_collisions);
  295. } // namespace mcell
  296. #endif // SRC4_DIFFUSE_REACT_EVENT_H_