LCOV - code coverage report
Current view: top level - cell - Reaction.hpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 18 20 90.0 %
Date: 2025-12-26 22:55:38 Functions: 8 8 100.0 %

          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 */

Generated by: LCOV version 1.14