Line data Source code
1 : #ifndef ED35F035_9593_4A1C_8F2D_8CE870BB9BF9_HPP
2 : #define ED35F035_9593_4A1C_8F2D_8CE870BB9BF9_HPP
3 :
4 : #include "DiscType.hpp"
5 : #include "StringUtils.hpp"
6 :
7 : #include <optional>
8 :
9 : namespace cell
10 : {
11 :
12 : class Reaction;
13 :
14 : /**
15 : * @brief Checks if all products and educts have identical disc type names
16 : */
17 : bool operator==(const Reaction& reaction1, const Reaction& reaction2);
18 :
19 : /**
20 : * @brief String representation in the form of A + B -> C + D
21 : */
22 : std::string toString(const Reaction& reaction, const DiscTypeRegistry& discTypeRegistry);
23 :
24 : /**
25 : * @returns `true` if the given disctype is part of the educts or products of the reaction
26 : */
27 : bool contains(const Reaction& reaction, DiscTypeID discType);
28 :
29 : /**
30 : * @brief Contains a uni- or bimolecular reaction.
31 : *
32 : * Given `DiscType`s A, B, C and D, and reaction probability 0 <= p <=
33 : * 1, supported reaction types are:
34 : * ```cpp
35 : * Reaction(A, nullopt, B, nullopt, p); // Transformation reaction: A -> B
36 : * Reaction(A, nullopt, B, C, p); // Decomposition reaction: A -> B + C
37 : * Reaction(A, B, C, nullopt, p); // Combination reaction: A + B -> C
38 : * Reaction(A, B, C, D, p); // Exchange reaction: A + B -> C + D
39 : * ```
40 : *
41 : * For transformation and decomposition reactions, p is interpreted in terms of probability per second for each disc in
42 : * the simulation. For combination and exchange reactions, p is the reaction probability for a single collision
43 : * @note For bimolecular reactions, probabilities are per second, but the edge case p = 1 breaks this and will cause an
44 : * immediate reaction no matter how small the simulation time step is. Use a value close to, but not equal to 1 to avoid
45 : * this (like 0.99)
46 : */
47 : class Reaction
48 : {
49 : public:
50 : enum class Type
51 : {
52 : Transformation,
53 : Decomposition,
54 : Combination,
55 : Exchange,
56 : None
57 : };
58 :
59 : public:
60 : /**
61 : * @brief Creates a new reaction, inferring the type from the provided arguments. Throws if the given probability is
62 : * not in the interval [0, 1]
63 : */
64 : Reaction(DiscTypeID educt1, const std::optional<DiscTypeID>& educt2, DiscTypeID product1,
65 : const std::optional<DiscTypeID>& product2, double probability);
66 :
67 : // Boilerplate getters and setters with no additional documentation
68 :
69 44 : DiscTypeID getEduct1() const noexcept
70 : {
71 44 : return educt1_;
72 : }
73 :
74 : void setEduct1(DiscTypeID educt1) noexcept
75 : {
76 : educt1_ = educt1;
77 : }
78 :
79 25 : DiscTypeID getEduct2() const
80 : {
81 : #ifdef DEBUG
82 25 : if (!educt2_)
83 0 : throw ExceptionWithLocation("Can't get educt2 for reaction of type" + getTypeString());
84 : #endif
85 :
86 25 : return *educt2_;
87 : }
88 :
89 16 : bool hasEduct2() const noexcept
90 : {
91 16 : return type_ == Type::Combination || type_ == Type::Exchange;
92 : }
93 :
94 : void setEduct2(DiscTypeID educt2)
95 : {
96 : #ifdef DEBUG
97 : if (!educt2_)
98 : throw ExceptionWithLocation("Can't set educt2 for reaction of type" + getTypeString());
99 : #endif
100 :
101 : educt2_ = educt2;
102 : }
103 :
104 20 : DiscTypeID getProduct1() const noexcept
105 : {
106 20 : return product1_;
107 : }
108 :
109 : void setProduct1(DiscTypeID product1) noexcept
110 : {
111 : product1_ = product1;
112 : }
113 :
114 8 : DiscTypeID getProduct2() const
115 : {
116 : #ifdef DEBUG
117 8 : if (!product2_)
118 0 : throw ExceptionWithLocation("Can't get product2 for reaction of type" + getTypeString());
119 : #endif
120 :
121 8 : return *product2_;
122 : }
123 :
124 16 : bool hasProduct2() const noexcept
125 : {
126 16 : return type_ == Type::Decomposition || type_ == Type::Exchange;
127 : }
128 :
129 : void setProduct2(DiscTypeID product2)
130 : {
131 : #ifdef DEBUG
132 : if (!product2_)
133 : throw ExceptionWithLocation("Can't set product2 for reaction of type" + getTypeString());
134 : #endif
135 :
136 : product2_ = product2;
137 : }
138 :
139 8 : double getProbability() const noexcept
140 : {
141 8 : return probability_;
142 : }
143 :
144 : void setProbability(double probability);
145 :
146 86 : Type getType() const noexcept
147 : {
148 86 : return type_;
149 : }
150 :
151 : /**
152 : * @brief Validates that
153 : *
154 : * - educts and products of transformation reactions A -> B are not identical (A must be unequal B)
155 : *
156 : * - educt and product masses are the same
157 : */
158 : void validate(const DiscTypeRegistry& discTypeRegistry) const;
159 :
160 : private:
161 : std::string getTypeString() const;
162 :
163 : private:
164 : DiscTypeID educt1_;
165 : std::optional<DiscTypeID> educt2_;
166 : DiscTypeID product1_;
167 : std::optional<DiscTypeID> product2_;
168 : double probability_ = 0;
169 : Type type_ = Type::None;
170 : };
171 :
172 : Reaction::Type inferReactionType(bool educt2, bool product2);
173 :
174 : } // namespace cell
175 :
176 : #endif /* ED35F035_9593_4A1C_8F2D_8CE870BB9BF9_HPP */
|