diff --git a/coverage/arcade.patch.agent.cell/PatchCell.html b/coverage/arcade.patch.agent.cell/PatchCell.html
index c2d818cd..07fc43de 100644
--- a/coverage/arcade.patch.agent.cell/PatchCell.html
+++ b/coverage/arcade.patch.agent.cell/PatchCell.html
@@ -1 +1 @@
-
PatchCellPatchCell
Element | Missed Instructions | Cov. | Missed Branches | Cov. | Missed | Cxty | Missed | Lines | Missed | Methods |
Total | 287 of 540 | 46% | 38 of 53 | 28% | 41 | 58 | 69 | 131 | 19 | 30 |
findFreeLocations(Simulation, PatchLocation, double, double) | | 28% | | 7% | 7 | 8 | 18 | 25 | 0 | 1 |
step(SimState) | | 51% | | 34% | 10 | 14 | 13 | 24 | 0 | 1 |
convert() | | 0% | | n/a | 1 | 1 | 1 | 1 | 1 | 1 |
PatchCell(PatchCellContainer, Location, Parameters, GrabBag) | | 81% | | 50% | 1 | 2 | 5 | 30 | 0 | 1 |
calculateTotalVolume(Bag) | | 0% | | 0% | 2 | 2 | 5 | 5 | 1 | 1 |
selectBestLocation(Simulation, PatchLocation, double, double, MersenneTwisterFast) | | 0% | | 0% | 2 | 2 | 3 | 3 | 1 | 1 |
makeProcess(ProcessDomain, String) | | 0% | | 0% | 3 | 3 | 4 | 4 | 1 | 1 |
schedule(Schedule) | | 0% | | n/a | 1 | 1 | 2 | 2 | 1 | 1 |
getProcess(ProcessDomain) | | 0% | | n/a | 1 | 1 | 1 | 1 | 1 | 1 |
setFlag(PatchEnums.Flag) | | 0% | | n/a | 1 | 1 | 2 | 2 | 1 | 1 |
setVolume(double) | | 0% | | n/a | 1 | 1 | 2 | 2 | 1 | 1 |
setEnergy(double) | | 0% | | n/a | 1 | 1 | 2 | 2 | 1 | 1 |
stop() | | 0% | | n/a | 1 | 1 | 2 | 2 | 1 | 1 |
getID() | | 0% | | n/a | 1 | 1 | 1 | 1 | 1 | 1 |
getParent() | | 0% | | n/a | 1 | 1 | 1 | 1 | 1 | 1 |
getPop() | | 0% | | n/a | 1 | 1 | 1 | 1 | 1 | 1 |
getAge() | | 0% | | n/a | 1 | 1 | 1 | 1 | 1 | 1 |
getDivisions() | | 0% | | n/a | 1 | 1 | 1 | 1 | 1 | 1 |
getModule() | | 0% | | n/a | 1 | 1 | 1 | 1 | 1 | 1 |
getVolume() | | 0% | | n/a | 1 | 1 | 1 | 1 | 1 | 1 |
getHeight() | | 0% | | n/a | 1 | 1 | 1 | 1 | 1 | 1 |
getEnergy() | | 0% | | n/a | 1 | 1 | 1 | 1 | 1 | 1 |
setState(CellState) | | 100% | | 100% | 0 | 4 | 0 | 11 | 0 | 1 |
addCycle(int) | | 100% | | n/a | 0 | 1 | 0 | 2 | 0 | 1 |
getState() | | 100% | | n/a | 0 | 1 | 0 | 1 | 0 | 1 |
getLocation() | | 100% | | n/a | 0 | 1 | 0 | 1 | 0 | 1 |
getParameters() | | 100% | | n/a | 0 | 1 | 0 | 1 | 0 | 1 |
getCriticalVolume() | | 100% | | n/a | 0 | 1 | 0 | 1 | 0 | 1 |
getCriticalHeight() | | 100% | | n/a | 0 | 1 | 0 | 1 | 0 | 1 |
getCycles() | | 100% | | n/a | 0 | 1 | 0 | 1 | 0 | 1 |
\ No newline at end of file
+PatchCellPatchCell
Element | Missed Instructions | Cov. | Missed Branches | Cov. | Missed | Cxty | Missed | Lines | Missed | Methods |
Total | 183 of 606 | 69% | 20 of 65 | 69% | 29 | 65 | 41 | 140 | 16 | 31 |
step(SimState) | | 59% | | 46% | 9 | 14 | 10 | 24 | 0 | 1 |
convert() | | 0% | | n/a | 1 | 1 | 1 | 1 | 1 | 1 |
PatchCell(PatchCellContainer, Location, Parameters, GrabBag) | | 82% | | 75% | 1 | 3 | 5 | 32 | 0 | 1 |
selectBestLocation(Simulation, MersenneTwisterFast) | | 0% | | 0% | 2 | 2 | 3 | 3 | 1 | 1 |
makeProcess(ProcessDomain, String) | | 0% | | 0% | 3 | 3 | 4 | 4 | 1 | 1 |
schedule(Schedule) | | 0% | | n/a | 1 | 1 | 2 | 2 | 1 | 1 |
getProcess(ProcessDomain) | | 0% | | n/a | 1 | 1 | 1 | 1 | 1 | 1 |
setFlag(PatchEnums.Flag) | | 0% | | n/a | 1 | 1 | 2 | 2 | 1 | 1 |
setVolume(double) | | 0% | | n/a | 1 | 1 | 2 | 2 | 1 | 1 |
setEnergy(double) | | 0% | | n/a | 1 | 1 | 2 | 2 | 1 | 1 |
stop() | | 0% | | n/a | 1 | 1 | 2 | 2 | 1 | 1 |
getID() | | 0% | | n/a | 1 | 1 | 1 | 1 | 1 | 1 |
getParent() | | 0% | | n/a | 1 | 1 | 1 | 1 | 1 | 1 |
getAge() | | 0% | | n/a | 1 | 1 | 1 | 1 | 1 | 1 |
getDivisions() | | 0% | | n/a | 1 | 1 | 1 | 1 | 1 | 1 |
getModule() | | 0% | | n/a | 1 | 1 | 1 | 1 | 1 | 1 |
getHeight() | | 0% | | n/a | 1 | 1 | 1 | 1 | 1 | 1 |
getEnergy() | | 0% | | n/a | 1 | 1 | 1 | 1 | 1 | 1 |
findFreeLocations(Simulation) | | 100% | | 100% | 0 | 6 | 0 | 12 | 0 | 1 |
checkLocation(Simulation, PatchLocation, double, double, int, int) | | 100% | | 100% | 0 | 8 | 0 | 20 | 0 | 1 |
setState(CellState) | | 100% | | 100% | 0 | 4 | 0 | 11 | 0 | 1 |
calculateTotalVolume(Bag) | | 100% | | 100% | 0 | 2 | 0 | 5 | 0 | 1 |
addCycle(int) | | 100% | | n/a | 0 | 1 | 0 | 2 | 0 | 1 |
getPop() | | 100% | | n/a | 0 | 1 | 0 | 1 | 0 | 1 |
getState() | | 100% | | n/a | 0 | 1 | 0 | 1 | 0 | 1 |
getLocation() | | 100% | | n/a | 0 | 1 | 0 | 1 | 0 | 1 |
getParameters() | | 100% | | n/a | 0 | 1 | 0 | 1 | 0 | 1 |
getVolume() | | 100% | | n/a | 0 | 1 | 0 | 1 | 0 | 1 |
getCriticalVolume() | | 100% | | n/a | 0 | 1 | 0 | 1 | 0 | 1 |
getCriticalHeight() | | 100% | | n/a | 0 | 1 | 0 | 1 | 0 | 1 |
getCycles() | | 100% | | n/a | 0 | 1 | 0 | 1 | 0 | 1 |
\ No newline at end of file
diff --git a/coverage/arcade.patch.agent.cell/PatchCell.java.html b/coverage/arcade.patch.agent.cell/PatchCell.java.html
index 5d83aaf0..2b58524a 100644
--- a/coverage/arcade.patch.agent.cell/PatchCell.java.html
+++ b/coverage/arcade.patch.agent.cell/PatchCell.java.html
@@ -77,6 +77,9 @@
/** Cell population index. */
final int pop;
+ /** Maximum number of cells from its population allowed in a {@link Location}. */
+ final int maxDensity;
+
/** Cell state. */
CellState state;
@@ -129,7 +132,7 @@
final GrabBag links;
/** List of cell cycle lengths (in minutes). */
- private final Bag cycles = new Bag();
+ private final Bag cycles = new Bag();
/**
* Creates a {@code PatchCell} agent.
@@ -149,109 +152,112 @@
* @param links the map of population links
*/
public PatchCell(
- PatchCellContainer container, Location location, Parameters parameters, GrabBag links) {
- this.id = container.id;
- this.parent = container.parent;
- this.pop = container.pop;
- this.age = container.age;
- this.energy = 0;
- this.divisions = container.divisions;
- this.location = (PatchLocation) location;
- this.volume = container.volume;
- this.height = container.height;
- this.criticalVolume = container.criticalVolume;
- this.criticalHeight = container.criticalHeight;
- this.flag = Flag.UNDEFINED;
- this.parameters = parameters;
- this.links = links;
-
- setState(container.state);
+ PatchCellContainer container, Location location, Parameters parameters, GrabBag links) {
+ this.id = container.id;
+ this.parent = container.parent;
+ this.pop = container.pop;
+ this.age = container.age;
+ this.energy = 0;
+ this.divisions = container.divisions;
+ this.location = (PatchLocation) location;
+ this.volume = container.volume;
+ this.height = container.height;
+ this.criticalVolume = container.criticalVolume;
+ this.criticalHeight = container.criticalHeight;
+ this.flag = Flag.UNDEFINED;
+ this.parameters = parameters;
+ this.links = links;
+
+ setState(container.state);
// Set loaded parameters.
- necroticFraction = parameters.getDouble("NECROTIC_FRACTION");
- senescentFraction = parameters.getDouble("SENESCENT_FRACTION");
- energyThreshold = -parameters.getDouble("ENERGY_THRESHOLD");
- apoptosisAge = parameters.getDouble("APOPTOSIS_AGE");
+ necroticFraction = parameters.getDouble("NECROTIC_FRACTION");
+ senescentFraction = parameters.getDouble("SENESCENT_FRACTION");
+ energyThreshold = -parameters.getDouble("ENERGY_THRESHOLD");
+ apoptosisAge = parameters.getDouble("APOPTOSIS_AGE");
+
+ int densityInput = parameters.getInt("MAX_DENSITY");
+ maxDensity = (densityInput >= 0 ? densityInput : Integer.MAX_VALUE);
// Add cell processes.
- processes = new HashMap<>();
- MiniBox processBox = parameters.filter("(PROCESS)");
- for (String processKey : processBox.getKeys()) {
- ProcessDomain domain = Domain.valueOf(processKey);
- String version = processBox.get(processKey);
- Process process = makeProcess(domain, version);
- processes.put(domain, process);
- }
- }
+ processes = new HashMap<>();
+ MiniBox processBox = parameters.filter("(PROCESS)");
+ for (String processKey : processBox.getKeys()) {
+ ProcessDomain domain = Domain.valueOf(processKey);
+ String version = processBox.get(processKey);
+ Process process = makeProcess(domain, version);
+ processes.put(domain, process);
+ }
+ }
@Override
public int getID() {
- return id;
+ return id;
}
@Override
public int getParent() {
- return parent;
+ return parent;
}
@Override
public int getPop() {
- return pop;
+ return pop;
}
@Override
public CellState getState() {
- return state;
+ return state;
}
@Override
public int getAge() {
- return age;
+ return age;
}
@Override
public int getDivisions() {
- return divisions;
+ return divisions;
}
@Override
public Location getLocation() {
- return location;
+ return location;
}
@Override
public Module getModule() {
- return module;
+ return module;
}
@Override
public Process getProcess(ProcessDomain domain) {
- return processes.get(domain);
+ return processes.get(domain);
}
@Override
public Parameters getParameters() {
- return parameters;
+ return parameters;
}
@Override
public double getVolume() {
- return volume;
+ return volume;
}
@Override
public double getHeight() {
- return height;
+ return height;
}
@Override
public double getCriticalVolume() {
- return criticalVolume;
+ return criticalVolume;
}
@Override
public double getCriticalHeight() {
- return criticalHeight;
+ return criticalHeight;
}
/**
@@ -260,7 +266,7 @@
* @return the energy level
*/
public double getEnergy() {
- return energy;
+ return energy;
}
/**
@@ -269,8 +275,8 @@
* @param flag the target cell flag
*/
public void setFlag(Flag flag) {
- this.flag = flag;
- }
+ this.flag = flag;
+ }
/**
* Sets the cell volume.
@@ -278,8 +284,8 @@
* @param volume the target cell volume
*/
public void setVolume(double volume) {
- this.volume = volume;
- }
+ this.volume = volume;
+ }
/**
* Sets the cell energy level.
@@ -287,8 +293,8 @@
* @param energy the target energy level
*/
public void setEnergy(double energy) {
- this.energy = energy;
- }
+ this.energy = energy;
+ }
/**
* Adds a completed cell cycle length [min] to the list of lengths.
@@ -296,8 +302,8 @@
* @param val the cell cycle length
*/
public void addCycle(int val) {
- cycles.add(val);
- }
+ cycles.add(val);
+ }
/**
* Gets the list of cell cycle lengths.
@@ -305,34 +311,34 @@
* @return the list of cell cycle lengths
*/
public Bag getCycles() {
- return cycles;
+ return cycles;
}
@Override
public void stop() {
- stopper.stop();
- }
+ stopper.stop();
+ }
@Override
public void setState(CellState state) {
- this.state = state;
- this.flag = Flag.UNDEFINED;
+ this.state = state;
+ this.flag = Flag.UNDEFINED;
- switch ((State) state) {
+ switch ((State) state) {
case PROLIFERATIVE:
- module = new PatchModuleProliferation(this);
- break;
+ module = new PatchModuleProliferation(this);
+ break;
case MIGRATORY:
- module = new PatchModuleMigration(this);
- break;
+ module = new PatchModuleMigration(this);
+ break;
case APOPTOTIC:
- module = new PatchModuleApoptosis(this);
- break;
+ module = new PatchModuleApoptosis(this);
+ break;
default:
- module = null;
+ module = null;
break;
}
- }
+ }
/**
* Makes the specified {@link Process} object.
@@ -342,76 +348,76 @@
* @return the process instance
*/
public Process makeProcess(ProcessDomain domain, String version) {
- switch ((Domain) domain) {
+ switch ((Domain) domain) {
case METABOLISM:
- return PatchProcessMetabolism.make(this, version);
+ return PatchProcessMetabolism.make(this, version);
case SIGNALING:
- return PatchProcessSignaling.make(this, version);
+ return PatchProcessSignaling.make(this, version);
case UNDEFINED:
default:
- return null;
+ return null;
}
}
@Override
public void schedule(Schedule schedule) {
- stopper = schedule.scheduleRepeating(this, Ordering.CELLS.ordinal(), 1);
- }
+ stopper = schedule.scheduleRepeating(this, Ordering.CELLS.ordinal(), 1);
+ }
@Override
public void step(SimState simstate) {
- Simulation sim = (Simulation) simstate;
+ Simulation sim = (Simulation) simstate;
// Increase age of cell.
- age++;
+ age++;
- if (state != State.APOPTOTIC && age > apoptosisAge) {
- setState(State.APOPTOTIC);
+ if (state != State.APOPTOTIC && age > apoptosisAge) {
+ setState(State.APOPTOTIC);
}
// Step metabolism process.
- processes.get(Domain.METABOLISM).step(simstate.random, sim);
+ processes.get(Domain.METABOLISM).step(simstate.random, sim);
// Check energy status. If cell has less energy than threshold, it will
// necrose. If overall energy is negative, then cell enters quiescence.
- if (state != State.APOPTOTIC && energy < 0) {
- if (energy < energyThreshold) {
- if (simstate.random.nextDouble() > necroticFraction) {
- setState(State.APOPTOTIC);
+ if (state != State.APOPTOTIC && energy < 0) {
+ if (energy < energyThreshold) {
+ if (simstate.random.nextDouble() > necroticFraction) {
+ setState(State.APOPTOTIC);
} else {
- setState(State.NECROTIC);
+ setState(State.NECROTIC);
}
- } else if (state != State.QUIESCENT && state != State.SENESCENT) {
- setState(State.QUIESCENT);
+ } else if (state != State.QUIESCENT && state != State.SENESCENT) {
+ setState(State.QUIESCENT);
}
}
// Step signaling network process.
- processes.get(Domain.SIGNALING).step(simstate.random, sim);
+ processes.get(Domain.SIGNALING).step(simstate.random, sim);
// Change state from undefined.
- if (state == State.UNDEFINED) {
- if (flag == Flag.MIGRATORY) {
- setState(State.MIGRATORY);
- } else if (divisions == 0) {
- if (simstate.random.nextDouble() > senescentFraction) {
- setState(State.APOPTOTIC);
+ if (state == State.UNDEFINED) {
+ if (flag == Flag.MIGRATORY) {
+ setState(State.MIGRATORY);
+ } else if (divisions == 0) {
+ if (simstate.random.nextDouble() > senescentFraction) {
+ setState(State.APOPTOTIC);
} else {
- setState(State.SENESCENT);
+ setState(State.SENESCENT);
}
} else {
- setState(State.PROLIFERATIVE);
+ setState(State.PROLIFERATIVE);
}
}
// Step the module for the cell state.
- if (module != null) {
- module.step(simstate.random, sim);
+ if (module != null) {
+ module.step(simstate.random, sim);
}
- }
+ }
@Override
public CellContainer convert() {
- return new PatchCellContainer(
+ return new PatchCellContainer(
id,
parent,
pop,
@@ -431,101 +437,103 @@
* @return the total volume
*/
public static double calculateTotalVolume(Bag bag) {
- double totalVolume = 0;
- for (Object obj : bag) {
- totalVolume += ((Cell) obj).getVolume();
- }
- return totalVolume;
+ double totalVolume = 0;
+ for (Object obj : bag) {
+ totalVolume += ((Cell) obj).getVolume();
+ }
+ return totalVolume;
}
/**
- * Find free locations in the patch neighborhood.
+ * Selects a random location for a cell to be added or move into.
*
* @param sim the simulation instance
- * @param currentLocation the current location
- * @param targetVolume the target volume of the cell to add or move
- * @param targetHeight the target height of the cell to add or move
- * @return a list of free locations
+ * @param random the random number generator
+ * @return the best location or null if no valid locations
*/
- static Bag findFreeLocations(
- Simulation sim,
- PatchLocation currentLocation,
- double targetVolume,
- double targetHeight) {
- Bag freeLocations = new Bag();
- int locationMax = currentLocation.getMaximum();
- double locationVolume = currentLocation.getVolume();
- double locationArea = currentLocation.getArea();
- PatchGrid grid = (PatchGrid) sim.getGrid();
-
- // Iterate through each neighbor location and check if cell is able
- // to move into it based on if it does not increase volume above hex
- // volume and that each agent exists at tolerable height.
- locationCheck:
- for (Location neighborLocation : currentLocation.getNeighbors()) {
- Bag bag = new Bag(grid.getObjectsAtLocation(neighborLocation));
- int n = bag.numObjs; // number of agents in location
-
- if (n == 0) {
- freeLocations.add(neighborLocation); // no other cells in new location
- } else if (n == locationMax) {
- continue; // location already full
- } else {
- double totalVolume = calculateTotalVolume(bag) + targetVolume;
- double currentHeight = totalVolume / locationArea;
-
- // Check if total volume of cells with addition does not exceed
- // volume of the hexagonal location.
- if (totalVolume > locationVolume) {
- continue;
- }
-
- // Check if proposed cell can exist at a tolerable height.
- if (currentHeight > targetHeight) {
- continue;
- }
-
- // Check if neighbor cells can exist at a tolerable height.
- for (Object obj : bag) {
- if (currentHeight > ((Cell) obj).getCriticalHeight()) {
- continue locationCheck;
- }
- }
+ public PatchLocation selectBestLocation(Simulation sim, MersenneTwisterFast random) {
+ Bag locs = findFreeLocations(sim);
+ locs.shuffle(random);
+ return (locs.size() > 0 ? (PatchLocation) locs.get(0) : null);
+ }
- // TODO: ADD CHECK FOR MORE THAN ONE HEALTHY CELL AGENT.
+ /**
+ * Find free locations in the neighborhood of the cell.
+ *
+ * @param sim the simulation instance
+ * @return a list of free locations
+ */
+ public Bag findFreeLocations(Simulation sim) {
+ Bag freeLocations = new Bag();
+ PatchLocation currentLocation = this.location;
+ double targetVolume = (state == State.PROLIFERATIVE) ? volume * 0.5 : volume;
+ int densityAdjustment = (state == State.PROLIFERATIVE) ? 1 : 0;
+
+ if (checkLocation(
+ sim, currentLocation, 0, criticalHeight, pop, maxDensity - densityAdjustment)) {
+ freeLocations.add(currentLocation);
+ }
- // Add location to list of free locations.
- freeLocations.add(neighborLocation);
+ for (Location neighborLocation : currentLocation.getNeighbors()) {
+ PatchLocation neighbor = (PatchLocation) neighborLocation;
+ if (checkLocation(sim, neighbor, targetVolume, criticalHeight, pop, maxDensity)) {
+ freeLocations.add(neighborLocation);
}
- }
-
- // TODO: ADD CURRENT LOCATION
-
- return freeLocations;
+ }
+ return freeLocations;
}
/**
- * Selects the best location for a cell to be added or move into.
+ * Determine if a patch location is free.
*
- * <p>Each free location is scored based on glucose availability and distance from the center of
- * the simulation.
+ * <p>A location is free if the proposed cell volume can fit in the location without exceeding
+ * the max volume of a location, exceeding constituents' critical heights, and exceeding the
+ * population density is below the maximum.
*
* @param sim the simulation instance
- * @param location the current location
- * @param volume the target volume of cell to add or move
- * @param height the target height of the cell to add or move
- * @param random the random number generator
- * @return the best location
+ * @param loc the location
+ * @param addedVolume the volume added to the location
+ * @param maxHeight the maximum height tolerance
+ * @param population the population index
+ * @param maxDensity the maximum density of population in the location
+ * @return a list of free locations
*/
- public static PatchLocation selectBestLocation(
+ static boolean checkLocation(
Simulation sim,
- PatchLocation location,
- double volume,
- double height,
- MersenneTwisterFast random) {
- Bag locs = findFreeLocations(sim, location, volume, height);
- locs.shuffle(random);
- return (locs.size() > 0 ? (PatchLocation) locs.get(0) : null);
+ PatchLocation loc,
+ double addedVolume,
+ double maxHeight,
+ int population,
+ int maxDensity) {
+ double locationVolume = loc.getVolume();
+ double locationArea = loc.getArea();
+ PatchGrid grid = (PatchGrid) sim.getGrid();
+
+ Bag bag = new Bag(grid.getObjectsAtLocation(loc));
+
+ if (bag.numObjs != 0) {
+ double proposedVolume = calculateTotalVolume(bag) + addedVolume;
+ double proposedHeight = proposedVolume / locationArea;
+
+ if (proposedVolume > locationVolume || proposedHeight > maxHeight) {
+ return false;
+ }
+
+ int count = 0;
+ for (Object obj : bag) {
+ PatchCell cell = (PatchCell) obj;
+ if (proposedHeight > cell.getCriticalHeight()) {
+ return false;
+ }
+ if (cell.getPop() == population) {
+ count++;
+ if (count >= maxDensity) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
}
}