LCOV - code coverage report
Current view: top level - cell - Reaction.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 58 99 58.6 %
Date: 2025-12-06 00:15:40 Functions: 15 22 68.2 %

          Line data    Source code
       1             : #include "Reaction.hpp"
       2             : #include "ExceptionWithLocation.hpp"
       3             : #include "Hashing.hpp"
       4             : 
       5             : namespace cell
       6             : {
       7             : 
       8             : namespace
       9             : {
      10           0 : std::string toString(Reaction::Type type)
      11             : {
      12           0 :     switch (type)
      13             :     {
      14           0 :     case Reaction::Type::Decomposition: return "Decomposition";
      15           0 :     case Reaction::Type::Transformation: return "Transformation";
      16           0 :     case Reaction::Type::Combination: return "Combination";
      17           0 :     case Reaction::Type::Exchange: return "Exchange";
      18           0 :     case Reaction::Type::None: return "None";
      19           0 :     default: throw ExceptionWithLocation("Invalid reaction type");
      20             :     }
      21             : }
      22             : } // namespace
      23             : 
      24           4 : bool operator==(const Reaction& a, const Reaction& b)
      25             : {
      26           8 :     return a.getEduct1() == b.getEduct1() && a.hasEduct2() == b.hasEduct2() &&
      27           8 :            (!a.hasEduct2() || a.getEduct2() == b.getEduct2()) && a.getProduct1() == b.getProduct1() &&
      28          12 :            a.hasProduct2() == b.hasProduct2() && (!a.hasProduct2() || a.getProduct2() == b.getProduct2());
      29             : }
      30             : 
      31           4 : std::string toString(const Reaction& reaction, const DiscTypeRegistry& discTypeRegistry)
      32             : {
      33           4 :     std::string result = discTypeRegistry.getByID(reaction.getEduct1()).getName();
      34             : 
      35           4 :     if (reaction.hasEduct2())
      36           2 :         result += " + " + discTypeRegistry.getByID(reaction.getEduct2()).getName();
      37             : 
      38           4 :     result += " -> " + discTypeRegistry.getByID(reaction.getProduct1()).getName();
      39             : 
      40           4 :     if (reaction.hasProduct2())
      41           2 :         result += " + " + discTypeRegistry.getByID(reaction.getProduct2()).getName();
      42             : 
      43           4 :     return result;
      44           0 : }
      45             : 
      46           0 : bool contains(const Reaction& reaction, DiscTypeID discType)
      47             : {
      48           0 :     return reaction.getEduct1() == discType || reaction.getEduct2() == discType || reaction.getProduct1() == discType ||
      49           0 :            reaction.getProduct2() == discType;
      50             : }
      51             : 
      52          10 : Reaction::Type inferReactionType(bool educt2, bool product2)
      53             : {
      54          10 :     if (!educt2 && !product2)
      55           2 :         return Reaction::Type::Transformation;
      56           8 :     else if (educt2 && !product2)
      57           4 :         return Reaction::Type::Combination;
      58           4 :     else if (!educt2 && product2)
      59           2 :         return Reaction::Type::Decomposition;
      60             :     else
      61           2 :         return Reaction::Type::Exchange;
      62             : }
      63             : 
      64           0 : size_t ReactionHash::operator()(const Reaction& reaction) const
      65             : {
      66           0 :     auto hash = calculateHash(reaction.getEduct1(), reaction.getProduct1());
      67             : 
      68           0 :     if (reaction.hasEduct2())
      69           0 :         hashCombine(hash, reaction.getEduct2());
      70             : 
      71           0 :     if (reaction.hasProduct2())
      72           0 :         hashCombine(hash, reaction.getProduct2());
      73             : 
      74           0 :     return hash;
      75             : }
      76             : 
      77          10 : Reaction::Reaction(DiscTypeID educt1, const std::optional<DiscTypeID>& educt2, DiscTypeID product1,
      78          10 :                    const std::optional<DiscTypeID>& product2, double probability)
      79          10 :     : educt1_(educt1)
      80          10 :     , educt2_(educt2)
      81          10 :     , product1_(product1)
      82          10 :     , product2_(product2)
      83          10 :     , type_(inferReactionType(educt2.has_value(), product2.has_value()))
      84             : {
      85          10 :     setProbability(probability);
      86          10 : }
      87             : 
      88          56 : DiscTypeID Reaction::getEduct1() const
      89             : {
      90          56 :     return educt1_;
      91             : }
      92             : 
      93           0 : void Reaction::setEduct1(DiscTypeID educt1)
      94             : {
      95           0 :     educt1_ = educt1;
      96           0 : }
      97             : 
      98          37 : DiscTypeID Reaction::getEduct2() const
      99             : {
     100          37 :     if (!educt2_)
     101           0 :         throw ExceptionWithLocation("Can't get educt2 for reaction of type" + toString(type_));
     102             : 
     103          37 :     return *educt2_;
     104             : }
     105             : 
     106          16 : bool Reaction::hasEduct2() const
     107             : {
     108          16 :     return type_ == Type::Combination || type_ == Type::Exchange;
     109             : }
     110             : 
     111           0 : void Reaction::setEduct2(DiscTypeID educt2)
     112             : {
     113           0 :     if (!educt2_)
     114           0 :         throw ExceptionWithLocation("Can't set educt2 for reaction of type" + toString(type_));
     115           0 :     educt2_ = educt2;
     116           0 : }
     117             : 
     118          22 : DiscTypeID Reaction::getProduct1() const
     119             : {
     120          22 :     return product1_;
     121             : }
     122             : 
     123           0 : void Reaction::setProduct1(DiscTypeID product1)
     124             : {
     125           0 :     product1_ = product1;
     126           0 : }
     127             : 
     128           9 : DiscTypeID Reaction::getProduct2() const
     129             : {
     130           9 :     if (!product2_)
     131           0 :         throw ExceptionWithLocation("Can't get product2 for reaction of type" + toString(type_));
     132             : 
     133           9 :     return *product2_;
     134             : }
     135             : 
     136          16 : bool Reaction::hasProduct2() const
     137             : {
     138          16 :     return type_ == Type::Decomposition || type_ == Type::Exchange;
     139             : }
     140             : 
     141           0 : void Reaction::setProduct2(DiscTypeID product2)
     142             : {
     143           0 :     if (!product2_)
     144           0 :         throw ExceptionWithLocation("Can't set product2 for reaction of type" + toString(type_));
     145             : 
     146           0 :     product2_ = product2;
     147           0 : }
     148             : 
     149           6 : double Reaction::getProbability() const
     150             : {
     151           6 :     return probability_;
     152             : }
     153             : 
     154          10 : void Reaction::setProbability(double probability)
     155             : {
     156          10 :     if (probability < 0 || probability > 1)
     157           0 :         throw ExceptionWithLocation("Probability must be between 0 and 1");
     158             : 
     159          10 :     probability_ = probability;
     160          10 : }
     161             : 
     162          72 : const Reaction::Type& Reaction::getType() const
     163             : {
     164          72 :     return type_;
     165             : }
     166             : 
     167          14 : void Reaction::validate(const DiscTypeRegistry& discTypeRegistry) const
     168             : {
     169          42 :     auto getMass = [&](DiscTypeID discTypeID) { return discTypeRegistry.getByID(discTypeID).getMass(); };
     170             : 
     171          14 :     const auto eductMassSum = getMass(educt1_) + (educt2_ ? getMass(*educt2_) : 0);
     172          14 :     const auto productMassSum = getMass(product1_) + (product2_ ? getMass(*product2_) : 0);
     173             : 
     174          14 :     if (eductMassSum != productMassSum)
     175           0 :         throw ExceptionWithLocation(toString(*this, discTypeRegistry) +
     176           0 :                                     ": Product- and educt masses need to be identical");
     177             : 
     178          14 :     if (type_ == Type::Transformation && educt1_ == product1_)
     179           0 :         throw ExceptionWithLocation(toString(*this, discTypeRegistry) + ": Educt 1 and product 1 are identical");
     180          14 : }
     181             : 
     182             : } // namespace cell

Generated by: LCOV version 1.14