Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
803889e
all work I have done untill the midterm: tumor replicated from the na…
salva24 Aug 15, 2025
e612c20
car-t oxygen consumption
salva24 Aug 15, 2025
293c1d4
Update README.md
salva24 Aug 16, 2025
1b45fd8
Update src/cart_cell.cc
salva24 Aug 16, 2025
cc8e2bc
still in progress CAR-T displacement
salva24 Aug 16, 2025
1f81855
cleaned comments to follow Doxygen-style
salva24 Aug 16, 2025
126a7ad
Merge branch 'master' of https://github.com/salva24/CARTopiaX
salva24 Aug 16, 2025
0494c5c
changed comments to follow doxygen-style
salva24 Aug 16, 2025
d5ece7f
Remove draft_code_my_own_analysis/ from tracking and add to .gitignore
salva24 Aug 16, 2025
2f41925
remove draft_code_my_own_analysis
salva24 Aug 16, 2025
bb8fe6b
add to gitignore draft_code_my_own_analysis
salva24 Aug 16, 2025
6d5b9aa
fixing comments
salva24 Aug 16, 2025
3aa026d
[ci] Add basic github actions infrastructure
vgvassilev Aug 17, 2025
54df45b
Merge branch 'master' into master
vgvassilev Aug 17, 2025
4309a1c
Update CMakeLists.txt
salva24 Aug 17, 2025
5c5717c
Update README.md
salva24 Aug 17, 2025
d82301f
Update README.md
salva24 Aug 17, 2025
58a5a02
Update src/cart_cell.cc
salva24 Aug 17, 2025
934f828
Update src/cart_cell.cc
salva24 Aug 17, 2025
4a32933
Update src/forces_tumor_cart.cc
salva24 Aug 17, 2025
b7a48e6
changed some things to imporve code quality
salva24 Aug 17, 2025
bcd0b26
cart_cell comments fixed
salva24 Aug 17, 2025
a8471bb
changed all comments to /// in the .h and changed some of them
salva24 Aug 17, 2025
4826179
changed the project name + new readme part Results
salva24 Aug 17, 2025
532d758
minor change spelling
salva24 Aug 17, 2025
6c842c9
30-days simulation
salva24 Aug 17, 2025
6a4d6d1
Merge branch 'compiler-research:master' into add_cart
salva24 Aug 17, 2025
ef7787b
Merge branch 'add_cart' into midterm_code_push
salva24 Aug 17, 2025
ec172b3
Merge pull request #1 from salva24/midterm_code_push
salva24 Aug 17, 2025
1e83fb1
some small changes lost in the merge
salva24 Aug 17, 2025
9be9b62
car-t motility adn more progress
salva24 Aug 18, 2025
7a727d7
Apoptosis flow on an attached cancer cell
salva24 Aug 18, 2025
a7dc873
car-t looking for victim target cell
salva24 Aug 19, 2025
29c697c
testing cart cells
salva24 Aug 19, 2025
17d06a0
debugging car-t
salva24 Aug 19, 2025
e7467c4
cart cell spawn
salva24 Aug 19, 2025
eeede9f
model with car-t
salva24 Aug 19, 2025
ba1141e
solved some bugs + probability of getting attached for a car-T
salva24 Aug 20, 2025
fcb5170
latest version with no debugging. CART implemented
salva24 Aug 20, 2025
877ea4b
avoid race condition in CAR-T adhesion to tumor cell
salva24 Aug 21, 2025
d803aec
solved bug with BioDynaMo's GetSimulatedTime() when spawning CAR-T
salva24 Aug 21, 2025
6e6ca0a
name casted to int
salva24 Aug 21, 2025
348b5a2
solved bug in apoptosis triel that was executed only once
salva24 Aug 21, 2025
4dee9c7
30 dys
salva24 Aug 21, 2025
382eb16
uncommented velocity computation that was commented for debugging
salva24 Aug 22, 2025
66ee120
big issue when saving a pointer to another cell
salva24 Aug 23, 2025
1c4daa2
solved bug in attached cell invalid pointer
salva24 Aug 24, 2025
9b39639
merged two fors for efficiency
salva24 Aug 24, 2025
d204df0
more dubugging. Pushing force of carts stopped
salva24 Aug 24, 2025
ad8ac85
adhesion probability adjusted
salva24 Aug 25, 2025
d5e4573
doubled forces + changed probability adhesion
salva24 Aug 25, 2025
a37c61d
change agent UID references into using the AgentPointer<>
salva24 Aug 26, 2025
d23cbe3
tunning hyperparameter
salva24 Aug 30, 2025
a2e6c82
latest versio tunned adhesion rate
salva24 Sep 3, 2025
50a7aa0
latest versio tunned adhesion rate
salva24 Sep 3, 2025
74a1453
new version
salva24 Sep 4, 2025
efc41e2
Merge branch 'add_cart' of https://github.com/salva24/CARTopiaX into …
salva24 Sep 4, 2025
749cad9
output average oncoprotein
salva24 Sep 4, 2025
c39cd27
scale 1:1
salva24 Sep 4, 2025
c27931d
dead cells have 0 oncoprotein
salva24 Sep 4, 2025
ab23855
output oxygen level and delete restriction for pushing cart cells
salva24 Sep 5, 2025
d2b6b00
solved pushing cart
salva24 Sep 5, 2025
b829a5c
two dosis 1:1
salva24 Sep 5, 2025
13f0965
minor change comment
salva24 Sep 5, 2025
557b23b
delete export of oxygen and inmmunostimulatory factor diffusion grids…
salva24 Sep 6, 2025
e8c55fc
version with all solved
salva24 Sep 11, 2025
08ff61c
deleted all debugs
salva24 Sep 12, 2025
09b70c8
first merge all files, needs to be executed and debugged
salva24 Sep 14, 2025
607fa7f
compiling rebased project
salva24 Sep 16, 2025
a0ed4e3
clang format
salva24 Sep 16, 2025
133165f
clang tidy issues solved
salva24 Sep 18, 2025
3bfae10
tidy left issues
salva24 Sep 18, 2025
7ab111d
Update use auto for type
salva24 Sep 18, 2025
c7c4ecf
quick test clang warning
salva24 Sep 18, 2025
a0f4af1
solved vassil's recomendations
salva24 Sep 18, 2025
8b68963
latest calng tidy
salva24 Sep 18, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,7 @@ doc/latex
*.dat

# Draft code for comparing models
draft_code_my_own_analysis/
draft_code_my_own_analysis/

# Temporary files
cout.txt
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.19.3)
project(cart_tumor)
project(CARTopiaX)


# BioDynaMo curretly uses the C++17 standard.
Expand Down
7 changes: 7 additions & 0 deletions bdm.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,12 @@ additional_data_members = [
{name = "cell_type", function = "GetTypeAsInt"}
]

[[visualize_agent]]
name = "CarTCell"
additional_data_members = ["diameter_","volume_"]

[[visualize_diffusion]]
name = "oxygen"

[[visualize_diffusion]]
name = "immunostimulatory_factor"
231 changes: 207 additions & 24 deletions src/cart_cell.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,17 @@
#include "tumor_cell.h"
#include "utils_aux.h"
#include "core/agent/agent.h"
#include "core/agent/agent_pointer.h"
#include "core/agent/new_agent_event.h"
#include "core/container/math_array.h"
#include "core/diffusion/diffusion_grid.h"
#include "core/functor.h"
#include "core/interaction_force.h"
#include "core/real_t.h"
#include "core/resource_manager.h"
#include "core/simulation.h"
#include "core/util/log.h"
#include "core/util/random.h"
#include <algorithm>
#include <cmath>
#include <cstdint>
Expand All @@ -47,6 +50,12 @@ CarTCell::CarTCell(const Real3& position) {
oxygen_dgrid_ = rm.GetDiffusionGrid("oxygen");
immunostimulatory_factor_dgrid_ =
rm.GetDiffusionGrid("immunostimulatory_factor");

SetCurrentLiveTime(kAverageMaximumTimeUntillApoptosisCart);
// Add Consumption and Secretion
// Set default oxygen consumption rate
SetOxygenConsumptionRate(kDefaultOxygenConsumptionCarT);
// Compute constants for all ConsumptionSecretion of Oxygen
ComputeConstantsConsumptionSecretion();
}

Expand Down Expand Up @@ -138,6 +147,8 @@ void CarTCell::ChangeVolumeExponentialRelaxationEquation(
// compute Displacement
Real3 CarTCell::CalculateDisplacement(const InteractionForce* force,
real_t squared_radius, real_t /*dt*/) {
Simulation* sim = Simulation::GetActive();

// real_t h = dt;
Real3 movement_at_next_step{0, 0, 0};
// this should be chaged in a future version of BioDynaMo in order to have a
Expand All @@ -148,33 +159,114 @@ Real3 CarTCell::CalculateDisplacement(const InteractionForce* force,

Real3 translation_velocity_on_point_mass{0, 0, 0};

// We check for every neighbor object if they touch us, i.e. push us
// away and agreagate the velocities
//--------------------------------------------
// CAR-T self motility (in case of migration)
//--------------------------------------------
Real3 current_position = GetPosition();
ExecutionContext* ctxt = sim->GetExecutionContext();
Random* rng = sim->GetRandom();
Real3 motility;
if (DoesCellMove()) {
// compute motility
if (rng->Uniform(0.0, 1.0) < kMotilityProbability) {
// random direction as unitary vector
const Real3 random_direction = GenerateRandomDirection();
Real3 direction_to_immunostimulatory_factor;
// returns normalized gradient towards the immunostimulatory factor source
immunostimulatory_factor_dgrid_->GetGradient(
current_position, &direction_to_immunostimulatory_factor, true);
// motility = bias * direction_to_immunostimulatory_factor +
// (1-bias)*random_direction
motility = kMigrationBiasCart * direction_to_immunostimulatory_factor +
kMigrationOneMinusBiasCart * random_direction;
const real_t motility_norm_squared = motility[0] * motility[0] +
motility[1] * motility[1] +
motility[2] * motility[2];
// Convert to unit direction
if (motility_norm_squared > 0) {
motility.Normalize();
}
// Scale by migration speed and add to the velocity
translation_velocity_on_point_mass += motility * kMigrationSpeedCart;
}
}

//--------------------------------------------
// CAR-T killing or victim cell escaping
//--------------------------------------------
// If cell is not apoptotic
if (state_ == CarTCellState::kAlive) {
// if it is attached to tumor cell
if (attached_to_tumor_cell_) {
// try to kill the cancer cell and in case of failure see if it manages to
// scape the order needs to be this one because it should try to kill
// before seeing if it scapes
if (TryToInduceApoptosis(attached_cell_ptr_, rng) ||
rng->Uniform(0.0, 1.0) < kProbabilityEscape) {
// the cancer cell is detached
attached_cell_ptr_->SetAttachedToCart(false);
// empty ID
attached_cell_ptr_ = nullptr;
attached_to_tumor_cell_ = false;
}
}

uint64_t non_zero_neighbor_forces = 0;
if (!IsStatic()) {
auto* ctxt = Simulation::GetActive()->GetExecutionContext();
auto calculate_neighbor_forces =
//--------------------------------------------
// CAR-T adhesion to victim cell
//--------------------------------------------
// Compute forces between the cells and check for a new attachment
auto calculate_forces_and_elastic_displacement =
L2F([&](Agent* neighbor, real_t /*squared_distance*/) {
auto neighbor_force = force->Calculate(this, neighbor);
if (neighbor_force[0] != 0 || neighbor_force[1] != 0 ||
neighbor_force[2] != 0) {
non_zero_neighbor_forces++;
translation_velocity_on_point_mass[0] += neighbor_force[0];
translation_velocity_on_point_mass[1] += neighbor_force[1];
translation_velocity_on_point_mass[2] += neighbor_force[2];
// Adhesion repulsion forces between cells
// We check for every neighbor object if they touch us, i.e. push us
// away and aggregate the velocities
Real4 neighbor_force = force->Calculate(this, neighbor);
translation_velocity_on_point_mass[0] += neighbor_force[0];
translation_velocity_on_point_mass[1] += neighbor_force[1];
translation_velocity_on_point_mass[2] += neighbor_force[2];

// CAR-T adhesion to new victim cell
Real3 displac = neighbor->GetPosition() - current_position;

if (auto* cancer_cell = dynamic_cast<TumorCell*>(neighbor)) {
// movement towards the tumor cells
const real_t sq_norm_displac = displac[0] * displac[0] +
displac[1] * displac[1] +
displac[2] * displac[2];

// The cart moves towards the tumor cell only if they are not
// touching already If they are too close the only force affecting
// is the adhesion force to avoid CAR-T non-stop pushing tumor
// cells. In case of being closer than
// gKMaxSquaredDistanceCartMovingTowardsTumorCell there is a
// probability kProbabilityPushing for the CAR-T to keep pushing the
// tumor cell
if (sq_norm_displac >
gKMaxSquaredDistanceCartMovingTowardsTumorCell) {
translation_velocity_on_point_mass[0] +=
displac[0] * kElasticConstantCart;
translation_velocity_on_point_mass[1] +=
displac[1] * kElasticConstantCart;
translation_velocity_on_point_mass[2] +=
displac[2] * kElasticConstantCart;
}

// If the CAR-T has not succeeded in attaching to a tumor cell yet,
// it tries again
if (!attached_to_tumor_cell_) {
TryToGetAttachedTo(cancer_cell, sq_norm_displac, rng);
}
}
});
ctxt->ForEachNeighbor(calculate_neighbor_forces, *this, squared_radius);

if (non_zero_neighbor_forces > 1) {
SetStaticnessNextTimestep(false);
}
ctxt->ForEachNeighbor(calculate_forces_and_elastic_displacement, *this,
squared_radius);
}

//--------------------------------------------
// Two step Adams-Bashforth approximation of the time derivative for position
// position(t + dt) ≈ position(t) + dt * [ 1.5 * velocity(t) - 0.5 *
// velocity(t - dt) ]
//--------------------------------------------
movement_at_next_step +=
translation_velocity_on_point_mass * kDnew + older_velocity_ * kDold;

Expand All @@ -184,6 +276,97 @@ Real3 CarTCell::CalculateDisplacement(const InteractionForce* force,
return movement_at_next_step;
}

// Try to get attached to a tumor cell
void CarTCell::TryToGetAttachedTo(TumorCell* victim, real_t squared_distance,
Random* rng) {
// If the tumor cell is not already attached to a CAR-T cell, is not dead and
// is not too far away.
if (!victim->IsAttachedToCart() && !victim->IsDead() &&
squared_distance < kSquaredMaxAdhesionDistanceCart) {
// factor of how high is the oncoprotein level of the cancer cell
real_t oncoprotein_scale_factor =
(victim->GetOncoproteinLevel() - kOncoproteinLimit) /
kOncoproteinDifference;
// Clamp scale_factor to be in [0,1]
if (oncoprotein_scale_factor > 1.0) {
oncoprotein_scale_factor = 1.0;
}
// If oncoprotein level is lower than the limit the cancer cell does not get
// detected
if (oncoprotein_scale_factor <= 0.0) {
// oncoprotein_scale_factor = 0.0; the probability is going to be 0 so
// return the function is the most efficient
return;
}

// factor of how far the cancer cell is
real_t distance_scale_factor =
(kMaxAdhesionDistanceCart - std::sqrt(squared_distance)) /
kDifferenceCartAdhesionDistances;
// Clamp scale_factor to be in [0,1]. We already checked that it is > 0
// because squared_distance < kSquaredMaxAdhesionDistanceCart
if (distance_scale_factor > 1.0) {
distance_scale_factor = 1.0;
}

// It tries to attach the CAR-T cell to the tumor cell with probability
// kAdhesionRateCart * oncoprotein_scale_factor * distance_scale_factor *
// kDtMechanics
if (rng->Uniform(0.0, 1.0) < kAdhesionRateCart * oncoprotein_scale_factor *
distance_scale_factor * kDtMechanics) {
// avoid race condition. Only one cell can be attached to the tumor cell.
#pragma omp critical
{
// We need to check again if the victim is not attached to a CAR-T cell
// yet. This could be made more efficiently with a semaphore for each
// cancer cell
if (!victim->IsAttachedToCart()) {
attached_to_tumor_cell_ = true;
attached_cell_ptr_ = victim->GetAgentPtr<TumorCell>();
victim->SetAttachedToCart(true);
}
}
}
}
}

// Try to induce apoptosis
bool CarTCell::TryToInduceApoptosis(bdm::AgentPointer<TumorCell> attached_cell,
Random* rng) const {
// If there is no attached cell (this should not happen)

if (!attached_to_tumor_cell_) {
return false;
}

// factor of how high is the oncoprotein levelof the cancer cell
real_t scale_factor =
(attached_cell->GetOncoproteinLevel() - kOncoproteinLimit) /
kOncoproteinDifference;
// Clamp scale_factor to be in [0,1]
if (scale_factor > 1.0) {
scale_factor = 1.0;
}
// If oncoprotein level is lower than the limit the cancer cell does not
// become apoptotic
if (scale_factor < 0.0) {
// scale_factor = 0.0; the probability is going to be 0 so return the
// function is the most efficient
return false;
}
// CAR-T success of killing probability: aggressive cancer cells (high
// oncoprotein level) are more likely to be killed
const bool succeeded =
rng->Uniform(0.0, 1.0) < kKillRateCart * scale_factor * kDtMechanics;

// The CAR-T has succeeded to induce apoptosis on the Cancer Cell
if (succeeded) {
attached_cell->StartApoptosis();
}

return succeeded;
}

// Compute new oxygen or immunostimulatory factor concentration after
// consumption/ secretion
real_t CarTCell::ConsumeSecreteSubstance(int substance_id,
Expand All @@ -194,7 +377,7 @@ real_t CarTCell::ConsumeSecreteSubstance(int substance_id,
res = (old_concentration + constant1_oxygen_) / constant2_oxygen_;
} else if (substance_id ==
immunostimulatory_factor_dgrid_->GetContinuumId()) {
// This point should never be reached
// CAR-T do not change immunostimulatory factor levels
res = old_concentration;
} else {
throw std::invalid_argument("Unknown substance id: " +
Expand Down Expand Up @@ -230,7 +413,7 @@ void CarTCell::ComputeConstantsConsumptionSecretion() {

/// Main behavior executed at each simulation step
void StateControlCart::Run(Agent* agent) {
auto* sim = Simulation::GetActive();
Simulation* sim = Simulation::GetActive();
// Run only every kDtCycle minutes, fmod does not work with the type
// returned by GetSimulatedTime()
if (sim->GetScheduler()->GetSimulatedSteps() % kStepsPerCycle != 0) {
Expand All @@ -241,7 +424,7 @@ void StateControlCart::Run(Agent* agent) {
switch (cell->GetState()) {
case CarTCellState::kAlive: {
// the cell is growing to real_t its size before mitosis
// Probability of death= 1/CurrentLiveTime, division by 0
// Probability of death= 1/CurrentLiveTime,avoiding division by 0
if (sim->GetRandom()->Uniform(1.0) <
kDtCycle / std::max(cell->GetCurrentLiveTime(), kEpsilon)) {
// the cell Dies
Expand All @@ -260,8 +443,8 @@ void StateControlCart::Run(Agent* agent) {
cell->ComputeConstantsConsumptionSecretion();
// Detach from tumor cell if it was attached
if (cell->IsAttachedToTumorCell()) {
cell->GetAttachedCell()->SetAttachedToCart(false);
cell->SetAttachedCell(nullptr);
cell->GetAttachedCellPointer()->SetAttachedToCart(false);
cell->SetAttachedCellPointer(nullptr);
cell->SetAttachedToTumorCell(false);
}
} else {
Expand All @@ -284,7 +467,7 @@ void StateControlCart::Run(Agent* agent) {
// duration transition)
if (kTimeApoptosis < cell->GetTimerState()) {
// remove the cell from the simulation
auto* ctxt = sim->GetExecutionContext();
ExecutionContext* ctxt = sim->GetExecutionContext();
ctxt->RemoveAgent(agent->GetUid());
}
break;
Expand Down
Loading