From 57817c13b42afd4c5dc7ce8edaec6bd3d1553b65 Mon Sep 17 00:00:00 2001 From: jannetty Date: Sat, 11 Apr 2026 19:33:48 -0700 Subject: [PATCH 01/10] add updateGrowthRate framework and make getUniqueIDs public --- .../PottsModuleFlyGMCDifferentiation.java | 85 ++++++++- ...oduleProliferationVolumeBasedDivision.java | 39 +++- src/arcade/potts/sim/Potts.java | 2 +- src/arcade/potts/sim/Potts2D.java | 2 +- src/arcade/potts/sim/Potts3D.java | 2 +- .../PottsModuleFlyGMCDifferentiation.java | 171 ++++++++++++++++++ .../PottsModuleFlyGMCDifferentiationTest.java | 167 ----------------- ...eProliferationVolumeBasedDivisionTest.java | 141 ++++++++++++++- test/arcade/potts/sim/PottsTest.java | 2 +- 9 files changed, 427 insertions(+), 184 deletions(-) create mode 100644 test/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiation.java delete mode 100644 test/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiationTest.java diff --git a/src/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiation.java b/src/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiation.java index 4405e45dc..a7653e002 100644 --- a/src/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiation.java +++ b/src/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiation.java @@ -16,10 +16,15 @@ /** * Implementation of {@link PottsModuleProliferationVolumeBasedDivision} for fly GMC agents. These * cells divide into two {@link PottsCellFlyNeuron} cells. The links must be set in the setup file - * so that 100% of the daughter cells are Neurons. + * so that 100% of the daughter cells are Neurons. Implementation of {@link + * PottsModuleProliferationVolumeBasedDivision} for fly GMC agents. These cells divide into two + * {@link PottsCellFlyNeuron} cells. The links must be set in the setup file so that 100% of the + * daughter cells are Neurons. */ public class PottsModuleFlyGMCDifferentiation extends PottsModuleProliferationVolumeBasedDivision { + Boolean pdeLike; + /** * Creates a fly GMC proliferation module. * @@ -27,13 +32,42 @@ public class PottsModuleFlyGMCDifferentiation extends PottsModuleProliferationVo */ public PottsModuleFlyGMCDifferentiation(PottsCellFlyGMC cell) { super(cell); + pdeLike = (cell.getParameters().getInt("proliferation/PDELIKE") != 0); + } + + /** + * Computes the expected equilibrium average GMC volume over one cell cycle. + * + *

In the Potts model, a cell's target volume is initialized to {@code criticalVolume} on + * reset. The Potts energy immediately drives the cell's actual volume toward this target, + * regardless of the current growth rate. As a result, the volume-regulated growth phase + * effectively begins at {@code criticalVolume} (not the birth volume), even when {@code + * VOLUME_BASED_CRITICAL_VOLUME} is off and birth volume is below {@code criticalVolume}. + * + *

The regulated growth phase therefore runs from {@code criticalVolume} to {@code sizeTarget + * * criticalVolume}. Under constant-rate growth, the time-average volume over this phase is the + * arithmetic mean of the two endpoints: + * + *

+     *   V_ref = (criticalVolume + sizeTarget * criticalVolume) / 2
+     *         = criticalVolume * (1 + sizeTarget) / 2
+     * 
+ * + *

This formula is consistent with the PDE-like branch, which uses {@code avgCritVol * (1 + + * sizeTarget) / 2}, and holds whether or not {@code VOLUME_BASED_CRITICAL_VOLUME} is enabled. + * + * @return the expected equilibrium average GMC volume + */ + double computeEquilibriumVolume() { + return cell.getCriticalVolume() * (1.0 + sizeTarget) / 2.0; } /** * Adds a cell to the simulation. * *

The cell location is split. The new neuron cell is created, initialized, and added to the - * schedule. This cell's location is also assigned to a new Neuron cell. + * schedule. This cell's location is also assigned to a new Neuron cell. The critical volume of + * both neurons is set to the initial volume of each neuron's location. * * @param random the random number generator * @param sim the simulation instance @@ -55,7 +89,7 @@ void addCell(MersenneTwisterFast random, Simulation sim) { (PottsCell) newContainer.convert(sim.getCellFactory(), newLocation, random); sim.getGrid().addObject(newCell, null); potts.register(newCell); - newCell.reset(potts.ids, potts.regions); + newCell.initialize(potts.ids, potts.regions); newCell.schedule(sim.getSchedule()); // remove old GMC cell from simulation @@ -88,7 +122,50 @@ void addCell(MersenneTwisterFast random, Simulation sim) { sim.getGrid().addObject(differentiatedGMC, null); potts.register(differentiatedGMC); - differentiatedGMC.reset(potts.ids, potts.regions); + differentiatedGMC.initialize(potts.ids, potts.regions); differentiatedGMC.schedule(sim.getSchedule()); } + + public void updateGrowthRate(Simulation sim) { + if (!dynamicGrowthRateVolume) { + cellGrowthRate = cellGrowthRateBase; + } else { + if (!pdeLike) { + updateCellVolumeBasedGrowthRate( + cell.getLocation().getVolume(), computeEquilibriumVolume()); + } else { + // PDE-like: use population-wide averages for GMCs (same pop as this cell). + // The reference volume is the population-average equilibrium volume: + // avgVRef = avgCritVol * (1 + sizeTarget) / 2 + // This assumes VOLUME_BASED_CRITICAL_VOLUME_MULTIPLIER = 1 (so each GMC's + // birth volume equals its critVol). For multiplier != 1, avgCritVol would need + // to be replaced by the mean of (critVol_i / multiplier + sizeTarget*critVol_i)/2. + sim.util.Bag objs = sim.getGrid().getAllObjects(); + + double volSum = 0.0; + double critSum = 0.0; + int count = 0; + + for (int i = 0; i < objs.numObjs; i++) { + Object o = objs.objs[i]; + if (!(o instanceof arcade.potts.agent.cell.PottsCell)) continue; + + arcade.potts.agent.cell.PottsCell c = (arcade.potts.agent.cell.PottsCell) o; + if (c.getPop() != cell.getPop()) continue; // keep to same population + + if (o instanceof arcade.potts.agent.cell.PottsCellFlyGMC) { + arcade.potts.agent.cell.PottsCellFlyGMC gmc = + (arcade.potts.agent.cell.PottsCellFlyGMC) o; + volSum += gmc.getLocation().getVolume(); + critSum += gmc.getCriticalVolume(); + count++; + } + } + double avgVolume = volSum / count; + double avgCritVol = critSum / count; + double avgVRef = avgCritVol * (1.0 + sizeTarget) / 2.0; + updateCellVolumeBasedGrowthRate(avgVolume, avgVRef); + } + } + } } diff --git a/src/arcade/potts/agent/module/PottsModuleProliferationVolumeBasedDivision.java b/src/arcade/potts/agent/module/PottsModuleProliferationVolumeBasedDivision.java index e154be0d4..2e1de6699 100644 --- a/src/arcade/potts/agent/module/PottsModuleProliferationVolumeBasedDivision.java +++ b/src/arcade/potts/agent/module/PottsModuleProliferationVolumeBasedDivision.java @@ -7,13 +7,16 @@ import arcade.potts.util.PottsEnums.Phase; /** - * Implementation of {@link PottsModule} for fly GMC agents. The links must be set in the setup file - * so that 100% of the daughter cells are Neurons. + * Implementation of {@link PottsModule} for agents that divide upon reaching a volume threshold + * without any cell-cycle duration requirements. */ public abstract class PottsModuleProliferationVolumeBasedDivision extends PottsModuleProliferation { - /** Overall growth rate for cell (voxels/tick). */ - final double cellGrowthRate; + /** Base growth rate for cells (voxels/tick). */ + final double cellGrowthRateBase; + + /** Current growth rate for stem cells (voxels/tick). */ + double cellGrowthRate; /** * Target ratio of critical volume for division size checkpoint (cell must reach CRITICAL_VOLUME @@ -21,6 +24,14 @@ public abstract class PottsModuleProliferationVolumeBasedDivision extends PottsM */ final double sizeTarget; + /** Boolean flag indicating whether the growth rate should follow volume-sensitive ruleset. */ + final boolean dynamicGrowthRateVolume; + + /** + * Sensitivity of growth rate to cell volume, only relevant if dynamicGrowthRateVolume is true. + */ + final double growthRateVolumeSensitivity; + /** * Creates a proliferation module in which division is solely dependent on cell volume. * @@ -30,16 +41,34 @@ public PottsModuleProliferationVolumeBasedDivision(PottsCell cell) { super(cell); Parameters parameters = cell.getParameters(); sizeTarget = parameters.getDouble("proliferation/SIZE_TARGET"); - cellGrowthRate = parameters.getDouble("proliferation/CELL_GROWTH_RATE"); + cellGrowthRateBase = parameters.getDouble("proliferation/CELL_GROWTH_RATE"); + dynamicGrowthRateVolume = + (parameters.getInt("proliferation/DYNAMIC_GROWTH_RATE_VOLUME") != 0); + growthRateVolumeSensitivity = + parameters.getDouble("proliferation/GROWTH_RATE_VOLUME_SENSITIVITY"); setPhase(Phase.UNDEFINED); + cellGrowthRate = cellGrowthRateBase; } @Override public void step(MersenneTwisterFast random, Simulation sim) { + updateGrowthRate(sim); cell.updateTarget(cellGrowthRate, sizeTarget); boolean sizeCheck = cell.getVolume() >= sizeTarget * cell.getCriticalVolume(); if (sizeCheck) { addCell(random, sim); } } + + /** + * Updates the effective growth rate according to boolean flags specified in parameters. + * + * @param sim the simulation + */ + public abstract void updateGrowthRate(Simulation sim); + + public void updateCellVolumeBasedGrowthRate(double volume, double cellCriticalVolume) { + double Ka = cellCriticalVolume; + cellGrowthRate = cellGrowthRateBase * Math.pow((volume / Ka), growthRateVolumeSensitivity); + } } diff --git a/src/arcade/potts/sim/Potts.java b/src/arcade/potts/sim/Potts.java index a0b46f0db..a4ffb0ee2 100644 --- a/src/arcade/potts/sim/Potts.java +++ b/src/arcade/potts/sim/Potts.java @@ -398,7 +398,7 @@ public PottsCell getCell(int id) { * @param z the z coordinate * @return the list of unique IDs */ - abstract HashSet getUniqueIDs(int x, int y, int z); + public abstract HashSet getUniqueIDs(int x, int y, int z); /** * Gets unique regions adjacent to given voxel. diff --git a/src/arcade/potts/sim/Potts2D.java b/src/arcade/potts/sim/Potts2D.java index 011d6f850..f6d7dbb6f 100644 --- a/src/arcade/potts/sim/Potts2D.java +++ b/src/arcade/potts/sim/Potts2D.java @@ -151,7 +151,7 @@ private boolean getConnectivityThreeNeighbors(boolean[][] subarray) { } @Override - HashSet getUniqueIDs(int x, int y, int z) { + public HashSet getUniqueIDs(int x, int y, int z) { int id = ids[z][x][y]; HashSet unique = new HashSet<>(); diff --git a/src/arcade/potts/sim/Potts3D.java b/src/arcade/potts/sim/Potts3D.java index 7c4686e8d..7f3429650 100644 --- a/src/arcade/potts/sim/Potts3D.java +++ b/src/arcade/potts/sim/Potts3D.java @@ -465,7 +465,7 @@ private boolean getConnectivityFiveNeighbors(boolean[][][] array) { } @Override - HashSet getUniqueIDs(int x, int y, int z) { + public HashSet getUniqueIDs(int x, int y, int z) { int id = ids[z][x][y]; HashSet unique = new HashSet<>(); diff --git a/test/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiation.java b/test/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiation.java new file mode 100644 index 000000000..a7653e002 --- /dev/null +++ b/test/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiation.java @@ -0,0 +1,171 @@ +package arcade.potts.agent.module; + +import ec.util.MersenneTwisterFast; +import arcade.core.agent.cell.CellContainer; +import arcade.core.env.location.Location; +import arcade.core.sim.Simulation; +import arcade.potts.agent.cell.PottsCell; +import arcade.potts.agent.cell.PottsCellContainer; +import arcade.potts.agent.cell.PottsCellFlyGMC; +import arcade.potts.agent.cell.PottsCellFlyNeuron; +import arcade.potts.env.location.PottsLocation2D; +import arcade.potts.sim.Potts; +import arcade.potts.sim.PottsSimulation; +import arcade.potts.util.PottsEnums.State; + +/** + * Implementation of {@link PottsModuleProliferationVolumeBasedDivision} for fly GMC agents. These + * cells divide into two {@link PottsCellFlyNeuron} cells. The links must be set in the setup file + * so that 100% of the daughter cells are Neurons. Implementation of {@link + * PottsModuleProliferationVolumeBasedDivision} for fly GMC agents. These cells divide into two + * {@link PottsCellFlyNeuron} cells. The links must be set in the setup file so that 100% of the + * daughter cells are Neurons. + */ +public class PottsModuleFlyGMCDifferentiation extends PottsModuleProliferationVolumeBasedDivision { + + Boolean pdeLike; + + /** + * Creates a fly GMC proliferation module. + * + * @param cell the cell to which this module is attached + */ + public PottsModuleFlyGMCDifferentiation(PottsCellFlyGMC cell) { + super(cell); + pdeLike = (cell.getParameters().getInt("proliferation/PDELIKE") != 0); + } + + /** + * Computes the expected equilibrium average GMC volume over one cell cycle. + * + *

In the Potts model, a cell's target volume is initialized to {@code criticalVolume} on + * reset. The Potts energy immediately drives the cell's actual volume toward this target, + * regardless of the current growth rate. As a result, the volume-regulated growth phase + * effectively begins at {@code criticalVolume} (not the birth volume), even when {@code + * VOLUME_BASED_CRITICAL_VOLUME} is off and birth volume is below {@code criticalVolume}. + * + *

The regulated growth phase therefore runs from {@code criticalVolume} to {@code sizeTarget + * * criticalVolume}. Under constant-rate growth, the time-average volume over this phase is the + * arithmetic mean of the two endpoints: + * + *

+     *   V_ref = (criticalVolume + sizeTarget * criticalVolume) / 2
+     *         = criticalVolume * (1 + sizeTarget) / 2
+     * 
+ * + *

This formula is consistent with the PDE-like branch, which uses {@code avgCritVol * (1 + + * sizeTarget) / 2}, and holds whether or not {@code VOLUME_BASED_CRITICAL_VOLUME} is enabled. + * + * @return the expected equilibrium average GMC volume + */ + double computeEquilibriumVolume() { + return cell.getCriticalVolume() * (1.0 + sizeTarget) / 2.0; + } + + /** + * Adds a cell to the simulation. + * + *

The cell location is split. The new neuron cell is created, initialized, and added to the + * schedule. This cell's location is also assigned to a new Neuron cell. The critical volume of + * both neurons is set to the initial volume of each neuron's location. + * + * @param random the random number generator + * @param sim the simulation instance + */ + @Override + void addCell(MersenneTwisterFast random, Simulation sim) { + Potts potts = ((PottsSimulation) sim).getPotts(); + + // Split current location + Location newLocation = ((PottsLocation2D) cell.getLocation()).split(random); + + // Reset current cell + cell.reset(potts.ids, potts.regions); + + // Create and schedule new neuron cell + int newID = sim.getID(); + CellContainer newContainer = cell.make(newID, State.QUIESCENT, random); + PottsCell newCell = + (PottsCell) newContainer.convert(sim.getCellFactory(), newLocation, random); + sim.getGrid().addObject(newCell, null); + potts.register(newCell); + newCell.initialize(potts.ids, potts.regions); + newCell.schedule(sim.getSchedule()); + + // remove old GMC cell from simulation + PottsCellFlyGMC oldCell = (PottsCellFlyGMC) cell; + Location location = oldCell.getLocation(); + sim.getGrid().removeObject(oldCell, location); + oldCell.stop(); + + // create new neuron cell and add to simulation. + int newPop = oldCell.getLinks().next(random); + + PottsCellContainer differentiatedGMCContainer = + new PottsCellContainer( + oldCell.getID(), + oldCell.getParent(), + newPop, + oldCell.getAge(), + oldCell.getDivisions(), + State.QUIESCENT, + null, + 0, + null, + oldCell.getCriticalVolume(), + oldCell.getCriticalHeight(), + oldCell.getCriticalRegionVolumes(), + oldCell.getCriticalRegionHeights()); + PottsCellFlyNeuron differentiatedGMC = + (PottsCellFlyNeuron) + differentiatedGMCContainer.convert(sim.getCellFactory(), location, random); + + sim.getGrid().addObject(differentiatedGMC, null); + potts.register(differentiatedGMC); + differentiatedGMC.initialize(potts.ids, potts.regions); + differentiatedGMC.schedule(sim.getSchedule()); + } + + public void updateGrowthRate(Simulation sim) { + if (!dynamicGrowthRateVolume) { + cellGrowthRate = cellGrowthRateBase; + } else { + if (!pdeLike) { + updateCellVolumeBasedGrowthRate( + cell.getLocation().getVolume(), computeEquilibriumVolume()); + } else { + // PDE-like: use population-wide averages for GMCs (same pop as this cell). + // The reference volume is the population-average equilibrium volume: + // avgVRef = avgCritVol * (1 + sizeTarget) / 2 + // This assumes VOLUME_BASED_CRITICAL_VOLUME_MULTIPLIER = 1 (so each GMC's + // birth volume equals its critVol). For multiplier != 1, avgCritVol would need + // to be replaced by the mean of (critVol_i / multiplier + sizeTarget*critVol_i)/2. + sim.util.Bag objs = sim.getGrid().getAllObjects(); + + double volSum = 0.0; + double critSum = 0.0; + int count = 0; + + for (int i = 0; i < objs.numObjs; i++) { + Object o = objs.objs[i]; + if (!(o instanceof arcade.potts.agent.cell.PottsCell)) continue; + + arcade.potts.agent.cell.PottsCell c = (arcade.potts.agent.cell.PottsCell) o; + if (c.getPop() != cell.getPop()) continue; // keep to same population + + if (o instanceof arcade.potts.agent.cell.PottsCellFlyGMC) { + arcade.potts.agent.cell.PottsCellFlyGMC gmc = + (arcade.potts.agent.cell.PottsCellFlyGMC) o; + volSum += gmc.getLocation().getVolume(); + critSum += gmc.getCriticalVolume(); + count++; + } + } + double avgVolume = volSum / count; + double avgCritVol = critSum / count; + double avgVRef = avgCritVol * (1.0 + sizeTarget) / 2.0; + updateCellVolumeBasedGrowthRate(avgVolume, avgVRef); + } + } + } +} diff --git a/test/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiationTest.java b/test/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiationTest.java deleted file mode 100644 index c1b04e272..000000000 --- a/test/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiationTest.java +++ /dev/null @@ -1,167 +0,0 @@ -package arcade.potts.agent.module; - -import java.util.EnumMap; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.MockedConstruction; -import sim.engine.Schedule; -import ec.util.MersenneTwisterFast; -import arcade.core.env.grid.Grid; -import arcade.core.sim.Simulation; -import arcade.core.util.GrabBag; -import arcade.core.util.Parameters; -import arcade.potts.agent.cell.PottsCell; -import arcade.potts.agent.cell.PottsCellContainer; -import arcade.potts.agent.cell.PottsCellFactory; -import arcade.potts.agent.cell.PottsCellFlyGMC; -import arcade.potts.agent.cell.PottsCellFlyNeuron; -import arcade.potts.env.location.PottsLocation; -import arcade.potts.env.location.PottsLocation2D; -import arcade.potts.sim.Potts; -import arcade.potts.sim.PottsSimulation; -import arcade.potts.util.PottsEnums.Region; -import arcade.potts.util.PottsEnums.State; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.mockConstruction; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class PottsModuleFlyGMCDifferentiationTest { - private int[][][] dummyIDs; - - private int[][][] dummyRegions; - - private Simulation sim; - - private Potts potts; - - private Grid grid; - - private PottsCellFactory cellFactory; - - private Schedule schedule; - - private PottsCellFlyGMC gmcCell; - - private PottsLocation2D location; - - private PottsLocation newLocation; - - private PottsCellContainer container; - - private PottsCell newCell; - - private GrabBag links; - - private Parameters parameters; - - private MersenneTwisterFast random; - - private MockedConstruction mockedConstruction; - - @BeforeEach - public final void setupMocks() { - dummyIDs = new int[1][1][1]; - dummyRegions = new int[0][0][0]; - - sim = mock(PottsSimulation.class); - potts = mock(Potts.class); - when(((PottsSimulation) sim).getPotts()).thenReturn(potts); - potts.ids = dummyIDs; - potts.regions = dummyRegions; - - grid = mock(Grid.class); - when(sim.getGrid()).thenReturn(grid); - cellFactory = mock(PottsCellFactory.class); - when(sim.getCellFactory()).thenReturn(cellFactory); - schedule = mock(Schedule.class); - when(sim.getSchedule()).thenReturn(schedule); - when(sim.getID()).thenReturn(123); - - gmcCell = mock(PottsCellFlyGMC.class); - location = mock(PottsLocation2D.class); - when(gmcCell.getLocation()).thenReturn(location); - newLocation = mock(PottsLocation.class); - when(location.split(any(MersenneTwisterFast.class))).thenReturn(newLocation); - - links = mock(GrabBag.class); - when(gmcCell.getLinks()).thenReturn(links); - int newPop = 2; - when(links.next(any(MersenneTwisterFast.class))).thenReturn(newPop); - - // Stub getters on the GMC cell for differentiated cell creation - when(gmcCell.getID()).thenReturn(100); - int parent = 0; - when(gmcCell.getParent()).thenReturn(parent); - when(gmcCell.getAge()).thenReturn(5); - when(gmcCell.getDivisions()).thenReturn(2); - when(gmcCell.getCriticalVolume()).thenReturn(1.0); - when(gmcCell.getCriticalHeight()).thenReturn(2.0); - EnumMap critRegionVolumes = new EnumMap<>(Region.class); - EnumMap critRegionHeights = new EnumMap<>(Region.class); - when(gmcCell.getCriticalRegionVolumes()).thenReturn(critRegionVolumes); - when(gmcCell.getCriticalRegionHeights()).thenReturn(critRegionHeights); - - parameters = mock(Parameters.class); - when(gmcCell.getParameters()).thenReturn(parameters); - - random = mock(MersenneTwisterFast.class); - - // Intercept construction of the differentiated cell container - mockedConstruction = - mockConstruction( - PottsCellContainer.class, - (mockContainer, context) -> { - // When convert() is called on this new container, return a - // differentiated cell - PottsCellFlyNeuron diffCell = mock(PottsCellFlyNeuron.class); - when(mockContainer.convert( - eq(cellFactory), - eq(location), - any(MersenneTwisterFast.class))) - .thenReturn(diffCell); - }); - } - - @AfterEach - final void tearDown() { - mockedConstruction.close(); - } - - @Test - public void addCell_called_callsExpectedMethods() { - // When the module calls make() on the cell, return Quiescent PottsCellContainer mock - container = mock(PottsCellContainer.class); - when(gmcCell.make(eq(123), eq(State.QUIESCENT), any(MersenneTwisterFast.class))) - .thenReturn(container); - newCell = mock(PottsCell.class); - when(container.convert(eq(cellFactory), eq(newLocation), any(MersenneTwisterFast.class))) - .thenReturn(newCell); - - PottsModuleProliferationVolumeBasedDivision module = - new PottsModuleFlyGMCDifferentiation(gmcCell); - module.addCell(random, sim); - verify(location).split(random); - verify(gmcCell).reset(dummyIDs, dummyRegions); - verify(gmcCell).make(123, State.QUIESCENT, random); - - verify(grid).addObject(newCell, null); - verify(potts).register(newCell); - verify(newCell).reset(dummyIDs, dummyRegions); - verify(newCell).schedule(schedule); - - verify(grid).removeObject(gmcCell, location); - verify(gmcCell).stop(); - - PottsCellContainer constructed = mockedConstruction.constructed().get(0); - PottsCellFlyNeuron diffCell = - (PottsCellFlyNeuron) constructed.convert(cellFactory, location, random); - verify(grid).addObject(diffCell, null); - verify(potts).register(diffCell); - verify(diffCell).reset(dummyIDs, dummyRegions); - verify(diffCell).schedule(schedule); - } -} diff --git a/test/arcade/potts/agent/module/PottsModuleProliferationVolumeBasedDivisionTest.java b/test/arcade/potts/agent/module/PottsModuleProliferationVolumeBasedDivisionTest.java index 4856f81e0..254cc1371 100644 --- a/test/arcade/potts/agent/module/PottsModuleProliferationVolumeBasedDivisionTest.java +++ b/test/arcade/potts/agent/module/PottsModuleProliferationVolumeBasedDivisionTest.java @@ -5,6 +5,9 @@ import arcade.core.sim.Simulation; import arcade.core.util.Parameters; import arcade.potts.agent.cell.PottsCellFlyGMC; +import arcade.potts.env.location.PottsLocation2D; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.mockito.Mockito.*; public class PottsModuleProliferationVolumeBasedDivisionTest { @@ -12,6 +15,7 @@ public class PottsModuleProliferationVolumeBasedDivisionTest { static class PottsModuleProliferationVolumeBasedDivisionMock extends PottsModuleProliferationVolumeBasedDivision { boolean addCellCalled = false; + boolean growthRateUpdated = false; PottsModuleProliferationVolumeBasedDivisionMock(PottsCellFlyGMC cell) { super(cell); @@ -21,15 +25,43 @@ static class PottsModuleProliferationVolumeBasedDivisionMock void addCell(MersenneTwisterFast random, Simulation sim) { addCellCalled = true; } + + @Override + public void updateGrowthRate(Simulation sim) { + growthRateUpdated = true; + cellGrowthRate = 7.5; + } } @Test - public void step_belowCheckpoint_updatesTargetOnly() { + public void step_called_usesGrowthRateSetByUpdateGrowthRate() { PottsCellFlyGMC cell = mock(PottsCellFlyGMC.class); Parameters params = mock(Parameters.class); + Simulation sim = mock(Simulation.class); + when(cell.getParameters()).thenReturn(params); when(params.getDouble("proliferation/SIZE_TARGET")).thenReturn(1.2); when(params.getDouble("proliferation/CELL_GROWTH_RATE")).thenReturn(4.0); + when(params.getInt("proliferation/DYNAMIC_GROWTH_RATE_VOLUME")).thenReturn(0); + when(params.getDouble("proliferation/GROWTH_RATE_VOLUME_SENSITIVITY")).thenReturn(2.0); + + when(cell.getVolume()).thenReturn(50.0); + when(cell.getCriticalVolume()).thenReturn(100.0); + + PottsModuleProliferationVolumeBasedDivisionMock module = + new PottsModuleProliferationVolumeBasedDivisionMock(cell); + module.step(new MersenneTwisterFast(), sim); + + verify(cell).updateTarget(7.5, 1.2); + assertFalse(module.addCellCalled); + } + + @Test + public void step_belowCheckpoint_updates() { + PottsCellFlyGMC cell = mock(PottsCellFlyGMC.class); + Parameters params = mock(Parameters.class); + when(cell.getParameters()).thenReturn(params); + when(params.getDouble("proliferation/SIZE_TARGET")).thenReturn(1.2); when(cell.getCriticalVolume()).thenReturn(100.0); when(cell.getVolume()).thenReturn(50.0); // below checkpoint @@ -38,7 +70,8 @@ public void step_belowCheckpoint_updatesTargetOnly() { module.step(mock(MersenneTwisterFast.class), mock(Simulation.class)); - verify(cell).updateTarget(4.0, 1.2); + verify(cell).updateTarget(7.5, 1.2); + assert module.growthRateUpdated : "growth rate should be updated on every step"; assert !module.addCellCalled : "addCell should not be called below checkpoint"; } @@ -49,7 +82,6 @@ public void step_atOrAboveCheckpoint_triggersAddCell() { Parameters params = mock(Parameters.class); when(cell.getParameters()).thenReturn(params); when(params.getDouble("proliferation/SIZE_TARGET")).thenReturn(1.2); - when(params.getDouble("proliferation/CELL_GROWTH_RATE")).thenReturn(4.0); when(cell.getCriticalVolume()).thenReturn(100.0); when(cell.getVolume()).thenReturn(120.0); // at or above checkpoint @@ -58,7 +90,108 @@ public void step_atOrAboveCheckpoint_triggersAddCell() { module.step(mock(MersenneTwisterFast.class), mock(Simulation.class)); - verify(cell).updateTarget(4.0, 1.2); + verify(cell).updateTarget(7.5, 1.2); + assert module.growthRateUpdated : "growth rate should be updated on every step"; assert module.addCellCalled : "addCell should be called at or above checkpoint"; } + + @Test + public void updateVolumeBasedGrowthRate_ratioOne_keepsBaseRate() { + // baseGrowth = 4.0, volume = Ka => growth = 4.0 + PottsCellFlyGMC cell = mock(PottsCellFlyGMC.class); + Parameters params = mock(Parameters.class); + PottsLocation2D loc = mock(PottsLocation2D.class); + + when(cell.getParameters()).thenReturn(params); + when(params.getDouble("proliferation/SIZE_TARGET")).thenReturn(1.2); + when(params.getDouble("proliferation/CELL_GROWTH_RATE")).thenReturn(4.0); + when(params.getInt("proliferation/DYNAMIC_GROWTH_RATE_VOLUME")).thenReturn(1); + when(params.getDouble("proliferation/GROWTH_RATE_VOLUME_SENSITIVITY")).thenReturn(2.0); + + when(cell.getLocation()).thenReturn(loc); + when(loc.getVolume()).thenReturn(100.0); + when(cell.getCriticalVolume()).thenReturn(100.0); + + PottsModuleProliferationVolumeBasedDivisionTest + .PottsModuleProliferationVolumeBasedDivisionMock + module = new PottsModuleProliferationVolumeBasedDivisionMock(cell); + + module.updateCellVolumeBasedGrowthRate(loc.getVolume(), cell.getCriticalVolume()); + assertEquals(4.0, module.cellGrowthRate, 1e-9); + } + + @Test + public void updateVolumeBasedGrowthRate_ratioGreaterThanOne_scalesUpByPowerLaw() { + // baseGrowth = 2.0, ratio = 2.0, sensitivity = 3 => 2 * 2^3 = 2 * 8 = 12 + PottsCellFlyGMC cell = mock(PottsCellFlyGMC.class); + Parameters params = mock(Parameters.class); + PottsLocation2D loc = mock(PottsLocation2D.class); + + when(cell.getParameters()).thenReturn(params); + when(params.getDouble("proliferation/SIZE_TARGET")).thenReturn(1.2); + when(params.getDouble("proliferation/CELL_GROWTH_RATE")).thenReturn(2.0); + when(params.getInt("proliferation/DYNAMIC_GROWTH_RATE_VOLUME")).thenReturn(1); + when(params.getDouble("proliferation/GROWTH_RATE_VOLUME_SENSITIVITY")).thenReturn(3.0); + + when(cell.getLocation()).thenReturn(loc); + when(loc.getVolume()).thenReturn(200.0); + when(cell.getCriticalVolume()).thenReturn(100.0); + + PottsModuleProliferationVolumeBasedDivisionTest + .PottsModuleProliferationVolumeBasedDivisionMock + module = new PottsModuleProliferationVolumeBasedDivisionMock(cell); + + module.updateCellVolumeBasedGrowthRate(loc.getVolume(), cell.getCriticalVolume()); + assertEquals(16.0, module.cellGrowthRate, 1e-9); + } + + @Test + public void updateVolumeBasedGrowthRate_ratioLessThanOne_scalesDownByPowerLaw() { + // baseGrowth = 4.0, ratio = 0.5, sensitivity = 2.0 => 4 * 0.5^2 = 1.0 + PottsCellFlyGMC cell = mock(PottsCellFlyGMC.class); + Parameters params = mock(Parameters.class); + PottsLocation2D loc = mock(PottsLocation2D.class); + + when(cell.getParameters()).thenReturn(params); + when(params.getDouble("proliferation/SIZE_TARGET")).thenReturn(1.2); + when(params.getDouble("proliferation/CELL_GROWTH_RATE")).thenReturn(4.0); + when(params.getInt("proliferation/DYNAMIC_GROWTH_RATE_VOLUME")).thenReturn(1); + when(params.getDouble("proliferation/GROWTH_RATE_VOLUME_SENSITIVITY")).thenReturn(2.0); + + when(cell.getLocation()).thenReturn(loc); + when(loc.getVolume()).thenReturn(50.0); + when(cell.getCriticalVolume()).thenReturn(100.0); + + PottsModuleProliferationVolumeBasedDivisionTest + .PottsModuleProliferationVolumeBasedDivisionMock + module = new PottsModuleProliferationVolumeBasedDivisionMock(cell); + + module.updateCellVolumeBasedGrowthRate(loc.getVolume(), cell.getCriticalVolume()); + assertEquals(1.0, module.cellGrowthRate, 1e-9); + } + + @Test + public void updateVolumeBasedGrowthRate_zeroSensitivity_returnsBaseRateRegardlessOfVolume() { + // sensitivity = 0 => growth = baseGrowth * ratio^0 = baseGrowth + PottsCellFlyGMC cell = mock(PottsCellFlyGMC.class); + Parameters params = mock(Parameters.class); + PottsLocation2D loc = mock(PottsLocation2D.class); + + when(cell.getParameters()).thenReturn(params); + when(params.getDouble("proliferation/SIZE_TARGET")).thenReturn(1.2); + when(params.getDouble("proliferation/CELL_GROWTH_RATE")).thenReturn(3.5); + when(params.getInt("proliferation/DYNAMIC_GROWTH_RATE_VOLUME")).thenReturn(1); + when(params.getDouble("proliferation/GROWTH_RATE_VOLUME_SENSITIVITY")).thenReturn(0.0); + + when(cell.getLocation()).thenReturn(loc); + when(loc.getVolume()).thenReturn(250.0); + when(cell.getCriticalVolume()).thenReturn(100.0); + + PottsModuleProliferationVolumeBasedDivisionTest + .PottsModuleProliferationVolumeBasedDivisionMock + module = new PottsModuleProliferationVolumeBasedDivisionMock(cell); + + module.updateCellVolumeBasedGrowthRate(loc.getVolume(), cell.getCriticalVolume()); + assertEquals(3.5, module.cellGrowthRate, 1e-9); + } } diff --git a/test/arcade/potts/sim/PottsTest.java b/test/arcade/potts/sim/PottsTest.java index 04c61d693..305658832 100644 --- a/test/arcade/potts/sim/PottsTest.java +++ b/test/arcade/potts/sim/PottsTest.java @@ -61,7 +61,7 @@ boolean getConnectivity(boolean[][][] array, boolean zero) { } @Override - HashSet getUniqueIDs(int x, int y, int z) { + public HashSet getUniqueIDs(int x, int y, int z) { HashSet set = new HashSet<>(); if (x == 0 && y == 0) { set.add(1); From 6392d9ed5df21ea996898d1f73064209a20c0303 Mon Sep 17 00:00:00 2001 From: jannetty Date: Sat, 11 Apr 2026 22:06:13 -0700 Subject: [PATCH 02/10] adding dostrings --- ...oduleProliferationVolumeBasedDivision.java | 17 ++++++++++ .../PottsModuleFlyGMCDifferentiation.java | 32 ++++++++++++------- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/src/arcade/potts/agent/module/PottsModuleProliferationVolumeBasedDivision.java b/src/arcade/potts/agent/module/PottsModuleProliferationVolumeBasedDivision.java index 2e1de6699..b6e0a88f1 100644 --- a/src/arcade/potts/agent/module/PottsModuleProliferationVolumeBasedDivision.java +++ b/src/arcade/potts/agent/module/PottsModuleProliferationVolumeBasedDivision.java @@ -67,6 +67,23 @@ public void step(MersenneTwisterFast random, Simulation sim) { */ public abstract void updateGrowthRate(Simulation sim); + /** + * Updates {@code cellGrowthRate} from a power-law relationship between current volume and a + * reference volume. + * + *

The updated rate is + * + *

+     * cellGrowthRate = cellGrowthRateBase * (volume / referenceVolume)^growthRateVolumeSensitivity
+     * 
+ * + *

The reference volume is the scale at which the basal growth rate is recovered. In the + * simplest case this can be the cell's critical volume, but callers may also supply another + * biologically motivated reference such as an equilibrium or population-averaged volume. + * + * @param volume the current volume used in the growth-rate scaling + * @param referenceVolume the reference volume that defines the baseline growth-rate scale + */ public void updateCellVolumeBasedGrowthRate(double volume, double cellCriticalVolume) { double Ka = cellCriticalVolume; cellGrowthRate = cellGrowthRateBase * Math.pow((volume / Ka), growthRateVolumeSensitivity); diff --git a/test/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiation.java b/test/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiation.java index a7653e002..f62db78a0 100644 --- a/test/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiation.java +++ b/test/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiation.java @@ -16,13 +16,14 @@ /** * Implementation of {@link PottsModuleProliferationVolumeBasedDivision} for fly GMC agents. These * cells divide into two {@link PottsCellFlyNeuron} cells. The links must be set in the setup file - * so that 100% of the daughter cells are Neurons. Implementation of {@link - * PottsModuleProliferationVolumeBasedDivision} for fly GMC agents. These cells divide into two - * {@link PottsCellFlyNeuron} cells. The links must be set in the setup file so that 100% of the - * daughter cells are Neurons. + * so that 100% of the daughter cells are Neurons. */ public class PottsModuleFlyGMCDifferentiation extends PottsModuleProliferationVolumeBasedDivision { + /** + * Indicates whether GMC growth rate is based on individual cell conditions or average cell + * conditions + */ Boolean pdeLike; /** @@ -39,10 +40,10 @@ public PottsModuleFlyGMCDifferentiation(PottsCellFlyGMC cell) { * Computes the expected equilibrium average GMC volume over one cell cycle. * *

In the Potts model, a cell's target volume is initialized to {@code criticalVolume} on - * reset. The Potts energy immediately drives the cell's actual volume toward this target, - * regardless of the current growth rate. As a result, the volume-regulated growth phase - * effectively begins at {@code criticalVolume} (not the birth volume), even when {@code - * VOLUME_BASED_CRITICAL_VOLUME} is off and birth volume is below {@code criticalVolume}. + * reset. The Potts energy drives the cell's actual volume toward this target, regardless of + * current growth rate. As a result, the volume-regulated growth phase effectively begins at + * {@code criticalVolume} (not the birth volume), even when {@code VOLUME_BASED_CRITICAL_VOLUME} + * is off and birth volume is below {@code criticalVolume}. * *

The regulated growth phase therefore runs from {@code criticalVolume} to {@code sizeTarget * * criticalVolume}. Under constant-rate growth, the time-average volume over this phase is the @@ -53,9 +54,6 @@ public PottsModuleFlyGMCDifferentiation(PottsCellFlyGMC cell) { * = criticalVolume * (1 + sizeTarget) / 2 * * - *

This formula is consistent with the PDE-like branch, which uses {@code avgCritVol * (1 + - * sizeTarget) / 2}, and holds whether or not {@code VOLUME_BASED_CRITICAL_VOLUME} is enabled. - * * @return the expected equilibrium average GMC volume */ double computeEquilibriumVolume() { @@ -126,7 +124,17 @@ void addCell(MersenneTwisterFast random, Simulation sim) { differentiatedGMC.schedule(sim.getSchedule()); } - public void updateGrowthRate(Simulation sim) { + /** + * Updates the GMC growth rate for the current simulation step. + * + *

If dynamic growth is disabled, the basal growth rate is used. Otherwise, the update is + * volume-based: either from this cell's own volume relative to its equilibrium reference + * volume, or in {@code pdeLike} mode from the population-average GMC volume and average + * equilibrium reference volume for cells in the same population. + * + * @param sim the simulation instance used to access the cell population + */ + public final void updateGrowthRate(Simulation sim) { if (!dynamicGrowthRateVolume) { cellGrowthRate = cellGrowthRateBase; } else { From 488ab02cd2c2be2fd3c61d55832e292a95ace311 Mon Sep 17 00:00:00 2001 From: jannetty Date: Sat, 11 Apr 2026 22:09:21 -0700 Subject: [PATCH 03/10] another docstring --- .../module/PottsModuleFlyGMCDifferentiation.java | 1 + .../module/PottsModuleFlyGMCDifferentiation.java | 15 ++++++--------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiation.java b/src/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiation.java index a7653e002..818209568 100644 --- a/src/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiation.java +++ b/src/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiation.java @@ -23,6 +23,7 @@ */ public class PottsModuleFlyGMCDifferentiation extends PottsModuleProliferationVolumeBasedDivision { + /** Indicates whether GMC growth rate is based on individual cell conditions or average cell conditions */ Boolean pdeLike; /** diff --git a/test/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiation.java b/test/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiation.java index f62db78a0..02bc73f48 100644 --- a/test/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiation.java +++ b/test/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiation.java @@ -20,10 +20,7 @@ */ public class PottsModuleFlyGMCDifferentiation extends PottsModuleProliferationVolumeBasedDivision { - /** - * Indicates whether GMC growth rate is based on individual cell conditions or average cell - * conditions - */ + /** Indicates whether GMC growth rate is based on individual cell conditions or average cell conditions */ Boolean pdeLike; /** @@ -40,10 +37,10 @@ public PottsModuleFlyGMCDifferentiation(PottsCellFlyGMC cell) { * Computes the expected equilibrium average GMC volume over one cell cycle. * *

In the Potts model, a cell's target volume is initialized to {@code criticalVolume} on - * reset. The Potts energy drives the cell's actual volume toward this target, regardless of - * current growth rate. As a result, the volume-regulated growth phase effectively begins at - * {@code criticalVolume} (not the birth volume), even when {@code VOLUME_BASED_CRITICAL_VOLUME} - * is off and birth volume is below {@code criticalVolume}. + * reset. The Potts energy drives the cell's actual volume toward this target, + * regardless of current growth rate. As a result, the volume-regulated growth phase + * effectively begins at {@code criticalVolume} (not the birth volume), even when {@code + * VOLUME_BASED_CRITICAL_VOLUME} is off and birth volume is below {@code criticalVolume}. * *

The regulated growth phase therefore runs from {@code criticalVolume} to {@code sizeTarget * * criticalVolume}. Under constant-rate growth, the time-average volume over this phase is the @@ -134,7 +131,7 @@ void addCell(MersenneTwisterFast random, Simulation sim) { * * @param sim the simulation instance used to access the cell population */ - public final void updateGrowthRate(Simulation sim) { + final public void updateGrowthRate(Simulation sim) { if (!dynamicGrowthRateVolume) { cellGrowthRate = cellGrowthRateBase; } else { From 4376f32e4737ad41bf5a53dabd12f1e2300792e1 Mon Sep 17 00:00:00 2001 From: jannetty Date: Sat, 11 Apr 2026 22:20:08 -0700 Subject: [PATCH 04/10] more formatting --- .../PottsModuleFlyGMCDifferentiation.java | 18 +- ...oduleProliferationVolumeBasedDivision.java | 11 +- .../PottsModuleFlyGMCDifferentiation.java | 176 ---------- .../PottsModuleFlyGMCDifferentiationTest.java | 322 ++++++++++++++++++ ...eProliferationVolumeBasedDivisionTest.java | 1 + 5 files changed, 344 insertions(+), 184 deletions(-) delete mode 100644 test/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiation.java create mode 100644 test/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiationTest.java diff --git a/src/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiation.java b/src/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiation.java index 818209568..b289586fa 100644 --- a/src/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiation.java +++ b/src/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiation.java @@ -23,7 +23,10 @@ */ public class PottsModuleFlyGMCDifferentiation extends PottsModuleProliferationVolumeBasedDivision { - /** Indicates whether GMC growth rate is based on individual cell conditions or average cell conditions */ + /** + * Indicates whether GMC growth rate is based on individual cell conditions or average cell + * conditions. + */ Boolean pdeLike; /** @@ -127,6 +130,11 @@ void addCell(MersenneTwisterFast random, Simulation sim) { differentiatedGMC.schedule(sim.getSchedule()); } + /** + * Updates the effective growth rate according to boolean flags specified in parameters. + * + * @param sim the simulation + */ public void updateGrowthRate(Simulation sim) { if (!dynamicGrowthRateVolume) { cellGrowthRate = cellGrowthRateBase; @@ -149,10 +157,14 @@ public void updateGrowthRate(Simulation sim) { for (int i = 0; i < objs.numObjs; i++) { Object o = objs.objs[i]; - if (!(o instanceof arcade.potts.agent.cell.PottsCell)) continue; + if (!(o instanceof arcade.potts.agent.cell.PottsCell)) { + continue; + } arcade.potts.agent.cell.PottsCell c = (arcade.potts.agent.cell.PottsCell) o; - if (c.getPop() != cell.getPop()) continue; // keep to same population + if (c.getPop() != cell.getPop()) { + continue; // keep to same population + } if (o instanceof arcade.potts.agent.cell.PottsCellFlyGMC) { arcade.potts.agent.cell.PottsCellFlyGMC gmc = diff --git a/src/arcade/potts/agent/module/PottsModuleProliferationVolumeBasedDivision.java b/src/arcade/potts/agent/module/PottsModuleProliferationVolumeBasedDivision.java index b6e0a88f1..aae4bc94f 100644 --- a/src/arcade/potts/agent/module/PottsModuleProliferationVolumeBasedDivision.java +++ b/src/arcade/potts/agent/module/PottsModuleProliferationVolumeBasedDivision.java @@ -77,15 +77,16 @@ public void step(MersenneTwisterFast random, Simulation sim) { * cellGrowthRate = cellGrowthRateBase * (volume / referenceVolume)^growthRateVolumeSensitivity * * - *

The reference volume is the scale at which the basal growth rate is recovered. In the - * simplest case this can be the cell's critical volume, but callers may also supply another + *

The reference volume is the cell volume at which the basal growth rate is recovered. In + * the simplest case this can be the cell's critical volume, but users may use another * biologically motivated reference such as an equilibrium or population-averaged volume. * * @param volume the current volume used in the growth-rate scaling * @param referenceVolume the reference volume that defines the baseline growth-rate scale */ - public void updateCellVolumeBasedGrowthRate(double volume, double cellCriticalVolume) { - double Ka = cellCriticalVolume; - cellGrowthRate = cellGrowthRateBase * Math.pow((volume / Ka), growthRateVolumeSensitivity); + public void updateCellVolumeBasedGrowthRate(double volume, double referenceVolume) { + double refVol = referenceVolume; + cellGrowthRate = + cellGrowthRateBase * Math.pow((volume / refVol), growthRateVolumeSensitivity); } } diff --git a/test/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiation.java b/test/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiation.java deleted file mode 100644 index 02bc73f48..000000000 --- a/test/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiation.java +++ /dev/null @@ -1,176 +0,0 @@ -package arcade.potts.agent.module; - -import ec.util.MersenneTwisterFast; -import arcade.core.agent.cell.CellContainer; -import arcade.core.env.location.Location; -import arcade.core.sim.Simulation; -import arcade.potts.agent.cell.PottsCell; -import arcade.potts.agent.cell.PottsCellContainer; -import arcade.potts.agent.cell.PottsCellFlyGMC; -import arcade.potts.agent.cell.PottsCellFlyNeuron; -import arcade.potts.env.location.PottsLocation2D; -import arcade.potts.sim.Potts; -import arcade.potts.sim.PottsSimulation; -import arcade.potts.util.PottsEnums.State; - -/** - * Implementation of {@link PottsModuleProliferationVolumeBasedDivision} for fly GMC agents. These - * cells divide into two {@link PottsCellFlyNeuron} cells. The links must be set in the setup file - * so that 100% of the daughter cells are Neurons. - */ -public class PottsModuleFlyGMCDifferentiation extends PottsModuleProliferationVolumeBasedDivision { - - /** Indicates whether GMC growth rate is based on individual cell conditions or average cell conditions */ - Boolean pdeLike; - - /** - * Creates a fly GMC proliferation module. - * - * @param cell the cell to which this module is attached - */ - public PottsModuleFlyGMCDifferentiation(PottsCellFlyGMC cell) { - super(cell); - pdeLike = (cell.getParameters().getInt("proliferation/PDELIKE") != 0); - } - - /** - * Computes the expected equilibrium average GMC volume over one cell cycle. - * - *

In the Potts model, a cell's target volume is initialized to {@code criticalVolume} on - * reset. The Potts energy drives the cell's actual volume toward this target, - * regardless of current growth rate. As a result, the volume-regulated growth phase - * effectively begins at {@code criticalVolume} (not the birth volume), even when {@code - * VOLUME_BASED_CRITICAL_VOLUME} is off and birth volume is below {@code criticalVolume}. - * - *

The regulated growth phase therefore runs from {@code criticalVolume} to {@code sizeTarget - * * criticalVolume}. Under constant-rate growth, the time-average volume over this phase is the - * arithmetic mean of the two endpoints: - * - *

-     *   V_ref = (criticalVolume + sizeTarget * criticalVolume) / 2
-     *         = criticalVolume * (1 + sizeTarget) / 2
-     * 
- * - * @return the expected equilibrium average GMC volume - */ - double computeEquilibriumVolume() { - return cell.getCriticalVolume() * (1.0 + sizeTarget) / 2.0; - } - - /** - * Adds a cell to the simulation. - * - *

The cell location is split. The new neuron cell is created, initialized, and added to the - * schedule. This cell's location is also assigned to a new Neuron cell. The critical volume of - * both neurons is set to the initial volume of each neuron's location. - * - * @param random the random number generator - * @param sim the simulation instance - */ - @Override - void addCell(MersenneTwisterFast random, Simulation sim) { - Potts potts = ((PottsSimulation) sim).getPotts(); - - // Split current location - Location newLocation = ((PottsLocation2D) cell.getLocation()).split(random); - - // Reset current cell - cell.reset(potts.ids, potts.regions); - - // Create and schedule new neuron cell - int newID = sim.getID(); - CellContainer newContainer = cell.make(newID, State.QUIESCENT, random); - PottsCell newCell = - (PottsCell) newContainer.convert(sim.getCellFactory(), newLocation, random); - sim.getGrid().addObject(newCell, null); - potts.register(newCell); - newCell.initialize(potts.ids, potts.regions); - newCell.schedule(sim.getSchedule()); - - // remove old GMC cell from simulation - PottsCellFlyGMC oldCell = (PottsCellFlyGMC) cell; - Location location = oldCell.getLocation(); - sim.getGrid().removeObject(oldCell, location); - oldCell.stop(); - - // create new neuron cell and add to simulation. - int newPop = oldCell.getLinks().next(random); - - PottsCellContainer differentiatedGMCContainer = - new PottsCellContainer( - oldCell.getID(), - oldCell.getParent(), - newPop, - oldCell.getAge(), - oldCell.getDivisions(), - State.QUIESCENT, - null, - 0, - null, - oldCell.getCriticalVolume(), - oldCell.getCriticalHeight(), - oldCell.getCriticalRegionVolumes(), - oldCell.getCriticalRegionHeights()); - PottsCellFlyNeuron differentiatedGMC = - (PottsCellFlyNeuron) - differentiatedGMCContainer.convert(sim.getCellFactory(), location, random); - - sim.getGrid().addObject(differentiatedGMC, null); - potts.register(differentiatedGMC); - differentiatedGMC.initialize(potts.ids, potts.regions); - differentiatedGMC.schedule(sim.getSchedule()); - } - - /** - * Updates the GMC growth rate for the current simulation step. - * - *

If dynamic growth is disabled, the basal growth rate is used. Otherwise, the update is - * volume-based: either from this cell's own volume relative to its equilibrium reference - * volume, or in {@code pdeLike} mode from the population-average GMC volume and average - * equilibrium reference volume for cells in the same population. - * - * @param sim the simulation instance used to access the cell population - */ - final public void updateGrowthRate(Simulation sim) { - if (!dynamicGrowthRateVolume) { - cellGrowthRate = cellGrowthRateBase; - } else { - if (!pdeLike) { - updateCellVolumeBasedGrowthRate( - cell.getLocation().getVolume(), computeEquilibriumVolume()); - } else { - // PDE-like: use population-wide averages for GMCs (same pop as this cell). - // The reference volume is the population-average equilibrium volume: - // avgVRef = avgCritVol * (1 + sizeTarget) / 2 - // This assumes VOLUME_BASED_CRITICAL_VOLUME_MULTIPLIER = 1 (so each GMC's - // birth volume equals its critVol). For multiplier != 1, avgCritVol would need - // to be replaced by the mean of (critVol_i / multiplier + sizeTarget*critVol_i)/2. - sim.util.Bag objs = sim.getGrid().getAllObjects(); - - double volSum = 0.0; - double critSum = 0.0; - int count = 0; - - for (int i = 0; i < objs.numObjs; i++) { - Object o = objs.objs[i]; - if (!(o instanceof arcade.potts.agent.cell.PottsCell)) continue; - - arcade.potts.agent.cell.PottsCell c = (arcade.potts.agent.cell.PottsCell) o; - if (c.getPop() != cell.getPop()) continue; // keep to same population - - if (o instanceof arcade.potts.agent.cell.PottsCellFlyGMC) { - arcade.potts.agent.cell.PottsCellFlyGMC gmc = - (arcade.potts.agent.cell.PottsCellFlyGMC) o; - volSum += gmc.getLocation().getVolume(); - critSum += gmc.getCriticalVolume(); - count++; - } - } - double avgVolume = volSum / count; - double avgCritVol = critSum / count; - double avgVRef = avgCritVol * (1.0 + sizeTarget) / 2.0; - updateCellVolumeBasedGrowthRate(avgVolume, avgVRef); - } - } - } -} diff --git a/test/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiationTest.java b/test/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiationTest.java new file mode 100644 index 000000000..1334d9922 --- /dev/null +++ b/test/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiationTest.java @@ -0,0 +1,322 @@ +package arcade.potts.agent.module; + +import java.util.EnumMap; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.MockedConstruction; +import sim.engine.Schedule; +import ec.util.MersenneTwisterFast; +import arcade.core.env.grid.Grid; +import arcade.core.sim.Simulation; +import arcade.core.util.GrabBag; +import arcade.core.util.Parameters; +import arcade.potts.agent.cell.PottsCell; +import arcade.potts.agent.cell.PottsCellContainer; +import arcade.potts.agent.cell.PottsCellFactory; +import arcade.potts.agent.cell.PottsCellFlyGMC; +import arcade.potts.agent.cell.PottsCellFlyNeuron; +import arcade.potts.env.location.PottsLocation; +import arcade.potts.env.location.PottsLocation2D; +import arcade.potts.sim.Potts; +import arcade.potts.sim.PottsSimulation; +import arcade.potts.util.PottsEnums.Region; +import arcade.potts.util.PottsEnums.State; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockConstruction; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class PottsModuleFlyGMCDifferentiationTest { + private int[][][] dummyIDs; + + private int[][][] dummyRegions; + + private Simulation sim; + + private Potts potts; + + private Grid grid; + + private PottsCellFactory cellFactory; + + private Schedule schedule; + + private PottsCellFlyGMC gmcCell; + + private PottsLocation2D location; + + private PottsLocation newLocation; + + private PottsCellContainer container; + + private PottsCell newCell; + + private GrabBag links; + + private Parameters parameters; + + private MersenneTwisterFast random; + + private MockedConstruction mockedConstruction; + + @BeforeEach + public final void setupMocks() { + dummyIDs = new int[1][1][1]; + dummyRegions = new int[0][0][0]; + + sim = mock(PottsSimulation.class); + potts = mock(Potts.class); + when(((PottsSimulation) sim).getPotts()).thenReturn(potts); + potts.ids = dummyIDs; + potts.regions = dummyRegions; + + grid = mock(Grid.class); + when(sim.getGrid()).thenReturn(grid); + cellFactory = mock(PottsCellFactory.class); + when(sim.getCellFactory()).thenReturn(cellFactory); + schedule = mock(Schedule.class); + when(sim.getSchedule()).thenReturn(schedule); + when(sim.getID()).thenReturn(123); + + gmcCell = mock(PottsCellFlyGMC.class); + location = mock(PottsLocation2D.class); + when(gmcCell.getLocation()).thenReturn(location); + newLocation = mock(PottsLocation.class); + when(location.split(any(MersenneTwisterFast.class))).thenReturn(newLocation); + + links = mock(GrabBag.class); + when(gmcCell.getLinks()).thenReturn(links); + int newPop = 2; + when(links.next(any(MersenneTwisterFast.class))).thenReturn(newPop); + + // Stub getters on the GMC cell for differentiated cell creation + when(gmcCell.getID()).thenReturn(100); + int parent = 0; + when(gmcCell.getParent()).thenReturn(parent); + when(gmcCell.getAge()).thenReturn(5); + when(gmcCell.getDivisions()).thenReturn(2); + when(gmcCell.getCriticalVolume()).thenReturn(1.0); + when(gmcCell.getCriticalHeight()).thenReturn(2.0); + EnumMap critRegionVolumes = new EnumMap<>(Region.class); + EnumMap critRegionHeights = new EnumMap<>(Region.class); + when(gmcCell.getCriticalRegionVolumes()).thenReturn(critRegionVolumes); + when(gmcCell.getCriticalRegionHeights()).thenReturn(critRegionHeights); + + parameters = mock(Parameters.class); + when(gmcCell.getParameters()).thenReturn(parameters); + + random = mock(MersenneTwisterFast.class); + + // Intercept construction of the differentiated cell container + mockedConstruction = + mockConstruction( + PottsCellContainer.class, + (mockContainer, context) -> { + // When convert() is called on this new container, return a + // differentiated cell + PottsCellFlyNeuron diffCell = mock(PottsCellFlyNeuron.class); + when(mockContainer.convert( + eq(cellFactory), + eq(location), + any(MersenneTwisterFast.class))) + .thenReturn(diffCell); + }); + } + + @AfterEach + final void tearDown() { + mockedConstruction.close(); + } + + @Test + public void addCell_called_callsExpectedMethods() { + // When the module calls make() on the cell, return Quiescent PottsCellContainer + // mock + container = mock(PottsCellContainer.class); + when(gmcCell.make(eq(123), eq(State.QUIESCENT), any(MersenneTwisterFast.class))) + .thenReturn(container); + newCell = mock(PottsCell.class); + when(container.convert(eq(cellFactory), eq(newLocation), any(MersenneTwisterFast.class))) + .thenReturn(newCell); + + PottsModuleProliferationVolumeBasedDivision module = + new PottsModuleFlyGMCDifferentiation(gmcCell); + module.addCell(random, sim); + verify(location).split(random); + verify(gmcCell).reset(dummyIDs, dummyRegions); + verify(gmcCell).make(123, State.QUIESCENT, random); + + verify(grid).addObject(newCell, null); + verify(potts).register(newCell); + verify(newCell).initialize(dummyIDs, dummyRegions); + verify(newCell).schedule(schedule); + + verify(grid).removeObject(gmcCell, location); + verify(gmcCell).stop(); + + PottsCellContainer constructed = mockedConstruction.constructed().get(0); + PottsCellFlyNeuron diffCell = + (PottsCellFlyNeuron) constructed.convert(cellFactory, location, random); + verify(grid).addObject(diffCell, null); + verify(potts).register(diffCell); + verify(diffCell).initialize(dummyIDs, dummyRegions); + verify(diffCell).schedule(schedule); + } + + @Test + public void updateGrowthRate_dynamicOff_setsBaseRate() { + // dynamicGrowthRateVolume = 0; base rate used + when(gmcCell.getParameters()).thenReturn(parameters); + when(parameters.getInt("proliferation/DYNAMIC_GROWTH_RATE_VOLUME")).thenReturn(0); + when(parameters.getDouble("proliferation/CELL_GROWTH_RATE")).thenReturn(7.5); + + PottsModuleFlyGMCDifferentiation module = new PottsModuleFlyGMCDifferentiation(gmcCell); + + module.updateGrowthRate(sim); + org.junit.jupiter.api.Assertions.assertEquals(7.5, module.cellGrowthRate, 1e-9); + } + + @Test + public void updateGrowthRate_dynamicOn_pdeLikeFalse_usesSelfVolumeAndEquilibriumRef() { + when(gmcCell.getParameters()).thenReturn(parameters); + when(parameters.getInt("proliferation/DYNAMIC_GROWTH_RATE_VOLUME")).thenReturn(1); + when(parameters.getDouble("proliferation/CELL_GROWTH_RATE")).thenReturn(4.0); + when(parameters.getDouble("proliferation/SIZE_TARGET")).thenReturn(1.2); + when(parameters.getInt("proliferation/PDELIKE")).thenReturn(0); + + // critVol = 150.0; sizeTarget = 1.2 + // vRef = critVol * (1 + sizeTarget) / 2 = 150.0 * 2.2 / 2 = 165.0 + when(gmcCell.getCriticalVolume()).thenReturn(150.0); + when(gmcCell.getLocation().getVolume()).thenReturn(30.0); + + PottsModuleFlyGMCDifferentiation module = + org.mockito.Mockito.spy(new PottsModuleFlyGMCDifferentiation(gmcCell)); + + org.mockito.Mockito.doNothing() + .when(module) + .updateCellVolumeBasedGrowthRate( + org.mockito.ArgumentMatchers.anyDouble(), + org.mockito.ArgumentMatchers.anyDouble()); + + module.updateGrowthRate(sim); + + double expectedVRef = 150.0 * (1.0 + 1.2) / 2.0; // 165.0 + org.mockito.Mockito.verify(module) + .updateCellVolumeBasedGrowthRate( + org.mockito.ArgumentMatchers.eq(30.0), + org.mockito.ArgumentMatchers.eq(expectedVRef)); + } + + @Test + public void + updateGrowthRate_dynamicOnPdeLikeTrue_usesAverageVolumeAndEquilibriumRefAcrossGMCs() { + // Flags + when(gmcCell.getParameters()).thenReturn(parameters); + when(parameters.getInt("proliferation/DYNAMIC_GROWTH_RATE_VOLUME")).thenReturn(1); + when(parameters.getDouble("proliferation/CELL_GROWTH_RATE")).thenReturn(4.0); + when(parameters.getDouble("proliferation/SIZE_TARGET")).thenReturn(1.2); + when(parameters.getInt("proliferation/PDELIKE")).thenReturn(1); + + // Same population for all GMCs we want included + when(gmcCell.getPop()).thenReturn(3); + + // Self (included in average) + when(gmcCell.getLocation().getVolume()).thenReturn(30.0); + when(gmcCell.getCriticalVolume()).thenReturn(150.0); + + // Two more GMCs in same population + PottsCellFlyGMC gmcB = mock(PottsCellFlyGMC.class); + PottsCellFlyGMC gmcC = mock(PottsCellFlyGMC.class); + when(gmcB.getPop()).thenReturn(3); + when(gmcC.getPop()).thenReturn(3); + + PottsLocation locB = mock(PottsLocation.class); + PottsLocation locC = mock(PottsLocation.class); + when(gmcB.getLocation()).thenReturn(locB); + when(gmcC.getLocation()).thenReturn(locC); + when(locB.getVolume()).thenReturn(10.0); + when(locC.getVolume()).thenReturn(20.0); + when(gmcB.getCriticalVolume()).thenReturn(100.0); + when(gmcC.getCriticalVolume()).thenReturn(200.0); + + // Noise: different type and/or different pop → must be ignored + PottsCell randomOtherPop = mock(PottsCell.class); + when(randomOtherPop.getPop()).thenReturn(99); + PottsCellFlyNeuron neuronSamePop = mock(PottsCellFlyNeuron.class); + when(neuronSamePop.getPop()).thenReturn(3); + + // Bag with self + two GMCs + noise + sim.util.Bag bag = new sim.util.Bag(); + bag.add(gmcCell); // self GMC (pop 3) + bag.add(gmcB); // GMC (pop 3) + bag.add(gmcC); // GMC (pop 3) + bag.add(randomOtherPop); // different pop → ignored + bag.add(neuronSamePop); // not a GMC → ignored + when(sim.getGrid().getAllObjects()).thenReturn(bag); + + PottsModuleFlyGMCDifferentiation module = + org.mockito.Mockito.spy(new PottsModuleFlyGMCDifferentiation(gmcCell)); + + // Observe the averaged args + org.mockito.Mockito.doNothing() + .when(module) + .updateCellVolumeBasedGrowthRate( + org.mockito.ArgumentMatchers.anyDouble(), + org.mockito.ArgumentMatchers.anyDouble()); + + module.updateGrowthRate(sim); + + // avgVol = (30 + 10 + 20) / 3 = 20.0 + // avgCritVol = (150 + 100 + 200) / 3 = 150.0 + // avgVRef = avgCritVol * (1 + sizeTarget) / 2 = 150.0 * (1 + 1.2) / 2 = 165.0 + double expectedAvgVol = (30.0 + 10.0 + 20.0) / 3.0; // 20.0 + double expectedAvgCrit = (150.0 + 100.0 + 200.0) / 3.0; // 150.0 + double expectedAvgVRef = expectedAvgCrit * (1.0 + 1.2) / 2.0; // 165.0 + + org.mockito.Mockito.verify(module) + .updateCellVolumeBasedGrowthRate( + org.mockito.ArgumentMatchers.eq(expectedAvgVol), + org.mockito.ArgumentMatchers.eq(expectedAvgVRef)); + } + + // computeEquilibriumVolume tests + + @Test + public void computeEquilibriumVolume_returnsArithmeticMeanOfCritAndDivisionVolumes() { + // critVol = 150.0; sizeTarget = 1.2 + // vRef = critVol * (1 + sizeTarget) / 2 = 150.0 * 2.2 / 2 = 165.0 + when(parameters.getDouble("proliferation/SIZE_TARGET")).thenReturn(1.2); + when(gmcCell.getCriticalVolume()).thenReturn(150.0); + + PottsModuleFlyGMCDifferentiation module = new PottsModuleFlyGMCDifferentiation(gmcCell); + org.junit.jupiter.api.Assertions.assertEquals( + 165.0, module.computeEquilibriumVolume(), 1e-9); + } + + @Test + public void computeEquilibriumVolume_differentSizeTarget_scalesCorrectly() { + // critVol = 100.0; sizeTarget = 2.0 + // vRef = 100.0 * (1 + 2.0) / 2 = 150.0 + when(parameters.getDouble("proliferation/SIZE_TARGET")).thenReturn(2.0); + when(gmcCell.getCriticalVolume()).thenReturn(100.0); + + PottsModuleFlyGMCDifferentiation module = new PottsModuleFlyGMCDifferentiation(gmcCell); + org.junit.jupiter.api.Assertions.assertEquals( + 150.0, module.computeEquilibriumVolume(), 1e-9); + } + + @Test + public void computeEquilibriumVolume_differentCritVol_scalesCorrectly() { + // critVol = 200.0; sizeTarget = 1.2 + // vRef = 200.0 * (1 + 1.2) / 2 = 220.0 + when(parameters.getDouble("proliferation/SIZE_TARGET")).thenReturn(1.2); + when(gmcCell.getCriticalVolume()).thenReturn(200.0); + + PottsModuleFlyGMCDifferentiation module = new PottsModuleFlyGMCDifferentiation(gmcCell); + org.junit.jupiter.api.Assertions.assertEquals( + 220.0, module.computeEquilibriumVolume(), 1e-9); + } +} diff --git a/test/arcade/potts/agent/module/PottsModuleProliferationVolumeBasedDivisionTest.java b/test/arcade/potts/agent/module/PottsModuleProliferationVolumeBasedDivisionTest.java index 254cc1371..4b028a17f 100644 --- a/test/arcade/potts/agent/module/PottsModuleProliferationVolumeBasedDivisionTest.java +++ b/test/arcade/potts/agent/module/PottsModuleProliferationVolumeBasedDivisionTest.java @@ -14,6 +14,7 @@ public class PottsModuleProliferationVolumeBasedDivisionTest { static class PottsModuleProliferationVolumeBasedDivisionMock extends PottsModuleProliferationVolumeBasedDivision { + boolean addCellCalled = false; boolean growthRateUpdated = false; From 731082f54a425a77f51d5073ea274e577f7f9fde Mon Sep 17 00:00:00 2001 From: jannetty Date: Sat, 11 Apr 2026 22:22:47 -0700 Subject: [PATCH 05/10] final formatting --- .../module/PottsModuleProliferationVolumeBasedDivisionTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/test/arcade/potts/agent/module/PottsModuleProliferationVolumeBasedDivisionTest.java b/test/arcade/potts/agent/module/PottsModuleProliferationVolumeBasedDivisionTest.java index 4b028a17f..733aaf896 100644 --- a/test/arcade/potts/agent/module/PottsModuleProliferationVolumeBasedDivisionTest.java +++ b/test/arcade/potts/agent/module/PottsModuleProliferationVolumeBasedDivisionTest.java @@ -16,6 +16,7 @@ static class PottsModuleProliferationVolumeBasedDivisionMock extends PottsModuleProliferationVolumeBasedDivision { boolean addCellCalled = false; + boolean growthRateUpdated = false; PottsModuleProliferationVolumeBasedDivisionMock(PottsCellFlyGMC cell) { From 6cb465dac0e49f077cdff0e074feb6d2aa9db29a Mon Sep 17 00:00:00 2001 From: jannetty Date: Sat, 11 Apr 2026 22:32:27 -0700 Subject: [PATCH 06/10] adding missing parameters to potts xml. Removing unnecessary parameter --- .../agent/module/PottsModuleFlyGMCDifferentiation.java | 3 --- src/arcade/potts/parameter.potts.xml | 7 +++++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiation.java b/src/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiation.java index b289586fa..35cc8fa2b 100644 --- a/src/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiation.java +++ b/src/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiation.java @@ -146,9 +146,6 @@ public void updateGrowthRate(Simulation sim) { // PDE-like: use population-wide averages for GMCs (same pop as this cell). // The reference volume is the population-average equilibrium volume: // avgVRef = avgCritVol * (1 + sizeTarget) / 2 - // This assumes VOLUME_BASED_CRITICAL_VOLUME_MULTIPLIER = 1 (so each GMC's - // birth volume equals its critVol). For multiplier != 1, avgCritVol would need - // to be replaced by the mean of (critVol_i / multiplier + sizeTarget*critVol_i)/2. sim.util.Bag objs = sim.getGrid().getAllObjects(); double volSum = 0.0; diff --git a/src/arcade/potts/parameter.potts.xml b/src/arcade/potts/parameter.potts.xml index ebc46e0da..c95d0ce61 100644 --- a/src/arcade/potts/parameter.potts.xml +++ b/src/arcade/potts/parameter.potts.xml @@ -64,6 +64,13 @@ + + + + + + + From 64ce606989f6b90c9df231418db55c27cacc5df1 Mon Sep 17 00:00:00 2001 From: jannetty Date: Sat, 11 Apr 2026 22:33:36 -0700 Subject: [PATCH 07/10] removing redundant section of docstring --- .../potts/agent/module/PottsModuleFlyGMCDifferentiation.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiation.java b/src/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiation.java index 35cc8fa2b..299116b01 100644 --- a/src/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiation.java +++ b/src/arcade/potts/agent/module/PottsModuleFlyGMCDifferentiation.java @@ -16,10 +16,7 @@ /** * Implementation of {@link PottsModuleProliferationVolumeBasedDivision} for fly GMC agents. These * cells divide into two {@link PottsCellFlyNeuron} cells. The links must be set in the setup file - * so that 100% of the daughter cells are Neurons. Implementation of {@link - * PottsModuleProliferationVolumeBasedDivision} for fly GMC agents. These cells divide into two - * {@link PottsCellFlyNeuron} cells. The links must be set in the setup file so that 100% of the - * daughter cells are Neurons. + * so that 100% of the daughter cells are Neurons. */ public class PottsModuleFlyGMCDifferentiation extends PottsModuleProliferationVolumeBasedDivision { From 2ce8a27ce068ce820308c5c213ea0b7a4ee70037 Mon Sep 17 00:00:00 2001 From: jannetty Date: Sat, 11 Apr 2026 22:37:23 -0700 Subject: [PATCH 08/10] puppycrawler asking for some odd spacing --- .../module/PottsModuleProliferationVolumeBasedDivisionTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/test/arcade/potts/agent/module/PottsModuleProliferationVolumeBasedDivisionTest.java b/test/arcade/potts/agent/module/PottsModuleProliferationVolumeBasedDivisionTest.java index 733aaf896..7063f37bf 100644 --- a/test/arcade/potts/agent/module/PottsModuleProliferationVolumeBasedDivisionTest.java +++ b/test/arcade/potts/agent/module/PottsModuleProliferationVolumeBasedDivisionTest.java @@ -17,6 +17,7 @@ static class PottsModuleProliferationVolumeBasedDivisionMock boolean addCellCalled = false; + boolean growthRateUpdated = false; PottsModuleProliferationVolumeBasedDivisionMock(PottsCellFlyGMC cell) { From 3e8bebc1af88d046b7b52ce1842539af4273af06 Mon Sep 17 00:00:00 2001 From: jannetty Date: Sat, 11 Apr 2026 22:38:57 -0700 Subject: [PATCH 09/10] puppycrawl now wants me to undo the odd spacing it asked for --- .../module/PottsModuleProliferationVolumeBasedDivisionTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/test/arcade/potts/agent/module/PottsModuleProliferationVolumeBasedDivisionTest.java b/test/arcade/potts/agent/module/PottsModuleProliferationVolumeBasedDivisionTest.java index 7063f37bf..733aaf896 100644 --- a/test/arcade/potts/agent/module/PottsModuleProliferationVolumeBasedDivisionTest.java +++ b/test/arcade/potts/agent/module/PottsModuleProliferationVolumeBasedDivisionTest.java @@ -17,7 +17,6 @@ static class PottsModuleProliferationVolumeBasedDivisionMock boolean addCellCalled = false; - boolean growthRateUpdated = false; PottsModuleProliferationVolumeBasedDivisionMock(PottsCellFlyGMC cell) { From 9238f516207b8bdd11ef83f72a53fea52a02994a Mon Sep 17 00:00:00 2001 From: jannetty Date: Sat, 11 Apr 2026 22:48:59 -0700 Subject: [PATCH 10/10] removing part of PR more relevant to neuroblasts --- src/arcade/potts/sim/Potts.java | 2 +- src/arcade/potts/sim/Potts2D.java | 2 +- src/arcade/potts/sim/Potts3D.java | 2 +- test/arcade/potts/sim/PottsTest.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/arcade/potts/sim/Potts.java b/src/arcade/potts/sim/Potts.java index a4ffb0ee2..a0b46f0db 100644 --- a/src/arcade/potts/sim/Potts.java +++ b/src/arcade/potts/sim/Potts.java @@ -398,7 +398,7 @@ public PottsCell getCell(int id) { * @param z the z coordinate * @return the list of unique IDs */ - public abstract HashSet getUniqueIDs(int x, int y, int z); + abstract HashSet getUniqueIDs(int x, int y, int z); /** * Gets unique regions adjacent to given voxel. diff --git a/src/arcade/potts/sim/Potts2D.java b/src/arcade/potts/sim/Potts2D.java index f6d7dbb6f..011d6f850 100644 --- a/src/arcade/potts/sim/Potts2D.java +++ b/src/arcade/potts/sim/Potts2D.java @@ -151,7 +151,7 @@ private boolean getConnectivityThreeNeighbors(boolean[][] subarray) { } @Override - public HashSet getUniqueIDs(int x, int y, int z) { + HashSet getUniqueIDs(int x, int y, int z) { int id = ids[z][x][y]; HashSet unique = new HashSet<>(); diff --git a/src/arcade/potts/sim/Potts3D.java b/src/arcade/potts/sim/Potts3D.java index 7f3429650..7c4686e8d 100644 --- a/src/arcade/potts/sim/Potts3D.java +++ b/src/arcade/potts/sim/Potts3D.java @@ -465,7 +465,7 @@ private boolean getConnectivityFiveNeighbors(boolean[][][] array) { } @Override - public HashSet getUniqueIDs(int x, int y, int z) { + HashSet getUniqueIDs(int x, int y, int z) { int id = ids[z][x][y]; HashSet unique = new HashSet<>(); diff --git a/test/arcade/potts/sim/PottsTest.java b/test/arcade/potts/sim/PottsTest.java index 305658832..04c61d693 100644 --- a/test/arcade/potts/sim/PottsTest.java +++ b/test/arcade/potts/sim/PottsTest.java @@ -61,7 +61,7 @@ boolean getConnectivity(boolean[][][] array, boolean zero) { } @Override - public HashSet getUniqueIDs(int x, int y, int z) { + HashSet getUniqueIDs(int x, int y, int z) { HashSet set = new HashSet<>(); if (x == 0 && y == 0) { set.add(1);