From 816f7d08b678eeb730995e413f13ba179716828b Mon Sep 17 00:00:00 2001 From: pohaoc2 Date: Sun, 16 Mar 2025 21:21:35 -0700 Subject: [PATCH 01/28] logging with correct necrotic --- .../agent/action/PatchActionConvert.java | 3 +- src/arcade/patch/agent/cell/PatchCell.java | 9 ++-- .../patch/agent/cell/PatchCellCancer.java | 3 +- .../patch/agent/cell/PatchCellCancerStem.java | 3 +- .../patch/agent/cell/PatchCellContainer.java | 9 +++- .../patch/agent/cell/PatchCellFactory.java | 15 ++++++- .../patch/agent/cell/PatchCellRandom.java | 3 +- .../patch/agent/cell/PatchCellTissue.java | 3 +- .../sim/output/PatchOutputDeserializer.java | 9 +++- .../sim/output/PatchOutputSerializer.java | 8 +++- .../patch/agent/cell/PatchCellCARTTest.java | 8 +++- .../agent/cell/PatchCellCancerStemTest.java | 12 ++++-- .../patch/agent/cell/PatchCellCancerTest.java | 9 +++- .../patch/agent/cell/PatchCellRandomTest.java | 12 ++++-- .../patch/agent/cell/PatchCellTest.java | 29 +++++++++---- .../patch/agent/cell/PatchCellTissueTest.java | 42 +++++++++++++------ v2.4 | 1 + 17 files changed, 131 insertions(+), 47 deletions(-) create mode 160000 v2.4 diff --git a/src/arcade/patch/agent/action/PatchActionConvert.java b/src/arcade/patch/agent/action/PatchActionConvert.java index 1c33b50d6..72777e81f 100644 --- a/src/arcade/patch/agent/action/PatchActionConvert.java +++ b/src/arcade/patch/agent/action/PatchActionConvert.java @@ -87,7 +87,8 @@ public void step(SimState simstate) { oldCell.getVolume(), oldCell.getHeight(), oldCell.getCriticalVolume(), - oldCell.getCriticalHeight()); + oldCell.getCriticalHeight(), + oldCell.getCycles()); PatchCell newCell = (PatchCell) cellContainer.convert(sim.cellFactory, location, sim.random); grid.addObject(newCell, location); diff --git a/src/arcade/patch/agent/cell/PatchCell.java b/src/arcade/patch/agent/cell/PatchCell.java index b495215ae..11301e41b 100644 --- a/src/arcade/patch/agent/cell/PatchCell.java +++ b/src/arcade/patch/agent/cell/PatchCell.java @@ -120,12 +120,12 @@ public abstract class PatchCell implements Cell { /** Cell parameters. */ final Parameters parameters; + /** List of cell cycle lengths (in minutes). */ + public final Bag cycles = new Bag(); + /** Cell population links. */ final GrabBag links; - /** List of cell cycle lengths (in minutes). */ - private final Bag cycles = new Bag(); - /** If cell is stopped in the simulation. */ private boolean isStopped; @@ -403,7 +403,8 @@ public CellContainer convert() { volume, height, criticalVolume, - criticalHeight); + criticalHeight, + cycles); } /** diff --git a/src/arcade/patch/agent/cell/PatchCellCancer.java b/src/arcade/patch/agent/cell/PatchCellCancer.java index 01d505229..0b4c002d0 100644 --- a/src/arcade/patch/agent/cell/PatchCellCancer.java +++ b/src/arcade/patch/agent/cell/PatchCellCancer.java @@ -71,7 +71,8 @@ public PatchCellContainer make(int newID, CellState newState, MersenneTwisterFas volume, height, criticalVolume, - criticalHeight); + criticalHeight, + cycles); } /** diff --git a/src/arcade/patch/agent/cell/PatchCellCancerStem.java b/src/arcade/patch/agent/cell/PatchCellCancerStem.java index b1701504c..a6a30948a 100644 --- a/src/arcade/patch/agent/cell/PatchCellCancerStem.java +++ b/src/arcade/patch/agent/cell/PatchCellCancerStem.java @@ -65,6 +65,7 @@ public PatchCellContainer make(int newID, CellState newState, MersenneTwisterFas volume, height, criticalVolume, - criticalHeight); + criticalHeight, + cycles); } } diff --git a/src/arcade/patch/agent/cell/PatchCellContainer.java b/src/arcade/patch/agent/cell/PatchCellContainer.java index 960d5df6c..36485525c 100644 --- a/src/arcade/patch/agent/cell/PatchCellContainer.java +++ b/src/arcade/patch/agent/cell/PatchCellContainer.java @@ -1,5 +1,6 @@ package arcade.patch.agent.cell; +import sim.util.Bag; import ec.util.MersenneTwisterFast; import arcade.core.agent.cell.Cell; import arcade.core.agent.cell.CellContainer; @@ -47,6 +48,9 @@ public final class PatchCellContainer implements CellContainer { /** Critical cell height [um]. */ public final double criticalHeight; + /** Cell cycles. */ + public final Bag cycles; + /** * Creates a {@code PatchCellContainer} instance. * @@ -60,6 +64,7 @@ public final class PatchCellContainer implements CellContainer { * @param height the cell height * @param criticalVolume the critical volume * @param criticalHeight the critical height + * @param cycles the cell cycles */ public PatchCellContainer( int id, @@ -71,7 +76,8 @@ public PatchCellContainer( double volume, double height, double criticalVolume, - double criticalHeight) { + double criticalHeight, + Bag cycles) { this.id = id; this.parent = parent; this.pop = pop; @@ -82,6 +88,7 @@ public PatchCellContainer( this.height = height; this.criticalVolume = criticalVolume; this.criticalHeight = criticalHeight; + this.cycles = cycles; } @Override diff --git a/src/arcade/patch/agent/cell/PatchCellFactory.java b/src/arcade/patch/agent/cell/PatchCellFactory.java index 0492e0801..b78a1b005 100644 --- a/src/arcade/patch/agent/cell/PatchCellFactory.java +++ b/src/arcade/patch/agent/cell/PatchCellFactory.java @@ -6,6 +6,7 @@ import java.util.HashSet; import java.util.Set; import java.util.logging.Logger; +import sim.util.Bag; import ec.util.MersenneTwisterFast; import arcade.core.agent.cell.*; import arcade.core.sim.Series; @@ -158,9 +159,19 @@ public PatchCellContainer createCellForPopulation(int id, int pop) { double volume = parameters.getDouble("CELL_VOLUME"); double height = parameters.getDouble("CELL_HEIGHT"); int age = parameters.getInt("CELL_AGE"); - + Bag cycles = new Bag(); return new PatchCellContainer( - id, 0, pop, age, 0, State.UNDEFINED, volume, height, volume, height + compression); + id, + 0, + pop, + age, + 0, + State.UNDEFINED, + volume, + height, + volume, + height + compression, + cycles); } /** diff --git a/src/arcade/patch/agent/cell/PatchCellRandom.java b/src/arcade/patch/agent/cell/PatchCellRandom.java index 19a31a035..3db18519d 100644 --- a/src/arcade/patch/agent/cell/PatchCellRandom.java +++ b/src/arcade/patch/agent/cell/PatchCellRandom.java @@ -56,7 +56,8 @@ public PatchCellContainer make(int newID, CellState newState, MersenneTwisterFas volume, height, criticalVolume, - criticalHeight); + criticalHeight, + cycles); } @Override diff --git a/src/arcade/patch/agent/cell/PatchCellTissue.java b/src/arcade/patch/agent/cell/PatchCellTissue.java index 352260b28..385eef051 100644 --- a/src/arcade/patch/agent/cell/PatchCellTissue.java +++ b/src/arcade/patch/agent/cell/PatchCellTissue.java @@ -82,7 +82,8 @@ public PatchCellContainer make(int newID, CellState newState, MersenneTwisterFas volume, height, criticalVolume, - criticalHeight); + criticalHeight, + cycles); } @Override diff --git a/src/arcade/patch/sim/output/PatchOutputDeserializer.java b/src/arcade/patch/sim/output/PatchOutputDeserializer.java index 80c1c73f2..da136db75 100644 --- a/src/arcade/patch/sim/output/PatchOutputDeserializer.java +++ b/src/arcade/patch/sim/output/PatchOutputDeserializer.java @@ -10,6 +10,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; +import sim.util.Bag; import arcade.core.agent.cell.CellContainer; import arcade.core.env.location.LocationContainer; import arcade.core.sim.output.OutputDeserializer; @@ -67,7 +68,10 @@ public PatchCellContainer deserialize( int divisions = jsonObject.get("divisions").getAsInt(); double volume = jsonObject.get("volume").getAsDouble(); double height = jsonObject.get("height").getAsDouble(); - + Bag cycles = new Bag(); + for (JsonElement cycle : jsonObject.get("cycles").getAsJsonArray()) { + cycles.add(cycle.getAsDouble()); + } State state = State.valueOf(jsonObject.get("state").getAsString()); JsonArray criticals = jsonObject.get("criticals").getAsJsonArray(); @@ -84,7 +88,8 @@ public PatchCellContainer deserialize( volume, height, criticalVolume, - criticalHeight); + criticalHeight, + cycles); } } diff --git a/src/arcade/patch/sim/output/PatchOutputSerializer.java b/src/arcade/patch/sim/output/PatchOutputSerializer.java index dc27b19ec..582272e19 100644 --- a/src/arcade/patch/sim/output/PatchOutputSerializer.java +++ b/src/arcade/patch/sim/output/PatchOutputSerializer.java @@ -10,6 +10,7 @@ import com.google.gson.JsonObject; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; +import sim.util.Bag; import arcade.core.agent.cell.CellContainer; import arcade.core.env.location.LocationContainer; import arcade.core.sim.Series; @@ -146,7 +147,12 @@ public JsonElement serialize( json.add("criticals", criticals); // TODO: add cycles - + Bag cycles = src.cycles; + JsonArray jsonCycles = new JsonArray(); + for (Object cycle : cycles) { + jsonCycles.add(cycle.toString()); + } + json.add("cycles", jsonCycles); return json; } } diff --git a/test/arcade/patch/agent/cell/PatchCellCARTTest.java b/test/arcade/patch/agent/cell/PatchCellCARTTest.java index 09afbb5df..bb47afc9f 100644 --- a/test/arcade/patch/agent/cell/PatchCellCARTTest.java +++ b/test/arcade/patch/agent/cell/PatchCellCARTTest.java @@ -44,6 +44,8 @@ public class PatchCellCARTTest { private static Bag bag; + static Bag cycles = new Bag(); + static class PatchCellMock extends PatchCellCART { PatchCellMock(PatchCellContainer container, Location location, Parameters parameters) { super(container, location, parameters, null); @@ -61,7 +63,8 @@ public PatchCellContainer make(int newID, CellState newState, MersenneTwisterFas volume, height, criticalVolume, - criticalHeight); + criticalHeight, + cycles); } @Override @@ -98,7 +101,8 @@ public final void setUp() throws NoSuchFieldException, IllegalAccessException { volume, height, criticalVolume, - criticalHeight); + criticalHeight, + cycles); when(parameters.getDouble("ENERGY_THRESHOLD")).thenReturn(1.0); when(parameters.getDouble("NECROTIC_FRACTION")) diff --git a/test/arcade/patch/agent/cell/PatchCellCancerStemTest.java b/test/arcade/patch/agent/cell/PatchCellCancerStemTest.java index a87bc1566..ffa549f52 100644 --- a/test/arcade/patch/agent/cell/PatchCellCancerStemTest.java +++ b/test/arcade/patch/agent/cell/PatchCellCancerStemTest.java @@ -3,6 +3,7 @@ import java.util.ArrayList; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import sim.util.Bag; import ec.util.MersenneTwisterFast; import arcade.core.util.GrabBag; import arcade.core.util.MiniBox; @@ -60,6 +61,8 @@ public class PatchCellCancerStemTest { static State cellState = State.QUIESCENT; + static Bag cellCycles = new Bag(); + @BeforeAll public static void setupMocks() { simMock = mock(PatchSimulation.class); @@ -99,7 +102,8 @@ public void step_calledWhenAgeGreaterThanApoptosisAge_doesNotSetApoptoticState() cellVolume, cellHeight, cellCriticalVolume, - cellCriticalHeight); + cellCriticalHeight, + cellCycles); PatchCell cell = spy(new PatchCellCancerStem(container, locationMock, parametersMock)); cell.module = module; cell.processes.put(Domain.METABOLISM, metabolismMock); @@ -149,7 +153,8 @@ public void make_called_createsContainer() { volume, height, criticalVolume, - criticalHeight); + criticalHeight, + cellCycles); PatchCellCancerStem cell = new PatchCellCancerStem(cellContainer, locationMock, parametersMock, links); @@ -198,7 +203,8 @@ public void make_calledWithLinks_createsContainer() { volume, height, criticalVolume, - criticalHeight); + criticalHeight, + cellCycles); PatchCellCancerStem cell = new PatchCellCancerStem(cellContainer, locationMock, parametersMock, links); diff --git a/test/arcade/patch/agent/cell/PatchCellCancerTest.java b/test/arcade/patch/agent/cell/PatchCellCancerTest.java index f7f80df21..36c2e111b 100644 --- a/test/arcade/patch/agent/cell/PatchCellCancerTest.java +++ b/test/arcade/patch/agent/cell/PatchCellCancerTest.java @@ -2,6 +2,7 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import sim.util.Bag; import ec.util.MersenneTwisterFast; import arcade.core.util.GrabBag; import arcade.core.util.MiniBox; @@ -56,6 +57,8 @@ public class PatchCellCancerTest { static State cellState = State.QUIESCENT; + static Bag cellCycles = new Bag(); + @BeforeAll public static void setupMocks() { simMock = mock(PatchSimulation.class); @@ -99,7 +102,8 @@ public void make_called_createsContainer() { volume, height, criticalVolume, - criticalHeight); + criticalHeight, + cellCycles); PatchCellCancer cell = new PatchCellCancer(cellContainer, locationMock, parametersMock, links); @@ -148,7 +152,8 @@ public void make_calledWithLinks_createsContainer() { volume, height, criticalVolume, - criticalHeight); + criticalHeight, + cellCycles); PatchCellCancer cell = new PatchCellCancer(cellContainer, locationMock, parametersMock, links); diff --git a/test/arcade/patch/agent/cell/PatchCellRandomTest.java b/test/arcade/patch/agent/cell/PatchCellRandomTest.java index 7f71b8feb..2112db81f 100644 --- a/test/arcade/patch/agent/cell/PatchCellRandomTest.java +++ b/test/arcade/patch/agent/cell/PatchCellRandomTest.java @@ -2,6 +2,7 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import sim.util.Bag; import ec.util.MersenneTwisterFast; import arcade.core.util.GrabBag; import arcade.core.util.MiniBox; @@ -43,6 +44,8 @@ public class PatchCellRandomTest { static State cellState = State.QUIESCENT; + static Bag cellCycles = new Bag(); + static PatchCellContainer baseContainer = new PatchCellContainer( cellID, @@ -54,7 +57,8 @@ public class PatchCellRandomTest { cellVolume, cellHeight, cellCriticalVolume, - cellCriticalHeight); + cellCriticalHeight, + cellCycles); @BeforeAll public static void setupMocks() { @@ -84,7 +88,8 @@ public void make_calledNoLinks_createsContainer() { volume, height, criticalVolume, - criticalHeight); + criticalHeight, + cellCycles); PatchCellRandom cell = new PatchCellRandom(cellContainer, locationMock, parametersMock, null); @@ -130,7 +135,8 @@ public void make_calledWithLinks_createsContainer() { volume, height, criticalVolume, - criticalHeight); + criticalHeight, + cellCycles); PatchCellRandom cell = new PatchCellRandom(cellContainer, locationMock, parametersMock, links); diff --git a/test/arcade/patch/agent/cell/PatchCellTest.java b/test/arcade/patch/agent/cell/PatchCellTest.java index 63ccb0367..a75a29d62 100644 --- a/test/arcade/patch/agent/cell/PatchCellTest.java +++ b/test/arcade/patch/agent/cell/PatchCellTest.java @@ -58,6 +58,8 @@ public class PatchCellTest { static State cellState = State.QUIESCENT; + static Bag cellCycles = new Bag(); + static PatchCellContainer baseContainer = new PatchCellContainer( cellID, @@ -69,7 +71,8 @@ public class PatchCellTest { cellVolume, cellHeight, cellCriticalVolume, - cellCriticalHeight); + cellCriticalHeight, + cellCycles); static class PatchCellMock extends PatchCellTissue { PatchCellMock(PatchCellContainer container, Location location, Parameters parameters) { @@ -88,7 +91,8 @@ public PatchCellContainer make(int newID, CellState newState, MersenneTwisterFas volume, height, criticalVolume, - criticalHeight); + criticalHeight, + cycles); } } @@ -275,7 +279,8 @@ public void setState_proliferation_createsCell() { volume, cellHeight, critVolume, - critHeight); + critHeight, + cellCycles); PatchCellContainer daughterContainer = new PatchCellContainer( @@ -288,7 +293,8 @@ public void setState_proliferation_createsCell() { volume, cellHeight, critVolume, - critHeight); + critHeight, + cellCycles); PatchCell cell = spy(new PatchCellMock(container, locationMock, parametersMock)); cell.setEnergy(200.); @@ -344,7 +350,8 @@ public void setState_proliferationWithNoFreeLocation_setQuiescent() { volume, cellHeight, critVolume, - critHeight); + critHeight, + cellCycles); PatchCell cell = spy(new PatchCellMock(container, locationMock, parametersMock)); Bag locationBag = new Bag(); @@ -379,7 +386,8 @@ public void setState_proliferativeWhenHeightExceedsCriticalHeight_setQuiescent() volume, cellHeight, cellCriticalVolume, - critHeight); + critHeight, + cellCycles); PatchCell cell = spy(new PatchCellMock(container, locationMock, parametersMock)); Bag locationBag = new Bag(); @@ -449,7 +457,8 @@ final Bag createPatchCellsWithVolumeAndCriticalHeight(int n, double volume, doub volume, cellHeight, cellCriticalVolume, - critHeight); + critHeight, + cellCycles); PatchCell cell = new PatchCellMock(container, locationMock, parametersMock); bag.add(cell); } @@ -612,7 +621,8 @@ public void findFreeLocations_whenOnlyOneNeighborIsFree_returnsCurrentAndOpenLoc cellVolume, cellHeight, cellCriticalVolume, - cellCriticalHeight); + cellCriticalHeight, + cellCycles); PatchCell cell = new PatchCellMock(container, locationMock, parametersMock); Bag currentBag = new Bag(); @@ -664,7 +674,8 @@ public void findFreeLocations_whenOnlyOneNeighborIsFree_returnsCurrentAndOpenLoc cellVolume, cellHeight, cellCriticalVolume, - cellCriticalHeight); + cellCriticalHeight, + cellCycles); PatchCell cell = new PatchCellMock(container, locationMock, parametersMock); Bag currentBag = new Bag(); diff --git a/test/arcade/patch/agent/cell/PatchCellTissueTest.java b/test/arcade/patch/agent/cell/PatchCellTissueTest.java index 006acccdf..20a11bfcf 100644 --- a/test/arcade/patch/agent/cell/PatchCellTissueTest.java +++ b/test/arcade/patch/agent/cell/PatchCellTissueTest.java @@ -3,6 +3,7 @@ import java.util.ArrayList; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import sim.util.Bag; import ec.util.MersenneTwisterFast; import arcade.core.agent.cell.CellState; import arcade.core.env.location.*; @@ -58,6 +59,8 @@ public class PatchCellTissueTest { static double cellCriticalHeight = randomDoubleBetween(10, 100); + static Bag cycles = new Bag(); + static class PatchCellMock extends PatchCellTissue { PatchCellMock(PatchCellContainer container, Location location, Parameters parameters) { super(container, location, parameters, null); @@ -75,7 +78,8 @@ public PatchCellContainer make(int newID, CellState newState, MersenneTwisterFas volume, height, criticalVolume, - criticalHeight); + criticalHeight, + cycles); } } @@ -117,7 +121,8 @@ public void step_calledWhenAgeGreaterThanApoptosisAge_setsApoptoticState() { cellVolume, cellHeight, cellCriticalVolume, - cellCriticalHeight); + cellCriticalHeight, + cycles); PatchCell cell = spy(new PatchCellMock(container, locationMock, parametersMock)); cell.processes.put(Domain.METABOLISM, metabolismMock); cell.processes.put(Domain.SIGNALING, signalingMock); @@ -160,7 +165,8 @@ public void step_calledWhenAgeLessThanApoptosisAge_doesNotSetState() { cellVolume, cellHeight, cellCriticalVolume, - cellCriticalHeight); + cellCriticalHeight, + cycles); PatchCell cell = spy(new PatchCellMock(container, locationMock, parametersMock)); cell.processes.put(Domain.METABOLISM, metabolismMock); cell.processes.put(Domain.SIGNALING, signalingMock); @@ -199,7 +205,8 @@ public void step_calledApoptoticStateAndApoptoticAge_doesNotResetState() { cellVolume, cellHeight, cellCriticalVolume, - cellCriticalHeight); + cellCriticalHeight, + cycles); PatchCell cell = spy(new PatchCellMock(container, locationMock, parametersMock)); cell.processes.put(Domain.METABOLISM, metabolismMock); cell.processes.put(Domain.SIGNALING, signalingMock); @@ -244,7 +251,8 @@ public void step_nutrientStarved_setNecroticStateWithProbability() { cellVolume, cellHeight, cellCriticalVolume, - cellCriticalHeight); + cellCriticalHeight, + cycles); PatchCell cell = spy(new PatchCellMock(container, locationMock, parametersMock)); cell.processes.put(Domain.METABOLISM, metabolismMock); cell.processes.put(Domain.SIGNALING, signalingMock); @@ -291,7 +299,8 @@ public void step_nutrientStarved_setApototicStateWithProbability() { cellVolume, cellHeight, cellCriticalVolume, - cellCriticalHeight); + cellCriticalHeight, + cycles); PatchCell cell = spy(new PatchCellMock(container, locationMock, parametersMock)); cell.processes.put(Domain.METABOLISM, metabolismMock); cell.processes.put(Domain.SIGNALING, signalingMock); @@ -336,7 +345,8 @@ public void step_energyDeficitDoesNotExceedThreshold_setQuiescent() { cellVolume, cellHeight, cellCriticalVolume, - cellCriticalHeight); + cellCriticalHeight, + cycles); PatchCell cell = spy(new PatchCellMock(container, locationMock, parametersMock)); cell.processes.put(Domain.METABOLISM, metabolismMock); cell.processes.put(Domain.SIGNALING, signalingMock); @@ -377,7 +387,8 @@ public void step_undefinedCellWithMigratoryFlag_setsMigratoryState() { cellVolume, cellHeight, cellCriticalVolume, - cellCriticalHeight); + cellCriticalHeight, + cycles); PatchCell cell = spy(new PatchCellMock(container, locationMock, parametersMock)); cell.processes.put(Domain.METABOLISM, metabolismMock); cell.processes.put(Domain.SIGNALING, signalingMock); @@ -417,7 +428,8 @@ public void step_undefinedCellWithProliferativeFlag_setsProliferativeState() { cellVolume, cellHeight, cellCriticalVolume, - cellCriticalHeight); + cellCriticalHeight, + cycles); PatchCell cell = spy(new PatchCellMock(container, locationMock, parametersMock)); cell.processes.put(Domain.METABOLISM, metabolismMock); cell.processes.put(Domain.SIGNALING, signalingMock); @@ -462,7 +474,8 @@ public void step_undefinedCellWithProliferativeFlag_setsProliferativeState() { cellVolume, cellHeight, cellCriticalVolume, - cellCriticalHeight); + cellCriticalHeight, + cycles); PatchCell cell = spy(new PatchCellMock(container, locationMock, parametersMock)); cell.processes.put(Domain.METABOLISM, metabolismMock); cell.processes.put(Domain.SIGNALING, signalingMock); @@ -507,7 +520,8 @@ public void step_undefinedCellWithProliferativeFlag_setsProliferativeState() { cellVolume, cellHeight, cellCriticalVolume, - cellCriticalHeight); + cellCriticalHeight, + cycles); PatchCell cell = spy(new PatchCellMock(container, locationMock, parametersMock)); cell.processes.put(Domain.METABOLISM, metabolismMock); cell.processes.put(Domain.SIGNALING, signalingMock); @@ -556,7 +570,8 @@ public void make_calledWithoutLinks_createsContainer() { volume, height, criticalVolume, - criticalHeight); + criticalHeight, + cycles); PatchCellTissue cell = new PatchCellTissue(cellContainer, locationMock, parametersMock, links); @@ -605,7 +620,8 @@ public void make_calledWithLinks_createsContainer() { volume, height, criticalVolume, - criticalHeight); + criticalHeight, + cycles); PatchCellTissue cell = new PatchCellTissue(cellContainer, locationMock, parametersMock, links); diff --git a/v2.4 b/v2.4 new file mode 160000 index 000000000..b8adced65 --- /dev/null +++ b/v2.4 @@ -0,0 +1 @@ +Subproject commit b8adced65b0bdf90e1a989e91b3e7c65b5ae88a2 From 2bb3c09aa3d55a82e644cb03d12830f247d768d5 Mon Sep 17 00:00:00 2001 From: cainja Date: Fri, 25 Apr 2025 18:39:40 -0700 Subject: [PATCH 02/28] adding combined t cell inflammation --- .../agent/cell/PatchCellCARTCombined.java | 172 ++++++++++++++++++ .../agent/module/PatchModuleStimulation.java | 8 +- .../process/PatchProcessInflammation.java | 111 ++++++++++- 3 files changed, 283 insertions(+), 8 deletions(-) create mode 100644 src/arcade/patch/agent/cell/PatchCellCARTCombined.java diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombined.java b/src/arcade/patch/agent/cell/PatchCellCARTCombined.java new file mode 100644 index 000000000..b5bddf37f --- /dev/null +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombined.java @@ -0,0 +1,172 @@ +package arcade.patch.agent.cell; + +import sim.engine.SimState; +import ec.util.MersenneTwisterFast; +import arcade.core.agent.cell.CellState; +import arcade.core.env.location.Location; +import arcade.core.sim.Simulation; +import arcade.core.util.GrabBag; +import arcade.core.util.Parameters; +import arcade.patch.util.PatchEnums.AntigenFlag; +import arcade.patch.util.PatchEnums.Domain; +import arcade.patch.util.PatchEnums.State; + +/** Extension of {@link PatchCellCART} for CD8 CART-cells with selected module versions. */ +public class PatchCellCARTCombined extends PatchCellCART { + + /** + * Creates a T cell {@code PatchCellCARTCD8} agent. * + * + * @param container the cell container + * @param location the {@link Location} of the cell + * @param parameters the dictionary of parameters + */ + public PatchCellCARTCombined( + PatchCellContainer container, Location location, Parameters parameters) { + this(container, location, parameters, null); + } + + /** + * Creates a T cell {@code PatchCellCARTCD8} agent. * + * + * @param container the cell container + * @param location the {@link Location} of the cell + * @param parameters the dictionary of parameters + * @param links the map of population links + */ + public PatchCellCARTCombined( + PatchCellContainer container, Location location, Parameters parameters, GrabBag links) { + super(container, location, parameters, links); + } + + @Override + public PatchCellContainer make(int newID, CellState newState, MersenneTwisterFast random) { + divisions++; + return new PatchCellContainer( + newID, + id, + pop, + age, + divisions, + newState, + volume, + height, + criticalVolume, + criticalHeight); + } + + @Override + public void step(SimState simstate) { + Simulation sim = (Simulation) simstate; + + super.age++; + + if (state != State.APOPTOTIC && age > apoptosisAge) { + setState(State.APOPTOTIC); + super.unbind(); + this.activated = false; + } + + super.lastActiveTicker++; + + if (super.lastActiveTicker != 0 && super.lastActiveTicker % MINUTES_IN_DAY == 0) { + if (super.boundCARAntigensCount != 0) { + super.boundCARAntigensCount--; + } + } + if (super.lastActiveTicker / MINUTES_IN_DAY >= 7) { + super.activated = false; + } + + super.processes.get(Domain.METABOLISM).step(simstate.random, sim); + + // Check energy status. If cell has less energy than threshold, it will + // apoptose. If overall energy is negative, then cell enters quiescence. + if (state != State.APOPTOTIC) { + if (super.energy < super.energyThreshold) { + + super.setState(State.APOPTOTIC); + super.unbind(); + this.activated = false; + } else if (state != State.ANERGIC + && state != State.SENESCENT + && state != State.EXHAUSTED + && state != State.STARVED + && energy < 0) { + + super.setState(State.STARVED); + super.unbind(); + } else if (state == State.STARVED && energy >= 0) { + super.setState(State.UNDEFINED); + } + } + + super.processes.get(Domain.INFLAMMATION).step(simstate.random, sim); + + if (super.state == State.UNDEFINED || super.state == State.PAUSED) { + if (divisions == divisionPotential) { + if (simstate.random.nextDouble() > super.senescentFraction) { + super.setState(State.APOPTOTIC); + } else { + super.setState(State.SENESCENT); + } + super.unbind(); + this.activated = false; + } else { + PatchCellTissue target = super.bindTarget(sim, location, simstate.random); + super.boundTarget = target; + + // If cell is bound to both antigen and self it will become anergic. + if (super.getBindingFlag() == AntigenFlag.BOUND_ANTIGEN_CELL_RECEPTOR) { + if (simstate.random.nextDouble() > super.anergicFraction) { + super.setState(State.APOPTOTIC); + } else { + super.setState(State.ANERGIC); + } + super.unbind(); + this.activated = false; + } else if (super.getBindingFlag() == AntigenFlag.BOUND_ANTIGEN) { + // If cell is only bound to target antigen, the cell + // can potentially become properly activated. + + // Check overstimulation. If cell has bound to + // target antigens too many times, becomes exhausted. + if (boundCARAntigensCount > maxAntigenBinding) { + if (simstate.random.nextDouble() > super.exhaustedFraction) { + super.setState(State.APOPTOTIC); + } else { + super.setState(State.EXHAUSTED); + } + super.unbind(); + this.activated = false; + } else { + // if CD8 cell is properly activated, it can be cytotoxic + this.lastActiveTicker = 0; + this.activated = true; + super.setState(State.CYTOTOXIC); + } + } else { + // If self binding, unbind + if (super.getBindingFlag() == AntigenFlag.BOUND_CELL_RECEPTOR) { + super.unbind(); + } + // Check activation status. If cell has been activated before, + // it will proliferate. If not, it will migrate. + if (activated) { + super.setState(State.PROLIFERATIVE); + } else { + if (simstate.random.nextDouble() > super.proliferativeFraction) { + super.setState(State.MIGRATORY); + } else { + super.setState(State.PROLIFERATIVE); + } + } + } + } + } + + if (super.module != null) { + super.module.step(simstate.random, sim); + } + } +} diff --git a/src/arcade/patch/agent/module/PatchModuleStimulation.java b/src/arcade/patch/agent/module/PatchModuleStimulation.java index 48f961dcb..8f4c3d0cb 100644 --- a/src/arcade/patch/agent/module/PatchModuleStimulation.java +++ b/src/arcade/patch/agent/module/PatchModuleStimulation.java @@ -9,11 +9,9 @@ import arcade.patch.util.PatchEnums.State; /** - * Implementation of {@link Module} for stimulatory T cell agents. - * - *

{@code PatchModuleStimulation} is stepped once after a CD4 CAR T-cell gets stimulated. The - * {@code PatchModuleStimulation} activates the T cell, unbinds to any target cell that the T cell - * is bound to, and sets the cell state back to undefined. + * Implementation of {@link Module} for stimulatory T cell agents. {@code PatchModuleStimulation} + * activates the T cell, unbinds to any target cell that the T cell is bound to, and sets the cell + * state back to undefined. */ public class PatchModuleStimulation extends PatchModule { /** Target cell thgt CAR T-cell is bound to. */ diff --git a/src/arcade/patch/agent/process/PatchProcessInflammation.java b/src/arcade/patch/agent/process/PatchProcessInflammation.java index 29675a561..1c8a37efc 100644 --- a/src/arcade/patch/agent/process/PatchProcessInflammation.java +++ b/src/arcade/patch/agent/process/PatchProcessInflammation.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.List; import ec.util.MersenneTwisterFast; +import arcade.core.agent.process.Process; import arcade.core.env.location.Location; import arcade.core.sim.Simulation; import arcade.core.util.Parameters; @@ -19,7 +20,7 @@ * *

The {@code Inflammation} module represents an 8-component signaling network. */ -public abstract class PatchProcessInflammation extends PatchProcess { +public class PatchProcessInflammation extends PatchProcess { /** Number of components in signaling network. */ protected static final int NUM_COMPONENTS = 8; @@ -117,6 +118,30 @@ public abstract class PatchProcessInflammation extends PatchProcess { /** Total 2-complex receptors. */ protected final double iL2Receptors; + /** Moles of granzyme produced per moles IL-2 [mol granzyme/mol IL-2]. */ + private static final double GRANZ_PER_IL2 = 0.005; + + /** Delay in IL-2 synthesis after antigen-induced activation. */ + private final int granzSynthesisDelay; + + /** Amount of IL-2 bound in past being used for current granzyme production calculation. */ + private double priorIL2granz; + + /** Rate of IL-2 production due to antigen-induced activation [molecules IL-2/cell/min]. */ + private final double iL2ProdRateActive = 293.27; + + /** Rate of IL-2 production due to IL-2 feedback [molecules IL-2/cell/min]. */ + private final double iL2ProdRateMaxFeedback = 16.62; + + /** Delay in IL-2 synthesis after antigen-induced activation. */ + private final int iL2SynthesisDelay; + + /** Total rate of IL-2 production. */ + private double iL2ProdRate; + + /** Amount of IL-2 bound in past being used for current IL-2 production calculation. */ + private double priorIL2prod; + /** * Creates an {@code Inflammation} module for the given {@link PatchCellCART}. * @@ -138,6 +163,11 @@ public PatchProcessInflammation(PatchCellCART cell) { Parameters parameters = cell.getParameters(); this.shellThickness = parameters.getDouble("inflammation/SHELL_THICKNESS"); this.iL2Receptors = parameters.getDouble("inflammation/IL2_RECEPTORS"); + this.iL2SynthesisDelay = parameters.getInt("inflammation/IL2_SYNTHESIS_DELAY"); + this.granzSynthesisDelay = parameters.getInt("inflammation/GRANZ_SYNTHESIS_DELAY"); + + priorIL2granz = 0; + iL2ProdRate = 0; extIL2 = 0; amts = new double[NUM_COMPONENTS]; @@ -147,6 +177,7 @@ public PatchProcessInflammation(PatchCellCART cell) { amts[IL2RBGA] = 0; amts[IL2_IL2RBG] = 0; amts[IL2_IL2RBGA] = 0; + amts[GRANZYME] = 1; // [molecules] names = new ArrayList(); names.add(IL2_INT_TOTAL, "IL-2"); @@ -156,6 +187,7 @@ public PatchProcessInflammation(PatchCellCART cell) { names.add(IL2RBGA, "IL2R_three_chain_complex"); names.add(IL2_IL2RBG, "IL-2_IL2R_two_chain_complex"); names.add(IL2_IL2RBGA, "IL-2_IL2R_three_chain_complex"); + names.add(GRANZYME, "granzyme"); // Initialize prior IL2 array. this.boundArray = new double[180]; @@ -252,7 +284,80 @@ public void setInternal(String key, double val) { * @param random the random number generator * @param sim the simulation instance */ - abstract void stepProcess(MersenneTwisterFast random, Simulation sim); + void stepProcess(MersenneTwisterFast random, Simulation sim) { + stepCD4(sim); + stepCD8(sim); + double iL2Env = + (((extIL2 - (extIL2 * fraction - amts[IL2_EXT])) + iL2ProdRate) + * 1E12 + / loc.getVolume()); + + sim.getLattice("IL-2").setValue(loc, iL2Env); + } + + void stepCD4(Simulation sim) { + + // Determine IL-2 production rate as a function of IL-2 bound. + int prodIndex = (iL2Ticker % boundArray.length) - iL2SynthesisDelay; + if (prodIndex < 0) { + prodIndex += boundArray.length; + } + priorIL2prod = boundArray[prodIndex]; + iL2ProdRate = iL2ProdRateMaxFeedback * (priorIL2prod / iL2Receptors); + + // Add IL-2 production rate dependent on antigen-induced + // cell activation if cell is activated. + if (active && activeTicker >= iL2SynthesisDelay) { + iL2ProdRate += iL2ProdRateActive; + } + } + + void stepCD8(Simulation sim) { + + // Determine amount of granzyme production based on if cell is activated + // as a function of IL-2 production. + int granzIndex = (iL2Ticker % boundArray.length) - granzSynthesisDelay; + if (granzIndex < 0) { + granzIndex += boundArray.length; + } + priorIL2granz = boundArray[granzIndex]; + + if (active && activeTicker > granzSynthesisDelay) { + amts[GRANZYME] += GRANZ_PER_IL2 * (priorIL2granz / iL2Receptors); + } + } + + @Override + public void update(Process process) { + PatchProcessInflammation inflammation = (PatchProcessInflammation) process; + double split = (this.cell.getVolume() / this.volume); + + // Update daughter cell inflammation as a fraction of parent. + this.amts[IL2RBGA] = inflammation.amts[IL2RBGA] * split; + this.amts[IL2_IL2RBG] = inflammation.amts[IL2_IL2RBG] * split; + this.amts[IL2_IL2RBGA] = inflammation.amts[IL2_IL2RBGA] * split; + this.amts[IL2RBG] = + iL2Receptors - this.amts[IL2RBGA] - this.amts[IL2_IL2RBG] - this.amts[IL2_IL2RBGA]; + this.amts[IL2_INT_TOTAL] = this.amts[IL2_IL2RBG] + this.amts[IL2_IL2RBGA]; + this.amts[IL2R_TOTAL] = this.amts[IL2RBG] + this.amts[IL2RBGA]; + this.amts[GRANZYME] = inflammation.amts[GRANZYME] * split; + this.boundArray = (inflammation.boundArray).clone(); + + // Update parent cell with remaining fraction. + inflammation.amts[IL2RBGA] *= (1 - split); + inflammation.amts[IL2_IL2RBG] *= (1 - split); + inflammation.amts[IL2_IL2RBGA] *= (1 - split); + inflammation.amts[IL2RBG] = + iL2Receptors + - inflammation.amts[IL2RBGA] + - inflammation.amts[IL2_IL2RBG] + - inflammation.amts[IL2_IL2RBGA]; + inflammation.amts[IL2_INT_TOTAL] = + inflammation.amts[IL2_IL2RBG] + inflammation.amts[IL2_IL2RBGA]; + inflammation.amts[IL2R_TOTAL] = inflammation.amts[IL2RBG] + inflammation.amts[IL2RBGA]; + inflammation.amts[GRANZYME] *= (1 - split); + inflammation.volume *= (1 - split); + } /** * Gets the external amounts of IL-2. @@ -313,7 +418,7 @@ public static PatchProcess make(PatchCell cell, String version) { case "CD8": return new PatchProcessInflammationCD8((PatchCellCART) cell); default: - return null; + return new PatchProcessInflammation((PatchCellCART) cell); } } } From c579357d534e7c7ba4d26ae829eebd29b6a98854 Mon Sep 17 00:00:00 2001 From: cainja Date: Mon, 28 Apr 2025 13:25:20 -0700 Subject: [PATCH 03/28] fixed replacement, added some more mechanisms --- .../agent/action/PatchActionReplace.java | 149 ++++++++++++++++++ .../patch/agent/cell/PatchCellCART.java | 42 ++--- .../cell/PatchCellCARTCombinedInducible.java | 130 +++++++++++++++ .../cell/PatchCellCARTCombinedInhibitory.java | 129 +++++++++++++++ .../patch/agent/cell/PatchCellContainer.java | 6 + .../patch/agent/cell/PatchCellTissue.java | 17 ++ src/arcade/patch/parameter.patch.xml | 15 +- src/arcade/patch/sim/PatchSimulationHex.java | 3 + src/arcade/patch/sim/PatchSimulationRect.java | 3 + 9 files changed, 473 insertions(+), 21 deletions(-) create mode 100644 src/arcade/patch/agent/action/PatchActionReplace.java create mode 100644 src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java create mode 100644 src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java diff --git a/src/arcade/patch/agent/action/PatchActionReplace.java b/src/arcade/patch/agent/action/PatchActionReplace.java new file mode 100644 index 000000000..83a1c3efa --- /dev/null +++ b/src/arcade/patch/agent/action/PatchActionReplace.java @@ -0,0 +1,149 @@ +package arcade.patch.agent.action; + +import java.util.ArrayList; +import java.util.logging.Logger; +import sim.engine.Schedule; +import sim.engine.SimState; +import sim.util.Bag; +import arcade.core.agent.action.Action; +import arcade.core.env.location.Location; +import arcade.core.sim.Series; +import arcade.core.sim.Simulation; +import arcade.core.util.MiniBox; +import arcade.core.util.Utilities; +import arcade.patch.agent.cell.PatchCell; +import arcade.patch.agent.cell.PatchCellContainer; +import arcade.patch.env.grid.PatchGrid; +import arcade.patch.env.location.Coordinate; +import arcade.patch.env.location.PatchLocationContainer; +import arcade.patch.sim.PatchSeries; +import arcade.patch.sim.PatchSimulation; +import static arcade.patch.util.PatchEnums.Ordering; + +/** + * Implementation of {@link Action} for inserting cell agents. + * + *

The action is stepped once after {@code TIME_DELAY}. The action will insert a mixture of + * {@code INSERT_NUMBER} cells from each of the registered populations into locations within the + * specified radius {@code INSERT_RADIUS} from the center of the simulation. + */ +public class PatchActionReplace implements Action { + private static final Logger LOGGER = Logger.getLogger(PatchActionReplace.class.getName()); + + /** Time delay before calling the action [min]. */ + private final int timeDelay; + + /** Grid radius that cells are inserted into. */ + private final int insertRadius; + + /** Grid depth that cells are inserted into. */ + private final int insertDepth; + + /** Number of cells to insert from each population. */ + private final int insertNumber; + + /** List of populations. */ + private final ArrayList populations; + + /** + * Creates a {@link Action} for removing cell agents. + * + *

Loaded parameters include: + * + *

+ * + * @param series the simulation series + * @param parameters the component parameters dictionary + */ + public PatchActionReplace(Series series, MiniBox parameters) { + int maxRadius = ((PatchSeries) series).radius; + + // Set loaded parameters. + timeDelay = parameters.getInt("TIME_DELAY"); + insertRadius = Math.min(maxRadius, parameters.getInt("INSERT_RADIUS")); + insertDepth = ((PatchSeries) series).depth; + insertNumber = parameters.getInt("INSERT_NUMBER"); + + // Initialize population register. + populations = new ArrayList<>(); + LOGGER.info( + "Action Replace: " + + parameters.getInt("TIME_DELAY") + + " " + + insertRadius + + " " + + insertNumber); + } + + @Override + public void schedule(Schedule schedule) { + schedule.scheduleOnce(timeDelay, Ordering.ACTIONS.ordinal(), this); + } + + @Override + public void register(Simulation sim, String population) { + populations.add(sim.getSeries().populations.get(population)); + } + + @Override + public void step(SimState simstate) { + PatchSimulation sim = (PatchSimulation) simstate; + PatchGrid grid = (PatchGrid) sim.getGrid(); + + // Select valid coordinates to insert into and shuffle. + ArrayList coordinates = + sim.locationFactory.getCoordinates(insertRadius, insertDepth); + Utilities.shuffleList(coordinates, sim.random); + + // Add cells from each population into insertion area. + for (MiniBox population : populations) { + int id = sim.getID(); + int pop = population.getInt("CODE"); + + for (int i = 0; i < insertNumber; i++) { + if (coordinates.isEmpty()) { + break; + } + + Coordinate coord = coordinates.remove(0); + PatchLocationContainer locationContainer = new PatchLocationContainer(id, coord); + PatchCellContainer tempContainer = sim.cellFactory.createCellForPopulation(id, pop); + Location tempLocation = + locationContainer.convert(sim.locationFactory, tempContainer); + + Bag bag = (Bag) grid.getObjectAt(tempLocation.hashCode()); + + if (bag == null) { + continue; + } + + // Select old cell and remove from simulation. + PatchCell oldCell = (PatchCell) bag.get(0); + Location location = oldCell.getLocation(); + grid.removeObject(oldCell, oldCell.getLocation()); + oldCell.stop(); + // Create new cell and add to simulation. + PatchCellContainer cellContainer = + new PatchCellContainer( + oldCell.getID(), + oldCell.getParent(), + pop, + oldCell.getAge(), + oldCell.getDivisions(), + oldCell.getState(), + oldCell.getVolume(), + oldCell.getHeight(), + oldCell.getCriticalVolume(), + oldCell.getCriticalHeight()); + PatchCell newCell = + (PatchCell) cellContainer.convert(sim.cellFactory, location, sim.random); + grid.addObject(newCell, location); + newCell.schedule(sim.getSchedule()); + } + } + } +} diff --git a/src/arcade/patch/agent/cell/PatchCellCART.java b/src/arcade/patch/agent/cell/PatchCellCART.java index 25cc71835..801704594 100644 --- a/src/arcade/patch/agent/cell/PatchCellCART.java +++ b/src/arcade/patch/agent/cell/PatchCellCART.java @@ -9,6 +9,8 @@ import arcade.core.util.Parameters; import arcade.patch.env.grid.PatchGrid; import arcade.patch.env.location.PatchLocation; +import arcade.patch.util.PatchEnums.AntigenFlag; +import arcade.patch.util.PatchEnums.State; import static arcade.patch.util.PatchEnums.AntigenFlag; import static arcade.patch.util.PatchEnums.State; @@ -95,7 +97,7 @@ public abstract class PatchCellCART extends PatchCell { protected final int maxAntigenBinding; /** number of CARs on T cell surface. */ - protected final int cars; + protected int cars; /** simulation time since T cell was last activated. */ protected int lastActiveTicker; @@ -202,7 +204,7 @@ public PatchCellTissue bindTarget( double kDSelf = computeAffinity(selfReceptorAffinity, loc); PatchGrid grid = (PatchGrid) sim.getGrid(); - Bag allAgents = grabAllTissueNeighbors(grid, loc); + Bag allAgents = getAllTissueNeighbors(grid, loc); allAgents.remove(this); allAgents.shuffle(random); int neighbors = allAgents.size(); @@ -259,21 +261,6 @@ public boolean getActivationStatus() { return this.activated; } - /** - * Adds only tissue cells to the provided bag. - * - * @param tissueAgents the bag to add tissue cells into - * @param possibleAgents the bag of possible agents to check for tissue cells - */ - private void grabTissueAgents(Bag tissueAgents, Bag possibleAgents) { - for (Object agent : possibleAgents) { - Cell cell = (Cell) agent; - if (cell instanceof PatchCellTissue) { - tissueAgents.add(cell); - } - } - } - /** * Computes the binding probability for the receptor with the given parameters. * @@ -337,6 +324,21 @@ private PatchCellTissue bindToSelfAntigen(PatchCellTissue tissueCell) { return tissueCell; } + /** + * Adds only tissue cells to the provided bag. Helper method for bindTarget. + * + * @param tissueAgents the bag to add tissue cells into + * @param possibleAgents the bag of possible agents to check for tissue cells + */ + public void getTissueAgents(Bag tissueAgents, Bag possibleAgents) { + for (Object agent : possibleAgents) { + Cell cell = (Cell) agent; + if (cell instanceof PatchCellTissue) { + tissueAgents.add(cell); + } + } + } + /** * Returns all tissue cells in neighborhood and current location. * @@ -344,12 +346,12 @@ private PatchCellTissue bindToSelfAntigen(PatchCellTissue tissueCell) { * @param loc current location of the cell * @return bag of all tissue cells in neighborhood and current location */ - private Bag grabAllTissueNeighbors(PatchGrid grid, PatchLocation loc) { + private Bag getAllTissueNeighbors(PatchGrid grid, PatchLocation loc) { Bag neighbors = new Bag(); - grabTissueAgents(neighbors, grid.getObjectsAtLocation(loc)); + getTissueAgents(neighbors, grid.getObjectsAtLocation(loc)); for (Location neighborLocation : loc.getNeighbors()) { Bag bag = new Bag(grid.getObjectsAtLocation(neighborLocation)); - grabTissueAgents(neighbors, bag); + getTissueAgents(neighbors, bag); } return neighbors; diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java new file mode 100644 index 000000000..901a1e316 --- /dev/null +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java @@ -0,0 +1,130 @@ +package arcade.patch.agent.cell; + +import java.util.logging.Logger; +import sim.engine.SimState; +import sim.util.Bag; +import sim.util.distribution.Poisson; +import ec.util.MersenneTwisterFast; +import arcade.core.env.location.Location; +import arcade.core.sim.Simulation; +import arcade.core.util.GrabBag; +import arcade.core.util.Parameters; +import arcade.patch.env.grid.PatchGrid; + +public class PatchCellCARTCombinedInducible extends PatchCellCARTCombined { + private static final Logger LOGGER = + Logger.getLogger(PatchCellCARTCombinedInducible.class.getName()); + protected final double synNotchThreshold; + protected final double bindingConstant; + protected final double unbindingConstant; + protected final double carDegradationConstant; + public final int synnotchs; + public int boundSynNotch; + protected final int maxCars; + PoissonFactory poissonFactory; + private PatchCellTissue boundCell; + + /** + * Creates a tissue {@code PatchCellSynNotch} agent. * + * + * @param location the {@link Location} of the cell + * @param parameters the dictionary of parameters + */ + public PatchCellCARTCombinedInducible( + PatchCellContainer container, Location location, Parameters parameters) { + this(container, location, parameters, null); + } + + public PatchCellCARTCombinedInducible( + PatchCellContainer container, Location location, Parameters parameters, GrabBag links) { + super(container, location, parameters, links); + bindingConstant = parameters.getDouble("K_SYNNOTCH_ON"); + unbindingConstant = parameters.getDouble("K_SYNNOTCH_OFF"); + carDegradationConstant = parameters.getDouble("K_CAR_DEGRADE"); + synnotchs = parameters.getInt("SYNNOTCHS"); + synNotchThreshold = parameters.getDouble("SYNNOTCH_THRESHOLD") * synnotchs; + boundSynNotch = 0; + maxCars = cars; + cars = 0; + poissonFactory = Poisson::new; + } + + public double callPoisson(double lambda, MersenneTwisterFast random) { + return poissonFactory.createPoisson(lambda, random).nextInt(); + } + + @Override + public void step(SimState simstate) { + if (boundCell == null) { + checkForBinding(simstate); + } else { + calculateCARS(simstate.random); + } + super.step(simstate); + } + + private void calculateCARS(MersenneTwisterFast random) { + int TAU = 60; + int unboundSynNotch = synnotchs - boundSynNotch; + double expectedBindingEvents = + bindingConstant + / (volume * 6.0221415e23 * 1e-15) + * unboundSynNotch + * boundCell.getSynNotchAntigens() + * contactFraction + * TAU; + int bindingEvents = poissonFactory.createPoisson(expectedBindingEvents, random).nextInt(); + double expectedUnbindingEvents = unbindingConstant * boundSynNotch * TAU; + int unbindingEvents = + poissonFactory.createPoisson(expectedUnbindingEvents, random).nextInt(); + + boundSynNotch += bindingEvents; + boundSynNotch -= unbindingEvents; + boundCell.updateSynNotchAntigens(unbindingEvents, bindingEvents); + double n = 4.4; + int new_cars = + (int) (maxCars / (1 + Math.pow(synNotchThreshold, n) / Math.pow(boundSynNotch, n))); + + cars = Math.max((int) (cars - (carDegradationConstant * cars * TAU)), new_cars); + } + + /** A {@code PoissonFactory} object instantiates Poisson distributions. */ + interface PoissonFactory { + /** + * Creates instance of Poisson. + * + * @param lambda the Poisson distribution lambda + * @param random the random number generator + * @return a Poisson distribution instance + */ + Poisson createPoisson(double lambda, MersenneTwisterFast random); + } + + private void checkForBinding(SimState simstate) { + Simulation sim = (Simulation) simstate; + PatchGrid grid = (PatchGrid) sim.getGrid(); + + Bag allAgents = new Bag(); + getTissueAgents(allAgents, grid.getObjectsAtLocation(location)); + for (Location neighborLocation : location.getNeighbors()) { + Bag bag = new Bag(grid.getObjectsAtLocation(neighborLocation)); + getTissueAgents(allAgents, bag); + } + + if (allAgents.size() > 0) { + PatchCellTissue randomCell = + (PatchCellTissue) allAgents.get(simstate.random.nextInt(allAgents.size())); + if (randomCell.getSynNotchAntigens() > 0) { + boundCell = randomCell; + } + } + } + + public void resetBoundCell() { + if (boundCell != null) { + boundCell.updateSynNotchAntigens(boundSynNotch, 0); + boundCell = null; + } + boundSynNotch = 0; + } +} diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java new file mode 100644 index 000000000..2e37687e9 --- /dev/null +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java @@ -0,0 +1,129 @@ +package arcade.patch.agent.cell; + +import java.util.logging.Logger; +import sim.engine.SimState; +import sim.util.Bag; +import sim.util.distribution.Poisson; +import ec.util.MersenneTwisterFast; +import arcade.core.env.location.Location; +import arcade.core.sim.Simulation; +import arcade.core.util.GrabBag; +import arcade.core.util.Parameters; +import arcade.patch.env.grid.PatchGrid; + +public class PatchCellCARTCombinedInhibitory extends PatchCellCARTCombined { + private static final Logger LOGGER = + Logger.getLogger(PatchCellCARTCombinedInducible.class.getName()); + protected final double synNotchThreshold; + protected final double bindingConstant; + protected final double unbindingConstant; + protected final double basalCARGenerationRate; + public final int synnotchs; + public int boundSynNotch; + protected final int maxCars; + PoissonFactory poissonFactory; + private PatchCellTissue boundCell; + + /** + * Creates a tissue {@code PatchCellSynNotch} agent. * + * + * @param location the {@link Location} of the cell + * @param parameters the dictionary of parameters + */ + public PatchCellCARTCombinedInhibitory( + PatchCellContainer container, Location location, Parameters parameters) { + this(container, location, parameters, null); + } + + public PatchCellCARTCombinedInhibitory( + PatchCellContainer container, Location location, Parameters parameters, GrabBag links) { + super(container, location, parameters, links); + bindingConstant = parameters.getDouble("K_SYNNOTCH_ON"); + unbindingConstant = parameters.getDouble("K_SYNNOTCH_OFF"); + basalCARGenerationRate = parameters.getDouble("K_CAR_GENERATION"); + synnotchs = parameters.getInt("SYNNOTCHS"); + synNotchThreshold = parameters.getDouble("SYNNOTCH_THRESHOLD") * synnotchs; + boundCell = null; + boundSynNotch = 0; + maxCars = cars; + poissonFactory = Poisson::new; + } + + public double callPoisson(double lambda, MersenneTwisterFast random) { + return poissonFactory.createPoisson(lambda, random).nextInt(); + } + + @Override + public void step(SimState simstate) { + if (boundCell == null) { + checkForBinding(simstate); + } else { + calculateCARS(simstate.random); + } + super.step(simstate); + } + + private void calculateCARS(MersenneTwisterFast random) { + int TAU = 60; + int unboundSynNotch = synnotchs - boundSynNotch; + double expectedBindingEvents = + bindingConstant + / (volume * 6.0221415e23 * 1e-15) + * unboundSynNotch + * boundCell.getSynNotchAntigens() + * contactFraction + * TAU; + int bindingEvents = poissonFactory.createPoisson(expectedBindingEvents, random).nextInt(); + double expectedUnbindingEvents = unbindingConstant * boundSynNotch * TAU; + int unbindingEvents = + poissonFactory.createPoisson(expectedUnbindingEvents, random).nextInt(); + + boundSynNotch += bindingEvents; + boundSynNotch -= unbindingEvents; + boundCell.updateSynNotchAntigens(unbindingEvents, bindingEvents); + double n = 8; + int removeCARs = + (int) (maxCars / (1 + Math.pow(synNotchThreshold, n) / Math.pow(boundSynNotch, n))); + cars = Math.min((int) (cars + (basalCARGenerationRate * TAU)), maxCars - removeCARs); + } + + /** A {@code PoissonFactory} object instantiates Poisson distributions. */ + interface PoissonFactory { + /** + * Creates instance of Poisson. + * + * @param lambda the Poisson distribution lambda + * @param random the random number generator + * @return a Poisson distribution instance + */ + Poisson createPoisson(double lambda, MersenneTwisterFast random); + } + + private void checkForBinding(SimState simstate) { + Simulation sim = (Simulation) simstate; + PatchGrid grid = (PatchGrid) sim.getGrid(); + + Bag allAgents = new Bag(); + getTissueAgents(allAgents, grid.getObjectsAtLocation(location)); + for (Location neighborLocation : location.getNeighbors()) { + Bag bag = new Bag(grid.getObjectsAtLocation(neighborLocation)); + getTissueAgents(allAgents, bag); + } + + if (allAgents.size() > 0) { + PatchCellTissue randomCell = + (PatchCellTissue) allAgents.get(simstate.random.nextInt(allAgents.size())); + if (randomCell.getSynNotchAntigens() > 0) { + boundCell = randomCell; + } + } + } + + public void resetBoundCell() { + if (boundCell != null) { + boundCell.updateSynNotchAntigens(boundSynNotch, 0); + boundCell = null; + } + boundSynNotch = 0; + } +} diff --git a/src/arcade/patch/agent/cell/PatchCellContainer.java b/src/arcade/patch/agent/cell/PatchCellContainer.java index 3a942c388..f4805ee3f 100644 --- a/src/arcade/patch/agent/cell/PatchCellContainer.java +++ b/src/arcade/patch/agent/cell/PatchCellContainer.java @@ -119,6 +119,12 @@ public Cell convert( return new PatchCellCARTCD8(this, location, parameters, links); case "cart_cd4": return new PatchCellCARTCD4(this, location, parameters, links); + case "combined": + return new PatchCellCARTCombined(this, location, parameters, links); + case "inducible_cart": + return new PatchCellCARTCombinedInducible(this, location, parameters, links); + case "inhibitory_cart": + return new PatchCellCARTCombinedInhibitory(this, location, parameters, links); case "random": return new PatchCellRandom(this, location, parameters, links); } diff --git a/src/arcade/patch/agent/cell/PatchCellTissue.java b/src/arcade/patch/agent/cell/PatchCellTissue.java index 352260b28..d602d0f4f 100644 --- a/src/arcade/patch/agent/cell/PatchCellTissue.java +++ b/src/arcade/patch/agent/cell/PatchCellTissue.java @@ -42,6 +42,9 @@ public class PatchCellTissue extends PatchCell { /** Cell surface PDL1 count. */ private final int selfTargets; + /** Cell surface SynNotch antigen count */ + private int synNotchAntigens; + /** * Creates a tissue {@code PatchCell} agent. * @@ -153,4 +156,18 @@ public int getCarAntigens() { public int getSelfAntigens() { return selfTargets; } + + /** + * Returns the number of synnotch antigens on this cell. + * + * @return the number of self receptor antigens on this cell. + */ + public int getSynNotchAntigens() { + return synNotchAntigens; + } + + public void updateSynNotchAntigens(int add, int subtract) { + synNotchAntigens += add; + synNotchAntigens -= subtract; + } } diff --git a/src/arcade/patch/parameter.patch.xml b/src/arcade/patch/parameter.patch.xml index f2263676d..ce81ba287 100644 --- a/src/arcade/patch/parameter.patch.xml +++ b/src/arcade/patch/parameter.patch.xml @@ -25,7 +25,6 @@ - @@ -45,6 +44,15 @@ + + + + + + + + + @@ -113,6 +121,11 @@ + + + + + diff --git a/src/arcade/patch/sim/PatchSimulationHex.java b/src/arcade/patch/sim/PatchSimulationHex.java index 6eddf28b5..fad2226ee 100644 --- a/src/arcade/patch/sim/PatchSimulationHex.java +++ b/src/arcade/patch/sim/PatchSimulationHex.java @@ -7,6 +7,7 @@ import arcade.patch.agent.action.PatchActionConvert; import arcade.patch.agent.action.PatchActionInsert; import arcade.patch.agent.action.PatchActionRemove; +import arcade.patch.agent.action.PatchActionReplace; import arcade.patch.agent.cell.PatchCellFactory; import arcade.patch.env.component.PatchComponentCycle; import arcade.patch.env.component.PatchComponentDegrade; @@ -58,6 +59,8 @@ public Action makeAction(String actionClass, MiniBox parameters) { return new PatchActionRemove(series, parameters); case "convert": return new PatchActionConvert(series, parameters); + case "replace": + return new PatchActionReplace(series, parameters); default: return null; } diff --git a/src/arcade/patch/sim/PatchSimulationRect.java b/src/arcade/patch/sim/PatchSimulationRect.java index 6623fefec..7d9b76188 100644 --- a/src/arcade/patch/sim/PatchSimulationRect.java +++ b/src/arcade/patch/sim/PatchSimulationRect.java @@ -7,6 +7,7 @@ import arcade.patch.agent.action.PatchActionConvert; import arcade.patch.agent.action.PatchActionInsert; import arcade.patch.agent.action.PatchActionRemove; +import arcade.patch.agent.action.PatchActionReplace; import arcade.patch.agent.cell.PatchCellFactory; import arcade.patch.env.component.PatchComponentCycle; import arcade.patch.env.component.PatchComponentDegrade; @@ -58,6 +59,8 @@ public Action makeAction(String actionClass, MiniBox parameters) { return new PatchActionRemove(series, parameters); case "convert": return new PatchActionConvert(series, parameters); + case "replace": + return new PatchActionReplace(series, parameters); default: return null; } From 2776fc7915d8e4ce9021971d487de3158c78aad9 Mon Sep 17 00:00:00 2001 From: cainja Date: Mon, 28 Apr 2025 22:40:54 -0700 Subject: [PATCH 04/28] added treat back --- .../patch/agent/action/PatchActionTreat.java | 370 ++++++++++++++++++ src/arcade/patch/parameter.patch.xml | 7 + 2 files changed, 377 insertions(+) create mode 100644 src/arcade/patch/agent/action/PatchActionTreat.java diff --git a/src/arcade/patch/agent/action/PatchActionTreat.java b/src/arcade/patch/agent/action/PatchActionTreat.java new file mode 100644 index 000000000..c5202ea81 --- /dev/null +++ b/src/arcade/patch/agent/action/PatchActionTreat.java @@ -0,0 +1,370 @@ +package arcade.patch.agent.action; + +import java.util.ArrayList; +import java.util.Objects; +import sim.engine.Schedule; +import sim.engine.SimState; +import sim.util.Bag; +import arcade.core.agent.action.Action; +import arcade.core.env.location.Location; +import arcade.core.env.location.LocationContainer; +import arcade.core.sim.Series; +import arcade.core.sim.Simulation; +import arcade.core.util.Graph; +import arcade.core.util.MiniBox; +import arcade.core.util.Utilities; +import arcade.patch.agent.cell.PatchCell; +import arcade.patch.agent.cell.PatchCellCART; +import arcade.patch.agent.cell.PatchCellContainer; +import arcade.patch.agent.cell.PatchCellTissue; +import arcade.patch.env.component.PatchComponentSites; +import arcade.patch.env.component.PatchComponentSitesGraph; +import arcade.patch.env.component.PatchComponentSitesGraph.SiteEdge; +import arcade.patch.env.component.PatchComponentSitesGraphRect; +import arcade.patch.env.component.PatchComponentSitesGraphTri; +import arcade.patch.env.component.PatchComponentSitesPattern; +import arcade.patch.env.component.PatchComponentSitesSource; +import arcade.patch.env.grid.PatchGrid; +import arcade.patch.env.location.Coordinate; +import arcade.patch.env.location.CoordinateXYZ; +import arcade.patch.env.location.PatchLocation; +import arcade.patch.env.location.PatchLocationContainer; +import arcade.patch.sim.PatchSeries; +import arcade.patch.sim.PatchSimulation; +import arcade.patch.util.PatchEnums.Ordering; + +/** + * Implementation of {@link Action} for inserting T cell agents. + * + *

The action is stepped once after {@code TIME_DELAY}. The {@code TreatAction} will add CAR + * T-cell agents of specified dose and ratio next to source points or vasculature. + */ +public class PatchActionTreat implements Action { + + /** Delay before calling the helper (in minutes). */ + private final int delay; + + /** Total number of CAR T-cells to treat with. */ + private final int dose; + + /** List of fraction of each population to treat with. CD4 to CD8 ratio. */ + private final double treatFrac; + + /** Maximum damage value at which T-cells can spawn next to in source or pattern source. */ + private double maxDamage; + + /** Minimum radius value at which T- cells can spawn next to in graph source. */ + private final double minDamageRadius; + + /** Number of agent positions per lattice site. */ + private int latPositions; + + /** Coordinate system used for simulation. */ + private final String coord; + + /** List of populations. */ + private final ArrayList populations; + + /** parameters. */ + MiniBox parameters; + + /** Maximum confluency of cells in any location. */ + final int maxConfluency; + + /** + * Creates an {@code Action} to add agents after a delay. + * + * @param series the simulation series + * @param parameters the component parameters dictionary + */ + public PatchActionTreat(Series series, MiniBox parameters) { + this.delay = parameters.getInt("TIME_DELAY"); + this.dose = parameters.getInt("DOSE"); + this.treatFrac = parameters.getDouble("RATIO"); + this.maxDamage = parameters.getDouble("MAX_DAMAGE_SEED"); + this.minDamageRadius = parameters.getDouble("MIN_RADIUS_SEED"); + this.maxConfluency = 54; + this.parameters = parameters; + + this.coord = + ((PatchSeries) series).patch.get("GEOMETRY").equalsIgnoreCase("HEX") + ? "Hex" + : "Rect"; + if (coord.equals("Hex")) { + latPositions = 9; + } + if (coord.equals("Rect")) { + latPositions = 16; + } + + populations = new ArrayList<>(); + } + + @Override + public void schedule(Schedule schedule) { + schedule.scheduleOnce(delay, Ordering.ACTIONS.ordinal(), this); + } + + @Override + public void register(Simulation sim, String population) { + populations.add(sim.getSeries().populations.get(population)); + } + + /** + * Steps the action to insert cells of the treatment population(s). + * + * @param simstate the MASON simulation state + */ + public void step(SimState simstate) { + + PatchSimulation sim = (PatchSimulation) simstate; + String type = "null"; + PatchGrid grid = (PatchGrid) sim.getGrid(); + PatchComponentSites comp = (PatchComponentSites) sim.getComponent("SITES"); + + ArrayList locs = sim.getLocations(); + + ArrayList siteLocs0 = new ArrayList(); + ArrayList siteLocs1 = new ArrayList(); + ArrayList siteLocs2 = new ArrayList(); + ArrayList siteLocs3 = new ArrayList(); + ArrayList siteLocs = new ArrayList(); + + // Determine type of sites component implemented. + if (comp instanceof PatchComponentSitesSource) { + type = "source"; + } else if (comp instanceof PatchComponentSitesPattern) { + type = "pattern"; + } else if (comp instanceof PatchComponentSitesGraph) { + type = "graph"; + } + + // Find sites without specified level of damage based on component type. + switch (type) { + case "source": + case "pattern": + double[][][] damage; + boolean[][][] sitesLat; + + if (type.equals("source")) { + damage = ((PatchComponentSitesSource) comp).getDamage(); + sitesLat = ((PatchComponentSitesSource) comp).getSources(); + } else { + damage = ((PatchComponentSitesPattern) comp).getDamage(); + sitesLat = ((PatchComponentSitesPattern) comp).getPatterns(); + } + + // Iterate through list of locations and remove locations not next to a site. + for (LocationContainer l : locs) { + PatchLocationContainer contain = (PatchLocationContainer) l; + PatchLocation loc = + (PatchLocation) + contain.convert( + sim.locationFactory, + sim.cellFactory.createCellForPopulation( + 0, populations.get(0).getInt("CODE"))); + CoordinateXYZ coordinate = (CoordinateXYZ) loc.getSubcoordinate(); + int z = coordinate.z; + if (sitesLat[z][coordinate.x][coordinate.y] + && damage[z][coordinate.x][coordinate.y] <= this.maxDamage) { + addLocationsIntoList(grid, loc, siteLocs0, siteLocs1, siteLocs2, siteLocs3); + } + } + break; + + case "graph": + Graph graph = ((PatchComponentSitesGraph) comp).getGraph(); + Bag allEdges = new Bag(graph.getAllEdges()); + PatchComponentSitesGraph graphSites = (PatchComponentSitesGraph) comp; + + for (Object edgeObj : allEdges) { + SiteEdge edge = (SiteEdge) edgeObj; + Bag allEdgeLocs = new Bag(); + if (Objects.equals(coord, "Hex")) { + allEdgeLocs.add( + ((PatchComponentSitesGraphTri) graphSites) + .getSpan(edge.getFrom(), edge.getTo())); + } else { + allEdgeLocs.add( + ((PatchComponentSitesGraphRect) graphSites) + .getSpan(edge.getFrom(), edge.getTo())); + } + + for (Object locObj : allEdgeLocs) { + Location loc = (Location) locObj; + if (locs.contains(loc)) { + if (edge.getRadius() >= minDamageRadius) { + addLocationsIntoList( + grid, loc, siteLocs0, siteLocs1, siteLocs2, siteLocs3); + } + } + } + } + break; + + default: + throw new IllegalArgumentException( + "Invalid component type: " + + type + + ". Must be of type source, pattern, or graph."); + } + + Utilities.shuffleList(siteLocs3, sim.random); + Utilities.shuffleList(siteLocs2, sim.random); + Utilities.shuffleList(siteLocs1, sim.random); + Utilities.shuffleList(siteLocs0, sim.random); + siteLocs.addAll(siteLocs3); + siteLocs.addAll(siteLocs2); + siteLocs.addAll(siteLocs1); + siteLocs.addAll(siteLocs0); + insert(siteLocs, simstate); + } + + /** + * Helper method to sort locations into lists. + * + * @param grid the simulation grid + * @param loc the current location being looked at + * @param siteLocs0 the list of locations with 0 agents + * @param siteLocs1 the list of locations with 1 agent + * @param siteLocs2 the list of locations with 2 agents + * @param siteLocs3 the list of locations with 3 agents + */ + private void addLocationsIntoList( + PatchGrid grid, + Location loc, + ArrayList siteLocs0, + ArrayList siteLocs1, + ArrayList siteLocs2, + ArrayList siteLocs3) { + Bag bag = new Bag(grid.getObjectsAtLocation(loc)); + int numAgents = bag.numObjs; + + if (numAgents == 0) { + for (int p = 0; p < latPositions; p++) { + siteLocs0.add(loc); + } + } else if (numAgents == 1) { + for (int p = 0; p < latPositions; p++) { + siteLocs1.add(loc); + } + } else if (numAgents == 2) { + for (int p = 0; p < latPositions; p++) { + siteLocs2.add(loc); + } + } else { + for (int p = 0; p < latPositions; p++) { + siteLocs3.add(loc); + } + } + // Remove break statement if more than one per hex can appear + // with break statement, each location can only be added to list once + // without it, places with more vasc sites get added more times to list + // break; + } + + /** + * Helper method to add cells into the grid. + * + * @param coordinates the locations to insert the cells + * @param simstate the simulation state + */ + private void insert(ArrayList coordinates, SimState simstate) { + PatchSimulation sim = (PatchSimulation) simstate; + PatchGrid grid = (PatchGrid) sim.getGrid(); + Utilities.shuffleList(coordinates, sim.random); + + int cd4Code = 0; + int cd8Code = 0; + + for (MiniBox population : populations) { + String className = population.get("CLASS"); + if (className.equals("cart_cd4")) { + cd4Code = population.getInt("CODE"); + } + if (className.equals("cart_cd8")) { + cd8Code = population.getInt("CODE"); + } + } + + for (int i = 0; i < dose; i++) { + + int id = sim.getID(); + + int pop = cd4Code; + + if (sim.random.nextDouble() > treatFrac) { + pop = cd8Code; + } + + PatchLocation loc = ((PatchLocation) coordinates.remove(0)); + Coordinate coordinate = loc.getCoordinate(); + + while (!coordinates.isEmpty() && !checkLocationSpace(loc, grid)) { + loc = (PatchLocation) coordinates.remove(0); + } + + if (coordinates.isEmpty()) { + break; + } + + PatchLocationContainer locationContainer = new PatchLocationContainer(id, coordinate); + PatchCellContainer cellContainer = sim.cellFactory.createCellForPopulation(id, pop); + Location location = locationContainer.convert(sim.locationFactory, cellContainer); + PatchCell cell = + (PatchCell) cellContainer.convert(sim.cellFactory, location, sim.random); + grid.addObject(cell, location); + cell.schedule(sim.getSchedule()); + } + } + + /** + * Helper method to check if location is available. + * + * @param grid the simulation grid + * @param loc the current location being looked at + * @return boolean indicating if location is free + */ + protected boolean checkLocationSpace(Location loc, PatchGrid grid) { + boolean available; + int locMax = this.maxConfluency; + double locVolume = ((PatchLocation) loc).getVolume(); + double locArea = ((PatchLocation) loc).getArea(); + + Bag bag = new Bag(grid.getObjectsAtLocation(loc)); + int n = bag.numObjs; // number of agents in location + + if (n == 0) { + // no cells in location + available = true; + } else if (n >= locMax) { + // location already full + available = false; + } else { + available = true; + double totalVol = PatchCell.calculateTotalVolume(bag); + double currentHeight = totalVol / locArea; + + if (totalVol > locVolume) { + available = false; + } + + for (Object cellObj : bag) { + PatchCell cell = (PatchCell) cellObj; + if (cell instanceof PatchCellCART) { + totalVol = + PatchCell.calculateTotalVolume(bag) + + parameters.getDouble("T_CELL_VOL_AVG"); + currentHeight = totalVol / locArea; + } + if (cell instanceof PatchCellTissue) { + if (currentHeight > cell.getCriticalHeight()) { + available = false; + } + } + } + } + + return available; + } +} \ No newline at end of file diff --git a/src/arcade/patch/parameter.patch.xml b/src/arcade/patch/parameter.patch.xml index ce81ba287..86f26e6fd 100644 --- a/src/arcade/patch/parameter.patch.xml +++ b/src/arcade/patch/parameter.patch.xml @@ -133,6 +133,13 @@ + + + + + + + From c35bec4ebcd9077e7e8b6bcc56accc127306814a Mon Sep 17 00:00:00 2001 From: cainja Date: Wed, 14 May 2025 13:59:14 -0700 Subject: [PATCH 05/28] fixed some changes --- src/arcade/patch/agent/action/PatchActionTreat.java | 2 +- src/arcade/patch/parameter.patch.xml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/arcade/patch/agent/action/PatchActionTreat.java b/src/arcade/patch/agent/action/PatchActionTreat.java index c5202ea81..ea0dfc03e 100644 --- a/src/arcade/patch/agent/action/PatchActionTreat.java +++ b/src/arcade/patch/agent/action/PatchActionTreat.java @@ -367,4 +367,4 @@ protected boolean checkLocationSpace(Location loc, PatchGrid grid) { return available; } -} \ No newline at end of file +} diff --git a/src/arcade/patch/parameter.patch.xml b/src/arcade/patch/parameter.patch.xml index 86f26e6fd..a08b20e52 100644 --- a/src/arcade/patch/parameter.patch.xml +++ b/src/arcade/patch/parameter.patch.xml @@ -48,6 +48,7 @@ + From 08b736f7e32948ed2e362fe178560f1dc5c4ea45 Mon Sep 17 00:00:00 2001 From: allison-li-1016 Date: Wed, 18 Jun 2025 00:09:35 +0000 Subject: [PATCH 06/28] added all 4 logical cars circuits + refactoring --- .../PatchCellCARTCombinedCombinatorial.java | 150 +++++++++++++++++ .../cell/PatchCellCARTCombinedInducible.java | 90 +--------- ...atchCellCARTCombinedInducibleSeparate.java | 159 ++++++++++++++++++ .../cell/PatchCellCARTCombinedInhibitory.java | 93 +--------- ...tchCellCARTCombinedInhibitorySeparate.java | 56 ++++++ .../patch/agent/cell/PatchCellContainer.java | 4 + src/arcade/patch/parameter.patch.xml | 1 + 7 files changed, 385 insertions(+), 168 deletions(-) create mode 100644 src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java create mode 100644 src/arcade/patch/agent/cell/PatchCellCARTCombinedInducibleSeparate.java create mode 100644 src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitorySeparate.java diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java new file mode 100644 index 000000000..d592cecc0 --- /dev/null +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java @@ -0,0 +1,150 @@ +package arcade.patch.agent.cell; + +import arcade.core.env.location.Location; +import arcade.core.sim.Simulation; +import arcade.core.util.GrabBag; +import arcade.core.util.Parameters; +import arcade.patch.env.grid.PatchGrid; +import ec.util.MersenneTwisterFast; +import sim.engine.SimState; +import sim.util.Bag; +import sim.util.distribution.Poisson; + +import java.util.Deque; +import java.util.logging.Logger; +import java.util.LinkedList; + +public abstract class PatchCellCARTCombinedCombinatorial extends PatchCellCARTCombined{ + + private static final Logger LOGGER = + Logger.getLogger(PatchCellCARTCombinedCombinatorial.class.getName()); + protected final double synNotchThreshold; + protected final double bindingConstant; + protected final double unbindingConstant; + protected final double carDegradationConstant; + public int synnotchs; + public int boundSynNotch; + protected final int maxCars; + PatchCellCARTCombinedInducible.PoissonFactory poissonFactory; + protected PatchCellTissue boundCell; + protected final double basalCARGenerationRate; + protected final double synNotchActivationDelay; + protected Deque bindingHistory = new LinkedList<>(); + + public PatchCellCARTCombinedCombinatorial(PatchCellContainer container, Location location, Parameters parameters) { + this(container, location, parameters, null); + } + + public PatchCellCARTCombinedCombinatorial(PatchCellContainer container, Location location, Parameters parameters, GrabBag links) { + super(container, location, parameters, links); + bindingConstant = parameters.getDouble("K_SYNNOTCH_ON"); + unbindingConstant = parameters.getDouble("K_SYNNOTCH_OFF"); + carDegradationConstant = parameters.getDouble("K_CAR_DEGRADE"); + synnotchs = parameters.getInt("SYNNOTCHS"); + synNotchThreshold = parameters.getDouble("SYNNOTCH_THRESHOLD") * synnotchs; + basalCARGenerationRate = parameters.getDouble("K_CAR_GENERATION"); + synNotchActivationDelay = parameters.getDouble("SYNNOTCH_ACTIVATION_DELAY"); + boundSynNotch = 0; + maxCars = cars; + poissonFactory = Poisson::new; + } + + protected void checkForBinding(SimState simstate) { + Simulation sim = (Simulation) simstate; + PatchGrid grid = (PatchGrid) sim.getGrid(); + + Bag allAgents = new Bag(); + getTissueAgents(allAgents, grid.getObjectsAtLocation(location)); + for (Location neighborLocation : location.getNeighbors()) { + Bag bag = new Bag(grid.getObjectsAtLocation(neighborLocation)); + getTissueAgents(allAgents, bag); + } + + if (allAgents.size() > 0) { + PatchCellTissue randomCell = + (PatchCellTissue) allAgents.get(simstate.random.nextInt(allAgents.size())); + if (randomCell.getSynNotchAntigens() > 0) { + boundCell = randomCell; + } + } + } + + protected void calculateCARS(MersenneTwisterFast random, Simulation sim) { + int TAU = 60; + double currentTime = sim.getSchedule().getTime(); + int unboundSynNotch = synnotchs - boundSynNotch; + + double expectedBindingEvents = + bindingConstant + / (volume * 6.0221415e23 * 1e-15) + * unboundSynNotch + * boundCell.getSynNotchAntigens() + * contactFraction + * TAU; + + int bindingEvents = poissonFactory.createPoisson(expectedBindingEvents, random).nextInt(); + + if (bindingEvents > 0) { + bindingHistory.addLast(new BindingEvent(currentTime, bindingEvents)); + } + double expectedUnbindingEvents = unbindingConstant * boundSynNotch * TAU; + int unbindingEvents = + poissonFactory.createPoisson(expectedUnbindingEvents, random).nextInt(); + + boundSynNotch += bindingEvents; + boundSynNotch -= unbindingEvents; + boundCell.updateSynNotchAntigens(unbindingEvents, bindingEvents); + + // model synnotch activation TF degradation + int ineffectiveBoundSynNotchs = 0; + //find all binding events that are older than the synNotchActivationDelay + for (BindingEvent e : bindingHistory) { + if (currentTime - e.timeStep >= synNotchActivationDelay) { + ineffectiveBoundSynNotchs += e.count; + } + } + + boundSynNotch -= ineffectiveBoundSynNotchs; + synnotchs = Math.max(0, synnotchs-ineffectiveBoundSynNotchs); + + //remove all binding events that are older than the synNotchActivationDelay + while (!bindingHistory.isEmpty() && + bindingHistory.peekFirst().timeStep <= currentTime - synNotchActivationDelay) { + bindingHistory.pollFirst(); + } + } + + /** A {@code PoissonFactory} object instantiates Poisson distributions. */ + interface PoissonFactory { + /** + * Creates instance of Poisson. + * + * @param lambda the Poisson distribution lambda + * @param random the random number generator + * @return a Poisson distribution instance + */ + Poisson createPoisson(double lambda, MersenneTwisterFast random); + } + + public double callPoisson(double lambda, MersenneTwisterFast random) { + return poissonFactory.createPoisson(lambda, random).nextInt(); + } + + public void resetBoundCell() { + if (boundCell != null) { + boundCell.updateSynNotchAntigens(boundSynNotch, 0); + boundCell = null; + } + boundSynNotch = 0; + } + + private static class BindingEvent { + double timeStep; + int count; + + BindingEvent(double timeStep, int count) { + this.timeStep = timeStep; + this.count = count; + } + } +} diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java index 901a1e316..e57d4e040 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java @@ -11,18 +11,9 @@ import arcade.core.util.Parameters; import arcade.patch.env.grid.PatchGrid; -public class PatchCellCARTCombinedInducible extends PatchCellCARTCombined { +public class PatchCellCARTCombinedInducible extends PatchCellCARTCombinedCombinatorial { private static final Logger LOGGER = Logger.getLogger(PatchCellCARTCombinedInducible.class.getName()); - protected final double synNotchThreshold; - protected final double bindingConstant; - protected final double unbindingConstant; - protected final double carDegradationConstant; - public final int synnotchs; - public int boundSynNotch; - protected final int maxCars; - PoissonFactory poissonFactory; - private PatchCellTissue boundCell; /** * Creates a tissue {@code PatchCellSynNotch} agent. * @@ -38,93 +29,26 @@ public PatchCellCARTCombinedInducible( public PatchCellCARTCombinedInducible( PatchCellContainer container, Location location, Parameters parameters, GrabBag links) { super(container, location, parameters, links); - bindingConstant = parameters.getDouble("K_SYNNOTCH_ON"); - unbindingConstant = parameters.getDouble("K_SYNNOTCH_OFF"); - carDegradationConstant = parameters.getDouble("K_CAR_DEGRADE"); - synnotchs = parameters.getInt("SYNNOTCHS"); - synNotchThreshold = parameters.getDouble("SYNNOTCH_THRESHOLD") * synnotchs; - boundSynNotch = 0; - maxCars = cars; cars = 0; - poissonFactory = Poisson::new; - } - - public double callPoisson(double lambda, MersenneTwisterFast random) { - return poissonFactory.createPoisson(lambda, random).nextInt(); } @Override public void step(SimState simstate) { - if (boundCell == null) { - checkForBinding(simstate); + Simulation sim = (Simulation) simstate; + if (super.boundCell == null) { + super.checkForBinding(simstate); } else { - calculateCARS(simstate.random); + calculateCARS(simstate.random, sim); } super.step(simstate); } - private void calculateCARS(MersenneTwisterFast random) { + protected void calculateCARS(MersenneTwisterFast random, Simulation sim) { int TAU = 60; - int unboundSynNotch = synnotchs - boundSynNotch; - double expectedBindingEvents = - bindingConstant - / (volume * 6.0221415e23 * 1e-15) - * unboundSynNotch - * boundCell.getSynNotchAntigens() - * contactFraction - * TAU; - int bindingEvents = poissonFactory.createPoisson(expectedBindingEvents, random).nextInt(); - double expectedUnbindingEvents = unbindingConstant * boundSynNotch * TAU; - int unbindingEvents = - poissonFactory.createPoisson(expectedUnbindingEvents, random).nextInt(); - - boundSynNotch += bindingEvents; - boundSynNotch -= unbindingEvents; - boundCell.updateSynNotchAntigens(unbindingEvents, bindingEvents); + super.calculateCARS(random, sim); double n = 4.4; int new_cars = (int) (maxCars / (1 + Math.pow(synNotchThreshold, n) / Math.pow(boundSynNotch, n))); - cars = Math.max((int) (cars - (carDegradationConstant * cars * TAU)), new_cars); } - - /** A {@code PoissonFactory} object instantiates Poisson distributions. */ - interface PoissonFactory { - /** - * Creates instance of Poisson. - * - * @param lambda the Poisson distribution lambda - * @param random the random number generator - * @return a Poisson distribution instance - */ - Poisson createPoisson(double lambda, MersenneTwisterFast random); - } - - private void checkForBinding(SimState simstate) { - Simulation sim = (Simulation) simstate; - PatchGrid grid = (PatchGrid) sim.getGrid(); - - Bag allAgents = new Bag(); - getTissueAgents(allAgents, grid.getObjectsAtLocation(location)); - for (Location neighborLocation : location.getNeighbors()) { - Bag bag = new Bag(grid.getObjectsAtLocation(neighborLocation)); - getTissueAgents(allAgents, bag); - } - - if (allAgents.size() > 0) { - PatchCellTissue randomCell = - (PatchCellTissue) allAgents.get(simstate.random.nextInt(allAgents.size())); - if (randomCell.getSynNotchAntigens() > 0) { - boundCell = randomCell; - } - } - } - - public void resetBoundCell() { - if (boundCell != null) { - boundCell.updateSynNotchAntigens(boundSynNotch, 0); - boundCell = null; - } - boundSynNotch = 0; - } } diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducibleSeparate.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducibleSeparate.java new file mode 100644 index 000000000..b91b74214 --- /dev/null +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducibleSeparate.java @@ -0,0 +1,159 @@ +package arcade.patch.agent.cell; + +import arcade.core.env.location.Location; +import arcade.core.sim.Simulation; +import arcade.core.util.GrabBag; +import arcade.core.util.Parameters; +import arcade.patch.util.PatchEnums; +import ec.util.MersenneTwisterFast; +import sim.engine.SimState; + +import java.util.logging.Logger; + +public class PatchCellCARTCombinedInducibleSeparate extends PatchCellCARTCombinedCombinatorial { + + private static final Logger LOGGER = + Logger.getLogger(PatchCellCARTCombinedInducibleSeparate.class.getName()); + + /** + * Creates a tissue {@code PatchCellSynNotch} agent. * + * + * @param location the {@link Location} of the cell + * @param parameters the dictionary of parameters + */ + public PatchCellCARTCombinedInducibleSeparate( + PatchCellContainer container, Location location, Parameters parameters) { + this(container, location, parameters, null); + } + + public PatchCellCARTCombinedInducibleSeparate( + PatchCellContainer container, Location location, Parameters parameters, GrabBag links) { + super(container, location, parameters, links); + cars = 0; + } + + @Override + public void step(SimState simstate) { + Simulation sim = (Simulation) simstate; + if (super.boundCell == null) { + super.checkForBinding(simstate); + } else { + calculateActivation(simstate.random, sim); + } + + super.age++; + + if (state != PatchEnums.State.APOPTOTIC && age > apoptosisAge) { + setState(PatchEnums.State.APOPTOTIC); + super.unbind(); + this.activated = false; + } + + super.lastActiveTicker++; + + if (super.lastActiveTicker != 0 && super.lastActiveTicker % MINUTES_IN_DAY == 0) { + if (super.boundCARAntigensCount != 0) { + super.boundCARAntigensCount--; + } + } + if (super.lastActiveTicker / MINUTES_IN_DAY >= 7) { + super.activated = false; + } + + super.processes.get(PatchEnums.Domain.METABOLISM).step(simstate.random, sim); + + // Check energy status. If cell has less energy than threshold, it will + // apoptose. If overall energy is negative, then cell enters quiescence. + if (state != PatchEnums.State.APOPTOTIC) { + if (super.energy < super.energyThreshold) { + + super.setState(PatchEnums.State.APOPTOTIC); + super.unbind(); + this.activated = false; + } else if (state != PatchEnums.State.ANERGIC + && state != PatchEnums.State.SENESCENT + && state != PatchEnums.State.EXHAUSTED + && state != PatchEnums.State.STARVED + && energy < 0) { + + super.setState(PatchEnums.State.STARVED); + super.unbind(); + } else if (state == PatchEnums.State.STARVED && energy >= 0) { + super.setState(PatchEnums.State.UNDEFINED); + } + } + + super.processes.get(PatchEnums.Domain.INFLAMMATION).step(simstate.random, sim); + + if (super.state == PatchEnums.State.UNDEFINED || super.state == PatchEnums.State.PAUSED) { + if (divisions == divisionPotential) { + if (simstate.random.nextDouble() > super.senescentFraction) { + super.setState(PatchEnums.State.APOPTOTIC); + } else { + super.setState(PatchEnums.State.SENESCENT); + } + super.unbind(); + this.activated = false; + } else { + PatchCellTissue target = super.bindTarget(sim, location, simstate.random); + super.boundTarget = target; + + // If cell is bound to both antigen and self it will become anergic. + if (super.getBindingFlag() == PatchEnums.AntigenFlag.BOUND_ANTIGEN_CELL_RECEPTOR) { + if (simstate.random.nextDouble() > super.anergicFraction) { + super.setState(PatchEnums.State.APOPTOTIC); + } else { + super.setState(PatchEnums.State.ANERGIC); + } + super.unbind(); + this.activated = false; + } else if (super.getBindingFlag() == PatchEnums.AntigenFlag.BOUND_ANTIGEN) { + // If cell is only bound to target antigen, the cell + // can potentially become properly activated. + + // Check overstimulation. If cell has bound to + // target antigens too many times, becomes exhausted. + if (boundCARAntigensCount > maxAntigenBinding) { + if (simstate.random.nextDouble() > super.exhaustedFraction) { + super.setState(PatchEnums.State.APOPTOTIC); + } else { + super.setState(PatchEnums.State.EXHAUSTED); + } + super.unbind(); + this.activated = false; + } else { + // if CD8 cell is properly activated, it can be cytotoxic + super.setState(PatchEnums.State.CYTOTOXIC); + } + } else { + // If self binding, unbind + if (super.getBindingFlag() == PatchEnums.AntigenFlag.BOUND_CELL_RECEPTOR) { + super.unbind(); + } + // Check activation status. If cell has been activated before, + // it will proliferate. If not, it will migrate. + if (activated) { + super.setState(PatchEnums.State.PROLIFERATIVE); + } else { + if (simstate.random.nextDouble() > super.proliferativeFraction) { + super.setState(PatchEnums.State.MIGRATORY); + } else { + super.setState(PatchEnums.State.PROLIFERATIVE); + } + } + } + } + } + } + + protected void calculateActivation(MersenneTwisterFast random, Simulation sim) { + int TAU = 60; + super.calculateCARS(random, sim); + cars = Math.max((int) (cars + (basalCARGenerationRate * TAU) - (carDegradationConstant * cars * TAU)), 0); + if (boundSynNotch >= synNotchThreshold) { + this.lastActiveTicker = 0; + this.activated = true; + } + } + +} diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java index 2e37687e9..1801200c9 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java @@ -11,19 +11,9 @@ import arcade.core.util.Parameters; import arcade.patch.env.grid.PatchGrid; -public class PatchCellCARTCombinedInhibitory extends PatchCellCARTCombined { +public class PatchCellCARTCombinedInhibitory extends PatchCellCARTCombinedCombinatorial { private static final Logger LOGGER = - Logger.getLogger(PatchCellCARTCombinedInducible.class.getName()); - protected final double synNotchThreshold; - protected final double bindingConstant; - protected final double unbindingConstant; - protected final double basalCARGenerationRate; - public final int synnotchs; - public int boundSynNotch; - protected final int maxCars; - PoissonFactory poissonFactory; - private PatchCellTissue boundCell; - + Logger.getLogger(PatchCellCARTCombinedInhibitory.class.getName()); /** * Creates a tissue {@code PatchCellSynNotch} agent. * * @@ -38,92 +28,25 @@ public PatchCellCARTCombinedInhibitory( public PatchCellCARTCombinedInhibitory( PatchCellContainer container, Location location, Parameters parameters, GrabBag links) { super(container, location, parameters, links); - bindingConstant = parameters.getDouble("K_SYNNOTCH_ON"); - unbindingConstant = parameters.getDouble("K_SYNNOTCH_OFF"); - basalCARGenerationRate = parameters.getDouble("K_CAR_GENERATION"); - synnotchs = parameters.getInt("SYNNOTCHS"); - synNotchThreshold = parameters.getDouble("SYNNOTCH_THRESHOLD") * synnotchs; - boundCell = null; - boundSynNotch = 0; - maxCars = cars; - poissonFactory = Poisson::new; - } - - public double callPoisson(double lambda, MersenneTwisterFast random) { - return poissonFactory.createPoisson(lambda, random).nextInt(); } @Override public void step(SimState simstate) { - if (boundCell == null) { - checkForBinding(simstate); + Simulation sim = (Simulation) simstate; + if (super.boundCell == null) { + super.checkForBinding(simstate); } else { - calculateCARS(simstate.random); + calculateCARS(simstate.random, sim); } super.step(simstate); } - private void calculateCARS(MersenneTwisterFast random) { + protected void calculateCARS(MersenneTwisterFast random, Simulation sim) { int TAU = 60; - int unboundSynNotch = synnotchs - boundSynNotch; - double expectedBindingEvents = - bindingConstant - / (volume * 6.0221415e23 * 1e-15) - * unboundSynNotch - * boundCell.getSynNotchAntigens() - * contactFraction - * TAU; - int bindingEvents = poissonFactory.createPoisson(expectedBindingEvents, random).nextInt(); - double expectedUnbindingEvents = unbindingConstant * boundSynNotch * TAU; - int unbindingEvents = - poissonFactory.createPoisson(expectedUnbindingEvents, random).nextInt(); - - boundSynNotch += bindingEvents; - boundSynNotch -= unbindingEvents; - boundCell.updateSynNotchAntigens(unbindingEvents, bindingEvents); + super.calculateCARS(random, sim); double n = 8; int removeCARs = (int) (maxCars / (1 + Math.pow(synNotchThreshold, n) / Math.pow(boundSynNotch, n))); cars = Math.min((int) (cars + (basalCARGenerationRate * TAU)), maxCars - removeCARs); } - - /** A {@code PoissonFactory} object instantiates Poisson distributions. */ - interface PoissonFactory { - /** - * Creates instance of Poisson. - * - * @param lambda the Poisson distribution lambda - * @param random the random number generator - * @return a Poisson distribution instance - */ - Poisson createPoisson(double lambda, MersenneTwisterFast random); - } - - private void checkForBinding(SimState simstate) { - Simulation sim = (Simulation) simstate; - PatchGrid grid = (PatchGrid) sim.getGrid(); - - Bag allAgents = new Bag(); - getTissueAgents(allAgents, grid.getObjectsAtLocation(location)); - for (Location neighborLocation : location.getNeighbors()) { - Bag bag = new Bag(grid.getObjectsAtLocation(neighborLocation)); - getTissueAgents(allAgents, bag); - } - - if (allAgents.size() > 0) { - PatchCellTissue randomCell = - (PatchCellTissue) allAgents.get(simstate.random.nextInt(allAgents.size())); - if (randomCell.getSynNotchAntigens() > 0) { - boundCell = randomCell; - } - } - } - - public void resetBoundCell() { - if (boundCell != null) { - boundCell.updateSynNotchAntigens(boundSynNotch, 0); - boundCell = null; - } - boundSynNotch = 0; - } } diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitorySeparate.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitorySeparate.java new file mode 100644 index 000000000..d7cc25431 --- /dev/null +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitorySeparate.java @@ -0,0 +1,56 @@ +package arcade.patch.agent.cell; + +import arcade.core.env.location.Location; +import arcade.core.sim.Simulation; +import arcade.core.util.GrabBag; +import arcade.core.util.Parameters; +import arcade.patch.env.grid.PatchGrid; +import arcade.patch.util.PatchEnums; +import ec.util.MersenneTwisterFast; +import sim.engine.SimState; +import sim.util.Bag; +import sim.util.distribution.Poisson; + +import java.util.logging.Logger; + +public class PatchCellCARTCombinedInhibitorySeparate extends PatchCellCARTCombinedCombinatorial { + + private static final Logger LOGGER = + Logger.getLogger(PatchCellCARTCombinedInhibitorySeparate.class.getName()); + + /** + * Creates a tissue {@code PatchCellSynNotch} agent. * + * + * @param location the {@link Location} of the cell + * @param parameters the dictionary of parameters + */ + public PatchCellCARTCombinedInhibitorySeparate( + PatchCellContainer container, Location location, Parameters parameters) { + this(container, location, parameters, null); + } + + public PatchCellCARTCombinedInhibitorySeparate( + PatchCellContainer container, Location location, Parameters parameters, GrabBag links) { + super(container, location, parameters, links); + } + + @Override + public void step(SimState simstate) { + Simulation sim = (Simulation) simstate; + if (super.boundCell == null) { + super.checkForBinding(simstate); + } else { + calculateActivation(simstate.random, sim); + } + super.step(simstate); + } + + private void calculateActivation(MersenneTwisterFast random, Simulation sim) { + int TAU = 60; + super.calculateCARS(random, sim); + cars = Math.max((int) (cars + (basalCARGenerationRate * TAU) - (carDegradationConstant * cars * TAU)), 0); + if (boundSynNotch >= synNotchThreshold) { + this.activated = false; + } + } +} diff --git a/src/arcade/patch/agent/cell/PatchCellContainer.java b/src/arcade/patch/agent/cell/PatchCellContainer.java index f4805ee3f..14fb23dec 100644 --- a/src/arcade/patch/agent/cell/PatchCellContainer.java +++ b/src/arcade/patch/agent/cell/PatchCellContainer.java @@ -125,6 +125,10 @@ public Cell convert( return new PatchCellCARTCombinedInducible(this, location, parameters, links); case "inhibitory_cart": return new PatchCellCARTCombinedInhibitory(this, location, parameters, links); + case "inducible_cart_separate": + return new PatchCellCARTCombinedInducibleSeparate(this, location, parameters, links); + case "inhibitory_cart_separate": + return new PatchCellCARTCombinedInhibitorySeparate(this, location, parameters, links); case "random": return new PatchCellRandom(this, location, parameters, links); } diff --git a/src/arcade/patch/parameter.patch.xml b/src/arcade/patch/parameter.patch.xml index a08b20e52..4f4a9877f 100644 --- a/src/arcade/patch/parameter.patch.xml +++ b/src/arcade/patch/parameter.patch.xml @@ -53,6 +53,7 @@ + From 2ac0c1bc492e0e2ed01aa59a4b8ebf3a26a03615 Mon Sep 17 00:00:00 2001 From: allison-li-1016 Date: Wed, 18 Jun 2025 00:29:34 +0000 Subject: [PATCH 07/28] linting --- .../PatchCellCARTCombinedCombinatorial.java | 77 +++++++++++++++---- .../cell/PatchCellCARTCombinedInducible.java | 16 +++- ...atchCellCARTCombinedInducibleSeparate.java | 28 +++++-- .../cell/PatchCellCARTCombinedInhibitory.java | 17 +++- ...tchCellCARTCombinedInhibitorySeparate.java | 30 +++++--- .../patch/agent/cell/PatchCellContainer.java | 6 +- 6 files changed, 131 insertions(+), 43 deletions(-) diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java index d592cecc0..cc08c10ca 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java @@ -1,41 +1,86 @@ package arcade.patch.agent.cell; +import java.util.Deque; +import java.util.LinkedList; +import java.util.logging.Logger; +import sim.engine.SimState; +import sim.util.Bag; +import sim.util.distribution.Poisson; +import ec.util.MersenneTwisterFast; import arcade.core.env.location.Location; import arcade.core.sim.Simulation; import arcade.core.util.GrabBag; import arcade.core.util.Parameters; import arcade.patch.env.grid.PatchGrid; -import ec.util.MersenneTwisterFast; -import sim.engine.SimState; -import sim.util.Bag; -import sim.util.distribution.Poisson; -import java.util.Deque; -import java.util.logging.Logger; -import java.util.LinkedList; - -public abstract class PatchCellCARTCombinedCombinatorial extends PatchCellCARTCombined{ +/** + * Abstract class of {@link PatchCellCART} for combined CD4/CD8 combinatorial CART-cells with + * selected module versions. + */ +public abstract class PatchCellCARTCombinedCombinatorial extends PatchCellCARTCombined { + /** Logger for this class. */ private static final Logger LOGGER = Logger.getLogger(PatchCellCARTCombinedCombinatorial.class.getName()); + + /** Number of bound synnotchs required to trigger activation/inactivation. */ protected final double synNotchThreshold; + + /** synnotch receptor-antigen binding rate. */ protected final double bindingConstant; + + /** synnotch receptor-antigen unbinding rate. */ protected final double unbindingConstant; + + /** car receptor degradation rate. */ protected final double carDegradationConstant; + + /** Number of synnotch receptors on this cell. */ public int synnotchs; + + /** Number of bound synnotch receptors on this cell. */ public int boundSynNotch; + + /** maximum CAR receptors possible. */ protected final int maxCars; + + /** poisson distribution. */ PatchCellCARTCombinedInducible.PoissonFactory poissonFactory; + + /** Target cell that is bound. */ protected PatchCellTissue boundCell; + + /** basal CAR receptor expression rate. */ protected final double basalCARGenerationRate; + + /** Half-life of synnotch activation TF. */ protected final double synNotchActivationDelay; + + /** List of recent synnotch binding events. */ protected Deque bindingHistory = new LinkedList<>(); - public PatchCellCARTCombinedCombinatorial(PatchCellContainer container, Location location, Parameters parameters) { + /** + * Creates a T cell {@code PatchCellCARTCombinedCombinatorial} agent. * + * + * @param container the cell container + * @param location the {@link Location} of the cell + * @param parameters the dictionary of parameters + */ + public PatchCellCARTCombinedCombinatorial( + PatchCellContainer container, Location location, Parameters parameters) { this(container, location, parameters, null); } - public PatchCellCARTCombinedCombinatorial(PatchCellContainer container, Location location, Parameters parameters, GrabBag links) { + /** + * Creates a T cell {@code PatchCellCARTCombinedCombinatorial} agent. * + * + * @param container the cell container + * @param location the {@link Location} of the cell + * @param parameters the dictionary of parameters + * @param links the map of population links + */ + public PatchCellCARTCombinedCombinatorial( + PatchCellContainer container, Location location, Parameters parameters, GrabBag links) { super(container, location, parameters, links); bindingConstant = parameters.getDouble("K_SYNNOTCH_ON"); unbindingConstant = parameters.getDouble("K_SYNNOTCH_OFF"); @@ -97,7 +142,7 @@ protected void calculateCARS(MersenneTwisterFast random, Simulation sim) { // model synnotch activation TF degradation int ineffectiveBoundSynNotchs = 0; - //find all binding events that are older than the synNotchActivationDelay + // find all binding events that are older than the synNotchActivationDelay for (BindingEvent e : bindingHistory) { if (currentTime - e.timeStep >= synNotchActivationDelay) { ineffectiveBoundSynNotchs += e.count; @@ -105,11 +150,11 @@ protected void calculateCARS(MersenneTwisterFast random, Simulation sim) { } boundSynNotch -= ineffectiveBoundSynNotchs; - synnotchs = Math.max(0, synnotchs-ineffectiveBoundSynNotchs); + synnotchs = Math.max(0, synnotchs - ineffectiveBoundSynNotchs); - //remove all binding events that are older than the synNotchActivationDelay - while (!bindingHistory.isEmpty() && - bindingHistory.peekFirst().timeStep <= currentTime - synNotchActivationDelay) { + // remove all binding events that are older than the synNotchActivationDelay + while (!bindingHistory.isEmpty() + && bindingHistory.peekFirst().timeStep <= currentTime - synNotchActivationDelay) { bindingHistory.pollFirst(); } } diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java index e57d4e040..ca1d42325 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java @@ -2,21 +2,21 @@ import java.util.logging.Logger; import sim.engine.SimState; -import sim.util.Bag; -import sim.util.distribution.Poisson; import ec.util.MersenneTwisterFast; import arcade.core.env.location.Location; import arcade.core.sim.Simulation; import arcade.core.util.GrabBag; import arcade.core.util.Parameters; -import arcade.patch.env.grid.PatchGrid; +/** Extension of {@link PatchCellCARTCombinedCombinatorial} for synnotch circuit. */ public class PatchCellCARTCombinedInducible extends PatchCellCARTCombinedCombinatorial { + + /** Logger for this class. */ private static final Logger LOGGER = Logger.getLogger(PatchCellCARTCombinedInducible.class.getName()); /** - * Creates a tissue {@code PatchCellSynNotch} agent. * + * Creates a tissue {@code PatchCellCARTCombinedInducible} agent. * * * @param location the {@link Location} of the cell * @param parameters the dictionary of parameters @@ -26,6 +26,14 @@ public PatchCellCARTCombinedInducible( this(container, location, parameters, null); } + /** + * Creates a T cell {@code PatchCellCARTCombinedInducible} agent. * + * + * @param container the cell container + * @param location the {@link Location} of the cell + * @param parameters the dictionary of parameters + * @param links the map of population links + */ public PatchCellCARTCombinedInducible( PatchCellContainer container, Location location, Parameters parameters, GrabBag links) { super(container, location, parameters, links); diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducibleSeparate.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducibleSeparate.java index b91b74214..d35c1b16b 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducibleSeparate.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducibleSeparate.java @@ -1,22 +1,23 @@ package arcade.patch.agent.cell; +import java.util.logging.Logger; +import sim.engine.SimState; +import ec.util.MersenneTwisterFast; import arcade.core.env.location.Location; import arcade.core.sim.Simulation; import arcade.core.util.GrabBag; import arcade.core.util.Parameters; import arcade.patch.util.PatchEnums; -import ec.util.MersenneTwisterFast; -import sim.engine.SimState; - -import java.util.logging.Logger; +/** Extension of {@link PatchCellCARTCombinedCombinatorial} for induced combinatorial circuit. */ public class PatchCellCARTCombinedInducibleSeparate extends PatchCellCARTCombinedCombinatorial { + /** Logger for this class. */ private static final Logger LOGGER = Logger.getLogger(PatchCellCARTCombinedInducibleSeparate.class.getName()); /** - * Creates a tissue {@code PatchCellSynNotch} agent. * + * Creates a tissue {@code PatchCellCombinedInducibleSeparate} agent. * * * @param location the {@link Location} of the cell * @param parameters the dictionary of parameters @@ -26,6 +27,14 @@ public PatchCellCARTCombinedInducibleSeparate( this(container, location, parameters, null); } + /** + * Creates a T cell {@code PatchCellCombinedInducibleSeparate} agent. * + * + * @param container the cell container + * @param location the {@link Location} of the cell + * @param parameters the dictionary of parameters + * @param links the map of population links + */ public PatchCellCARTCombinedInducibleSeparate( PatchCellContainer container, Location location, Parameters parameters, GrabBag links) { super(container, location, parameters, links); @@ -149,11 +158,16 @@ public void step(SimState simstate) { protected void calculateActivation(MersenneTwisterFast random, Simulation sim) { int TAU = 60; super.calculateCARS(random, sim); - cars = Math.max((int) (cars + (basalCARGenerationRate * TAU) - (carDegradationConstant * cars * TAU)), 0); + cars = + Math.max( + (int) + (cars + + (basalCARGenerationRate * TAU) + - (carDegradationConstant * cars * TAU)), + 0); if (boundSynNotch >= synNotchThreshold) { this.lastActiveTicker = 0; this.activated = true; } } - } diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java index 1801200c9..a3d5832c5 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java @@ -2,20 +2,21 @@ import java.util.logging.Logger; import sim.engine.SimState; -import sim.util.Bag; -import sim.util.distribution.Poisson; import ec.util.MersenneTwisterFast; import arcade.core.env.location.Location; import arcade.core.sim.Simulation; import arcade.core.util.GrabBag; import arcade.core.util.Parameters; -import arcade.patch.env.grid.PatchGrid; +/** Extension of {@link PatchCellCARTCombinedCombinatorial} for iCAR synnotch circuit. */ public class PatchCellCARTCombinedInhibitory extends PatchCellCARTCombinedCombinatorial { + + /** Logger for this class. */ private static final Logger LOGGER = Logger.getLogger(PatchCellCARTCombinedInhibitory.class.getName()); + /** - * Creates a tissue {@code PatchCellSynNotch} agent. * + * Creates a tissue {@code PatchCellCARTCombinedInhibitory} agent. * * * @param location the {@link Location} of the cell * @param parameters the dictionary of parameters @@ -25,6 +26,14 @@ public PatchCellCARTCombinedInhibitory( this(container, location, parameters, null); } + /** + * Creates a T cell {@code PatchCellCombinedInhibitory} agent. * + * + * @param container the cell container + * @param location the {@link Location} of the cell + * @param parameters the dictionary of parameters + * @param links the map of population links + */ public PatchCellCARTCombinedInhibitory( PatchCellContainer container, Location location, Parameters parameters, GrabBag links) { super(container, location, parameters, links); diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitorySeparate.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitorySeparate.java index d7cc25431..65d344ff1 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitorySeparate.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitorySeparate.java @@ -1,25 +1,21 @@ package arcade.patch.agent.cell; +import java.util.logging.Logger; +import sim.engine.SimState; +import ec.util.MersenneTwisterFast; import arcade.core.env.location.Location; import arcade.core.sim.Simulation; import arcade.core.util.GrabBag; import arcade.core.util.Parameters; -import arcade.patch.env.grid.PatchGrid; -import arcade.patch.util.PatchEnums; -import ec.util.MersenneTwisterFast; -import sim.engine.SimState; -import sim.util.Bag; -import sim.util.distribution.Poisson; - -import java.util.logging.Logger; +/** Extension of {@link PatchCellCARTCombinedCombinatorial} for iCAR circuit. */ public class PatchCellCARTCombinedInhibitorySeparate extends PatchCellCARTCombinedCombinatorial { private static final Logger LOGGER = Logger.getLogger(PatchCellCARTCombinedInhibitorySeparate.class.getName()); /** - * Creates a tissue {@code PatchCellSynNotch} agent. * + * Creates a tissue {@code PatchCellCombinedInhibitorySeparate} agent. * * * @param location the {@link Location} of the cell * @param parameters the dictionary of parameters @@ -29,6 +25,14 @@ public PatchCellCARTCombinedInhibitorySeparate( this(container, location, parameters, null); } + /** + * Creates a T cell {@code PatchCellCombinedInhibitorySeparate} agent. * + * + * @param container the cell container + * @param location the {@link Location} of the cell + * @param parameters the dictionary of parameters + * @param links the map of population links + */ public PatchCellCARTCombinedInhibitorySeparate( PatchCellContainer container, Location location, Parameters parameters, GrabBag links) { super(container, location, parameters, links); @@ -48,7 +52,13 @@ public void step(SimState simstate) { private void calculateActivation(MersenneTwisterFast random, Simulation sim) { int TAU = 60; super.calculateCARS(random, sim); - cars = Math.max((int) (cars + (basalCARGenerationRate * TAU) - (carDegradationConstant * cars * TAU)), 0); + cars = + Math.max( + (int) + (cars + + (basalCARGenerationRate * TAU) + - (carDegradationConstant * cars * TAU)), + 0); if (boundSynNotch >= synNotchThreshold) { this.activated = false; } diff --git a/src/arcade/patch/agent/cell/PatchCellContainer.java b/src/arcade/patch/agent/cell/PatchCellContainer.java index 14fb23dec..b0d910470 100644 --- a/src/arcade/patch/agent/cell/PatchCellContainer.java +++ b/src/arcade/patch/agent/cell/PatchCellContainer.java @@ -126,9 +126,11 @@ public Cell convert( case "inhibitory_cart": return new PatchCellCARTCombinedInhibitory(this, location, parameters, links); case "inducible_cart_separate": - return new PatchCellCARTCombinedInducibleSeparate(this, location, parameters, links); + return new PatchCellCARTCombinedInducibleSeparate( + this, location, parameters, links); case "inhibitory_cart_separate": - return new PatchCellCARTCombinedInhibitorySeparate(this, location, parameters, links); + return new PatchCellCARTCombinedInhibitorySeparate( + this, location, parameters, links); case "random": return new PatchCellRandom(this, location, parameters, links); } From 16dd26e9577c259ce0c62a27a63b28ecb86f4293 Mon Sep 17 00:00:00 2001 From: allison-li-1016 Date: Wed, 18 Jun 2025 00:43:49 +0000 Subject: [PATCH 08/28] adding documentation --- .../PatchCellCARTCombinedCombinatorial.java | 24 +++++++++++++++++++ .../cell/PatchCellCARTCombinedInducible.java | 1 + ...atchCellCARTCombinedInducibleSeparate.java | 6 +++++ .../cell/PatchCellCARTCombinedInhibitory.java | 1 + ...tchCellCARTCombinedInhibitorySeparate.java | 6 +++++ 5 files changed, 38 insertions(+) diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java index cc08c10ca..b204571c6 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java @@ -94,6 +94,11 @@ public PatchCellCARTCombinedCombinatorial( poissonFactory = Poisson::new; } + /** + * Binds to target cell in neighborhood. * + * + * @param simstate the simulation state + */ protected void checkForBinding(SimState simstate) { Simulation sim = (Simulation) simstate; PatchGrid grid = (PatchGrid) sim.getGrid(); @@ -114,6 +119,12 @@ protected void checkForBinding(SimState simstate) { } } + /** + * Calculates the number of binding and unbinding events for the synnotch receptor . * + * + * @param random the random object + * @param sim the simulation instance + */ protected void calculateCARS(MersenneTwisterFast random, Simulation sim) { int TAU = 60; double currentTime = sim.getSchedule().getTime(); @@ -171,10 +182,18 @@ interface PoissonFactory { Poisson createPoisson(double lambda, MersenneTwisterFast random); } + /** + * returns the poisson distribution. + * + * @param lambda the Poisson distribution lambda + * @param random the random number generator + * @return a Poisson distribution instance + */ public double callPoisson(double lambda, MersenneTwisterFast random) { return poissonFactory.createPoisson(lambda, random).nextInt(); } + /** resets bound target cell and unbinds from it. */ public void resetBoundCell() { if (boundCell != null) { boundCell.updateSynNotchAntigens(boundSynNotch, 0); @@ -183,8 +202,13 @@ public void resetBoundCell() { boundSynNotch = 0; } + /** private class for tracking synnotch binding events. */ private static class BindingEvent { + + /** timestamp for binding events. */ double timeStep; + + /** number of binding events at this time step. */ int count; BindingEvent(double timeStep, int count) { diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java index ca1d42325..57c303f9b 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java @@ -51,6 +51,7 @@ public void step(SimState simstate) { super.step(simstate); } + @Override protected void calculateCARS(MersenneTwisterFast random, Simulation sim) { int TAU = 60; super.calculateCARS(random, sim); diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducibleSeparate.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducibleSeparate.java index d35c1b16b..633d21b00 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducibleSeparate.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducibleSeparate.java @@ -155,6 +155,12 @@ public void step(SimState simstate) { } } + /** + * Calculates T cell activation given bound synnotchs. * + * + * @param random the random object + * @param sim the simulation instance + */ protected void calculateActivation(MersenneTwisterFast random, Simulation sim) { int TAU = 60; super.calculateCARS(random, sim); diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java index a3d5832c5..05b63b50e 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java @@ -50,6 +50,7 @@ public void step(SimState simstate) { super.step(simstate); } + @Override protected void calculateCARS(MersenneTwisterFast random, Simulation sim) { int TAU = 60; super.calculateCARS(random, sim); diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitorySeparate.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitorySeparate.java index 65d344ff1..cace79202 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitorySeparate.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitorySeparate.java @@ -49,6 +49,12 @@ public void step(SimState simstate) { super.step(simstate); } + /** + * Calculates T cell activation given bound synnotchs. * + * + * @param random the random object + * @param sim the simulation instance + */ private void calculateActivation(MersenneTwisterFast random, Simulation sim) { int TAU = 60; super.calculateCARS(random, sim); From 58ea66a3a44c262ca7d945fd042249f3cf0e96d7 Mon Sep 17 00:00:00 2001 From: allison-li-1016 Date: Wed, 18 Jun 2025 00:48:06 +0000 Subject: [PATCH 09/28] adding leftover javadoc and variable casing fixes --- .../patch/agent/cell/PatchCellCARTCombinedCombinatorial.java | 1 + .../patch/agent/cell/PatchCellCARTCombinedInducible.java | 5 +++-- .../agent/cell/PatchCellCARTCombinedInducibleSeparate.java | 1 + .../patch/agent/cell/PatchCellCARTCombinedInhibitory.java | 1 + .../agent/cell/PatchCellCARTCombinedInhibitorySeparate.java | 2 ++ 5 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java index b204571c6..cddeb4858 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java @@ -211,6 +211,7 @@ private static class BindingEvent { /** number of binding events at this time step. */ int count; + /** Instantiates the binding event. */ BindingEvent(double timeStep, int count) { this.timeStep = timeStep; this.count = count; diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java index 57c303f9b..62b3d8a3e 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java @@ -19,6 +19,7 @@ public class PatchCellCARTCombinedInducible extends PatchCellCARTCombinedCombina * Creates a tissue {@code PatchCellCARTCombinedInducible} agent. * * * @param location the {@link Location} of the cell + * @param container the cell container * @param parameters the dictionary of parameters */ public PatchCellCARTCombinedInducible( @@ -56,8 +57,8 @@ protected void calculateCARS(MersenneTwisterFast random, Simulation sim) { int TAU = 60; super.calculateCARS(random, sim); double n = 4.4; - int new_cars = + int newCars = (int) (maxCars / (1 + Math.pow(synNotchThreshold, n) / Math.pow(boundSynNotch, n))); - cars = Math.max((int) (cars - (carDegradationConstant * cars * TAU)), new_cars); + cars = Math.max((int) (cars - (carDegradationConstant * cars * TAU)), newCars); } } diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducibleSeparate.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducibleSeparate.java index 633d21b00..4641c2257 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducibleSeparate.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducibleSeparate.java @@ -20,6 +20,7 @@ public class PatchCellCARTCombinedInducibleSeparate extends PatchCellCARTCombine * Creates a tissue {@code PatchCellCombinedInducibleSeparate} agent. * * * @param location the {@link Location} of the cell + * @param container the cell container * @param parameters the dictionary of parameters */ public PatchCellCARTCombinedInducibleSeparate( diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java index 05b63b50e..d3f9c4e03 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java @@ -19,6 +19,7 @@ public class PatchCellCARTCombinedInhibitory extends PatchCellCARTCombinedCombin * Creates a tissue {@code PatchCellCARTCombinedInhibitory} agent. * * * @param location the {@link Location} of the cell + * @param container the cell container * @param parameters the dictionary of parameters */ public PatchCellCARTCombinedInhibitory( diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitorySeparate.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitorySeparate.java index cace79202..831f05543 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitorySeparate.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitorySeparate.java @@ -11,6 +11,7 @@ /** Extension of {@link PatchCellCARTCombinedCombinatorial} for iCAR circuit. */ public class PatchCellCARTCombinedInhibitorySeparate extends PatchCellCARTCombinedCombinatorial { + /** Logger for this class. */ private static final Logger LOGGER = Logger.getLogger(PatchCellCARTCombinedInhibitorySeparate.class.getName()); @@ -18,6 +19,7 @@ public class PatchCellCARTCombinedInhibitorySeparate extends PatchCellCARTCombin * Creates a tissue {@code PatchCellCombinedInhibitorySeparate} agent. * * * @param location the {@link Location} of the cell + * @param container the cell container * @param parameters the dictionary of parameters */ public PatchCellCARTCombinedInhibitorySeparate( From 8f49d203bae415bb247c0054cb5b5c0831b93fdd Mon Sep 17 00:00:00 2001 From: allison-li-1016 Date: Wed, 18 Jun 2025 00:51:47 +0000 Subject: [PATCH 10/28] updating javadoc and parameter description --- .../agent/cell/PatchCellCARTCombinedCombinatorial.java | 7 ++++++- src/arcade/patch/parameter.patch.xml | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java index cddeb4858..8b0ee6ab8 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java @@ -211,7 +211,12 @@ private static class BindingEvent { /** number of binding events at this time step. */ int count; - /** Instantiates the binding event. */ + /** + * Instantiates the binding event. + * + * @param timeStep simulation timestamp of binding event + * @param count number of binding events + */ BindingEvent(double timeStep, int count) { this.timeStep = timeStep; this.count = count; diff --git a/src/arcade/patch/parameter.patch.xml b/src/arcade/patch/parameter.patch.xml index 4f4a9877f..474a35760 100644 --- a/src/arcade/patch/parameter.patch.xml +++ b/src/arcade/patch/parameter.patch.xml @@ -53,7 +53,7 @@ - + From 34d21b70e3a1ab6cb62db9408dc4f1e7ae4c68f1 Mon Sep 17 00:00:00 2001 From: allison-li-1016 Date: Wed, 18 Jun 2025 01:02:48 +0000 Subject: [PATCH 11/28] simplfying binding event history logic --- .../cell/PatchCellCARTCombinedCombinatorial.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java index 8b0ee6ab8..21f84eec2 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java @@ -1,6 +1,7 @@ package arcade.patch.agent.cell; import java.util.Deque; +import java.util.Iterator; import java.util.LinkedList; import java.util.logging.Logger; import sim.engine.SimState; @@ -154,20 +155,18 @@ protected void calculateCARS(MersenneTwisterFast random, Simulation sim) { // model synnotch activation TF degradation int ineffectiveBoundSynNotchs = 0; // find all binding events that are older than the synNotchActivationDelay - for (BindingEvent e : bindingHistory) { + Iterator it = bindingHistory.iterator(); + while (it.hasNext()) { + BindingEvent e = it.next(); if (currentTime - e.timeStep >= synNotchActivationDelay) { ineffectiveBoundSynNotchs += e.count; + // remove binding event from history if older than delay + it.remove(); } } boundSynNotch -= ineffectiveBoundSynNotchs; synnotchs = Math.max(0, synnotchs - ineffectiveBoundSynNotchs); - - // remove all binding events that are older than the synNotchActivationDelay - while (!bindingHistory.isEmpty() - && bindingHistory.peekFirst().timeStep <= currentTime - synNotchActivationDelay) { - bindingHistory.pollFirst(); - } } /** A {@code PoissonFactory} object instantiates Poisson distributions. */ From 38fc568056bc69664c5c12c23e4c2ccbc3c1a43b Mon Sep 17 00:00:00 2001 From: allison-li-1016 Date: Mon, 30 Jun 2025 19:25:46 +0000 Subject: [PATCH 12/28] decomplicating synnotch inactivation --- .../PatchCellCARTCombinedCombinatorial.java | 53 +------------------ src/arcade/patch/parameter.patch.xml | 1 - 2 files changed, 1 insertion(+), 53 deletions(-) diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java index 21f84eec2..d45c3c913 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java @@ -1,8 +1,5 @@ package arcade.patch.agent.cell; -import java.util.Deque; -import java.util.Iterator; -import java.util.LinkedList; import java.util.logging.Logger; import sim.engine.SimState; import sim.util.Bag; @@ -54,12 +51,6 @@ public abstract class PatchCellCARTCombinedCombinatorial extends PatchCellCARTCo /** basal CAR receptor expression rate. */ protected final double basalCARGenerationRate; - /** Half-life of synnotch activation TF. */ - protected final double synNotchActivationDelay; - - /** List of recent synnotch binding events. */ - protected Deque bindingHistory = new LinkedList<>(); - /** * Creates a T cell {@code PatchCellCARTCombinedCombinatorial} agent. * * @@ -89,7 +80,6 @@ public PatchCellCARTCombinedCombinatorial( synnotchs = parameters.getInt("SYNNOTCHS"); synNotchThreshold = parameters.getDouble("SYNNOTCH_THRESHOLD") * synnotchs; basalCARGenerationRate = parameters.getDouble("K_CAR_GENERATION"); - synNotchActivationDelay = parameters.getDouble("SYNNOTCH_ACTIVATION_DELAY"); boundSynNotch = 0; maxCars = cars; poissonFactory = Poisson::new; @@ -128,7 +118,6 @@ protected void checkForBinding(SimState simstate) { */ protected void calculateCARS(MersenneTwisterFast random, Simulation sim) { int TAU = 60; - double currentTime = sim.getSchedule().getTime(); int unboundSynNotch = synnotchs - boundSynNotch; double expectedBindingEvents = @@ -140,10 +129,6 @@ protected void calculateCARS(MersenneTwisterFast random, Simulation sim) { * TAU; int bindingEvents = poissonFactory.createPoisson(expectedBindingEvents, random).nextInt(); - - if (bindingEvents > 0) { - bindingHistory.addLast(new BindingEvent(currentTime, bindingEvents)); - } double expectedUnbindingEvents = unbindingConstant * boundSynNotch * TAU; int unbindingEvents = poissonFactory.createPoisson(expectedUnbindingEvents, random).nextInt(); @@ -151,22 +136,7 @@ protected void calculateCARS(MersenneTwisterFast random, Simulation sim) { boundSynNotch += bindingEvents; boundSynNotch -= unbindingEvents; boundCell.updateSynNotchAntigens(unbindingEvents, bindingEvents); - - // model synnotch activation TF degradation - int ineffectiveBoundSynNotchs = 0; - // find all binding events that are older than the synNotchActivationDelay - Iterator it = bindingHistory.iterator(); - while (it.hasNext()) { - BindingEvent e = it.next(); - if (currentTime - e.timeStep >= synNotchActivationDelay) { - ineffectiveBoundSynNotchs += e.count; - // remove binding event from history if older than delay - it.remove(); - } - } - - boundSynNotch -= ineffectiveBoundSynNotchs; - synnotchs = Math.max(0, synnotchs - ineffectiveBoundSynNotchs); + synnotchs = Math.max(0, synnotchs - bindingEvents); } /** A {@code PoissonFactory} object instantiates Poisson distributions. */ @@ -200,25 +170,4 @@ public void resetBoundCell() { } boundSynNotch = 0; } - - /** private class for tracking synnotch binding events. */ - private static class BindingEvent { - - /** timestamp for binding events. */ - double timeStep; - - /** number of binding events at this time step. */ - int count; - - /** - * Instantiates the binding event. - * - * @param timeStep simulation timestamp of binding event - * @param count number of binding events - */ - BindingEvent(double timeStep, int count) { - this.timeStep = timeStep; - this.count = count; - } - } } diff --git a/src/arcade/patch/parameter.patch.xml b/src/arcade/patch/parameter.patch.xml index 474a35760..a08b20e52 100644 --- a/src/arcade/patch/parameter.patch.xml +++ b/src/arcade/patch/parameter.patch.xml @@ -53,7 +53,6 @@ - From e0c6fd225d5dda67a345acce38d178caf431832f Mon Sep 17 00:00:00 2001 From: allison-li-1016 Date: Wed, 2 Jul 2025 16:44:16 +0000 Subject: [PATCH 13/28] removing unnecessary classes, adding enums in --- .../PatchCellCARTCombinedCombinatorial.java | 1 + .../cell/PatchCellCARTCombinedInducible.java | 162 +++++++++++++++- ...atchCellCARTCombinedInducibleSeparate.java | 180 ------------------ .../cell/PatchCellCARTCombinedInhibitory.java | 46 ++++- ...tchCellCARTCombinedInhibitorySeparate.java | 74 ------- .../patch/agent/cell/PatchCellContainer.java | 13 +- src/arcade/patch/util/PatchEnums.java | 25 +++ 7 files changed, 236 insertions(+), 265 deletions(-) delete mode 100644 src/arcade/patch/agent/cell/PatchCellCARTCombinedInducibleSeparate.java delete mode 100644 src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitorySeparate.java diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java index d45c3c913..ae0e745b9 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java @@ -10,6 +10,7 @@ import arcade.core.util.GrabBag; import arcade.core.util.Parameters; import arcade.patch.env.grid.PatchGrid; +import arcade.patch.util.PatchEnums.LogicalCARs; /** * Abstract class of {@link PatchCellCART} for combined CD4/CD8 combinatorial CART-cells with diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java index 62b3d8a3e..0df0a174c 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java @@ -7,6 +7,8 @@ import arcade.core.sim.Simulation; import arcade.core.util.GrabBag; import arcade.core.util.Parameters; +import arcade.patch.util.PatchEnums; +import arcade.patch.util.PatchEnums.LogicalCARs; /** Extension of {@link PatchCellCARTCombinedCombinatorial} for synnotch circuit. */ public class PatchCellCARTCombinedInducible extends PatchCellCARTCombinedCombinatorial { @@ -14,6 +16,9 @@ public class PatchCellCARTCombinedInducible extends PatchCellCARTCombinedCombina /** Logger for this class. */ private static final Logger LOGGER = Logger.getLogger(PatchCellCARTCombinedInducible.class.getName()); + + /** Type of combinatorial circuit. */ + private final LogicalCARs type; /** * Creates a tissue {@code PatchCellCARTCombinedInducible} agent. * @@ -37,28 +42,179 @@ public PatchCellCARTCombinedInducible( */ public PatchCellCARTCombinedInducible( PatchCellContainer container, Location location, Parameters parameters, GrabBag links) { + this(container, location, parameters, links, null); + } + + /** + * Creates a T cell {@code PatchCellCARTCombinedInducible} agent. * + * + * @param container the cell container + * @param location the {@link Location} of the cell + * @param parameters the dictionary of parameters + * @param links the map of population links + * @param type the type of combinatorial circuit + */ + public PatchCellCARTCombinedInducible( + PatchCellContainer container, Location location, Parameters parameters, GrabBag links, LogicalCARs type) { super(container, location, parameters, links); cars = 0; + this.type = type; } @Override public void step(SimState simstate) { Simulation sim = (Simulation) simstate; + if (super.boundCell == null) { super.checkForBinding(simstate); } else { calculateCARS(simstate.random, sim); } - super.step(simstate); + + if (type.equals(LogicalCARs.INDUCIBLE_SYNNOTCH)) { + super.step(simstate); + } else if (type.equals(LogicalCARs.INDUCIBLE_INFLAMMATION)) { + inflammationStep(simstate); + } } @Override protected void calculateCARS(MersenneTwisterFast random, Simulation sim) { int TAU = 60; super.calculateCARS(random, sim); + if (type.equals(LogicalCARs.INDUCIBLE_SYNNOTCH)) { + synNotchCARCalculation(TAU); + } else if (type.equals(LogicalCARs.INDUCIBLE_INFLAMMATION)) { + inflammationActivation(TAU); + } + } + + protected void synNotchCARCalculation(int tau){ double n = 4.4; int newCars = - (int) (maxCars / (1 + Math.pow(synNotchThreshold, n) / Math.pow(boundSynNotch, n))); - cars = Math.max((int) (cars - (carDegradationConstant * cars * TAU)), newCars); + (int) (maxCars / (1 + Math.pow(synNotchThreshold, n) / Math.pow(boundSynNotch, n))); + cars = Math.max((int) (cars - (carDegradationConstant * cars * tau)), newCars); + } + + protected void inflammationActivation(int tau) { + cars = + Math.max( + (int) + (cars + + (basalCARGenerationRate * tau) + - (carDegradationConstant * cars * tau)), + 0); + if (boundSynNotch >= synNotchThreshold) { + this.lastActiveTicker = 0; + this.activated = true; + } + } + + protected void inflammationStep(SimState simstate) { + Simulation sim = (Simulation) simstate; + + super.age++; + + if (state != PatchEnums.State.APOPTOTIC && age > apoptosisAge) { + setState(PatchEnums.State.APOPTOTIC); + super.unbind(); + this.activated = false; + } + + super.lastActiveTicker++; + + if (super.lastActiveTicker != 0 && super.lastActiveTicker % MINUTES_IN_DAY == 0) { + if (super.boundCARAntigensCount != 0) { + super.boundCARAntigensCount--; + } + } + if (super.lastActiveTicker / MINUTES_IN_DAY >= 7) { + super.activated = false; + } + + super.processes.get(PatchEnums.Domain.METABOLISM).step(simstate.random, sim); + + // Check energy status. If cell has less energy than threshold, it will + // apoptose. If overall energy is negative, then cell enters quiescence. + if (state != PatchEnums.State.APOPTOTIC) { + if (super.energy < super.energyThreshold) { + + super.setState(PatchEnums.State.APOPTOTIC); + super.unbind(); + this.activated = false; + } else if (state != PatchEnums.State.ANERGIC + && state != PatchEnums.State.SENESCENT + && state != PatchEnums.State.EXHAUSTED + && state != PatchEnums.State.STARVED + && energy < 0) { + + super.setState(PatchEnums.State.STARVED); + super.unbind(); + } else if (state == PatchEnums.State.STARVED && energy >= 0) { + super.setState(PatchEnums.State.UNDEFINED); + } + } + + super.processes.get(PatchEnums.Domain.INFLAMMATION).step(simstate.random, sim); + + if (super.state == PatchEnums.State.UNDEFINED || super.state == PatchEnums.State.PAUSED) { + if (divisions == divisionPotential) { + if (simstate.random.nextDouble() > super.senescentFraction) { + super.setState(PatchEnums.State.APOPTOTIC); + } else { + super.setState(PatchEnums.State.SENESCENT); + } + super.unbind(); + this.activated = false; + } else { + PatchCellTissue target = super.bindTarget(sim, location, simstate.random); + super.boundTarget = target; + + // If cell is bound to both antigen and self it will become anergic. + if (super.getBindingFlag() == PatchEnums.AntigenFlag.BOUND_ANTIGEN_CELL_RECEPTOR) { + if (simstate.random.nextDouble() > super.anergicFraction) { + super.setState(PatchEnums.State.APOPTOTIC); + } else { + super.setState(PatchEnums.State.ANERGIC); + } + super.unbind(); + this.activated = false; + } else if (super.getBindingFlag() == PatchEnums.AntigenFlag.BOUND_ANTIGEN) { + // If cell is only bound to target antigen, the cell + // can potentially become properly activated. + + // Check overstimulation. If cell has bound to + // target antigens too many times, becomes exhausted. + if (boundCARAntigensCount > maxAntigenBinding) { + if (simstate.random.nextDouble() > super.exhaustedFraction) { + super.setState(PatchEnums.State.APOPTOTIC); + } else { + super.setState(PatchEnums.State.EXHAUSTED); + } + super.unbind(); + this.activated = false; + } else { + // if CD8 cell is properly activated, it can be cytotoxic + super.setState(PatchEnums.State.CYTOTOXIC); + } + } else { + // If self binding, unbind + if (super.getBindingFlag() == PatchEnums.AntigenFlag.BOUND_CELL_RECEPTOR) { + super.unbind(); + } + // Check activation status. If cell has been activated before, + // it will proliferate. If not, it will migrate. + if (activated) { + super.setState(PatchEnums.State.PROLIFERATIVE); + } else { + if (simstate.random.nextDouble() > super.proliferativeFraction) { + super.setState(PatchEnums.State.MIGRATORY); + } else { + super.setState(PatchEnums.State.PROLIFERATIVE); + } + } + } + } + } } } diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducibleSeparate.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducibleSeparate.java deleted file mode 100644 index 4641c2257..000000000 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducibleSeparate.java +++ /dev/null @@ -1,180 +0,0 @@ -package arcade.patch.agent.cell; - -import java.util.logging.Logger; -import sim.engine.SimState; -import ec.util.MersenneTwisterFast; -import arcade.core.env.location.Location; -import arcade.core.sim.Simulation; -import arcade.core.util.GrabBag; -import arcade.core.util.Parameters; -import arcade.patch.util.PatchEnums; - -/** Extension of {@link PatchCellCARTCombinedCombinatorial} for induced combinatorial circuit. */ -public class PatchCellCARTCombinedInducibleSeparate extends PatchCellCARTCombinedCombinatorial { - - /** Logger for this class. */ - private static final Logger LOGGER = - Logger.getLogger(PatchCellCARTCombinedInducibleSeparate.class.getName()); - - /** - * Creates a tissue {@code PatchCellCombinedInducibleSeparate} agent. * - * - * @param location the {@link Location} of the cell - * @param container the cell container - * @param parameters the dictionary of parameters - */ - public PatchCellCARTCombinedInducibleSeparate( - PatchCellContainer container, Location location, Parameters parameters) { - this(container, location, parameters, null); - } - - /** - * Creates a T cell {@code PatchCellCombinedInducibleSeparate} agent. * - * - * @param container the cell container - * @param location the {@link Location} of the cell - * @param parameters the dictionary of parameters - * @param links the map of population links - */ - public PatchCellCARTCombinedInducibleSeparate( - PatchCellContainer container, Location location, Parameters parameters, GrabBag links) { - super(container, location, parameters, links); - cars = 0; - } - - @Override - public void step(SimState simstate) { - Simulation sim = (Simulation) simstate; - if (super.boundCell == null) { - super.checkForBinding(simstate); - } else { - calculateActivation(simstate.random, sim); - } - - super.age++; - - if (state != PatchEnums.State.APOPTOTIC && age > apoptosisAge) { - setState(PatchEnums.State.APOPTOTIC); - super.unbind(); - this.activated = false; - } - - super.lastActiveTicker++; - - if (super.lastActiveTicker != 0 && super.lastActiveTicker % MINUTES_IN_DAY == 0) { - if (super.boundCARAntigensCount != 0) { - super.boundCARAntigensCount--; - } - } - if (super.lastActiveTicker / MINUTES_IN_DAY >= 7) { - super.activated = false; - } - - super.processes.get(PatchEnums.Domain.METABOLISM).step(simstate.random, sim); - - // Check energy status. If cell has less energy than threshold, it will - // apoptose. If overall energy is negative, then cell enters quiescence. - if (state != PatchEnums.State.APOPTOTIC) { - if (super.energy < super.energyThreshold) { - - super.setState(PatchEnums.State.APOPTOTIC); - super.unbind(); - this.activated = false; - } else if (state != PatchEnums.State.ANERGIC - && state != PatchEnums.State.SENESCENT - && state != PatchEnums.State.EXHAUSTED - && state != PatchEnums.State.STARVED - && energy < 0) { - - super.setState(PatchEnums.State.STARVED); - super.unbind(); - } else if (state == PatchEnums.State.STARVED && energy >= 0) { - super.setState(PatchEnums.State.UNDEFINED); - } - } - - super.processes.get(PatchEnums.Domain.INFLAMMATION).step(simstate.random, sim); - - if (super.state == PatchEnums.State.UNDEFINED || super.state == PatchEnums.State.PAUSED) { - if (divisions == divisionPotential) { - if (simstate.random.nextDouble() > super.senescentFraction) { - super.setState(PatchEnums.State.APOPTOTIC); - } else { - super.setState(PatchEnums.State.SENESCENT); - } - super.unbind(); - this.activated = false; - } else { - PatchCellTissue target = super.bindTarget(sim, location, simstate.random); - super.boundTarget = target; - - // If cell is bound to both antigen and self it will become anergic. - if (super.getBindingFlag() == PatchEnums.AntigenFlag.BOUND_ANTIGEN_CELL_RECEPTOR) { - if (simstate.random.nextDouble() > super.anergicFraction) { - super.setState(PatchEnums.State.APOPTOTIC); - } else { - super.setState(PatchEnums.State.ANERGIC); - } - super.unbind(); - this.activated = false; - } else if (super.getBindingFlag() == PatchEnums.AntigenFlag.BOUND_ANTIGEN) { - // If cell is only bound to target antigen, the cell - // can potentially become properly activated. - - // Check overstimulation. If cell has bound to - // target antigens too many times, becomes exhausted. - if (boundCARAntigensCount > maxAntigenBinding) { - if (simstate.random.nextDouble() > super.exhaustedFraction) { - super.setState(PatchEnums.State.APOPTOTIC); - } else { - super.setState(PatchEnums.State.EXHAUSTED); - } - super.unbind(); - this.activated = false; - } else { - // if CD8 cell is properly activated, it can be cytotoxic - super.setState(PatchEnums.State.CYTOTOXIC); - } - } else { - // If self binding, unbind - if (super.getBindingFlag() == PatchEnums.AntigenFlag.BOUND_CELL_RECEPTOR) { - super.unbind(); - } - // Check activation status. If cell has been activated before, - // it will proliferate. If not, it will migrate. - if (activated) { - super.setState(PatchEnums.State.PROLIFERATIVE); - } else { - if (simstate.random.nextDouble() > super.proliferativeFraction) { - super.setState(PatchEnums.State.MIGRATORY); - } else { - super.setState(PatchEnums.State.PROLIFERATIVE); - } - } - } - } - } - } - - /** - * Calculates T cell activation given bound synnotchs. * - * - * @param random the random object - * @param sim the simulation instance - */ - protected void calculateActivation(MersenneTwisterFast random, Simulation sim) { - int TAU = 60; - super.calculateCARS(random, sim); - cars = - Math.max( - (int) - (cars - + (basalCARGenerationRate * TAU) - - (carDegradationConstant * cars * TAU)), - 0); - if (boundSynNotch >= synNotchThreshold) { - this.lastActiveTicker = 0; - this.activated = true; - } - } -} diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java index d3f9c4e03..20ed37521 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java @@ -7,6 +7,7 @@ import arcade.core.sim.Simulation; import arcade.core.util.GrabBag; import arcade.core.util.Parameters; +import arcade.patch.util.PatchEnums.LogicalCARs; /** Extension of {@link PatchCellCARTCombinedCombinatorial} for iCAR synnotch circuit. */ public class PatchCellCARTCombinedInhibitory extends PatchCellCARTCombinedCombinatorial { @@ -15,6 +16,9 @@ public class PatchCellCARTCombinedInhibitory extends PatchCellCARTCombinedCombin private static final Logger LOGGER = Logger.getLogger(PatchCellCARTCombinedInhibitory.class.getName()); + /** Type of combinatorial circuit. */ + private final LogicalCARs type; + /** * Creates a tissue {@code PatchCellCARTCombinedInhibitory} agent. * * @@ -37,7 +41,23 @@ public PatchCellCARTCombinedInhibitory( */ public PatchCellCARTCombinedInhibitory( PatchCellContainer container, Location location, Parameters parameters, GrabBag links) { + this(container, location, parameters, links, null); + } + + /** + * Creates a T cell {@code PatchCellCARTCombinedInhibitory} agent. * + * + * @param container the cell container + * @param location the {@link Location} of the cell + * @param parameters the dictionary of parameters + * @param links the map of population links + * @param type the type of combinatorial circuit + */ + public PatchCellCARTCombinedInhibitory( + PatchCellContainer container, Location location, Parameters parameters, GrabBag links, LogicalCARs type) { super(container, location, parameters, links); + cars = 0; + this.type = type; } @Override @@ -55,9 +75,31 @@ public void step(SimState simstate) { protected void calculateCARS(MersenneTwisterFast random, Simulation sim) { int TAU = 60; super.calculateCARS(random, sim); + + if (type.equals(LogicalCARs.INHIBITORY_RECEPTOR)) { + receptorCars(TAU); + } else if (type.equals(LogicalCARs.INHIBITORY_INFLAMMATION)) { + inflammationCars(TAU); + } + } + + protected void receptorCars(int tau) { double n = 8; int removeCARs = (int) (maxCars / (1 + Math.pow(synNotchThreshold, n) / Math.pow(boundSynNotch, n))); - cars = Math.min((int) (cars + (basalCARGenerationRate * TAU)), maxCars - removeCARs); + cars = Math.min((int) (cars + (basalCARGenerationRate * tau)), maxCars - removeCARs); + } + + protected void inflammationCars(int tau) { + cars = + Math.max( + (int) + (cars + + (basalCARGenerationRate * tau) + - (carDegradationConstant * cars * tau)), + 0); + if (boundSynNotch >= synNotchThreshold) { + this.activated = false; + } } -} +} \ No newline at end of file diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitorySeparate.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitorySeparate.java deleted file mode 100644 index 831f05543..000000000 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitorySeparate.java +++ /dev/null @@ -1,74 +0,0 @@ -package arcade.patch.agent.cell; - -import java.util.logging.Logger; -import sim.engine.SimState; -import ec.util.MersenneTwisterFast; -import arcade.core.env.location.Location; -import arcade.core.sim.Simulation; -import arcade.core.util.GrabBag; -import arcade.core.util.Parameters; - -/** Extension of {@link PatchCellCARTCombinedCombinatorial} for iCAR circuit. */ -public class PatchCellCARTCombinedInhibitorySeparate extends PatchCellCARTCombinedCombinatorial { - - /** Logger for this class. */ - private static final Logger LOGGER = - Logger.getLogger(PatchCellCARTCombinedInhibitorySeparate.class.getName()); - - /** - * Creates a tissue {@code PatchCellCombinedInhibitorySeparate} agent. * - * - * @param location the {@link Location} of the cell - * @param container the cell container - * @param parameters the dictionary of parameters - */ - public PatchCellCARTCombinedInhibitorySeparate( - PatchCellContainer container, Location location, Parameters parameters) { - this(container, location, parameters, null); - } - - /** - * Creates a T cell {@code PatchCellCombinedInhibitorySeparate} agent. * - * - * @param container the cell container - * @param location the {@link Location} of the cell - * @param parameters the dictionary of parameters - * @param links the map of population links - */ - public PatchCellCARTCombinedInhibitorySeparate( - PatchCellContainer container, Location location, Parameters parameters, GrabBag links) { - super(container, location, parameters, links); - } - - @Override - public void step(SimState simstate) { - Simulation sim = (Simulation) simstate; - if (super.boundCell == null) { - super.checkForBinding(simstate); - } else { - calculateActivation(simstate.random, sim); - } - super.step(simstate); - } - - /** - * Calculates T cell activation given bound synnotchs. * - * - * @param random the random object - * @param sim the simulation instance - */ - private void calculateActivation(MersenneTwisterFast random, Simulation sim) { - int TAU = 60; - super.calculateCARS(random, sim); - cars = - Math.max( - (int) - (cars - + (basalCARGenerationRate * TAU) - - (carDegradationConstant * cars * TAU)), - 0); - if (boundSynNotch >= synNotchThreshold) { - this.activated = false; - } - } -} diff --git a/src/arcade/patch/agent/cell/PatchCellContainer.java b/src/arcade/patch/agent/cell/PatchCellContainer.java index b0d910470..6c860409a 100644 --- a/src/arcade/patch/agent/cell/PatchCellContainer.java +++ b/src/arcade/patch/agent/cell/PatchCellContainer.java @@ -9,6 +9,7 @@ import arcade.core.util.GrabBag; import arcade.core.util.MiniBox; import arcade.core.util.Parameters; +import arcade.patch.util.PatchEnums.LogicalCARs; /** * Implementation of {@link CellContainer} for {@link PatchCell} agents. @@ -122,15 +123,15 @@ public Cell convert( case "combined": return new PatchCellCARTCombined(this, location, parameters, links); case "inducible_cart": - return new PatchCellCARTCombinedInducible(this, location, parameters, links); + return new PatchCellCARTCombinedInducible(this, location, parameters, links, LogicalCARs.INDUCIBLE_SYNNOTCH); case "inhibitory_cart": - return new PatchCellCARTCombinedInhibitory(this, location, parameters, links); + return new PatchCellCARTCombinedInhibitory(this, location, parameters, links, LogicalCARs.INHIBITORY_RECEPTOR); case "inducible_cart_separate": - return new PatchCellCARTCombinedInducibleSeparate( - this, location, parameters, links); + return new PatchCellCARTCombinedInducible( + this, location, parameters, links, LogicalCARs.INDUCIBLE_INFLAMMATION); case "inhibitory_cart_separate": - return new PatchCellCARTCombinedInhibitorySeparate( - this, location, parameters, links); + return new PatchCellCARTCombinedInhibitory( + this, location, parameters, links, LogicalCARs.INHIBITORY_INFLAMMATION); case "random": return new PatchCellRandom(this, location, parameters, links); } diff --git a/src/arcade/patch/util/PatchEnums.java b/src/arcade/patch/util/PatchEnums.java index 6cc940453..5e8b581d5 100644 --- a/src/arcade/patch/util/PatchEnums.java +++ b/src/arcade/patch/util/PatchEnums.java @@ -197,6 +197,31 @@ public static AntigenFlag random(MersenneTwisterFast rng) { } } + /** Combinatorial circuit types. */ + public enum LogicalCARs { + /** Code for inducible synNotch. */ + INDUCIBLE_SYNNOTCH, + + /** Code for inducible inflammation. */ + INDUCIBLE_INFLAMMATION, + + /** Code for inhibitory receptor. */ + INHIBITORY_RECEPTOR, + + /** Code for inhibitory inflammation. */ + INHIBITORY_INFLAMMATION; + + /** + * Randomly selects a {@code LogicalCARs}. + * + * @param rng the random number generator + * @return a random {@code LogicalCARs} + */ + public static LogicalCARs random(MersenneTwisterFast rng) { + return values()[rng.nextInt(values().length - 1) + 1]; + } + } + /** Operation category codes for patch simulations. */ public enum Category implements OperationCategory { /** Code for undefined category. */ From 51b115bdad33fe5fe20ab1a36c591a757723ef83 Mon Sep 17 00:00:00 2001 From: allison-li-1016 Date: Wed, 9 Jul 2025 16:05:44 +0000 Subject: [PATCH 14/28] spotless linting --- .../patch/agent/cell/PatchCellCARTCD4.java | 2 +- .../PatchCellCARTCombinedCombinatorial.java | 1 - .../cell/PatchCellCARTCombinedInducible.java | 24 +++++++++++-------- .../cell/PatchCellCARTCombinedInhibitory.java | 12 ++++++---- .../patch/agent/cell/PatchCellContainer.java | 6 +++-- 5 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCD4.java b/src/arcade/patch/agent/cell/PatchCellCARTCD4.java index 609be4934..ff7479c24 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCD4.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCD4.java @@ -63,7 +63,7 @@ public void step(SimState simstate) { if (state != State.APOPTOTIC && age > apoptosisAge) { setState(State.APOPTOTIC); - super.setBindingFlag(AntigenFlag.UNBOUND); + super.unbind(); this.activated = false; } diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java index ae0e745b9..d45c3c913 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java @@ -10,7 +10,6 @@ import arcade.core.util.GrabBag; import arcade.core.util.Parameters; import arcade.patch.env.grid.PatchGrid; -import arcade.patch.util.PatchEnums.LogicalCARs; /** * Abstract class of {@link PatchCellCART} for combined CD4/CD8 combinatorial CART-cells with diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java index 0df0a174c..47d75e4cb 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java @@ -16,7 +16,7 @@ public class PatchCellCARTCombinedInducible extends PatchCellCARTCombinedCombina /** Logger for this class. */ private static final Logger LOGGER = Logger.getLogger(PatchCellCARTCombinedInducible.class.getName()); - + /** Type of combinatorial circuit. */ private final LogicalCARs type; @@ -55,7 +55,11 @@ public PatchCellCARTCombinedInducible( * @param type the type of combinatorial circuit */ public PatchCellCARTCombinedInducible( - PatchCellContainer container, Location location, Parameters parameters, GrabBag links, LogicalCARs type) { + PatchCellContainer container, + Location location, + Parameters parameters, + GrabBag links, + LogicalCARs type) { super(container, location, parameters, links); cars = 0; this.type = type; @@ -89,21 +93,21 @@ protected void calculateCARS(MersenneTwisterFast random, Simulation sim) { } } - protected void synNotchCARCalculation(int tau){ + protected void synNotchCARCalculation(int tau) { double n = 4.4; int newCars = - (int) (maxCars / (1 + Math.pow(synNotchThreshold, n) / Math.pow(boundSynNotch, n))); + (int) (maxCars / (1 + Math.pow(synNotchThreshold, n) / Math.pow(boundSynNotch, n))); cars = Math.max((int) (cars - (carDegradationConstant * cars * tau)), newCars); } protected void inflammationActivation(int tau) { cars = - Math.max( - (int) - (cars - + (basalCARGenerationRate * tau) - - (carDegradationConstant * cars * tau)), - 0); + Math.max( + (int) + (cars + + (basalCARGenerationRate * tau) + - (carDegradationConstant * cars * tau)), + 0); if (boundSynNotch >= synNotchThreshold) { this.lastActiveTicker = 0; this.activated = true; diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java index 20ed37521..4c9b3a08b 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java @@ -16,7 +16,7 @@ public class PatchCellCARTCombinedInhibitory extends PatchCellCARTCombinedCombin private static final Logger LOGGER = Logger.getLogger(PatchCellCARTCombinedInhibitory.class.getName()); - /** Type of combinatorial circuit. */ + /** Type of combinatorial circuit. */ private final LogicalCARs type; /** @@ -54,7 +54,11 @@ public PatchCellCARTCombinedInhibitory( * @param type the type of combinatorial circuit */ public PatchCellCARTCombinedInhibitory( - PatchCellContainer container, Location location, Parameters parameters, GrabBag links, LogicalCARs type) { + PatchCellContainer container, + Location location, + Parameters parameters, + GrabBag links, + LogicalCARs type) { super(container, location, parameters, links); cars = 0; this.type = type; @@ -82,7 +86,7 @@ protected void calculateCARS(MersenneTwisterFast random, Simulation sim) { inflammationCars(TAU); } } - + protected void receptorCars(int tau) { double n = 8; int removeCARs = @@ -102,4 +106,4 @@ protected void inflammationCars(int tau) { this.activated = false; } } -} \ No newline at end of file +} diff --git a/src/arcade/patch/agent/cell/PatchCellContainer.java b/src/arcade/patch/agent/cell/PatchCellContainer.java index 6c860409a..5b9c782a9 100644 --- a/src/arcade/patch/agent/cell/PatchCellContainer.java +++ b/src/arcade/patch/agent/cell/PatchCellContainer.java @@ -123,9 +123,11 @@ public Cell convert( case "combined": return new PatchCellCARTCombined(this, location, parameters, links); case "inducible_cart": - return new PatchCellCARTCombinedInducible(this, location, parameters, links, LogicalCARs.INDUCIBLE_SYNNOTCH); + return new PatchCellCARTCombinedInducible( + this, location, parameters, links, LogicalCARs.INDUCIBLE_SYNNOTCH); case "inhibitory_cart": - return new PatchCellCARTCombinedInhibitory(this, location, parameters, links, LogicalCARs.INHIBITORY_RECEPTOR); + return new PatchCellCARTCombinedInhibitory( + this, location, parameters, links, LogicalCARs.INHIBITORY_RECEPTOR); case "inducible_cart_separate": return new PatchCellCARTCombinedInducible( this, location, parameters, links, LogicalCARs.INDUCIBLE_INFLAMMATION); From 011f594c90715542690c4b0bf560e852edd4ce96 Mon Sep 17 00:00:00 2001 From: allison-li-1016 Date: Wed, 9 Jul 2025 16:13:47 +0000 Subject: [PATCH 15/28] adding javadoc --- .../agent/cell/PatchCellCARTCombinedInducible.java | 5 +++++ .../agent/cell/PatchCellCARTCombinedInhibitory.java | 11 ++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java index 47d75e4cb..6e971c9d4 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java @@ -114,6 +114,11 @@ protected void inflammationActivation(int tau) { } } + /** + * Steps through T-cell rules using inflamation circuit. * + * + * @param simstate the current simulation state + */ protected void inflammationStep(SimState simstate) { Simulation sim = (Simulation) simstate; diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java index 4c9b3a08b..2bc14e27b 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java @@ -86,7 +86,11 @@ protected void calculateCARS(MersenneTwisterFast random, Simulation sim) { inflammationCars(TAU); } } - + /** + * Calculates the number of cars produced. * + * + * @param tau the time step + */ protected void receptorCars(int tau) { double n = 8; int removeCARs = @@ -94,6 +98,11 @@ protected void receptorCars(int tau) { cars = Math.min((int) (cars + (basalCARGenerationRate * tau)), maxCars - removeCARs); } + /** + * Calculates T-cell activation caused by inflammation. * + * + * @param tau the time step + */ protected void inflammationCars(int tau) { cars = Math.max( From 95b9f8e3ded77df6764201e3d508baea9ab7ad03 Mon Sep 17 00:00:00 2001 From: allison-li-1016 Date: Wed, 9 Jul 2025 16:14:58 +0000 Subject: [PATCH 16/28] linting --- src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java | 2 +- .../patch/agent/cell/PatchCellCARTCombinedInhibitory.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java index 6e971c9d4..e21d43eed 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java @@ -115,7 +115,7 @@ protected void inflammationActivation(int tau) { } /** - * Steps through T-cell rules using inflamation circuit. * + * Steps through T-cell rules using inflammation circuit. * * * @param simstate the current simulation state */ diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java index 2bc14e27b..c19e06626 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java @@ -86,6 +86,7 @@ protected void calculateCARS(MersenneTwisterFast random, Simulation sim) { inflammationCars(TAU); } } + /** * Calculates the number of cars produced. * * From 2b26d406721bf2f3ea484c670b923b774688f95b Mon Sep 17 00:00:00 2001 From: allison-li-1016 Date: Wed, 9 Jul 2025 16:26:24 +0000 Subject: [PATCH 17/28] adding more javadoc, moving TAU to final variable --- .../cell/PatchCellCARTCombinedInducible.java | 20 ++++++++++------- .../cell/PatchCellCARTCombinedInhibitory.java | 22 ++++++++++--------- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java index e21d43eed..6c8e9f91b 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java @@ -20,6 +20,9 @@ public class PatchCellCARTCombinedInducible extends PatchCellCARTCombinedCombina /** Type of combinatorial circuit. */ private final LogicalCARs type; + /** time step for tau stepping. */ + private final int TAU = 60; + /** * Creates a tissue {@code PatchCellCARTCombinedInducible} agent. * * @@ -84,29 +87,30 @@ public void step(SimState simstate) { @Override protected void calculateCARS(MersenneTwisterFast random, Simulation sim) { - int TAU = 60; super.calculateCARS(random, sim); if (type.equals(LogicalCARs.INDUCIBLE_SYNNOTCH)) { - synNotchCARCalculation(TAU); + synNotchCARCalculation(); } else if (type.equals(LogicalCARs.INDUCIBLE_INFLAMMATION)) { - inflammationActivation(TAU); + inflammationActivation(); } } - protected void synNotchCARCalculation(int tau) { + /** Calculates the number of cars produced for synnotch circuit. * */ + protected void synNotchCARCalculation() { double n = 4.4; int newCars = (int) (maxCars / (1 + Math.pow(synNotchThreshold, n) / Math.pow(boundSynNotch, n))); - cars = Math.max((int) (cars - (carDegradationConstant * cars * tau)), newCars); + cars = Math.max((int) (cars - (carDegradationConstant * cars * TAU)), newCars); } - protected void inflammationActivation(int tau) { + /** Calculates the number of cars produced for inflammation circuit. * */ + protected void inflammationActivation() { cars = Math.max( (int) (cars - + (basalCARGenerationRate * tau) - - (carDegradationConstant * cars * tau)), + + (basalCARGenerationRate * TAU) + - (carDegradationConstant * cars * TAU)), 0); if (boundSynNotch >= synNotchThreshold) { this.lastActiveTicker = 0; diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java index c19e06626..3e328987b 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java @@ -19,6 +19,9 @@ public class PatchCellCARTCombinedInhibitory extends PatchCellCARTCombinedCombin /** Type of combinatorial circuit. */ private final LogicalCARs type; + /** time step for tau stepping. */ + private final int TAU = 60; + /** * Creates a tissue {@code PatchCellCARTCombinedInhibitory} agent. * * @@ -77,40 +80,39 @@ public void step(SimState simstate) { @Override protected void calculateCARS(MersenneTwisterFast random, Simulation sim) { - int TAU = 60; super.calculateCARS(random, sim); if (type.equals(LogicalCARs.INHIBITORY_RECEPTOR)) { - receptorCars(TAU); + receptorCars(); } else if (type.equals(LogicalCARs.INHIBITORY_INFLAMMATION)) { - inflammationCars(TAU); + inflammationCars(); } } /** - * Calculates the number of cars produced. * + * Calculates the number of cars produced for receptor circuit. * * * @param tau the time step */ - protected void receptorCars(int tau) { + protected void receptorCars() { double n = 8; int removeCARs = (int) (maxCars / (1 + Math.pow(synNotchThreshold, n) / Math.pow(boundSynNotch, n))); - cars = Math.min((int) (cars + (basalCARGenerationRate * tau)), maxCars - removeCARs); + cars = Math.min((int) (cars + (basalCARGenerationRate * TAU)), maxCars - removeCARs); } /** - * Calculates T-cell activation caused by inflammation. * + * Calculates T-cell activation caused by inflammation circuit. * * * @param tau the time step */ - protected void inflammationCars(int tau) { + protected void inflammationCars() { cars = Math.max( (int) (cars - + (basalCARGenerationRate * tau) - - (carDegradationConstant * cars * tau)), + + (basalCARGenerationRate * TAU) + - (carDegradationConstant * cars * TAU)), 0); if (boundSynNotch >= synNotchThreshold) { this.activated = false; From 80fe58dfff629dce90eacfc591178f155637f1e0 Mon Sep 17 00:00:00 2001 From: allison-li-1016 Date: Wed, 9 Jul 2025 16:31:41 +0000 Subject: [PATCH 18/28] once again, addressing linter issues --- .../patch/agent/cell/PatchCellCARTCombinedCombinatorial.java | 4 +++- .../patch/agent/cell/PatchCellCARTCombinedInducible.java | 2 +- .../patch/agent/cell/PatchCellCARTCombinedInhibitory.java | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java index d45c3c913..203f28ede 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java @@ -51,6 +51,9 @@ public abstract class PatchCellCARTCombinedCombinatorial extends PatchCellCARTCo /** basal CAR receptor expression rate. */ protected final double basalCARGenerationRate; + /** time step for tau stepping. */ + private static final int TAU = 60; + /** * Creates a T cell {@code PatchCellCARTCombinedCombinatorial} agent. * * @@ -117,7 +120,6 @@ protected void checkForBinding(SimState simstate) { * @param sim the simulation instance */ protected void calculateCARS(MersenneTwisterFast random, Simulation sim) { - int TAU = 60; int unboundSynNotch = synnotchs - boundSynNotch; double expectedBindingEvents = diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java index 6c8e9f91b..0d9e79196 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java @@ -21,7 +21,7 @@ public class PatchCellCARTCombinedInducible extends PatchCellCARTCombinedCombina private final LogicalCARs type; /** time step for tau stepping. */ - private final int TAU = 60; + private static final int TAU = 60; /** * Creates a tissue {@code PatchCellCARTCombinedInducible} agent. * diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java index 3e328987b..4f93644b0 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java @@ -20,7 +20,7 @@ public class PatchCellCARTCombinedInhibitory extends PatchCellCARTCombinedCombin private final LogicalCARs type; /** time step for tau stepping. */ - private final int TAU = 60; + private static final int TAU = 60; /** * Creates a tissue {@code PatchCellCARTCombinedInhibitory} agent. * From 0b3a5b27c8d12fc9566f1f6b0ae324b4d707671c Mon Sep 17 00:00:00 2001 From: allison-li-1016 Date: Wed, 9 Jul 2025 16:36:38 +0000 Subject: [PATCH 19/28] deleting unnecessary tags for unused params in javadoc --- .../patch/agent/cell/PatchCellCARTCombinedInhibitory.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java index 4f93644b0..e24293140 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java @@ -91,8 +91,6 @@ protected void calculateCARS(MersenneTwisterFast random, Simulation sim) { /** * Calculates the number of cars produced for receptor circuit. * - * - * @param tau the time step */ protected void receptorCars() { double n = 8; @@ -103,8 +101,6 @@ protected void receptorCars() { /** * Calculates T-cell activation caused by inflammation circuit. * - * - * @param tau the time step */ protected void inflammationCars() { cars = From ddf1afc6ff98b1170ce510a312f5bf9bc114e456 Mon Sep 17 00:00:00 2001 From: allison-li-1016 Date: Wed, 9 Jul 2025 16:39:39 +0000 Subject: [PATCH 20/28] spotlessApply --- .../patch/agent/cell/PatchCellCARTCombinedInhibitory.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java index e24293140..a3510e336 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java @@ -89,9 +89,7 @@ protected void calculateCARS(MersenneTwisterFast random, Simulation sim) { } } - /** - * Calculates the number of cars produced for receptor circuit. * - */ + /** Calculates the number of cars produced for receptor circuit. * */ protected void receptorCars() { double n = 8; int removeCARs = @@ -99,9 +97,7 @@ protected void receptorCars() { cars = Math.min((int) (cars + (basalCARGenerationRate * TAU)), maxCars - removeCARs); } - /** - * Calculates T-cell activation caused by inflammation circuit. * - */ + /** Calculates T-cell activation caused by inflammation circuit. * */ protected void inflammationCars() { cars = Math.max( From 3090b06d034f68d517e900beb022ac9f1c2995e9 Mon Sep 17 00:00:00 2001 From: allison-li-1016 Date: Wed, 9 Jul 2025 16:43:58 +0000 Subject: [PATCH 21/28] reverting cd4 rule change --- src/arcade/patch/agent/cell/PatchCellCARTCD4.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCD4.java b/src/arcade/patch/agent/cell/PatchCellCARTCD4.java index ff7479c24..609be4934 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCD4.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCD4.java @@ -63,7 +63,7 @@ public void step(SimState simstate) { if (state != State.APOPTOTIC && age > apoptosisAge) { setState(State.APOPTOTIC); - super.unbind(); + super.setBindingFlag(AntigenFlag.UNBOUND); this.activated = false; } From 7590e7d91f7e082734728be30971685ed0a5996a Mon Sep 17 00:00:00 2001 From: allison-li-1016 Date: Thu, 17 Jul 2025 23:31:24 +0000 Subject: [PATCH 22/28] pushing carcade revisions to logicalCars --- .../patch/agent/action/PatchActionTreat.java | 317 +++++++++--------- .../patch/agent/cell/PatchCellCART.java | 20 +- .../patch/agent/cell/PatchCellContainer.java | 8 +- .../patch/agent/cell/PatchCellFactory.java | 8 +- .../agent/module/PatchModuleApoptosis.java | 24 +- .../module/PatchModuleProliferation.java | 15 +- src/arcade/patch/parameter.patch.xml | 4 +- src/arcade/patch/sim/PatchSimulationHex.java | 3 + src/arcade/patch/sim/PatchSimulationRect.java | 3 + src/arcade/patch/util/PatchEnums.java | 37 ++ .../patch/agent/cell/PatchCellTest.java | 2 +- 11 files changed, 263 insertions(+), 178 deletions(-) diff --git a/src/arcade/patch/agent/action/PatchActionTreat.java b/src/arcade/patch/agent/action/PatchActionTreat.java index ea0dfc03e..a3a348e21 100644 --- a/src/arcade/patch/agent/action/PatchActionTreat.java +++ b/src/arcade/patch/agent/action/PatchActionTreat.java @@ -1,7 +1,11 @@ package arcade.patch.agent.action; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; import sim.engine.Schedule; import sim.engine.SimState; import sim.util.Bag; @@ -31,13 +35,14 @@ import arcade.patch.env.location.PatchLocationContainer; import arcade.patch.sim.PatchSeries; import arcade.patch.sim.PatchSimulation; +import arcade.patch.util.PatchEnums.Immune; import arcade.patch.util.PatchEnums.Ordering; /** - * Implementation of {@link Action} for inserting T cell agents. + * Implementation of {@link Action} for inserting T-cell agents. * *

The action is stepped once after {@code TIME_DELAY}. The {@code TreatAction} will add CAR - * T-cell agents of specified dose and ratio next to source points or vasculature. + * T-cell agents of specified dose next to source points or vasculature. */ public class PatchActionTreat implements Action { @@ -47,13 +52,10 @@ public class PatchActionTreat implements Action { /** Total number of CAR T-cells to treat with. */ private final int dose; - /** List of fraction of each population to treat with. CD4 to CD8 ratio. */ - private final double treatFrac; - /** Maximum damage value at which T-cells can spawn next to in source or pattern source. */ - private double maxDamage; + private final double maxDamage; - /** Minimum radius value at which T- cells can spawn next to in graph source. */ + /** Minimum radius value at which T-cells can spawn next to in graph source. */ private final double minDamageRadius; /** Number of agent positions per lattice site. */ @@ -69,7 +71,7 @@ public class PatchActionTreat implements Action { MiniBox parameters; /** Maximum confluency of cells in any location. */ - final int maxConfluency; + int maxConfluency; /** * Creates an {@code Action} to add agents after a delay. @@ -80,21 +82,17 @@ public class PatchActionTreat implements Action { public PatchActionTreat(Series series, MiniBox parameters) { this.delay = parameters.getInt("TIME_DELAY"); this.dose = parameters.getInt("DOSE"); - this.treatFrac = parameters.getDouble("RATIO"); this.maxDamage = parameters.getDouble("MAX_DAMAGE_SEED"); this.minDamageRadius = parameters.getDouble("MIN_RADIUS_SEED"); - this.maxConfluency = 54; this.parameters = parameters; - this.coord = ((PatchSeries) series).patch.get("GEOMETRY").equalsIgnoreCase("HEX") ? "Hex" : "Rect"; if (coord.equals("Hex")) { - latPositions = 9; - } - if (coord.equals("Rect")) { - latPositions = 16; + this.latPositions = 9; + } else { + this.latPositions = 16; } populations = new ArrayList<>(); @@ -116,20 +114,11 @@ public void register(Simulation sim, String population) { * @param simstate the MASON simulation state */ public void step(SimState simstate) { - PatchSimulation sim = (PatchSimulation) simstate; String type = "null"; PatchGrid grid = (PatchGrid) sim.getGrid(); PatchComponentSites comp = (PatchComponentSites) sim.getComponent("SITES"); - ArrayList locs = sim.getLocations(); - - ArrayList siteLocs0 = new ArrayList(); - ArrayList siteLocs1 = new ArrayList(); - ArrayList siteLocs2 = new ArrayList(); - ArrayList siteLocs3 = new ArrayList(); - ArrayList siteLocs = new ArrayList(); - // Determine type of sites component implemented. if (comp instanceof PatchComponentSitesSource) { type = "source"; @@ -139,128 +128,165 @@ public void step(SimState simstate) { type = "graph"; } - // Find sites without specified level of damage based on component type. - switch (type) { - case "source": - case "pattern": - double[][][] damage; - boolean[][][] sitesLat; - - if (type.equals("source")) { - damage = ((PatchComponentSitesSource) comp).getDamage(); - sitesLat = ((PatchComponentSitesSource) comp).getSources(); - } else { - damage = ((PatchComponentSitesPattern) comp).getDamage(); - sitesLat = ((PatchComponentSitesPattern) comp).getPatterns(); - } + Set immuneCells = + Arrays.stream(Immune.values()).map(Enum::name).collect(Collectors.toSet()); - // Iterate through list of locations and remove locations not next to a site. - for (LocationContainer l : locs) { - PatchLocationContainer contain = (PatchLocationContainer) l; - PatchLocation loc = - (PatchLocation) - contain.convert( - sim.locationFactory, - sim.cellFactory.createCellForPopulation( - 0, populations.get(0).getInt("CODE"))); - CoordinateXYZ coordinate = (CoordinateXYZ) loc.getSubcoordinate(); - int z = coordinate.z; - if (sitesLat[z][coordinate.x][coordinate.y] - && damage[z][coordinate.x][coordinate.y] <= this.maxDamage) { - addLocationsIntoList(grid, loc, siteLocs0, siteLocs1, siteLocs2, siteLocs3); - } - } - break; + for (MiniBox population : populations) { + String className = population.get("CLASS").toUpperCase(); - case "graph": - Graph graph = ((PatchComponentSitesGraph) comp).getGraph(); - Bag allEdges = new Bag(graph.getAllEdges()); - PatchComponentSitesGraph graphSites = (PatchComponentSitesGraph) comp; - - for (Object edgeObj : allEdges) { - SiteEdge edge = (SiteEdge) edgeObj; - Bag allEdgeLocs = new Bag(); - if (Objects.equals(coord, "Hex")) { - allEdgeLocs.add( - ((PatchComponentSitesGraphTri) graphSites) - .getSpan(edge.getFrom(), edge.getTo())); - } else { - allEdgeLocs.add( - ((PatchComponentSitesGraphRect) graphSites) - .getSpan(edge.getFrom(), edge.getTo())); - } + if (!immuneCells.contains(className)) { + throw new IllegalArgumentException( + "Population " + + population.get("CLASS") + + " is not an immune cell and cannot be treated."); + } + + maxConfluency = population.getInt("MAX_DENSITY"); + + int pop = population.getInt("CODE"); + + ArrayList locs = sim.getLocations(); + ArrayList siteLocs = new ArrayList(); + + // Find sites without specified level of damage based on component type. + findLocations(comp, type, locs, siteLocs, sim); + Utilities.shuffleList(siteLocs, sim.random); + // sort locations in descending order from highest to lowest density + siteLocs.sort(Comparator.comparingInt(l -> -computeDensity(grid, l))); + insert(siteLocs, simstate, pop); + } + } + + /** + * Helper method to find possible locations to insert T-cells. + * + * @param comp the component + * @param type the type of component (source, pattern, or graph) + * @param locs the locations to check + * @param siteLocs the locations that meet the criteria + * @param sim the simulation instance + * @throws IllegalArgumentException if the component type is invalid + */ + private void findLocations( + PatchComponentSites comp, + String type, + ArrayList locs, + ArrayList siteLocs, + PatchSimulation sim) { + if (type.equals("graph")) { + findGraphSites(comp, locs, siteLocs); + } else if (type.equals("source") || type.equals("pattern")) { + double[][][] damage; + boolean[][][] sitesLat; + + if (type.equals("source")) { + damage = ((PatchComponentSitesSource) comp).getDamage(); + sitesLat = ((PatchComponentSitesSource) comp).getSources(); + } else { + damage = ((PatchComponentSitesPattern) comp).getDamage(); + sitesLat = ((PatchComponentSitesPattern) comp).getPatterns(); + } + pruneSite(locs, sim, damage, sitesLat, siteLocs); + } else { + throw new IllegalArgumentException( + "Invalid component type: " + + type + + ". Must be of type source, pattern, or graph."); + } + } + + /** + * Helper method to check if radius is wide enough for T-cells to pass through. + * + * @param comp the component + * @param locs the locations to check + * @param siteLocs the locations that meet the criteria + */ + private void findGraphSites( + PatchComponentSites comp, + ArrayList locs, + ArrayList siteLocs) { + Graph graph = ((PatchComponentSitesGraph) comp).getGraph(); + Bag allEdges = new Bag(graph.getAllEdges()); + PatchComponentSitesGraph graphSites = (PatchComponentSitesGraph) comp; + + Set coordinateSet = + locs.stream() + .map(container -> ((PatchLocationContainer) container).coordinate) + .collect(Collectors.toSet()); + + for (Object edgeObj : allEdges) { + SiteEdge edge = (SiteEdge) edgeObj; + Bag allEdgeLocs = new Bag(); + if (Objects.equals(coord, "Hex")) { + allEdgeLocs.add( + ((PatchComponentSitesGraphTri) graphSites) + .getSpan(edge.getFrom(), edge.getTo())); + } else { + allEdgeLocs.add( + ((PatchComponentSitesGraphRect) graphSites) + .getSpan(edge.getFrom(), edge.getTo())); + } - for (Object locObj : allEdgeLocs) { - Location loc = (Location) locObj; - if (locs.contains(loc)) { - if (edge.getRadius() >= minDamageRadius) { - addLocationsIntoList( - grid, loc, siteLocs0, siteLocs1, siteLocs2, siteLocs3); - } + for (Object locObj : allEdgeLocs) { + Location loc = (Location) locObj; + if (coordinateSet.contains(((PatchLocation) loc).getCoordinate())) { + if (edge.getRadius() >= minDamageRadius) { + for (int p = 0; p < latPositions; p++) { + siteLocs.add(loc); } } } - break; - - default: - throw new IllegalArgumentException( - "Invalid component type: " - + type - + ". Must be of type source, pattern, or graph."); + } } + } - Utilities.shuffleList(siteLocs3, sim.random); - Utilities.shuffleList(siteLocs2, sim.random); - Utilities.shuffleList(siteLocs1, sim.random); - Utilities.shuffleList(siteLocs0, sim.random); - siteLocs.addAll(siteLocs3); - siteLocs.addAll(siteLocs2); - siteLocs.addAll(siteLocs1); - siteLocs.addAll(siteLocs0); - insert(siteLocs, simstate); + /** + * Helper method to remove locations that are not next to a site or have too much damage for + * T-cells to pass through. + * + * @param locs the locations to check + * @param sim the simuation instance + * @param damage the damage array for sites + * @param sitesLat the lattice array for sites + * @param siteLocs the locations that meet the criteria + */ + public void pruneSite( + ArrayList locs, + PatchSimulation sim, + double[][][] damage, + boolean[][][] sitesLat, + ArrayList siteLocs) { + for (LocationContainer l : locs) { + PatchLocationContainer contain = (PatchLocationContainer) l; + PatchLocation loc = + (PatchLocation) + contain.convert( + sim.locationFactory, + sim.cellFactory.createCellForPopulation( + 0, populations.get(0).getInt("CODE"))); + CoordinateXYZ coordinate = (CoordinateXYZ) loc.getSubcoordinate(); + int z = coordinate.z; + if (sitesLat[z][coordinate.x][coordinate.y] + && damage[z][coordinate.x][coordinate.y] <= this.maxDamage) { + for (int p = 0; p < latPositions; p++) { + siteLocs.add(loc); + } + } + } } /** - * Helper method to sort locations into lists. + * Helper method to sort locations. * * @param grid the simulation grid - * @param loc the current location being looked at - * @param siteLocs0 the list of locations with 0 agents - * @param siteLocs1 the list of locations with 1 agent - * @param siteLocs2 the list of locations with 2 agents - * @param siteLocs3 the list of locations with 3 agents + * @param loc the current location being looked + * @return the density of agents at the location */ - private void addLocationsIntoList( - PatchGrid grid, - Location loc, - ArrayList siteLocs0, - ArrayList siteLocs1, - ArrayList siteLocs2, - ArrayList siteLocs3) { + private int computeDensity(PatchGrid grid, Location loc) { Bag bag = new Bag(grid.getObjectsAtLocation(loc)); int numAgents = bag.numObjs; - - if (numAgents == 0) { - for (int p = 0; p < latPositions; p++) { - siteLocs0.add(loc); - } - } else if (numAgents == 1) { - for (int p = 0; p < latPositions; p++) { - siteLocs1.add(loc); - } - } else if (numAgents == 2) { - for (int p = 0; p < latPositions; p++) { - siteLocs2.add(loc); - } - } else { - for (int p = 0; p < latPositions; p++) { - siteLocs3.add(loc); - } - } - // Remove break statement if more than one per hex can appear - // with break statement, each location can only be added to list once - // without it, places with more vasc sites get added more times to list - // break; + return numAgents; } /** @@ -268,51 +294,34 @@ private void addLocationsIntoList( * * @param coordinates the locations to insert the cells * @param simstate the simulation state + * @param pop the population code for the cells */ - private void insert(ArrayList coordinates, SimState simstate) { + private void insert(ArrayList coordinates, SimState simstate, int pop) { PatchSimulation sim = (PatchSimulation) simstate; PatchGrid grid = (PatchGrid) sim.getGrid(); Utilities.shuffleList(coordinates, sim.random); - int cd4Code = 0; - int cd8Code = 0; - - for (MiniBox population : populations) { - String className = population.get("CLASS"); - if (className.equals("cart_cd4")) { - cd4Code = population.getInt("CODE"); - } - if (className.equals("cart_cd8")) { - cd8Code = population.getInt("CODE"); - } - } - for (int i = 0; i < dose; i++) { - int id = sim.getID(); - int pop = cd4Code; - - if (sim.random.nextDouble() > treatFrac) { - pop = cd8Code; - } - PatchLocation loc = ((PatchLocation) coordinates.remove(0)); - Coordinate coordinate = loc.getCoordinate(); while (!coordinates.isEmpty() && !checkLocationSpace(loc, grid)) { - loc = (PatchLocation) coordinates.remove(0); + loc = ((PatchLocation) coordinates.remove(0)); } if (coordinates.isEmpty()) { break; } + Coordinate coordinate = loc.getCoordinate(); PatchLocationContainer locationContainer = new PatchLocationContainer(id, coordinate); PatchCellContainer cellContainer = sim.cellFactory.createCellForPopulation(id, pop); + Location location = locationContainer.convert(sim.locationFactory, cellContainer); PatchCell cell = (PatchCell) cellContainer.convert(sim.cellFactory, location, sim.random); + grid.addObject(cell, location); cell.schedule(sim.getSchedule()); } @@ -354,7 +363,7 @@ protected boolean checkLocationSpace(Location loc, PatchGrid grid) { if (cell instanceof PatchCellCART) { totalVol = PatchCell.calculateTotalVolume(bag) - + parameters.getDouble("T_CELL_VOL_AVG"); + + cell.getVolume(); currentHeight = totalVol / locArea; } if (cell instanceof PatchCellTissue) { diff --git a/src/arcade/patch/agent/cell/PatchCellCART.java b/src/arcade/patch/agent/cell/PatchCellCART.java index 801704594..f6cf02411 100644 --- a/src/arcade/patch/agent/cell/PatchCellCART.java +++ b/src/arcade/patch/agent/cell/PatchCellCART.java @@ -58,16 +58,16 @@ public abstract class PatchCellCART extends PatchCell { protected boolean activated; /** number of current PDL-1 receptors on CART cell. */ - protected int selfReceptors; + public int selfReceptors; /** initial number of PDL-1 receptors on CART cell. */ protected int selfReceptorsStart; /** number of bound CAR antigens. */ - protected int boundCARAntigensCount; + public int boundCARAntigensCount; /** number of bound PDL-1 antigens. */ - protected int boundSelfAntigensCount; + public int boundSelfAntigensCount; /** number of neighbors that T cell is able to search through. */ protected final double searchAbility; @@ -162,8 +162,8 @@ public PatchCellCART( // initialized non-loaded parameters boundCARAntigensCount = 0; boundSelfAntigensCount = 0; - lastActiveTicker = 0; - activated = true; + // lastActiveTicker = 0; + activated = false; boundTarget = null; // Set loaded parameters. @@ -420,4 +420,14 @@ public void unbind() { super.setBindingFlag(AntigenFlag.UNBOUND); this.boundTarget = null; } + + /** + * Sets the cell activation status. + * + * @param activated the activation status to set + */ + public void setActivationStatus(boolean activated) { + this.activated = activated; + } + } diff --git a/src/arcade/patch/agent/cell/PatchCellContainer.java b/src/arcade/patch/agent/cell/PatchCellContainer.java index 5b9c782a9..e39463f45 100644 --- a/src/arcade/patch/agent/cell/PatchCellContainer.java +++ b/src/arcade/patch/agent/cell/PatchCellContainer.java @@ -122,16 +122,16 @@ public Cell convert( return new PatchCellCARTCD4(this, location, parameters, links); case "combined": return new PatchCellCARTCombined(this, location, parameters, links); - case "inducible_cart": + case "inducible_synnotch": return new PatchCellCARTCombinedInducible( this, location, parameters, links, LogicalCARs.INDUCIBLE_SYNNOTCH); - case "inhibitory_cart": + case "inhibitory_inhibitory_receptor": return new PatchCellCARTCombinedInhibitory( this, location, parameters, links, LogicalCARs.INHIBITORY_RECEPTOR); - case "inducible_cart_separate": + case "inducible_inflammation": return new PatchCellCARTCombinedInducible( this, location, parameters, links, LogicalCARs.INDUCIBLE_INFLAMMATION); - case "inhibitory_cart_separate": + case "inhibitory_inflammation": return new PatchCellCARTCombinedInhibitory( this, location, parameters, links, LogicalCARs.INHIBITORY_INFLAMMATION); case "random": diff --git a/src/arcade/patch/agent/cell/PatchCellFactory.java b/src/arcade/patch/agent/cell/PatchCellFactory.java index 0492e0801..27d83945b 100644 --- a/src/arcade/patch/agent/cell/PatchCellFactory.java +++ b/src/arcade/patch/agent/cell/PatchCellFactory.java @@ -13,6 +13,9 @@ import arcade.core.util.MiniBox; import arcade.core.util.Parameters; import arcade.patch.sim.PatchSeries; +import arcade.patch.util.PatchEnums.Domain; +import arcade.patch.util.PatchEnums.State; + import static arcade.core.util.MiniBox.TAG_SEPARATOR; import static arcade.patch.util.PatchEnums.Domain; import static arcade.patch.util.PatchEnums.State; @@ -153,7 +156,10 @@ public PatchCellContainer createCellForPopulation(int id, int pop) { MiniBox population = popToParameters.get(pop); Parameters parameters = new Parameters(population, null, random); - double compression = parameters.getDouble("COMPRESSION_TOLERANCE"); + double compression = + parameters.getDouble("COMPRESSION_TOLERANCE") >= 0 + ? parameters.getDouble("COMPRESSION_TOLERANCE") + : Double.MAX_VALUE; double volume = parameters.getDouble("CELL_VOLUME"); double height = parameters.getDouble("CELL_HEIGHT"); diff --git a/src/arcade/patch/agent/module/PatchModuleApoptosis.java b/src/arcade/patch/agent/module/PatchModuleApoptosis.java index 34518d0c8..3c46bf578 100644 --- a/src/arcade/patch/agent/module/PatchModuleApoptosis.java +++ b/src/arcade/patch/agent/module/PatchModuleApoptosis.java @@ -8,6 +8,7 @@ import arcade.core.sim.Simulation; import arcade.core.util.Parameters; import arcade.patch.agent.cell.PatchCell; +import arcade.patch.agent.cell.PatchCellCART; import arcade.patch.env.grid.PatchGrid; import static arcade.patch.util.PatchEnums.State; @@ -47,17 +48,20 @@ public PatchModuleApoptosis(PatchCell cell) { @Override public void step(MersenneTwisterFast random, Simulation sim) { if (ticker > deathDuration) { - // Induce one neighboring quiescent cell to proliferate. - ArrayList neighborhood = location.getNeighbors(); - neighborhood.add(location); - Bag bag = ((PatchGrid) sim.getGrid()).getObjectsAtLocations(neighborhood); + // CART cells do not induce neighboring tissue cells to proliferate. + if (!(cell instanceof PatchCellCART)) { + // Induce one neighboring quiescent cell to proliferate. + ArrayList neighborhood = location.getNeighbors(); + neighborhood.add(location); + Bag bag = ((PatchGrid) sim.getGrid()).getObjectsAtLocations(neighborhood); - bag.shuffle(random); - for (Object obj : bag) { - Cell neighbor = (Cell) obj; - if (neighbor.getState() == State.QUIESCENT) { - neighbor.setState(State.PROLIFERATIVE); - break; + bag.shuffle(random); + for (Object obj : bag) { + Cell neighbor = (Cell) obj; + if (neighbor.getState() == State.QUIESCENT) { + neighbor.setState(State.PROLIFERATIVE); + break; + } } } diff --git a/src/arcade/patch/agent/module/PatchModuleProliferation.java b/src/arcade/patch/agent/module/PatchModuleProliferation.java index e5134bf8b..a865739a3 100644 --- a/src/arcade/patch/agent/module/PatchModuleProliferation.java +++ b/src/arcade/patch/agent/module/PatchModuleProliferation.java @@ -12,6 +12,9 @@ import arcade.patch.agent.process.PatchProcess; import arcade.patch.env.grid.PatchGrid; import arcade.patch.env.location.PatchLocation; +import arcade.patch.util.PatchEnums.Domain; +import arcade.patch.util.PatchEnums.State; + import static arcade.patch.util.PatchEnums.Domain; import static arcade.patch.util.PatchEnums.State; @@ -59,7 +62,7 @@ public PatchModuleProliferation(PatchCell cell) { duration = 0; // Load parameters. Parameters parameters = cell.getParameters(); - synthesisDuration = parameters.getInt("proliferation/SYNTHESIS_DURATION"); + synthesisDuration = parameters.getInt("SYNTHESIS_DURATION"); } @Override @@ -106,6 +109,16 @@ public void step(MersenneTwisterFast random, Simulation sim) { newLocation, random, newParameters); + if (cell instanceof PatchCellCART) { + ((PatchCellCART) newCell) + .setActivationStatus(((PatchCellCART) cell).getActivationStatus()); + ((PatchCellCART) newCell).boundSelfAntigensCount = + ((PatchCellCART) cell).boundSelfAntigensCount; + ((PatchCellCART) newCell).selfReceptors = + ((PatchCellCART) cell).selfReceptors; + ((PatchCellCART) newCell).boundCARAntigensCount = + ((PatchCellCART) cell).boundCARAntigensCount; + } sim.getGrid().addObject(newCell, newLocation); newCell.schedule(sim.getSchedule()); diff --git a/src/arcade/patch/parameter.patch.xml b/src/arcade/patch/parameter.patch.xml index a08b20e52..f7191127a 100644 --- a/src/arcade/patch/parameter.patch.xml +++ b/src/arcade/patch/parameter.patch.xml @@ -25,6 +25,7 @@ + @@ -54,8 +55,7 @@ - - + diff --git a/src/arcade/patch/sim/PatchSimulationHex.java b/src/arcade/patch/sim/PatchSimulationHex.java index fad2226ee..237e7b9fc 100644 --- a/src/arcade/patch/sim/PatchSimulationHex.java +++ b/src/arcade/patch/sim/PatchSimulationHex.java @@ -8,6 +8,7 @@ import arcade.patch.agent.action.PatchActionInsert; import arcade.patch.agent.action.PatchActionRemove; import arcade.patch.agent.action.PatchActionReplace; +import arcade.patch.agent.action.PatchActionTreat; import arcade.patch.agent.cell.PatchCellFactory; import arcade.patch.env.component.PatchComponentCycle; import arcade.patch.env.component.PatchComponentDegrade; @@ -61,6 +62,8 @@ public Action makeAction(String actionClass, MiniBox parameters) { return new PatchActionConvert(series, parameters); case "replace": return new PatchActionReplace(series, parameters); + case "treat": + return new PatchActionTreat(series, parameters); default: return null; } diff --git a/src/arcade/patch/sim/PatchSimulationRect.java b/src/arcade/patch/sim/PatchSimulationRect.java index 7d9b76188..7e516a473 100644 --- a/src/arcade/patch/sim/PatchSimulationRect.java +++ b/src/arcade/patch/sim/PatchSimulationRect.java @@ -8,6 +8,7 @@ import arcade.patch.agent.action.PatchActionInsert; import arcade.patch.agent.action.PatchActionRemove; import arcade.patch.agent.action.PatchActionReplace; +import arcade.patch.agent.action.PatchActionTreat; import arcade.patch.agent.cell.PatchCellFactory; import arcade.patch.env.component.PatchComponentCycle; import arcade.patch.env.component.PatchComponentDegrade; @@ -61,6 +62,8 @@ public Action makeAction(String actionClass, MiniBox parameters) { return new PatchActionConvert(series, parameters); case "replace": return new PatchActionReplace(series, parameters); + case "treat": + return new PatchActionTreat(series, parameters); default: return null; } diff --git a/src/arcade/patch/util/PatchEnums.java b/src/arcade/patch/util/PatchEnums.java index 5e8b581d5..5514bc795 100644 --- a/src/arcade/patch/util/PatchEnums.java +++ b/src/arcade/patch/util/PatchEnums.java @@ -222,6 +222,43 @@ public static LogicalCARs random(MersenneTwisterFast rng) { } } + /** Cell types for immune cell classification. */ + public enum Immune { + /** Code for cd4 T cell. */ + CART_CD4, + + /** Code for cd8 T cell. */ + CART_CD8, + + /** Code for macrophage cell. */ + MACROPHAGE, + + /** Code for killer cd8 cell. */ + KILLER, + + /** Code for inducible synNotch. */ + INDUCIBLE_SYNNOTCH, + + /** Code for inducible inflammation. */ + INDUCIBLE_INFLAMMATION, + + /** Code for inhibitory receptor. */ + INHIBITORY_RECEPTOR, + + /** Code for inhibitory inflammation. */ + INHIBITORY_INFLAMMATION; + + /** + * Randomly selects a {@code Immune} cell type. + * + * @param rng the random number generator + * @return a random {@code Immune} cell type + */ + public static Immune random(MersenneTwisterFast rng) { + return values()[rng.nextInt(values().length - 1) + 1]; + } + } + /** Operation category codes for patch simulations. */ public enum Category implements OperationCategory { /** Code for undefined category. */ diff --git a/test/arcade/patch/agent/cell/PatchCellTest.java b/test/arcade/patch/agent/cell/PatchCellTest.java index 63ccb0367..5c68f15ff 100644 --- a/test/arcade/patch/agent/cell/PatchCellTest.java +++ b/test/arcade/patch/agent/cell/PatchCellTest.java @@ -251,7 +251,7 @@ public void setState_proliferation_createsCell() { Schedule scheduleMock = mock(Schedule.class); doReturn(0.0).when(parametersMock).getDouble(any(String.class)); doReturn(0).when(parametersMock).getInt(any(String.class)); - doReturn(1).when(parametersMock).getInt("proliferation/SYNTHESIS_DURATION"); + doReturn(1).when(parametersMock).getInt("SYNTHESIS_DURATION"); doReturn(cellID + 1).when(simMock).getID(); doReturn(scheduleMock).when(simMock).getSchedule(); doReturn(null).when(scheduleMock).scheduleRepeating(anyInt(), anyInt(), any()); From 0f44fcdf95d078126aefd1267b10eaab81a1b441 Mon Sep 17 00:00:00 2001 From: allison-li-1016 Date: Fri, 18 Jul 2025 02:45:11 +0000 Subject: [PATCH 23/28] debugging logical circuits --- src/arcade/patch/agent/action/PatchActionTreat.java | 7 +++---- src/arcade/patch/agent/cell/PatchCellCART.java | 1 - .../patch/agent/cell/PatchCellCARTCombinedInducible.java | 4 ++++ src/arcade/patch/agent/cell/PatchCellContainer.java | 2 +- src/arcade/patch/agent/cell/PatchCellFactory.java | 1 - .../patch/agent/module/PatchModuleProliferation.java | 1 - src/arcade/patch/parameter.patch.xml | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/arcade/patch/agent/action/PatchActionTreat.java b/src/arcade/patch/agent/action/PatchActionTreat.java index a3a348e21..9e9d96271 100644 --- a/src/arcade/patch/agent/action/PatchActionTreat.java +++ b/src/arcade/patch/agent/action/PatchActionTreat.java @@ -89,7 +89,7 @@ public PatchActionTreat(Series series, MiniBox parameters) { ((PatchSeries) series).patch.get("GEOMETRY").equalsIgnoreCase("HEX") ? "Hex" : "Rect"; - if (coord.equals("Hex")) { + if (this.coord.equals("Hex")) { this.latPositions = 9; } else { this.latPositions = 16; @@ -142,6 +142,7 @@ public void step(SimState simstate) { } maxConfluency = population.getInt("MAX_DENSITY"); + maxConfluency = (maxConfluency >= 0 ? maxConfluency : Integer.MAX_VALUE); int pop = population.getInt("CODE"); @@ -361,9 +362,7 @@ protected boolean checkLocationSpace(Location loc, PatchGrid grid) { for (Object cellObj : bag) { PatchCell cell = (PatchCell) cellObj; if (cell instanceof PatchCellCART) { - totalVol = - PatchCell.calculateTotalVolume(bag) - + cell.getVolume(); + totalVol = PatchCell.calculateTotalVolume(bag) + cell.getVolume(); currentHeight = totalVol / locArea; } if (cell instanceof PatchCellTissue) { diff --git a/src/arcade/patch/agent/cell/PatchCellCART.java b/src/arcade/patch/agent/cell/PatchCellCART.java index f6cf02411..e98f571be 100644 --- a/src/arcade/patch/agent/cell/PatchCellCART.java +++ b/src/arcade/patch/agent/cell/PatchCellCART.java @@ -429,5 +429,4 @@ public void unbind() { public void setActivationStatus(boolean activated) { this.activated = activated; } - } diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java index 0d9e79196..8744e26be 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java @@ -229,5 +229,9 @@ protected void inflammationStep(SimState simstate) { } } } + // Step the module for the cell state. + if (super.module != null) { + super.module.step(simstate.random, sim); + } } } diff --git a/src/arcade/patch/agent/cell/PatchCellContainer.java b/src/arcade/patch/agent/cell/PatchCellContainer.java index e39463f45..aef6b8606 100644 --- a/src/arcade/patch/agent/cell/PatchCellContainer.java +++ b/src/arcade/patch/agent/cell/PatchCellContainer.java @@ -125,7 +125,7 @@ public Cell convert( case "inducible_synnotch": return new PatchCellCARTCombinedInducible( this, location, parameters, links, LogicalCARs.INDUCIBLE_SYNNOTCH); - case "inhibitory_inhibitory_receptor": + case "inhibitory_receptor": return new PatchCellCARTCombinedInhibitory( this, location, parameters, links, LogicalCARs.INHIBITORY_RECEPTOR); case "inducible_inflammation": diff --git a/src/arcade/patch/agent/cell/PatchCellFactory.java b/src/arcade/patch/agent/cell/PatchCellFactory.java index 27d83945b..e2930df0f 100644 --- a/src/arcade/patch/agent/cell/PatchCellFactory.java +++ b/src/arcade/patch/agent/cell/PatchCellFactory.java @@ -15,7 +15,6 @@ import arcade.patch.sim.PatchSeries; import arcade.patch.util.PatchEnums.Domain; import arcade.patch.util.PatchEnums.State; - import static arcade.core.util.MiniBox.TAG_SEPARATOR; import static arcade.patch.util.PatchEnums.Domain; import static arcade.patch.util.PatchEnums.State; diff --git a/src/arcade/patch/agent/module/PatchModuleProliferation.java b/src/arcade/patch/agent/module/PatchModuleProliferation.java index a865739a3..29f1251bc 100644 --- a/src/arcade/patch/agent/module/PatchModuleProliferation.java +++ b/src/arcade/patch/agent/module/PatchModuleProliferation.java @@ -14,7 +14,6 @@ import arcade.patch.env.location.PatchLocation; import arcade.patch.util.PatchEnums.Domain; import arcade.patch.util.PatchEnums.State; - import static arcade.patch.util.PatchEnums.Domain; import static arcade.patch.util.PatchEnums.State; diff --git a/src/arcade/patch/parameter.patch.xml b/src/arcade/patch/parameter.patch.xml index f7191127a..0a8cdaf53 100644 --- a/src/arcade/patch/parameter.patch.xml +++ b/src/arcade/patch/parameter.patch.xml @@ -55,7 +55,7 @@ - + From 165090b8f84c1facf759939e275372a5664a3681 Mon Sep 17 00:00:00 2001 From: allison-li-1016 Date: Tue, 22 Jul 2025 18:25:51 +0000 Subject: [PATCH 24/28] connecting synnotch antigens to actual tissue cells --- src/arcade/patch/agent/cell/PatchCellTissue.java | 1 + src/arcade/patch/parameter.patch.xml | 2 +- src/arcade/patch/util/PatchEnums.java | 3 +++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/arcade/patch/agent/cell/PatchCellTissue.java b/src/arcade/patch/agent/cell/PatchCellTissue.java index d602d0f4f..81e5bfbc2 100644 --- a/src/arcade/patch/agent/cell/PatchCellTissue.java +++ b/src/arcade/patch/agent/cell/PatchCellTissue.java @@ -69,6 +69,7 @@ public PatchCellTissue( super(container, location, parameters, links); carAntigens = parameters.getInt("CAR_ANTIGENS"); selfTargets = parameters.getInt("SELF_TARGETS"); + synNotchAntigens = parameters.getInt("SYNNOTCH_ANTIGENS"); } @Override diff --git a/src/arcade/patch/parameter.patch.xml b/src/arcade/patch/parameter.patch.xml index 0a8cdaf53..a69664f28 100644 --- a/src/arcade/patch/parameter.patch.xml +++ b/src/arcade/patch/parameter.patch.xml @@ -51,7 +51,7 @@ - + diff --git a/src/arcade/patch/util/PatchEnums.java b/src/arcade/patch/util/PatchEnums.java index 5514bc795..61a294d5e 100644 --- a/src/arcade/patch/util/PatchEnums.java +++ b/src/arcade/patch/util/PatchEnums.java @@ -230,6 +230,9 @@ public enum Immune { /** Code for cd8 T cell. */ CART_CD8, + /** Code for combined cd4/cd8 T cell. */ + COMBINED, + /** Code for macrophage cell. */ MACROPHAGE, From 872de39200e0de57d55c90e08dfbafc1ba97064a Mon Sep 17 00:00:00 2001 From: allison-li-1016 Date: Tue, 23 Sep 2025 20:36:50 +0000 Subject: [PATCH 25/28] updated version of model --- src/arcade/patch/PatchARCADE.java | 1 + .../patch/agent/action/PatchActionTreat.java | 55 +++++++++++++------ .../patch/agent/cell/PatchCellCART.java | 23 +++++++- .../PatchCellCARTCombinedCombinatorial.java | 2 +- .../cell/PatchCellCARTCombinedInducible.java | 3 +- .../cell/PatchCellCARTCombinedInhibitory.java | 5 +- .../agent/module/PatchModuleCytotoxicity.java | 15 +++++ .../module/PatchModuleProliferation.java | 9 ++- src/arcade/patch/command.patch.xml | 1 + .../env/component/PatchComponentDegrade.java | 3 + .../component/PatchComponentSitesGraph.java | 4 +- .../env/location/PatchLocationContainer.java | 1 - src/arcade/patch/parameter.patch.xml | 4 +- src/arcade/patch/sim/PatchSimulation.java | 25 +++++++++ .../patch/sim/output/PatchOutputSaver.java | 24 ++++++++ 15 files changed, 142 insertions(+), 33 deletions(-) diff --git a/src/arcade/patch/PatchARCADE.java b/src/arcade/patch/PatchARCADE.java index 115823a6b..1759df94b 100644 --- a/src/arcade/patch/PatchARCADE.java +++ b/src/arcade/patch/PatchARCADE.java @@ -34,6 +34,7 @@ public OutputSaver getSaver(Series series) { PatchOutputSaver saver = new PatchOutputSaver(series); saver.saveGraph = settings.contains("SAVE_GRAPH"); saver.saveLattice = settings.contains("SAVE_LAYERS"); + saver.saveEvents = settings.contains("SAVE_EVENTS"); return saver; } } diff --git a/src/arcade/patch/agent/action/PatchActionTreat.java b/src/arcade/patch/agent/action/PatchActionTreat.java index 9e9d96271..e16a2326d 100644 --- a/src/arcade/patch/agent/action/PatchActionTreat.java +++ b/src/arcade/patch/agent/action/PatchActionTreat.java @@ -3,7 +3,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; -import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; import sim.engine.Schedule; @@ -24,8 +23,6 @@ import arcade.patch.env.component.PatchComponentSites; import arcade.patch.env.component.PatchComponentSitesGraph; import arcade.patch.env.component.PatchComponentSitesGraph.SiteEdge; -import arcade.patch.env.component.PatchComponentSitesGraphRect; -import arcade.patch.env.component.PatchComponentSitesGraphTri; import arcade.patch.env.component.PatchComponentSitesPattern; import arcade.patch.env.component.PatchComponentSitesSource; import arcade.patch.env.grid.PatchGrid; @@ -175,7 +172,7 @@ private void findLocations( ArrayList siteLocs, PatchSimulation sim) { if (type.equals("graph")) { - findGraphSites(comp, locs, siteLocs); + findGraphSites(comp, locs, siteLocs, sim); } else if (type.equals("source") || type.equals("pattern")) { double[][][] damage; boolean[][][] sitesLat; @@ -202,14 +199,16 @@ private void findLocations( * @param comp the component * @param locs the locations to check * @param siteLocs the locations that meet the criteria + * @param sim the simulation instance */ private void findGraphSites( PatchComponentSites comp, ArrayList locs, - ArrayList siteLocs) { - Graph graph = ((PatchComponentSitesGraph) comp).getGraph(); - Bag allEdges = new Bag(graph.getAllEdges()); + ArrayList siteLocs, + PatchSimulation sim) { PatchComponentSitesGraph graphSites = (PatchComponentSitesGraph) comp; + Graph graph = graphSites.getGraph(); + Bag allEdges = new Bag(graph.getAllEdges()); Set coordinateSet = locs.stream() @@ -218,19 +217,34 @@ private void findGraphSites( for (Object edgeObj : allEdges) { SiteEdge edge = (SiteEdge) edgeObj; - Bag allEdgeLocs = new Bag(); - if (Objects.equals(coord, "Hex")) { - allEdgeLocs.add( - ((PatchComponentSitesGraphTri) graphSites) - .getSpan(edge.getFrom(), edge.getTo())); - } else { - allEdgeLocs.add( - ((PatchComponentSitesGraphRect) graphSites) - .getSpan(edge.getFrom(), edge.getTo())); + ArrayList spans = new ArrayList<>(); + ArrayList spanLocs = new ArrayList<>(); + + // if (Objects.equals(coord, "Hex")) { + // spans = ( + // ((PatchComponentSitesGraphTri) graphSites) + // .getSpan(edge.getFrom(), edge.getTo())); + // for (CoordinateXYZ span : spans) { + // spanLocs.add(((PatchComponentSitesGraphTri) graphSites).getLocation(span)); + // } + // } else { + // spans = ( + // ((PatchComponentSitesGraphRect) graphSites) + // .getSpan(edge.getFrom(), edge.getTo())); + // for (CoordinateXYZ span : spans) { + // spanLocs.add(((PatchComponentSitesGraphRect) graphSites).getLocation(span)); + // } + // } + + spans = graphSites.getSpan(edge.getFrom(), edge.getTo()); + for (CoordinateXYZ span : spans) { + Location newLoc = graphSites.getLocation(span); + if (newLoc != null) { + spanLocs.add(newLoc); + } } - for (Object locObj : allEdgeLocs) { - Location loc = (Location) locObj; + for (Location loc : spanLocs) { if (coordinateSet.contains(((PatchLocation) loc).getCoordinate())) { if (edge.getRadius() >= minDamageRadius) { for (int p = 0; p < latPositions; p++) { @@ -305,6 +319,10 @@ private void insert(ArrayList coordinates, SimState simstate, int pop) for (int i = 0; i < dose; i++) { int id = sim.getID(); + if (coordinates.isEmpty()) { + break; + } + PatchLocation loc = ((PatchLocation) coordinates.remove(0)); while (!coordinates.isEmpty() && !checkLocationSpace(loc, grid)) { @@ -320,6 +338,7 @@ private void insert(ArrayList coordinates, SimState simstate, int pop) PatchCellContainer cellContainer = sim.cellFactory.createCellForPopulation(id, pop); Location location = locationContainer.convert(sim.locationFactory, cellContainer); + PatchCell cell = (PatchCell) cellContainer.convert(sim.cellFactory, location, sim.random); diff --git a/src/arcade/patch/agent/cell/PatchCellCART.java b/src/arcade/patch/agent/cell/PatchCellCART.java index e98f571be..6078610d3 100644 --- a/src/arcade/patch/agent/cell/PatchCellCART.java +++ b/src/arcade/patch/agent/cell/PatchCellCART.java @@ -99,6 +99,9 @@ public abstract class PatchCellCART extends PatchCell { /** number of CARs on T cell surface. */ protected int cars; + /** number of starting CARs on T cell surface. */ + protected int startCars; + /** simulation time since T cell was last activated. */ protected int lastActiveTicker; @@ -182,7 +185,8 @@ public PatchCellCART( selfBeta = parameters.getDouble("SELF_BETA"); contactFraction = parameters.getDouble("CONTACT_FRAC"); maxAntigenBinding = parameters.getInt("MAX_ANTIGEN_BINDING"); - cars = parameters.getInt("CARS"); + startCars = parameters.getInt("CARS"); + cars = startCars; } /** @@ -222,7 +226,8 @@ public PatchCellTissue bindTarget( double selfTargets = tissueCell.getSelfAntigens(); double probabilityCAR = - computeProbability(cARAntigens, kDCAR, cars, 5000, carAlpha, carBeta); + computeProbability( + cARAntigens, kDCAR, cars, startCars, carAlpha, carBeta); double probabilitySelf = computeProbability( selfTargets, @@ -429,4 +434,18 @@ public void unbind() { public void setActivationStatus(boolean activated) { this.activated = activated; } + + /** + * Sets the car amount. + * + * @param cars the car amount to set + */ + public void setCars(int cars) { + this.cars = cars; + } + + /** Gets the car amount. */ + public int getCars() { + return cars; + } } diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java index 203f28ede..849de45dc 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java @@ -84,7 +84,7 @@ public PatchCellCARTCombinedCombinatorial( synNotchThreshold = parameters.getDouble("SYNNOTCH_THRESHOLD") * synnotchs; basalCARGenerationRate = parameters.getDouble("K_CAR_GENERATION"); boundSynNotch = 0; - maxCars = cars; + maxCars = 50000; poissonFactory = Poisson::new; } diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java index 8744e26be..b0acfb7ac 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java @@ -64,7 +64,6 @@ public PatchCellCARTCombinedInducible( GrabBag links, LogicalCARs type) { super(container, location, parameters, links); - cars = 0; this.type = type; } @@ -97,7 +96,7 @@ protected void calculateCARS(MersenneTwisterFast random, Simulation sim) { /** Calculates the number of cars produced for synnotch circuit. * */ protected void synNotchCARCalculation() { - double n = 4.4; + double n = 8; int newCars = (int) (maxCars / (1 + Math.pow(synNotchThreshold, n) / Math.pow(boundSynNotch, n))); cars = Math.max((int) (cars - (carDegradationConstant * cars * TAU)), newCars); diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java index a3510e336..cd3984fbb 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java @@ -63,7 +63,6 @@ public PatchCellCARTCombinedInhibitory( GrabBag links, LogicalCARs type) { super(container, location, parameters, links); - cars = 0; this.type = type; } @@ -93,8 +92,8 @@ protected void calculateCARS(MersenneTwisterFast random, Simulation sim) { protected void receptorCars() { double n = 8; int removeCARs = - (int) (maxCars / (1 + Math.pow(synNotchThreshold, n) / Math.pow(boundSynNotch, n))); - cars = Math.min((int) (cars + (basalCARGenerationRate * TAU)), maxCars - removeCARs); + (int) (maxCars / (1 + Math.pow(boundSynNotch, n) / Math.pow(synNotchThreshold, n))); + cars = Math.min(cars + (int) (basalCARGenerationRate * TAU), removeCARs); } /** Calculates T-cell activation caused by inflammation circuit. * */ diff --git a/src/arcade/patch/agent/module/PatchModuleCytotoxicity.java b/src/arcade/patch/agent/module/PatchModuleCytotoxicity.java index f302193a2..f7ee3aec3 100644 --- a/src/arcade/patch/agent/module/PatchModuleCytotoxicity.java +++ b/src/arcade/patch/agent/module/PatchModuleCytotoxicity.java @@ -1,5 +1,7 @@ package arcade.patch.agent.module; +import java.util.HashMap; +import java.util.Map; import ec.util.MersenneTwisterFast; import arcade.core.sim.Simulation; import arcade.core.util.Parameters; @@ -7,6 +9,9 @@ import arcade.patch.agent.cell.PatchCellCART; import arcade.patch.agent.cell.PatchCellTissue; import arcade.patch.agent.process.PatchProcessInflammation; +import arcade.patch.sim.PatchSimulation; +import arcade.patch.util.PatchEnums.Domain; +import arcade.patch.util.PatchEnums.State; import static arcade.patch.util.PatchEnums.Domain; import static arcade.patch.util.PatchEnums.State; @@ -68,6 +73,16 @@ public void step(MersenneTwisterFast random, Simulation sim) { tissueCell.setState(State.APOPTOTIC); granzyme--; inflammation.setInternal("granzyme", granzyme); + + // Log cytotoxicity event + PatchSimulation patchSim = (PatchSimulation) sim; + Map eventData = new HashMap<>(); + eventData.put("t-cell-id", cell.getID()); + eventData.put("tissue-cell-id", target.getID()); + eventData.put("tissue-cell-type", target.getPop()); + eventData.put("type", "lysis"); + eventData.put("timestamp", (int) ((PatchSimulation) sim).getSchedule().getTime()); + patchSim.logEvent(eventData); } } diff --git a/src/arcade/patch/agent/module/PatchModuleProliferation.java b/src/arcade/patch/agent/module/PatchModuleProliferation.java index 29f1251bc..424093c4d 100644 --- a/src/arcade/patch/agent/module/PatchModuleProliferation.java +++ b/src/arcade/patch/agent/module/PatchModuleProliferation.java @@ -9,11 +9,10 @@ import arcade.core.util.Parameters; import arcade.patch.agent.cell.PatchCell; import arcade.patch.agent.cell.PatchCellCART; +import arcade.patch.agent.cell.PatchCellCARTCombinedCombinatorial; import arcade.patch.agent.process.PatchProcess; import arcade.patch.env.grid.PatchGrid; import arcade.patch.env.location.PatchLocation; -import arcade.patch.util.PatchEnums.Domain; -import arcade.patch.util.PatchEnums.State; import static arcade.patch.util.PatchEnums.Domain; import static arcade.patch.util.PatchEnums.State; @@ -117,6 +116,12 @@ public void step(MersenneTwisterFast random, Simulation sim) { ((PatchCellCART) cell).selfReceptors; ((PatchCellCART) newCell).boundCARAntigensCount = ((PatchCellCART) cell).boundCARAntigensCount; + if (cell instanceof PatchCellCARTCombinedCombinatorial) { + ((PatchCellCARTCombinedCombinatorial) newCell).boundSynNotch = + ((PatchCellCARTCombinedCombinatorial) cell).boundSynNotch; + ((PatchCellCARTCombinedCombinatorial) newCell) + .setCars(((PatchCellCARTCombinedCombinatorial) cell).getCars()); + } } sim.getGrid().addObject(newCell, newLocation); newCell.schedule(sim.getSchedule()); diff --git a/src/arcade/patch/command.patch.xml b/src/arcade/patch/command.patch.xml index 4902b6289..2fda14ff3 100644 --- a/src/arcade/patch/command.patch.xml +++ b/src/arcade/patch/command.patch.xml @@ -1,4 +1,5 @@ + diff --git a/src/arcade/patch/env/component/PatchComponentDegrade.java b/src/arcade/patch/env/component/PatchComponentDegrade.java index 35da75184..eaa2ec574 100644 --- a/src/arcade/patch/env/component/PatchComponentDegrade.java +++ b/src/arcade/patch/env/component/PatchComponentDegrade.java @@ -102,6 +102,9 @@ public void step(SimState state) { // Get agents at locations. locations.remove(null); + if (!locations.isEmpty()) { + continue; + } Bag agents = grid.getObjectsAtLocations(new ArrayList<>(locations)); // If any agents are cancerous, then degrade the wall. diff --git a/src/arcade/patch/env/component/PatchComponentSitesGraph.java b/src/arcade/patch/env/component/PatchComponentSitesGraph.java index 771147dd6..8d21fabcf 100644 --- a/src/arcade/patch/env/component/PatchComponentSitesGraph.java +++ b/src/arcade/patch/env/component/PatchComponentSitesGraph.java @@ -130,7 +130,7 @@ public Graph getGraph() { * @param to the node the edge extends to * @return the list of span coordinates */ - abstract ArrayList getSpan(SiteNode from, SiteNode to); + public abstract ArrayList getSpan(SiteNode from, SiteNode to); /** * Checks if given coordinates are within the environment to add to list. @@ -152,7 +152,7 @@ void checkSite(ArrayList s, int x, int y, int z) { * @param span the span coordinate * @return a location object */ - abstract Location getLocation(CoordinateXYZ span); + public abstract Location getLocation(CoordinateXYZ span); /** * Initializes graph for representing sites. diff --git a/src/arcade/patch/env/location/PatchLocationContainer.java b/src/arcade/patch/env/location/PatchLocationContainer.java index 26524ab76..c47d1c534 100644 --- a/src/arcade/patch/env/location/PatchLocationContainer.java +++ b/src/arcade/patch/env/location/PatchLocationContainer.java @@ -40,7 +40,6 @@ public Location convert(LocationFactory factory, CellContainer cell) { } else { location = new PatchLocationHex((CoordinateUVWZ) coordinate); } - return location; } } diff --git a/src/arcade/patch/parameter.patch.xml b/src/arcade/patch/parameter.patch.xml index e6efa3e62..730c614bd 100644 --- a/src/arcade/patch/parameter.patch.xml +++ b/src/arcade/patch/parameter.patch.xml @@ -46,14 +46,14 @@ - + - + diff --git a/src/arcade/patch/sim/PatchSimulation.java b/src/arcade/patch/sim/PatchSimulation.java index 570ff3c18..452869b7d 100644 --- a/src/arcade/patch/sim/PatchSimulation.java +++ b/src/arcade/patch/sim/PatchSimulation.java @@ -4,6 +4,8 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import java.util.List; +import java.util.Map; import java.util.Set; import com.google.gson.reflect.TypeToken; import sim.engine.Schedule; @@ -55,6 +57,9 @@ public abstract class PatchSimulation extends SimState implements Simulation { /** Cell ID tracker. */ int id; + /** List to store events throughout the simulation. */ + private final List> events; + /** Location factory instance for the simulation. */ public final PatchLocationFactory locationFactory; @@ -77,6 +82,7 @@ public PatchSimulation(long seed, Series series) { super(seed); this.series = (PatchSeries) series; this.seed = (int) seed - Series.SEED_OFFSET; + this.events = new ArrayList<>(); this.locationFactory = makeLocationFactory(); this.cellFactory = makeCellFactory(); @@ -103,6 +109,25 @@ public final int getID() { return ++id; } + /** + * Log an event to the simulation's event list. + * + * @param eventType the type of event + * @param eventData the event data + */ + public void logEvent(Map event) { + events.add(event); + } + + /** + * Get the list of events logged during the simulation. + * + * @return the list of events + */ + public List> getEvents() { + return new ArrayList<>(events); + } + @Override public final ArrayList getCells() { ArrayList cellContainers = new ArrayList<>(); diff --git a/src/arcade/patch/sim/output/PatchOutputSaver.java b/src/arcade/patch/sim/output/PatchOutputSaver.java index 0a3447d8f..aa2a02722 100644 --- a/src/arcade/patch/sim/output/PatchOutputSaver.java +++ b/src/arcade/patch/sim/output/PatchOutputSaver.java @@ -1,5 +1,7 @@ package arcade.patch.sim.output; +import java.util.List; +import java.util.Map; import com.google.gson.Gson; import arcade.core.env.component.Component; import arcade.core.sim.Series; @@ -17,6 +19,9 @@ public final class PatchOutputSaver extends OutputSaver { /** {@code true} to save lattices, {@code false} otherwise. */ public boolean saveLattice; + /** {@code true} to save events, {@code false} otherwise. */ + public boolean saveEvents; + /** * Creates an {@code PatchOutputSaver} for the series. * @@ -26,6 +31,22 @@ public PatchOutputSaver(Series series) { super(series); } + /** + * Save the collection of events to a JSON. + * + * @param tick the simulation tick + */ + public void saveEventsToFile(int tick) { + if (saveEvents) { + List> events = ((PatchSimulation) sim).getEvents(); + if (!events.isEmpty()) { + String json = gson.toJson(events); + String path = prefix + String.format("_%06d.EVENTS.json", tick); + write(path, format(json, FORMAT_ELEMENTS)); + } + } + } + @Override protected Gson makeGSON() { return PatchOutputSerializer.makeGSON(); @@ -70,5 +91,8 @@ public void save(int tick) { if (saveLattice) { saveLayers(tick); } + if (saveEvents) { + saveEventsToFile(tick); + } } } From 03556f873528cf2674f58477e266ef0b209a0cad Mon Sep 17 00:00:00 2001 From: allison-li-1016 Date: Wed, 24 Sep 2025 17:38:12 +0000 Subject: [PATCH 26/28] added cell cycle tracking --- src/arcade/patch/agent/action/PatchActionReplace.java | 3 ++- src/arcade/patch/agent/cell/PatchCellCARTCD4.java | 3 ++- src/arcade/patch/agent/cell/PatchCellCARTCD8.java | 3 ++- src/arcade/patch/agent/cell/PatchCellCARTCombined.java | 3 ++- .../patch/agent/module/PatchModuleProliferation.java | 1 - test/arcade/patch/agent/cell/PatchCellCARTCD4Test.java | 5 ++++- test/arcade/patch/agent/cell/PatchCellCARTCD8Test.java | 7 ++++++- 7 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/arcade/patch/agent/action/PatchActionReplace.java b/src/arcade/patch/agent/action/PatchActionReplace.java index 83a1c3efa..b50d54db5 100644 --- a/src/arcade/patch/agent/action/PatchActionReplace.java +++ b/src/arcade/patch/agent/action/PatchActionReplace.java @@ -138,7 +138,8 @@ public void step(SimState simstate) { oldCell.getVolume(), oldCell.getHeight(), oldCell.getCriticalVolume(), - oldCell.getCriticalHeight()); + oldCell.getCriticalHeight(), + oldCell.getCycles()); PatchCell newCell = (PatchCell) cellContainer.convert(sim.cellFactory, location, sim.random); grid.addObject(newCell, location); diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCD4.java b/src/arcade/patch/agent/cell/PatchCellCARTCD4.java index 609be4934..3090fdb36 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCD4.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCD4.java @@ -52,7 +52,8 @@ public PatchCellContainer make(int newID, CellState newState, MersenneTwisterFas volume, height, criticalVolume, - criticalHeight); + criticalHeight, + cycles); } @Override diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCD8.java b/src/arcade/patch/agent/cell/PatchCellCARTCD8.java index d7f66c9a0..6d19517b7 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCD8.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCD8.java @@ -52,7 +52,8 @@ public PatchCellContainer make(int newID, CellState newState, MersenneTwisterFas volume, height, criticalVolume, - criticalHeight); + criticalHeight, + cycles); } @Override diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombined.java b/src/arcade/patch/agent/cell/PatchCellCARTCombined.java index b5bddf37f..c30dcedb7 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombined.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombined.java @@ -52,7 +52,8 @@ public PatchCellContainer make(int newID, CellState newState, MersenneTwisterFas volume, height, criticalVolume, - criticalHeight); + criticalHeight, + cycles); } @Override diff --git a/src/arcade/patch/agent/module/PatchModuleProliferation.java b/src/arcade/patch/agent/module/PatchModuleProliferation.java index 424093c4d..ec9232d58 100644 --- a/src/arcade/patch/agent/module/PatchModuleProliferation.java +++ b/src/arcade/patch/agent/module/PatchModuleProliferation.java @@ -91,7 +91,6 @@ public void step(MersenneTwisterFast random, Simulation sim) { } } else if (cell.getVolume() >= targetVolume) { if (ticker > synthesisDuration) { - cell.addCycle(duration); // Reset current cell. cell.setState(State.UNDEFINED); diff --git a/test/arcade/patch/agent/cell/PatchCellCARTCD4Test.java b/test/arcade/patch/agent/cell/PatchCellCARTCD4Test.java index 275892652..c98739fec 100644 --- a/test/arcade/patch/agent/cell/PatchCellCARTCD4Test.java +++ b/test/arcade/patch/agent/cell/PatchCellCARTCD4Test.java @@ -5,6 +5,7 @@ import org.junit.jupiter.api.Test; import sim.engine.Schedule; import sim.engine.Steppable; +import sim.util.Bag; import ec.util.MersenneTwisterFast; import arcade.core.sim.Simulation; import arcade.core.util.MiniBox; @@ -50,6 +51,7 @@ public final void setUp() { double height = randomDoubleBetween(4, 10); double criticalVolume = randomDoubleBetween(100, 200); double criticalHeight = randomDoubleBetween(4, 10); + Bag cycles = new Bag(); State state = State.UNDEFINED; container = @@ -63,7 +65,8 @@ public final void setUp() { volume, height, criticalVolume, - criticalHeight); + criticalHeight, + cycles); doReturn(1.0).when(parametersMock).getDouble(any(String.class)); doReturn(1).when(parametersMock).getInt(any(String.class)); diff --git a/test/arcade/patch/agent/cell/PatchCellCARTCD8Test.java b/test/arcade/patch/agent/cell/PatchCellCARTCD8Test.java index a28ec9bb5..f13b88e77 100644 --- a/test/arcade/patch/agent/cell/PatchCellCARTCD8Test.java +++ b/test/arcade/patch/agent/cell/PatchCellCARTCD8Test.java @@ -5,6 +5,7 @@ import org.junit.jupiter.api.Test; import sim.engine.Schedule; import sim.engine.Steppable; +import sim.util.Bag; import ec.util.MersenneTwisterFast; import arcade.core.sim.Simulation; import arcade.core.util.MiniBox; @@ -15,7 +16,9 @@ import arcade.patch.agent.process.PatchProcessSignaling; import arcade.patch.env.location.PatchLocation; import arcade.patch.sim.PatchSimulation; +import arcade.patch.util.PatchEnums.AntigenFlag; import arcade.patch.util.PatchEnums.Domain; +import arcade.patch.util.PatchEnums.State; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; @@ -51,6 +54,7 @@ public final void setUp() throws NoSuchFieldException, IllegalAccessException { double criticalVolume = randomDoubleBetween(100, 200); double criticalHeight = randomDoubleBetween(4, 10); State state = State.UNDEFINED; + Bag cycles = new Bag(); container = new PatchCellContainer( @@ -63,7 +67,8 @@ public final void setUp() throws NoSuchFieldException, IllegalAccessException { volume, height, criticalVolume, - criticalHeight); + criticalHeight, + cycles); doReturn(0.0).when(parameters).getDouble(any(String.class)); doReturn(0).when(parameters).getInt(any(String.class)); From c24df441bdfd36c7bc60495a2b415d6ab2cb71e6 Mon Sep 17 00:00:00 2001 From: allison-li-1016 Date: Wed, 12 Nov 2025 06:31:49 +0000 Subject: [PATCH 27/28] lysis location logging, proliferative antigen tracking, matrigel non-migration option --- .../patch/agent/cell/PatchCellCART.java | 8 ++++++- .../agent/cell/PatchCellCARTCombined.java | 4 ++++ .../PatchCellCARTCombinedCombinatorial.java | 22 +++++++++++++++++++ .../cell/PatchCellCARTCombinedInducible.java | 2 +- .../cell/PatchCellCARTCombinedInhibitory.java | 2 +- .../agent/module/PatchModuleCytotoxicity.java | 3 +++ .../agent/module/PatchModuleMigration.java | 7 +++++- src/arcade/patch/parameter.patch.xml | 3 ++- 8 files changed, 46 insertions(+), 5 deletions(-) diff --git a/src/arcade/patch/agent/cell/PatchCellCART.java b/src/arcade/patch/agent/cell/PatchCellCART.java index 6078610d3..4c69ca9ae 100644 --- a/src/arcade/patch/agent/cell/PatchCellCART.java +++ b/src/arcade/patch/agent/cell/PatchCellCART.java @@ -380,8 +380,14 @@ private double calculateMichaelisMenten( int startReceptors, double alpha, double beta) { + + double correctedStartReceptors = startReceptors; + + if (startReceptors == 0) { + correctedStartReceptors = 1; + } return (targets * contactFraction / (affinity * beta + targets * contactFraction)) - * (currentReceptors / startReceptors) + * (currentReceptors / correctedStartReceptors) * alpha; } diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombined.java b/src/arcade/patch/agent/cell/PatchCellCARTCombined.java index c30dcedb7..055ed33f5 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombined.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombined.java @@ -60,6 +60,10 @@ public PatchCellContainer make(int newID, CellState newState, MersenneTwisterFas public void step(SimState simstate) { Simulation sim = (Simulation) simstate; + if (sim.getSchedule().getTime() == 2880) { + int a = 0; + } + super.age++; if (state != State.APOPTOTIC && age > apoptosisAge) { diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java index 849de45dc..3df712a2b 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java @@ -120,7 +120,17 @@ protected void checkForBinding(SimState simstate) { * @param sim the simulation instance */ protected void calculateCARS(MersenneTwisterFast random, Simulation sim) { + // T cell cannot bind if no synnotch receptors are available + if (synnotchs == 0) { + if (boundSynNotch != 0) { + boundSynNotch = 0; + } + return; + } + + // unbound synnotch should never be negative int unboundSynNotch = synnotchs - boundSynNotch; + unboundSynNotch = Math.max(0, unboundSynNotch); double expectedBindingEvents = bindingConstant @@ -130,14 +140,26 @@ protected void calculateCARS(MersenneTwisterFast random, Simulation sim) { * contactFraction * TAU; + // binding events should not exceed available unbound receptors + expectedBindingEvents = Math.min(expectedBindingEvents, unboundSynNotch); + int bindingEvents = poissonFactory.createPoisson(expectedBindingEvents, random).nextInt(); double expectedUnbindingEvents = unbindingConstant * boundSynNotch * TAU; + + expectedUnbindingEvents = Math.min(expectedUnbindingEvents, boundSynNotch); + + // unbinding events should not exceed available bound receptors int unbindingEvents = poissonFactory.createPoisson(expectedUnbindingEvents, random).nextInt(); boundSynNotch += bindingEvents; boundSynNotch -= unbindingEvents; + + // bound synnotch should never be negative + boundSynNotch = Math.max(0, boundSynNotch); boundCell.updateSynNotchAntigens(unbindingEvents, bindingEvents); + + // synnotch receptors become unavailable after binding synnotchs = Math.max(0, synnotchs - bindingEvents); } diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java index b0acfb7ac..7bf1316ed 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java @@ -96,7 +96,7 @@ protected void calculateCARS(MersenneTwisterFast random, Simulation sim) { /** Calculates the number of cars produced for synnotch circuit. * */ protected void synNotchCARCalculation() { - double n = 8; + double n = 4.4; int newCars = (int) (maxCars / (1 + Math.pow(synNotchThreshold, n) / Math.pow(boundSynNotch, n))); cars = Math.max((int) (cars - (carDegradationConstant * cars * TAU)), newCars); diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java index cd3984fbb..f93222b39 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java @@ -90,7 +90,7 @@ protected void calculateCARS(MersenneTwisterFast random, Simulation sim) { /** Calculates the number of cars produced for receptor circuit. * */ protected void receptorCars() { - double n = 8; + double n = 4.4; int removeCARs = (int) (maxCars / (1 + Math.pow(boundSynNotch, n) / Math.pow(synNotchThreshold, n))); cars = Math.min(cars + (int) (basalCARGenerationRate * TAU), removeCARs); diff --git a/src/arcade/patch/agent/module/PatchModuleCytotoxicity.java b/src/arcade/patch/agent/module/PatchModuleCytotoxicity.java index f7ee3aec3..7f4997e25 100644 --- a/src/arcade/patch/agent/module/PatchModuleCytotoxicity.java +++ b/src/arcade/patch/agent/module/PatchModuleCytotoxicity.java @@ -9,6 +9,7 @@ import arcade.patch.agent.cell.PatchCellCART; import arcade.patch.agent.cell.PatchCellTissue; import arcade.patch.agent.process.PatchProcessInflammation; +import arcade.patch.env.location.PatchLocation; import arcade.patch.sim.PatchSimulation; import arcade.patch.util.PatchEnums.Domain; import arcade.patch.util.PatchEnums.State; @@ -82,6 +83,8 @@ public void step(MersenneTwisterFast random, Simulation sim) { eventData.put("tissue-cell-type", target.getPop()); eventData.put("type", "lysis"); eventData.put("timestamp", (int) ((PatchSimulation) sim).getSchedule().getTime()); + eventData.put( + "tissue-location", ((PatchLocation) target.getLocation()).getCoordinate()); patchSim.logEvent(eventData); } } diff --git a/src/arcade/patch/agent/module/PatchModuleMigration.java b/src/arcade/patch/agent/module/PatchModuleMigration.java index e17987aff..99d91529a 100644 --- a/src/arcade/patch/agent/module/PatchModuleMigration.java +++ b/src/arcade/patch/agent/module/PatchModuleMigration.java @@ -25,6 +25,9 @@ public class PatchModuleMigration extends PatchModule { /** Time required for cell migration [min]. */ private final double movementDuration; + /** Boolean indicating if cell is on a matrigel. */ + private final double matrigel; + /** * Creates a migration {@link PatchModule} for the given cell. * @@ -32,6 +35,7 @@ public class PatchModuleMigration extends PatchModule { * *

    *
  • {@code MIGRATION_RATE} = cell migration rate + *
  • {@code MATRIGEL} = boolean indicating if cell is on a matrigel *
* * @param cell the {@link PatchCell} the module is associated with @@ -42,6 +46,7 @@ public PatchModuleMigration(PatchCell cell) { // Set loaded parameters. Parameters parameters = cell.getParameters(); migrationRate = parameters.getDouble("migration/MIGRATION_RATE"); + matrigel = parameters.getDouble("migration/MATRIGEL"); movementDuration = Math.round(location.getCoordinateSize() / migrationRate); } @@ -49,7 +54,7 @@ public PatchModuleMigration(PatchCell cell) { public void step(MersenneTwisterFast random, Simulation sim) { if (ticker > movementDuration) { PatchLocation newLocation = cell.selectBestLocation(sim, random); - if (newLocation == null) { + if (matrigel > 0 || newLocation == null) { if (cell instanceof PatchCellCART) { cell.setState(State.PAUSED); } else { diff --git a/src/arcade/patch/parameter.patch.xml b/src/arcade/patch/parameter.patch.xml index 730c614bd..1a7fa4cc8 100644 --- a/src/arcade/patch/parameter.patch.xml +++ b/src/arcade/patch/parameter.patch.xml @@ -46,7 +46,7 @@ - + @@ -59,6 +59,7 @@ + From d64fd3da113b367f4b08026feecddc1b08107c3f Mon Sep 17 00:00:00 2001 From: allison-li-1016 Date: Fri, 27 Feb 2026 18:41:33 +0000 Subject: [PATCH 28/28] new iCAR model --- src/arcade/patch/agent/cell/PatchCell.java | 4 + .../patch/agent/cell/PatchCellCART.java | 16 +- .../agent/cell/PatchCellCARTCombined.java | 6 +- .../PatchCellCARTCombinedCombinatorial.java | 13 +- .../cell/PatchCellCARTCombinedInducible.java | 10 +- .../cell/PatchCellCARTCombinedInhibitory.java | 246 +++++++++++++++++- .../patch/agent/cell/PatchCellTissue.java | 4 + src/arcade/patch/parameter.patch.xml | 4 + 8 files changed, 279 insertions(+), 24 deletions(-) diff --git a/src/arcade/patch/agent/cell/PatchCell.java b/src/arcade/patch/agent/cell/PatchCell.java index 085ba0942..7ecb4b733 100644 --- a/src/arcade/patch/agent/cell/PatchCell.java +++ b/src/arcade/patch/agent/cell/PatchCell.java @@ -32,6 +32,10 @@ import arcade.patch.env.grid.PatchGrid; import arcade.patch.env.location.PatchLocation; import arcade.patch.util.PatchEnums; +import arcade.patch.util.PatchEnums.Domain; +import arcade.patch.util.PatchEnums.Flag; +import arcade.patch.util.PatchEnums.Ordering; +import arcade.patch.util.PatchEnums.State; import static arcade.patch.util.PatchEnums.Domain; import static arcade.patch.util.PatchEnums.Flag; import static arcade.patch.util.PatchEnums.Ordering; diff --git a/src/arcade/patch/agent/cell/PatchCellCART.java b/src/arcade/patch/agent/cell/PatchCellCART.java index 4c69ca9ae..0f34a3856 100644 --- a/src/arcade/patch/agent/cell/PatchCellCART.java +++ b/src/arcade/patch/agent/cell/PatchCellCART.java @@ -120,6 +120,9 @@ public abstract class PatchCellCART extends PatchCell { /** Target cell that current T cell is bound to. */ protected PatchCell boundTarget; + /** maximum number of CAR receptors on a T cell. */ + static final int MAX_CARS = 50000; + /** * Creates a {@code PatchCellCART} agent. * * @@ -185,8 +188,8 @@ public PatchCellCART( selfBeta = parameters.getDouble("SELF_BETA"); contactFraction = parameters.getDouble("CONTACT_FRAC"); maxAntigenBinding = parameters.getInt("MAX_ANTIGEN_BINDING"); - startCars = parameters.getInt("CARS"); - cars = startCars; + startCars = MAX_CARS; + cars = parameters.getInt("CARS"); } /** @@ -277,7 +280,7 @@ public boolean getActivationStatus() { * @param beta fudge factor for receptor binding * @return the binding probability for the receptor */ - private double computeProbability( + protected double computeProbability( double antigens, double kD, int currentReceptors, @@ -323,7 +326,7 @@ private PatchCellTissue bindToCARAndSelfAntigen(PatchCellTissue tissueCell) { * @param tissueCell the target cell to bind to * @return the target tissue cell to bind to */ - private PatchCellTissue bindToSelfAntigen(PatchCellTissue tissueCell) { + protected PatchCellTissue bindToSelfAntigen(PatchCellTissue tissueCell) { super.setBindingFlag(AntigenFlag.BOUND_CELL_RECEPTOR); boundSelfAntigensCount++; return tissueCell; @@ -351,7 +354,7 @@ public void getTissueAgents(Bag tissueAgents, Bag possibleAgents) { * @param loc current location of the cell * @return bag of all tissue cells in neighborhood and current location */ - private Bag getAllTissueNeighbors(PatchGrid grid, PatchLocation loc) { + protected Bag getAllTissueNeighbors(PatchGrid grid, PatchLocation loc) { Bag neighbors = new Bag(); getTissueAgents(neighbors, grid.getObjectsAtLocation(loc)); for (Location neighborLocation : loc.getNeighbors()) { @@ -386,6 +389,7 @@ private double calculateMichaelisMenten( if (startReceptors == 0) { correctedStartReceptors = 1; } + return (targets * contactFraction / (affinity * beta + targets * contactFraction)) * (currentReceptors / correctedStartReceptors) * alpha; @@ -408,7 +412,7 @@ private double applySigmoid(double bindingCoefficient) { * @param loc the current location of the cell * @return the affinity per receptor molecule */ - private double computeAffinity(double affinity, PatchLocation loc) { + protected double computeAffinity(double affinity, PatchLocation loc) { return affinity * (loc.getVolume() * 1e-15 * 6.022E23); } diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombined.java b/src/arcade/patch/agent/cell/PatchCellCARTCombined.java index 055ed33f5..b551ebb98 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombined.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombined.java @@ -60,10 +60,6 @@ public PatchCellContainer make(int newID, CellState newState, MersenneTwisterFas public void step(SimState simstate) { Simulation sim = (Simulation) simstate; - if (sim.getSchedule().getTime() == 2880) { - int a = 0; - } - super.age++; if (state != State.APOPTOTIC && age > apoptosisAge) { @@ -155,7 +151,7 @@ public void step(SimState simstate) { if (super.getBindingFlag() == AntigenFlag.BOUND_CELL_RECEPTOR) { super.unbind(); } - // Check activation status. If cell has been activated before, + // Check activation status. If cell has been activated before,s // it will proliferate. If not, it will migrate. if (activated) { super.setState(State.PROLIFERATIVE); diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java index 3df712a2b..4f978dddd 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedCombinatorial.java @@ -39,9 +39,6 @@ public abstract class PatchCellCARTCombinedCombinatorial extends PatchCellCARTCo /** Number of bound synnotch receptors on this cell. */ public int boundSynNotch; - /** maximum CAR receptors possible. */ - protected final int maxCars; - /** poisson distribution. */ PatchCellCARTCombinedInducible.PoissonFactory poissonFactory; @@ -84,7 +81,6 @@ public PatchCellCARTCombinedCombinatorial( synNotchThreshold = parameters.getDouble("SYNNOTCH_THRESHOLD") * synnotchs; basalCARGenerationRate = parameters.getDouble("K_CAR_GENERATION"); boundSynNotch = 0; - maxCars = 50000; poissonFactory = Poisson::new; } @@ -194,4 +190,13 @@ public void resetBoundCell() { } boundSynNotch = 0; } + + /** + * returns the synnotch threshold. + * + * @return the synnotch threshold + */ + public double getSynNotchThreshold() { + return synNotchThreshold; + } } diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java index 7bf1316ed..4bf1b8370 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInducible.java @@ -65,6 +65,10 @@ public PatchCellCARTCombinedInducible( LogicalCARs type) { super(container, location, parameters, links); this.type = type; + if (this.type.equals(LogicalCARs.INDUCIBLE_SYNNOTCH)) { + // for receptor based circuits, receptor binding depends on initial receptors + this.startCars = cars; + } } @Override @@ -98,7 +102,11 @@ protected void calculateCARS(MersenneTwisterFast random, Simulation sim) { protected void synNotchCARCalculation() { double n = 4.4; int newCars = - (int) (maxCars / (1 + Math.pow(synNotchThreshold, n) / Math.pow(boundSynNotch, n))); + (int) + (MAX_CARS + / (1 + + Math.pow(synNotchThreshold, n) + / Math.pow(boundSynNotch, n))); cars = Math.max((int) (cars - (carDegradationConstant * cars * TAU)), newCars); } diff --git a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java index f93222b39..aba48f780 100644 --- a/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java +++ b/src/arcade/patch/agent/cell/PatchCellCARTCombinedInhibitory.java @@ -2,12 +2,19 @@ import java.util.logging.Logger; import sim.engine.SimState; +import sim.util.Bag; import ec.util.MersenneTwisterFast; +import arcade.core.agent.cell.Cell; import arcade.core.env.location.Location; import arcade.core.sim.Simulation; import arcade.core.util.GrabBag; import arcade.core.util.Parameters; +import arcade.patch.env.grid.PatchGrid; +import arcade.patch.env.location.PatchLocation; +import arcade.patch.util.PatchEnums.AntigenFlag; +import arcade.patch.util.PatchEnums.Domain; import arcade.patch.util.PatchEnums.LogicalCARs; +import arcade.patch.util.PatchEnums.State; /** Extension of {@link PatchCellCARTCombinedCombinatorial} for iCAR synnotch circuit. */ public class PatchCellCARTCombinedInhibitory extends PatchCellCARTCombinedCombinatorial { @@ -22,6 +29,33 @@ public class PatchCellCARTCombinedInhibitory extends PatchCellCARTCombinedCombin /** time step for tau stepping. */ private static final int TAU = 60; + /** Tracker for internal proteasome levels. */ + private double proteasome; + + /** Current proteasome production rate. */ + private double proteasomeProdRate; + + /** Proteasome threshold for CAR activation. */ + private double proteasomeActivationThreshold; + + /** Basal rate of proteasome decay. */ + private static final double BASAL_PROTEASOME_DECAY_RATE = 0.1; + + /** Synnotch binding status. */ + public boolean boundPD1 = false; + + /** Initial synnotch receptors. */ + private int initialSynnotchReceptors; + + /** Whether or not inhibitory mechanism is initiated. */ + private boolean pdel; + + /** icar_affinity. */ + private double icarReceptorAffinity; + + /** max number of iCAR receptors on iCAR surface. */ + static final int MAX_SYNNOTCHS = 20000; + /** * Creates a tissue {@code PatchCellCARTCombinedInhibitory} agent. * * @@ -64,17 +98,200 @@ public PatchCellCARTCombinedInhibitory( LogicalCARs type) { super(container, location, parameters, links); this.type = type; + proteasome = 0; + proteasomeProdRate = + parameters.getInt("PROTEASOME_PRODUCTION_RATIO") * BASAL_PROTEASOME_DECAY_RATE; + double maxProteasome = parameters.getInt("PROTEASOME_PRODUCTION_RATIO") * synnotchs; + proteasomeActivationThreshold = parameters.getDouble("SYNNOTCH_THRESHOLD") * maxProteasome; + initialSynnotchReceptors = parameters.getInt("SYNNOTCHS"); + pdel = parameters.getInt("PDEL") > 0 ? true : false; + icarReceptorAffinity = parameters.getDouble("ICAR_AFFINITY"); + // for receptor based circuits, receptor binding depends on initial receptors + if (this.type.equals(LogicalCARs.INHIBITORY_RECEPTOR)) { + this.startCars = cars; + } else { + // for inflammation based circuits, receptor binding depends on max receptors + this.initialSynnotchReceptors = MAX_SYNNOTCHS; + } } @Override public void step(SimState simstate) { Simulation sim = (Simulation) simstate; - if (super.boundCell == null) { - super.checkForBinding(simstate); + if (type.equals(LogicalCARs.INHIBITORY_INFLAMMATION)) { + // primary receptor binding + if (!pdel) { + bindTargetPD1(sim, location, simstate.random); + } + stepInflammation(simstate); } else { - calculateCARS(simstate.random, sim); + if (super.boundCell == null) { + super.checkForBinding(simstate); + } else { + calculateCARS(simstate.random, sim); + } + super.step(simstate); + } + } + + public void bindTargetPD1(Simulation sim, PatchLocation loc, MersenneTwisterFast random) { + + double kDSelf = computeAffinity(icarReceptorAffinity, loc); + PatchGrid grid = (PatchGrid) sim.getGrid(); + + Bag allAgents = getAllTissueNeighbors(grid, loc); + allAgents.remove(this); + allAgents.shuffle(random); + int neighbors = allAgents.size(); + + if (neighbors == 0) { + super.setBindingFlag(AntigenFlag.UNBOUND); + return; + } else { + int maxSearch = (int) Math.min(neighbors, searchAbility); + for (int i = 0; i < maxSearch; i++) { + Cell cell = (Cell) allAgents.get(i); + if (cell.getState() != State.APOPTOTIC && cell.getState() != State.NECROTIC) { + PatchCellTissue tissueCell = (PatchCellTissue) cell; + double selfTargets = tissueCell.getSynNotchAntigens(); + + double probabilitySelf = + computeProbability( + selfTargets, + kDSelf, + synnotchs, + initialSynnotchReceptors, + selfAlpha, + selfBeta); + + double randomSelf = random.nextDouble(); + + if (probabilitySelf >= randomSelf) { + boundPD1 = true; + boundSelfAntigensCount++; + synnotchs--; + } else { + boundPD1 = false; + } + } + } + } + } + + public void stepInflammation(SimState simstate) { + Simulation sim = (Simulation) simstate; + + super.age++; + + if (state != State.APOPTOTIC && age > apoptosisAge) { + setState(State.APOPTOTIC); + super.unbind(); + this.activated = false; + } + + super.lastActiveTicker++; + + if (super.lastActiveTicker != 0 && super.lastActiveTicker % MINUTES_IN_DAY == 0) { + if (super.boundCARAntigensCount != 0) { + super.boundCARAntigensCount--; + } + } + if (super.lastActiveTicker / MINUTES_IN_DAY >= 7) { + super.activated = false; + } + + super.processes.get(Domain.METABOLISM).step(simstate.random, sim); + + // Check energy status. If cell has less energy than threshold, it will + // apoptose. If overall energy is negative, then cell enters quiescence. + if (state != State.APOPTOTIC) { + if (super.energy < super.energyThreshold) { + super.setState(State.APOPTOTIC); + super.unbind(); + this.activated = false; + } else if (state != State.ANERGIC + && state != State.SENESCENT + && state != State.EXHAUSTED + && state != State.STARVED + && energy < 0) { + + super.setState(State.STARVED); + super.unbind(); + } else if (state == State.STARVED && energy >= 0) { + super.setState(State.UNDEFINED); + } + } + + super.processes.get(Domain.INFLAMMATION).step(simstate.random, sim); + + if (super.state == State.UNDEFINED || super.state == State.PAUSED) { + if (divisions == divisionPotential) { + if (simstate.random.nextDouble() > super.senescentFraction) { + super.setState(State.APOPTOTIC); + } else { + super.setState(State.SENESCENT); + } + super.unbind(); + this.activated = false; + } else { + // CAR receptor binding + PatchCellTissue target = super.bindTarget(sim, location, simstate.random); + super.boundTarget = target; + + // If cell is bound to both antigen and self it will become anergic. + if (super.getBindingFlag() == AntigenFlag.BOUND_ANTIGEN_CELL_RECEPTOR + || (boundPD1 && super.getBindingFlag() == AntigenFlag.BOUND_ANTIGEN)) { + if (simstate.random.nextDouble() > super.anergicFraction) { + super.setState(State.APOPTOTIC); + } else { + super.setState(State.ANERGIC); + } + super.unbind(); + this.activated = false; + } else if (super.getBindingFlag() == AntigenFlag.BOUND_ANTIGEN) { + // If cell is only bound to target antigen, the cell + // can potentially become properly activated. + + // Check overstimulation. If cell has bound to + // target antigens too many times, becomes exhausted. + if (boundCARAntigensCount > maxAntigenBinding + || boundSelfAntigensCount > maxAntigenBinding) { + if (simstate.random.nextDouble() > super.exhaustedFraction) { + super.setState(State.APOPTOTIC); + } else { + super.setState(State.EXHAUSTED); + } + super.unbind(); + this.activated = false; + } else { + // if CD8 cell is properly activated, it can be cytotoxic + this.lastActiveTicker = 0; + this.activated = true; + super.setState(State.CYTOTOXIC); + } + } else { + // If self binding, unbind + if (super.getBindingFlag() == AntigenFlag.BOUND_CELL_RECEPTOR) { + super.unbind(); + } + // Check activation status. If cell has been activated before,s + // it will proliferate. If not, it will migrate. + if (activated) { + super.setState(State.PROLIFERATIVE); + } else { + if (simstate.random.nextDouble() > super.proliferativeFraction) { + super.setState(State.MIGRATORY); + } else { + super.setState(State.PROLIFERATIVE); + } + } + } + } + } + + if (super.module != null) { + super.module.step(simstate.random, sim); } - super.step(simstate); } @Override @@ -90,9 +307,14 @@ protected void calculateCARS(MersenneTwisterFast random, Simulation sim) { /** Calculates the number of cars produced for receptor circuit. * */ protected void receptorCars() { + proteasome = proteasomeProdRate * boundSynNotch - BASAL_PROTEASOME_DECAY_RATE * proteasome; double n = 4.4; int removeCARs = - (int) (maxCars / (1 + Math.pow(boundSynNotch, n) / Math.pow(synNotchThreshold, n))); + (int) + (MAX_CARS + / (1 + + Math.pow(proteasome, n) + / Math.pow(proteasomeActivationThreshold, n))); cars = Math.min(cars + (int) (basalCARGenerationRate * TAU), removeCARs); } @@ -105,8 +327,16 @@ protected void inflammationCars() { + (basalCARGenerationRate * TAU) - (carDegradationConstant * cars * TAU)), 0); - if (boundSynNotch >= synNotchThreshold) { - this.activated = false; - } + } + + /** Calculates the proportion of inhibition given amount of SynNotch bound * */ + public double getInflammationInhibition() { + double n = 4.4; + return (1 / (1 + Math.pow(boundSynNotch, n) / Math.pow(synNotchThreshold, n))); + } + + /** Calculates the proportion of inhibition given amount of SynNotch bound * */ + public boolean isInhibited() { + return (synNotchThreshold <= boundSynNotch); } } diff --git a/src/arcade/patch/agent/cell/PatchCellTissue.java b/src/arcade/patch/agent/cell/PatchCellTissue.java index ac12cbf63..09a978fbf 100644 --- a/src/arcade/patch/agent/cell/PatchCellTissue.java +++ b/src/arcade/patch/agent/cell/PatchCellTissue.java @@ -93,6 +93,10 @@ public PatchCellContainer make(int newID, CellState newState, MersenneTwisterFas @Override public void step(SimState simstate) { Simulation sim = (Simulation) simstate; + + if (sim.getSchedule().getTime() >= 2500) { + int a = 0; + } // Increase age of cell. age++; diff --git a/src/arcade/patch/parameter.patch.xml b/src/arcade/patch/parameter.patch.xml index 1a7fa4cc8..bb86f29d1 100644 --- a/src/arcade/patch/parameter.patch.xml +++ b/src/arcade/patch/parameter.patch.xml @@ -55,6 +55,10 @@ + + + +