LCOV - code coverage report
Current view: top level - cell - Compartment.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 88 109 80.7 %
Date: 2025-12-06 00:15:40 Functions: 16 17 94.1 %

          Line data    Source code
       1             : #include "Compartment.hpp"
       2             : #include "CollisionDetector.hpp"
       3             : #include "CollisionHandler.hpp"
       4             : #include "Disc.hpp"
       5             : #include "MathUtils.hpp"
       6             : #include "ReactionEngine.hpp"
       7             : 
       8             : namespace cell
       9             : {
      10             : 
      11          19 : Compartment::Compartment(Compartment* parent, Membrane membrane, SimulationContext simulationContext)
      12          19 :     : parent_(parent)
      13          19 :     , membrane_(std::move(membrane))
      14          19 :     , simulationContext_(std::move(simulationContext))
      15             : {
      16          19 :     membrane_.setCompartment(this);
      17          19 : }
      18             : 
      19          19 : Compartment::~Compartment() = default;
      20             : 
      21      362925 : const Membrane& Compartment::getMembrane() const
      22             : {
      23      362925 :     return membrane_;
      24             : }
      25             : 
      26           0 : void Compartment::setDiscs(std::vector<Disc>&& discs)
      27             : {
      28           0 :     discs_ = std::move(discs);
      29           0 : }
      30             : 
      31         319 : void Compartment::addDisc(Disc disc)
      32             : {
      33         319 :     discs_.push_back(std::move(disc));
      34         319 : }
      35             : 
      36          30 : const std::vector<Disc>& Compartment::getDiscs() const
      37             : {
      38          30 :     return discs_;
      39             : }
      40             : 
      41           2 : void Compartment::addIntrudingDisc(Disc& disc)
      42             : {
      43           2 :     intrudingDiscs_.push_back(&disc);
      44           2 : }
      45             : 
      46      462360 : std::vector<std::unique_ptr<Compartment>>& Compartment::getCompartments()
      47             : {
      48      462360 :     return compartments_;
      49             : }
      50             : 
      51          10 : const std::vector<std::unique_ptr<Compartment>>& Compartment::getCompartments() const
      52             : {
      53          10 :     return compartments_;
      54             : }
      55             : 
      56           3 : const Compartment* Compartment::getParent() const
      57             : {
      58           3 :     return parent_;
      59             : }
      60             : 
      61           9 : auto Compartment::detectCollisions()
      62             : {
      63           9 :     simulationContext_.collisionDetector.buildEntries(discs_, membranes_, intrudingDiscs_);
      64           9 :     return simulationContext_.collisionDetector.detectCollisions(
      65           9 :         CollisionDetector::Params{.discs = &discs_,
      66           9 :                                   .membranes = &membranes_,
      67           9 :                                   .intrudingDiscs = &intrudingDiscs_,
      68          18 :                                   .containingMembrane = &membrane_});
      69             : }
      70             : 
      71           9 : void Compartment::update(double dt)
      72             : {
      73           9 :     auto detectedCollisions = detectCollisions();
      74             : 
      75           9 :     simulationContext_.reactionEngine.applyBimolecularReactions(detectedCollisions);
      76           9 :     moveDiscsIntoChildCompartments(detectedCollisions);
      77           9 :     moveDiscsIntoParentCompartment(detectedCollisions);
      78           9 :     simulationContext_.collisionHandler.resolveCollisions(detectedCollisions);
      79           9 :     updateChildCompartments(dt);
      80           9 :     moveDiscsAndApplyUnimolecularReactions(dt); // Removes destroyed discs
      81           9 :     intrudingDiscs_.clear();
      82           9 : }
      83             : 
      84          10 : Compartment* Compartment::createSubCompartment(Membrane membrane)
      85             : {
      86          10 :     auto compartment = std::make_unique<Compartment>(this, std::move(membrane), simulationContext_);
      87          10 :     membranes_.push_back(compartment->getMembrane());
      88          10 :     compartments_.push_back(std::move(compartment));
      89             : 
      90          20 :     return compartments_.back().get();
      91          10 : }
      92             : 
      93           9 : void Compartment::moveDiscsAndApplyUnimolecularReactions(double dt)
      94             : {
      95           9 :     std::vector<Disc> newDiscs;
      96             : 
      97          27 :     for (std::size_t i = 0; i < discs_.size(); ++i)
      98             :     {
      99          18 :         auto& disc = discs_[i];
     100          18 :         if (disc.isMarkedDestroyed())
     101             :         {
     102             :             // This function also removes destroyed discs and thus needs to be called first
     103           3 :             discs_[i] = std::move(discs_.back());
     104           3 :             discs_.pop_back();
     105           3 :             --i;
     106           3 :             continue;
     107             :         }
     108             : 
     109          15 :         disc.move(disc.getVelocity() * dt);
     110             : 
     111             :         // A -> B returns nothing, A -> B + C returns 1 new disc
     112          15 :         if (auto newDisc = simulationContext_.reactionEngine.applyUnimolecularReactions(disc, dt))
     113           1 :             newDiscs.push_back(std::move(*newDisc));
     114             :     }
     115             : 
     116           9 :     if (!newDiscs.empty())
     117           1 :         discs_.insert(discs_.end(), newDiscs.begin(), newDiscs.end());
     118           9 : }
     119             : 
     120           9 : void Compartment::moveDiscsIntoChildCompartments(const CollisionDetector::DetectedCollisions& detectedCollisions)
     121             : {
     122           9 :     const auto& indexes = detectedCollisions.indexes.find(CollisionDetector::CollisionType::DiscChildMembrane);
     123           9 :     if (indexes == detectedCollisions.indexes.end())
     124           7 :         return;
     125             : 
     126           8 :     for (std::size_t index : indexes->second)
     127             :     {
     128           6 :         const auto& collision = detectedCollisions.collisions[index];
     129           6 :         if (collision.isInvalidatedByDestroyedDisc())
     130           4 :             continue;
     131             : 
     132           5 :         const auto permeability = simulationContext_.membraneTypeRegistry.getByID(collision.membrane->getTypeID())
     133           5 :                                       .getPermeabilityFor(collision.disc->getTypeID());
     134           5 :         if (permeability == MembraneType::Permeability::None || permeability == MembraneType::Permeability::Outward)
     135           3 :             continue;
     136             : 
     137           2 :         const auto& discRadius = simulationContext_.discTypeRegistry.getByID(collision.disc->getTypeID()).getRadius();
     138             :         const auto& membraneRadius =
     139           2 :             simulationContext_.membraneTypeRegistry.getByID(collision.membrane->getTypeID()).getRadius();
     140           2 :         if (mathutils::circleIsFullyContainedByCircle(collision.disc->getPosition(), discRadius,
     141           2 :                                                       collision.membrane->getPosition(), membraneRadius))
     142             :         {
     143           0 :             collision.membrane->getCompartment()->addDisc(*collision.disc);
     144           0 :             collision.disc->markDestroyed();
     145             :         }
     146             :         else
     147           2 :             collision.membrane->getCompartment()->addIntrudingDisc(*collision.disc);
     148             :     }
     149             : }
     150             : 
     151           9 : void Compartment::moveDiscsIntoParentCompartment(const CollisionDetector::DetectedCollisions& detectedCollisions)
     152             : {
     153             :     // Only the case for the containing cell
     154           9 :     if (!parent_)
     155           9 :         return;
     156             : 
     157           2 :     const auto& indexes = detectedCollisions.indexes.find(CollisionDetector::CollisionType::DiscContainingMembrane);
     158           2 :     if (indexes == detectedCollisions.indexes.end())
     159           2 :         return;
     160             : 
     161           0 :     const auto& membraneType = simulationContext_.membraneTypeRegistry.getByID(membrane_.getTypeID());
     162           0 :     const auto M = membrane_.getPosition();
     163           0 :     const auto R = membraneType.getRadius();
     164             : 
     165           0 :     for (std::size_t index : indexes->second)
     166             :     {
     167           0 :         const auto& collision = detectedCollisions.collisions[index];
     168           0 :         if (collision.isInvalidatedByDestroyedDisc())
     169           0 :             continue;
     170             : 
     171           0 :         const auto permeability = simulationContext_.membraneTypeRegistry.getByID(collision.membrane->getTypeID())
     172           0 :                                       .getPermeabilityFor(collision.disc->getTypeID());
     173           0 :         if (permeability == MembraneType::Permeability::None || permeability == MembraneType::Permeability::Inward)
     174           0 :             continue;
     175             : 
     176           0 :         const auto discRadius = simulationContext_.discTypeRegistry.getByID(collision.disc->getTypeID()).getRadius();
     177           0 :         if (!mathutils::circlesOverlap(collision.disc->getPosition(), discRadius, M, R))
     178             :         {
     179           0 :             parent_->addDisc(*collision.disc);
     180           0 :             collision.disc->markDestroyed();
     181             :         }
     182             :         else
     183           0 :             parent_->addIntrudingDisc(*collision.disc);
     184             :     }
     185             : }
     186             : 
     187           9 : void Compartment::updateChildCompartments(double dt)
     188             : {
     189          11 :     for (auto& compartment : compartments_)
     190           2 :         compartment->update(dt);
     191           9 : }
     192             : 
     193             : } // namespace cell

Generated by: LCOV version 1.14