- * The class loads two XML files {@code command.xml} and {@code parameter.xml} - * that specify the command line parser options and the default parameter - * values, respectively. The setup XML file is then parsed to produce an array - * of {@link Series} objects, each of which defines replicates (differing only - * in random seed) of {@link arcade.core.sim.Simulation} instances to run. - *
- * If the visualization flag is used, only the first valid {@link Series} in the - * array is run. Otherwise, all valid {@code Series} are run. - *
- * An implementing package {@code The class loads two XML files {@code command.xml} and {@code parameter.xml} that specify the
+ * command line parser options and the default parameter values, respectively. The setup XML file is
+ * then parsed to produce an array of {@link Series} objects, each of which defines replicates
+ * (differing only in random seed) of {@link arcade.core.sim.Simulation} instances to run.
+ *
+ * If the visualization flag is used, only the first valid {@link Series} in the array is run.
+ * Otherwise, all valid {@code Series} are run.
+ *
+ * An implementing package {@code If running with a jar, the version is pulled from the jar manifest. Otherwise, the version
+ * is extracted using git.
*
- * @return the version number
+ * @return the version number
*/
static String loadVersion() {
String className = ARCADE.class.getSimpleName() + ".class";
String classPath = Objects.requireNonNull(ARCADE.class.getResource(className)).toString();
-
+
try {
if (classPath.startsWith("jar")) {
- String manifestPath = classPath.substring(0, classPath.lastIndexOf("!") + 1)
- + "/META-INF/MANIFEST.MF";
+ String manifestPath =
+ classPath.substring(0, classPath.lastIndexOf("!") + 1)
+ + "/META-INF/MANIFEST.MF";
Manifest manifest = new Manifest(new URL(manifestPath).openStream());
Attributes attr = manifest.getMainAttributes();
return attr.getValue("Implementation-Version");
} else {
Runtime runtime = Runtime.getRuntime();
-
+
InputStream inputStream = runtime.exec("git describe --tags").getInputStream();
Scanner scanner = new Scanner(inputStream).useDelimiter("\\A");
String describe = scanner.hasNext() ? scanner.next() : "";
-
+
inputStream = runtime.exec("git status --porcelain").getInputStream();
scanner = new Scanner(inputStream).useDelimiter("\\A");
String status = scanner.hasNext() ? scanner.next() : "";
-
+
return describe.trim().substring(1) + (status.isEmpty() ? "" : ".dirty");
}
} catch (Exception e) {
return "
- * If the {@code --vis} flag is set, then only the first valid series is
- * run. Otherwise, all valid series in the list are run.
*
- * @param series the list of {@link Series} instances
- * @param settings a container of parsed arguments
+ * If the {@code --vis} flag is set, then only the first valid series is run. Otherwise, all
+ * valid series in the list are run.
+ *
+ * @param series the list of {@link Series} instances
+ * @param settings a container of parsed arguments
*/
void runSeries(ArrayList
- * {@code Action} objects represent any entity that interacts with agents. They
- * can be used for:
+ *
+ * {@code Action} objects represent any entity that interacts with agents. They can be used for:
+ *
*
- * {@code Action} objects can affect {@link arcade.core.agent.cell.Cell}
- * populations or cell {@link arcade.core.agent.module.Module} or
- * {@link arcade.core.agent.process.Process} instances.
- * {@code Action} objects are analogs to {@link arcade.core.env.component.Component}
- * for steppables that affect agents.
+ *
+ * {@code Action} objects can affect {@link arcade.core.agent.cell.Cell} populations or cell
+ * {@link arcade.core.agent.module.Module} or {@link arcade.core.agent.process.Process} instances.
+ * {@code Action} objects are analogs to {@link arcade.core.env.component.Component} for steppables
+ * that affect agents.
*/
-
public interface Action extends Steppable {
/**
* Schedules the action in the simulation.
*
- * @param schedule the simulation schedule
+ * @param schedule the simulation schedule
*/
void schedule(Schedule schedule);
-
+
/**
* Registers a cell population to the action.
*
- * @param sim the simulation instance
- * @param population the cell population
+ * @param sim the simulation instance
+ * @param population the cell population
*/
void register(Simulation sim, String population);
}
diff --git a/src/arcade/core/agent/cell/Cell.java b/src/arcade/core/agent/cell/Cell.java
index f50688978..305e28a2d 100644
--- a/src/arcade/core/agent/cell/Cell.java
+++ b/src/arcade/core/agent/cell/Cell.java
@@ -7,152 +7,147 @@
import arcade.core.agent.process.Process;
import arcade.core.agent.process.ProcessDomain;
import arcade.core.env.location.Location;
-import arcade.core.util.MiniBox;
+import arcade.core.util.Parameters;
/**
* A {@code Cell} object represents a cell agent.
- *
- * Each cell is associated with a {@link Location} object that defines their
- * physical location. Each cell is also associated with a {@link Module} object
- * and/or {@link Process} objects that characterizes cellular behaviors and
- * states. The {@link Module} or {@link Process} object(s) are stepped during
- * the step method of the {@code Cell}.
+ *
+ * Each cell is associated with a {@link Location} object that defines their physical location.
+ * Each cell is also associated with a {@link Module} object and/or {@link Process} objects that
+ * characterizes cellular behaviors and states. The {@link Module} or {@link Process} object(s) are
+ * stepped during the step method of the {@code Cell}.
*/
-
public interface Cell extends Steppable {
/**
* Converts the cell into a {@link CellContainer}.
*
- * @return a {@link CellContainer} instance
+ * @return a {@link CellContainer} instance
*/
CellContainer convert();
-
+
/**
* Gets the unique cell ID.
*
- * @return the cell ID
+ * @return the cell ID
*/
int getID();
-
+
/**
* Gets the cell parent ID.
*
- * @return the parent ID
+ * @return the parent ID
*/
int getParent();
-
+
/**
* Gets the cell population index.
*
- * @return the cell population
+ * @return the cell population
*/
int getPop();
-
+
/**
* Gets the cell state.
*
- * @return the cell state
+ * @return the cell state
*/
CellState getState();
-
+
/**
* Gets the cell age.
*
- * @return the cell age
+ * @return the cell age
*/
int getAge();
-
+
/**
* Gets the cell divisions.
*
- * @return the number of divisions
+ * @return the number of divisions
*/
int getDivisions();
-
+
/**
* Gets the cell location object.
*
- * @return the cell location
+ * @return the cell location
*/
Location getLocation();
-
+
/**
* Gets the cell module object.
*
- * @return the cell module
+ * @return the cell module
*/
Module getModule();
-
+
/**
* Gets the cell process object.
*
- * @param domain the process domain
- * @return the cell process
+ * @param domain the process domain
+ * @return the cell process
*/
Process getProcess(ProcessDomain domain);
-
+
/**
- * Gets the cell population parameters.
+ * Gets the cell parameters.
*
- * @return a dictionary of parameters
+ * @return the cell parameters
*/
- MiniBox getParameters();
-
+ Parameters getParameters();
+
/**
* Gets the cell volume.
*
- * @return the cell volume
+ * @return the cell volume
*/
double getVolume();
-
+
/**
* Gets the cell height.
*
- * @return the cell height
+ * @return the cell height
*/
double getHeight();
-
+
/**
* Gets the critical volume.
*
- * @return the critical volume
+ * @return the critical volume
*/
double getCriticalVolume();
-
+
/**
* Gets the critical height.
*
- * @return the critical height
+ * @return the critical height
*/
double getCriticalHeight();
-
+
/**
* Sets the cell state.
*
- * @param state the cell state
+ * @param state the cell state
*/
void setState(CellState state);
-
- /**
- * Stop the cell from stepping.
- */
+
+ /** Stop the cell from stepping. */
void stop();
-
+
/**
- * Creates a new cell.
+ * Creates a new cell container.
*
- * @param id the new cell ID
- * @param state the new cell state
- * @param location the new cell location
- * @param random the random number generator
- * @return the new {@code Cell} object
+ * @param id the new cell ID
+ * @param state the new cell state
+ * @param random the random number generator
+ * @return the new {@code Cell} object
*/
- Cell make(int id, CellState state, Location location, MersenneTwisterFast random);
-
+ CellContainer make(int id, CellState state, MersenneTwisterFast random);
+
/**
* Schedules the cell in the simulation.
*
- * @param schedule the simulation schedule
+ * @param schedule the simulation schedule
*/
void schedule(Schedule schedule);
}
diff --git a/src/arcade/core/agent/cell/CellContainer.java b/src/arcade/core/agent/cell/CellContainer.java
index 7443d7075..ac2600465 100644
--- a/src/arcade/core/agent/cell/CellContainer.java
+++ b/src/arcade/core/agent/cell/CellContainer.java
@@ -1,29 +1,46 @@
package arcade.core.agent.cell;
+import ec.util.MersenneTwisterFast;
import arcade.core.env.location.Location;
+import arcade.core.util.Parameters;
/**
* Container class for {@link Cell} objects.
- *
- * The container implementation should contain the minimal set of information
- * needed to initialize a {@link Cell} object. The container is used by the
- * serializers/deserializers to save/load cell objects for the simulation.
+ *
+ * The container implementation should contain the minimal set of information needed to
+ * initialize a {@link Cell} object. The container is used by the serializers/deserializers to
+ * save/load cell objects for the simulation.
*/
-
public interface CellContainer {
/**
* Gets the unique cell container ID.
*
- * @return the cell container ID
+ * @return the cell container ID
*/
int getID();
-
+
+ /**
+ * Converts the cell container into a {@link Cell}.
+ *
+ * @param factory the cell factory instance
+ * @param location the cell location
+ * @param random the random number generator
+ * @return a {@link Cell} instance
+ */
+ Cell convert(CellFactory factory, Location location, MersenneTwisterFast random);
+
/**
* Converts the cell container into a {@link Cell}.
*
- * @param factory the cell factory instance
- * @param location the cell location
- * @return a {@link Cell} instance
+ * @param factory the cell factory instance
+ * @param location the cell location
+ * @param random the random number generator
+ * @param parameters the base parameters
+ * @return a {@link Cell} instance
*/
- Cell convert(CellFactory factory, Location location);
+ Cell convert(
+ CellFactory factory,
+ Location location,
+ MersenneTwisterFast random,
+ Parameters parameters);
}
diff --git a/src/arcade/core/agent/cell/CellFactory.java b/src/arcade/core/agent/cell/CellFactory.java
index 1c1ff5570..f023771d0 100644
--- a/src/arcade/core/agent/cell/CellFactory.java
+++ b/src/arcade/core/agent/cell/CellFactory.java
@@ -2,39 +2,55 @@
import ec.util.MersenneTwisterFast;
import arcade.core.sim.Series;
+import arcade.core.util.GrabBag;
+import arcade.core.util.MiniBox;
/**
* Factory class for {@link Cell} objects.
- *
- * The factory manages the creation of {@link Cell} objects by either:
+ *
+ * The factory manages the creation of {@link Cell} objects by either:
+ *
*
- * {@code Module} objects represent subcellular behaviors or mechanisms within a
- * {@link arcade.core.agent.cell.Cell} object, such as the cell cycle or cell
- * death. The {@code Module} should be called during the step method of the
- * corresponding {@link arcade.core.agent.cell.Cell} object. A {@code Module}
- * can be implemented with different versions; the specific class can be
+ *
+ * {@code Module} objects represent subcellular behaviors or mechanisms within a {@link
+ * arcade.core.agent.cell.Cell} object, such as the cell cycle or cell death. The {@code Module}
+ * should be called during the step method of the corresponding {@link arcade.core.agent.cell.Cell}
+ * object. A {@code Module} can be implemented with different versions; the specific class can be
* selected when switching between {@code Module} instances.
- *
- * Only one {@code Module} can be active for a given
- * {@link arcade.core.agent.cell.Cell} object. Use
- * {@link arcade.core.agent.process.Process} for non-exclusive steppables.
+ *
+ * Only one {@code Module} can be active for a given {@link arcade.core.agent.cell.Cell} object.
+ * Use {@link arcade.core.agent.process.Process} for non-exclusive steppables.
*/
-
public interface Module {
/**
- * Performs the actions of the module during the
- * {@link arcade.core.agent.cell.Cell} step.
+ * Performs the actions of the module during the {@link arcade.core.agent.cell.Cell} step.
*
- * @param random the random number generator
- * @param sim the simulation instance
+ * @param random the random number generator
+ * @param sim the simulation instance
*/
void step(MersenneTwisterFast random, Simulation sim);
}
diff --git a/src/arcade/core/agent/process/Process.java b/src/arcade/core/agent/process/Process.java
index a2e771a6a..7257b43ec 100644
--- a/src/arcade/core/agent/process/Process.java
+++ b/src/arcade/core/agent/process/Process.java
@@ -5,31 +5,26 @@
/**
* A {@code Process} object is a non-exclusive subcellular steppable.
- *
- * {@code Process} objects represent subcellular behaviors or mechanisms within
- * a {@link arcade.core.agent.cell.Cell} object, such as metabolism, signaling
- * networks, and angiogenesis. The {@code Process} should be called during the
- * step method of the corresponding {@link arcade.core.agent.cell.Cell} object.
- * A {@code Process} can be implemented with different versions; the specific
- * class can be selected when instantiating the
- * {@link arcade.core.agent.cell.Cell} object.
- *
- * More than one {@code Process} can be active for a given
- * {@link arcade.core.agent.cell.Cell} object. Use
- * {@link arcade.core.agent.module.Module} for exclusive steppables.
- *
- * {@code Process} objects are analogs to
- * {@link arcade.core.env.operation.Operation} for steppables that affect
- * cells.
+ *
+ * {@code Process} objects represent subcellular behaviors or mechanisms within a {@link
+ * arcade.core.agent.cell.Cell} object, such as metabolism, signaling networks, and angiogenesis.
+ * The {@code Process} should be called during the step method of the corresponding {@link
+ * arcade.core.agent.cell.Cell} object. A {@code Process} can be implemented with different
+ * versions; the specific class can be selected when instantiating the {@link
+ * arcade.core.agent.cell.Cell} object.
+ *
+ * More than one {@code Process} can be active for a given {@link arcade.core.agent.cell.Cell}
+ * object. Use {@link arcade.core.agent.module.Module} for exclusive steppables.
+ *
+ * {@code Process} objects are analogs to {@link arcade.core.env.operation.Operation} for
+ * steppables that affect cells.
*/
-
public interface Process {
/**
- * Performs the actions of the process during the
- * {@link arcade.core.agent.cell.Cell} step.
+ * Performs the actions of the process during the {@link arcade.core.agent.cell.Cell} step.
*
- * @param random the random number generator
- * @param sim the simulation instance
+ * @param random the random number generator
+ * @param sim the simulation instance
*/
void step(MersenneTwisterFast random, Simulation sim);
}
diff --git a/src/arcade/core/agent/process/ProcessDomain.java b/src/arcade/core/agent/process/ProcessDomain.java
index e1bb2e618..3fdabe69b 100644
--- a/src/arcade/core/agent/process/ProcessDomain.java
+++ b/src/arcade/core/agent/process/ProcessDomain.java
@@ -1,9 +1,4 @@
package arcade.core.agent.process;
-/**
- * A {@code ProcessDomain} enum represents an agent process domain.
- */
-
-public interface ProcessDomain {
-
-}
+/** A {@code ProcessDomain} enum represents an agent process domain. */
+public interface ProcessDomain {}
diff --git a/src/arcade/core/env/component/Component.java b/src/arcade/core/env/component/Component.java
index 0d79fd7e3..443c486fc 100644
--- a/src/arcade/core/env/component/Component.java
+++ b/src/arcade/core/env/component/Component.java
@@ -5,38 +5,35 @@
import arcade.core.sim.Simulation;
/**
- * A {@code Component} object is a steppable that interacts with the
- * environment.
- *
- * {@code Component} objects represent any entity that interacts with the
- * environment. They can be used for:
+ * A {@code Component} object is a steppable that interacts with the environment.
+ *
+ * {@code Component} objects represent any entity that interacts with the environment. They can
+ * be used for:
+ *
*
- * {@code Component} objects can affect {@link arcade.core.env.lattice.Lattice}
- * layers or layer {@link arcade.core.env.operation.Operation} instances.
- * {@code Component} objects are analogs to
- * {@link arcade.core.agent.action.Action} for steppables that affect the
- * environment.
+ *
+ * {@code Component} objects can affect {@link arcade.core.env.lattice.Lattice} layers or layer
+ * {@link arcade.core.env.operation.Operation} instances. {@code Component} objects are analogs to
+ * {@link arcade.core.agent.action.Action} for steppables that affect the environment.
*/
-
public interface Component extends Steppable {
/**
* Schedules the component in the simulation.
*
- * @param schedule the simulation schedule
+ * @param schedule the simulation schedule
*/
void schedule(Schedule schedule);
-
+
/**
* Registers a lattice layer to the component.
*
- * @param sim the simulation instance
- * @param layer the lattice layer
+ * @param sim the simulation instance
+ * @param layer the lattice layer
*/
void register(Simulation sim, String layer);
}
diff --git a/src/arcade/core/env/grid/Grid.java b/src/arcade/core/env/grid/Grid.java
index f1d9ac999..c6dad0bc5 100644
--- a/src/arcade/core/env/grid/Grid.java
+++ b/src/arcade/core/env/grid/Grid.java
@@ -5,50 +5,49 @@
/**
* A {@code Grid} represents the environment for agents.
- *
- * Calculations for geometry, bounds, size, etc. can be handled either by the
- * {@link Location} object that is passed in with the agent (using the
- * {@code Grid} as a container class) or vice versa.
+ *
+ * Calculations for geometry, bounds, size, etc. can be handled either by the {@link Location}
+ * object that is passed in with the agent (using the {@code Grid} as a container class) or vice
+ * versa.
*/
-
public interface Grid {
/**
* Gets all agent objects in the grid.
*
- * @return a bag containing all agent objects
+ * @return a bag containing all agent objects
*/
Bag getAllObjects();
-
+
/**
* Adds an object to the grid.
*
- * @param object the object to add to the grid
- * @param location the location to add the object to
+ * @param object the object to add to the grid
+ * @param location the location to add the object to
*/
void addObject(Object object, Location location);
-
+
/**
* Removes an object from the grid.
*
- * @param object the object to remove from the grid
- * @param location the location to remove the object from
+ * @param object the object to remove from the grid
+ * @param location the location to remove the object from
*/
void removeObject(Object object, Location location);
-
+
/**
* Moves an object to a new location.
*
- * @param object the object to move in the grid
- * @param fromLocation the location to move the object from
- * @param toLocation the location to move the object to
+ * @param object the object to move in the grid
+ * @param fromLocation the location to move the object from
+ * @param toLocation the location to move the object to
*/
void moveObject(Object object, Location fromLocation, Location toLocation);
-
+
/**
* Gets the object at the given index.
*
- * @param index the object index
- * @return the object
+ * @param index the object index
+ * @return the object
*/
Object getObjectAt(int index);
}
diff --git a/src/arcade/core/env/lattice/Lattice.java b/src/arcade/core/env/lattice/Lattice.java
index 9e25c88ce..85c6200c2 100644
--- a/src/arcade/core/env/lattice/Lattice.java
+++ b/src/arcade/core/env/lattice/Lattice.java
@@ -9,124 +9,122 @@
/**
* A {@code Lattice} represents an environment layer.
- *
- * Each lattice is a 3D array of doubles, where the values can represent
- * molecular concentrations or other continuous quantities. Each lattice is
- * associated with {@link Operation} objects that characterize environmental
- * behaviors. The {@link Operation} object(s) are stepped during the step method
- * of the {@code Lattice}.
+ *
+ * Each lattice is a 3D array of doubles, where the values can represent molecular concentrations
+ * or other continuous quantities. Each lattice is associated with {@link Operation} objects that
+ * characterize environmental behaviors. The {@link Operation} object(s) are stepped during the step
+ * method of the {@code Lattice}.
*/
-
public interface Lattice extends Steppable {
/**
* Gets the underlying lattice array.
*
- * @return the array
+ * @return the array
*/
double[][][] getField();
-
+
/**
* Gets the length of the lattice (x direction).
*
- * @return the length of the lattice
+ * @return the length of the lattice
*/
int getLength();
-
+
/**
* Gets the width of the lattice (y direction).
*
- * @return the width of the lattice
+ * @return the width of the lattice
*/
int getWidth();
-
+
/**
* Gets the height of the lattice (z direction).
*
- * @return the height of the lattice
+ * @return the height of the lattice
*/
int getHeight();
-
+
/**
* Gets the lattice operation object.
*
- * @param category the operation category
- * @return the lattice operation
+ * @param category the operation category
+ * @return the lattice operation
*/
Operation getOperation(OperationCategory category);
-
+
/**
* Gets the lattice layer parameters.
*
- * @return a dictionary of parameters
+ * @return a dictionary of parameters
*/
MiniBox getParameters();
-
+
/**
* Sets the underlying array at the height index to the given array.
*
- * @param values the array of values
- * @param index the height index
+ * @param values the array of values
+ * @param index the height index
*/
void setField(double[][] values, int index);
-
+
/**
* Sets the underlying array to the given array of values.
*
- * @param values the array of values
+ * @param values the array of values
*/
void setField(double[][][] values);
-
+
/**
* Sets the underlying array to the given value.
*
- * @param value the value to set
+ * @param value the value to set
*/
void setField(double value);
-
+
/**
* Gets the sum of values across lattice coordinates for the location.
*
- * @param location the location
- * @return the sum value
+ * @param location the location
+ * @return the sum value
*/
double getTotalValue(Location location);
-
+
/**
* Gets the average value across lattice coordinates for the location.
*
- * @param location the location
- * @return the average values
+ * @param location the location
+ * @return the average values
*/
double getAverageValue(Location location);
-
+
/**
* Updates the value at the lattice coordinates for the location.
*
- * @param location the location
- * @param fraction the fraction change in value
+ * @param location the location
+ * @param fraction the fraction change in value
*/
void updateValue(Location location, double fraction);
-
+
/**
* Increments the value at the lattice coordinates for the location.
*
- * @param location the location
- * @param increment the change in value
+ * @param location the location
+ * @param increment the change in value
*/
void incrementValue(Location location, double increment);
-
+
/**
* Sets the value at the lattice coordinates corresponding to the location.
*
- * @param location the location
- * @param value the new value
+ * @param location the location
+ * @param value the new value
*/
void setValue(Location location, double value);
-
+
/**
* Schedules the lattice in the simulation.
*
- * @param schedule the simulation schedule
+ * @param schedule the simulation schedule
*/
void schedule(Schedule schedule);
}
diff --git a/src/arcade/core/env/lattice/LatticeFactory.java b/src/arcade/core/env/lattice/LatticeFactory.java
index 7ff9b136f..f0bdc1f90 100644
--- a/src/arcade/core/env/lattice/LatticeFactory.java
+++ b/src/arcade/core/env/lattice/LatticeFactory.java
@@ -5,26 +5,26 @@
/**
* Factory class for {@link Lattice} objects.
- *
- * The factory manages the creation of {@link Lattice} objects by:
+ *
+ * The factory manages the creation of {@link Lattice} objects by:
+ *
*
- * Each agent has a {@code Location} that identifies where they are within the
- * {@link arcade.core.env.grid.Grid} (relative to other agents) and the
- * {@link arcade.core.env.lattice.Lattice} (local molecule concentrations).
+ *
+ * Each agent has a {@code Location} that identifies where they are within the {@link
+ * arcade.core.env.grid.Grid} (relative to other agents) and the {@link
+ * arcade.core.env.lattice.Lattice} (local molecule concentrations).
*/
-
public interface Location {
/**
* Converts the location into a {@link LocationContainer}.
*
- * @param id the location id
- * @return a {@link LocationContainer} instance
+ * @param id the location id
+ * @return a {@link LocationContainer} instance
*/
LocationContainer convert(int id);
-
+
/**
* Gets the volume of the location.
*
- * @return the location volume
+ * @return the location volume
*/
double getVolume();
-
+
/**
* Gets the surface area of the location.
*
- * @return the location surface area
+ * @return the location surface area
*/
double getSurface();
-
+
/**
* Gets the height of the location.
*
- * @return the location height
+ * @return the location height
*/
double getHeight();
}
diff --git a/src/arcade/core/env/location/LocationContainer.java b/src/arcade/core/env/location/LocationContainer.java
index ddc6436ba..dfb4cf940 100644
--- a/src/arcade/core/env/location/LocationContainer.java
+++ b/src/arcade/core/env/location/LocationContainer.java
@@ -4,26 +4,25 @@
/**
* Container class for {@link Location} objects.
- *
- * The container implementation should contain the minimal set of information
- * needed to initialize a {@link Location} object. The container is used by the
- * serializers/deserializers to save/load location objects for the simulation.
+ *
+ * The container implementation should contain the minimal set of information needed to
+ * initialize a {@link Location} object. The container is used by the serializers/deserializers to
+ * save/load location objects for the simulation.
*/
-
public interface LocationContainer {
/**
* Gets the unique location container ID.
*
- * @return the location container ID
+ * @return the location container ID
*/
int getID();
-
+
/**
* Converts the location container into a {@link Location}.
*
- * @param factory the location factory instance
- * @param cell the cell container
- * @return a {@link Location} instance
+ * @param factory the location factory instance
+ * @param cell the cell container
+ * @return a {@link Location} instance
*/
Location convert(LocationFactory factory, CellContainer cell);
}
diff --git a/src/arcade/core/env/location/LocationFactory.java b/src/arcade/core/env/location/LocationFactory.java
index 3edd4d4ef..677820c33 100644
--- a/src/arcade/core/env/location/LocationFactory.java
+++ b/src/arcade/core/env/location/LocationFactory.java
@@ -5,36 +5,34 @@
/**
* Factory class for {@link Location} objects.
- *
- * The factory manages the creation of {@link Location} objects by either:
+ *
+ * The factory manages the creation of {@link Location} objects by either:
+ *
*
- * {@code Operation} objects represent environmental behaviors or mechanisms
- * within a {@link arcade.core.env.lattice.Lattice} object, such as diffusion.
- * The {@code Operation} should be called during the step method of the
- * corresponding {@link arcade.core.env.lattice.Lattice} object.
- * An {@code Operation} can be implemented with different versions; the specific
- * class can be selected when instantiating the
- * {@link arcade.core.env.lattice.Lattice} object.
- *
- * More than one {@code Operation} can be active for a given
- * {@link arcade.core.env.lattice.Lattice} object.
- *
- * {@code Operation} objects are analogs to
- * {@link arcade.core.agent.process.Process} for steppables that affect the
- * environment.
+ *
+ * {@code Operation} objects represent environmental behaviors or mechanisms within a {@link
+ * arcade.core.env.lattice.Lattice} object, such as diffusion. The {@code Operation} should be
+ * called during the step method of the corresponding {@link arcade.core.env.lattice.Lattice}
+ * object. An {@code Operation} can be implemented with different versions; the specific class can
+ * be selected when instantiating the {@link arcade.core.env.lattice.Lattice} object.
+ *
+ * More than one {@code Operation} can be active for a given {@link
+ * arcade.core.env.lattice.Lattice} object.
+ *
+ * {@code Operation} objects are analogs to {@link arcade.core.agent.process.Process} for
+ * steppables that affect the environment.
*/
-
public interface Operation {
/**
- * Performs the actions of the process during the
- * {@link arcade.core.env.lattice.Lattice} step.
+ * Performs the actions of the process during the {@link arcade.core.env.lattice.Lattice} step.
*
- * @param random the random number generator
- * @param sim the simulation instance
+ * @param random the random number generator
+ * @param sim the simulation instance
*/
void step(MersenneTwisterFast random, Simulation sim);
}
diff --git a/src/arcade/core/env/operation/OperationCategory.java b/src/arcade/core/env/operation/OperationCategory.java
index a74dfe833..bcaaa4d41 100644
--- a/src/arcade/core/env/operation/OperationCategory.java
+++ b/src/arcade/core/env/operation/OperationCategory.java
@@ -1,9 +1,4 @@
package arcade.core.env.operation;
-/**
- * An {@code OperationCategory} enum represents an environment operation category.
- */
-
-public interface OperationCategory {
-
-}
+/** An {@code OperationCategory} enum represents an environment operation category. */
+public interface OperationCategory {}
diff --git a/src/arcade/core/gui/GUI.java b/src/arcade/core/gui/GUI.java
index a2be24b2c..4e1d6d76f 100644
--- a/src/arcade/core/gui/GUI.java
+++ b/src/arcade/core/gui/GUI.java
@@ -33,211 +33,217 @@
/**
* Creates a {@code GUI} for selecting setup file and running the simulation.
- *
- * When the model is called with arguments, then the {@code main} method in
- * {@link arcade.core.ARCADE} is called directly and {@code GUI} is not shown.
+ *
+ * When the model is called with arguments, then the {@code main} method in {@link
+ * arcade.core.ARCADE} is called directly and {@code GUI} is not shown.
*/
-
public class GUI implements ActionListener {
/** GUI frame. */
private static JFrame frame;
-
+
/** Directory for file chooser. */
private static String chooserDir = null;
-
+
/** Text field for file. */
private JTextField inputFileField;
-
+
/** Text field for output path. */
private JTextField outputPathField;
-
+
/** Button for run simulation. */
private JButton runButton;
-
+
/** Text area for display. */
private JTextArea displayArea;
-
+
/** Check box for visualization. */
private JCheckBox visCheck;
-
+
/** Input file. */
private File inputFile;
-
+
/** Output path. */
private File outputPath;
-
+
/** Implementation name. */
private String implementation;
-
+
/**
* Main function for running ARCADE simulations through the GUI.
*
- * @param args list of command line arguments
+ * @param args list of command line arguments
*/
public static void main(String[] args) throws Exception {
FlatDarculaLaf.install();
-
+
if (args.length > 0) {
ARCADE.main(args);
} else {
SwingUtilities.invokeLater(GUI::createAndShowGUI);
}
}
-
+
/** Creates the GUI and makes it visible. */
private static void createAndShowGUI() {
frame = new JFrame();
-
+
// Create and set up the content pane.
GUI gui = new GUI();
frame.setContentPane(gui.createContent());
-
+
// Creates an instance of a MASON SimApplet so the doQuit() method of
// Console does not exit (so that the GUI console is not forced to close).
new SimApplet();
-
+
// Display the window.
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
-
+
/**
* Creates the content pane.
*
- * @return the content panel
+ * @return the content panel
*/
private JPanel createContent() {
frame.setSize(1200, 700);
-
+
JPanel screen = new JPanel();
screen.setLayout(new BorderLayout());
-
+
// Add north panel containing file select and run buttons.
JPanel northPanel = new JPanel();
northPanel.setBorder(makeBorder());
GroupLayout grouping = prepGrouping(northPanel);
-
+
// Label panel.
JPanel labelPanel = new JPanel();
labelPanel.setLayout(new BoxLayout(labelPanel, BoxLayout.Y_AXIS));
labelPanel.setBorder(new EmptyBorder(10, 0, 20, 0));
-
+
JLabel titleLabel = new JLabel("ARCADE v3.1");
labelPanel.add(titleLabel);
-
- JLabel nameLabel = new JLabel("Agent-based Representation "
- + "of Cells And Dynamic Environments");
+
+ JLabel nameLabel =
+ new JLabel(
+ "Agent-based Representation "
+ + "of Cells And Dynamic Environments");
labelPanel.add(nameLabel);
-
+
northPanel.add(labelPanel);
-
+
// Select input file panel.
addATextField("No input file selected", 40, northPanel);
((JTextField) northPanel.getComponent(1)).setEditable(false);
inputFileField = ((JTextField) northPanel.getComponent(1));
-
+
JButton inputSelectButton = addAButton("SELECT INPUT FILE", northPanel);
inputSelectButton.addActionListener(this);
inputSelectButton.setActionCommand("INPUT");
-
+
// Select output path panel.
addATextField("No output path selected", 40, northPanel);
((JTextField) northPanel.getComponent(3)).setEditable(false);
outputPathField = ((JTextField) northPanel.getComponent(3));
-
+
JButton outputSelectButton = addAButton("SELECT OUTPUT PATH", northPanel);
outputSelectButton.addActionListener(this);
outputSelectButton.setActionCommand("OUTPUT");
-
+
// Implementation panel.
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS));
implementation = "potts";
-
+
JRadioButton patchImplButton = addARadioButton("patch implementation", buttonPanel);
patchImplButton.addActionListener(this);
patchImplButton.setActionCommand("patch");
patchImplButton.setEnabled(false);
-
+
JRadioButton pottImplButton = addARadioButton("potts implementation", buttonPanel);
pottImplButton.addActionListener(this);
pottImplButton.setActionCommand("potts");
pottImplButton.setSelected(true);
-
+
northPanel.add(buttonPanel);
-
+
ButtonGroup implementations = new ButtonGroup();
implementations.add(patchImplButton);
implementations.add(pottImplButton);
-
+
// Run simulation panel.
runButton = addAButton("RUN SIMULATIONS", northPanel);
runButton.setEnabled(false);
runButton.addActionListener(this);
runButton.setActionCommand("RUN");
-
+
visCheck = addACheckBox("vis", northPanel);
visCheck.setEnabled(false);
visCheck.setSelected(false);
-
+
grouping.setHorizontalGroup(
grouping.createSequentialGroup()
- .addGroup(grouping.createParallelGroup(GroupLayout.Alignment.LEADING)
- .addComponent(northPanel.getComponent(0))
- .addComponent(northPanel.getComponent(1))
- .addComponent(northPanel.getComponent(3))
- .addComponent(northPanel.getComponent(5)))
- .addGroup(grouping.createParallelGroup(GroupLayout.Alignment.LEADING)
- .addComponent(northPanel.getComponent(2))
- .addComponent(northPanel.getComponent(4))
- .addComponent(northPanel.getComponent(6)))
- .addGroup(grouping.createParallelGroup(GroupLayout.Alignment.TRAILING)
- .addComponent(northPanel.getComponent(7)))
- );
-
+ .addGroup(
+ grouping.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addComponent(northPanel.getComponent(0))
+ .addComponent(northPanel.getComponent(1))
+ .addComponent(northPanel.getComponent(3))
+ .addComponent(northPanel.getComponent(5)))
+ .addGroup(
+ grouping.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addComponent(northPanel.getComponent(2))
+ .addComponent(northPanel.getComponent(4))
+ .addComponent(northPanel.getComponent(6)))
+ .addGroup(
+ grouping.createParallelGroup(GroupLayout.Alignment.TRAILING)
+ .addComponent(northPanel.getComponent(7))));
+
grouping.setVerticalGroup(
grouping.createSequentialGroup()
- .addGroup(grouping.createParallelGroup(GroupLayout.Alignment.BASELINE)
- .addComponent(northPanel.getComponent(0)))
- .addGroup(grouping.createParallelGroup(GroupLayout.Alignment.BASELINE)
- .addComponent(northPanel.getComponent(1))
- .addComponent(northPanel.getComponent(2)))
- .addGroup(grouping.createParallelGroup(GroupLayout.Alignment.BASELINE)
- .addComponent(northPanel.getComponent(3))
- .addComponent(northPanel.getComponent(4)))
- .addGroup(grouping.createParallelGroup(GroupLayout.Alignment.BASELINE)
- .addComponent(northPanel.getComponent(5))
- .addComponent(northPanel.getComponent(6))
- .addComponent(northPanel.getComponent(7)))
- );
-
+ .addGroup(
+ grouping.createParallelGroup(GroupLayout.Alignment.BASELINE)
+ .addComponent(northPanel.getComponent(0)))
+ .addGroup(
+ grouping.createParallelGroup(GroupLayout.Alignment.BASELINE)
+ .addComponent(northPanel.getComponent(1))
+ .addComponent(northPanel.getComponent(2)))
+ .addGroup(
+ grouping.createParallelGroup(GroupLayout.Alignment.BASELINE)
+ .addComponent(northPanel.getComponent(3))
+ .addComponent(northPanel.getComponent(4)))
+ .addGroup(
+ grouping.createParallelGroup(GroupLayout.Alignment.BASELINE)
+ .addComponent(northPanel.getComponent(5))
+ .addComponent(northPanel.getComponent(6))
+ .addComponent(northPanel.getComponent(7))));
+
screen.add(northPanel, BorderLayout.NORTH);
-
+
// Add center panel containing text area.
JPanel centerPanel = new JPanel();
centerPanel.setLayout(new BorderLayout());
centerPanel.setBorder(makeBorder());
-
+
displayArea = addATextArea(centerPanel, "");
PrintStream printStream = new PrintStream(new CustomOutputStream(displayArea));
System.setOut(printStream);
System.setErr(printStream);
-
+
screen.add(centerPanel, BorderLayout.CENTER);
-
+
return screen;
}
-
+
/**
* Performs the action for the given event.
*
- * @param event the action event
+ * @param event the action event
*/
@Override
public void actionPerformed(ActionEvent event) {
String cmd = event.getActionCommand();
-
+
switch (cmd) {
case "INPUT":
inputFile = getFile();
@@ -248,7 +254,7 @@ public void actionPerformed(ActionEvent event) {
} else {
displayArea.append("\nselected input xml [ " + inputFile.getName() + " ]\n");
inputFileField.setText(inputFile.getAbsolutePath());
-
+
if (outputPath != null) {
runButton.setEnabled(true);
visCheck.setEnabled(true);
@@ -267,7 +273,7 @@ public void actionPerformed(ActionEvent event) {
} else {
displayArea.append("\nselected output path [ " + outputPath.getPath() + " ]\n");
outputPathField.setText(outputPath.getAbsolutePath());
-
+
if (inputFile != null) {
runButton.setEnabled(true);
visCheck.setEnabled(true);
@@ -283,41 +289,45 @@ public void actionPerformed(ActionEvent event) {
displayArea.append("\nselected implementation [ " + implementation + " ]\n");
break;
case "RUN":
- Thread thread = new Thread(() -> {
- try {
- displayArea.append("\n\n");
- LogManager.getLogManager().reset();
-
- if (visCheck.isSelected()) {
- ARCADE.main(new String[] {
- implementation,
- inputFile.getAbsolutePath(),
- outputPath.getAbsolutePath(),
- "--vis"
- });
- } else {
- ARCADE.main(new String[] {
- implementation,
- inputFile.getAbsolutePath(),
- outputPath.getAbsolutePath()
- });
- }
- } catch (Exception ex) {
- ex.printStackTrace();
- }
- });
+ Thread thread =
+ new Thread(
+ () -> {
+ try {
+ displayArea.append("\n\n");
+ LogManager.getLogManager().reset();
+
+ if (visCheck.isSelected()) {
+ ARCADE.main(
+ new String[] {
+ implementation,
+ inputFile.getAbsolutePath(),
+ outputPath.getAbsolutePath(),
+ "--vis"
+ });
+ } else {
+ ARCADE.main(
+ new String[] {
+ implementation,
+ inputFile.getAbsolutePath(),
+ outputPath.getAbsolutePath()
+ });
+ }
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ });
thread.start();
-
+
break;
default:
break;
}
}
-
+
/**
* Opens dialog to select input file.
*
- * @return the selected file, null if no file is selected
+ * @return the selected file, null if no file is selected
*/
public File getFile() {
JFileChooser chooser = new JFileChooser(chooserDir);
@@ -326,21 +336,21 @@ public File getFile() {
chooser.addChoosableFileFilter(new XMLFileFilter());
chooser.setAcceptAllFileFilterUsed(false);
File file;
-
+
if (chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
file = chooser.getSelectedFile();
chooserDir = file.getParent();
} else {
return null;
}
-
+
return file;
}
-
+
/**
* Opens dialog to select output path.
*
- * @return the selected path, null if no path is selected
+ * @return the selected path, null if no path is selected
*/
public File getPath() {
JFileChooser chooser = new JFileChooser(chooserDir);
@@ -349,24 +359,24 @@ public File getPath() {
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
chooser.setAcceptAllFileFilterUsed(false);
File file;
-
+
if (chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
file = chooser.getCurrentDirectory();
chooserDir = file.getParent();
} else {
return null;
}
-
+
return file;
}
-
+
/** Custom file filter for XML files. */
private static class XMLFileFilter extends FileFilter {
/**
* Determines if the file is an XML file.
*
- * @param file the file
- * @return {@code true} if the file is an XML, {@code false} otherwise
+ * @param file the file
+ * @return {@code true} if the file is an XML, {@code false} otherwise
*/
@Override
public boolean accept(File file) {
@@ -377,99 +387,97 @@ public boolean accept(File file) {
String extension = filename[filename.length - 1];
return extension.equalsIgnoreCase("xml");
}
-
+
@Override
public String getDescription() {
return null;
}
}
-
+
/** Custom output stream for console text. */
public static class CustomOutputStream extends OutputStream {
/** Text area for output. */
private final JTextArea textArea;
-
+
/**
* Creates an output stream for the text area.
*
- * @param textArea the text area
+ * @param textArea the text area
*/
CustomOutputStream(JTextArea textArea) {
this.textArea = textArea;
}
-
- /**
- * Writes to the text area.
- */
+
+ /** Writes to the text area. */
@Override
public void write(int b) {
// Redirects data to the text area.
textArea.append(String.valueOf((char) b));
-
+
// Scrolls the text area to the end of data.
textArea.setCaretPosition(textArea.getDocument().getLength());
}
}
-
+
/**
* Adds a button to the container.
*
- * @param text the text for the button
- * @param container the container to add to
- * @return the button object
+ * @param text the text for the button
+ * @param container the container to add to
+ * @return the button object
*/
private static JButton addAButton(String text, Container container) {
JButton button = new JButton(text);
container.add(button);
return button;
}
-
+
/**
* Adds a text field to the container.
*
- * @param text the text for the field
- * @param length the length of the text field
- * @param container the container to add to
- * @return the text field object
+ * @param text the text for the field
+ * @param length the length of the text field
+ * @param container the container to add to
+ * @return the text field object
*/
private static JTextField addATextField(String text, int length, Container container) {
JTextField textField = new JTextField(text, length);
container.add(textField);
return textField;
}
-
+
/**
* Adds a check box to the container.
*
- * @param text the text for the check box
- * @param container the container to add to
- * @return the check box object
+ * @param text the text for the check box
+ * @param container the container to add to
+ * @return the check box object
*/
private static JCheckBox addACheckBox(String text, Container container) {
JCheckBox checkBox = new JCheckBox(text);
container.add(checkBox);
return checkBox;
}
-
+
/**
* Adds a radio button to the container.
*
- * @param text the text for the radio button
- * @param container the container to add to
- * @return the radio button object
+ * @param text the text for the radio button
+ * @param container the container to add to
+ * @return the radio button object
*/
private static JRadioButton addARadioButton(String text, Container container) {
JRadioButton radioButton = new JRadioButton(text);
container.add(radioButton);
return radioButton;
}
-
+
/**
* Adds a text area to the container.
*
- * @param container the container to add to
- * @param text the text to add
- * @return the text area object
+ * @param container the container to add to
+ * @param text the text to add
+ * @return the text area object
*/
private static JTextArea addATextArea(Container container, String text) {
JTextArea textArea = new JTextArea();
@@ -480,12 +488,12 @@ private static JTextArea addATextArea(Container container, String text) {
container.add(scrollPane);
return textArea;
}
-
+
/**
* Prepares a grouping layout.
*
- * @param pane the container
- * @return the group layout
+ * @param pane the container
+ * @return the group layout
*/
private static GroupLayout prepGrouping(Container pane) {
GroupLayout gl = new GroupLayout(pane);
@@ -494,11 +502,11 @@ private static GroupLayout prepGrouping(Container pane) {
gl.setAutoCreateContainerGaps(true);
return gl;
}
-
+
/**
* Creates a border with just padding.
*
- * @return the border
+ * @return the border
*/
private static Border makeBorder() {
return BorderFactory.createCompoundBorder(
diff --git a/src/arcade/core/parameter.xml b/src/arcade/core/parameter.xml
index e421b464c..d1675a1d2 100644
--- a/src/arcade/core/parameter.xml
+++ b/src/arcade/core/parameter.xml
@@ -8,7 +8,7 @@
- * The class is instantiated by parsing an XML document specifying model setup.
- * Constructors for the {@link Simulation} objects are built, but not called to
- * instantiate the simulation until the series is run. {@code Series} objects
- * that are not valid are flagged with {@code isSkipped} and are not run.
- *
- * {@link Simulation} objects are passed their parent {@code Series} object.
+ * Abstract simulation manager for {@link Simulation} objects, differing only in random seed.
+ *
+ * The class is instantiated by parsing an XML document specifying model setup. Constructors for
+ * the {@link Simulation} objects are built, but not called to instantiate the simulation until the
+ * series is run. {@code Series} objects that are not valid are flagged with {@code isSkipped} and
+ * are not run.
+ *
+ * {@link Simulation} objects are passed their parent {@code Series} object.
*/
-
public abstract class Series {
/** Logger for {@code Series}. */
private static final Logger LOGGER = Logger.getLogger(Series.class.getName());
-
+
/** Regular expression for numbers. */
private static final String NUMBER_REGEX = "^(\\d+)|(\\d+E\\d+)$";
-
+
/** Regular expression for fractions. */
private static final String FRACTION_REGEX = "^(([0]*(\\.\\d*|))|(1[\\.0]*))$";
-
+
+ /** Regular expression for distributions. */
+ public static final String DISTRIBUTION_REGEX =
+ "^([A-Z\\_]+)\\(([A-Z]+)=([\\d\\.]+)(?:,([A-Z]+)=([\\d\\.]+))*\\)$";
+
/** Offset of random seed to avoid using seed of 0. */
public static final int SEED_OFFSET = 1000;
-
+
/** {@code true} if {@code Series} is not valid, {@code false} otherwise. */
public boolean isSkipped;
-
+
/** {@code true} if {@code Series} is visualized, {@code false} otherwise. */
public boolean isVis;
-
+
/** Output saver for the simulation. */
public OutputSaver saver;
-
+
/** Output loader for the simulation. */
public OutputLoader loader;
-
+
/** Name of the series. */
private final String name;
-
+
/** Path and prefix for the series. */
private final String prefix;
-
+
/** Spatial conversion factor (um/voxel). */
public final double ds;
-
+
/** Spatial conversion factor in z (um/voxel). */
public final double dz;
-
+
/** Temporal conversion factor (hrs/tick). */
public final double dt;
-
+
/** Constructor for the simulation. */
protected Constructor> simCons;
-
+
/** Constructor for the visualization. */
protected Constructor> visCons;
-
+
/** Random seed of the first simulation in the series. */
private final int startSeed;
-
+
/** Random seed of the last simulation in the series. */
private final int endSeed;
-
+
/** Simulation length in ticks. */
private final int ticks;
-
+
/** Snapshot interval in ticks. */
private final int interval;
-
+
/** Length of the simulation. */
public final int length;
-
+
/** Width of the simulation. */
public final int width;
-
+
/** Height of the simulation. */
public final int height;
-
+
/** Margin for the simulation. */
public final int margin;
-
+
/** Map of population settings. */
public HashMap
- * Conversion string is in the form of {@code D^N} where {@code D} is either
- * {@code DS}, {@code DZ}, or {@code DT} and {@code N} is an integer
- * exponent. Conversions with {@code DZ} are replaced with {@code DS}.
- * Multiple terms can be chained in the form {@code D^N1.D^N2}. The
- * {@code ^N} is not required if N = 1.
*
- * @param convert the conversion string
- * @param ds the spatial conversion factor
- * @param dt the temporal conversion factor
- * @return the updated conversion factor
+ * Conversion string is in the form of {@code D^N} where {@code D} is either {@code DS},
+ * {@code DZ}, or {@code DT} and {@code N} is an integer exponent. Conversions with {@code DZ}
+ * are replaced with {@code DS}. Multiple terms can be chained in the form {@code D^N1.D^N2}.
+ * The {@code ^N} is not required if N = 1.
+ *
+ * @param convert the conversion string
+ * @param ds the spatial conversion factor
+ * @param dt the temporal conversion factor
+ * @return the updated conversion factor
*/
protected static double parseConversion(String convert, double ds, double dt) {
return parseConversion(convert, ds, ds, dt);
}
-
+
/**
* Updates conversion string into a value.
- *
- * Conversion string is in the form of {@code D^N} where {@code D} is either
- * {@code DS}, {@code DZ}, or {@code DT} and {@code N} is an integer
- * exponent. Multiple terms can be chained in the form {@code D^N1.D^N2}.
- * The {@code ^N} is not required if N = 1.
*
- * @param convert the conversion string
- * @param ds the spatial conversion factor in xy
- * @param dz the spatial conversion factor in z
- * @param dt the temporal conversion factor
- * @return the updated conversion factor
+ * Conversion string is in the form of {@code D^N} where {@code D} is either {@code DS},
+ * {@code DZ}, or {@code DT} and {@code N} is an integer exponent. Multiple terms can be chained
+ * in the form {@code D^N1.D^N2}. The {@code ^N} is not required if N = 1.
+ *
+ * @param convert the conversion string
+ * @param ds the spatial conversion factor in xy
+ * @param dz the spatial conversion factor in z
+ * @param dt the temporal conversion factor
+ * @return the updated conversion factor
*/
protected static double parseConversion(String convert, double ds, double dz, double dt) {
double value = 1;
String[] split = convert.split("\\.");
for (String s : split) {
String[] subsplit = s.replace(" ", "").split("\\^");
- double v = (subsplit[0].equals("DS") ? ds
- : (subsplit[0].equals("DZ") ? dz
- : (subsplit[0].equals("DT") ? dt : 1)));
+ double v =
+ (subsplit[0].equals("DS")
+ ? ds
+ : (subsplit[0].equals("DZ")
+ ? dz
+ : (subsplit[0].equals("DT") ? dt : 1)));
int n = (subsplit.length == 2 ? Integer.parseInt(subsplit[1]) : 1);
value *= Math.pow(v, n);
}
return value;
}
-
- /**
- * Uses reflections to build constructors for simulation and visualization.
- */
+
+ /** Uses reflections to build constructors for simulation and visualization. */
protected void makeConstructors() {
// Create constructor for simulation class.
try {
@@ -374,7 +387,7 @@ protected void makeConstructors() {
e.printStackTrace();
isSkipped = true;
}
-
+
// Create constructor for visualization class.
try {
Class> c = Class.forName(getVisClass());
@@ -385,61 +398,63 @@ protected void makeConstructors() {
isSkipped = true;
}
}
-
+
/**
* Gets the class name for the simulation.
*
- * @return the simulation class
+ * @return the simulation class
*/
protected abstract String getSimClass();
-
+
/**
* Gets the class name for the visualization.
*
- * @return the visualization class
+ * @return the visualization class
*/
protected abstract String getVisClass();
-
+
/**
* Calls {@code runSim} for each random seed.
*
- * @throws Exception if simulation constructor cannot be instantiated
+ * @throws Exception if simulation constructor cannot be instantiated
*/
public void runSims() throws Exception {
long simStart;
long simEnd;
-
+
// Iterate through each seed.
for (int seed = startSeed; seed <= endSeed; seed++) {
// Pre-simulation output.
LOGGER.info(String.format("simulation [ %s | %04d ] started", name, seed));
simStart = System.currentTimeMillis();
-
+
// Run simulation.
SimState simstate = (SimState) (simCons.newInstance(seed + SEED_OFFSET, this));
runSim(simstate, seed);
-
+
// Post-simulation output.
simEnd = System.currentTimeMillis();
- LOGGER.info(String.format("simulation [ %s | %04d ] finished in %.4f minutes",
- name, seed, (double) (simEnd - simStart) / 1000 / 60));
+ LOGGER.info(
+ String.format(
+ "simulation [ %s | %04d ] finished in %.4f minutes",
+ name, seed, (double) (simEnd - simStart) / 1000 / 60));
}
}
-
+
/**
* Iterates through each tick of the simulation.
*
- * @param simstate the simulation state instance
- * @param seed the random seed
+ * @param simstate the simulation state instance
+ * @param seed the random seed
*/
void runSim(SimState simstate, int seed) {
// Start simulation.
simstate.start();
-
+
// Set up logger checkpoints.
double delta = ticks / 10.0;
double checkpoint = delta;
-
+
// Run simulation loop.
double tick;
do {
@@ -447,22 +462,24 @@ void runSim(SimState simstate, int seed) {
break;
}
tick = simstate.schedule.getTime();
-
+
if (tick >= checkpoint) {
- LOGGER.info(String.format("simulation [ %s | %04d ] tick %6d ( %4.2f %% )",
- name, seed, (int) tick, (100 * tick / ticks)));
+ LOGGER.info(
+ String.format(
+ "simulation [ %s | %04d ] tick %6d ( %4.2f %% )",
+ name, seed, (int) tick, (100 * tick / ticks)));
checkpoint += delta;
}
} while (tick < ticks - 1);
-
+
// Finish simulation.
simstate.finish();
}
-
+
/**
* Creates controller for visualization.
*
- * @throws Exception if visualization constructor cannot be instantiated
+ * @throws Exception if visualization constructor cannot be instantiated
*/
public void runVis() throws Exception {
if (System.getProperty("java.awt.headless") != null
diff --git a/src/arcade/core/sim/Simulation.java b/src/arcade/core/sim/Simulation.java
index d5b41f924..fee0c690c 100644
--- a/src/arcade/core/sim/Simulation.java
+++ b/src/arcade/core/sim/Simulation.java
@@ -6,142 +6,153 @@
import sim.engine.Schedule;
import arcade.core.agent.action.Action;
import arcade.core.agent.cell.CellContainer;
+import arcade.core.agent.cell.CellFactory;
import arcade.core.env.component.Component;
import arcade.core.env.grid.Grid;
import arcade.core.env.lattice.Lattice;
import arcade.core.env.location.LocationContainer;
+import arcade.core.env.location.LocationFactory;
/**
* A {@code Simulation} sets up agents and environments for a simulation.
- *
- * A {@code Simulation} consists of stepping the model for a given random seed.
- * At the start, agents and environments are added the instance and scheduled.
- * Any additional steppables, including actions and components, are also
- * scheduled.
- *
- * A {@code Simulation} should also extend {@code SimState} from the
- * MASON library.
- * {@code SimState} manages the actual "stepping" of the model, while the
- * {@code Simulation} interface ensures the model can interact with other
- * interfaces and classes in the package.
+ *
+ * A {@code Simulation} consists of stepping the model for a given random seed. At the start,
+ * agents and environments are added the instance and scheduled. Any additional steppables,
+ * including actions and components, are also scheduled.
+ *
+ * A {@code Simulation} should also extend {@code SimState} from the MASON library. {@code SimState} manages the
+ * actual "stepping" of the model, while the {@code Simulation} interface ensures the model can
+ * interact with other interfaces and classes in the package.
*/
-
public interface Simulation {
/** Default type for cell container list. */
- Type DEFAULT_CELL_TYPE = new TypeToken
- * The {@link Series} object can be further queried for information on
- * configuration and parameters.
*
- * @return the {@link Series} instance
+ * The {@link Series} object can be further queried for information on configuration and
+ * parameters.
+ *
+ * @return the {@link Series} instance
*/
Series getSeries();
-
+
/**
* Gets the current schedule for the simulation.
*
- * @return the schedule instance
+ * @return the schedule instance
*/
Schedule getSchedule();
-
+
/**
* Gets the random number generator seed.
*
- * @return the random seed
+ * @return the random seed
*/
int getSeed();
-
+
/**
* Gets the next available ID in the simulation.
*
- * @return the id
+ * @return the id
*/
int getID();
-
+
/**
* Gets the list of {@link CellContainer} objects.
*
- * @return a list of {@link CellContainer} objects
+ * @return a list of {@link CellContainer} objects
*/
ArrayList
- * The concrete implementing class calls this and other setup methods from
- * the MASON library {@code start()} method, which is called before the
- * schedule starts stepping the simulation.
+ *
+ * The concrete implementing class calls this and other setup methods from the MASON library
+ * {@code start()} method, which is called before the schedule starts stepping the simulation.
*/
void setupAgents();
-
+
/**
* Sets up the environment using lattices for the simulation.
- *
- * The concrete implementing class calls this and other setup methods from
- * the MASON library {@code start()} method, which is called before the
- * schedule starts stepping the simulation.
+ *
+ * The concrete implementing class calls this and other setup methods from the MASON library
+ * {@code start()} method, which is called before the schedule starts stepping the simulation.
*/
void setupEnvironment();
-
+
/**
* Schedules any {@link Action} instances.
- *
- * The concrete implementing class calls this and other schedule methods
- * from the MASON library {@code start()} method, which is called before the
- * schedule starts stepping the simulation.
+ *
+ * The concrete implementing class calls this and other schedule methods from the MASON
+ * library {@code start()} method, which is called before the schedule starts stepping the
+ * simulation.
*/
void scheduleActions();
-
+
/**
* Schedules any {@link Component} instances.
- *
- * The concrete implementing class calls this and other schedule methods
- * from the MASON library {@code start()} method, which is called before the
- * schedule starts stepping the simulation.
+ *
+ * The concrete implementing class calls this and other schedule methods from the MASON
+ * library {@code start()} method, which is called before the schedule starts stepping the
+ * simulation.
*/
void scheduleComponents();
}
diff --git a/src/arcade/core/sim/input/InputBuilder.java b/src/arcade/core/sim/input/InputBuilder.java
index 75a648162..755875ab0 100644
--- a/src/arcade/core/sim/input/InputBuilder.java
+++ b/src/arcade/core/sim/input/InputBuilder.java
@@ -17,15 +17,15 @@
/**
* Custom builder for simulation setup XMLs.
- *
- * The class checks for specific tags, which determine where the parsed data is
- * placed for further processing by the {@link arcade.core.sim.Series} class.
- * Once the end tag for a given {@code
- * General structure of the XML file (attributes not listed):
+ *
+ * The class checks for specific tags, which determine where the parsed data is placed for
+ * further processing by the {@link arcade.core.sim.Series} class. Once the end tag for a given
+ * {@code General structure of the XML file (attributes not listed):
+ *
*
- * Reads through the setup XML file using an SAX parser with custom defined
- * content handler, which creates the {@link arcade.core.sim.Series} objects
- * as they are parsed. SAX parses XML files using event handlers and so does
- * not load the entire XML file into memory (in contrast to DOM).
*
- * @param xml the XML file
- * @return a list of {@link arcade.core.sim.Series} instances
+ * Reads through the setup XML file using an SAX parser with custom defined content handler,
+ * which creates the {@link arcade.core.sim.Series} objects as they are parsed. SAX parses XML
+ * files using event handlers and so does not load the entire XML file into memory (in contrast
+ * to DOM).
+ *
+ * @param xml the XML file
+ * @return a list of {@link arcade.core.sim.Series} instances
*/
- public ArrayList
- * XML files should only be one level deep, with all values as attributes.
- * Results are stored in a {@link arcade.core.util.Box} object.
+ *
+ * XML files should only be one level deep, with all values as attributes. Results are stored in
+ * a {@link arcade.core.util.Box} object.
*/
-
public class InputLoader extends DefaultHandler {
/** Logger for {@code InputLoader}. */
private static final Logger LOGGER = Logger.getLogger(InputLoader.class.getName());
-
+
/** XML reader. */
XMLReader xmlReader;
-
+
/** Box holding parsed XML. */
Box box;
-
- /**
- * Creates a {@code InputLoader} using {@code SAXParserFactory}.
- */
+
+ /** Creates a {@code InputLoader} using {@code SAXParserFactory}. */
public InputLoader() {
try {
SAXParserFactory spf = SAXParserFactory.newInstance();
@@ -41,24 +38,24 @@ public InputLoader() {
e.printStackTrace();
}
}
-
+
/**
* Loads the given XML file into a {@link arcade.core.util.Box}.
*
- * @param xml the XML file
- * @return the box containing the parsed XML
+ * @param xml the XML file
+ * @return the box containing the parsed XML
*/
public Box load(String xml) throws IOException, SAXException {
this.box = new Box();
return load(xml, box);
}
-
+
/**
* Loads the given XML file into given {@link arcade.core.util.Box}.
*
- * @param xml the XML file
- * @param loadBox the box to load into
- * @return the box containing the parsed XML
+ * @param xml the XML file
+ * @param loadBox the box to load into
+ * @return the box containing the parsed XML
*/
public Box load(String xml, Box loadBox) throws IOException, SAXException {
this.box = loadBox;
@@ -67,16 +64,16 @@ public Box load(String xml, Box loadBox) throws IOException, SAXException {
LOGGER.config("successfully loaded XML file [ " + xml + " ]\n\n" + box.toString());
return box;
}
-
+
/**
* Called at the start of an XML element.
- *
- * Iterates through each attribute and adds to the box.
*
- * @param uri the namespace URI
- * @param lName the local name
- * @param qName the qualified name
- * @param att the attributes
+ * Iterates through each attribute and adds to the box.
+ *
+ * @param uri the namespace URI
+ * @param lName the local name
+ * @param qName the qualified name
+ * @param att the attributes
*/
@Override
public void startElement(String uri, String lName, String qName, Attributes att) {
@@ -84,12 +81,12 @@ public void startElement(String uri, String lName, String qName, Attributes att)
String id;
String tag;
String filter;
-
+
// Iterate through each attribute and add to a map.
if (numAtts > 0) {
// Set id.
id = att.getValue("id");
-
+
// Search for any special attributes to set as tag.
String[] split = qName.split("\\.");
if (split.length == 2) {
@@ -102,14 +99,14 @@ public void startElement(String uri, String lName, String qName, Attributes att)
} else {
filter = "";
}
-
+
// Add target tag if set.
if (att.getValue("class") != null) {
id = att.getValue("class") + TAG_SEPARATOR + id;
}
-
+
box.addTag(id, split[0].toUpperCase());
-
+
for (int i = 0; i < numAtts; i++) {
String name = att.getQName(i);
if (!name.equals("id") && !name.equals(filter)) {
diff --git a/src/arcade/core/sim/input/InputParser.java b/src/arcade/core/sim/input/InputParser.java
index 9ee8f488d..957868213 100644
--- a/src/arcade/core/sim/input/InputParser.java
+++ b/src/arcade/core/sim/input/InputParser.java
@@ -8,19 +8,21 @@
/**
* Command line parser built from XML defining the possible commands.
- *
- * {@code InputParser} is built using the {@link arcade.core.util.Box} created
- * by {@link arcade.core.sim.input.InputLoader} when parsing
- * {@code command.xml}. There are three command argument types:
+ *
+ * {@code InputParser} is built using the {@link arcade.core.util.Box} created by {@link
+ * arcade.core.sim.input.InputLoader} when parsing {@code command.xml}. There are three command
+ * argument types:
+ *
*
- * General structure of {@code command.xml}:
+ *
+ * General structure of {@code command.xml}:
+ *
*
- * A {@code Command} object is created for each command defined from parsing
- * {@code command.xml}.
+ *
+ * A {@code Command} object is created for each command defined from parsing {@code
+ * command.xml}.
*/
static class Command {
/** Format string. */
String format = "\t%20s %s\n";
-
+
/** Command type. */
int type;
-
+
/** Command id. */
String id;
-
+
/** Command default value. */
String defaults;
-
+
/** Command help text. */
String help;
-
+
/** Command short flag. */
String shortFlag;
-
+
/** Command long flag. */
String longFlag;
-
+
/**
* Creates a {@code Command} object of a given type.
*
- * @param id the unique id of the command
- * @param type the command type
+ * @param id the unique id of the command
+ * @param type the command type
*/
Command(String id, int type) {
this.id = id;
this.type = type;
}
-
+
/**
* Formats command as a string.
*
- * @return a string representation of the command
+ * @return a string representation of the command
*/
public String toString() {
- return "\t" + id.toUpperCase() + "\n"
+ return "\t"
+ + id.toUpperCase()
+ + "\n"
+ (help == null ? "" : String.format(format, "[help]", help))
+ (defaults == null ? "" : String.format(format, "[default]", defaults))
+ (shortFlag == null ? "" : String.format(format, "[short]", shortFlag))
+ (longFlag == null ? "" : String.format(format, "[long]", longFlag));
}
}
-
+
/**
* Parse the given arguments into a dictionary.
*
- * @param args the list of arguments from command line
- * @return a dictionary of parsed commands
+ * @param args the list of arguments from command line
+ * @return a dictionary of parsed commands
*/
public MiniBox parse(String[] args) {
LOGGER.config("parsing command line arguments");
parsed = new MiniBox();
-
+
addDefaults();
parseArguments(args);
-
+
if (positionIndex != positionCommands.size()) {
LOGGER.severe("missing position arguments");
throw new IllegalArgumentException();
} else {
LOGGER.config("successfully parsed commands\n\n" + parsed.toString());
}
-
+
return parsed;
}
-
+
/**
* Adds default values for all commands.
- *
- * Switches are assumed to be {@code false} if not present.
+ *
+ * Switches are assumed to be {@code false} if not present.
*/
void addDefaults() {
for (Command cmd : allCommands) {
@@ -231,20 +234,20 @@ void addDefaults() {
}
}
}
-
+
/**
* Parses a list of arguments.
*
- * @param args the list of arguments
+ * @param args the list of arguments
*/
void parseArguments(String[] args) {
positionIndex = 0;
int currentIndex = 0;
int argCount = args.length;
-
+
while (currentIndex < argCount) {
String arg = args[currentIndex];
-
+
if (arg.startsWith("--")) {
Command cmd = longToCommand.get(args[currentIndex].substring(2));
currentIndex = parseFlaggedArgument(args, currentIndex, cmd);
@@ -256,14 +259,14 @@ void parseArguments(String[] args) {
}
}
}
-
+
/**
* Parses a flagged (either option or switch) argument.
*
- * @param args the argument contents
- * @param index the argument index
- * @param cmd the command object
- * @return the next argument index
+ * @param args the argument contents
+ * @param index the argument index
+ * @param cmd the command object
+ * @return the next argument index
*/
int parseFlaggedArgument(String[] args, int index, Command cmd) {
if (cmd.type == SWITCH) {
@@ -273,24 +276,24 @@ int parseFlaggedArgument(String[] args, int index, Command cmd) {
}
return ++index;
}
-
+
/**
* Parses a position argument.
*
- * @param args the argument contents
- * @param index the argument index
- * @return the next argument index
+ * @param args the argument contents
+ * @param index the argument index
+ * @return the next argument index
*/
int parsePositionArgument(String[] args, int index) {
parsed.put(positionCommands.get(positionIndex).id, args[index]);
positionIndex++;
return ++index;
}
-
+
/**
* Formats parser as a string.
*
- * @return a string representation of the parser
+ * @return a string representation of the parser
*/
public String toString() {
StringBuilder s = new StringBuilder();
diff --git a/src/arcade/core/sim/output/OutputDeserializer.java b/src/arcade/core/sim/output/OutputDeserializer.java
index 82a0f1006..095825212 100644
--- a/src/arcade/core/sim/output/OutputDeserializer.java
+++ b/src/arcade/core/sim/output/OutputDeserializer.java
@@ -16,28 +16,25 @@
/**
* Container class for object deserializers.
- *
- * Generic deserializers include:
+ *
+ * Generic deserializers include:
+ *
*
- * The loader is associated with an implementation-specific {@code Gson}
- * instance that defines deserialization of implementation-specific classes. The
- * associated {@link arcade.core.sim.Series} instance provides any static
- * series-specific information needed for loading. The equipped
- * {@link arcade.core.sim.Simulation} instance is called to get the random seed
- * (if needed) to select the correct files to load. The tag {@code [#]} in the
- * load path is replaced with the random seed of the simulation instance.
+ *
+ * The loader is associated with an implementation-specific {@code Gson} instance that defines
+ * deserialization of implementation-specific classes. The associated {@link arcade.core.sim.Series}
+ * instance provides any static series-specific information needed for loading. The equipped {@link
+ * arcade.core.sim.Simulation} instance is called to get the random seed (if needed) to select the
+ * correct files to load. The tag {@code [#]} in the load path is replaced with the random seed of
+ * the simulation instance.
*/
-
public abstract class OutputLoader {
/** Logger for {@code OutputLoader}. */
private static final Logger LOGGER = Logger.getLogger(OutputLoader.class.getName());
-
+
/** JSON representation. */
final Gson gson;
-
+
/** {@link arcade.core.sim.Series} instance. */
final Series series;
-
+
/** Prefix for loaded files. */
public String prefix;
-
+
/** {@code true} if cells are loaded, {@code false} otherwise. */
public boolean loadCells;
-
+
/** {@code true} if locations are loaded, {@code false} otherwise. */
public boolean loadLocations;
-
+
/** JSON for cells. */
String cellJson;
-
+
/** JSON for locations. */
String locationJson;
-
+
/**
* Creates an {@code OutputLoader} for the series.
*
- * @param series the simulation series
+ * @param series the simulation series
*/
public OutputLoader(Series series) {
this.series = series;
this.gson = makeGSON();
}
-
+
/**
* Creates a {@code Gson} instance for deserializing objects.
*
- * @return a {@code Gson} instance
+ * @return a {@code Gson} instance
*/
protected abstract Gson makeGSON();
-
+
/**
* Equips a {@link arcade.core.sim.Simulation} instance to the loader.
*
- * @param sim the simulation instance
+ * @param sim the simulation instance
*/
public void equip(Simulation sim) {
String seed = String.format("%04d", sim.getSeed());
@@ -84,30 +82,30 @@ public void equip(Simulation sim) {
this.locationJson = read(path + ".LOCATIONS.json");
}
}
-
+
/**
* Loads the JSON for a list of {@link CellContainer} objects.
*
- * @return a list of {@link CellContainer} objects
+ * @return a list of {@link CellContainer} objects
*/
public ArrayList
- * The saver is associated with an implementation-specific {@code Gson} instance
- * that defines serialization of implementation-specific classes. The associated
- * {@link arcade.core.sim.Series} instance is used to save static information
- * specific to the series. The equipped {@link arcade.core.sim.Simulation}
- * instance is called to get cells / locations that are saved at a given tick.
+ *
+ * The saver is associated with an implementation-specific {@code Gson} instance that defines
+ * serialization of implementation-specific classes. The associated {@link arcade.core.sim.Series}
+ * instance is used to save static information specific to the series. The equipped {@link
+ * arcade.core.sim.Simulation} instance is called to get cells / locations that are saved at a given
+ * tick.
*/
-
public abstract class OutputSaver implements Steppable {
/** Logger for {@code OutputSaver}. */
private static final Logger LOGGER = Logger.getLogger(OutputSaver.class.getName());
-
+
/** Number of elements to format in output string. */
private static final int FORMAT_ELEMENTS = 6;
-
+
/** JSON representation. */
final Gson gson;
-
+
/** {@link arcade.core.sim.Series} instance. */
final Series series;
-
+
/** Prefix for saved files. */
public String prefix;
-
+
/** {@link arcade.core.sim.Simulation} instance. */
Simulation sim;
-
+
/**
* Creates an {@code OutputSaver} for the series.
*
- * @param series the simulation series
+ * @param series the simulation series
*/
public OutputSaver(Series series) {
this.series = series;
this.gson = makeGSON();
}
-
+
/**
* Creates a {@code Gson} instance for serializing objects.
*
- * @return a {@code Gson} instance
+ * @return a {@code Gson} instance
*/
protected abstract Gson makeGSON();
-
+
/**
* Equips a {@link arcade.core.sim.Simulation} instance to the saver.
*
- * @param sim the simulation instance
+ * @param sim the simulation instance
*/
public void equip(Simulation sim) {
this.prefix = String.format("%s_%04d", series.getPrefix(), sim.getSeed());
this.sim = sim;
}
-
- /**
- * Saves the {@link arcade.core.sim.Series} as a JSON.
- */
+
+ /** Saves the {@link arcade.core.sim.Series} as a JSON. */
public void saveSeries() {
String path = series.getPrefix() + ".json";
String json = gson.toJson(series);
write(path, format(json, FORMAT_ELEMENTS));
}
-
+
/**
* Save a list of {@link arcade.core.agent.cell.CellContainer} to a JSON.
*
- * @param tick the simulation tick
+ * @param tick the simulation tick
*/
public void saveCells(int tick) {
String path = prefix + String.format("_%06d.CELLS.json", tick);
String json = gson.toJson(sim.getCells(), DEFAULT_CELL_TYPE);
write(path, format(json, FORMAT_ELEMENTS));
}
-
+
/**
* Save a list of {@link arcade.core.env.location.LocationContainer} to a JSON.
*
- * @param tick the simulation tick
+ * @param tick the simulation tick
*/
public void saveLocations(int tick) {
String path = prefix + String.format("_%06d.LOCATIONS.json", tick);
String json = gson.toJson(sim.getLocations(), DEFAULT_LOCATION_TYPE);
write(path, format(json, FORMAT_ELEMENTS));
}
-
+
/**
* Steps through cell rules.
*
- * @param simstate the MASON simulation state
+ * @param simstate the MASON simulation state
*/
@Override
public void step(SimState simstate) {
@@ -115,22 +112,22 @@ public void step(SimState simstate) {
saveCells(tick);
saveLocations(tick);
}
-
+
/**
* Schedules the saver to take snapshots at the given interval.
*
- * @param schedule the simulation schedule
- * @param interval the interval (in ticks) between snapshots
+ * @param schedule the simulation schedule
+ * @param interval the interval (in ticks) between snapshots
*/
public void schedule(Schedule schedule, double interval) {
schedule.scheduleRepeating(Schedule.EPOCH, -1, this, interval);
}
-
+
/**
* Writes the contents to the given file path.
*
- * @param filepath the path for the file
- * @param contents the contents of the file
+ * @param filepath the path for the file
+ * @param contents the contents of the file
*/
public void write(String filepath, String contents) {
try {
@@ -138,14 +135,14 @@ public void write(String filepath, String contents) {
File outfile = new File(filepath);
FileOutputStream fos = new FileOutputStream(outfile, false);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(fos));
-
+
// Write contents
bw.write(contents);
-
+
// Close streams.
bw.close();
fos.close();
-
+
LOGGER.info("file [ " + filepath + " ] successfully written");
} catch (IOException ex) {
LOGGER.severe("error writing [ " + filepath + " ] due to " + ex.getClass().getName());
@@ -153,37 +150,38 @@ public void write(String filepath, String contents) {
series.isSkipped = true;
}
}
-
+
/**
* Formats the arrays in the given string.
- *
- * Method reformats the output of GSON pretty printing by converting
- * {@code [\n A,\n B,\n ... N\n ]} to {@code [ A, B, ..., N ]} for lists of
- * up to N elements.
*
- * @param string the string to format
- * @param maxElements the maximum number of elements to format.
- * @return the formatted string
+ * Method reformats the output of GSON pretty printing by converting {@code [\n A,\n B,\n ...
+ * N\n ]} to {@code [ A, B, ..., N ]} for lists of up to N elements.
+ *
+ * @param string the string to format
+ * @param maxElements the maximum number of elements to format.
+ * @return the formatted string
*/
protected static String format(String string, int maxElements) {
String formatted = string;
-
+
for (int elements = 1; elements < maxElements + 1; elements++) {
- String inputPattern = IntStream.rangeClosed(1, elements)
- .mapToObj(Integer::toString)
- .map(s -> "([\\-\\d\\.]+)")
- .collect(Collectors.joining(",\\n[\\s\\t]+"));
+ String inputPattern =
+ IntStream.rangeClosed(1, elements)
+ .mapToObj(Integer::toString)
+ .map(s -> "([\\-\\d\\.]+)")
+ .collect(Collectors.joining(",\\n[\\s\\t]+"));
inputPattern = "\\[\\n[\\s\\t]+" + inputPattern + "\\n[\\s\\t]+\\]";
-
- String outputPattern = IntStream.rangeClosed(1, elements)
- .mapToObj(Integer::toString)
- .map(s -> "$" + s)
- .collect(Collectors.joining(", "));
+
+ String outputPattern =
+ IntStream.rangeClosed(1, elements)
+ .mapToObj(Integer::toString)
+ .map(s -> "$" + s)
+ .collect(Collectors.joining(", "));
outputPattern = "[" + outputPattern + "]";
-
+
formatted = formatted.replaceAll(inputPattern, outputPattern);
}
-
+
return formatted;
}
}
diff --git a/src/arcade/core/sim/output/OutputSerializer.java b/src/arcade/core/sim/output/OutputSerializer.java
index f64a0eb5a..b211ec158 100644
--- a/src/arcade/core/sim/output/OutputSerializer.java
+++ b/src/arcade/core/sim/output/OutputSerializer.java
@@ -20,36 +20,32 @@
/**
* Container class for object serializers.
- *
- * Generic serializers include:
+ *
+ * Generic serializers include:
+ *
*
- * The contents of the box are formatted as:
+ *
+ * The contents of the box are formatted as:
+ *
*
- * The series object is formatted as:
+ *
+ * The series object is formatted as:
+ *
*
- * The series object is formatted as:
+ *
+ * The series object is formatted as:
+ *
*
- * The series object is formatted as:
+ *
+ * The series object is formatted as:
+ *
*
- * {@code Box} objects use two {@link arcade.core.util.MiniBox} objects to map
- * between key, tags, and attributes. Rather than nesting the key to attribute
- * to values, the class automatically joins key and attribute into a new key.
+ *
+ * {@code Box} objects use two {@link arcade.core.util.MiniBox} objects to map between key, tags,
+ * and attributes. Rather than nesting the key to attribute to values, the class automatically joins
+ * key and attribute into a new key.
*/
-
public class Box {
/** Separator character for keys. */
public static final String KEY_SEPARATOR = "~";
-
+
/** List of keys. */
final ArrayList
- * Automatically updates the list of keys.
*
- * @param id the id
- * @param tag the tag
+ * Automatically updates the list of keys.
+ *
+ * @param id the id
+ * @param tag the tag
*/
public void addTag(String id, String tag) {
if (!keys.contains(id)) {
@@ -78,13 +83,13 @@ public void addTag(String id, String tag) {
}
idToTag.put(id, tag);
}
-
+
/**
* Adds an attribute for the given id.
*
- * @param id the id
- * @param att the attribute name
- * @param val the attribute value
+ * @param id the id
+ * @param att the attribute name
+ * @param val the attribute value
*/
public void addAtt(String id, String att, String val) {
if (!keys.contains(id)) {
@@ -92,12 +97,12 @@ public void addAtt(String id, String att, String val) {
}
idToVal.put(id + KEY_SEPARATOR + att, val);
}
-
+
/**
* Adds a value for a given id.
*
- * @param id the id
- * @param val the value
+ * @param id the id
+ * @param val the value
*/
public void add(String id, String val) {
String key = id.split(KEY_SEPARATOR)[0];
@@ -106,12 +111,12 @@ public void add(String id, String val) {
}
idToVal.put(id, val);
}
-
+
/**
* Gets a mapping from attribute name to value for a given id.
*
- * @param id the id
- * @return a map of attribute names to values
+ * @param id the id
+ * @return a map of attribute names to values
*/
public MiniBox getAttValForId(String id) {
MiniBox result = new MiniBox();
@@ -123,11 +128,11 @@ public MiniBox getAttValForId(String id) {
}
return result;
}
-
+
/**
* Gets a mapping from id to value for untagged entries.
*
- * @return a map of id to value
+ * @return a map of id to value
*/
public MiniBox getIdVal() {
MiniBox result = new MiniBox();
@@ -139,21 +144,23 @@ public MiniBox getIdVal() {
}
return result;
}
-
+
/**
* Gets a mapping from id to value of "value" attribute for a given tag.
*
- * @param tag the tag
- * @return the map of id to value
+ * @param tag the tag
+ * @return the map of id to value
*/
- public MiniBox getIdValForTag(String tag) { return getIdValForTagAtt(tag, "value"); }
-
+ public MiniBox getIdValForTag(String tag) {
+ return getIdValForTagAtt(tag, "value");
+ }
+
/**
* Gets a mapping from id to selected attribute value for a given tag.
*
- * @param tag the tag
- * @param att the attribute name
- * @return a map of id to selected attribute value
+ * @param tag the tag
+ * @param att the attribute name
+ * @return a map of id to selected attribute value
*/
public MiniBox getIdValForTagAtt(String tag, String att) {
MiniBox result = new MiniBox();
@@ -165,34 +172,34 @@ public MiniBox getIdValForTagAtt(String tag, String att) {
}
return result;
}
-
+
/**
* Filters box for entries matching the given tag.
*
- * @param tag the tag
- * @return a list of unique entries
+ * @param tag the tag
+ * @return a list of unique entries
*/
public HashSet
- * Custom color map management for use with visualization classes in
- * MASON library.
+ *
+ * Custom color map management for use with visualization classes in MASON library.
*/
-
public class Colors implements ColorMap {
/** Number of bins. */
private static final int BINS = 256;
-
+
/** Color with no alpha. */
private static final Color EMPTY = new Color(0, 0, 0, 0);
-
+
/** Color map. */
private final Color[] colors;
-
+
/** Minimum value. */
private final double min;
-
+
/** Maximum value. */
private final double max;
-
+
/** Number of colors in the color map. */
private final int len;
-
+
/** Default value. */
private final double defaultValue;
-
+
/** Modulo on index, 0 if no modulo is applied. */
private final int mod;
-
+
/**
* Creates {@code Colors} table.
*
* @param colors the table of colors
*/
- public Colors(Color[] colors) { this(colors, 0); }
-
+ public Colors(Color[] colors) {
+ this(colors, 0);
+ }
+
/**
* Creates {@code Colors} table with modulo index.
*
- * @param colors the table of colors
- * @param mod the value of modulo on index before selecting color
+ * @param colors the table of colors
+ * @param mod the value of modulo on index before selecting color
*/
public Colors(Color[] colors, int mod) {
this.colors = colors;
@@ -56,24 +57,24 @@ public Colors(Color[] colors, int mod) {
this.defaultValue = -1;
this.mod = mod;
}
-
+
/**
* Creates {@code Colors} between two values.
*
- * @param minCol the color associated with the lower bound
- * @param maxCol the color associated with the upper bound
- * @param minVal the value of the lower bound
- * @param maxVal the value of the upper bound
+ * @param minCol the color associated with the lower bound
+ * @param maxCol the color associated with the upper bound
+ * @param minVal the value of the lower bound
+ * @param maxVal the value of the upper bound
*/
public Colors(Color minCol, Color maxCol, double minVal, double maxVal) {
- this(new Color[] { minCol, maxCol }, new double[] { minVal, maxVal });
+ this(new Color[] {minCol, maxCol}, new double[] {minVal, maxVal});
}
-
+
/**
* Creates {@code Colors} between multiple values.
*
- * @param colors the array of colors associated with each bound
- * @param vals the list of values at each bound
+ * @param colors the array of colors associated with each bound
+ * @param vals the list of values at each bound
*/
public Colors(Color[] colors, double[] vals) {
int n = vals.length - 1;
@@ -83,26 +84,26 @@ public Colors(Color[] colors, double[] vals) {
this.len = BINS;
this.defaultValue = min - 1;
this.mod = 0;
-
+
int sum = 0;
for (int i = 0; i < n; i++) {
- int bin = (int) Math.round(BINS * (vals[i + 1] - vals[i]) / (max - min));
+ int bin = (int) (BINS * (vals[i + 1] - vals[i]) / (max - min));
interpColors(colors[i], colors[i + 1], sum, sum + bin);
sum += bin;
}
-
+
for (int i = Math.min(BINS, sum); i < BINS + 1; i++) {
this.colors[i] = colors[n];
}
}
-
+
/**
* Interpolates between two colors.
*
- * @param minCol the minimum color
- * @param maxCol the maximum color
- * @param start the starting value
- * @param end the ending value
+ * @param minCol the minimum color
+ * @param maxCol the maximum color
+ * @param start the starting value
+ * @param end the ending value
*/
private void interpColors(Color minCol, Color maxCol, int start, int end) {
int n = (Math.min(end, BINS)) - start;
@@ -111,7 +112,7 @@ private void interpColors(Color minCol, Color maxCol, int start, int end) {
int b;
int a;
double delta;
-
+
// Create color array.
int minR = minCol.getRed();
int minG = minCol.getGreen();
@@ -121,7 +122,7 @@ private void interpColors(Color minCol, Color maxCol, int start, int end) {
int maxG = maxCol.getGreen();
int maxB = maxCol.getBlue();
int maxA = maxCol.getAlpha();
-
+
// Increment color between bounds.
for (int i = 0; i < n; i++) {
delta = (double) i / n;
@@ -132,78 +133,81 @@ private void interpColors(Color minCol, Color maxCol, int start, int end) {
colors[i + start] = new Color(r, g, b, a);
}
}
-
+
/**
* Gets color map index for given number value.
- *
- * Applies modulo if the {@code mod} is not zero. Index is determined as
- * (length of bins in the colormap)*(level scaled between the minimum and
- * maximum).
*
- * @param level the number value
- * @return the color map index
+ * Applies modulo if the {@code mod} is not zero. Index is determined as (length of bins in
+ * the colormap)*(level scaled between the minimum and maximum).
+ *
+ * @param level the number value
+ * @return the color map index
*/
private int getIndex(double level) {
int index = (int) (len * (((mod == 0 ? level : level % mod) - min) / (max - min)));
return index < 0 ? 0 : Math.min(index, len);
}
-
+
/**
* Gets the color corresponding to level.
*
- * @param level the number value
- * @return the color
+ * @param level the number value
+ * @return the color
*/
@Override
public Color getColor(double level) {
- if (level == defaultValue) {
+ if (level <= defaultValue) {
return EMPTY;
}
return colors[getIndex(level)];
}
-
+
/**
* Gets RGB corresponding to level.
*
- * @param level the number value
- * @return the RGB value
+ * @param level the number value
+ * @return the RGB value
*/
@Override
public int getRGB(double level) {
- if (level == defaultValue) {
+ if (level <= defaultValue) {
return EMPTY.getRGB();
}
return colors[getIndex(level)].getRGB();
}
-
+
/**
* Gets the alpha corresponding to level.
*
- * @param level the number value
- * @return the alpha value
+ * @param level the number value
+ * @return the alpha value
*/
@Override
public int getAlpha(double level) {
- if (level == defaultValue) {
+ if (level <= defaultValue) {
return EMPTY.getAlpha();
}
return colors[getIndex(level)].getAlpha();
}
-
+
/**
* Checks if the number value is between the minimum and maximum.
*
- * @param level the number value
- * @return {@code true} if level is valid, {@code false} otherwise
+ * @param level the number value
+ * @return {@code true} if level is valid, {@code false} otherwise
*/
@Override
- public boolean validLevel(double level) { return level >= min && level <= max; }
-
+ public boolean validLevel(double level) {
+ return level >= min && level <= max;
+ }
+
/**
* Gets default value.
*
- * @return the default number value
+ * @return the default number value
*/
@Override
- public double defaultValue() { return defaultValue; }
+ public double defaultValue() {
+ return defaultValue;
+ }
}
diff --git a/src/arcade/core/util/Distribution.java b/src/arcade/core/util/Distribution.java
deleted file mode 100644
index 9e4e20bd9..000000000
--- a/src/arcade/core/util/Distribution.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package arcade.core.util;
-
-import sim.util.distribution.Normal;
-import ec.util.MersenneTwisterFast;
-
-/**
- * Container class for truncated normal distribution.
- */
-
-public class Distribution {
- /** Normal distribution. */
- private final Normal normal;
-
- /** Values for truncated distribution bounds. */
- private final double[] bounds;
-
- /** Mean of the distribution. */
- private final double mu;
-
- /** Standard deviation of the distribution. */
- private final double sigma;
-
- /**
- * Creates a truncated normal {@code Distribution}.
- *
- * @param mu the mean of the normal distribution
- * @param sigma the standard deviation of the normal distribution
- * @param random the random number generator instance
- */
- public Distribution(double mu, double sigma, MersenneTwisterFast random) {
- this.mu = mu;
- this.sigma = sigma;
- this.normal = new Normal(mu, Math.abs(sigma), random);
-
- bounds = new double[2];
- bounds[0] = mu - 2 * sigma;
- bounds[1] = mu + 2 * sigma;
- }
-
- /**
- * Gets the mean of the distribution.
- *
- * @return the distribution mean
- */
- public double getMu() { return mu; }
-
- /**
- * Gets the standard deviation of the distribution.
- *
- * @return the distribution standard deviation
- */
- public double getSigma() { return sigma; }
-
- /**
- * Draws a double from the truncated normal distribution.
- *
- * @return a double drawn from the distribution
- */
- public double nextDouble() {
- return Math.min(Math.max(normal.nextDouble(), bounds[0]), bounds[1]);
- }
-}
diff --git a/src/arcade/core/util/GrabBag.java b/src/arcade/core/util/GrabBag.java
new file mode 100644
index 000000000..c25890287
--- /dev/null
+++ b/src/arcade/core/util/GrabBag.java
@@ -0,0 +1,81 @@
+package arcade.core.util;
+
+import java.util.NavigableMap;
+import java.util.TreeMap;
+import ec.util.MersenneTwisterFast;
+
+/**
+ * Container for weighted collection of integers.
+ *
+ * {@code GrabBag} objects are collections of integers, where each integer has a weighted
+ * probability of selection. For example, integers A, B, and C with weights a, b, and c,
+ * respectively, have the following probabilities of selection:
+ *
+ *
- * {@code Edge} objects represent edges in the graph and {@code Node} objects
- * represent nodes in the graph. Nodes may have more than one edge in or out.
+ *
+ * {@code Edge} objects represent edges in the graph and {@code Node} objects represent nodes in
+ * the graph. Nodes may have more than one edge in or out.
*/
-
public final class Graph {
+
+ /** Calculation strategies. */
+ public enum Strategy {
+ /** Code for upstream calculation strategy. */
+ UPSTREAM,
+
+ /** Code for downstream direction strategy. */
+ DOWNSTREAM
+ }
+
/** Collection of all {@code Edge} objects in a graph. */
private final Bag allEdges;
-
+
/** Map of {@code Node} OUT to bag of {@code Edge} objects. */
private final Map
- * Notes that the links in the subgraph are not correct.
*
- * @param g the graph to add filtered edges to
- * @param f the edge filter
+ * Notes that the links in the subgraph are not correct.
+ *
+ * @param g the graph to add filtered edges to
+ * @param f the edge filter
*/
public void getSubgraph(Graph g, GraphFilter f) {
for (Object obj : allEdges) {
@@ -155,25 +212,34 @@ public void getSubgraph(Graph g, GraphFilter f) {
}
}
}
-
+
/**
- * Sets the TO and FROM nodes for edges to be the same object.
+ * Retrieves all nodes in the graph.
+ *
+ * @return a set containing the nodes
*/
- public void mergeNodes() {
+ private Set
- * The node tracks its corresponding position in the lattice.
+ *
+ * The node tracks its corresponding position in the lattice.
*/
- public abstract static class Node implements Comparable
- * The edge tracks its corresponding nodes as well as the edges into the
- * FROM node and out of the TO node.
+ *
+ * The edge tracks its corresponding nodes as well as the edges into the FROM node and out of
+ * the TO node.
*/
- public abstract static class Edge {
+ public static class Edge {
/** Node this edge points to. */
protected Node to;
-
+
/** Node this edge points from. */
protected Node from;
-
+
/** List of edges that point into the node this edge points from. */
private final ArrayList
- * Class provides a subset of matrix operations needed for solving a system
- * of linear equations using the successive over-relaxation method in
- * {@link arcade.core.util.Solver}.
+ *
+ * Class provides a subset of matrix operations needed for solving a system of linear equations
+ * using the successive over-relaxation method in {@link arcade.core.util.Solver}.
*/
-
public class Matrix {
/** Container class for sparse matrix representation. */
public static class Value {
/** Row index of value. */
int i;
-
+
/** Column index of value. */
int j;
-
+
/** Value in matrix. */
double v;
-
+
/**
* Creates a value in a sparse matrix.
*
- * @param i the row index of the value
- * @param j the column index of the value
- * @param v the value
+ * @param i the row index of the value
+ * @param j the column index of the value
+ * @param v the value
*/
Value(int i, int j, double v) {
this.i = i;
this.j = j;
this.v = v;
}
-
+
/**
* Gets hash based on (i, j) indices.
*
- * @return the hash
+ * @return the hash
*/
- public final int hashCode() { return i + (j << 8); }
-
+ public final int hashCode() {
+ return i + (j << 8);
+ }
+
/**
* Checks if two values have the same (i, j) indices.
*
- * @param obj the value to compare
- * @return {@code true} if values have the same indices, {@code false} otherwise
+ * @param obj the value to compare
+ * @return {@code true} if values have the same indices, {@code false} otherwise
*/
public final boolean equals(Object obj) {
- if (!(obj instanceof Value)) { return false; }
+ if (!(obj instanceof Value)) {
+ return false;
+ }
Value value = (Value) obj;
return value.i == i && value.j == j && value.v == v;
}
-
+
/**
* Formats value as a string.
*
- * @return a string representation of the value
+ * @return a string representation of the value
*/
public String toString() {
return "(" + i + "," + j + ") = " + v;
}
}
-
- /**
- * Hidden utility class constructor.
- */
+
+ /** Hidden utility class constructor. */
protected Matrix() {
throw new UnsupportedOperationException();
}
-
+
/**
* Converts a dense matrix representation to a sparse matrix representation.
*
- * @param mat the dense matrix representation
- * @return the sparse matrix representation
+ * @param mat the dense matrix representation
+ * @return the sparse matrix representation
*/
public static ArrayList
- * Matrix L must be a square lower triangular matrix.
+ * Solves the equation {@code Lx = b} using forward substitution for a dense matrix.
+ *
+ * Matrix L must be a square lower triangular matrix.
*
- * @param mat the matrix of coefficients
- * @param vec the right-hand side vector
- * @return the left-hand side vector
+ * @param mat the matrix of coefficients
+ * @param vec the right-hand side vector
+ * @return the left-hand side vector
*/
public static double[] forwardSubstitution(double[][] mat, double[] vec) {
int n = vec.length;
@@ -182,16 +195,15 @@ public static double[] forwardSubstitution(double[][] mat, double[] vec) {
}
return subbed;
}
-
+
/**
- * Solves the equation {@code Lx = U} using forward substitution for a
- * dense matrix.
- *
- * The matrices {@code L} and {@code U} are the square lower and upper
- * triangular matrices of the given matrix.
+ * Solves the equation {@code Lx = U} using forward substitution for a dense matrix.
+ *
+ * The matrices {@code L} and {@code U} are the square lower and upper triangular matrices of
+ * the given matrix.
*
- * @param mat the matrix of coefficients
- * @return the left-hand side matrix
+ * @param mat the matrix of coefficients
+ * @return the left-hand side matrix
*/
public static double[][] forwardSubstitution(double[][] mat) {
double[][] lower = getLower(mat, false);
@@ -210,23 +222,21 @@ public static double[][] forwardSubstitution(double[][] mat) {
}
return subbed;
}
-
+
/**
- * Solves the equation {@code Lx = b} using forward substitution for a
- * sparse matrix.
+ * Solves the equation {@code Lx = b} using forward substitution for a sparse matrix.
*
- * @param mat the matrix of coefficients
- * @param vec the right-hand side vector
- * @return the left-hand side vector
+ * @param mat the matrix of coefficients
+ * @param vec the right-hand side vector
+ * @return the left-hand side vector
*/
public static double[] forwardSubstitution(ArrayList
- * The matrices {@code L} and {@code U} are the square lower and upper
- * triangular matrices of the given matrix.
+ * Solves the equation {@code Lx = U} using forward substitution for a sparse matrix.
*
- * @param mat the matrix of coefficients
- * @return the left-hand side matrix
+ * The matrices {@code L} and {@code U} are the square lower and upper triangular matrices of
+ * the given matrix.
+ *
+ * @param mat the matrix of coefficients
+ * @return the left-hand side matrix
*/
public static ArrayList
- * {@code MiniBox} objects are dictionaries that use a String to String hashmap.
- * Utility methods are provided to return the contents as specific types.
+ *
+ * {@code MiniBox} objects are dictionaries that use a String to String hashmap. Utility methods
+ * are provided to return the contents as specific types.
*/
-
public class MiniBox {
/** Separator character for tags. */
public static final String TAG_SEPARATOR = "/";
-
+
/** Regular expression for numbers. */
- private static final String NUMBER_REGEX = "^(-?\\d*\\.\\d*)$|^(-?\\d+)$|"
- + "^(-?\\d+E-?\\d+)$|^(-?\\d*\\.\\d*E-?\\d+)$";
-
+ private static final String NUMBER_REGEX =
+ "^(-?\\d*\\.\\d*)$|^(-?\\d+)$|" + "^(-?\\d+E-?\\d+)$|^(-?\\d*\\.\\d*E-?\\d+)$";
+
/** List of keys. */
final ArrayList
- * Entries in the form "key = value" where key = code/subkey can be
- * filtered. The returned box contains all entries in the form "subkey =
- * value" for all entries where the code matches the given code.
*
- * @param code the code to filter by
- * @return the filtered box
+ * Entries in the form "key = value" where key = code/subkey can be filtered. The returned
+ * box contains all entries in the form "subkey = value" for all entries where the code matches
+ * the given code.
+ *
+ * @param code the code to filter by
+ * @return the filtered box
*/
public MiniBox filter(String code) {
MiniBox results = new MiniBox();
@@ -139,37 +177,35 @@ public MiniBox filter(String code) {
}
return results;
}
-
+
/**
* Compares two {@code MiniBox} instances.
*
- * @param box the {@code MiniBox} to compare to
- * @return {@code true} if entries match, {@code false} otherwise
+ * @param box the {@code MiniBox} to compare to
+ * @return {@code true} if entries match, {@code false} otherwise
*/
public boolean compare(MiniBox box) {
HashSet
- * Each {@code Parameter} is associated with a random number generator to select
- * additional parameter values from a normal distribution.
- * For parameters that are fractions (bounded between 0 and 1), the tails of the
- * distribution are truncated.
- */
-
-public class Parameter implements Serializable {
- /** Random number generator. */
- private final MersenneTwisterFast random;
-
- /** Normal distribution. */
- private final Normal normal;
-
- /** Values for truncated distributions. */
- private final double[] tails;
-
- /** {@code true} if parameter is a fraction between 0 and 1, {@code false} otherwise. */
- private final boolean isFrac;
-
- /** Mean of the distribution. */
- private final double mu;
-
- /** Standard deviation of the distribution. */
- private final double sigma;
-
- /** Heterogeneity of the parameter. */
- private final double h;
-
- /**
- * Creates a {@code Parameter} normal distribution.
- *
- * @param mu the mean of parameter normal distribution
- * @param h the amount of heterogeneity where standard deviation sigma = h*mu
- * @param isFrac indicates if distribution is truncated between 0 and 1
- * @param random the random number generator
- */
- public Parameter(double mu, double h, boolean isFrac, MersenneTwisterFast random) {
- this.h = h;
- this.isFrac = isFrac;
- this.random = random;
- this.mu = mu;
- this.sigma = mu * h;
-
- normal = new Normal(mu, Math.abs(sigma), random);
- tails = new double[2];
- tails[(mu < 0 ? 1 : 0)] = mu + 2 * sigma;
- tails[(mu < 0 ? 0 : 1)] = mu - 2 * sigma;
-
- if (isFrac) {
- tails[0] = Math.min(tails[0], 1.0);
- tails[1] = Math.max(tails[1], 0.0);
- }
- }
-
- /**
- * Gets the mean of the distribution.
- *
- * @return the distribution mean
- */
- public double getMu() { return mu; }
-
- /**
- * Gets the standard deviation of the distribution.
- *
- * @return the distribution standard deviation
- */
- public double getSigma() { return sigma; }
-
- /**
- * Creates a new parameter with updated mean.
- *
- * @param mean the mean of the new parameter
- * @return a parameter instance with the new mean
- */
- public Parameter update(double mean) {
- return new Parameter(mean, h, isFrac, random);
- }
-
- /**
- * Draws a double from the bounded normal distribution.
- *
- * @return a double drawn from the distribution
- */
- public double nextDouble() {
- return Math.max(Math.min(normal.nextDouble(), tails[0]), tails[1]);
- }
-
- /**
- * Draws a integer from the bounded normal distribution.
- *
- * @return an integer drawn from the distribution
- */
- public int nextInt() {
- return (int) nextDouble();
- }
-}
diff --git a/src/arcade/core/util/Parameters.java b/src/arcade/core/util/Parameters.java
new file mode 100644
index 000000000..0a56f3363
--- /dev/null
+++ b/src/arcade/core/util/Parameters.java
@@ -0,0 +1,145 @@
+package arcade.core.util;
+
+import java.security.InvalidParameterException;
+import java.util.HashMap;
+import java.util.HashSet;
+import ec.util.MersenneTwisterFast;
+import arcade.core.util.distributions.Distribution;
+
+/**
+ * Container for parameters and parameter distributions.
+ *
+ * {@code Parameters} objects contain a {@link MiniBox} of population parameters along with
+ * parameter distributions. Utility methods are provided to return parameters as specific types.
+ */
+public class Parameters {
+ /** Population parameters. */
+ final MiniBox popParameters;
+
+ /** Map of parameter names to distributions. */
+ final HashMap Parameters with distributions are tagged as {@code DISTRIBUTION} in the population
+ * parameters dictionary. Each of these parameters are converted to a {@link Distribution}
+ * instance. If a parent cell parameters is passed, the parent parameter distributions are used
+ * to generate the {@link Distribution} instance instead.
+ *
+ * @param popParameters the cell population parameters
+ * @param cellParameters the parent cell parameters
+ * @param random the random number generator
+ */
+ public Parameters(
+ MiniBox popParameters, Parameters cellParameters, MersenneTwisterFast random) {
+ this.popParameters = popParameters;
+ distributions = new HashMap<>();
+
+ MiniBox distributionsBox = popParameters.filter("(DISTRIBUTION)");
+ for (String key : distributionsBox.getKeys()) {
+ Distribution distribution;
+
+ if (cellParameters != null && cellParameters.distributions.containsKey(key)) {
+ distribution = cellParameters.distributions.get(key).rebase(random);
+ } else {
+ distribution = popParameters.getDistribution(key, random);
+ }
+
+ distributions.put(key, distribution);
+ }
+ }
+
+ /**
+ * Gets the parameter value as a double.
+ *
+ * The parameter value is pulled from the distribution object, if it exists. Otherwise, the
+ * parameter is pulled from the population parameter dictionary.
+ *
+ * @param key the parameter key
+ * @return the parameter value as a double
+ */
+ public double getDouble(String key) {
+ if (distributions.containsKey(key)) {
+ return distributions.get(key).getDoubleValue();
+ } else if (popParameters.contains(key)) {
+ return popParameters.getDouble(key);
+ } else {
+ throw new InvalidParameterException();
+ }
+ }
+
+ /**
+ * Gets the parameter value as an integer.
+ *
+ * The parameter value is pulled from the distribution object, if it exists. Otherwise, the
+ * parameter is pulled from the population parameter dictionary.
+ *
+ * @param key the parameter key
+ * @return the parameter value as an integer
+ */
+ public int getInt(String key) {
+ if (distributions.containsKey(key)) {
+ return distributions.get(key).getIntValue();
+ } else if (popParameters.contains(key)) {
+ return popParameters.getInt(key);
+ } else {
+ throw new InvalidParameterException();
+ }
+ }
+
+ /**
+ * Gets the parameter value as a distribution, if it exists.
+ *
+ * @param key the parameter key
+ * @return the parameter value as a distribution
+ */
+ public Distribution getDistribution(String key) {
+ if (distributions.containsKey(key)) {
+ return distributions.get(key);
+ } else {
+ throw new InvalidParameterException();
+ }
+ }
+
+ /**
+ * Filters parameters by the given code.
+ *
+ * @param code the code to filter by
+ * @return the filtered box
+ */
+ public MiniBox filter(String code) {
+ return popParameters.filter(code);
+ }
+
+ /**
+ * Compares two {@code Parameters} instances.
+ *
+ * Instances are equal if (1) both parameters have the same population parameters and (2)
+ * both parameters have the same distributions. Note that distributions are the same if they
+ * have the same distribution parameters; the value pulled from each distribution is ignored.
+ *
+ * @param parameters the {@code Parameters} to compare to
+ * @return {@code true} if contents match, {@code false} otherwise
+ */
+ public boolean compare(Parameters parameters) {
+ HashSet
- * Implemented solvers include:
+ *
+ * Implemented solvers include:
+ *
*
- * Based on matrix size, the algorithm with use a dense or sparse approach.
+ * Solves a linear system of equations using successive over-relaxation with default sparse
+ * representation thresholding and maximum iterations.
*
- * @param mat the matrix of coefficients
- * @param vec the right-hand side vector
- * @param x0 the initial guess for the left-hand side vector
- * @return the vector of final values
+ * Based on matrix size, the algorithm with use a dense or sparse approach.
+ *
+ * @param mat the matrix of coefficients
+ * @param vec the right-hand side vector
+ * @param x0 the initial guess for the left-hand side vector
+ * @return the vector of final values
*/
public static double[] sor(double[][] mat, double[] vec, double[] x0) {
+ return sor(mat, vec, x0, MATRIX_THRESHOLD, MAX_ITERS, TOLERANCE);
+ }
+
+ /**
+ * Solves a linear system of equations using successive over-relaxation.
+ *
+ * Based on matrix size, the algorithm with use a dense or sparse approach.
+ *
+ * @param mat the matrix of coefficients
+ * @param vec the right-hand side vector
+ * @param x0 the initial guess for the left-hand side vector
+ * @param matrixThreshold the threshold for matrix size
+ * @param maxIters the maximum number of iterations
+ * @param tolerance the error tolerance
+ * @return the vector of final values
+ */
+ public static double[] sor(
+ double[][] mat,
+ double[] vec,
+ double[] x0,
+ int matrixThreshold,
+ int maxIters,
+ double tolerance) {
int n = mat.length;
- if (n < MATRIX_THRESHOLD) {
- return denseSOR(mat, vec, x0);
+ if (n < matrixThreshold) {
+ return denseSOR(mat, vec, x0, maxIters, tolerance);
} else {
- return sparseSOR(mat, vec, x0);
+ return sparseSOR(mat, vec, x0, maxIters, tolerance);
}
}
-
+
/**
* Solves linear system of equations using SOR with dense matrix representation.
*
- * @param mat the matrix of coefficients
- * @param vec the right-hand side vector
- * @param x0 the initial guess for the left-hand side vector
- * @return the vector of final values
+ * @param mat the matrix of coefficients
+ * @param vec the right-hand side vector
+ * @param x0 the initial guess for the left-hand side vector
+ * @param maxIters the maximum number of iterations
+ * @param tolerance the error tolerance
+ * @return the vector of final values
*/
- private static double[] denseSOR(double[][] mat, double[] vec, double[] x0) {
+ private static double[] denseSOR(
+ double[][] mat, double[] vec, double[] x0, int maxIters, double tolerance) {
int i = 0;
double error = Double.POSITIVE_INFINITY;
-
+
// Calculate iteration factors
double[] c = forwardSubstitution(mat, vec);
double[][] t = forwardSubstitution(mat);
t = scale(t, -1);
-
+
// Set initial guess.
double[] xCurr = x0;
double[] xPrev = x0;
-
+
// Iterate until convergence.
- while (i < MAX_ITERS && error > TOLERANCE) {
+ while (i < maxIters && error > tolerance) {
// Calculate new guess for x.
xCurr = add(scale(add(multiply(t, xPrev), c), OMEGA), scale(xPrev, 1 - OMEGA));
-
+
// Set previous to copy of current and increment iteration count.
xPrev = xCurr;
i++;
-
+
// Calculate L2 norm of residuals to check for convergence.
double[] r = subtract(vec, multiply(mat, xCurr));
error = normalize(r);
}
-
+
return xCurr;
}
-
+
/**
* Solves linear system of equations using SOR with sparse matrix representation.
*
- * @param mat the matrix of coefficients
- * @param vec the right-hand side vector
- * @param x0 the initial guess for the left-hand side vector
- * @return the vector of final values
+ * @param mat the matrix of coefficients
+ * @param vec the right-hand side vector
+ * @param x0 the initial guess for the left-hand side vector
+ * @param maxIters the maximum number of iterations
+ * @param tolerance the error tolerance
+ * @return the vector of final values
*/
- private static double[] sparseSOR(double[][] mat, double[] vec, double[] x0) {
+ private static double[] sparseSOR(
+ double[][] mat, double[] vec, double[] x0, int maxIters, double tolerance) {
int i = 0;
double error = Double.POSITIVE_INFINITY;
-
+
// Convert to sparse representation.
ArrayList
- * Root is found by repeatedly bisecting the interval and selecting the
- * interval in which the function changes sign.
- * If no root is found, the simulation will exit.
*
- * @param func the function
- * @param a the lower bound on the interval
- * @param b the upper bound on the interval
- * @return the root of the function
+ * Root is found by repeatedly bisecting the interval and selecting the interval in which the
+ * function changes sign. If no root is found, the simulation will throw an ArithmeticException.
+ *
+ * @param func the function
+ * @param a the lower bound on the interval
+ * @param b the upper bound on the interval
+ * @param maxIters the maximum number of iterations
+ * @return the root of the function
*/
- public static double bisection(Function func, double a, double b) {
+ public static double bisection(Function func, double a, double b, int maxIters) {
double c;
double fc;
int i = 0;
-
+
+ if (a > b) {
+ a = a + b;
+ b = a - b;
+ a = a - b;
+ }
+
// Check that given bounds are opposite signs.
if (Math.signum(func.f(a)) == Math.signum(func.f(b))) {
- LOGGER.severe("bisection unable to find root");
- System.exit(-1);
+ throw new ArithmeticException("Bisection cannot find root with given bounds.");
}
-
- while (i < MAX_ITERS) {
+
+ while (i < maxIters) {
// Calculate new midpoint.
c = (a + b) / 2;
fc = func.f(c);
-
+
// Check for exit conditions.
if (fc == 0 || (b - a) / 2 < DELTA) {
return c;
@@ -392,11 +460,26 @@ public static double bisection(Function func, double a, double b) {
} else {
b = c;
}
-
+
i++;
}
}
-
+
return Double.NaN;
}
+
+ /**
+ * Finds root using bisection method with default maximum iterations.
+ *
+ * Root is found by repeatedly bisecting the interval and selecting the interval in which the
+ * function changes sign. If no root is found, the simulation will throw an ArithmeticException.
+ *
+ * @param func the function
+ * @param a the lower bound on the interval
+ * @param b the upper bound on the interval
+ * @return the root of the function
+ */
+ public static double bisection(Function func, double a, double b) {
+ return bisection(func, a, b, MAX_ITERS);
+ }
}
diff --git a/src/arcade/core/util/Utilities.java b/src/arcade/core/util/Utilities.java
index 26947f55b..c4c6c0355 100644
--- a/src/arcade/core/util/Utilities.java
+++ b/src/arcade/core/util/Utilities.java
@@ -4,26 +4,21 @@
import java.util.ListIterator;
import ec.util.MersenneTwisterFast;
-/**
- * Container class for utility methods.
- */
-
+/** Container class for utility methods. */
public final class Utilities {
- /**
- * Hidden utility class constructor.
- */
+ /** Hidden utility class constructor. */
protected Utilities() {
throw new UnsupportedOperationException();
}
-
+
/**
* Copies the contents on one 3D array to another 3D array.
- *
- * The {@code clone} method only works at the one-dimensional level.
- * Otherwise, we would have shallow cloning.
*
- * @param fromArray the array to copy from
- * @param toArray the array to copy to
+ * The {@code clone} method only works at the one-dimensional level. Otherwise, we would have
+ * shallow cloning.
+ *
+ * @param fromArray the array to copy from
+ * @param toArray the array to copy to
*/
public static void copyArray(double[][][] fromArray, double[][][] toArray) {
for (int k = 0; k < fromArray.length; k++) {
@@ -32,16 +27,15 @@ public static void copyArray(double[][][] fromArray, double[][][] toArray) {
}
}
}
-
+
/**
* Shuffles the given list using a seeded random number generator.
- *
- * The list is shuffled in placed.
- * Based on {@code java.util.Collections} and adapted to use the seeded
- * random number generator.
*
- * @param list the list to be shuffled
- * @param rng the random number generator
+ * The list is shuffled in placed. Based on {@code java.util.Collections} and adapted to use
+ * the seeded random number generator.
+ *
+ * @param list the list to be shuffled
+ * @param rng the random number generator
*/
public static void shuffleList(ArrayList> list, MersenneTwisterFast rng) {
int size = list.size();
@@ -52,19 +46,19 @@ public static void shuffleList(ArrayList> list, MersenneTwisterFast rng) {
}
ListIterator it = list.listIterator();
-
+
for (int i = 0; i < size; i++) {
it.next();
it.set(arr[i]);
}
}
-
+
/**
* Swaps two objects in an array in place.
*
- * @param arr the array containing the objects
- * @param i the index of the first object
- * @param j the index of the second object
+ * @param arr the array containing the objects
+ * @param i the index of the first object
+ * @param j the index of the second object
*/
static void swap(Object[] arr, int i, int j) {
Object temp = arr[i];
diff --git a/src/arcade/core/util/distributions/BernoulliDistribution.java b/src/arcade/core/util/distributions/BernoulliDistribution.java
new file mode 100644
index 000000000..41296bf72
--- /dev/null
+++ b/src/arcade/core/util/distributions/BernoulliDistribution.java
@@ -0,0 +1,77 @@
+package arcade.core.util.distributions;
+
+import sim.util.distribution.Binomial;
+import ec.util.MersenneTwisterFast;
+import arcade.core.util.MiniBox;
+
+/** Container class for Bernoulli distribution. */
+public class BernoulliDistribution implements Distribution {
+ /** Probability of success for the distribution. */
+ final double probability;
+
+ /** Value drawn from the distribution. */
+ final double value;
+
+ /** Bernoulli distribution. */
+ private final Binomial bernoulli;
+
+ /**
+ * Creates a Bernoulli {@code Distribution} from parameters dictionary.
+ *
+ * @param name the distribution parameter name
+ * @param parameters the distribution parameters dictionary
+ * @param random the random number generator instance
+ */
+ public BernoulliDistribution(String name, MiniBox parameters, MersenneTwisterFast random) {
+ this(parameters.getDouble(name + "_PROBABILITY"), random);
+ }
+
+ /**
+ * Creates a Bernoulli {@code Distribution} from parameters.
+ *
+ * @param probability the probability of success of the Bernoulli distribution
+ * @param random the random number generator instance
+ */
+ public BernoulliDistribution(double probability, MersenneTwisterFast random) {
+ this.probability = probability;
+ this.bernoulli = new Binomial(1, probability, random);
+ this.value = bernoulli.nextDouble();
+ }
+
+ @Override
+ public MiniBox getParameters() {
+ MiniBox parameters = new MiniBox();
+ parameters.put("PROBABILITY", probability);
+ return parameters;
+ }
+
+ @Override
+ public double getExpected() {
+ return probability;
+ }
+
+ @Override
+ public double getDoubleValue() {
+ return value;
+ }
+
+ @Override
+ public int getIntValue() {
+ return (int) Math.round(value);
+ }
+
+ @Override
+ public double nextDouble() {
+ return bernoulli.nextDouble();
+ }
+
+ @Override
+ public int nextInt() {
+ return (int) Math.round(nextDouble());
+ }
+
+ @Override
+ public Distribution rebase(MersenneTwisterFast random) {
+ return new BernoulliDistribution(probability, random);
+ }
+}
diff --git a/src/arcade/core/util/distributions/Distribution.java b/src/arcade/core/util/distributions/Distribution.java
new file mode 100644
index 000000000..be511d7a0
--- /dev/null
+++ b/src/arcade/core/util/distributions/Distribution.java
@@ -0,0 +1,66 @@
+package arcade.core.util.distributions;
+
+import ec.util.MersenneTwisterFast;
+import arcade.core.util.MiniBox;
+
+/**
+ * A {@code Distribution} object represents a parameter distribution.
+ *
+ * When created, the object immediately draws an initial value from the distribution. All getters
+ * should return this initial value. Additional values can be pulled from the distribution using the
+ * next methods, but does not change the initial value.
+ *
+ * A new distribution object can be created, in which the initial value is used as the new base
+ * value.
+ */
+public interface Distribution {
+ /**
+ * Gets the initial value drawn from the distribution as a double.
+ *
+ * @return the double drawn from the distribution
+ */
+ double getDoubleValue();
+
+ /**
+ * Gets the initial value drawn from the distribution as an integer.
+ *
+ * @return the integer drawn from the distribution
+ */
+ int getIntValue();
+
+ /**
+ * Draws a new double from the distribution.
+ *
+ * @return a double drawn from the distribution
+ */
+ double nextDouble();
+
+ /**
+ * Draws a new integer from the distribution.
+ *
+ * @return an integer drawn from the distribution
+ */
+ int nextInt();
+
+ /**
+ * Gets the distribution parameters.
+ *
+ * @return the distribution parameters
+ */
+ MiniBox getParameters();
+
+ /**
+ * Gets the expected value of the distribution.
+ *
+ * @return the expected value
+ */
+ double getExpected();
+
+ /**
+ * Creates a new distribution based on the initial value drawn.
+ *
+ * @param random the random number generator
+ * @return the new distribution
+ */
+ Distribution rebase(MersenneTwisterFast random);
+}
diff --git a/src/arcade/core/util/distributions/NormalDistribution.java b/src/arcade/core/util/distributions/NormalDistribution.java
new file mode 100644
index 000000000..52e644452
--- /dev/null
+++ b/src/arcade/core/util/distributions/NormalDistribution.java
@@ -0,0 +1,100 @@
+package arcade.core.util.distributions;
+
+import sim.util.distribution.Normal;
+import ec.util.MersenneTwisterFast;
+import arcade.core.util.MiniBox;
+
+/** Container class for normal distribution. */
+public class NormalDistribution implements Distribution {
+ /** Values for distribution bounds. */
+ final double[] bounds;
+
+ /** Mean of the distribution. */
+ final double mu;
+
+ /** Standard deviation of the distribution. */
+ final double sigma;
+
+ /** Value drawn from the distribution. */
+ final double value;
+
+ /** Normal distribution. */
+ private final Normal normal;
+
+ /**
+ * Creates a normal {@code Distribution} from parameters dictionary.
+ *
+ * @param name the distribution parameter name
+ * @param parameters the distribution parameters dictionary
+ * @param random the random number generator instance
+ */
+ public NormalDistribution(String name, MiniBox parameters, MersenneTwisterFast random) {
+ this(parameters.getDouble(name + "_MU"), parameters.getDouble(name + "_SIGMA"), random);
+ }
+
+ /**
+ * Creates a normal {@code Distribution} from parameters.
+ *
+ * @param mu the mean of the normal distribution
+ * @param sigma the standard deviation of the normal distribution
+ * @param random the random number generator instance
+ */
+ public NormalDistribution(double mu, double sigma, MersenneTwisterFast random) {
+ this.mu = mu;
+ this.sigma = Math.abs(sigma);
+ this.normal = new Normal(mu, sigma, random);
+ this.bounds = getBounds();
+ this.value = nextDouble();
+ }
+
+ /**
+ * Calculate bounds on distribution values.
+ *
+ * @return the distribution bounds.
+ */
+ double[] getBounds() {
+ return null;
+ }
+
+ @Override
+ public MiniBox getParameters() {
+ MiniBox parameters = new MiniBox();
+ parameters.put("MU", mu);
+ parameters.put("SIGMA", sigma);
+ return parameters;
+ }
+
+ @Override
+ public double getExpected() {
+ return mu;
+ }
+
+ @Override
+ public double getDoubleValue() {
+ return value;
+ }
+
+ @Override
+ public int getIntValue() {
+ return (int) Math.round(value);
+ }
+
+ @Override
+ public double nextDouble() {
+ if (bounds != null) {
+ return Math.min(Math.max(normal.nextDouble(), bounds[0]), bounds[1]);
+ } else {
+ return normal.nextDouble();
+ }
+ }
+
+ @Override
+ public int nextInt() {
+ return (int) Math.round(nextDouble());
+ }
+
+ @Override
+ public Distribution rebase(MersenneTwisterFast random) {
+ return new NormalDistribution(value, sigma, random);
+ }
+}
diff --git a/src/arcade/core/util/distributions/NormalFractionalDistribution.java b/src/arcade/core/util/distributions/NormalFractionalDistribution.java
new file mode 100644
index 000000000..ba0cc9a7b
--- /dev/null
+++ b/src/arcade/core/util/distributions/NormalFractionalDistribution.java
@@ -0,0 +1,49 @@
+package arcade.core.util.distributions;
+
+import ec.util.MersenneTwisterFast;
+import arcade.core.util.MiniBox;
+import arcade.core.util.exceptions.OutOfBoundsException;
+
+/** Container class for fractional normal distribution. */
+public class NormalFractionalDistribution extends NormalDistribution {
+ /**
+ * Creates a fractional normal {@code Distribution} from parameters dictionary.
+ *
+ * @param name the distribution parameter name
+ * @param parameters the distribution parameters dictionary
+ * @param random the random number generator instance
+ */
+ public NormalFractionalDistribution(
+ String name, MiniBox parameters, MersenneTwisterFast random) {
+ super(name, parameters, random);
+ }
+
+ /**
+ * Creates a fractional normal {@code Distribution} from parameters.
+ *
+ * @param mu the mean of the normal distribution
+ * @param sigma the standard deviation of the normal distribution
+ * @param random the random number generator instance
+ */
+ public NormalFractionalDistribution(double mu, double sigma, MersenneTwisterFast random) {
+ super(mu, sigma, random);
+ }
+
+ @Override
+ double[] getBounds() {
+ if (mu <= 0 || mu >= 1) {
+ throw new OutOfBoundsException(mu, 0.0, 1.0);
+ }
+
+ double[] bounds = new double[2];
+ bounds[0] = Math.max(mu - 2 * sigma, 0.0);
+ bounds[1] = Math.min(mu + 2 * sigma, 1.0);
+
+ return bounds;
+ }
+
+ @Override
+ public Distribution rebase(MersenneTwisterFast random) {
+ return new NormalFractionalDistribution(value, sigma, random);
+ }
+}
diff --git a/src/arcade/core/util/distributions/NormalTruncatedDistribution.java b/src/arcade/core/util/distributions/NormalTruncatedDistribution.java
new file mode 100644
index 000000000..0935f638b
--- /dev/null
+++ b/src/arcade/core/util/distributions/NormalTruncatedDistribution.java
@@ -0,0 +1,43 @@
+package arcade.core.util.distributions;
+
+import ec.util.MersenneTwisterFast;
+import arcade.core.util.MiniBox;
+
+/** Container class for truncated normal distribution. */
+public class NormalTruncatedDistribution extends NormalDistribution {
+ /**
+ * Creates a truncated normal {@code Distribution} from parameters dictionary.
+ *
+ * @param name the distribution parameter name
+ * @param parameters the distribution parameters dictionary
+ * @param random the random number generator instance
+ */
+ public NormalTruncatedDistribution(
+ String name, MiniBox parameters, MersenneTwisterFast random) {
+ super(name, parameters, random);
+ }
+
+ /**
+ * Creates a truncated normal {@code Distribution} from parameters.
+ *
+ * @param mu the mean of the normal distribution
+ * @param sigma the standard deviation of the normal distribution
+ * @param random the random number generator instance
+ */
+ public NormalTruncatedDistribution(double mu, double sigma, MersenneTwisterFast random) {
+ super(mu, sigma, random);
+ }
+
+ @Override
+ double[] getBounds() {
+ double[] bounds = new double[2];
+ bounds[0] = mu - 2 * sigma;
+ bounds[1] = mu + 2 * sigma;
+ return bounds;
+ }
+
+ @Override
+ public Distribution rebase(MersenneTwisterFast random) {
+ return new NormalTruncatedDistribution(value, sigma, random);
+ }
+}
diff --git a/src/arcade/core/util/distributions/UniformDistribution.java b/src/arcade/core/util/distributions/UniformDistribution.java
new file mode 100644
index 000000000..44a61a1d0
--- /dev/null
+++ b/src/arcade/core/util/distributions/UniformDistribution.java
@@ -0,0 +1,83 @@
+package arcade.core.util.distributions;
+
+import sim.util.distribution.Uniform;
+import ec.util.MersenneTwisterFast;
+import arcade.core.util.MiniBox;
+
+/** Container class for uniform distribution. */
+public class UniformDistribution implements Distribution {
+ /** Minimum of the distribution. */
+ final double min;
+
+ /** Maximum of the distribution. */
+ final double max;
+
+ /** Value drawn from the distribution. */
+ final double value;
+
+ /** Uniform distribution. */
+ private final Uniform uniform;
+
+ /**
+ * Creates a uniform {@code Distribution} from parameters dictionary.
+ *
+ * @param name the distribution parameter name
+ * @param parameters the distribution parameters dictionary
+ * @param random the random number generator instance
+ */
+ public UniformDistribution(String name, MiniBox parameters, MersenneTwisterFast random) {
+ this(parameters.getDouble(name + "_MIN"), parameters.getDouble(name + "_MAX"), random);
+ }
+
+ /**
+ * Creates a uniform {@code Distribution} from parameters.
+ *
+ * @param min the minimum of the uniform distribution
+ * @param max the maximum of the uniform distribution
+ * @param random the random number generator instance
+ */
+ public UniformDistribution(double min, double max, MersenneTwisterFast random) {
+ this.min = min;
+ this.max = max;
+ this.uniform = new Uniform(min, max, random);
+ this.value = nextDouble();
+ }
+
+ @Override
+ public MiniBox getParameters() {
+ MiniBox parameters = new MiniBox();
+ parameters.put("MIN", min);
+ parameters.put("MAX", max);
+ return parameters;
+ }
+
+ @Override
+ public double getExpected() {
+ return (min + max) / 2.0;
+ }
+
+ @Override
+ public double getDoubleValue() {
+ return value;
+ }
+
+ @Override
+ public int getIntValue() {
+ return (int) Math.round(value);
+ }
+
+ @Override
+ public double nextDouble() {
+ return uniform.nextDouble();
+ }
+
+ @Override
+ public int nextInt() {
+ return (int) Math.round(nextDouble());
+ }
+
+ @Override
+ public Distribution rebase(MersenneTwisterFast random) {
+ return new UniformDistribution(min, max, random);
+ }
+}
diff --git a/src/arcade/core/util/exceptions/OutOfBoundsException.java b/src/arcade/core/util/exceptions/OutOfBoundsException.java
new file mode 100644
index 000000000..bad3a50ce
--- /dev/null
+++ b/src/arcade/core/util/exceptions/OutOfBoundsException.java
@@ -0,0 +1,18 @@
+package arcade.core.util.exceptions;
+
+/** Exception thrown when a parameter is out of bounds. */
+public class OutOfBoundsException extends RuntimeException {
+ /**
+ * Constructs an {@code OutOfBoundsException} with the specified detail message.
+ *
+ * @param given the given valid parameter value
+ * @param minValid the minimum valid parameter value
+ * @param maxValid the maximum valid parameter value
+ */
+ public OutOfBoundsException(double given, double minValid, double maxValid) {
+ super(
+ String.format(
+ "Parameter value [ %f ] must be between [ %f ] and [ %f ]",
+ given, minValid, maxValid));
+ }
+}
diff --git a/src/arcade/core/vis/Drawer.java b/src/arcade/core/vis/Drawer.java
index 5076b3451..aa7431ca4 100644
--- a/src/arcade/core/vis/Drawer.java
+++ b/src/arcade/core/vis/Drawer.java
@@ -7,44 +7,49 @@
/**
* Visualization for simulation objects.
- *
- * {@code Drawer} objects convert simulation objects into
- * MASON Portrayals,
- * which can then be displayed.
+ *
+ * {@code Drawer} objects convert simulation objects into MASON Portrayals, which can then be
+ * displayed.
*/
-
public abstract class Drawer implements Steppable {
/** Portrayal. */
protected final Portrayal port;
-
+
/** Name of drawing. */
protected final String name;
-
+
/** Color map for drawing. */
protected final ColorMap map;
-
+
/** Length of the array (x direction). */
protected final int length;
-
+
/** Width of the array (y direction). */
protected final int width;
-
+
/** Height of the array (z direction). */
protected final int height;
-
+
/**
* Creates a {@code Drawer} and attaches it to the panel.
*
- * @param panel the panel the drawer is attached to
- * @param name the name of the drawer
- * @param length the length of array (x direction)
- * @param width the width of array (y direction)
- * @param height the height of array (z direction)
- * @param map the color map for the array
- * @param bounds the size of the drawer within the panel
+ * @param panel the panel the drawer is attached to
+ * @param name the name of the drawer
+ * @param length the length of array (x direction)
+ * @param width the width of array (y direction)
+ * @param height the height of array (z direction)
+ * @param map the color map for the array
+ * @param bounds the size of the drawer within the panel
*/
- public Drawer(Panel panel, String name, int length, int width, int height,
- ColorMap map, Rectangle2D.Double bounds) {
+ public Drawer(
+ Panel panel,
+ String name,
+ int length,
+ int width,
+ int height,
+ ColorMap map,
+ Rectangle2D.Double bounds) {
this.name = name;
this.length = length;
this.width = width;
@@ -53,18 +58,20 @@ public Drawer(Panel panel, String name, int length, int width, int height,
this.port = makePort();
panel.attach(this, name, bounds);
}
-
+
/**
* Gets the portrayal.
*
- * @return the portrayal
+ * @return the portrayal
*/
- public Portrayal getPortrayal() { return port; }
-
+ public Portrayal getPortrayal() {
+ return port;
+ }
+
/**
* Creates the portrayal and underlying array objects.
*
- * @return the portrayal
+ * @return the portrayal
*/
public abstract Portrayal makePort();
}
diff --git a/src/arcade/core/vis/Panel.java b/src/arcade/core/vis/Panel.java
index 557fc2f34..5b5db749f 100644
--- a/src/arcade/core/vis/Panel.java
+++ b/src/arcade/core/vis/Panel.java
@@ -10,31 +10,29 @@
/**
* Wrapper for JFrame windows containing visualizations.
- *
- * Each JFrame object is generated by a Display object from the
- * MASON library.
- * Each {@code Panel} is a window that can contain one or more drawings made by
- * {@link arcade.core.vis.Drawer} objects. All {@code Panel} objects are created
- * by {@link arcade.core.vis.Visualization} and then attaches
+ *
+ * Each JFrame object is generated by a Display object from the MASON library. Each {@code Panel} is a
+ * window that can contain one or more drawings made by {@link arcade.core.vis.Drawer} objects. All
+ * {@code Panel} objects are created by {@link arcade.core.vis.Visualization} and then attaches
* {@link arcade.core.vis.Drawer} objects to their assigned {@code Panel}.
*/
-
public class Panel {
/** Frame for panel. */
JFrame frame;
-
+
/** Display object for 2D. */
final Display2D display;
-
+
/**
* Creates a {@link arcade.core.vis.Panel} for display.
*
- * @param title the title of the panel
- * @param x the x position of the panel in pixels
- * @param y the y position of the panel in pixels
- * @param w the width of the panel in pixels
- * @param h the height of the panel in pixels
- * @param vis the visualization instance
+ * @param title the title of the panel
+ * @param x the x position of the panel in pixels
+ * @param y the y position of the panel in pixels
+ * @param w the width of the panel in pixels
+ * @param h the height of the panel in pixels
+ * @param vis the visualization instance
*/
public Panel(String title, int x, int y, int w, int h, Visualization vis) {
display = new Display2D(w, h, vis);
@@ -42,20 +40,22 @@ public Panel(String title, int x, int y, int w, int h, Visualization vis) {
frame = display.createFrame();
setup(title, x, y);
}
-
+
/**
* Gets the frame.
*
- * @return the frame
+ * @return the frame
*/
- public JFrame getFrame() { return frame; }
-
+ public JFrame getFrame() {
+ return frame;
+ }
+
/**
* Attaches a {@link arcade.core.vis.Panel} to the panel.
*
- * @param drawer the drawer
- * @param name the name of the drawer
- * @param bounds the bounds for the drawing
+ * @param drawer the drawer
+ * @param name the name of the drawer
+ * @param bounds the bounds for the drawing
*/
public void attach(Drawer drawer, String name, Rectangle2D.Double bounds) {
FieldPortrayal2D port = (FieldPortrayal2D) drawer.getPortrayal();
@@ -65,42 +65,38 @@ public void attach(Drawer drawer, String name, Rectangle2D.Double bounds) {
display.attach(port, name, bounds);
}
}
-
- /**
- * Resets the panel.
- */
+
+ /** Resets the panel. */
public void reset() {
display.reset();
display.repaint();
}
-
+
/**
* Sets up the title and location of the frame.
*
- * @param title the title of the frame
- * @param x the x position of the frame
- * @param y the y position of the frame
+ * @param title the title of the frame
+ * @param x the x position of the frame
+ * @param y the y position of the frame
*/
public void setup(String title, int x, int y) {
frame.setVisible(true);
frame.setTitle(title);
frame.setLocation(new Point(x, y));
}
-
- /**
- * Removes the frame.
- */
+
+ /** Removes the frame. */
public void remove() {
if (frame != null) {
frame.dispose();
}
frame = null;
}
-
+
/**
* Registers the frame to the controller.
*
- * @param controller the controller
+ * @param controller the controller
*/
public void register(Controller controller) {
controller.registerFrame(frame);
diff --git a/src/arcade/core/vis/Visualization.java b/src/arcade/core/vis/Visualization.java
index a4097cc02..ccdececc2 100644
--- a/src/arcade/core/vis/Visualization.java
+++ b/src/arcade/core/vis/Visualization.java
@@ -8,94 +8,94 @@
/**
* Extension of {@code GUIState} wrapper of simulations for visualization.
- *
- * {@code Visualization} organizes the visualization into
- * {@link arcade.core.vis.Panel} objects, on which visualizations are drawn, and
- * {@link arcade.core.vis.Drawer} objects, which draw the visualization through
- * methods provided by the
- * MASON library.
+ *
+ * {@code Visualization} organizes the visualization into {@link arcade.core.vis.Panel} objects,
+ * on which visualizations are drawn, and {@link arcade.core.vis.Drawer} objects, which draw the
+ * visualization through methods provided by the MASON library.
*/
-
public abstract class Visualization extends GUIState {
/** List of panels in the visualization. */
protected Panel[] panels;
-
+
/** List of drawers in the visualization. */
protected Drawer[] drawers;
-
+
/**
* Creates a {@code Visualization} for the given simulation.
*
- * @param simstate the simulation state instance
+ * @param simstate the simulation state instance
*/
- protected Visualization(SimState simstate) { super(simstate); }
-
+ protected Visualization(SimState simstate) {
+ super(simstate);
+ }
+
/**
* Sets the inspector to get state property methods.
*
- * @return the MASON simulation state
+ * @return the MASON simulation state
*/
@Override
- public Object getSimulationInspectedObject() { return state; }
-
+ public Object getSimulationInspectedObject() {
+ return state;
+ }
+
/**
* Remove the model inspector.
*
- * @return a {@code null} inspector
+ * @return a {@code null} inspector
*/
@Override
- public Inspector getInspector() { return null; }
-
+ public Inspector getInspector() {
+ return null;
+ }
+
/**
* Creates panels for the visualization.
*
- * @return the list of panels
+ * @return the list of panels
*/
protected abstract Panel[] createPanels();
-
+
/**
* Creates drawers for the visualization.
*
- * @return the list of drawers
+ * @return the list of drawers
*/
protected abstract Drawer[] createDrawers();
-
+
/**
* Creates a bounding box for panels.
*
- * @param x the x position of the bounding box
- * @param y the y position of the bounding box
- * @param h the horizontal size of the bounding box
- * @param v the vertical size of the bounding box
- * @return the bounding box
+ * @param x the x position of the bounding box
+ * @param y the y position of the bounding box
+ * @param h the horizontal size of the bounding box
+ * @param v the vertical size of the bounding box
+ * @return the bounding box
*/
protected static Rectangle2D.Double getBox(int x, int y, int h, int v) {
return new Rectangle2D.Double(x, y, h, v);
}
-
- /**
- * Starts a visualization.
- */
+
+ /** Starts a visualization. */
@Override
public void start() {
super.start();
setup();
}
-
+
/**
* Loads a visualization from the given simulation.
*
- * @param simstate the MASON simulation state
+ * @param simstate the MASON simulation state
*/
@Override
public void load(SimState simstate) {
super.load(simstate);
setup();
}
-
- /**
- * Quits the visualization.
- */
+
+ /** Quits the visualization. */
@Override
public void quit() {
super.quit();
@@ -103,11 +103,11 @@ public void quit() {
panel.remove();
}
}
-
+
/**
* Initializes the visualization.
*
- * @param controller the controller
+ * @param controller the controller
*/
@Override
public void init(Controller controller) {
@@ -118,15 +118,13 @@ public void init(Controller controller) {
panel.register(controller);
}
}
-
- /**
- * Sets up and schedules portrayals.
- */
+
+ /** Sets up and schedules portrayals. */
public void setup() {
for (Drawer drawer : drawers) {
this.scheduleRepeatingImmediatelyAfter(drawer);
}
-
+
for (Panel panel : panels) {
panel.reset();
}
diff --git a/src/arcade/patch/PatchARCADE.java b/src/arcade/patch/PatchARCADE.java
index 16728594c..2916208f8 100644
--- a/src/arcade/patch/PatchARCADE.java
+++ b/src/arcade/patch/PatchARCADE.java
@@ -9,25 +9,28 @@
import arcade.patch.sim.output.PatchOutputLoader;
import arcade.patch.sim.output.PatchOutputSaver;
-/**
- * Implementation of ARCADE for patch models.
- */
-
+/** Implementation of ARCADE for patch models. */
public final class PatchARCADE extends ARCADE {
- /**
- * ARCADE model with patches.
- */
- public PatchARCADE() { }
-
+ /** ARCADE model with patches. */
+ public PatchARCADE() {}
+
@Override
- public String getResource(String s) { return PatchARCADE.class.getResource(s).toString(); }
-
+ public String getResource(String s) {
+ return PatchARCADE.class.getResource(s).toString();
+ }
+
@Override
- public InputBuilder getBuilder() { return new PatchInputBuilder(); }
-
+ public InputBuilder getBuilder() {
+ return new PatchInputBuilder();
+ }
+
@Override
- public OutputLoader getLoader(Series series) { return new PatchOutputLoader(series); }
-
+ public OutputLoader getLoader(Series series) {
+ return new PatchOutputLoader(series);
+ }
+
@Override
- public OutputSaver getSaver(Series series) { return new PatchOutputSaver(series); }
+ public OutputSaver getSaver(Series series) {
+ return new PatchOutputSaver(series);
+ }
}
diff --git a/src/arcade/patch/agent/action/PatchActionConvert.java b/src/arcade/patch/agent/action/PatchActionConvert.java
index de82d5250..1c33b50d6 100644
--- a/src/arcade/patch/agent/action/PatchActionConvert.java
+++ b/src/arcade/patch/agent/action/PatchActionConvert.java
@@ -17,71 +17,79 @@
/**
* Implementation of {@link Action} for converting cells to a different class.
- *
- * The action is stepped once after {@code TIME_DELAY}. The action will select
- * one cell located at the center of the simulation and convert it to a cell
- * agent of the new population by removing the old cell and creating a new cell
- * with the same age and volume.
+ *
+ * The action is stepped once after {@code TIME_DELAY}. The action will select one cell located
+ * at the center of the simulation and convert it to a cell agent of the new population by removing
+ * the old cell and creating a new cell with the same age and volume.
*/
-
public class PatchActionConvert implements Action {
/** Time delay before calling the action [min]. */
private final int timeDelay;
-
+
/** Target population id for conversion. */
private int pop;
-
+
/**
* Creates a {@link Action} for converting cell agent classes.
- *
- * Loaded parameters include:
+ *
+ * Loaded parameters include:
+ *
*
- * The action is stepped once after {@code TIME_DELAY}. The action will insert a
- * mixture of {@code INSERT_NUMBER} cells from each of the registered
- * populations into locations within the specified radius {@code INSERT_RADIUS}
- * from the center of the simulation.
+ *
+ * The action is stepped once after {@code TIME_DELAY}. The action will insert a mixture of
+ * {@code INSERT_NUMBER} cells from each of the registered populations into locations within the
+ * specified radius {@code INSERT_RADIUS} from the center of the simulation.
*/
-
public class PatchActionInsert implements Action {
/** Time delay before calling the action [min]. */
private final int timeDelay;
-
+
/** Grid radius that cells are inserted into. */
private final int insertRadius;
-
+
/** Grid depth that cells are inserted into. */
private final int insertDepth;
-
+
/** Number of cells to insert from each population. */
private final int insertNumber;
-
+
/** List of populations. */
private final ArrayList
- * Loaded parameters include:
+ *
+ * Loaded parameters include:
+ *
*
- * The action is stepped once after {@code TIME_DELAY}. The action will remove
- * all cell agents within the specified radius {@code REMOVE_RADIUS} from the
- * center of the simulation. Quiescent cells bordering the removal site are set
- * to undefined state.
+ *
+ * The action is stepped once after {@code TIME_DELAY}. The action will remove all cell agents
+ * within the specified radius {@code REMOVE_RADIUS} from the center of the simulation. Quiescent
+ * cells bordering the removal site are set to undefined state.
*/
-
public class PatchActionRemove implements Action {
/** Time delay before calling the action [min]. */
private final int timeDelay;
-
+
/** Grid radius that cells are removed from. */
private final int removeRadius;
-
+
/** Grid depth that cells are removed from. */
private final int removeDepth;
-
+
/**
* Creates a {@link Action} for removing cell agents.
- *
- * Loaded parameters include:
+ *
+ * Loaded parameters include:
+ *
*
- * {@code PatchCell} agents exist in one of seven states: undefined, apoptotic,
- * quiescent, migratory, proliferative, senescent, and necrotic. The undefined
- * state is a transition state for "undecided" cells, and does not have any
- * biological analog.
- *
- * {@code PatchCell} agents have two required {@link Process} domains:
- * metabolism and signaling. Metabolism controls changes in cell energy and
- * volume. Signaling controls the proliferative vs. migratory decision.
- *
- * General order of rules for the {@code PatchCell} step:
+ *
+ * {@code PatchCell} agents exist in one of seven states: undefined, apoptotic, quiescent,
+ * migratory, proliferative, senescent, and necrotic. The undefined state is a transition state for
+ * "undecided" cells, and does not have any biological analog.
+ *
+ * {@code PatchCell} agents have two required {@link Process} domains: metabolism and signaling.
+ * Metabolism controls changes in cell energy and volume. Signaling controls the proliferative vs.
+ * migratory decision.
+ *
+ * General order of rules for the {@code PatchCell} step:
+ *
*
- * Cells that become necrotic or senescent have a change to become apoptotic
- * instead ({@code NECROTIC_FRACTION} and {@code SENESCENT_FRACTION},
- * respectively).
- *
- * Cell parameters are tracked using a map between the parameter name and value.
- * Daughter cell parameter values are drawn from a distribution centered on the
- * parent cell parameter with the specified amount of heterogeneity
- * ({@code HETEROGENEITY}).
+ *
+ * Cells that become necrotic or senescent have a change to become apoptotic instead ({@code
+ * NECROTIC_FRACTION} and {@code SENESCENT_FRACTION}, respectively).
+ *
+ * Cell parameters are tracked using a map between the parameter name and value. Daughter cell
+ * parameter values are drawn from a distribution centered on the parent cell parameter with the
+ * specified amount of heterogeneity ({@code HETEROGENEITY}).
*/
-
public abstract class PatchCell implements Cell {
/** Stopper used to stop this agent from being stepped in the schedule. */
Stoppable stopper;
-
+
/** Cell {@link Location} object. */
final PatchLocation location;
-
+
/** Unique cell ID. */
final int id;
-
+
/** Cell parent ID. */
final int parent;
-
+
/** Cell population index. */
final int pop;
-
+
/** Cell state. */
CellState state;
-
+
/** Cell age [min]. */
int age;
-
+
/** Cell energy [fmol ATP]. */
private double energy;
-
+
/** Number of divisions. */
int divisions;
-
+
/** Cell volume [um3]. */
double volume;
-
+
/** Cell height [um]. */
double height;
-
+
/** Critical volume for cell [um3]. */
final double criticalVolume;
-
+
/** Critical height for cell [um]. */
final double criticalHeight;
-
+
/** Cell state change flag. */
private Flag flag;
-
- /** Variation in cell agent parameters. */
- private final double heterogeneity;
-
+
/** Fraction of necrotic cells that become apoptotic. */
private final double necroticFraction;
-
+
/** Fraction of senescent cells that become apoptotic. */
private final double senescentFraction;
-
+
/** Maximum energy deficit before necrosis. */
private final double energyThreshold;
-
+
/** Cell state module. */
protected Module module;
-
+
/** Map of process domains and {@link Process} instance. */
protected final Map
- * Loaded parameters include:
+ *
+ * Loaded parameters include:
+ *
*
- * Each free location is scored based on glucose availability and distance
- * from the center of the simulation.
*
- * @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
+ * Each free location is scored based on glucose availability and distance from the center of
+ * the simulation.
+ *
+ * @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
*/
- public static PatchLocation selectBestLocation(Simulation sim, PatchLocation location,
- double volume, double height,
- MersenneTwisterFast random) {
+ public static PatchLocation selectBestLocation(
+ 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);
diff --git a/src/arcade/patch/agent/cell/PatchCellCancer.java b/src/arcade/patch/agent/cell/PatchCellCancer.java
index 22d872d1f..9ba152b95 100644
--- a/src/arcade/patch/agent/cell/PatchCellCancer.java
+++ b/src/arcade/patch/agent/cell/PatchCellCancer.java
@@ -5,47 +5,49 @@
import arcade.core.agent.cell.CellState;
import arcade.core.env.location.Location;
import arcade.core.sim.Simulation;
-import arcade.core.util.MiniBox;
+import arcade.core.util.GrabBag;
+import arcade.core.util.Parameters;
import static arcade.patch.util.PatchEnums.State;
/**
* Extension of {@link PatchCellTissue} for cancerous tissue cells.
- *
- * {@code PatchCellCancer} agents are modified from their superclass:
+ *
+ * {@code PatchCellCancer} agents are modified from their superclass:
+ *
*
- * Quiescent cells will check their neighborhood for free locations.
+ *
+ * Quiescent cells will check their neighborhood for free locations.
*/
@Override
public void step(SimState simstate) {
@@ -54,22 +56,31 @@ public void step(SimState simstate) {
}
super.step(simstate);
}
-
+
@Override
- public PatchCell make(int newID, CellState newState, Location newLocation,
- MersenneTwisterFast random) {
+ public PatchCellContainer make(int newID, CellState newState, MersenneTwisterFast random) {
divisions--;
- return new PatchCellTissue(newID, id, pop, newState, age, divisions, newLocation,
- parameters, volume, height, criticalVolume, criticalHeight);
+ int newPop = links == null ? pop : links.next(random);
+ return new PatchCellContainer(
+ newID,
+ id,
+ newPop,
+ age,
+ divisions,
+ newState,
+ volume,
+ height,
+ criticalVolume,
+ criticalHeight);
}
-
+
/**
* Checks neighborhood for free locations.
- *
- * If there is at least one free location, cell state becomes undefined.
*
- * @param simstate the MASON simulation state
- * @param cell the reference cell
+ * If there is at least one free location, cell state becomes undefined.
+ *
+ * @param simstate the MASON simulation state
+ * @param cell the reference cell
*/
private static void checkNeighborhood(SimState simstate, PatchCell cell) {
Simulation sim = (Simulation) simstate;
diff --git a/src/arcade/patch/agent/cell/PatchCellCancerStem.java b/src/arcade/patch/agent/cell/PatchCellCancerStem.java
index 886ff118d..694c8abd6 100644
--- a/src/arcade/patch/agent/cell/PatchCellCancerStem.java
+++ b/src/arcade/patch/agent/cell/PatchCellCancerStem.java
@@ -3,71 +3,68 @@
import ec.util.MersenneTwisterFast;
import arcade.core.agent.cell.CellState;
import arcade.core.env.location.Location;
-import arcade.core.util.MiniBox;
+import arcade.core.util.GrabBag;
+import arcade.core.util.Parameters;
/**
* Extension of {@link PatchCellCancer} for cancerous stem cells.
- *
- * {@code PatchCellCancerStem} agents are modified from their superclass:
+ *
+ * {@code PatchCellCancerStem} agents are modified from their superclass:
+ *
*
- * Loaded parameters include:
- *
- * Cells have a certain probability of producing another cancer stem cell.
+ *
+ * Cells have a certain probability of producing another cancer stem cell.
*/
@Override
- public PatchCell make(int newID, CellState newState, Location newLocation,
- MersenneTwisterFast random) {
- return random.nextDouble() < symmetricFraction
- ? new PatchCellCancerStem(newID, id, pop, newState, age, divisions, newLocation,
- parameters, volume, height, criticalVolume, criticalHeight)
- : new PatchCellCancer(newID, id, pop, newState, age, divisions - 1, newLocation,
- parameters, volume, height, criticalVolume, criticalHeight);
+ public PatchCellContainer make(int newID, CellState newState, MersenneTwisterFast random) {
+ int newPop = links == null ? pop : links.next(random);
+ int newDivisions = newPop == pop ? divisions : divisions - 1;
+ return new PatchCellContainer(
+ newID,
+ id,
+ newPop,
+ age,
+ newDivisions,
+ newState,
+ volume,
+ height,
+ criticalVolume,
+ criticalHeight);
}
}
diff --git a/src/arcade/patch/agent/cell/PatchCellContainer.java b/src/arcade/patch/agent/cell/PatchCellContainer.java
index e88854b75..960d5df6c 100644
--- a/src/arcade/patch/agent/cell/PatchCellContainer.java
+++ b/src/arcade/patch/agent/cell/PatchCellContainer.java
@@ -1,67 +1,77 @@
package arcade.patch.agent.cell;
+import ec.util.MersenneTwisterFast;
import arcade.core.agent.cell.Cell;
import arcade.core.agent.cell.CellContainer;
import arcade.core.agent.cell.CellFactory;
import arcade.core.agent.cell.CellState;
import arcade.core.env.location.Location;
+import arcade.core.util.GrabBag;
import arcade.core.util.MiniBox;
+import arcade.core.util.Parameters;
/**
* Implementation of {@link CellContainer} for {@link PatchCell} agents.
- *
- * Cell parameters are drawn from the associated {@link PatchCellFactory}
- * instance for the given population.
+ *
+ * Cell parameters are drawn from the associated {@link PatchCellFactory} instance for the given
+ * population.
*/
-
public final class PatchCellContainer implements CellContainer {
/** Unique cell container ID. */
public final int id;
-
+
/** Cell parent ID. */
public final int parent;
-
+
/** Cell population index. */
public final int pop;
-
+
/** Cell age [min]. */
public final int age;
-
+
/** Number of divisions. */
public final int divisions;
-
+
/** Cell state. */
public final CellState state;
-
+
/** Cell volume [um3]. */
public final double volume;
-
+
/** Cell height [um]. */
public final double height;
-
+
/** Critical cell volume [um3]. */
public final double criticalVolume;
-
+
/** Critical cell height [um]. */
public final double criticalHeight;
-
+
/**
* Creates a {@code PatchCellContainer} instance.
*
- * @param id the cell ID
- * @param parent the parent ID
- * @param pop the cell population index
- * @param age the cell age
- * @param divisions the number of cell divisions
- * @param state the cell state
- * @param volume the cell volume
- * @param height the cell height
- * @param criticalVolume the critical volume
- * @param criticalHeight the critical height
+ * @param id the cell ID
+ * @param parent the parent ID
+ * @param pop the cell population index
+ * @param age the cell age
+ * @param divisions the number of cell divisions
+ * @param state the cell state
+ * @param volume the cell volume
+ * @param height the cell height
+ * @param criticalVolume the critical volume
+ * @param criticalHeight the critical height
*/
- public PatchCellContainer(int id, int parent, int pop, int age, int divisions,
- CellState state, double volume, double height,
- double criticalVolume, double criticalHeight) {
+ public PatchCellContainer(
+ int id,
+ int parent,
+ int pop,
+ int age,
+ int divisions,
+ CellState state,
+ double volume,
+ double height,
+ double criticalVolume,
+ double criticalHeight) {
this.id = id;
this.parent = parent;
this.pop = pop;
@@ -73,38 +83,40 @@ public PatchCellContainer(int id, int parent, int pop, int age, int divisions,
this.criticalVolume = criticalVolume;
this.criticalHeight = criticalHeight;
}
-
+
@Override
- public int getID() { return id; }
-
+ public int getID() {
+ return id;
+ }
+
@Override
- public Cell convert(CellFactory factory, Location location) {
- return convert((PatchCellFactory) factory, location);
+ public Cell convert(CellFactory factory, Location location, MersenneTwisterFast random) {
+ return convert(factory, location, random, null);
}
-
- /**
- * Converts the cell container into a {@link PatchCell}.
- *
- * @param factory the cell factory instance
- * @param location the cell location
- * @return a {@link PatchCell} instance
- */
- private Cell convert(PatchCellFactory factory, Location location) {
- // Get parameters for the cell population.
- MiniBox parameters = factory.popToParameters.get(pop);
-
+
+ @Override
+ public Cell convert(
+ CellFactory factory,
+ Location location,
+ MersenneTwisterFast random,
+ Parameters cellParameters) {
+ MiniBox popParameters = factory.getParameters(pop);
+ Parameters parameters = new Parameters(popParameters, cellParameters, random);
+
+ // Get links for the cell population.
+ GrabBag links = factory.getLinks(pop);
+
// Make cell.
- switch (parameters.get("CLASS")) {
+ switch (popParameters.get("CLASS")) {
default:
case "tissue":
- return new PatchCellTissue(id, parent, pop, state, age, divisions, location,
- parameters, volume, height, criticalVolume, criticalHeight);
+ return new PatchCellTissue(this, location, parameters, links);
case "cancer":
- return new PatchCellCancer(id, parent, pop, state, age, divisions, location,
- parameters, volume, height, criticalVolume, criticalHeight);
+ return new PatchCellCancer(this, location, parameters, links);
case "cancer_stem":
- return new PatchCellCancerStem(id, parent, pop, state, age, divisions, location,
- parameters, volume, height, criticalVolume, criticalHeight);
+ return new PatchCellCancerStem(this, location, parameters, links);
+ case "random":
+ return new PatchCellRandom(this, location, parameters, links);
}
}
}
diff --git a/src/arcade/patch/agent/cell/PatchCellFactory.java b/src/arcade/patch/agent/cell/PatchCellFactory.java
index d7ce2a9b0..8ce80fbbf 100644
--- a/src/arcade/patch/agent/cell/PatchCellFactory.java
+++ b/src/arcade/patch/agent/cell/PatchCellFactory.java
@@ -5,78 +5,56 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
-import sim.util.distribution.Normal;
-import sim.util.distribution.Uniform;
+import java.util.logging.Logger;
import ec.util.MersenneTwisterFast;
import arcade.core.agent.cell.*;
import arcade.core.sim.Series;
+import arcade.core.util.GrabBag;
import arcade.core.util.MiniBox;
+import arcade.core.util.Parameters;
+import arcade.patch.sim.PatchSeries;
import static arcade.core.util.MiniBox.TAG_SEPARATOR;
import static arcade.patch.util.PatchEnums.Domain;
import static arcade.patch.util.PatchEnums.State;
/**
* Implementation of {@link CellFactory} for {@link PatchCell} agents.
- *
- * For a given {@link Series}, the factory parses out parameter values into a
- * series of maps from population to the parameter values. These maps are then
- * combined with a {@link PatchCellContainer} to instantiate a {@link PatchCell}
- * agent.
- *
- * Cell volumes ({@code CELL_VOLUME_MEAN}, {@code CELL_VOLUME_STDEV}) and cell
- * heights ({@code CELL_HEIGHT_MEAN}, {@code CELL_HEIGHT_STDEV}) are drawn from
- * normal distributions. Cell ages ({@code CELL_AGE_MIN}, {@code CELL_AGE_MAX})
- * are drawn from a uniform distribution. Cell division potential is initialized
- * to {@code DIVISION_POTENTIAL}. Cell compression tolerance
- * ({@code COMPRESSION_TOLERANCE}) is added to the cell critical height.
+ *
+ * For a given {@link Series}, the factory parses out parameter values into a series of maps from
+ * population to the parameter values. These maps are then combined with a {@link
+ * PatchCellContainer} to instantiate a {@link PatchCell} agent.
*/
-
public final class PatchCellFactory implements CellFactory {
+ /** Logger for {@code PatchCellFactory}. */
+ private static final Logger LOGGER = Logger.getLogger(PatchCellFactory.class.getName());
+
/** Random number generator instance. */
MersenneTwisterFast random;
-
- /** Map of population to critical volumes [um3]. */
- HashMap
- * Population sizes are determined from the given series. The list of loaded
- * containers is filtered by population code and population size so that
- * extra containers are discarded.
+ *
+ * Population sizes are determined from the given series. The list of loaded containers is
+ * filtered by population code and population size so that extra containers are discarded.
*/
@Override
public void loadCells(Series series) {
// Load cells.
ArrayList
- * For each population specified in the given series, containers are created
- * until the population size is met.
+ *
+ * For each population specified in the given series, containers are created until the
+ * population size is met.
*/
@Override
public void createCells(Series series) {
int id = 1;
-
+
// Create containers for each population.
for (MiniBox population : series.populations.values()) {
- int n = population.getInt("INIT");
+ int init = 0;
+
+ if (population.contains("PERCENT")) {
+ int totalPatches = ((PatchSeries) series).patch.getInt("TOTAL_PATCHES");
+ int percent = population.getInt("PERCENT");
+ init = Math.min((int) Math.round(percent * totalPatches / 100.0), totalPatches);
+ } else if (population.contains("COUNT")) {
+ init = population.getInt("COUNT");
+ } else {
+ LOGGER.severe("Population must contain PERCENT or COUNT initialization key");
+ System.exit(-1);
+ }
+
int pop = population.getInt("CODE");
-
- for (int i = 0; i < n; i++) {
+
+ for (int i = 0; i < init; i++) {
PatchCellContainer container = createCellForPopulation(id, pop);
- cells.put(container.id, container);
- popToIDs.get(pop).add(container.id);
+ cells.put(id, container);
+ popToIDs.get(pop).add(id);
id++;
}
}
}
-
+
/**
* Create a {@link CellContainer} for a cell in given population.
*
- * @param id the cell container id
- * @param pop the cell population
- * @return the cell container
+ * @param id the cell container id
+ * @param pop the cell population
+ * @return the cell container
*/
public PatchCellContainer createCellForPopulation(int id, int pop) {
- Normal volumes = popToCriticalVolumes.get(pop);
- Normal heights = popToCriticalHeights.get(pop);
- Uniform ages = popToAges.get(pop);
-
- int divisions = popToDivisions.get(pop);
- double compression = popToCompression.get(pop);
-
- double volume = volumes.nextDouble();
- double height = heights.nextDouble();
- int age = ages.nextInt();
-
- return new PatchCellContainer(id, 0, pop, age, divisions, State.UNDEFINED,
- volume, height, volume, height + compression);
+ MiniBox population = popToParameters.get(pop);
+ Parameters parameters = new Parameters(population, null, random);
+
+ int divisions = parameters.getInt("DIVISION_POTENTIAL");
+ double compression = parameters.getDouble("COMPRESSION_TOLERANCE");
+
+ double volume = parameters.getDouble("CELL_VOLUME");
+ double height = parameters.getDouble("CELL_HEIGHT");
+ int age = parameters.getInt("CELL_AGE");
+
+ return new PatchCellContainer(
+ id,
+ 0,
+ pop,
+ age,
+ divisions,
+ State.UNDEFINED,
+ volume,
+ height,
+ volume,
+ height + compression);
}
-
+
/**
- * Parses the population settings into maps to parameter value.
- *
- * Loaded parameters include:
- * These agents will simulate their metabolism and signaling processes, like {@link
+ * PatchCellTissue}, but cell states are randomly selected from all possible states, rather than
+ * following specific rules that guide
+ */
+public class PatchCellRandom extends PatchCell {
+ /**
+ * Creates a random {@code PatchCell} agent.
+ *
+ * @param container the cell container
+ * @param location the {@link Location} of the cell
+ * @param parameters the dictionary of parameters
+ */
+ public PatchCellRandom(PatchCellContainer container, Location location, Parameters parameters) {
+ this(container, location, parameters, null);
+ }
+
+ /**
+ * Creates a random {@code PatchCell} agent with population links.
+ *
+ * @param container the cell container
+ * @param location the {@link Location} of the cell
+ * @param parameters the dictionary of parameters
+ * @param links the map of population links
+ */
+ public PatchCellRandom(
+ PatchCellContainer container, Location location, Parameters parameters, GrabBag links) {
+ super(container, location, parameters, links);
+ }
+
+ @Override
+ public PatchCellContainer make(int newID, CellState newState, MersenneTwisterFast random) {
+ divisions--;
+ int newPop = links == null ? pop : links.next(random);
+ return new PatchCellContainer(
+ newID,
+ id,
+ newPop,
+ age,
+ divisions,
+ newState,
+ volume,
+ height,
+ criticalVolume,
+ criticalHeight);
+ }
+
+ @Override
+ public void step(SimState simstate) {
+ Simulation sim = (Simulation) simstate;
+
+ // Increase age of cell.
+ age++;
+
+ // Randomly select a cell state.
+ if (state == State.UNDEFINED) {
+ setState(State.random(simstate.random));
+ }
+
+ // Step metabolism process.
+ processes.get(Domain.METABOLISM).step(simstate.random, sim);
+
+ // Step signaling network process.
+ processes.get(Domain.SIGNALING).step(simstate.random, sim);
+
+ // Step the module for the cell state.
+ if (module != null) {
+ module.step(simstate.random, sim);
+ }
+ }
+}
diff --git a/src/arcade/patch/agent/cell/PatchCellTissue.java b/src/arcade/patch/agent/cell/PatchCellTissue.java
index 5caaae3eb..761647f62 100644
--- a/src/arcade/patch/agent/cell/PatchCellTissue.java
+++ b/src/arcade/patch/agent/cell/PatchCellTissue.java
@@ -3,41 +3,49 @@
import ec.util.MersenneTwisterFast;
import arcade.core.agent.cell.CellState;
import arcade.core.env.location.Location;
-import arcade.core.util.MiniBox;
-
-/**
- * Extension of {@link PatchCell} for healthy tissue cells.
- */
+import arcade.core.util.GrabBag;
+import arcade.core.util.Parameters;
+/** Extension of {@link PatchCell} for healthy tissue cells. */
public class PatchCellTissue extends PatchCell {
/**
* Creates a tissue {@code PatchCell} agent.
*
- * @param id the cell ID
- * @param parent the parent ID
- * @param pop the cell population index
- * @param state the cell state
- * @param age the cell age
- * @param divisions the number of cell divisions
- * @param location the {@link Location} of the cell
- * @param parameters the dictionary of parameters
- * @param volume the cell volume
- * @param height the cell height
- * @param criticalVolume the critical cell volume
- * @param criticalHeight the critical cell height
+ * @param container the cell container
+ * @param location the {@link Location} of the cell
+ * @param parameters the dictionary of parameters
*/
- public PatchCellTissue(int id, int parent, int pop, CellState state, int age, int divisions,
- Location location, MiniBox parameters, double volume, double height,
- double criticalVolume, double criticalHeight) {
- super(id, parent, pop, state, age, divisions, location, parameters,
- volume, height, criticalVolume, criticalHeight);
+ public PatchCellTissue(PatchCellContainer container, Location location, Parameters parameters) {
+ this(container, location, parameters, null);
}
-
+
+ /**
+ * Creates a tissue {@code PatchCell} agent with population links.
+ *
+ * @param container the cell container
+ * @param location the {@link Location} of the cell
+ * @param parameters the dictionary of parameters
+ * @param links the map of population links
+ */
+ public PatchCellTissue(
+ PatchCellContainer container, Location location, Parameters parameters, GrabBag links) {
+ super(container, location, parameters, links);
+ }
+
@Override
- public PatchCell make(int newID, CellState newState, Location newLocation,
- MersenneTwisterFast random) {
+ public PatchCellContainer make(int newID, CellState newState, MersenneTwisterFast random) {
divisions--;
- return new PatchCellTissue(newID, id, pop, newState, age, divisions, newLocation,
- parameters, volume, height, criticalVolume, criticalHeight);
+ int newPop = links == null ? pop : links.next(random);
+ return new PatchCellContainer(
+ newID,
+ id,
+ newPop,
+ age,
+ divisions,
+ newState,
+ volume,
+ height,
+ criticalVolume,
+ criticalHeight);
}
}
diff --git a/src/arcade/patch/agent/module/PatchModule.java b/src/arcade/patch/agent/module/PatchModule.java
index 854969fca..5469d216c 100644
--- a/src/arcade/patch/agent/module/PatchModule.java
+++ b/src/arcade/patch/agent/module/PatchModule.java
@@ -6,44 +6,47 @@
/**
* Abstract implementation of {@link Module} for {@link PatchCell} agents.
- *
- * Each module represents the behaviors of a cell in a given state.
+ *
+ * Each module represents the behaviors of a cell in a given state.
*/
-
public abstract class PatchModule implements Module {
/** The {@link PatchCell} the module is associated with. */
final PatchCell cell;
-
+
/** The {@link PatchLocation} the module is associated with. */
final PatchLocation location;
-
+
/** Tick the {@code Module} was started. */
double start;
-
+
/** Tick the {@code Module} was stopped. */
double stop;
-
+
/**
* Creates a module for a {@link PatchCell} state.
*
- * @param cell the {@link PatchCell} the module is associated with
+ * @param cell the {@link PatchCell} the module is associated with
*/
public PatchModule(PatchCell cell) {
this.cell = cell;
this.location = (PatchLocation) cell.getLocation();
}
-
+
/**
* Gets the module start tick.
*
- * @return the module start
+ * @return the module start
*/
- public double getStart() { return start; }
-
+ public double getStart() {
+ return start;
+ }
+
/**
* Gets the module start tick.
*
- * @return the module start
+ * @return the module start
*/
- public double getStop() { return stop; }
+ public double getStop() {
+ return stop;
+ }
}
diff --git a/src/arcade/patch/agent/module/PatchModuleApoptosis.java b/src/arcade/patch/agent/module/PatchModuleApoptosis.java
index 4df1c4da2..8f4e60843 100644
--- a/src/arcade/patch/agent/module/PatchModuleApoptosis.java
+++ b/src/arcade/patch/agent/module/PatchModuleApoptosis.java
@@ -4,45 +4,44 @@
import ec.util.MersenneTwisterFast;
import arcade.core.agent.cell.Cell;
import arcade.core.sim.Simulation;
-import arcade.core.util.MiniBox;
+import arcade.core.util.Parameters;
import arcade.patch.agent.cell.PatchCell;
import arcade.patch.env.grid.PatchGrid;
import static arcade.patch.util.PatchEnums.State;
/**
* Extension of {@link PatchModule} for apoptosis.
- *
- * During apoptosis, the module is stepped once after the number of ticks
- * corresponding to the duration of apoptosis ({@code DEATH_DURATION}) has
- * passed. The module will remove the cell from the simulation and induce one of
- * the quiescent neighboring cells to proliferate.
+ *
+ * During apoptosis, the module is stepped once after the number of ticks corresponding to the
+ * duration of apoptosis ({@code DEATH_DURATION}) has passed. The module will remove the cell from
+ * the simulation and induce one of the quiescent neighboring cells to proliferate.
*/
-
public class PatchModuleApoptosis extends PatchModule {
/** Tracker for duration of cell death. */
private int ticker;
-
+
/** Time required for cell death [min]. */
private final double deathDuration;
-
+
/**
* Creates an apoptosis {@link PatchModule} for the given cell.
- *
- * Loaded parameters include:
+ *
+ * Loaded parameters include:
+ *
*
- * During migration, the module is stepped once after the number of ticks
- * corresponding to (distance to move) / {@code MIGRATION_RATE} has passed. The
- * module will move the cell from one location to the best valid location in the
- * neighborhood.
+ *
+ * During migration, the module is stepped once after the number of ticks corresponding to
+ * (distance to move) / {@code MIGRATION_RATE} has passed. The module will move the cell from one
+ * location to the best valid location in the neighborhood.
*/
-
public class PatchModuleMigration extends PatchModule {
/** Tracker for duration of cell movement. */
private int ticker;
-
+
/** Cell migration rate [um/min]. */
private final double migrationRate;
-
+
/** Time required for cell migration [min]. */
private final double movementDuration;
-
+
/**
* Creates a migration {@link PatchModule} for the given cell.
- *
- * Loaded parameters include:
+ *
+ * Loaded parameters include:
+ *
*
- * During proliferation, the module is repeatedly stepped from its creation
- * until either the cell is no longer able to proliferate or it has successfully
- * doubled in size and is able to create a new cell object. The module will wait
- * for at least {@code SYNTHESIS_DURATION} ticks to pass before creating a new
- * cell.
+ *
+ * During proliferation, the module is repeatedly stepped from its creation until either the cell
+ * is no longer able to proliferate or it has successfully doubled in size and is able to create a
+ * new cell object. The module will wait for at least {@code SYNTHESIS_DURATION} ticks to pass
+ * before creating a new cell.
*/
-
public class PatchModuleProliferation extends PatchModule {
/** Tracker for duration of cell cycle. */
private int ticker;
-
+
/** Target volume for division. */
private final double targetVolume;
-
+
/** Maximum tolerable height for cell. */
private final double maxHeight;
-
+
/** Time required for DNA synthesis [min]. */
private final double synthesisDuration;
-
+
/**
* Creates a proliferation {@link PatchModule} for the given cell.
- *
- * Loaded parameters include:
+ *
+ * Loaded parameters include:
+ *
*
- * Each process represents internal cell mechanisms.
+ *
+ * Each process represents internal cell mechanisms.
*/
-
public abstract class PatchProcess implements Process {
/** The {@link PatchCell} the process is associated with. */
final PatchCell cell;
-
+
/** The {@link PatchLocation} the process is associated with. */
final PatchLocation location;
-
+
/**
* Creates a module for a {@link PatchCell} state.
*
- * @param cell the {@link PatchCell} the process is associated with
+ * @param cell the {@link PatchCell} the process is associated with
*/
public PatchProcess(PatchCell cell) {
this.cell = cell;
this.location = (PatchLocation) cell.getLocation();
}
-
+
/**
* Update the process with values from the given process.
*
- * @param process the reference process.
+ * @param process the reference process.
*/
public abstract void update(Process process);
}
diff --git a/src/arcade/patch/agent/process/PatchProcessMetabolism.java b/src/arcade/patch/agent/process/PatchProcessMetabolism.java
index 1776febed..2dfd87e67 100644
--- a/src/arcade/patch/agent/process/PatchProcessMetabolism.java
+++ b/src/arcade/patch/agent/process/PatchProcessMetabolism.java
@@ -4,206 +4,208 @@
import sim.util.Bag;
import ec.util.MersenneTwisterFast;
import arcade.core.sim.Simulation;
-import arcade.core.util.MiniBox;
+import arcade.core.util.Parameters;
import arcade.patch.agent.cell.PatchCell;
import arcade.patch.env.grid.PatchGrid;
import static arcade.patch.util.PatchEnums.State;
/**
* Implementation of {@link Process} for cell metabolism.
- *
- * The {@code PatchProcessMetabolism} process:
+ *
+ * The {@code PatchProcessMetabolism} process:
+ *
*
- * All metabolism complexities use both the glycolysis and oxidative
- * phosphorylation pathways to generate energy.
- * Several stoichiometric ratios for glucose, oxygen, and pyruvate in glycolysis
- * and oxidative phosphorylation are provided.
- * Glucose and oxygen are numbered constants, codes may be added for additional
- * molecules.
+ *
+ * All metabolism complexities use both the glycolysis and oxidative phosphorylation pathways to
+ * generate energy. Several stoichiometric ratios for glucose, oxygen, and pyruvate in glycolysis
+ * and oxidative phosphorylation are provided. Glucose and oxygen are numbered constants, codes may
+ * be added for additional molecules.
*/
-
public abstract class PatchProcessMetabolism extends PatchProcess {
/** ID for glucose. */
static final int GLUCOSE = 0;
-
+
/** ID for oxygen. */
static final int OXYGEN = 1;
-
- /** Energy from glycolysis [mol ATP/mol glucose]. */
+
+ /** Energy from glycolysis [mol ATP/mol glucose]. */
static final int ENERGY_FROM_GLYC = 2;
-
+
/** Energy from oxidative phosphorylation [mol ATP/mol pyruvate]. */
static final int ENERGY_FROM_OXPHOS = 15;
-
+
/** Stoichiometric ratio for oxygen:pyruvate [mol oxygen/mol pyruvate]. */
static final int OXY_PER_PYRU = 3;
-
+
/** Stoichiometric ratio for pyruvate:glucose [mol pyruvate/mol glucose]. */
static final int PYRU_PER_GLUC = 2;
-
+
/** Basal energy requirement [fmol ATP/um3 cell/min]. */
private final double basalEnergy;
-
+
/** Additional energy required for proliferation [fmol ATP/um3 cell/min]. */
private final double proliferationEnergy;
-
+
/** Additional energy required for migration [fmol ATP/um3 cell/min]. */
private final double migrationEnergy;
-
+
/** Oxygen solubility in tissue [fmol O2/um3/mmHg]. */
private final double oxygenSolubilityTissue;
-
+
/** Cell density [ng/um3]. */
final double cellDensity;
-
+
/** Ratio of glucose to biomass [fmol glucose/ng biomass]. */
final double ratioGlucoseBiomass;
-
+
/** List of internal names. */
List
- * Process parameters are specific for the cell population. Loaded
- * parameters include:
+ *
+ * Process parameters are specific for the cell population. Loaded parameters include:
+ *
*
- * The process starts with energy at zero and assumes a constant ratio
- * between mass and volume (through density).
*
- * @param cell the {@link PatchCell} the process is associated with
+ * The process starts with energy at zero and assumes a constant ratio between mass and
+ * volume (through density).
+ *
+ * @param cell the {@link PatchCell} the process is associated with
*/
PatchProcessMetabolism(PatchCell cell) {
super(cell);
-
+
// Set parameters.
- MiniBox parameters = cell.getParameters();
+ Parameters parameters = cell.getParameters();
basalEnergy = parameters.getDouble("metabolism/BASAL_ENERGY");
proliferationEnergy = parameters.getDouble("metabolism/PROLIFERATION_ENERGY");
migrationEnergy = parameters.getDouble("metabolism/MIGRATION_ENERGY");
cellDensity = parameters.getDouble("metabolism/CELL_DENSITY");
ratioGlucoseBiomass = parameters.getDouble("metabolism/RATIO_GLUCOSE_BIOMASS");
oxygenSolubilityTissue = parameters.getDouble("metabolism/OXYGEN_SOLUBILITY_TISSUE");
-
+
// Initialize process.
volume = cell.getVolume();
energy = 0;
mass = cell.getVolume() * cellDensity;
critMass = cell.getCriticalVolume() * cellDensity;
-
+
// Initialize external and uptake concentration arrays;
extAmts = new double[2];
upAmts = new double[2];
}
-
+
/**
* Steps the metabolism process.
*
- * @param random the random number generator
- * @param sim the simulation instance
+ * @param random the random number generator
+ * @param sim the simulation instance
*/
abstract void stepProcess(MersenneTwisterFast random, Simulation sim);
-
+
/**
* Gets the external amounts of glucose and oxygen in fmol.
*
- * @param sim the simulation instance
+ * @param sim the simulation instance
*/
private void updateExternal(Simulation sim) {
- extAmts[GLUCOSE] = sim.getLattice("GLUCOSE").getAverageValue(location)
- * location.getVolume();
- extAmts[OXYGEN] = sim.getLattice("OXYGEN").getAverageValue(location)
- * location.getVolume() * oxygenSolubilityTissue;
+ extAmts[GLUCOSE] =
+ sim.getLattice("GLUCOSE").getAverageValue(location) * location.getVolume();
+ extAmts[OXYGEN] =
+ sim.getLattice("OXYGEN").getAverageValue(location)
+ * location.getVolume()
+ * oxygenSolubilityTissue;
}
-
+
@Override
public void step(MersenneTwisterFast random, Simulation sim) {
// Calculate fraction of volume occupied by cell.
Bag bag = ((PatchGrid) sim.getGrid()).getObjectsAtLocation(location);
double totalVolume = PatchCell.calculateTotalVolume(bag);
f = volume / totalVolume;
-
+
updateExternal(sim);
-
+
// Check cell state.
isProliferative = cell.getState() == State.PROLIFERATIVE;
isMigratory = cell.getState() == State.MIGRATORY;
-
+
// Calculate energy consumption.
- energyCons = volume * (basalEnergy
- + (isProliferative ? proliferationEnergy : 0)
- + (isMigratory ? migrationEnergy : 0));
+ energyCons =
+ volume
+ * (basalEnergy
+ + (isProliferative ? proliferationEnergy : 0)
+ + (isMigratory ? migrationEnergy : 0));
energyReq = energyCons - energy;
-
+
// Modify energy and volume.
stepProcess(random, sim);
-
+
// Update environment.
sim.getLattice("GLUCOSE").updateValue(location, 1.0 - upAmts[GLUCOSE] / extAmts[GLUCOSE]);
sim.getLattice("OXYGEN").updateValue(location, 1.0 - upAmts[OXYGEN] / extAmts[OXYGEN]);
-
+
// Update cell agent.
cell.setVolume(volume);
cell.setEnergy(energy);
}
-
+
/**
* Creates a {@code PatchProcessMetabolism} for given version.
*
- * @param cell the {@link PatchCell} the process is associated with
- * @param version the process version
- * @return the process instance
+ * @param cell the {@link PatchCell} the process is associated with
+ * @param version the process version
+ * @return the process instance
*/
public static PatchProcess make(PatchCell cell, String version) {
switch (version.toUpperCase()) {
diff --git a/src/arcade/patch/agent/process/PatchProcessMetabolismComplex.java b/src/arcade/patch/agent/process/PatchProcessMetabolismComplex.java
index f6ebb29e2..c4119bfc8 100644
--- a/src/arcade/patch/agent/process/PatchProcessMetabolismComplex.java
+++ b/src/arcade/patch/agent/process/PatchProcessMetabolismComplex.java
@@ -4,101 +4,96 @@
import ec.util.MersenneTwisterFast;
import arcade.core.agent.process.Process;
import arcade.core.sim.Simulation;
-import arcade.core.util.MiniBox;
+import arcade.core.util.Parameters;
import arcade.patch.agent.cell.PatchCell;
/**
* Extension of {@link PatchProcessMetabolism} for complex metabolism.
- *
- * {@code PatchProcessMetabolismComplex} explicitly includes pyruvate
- * intermediate between glycolysis and oxidative phosphorylation and glucose
- * uptake is based on cell surface area. Metabolic preference between glycolysis
- * and oxidative phosphorylation is controlled by {@code METABOLIC_PREFERENCE}.
- * The glycolysis pathway will compensate if there is not enough oxygen to meet
- * energetic requirements through the oxidative phosphorylation pathway given
- * the specified metabolic preference.
- *
- * {@code PatchProcessMetabolismComplex} will increase cell mass (using
- * specified fractions of internal glucose and pyruvate) if:
+ *
+ * {@code PatchProcessMetabolismComplex} explicitly includes pyruvate intermediate between
+ * glycolysis and oxidative phosphorylation and glucose uptake is based on cell surface area.
+ * Metabolic preference between glycolysis and oxidative phosphorylation is controlled by {@code
+ * METABOLIC_PREFERENCE}. The glycolysis pathway will compensate if there is not enough oxygen to
+ * meet energetic requirements through the oxidative phosphorylation pathway given the specified
+ * metabolic preference.
+ *
+ * {@code PatchProcessMetabolismComplex} will increase cell mass (using specified fractions of
+ * internal glucose and pyruvate) if:
+ *
*
- * {@code PatchProcessMetabolismComplex} will decrease cell mass if:
+ *
+ * {@code PatchProcessMetabolismComplex} will decrease cell mass if:
+ *
*
- * Internal pyruvate is removed through conversion to lactate.
+ *
+ * Internal pyruvate is removed through conversion to lactate.
*/
-
public class PatchProcessMetabolismComplex extends PatchProcessMetabolism {
/** ID for pyruvate. */
private static final int PYRUVATE = 1;
-
+
/** Preference for glycolysis over oxidative phosphorylation. */
private final double metabolicPreference;
-
+
/** Fraction of internal glucose/pyruvate converted to mass. */
private final double conversionFraction;
-
+
/** Minimum viable cell mass fraction. */
private final double minimumMassFraction;
-
+
/** Preference for glucose over pyruvate for mass. */
private final double ratioGlucosePyruvate;
-
+
/** Rate of lactate production [fmol lactate/fmol pyruvate]. */
private final double lactateRate;
-
+
/** Rate of autophagy [ng/min]. */
private final double autophagyRate;
-
+
/** Rate of glucose uptake [fmol glucose/um2 cell/min/M glucose]. */
private final double glucoseUptakeRate;
-
+
/**
- * Creates a complex metabolism {@code Process} for the given
- * {@link PatchCell}.
- *
- * Module has internal glucose and pyruvate.
- *
- * Loaded parameters include:
+ * Creates a complex metabolism {@code Process} for the given {@link PatchCell}.
+ *
+ * Module has internal glucose and pyruvate.
+ *
+ * Loaded parameters include:
+ *
*
- * {@code PatchProcessMetabolismMedium} does not use a pyruvate intermediate and
- * glucose uptake is based on cell volume. Metabolic preference between
- * glycolysis * and oxidative phosphorylation is controlled by
- * {@code METABOLIC_PREFERENCE}. The glycolysis pathway will compensate if there
- * is not enough oxygen to meet energetic requirements through the oxidative
- * phosphorylation pathway given the specified metabolic preference.
- *
- * {@code PatchProcessMetabolismMedium} will increase cell mass (using specified
- * fraction of internal glucose) if:
+ *
+ * {@code PatchProcessMetabolismMedium} does not use a pyruvate intermediate and glucose uptake
+ * is based on cell volume. Metabolic preference between glycolysis * and oxidative phosphorylation
+ * is controlled by {@code METABOLIC_PREFERENCE}. The glycolysis pathway will compensate if there is
+ * not enough oxygen to meet energetic requirements through the oxidative phosphorylation pathway
+ * given the specified metabolic preference.
+ *
+ * {@code PatchProcessMetabolismMedium} will increase cell mass (using specified fraction of
+ * internal glucose) if:
+ *
*
- * {@code PatchProcessMetabolismMedium} will decrease cell mass if:
+ *
+ * {@code PatchProcessMetabolismMedium} will decrease cell mass if:
+ *
*
- * Module only has internal glucose.
- *
- * Loaded parameters include:
+ * Creates a medium metabolism {@code Process} for the given {@link PatchCell}.
+ *
+ * Module only has internal glucose.
+ *
+ * Loaded parameters include:
+ *
*
- * {@code PatchProcessMetabolismRandom} will uptake a random fraction of glucose
- * and oxygen from the environment. Oxygen is converted to ATP through oxidative
- * phosphorylation and some random fraction of glucose is converted to ATP
- * through glycolysis.
- *
- * {@code PatchProcessMetabolismRandom} will increase cell mass (using random
- * fraction of internal glucose) if cell is dividing and less than double in
- * size.
+ *
+ * {@code PatchProcessMetabolismRandom} will uptake a random fraction of glucose and oxygen from
+ * the environment. Oxygen is converted to ATP through oxidative phosphorylation and some random
+ * fraction of glucose is converted to ATP through glycolysis.
+ *
+ * {@code PatchProcessMetabolismRandom} will increase cell mass (using random fraction of
+ * internal glucose) if cell is dividing and less than double in size.
*/
-
public class PatchProcessMetabolismRandom extends PatchProcessMetabolism {
/** Minimum glucose uptake. */
private static final double GLUC_UPTAKE_MIN = 0.005;
-
+
/** Maximum glucose uptake. */
private static final double GLUC_UPTAKE_MAX = 0.015;
-
+
/** Minimum oxygen uptake. */
private static final double OXY_UPTAKE_MIN = 0.2;
-
+
/** Maximum oxygen update. */
private static final double OXY_UPTAKE_MAX = 0.5;
-
+
/** Minimum fraction of glucose used for glycolysis. */
private static final double GLUC_FRAC_MIN = 0.2;
-
+
/** Maximum fraction of glucose used for glycolysis. */
private static final double GLUC_FRAC_MAX = 0.4;
-
+
/** Range of glucose uptake. */
private static final double GLUC_UPTAKE_DELTA = GLUC_UPTAKE_MAX - GLUC_UPTAKE_MIN;
-
+
/** Range of oxygen uptake. */
private static final double OXY_UPTAKE_DELTA = OXY_UPTAKE_MAX - OXY_UPTAKE_MIN;
-
+
/** Range of glucose fraction. */
private static final double GLUC_FRAC_DELTA = GLUC_FRAC_MAX - GLUC_FRAC_MIN;
-
+
/** Average cell volume [um3]. */
private final double averageCellVolume;
-
+
/**
- * Creates a random metabolism {@code Process} for the given
- * {@link PatchCell}.
- *
- * Module only has internal glucose.
- *
- * Loaded parameters include:
+ * Creates a random metabolism {@code Process} for the given {@link PatchCell}.
+ *
+ * Module only has internal glucose.
+ *
+ * Loaded parameters include:
+ *
*
- * {@code PatchProcessMetabolismSimple} assumes a constant glucose uptake rate
- * and constant ATP production rate. Ratio of ATP production that needs to be
- * produced through glycolysis or oxidative phosphorylation is controlled by the
- * {@code METABOLIC_PREFERENCE} parameter.
- *
- * {@code PatchProcessMetabolismSimple} will increase cell mass (using specified
- * fraction of internal glucose) if cell is dividing and less than double in
- * size.
+ *
+ * {@code PatchProcessMetabolismSimple} assumes a constant glucose uptake rate and constant ATP
+ * production rate. Ratio of ATP production that needs to be produced through glycolysis or
+ * oxidative phosphorylation is controlled by the {@code METABOLIC_PREFERENCE} parameter.
+ *
+ * {@code PatchProcessMetabolismSimple} will increase cell mass (using specified fraction of
+ * internal glucose) if cell is dividing and less than double in size.
*/
-
public class PatchProcessMetabolismSimple extends PatchProcessMetabolism {
/** Average cell volume [um3]. */
private final double averageCellVolume;
-
+
/** Preference for glycolysis over oxidative phosphorylation. */
private final double metabolicPreference;
-
+
/** Constant glucose uptake rate [fmol glucose/min/M glucose]. */
private final double glucoseUptakeRate;
-
+
/** Constant ATP production rate [fmol ATP/cell/min]. */
private final double atpProductionRate;
-
+
/** Constant volume growth rate [um3/min]. */
private final double volumeGrowthRate;
-
+
/**
- * Creates a simple metabolism {@code Process} for the given
- * {@link PatchCell}.
- *
- * Module only has internal glucose.
- *
- * Loaded parameters include:
+ * Creates a simple metabolism {@code Process} for the given {@link PatchCell}.
+ *
+ * Module only has internal glucose.
+ *
+ * Loaded parameters include:
+ *
*
- * The {@code PatchProcessSignaling} process can be used for networks comprising
- * a system of ODEs.
+ *
+ * The {@code PatchProcessSignaling} process can be used for networks comprising a system of
+ * ODEs.
*/
-
public abstract class PatchProcessSignaling extends PatchProcess {
/** Molecules in nM. */
static final double MOLEC_TO_NM = 1355.0;
-
+
/** Molecular weight of TGFa [g/mol]. */
static final double TGFA_MW = 17006.0;
-
+
/** Step size for process [sec]. */
static final double STEP_SIZE = 1.0;
-
+
/** List of internal names. */
List
- * {@code PatchProcessSignalingComplex} represents a 13-component signaling
- * network spanning the nucleus, cytoplasm, and cell membrane. Migratory flag is
- * set based on fold change in active PLCg using {@code MIGRATORY_THRESHOLD}.
- *
- * Network structure and parameters are derived from L. Zhang, C. A. Athale, and
- * T. S. Deisboeck. (2007). Development of a three-dimensional multiscale
- * agent-based tumor model: Simulating gene-protein interaction profiles, cell
- * phenotypes and multicellular patterns in brain cancer. Journal of
- * Theoretical Biology, 244(1), 96-107.
+ *
+ * {@code PatchProcessSignalingComplex} represents a 13-component signaling network spanning the
+ * nucleus, cytoplasm, and cell membrane. Migratory flag is set based on fold change in active PLCg
+ * using {@code MIGRATORY_THRESHOLD}.
+ *
+ * Network structure and parameters are derived from L. Zhang, C. A. Athale, and T. S. Deisboeck.
+ * (2007). Development of a three-dimensional multiscale agent-based tumor model: Simulating
+ * gene-protein interaction profiles, cell phenotypes and multicellular patterns in brain cancer.
+ * Journal of Theoretical Biology, 244(1), 96-107.
*/
-
public class PatchProcessSignalingComplex extends PatchProcessSignaling {
/** Number of components in signaling network. */
private static final int NUM_COMPONENTS = 13;
-
+
/** Initial membrane concentration [nM]. */
private static final double MEMBRANE = 25.0;
-
+
/** Initial cytoplasm concentration [nM]. */
private static final double CYTOPLASM = 5.0;
-
+
/** Constant total PLCg [nM]. */
private static final double PLCG = 1.0;
-
+
/** Nucelotide pool [nM]. */
private static final double NUCLEOTIDES = 5.0;
-
+
/** ID for Glucose, internal. */
private static final int G_INT = 0;
-
+
/** ID for TGFa, extracellular. */
private static final int T_EXT = 1;
-
+
/** ID for EGFR, membrane. */
private static final int E_MEM = 2;
-
+
/** ID for TGFa-EGFR complex, membrane, active. */
private static final int TE_MEM = 3;
-
+
/** ID for TGFa-EGFR complex, membrane, active. */
private static final int TE_MEM_P = 4;
-
+
/** ID for TGFa-EGFR complex, cytoplasmic. */
private static final int TE_CYTO = 5;
-
+
/** ID for EGFR, cytoplasmic. */
private static final int E_CYTO = 6;
-
+
/** ID for TGFa, cytoplasmic. */
private static final int T_CYTO = 7;
-
+
/** ID for EGFR RNA. */
private static final int E_RNA = 8;
-
+
/** ID for TGFa RNA. */
private static final int T_RNA = 9;
-
+
/** ID for PLCg, inactive. */
private static final int P_INACTIVE = 10;
-
+
/** ID for PLCg, active. */
private static final int P_ACTIVE = 11;
-
+
/** ID for nucleotide pool. */
private static final int POOL = 12;
-
+
/** Rate of TGFa-EGFR complex formation [/nM/sec]. */
private static final double K1 = 0.003;
-
+
/** Rate of TGFa-EGFR complex dissociation [/sec]. */
private static final double K_1 = 0.0038;
-
+
/** Rate of TGFa-EGFR phosphorylation [/sec]. */
private static final double K2 = 0.001;
-
+
/** Rate of p-TGFa-EGFR dephosphorylation [/sec]. */
private static final double K_2 = 0.000001;
-
+
/** Rate of membrane TGFa-EGFR internalization [/sec]. */
private static final double K3 = 0.00005;
-
+
/** Rate of membrane p-TGFa-EGFR internalization [/sec]. */
private static final double K4 = 0.00005;
-
+
/** Rate of cytoplasmic TGFa-EGFR dissociation [/sec]. */
private static final double K5 = 0.01;
-
+
/** Rate of cytoplasmic TGFa-EGFR association [/nM/sec]. */
private static final double K_5 = 0.000014;
-
+
/** Rate of cytoplasmic EGFR protein degradation [/sec ]. */
private static final double K6 = 0.000167;
-
+
/** Rate of cytoplasmic TGFa protein degradation [/sec]. */
private static final double K7 = 0.000167;
-
+
/** Rate of cytoplasmic EGFR insertion [/sec]. */
private static final double K8 = 0.005;
-
+
/** Rate of membrane EGFR internalization [/sec]. */
private static final double K_8 = 0.00005;
-
+
/** Rate of TGFa insertion + secretion [/sec]. */
private static final double K9 = 1.0;
-
+
/** Rate of membrane EGFR degradation (estimate) [/sec]. */
private static final double K10 = 0.0001;
-
+
/** Rate of extracellular TGFa degradation (estimate) [/sec]. */
private static final double K11 = 0.01;
-
+
/** Rate of activation of PLCg [/sec]. */
private static final double K12 = 0.1;
-
+
/** Rate of inactivation of PLCg [/sec]. */
private static final double K13 = 0.05;
-
+
/** Rate of translation of EGFR RNA [/sec]. */
private static final double K14 = 5.0 / MOLEC_TO_NM / 60 / NUCLEOTIDES;
-
+
/** Rate of translation of TGFa RNA [/sec]. */
private static final double K15 = 5.0 / MOLEC_TO_NM / 60 / NUCLEOTIDES;
-
+
/** Rate of transcription of EGFR RNA [/sec]. */
private static final double K16 = 2.17 / MOLEC_TO_NM / 60 / NUCLEOTIDES;
-
+
/** Rate of transcription of TGFa RNA [/sec]. */
private static final double K17 = 12.0 / MOLEC_TO_NM / 60 / NUCLEOTIDES;
-
+
/** Rate of EGFR RNA degradation [/sec]. */
private static final double K18 = 0.0012 / MOLEC_TO_NM / 60 / NUCLEOTIDES;
-
+
/** Rate of TGFa RNA degradation [/sec]. */
private static final double K19 = 0.0012 / MOLEC_TO_NM / 60 / NUCLEOTIDES;
-
+
/** Weight of TGFa-EGFR phosphorylation regulation by glucose. */
private static final double WG = 200.0;
-
+
/** Weight of EGFR translation regulation by p-TGFa-EGFR. */
private static final double WE = 2.0;
-
+
/** Weight of TGFa translation regulation by p-TGFa-EGFR. */
private static final double WT = 2.0;
-
+
/** Weight of PLCg activation regulation by p-TGFa-EGFR. */
private static final double WP = 5.0;
-
+
/** Weight of TGFa-EGFR dephosphorylation regulation by active PLCg. */
private static final double WC = 1.0;
-
+
/** Threshold fold change in PLCg for migration. */
private final double migratoryThreshold;
-
+
/** Fold change in PLCg of previous time step. */
private double previous = 1.0;
-
+
/** Fold change in PLCg for current time step. */
private double current = 1.0;
-
+
/** List of internal concentrations. */
private double[] concs;
-
+
/**
- * Creates a complex signaling {@code Process} for the given
- * {@link PatchCell}.
- *
- * Initial concentrations of all components in the network are assigned and
- * molecule names are added.
- *
- * Loaded parameters include:
+ * Creates a complex signaling {@code Process} for the given {@link PatchCell}.
+ *
+ * Initial concentrations of all components in the network are assigned and molecule names
+ * are added.
+ *
+ * Loaded parameters include:
+ *
*
- * Uses five regulatory weights:
+ *
+ * Uses five regulatory weights:
+ *
*
- * {@code PatchProcessSignalingMedium} represents a 8-component signaling
- * network spanning the cytoplasm and cell membrane. Migratory flag is set based
- * on fold change in active PLCg using {@code MIGRATORY_THRESHOLD}. Derived from
- * {@link PatchProcessSignalingComplex} with simplified transcription and
- * translation.
+ *
+ * {@code PatchProcessSignalingMedium} represents a 8-component signaling network spanning the
+ * cytoplasm and cell membrane. Migratory flag is set based on fold change in active PLCg using
+ * {@code MIGRATORY_THRESHOLD}. Derived from {@link PatchProcessSignalingComplex} with simplified
+ * transcription and translation.
*/
-
public class PatchProcessSignalingMedium extends PatchProcessSignaling {
/** Number of components in signaling network. */
private static final int NUM_COMPONENTS = 8;
-
+
/** Initial membrane concentration [nM]. */
private static final double MEMBRANE = 25.0;
-
+
/** Constant total PLCg [nM]. */
private static final double PLCG = 1.0;
-
+
/** ID for Glucose, internal. */
private static final int G_INT = 0;
-
+
/** ID for TGFa, extracellular. */
private static final int T_EXT = 1;
-
+
/** ID for EGFR, membrane. */
private static final int E_MEM = 2;
-
+
/** ID for TGFa-EGFR complex, membrane, active. */
private static final int TE_MEM = 3;
-
+
/** ID for TGFa-EGFR complex, membrane, active. */
private static final int TE_MEM_P = 4;
-
+
/** ID for TGFa-EGFR complex, cytoplasmic. */
private static final int TE_CYTO = 5;
-
+
/** ID for PLCg, inactive. */
private static final int P_INACTIVE = 6;
-
+
/** ID for PLCg, active. */
private static final int P_ACTIVE = 7;
-
+
/** Rate of TGFa-EGFR complex formation [/nM/sec]. */
private static final double K1 = 0.003;
-
+
/** Rate of TGFa-EGFR complex dissociation [/sec]. */
private static final double K_1 = 0.0038;
-
+
/** Rate of TGFa-EGFR phosphorylation [/sec]. */
private static final double K2 = 0.001;
-
+
/** Rate of p-TGFa-EGFR dephosphorylation [/sec]. */
private static final double K_2 = 0.000001;
-
+
/** Rate of membrane TGFa-EGFR internalization [/sec]. */
private static final double K3 = 0.00005;
-
+
/** Rate of membrane p-TGFa-EGFR internalization [/sec]. */
private static final double K4 = 0.00005;
-
+
/** Rate of cytoplasmic TGFa-EGFR dissociation [/sec]. */
private static final double K5 = 0.01;
-
+
/** Rate of membrane EGFR degradation (estimate) [/sec]. */
private static final double K6 = 0.0001;
-
+
/** Rate of extracellular TGFa degradation (estimate) [/sec]. */
private static final double K7 = 0.01;
-
+
/** Rate of activation of PLCg [/sec]. */
private static final double K8 = 0.1;
-
+
/** Rate of inactivation of PLCg [/sec]. */
private static final double K9 = 0.05;
-
+
/** Translation of EGFR RNA [nM/sec]. */
private static final double K10 = 5.0 / MOLEC_TO_NM / 60;
-
+
/** Translation of TGFa RNA [nM/sec]. */
private static final double K11 = 5.0 / MOLEC_TO_NM / 60;
-
+
/** Weight of TGFa-EGFR phosphorylation regulation by glucose. */
private static final double WG = 200.0;
-
+
/** Weight of PLCg activation regulation by p-TGFa-EGFR. */
private static final double WP = 5.0;
-
+
/** Weight of TGFa-EGFR dephosphorylation regulation by active PLCg. */
private static final double WC = 1.0;
-
+
/** Threshold fold change in PLCg for migration. */
private final double migratoryThreshold;
-
+
/** Fold change in PLCg of previous time step. */
private double previous = 1.0;
-
+
/** Fold change in PLCg for current time step. */
private double current = 1.0;
-
+
/** List of internal concentrations. */
private double[] concs;
-
+
/**
- * Creates a medium signaling {@code Process} for the given
- * {@link PatchCell}.
- *
- * Initial concentrations of all components in the network are assigned and
- * molecule names are added.
- *
- * Loaded parameters include:
+ * Creates a medium signaling {@code Process} for the given {@link PatchCell}.
+ *
+ * Initial concentrations of all components in the network are assigned and molecule names
+ * are added.
+ *
+ * Loaded parameters include:
+ *
*
- * Uses three regulatory weights:
+ *
+ * Uses three regulatory weights:
+ *
*
- * {@code PatchModuleSignalingRandom} randomly sets the migratory flag based on
- * {@code MIGRATORY_PROBABILITY}.
+ *
+ * {@code PatchModuleSignalingRandom} randomly sets the migratory flag based on {@code
+ * MIGRATORY_PROBABILITY}.
*/
-
public class PatchProcessSignalingRandom extends PatchProcessSignaling {
/** Probability of migration instead of proliferation. */
private final double migratoryProbability;
-
+
/**
- * Creates a random signaling {@code Process} for the given
- * {@link PatchCell}.
- *
- * Loaded parameters include:
+ * Creates a random signaling {@code Process} for the given {@link PatchCell}.
+ *
+ * Loaded parameters include:
+ *
*
- * {@code PatchModuleSignalingSimple} represents a 5-component signaling network
- * spanning the cytoplasm. Migratory flag is set based on fold change in active
- * PLCg using {@code MIGRATORY_THRESHOLD}. Derived from
- * {@link PatchProcessSignalingMedium} using minimal components.
+ *
+ * {@code PatchModuleSignalingSimple} represents a 5-component signaling network spanning the
+ * cytoplasm. Migratory flag is set based on fold change in active PLCg using {@code
+ * MIGRATORY_THRESHOLD}. Derived from {@link PatchProcessSignalingMedium} using minimal components.
*/
-
public class PatchProcessSignalingSimple extends PatchProcessSignaling {
/** Number of components in signaling network. */
private static final int NUM_COMPONENTS = 5;
-
+
/** Constant total PLCg [nM]. */
private static final double PLCG = 1.0;
-
+
/** ID for Glucose, internal. */
private static final int G_INT = 0;
-
+
/** ID for TGFa, extracellular. */
private static final int T_EXT = 1;
-
+
/** ID for TGFa-EGFR complex, cytoplasmic. */
private static final int TE_CYTO = 2;
-
+
/** ID for PLCg, inactive. */
private static final int P_INACTIVE = 3;
-
+
/** ID for PLCg, active. */
private static final int P_ACTIVE = 4;
-
+
/** Rate of TGFa-EGFR complex formation [/sec]. */
private static final double K1 = 0.003;
-
+
/** Rate of membrane EGFR degradation (estimate) [/sec]. */
private static final double K2 = 0.0001;
-
+
/** Rate of extracellular TGFa degradation (estimate) [/sec]. */
private static final double K3 = 0.01;
-
+
/** Rate of activation of PLCg [/sec]. */
private static final double K4 = 0.1;
-
+
/** Rate of inactivation of PLCg [/sec]. */
private static final double K5 = 0.05;
-
+
/** Translation of TGFa RNA [nM/sec]. */
private static final double K6 = 5.0 / MOLEC_TO_NM / 60;
-
+
/** Weight of TGFa-EGFR phosphorylation regulation by glucose. */
private static final double WG = 200.0;
-
+
/** Weight of PLCg activation regulation by p-TGFa-EGFR. */
private static final double WP = 5.0;
-
+
/** Weight of TGFa-EGFR dephosphorylation regulation by active PLCg. */
private static final double WC = 1.0;
-
+
/** Threshold fold change in PLCg for migration. */
private final double migratoryThreshold;
-
+
/** Fold change in PLCg of previous time step. */
private double previous = 1.0;
-
+
/** Fold change in PLCg for current time step. */
private double current = 1.0;
-
+
/** List of internal concentrations. */
private double[] concs;
-
+
/**
- * Creates a simple signaling {@code Process} for the given
- * {@link PatchCell}.
- *
- * Initial concentrations of all components in the network are assigned and
- * molecule names are added.
- *
- * Loaded parameters include:
+ * Creates a simple signaling {@code Process} for the given {@link PatchCell}.
+ *
+ * Initial concentrations of all components in the network are assigned and molecule names
+ * are added.
+ *
+ * Loaded parameters include:
+ *
*
- * Uses three regulatory weights:
+ *
+ * Uses three regulatory weights:
+ *
*
- * This component can only be used with {@link PatchComponentSitesSource}.
- * Multiple cycled molecules are tracked by a list of {@link CycleLayer}
- * objects. This component affects the source concentration of the specified
- * molecule ({@code CYCLE_MOLECULE}). At each time point, the amount of
- * concentration is set equal to a fraction of the initial concentration,
- * determined by a smoothed sawtooth function. The cycle repeats every day, with
- * three peaks per day.
+ *
+ * This component can only be used with {@link PatchComponentSitesSource}. Multiple cycled
+ * molecules are tracked by a list of {@link CycleLayer} objects. This component affects the source
+ * concentration of the specified molecule ({@code CYCLE_MOLECULE}). At each time point, the amount
+ * of concentration is set equal to a fraction of the initial concentration, determined by a
+ * smoothed sawtooth function. The cycle repeats every day, with three peaks per day.
*/
-
public class PatchComponentCycle implements Component {
/** Smoothing factor for sawtooth equation. */
private static final double SMOOTHING_FACTOR = 15;
-
+
/** List of cycle layers. */
private final ArrayList
- * This component can only be used with {@link PatchComponentSitesGraph}. The
- * component is stepped every {@code DEGRADATION_INTERVAL} ticks. wall thickness
- * of edges that are adjacent to a location with cancerous cells is decreased
- * ({@code DEGRADATION_RATE}). Edges that are below a minimum wall thickness and
- * have a shear stress below the shear threshold ({@code SHEAR_THRESHOLD}) are
- * removed from the graph. At the end of a step, if no edges have been removed
- * from the graph, then only the stresses in the graph are recalculated.
- * Otherwise, all hemodynamic properties are recalculated.
+ *
+ * This component can only be used with {@link PatchComponentSitesGraph}. The component is
+ * stepped every {@code DEGRADATION_INTERVAL} ticks. wall thickness of edges that are adjacent to a
+ * location with cancerous cells is decreased ({@code DEGRADATION_RATE}). Edges that are below a
+ * minimum wall thickness and have a shear stress below the shear threshold ({@code
+ * SHEAR_THRESHOLD}) are removed from the graph. At the end of a step, if no edges have been removed
+ * from the graph, then only the stresses in the graph are recalculated. Otherwise, all hemodynamic
+ * properties are recalculated.
*/
-
public class PatchComponentDegrade implements Component {
/** Interval between degradation steps [min]. */
private final int degradationInterval;
-
+
/** Rate of wall thickness degradation [um/min]. */
private final double degradationRate;
-
+
/** Shear threshold for vessel collapse [mmHg]. */
private final double shearThreshold;
-
+
/** The associated {@link PatchComponentSitesGraph} object. */
private PatchComponentSitesGraph sites;
-
+
/** The {@link Graph} object representing the sites. */
private Graph graph;
-
+
/**
* Creates a {@code Component} object for degrading graph sites.
- *
- * Loaded parameters include:
+ *
+ * Loaded parameters include:
+ *
*
- * This component can only be used with {@link PatchComponentSitesSource}.
- * Multiple pulsed molecules are tracked by a list of {@link PulseLayer}
- * objects.
- *
- * The amount of media ({@code MEDIA_AMOUNT}) is used to determine the total
- * amount of molecule available given total simulation area. The molecule
- * concentration is updated each step as the molecule is consumed or otherwise
- * removed from the environment. At the specified pulse interval
- * ({@code PULSE_INTERVAL}), a "pulse" of media is introduced, updating the
- * total amount of molecule available.
+ *
+ * This component can only be used with {@link PatchComponentSitesSource}. Multiple pulsed
+ * molecules are tracked by a list of {@link PulseLayer} objects.
+ *
+ * The amount of media ({@code MEDIA_AMOUNT}) is used to determine the total amount of molecule
+ * available given total simulation area. The molecule concentration is updated each step as the
+ * molecule is consumed or otherwise removed from the environment. At the specified pulse interval
+ * ({@code PULSE_INTERVAL}), a "pulse" of media is introduced, updating the total amount of molecule
+ * available.
*/
-
public class PatchComponentPulse implements Component {
/** List of pulse layers. */
private final ArrayList
- * Loaded parameters include:
+ *
+ * Loaded parameters include:
+ *
*
- * This component can only be used with {@link PatchComponentSitesGraph}. The
- * component is stepped every {@code REMODELING_INTERVAL} ticks. The radius and
- * wall thickness of edges are remodeled as a function of shear stress
- * ({@code SCALE_SHEAR}), circumferential stress ({@code SCALE_CIRCUM}), flow
- * rate ({@code SCALE_FLOW}), and metabolic demand ({@code SCALE_METABOLIC}). The
- * scaling based on shear (tau) and circumferential (sigma) stress mainly affect
- * radius mid and area mass, respectively, but can also affect the other term
- * ({@code SCALE_SIGMA} and {@code SCALE_TAU}). Edges that are below a minimum
- * wall thickness or radius are removed from the graph. All hemodynamic
- * properties are recalculated at the end of the step.
+ *
+ * This component can only be used with {@link PatchComponentSitesGraph}. The component is
+ * stepped every {@code REMODELING_INTERVAL} ticks. The radius and wall thickness of edges are
+ * remodeled as a function of shear stress ({@code SCALE_SHEAR}), circumferential stress ({@code
+ * SCALE_CIRCUM}), flow rate ({@code SCALE_FLOW}), and metabolic demand ({@code SCALE_METABOLIC}).
+ * The scaling based on shear (tau) and circumferential (sigma) stress mainly affect radius mid and
+ * area mass, respectively, but can also affect the other term ({@code SCALE_SIGMA} and {@code
+ * SCALE_TAU}). Edges that are below a minimum wall thickness or radius are removed from the graph.
+ * All hemodynamic properties are recalculated at the end of the step.
*/
-
public class PatchComponentRemodel implements Component {
/** Interval between remodeling steps [min]. */
private final int remodelingInterval;
-
+
/** Shear stress scaling. */
private final double scaleShear;
-
+
/** Circumferential stress scaling. */
private final double scaleCircum;
-
+
/** Flow rate scaling. */
private final double scaleFlow;
-
+
/** Metabolic demand scaling. */
private final double scaleMetabolic;
-
+
/** Shear stress contribution to area mass scaling. */
private final double scaleTau;
-
+
/** Circumferential stress contribution to radius scaling. */
private final double scaleSigma;
-
+
/** Reference shear stress. */
private double shearReference;
-
+
/** Reference circumferential stress. */
private double circumReference;
-
+
/** Reference flow rate. */
private double flowReference;
-
+
/** The associated {@link PatchComponentSitesGraph} object. */
private PatchComponentSitesGraph sites;
-
+
/** The {@link Graph} object representing the sites. */
private Graph graph;
-
+
/**
* Creates a {@link arcade.core.env.component.Component} object for remodeling.
- *
- * Loaded parameters include:
+ *
+ * Loaded parameters include:
+ *
*
- * The object defines the locations of sites from which molecules are generated
- * and added into the environment. Multiple molecules generated from the same
- * sites are tracked by a list of {@link SiteLayer} objects, which map the
- * component to the correct environment lattices.
+ *
+ * The object defines the locations of sites from which molecules are generated and added into
+ * the environment. Multiple molecules generated from the same sites are tracked by a list of {@link
+ * SiteLayer} objects, which map the component to the correct environment lattices.
*/
-
public abstract class PatchComponentSites implements Component {
/** List of site layers. */
final ArrayList
- * Layout of the underlying graph is specified by {@code GRAPH_LAYOUT}. The
- * pattern layout is specified by using {@code "*"}. The root layout is
- * specified by specifying roots:
+ *
+ * Layout of the underlying graph is specified by {@code GRAPH_LAYOUT}. The pattern layout is
+ * specified by using {@code "*"}. The root layout is specified by specifying roots:
+ *
*
- * The border {@code The border {@code
- * Loaded parameters include:
+ *
+ * Loaded parameters include:
+ *
*
- * Calls the correct method to populate the graph with edges (either pattern
- * or root layout). After the graph is defined, the corresponding indices in
- * the lattice adjacent to edges are marked.
*
- * @param random the random number generator
- * @return an initialized graph object
+ * Calls the correct method to populate the graph with edges (either pattern or root layout).
+ * After the graph is defined, the corresponding indices in the lattice adjacent to edges are
+ * marked.
+ *
+ * @param random the random number generator
+ * @return an initialized graph object
*/
Graph initializeGraph(MersenneTwisterFast random) {
Graph initGraph;
-
+
if (graphLayout.equals("*")) {
initGraph = graphFactory.initializePatternGraph(random);
} else {
@@ -176,35 +176,35 @@ Graph initializeGraph(MersenneTwisterFast random) {
iter++;
} while (initGraph.getAllEdges().numObjs == 0 && iter < MAXIMUM_ITERATIONS);
}
-
+
for (Object obj : initGraph.getAllEdges()) {
SiteEdge edge = (SiteEdge) obj;
edge.span = getSpan(edge.getFrom(), edge.getTo());
edge.transport.putIfAbsent("GLUCOSE", 0.);
edge.transport.putIfAbsent("OXYGEN", 0.);
}
-
+
return initGraph;
}
-
+
/**
* Graph step that only considers differences in concentration.
- *
- * Method is equivalent to the step used with
- * {@link arcade.patch.env.component.PatchComponentSitesSource} and
- * {@link arcade.patch.env.component.PatchComponentSitesPattern} where the amount
- * of concentration added is the difference between the source concentration
- * and the current concentration for a given molecule.
+ *
+ * Method is equivalent to the step used with {@link
+ * arcade.patch.env.component.PatchComponentSitesSource} and {@link
+ * arcade.patch.env.component.PatchComponentSitesPattern} where the amount of concentration
+ * added is the difference between the source concentration and the current concentration for a
+ * given molecule.
*/
void simpleStep() {
Bag allEdges = new Bag(graph.getAllEdges());
-
+
// Iterate through each molecule.
for (SiteLayer layer : layers) {
double[][][] delta = layer.delta;
double[][][] previous = layer.previous;
double concentration = layer.concentration;
-
+
// Clear lattice values.
for (int k = 0; k < latticeHeight; k++) {
for (int i = 0; i < latticeLength; i++) {
@@ -213,13 +213,13 @@ void simpleStep() {
}
}
}
-
+
for (Object obj : allEdges) {
SiteEdge edge = (SiteEdge) obj;
if (edge.isIgnored) {
continue;
}
-
+
for (CoordinateXYZ coordinate : edge.span) {
int i = coordinate.x;
int j = coordinate.y;
@@ -229,19 +229,18 @@ void simpleStep() {
}
}
}
-
+
/**
* Graph step that uses traversals to calculate exact hemodynamics.
- *
- * Traversing the graph updates the concentrations of molecules in each
- * edge. The amount of concentration added is a function of flow rate and
- * permeability to the given molecule.
*
- * @param random the random number generator
+ * Traversing the graph updates the concentrations of molecules in each edge. The amount of
+ * concentration added is a function of flow rate and permeability to the given molecule.
+ *
+ * @param random the random number generator
*/
void complexStep(MersenneTwisterFast random) {
Bag allEdges = new Bag(graph.getAllEdges());
-
+
// Check if graph has become unconnected.
boolean isConnected = false;
for (Object obj : allEdges) {
@@ -263,16 +262,16 @@ void complexStep(MersenneTwisterFast random) {
}
return;
}
-
+
// Iterate through each molecule.
for (SiteLayer layer : layers) {
double[][][] delta = layer.delta;
double[][][] current = layer.current;
double concentration = layer.concentration;
double permeability = layer.permeability;
-
+
stepGraph(layer.name);
-
+
// Clear lattice values.
for (int k = 0; k < latticeHeight; k++) {
for (int i = 0; i < latticeLength; i++) {
@@ -281,9 +280,9 @@ void complexStep(MersenneTwisterFast random) {
}
}
}
-
+
allEdges.shuffle(random);
-
+
// Iterate through each edge in graph.
for (Object obj : allEdges) {
SiteEdge edge = (SiteEdge) obj;
@@ -293,13 +292,13 @@ void complexStep(MersenneTwisterFast random) {
SiteNode from = edge.getFrom();
SiteNode to = edge.getTo();
edge.transport.put(layer.name, 0.0);
-
+
double extConc;
double intConc;
double dmdt;
double intConcNew;
double extConcNew;
-
+
// Get average external concentration across spanning locations.
extConc = 0;
for (CoordinateXYZ coordinate : edge.span) {
@@ -309,18 +308,18 @@ void complexStep(MersenneTwisterFast random) {
extConc += current[k][i][j] + delta[k][i][j];
}
extConc /= edge.span.size();
-
+
// Note permeability values are assumed to be for 1 um thickness.
// Here we multiply by (1 um) and then redivide by the actual
// thickness of the edge.
double flow = edge.flow / 60; // um^3/sec
double pa = edge.area * permeability / edge.wall; // um^3/sec
-
+
// Skip if flow is less than a certain speed.
if (flow < MINIMUM_FLOW) {
continue;
}
-
+
if (layer.name.equalsIgnoreCase("OXYGEN")) {
extConc = oxySoluTissue * extConc; // mmHg -> fmol/um^3
intConc = oxySoluPlasma * (from.oxygen + to.oxygen) / 2; // mmHg -> fmol/um^3
@@ -331,13 +330,14 @@ void complexStep(MersenneTwisterFast random) {
intConcNew = intConc; // fmol/um^3
extConcNew = extConc; // fmol/um^3
}
-
+
if (Math.abs(intConc - extConc) > DELTA_TOLERANCE) {
// Check for stability.
double max = latticePatchVolume / edge.area;
if (permeability > max) {
- intConcNew = (intConcNew * flow + latticePatchVolume * extConcNew)
- / (flow + latticePatchVolume);
+ intConcNew =
+ (intConcNew * flow + latticePatchVolume * extConcNew)
+ / (flow + latticePatchVolume);
extConcNew = intConcNew;
} else {
// Iterate for each second in the minute time step.
@@ -347,22 +347,25 @@ void complexStep(MersenneTwisterFast random) {
extConcNew += dmdt / latticePatchVolume;
}
}
-
+
// Update external concentrations.
for (CoordinateXYZ coordinate : edge.span) {
int i = coordinate.x;
int j = coordinate.y;
int k = coordinate.z;
-
+
if (layer.name.equalsIgnoreCase("OXYGEN")) {
- delta[k][i][j] += Math.max((extConcNew / oxySoluTissue
- - (current[k][i][j] + delta[k][i][j])), 0);
+ delta[k][i][j] +=
+ Math.max(
+ (extConcNew / oxySoluTissue
+ - (current[k][i][j] + delta[k][i][j])),
+ 0);
} else {
- delta[k][i][j] += Math.max((extConcNew - (current[k][i][j]
- + delta[k][i][j])), 0);
+ delta[k][i][j] +=
+ Math.max((extConcNew - (current[k][i][j] + delta[k][i][j])), 0);
}
}
-
+
// Set transport of edge (for graph step).
if (layer.name.equalsIgnoreCase("OXYGEN")) {
edge.transport.put(layer.name, (intConc - intConcNew) * edge.flow);
@@ -373,131 +376,133 @@ void complexStep(MersenneTwisterFast random) {
}
}
}
-
+
/**
* Extension of {@link arcade.core.util.Graph.Node} for site nodes.
- *
- * Node tracks additional hemodynamic properties including pressure and
- * oxygen.
+ *
+ * Node tracks additional hemodynamic properties including pressure and oxygen.
*/
public static class SiteNode extends Node {
/** Node ID. */
int id;
-
+
/** {@code true} if the node is a root, {@code false} otherwise. */
boolean isRoot;
-
+
/** Pressure of the node. */
double pressure;
-
+
/** Oxygen partial pressure of the node. */
double oxygen;
-
+
/** Distance for Dijkstra's algorithm. */
int distance;
-
+
/** Parent node. */
SiteNode prev;
-
+
/**
* Creates a {@link Node} for graph sites.
*
- * @param x the x coordinate
- * @param y the y coordinate
- * @param z the z coordinate
+ * @param x the x coordinate
+ * @param y the y coordinate
+ * @param z the z coordinate
*/
SiteNode(int x, int y, int z) {
super(x, y, z);
pressure = 0;
isRoot = false;
}
-
+
@Override
public Node duplicate() {
return new SiteNode(x, y, z);
}
-
+
/**
* Gets the root type of the node.
*
- * @return {@code true} if node is root, {@code false} otherwise
+ * @return {@code true} if node is root, {@code false} otherwise
*/
- public boolean getRoot() { return isRoot; }
-
+ public boolean getRoot() {
+ return isRoot;
+ }
+
/**
* Get the pressure of the node.
*
- * @return the node pressure
+ * @return the node pressure
*/
- public double getPressure() { return pressure; }
+ public double getPressure() {
+ return pressure;
+ }
}
-
+
/**
* Extension of {@link arcade.core.util.Graph.Edge} for site edges.
- *
- * Node tracks additional hemodynamic properties including radius, length,
- * wall thickness, shear stress, circumferential stress, and volumetric flow
- * rate.
+ *
+ * Node tracks additional hemodynamic properties including radius, length, wall thickness,
+ * shear stress, circumferential stress, and volumetric flow rate.
*/
public static class SiteEdge extends Edge {
/** List of lattice coordinates spanned by edge. */
ArrayList
- * Graph can be initialized in two ways:
+ *
+ * Graph can be initialized in two ways:
+ *
*
- *
*/
-
public abstract class ARCADE {
/** Logger for {@code ARCADE}. */
protected static Logger logger;
-
+
/** Version number. */
public static final String VERSION = loadVersion();
-
+
/**
* Gets the resource relative to the location of the class.
*
- * @param s the resource name
- * @return the resource location
+ * @param s the resource name
+ * @return the resource location
*/
protected abstract String getResource(String s);
-
+
/**
* Gets an {@link InputBuilder} instance.
*
- * @return an {@link InputBuilder} instance
+ * @return an {@link InputBuilder} instance
*/
protected abstract InputBuilder getBuilder();
-
+
/**
* Gets an {@link OutputLoader} instance for the series.
*
- * @param series the {@link Series} instance
- * @return an {@link OutputLoader} instance
+ * @param series the {@link Series} instance
+ * @return an {@link OutputLoader} instance
*/
protected abstract OutputLoader getLoader(Series series);
-
+
/**
* Gets an {@link OutputSaver} instance for the series.
*
- * @param series the {@link Series} instance
- * @return an {@link OutputSaver} instance
+ * @param series the {@link Series} instance
+ * @return an {@link OutputSaver} instance
*/
protected abstract OutputSaver getSaver(Series series);
-
+
/**
* Main function for running ARCADE simulations.
*
- * @param args list of command line arguments
+ * @param args list of command line arguments
*/
public static void main(String[] args) throws Exception {
updateLogger();
logger = Logger.getLogger(ARCADE.class.getName());
-
+
// Check that arguments includes at least one entry.
if (args.length == 0) {
logger.warning("ARCADE simulation type must be specified");
throw new InvalidParameterException();
}
-
+
// Extract ARCADE type.
ARCADE arcade;
-
+
switch (args[0]) {
case "patch":
logger.info("running ARCADE [ patch | " + VERSION + " ] simulations");
@@ -118,102 +117,113 @@ public static void main(String[] args) throws Exception {
logger.warning("ARCADE [ " + args[0] + " ] does not exist");
throw new InvalidParameterException();
}
-
+
// Load command and parameter XML files.
Box commands = arcade.loadCommands(args[0]);
Box parameters = arcade.loadParameters(args[0]);
-
+
// Parse arguments from command line.
MiniBox settings = arcade.parseArguments(args, commands);
-
+
// Build series
ArrayList
- *
- *
- *
*/
-
public interface CellFactory {
/**
* Initializes the factory for the given series.
*
- * @param series the simulation series
- * @param random the random number generator
+ * @param series the simulation series
+ * @param random the random number generator
*/
void initialize(Series series, MersenneTwisterFast random);
-
+
+ /**
+ * Gets the population parameters.
+ *
+ * @param pop the population code
+ * @return the population parameters
+ */
+ MiniBox getParameters(int pop);
+
+ /**
+ * Gets the population links.
+ *
+ * @param pop the population code
+ * @return the bag of population links
+ */
+ GrabBag getLinks(int pop);
+
/**
* Loads cell containers into the factory container.
*
- * @param series the simulation series
+ * @param series the simulation series
*/
void loadCells(Series series);
-
+
/**
* Creates cell containers from population settings.
*
- * @param series the simulation series
+ * @param series the simulation series
*/
void createCells(Series series);
}
diff --git a/src/arcade/core/agent/cell/CellState.java b/src/arcade/core/agent/cell/CellState.java
index b59a0b5d8..180a716fc 100644
--- a/src/arcade/core/agent/cell/CellState.java
+++ b/src/arcade/core/agent/cell/CellState.java
@@ -1,9 +1,4 @@
package arcade.core.agent.cell;
-/**
- * A {@code CellState} enum represents a cell agent state.
- */
-
-public interface CellState {
-
-}
+/** A {@code CellState} enum represents a cell agent state. */
+public interface CellState {}
diff --git a/src/arcade/core/agent/module/Module.java b/src/arcade/core/agent/module/Module.java
index 5eb592b76..588fecf87 100644
--- a/src/arcade/core/agent/module/Module.java
+++ b/src/arcade/core/agent/module/Module.java
@@ -5,26 +5,22 @@
/**
* A {@code Module} object is an exclusive subcellular steppable.
- *
- *
- *
- *
*/
-
public interface LatticeFactory {
/**
* Initializes the factory for the given series.
*
- * @param series the simulation series
- * @param random the random number generator
+ * @param series the simulation series
+ * @param random the random number generator
*/
void initialize(Series series, MersenneTwisterFast random);
-
+
/**
* Creates lattices from layer settings.
*
- * @param series the simulation series
+ * @param series the simulation series
*/
void createLattices(Series series);
}
diff --git a/src/arcade/core/env/location/Location.java b/src/arcade/core/env/location/Location.java
index caea211b9..e79eccc7e 100644
--- a/src/arcade/core/env/location/Location.java
+++ b/src/arcade/core/env/location/Location.java
@@ -2,39 +2,38 @@
/**
* A {@code Location} object defines the cell location within the environment.
- *
- *
*/
-
public interface LocationFactory {
/**
* Initializes the factory for the given series.
*
- * @param series the simulation series
- * @param random the random number generator
+ * @param series the simulation series
+ * @param random the random number generator
*/
void initialize(Series series, MersenneTwisterFast random);
-
+
/**
* Loads location containers into the factory container.
*
- * @param series the simulation series
+ * @param series the simulation series
*/
void loadLocations(Series series);
-
+
/**
* Creates location containers from population settings.
*
- * @param series the simulation series
+ * @param series the simulation series
*/
void createLocations(Series series);
}
diff --git a/src/arcade/core/env/operation/Operation.java b/src/arcade/core/env/operation/Operation.java
index c7903988f..174c8291c 100644
--- a/src/arcade/core/env/operation/Operation.java
+++ b/src/arcade/core/env/operation/Operation.java
@@ -5,30 +5,25 @@
/**
* An {@code Operation} object is a non-exclusive environmental layer steppable.
- *
* <set>
* <series>
@@ -37,41 +37,38 @@
* </set>
*
*/
-
public abstract class InputBuilder implements ContentHandler {
/** Logger for {@code InputBuilder}. */
protected static final Logger LOGGER = Logger.getLogger(InputBuilder.class.getName());
-
+
/** XML reader. */
XMLReader xmlReader;
-
+
/** List holding {@link arcade.core.sim.Series} instances. */
public ArrayList
- *
- *
* <commands>
* <position id="(unique id)" help="(help text)" />
@@ -34,42 +36,41 @@
* </commands>
*
*/
-
public class InputParser {
/** Logger for {@code InputParser}. */
private static final Logger LOGGER = Logger.getLogger(InputParser.class.getName());
-
+
/** ID for position commands. */
static final int POSITION = 0;
-
+
/** ID for option commands. */
static final int OPTION = 1;
-
+
/** ID for switch commands. */
static final int SWITCH = 2;
-
+
/** Dictionary of parsed commands. */
MiniBox parsed;
-
+
/** List of all commands. */
final ArrayList
- *
*/
-
public final class OutputDeserializer {
- /**
- * Hidden utility class constructor.
- */
+ /** Hidden utility class constructor. */
protected OutputDeserializer() {
throw new UnsupportedOperationException();
}
-
+
/**
* Creates a {@code GsonBuilder} with generic adaptors.
*
- * @return a {@code GsonBuilder} instance
+ * @return a {@code GsonBuilder} instance
*/
public static GsonBuilder makeGSONBuilder() {
GsonBuilder gsonBuilder = new GsonBuilder();
@@ -45,47 +42,43 @@ public static GsonBuilder makeGSONBuilder() {
gsonBuilder.registerTypeAdapter(DEFAULT_LOCATION_TYPE, new LocationListDeserializer());
return gsonBuilder;
}
-
- /**
- * Deserializer for a list of {@link CellContainer} objects.
- */
+
+ /** Deserializer for a list of {@link CellContainer} objects. */
public static final class CellListDeserializer
implements JsonDeserializer
- *
*/
-
public final class OutputSerializer {
/** Regular expression for fractions. */
public static final String DOUBLE_REGEX = "^(-?\\d*\\.\\d*)$|^(-?\\d*\\.\\d*E-?\\d+)$";
-
+
/** Regular expression for integers. */
public static final String INTEGER_REGEX = "^(-?\\d+)$|^(-?\\d+E-?\\d+)$";
-
- /**
- * Hidden utility class constructor.
- */
+
+ /** Hidden utility class constructor. */
protected OutputSerializer() {
throw new UnsupportedOperationException();
}
-
+
/**
* Creates a {@code GsonBuilder} with generic adaptors.
*
- * @return a {@code GsonBuilder} instance
+ * @return a {@code GsonBuilder} instance
*/
public static GsonBuilder makeGSONBuilder() {
GsonBuilder gsonBuilder = new GsonBuilder().setPrettyPrinting();
@@ -59,11 +55,12 @@ public static GsonBuilder makeGSONBuilder() {
gsonBuilder.registerTypeAdapter(DEFAULT_LOCATION_TYPE, new LocationListSerializer());
return gsonBuilder;
}
-
+
/**
* Serializer for {@link MiniBox} objects.
- *
* {
* "(key)" : (value),
@@ -74,13 +71,13 @@ public static GsonBuilder makeGSONBuilder() {
*/
public static final class MiniBoxSerializer implements JsonSerializer
* {
* "version": (version),
@@ -125,26 +123,25 @@ public JsonElement serialize(MiniBox src, Type typeOfSrc,
*/
public static final class SeriesSerializer implements JsonSerializer
* [
* (serialized cell container),
@@ -174,23 +172,24 @@ public JsonElement serialize(Series src, Type typeOfSrc,
public static final class CellListSerializer
implements JsonSerializer
* [
* (serialized location container),
@@ -202,16 +201,18 @@ public JsonElement serialize(ArrayList
+ *
+ */
+public class GrabBag {
+ /** Map of cumulative weights to items. */
+ private final NavigableMap
- *
*/
-
public class Solver {
/** Logger for {@code Solver}. */
private static final Logger LOGGER = Logger.getLogger(Solver.class.getName());
-
+
/** Error tolerance for Cash-Karp. */
private static final double ERROR = 1E-5;
-
+
/** Epsilon value for Cash-Karp. */
private static final double EPSILON = 1E-10;
-
+
/** Maximum number of steps for Cash-Karp. */
private static final int MAX_STEPS = 100;
-
+
/** Safety value for Cash-Karp. */
private static final double SAFETY = 0.9;
-
+
/** Relaxation factor for SOR. */
private static final double OMEGA = 1.4;
-
+
/** Maximum number of iterations. */
private static final int MAX_ITERS = 10000;
-
+
/** Error tolerance for SOR. */
private static final double TOLERANCE = 1E-8;
-
+
/** Convergence delta for bisection method. */
private static final double DELTA = 1E-5;
-
+
/** Matrix size threshold for dense representation. */
private static final int MATRIX_THRESHOLD = 100;
-
+
/** Defines ODE equations for numerical solvers. */
public interface Equations {
/**
* Applies equations to inputs.
*
- * @param t the time step
- * @param y the array of inputs
- * @return the array of outputs
+ * @param t the time step
+ * @param y the array of inputs
+ * @return the array of outputs
*/
double[] dydt(double t, double[] y);
}
-
+
/** Defines a continuous function. */
public interface Function {
/**
* Applies function to input.
*
- * @param x the input value
- * @return the output value
+ * @param x the input value
+ * @return the output value
*/
double f(double x);
}
-
- /**
- * Hidden constructor for {@code Solver} utility class.
- */
+
+ /** Hidden constructor for {@code Solver} utility class. */
protected Solver() {
throw new UnsupportedOperationException();
}
-
+
/**
* Solves a system of ODEs using forward Euler.
*
- * @param eq the system of equations
- * @param t0 the initial time
- * @param y0 the array of initial values
- * @param tf the final time
- * @param h the time step
- * @return the array of final values
+ * @param eq the system of equations
+ * @param t0 the initial time
+ * @param y0 the array of initial values
+ * @param tf the final time
+ * @param h the time step
+ * @return the array of final values
*/
public static double[] euler(Equations eq, double t0, double[] y0, double tf, double h) {
int n = y0.length;
double t = t0;
double[] dydt = new double[n];
double[] y = y0.clone();
-
+
// Adjust number of steps.
int nSteps = (int) ((tf - t0) / h);
h = (tf - t0) / nSteps;
-
+
// Iterate through steps.
for (int j = 0; j < nSteps; j++) {
t = t0 + j * h;
@@ -106,19 +105,19 @@ public static double[] euler(Equations eq, double t0, double[] y0, double tf, do
y[i] += h * dydt[i];
}
}
-
+
return y;
}
-
+
/**
* Solves a system of ODEs using classic Runge-Kutta.
*
- * @param eq the system of equations
- * @param t0 the initial time
- * @param y0 the array of initial values
- * @param tf the final time
- * @param h the time step
- * @return the array of final values
+ * @param eq the system of equations
+ * @param t0 the initial time
+ * @param y0 the array of initial values
+ * @param tf the final time
+ * @param h the time step
+ * @return the array of final values
*/
public static double[] rungeKutta(Equations eq, double t0, double[] y0, double tf, double h) {
int n = y0.length;
@@ -130,54 +129,70 @@ public static double[] rungeKutta(Equations eq, double t0, double[] y0, double t
double[] dydt = new double[n];
double[] y = y0.clone();
double[] w = new double[n];
-
+
// Adjust number of steps.
int nSteps = (int) ((tf - t0) / h);
h = (tf - t0) / nSteps;
-
+
// Iterate through steps.
for (int j = 0; j < nSteps; j++) {
t = t0 + j * h;
-
+
dydt = eq.dydt(t, y);
for (int i = 0; i < n; i++) {
k1[i] = h * dydt[i];
w[i] = y[i] + k1[i] / 2;
}
-
+
dydt = eq.dydt(t + h / 2, w);
for (int i = 0; i < n; i++) {
k2[i] = h * dydt[i];
w[i] = y[i] + k2[i] / 2;
}
-
+
dydt = eq.dydt(t + h / 2, w);
for (int i = 0; i < n; i++) {
k3[i] = h * dydt[i];
w[i] = y[i] + k3[i];
}
-
+
dydt = eq.dydt(t + h, w);
for (int i = 0; i < n; i++) {
k4[i] = h * dydt[i];
y[i] += k1[i] / 6 + k2[i] / 3 + k3[i] / 3 + k4[i] / 6;
}
}
-
+
return y;
}
-
+
/**
- * Solves a system of ODEs using adaptive timestep Cash-Karp.
+ * Solves a system of ODEs using adaptive timestep Cash-Karp with default maximum steps.
*
- * @param eq the system of equations
- * @param t0 the initial time
- * @param y0 the array of initial values
- * @param tf the final time
- * @param h the time step
- * @return the array of final values
+ * @param eq the system of equations
+ * @param t0 the initial time
+ * @param y0 the array of initial values
+ * @param tf the final time
+ * @param h the time step
+ * @return the array of final values
*/
public static double[] cashKarp(Equations eq, double t0, double[] y0, double tf, double h) {
+ return cashKarp(eq, t0, y0, tf, h, MAX_STEPS);
+ }
+
+ /**
+ * Solves a system of ODEs using adaptive timestep Cash-Karp.
+ *
+ * @param eq the system of equations
+ * @param t0 the initial time
+ * @param y0 the array of initial values
+ * @param tf the final time
+ * @param h the time step
+ * @param maxSteps the maximum number of steps
+ * @return the array of final values
+ */
+ public static double[] cashKarp(
+ Equations eq, double t0, double[] y0, double tf, double h, int maxSteps) {
int n = y0.length;
int steps = 0;
double t = t0;
@@ -195,55 +210,73 @@ public static double[] cashKarp(Equations eq, double t0, double[] y0, double tf,
double err;
double maxErr;
double tol;
-
- while (t < tf && steps < MAX_STEPS) {
+
+ while (t < tf && steps < maxSteps) {
steps++;
-
+
dydt = eq.dydt(t, y);
for (int i = 0; i < n; i++) {
k1[i] = h * dydt[i];
w[i] = y[i] + k1[i] / 5.0;
}
-
+
dydt = eq.dydt(t + h / 5.0, w);
for (int i = 0; i < n; i++) {
k2[i] = h * dydt[i];
w[i] = y[i] + (3 * k1[i] + 9 * k2[i]) / 40.0;
}
-
+
dydt = eq.dydt(t + 3 * h / 10.0, w);
for (int i = 0; i < n; i++) {
k3[i] = h * dydt[i];
w[i] = y[i] + (3 * k1[i] - 9 * k2[i] + 12 * k3[i]) / 10.0;
}
-
+
dydt = eq.dydt(t + 3 * h / 5.0, w);
for (int i = 0; i < n; i++) {
k4[i] = h * dydt[i];
- w[i] = y[i] - 11 * k1[i] / 54.0 + 5 * k2[i] / 2.0 - 70 * k3[i]
- / 27.0 + 35 * k4[i] / 27.0;
+ w[i] =
+ y[i]
+ - 11 * k1[i] / 54.0
+ + 5 * k2[i] / 2.0
+ - 70 * k3[i] / 27.0
+ + 35 * k4[i] / 27.0;
}
-
+
dydt = eq.dydt(t + h, w);
for (int i = 0; i < n; i++) {
k5[i] = h * dydt[i];
- w[i] = y[i] + 1631 * k1[i] / 55296.0 + 175 * k2[i] / 512.0
- + 575 * k3[i] / 13824.0 + 44275 * k4[i] / 110592.0 + 253 * k5[i] / 4096.0;
+ w[i] =
+ y[i]
+ + 1631 * k1[i] / 55296.0
+ + 175 * k2[i] / 512.0
+ + 575 * k3[i] / 13824.0
+ + 44275 * k4[i] / 110592.0
+ + 253 * k5[i] / 4096.0;
}
-
+
dydt = eq.dydt(t + 7 * h / 8.0, w);
maxErr = 0.0;
for (int i = 0; i < n; i++) {
k6[i] = h * dydt[i];
- y5[i] = y[i] + 2825.0 * k1[i] / 27648.0 + 18575.0 * k3[i] / 48384.0
- + 13525.0 * k4[i] / 55296.0 + 277.0 * k5[i] / 14336.0 + k6[i] / 4.0;
- y6[i] = y[i] + 37 * k1[i] / 378.0 + 250.0 * k3[i] / 621.0
- + 125.0 * k4[i] / 594.0 + 512.0 * k6[i] / 1771.0;
+ y5[i] =
+ y[i]
+ + 2825.0 * k1[i] / 27648.0
+ + 18575.0 * k3[i] / 48384.0
+ + 13525.0 * k4[i] / 55296.0
+ + 277.0 * k5[i] / 14336.0
+ + k6[i] / 4.0;
+ y6[i] =
+ y[i]
+ + 37 * k1[i] / 378.0
+ + 250.0 * k3[i] / 621.0
+ + 125.0 * k4[i] / 594.0
+ + 512.0 * k6[i] / 1771.0;
err = Math.abs(y6[i] - y5[i]);
tol = Math.abs(y5[i]) * ERROR + EPSILON;
maxErr = Math.max(maxErr, err / tol);
}
-
+
if (maxErr > 1) { // reduce step size with max 10-fold reduction
h *= Math.max(0.1, SAFETY * Math.pow(maxErr, -0.25));
} else { // increase step size with max 5-fold increase
@@ -253,136 +286,171 @@ public static double[] cashKarp(Equations eq, double t0, double[] y0, double tf,
y = y5.clone();
}
}
-
+
return y;
}
-
+
/**
- * Solves a linear system of equations using successive over-relaxation.
- *
- *
*
- * @param series the simulation series
- * @param parameters the component parameters dictionary
+ * @param series the simulation series
+ * @param parameters the component parameters dictionary
*/
public PatchActionConvert(Series series, MiniBox parameters) {
// Set loaded parameters.
timeDelay = parameters.getInt("TIME_DELAY");
}
-
+
@Override
public void schedule(Schedule schedule) {
schedule.scheduleOnce(timeDelay, Ordering.ACTIONS.ordinal(), this);
}
-
+
@Override
public void register(Simulation sim, String population) {
pop = sim.getSeries().populations.get(population).getInt("CODE");
}
-
+
@Override
public void step(SimState simstate) {
PatchSimulation sim = (PatchSimulation) simstate;
PatchGrid grid = (PatchGrid) sim.getGrid();
-
+
// Get cells at center of simulation.
Coordinate center = sim.locationFactory.getCoordinates(1, 1).get(0);
Bag bag = (Bag) grid.getObjectAt(center.hashCode());
-
+
if (bag == null) {
return;
}
-
+
// Select old cell and remove from simulation.
PatchCell oldCell = (PatchCell) bag.get(0);
Location location = oldCell.getLocation();
grid.removeObject(oldCell, oldCell.getLocation());
oldCell.stop();
-
+
// Create new cell and add to simulation.
- PatchCellContainer cellContainer = new PatchCellContainer(oldCell.getID(),
- oldCell.getParent(), pop, oldCell.getAge(), oldCell.getDivisions(),
- oldCell.getState(), oldCell.getVolume(), oldCell.getHeight(),
- oldCell.getCriticalVolume(), oldCell.getCriticalHeight());
- PatchCell newCell = (PatchCell) cellContainer.convert(sim.cellFactory, location);
+ PatchCellContainer cellContainer =
+ new PatchCellContainer(
+ oldCell.getID(),
+ oldCell.getParent(),
+ pop,
+ oldCell.getAge(),
+ oldCell.getDivisions(),
+ oldCell.getState(),
+ oldCell.getVolume(),
+ oldCell.getHeight(),
+ oldCell.getCriticalVolume(),
+ oldCell.getCriticalHeight());
+ PatchCell newCell =
+ (PatchCell) cellContainer.convert(sim.cellFactory, location, sim.random);
grid.addObject(newCell, location);
newCell.schedule(sim.getSchedule());
}
diff --git a/src/arcade/patch/agent/action/PatchActionInsert.java b/src/arcade/patch/agent/action/PatchActionInsert.java
index 49992be67..dd0df2756 100644
--- a/src/arcade/patch/agent/action/PatchActionInsert.java
+++ b/src/arcade/patch/agent/action/PatchActionInsert.java
@@ -20,95 +20,93 @@
/**
* Implementation of {@link Action} for inserting cell agents.
- *
- *
*
- * @param series the simulation series
- * @param parameters the component parameters dictionary
+ * @param series the simulation series
+ * @param parameters the component parameters dictionary
*/
public PatchActionInsert(Series series, MiniBox parameters) {
int maxRadius = ((PatchSeries) series).radius;
-
+
// Set loaded parameters.
timeDelay = parameters.getInt("TIME_DELAY");
insertRadius = Math.min(maxRadius, parameters.getInt("INSERT_RADIUS"));
insertDepth = ((PatchSeries) series).depth;
insertNumber = parameters.getInt("INSERT_NUMBER");
-
+
// Initialize population register.
populations = new ArrayList<>();
}
-
+
@Override
public void schedule(Schedule schedule) {
schedule.scheduleOnce(timeDelay, Ordering.ACTIONS.ordinal(), this);
}
-
+
@Override
public void register(Simulation sim, String population) {
populations.add(sim.getSeries().populations.get(population));
}
-
+
@Override
public void step(SimState simstate) {
PatchSimulation sim = (PatchSimulation) simstate;
PatchGrid grid = (PatchGrid) sim.getGrid();
-
+
// Select valid coordinates to insert into and shuffle.
ArrayList
- *
*
- * @param series the simulation series
- * @param parameters the component parameters dictionary
+ * @param series the simulation series
+ * @param parameters the component parameters dictionary
*/
public PatchActionRemove(Series series, MiniBox parameters) {
// Set loaded parameters.
@@ -55,32 +53,32 @@ public PatchActionRemove(Series series, MiniBox parameters) {
removeRadius = parameters.getInt("REMOVE_RADIUS");
removeDepth = ((PatchSeries) series).depth;
}
-
+
@Override
public void schedule(Schedule schedule) {
schedule.scheduleOnce(timeDelay, Ordering.ACTIONS.ordinal(), this);
}
-
+
@Override
- public void register(Simulation sim, String population) { }
-
+ public void register(Simulation sim, String population) {}
+
@Override
public void step(SimState simstate) {
PatchSimulation sim = (PatchSimulation) simstate;
PatchGrid grid = (PatchGrid) sim.getGrid();
-
+
// Select valid coordinates to remove from.
ArrayList
- *
- *
- *
*
- * @param id the cell ID
- * @param parent the parent ID
- * @param pop the cell population index
- * @param state the cell state
- * @param age the cell age
- * @param divisions the number of cell divisions
- * @param location the {@link Location} of the cell
- * @param parameters the dictionary of parameters
- * @param volume the cell volume
- * @param height the cell height
- * @param criticalVolume the critical cell volume
- * @param criticalHeight the critical cell height
+ * @param container the cell container
+ * @param location the {@link Location} of the cell
+ * @param parameters the cell parameters
+ * @param links the map of population links
*/
- public PatchCell(int id, int parent, int pop, CellState state, int age, int divisions,
- Location location, MiniBox parameters, double volume, double height,
- double criticalVolume, double criticalHeight) {
- this.id = id;
- this.parent = parent;
- this.pop = pop;
- this.age = age;
+ 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 = divisions;
+ this.divisions = container.divisions;
this.location = (PatchLocation) location;
- this.volume = volume;
- this.height = height;
- this.criticalVolume = criticalVolume;
- this.criticalHeight = criticalHeight;
+ this.volume = container.volume;
+ this.height = container.height;
+ this.criticalVolume = container.criticalVolume;
+ this.criticalHeight = container.criticalHeight;
this.flag = Flag.UNDEFINED;
this.parameters = parameters;
-
- setState(state);
-
+ this.links = links;
+
+ setState(container.state);
+
// Set loaded parameters.
- heterogeneity = parameters.getDouble("HETEROGENEITY");
necroticFraction = parameters.getDouble("NECROTIC_FRACTION");
senescentFraction = parameters.getDouble("SENESCENT_FRACTION");
energyThreshold = -parameters.getDouble("ENERGY_THRESHOLD");
-
- // TODO: implement heterogeneity
-
+
// Add cell processes.
processes = new HashMap<>();
MiniBox processBox = parameters.filter("(PROCESS)");
@@ -190,85 +176,123 @@ public PatchCell(int id, int parent, int pop, CellState state, int age, int divi
processes.put(domain, process);
}
}
-
+
@Override
- public int getID() { return id; }
-
+ public int getID() {
+ return id;
+ }
+
@Override
- public int getParent() { return parent; }
-
+ public int getParent() {
+ return parent;
+ }
+
@Override
- public int getPop() { return pop; }
-
+ public int getPop() {
+ return pop;
+ }
+
@Override
- public CellState getState() { return state; }
-
+ public CellState getState() {
+ return state;
+ }
+
@Override
- public int getAge() { return age; }
-
+ public int getAge() {
+ return age;
+ }
+
@Override
- public int getDivisions() { return divisions; }
-
+ public int getDivisions() {
+ return divisions;
+ }
+
@Override
- public Location getLocation() { return location; }
-
+ public Location getLocation() {
+ return location;
+ }
+
@Override
- public Module getModule() { return module; }
-
+ public Module getModule() {
+ return module;
+ }
+
@Override
- public Process getProcess(ProcessDomain domain) { return processes.get(domain); }
-
+ public Process getProcess(ProcessDomain domain) {
+ return processes.get(domain);
+ }
+
@Override
- public MiniBox getParameters() { return parameters; }
-
+ public Parameters getParameters() {
+ return parameters;
+ }
+
@Override
- public double getVolume() { return volume; }
-
+ public double getVolume() {
+ return volume;
+ }
+
@Override
- public double getHeight() { return height; }
-
+ public double getHeight() {
+ return height;
+ }
+
@Override
- public double getCriticalVolume() { return criticalVolume; }
-
+ public double getCriticalVolume() {
+ return criticalVolume;
+ }
+
@Override
- public double getCriticalHeight() { return criticalHeight; }
-
+ public double getCriticalHeight() {
+ return criticalHeight;
+ }
+
/**
* Gets the cell energy level.
*
- * @return the energy level
+ * @return the energy level
*/
- public double getEnergy() { return energy; }
-
+ public double getEnergy() {
+ return energy;
+ }
+
/**
* Sets the cell flag.
*
- * @param flag the target cell flag
+ * @param flag the target cell flag
*/
- public void setFlag(Flag flag) { this.flag = flag; }
-
+ public void setFlag(Flag flag) {
+ this.flag = flag;
+ }
+
/**
* Sets the cell volume.
*
- * @param volume the target cell volume
+ * @param volume the target cell volume
*/
- public void setVolume(double volume) { this.volume = volume; }
-
+ public void setVolume(double volume) {
+ this.volume = volume;
+ }
+
/**
* Sets the cell energy level.
*
- * @param energy the target energy level
+ * @param energy the target energy level
*/
- public void setEnergy(double energy) { this.energy = energy; }
-
+ public void setEnergy(double energy) {
+ this.energy = energy;
+ }
+
@Override
- public void stop() { stopper.stop(); }
-
+ public void stop() {
+ stopper.stop();
+ }
+
@Override
public void setState(CellState state) {
this.state = state;
this.flag = Flag.UNDEFINED;
-
+
switch ((State) state) {
case PROLIFERATIVE:
module = new PatchModuleProliferation(this);
@@ -284,13 +308,13 @@ public void setState(CellState state) {
break;
}
}
-
+
/**
* Makes the specified {@link Process} object.
*
- * @param domain the process domain
- * @param version the process version
- * @return the process instance
+ * @param domain the process domain
+ * @param version the process version
+ * @return the process instance
*/
public Process makeProcess(ProcessDomain domain, String version) {
switch ((Domain) domain) {
@@ -303,24 +327,24 @@ public Process makeProcess(ProcessDomain domain, String version) {
return null;
}
}
-
+
@Override
public void schedule(Schedule schedule) {
stopper = schedule.scheduleRepeating(this, Ordering.CELLS.ordinal(), 1);
}
-
+
@Override
public void step(SimState simstate) {
Simulation sim = (Simulation) simstate;
-
+
// Increase age of cell.
age++;
-
+
// TODO: check for death due to age
-
+
// Step metabolism process.
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) {
@@ -334,10 +358,10 @@ public void step(SimState simstate) {
setState(State.QUIESCENT);
}
}
-
+
// Step signaling network process.
processes.get(Domain.SIGNALING).step(simstate.random, sim);
-
+
// Change state from undefined.
if (state == State.UNDEFINED) {
if (flag == Flag.MIGRATORY) {
@@ -352,24 +376,33 @@ public void step(SimState simstate) {
setState(State.PROLIFERATIVE);
}
}
-
+
// Step the module for the cell state.
if (module != null) {
module.step(simstate.random, sim);
}
}
-
+
@Override
public CellContainer convert() {
- return new PatchCellContainer(id, parent, pop, age, divisions, state,
- volume, height, criticalVolume, criticalHeight);
+ return new PatchCellContainer(
+ id,
+ parent,
+ pop,
+ age,
+ divisions,
+ state,
+ volume,
+ height,
+ criticalVolume,
+ criticalHeight);
}
-
+
/**
* Calculates the total volume of {@code Cell} objects in a {@code Bag}.
*
- * @param bag the {@code Bag} containing cell objects
- * @return the total volume
+ * @param bag the {@code Bag} containing cell objects
+ * @return the total volume
*/
public static double calculateTotalVolume(Bag bag) {
double totalVolume = 0;
@@ -378,24 +411,27 @@ public static double calculateTotalVolume(Bag bag) {
}
return totalVolume;
}
-
+
/**
* Find free locations in the patch neighborhood.
*
- * @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 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
*/
- static Bag findFreeLocations(Simulation sim, PatchLocation currentLocation,
- double targetVolume, double targetHeight) {
+ 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.
@@ -403,61 +439,64 @@ static Bag findFreeLocations(Simulation sim, PatchLocation currentLocation,
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
+ 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;
}
}
-
+
// TODO: ADD CHECK FOR MORE THAN ONE HEALTHY CELL AGENT.
-
+
// Add location to list of free locations.
freeLocations.add(neighborLocation);
}
}
-
+
// TODO: ADD CURRENT LOCATION
-
+
return freeLocations;
}
-
+
/**
* Selects the best location for a cell to be added or move into.
- *
- *
*/
-
public class PatchCellCancer extends PatchCellTissue {
/**
- * Creates a tissue {@code PatchCell} agent.
+ * Creates a cancer {@code PatchCell} agent.
*
- * @param id the cell ID
- * @param parent the parent ID
- * @param pop the cell population index
- * @param state the cell state
- * @param age the cell age
- * @param divisions the number of cell divisions
- * @param location the {@link Location} of the cell
- * @param parameters the dictionary of parameters
- * @param volume the cell volume
- * @param height the cell height
- * @param criticalVolume the critical cell volume
- * @param criticalHeight the critical cell height
+ * @param container the cell container
+ * @param location the {@link Location} of the cell
+ * @param parameters the dictionary of parameters
*/
- public PatchCellCancer(int id, int parent, int pop, CellState state, int age, int divisions,
- Location location, MiniBox parameters, double volume, double height,
- double criticalVolume, double criticalHeight) {
- super(id, parent, pop, state, age, divisions, location, parameters,
- volume, height, criticalVolume, criticalHeight);
+ public PatchCellCancer(PatchCellContainer container, Location location, Parameters parameters) {
+ this(container, location, parameters, null);
}
-
+
+ /**
+ * Creates a cancer {@code PatchCell} agent with population links.
+ *
+ * @param container the cell container
+ * @param location the {@link Location} of the cell
+ * @param parameters the dictionary of parameters
+ * @param links the map of population links
+ */
+ public PatchCellCancer(
+ PatchCellContainer container, Location location, Parameters parameters, GrabBag links) {
+ super(container, location, parameters, links);
+ }
+
/**
* {@inheritDoc}
- *
- *
*/
-
public class PatchCellCancerStem extends PatchCellCancer {
- /** Fraction of divisions that are symmetric. */
- private final double symmetricFraction;
-
/**
- * Creates a tissue {@code PatchCell} agent.
- *
- *
+ * Creates a cancer stem {@code PatchCell} agent.
*
- * @param id the cell ID
- * @param parent the parent ID
- * @param pop the cell population index
- * @param state the cell state
- * @param age the cell age
- * @param divisions the number of cell divisions
- * @param location the {@link Location} of the cell
- * @param parameters the dictionary of parameters
- * @param volume the cell volume
- * @param height the cell height
- * @param criticalVolume the critical cell volume
- * @param criticalHeight the critical cell height
+ * @param container the cell container
+ * @param location the {@link Location} of the cell
+ * @param parameters the dictionary of parameters
*/
- public PatchCellCancerStem(int id, int parent, int pop, CellState state, int age, int divisions,
- Location location, MiniBox parameters, double volume, double height,
- double criticalVolume, double criticalHeight) {
- super(id, parent, pop, state, age, divisions, location, parameters,
- volume, height, criticalVolume, criticalHeight);
-
- // Set loaded parameters.
- symmetricFraction = parameters.getDouble("SYMMETRIC_FRACTION");
-
+ public PatchCellCancerStem(
+ PatchCellContainer container, Location location, Parameters parameters) {
+ this(container, location, parameters, null);
+ }
+
+ /**
+ * Creates a cancer stem {@code PatchCell} agent with population links.
+ *
+ * @param container the cell container
+ * @param location the {@link Location} of the cell
+ * @param parameters the dictionary of parameters
+ * @param links the map of population links
+ */
+ public PatchCellCancerStem(
+ PatchCellContainer container, Location location, Parameters parameters, GrabBag links) {
+ super(container, location, parameters, links);
+
// TODO: set death age
}
-
+
/**
* {@inheritDoc}
- *
- *
+ * Parses population settings into maps from population to parameter value.
*
- * @param series the simulation series
+ * @param series the simulation series
*/
void parseValues(Series series) {
Set
- *
*
- * @param cell the {@link PatchCell} the module is associated with
+ * @param cell the {@link PatchCell} the module is associated with
*/
public PatchModuleApoptosis(PatchCell cell) {
super(cell);
-
+
// Set loaded parameters.
- MiniBox parameters = cell.getParameters();
+ Parameters parameters = cell.getParameters();
deathDuration = parameters.getInt("apoptosis/DEATH_DURATION");
}
-
+
@Override
public void step(MersenneTwisterFast random, Simulation sim) {
if (ticker > deathDuration) {
@@ -56,7 +55,7 @@ public void step(MersenneTwisterFast random, Simulation sim) {
break;
}
}
-
+
// Remove current cell from simulation and schedule.
sim.getGrid().removeObject(cell, location);
cell.stop();
diff --git a/src/arcade/patch/agent/module/PatchModuleMigration.java b/src/arcade/patch/agent/module/PatchModuleMigration.java
index 84d6b6841..21491a620 100644
--- a/src/arcade/patch/agent/module/PatchModuleMigration.java
+++ b/src/arcade/patch/agent/module/PatchModuleMigration.java
@@ -2,61 +2,61 @@
import ec.util.MersenneTwisterFast;
import arcade.core.sim.Simulation;
-import arcade.core.util.MiniBox;
+import arcade.core.util.Parameters;
import arcade.patch.agent.cell.PatchCell;
import arcade.patch.env.location.PatchLocation;
import static arcade.patch.util.PatchEnums.State;
/**
* Extension of {@link PatchModule} for migration.
- *
- *
*
- * @param cell the {@link PatchCell} the module is associated with
+ * @param cell the {@link PatchCell} the module is associated with
*/
public PatchModuleMigration(PatchCell cell) {
super(cell);
-
+
// Set loaded parameters.
- MiniBox parameters = cell.getParameters();
+ Parameters parameters = cell.getParameters();
migrationRate = parameters.getDouble("migration/MIGRATION_RATE");
movementDuration = Math.round(location.getCoordinateSize() / migrationRate);
}
-
+
@Override
public void step(MersenneTwisterFast random, Simulation sim) {
if (ticker > movementDuration) {
- PatchLocation newLocation = PatchCell.selectBestLocation(sim, location,
- cell.getVolume(), cell.getCriticalHeight(), random);
-
+ PatchLocation newLocation =
+ PatchCell.selectBestLocation(
+ sim, location, cell.getVolume(), cell.getCriticalHeight(), random);
+
if (newLocation == null) {
cell.setState(State.QUIESCENT);
} else {
if (!location.equals(newLocation)) {
sim.getGrid().moveObject(cell, location, newLocation);
-
+
// TODO: Update environment generator sites.
}
cell.setState(State.UNDEFINED);
diff --git a/src/arcade/patch/agent/module/PatchModuleProliferation.java b/src/arcade/patch/agent/module/PatchModuleProliferation.java
index 70932814d..31e12e652 100644
--- a/src/arcade/patch/agent/module/PatchModuleProliferation.java
+++ b/src/arcade/patch/agent/module/PatchModuleProliferation.java
@@ -2,8 +2,9 @@
import sim.util.Bag;
import ec.util.MersenneTwisterFast;
+import arcade.core.agent.cell.CellContainer;
import arcade.core.sim.Simulation;
-import arcade.core.util.MiniBox;
+import arcade.core.util.Parameters;
import arcade.patch.agent.cell.PatchCell;
import arcade.patch.agent.process.PatchProcess;
import arcade.patch.env.grid.PatchGrid;
@@ -13,55 +14,54 @@
/**
* Extension of {@link PatchModule} for proliferation.
- *
- *
*
- * @param cell the {@link PatchCell} the module is associated with
+ * @param cell the {@link PatchCell} the module is associated with
*/
public PatchModuleProliferation(PatchCell cell) {
super(cell);
-
+
// Calculate thresholds.
targetVolume = 2 * cell.getCriticalVolume();
maxHeight = cell.getCriticalHeight();
-
+
// Set loaded parameters.
- MiniBox parameters = cell.getParameters();
+ Parameters parameters = cell.getParameters();
synthesisDuration = parameters.getInt("proliferation/SYNTHESIS_DURATION");
}
-
+
@Override
public void step(MersenneTwisterFast random, Simulation sim) {
Bag bag = ((PatchGrid) sim.getGrid()).getObjectsAtLocation(location);
double totalVolume = PatchCell.calculateTotalVolume(bag);
double currentHeight = totalVolume / location.getArea();
-
+
// Check if cell is no longer able to proliferate due to (i) other
// condition that has caused its type to no longer be proliferative,
// (ii) cell no longer exists at a tolerable height, or (iii) no
@@ -70,25 +70,32 @@ public void step(MersenneTwisterFast random, Simulation sim) {
if (currentHeight > maxHeight) {
cell.setState(State.QUIESCENT);
} else {
- PatchLocation newLocation = PatchCell.selectBestLocation(sim, location,
- cell.getVolume() * 0.5, maxHeight, random);
-
+ PatchLocation newLocation =
+ PatchCell.selectBestLocation(
+ sim, location, cell.getVolume() * 0.5, maxHeight, random);
+
if (newLocation == null) {
cell.setState(State.QUIESCENT);
} else if (cell.getVolume() >= targetVolume) {
if (ticker > synthesisDuration) {
// TODO: ADD CYCLE TIME TO TRACKER.
-
+
// Reset current cell.
cell.setState(State.UNDEFINED);
-
+
// Create and schedule new cell.
int newID = sim.getID();
- PatchCell newCell = (PatchCell) cell.make(newID, State.UNDEFINED,
- newLocation, random);
+ CellContainer newContainer = cell.make(newID, State.UNDEFINED, random);
+ PatchCell newCell =
+ (PatchCell)
+ newContainer.convert(
+ sim.getCellFactory(),
+ newLocation,
+ random,
+ cell.getParameters());
sim.getGrid().addObject(newCell, newLocation);
newCell.schedule(sim.getSchedule());
-
+
// Update cell volume and energy based on split.
double split = (random.nextDouble() / 10 + 0.45);
double volume = cell.getVolume();
@@ -97,13 +104,13 @@ public void step(MersenneTwisterFast random, Simulation sim) {
cell.setEnergy(energy * split);
newCell.setVolume(volume * (1 - split));
newCell.setEnergy(energy * (1 - split));
-
+
// Update processes.
PatchProcess metabolism = (PatchProcess) newCell.getProcess(Domain.METABOLISM);
metabolism.update(cell.getProcess(Domain.METABOLISM));
PatchProcess signaling = (PatchProcess) newCell.getProcess(Domain.SIGNALING);
signaling.update(cell.getProcess(Domain.SIGNALING));
-
+
// TODO: Update environment generator sites.
} else {
ticker++;
diff --git a/src/arcade/patch/agent/process/PatchProcess.java b/src/arcade/patch/agent/process/PatchProcess.java
index c39131763..589b996e3 100644
--- a/src/arcade/patch/agent/process/PatchProcess.java
+++ b/src/arcade/patch/agent/process/PatchProcess.java
@@ -6,31 +6,30 @@
/**
* Abstract implementation of {@link Process} for {@link PatchCell} agents.
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
*
- * @param cell the {@link PatchCell} the process is associated with
+ * @param cell the {@link PatchCell} the process is associated with
*/
public PatchProcessMetabolismComplex(PatchCell cell) {
super(cell);
-
+
// Initial internal concentrations.
intAmts = new double[2];
intAmts[GLUCOSE] = extAmts[GLUCOSE];
intAmts[PYRUVATE] = extAmts[GLUCOSE] * PYRU_PER_GLUC;
-
+
// Mapping for internal concentration access.
String[] intNames = new String[2];
intNames[GLUCOSE] = "glucose";
intNames[PYRUVATE] = "pyruvate";
names = Arrays.asList(intNames);
-
+
// Set loaded parameters.
- // TODO: pull metabolic preference from distribution
- MiniBox parameters = cell.getParameters();
+ Parameters parameters = cell.getParameters();
metabolicPreference = parameters.getDouble("metabolism/METABOLIC_PREFERENCE");
conversionFraction = parameters.getDouble("metabolism/CONVERSION_FRACTION");
minimumMassFraction = parameters.getDouble("metabolism/MINIMUM_MASS_FRACTION");
@@ -107,14 +102,14 @@ public PatchProcessMetabolismComplex(PatchCell cell) {
autophagyRate = parameters.getDouble("metabolism/AUTOPHAGY_RATE");
glucoseUptakeRate = parameters.getDouble("metabolism/GLUCOSE_UPTAKE_RATE");
}
-
+
@Override
void stepProcess(MersenneTwisterFast random, Simulation sim) {
- double glucInt = intAmts[GLUCOSE]; // [fmol]
+ double glucInt = intAmts[GLUCOSE]; // [fmol]
double pyruInt = intAmts[PYRUVATE]; // [fmol]
- double glucExt = extAmts[GLUCOSE]; // [fmol]
- double oxyExt = extAmts[OXYGEN]; // [fmol]
-
+ double glucExt = extAmts[GLUCOSE]; // [fmol]
+ double oxyExt = extAmts[OXYGEN]; // [fmol]
+
// Take up glucose from environment, relative to glucose gradient.
// If agent shares location with other agents, occupied area for
// calculating surface area is limited by the number of neighbors.
@@ -124,19 +119,19 @@ void stepProcess(MersenneTwisterFast random, Simulation sim) {
glucGrad *= glucGrad < 1E-10 ? 0 : 1;
double glucUptake = glucoseUptakeRate * surfaceArea * glucGrad;
glucInt += glucUptake;
-
+
// Determine energy requirement given current type in terms of glucose.
// Additional energy needed for cell that is migrating or proliferating.
// Arrays indicate oxidative phosphorylation (0) and glycolysis (1).
- double[] energyGen = { 0, 0 };
+ double[] energyGen = {0, 0};
double glucReq = metabolicPreference * energyReq / ENERGY_FROM_GLYC;
double pyruReq = (1 - metabolicPreference) * energyReq / ENERGY_FROM_OXPHOS;
-
+
// Calculate oxygen required and take up from environment.
double oxyReq = pyruReq * OXY_PER_PYRU;
double oxyUptake = Math.min(oxyExt, oxyReq);
oxyUptake *= oxyUptake < 1E-10 ? 0 : 1;
-
+
// Perform oxidative phosphorylation using internal pyruvate.
double oxyUptakeInPyru = oxyUptake / OXY_PER_PYRU;
if (pyruInt > oxyUptakeInPyru) {
@@ -147,14 +142,14 @@ void stepProcess(MersenneTwisterFast random, Simulation sim) {
oxyUptake = pyruInt * OXY_PER_PYRU; // return unused oxygen
pyruInt = 0.0; // use up internal pyruvate
}
-
+
// Check if more glucose needs to be diverted to compensate for energy
// deficit (from not enough oxygen) and is available.
if (energy <= 0 && glucInt > 0) {
double glucNeeded = -(energy - energyCons + energyGen[0]) / ENERGY_FROM_GLYC;
glucReq = Math.max(glucReq, glucNeeded);
}
-
+
// Perform glycolysis. Internal glucose is converted to internal pyruvate
// which is used in oxidative phosphorylation or to increase mass.
if (glucInt > glucReq) {
@@ -166,23 +161,26 @@ void stepProcess(MersenneTwisterFast random, Simulation sim) {
pyruInt += glucInt * PYRU_PER_GLUC; // increase internal pyruvate
glucInt = 0.0; // use up all internal glucose
}
-
+
// Update energy.
energy += energyGen[0];
energy += energyGen[1];
energy -= energyCons;
energy *= Math.abs(energy) < 1E-10 ? 0 : 1;
-
+
// Increase mass if (i) dividing and less than double mass or (ii)
// below critical mass for maintenance.
if ((energy >= 0 && isProliferative && mass < 2 * critMass)
|| (energy >= 0 && mass < 0.99 * critMass)) {
- mass += conversionFraction * (ratioGlucosePyruvate * glucInt
- + (1 - ratioGlucosePyruvate) * pyruInt / PYRU_PER_GLUC) / ratioGlucoseBiomass;
+ mass +=
+ conversionFraction
+ * (ratioGlucosePyruvate * glucInt
+ + (1 - ratioGlucosePyruvate) * pyruInt / PYRU_PER_GLUC)
+ / ratioGlucoseBiomass;
glucInt *= (1 - conversionFraction * ratioGlucosePyruvate);
pyruInt *= (1 - conversionFraction * (1 - ratioGlucosePyruvate));
}
-
+
// Decrease mass through autophagy if (i) negative energy indicating
// not enough nutrients or (ii) above critical mass for maintenance
if ((energy < 0 && mass > minimumMassFraction * critMass)
@@ -190,32 +188,32 @@ void stepProcess(MersenneTwisterFast random, Simulation sim) {
mass -= autophagyRate;
glucInt += autophagyRate * ratioGlucoseBiomass;
}
-
+
// Update volume based on changes in mass.
volume = mass / cellDensity;
-
+
// Convert internal pyruvate to lactate (i.e. remove pyruvate).
pyruInt -= lactateRate * pyruInt;
-
+
// Reset values.
intAmts[GLUCOSE] = glucInt;
upAmts[GLUCOSE] = glucUptake;
upAmts[OXYGEN] = oxyUptake;
intAmts[PYRUVATE] = pyruInt;
}
-
+
@Override
public void update(Process process) {
PatchProcessMetabolismComplex metabolism = (PatchProcessMetabolismComplex) process;
double split = this.cell.getVolume() / this.volume;
-
+
// Update this process as split of given process.
this.volume = this.cell.getVolume();
this.energy = this.cell.getEnergy();
this.mass = this.volume * cellDensity;
this.intAmts[GLUCOSE] = metabolism.intAmts[GLUCOSE] * split;
this.intAmts[PYRUVATE] = metabolism.intAmts[PYRUVATE] * split;
-
+
// Update given process with remaining split.
metabolism.volume = metabolism.cell.getVolume();
metabolism.energy = metabolism.cell.getEnergy();
diff --git a/src/arcade/patch/agent/process/PatchProcessMetabolismMedium.java b/src/arcade/patch/agent/process/PatchProcessMetabolismMedium.java
index 974eacdc6..40c795b48 100644
--- a/src/arcade/patch/agent/process/PatchProcessMetabolismMedium.java
+++ b/src/arcade/patch/agent/process/PatchProcessMetabolismMedium.java
@@ -4,116 +4,114 @@
import ec.util.MersenneTwisterFast;
import arcade.core.agent.process.Process;
import arcade.core.sim.Simulation;
-import arcade.core.util.MiniBox;
+import arcade.core.util.Parameters;
import arcade.patch.agent.cell.PatchCell;
/**
* Extension of {@link PatchProcessMetabolism} for medium metabolism.
- *
- *
- *
- *
*/
-
public class PatchProcessMetabolismMedium extends PatchProcessMetabolism {
/** Preference for glycolysis over oxidative phosphorylation. */
private final double metabolicPreference;
-
+
/** Fraction of internal glucose/pyruvate converted to mass. */
private final double conversionFraction;
-
+
/** Minimum viable cell mass fraction. */
private final double minimumMassFraction;
-
+
/** Rate of autophagy [ng/min]. */
private final double autophagyRate;
-
+
/** Rate of ATP production [fmol ATP/um3/min/M glucose]. */
private final double atpProductionRate;
-
+
/**
- * Creates a medium metabolism {@code Process} for the given
- * {@link PatchCell}.
- *
- *
*
- * @param cell the {@link PatchCell} the process is associated with
+ * @param cell the {@link PatchCell} the process is associated with
*/
public PatchProcessMetabolismMedium(PatchCell cell) {
super(cell);
-
+
// Initial internal concentrations.
intAmts = new double[1];
intAmts[GLUCOSE] = extAmts[GLUCOSE];
-
+
// Mapping for internal concentration access.
String[] intNames = new String[1];
intNames[GLUCOSE] = "glucose";
names = Arrays.asList(intNames);
-
+
// Set loaded parameters.
- // TODO: pull metabolic preference from distribution
- MiniBox parameters = cell.getParameters();
+ Parameters parameters = cell.getParameters();
metabolicPreference = parameters.getDouble("metabolism/METABOLIC_PREFERENCE");
conversionFraction = parameters.getDouble("metabolism/CONVERSION_FRACTION");
minimumMassFraction = parameters.getDouble("metabolism/MINIMUM_MASS_FRACTION");
autophagyRate = parameters.getDouble("metabolism/AUTOPHAGY_RATE");
atpProductionRate = parameters.getDouble("metabolism/ATP_PRODUCTION_RATE");
}
-
+
@Override
public void stepProcess(MersenneTwisterFast random, Simulation sim) {
double glucInt = intAmts[GLUCOSE]; // [fmol]
double glucExt = extAmts[GLUCOSE]; // [fmol]
- double oxyExt = extAmts[OXYGEN]; // [fmol]
-
+ double oxyExt = extAmts[OXYGEN]; // [fmol]
+
// Calculate glucose uptake and update internal glucose.
- double atpPerGlucose = (int) (metabolicPreference * ENERGY_FROM_GLYC
- + (1 - metabolicPreference) * ENERGY_FROM_OXPHOS * PYRU_PER_GLUC);
+ double atpPerGlucose =
+ (int)
+ (metabolicPreference * ENERGY_FROM_GLYC
+ + (1 - metabolicPreference) * ENERGY_FROM_OXPHOS * PYRU_PER_GLUC);
double glucGrad = (glucExt / location.getVolume()) - (glucInt / volume);
glucGrad *= glucGrad < 1E-10 ? 0 : 1;
double glucUptake = atpProductionRate * volume * glucGrad / atpPerGlucose;
glucInt += glucUptake;
-
+
// Calculate amount of glucose required.
double energyGen = 0;
double glucReqGlyc = energyReq * metabolicPreference / ENERGY_FROM_GLYC;
- double glucReqOxphos = energyReq * (1 - metabolicPreference) / ENERGY_FROM_OXPHOS
- / PYRU_PER_GLUC;
-
+ double glucReqOxphos =
+ energyReq * (1 - metabolicPreference) / ENERGY_FROM_OXPHOS / PYRU_PER_GLUC;
+
// Calculate oxygen required and take up from environment.
double oxyReq = glucReqOxphos * PYRU_PER_GLUC * OXY_PER_PYRU;
double oxyUptake = Math.min(oxyExt, oxyReq);
oxyUptake *= oxyUptake < 1E-10 ? 0 : 1;
-
+
// Generate energy from oxidative phosphorylation.
double oxyUptakeInGluc = oxyUptake / OXY_PER_PYRU / PYRU_PER_GLUC;
if (glucInt > oxyUptakeInGluc) {
@@ -124,14 +122,14 @@ public void stepProcess(MersenneTwisterFast random, Simulation sim) {
oxyUptake = glucInt * OXY_PER_PYRU * PYRU_PER_GLUC;
glucInt = 0.0;
}
-
+
// Check if more glucose needs to be diverted to compensate for energy
// deficit (from not enough oxygen) and is available.
if (energy <= 0 && glucInt > 0) {
double glucNeeded = -(energy - energyCons + energyGen) / ENERGY_FROM_GLYC;
glucReqGlyc = Math.max(glucReqGlyc, glucNeeded);
}
-
+
// Generate energy from glycolysis.
if (glucInt > glucReqGlyc) {
energyGen += glucReqGlyc * ENERGY_FROM_GLYC;
@@ -140,12 +138,12 @@ public void stepProcess(MersenneTwisterFast random, Simulation sim) {
energyGen += glucInt * ENERGY_FROM_GLYC;
glucInt = 0;
}
-
+
// Update energy.
energy += energyGen;
energy -= energyCons;
energy *= Math.abs(energy) < 1E-10 ? 0 : 1;
-
+
// Increase mass if (i) dividing and less than double mass or (ii)
// below critical mass for maintenance.
if ((energy >= 0 && isProliferative && mass < 2 * critMass)
@@ -153,7 +151,7 @@ public void stepProcess(MersenneTwisterFast random, Simulation sim) {
mass += conversionFraction * glucInt / ratioGlucoseBiomass;
glucInt *= (1 - conversionFraction);
}
-
+
// Decrease mass through autophagy if (i) negative energy indicating
// not enough nutrients or (ii) above critical mass for maintenance
if ((energy < 0 && mass > minimumMassFraction * critMass)
@@ -161,27 +159,27 @@ public void stepProcess(MersenneTwisterFast random, Simulation sim) {
mass -= autophagyRate;
glucInt += autophagyRate * ratioGlucoseBiomass;
}
-
+
// Update volume based on changes in mass.
volume = mass / cellDensity;
-
+
// Reset values.
intAmts[GLUCOSE] = glucInt;
upAmts[GLUCOSE] = glucUptake;
upAmts[OXYGEN] = oxyUptake;
}
-
+
@Override
public void update(Process process) {
PatchProcessMetabolismMedium metabolism = (PatchProcessMetabolismMedium) process;
double split = this.cell.getVolume() / this.volume;
-
+
// Update this process as split of given process.
this.volume = this.cell.getVolume();
this.energy = this.cell.getEnergy();
this.mass = this.volume * cellDensity;
this.intAmts[GLUCOSE] = metabolism.intAmts[GLUCOSE] * split;
-
+
// Update given process with remaining split.
metabolism.volume = metabolism.cell.getVolume();
metabolism.energy = metabolism.cell.getEnergy();
diff --git a/src/arcade/patch/agent/process/PatchProcessMetabolismRandom.java b/src/arcade/patch/agent/process/PatchProcessMetabolismRandom.java
index 204bc16c8..6f56285da 100644
--- a/src/arcade/patch/agent/process/PatchProcessMetabolismRandom.java
+++ b/src/arcade/patch/agent/process/PatchProcessMetabolismRandom.java
@@ -4,98 +4,95 @@
import ec.util.MersenneTwisterFast;
import arcade.core.agent.process.Process;
import arcade.core.sim.Simulation;
-import arcade.core.util.MiniBox;
+import arcade.core.util.Parameters;
import arcade.patch.agent.cell.PatchCell;
/**
* Extension of {@link PatchProcessMetabolism} for random metabolism.
- *
- *
*
- * @param cell the {@link PatchCell} the process is associated with
+ * @param cell the {@link PatchCell} the process is associated with
*/
public PatchProcessMetabolismRandom(PatchCell cell) {
super(cell);
-
+
// Initial internal concentrations.
intAmts = new double[1];
intAmts[GLUCOSE] = extAmts[GLUCOSE];
-
+
// Mapping for internal concentration access.
String[] intNames = new String[1];
intNames[GLUCOSE] = "glucose";
names = Arrays.asList(intNames);
-
+
// Set loaded parameters.
- MiniBox parameters = cell.getParameters();
- averageCellVolume = parameters.getDouble("CELL_VOLUME_MEAN");
+ Parameters parameters = cell.getParameters();
+ averageCellVolume = parameters.getDouble("CELL_VOLUME");
}
-
+
@Override
public void stepProcess(MersenneTwisterFast random, Simulation sim) {
double glucInt = intAmts[GLUCOSE]; // [fmol]
double glucExt = extAmts[GLUCOSE]; // [fmol]
- double oxyExt = extAmts[OXYGEN]; // [fmol]
-
+ double oxyExt = extAmts[OXYGEN]; // [fmol]
+
// Randomly uptake some glucose and oxygen from environment.
double glucUptake = glucExt * (random.nextDouble() * GLUC_UPTAKE_DELTA + GLUC_UPTAKE_MIN);
double oxyUptake = oxyExt * (random.nextDouble() * OXY_UPTAKE_DELTA + OXY_UPTAKE_MIN);
glucInt += glucUptake;
-
+
// Determine energy requirement.
double energyGen = 0;
double glucFrac = random.nextDouble() * GLUC_FRAC_DELTA + GLUC_FRAC_MIN;
-
+
// Generate energy from oxidative phosphorylation.
double oxyUptakeInGluc = oxyUptake / OXY_PER_PYRU / PYRU_PER_GLUC;
if (glucInt > oxyUptakeInGluc) {
@@ -106,7 +103,7 @@ public void stepProcess(MersenneTwisterFast random, Simulation sim) {
oxyUptake = glucInt * OXY_PER_PYRU * PYRU_PER_GLUC;
glucInt = 0.0;
}
-
+
// Generate energy from glycolysis.
if (glucInt > glucFrac) {
energyGen += glucFrac * ENERGY_FROM_GLYC;
@@ -115,12 +112,12 @@ public void stepProcess(MersenneTwisterFast random, Simulation sim) {
energyGen += glucInt * ENERGY_FROM_GLYC;
glucInt = 0;
}
-
+
// Update energy.
energy += energyGen;
energy -= energyCons / volume * averageCellVolume;
energy *= Math.abs(energy) < 1E-10 ? 0 : 1;
-
+
// Randomly increase mass if dividing and less than double mass.
// Set doubled flag to true once double mass is reached. Cell agent
// checks for this switch and will complete proliferation.
@@ -129,27 +126,27 @@ public void stepProcess(MersenneTwisterFast random, Simulation sim) {
mass += growth / ratioGlucoseBiomass;
glucInt -= growth;
}
-
+
// Update volume based on changes in mass.
volume = mass / cellDensity;
-
+
// Reset values.
intAmts[GLUCOSE] = glucInt;
upAmts[GLUCOSE] = glucUptake;
upAmts[OXYGEN] = oxyUptake;
}
-
+
@Override
public void update(Process process) {
PatchProcessMetabolismSimple metabolism = (PatchProcessMetabolismSimple) process;
double split = this.cell.getVolume() / this.volume;
-
+
// Update this process as split of given process.
this.volume = this.cell.getVolume();
this.energy = this.cell.getEnergy();
this.mass = this.volume * cellDensity;
this.intAmts[GLUCOSE] = metabolism.intAmts[GLUCOSE] * split;
-
+
// Update given process with remaining split.
metabolism.volume = metabolism.cell.getVolume();
metabolism.energy = metabolism.cell.getEnergy();
diff --git a/src/arcade/patch/agent/process/PatchProcessMetabolismSimple.java b/src/arcade/patch/agent/process/PatchProcessMetabolismSimple.java
index 60a8a84c4..5cc84646c 100644
--- a/src/arcade/patch/agent/process/PatchProcessMetabolismSimple.java
+++ b/src/arcade/patch/agent/process/PatchProcessMetabolismSimple.java
@@ -4,103 +4,95 @@
import ec.util.MersenneTwisterFast;
import arcade.core.agent.process.Process;
import arcade.core.sim.Simulation;
-import arcade.core.util.MiniBox;
+import arcade.core.util.Parameters;
import arcade.patch.agent.cell.PatchCell;
/**
* Extension of {@link PatchProcessMetabolism} for simple metabolism.
- *
- *
*
- * @param cell the {@link PatchCell} the process is associated with
+ * @param cell the {@link PatchCell} the process is associated with
*/
public PatchProcessMetabolismSimple(PatchCell cell) {
super(cell);
-
+
// Initial internal concentrations.
intAmts = new double[1];
intAmts[GLUCOSE] = extAmts[GLUCOSE];
-
+
// Mapping for internal concentration access.
String[] intNames = new String[1];
intNames[GLUCOSE] = "glucose";
names = Arrays.asList(intNames);
-
+
// Set loaded parameters.
- // TODO: pull metabolic preference from distribution
- MiniBox parameters = cell.getParameters();
- averageCellVolume = parameters.getDouble("CELL_VOLUME_MEAN");
+ Parameters parameters = cell.getParameters();
+ averageCellVolume = parameters.getDouble("CELL_VOLUME");
metabolicPreference = parameters.getDouble("metabolism/METABOLIC_PREFERENCE");
glucoseUptakeRate = parameters.getDouble("metabolism/CONSTANT_GLUCOSE_UPTAKE_RATE");
atpProductionRate = parameters.getDouble("metabolism/CONSTANT_ATP_PRODUCTION_RATE");
volumeGrowthRate = parameters.getDouble("metabolism/CONSTANT_VOLUME_GROWTH_RATE");
}
-
+
@Override
public void stepProcess(MersenneTwisterFast random, Simulation sim) {
double glucInt = intAmts[GLUCOSE]; // [fmol]
double glucExt = extAmts[GLUCOSE]; // [fmol]
- double oxyExt = extAmts[OXYGEN]; // [fmol]
-
+ double oxyExt = extAmts[OXYGEN]; // [fmol]
+
// Calculate glucose uptake rate.
double glucGrad = (glucExt / location.getVolume()) - (glucInt / volume);
glucGrad *= glucGrad < 1E-10 ? 0 : 1;
double glucUptake = glucoseUptakeRate * glucGrad;
glucInt += glucUptake;
-
+
// Determine glucose requirement and calculate oxygen required.
double energyGen = 0;
- double glucoseRequiredGlycolysis = atpProductionRate * metabolicPreference
- / ENERGY_FROM_GLYC;
- double glucoseRequiredOxPhos = atpProductionRate * (1 - metabolicPreference)
- / ENERGY_FROM_OXPHOS / PYRU_PER_GLUC;
+ double glucoseRequiredGlycolysis =
+ atpProductionRate * metabolicPreference / ENERGY_FROM_GLYC;
+ double glucoseRequiredOxPhos =
+ atpProductionRate * (1 - metabolicPreference) / ENERGY_FROM_OXPHOS / PYRU_PER_GLUC;
double oxyReq = glucoseRequiredOxPhos * PYRU_PER_GLUC * OXY_PER_PYRU;
double oxyUptake = Math.min(oxyExt, oxyReq);
oxyUptake *= oxyUptake < 1E-10 ? 0 : 1;
-
+
// Generate energy from oxidative phosphorylation.
double oxyUptakeInGluc = oxyUptake / OXY_PER_PYRU / PYRU_PER_GLUC;
if (glucInt > oxyUptakeInGluc) {
@@ -111,7 +103,7 @@ public void stepProcess(MersenneTwisterFast random, Simulation sim) {
oxyUptake = glucInt * OXY_PER_PYRU * PYRU_PER_GLUC;
glucInt = 0.0;
}
-
+
// Generate energy from glycolysis.
if (glucInt > glucoseRequiredGlycolysis) {
energyGen += glucoseRequiredGlycolysis * ENERGY_FROM_GLYC;
@@ -120,39 +112,41 @@ public void stepProcess(MersenneTwisterFast random, Simulation sim) {
energyGen += glucInt * ENERGY_FROM_GLYC;
glucInt = 0;
}
-
+
// Update energy.
energy += energyGen;
energy -= energyCons / volume * averageCellVolume;
energy *= Math.abs(energy) < 1E-10 ? 0 : 1;
-
+
// Increase mass if dividing and less than double mass.
- if (energy >= 0 && isProliferative && mass < 2 * critMass
+ if (energy >= 0
+ && isProliferative
+ && mass < 2 * critMass
&& glucInt > cellDensity * volumeGrowthRate * ratioGlucoseBiomass) {
mass += cellDensity * volumeGrowthRate;
glucInt -= (cellDensity * volumeGrowthRate * ratioGlucoseBiomass);
}
-
+
// Update volume based on changes in mass.
volume = mass / cellDensity;
-
+
// Reset values.
intAmts[GLUCOSE] = glucInt;
upAmts[GLUCOSE] = glucUptake;
upAmts[OXYGEN] = oxyUptake;
}
-
+
@Override
public void update(Process process) {
PatchProcessMetabolismSimple metabolism = (PatchProcessMetabolismSimple) process;
double split = this.cell.getVolume() / this.volume;
-
+
// Update this process as split of given process.
this.volume = this.cell.getVolume();
this.energy = this.cell.getEnergy();
this.mass = this.volume * cellDensity;
this.intAmts[GLUCOSE] = metabolism.intAmts[GLUCOSE] * split;
-
+
// Update given process with remaining split.
metabolism.volume = metabolism.cell.getVolume();
metabolism.energy = metabolism.cell.getEnergy();
diff --git a/src/arcade/patch/agent/process/PatchProcessSignaling.java b/src/arcade/patch/agent/process/PatchProcessSignaling.java
index 302b0bb79..910cdf4e8 100644
--- a/src/arcade/patch/agent/process/PatchProcessSignaling.java
+++ b/src/arcade/patch/agent/process/PatchProcessSignaling.java
@@ -5,39 +5,38 @@
/**
* Implementation of {@link Process} for cell metabolism.
- *
- *
*
- * @param cell the {@link PatchCell} the process is associated with
+ * @param cell the {@link PatchCell} the process is associated with
*/
public PatchProcessSignalingComplex(PatchCell cell) {
super(cell);
-
+
// Initial concentrations, all in nM (umol/m^3). Most are zeros.
concs = new double[NUM_COMPONENTS];
concs[E_MEM] = MEMBRANE;
@@ -204,7 +201,7 @@ public PatchProcessSignalingComplex(PatchCell cell) {
concs[P_INACTIVE] = K13 / (K12 + K13) * PLCG;
concs[P_ACTIVE] = K12 / (K12 + K13) * PLCG;
concs[POOL] = NUCLEOTIDES;
-
+
// Molecule names.
names = new ArrayList<>();
names.add(G_INT, "glucose_internal");
@@ -220,82 +217,108 @@ public PatchProcessSignalingComplex(PatchCell cell) {
names.add(P_INACTIVE, "plcg_inactive");
names.add(P_ACTIVE, "plcg_active");
names.add(POOL, "nucleotide_pool");
-
+
// Set loaded parameters.
- // TODO: pull migratory threshold from distribution
- MiniBox parameters = cell.getParameters();
- migratoryThreshold = parameters.getDouble("metabolism/MIGRATORY_THRESHOLD");
+ Parameters parameters = cell.getParameters();
+ migratoryThreshold = parameters.getDouble("signaling/MIGRATORY_THRESHOLD");
}
-
+
/**
* System of ODEs for network.
- *
- *
*/
- Equations equations = (t, y) -> {
- // Calculate weighting factors.
- double wG = 1 + y[G_INT] / (WG + y[G_INT]);
- double wE = 1 - y[TE_MEM_P] / (WE + y[TE_MEM_P]);
- double wT = 1 + y[TE_MEM_P] / (WT + y[TE_MEM_P]);
- double wP = 1 + y[TE_MEM_P] / (WP + y[TE_MEM_P]);
- double wC = 1 + y[P_ACTIVE] / (WC + y[P_ACTIVE]);
-
- double[] dydt = new double[NUM_COMPONENTS];
-
- dydt[G_INT] = 0;
- dydt[T_EXT] = K_1 * y[TE_MEM] - K1 * y[T_EXT] * y[E_MEM] + K9 * y[T_CYTO] - K11 * y[T_EXT];
- dydt[E_MEM] = K_1 * y[TE_MEM] - K1 * y[T_EXT] * y[E_MEM] + K8 * y[E_CYTO] - K_8 * y[E_MEM]
- - K10 * y[E_MEM];
- dydt[TE_MEM] = 2 * K1 * y[T_EXT] * y[E_MEM] - 2 * K_1 * y[TE_MEM] - K2 * y[TE_MEM]
- * wG + K_2 * y[TE_MEM_P] * wC - K3 * y[TE_MEM];
- dydt[TE_MEM_P] = K2 * y[TE_MEM] * wG - K_2 * y[TE_MEM_P] * wC - K4 * y[TE_MEM_P];
- dydt[TE_CYTO] = K3 * y[TE_MEM] + K4 * y[TE_MEM_P] + 2 * K_5 * y[E_CYTO] * y[T_CYTO]
- - 2 * K5 * y[TE_CYTO];
- dydt[E_CYTO] = K5 * y[TE_CYTO] - K_5 * y[E_CYTO] * y[T_CYTO] + K14 * y[E_RNA]
- - K6 * y[E_CYTO] - K8 * y[E_CYTO] + K_8 * y[E_MEM];
- dydt[T_CYTO] = K5 * y[TE_CYTO] - K_5 * y[E_CYTO] * y[T_CYTO] + K15 * y[T_RNA]
- - K7 * y[T_CYTO] - K9 * y[T_CYTO];
- dydt[E_RNA] = K16 * y[POOL] * wE - K18 * y[E_RNA];
- dydt[T_RNA] = K17 * y[POOL] * wT - K19 * y[T_RNA];
- dydt[P_INACTIVE] = K13 * y[P_ACTIVE] - K12 * (PLCG - y[P_ACTIVE]) * wP;
- dydt[P_ACTIVE] = K12 * (PLCG - y[P_ACTIVE]) * wP - K13 * y[P_ACTIVE];
- dydt[POOL] = -K16 * y[POOL] * wE - K17 * y[POOL] * wT + K18 * y[E_RNA] + K19 * y[T_RNA];
-
- return dydt;
- };
-
+ Equations equations =
+ (t, y) -> {
+ // Calculate weighting factors.
+ double wG = 1 + y[G_INT] / (WG + y[G_INT]);
+ double wE = 1 - y[TE_MEM_P] / (WE + y[TE_MEM_P]);
+ double wT = 1 + y[TE_MEM_P] / (WT + y[TE_MEM_P]);
+ double wP = 1 + y[TE_MEM_P] / (WP + y[TE_MEM_P]);
+ double wC = 1 + y[P_ACTIVE] / (WC + y[P_ACTIVE]);
+
+ double[] dydt = new double[NUM_COMPONENTS];
+
+ dydt[G_INT] = 0;
+ dydt[T_EXT] =
+ K_1 * y[TE_MEM]
+ - K1 * y[T_EXT] * y[E_MEM]
+ + K9 * y[T_CYTO]
+ - K11 * y[T_EXT];
+ dydt[E_MEM] =
+ K_1 * y[TE_MEM]
+ - K1 * y[T_EXT] * y[E_MEM]
+ + K8 * y[E_CYTO]
+ - K_8 * y[E_MEM]
+ - K10 * y[E_MEM];
+ dydt[TE_MEM] =
+ 2 * K1 * y[T_EXT] * y[E_MEM]
+ - 2 * K_1 * y[TE_MEM]
+ - K2 * y[TE_MEM] * wG
+ + K_2 * y[TE_MEM_P] * wC
+ - K3 * y[TE_MEM];
+ dydt[TE_MEM_P] = K2 * y[TE_MEM] * wG - K_2 * y[TE_MEM_P] * wC - K4 * y[TE_MEM_P];
+ dydt[TE_CYTO] =
+ K3 * y[TE_MEM]
+ + K4 * y[TE_MEM_P]
+ + 2 * K_5 * y[E_CYTO] * y[T_CYTO]
+ - 2 * K5 * y[TE_CYTO];
+ dydt[E_CYTO] =
+ K5 * y[TE_CYTO]
+ - K_5 * y[E_CYTO] * y[T_CYTO]
+ + K14 * y[E_RNA]
+ - K6 * y[E_CYTO]
+ - K8 * y[E_CYTO]
+ + K_8 * y[E_MEM];
+ dydt[T_CYTO] =
+ K5 * y[TE_CYTO]
+ - K_5 * y[E_CYTO] * y[T_CYTO]
+ + K15 * y[T_RNA]
+ - K7 * y[T_CYTO]
+ - K9 * y[T_CYTO];
+ dydt[E_RNA] = K16 * y[POOL] * wE - K18 * y[E_RNA];
+ dydt[T_RNA] = K17 * y[POOL] * wT - K19 * y[T_RNA];
+ dydt[P_INACTIVE] = K13 * y[P_ACTIVE] - K12 * (PLCG - y[P_ACTIVE]) * wP;
+ dydt[P_ACTIVE] = K12 * (PLCG - y[P_ACTIVE]) * wP - K13 * y[P_ACTIVE];
+ dydt[POOL] =
+ -K16 * y[POOL] * wE - K17 * y[POOL] * wT + K18 * y[E_RNA] + K19 * y[T_RNA];
+
+ return dydt;
+ };
+
@Override
public void step(MersenneTwisterFast random, Simulation sim) {
// Get metabolism process from cell.
- PatchProcessMetabolism metabolism = (PatchProcessMetabolism)
- cell.getProcess(Domain.METABOLISM);
-
+ PatchProcessMetabolism metabolism =
+ (PatchProcessMetabolism) cell.getProcess(Domain.METABOLISM);
+
// Get concentration of external TGFa and internal glucose in nM.
concs[G_INT] = metabolism.intAmts[0] / cell.getVolume() * 1E9;
concs[T_EXT] = sim.getLattice("TGFA").getAverageValue(location) / TGFA_MW;
-
+
// Solve system of equations.
double pre = concs[P_ACTIVE];
concs = Solver.euler(equations, 0, concs, 60, STEP_SIZE);
double post = concs[P_ACTIVE];
-
+
// Calculate fold change and set migratory or proliferative flag.
current = ((pre > post ? pre / post : post / pre) - 1);
double delta = (current > previous ? current / previous : previous / current);
cell.setFlag(delta > migratoryThreshold ? Flag.MIGRATORY : Flag.PROLIFERATIVE);
previous = current;
-
+
// Update environment.
sim.getLattice("TGFA").setValue(location, concs[T_EXT] * TGFA_MW);
}
-
+
@Override
public void update(Process process) {
PatchProcessSignalingComplex signaling = (PatchProcessSignalingComplex) process;
diff --git a/src/arcade/patch/agent/process/PatchProcessSignalingMedium.java b/src/arcade/patch/agent/process/PatchProcessSignalingMedium.java
index 1617ca573..46d00e8d1 100644
--- a/src/arcade/patch/agent/process/PatchProcessSignalingMedium.java
+++ b/src/arcade/patch/agent/process/PatchProcessSignalingMedium.java
@@ -4,7 +4,7 @@
import ec.util.MersenneTwisterFast;
import arcade.core.agent.process.Process;
import arcade.core.sim.Simulation;
-import arcade.core.util.MiniBox;
+import arcade.core.util.Parameters;
import arcade.core.util.Solver;
import arcade.core.util.Solver.Equations;
import arcade.patch.agent.cell.PatchCell;
@@ -13,132 +13,129 @@
/**
* Extension of {@link PatchProcessSignaling} for medium EGFR signaling.
- *
- *
*
- * @param cell the {@link PatchCell} the process is associated with
+ * @param cell the {@link PatchCell} the process is associated with
*/
public PatchProcessSignalingMedium(PatchCell cell) {
super(cell);
-
+
// Initial concentrations, all in nM (umol/m^3). Most are zeros.
concs = new double[NUM_COMPONENTS];
concs[E_MEM] = MEMBRANE;
concs[P_INACTIVE] = K9 / (K8 + K9) * PLCG;
concs[P_ACTIVE] = K8 / (K8 + K9) * PLCG;
-
+
// Molecule names.
names = new ArrayList<>();
names.add(G_INT, "glucose_internal");
@@ -149,68 +146,73 @@ public PatchProcessSignalingMedium(PatchCell cell) {
names.add(TE_CYTO, "tgfa_egfr_cytoplasmic");
names.add(P_INACTIVE, "plcg_inactive");
names.add(P_ACTIVE, "plcg_active");
-
+
// Set loaded parameters.
- // TODO: pull migratory threshold from distribution
- MiniBox parameters = cell.getParameters();
- migratoryThreshold = parameters.getDouble("metabolism/MIGRATORY_THRESHOLD");
+ Parameters parameters = cell.getParameters();
+ migratoryThreshold = parameters.getDouble("signaling/MIGRATORY_THRESHOLD");
}
-
+
/**
* System of ODEs for network.
- *
- *
*/
- Equations equations = (t, y) -> {
- double wG = 1 + y[G_INT] / (WG + y[G_INT]);
- double wP = 1 + y[TE_MEM_P] / (WP + y[TE_MEM_P]);
- double wC = 1 + y[P_ACTIVE] / (WC + y[P_ACTIVE]);
-
- double[] dydt = new double[NUM_COMPONENTS];
-
- dydt[G_INT] = 0;
- dydt[T_EXT] = K_1 * y[TE_MEM] - K1 * y[T_EXT] * y[E_MEM] - K7 * y[T_EXT] + K11;
- dydt[E_MEM] = K_1 * y[TE_MEM] - K1 * y[T_EXT] * y[E_MEM] - K6 * y[E_MEM] + K10;
- dydt[TE_MEM] = 2 * K1 * y[T_EXT] * y[E_MEM] - 2 * K_1 * y[TE_MEM] - K2 * y[TE_MEM] * wG
- + K_2 * y[TE_MEM_P] * wC - K3 * y[TE_MEM];
- dydt[TE_MEM_P] = K2 * y[TE_MEM] * wG - K_2 * y[TE_MEM_P] * wC - K4 * y[TE_MEM_P];
- dydt[TE_CYTO] = K3 * y[TE_MEM] + K4 * y[TE_MEM_P] - K5 * y[TE_CYTO];
- dydt[P_INACTIVE] = K9 * y[P_ACTIVE] - K8 * (PLCG - y[P_ACTIVE]) * wP;
- dydt[P_ACTIVE] = K8 * (PLCG - y[P_ACTIVE]) * wP - K9 * y[P_ACTIVE];
-
- return dydt;
- };
-
+ Equations equations =
+ (t, y) -> {
+ double wG = 1 + y[G_INT] / (WG + y[G_INT]);
+ double wP = 1 + y[TE_MEM_P] / (WP + y[TE_MEM_P]);
+ double wC = 1 + y[P_ACTIVE] / (WC + y[P_ACTIVE]);
+
+ double[] dydt = new double[NUM_COMPONENTS];
+
+ dydt[G_INT] = 0;
+ dydt[T_EXT] = K_1 * y[TE_MEM] - K1 * y[T_EXT] * y[E_MEM] - K7 * y[T_EXT] + K11;
+ dydt[E_MEM] = K_1 * y[TE_MEM] - K1 * y[T_EXT] * y[E_MEM] - K6 * y[E_MEM] + K10;
+ dydt[TE_MEM] =
+ 2 * K1 * y[T_EXT] * y[E_MEM]
+ - 2 * K_1 * y[TE_MEM]
+ - K2 * y[TE_MEM] * wG
+ + K_2 * y[TE_MEM_P] * wC
+ - K3 * y[TE_MEM];
+ dydt[TE_MEM_P] = K2 * y[TE_MEM] * wG - K_2 * y[TE_MEM_P] * wC - K4 * y[TE_MEM_P];
+ dydt[TE_CYTO] = K3 * y[TE_MEM] + K4 * y[TE_MEM_P] - K5 * y[TE_CYTO];
+ dydt[P_INACTIVE] = K9 * y[P_ACTIVE] - K8 * (PLCG - y[P_ACTIVE]) * wP;
+ dydt[P_ACTIVE] = K8 * (PLCG - y[P_ACTIVE]) * wP - K9 * y[P_ACTIVE];
+
+ return dydt;
+ };
+
@Override
public void step(MersenneTwisterFast random, Simulation sim) {
// Get metabolism process from cell.
- PatchProcessMetabolism metabolism = (PatchProcessMetabolism)
- cell.getProcess(Domain.METABOLISM);
-
+ PatchProcessMetabolism metabolism =
+ (PatchProcessMetabolism) cell.getProcess(Domain.METABOLISM);
+
// Get concentration of external TGFa and internal glucose in nM.
concs[G_INT] = metabolism.intAmts[0] / cell.getVolume() * 1E9;
concs[T_EXT] = sim.getLattice("TGFA").getAverageValue(location) / TGFA_MW;
-
+
// Solve system of equations.
double pre = concs[P_ACTIVE];
concs = Solver.euler(equations, 0, concs, 60, STEP_SIZE);
double post = concs[P_ACTIVE];
-
+
// Calculate fold change and set migratory or proliferative flag.
current = ((pre > post ? pre / post : post / pre) - 1);
double delta = (current > previous ? current / previous : previous / current);
cell.setFlag(delta > migratoryThreshold ? Flag.MIGRATORY : Flag.PROLIFERATIVE);
previous = current;
-
+
// Update environment.
sim.getLattice("TGFA").setValue(location, concs[T_EXT] * TGFA_MW);
}
-
+
@Override
public void update(Process process) {
PatchProcessSignalingMedium signaling = (PatchProcessSignalingMedium) process;
diff --git a/src/arcade/patch/agent/process/PatchProcessSignalingRandom.java b/src/arcade/patch/agent/process/PatchProcessSignalingRandom.java
index 5a6f3d51b..83f525e71 100644
--- a/src/arcade/patch/agent/process/PatchProcessSignalingRandom.java
+++ b/src/arcade/patch/agent/process/PatchProcessSignalingRandom.java
@@ -3,48 +3,45 @@
import ec.util.MersenneTwisterFast;
import arcade.core.agent.process.Process;
import arcade.core.sim.Simulation;
-import arcade.core.util.MiniBox;
+import arcade.core.util.Parameters;
import arcade.patch.agent.cell.PatchCell;
import static arcade.patch.util.PatchEnums.Flag;
/**
* Extension of {@link PatchProcessSignaling} for random EGFR signaling.
- *
- *
*
- * @param cell the {@link PatchCell} the process is associated with
+ * @param cell the {@link PatchCell} the process is associated with
*/
public PatchProcessSignalingRandom(PatchCell cell) {
super(cell);
-
+
// Set loaded parameters.
- // TODO: pull migratory threshold from distribution
- MiniBox parameters = cell.getParameters();
- migratoryProbability = parameters.getDouble("metabolism/MIGRATORY_PROBABILITY");
+ Parameters parameters = cell.getParameters();
+ migratoryProbability = parameters.getDouble("signaling/MIGRATORY_PROBABILITY");
}
-
+
@Override
public void step(MersenneTwisterFast random, Simulation sim) {
- cell.setFlag(random.nextDouble() < migratoryProbability
- ? Flag.MIGRATORY : Flag.PROLIFERATIVE);
+ cell.setFlag(
+ random.nextDouble() < migratoryProbability ? Flag.MIGRATORY : Flag.PROLIFERATIVE);
}
-
+
@Override
- public void update(Process process) { }
+ public void update(Process process) {}
}
diff --git a/src/arcade/patch/agent/process/PatchProcessSignalingSimple.java b/src/arcade/patch/agent/process/PatchProcessSignalingSimple.java
index e6bcb3e23..8a63c0c84 100644
--- a/src/arcade/patch/agent/process/PatchProcessSignalingSimple.java
+++ b/src/arcade/patch/agent/process/PatchProcessSignalingSimple.java
@@ -4,7 +4,7 @@
import ec.util.MersenneTwisterFast;
import arcade.core.agent.process.Process;
import arcade.core.sim.Simulation;
-import arcade.core.util.MiniBox;
+import arcade.core.util.Parameters;
import arcade.core.util.Solver;
import arcade.core.util.Solver.Equations;
import arcade.patch.agent.cell.PatchCell;
@@ -13,97 +13,94 @@
/**
* Extension of {@link PatchProcessSignaling} for simple EGFR signaling.
- *
- *
*
- * @param cell the {@link PatchCell} the process is associated with
+ * @param cell the {@link PatchCell} the process is associated with
*/
public PatchProcessSignalingSimple(PatchCell cell) {
super(cell);
-
+
// Initial concentrations, all in nM (umol/m^3). Most are zeros.
concs = new double[NUM_COMPONENTS];
concs[P_INACTIVE] = K5 / (K4 + K5) * PLCG;
concs[P_ACTIVE] = K4 / (K4 + K5) * PLCG;
-
+
// Molecule names.
names = new ArrayList<>();
names.add(G_INT, "glucose_internal");
@@ -111,64 +108,65 @@ public PatchProcessSignalingSimple(PatchCell cell) {
names.add(TE_CYTO, "tgfa_egfr_cytoplasmic");
names.add(P_INACTIVE, "plcg_inactive");
names.add(P_ACTIVE, "plcg_active");
-
+
// Set loaded parameters.
- // TODO: pull migratory threshold from distribution
- MiniBox parameters = cell.getParameters();
- migratoryThreshold = parameters.getDouble("metabolism/MIGRATORY_THRESHOLD");
+ Parameters parameters = cell.getParameters();
+ migratoryThreshold = parameters.getDouble("signaling/MIGRATORY_THRESHOLD");
}
-
+
/**
* System of ODEs for network.
- *
- *
*/
- Equations equations = (t, y) -> {
- double wG = 1 + y[G_INT] / (WG + y[G_INT]);
- double wP = 1 + y[TE_CYTO] / (WP + y[TE_CYTO]);
- double wC = 1 - y[P_ACTIVE] / (WC + y[P_ACTIVE]);
-
- double[] dydt = new double[NUM_COMPONENTS];
-
- dydt[G_INT] = 0;
- dydt[T_EXT] = K6 - K1 * y[T_EXT] * wG * wC - K3 * y[T_EXT];
- dydt[TE_CYTO] = K1 * y[T_EXT] * wG * wC - K2 * y[TE_CYTO];
- dydt[P_INACTIVE] = K5 * y[P_ACTIVE] - K4 * (PLCG - y[P_ACTIVE]) * wP;
- dydt[P_ACTIVE] = K4 * (PLCG - y[P_ACTIVE]) * wP - K5 * y[P_ACTIVE];
-
- return dydt;
- };
-
+ Equations equations =
+ (t, y) -> {
+ double wG = 1 + y[G_INT] / (WG + y[G_INT]);
+ double wP = 1 + y[TE_CYTO] / (WP + y[TE_CYTO]);
+ double wC = 1 - y[P_ACTIVE] / (WC + y[P_ACTIVE]);
+
+ double[] dydt = new double[NUM_COMPONENTS];
+
+ dydt[G_INT] = 0;
+ dydt[T_EXT] = K6 - K1 * y[T_EXT] * wG * wC - K3 * y[T_EXT];
+ dydt[TE_CYTO] = K1 * y[T_EXT] * wG * wC - K2 * y[TE_CYTO];
+ dydt[P_INACTIVE] = K5 * y[P_ACTIVE] - K4 * (PLCG - y[P_ACTIVE]) * wP;
+ dydt[P_ACTIVE] = K4 * (PLCG - y[P_ACTIVE]) * wP - K5 * y[P_ACTIVE];
+
+ return dydt;
+ };
+
@Override
public void step(MersenneTwisterFast random, Simulation sim) {
// Get metabolism process from cell.
- PatchProcessMetabolism metabolism = (PatchProcessMetabolism)
- cell.getProcess(Domain.METABOLISM);
-
+ PatchProcessMetabolism metabolism =
+ (PatchProcessMetabolism) cell.getProcess(Domain.METABOLISM);
+
// Get concentration of external TGFa and internal glucose in nM.
concs[G_INT] = metabolism.intAmts[0] / cell.getVolume() * 1E9;
concs[T_EXT] = sim.getLattice("TGFA").getAverageValue(location) / TGFA_MW;
-
+
// Solve system of equations.
double pre = concs[P_ACTIVE];
concs = Solver.euler(equations, 0, concs, 60, STEP_SIZE);
double post = concs[P_ACTIVE];
-
+
// Calculate fold change and set migratory or proliferative flag.
current = ((pre > post ? pre / post : post / pre) - 1);
double delta = (current > previous ? current / previous : previous / current);
cell.setFlag(delta > migratoryThreshold ? Flag.MIGRATORY : Flag.PROLIFERATIVE);
previous = current;
-
+
// Update environment.
sim.getLattice("TGFA").setValue(location, concs[T_EXT] * TGFA_MW);
}
-
+
@Override
public void update(Process process) {
PatchProcessSignalingSimple signaling = (PatchProcessSignalingSimple) process;
diff --git a/src/arcade/patch/env/component/PatchComponentCycle.java b/src/arcade/patch/env/component/PatchComponentCycle.java
index f6ff2c349..9bb51f855 100644
--- a/src/arcade/patch/env/component/PatchComponentCycle.java
+++ b/src/arcade/patch/env/component/PatchComponentCycle.java
@@ -16,52 +16,47 @@
/**
* Implementation of {@link Component} for cycling sources.
- *
- *
*
- * @param series the simulation series
- * @param parameters the component parameters dictionary
+ * @param series the simulation series
+ * @param parameters the component parameters dictionary
*/
public PatchComponentDegrade(Series series, MiniBox parameters) {
// Set loaded parameters.
@@ -67,52 +66,52 @@ public PatchComponentDegrade(Series series, MiniBox parameters) {
degradationRate = parameters.getDouble("DEGRADATION_RATE");
shearThreshold = parameters.getDouble("SHEAR_THRESHOLD");
}
-
+
@Override
public void schedule(Schedule schedule) {
schedule.scheduleRepeating(this, Ordering.LAST_COMPONENT.ordinal(), degradationInterval);
}
-
+
@Override
public void register(Simulation sim, String layer) {
Component component = sim.getComponent(layer);
-
+
if (!(component instanceof PatchComponentSitesGraph)) {
return;
}
-
+
sites = (PatchComponentSitesGraph) component;
graph = sites.graph;
}
-
+
@Override
public void step(SimState state) {
Simulation sim = (Simulation) state;
PatchGrid grid = (PatchGrid) sim.getGrid();
boolean removed = false;
-
+
// Iterate through all edges and degrade if there are cancerous cells.
for (Object edgeObj : new Bag(graph.getAllEdges())) {
SiteEdge edge = (SiteEdge) edgeObj;
HashSet
- *
*
- * @param series the simulation series
- * @param parameters the component parameters dictionary
+ * @param series the simulation series
+ * @param parameters the component parameters dictionary
*/
public PatchComponentPulse(Series series, MiniBox parameters) {
layers = new ArrayList<>();
-
+
latticeLength = series.length;
latticeWidth = series.width;
latticeHeight = series.height;
-
+
// Set loaded parameters.
pulseInterval = parameters.getDouble("PULSE_INTERVAL");
mediaAmount = parameters.getDouble("MEDIA_AMOUNT");
-
+
// Set patch parameters.
MiniBox patch = ((PatchSeries) series).patch;
latticePatchVolume = patch.getDouble("LATTICE_VOLUME");
latticePatchArea = patch.getDouble("LATTICE_AREA");
-
+
// Calculate media volume.
mediaVolume = latticePatchArea * latticeLength * latticeWidth * mediaAmount;
}
-
- /**
- * Specification of arrays and parameters for {@link PatchComponentPulse}.
- */
+
+ /** Specification of arrays and parameters for {@link PatchComponentPulse}. */
protected static class PulseLayer {
/** Unique name for layer. */
final String name;
-
+
/** Array holding current concentration values. */
final double[][][] current;
-
+
/** Array holding previous concentration values. */
final double[][][] previous;
-
+
/** Corresponding site layer instance. */
final SiteLayer siteLayer;
-
+
/** Initial concentration. */
final double initialConcentration;
-
+
/** Current amount. */
double currentAmount;
-
+
/**
* Creates a {@code PulseLayer} object.
*
- * @param name the layer name
- * @param siteLayer the associated site layer instance
- * @param generator the associated generator operation instance
+ * @param name the layer name
+ * @param siteLayer the associated site layer instance
+ * @param generator the associated generator operation instance
*/
PulseLayer(String name, SiteLayer siteLayer, PatchOperationGenerator generator) {
this.name = name;
@@ -128,46 +124,47 @@ protected static class PulseLayer {
currentAmount = 0;
}
}
-
+
@Override
public void schedule(Schedule schedule) {
schedule.scheduleOnce(this, Ordering.FIRST.ordinal() - 2);
schedule.scheduleRepeating(this, Ordering.FIRST_COMPONENT.ordinal(), 1);
}
-
+
@Override
public void register(Simulation sim, String layer) {
String[] layerSplit = layer.split(":");
Lattice lattice = sim.getLattice(layerSplit[1]);
Operation generator = lattice.getOperation(Category.GENERATOR);
Component component = sim.getComponent(layerSplit[0]);
-
+
if (!(component instanceof PatchComponentSitesSource)) {
return;
}
-
+
PatchComponentSitesSource sites = (PatchComponentSitesSource) component;
- SiteLayer siteLayer = sites.layers.stream()
- .filter(sl -> sl.name.equalsIgnoreCase(layerSplit[1]))
- .findFirst()
- .orElse(null);
-
+ SiteLayer siteLayer =
+ sites.layers.stream()
+ .filter(sl -> sl.name.equalsIgnoreCase(layerSplit[1]))
+ .findFirst()
+ .orElse(null);
+
if (siteLayer != null) {
- PulseLayer pulseLayer = new PulseLayer(layer, siteLayer,
- (PatchOperationGenerator) generator);
+ PulseLayer pulseLayer =
+ new PulseLayer(layer, siteLayer, (PatchOperationGenerator) generator);
layers.add(pulseLayer);
}
}
-
+
@Override
public void step(SimState simstate) {
double tick = simstate.schedule.getTime();
-
+
for (PulseLayer layer : layers) {
double[][][] previous = layer.previous;
double[][][] current = layer.current;
double delta = 0;
-
+
// Get total consumption.
for (int k = 0; k < latticeHeight; k++) {
for (int i = 0; i < latticeLength; i++) {
@@ -176,16 +173,15 @@ public void step(SimState simstate) {
}
}
}
-
+
// Update available concentrations.
layer.currentAmount = Math.max(0, layer.currentAmount - delta);
layer.siteLayer.concentration = layer.currentAmount / mediaVolume;
-
+
// Pulse returns concentration to initial value.
if (tick % pulseInterval == 0) {
layer.currentAmount = layer.initialConcentration * mediaVolume;
layer.siteLayer.concentration = layer.initialConcentration;
-
}
}
}
diff --git a/src/arcade/patch/env/component/PatchComponentRemodel.java b/src/arcade/patch/env/component/PatchComponentRemodel.java
index 957e14e7b..b2e1b4f6d 100644
--- a/src/arcade/patch/env/component/PatchComponentRemodel.java
+++ b/src/arcade/patch/env/component/PatchComponentRemodel.java
@@ -17,72 +17,70 @@
/**
* Implementation of {@link Component} for remodeling edges.
- *
- *
*
- * @param series the simulation series
- * @param parameters the component parameters dictionary
+ * @param series the simulation series
+ * @param parameters the component parameters dictionary
*/
public PatchComponentRemodel(Series series, MiniBox parameters) {
// Set loaded parameters.
@@ -94,24 +92,24 @@ public PatchComponentRemodel(Series series, MiniBox parameters) {
scaleTau = parameters.getDouble("SCALE_TAU");
scaleSigma = parameters.getDouble("SCALE_SIGMA");
}
-
+
@Override
public void schedule(Schedule schedule) {
schedule.scheduleRepeating(this, Ordering.LAST_COMPONENT.ordinal(), remodelingInterval);
}
-
+
@Override
public void register(Simulation sim, String layer) {
Component component = sim.getComponent(layer);
-
+
if (!(component instanceof PatchComponentSitesGraph)) {
return;
}
-
+
sites = (PatchComponentSitesGraph) component;
graph = sites.graph;
}
-
+
@Override
public void step(SimState state) {
Simulation sim = (Simulation) state;
@@ -120,10 +118,10 @@ public void step(SimState state) {
boolean removed = false;
double oxygenExternal;
double oxygenInternal;
-
+
for (Object edgeObj : new Bag(graph.getAllEdges())) {
SiteEdge edge = (SiteEdge) edgeObj;
-
+
// Get oxygen partial pressures.
oxygenExternal = 0;
for (CoordinateXYZ coordinate : edge.span) {
@@ -131,36 +129,39 @@ public void step(SimState state) {
}
oxygenExternal /= edge.span.size();
oxygenInternal = (edge.getFrom().oxygen + edge.getTo().oxygen) / 2;
-
+
if (oxygenInternal == 0) {
continue;
}
-
+
// Calculate weights based on reference value.
double sTau = scaleShear * Math.log10(edge.shear / shearReference);
double sSigma = scaleCircum * Math.log10(edge.circum / circumReference);
double sFlow = scaleFlow * Math.log10(flowReference / edge.flow);
- double sMetabolic = scaleMetabolic * (oxygenExternal == 0
- ? 1 : Math.log10(oxygenInternal / oxygenExternal));
+ double sMetabolic =
+ scaleMetabolic
+ * (oxygenExternal == 0
+ ? 1
+ : Math.log10(oxygenInternal / oxygenExternal));
double sWall = (1 + Math.log10(edge.wall / MINIMUM_WALL_THICKNESS));
-
+
// Calculate radius mid and area mass values.
double rm = edge.radius + edge.wall / 2;
double am = edge.wall * rm;
-
+
// Update radius mid and area mass values with scaling factors.
double rmNew = rm + rm * (sTau + sFlow + sMetabolic - scaleSigma * sSigma) / sWall;
double amNew = am + am * (sSigma - scaleTau * sTau) / sWall;
-
+
// Update radius and wall thickness.
edge.radius = rmNew - (amNew / rmNew) / 2;
edge.wall = amNew / rmNew;
-
+
// Check if ratio is too high.
if (edge.wall / edge.radius > MAXIMUM_WALL_RADIUS_FRACTION) {
edge.wall = edge.radius * MAXIMUM_WALL_RADIUS_FRACTION;
}
-
+
if (edge.radius < MINIMUM_CAPILLARY_RADIUS
|| edge.wall < MINIMUM_WALL_THICKNESS
|| Double.isNaN(edge.radius)) {
@@ -170,7 +171,7 @@ public void step(SimState state) {
removed = true;
}
}
-
+
// If any edges are removed, update the graph edges that are ignored.
// Otherwise, recalculate pressure, flow, and stresses.
if (removed) {
@@ -185,16 +186,14 @@ public void step(SimState state) {
PatchComponentSitesGraphUtilities.calculateStresses(graph);
}
}
-
- /**
- * Calculates reference values of shear and circumferential stress.
- */
+
+ /** Calculates reference values of shear and circumferential stress. */
private void calculateReferences() {
shearReference = 0;
circumReference = 0;
flowReference = 0;
int count = 0;
-
+
for (Object obj : graph.getAllEdges()) {
SiteEdge edge = (SiteEdge) obj;
if (edge.getFrom().isRoot) {
@@ -204,7 +203,7 @@ private void calculateReferences() {
count++;
}
}
-
+
shearReference /= count;
circumReference /= count;
flowReference /= count;
diff --git a/src/arcade/patch/env/component/PatchComponentSites.java b/src/arcade/patch/env/component/PatchComponentSites.java
index f45927d9b..f248f3ecd 100644
--- a/src/arcade/patch/env/component/PatchComponentSites.java
+++ b/src/arcade/patch/env/component/PatchComponentSites.java
@@ -13,66 +13,62 @@
/**
* Abstract implementation of {@link Component} for patch sites.
- *
- *
- *
- *
*
- * @param series the simulation series
- * @param parameters the component parameters dictionary
- * @param random the random number generator
+ * @param series the simulation series
+ * @param parameters the component parameters dictionary
+ * @param random the random number generator
*/
- public PatchComponentSitesGraph(Series series, MiniBox parameters,
- MersenneTwisterFast random) {
+ public PatchComponentSitesGraph(Series series, MiniBox parameters, MersenneTwisterFast random) {
super(series);
-
+
// Set loaded parameters.
graphLayout = parameters.get("GRAPH_LAYOUT");
oxySoluPlasma = parameters.getDouble("OXYGEN_SOLUBILITY_PLASMA");
oxySoluTissue = parameters.getDouble("OXYGEN_SOLUBILITY_TISSUE");
-
+
// Set patch parameters.
MiniBox patch = ((PatchSeries) series).patch;
latticePatchVolume = patch.getDouble("LATTICE_VOLUME");
-
+
// Create graph.
graphFactory = makeGraphFactory(series);
graph = initializeGraph(random);
}
-
+
/**
* Gets the {@link Graph} representing the sites.
*
- * @return the graph object
+ * @return the graph object
*/
- public Graph getGraph() { return graph; }
-
+ public Graph getGraph() {
+ return graph;
+ }
+
/**
* Creates a factory for graphs.
*
- * @param series the simulation series
- * @return a {@link Graph} factory
+ * @param series the simulation series
+ * @return a {@link Graph} factory
*/
abstract PatchComponentSitesGraphFactory makeGraphFactory(Series series);
-
+
/**
* Gets the lattice coordinates spanned by an edge between two nodes.
*
- * @param from the node the edge extends from
- * @param to the node the edge extends to
- * @return the list of span coordinates
+ * @param from the node the edge extends from
+ * @param to the node the edge extends to
+ * @return the list of span coordinates
*/
abstract ArrayList
- *
*/
-
public abstract class PatchComponentSitesGraphFactory {
/** Border directions. */
- enum Border { LEFT, RIGHT, TOP, BOTTOM }
-
+ enum Border {
+ LEFT,
+ RIGHT,
+ TOP,
+ BOTTOM
+ }
+
/** Edge types. */
enum EdgeType {
/** Code for arteriole edge type. */
ARTERIOLE(EdgeCategory.ARTERY),
-
+
/** Code for artery edge type. */
ARTERY(EdgeCategory.ARTERY),
-
+
/** Code for capillary edge type. */
CAPILLARY(EdgeCategory.CAPILLARY),
-
+
/** Code for vein edge type. */
VEIN(EdgeCategory.VEIN),
-
+
/** Code for venule edge type. */
VENULE(EdgeCategory.VEIN);
-
+
/** Edge category corresponding to the edge type. */
final EdgeCategory category;
-
+
/**
* Creates an {@code EdgeType} instance.
*
- * @param category the edge category
+ * @param category the edge category
*/
EdgeType(EdgeCategory category) {
this.category = category;
}
}
-
+
/** Edge categories. */
enum EdgeCategory {
/** Code for artery edge category. */
ARTERY(-1),
-
+
/** Code for capillary edge category. */
CAPILLARY(0),
-
+
/** Code for vein edge category. */
VEIN(1);
-
+
/** Sign corresponding to edge category. */
final int sign;
-
+
/**
* Creates an {@code EdgeCategory} instance.
*
- * @param sign the category sign
+ * @param sign the category sign
*/
EdgeCategory(int sign) {
this.sign = sign;
}
}
-
+
/** Edge tags. */
enum EdgeTag {
/** Tag for edge addition in iterative remodeling. */
ADD,
-
+
/** Tag for edge removal in iterative remodeling. */
REMOVE,
}
-
+
/** Edge levels. */
enum EdgeLevel {
/** Code for variable resolution level. */
VARIABLE(1),
-
+
/** Code for level 1 resolution. */
LEVEL_1(4),
-
+
/** Code for level 2 resolution. */
LEVEL_2(2);
-
+
/** Scaling corresponding to edge level. */
final int scale;
-
+
/**
* Creates an {@code EdgeLevel} instance.
*
- * @param scale the level scale
+ * @param scale the level scale
*/
EdgeLevel(int scale) {
this.scale = scale;
}
}
-
+
/** Edge directions. */
enum EdgeDirection {
/** Code for undefined edge direction. */
UNDEFINED,
-
+
/** Code for up edge direction. */
UP,
-
+
/** Code for up-right edge direction. */
UP_RIGHT,
-
+
/** Code for right edge direction. */
RIGHT,
-
+
/** Code for down-right edge direction. */
DOWN_RIGHT,
-
+
/** Code for down edge direction. */
DOWN,
-
+
/** Code for down-left edge direction. */
DOWN_LEFT,
-
+
/** Code for left edge direction. */
LEFT,
-
+
/** Code for up-left edge direction. */
UP_LEFT,
}
-
+
/** Edge motifs. */
enum EdgeMotif {
/** Code for triple edge motif. */
TRIPLE,
-
+
/** Code for double edge motif. */
DOUBLE,
-
+
/** Code for single edge motif. */
SINGLE,
}
-
+
/** Probability weighting for iterative remodeling. */
private static final double PROBABILITY_WEIGHT = 0.2;
-
+
/** Iterative remodeling fraction. */
private static final double REMODELING_FRACTION = 0.05;
-
+
/** Maximum number of iterations. */
private static final int MAX_ITERATIONS = 100;
-
+
/** Height of the array (z direction). */
final int latticeHeight;
-
+
/** Length of the array (x direction). */
final int latticeLength;
-
+
/** Width of the array (y direction). */
final int latticeWidth;
-
+
/**
* Creates a factory for making {@link Graph} sites.
*
- * @param series the simulation series
+ * @param series the simulation series
*/
public PatchComponentSitesGraphFactory(Series series) {
latticeLength = series.length;
latticeWidth = series.width;
latticeHeight = series.height;
}
-
+
/**
* Calculate the offset based on the layer index.
*
- * @param k the index in the z direction
- * @return the lattice offset
+ * @param k the index in the z direction
+ * @return the lattice offset
*/
abstract int calcOffset(int k);
-
+
/**
* Calculates the column of the pattern based on offset and index.
*
- * @param i the index in the x direction
- * @param offset the lattice offset
- * @return the column index
+ * @param i the index in the x direction
+ * @param offset the lattice offset
+ * @return the column index
*/
abstract int calcCol(int i, int offset);
-
+
/**
* Calculates the row of the pattern based on offset and index.
*
- * @param i the index in the x direction
- * @param j the index in the y direction
- * @param offset the lattice offset
- * @return the row index
+ * @param i the index in the x direction
+ * @param j the index in the y direction
+ * @param offset the lattice offset
+ * @return the row index
*/
abstract int calcRow(int i, int j, int offset);
-
+
/**
* Checks if the given node is outside the bounds of the environment.
*
- * @param node the node to check
- * @return {@code true} if node is within bounds, {@code false} otherwise
+ * @param node the node to check
+ * @return {@code true} if node is within bounds, {@code false} otherwise
*/
abstract boolean checkNode(Node node);
-
+
/**
* Gets direction code for an edge between given coordinates.
*
- * @param fromX the x coordinate of the node the edge is from
- * @param fromY the y coordinate of the node the edge is from
- * @param toX the x coordinate of the node the edge is to
- * @param toY the y coordinate of the node the edge is to
- * @return the code for the edge direction
+ * @param fromX the x coordinate of the node the edge is from
+ * @param fromY the y coordinate of the node the edge is from
+ * @param toX the x coordinate of the node the edge is to
+ * @param toY the y coordinate of the node the edge is to
+ * @return the code for the edge direction
*/
abstract EdgeDirection getDirection(int fromX, int fromY, int toX, int toY);
-
+
/**
* Adds a root motif to the graph.
*
- * @param graph the graph instance
- * @param node0 the node the motif starts at
- * @param dir the direction code of the root
- * @param type the root type
- * @param offsets the list of offsets for line roots, null otherwise
- * @param random the random number generator
- * @return the bag of active edges
+ * @param graph the graph instance
+ * @param node0 the node the motif starts at
+ * @param dir the direction code of the root
+ * @param type the root type
+ * @param offsets the list of offsets for line roots, null otherwise
+ * @param random the random number generator
+ * @return the bag of active edges
*/
- abstract Bag addRoot(Graph graph, SiteNode node0, EdgeDirection dir, EdgeType type,
- EdgeDirection[] offsets, MersenneTwisterFast random);
-
+ abstract Bag addRoot(
+ Graph graph,
+ SiteNode node0,
+ EdgeDirection dir,
+ EdgeType type,
+ EdgeDirection[] offsets,
+ MersenneTwisterFast random);
+
/**
* Adds an edge motif to the graph.
*
- * @param graph the graph instance
- * @param node0 the node the motif starts at
- * @param edge0 the edge the motif is being added to
- * @param type the edge type
- * @param level the graph resolution level
- * @param motif the motif type
- * @param random the random number generator
- * @return the bag of active edges
+ * @param graph the graph instance
+ * @param node0 the node the motif starts at
+ * @param edge0 the edge the motif is being added to
+ * @param type the edge type
+ * @param level the graph resolution level
+ * @param motif the motif type
+ * @param random the random number generator
+ * @return the bag of active edges
*/
- abstract Bag addMotif(Graph graph, SiteNode node0, SiteEdge edge0, EdgeType type,
- EdgeLevel level, EdgeMotif motif, MersenneTwisterFast random);
-
+ abstract Bag addMotif(
+ Graph graph,
+ SiteNode node0,
+ SiteEdge edge0,
+ EdgeType type,
+ EdgeLevel level,
+ EdgeMotif motif,
+ MersenneTwisterFast random);
+
/**
* Adds a capillary segment joining edges of different types to the graph.
*
- * @param graph the graph instance
- * @param node0 the node the segment starts at
- * @param dir the direction code for the segment
- * @param level the graph resolution level
- * @param random the random number generator
+ * @param graph the graph instance
+ * @param node0 the node the segment starts at
+ * @param dir the direction code for the segment
+ * @param level the graph resolution level
+ * @param random the random number generator
*/
- abstract void addSegment(Graph graph, SiteNode node0, EdgeDirection dir,
- EdgeLevel level, MersenneTwisterFast random);
-
+ abstract void addSegment(
+ Graph graph,
+ SiteNode node0,
+ EdgeDirection dir,
+ EdgeLevel level,
+ MersenneTwisterFast random);
+
/**
* Adds a connection joining edges of the same type to the graph.
*
- * @param graph the graph instance
- * @param node0 the node the connection starts at
- * @param dir the direction code for the segment
- * @param type the connection type
- * @param level the graph resolution level
- * @param random the random number generator
+ * @param graph the graph instance
+ * @param node0 the node the connection starts at
+ * @param dir the direction code for the segment
+ * @param type the connection type
+ * @param level the graph resolution level
+ * @param random the random number generator
*/
- abstract void addConnection(Graph graph, SiteNode node0, EdgeDirection dir, EdgeType type,
- EdgeLevel level, MersenneTwisterFast random);
-
+ abstract void addConnection(
+ Graph graph,
+ SiteNode node0,
+ EdgeDirection dir,
+ EdgeType type,
+ EdgeLevel level,
+ MersenneTwisterFast random);
+
/**
* Gets list of coordinate changes for to a given offset direction.
*
- * @param offset the offset code
- * @return the list of coordinate changes
+ * @param offset the offset code
+ * @return the list of coordinate changes
*/
abstract int[] getOffset(EdgeDirection offset);
-
+
/**
* Gets the length of the given edge.
*
- * @param edge the edge object
- * @param level the graph resolution level
- * @return the length of the edge
+ * @param edge the edge object
+ * @param level the graph resolution level
+ * @return the length of the edge
*/
abstract double getLength(SiteEdge edge, EdgeLevel level);
-
+
/**
* Creates graph sites using pattern layout.
*
- * @param graph the graph instance
+ * @param graph the graph instance
*/
abstract void createPattern(Graph graph);
-
+
/**
* Creates a {@link Root} for graph sites using a root layout.
*
- * @param border the border the root extends from
- * @param percent the percentage distance along the border
- * @param type the root type
- * @param level the graph resolution level
- * @return a {@link Root} object
+ * @param border the border the root extends from
+ * @param percent the percentage distance along the border
+ * @param type the root type
+ * @param level the graph resolution level
+ * @return a {@link Root} object
*/
abstract Root createRoot(Border border, double percent, EdgeType type, EdgeLevel level);
-
+
/**
* Creates offsets for a {@link Root} for graph sites using a root layout.
*
- * @param border the border the root extends from
- * @param percent the percentage distance in the perpendicular direction
- * @param level the graph resolution level
- * @param random the random number generator
- * @return a list of offsets
- */
- abstract EdgeDirection[] createRootOffsets(Border border, double percent, EdgeLevel level,
- MersenneTwisterFast random);
-
- /**
- * Container class for details of root nodes.
+ * @param border the border the root extends from
+ * @param percent the percentage distance in the perpendicular direction
+ * @param level the graph resolution level
+ * @param random the random number generator
+ * @return a list of offsets
*/
+ abstract EdgeDirection[] createRootOffsets(
+ Border border, double percent, EdgeLevel level, MersenneTwisterFast random);
+
+ /** Container class for details of root nodes. */
static class Root {
/** Corresponding node object. */
SiteNode node;
-
+
/** Corresponding edge object. */
SiteEdge edge;
-
+
/** Root type. */
final EdgeType type;
-
+
/** Root direction. */
final EdgeDirection dir;
-
+
/** List of offsets for line roots, null otherwise. */
EdgeDirection[] offsets;
-
+
/**
* Creates a {@code Root} object for generating root graphs.
*
- * @param x the x coordinate
- * @param y the y coordinate
- * @param type the edge type
- * @param dir the direction code of the root
+ * @param x the x coordinate
+ * @param y the y coordinate
+ * @param type the edge type
+ * @param dir the direction code of the root
*/
Root(int x, int y, EdgeType type, EdgeDirection dir) {
node = new SiteNode(x, y, 0);
@@ -368,59 +390,58 @@ static class Root {
this.dir = dir;
}
}
-
+
/**
* Gets direction code for an edge.
*
- * @param edge the edge object
- * @param level the graph resolution level
- * @return the code for the edge direction
+ * @param edge the edge object
+ * @param level the graph resolution level
+ * @return the code for the edge direction
*/
EdgeDirection getDirection(SiteEdge edge, EdgeLevel level) {
return getDirection(edge.getFrom(), edge.getTo(), level);
}
-
+
/**
* Gets direction code for an edge.
*
- * @param from the node the edge is from
- * @param to the node the edge is to
- * @param level the graph resolution level
- * @return the code for the edge direction
+ * @param from the node the edge is from
+ * @param to the node the edge is to
+ * @param level the graph resolution level
+ * @return the code for the edge direction
*/
EdgeDirection getDirection(SiteNode from, SiteNode to, EdgeLevel level) {
int scale = level.scale;
- return getDirection(from.getX() / scale, from.getY() / scale,
- to.getX() / scale, to.getY() / scale);
+ return getDirection(
+ from.getX() / scale, from.getY() / scale, to.getX() / scale, to.getY() / scale);
}
-
+
/**
* Creates a node offset in the given direction.
*
- * @param node the node of the initial location
- * @param offset the offset direction
- * @param level the graph resolution level
- * @return an offset node
+ * @param node the node of the initial location
+ * @param offset the offset direction
+ * @param level the graph resolution level
+ * @return an offset node
*/
SiteNode offsetNode(SiteNode node, EdgeDirection offset, EdgeLevel level) {
int[] offsets = getOffset(offset);
return new SiteNode(
node.getX() + offsets[0] * level.scale,
node.getY() + offsets[1] * level.scale,
- node.getZ() + offsets[2] * level.scale
- );
+ node.getZ() + offsets[2] * level.scale);
}
-
+
/**
* Initializes graph with edges and nodes in a pattern layout.
*
- * @param random the random number generator
- * @return a graph instance with pattern layout
+ * @param random the random number generator
+ * @return a graph instance with pattern layout
*/
public Graph initializePatternGraph(MersenneTwisterFast random) {
Graph graph = new Graph();
createPattern(graph);
-
+
// Remove edges that were not visited. Need to make a new copy of the
// bag otherwise we iterate over an object that is being changed.
Bag all = new Bag(graph.getAllEdges());
@@ -432,14 +453,14 @@ public Graph initializePatternGraph(MersenneTwisterFast random) {
edge.isPerfused = true;
}
}
-
+
// Traverse graph from capillaries to calculate radii.
- ArrayList