Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/config/checks.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
<property name="id" value="LineLengthTest"/>
<property name="fileExtensions" value=".java" />
<property name="max" value="120"/>
<property name="severity" value="error"/>
</module>

<!-- Checks for whitespace -->
Expand Down
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ jacocoTestReport {
})
}
reports {
xml.enabled true
html.enabled true
xml.required.set(true)
html.required.set(true)
}
}

Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
6 changes: 6 additions & 0 deletions src/arcade/potts/agent/cell/PottsCellContainer.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import arcade.core.util.GrabBag;
import arcade.core.util.MiniBox;
import arcade.core.util.Parameters;
import arcade.potts.util.PottsEnums.Phase;
import arcade.potts.util.PottsEnums.Region;
import static arcade.potts.util.PottsEnums.Phase;
import static arcade.potts.util.PottsEnums.Region;

Expand Down Expand Up @@ -176,6 +178,10 @@ public Cell convert(
return new PottsCellFlyNeuron(this, location, parameters, links);
case "fly-gmc":
return new PottsCellFlyGMC(this, location, parameters, links);
case "fly-stem-wt":
return new PottsCellFlyStem(this, location, parameters, links);
case "fly-stem-mudmut":
return new PottsCellFlyStem(this, location, parameters, links);
default:
case "stem":
return new PottsCellStem(this, location, parameters, links);
Expand Down
10 changes: 8 additions & 2 deletions src/arcade/potts/agent/cell/PottsCellFactory.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package arcade.potts.agent.cell;

import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.HashMap;
Expand Down Expand Up @@ -213,8 +214,13 @@ void parseValues(Series series) {
if (linkKeys.size() > 0) {
links = new GrabBag();
for (String linkKey : linkKeys) {
int popLink = series.populations.get(linkKey).getInt("CODE");
links.add(popLink, linksBox.getDouble(linkKey));
try {
int popLink = series.populations.get(linkKey).getInt("CODE");
links.add(popLink, linksBox.getDouble(linkKey));
} catch (Exception e) {
throw new InvalidParameterException(
"A population link is set that references a population that does not exist.");
}
}
}

Expand Down
179 changes: 179 additions & 0 deletions src/arcade/potts/agent/cell/PottsCellFlyStem.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
package arcade.potts.agent.cell;

import ec.util.MersenneTwisterFast;
import arcade.core.agent.cell.CellState;
import arcade.core.env.location.Location;
import arcade.core.util.GrabBag;
import arcade.core.util.Parameters;
import arcade.core.util.Vector;
import arcade.potts.agent.module.PottsModule;
import arcade.potts.agent.module.PottsModuleFlyStemProliferation;
import arcade.potts.util.PottsEnums.Phase;
import static arcade.potts.util.PottsEnums.State;

/**
* Implementation of {@link PottsCell} for fly stem agents. Genotype is specified by the StemType
* enum.
*/
public class PottsCellFlyStem extends PottsCell {
/** Enum outlining parameters for each cell type. */
public enum StemType {
/** Wild type stem cell. */
WT(50, 86, 0),
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make clear in documentation that these values are the named variables below


/** mud Mutant stem cell. */
MUDMUT(50, 50, -90);

/** Percentage x offset from cell edge where division will occur. */
public final int splitOffsetPercentX;

/** Percentage y offset from cell edge where division will occur. */
public final int splitOffsetPercentY;

/** Default direction of division is rotated this much off the apical vector. */
public final double splitDirectionRotation;

/**
* The proportion of the NB division volume allocated to the GMC daughter cell. Derived from
* {@code splitOffsetPercentY} as {@code 1 - splitOffsetPercentY / 100}
*/
public final double daughterCellCriticalVolumeProportion;

/**
* Constructor for StemType.
*
* @param splitOffsetPercentX percentage x offset from cell edge where division will occur
* @param splitOffsetPercentY percentage y offset from cell edge where division will occur
* @param splitDirectionRotation the plane of division's rotation off the apical vector
*/
StemType(int splitOffsetPercentX, int splitOffsetPercentY, double splitDirectionRotation) {
this.splitOffsetPercentX = splitOffsetPercentX;
this.splitOffsetPercentY = splitOffsetPercentY;
this.splitDirectionRotation = splitDirectionRotation;
this.daughterCellCriticalVolumeProportion = 1.0 - splitOffsetPercentY / 100.0;
}
}

/** The type of stem cell. */
public final StemType stemType;

/** The cell's apical axis. The vector points towards the apical membrane. */
private Vector apicalAxis;

/**
* Constructor for PottsCellFlyStem.
*
* @param container the container for the cell
* @param location the location of the cell
* @param parameters the parameters for the cell
* @param links the links for the cell
* @throws IllegalArgumentException if the stem type is not recognized
*/
public PottsCellFlyStem(
PottsCellContainer container, Location location, Parameters parameters, GrabBag links) {
super(container, location, parameters, links);

if (module != null) {
((PottsModule) module).setPhase(Phase.UNDEFINED);
}

String stemTypeString = parameters.getString("CLASS");
switch (stemTypeString) {
case "fly-stem-wt":
stemType = StemType.WT;
break;
case "fly-stem-mudmut":
stemType = StemType.MUDMUT;
break;
default:
throw new IllegalArgumentException("Unknown StemType: " + stemTypeString);
}
}

/**
* Sets the apical axis.
*
* @param apicalAxis the new apical axis
*/
public void setApicalAxis(Vector apicalAxis) {
this.apicalAxis = apicalAxis;
}

/**
* Gets the apical axis of the cell. If no apical axis is set, it returns a vector along the y
* axis as a default vector
*
* @return the apical axis of the cell
*/
public Vector getApicalAxis() {
if (apicalAxis != null) {
return apicalAxis;
} else {
return new Vector(0, 1, 0);
}
}

@Override
public PottsCellContainer make(int newID, CellState newState, MersenneTwisterFast random) {
throw new UnsupportedOperationException(
"make(int, CellState, MersenneTwisterFast) not supported."
+ "Please use make(int, CellState, MersenneTwisterFast, int, double) instead.");
}

/**
* Makes a potts cell container with information about the daughter cell's population and
* critical volume calculated by the proliferation module.
*
* @param newID the new cell ID
* @param newState the new cell state
* @param random the random number generator
* @param newPop the new cell population
* @param daughterCellCriticalVolume the new cell's critical volume
* @return a {@link PottsCellContainer} with the information needed to make the daughter cell
*/
public PottsCellContainer make(
int newID,
CellState newState,
MersenneTwisterFast random,
int newPop,
double daughterCellCriticalVolume) {

divisions++;

return new PottsCellContainer(
newID,
id,
newPop,
age,
divisions,
newState,
Phase.UNDEFINED,
0,
null,
daughterCellCriticalVolume,
criticalHeight,
criticalRegionVolumes,
criticalRegionHeights);
}

@Override
void setStateModule(CellState newState) {
switch ((State) newState) {
case PROLIFERATIVE:
module = new PottsModuleFlyStemProliferation(this);
break;
default:
module = null;
break;
}
}

/**
* Gets the stem type of the cell.
*
* @return the stem type of the cell
*/
public final StemType getStemType() {
return stemType;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package arcade.potts.agent.module;

import sim.util.Bag;
import ec.util.MersenneTwisterFast;
import arcade.core.agent.cell.CellContainer;
import arcade.core.env.location.Location;
Expand All @@ -20,20 +21,55 @@
*/
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.
*
* <p>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}.
*
* <p>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:
*
* <pre>
* V_ref = (criticalVolume + sizeTarget * criticalVolume) / 2
* = criticalVolume * (1 + sizeTarget) / 2
* </pre>
*
* <p>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.
*
* <p>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
Expand All @@ -55,7 +91,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
Expand Down Expand Up @@ -88,7 +124,55 @@ 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());
}

/**
* 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;
} 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
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 PottsCell)) {
continue;
}

PottsCell c = (PottsCell) o;
if (c.getPop() != cell.getPop()) {
continue; // keep to same population
}

if (o instanceof PottsCellFlyGMC) {
PottsCellFlyGMC gmc = (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);
}
}
}
}
Loading
Loading