Line data Source code
1 : #ifndef REACTIONENGINE_HPP 2 : #define REACTIONENGINE_HPP 3 : 4 : #include "CollisionDetector.hpp" 5 : #include "MathUtils.hpp" 6 : 7 : #include <functional> 8 : #include <optional> 9 : #include <unordered_set> 10 : 11 : namespace cell 12 : { 13 : 14 : class DiscType; 15 : class Disc; 16 : class ReactionTable; 17 : 18 : using SingleLookupMap = DiscTypeMap<std::vector<Reaction>>; 19 : using PairLookupMap = DiscTypePairMap<std::vector<Reaction>>; 20 : 21 : class ReactionEngine 22 : { 23 : public: 24 : ReactionEngine(const DiscTypeRegistry& discTypeRegistry, const ReactionTable& reactionTable); 25 : 26 : /** 27 : * @brief Transformation reaction A -> B. Changes the type of the disc to a new one if a reaction occurs. 28 : */ 29 : Disc transformationReaction(Disc* educt, DiscTypeID productID) const; 30 : 31 : /** 32 : * @brief Decomposition reaction A -> B + C. 33 : */ 34 : std::pair<Disc, Disc> decompositionReaction(Disc* educt, DiscTypeID product1ID, DiscTypeID product2ID) const; 35 : 36 : /** 37 : * @brief Combination reaction A + B -> C. Destroys one of the 2 educt discs and changes the other if a reaction 38 : * occurs. 39 : */ 40 : Disc combinationReaction(Disc* educt1, Disc* educt2, DiscTypeID productID) const; 41 : 42 : /** 43 : * @brief Exchange reaction A + B -> C + D. Just changes the disc types of the reacting discs. 44 : */ 45 : std::pair<Disc, Disc> exchangeReaction(Disc* educt1, Disc* educt2, DiscTypeID product1ID, 46 : DiscTypeID product2ID) const; 47 : 48 : void applyUnimolecularReactions(Disc& disc, double dt, std::vector<Disc>& newDiscs) const; 49 : 50 : void applyBimolecularReactions(const std::vector<CollisionDetector::Collision>& collisions, 51 : std::vector<Disc>& newDiscs) const; 52 : 53 : private: 54 : template <typename MapType, typename KeyType, typename Condition> 55 : const Reaction* selectReaction(const MapType& map, const KeyType& key, const Condition& condition) const; 56 : 57 : const Reaction* selectUnimolecularReaction(const DiscTypeID& key, double dt) const; 58 : const Reaction* selectBimolecularReaction(const std::pair<DiscTypeID, DiscTypeID>& key) const; 59 : void combineReactionsIntoSingleMaps(const ReactionTable& reactionTable); 60 : 61 : private: 62 : const DiscTypeRegistry& discTypeRegistry_; 63 : SingleLookupMap unimolecularReactions_; 64 : PairLookupMap bimolecularReactions_; 65 : }; 66 : 67 : template <typename MapType, typename KeyType, typename Condition> 68 33 : inline const Reaction* ReactionEngine::selectReaction(const MapType& map, const KeyType& key, 69 : const Condition& condition) const 70 : { 71 33 : auto iter = map.find(key); 72 33 : if (iter == map.end()) 73 25 : return nullptr; 74 : 75 8 : const auto& reactions = iter->second; 76 : 77 : // ReactionTable never constructs empty vectors, so reaction.size() is always > 0 78 8 : auto start = mathutils::getRandomNumber<std::size_t>(0, reactions.size() - 1); 79 : 80 8 : for (std::size_t i = 0; i < reactions.size(); ++i) 81 : { 82 8 : const auto& reaction = reactions[(start + i) % reactions.size()]; 83 8 : if (condition(reaction)) 84 8 : return &reaction; 85 : } 86 : 87 0 : return nullptr; 88 : } 89 : 90 : } // namespace cell 91 : 92 : #endif /* REACTIONENGINE_HPP */