From 5632a3bc62cc34fefd4f85ce9bce03d05087381b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20No=C3=ABl?= Date: Mon, 30 Mar 2026 09:00:07 -0300 Subject: [PATCH] Cleaning up attackers: introduce a vector of attackers for a cell not to have to look at all cells --- core/PhysiCell_cell.cpp | 12 ++++++++++++ core/PhysiCell_cell.h | 1 + core/PhysiCell_phenotype.cpp | 1 + core/PhysiCell_phenotype.h | 1 + core/PhysiCell_standard_models.cpp | 10 ++++++++++ 5 files changed, 25 insertions(+) diff --git a/core/PhysiCell_cell.cpp b/core/PhysiCell_cell.cpp index a14c70b99..9194aeecd 100644 --- a/core/PhysiCell_cell.cpp +++ b/core/PhysiCell_cell.cpp @@ -1207,6 +1207,9 @@ void delete_cell( int index ) // released internalized substrates (as of 1.5.x releases) pDeleteMe->release_internalized_substrates(); + // new Dec 2, 2025 + pDeleteMe->remove_self_from_attackers(); + // performance goal: don't delete in the middle -- very expensive reallocation // alternative: copy last element to index position, then shrink vector by 1 at the end O(constant) @@ -3433,6 +3436,15 @@ void Cell::remove_all_spring_attachments( void ) return; } +void Cell::remove_self_from_attackers( void ) +{ + for (Cell* pCell : phenotype.cell_interactions.attacked_by) + { + pCell->phenotype.cell_interactions.pAttackTarget = NULL; + } + phenotype.cell_interactions.attacked_by.clear(); + return; +} void attach_cells( Cell* pCell_1, Cell* pCell_2 ) { diff --git a/core/PhysiCell_cell.h b/core/PhysiCell_cell.h index 5b7c52d96..4de5fcebe 100644 --- a/core/PhysiCell_cell.h +++ b/core/PhysiCell_cell.h @@ -238,6 +238,7 @@ class Cell : public Basic_Agent void attach_cell_as_spring( Cell* pAddMe ); // done void detach_cell_as_spring( Cell* pRemoveMe ); // done void remove_all_spring_attachments( void ); // done + void remove_self_from_attackers( void ); // I want to eventually deprecate this, by ensuring that // critical BioFVM and PhysiCell data elements are synced when they are needed diff --git a/core/PhysiCell_phenotype.cpp b/core/PhysiCell_phenotype.cpp index 4d03249be..e83fee686 100644 --- a/core/PhysiCell_phenotype.cpp +++ b/core/PhysiCell_phenotype.cpp @@ -1277,6 +1277,7 @@ Cell_Interactions::Cell_Interactions() immunogenicities = {1}; pAttackTarget = NULL; + attacked_by = std::vector{}; total_damage_delivered = 0.0; attack_duration = 30.0; // a typical attack duration for a T cell using perforin/granzyme is ~30 minutes diff --git a/core/PhysiCell_phenotype.h b/core/PhysiCell_phenotype.h index 701d816b5..af288afaa 100644 --- a/core/PhysiCell_phenotype.h +++ b/core/PhysiCell_phenotype.h @@ -698,6 +698,7 @@ class Cell_Interactions double attack_damage_rate; Cell* pAttackTarget; + std::vector attacked_by; double total_damage_delivered; double attack_duration; diff --git a/core/PhysiCell_standard_models.cpp b/core/PhysiCell_standard_models.cpp index 48a70ccb8..17dfbaed7 100644 --- a/core/PhysiCell_standard_models.cpp +++ b/core/PhysiCell_standard_models.cpp @@ -68,6 +68,7 @@ #include "PhysiCell_standard_models.h" #include "PhysiCell_cell.h" #include "../modules/PhysiCell_pathology.h" +#include namespace PhysiCell{ @@ -1267,6 +1268,7 @@ void standard_cell_cell_interactions( Cell* pCell, Phenotype& phenotype, double if( UniformRandom() < probability ) { pCell->phenotype.cell_interactions.pAttackTarget = pTarget; + pTarget->phenotype.cell_interactions.attacked_by.push_back(pCell); attacked = true; /* std::cout << "********* ********* ******** start atack **** " << PhysiCell_globals.current_time << std::endl; @@ -1345,6 +1347,14 @@ void standard_cell_cell_interactions( Cell* pCell, Phenotype& phenotype, double detach_cells_as_spring(pCell,pTarget); pCell->phenotype.cell_interactions.pAttackTarget = NULL; + pTarget->phenotype.cell_interactions.attacked_by.erase( + std::remove( + pTarget->phenotype.cell_interactions.attacked_by.begin(), + pTarget->phenotype.cell_interactions.attacked_by.end(), + pCell), + pTarget->phenotype.cell_interactions.attacked_by.end() + ); + } }