diff --git a/.github/config/checks.xml b/.github/config/checks.xml index a7f382e07..ec6a8f485 100644 --- a/.github/config/checks.xml +++ b/.github/config/checks.xml @@ -58,7 +58,7 @@ - + @@ -122,7 +122,15 @@ - + + + + + + + + + diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b81f41c3c..445783ef2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,10 +11,10 @@ jobs: - name: Checkout the repo uses: actions/checkout@v4 - - name: Set up JDK 1.8 + - name: Set up JDK 1.11 uses: actions/setup-java@v3 with: - java-version: '8' + java-version: '11' distribution: 'corretto' - name: Validate Gradle wrapper diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index f340b16e5..e573aeca7 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -14,10 +14,10 @@ jobs: - name: Checkout the repo uses: actions/checkout@v4 - - name: Set up JDK 1.8 + - name: Set up JDK 1.11 uses: actions/setup-java@v3 with: - java-version: '8' + java-version: '11' distribution: 'corretto' - name: Validate Gradle wrapper diff --git a/build.gradle b/build.gradle index 219d3ced0..1550d5852 100644 --- a/build.gradle +++ b/build.gradle @@ -2,10 +2,11 @@ plugins { id "java" id "jacoco" id "com.palantir.git-version" version "3.0.0" + id "com.diffplug.spotless" version "6.25.0" } version = "3.1.4" -sourceCompatibility = 1.8 +sourceCompatibility = 1.11 repositories { mavenCentral() @@ -28,12 +29,17 @@ dependencies { implementation "com.formdev:flatlaf:0.36" implementation "com.google.code.gson:gson:2.8.6" runtimeOnly group: "javax.media", name: "jmf", version: "2.1.1e" - testImplementation "org.mockito:mockito-core:2.23.+" - testImplementation "org.mockito:mockito-inline:2.23.+" - testImplementation "junit:junit:4.12" + testImplementation "org.mockito:mockito-core:5.14.+" + testImplementation "org.mockito:mockito-inline:5.2.+" + testImplementation "org.junit.jupiter:junit-jupiter-api:5.11.2" + testImplementation "org.junit.jupiter:junit-jupiter-engine:5.11.2" testImplementation "commons-io:commons-io:2.8.0" } +test { + useJUnitPlatform() +} + javadoc { source = sourceSets.main.allJava classpath = configurations.compileClasspath @@ -61,6 +67,24 @@ jacocoTestReport { } } +spotless { + java { + removeUnusedImports() + googleJavaFormat().aosp() + .reorderImports(true) + .formatJavadoc(true) + importOrder('java|javax|org|com||sim|ec|arcade.core|arcade|\\#java|\\#org|\\#|\\#arcade.core|\\#arcade') + indentWithSpaces() + } + + format 'misc', { + target '**/.gitignore', '**/*.gradle', '**/*.md', 'src/**/*.xml', 'test/**/*.xml' + indentWithSpaces() + trimTrailingWhitespace() + endWithNewline() + } +} + jar { from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } } duplicatesStrategy = DuplicatesStrategy.INCLUDE diff --git a/settings.gradle b/settings.gradle index ecfed92c6..1fd9bd57b 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -rootProject.name = 'arcade' \ No newline at end of file +rootProject.name = 'arcade' diff --git a/src/arcade/core/ARCADE.java b/src/arcade/core/ARCADE.java index ac3b0402c..80363116a 100644 --- a/src/arcade/core/ARCADE.java +++ b/src/arcade/core/ARCADE.java @@ -28,83 +28,82 @@ /** * Entry point class for ARCADE simulations. - *

- * 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 } extends this class to define - * implementation specific: + * + *

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 } extends this class to define implementation + * specific: + * *

    - *
  • {@code command..xml} with custom command line parameters
  • - *
  • {@code parameter..xml} with new default parameter values
  • - *
  • {@link InputBuilder} for building implementation series from the setup XML
  • - *
  • {@link OutputLoader} for loading classes
  • - *
  • {@link OutputSaver} for saving classes
  • + *
  • {@code command..xml} with custom command line parameters + *
  • {@code parameter..xml} with new default parameter values + *
  • {@link InputBuilder} for building implementation series from the setup XML + *
  • {@link OutputLoader} for loading classes + *
  • {@link OutputSaver} for saving classes *
*/ - 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 series = arcade.buildSeries(parameters, settings); - + // Run series. arcade.runSeries(series, settings); } - + /** * Gets full version number. * - * If running with a jar, the version is pulled from the jar manifest. - * Otherwise, the version is extracted using git. + *

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 ""; } } - + /** * Loads command line parser from {@code command.xml} files. * - * @param implementation the implementation name - * @return a container of command line settings + * @param implementation the implementation name + * @return a container of command line settings */ Box loadCommands(String implementation) throws IOException, SAXException { InputLoader loader = new InputLoader(); - + logger.info("loading framework command line parser from [ command.xml ]"); Box commands = loader.load(ARCADE.class.getResource("command.xml").toString()); - - logger.info("loading implementation [ " + this.getClass().getSimpleName() + " ]" - + " command line parser from [ command." + implementation + ".xml ]"); + + logger.info( + "loading implementation [ " + + this.getClass().getSimpleName() + + " ]" + + " command line parser from [ command." + + implementation + + ".xml ]"); loader.load(this.getResource("command." + implementation + ".xml"), commands); - + return commands; } - + /** * Loads default parameter from {@code parameter.xml} files. * - * @param implementation the implementation name - * @return a container of default parameter values + * @param implementation the implementation name + * @return a container of default parameter values */ Box loadParameters(String implementation) throws IOException, SAXException { InputLoader loader = new InputLoader(); - + logger.info("loading framework default parameters from [ parameter.xml ]"); Box parameters = loader.load(ARCADE.class.getResource("parameter.xml").toString()); - - logger.info("loading implementation [ " + this.getClass().getSimpleName() + " ]" - + " default parameters from [ parameter." + implementation + ".xml ]"); + + logger.info( + "loading implementation [ " + + this.getClass().getSimpleName() + + " ]" + + " default parameters from [ parameter." + + implementation + + ".xml ]"); loader.load(this.getResource("parameter." + implementation + ".xml"), parameters); - + return parameters; } - + /** * Parses arguments using command line parser. * - * @param args the list of arguments - * @param commands the command line parser settings - * @return the container of parsed arguments + * @param args the list of arguments + * @param commands the command line parser settings + * @return the container of parsed arguments */ MiniBox parseArguments(String[] args, Box commands) { // Parse command line arguments. @@ -221,43 +231,43 @@ MiniBox parseArguments(String[] args, Box commands) { InputParser parser = new InputParser(commands); return parser.parse(args); } - + /** * Builds series based on setup file. * - * @param parameters a container of default parameter values - * @param settings a container of parsed arguments - * @return a list of {@link Series} instances + * @param parameters a container of default parameter values + * @param settings a container of parsed arguments + * @return a list of {@link Series} instances */ ArrayList buildSeries(Box parameters, MiniBox settings) throws IOException, SAXException { String xml = settings.get("XML"); String path = settings.get("PATH"); boolean isVis = settings.contains("VIS"); - + InputBuilder builder = this.getBuilder(); builder.path = path.endsWith("/") ? path : (path + "/"); builder.parameters = parameters; builder.isVis = isVis; - + return builder.build(xml); } - + /** * Runs simulations for each {@link Series}. - *

- * 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 series, MiniBox settings) throws Exception { boolean isVis = settings.contains("VIS"); String loadPath = settings.get("LOADPATH"); boolean loadCells = settings.contains("LOADCELLS"); boolean loadLocations = settings.contains("LOADLOCATIONS"); - + // Iterate through each series and run. for (Series s : series) { // Create saver and save series JSON (for non-vis only) @@ -265,7 +275,7 @@ void runSeries(ArrayList series, MiniBox settings) throws Exception { s.saver = this.getSaver(s); s.saver.saveSeries(); } - + // Create loader if flagged. if (loadCells || loadLocations) { s.loader = this.getLoader(s); @@ -273,12 +283,12 @@ void runSeries(ArrayList series, MiniBox settings) throws Exception { s.loader.loadCells = loadCells; s.loader.loadLocations = loadLocations; } - + // Skip simulations if there is an error in the series. if (s.isSkipped) { continue; } - + // Run with visualization if requested, otherwise run command line. if (isVis) { logger.info("running simulation with visualization"); @@ -290,31 +300,30 @@ void runSeries(ArrayList series, MiniBox settings) throws Exception { } } } - - /** - * Updates the logger handler with custom formatting. - */ + + /** Updates the logger handler with custom formatting. */ public static void updateLogger() { // Setup logger. Logger classLogger = Logger.getLogger("arcade"); classLogger.setUseParentHandlers(false); - + // Change logger display format. ConsoleHandler handler = new ConsoleHandler(); - handler.setFormatter(new SimpleFormatter() { - private static final String FORMAT = "%1$tF %1$tT %2$-7s %3$-35s : %4$s %n"; - - @Override - public synchronized String format(LogRecord lr) { - return String.format(FORMAT, - new Date(lr.getMillis()), - lr.getLevel().getLocalizedName(), - lr.getSourceClassName(), - lr.getMessage() - ); - } - }); - + handler.setFormatter( + new SimpleFormatter() { + private static final String FORMAT = "%1$tF %1$tT %2$-7s %3$-35s : %4$s %n"; + + @Override + public synchronized String format(LogRecord lr) { + return String.format( + FORMAT, + new Date(lr.getMillis()), + lr.getLevel().getLocalizedName(), + lr.getSourceClassName(), + lr.getMessage()); + } + }); + classLogger.addHandler(handler); } } diff --git a/src/arcade/core/agent/action/Action.java b/src/arcade/core/agent/action/Action.java index 23e21bfec..7f4e663cd 100644 --- a/src/arcade/core/agent/action/Action.java +++ b/src/arcade/core/agent/action/Action.java @@ -6,36 +6,34 @@ /** * An {@code Action} object is a steppable that interacts with agents. - *

- * {@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: + * *

    - *
  • introducing outside perturbations to the cells in the system, such as - * applying a treatment intervention or wounding the tissue
  • - *
  • modifying individual cell or cell population states, modules, or - * processes, such as simulating a mutation
  • + *
  • introducing outside perturbations to the cells in the system, such as applying a treatment + * intervention or wounding the tissue + *
  • modifying individual cell or cell population states, modules, or processes, such as + * simulating a mutation *
- *

- * {@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: + * *

    - *
  • Loading existing {@link CellContainer} instances from a given JSON - * file
  • - *
  • Generating new {@link CellContainer} instances based on population - * settings
  • + *
  • Loading existing {@link CellContainer} instances from a given JSON file + *
  • Generating new {@link CellContainer} instances based on population settings *
*/ - 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. - *

- * {@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: + * *

    - *
  • changing one or more layers or layer operations such as adding a drug - * pulse or time delayed nutrient variation or introduction of a drug
  • - *
  • representing physical entities within the environment such as - * capillary beds or matrix scaffolding
  • + *
  • changing one or more layers or layer operations such as adding a drug pulse or time delayed + * nutrient variation or introduction of a drug + *
  • representing physical entities within the environment such as capillary beds or matrix + * scaffolding *
- *

- * {@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: + * *

    - *
  • Generating new instances based on layer settings
  • + *
  • Generating new instances based on layer settings *
*/ - 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. - *

- * 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: + * *

    - *
  • Loading existing {@link LocationContainer} instances from a given - * file
  • - *
  • Generating new {@link LocationContainer} instances based on - * population settings
  • + *
  • Loading existing {@link LocationContainer} instances from a given file + *
  • Generating new {@link LocationContainer} instances based on population settings *
*/ - 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. - *

- * {@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 @@ - + diff --git a/src/arcade/core/sim/Series.java b/src/arcade/core/sim/Series.java index 803e72493..39193d707 100644 --- a/src/arcade/core/sim/Series.java +++ b/src/arcade/core/sim/Series.java @@ -4,224 +4,230 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import sim.display.GUIState; import sim.engine.SimState; import arcade.core.sim.output.*; import arcade.core.util.Box; import arcade.core.util.MiniBox; +import static arcade.core.util.MiniBox.TAG_SEPARATOR; /** - * 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. + * 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 populations; - + /** Map of layer settings. */ public HashMap layers; - + /** Map of action settings. */ public HashMap actions; - + /** Map of component settings. */ public HashMap components; - + /** * Creates a {@code Series} object given setup information parsed from XML. * - * @param setupDicts the map of attribute to value for single instance tags - * @param setupLists the map of attribute to value for multiple instance tags - * @param path the path for simulation output - * @param parameters the default parameter values - * @param isVis {@code true} if visualized, {@code false} otherwise + * @param setupDicts the map of attribute to value for single instance tags + * @param setupLists the map of attribute to value for multiple instance tags + * @param path the path for simulation output + * @param parameters the default parameter values + * @param isVis {@code true} if visualized, {@code false} otherwise */ - public Series(HashMap setupDicts, - HashMap> setupLists, - String path, Box parameters, boolean isVis) { + public Series( + HashMap setupDicts, + HashMap> setupLists, + String path, + Box parameters, + boolean isVis) { MiniBox set = setupDicts.get("set"); MiniBox series = setupDicts.get("series"); MiniBox defaults = parameters.getIdValForTag("DEFAULT"); - + this.isVis = isVis; - + // Set name and prefix. this.name = series.get("name"); this.prefix = path + (set.contains("prefix") ? set.get("prefix") : "") + name; - + // Set random seeds. - this.startSeed = (series.contains("start") - ? series.getInt("start") - : defaults.getInt("START_SEED")); - this.endSeed = (series.contains("end") - ? series.getInt("end") - : defaults.getInt("END_SEED")); - + this.startSeed = + (series.contains("start") ? series.getInt("start") : defaults.getInt("START_SEED")); + this.endSeed = + (series.contains("end") ? series.getInt("end") : defaults.getInt("END_SEED")); + // Set number of ticks and interval - this.ticks = (series.contains("ticks") - ? series.getInt("ticks") - : defaults.getInt("TICKS")); - this.interval = (series.contains("interval") - ? series.getInt("interval") - : defaults.getInt("INTERVAL")); - + this.ticks = (series.contains("ticks") ? series.getInt("ticks") : defaults.getInt("TICKS")); + this.interval = + (series.contains("interval") + ? series.getInt("interval") + : defaults.getInt("INTERVAL")); + // Set sizing. - this.length = (series.contains("length") - ? series.getInt("length") - : defaults.getInt("LENGTH")); - this.width = (series.contains("width") - ? series.getInt("width") - : defaults.getInt("WIDTH")); - this.height = (series.contains("height") - ? series.getInt("height") - : defaults.getInt("HEIGHT")); - this.margin = (series.contains("margin") - ? series.getInt("margin") - : defaults.getInt("MARGIN")); - + this.length = + (series.contains("length") ? series.getInt("length") : defaults.getInt("LENGTH")); + this.width = (series.contains("width") ? series.getInt("width") : defaults.getInt("WIDTH")); + this.height = + (series.contains("height") ? series.getInt("height") : defaults.getInt("HEIGHT")); + this.margin = + (series.contains("margin") ? series.getInt("margin") : defaults.getInt("MARGIN")); + // Set conversion factors. - this.ds = (series.contains("ds") - ? series.getDouble("ds") - : defaults.getDouble("DS")); - this.dz = (series.contains("dz") - ? series.getDouble("dz") - : defaults.getDouble("DZ")); - this.dt = (series.contains("dt") - ? series.getDouble("dt") - : defaults.getDouble("DT")); - + this.ds = (series.contains("ds") ? series.getDouble("ds") : defaults.getDouble("DS")); + this.dz = (series.contains("dz") ? series.getDouble("dz") : defaults.getDouble("DZ")); + this.dt = (series.contains("dt") ? series.getDouble("dt") : defaults.getDouble("DT")); + // Initialize simulation series. initialize(setupLists, parameters); - + // Create constructors for simulation and visualization. makeConstructors(); } - + /** * Gets the name of the series. * - * @return the name of the series + * @return the name of the series */ - public String getName() { return name; } - + public String getName() { + return name; + } + /** * Gets the prefix for the series, including file path. * - * @return the file path and prefix for the series + * @return the file path and prefix for the series */ - public String getPrefix() { return prefix; } - + public String getPrefix() { + return prefix; + } + /** * Gets the start random seed. * - * @return the random seed + * @return the random seed */ - public int getStartSeed() { return startSeed; } - + public int getStartSeed() { + return startSeed; + } + /** * Gets the end random seed. * - * @return the random seed + * @return the random seed */ - public int getEndSeed() { return endSeed; } - + public int getEndSeed() { + return endSeed; + } + /** * Gets the number of ticks per simulation. * - * @return the ticks + * @return the ticks */ - public int getTicks() { return ticks; } - + public int getTicks() { + return ticks; + } + /** * Gets the number of ticks between snapshots. * - * @return the interval + * @return the interval */ - public int getInterval() { return interval; } - + public int getInterval() { + return interval; + } + /** * Checks if string contains valid number greater than 0. * - * @param box the box containing the fraction - * @param key the number key - * @return {@code true if valid}, {@code false} otherwise + * @param box the box containing the fraction + * @param key the number key + * @return {@code true if valid}, {@code false} otherwise */ protected static boolean isValidNumber(Box box, String key) { if (box.getValue(key) == null) { @@ -229,13 +235,13 @@ protected static boolean isValidNumber(Box box, String key) { } return box.getValue(key).matches(NUMBER_REGEX); } - + /** * Checks if string contains valid fraction between 0 and 1, inclusive. * - * @param box the box containing the fraction - * @param key the fraction key - * @return {@code true if valid}, {@code false} otherwise + * @param box the box containing the fraction + * @param key the fraction key + * @return {@code true if valid}, {@code false} otherwise */ protected static boolean isValidFraction(Box box, String key) { if (box.getValue(key) == null) { @@ -243,127 +249,134 @@ protected static boolean isValidFraction(Box box, String key) { } return box.getValue(key).matches(FRACTION_REGEX); } - + /** * Initializes series simulation, agents, and environment. * - * @param setupLists the map of attribute to value for multiple instance tags - * @param parameters the default parameter values loaded from {@code parameter.xml} + * @param setupLists the map of attribute to value for multiple instance tags + * @param parameters the default parameter values loaded from {@code parameter.xml} */ - protected abstract void initialize(HashMap> setupLists, - Box parameters); - + protected abstract void initialize(HashMap> setupLists, Box parameters); + /** * Creates agent populations. * - * @param populationsBox the list of population setup dictionaries - * @param populationDefaults the dictionary of default population parameters - * @param populationConversions the dictionary of population parameter conversions + * @param populationsBox the list of population setup dictionaries + * @param populationDefaults the dictionary of default population parameters + * @param populationConversions the dictionary of population parameter conversions */ - protected abstract void updatePopulations(ArrayList populationsBox, - MiniBox populationDefaults, - MiniBox populationConversions); - + protected abstract void updatePopulations( + ArrayList populationsBox, + MiniBox populationDefaults, + MiniBox populationConversions); + /** * Creates environment layers. * - * @param layersBox the list of layer setup dictionaries - * @param layerDefaults the dictionary of default layer parameters - * @param layerConversions the dictionary of layer parameter conversions + * @param layersBox the list of layer setup dictionaries + * @param layerDefaults the dictionary of default layer parameters + * @param layerConversions the dictionary of layer parameter conversions */ - protected abstract void updateLayers(ArrayList layersBox, - MiniBox layerDefaults, - MiniBox layerConversions); - + protected abstract void updateLayers( + ArrayList layersBox, MiniBox layerDefaults, MiniBox layerConversions); + /** * Creates selected actions. * - * @param actionsBox the list of action dictionaries - * @param actionDefaults the dictionary of default action parameters + * @param actionsBox the list of action dictionaries + * @param actionDefaults the dictionary of default action parameters */ - protected abstract void updateActions(ArrayList actionsBox, - MiniBox actionDefaults); - + protected abstract void updateActions(ArrayList actionsBox, MiniBox actionDefaults); + /** * Creates selected components. * - * @param componentsBox the list of component dictionaries - * @param componentDefaults the dictionary of default component parameters + * @param componentsBox the list of component dictionaries + * @param componentDefaults the dictionary of default component parameters */ - protected abstract void updateComponents(ArrayList componentsBox, - MiniBox componentDefaults); - + protected abstract void updateComponents( + ArrayList componentsBox, MiniBox componentDefaults); + /** * Parses parameter values based on default value. * - * @param box the parameter map - * @param parameter the parameter name - * @param defaultParameter the default parameter value - * @param values the map of parameter values - * @param scales the map of parameter scaling + * @param box the parameter map + * @param parameter the parameter name + * @param defaultParameter the default parameter value + * @param values the map of parameter values + * @param scales the map of parameter scaling */ - protected static void parseParameter(MiniBox box, String parameter, String defaultParameter, - MiniBox values, MiniBox scales) { - box.put(parameter, defaultParameter); - - if (values.get(parameter) != null) { - box.put(parameter, values.get(parameter)); - } - - if (scales.get(parameter) != null) { - box.put(parameter, box.getDouble(parameter) * scales.getDouble(parameter)); + protected static void parseParameter( + MiniBox box, + String parameter, + String defaultParameter, + MiniBox values, + MiniBox scales) { + String value = values.contains(parameter) ? values.get(parameter) : defaultParameter; + Matcher match = Pattern.compile(DISTRIBUTION_REGEX).matcher(value); + + if (match.find()) { + box.put("(DISTRIBUTION)" + TAG_SEPARATOR + parameter, match.group(1).toUpperCase()); + for (int i = 0; i < (match.groupCount() - 1) / 2; i++) { + int index = 2 * (i + 1); + box.put(parameter + "_" + match.group(index), match.group(index + 1)); + } + } else { + box.put(parameter, value); + if (scales.contains(parameter)) { + box.put(parameter, box.getDouble(parameter) * scales.getDouble(parameter)); + } } } - + /** * 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. 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>() { }.getType(); - + Type DEFAULT_CELL_TYPE = new TypeToken>() {}.getType(); + /** Default type for location container list. */ - Type DEFAULT_LOCATION_TYPE = new TypeToken>() { }.getType(); - + Type DEFAULT_LOCATION_TYPE = new TypeToken>() {}.getType(); + /** * Gets the {@link Series} object for the current simulation. - *

- * 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 getCells(); - + /** * Gets the list of {@link LocationContainer} objects. * - * @return a list of {@link LocationContainer} objects + * @return a list of {@link LocationContainer} objects */ ArrayList getLocations(); - + + /** + * Gets the initialized {@link CellFactory} for the simulation. + * + * @return the {@link CellFactory} object + */ + CellFactory getCellFactory(); + + /** + * Gets the initialized {@link LocationFactory} for the simulation. + * + * @return the {@link LocationFactory} object + */ + LocationFactory getLocationFactory(); + /** * Gets the {@link Grid} object. * - * @return the {@link Grid} object + * @return the {@link Grid} object */ Grid getGrid(); - + /** * Gets the {@link Lattice} object for a given key. * - * @param key the name of the lattice - * @return the {@link Lattice} object + * @param key the name of the lattice + * @return the {@link Lattice} object */ Lattice getLattice(String key); - + /** * Gets the {@link Action} object for a given key. * - * @param key the name of the action - * @return the {@link Action} object + * @param key the name of the action + * @return the {@link Action} object */ Action getAction(String key); - + /** * Gets the {@link Component} object for a given key. * - * @param key the name of the component - * @return the {@link Component} object + * @param key the name of the component + * @return the {@link Component} object */ Component getComponent(String key); - + /** * Sets up the agents in the grid 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 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 } is reached, a new - * {@link arcade.core.sim.Series} object is instantiated. All content in the - * setup XML is stored as attribute-value pairs; there is no content between - * tags (the {@code characters} method is not used). - *

- * 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 } is reached, a new {@link arcade.core.sim.Series} object is instantiated. All + * content in the setup XML is stored as attribute-value pairs; there is no content between tags + * (the {@code characters} method is not used). + * + *

General structure of the XML file (attributes not listed): + * *

  *     <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 series; - + /** Tracker for document location. */ Locator locator; - + /** Document identifier. */ String document; - + /** Map of setup dictionaries. */ public HashMap setupDicts; - + /** Map of setup lists of dictionaries. */ public HashMap> setupLists; - + /** Simulation output file path. */ public String path; - + /** Container for default parameter values. */ public Box parameters; - + /** {@code true} if run with visualization, {@code false} otherwise. */ public boolean isVis; - - /** - * Creates a {@code Handler} using {@code SAXParserFactory}. - */ + + /** Creates a {@code Handler} using {@code SAXParserFactory}. */ public InputBuilder() { try { SAXParserFactory spf = SAXParserFactory.newInstance(); @@ -82,34 +79,33 @@ public InputBuilder() { e.printStackTrace(); } } - + /** * Builds {@link arcade.core.sim.Series} from the given XML file. - *

- * 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 build(String xml) - throws IOException, SAXException { + public ArrayList build(String xml) throws IOException, SAXException { series = new ArrayList<>(); - + LOGGER.config("building series from XML file [ " + xml + " ]"); xmlReader.parse(xml); LOGGER.config("successfully built series from XML file [ " + xml + " ]"); - + return series; } - + /** * Creates a {@link arcade.core.util.MiniBox} dictionary from attributes. * - * @param atts the attributes - * @return a dictionary + * @param atts the attributes + * @return a dictionary */ protected MiniBox makeMiniBox(Attributes atts) { MiniBox box = new MiniBox(); @@ -118,12 +114,12 @@ protected MiniBox makeMiniBox(Attributes atts) { } return box; } - + /** * Creates a {@link arcade.core.util.Box} dictionary from given attributes. * - * @param atts the attributes - * @return a dictionary + * @param atts the attributes + * @return a dictionary */ protected Box makeBox(Attributes atts) { Box box = new Box(); @@ -132,46 +128,46 @@ protected Box makeBox(Attributes atts) { } return box; } - + @Override - public void startPrefixMapping(String prefix, String uri) { } - + public void startPrefixMapping(String prefix, String uri) {} + @Override - public void endPrefixMapping(String prefix) { } - + public void endPrefixMapping(String prefix) {} + @Override - public void skippedEntity(String name) { } - + public void skippedEntity(String name) {} + @Override - public void characters(char[] ch, int start, int length) { } - + public void characters(char[] ch, int start, int length) {} + @Override - public void ignorableWhitespace(char[] ch, int start, int length) { } - + public void ignorableWhitespace(char[] ch, int start, int length) {} + @Override - public void processingInstruction(String target, String data) { } - + public void processingInstruction(String target, String data) {} + @Override public void setDocumentLocator(Locator documentLocator) { this.locator = documentLocator; this.document = locator.getSystemId(); } - + @Override public void startDocument() { setupDicts = new HashMap<>(); setupLists = new HashMap<>(); LOGGER.fine("start document [ " + document + " ]"); } - + @Override public void endDocument() { LOGGER.fine("end document [ " + document + " ]"); } - + @Override public abstract void startElement(String uri, String local, String name, Attributes atts); - + @Override public abstract void endElement(String uri, String local, String name); } diff --git a/src/arcade/core/sim/input/InputLoader.java b/src/arcade/core/sim/input/InputLoader.java index 08c2e9a12..a53c68b9b 100644 --- a/src/arcade/core/sim/input/InputLoader.java +++ b/src/arcade/core/sim/input/InputLoader.java @@ -13,24 +13,21 @@ /** * Custom XML file loader that uses SAX parsing to iterate through XML files. - *

- * 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: + * *

    - *
  • position arguments are ordered by their location in the - * command and all are required
  • - *
  • option arguments are indicated by a short ({@code -}) and/ - * or long ({@code --}) flag followed by the contents
  • - *
  • switch arguments are booleans for selecting an option
  • + *
  • position arguments are ordered by their location in the command and all are + * required + *
  • option arguments are indicated by a short ({@code -}) and/ or long ({@code --}) + * flag followed by the contents + *
  • switch arguments are booleans for selecting an option *
- *

- * General structure of {@code command.xml}: + * + *

General structure of {@code command.xml}: + * *

  *     <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 allCommands; - + /** Map of short flags to command. */ final HashMap shortToCommand; - + /** Map of long flags to command. */ final HashMap longToCommand; - + /** List of position commands. */ final ArrayList positionCommands; - + /** Current index for position arguments. */ int positionIndex; - + /** * Creates a command line {@code InputParser} object. * - * @param options the map of command line options + * @param options the map of command line options */ public InputParser(Box options) { // Initialize maps to commands. @@ -77,9 +78,9 @@ public InputParser(Box options) { shortToCommand = new HashMap<>(); longToCommand = new HashMap<>(); positionCommands = new ArrayList<>(); - + LOGGER.config("configuring parser"); - + // Create a Command object for each entry. for (String id : options.getKeys()) { // Create appropriate command type object. @@ -97,12 +98,12 @@ public InputParser(Box options) { default: continue; } - + // Modify selected attributes. MiniBox atts = options.getAttValForId(id); for (String att : atts.getKeys()) { String val = atts.get(att); - + switch (att) { case "help": cmd.help = val; @@ -126,7 +127,7 @@ public InputParser(Box options) { break; } } - + allCommands.add(cmd); if (cmd.type != POSITION) { if (cmd.shortFlag != null) { @@ -139,90 +140,92 @@ public InputParser(Box options) { positionCommands.add(cmd); } } - + LOGGER.config("successfully configured command line parser\n\n" + this.toString()); } - + /** * Container class for arguments of a command. - *

- * 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: + * *

    - *
  • {@link CellListDeserializer} for deserializing a list of - * {@link CellContainer} instances
  • - *
  • {@link LocationListDeserializer} for deserializing a list of - * {@link LocationContainer} instances
  • + *
  • {@link CellListDeserializer} for deserializing a list of {@link CellContainer} instances + *
  • {@link LocationListDeserializer} for deserializing a list of {@link LocationContainer} + * instances *
*/ - 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> { @Override - public ArrayList deserialize(JsonElement json, Type typeOfT, - JsonDeserializationContext context) + public ArrayList deserialize( + JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { ArrayList cells = new ArrayList<>(); JsonArray jsonArray = json.getAsJsonArray(); - + for (JsonElement element : jsonArray) { JsonObject cell = element.getAsJsonObject(); CellContainer cont = context.deserialize(cell, CellContainer.class); cells.add(cont); } - + return cells; } } - - /** - * Deserializer for a list of {@link LocationContainer} objects. - */ + + /** Deserializer for a list of {@link LocationContainer} objects. */ public static final class LocationListDeserializer implements JsonDeserializer> { @Override - public ArrayList deserialize(JsonElement json, Type typeOfT, - JsonDeserializationContext context) + public ArrayList deserialize( + JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { ArrayList locations = new ArrayList<>(); JsonArray jsonArray = json.getAsJsonArray(); - + for (JsonElement element : jsonArray) { JsonObject location = element.getAsJsonObject(); LocationContainer cont = context.deserialize(location, LocationContainer.class); locations.add(cont); } - + return locations; } } diff --git a/src/arcade/core/sim/output/OutputLoader.java b/src/arcade/core/sim/output/OutputLoader.java index c21700b1d..5a26b5a3e 100644 --- a/src/arcade/core/sim/output/OutputLoader.java +++ b/src/arcade/core/sim/output/OutputLoader.java @@ -17,62 +17,60 @@ /** * Custom loader for deserializing objects from JSON. - *

- * 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 loadCells() { return gson.fromJson(cellJson, DEFAULT_CELL_TYPE); } - + /** * Loads the JSON for a list of {@link LocationContainer} objects. * - * @return a list of {@link LocationContainer} objects + * @return a list of {@link LocationContainer} objects */ public ArrayList loadLocations() { return gson.fromJson(locationJson, DEFAULT_LOCATION_TYPE); } - + /** * Reads the contents of the given file path. * - * @param filepath the path for the file - * @return the contents of the path, {@code null} if unable to read + * @param filepath the path for the file + * @return the contents of the path, {@code null} if unable to read */ String read(String filepath) { try { @@ -115,18 +113,18 @@ String read(String filepath) { File infile = new File(filepath); FileInputStream fis = new FileInputStream(infile); BufferedReader br = new BufferedReader(new InputStreamReader(fis)); - + // Write contents StringBuilder contents = new StringBuilder(); String line; while ((line = br.readLine()) != null) { contents.append(line); } - + // Close streams. br.close(); fis.close(); - + LOGGER.info("file [ " + filepath + " ] successfully read"); return contents.toString(); } catch (IOException ex) { diff --git a/src/arcade/core/sim/output/OutputSaver.java b/src/arcade/core/sim/output/OutputSaver.java index 3749b7ac9..de75865ad 100644 --- a/src/arcade/core/sim/output/OutputSaver.java +++ b/src/arcade/core/sim/output/OutputSaver.java @@ -19,95 +19,92 @@ /** * Custom saver for serializing objects to JSON. - *

- * 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: + * *

    - *
  • {@code SeriesSerializer} for serializing {@link Series}
  • - *
  • {@code MiniBoxSerializer} for serializing {@link MiniBox}
  • - *
  • {@code CellListSerializer} for serializing a list of - * {@link CellContainer}
  • - *
  • {@code LocationListSerializer} for serializing a list of - * {@link LocationContainer}
  • + *
  • {@code SeriesSerializer} for serializing {@link Series} + *
  • {@code MiniBoxSerializer} for serializing {@link MiniBox} + *
  • {@code CellListSerializer} for serializing a list of {@link CellContainer} + *
  • {@code LocationListSerializer} for serializing a list of {@link LocationContainer} *
*/ - 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. - *

- * The contents of the box are formatted as: + * + *

The contents of the box are formatted as: + * *

      *     {
      *         "(key)" : (value),
@@ -74,13 +71,13 @@ public static GsonBuilder makeGSONBuilder() {
      */
     public static final class MiniBoxSerializer implements JsonSerializer {
         @Override
-        public JsonElement serialize(MiniBox src, Type typeOfSrc,
-                                     JsonSerializationContext context) {
+        public JsonElement serialize(
+                MiniBox src, Type typeOfSrc, JsonSerializationContext context) {
             JsonObject json = new JsonObject();
-            
+
             for (String key : src.getKeys()) {
                 String value = src.get(key);
-                
+
                 if (value.matches(INTEGER_REGEX)) {
                     json.addProperty(key, src.getInt(key));
                 } else if (value.matches(DOUBLE_REGEX)) {
@@ -89,15 +86,16 @@ public JsonElement serialize(MiniBox src, Type typeOfSrc,
                     json.addProperty(key, value);
                 }
             }
-            
+
             return json;
         }
     }
-    
+
     /**
      * Serializer for {@link Series} objects.
-     * 

- * The series object is formatted as: + * + *

The series object is formatted as: + * *

      *     {
      *         "version": (version),
@@ -125,26 +123,25 @@ public JsonElement serialize(MiniBox src, Type typeOfSrc,
      */
     public static final class SeriesSerializer implements JsonSerializer {
         @Override
-        public JsonElement serialize(Series src, Type typeOfSrc,
-                                     JsonSerializationContext context) {
+        public JsonElement serialize(Series src, Type typeOfSrc, JsonSerializationContext context) {
             JsonObject json = new JsonObject();
-            
+
             json.addProperty("version", ARCADE.VERSION);
-            
+
             JsonObject conversions = new JsonObject();
             conversions.addProperty("DS", src.ds);
             conversions.addProperty("DT", src.dt);
             json.add("conversions", conversions);
-            
+
             json.addProperty("ticks", src.getTicks());
-            
+
             JsonObject size = new JsonObject();
             size.addProperty("length", src.length);
             size.addProperty("width", src.width);
             size.addProperty("height", src.height);
             size.addProperty("margin", src.margin);
             json.add("size", size);
-            
+
             // Add population parameters.
             JsonObject populations = new JsonObject();
             List keys = new ArrayList<>(src.populations.keySet());
@@ -154,15 +151,16 @@ public JsonElement serialize(Series src, Type typeOfSrc,
                 populations.add(pop, population);
             }
             json.add("populations", populations);
-            
+
             return json;
         }
     }
-    
+
     /**
      * Serializer for a list of {@link CellContainer} objects.
-     * 

- * The series object is formatted as: + * + *

The series object is formatted as: + * *

      *     [
      *         (serialized cell container),
@@ -174,23 +172,24 @@ public JsonElement serialize(Series src, Type typeOfSrc,
     public static final class CellListSerializer
             implements JsonSerializer> {
         @Override
-        public JsonElement serialize(ArrayList src, Type typeOfSrc,
-                                     JsonSerializationContext context) {
+        public JsonElement serialize(
+                ArrayList src, Type typeOfSrc, JsonSerializationContext context) {
             JsonArray json = new JsonArray();
-            
+
             for (CellContainer cellContainer : src) {
                 JsonElement cell = context.serialize(cellContainer, CellContainer.class);
                 json.add(cell);
             }
-            
+
             return json;
         }
     }
-    
+
     /**
      * Serializer for a list of {@link LocationContainer} objects.
-     * 

- * The series object is formatted as: + * + *

The series object is formatted as: + * *

      *     [
      *         (serialized location container),
@@ -202,16 +201,18 @@ public JsonElement serialize(ArrayList src, Type typeOfSrc,
     public static final class LocationListSerializer
             implements JsonSerializer> {
         @Override
-        public JsonElement serialize(ArrayList src, Type typeOfSrc,
-                                     JsonSerializationContext context) {
+        public JsonElement serialize(
+                ArrayList src,
+                Type typeOfSrc,
+                JsonSerializationContext context) {
             JsonArray json = new JsonArray();
-            
+
             for (LocationContainer locationContainer : src) {
-                JsonElement location = context.serialize(locationContainer,
-                        LocationContainer.class);
+                JsonElement location =
+                        context.serialize(locationContainer, LocationContainer.class);
                 json.add(location);
             }
-            
+
             return json;
         }
     }
diff --git a/src/arcade/core/util/Box.java b/src/arcade/core/util/Box.java
index 9a7f73d2d..f0490dc76 100644
--- a/src/arcade/core/util/Box.java
+++ b/src/arcade/core/util/Box.java
@@ -5,72 +5,77 @@
 
 /**
  * Container that maps a key to a tag category and a series of attributes.
- * 

- * {@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 keys; - + /** Map of id to tag. */ final MiniBox idToTag; - + /** Map of id to value. */ final MiniBox idToVal; - - /** - * Creates a {@code Box} object. - */ + + /** Creates a {@code Box} object. */ public Box() { keys = new ArrayList<>(); idToTag = new MiniBox(); idToVal = new MiniBox(); } - + /** * Checks if the given key exists. * - * @param id the key - * @return {@code true} if the key exists, {@code false} otherwise + * @param id the key + * @return {@code true} if the key exists, {@code false} otherwise */ - public boolean contains(String id) { return keys.contains(id); } - + public boolean contains(String id) { + return keys.contains(id); + } + /** * Gets list of keys in the box. * - * @return the list of keys + * @return the list of keys */ - public ArrayList getKeys() { return keys; } - + public ArrayList getKeys() { + return keys; + } + /** * Gets the value for the given key. * - * @param key the key - * @return the entry + * @param key the key + * @return the entry */ - public String getValue(String key) { return idToVal.get(key); } - + public String getValue(String key) { + return idToVal.get(key); + } + /** * Gets the tag for a given key. * - * @param key the key - * @return the tag + * @param key the key + * @return the tag */ - public String getTag(String key) { return idToTag.get(key); } - + public String getTag(String key) { + return idToTag.get(key); + } + /** * Adds tag category for a given id. - *

- * 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 filterTags(String tag) { HashSet result = new HashSet<>(); - + for (String key : idToTag.getKeys()) { if (idToTag.get(key).equals(tag)) { result.add(key); } } - + return result; } - + /** * Filters box by entries matching the given tag. * - * @param tag the tag - * @return a box containing filtered entries + * @param tag the tag + * @return a box containing filtered entries */ public Box filterBoxByTag(String tag) { Box result = new Box(); - + // Check each key to see if tag matches given tag. for (String key : idToVal.getKeys()) { String[] split = key.split(KEY_SEPARATOR); @@ -202,27 +209,27 @@ public Box filterBoxByTag(String tag) { result.add(key, idToVal.get(key)); } } - + return result; } - + /** * Filters box by entries matching the given attribute. * - * @param att the attribute - * @return a box containing filtered entries + * @param att the attribute + * @return a box containing filtered entries */ public Box filterBoxByAtt(String att) { Box result = new Box(); ArrayList ids = new ArrayList<>(); - + // Get list of ids matching given attribute value. for (String key : keys) { if (idToVal.contains(key + KEY_SEPARATOR + att)) { ids.add(key); } } - + // Add all entries for the key to the new box. for (String key : idToVal.getKeys()) { String[] split = key.split(KEY_SEPARATOR); @@ -232,24 +239,24 @@ public Box filterBoxByAtt(String att) { result.add(key, idToVal.get(key)); } } - + return result; } - + /** * Compares two {@code Box} instances. * - * @param box the {@code Box} to compare to - * @return {@code true} if entries match, {@code false} otherwise + * @param box the {@code Box} to compare to + * @return {@code true} if entries match, {@code false} otherwise */ public boolean compare(Box box) { return idToTag.compare(box.idToTag) && idToVal.compare(box.idToVal); } - + /** * Formats the {@code Box} as a string. * - * @return the string + * @return the string */ public String toString() { String format = "\t[%s] %s\n"; diff --git a/src/arcade/core/util/Colors.java b/src/arcade/core/util/Colors.java index 686758e8a..2b853f27e 100644 --- a/src/arcade/core/util/Colors.java +++ b/src/arcade/core/util/Colors.java @@ -5,48 +5,49 @@ /** * Implementation of {@code ColorMap} for discrete and continuous colors. - *

- * 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: + * + *

    + *
  • P(A) = a / (a + b + c) + *
  • P(B) = b / (a + b + c) + *
  • P(C) = c / (a + b + c) + *
+ */ +public class GrabBag { + /** Map of cumulative weights to items. */ + private final NavigableMap map; + + /** Total weight of items in bag. */ + private double totalWeight; + + /** Creates a {@code GrabBag} object. */ + public GrabBag() { + map = new TreeMap<>(); + totalWeight = 0; + } + + /** + * Add item with given weight to bag. + * + * @param item the item to add + * @param weight the item weight + */ + public void add(int item, double weight) { + if (weight <= 0) { + return; + } + + totalWeight += weight; + map.put(totalWeight, item); + } + + /** + * Get an item from the bag with weighted probabilities. + * + * @param random the random number generator + * @return the selected item + */ + public int next(MersenneTwisterFast random) { + double value = random.nextDouble() * totalWeight; + return map.higherEntry(value).getValue(); + } + + /** + * Gets hash based on total weight and mapping. + * + * @return the hash + */ + public int hashCode() { + return (int) totalWeight + map.hashCode(); + } + + /** + * Checks if two bags have the same mappings. + * + * @param obj the bags to compare + * @return {@code true} if bags are the same, {@code false} otherwise + */ + public boolean equals(Object obj) { + if (!(obj instanceof GrabBag)) { + return false; + } + GrabBag grabbag = (GrabBag) obj; + return grabbag.totalWeight == totalWeight && grabbag.map.equals(map); + } +} diff --git a/src/arcade/core/util/Graph.java b/src/arcade/core/util/Graph.java index 6045eedd7..89c9dccaf 100644 --- a/src/arcade/core/util/Graph.java +++ b/src/arcade/core/util/Graph.java @@ -4,146 +4,203 @@ import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashSet; +import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Queue; import java.util.Set; import sim.util.Bag; /** * Container class for directed graph using nodes as hashes. - *

- * {@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 nodeToOutBag; - + /** Map of {@code Node} IN to bag of {@code Edge} objects. */ private final Map nodeToInBag; - - /** - * Creates an empty {@code Graph}. - */ + + /** Creates an empty {@code Graph}. */ public Graph() { allEdges = new Bag(); nodeToOutBag = new HashMap<>(); nodeToInBag = new HashMap<>(); } - + /** * Updates edges and nodes with contents of given graph. * - * @param graph the graph object + * @param graph the graph object */ public void update(Graph graph) { allEdges.addAll(graph.allEdges); nodeToOutBag.putAll(graph.nodeToOutBag); nodeToInBag.putAll(graph.nodeToInBag); } - - /** - * Clear edges and nodes from graph. - */ + + /** Clear edges and nodes from graph. */ public void clear() { allEdges.clear(); nodeToOutBag.clear(); nodeToInBag.clear(); } - + + /** + * Gets all nodes in the graph. + * + * @return a set containing the nodes + */ + public Set getAllNodes() { + return retrieveNodes(); + } + + /** + * Check to see if a graph contains a node. + * + * @param node the node to add + * @return {@code true} if node exists in graph, {@code false} otherwise + */ + public boolean contains(Node node) { + return getAllNodes().contains(node); + } + + /** + * Check to see if a graph contains an edge. + * + * @param edge the edge to add + * @return {@code true} if edge exists in graph, {@code false} otherwise + */ + public boolean contains(Edge edge) { + return checkEdge(edge); + } + /** * Gets all edges in the graph. * - * @return a bag containing the edges + * @return a bag containing the edges */ - public Bag getAllEdges() { return allEdges; } - + public Bag getAllEdges() { + return allEdges; + } + + /** + * Gets all edges in the graph based on the given node and category. + * + * @param node the node to get edges from + * @param strategy the category of edges to get + * @return a bag containing the edges + */ + public Bag getEdges(Node node, Strategy strategy) { + return (strategy == Strategy.UPSTREAM) ? nodeToInBag.get(node) : nodeToOutBag.get(node); + } + /** * Gets edges out of the given node. * - * @param node the node that edges are from - * @return a bag containing the edges + * @param node the node that edges are from + * @return a bag containing the edges */ - public Bag getEdgesOut(Node node) { return nodeToOutBag.get(node); } - + public Bag getEdgesOut(Node node) { + return getEdges(node, Strategy.DOWNSTREAM); + } + /** * Gets edges into the given node. * - * @param node the node that edges are to - * @return a bag containing the edges + * @param node the node that edges are to + * @return a bag containing the edges */ - public Bag getEdgesIn(Node node) { return nodeToInBag.get(node); } - + public Bag getEdgesIn(Node node) { + return getEdges(node, Strategy.UPSTREAM); + } + /** * Gets the in degree at the given node. * - * @param node the node - * @return the in degree + * @param node the node + * @return the in degree */ public int getInDegree(Node node) { return nodeToInBag.containsKey(node) ? nodeToInBag.get(node).numObjs : 0; } - + /** * Gets the out degree at the given node. * - * @param node the node - * @return the out degree + * @param node the node + * @return the out degree */ public int getOutDegree(Node node) { return nodeToOutBag.containsKey(node) ? nodeToOutBag.get(node).numObjs : 0; } - + /** * Gets the total degree (in degree + out degree) at the given node. * - * @param node the node - * @return the degree + * @param node the node + * @return the degree */ - public int getDegree(Node node) { return getInDegree(node) + getOutDegree(node); } - + public int getDegree(Node node) { + return getInDegree(node) + getOutDegree(node); + } + /** * Checks if the graph has an edge between the given nodes. * - * @param from the node the edge points from - * @param to the node the edge points to - * @return {@code true} if edge exists, {@code false} otherwise + * @param from the node the edge points from + * @param to the node the edge points to + * @return {@code true} if edge exists, {@code false} otherwise */ public boolean hasEdge(Node from, Node to) { - Bag bag = getEdgesOut(from); - if (bag == null) { - return false; - } - for (Object obj : bag) { - if (to.equals(((Edge) obj).to)) { - return true; - } - } - return false; + Edge e = new Edge(from, to); + return checkEdge(e); } - + + /** + * Checks if the graph has an edge. + * + * @param edge the edge + * @return {@code true} if edge exists, {@code false} otherwise + */ + private boolean checkEdge(Edge edge) { + return allEdges.contains(edge); + } + /** Defines a filter for edges in a graph. */ public interface GraphFilter { /** * Applies filter to an {link Edge} object. * - * @param edge the edge - * @return {@code true} if edge passes filter, {@code false} otherwise + * @param edge the edge + * @return {@code true} if edge passes filter, {@code false} otherwise */ boolean filter(Edge edge); } - + /** * Filters this graph for edges and copies them to the given graph object. - *

- * 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 retrieveNodes() { Set sOut = nodeToOutBag.keySet(); Set sIn = nodeToInBag.keySet(); - Set set = new LinkedHashSet() { - { - addAll(sOut); - addAll(sIn); - } - }; - + Set set = + new LinkedHashSet() { + { + addAll(sOut); + addAll(sIn); + } + }; + + return set; + } + + /** Sets the TO and FROM nodes for edges to be the same object. */ + public void mergeNodes() { + Set set = retrieveNodes(); for (Node obj : set) { Node join = obj.duplicate(); Bag out = getEdgesOut(obj); Bag in = getEdgesIn(obj); - + // Iterate through all edges OUT of node. if (out != null) { for (Object x : out) { @@ -181,7 +247,7 @@ public void mergeNodes() { e.setFrom(join); } } - + // Iterate through all edges IN to node. if (in != null) { for (Object x : in) { @@ -191,24 +257,35 @@ public void mergeNodes() { } } } - + + /** + * Adds edge to graph based on nodes. + * + * @param from the node to add as the from node. + * @param to the node to add as the to node. + */ + public void addEdge(Node from, Node to) { + addEdge(new Edge(from, to)); + } + /** * Adds edge to graph. * - * @param edge the edge to add + * @param edge the edge to add */ public void addEdge(Edge edge) { allEdges.add(edge); setOutMap(edge.getFrom(), edge); setInMap(edge.getTo(), edge); setLinks(edge); + mergeNodes(); } - + /** * Adds the edge to the bag for the mapping of OUT node to edge. * - * @param node the node hash - * @param edge the edge + * @param node the node hash + * @param edge the edge */ private void setOutMap(Node node, Edge edge) { Bag objs = nodeToOutBag.get(node); @@ -218,12 +295,12 @@ private void setOutMap(Node node, Edge edge) { } objs.add(edge); } - + /** * Adds the edge to the bag for the mapping of IN node to edge. * - * @param node the node hash - * @param edge the edge + * @param node the node hash + * @param edge the edge */ private void setInMap(Node node, Edge edge) { Bag objs = nodeToInBag.get(node); @@ -233,13 +310,13 @@ private void setInMap(Node node, Edge edge) { } objs.add(edge); } - + /** * Adds links between edges in and out of the nodes for a given edge. * - * @param edge the edge + * @param edge the edge */ - public void setLinks(Edge edge) { + private void setLinks(Edge edge) { Bag outTo = getEdgesOut(edge.getTo()); if (outTo != null) { for (Object obj : outTo) { @@ -252,7 +329,7 @@ public void setLinks(Edge edge) { } } } - + Bag inFrom = getEdgesIn(edge.getFrom()); if (inFrom != null) { for (Object obj : inFrom) { @@ -266,11 +343,11 @@ public void setLinks(Edge edge) { } } } - + /** * Removes edge from graph. * - * @param edge the edge to remove + * @param edge the edge to remove */ public void removeEdge(Edge edge) { allEdges.remove(edge); @@ -278,12 +355,12 @@ public void removeEdge(Edge edge) { unsetInMap(edge.getTo(), edge); unsetLinks(edge); } - + /** * Removes the edge from the bag for the mapping of OUT node to edge. * - * @param node the node hash - * @param edge the edge + * @param node the node hash + * @param edge the edge */ private void unsetOutMap(Node node, Edge edge) { Bag objs = nodeToOutBag.get(node); @@ -292,12 +369,12 @@ private void unsetOutMap(Node node, Edge edge) { nodeToOutBag.remove(node); } } - + /** * Removes the edge from the bag for the mapping of IN node to edge. * - * @param node the node hash - * @param edge the edge + * @param node the node hash + * @param edge the edge */ private void unsetInMap(Node node, Edge edge) { Bag objs = nodeToInBag.get(node); @@ -306,11 +383,11 @@ private void unsetInMap(Node node, Edge edge) { nodeToInBag.remove(node); } } - + /** * Removes links between edges in and out of the nodes for a given edge. * - * @param edge the edge + * @param edge the edge */ private void unsetLinks(Edge edge) { Bag outTo = getEdgesOut(edge.getTo()); @@ -321,7 +398,7 @@ private void unsetLinks(Edge edge) { edge.edgesOut.remove(e); } } - + Bag inFrom = getEdgesIn(edge.getFrom()); if (inFrom != null) { for (Object obj : inFrom) { @@ -331,30 +408,157 @@ private void unsetLinks(Edge edge) { } } } - + + /** + * Clear an edge's links to other edges. + * + * @param edge the edge + */ + public void clearEdge(Edge edge) { + edge.clear(); + } + + /** + * Find the first downstream node where two edges intersect. + * + * @param edge1 first edge to start from + * @param edge2 second edge to start from + * @return the intersection node or null if no intersection + */ + public Node findDownstreamIntersection(Edge edge1, Edge edge2) { + return findIntersection(edge1, edge2, Strategy.DOWNSTREAM); + } + + /** + * Find the first upstream node where two edges intersect. + * + * @param edge1 first edge to start from + * @param edge2 second edge to start from + * @return the intersection node or null if no intersection + */ + public Node findUpstreamIntersection(Edge edge1, Edge edge2) { + return findIntersection(edge1, edge2, Strategy.UPSTREAM); + } + + /** + * Find the first node where two edges intersect based on a calulcation strategy (upstream or + * downstream). + * + * @param edge1 first edge to start from + * @param edge2 second edge to start from + * @param strategy the direction to search + * @return the intersection node or null if no intersection + */ + private Node findIntersection(Edge edge1, Edge edge2, Strategy strategy) { + if (edge1.getNode(strategy).equals(edge2.getNode(strategy))) { + return edge1.getNode(strategy); + } + Bag allConnected = getConnectedNodes(edge1.getNode(strategy), strategy); + if (allConnected == null) { + return null; + } + Node intersection = breadthFirstSearch(edge2.getNode(strategy), allConnected, strategy); + return intersection; + } + + /** + * Get all nodes connected to the given node based on a calculation strategy (e.g. upstream or + * downstream). + * + * @param node the node to start from + * @param strategy the direction to search + * @return a bag of connected nodes + */ + private Bag getConnectedNodes(Node node, Strategy strategy) { + Bag first = getEdges(node, strategy); + if (first == null) { + return null; + } + Bag visited = new Bag(); + Queue queue = new LinkedList<>(); + for (Object e : first) { + Edge edge = (Edge) e; + queue.add(edge.getNode(strategy)); + } + + while (!queue.isEmpty()) { + Node active = queue.poll(); + visited.add(active); + if (getEdges(active, strategy) == null) { + continue; + } + for (Object next : getEdges(active, strategy)) { + Edge edge = (Edge) next; + if (!visited.contains(edge.getNode(strategy))) { + queue.add(edge.getNode(strategy)); + } + } + } + return visited; + } + + /** + * Breadth first search from node according to strategy for a subset of target nodes. + * + * @param node the node to start from + * @param targetNodes the bag of potential intersection nodes + * @param strategy the direction to search + * @return the target node or null if not found + */ + private Node breadthFirstSearch(Node node, Bag targetNodes, Strategy strategy) { + Bag first = getEdges(node, strategy); + if (first == null) { + return null; + } + Bag visited = new Bag(); + Queue queue = new LinkedList<>(); + for (Object e : first) { + Edge edge = (Edge) e; + queue.add(edge.getNode(strategy)); + } + + while (!queue.isEmpty()) { + Node active = queue.poll(); + visited.add(active); + if (targetNodes.contains(active)) { + return active; + } + if (getEdges(active, strategy) == null) { + continue; + } + for (Object next : getEdges(active, strategy)) { + Edge edge = (Edge) next; + if (!visited.contains(edge.getNode(strategy))) { + queue.add(edge.getNode(strategy)); + } + } + } + return null; + } + /** * Removes the given edge and adds the reversed edge. * - * @param edge the edge to reverse + * @param edge the edge to reverse */ public void reverseEdge(Edge edge) { removeEdge(edge); addEdge(edge.reverse()); } - + /** * Displays the graph as a list of edges and nodes. * - * @return the string representation of the graph + * @return the string representation of the graph */ public String toString() { String s = ""; - + s += "\nEDGES OUT\n\n"; Set setFrom = nodeToOutBag.keySet(); List sortedFrom = new ArrayList<>(setFrom); Collections.sort(sortedFrom); - + for (Object obj : sortedFrom) { Bag b = nodeToOutBag.get(obj); s += obj.toString() + " : "; @@ -363,12 +567,12 @@ public String toString() { } s += "\n"; } - + s += "\nEDGES IN\n\n"; Set setTo = nodeToInBag.keySet(); List sortedTo = new ArrayList<>(setTo); Collections.sort(sortedTo); - + for (Object obj : sortedTo) { Bag b = nodeToInBag.get(obj); s += obj.toString() + " : "; @@ -377,108 +581,117 @@ public String toString() { } s += "\n"; } - + return s; } - + /** * Nested class representing a graph node. - *

- * 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 { + public static class Node implements Comparable { /** Coordinate in x direction. */ protected int x; - + /** Coordinate in y direction. */ protected int y; - + /** Coordinate in z direction. */ protected int z; - + /** * Creates a {@code Node} at the given coordinates. * - * @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 */ public Node(int x, int y, int z) { this.x = x; this.y = y; this.z = z; } - + /** * Gets the x coordinate of the node. * - * @return the x coordinate + * @return the x coordinate */ - public int getX() { return x; } - + public int getX() { + return x; + } + /** * Gets the y coordinate of the node. * - * @return the y coordinate + * @return the y coordinate */ - public int getY() { return y; } - + public int getY() { + return y; + } + /** * Gets the z coordinate of the node. * - * @return the z coordinate + * @return the z coordinate */ - public int getZ() { return z; } - + public int getZ() { + return z; + } + /** * Compares a node to this node. * - * @param node the node to compare - * @return zero if the x and y coordinates are equal, otherwise the - * result of integer comparison for x and y + * @param node the node to compare + * @return zero if the x and y coordinates are equal, otherwise the result of integer + * comparison for x and y */ public int compareTo(Node node) { int xComp = Integer.compare(x, node.getX()); int yComp = Integer.compare(y, node.getY()); - + if (xComp == 0) { return yComp; } else { return xComp; } } - + /** * Creates a duplicate node with the same coordinates. * - * @return a {@code Node} copy + * @return a {@code Node} copy */ - public abstract Node duplicate(); - + public Node duplicate() { + return new Node(x, y, z); + } + /** - * Updates the position of this {@code Node} with coordinate from given - * {@code Node}. + * Updates the position of this {@code Node} with coordinate from given {@code Node}. * - * @param node the {@code Node} with coordinates to update with + * @param node the {@code Node} with coordinates to update with */ public void update(Node node) { this.x = node.x; this.y = node.y; this.z = node.z; } - + /** * Specifies object hashing based on coordinates. * - * @return a hash based on coordinates + * @return a hash based on coordinates */ - public final int hashCode() { return x + y << 8 + z << 16; } - + public final int hashCode() { + return x + y << 8 + z << 16; + } + /** * Checks if two nodes are equal based on coordinates. * - * @param obj the object to check - * @return {@code true} if coordinates match, {@code false} otherwise + * @param obj the object to check + * @return {@code true} if coordinates match, {@code false} otherwise */ public final boolean equals(Object obj) { if (obj instanceof Node) { @@ -487,41 +700,41 @@ public final boolean equals(Object obj) { } return false; } - + /** * Formats node as a string. * - * @return a string representation of the node + * @return a string representation of the node */ public String toString() { return "(" + x + "," + y + "," + z + ")"; } } - + /** * Nested class representing a graph edge. - *

- * 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 edgesIn; - + /** List of edges that point out of the node this edge points to. */ private final ArrayList edgesOut; - + /** * Creates an {@code Edge} between two {@link Node} objects. * - * @param from the node the edge is from - * @param to the node the edge is to + * @param from the node the edge is from + * @param to the node the edge is to */ public Edge(Node from, Node to) { this.from = from.duplicate(); @@ -529,53 +742,86 @@ public Edge(Node from, Node to) { edgesIn = new ArrayList<>(); edgesOut = new ArrayList<>(); } - + + /** + * Gets the node the edge points to based on the calculation strategy (e.g. upstream or + * downstream). + * + * @param strategy the calculation strategy + * @return the node the edge points to + */ + public Node getNode(Strategy strategy) { + return (strategy == Strategy.UPSTREAM) ? from : to; + } + /** * Gets the node the edge points from. * - * @return the node the edge points from + * @return the node the edge points from */ - public Node getFrom() { return from; } - + public Node getFrom() { + return from; + } + /** * Gets the node the edge points to. * - * @return the node the edge points to + * @return the node the edge points to */ - public Node getTo() { return to; } - + public Node getTo() { + return to; + } + /** * Sets the node the edge points to. * - * @param to the node the edge points to + * @param to the node the edge points to */ - public void setTo(Node to) { this.to = to; } - + public void setTo(Node to) { + this.to = to; + } + /** * Sets the node the edge points from. * - * @param from the node the edge points from + * @param from the node the edge points from + */ + public void setFrom(Node from) { + this.from = from; + } + + /** + * Gets list of edges based on calculation strategy (e.g. upstream or downstream). + * + * @param strategy the calculation strategy + * @return the list of edges */ - public void setFrom(Node from) { this.from = from; } - + public ArrayList getEdges(Strategy strategy) { + return (strategy == Strategy.UPSTREAM) ? edgesIn : edgesOut; + } + /** * Gets list of edges that point into the node this edge points from. * - * @return the list of edges + * @return the list of edges */ - public ArrayList getEdgesIn() { return edgesIn; } - + public ArrayList getEdgesIn() { + return getEdges(Strategy.UPSTREAM); + } + /** * Gets list of edges that point out of the node this edge points to. * - * @return the list of edges + * @return the list of edges */ - public ArrayList getEdgesOut() { return edgesOut; } - + public ArrayList getEdgesOut() { + return getEdges(Strategy.DOWNSTREAM); + } + /** * Reverses the edge by swapping the nodes. * - * @return the reversed edge + * @return the reversed edge */ Edge reverse() { Node tempTo = to; @@ -584,22 +830,43 @@ Edge reverse() { from = tempTo; return this; } - - /** - * Removes the linked edges. - */ + + /** Removes the linked edges. */ public void clear() { edgesIn.clear(); edgesOut.clear(); } - + /** * Formats edge as a string. * - * @return a string representation of the edge + * @return a string representation of the edge */ public String toString() { return "[" + from.toString() + "~" + to.toString() + "]"; } + + /** + * Checks if two nodes are equal based on to and from nodes. + * + * @param obj the object to check + * @return {@code true} if coordinates of both nodes match, {@code false} otherwise + */ + public boolean equals(Object obj) { + if (obj instanceof Edge) { + Edge edge = (Edge) obj; + return to.equals(edge.to) && from.equals(edge.from); + } + return false; + } + + /** + * Specifies object hashing based on from and to coordinates. + * + * @return a hash based on coordinates + */ + public final int hashCode() { + return this.from.hashCode() << 16 + this.to.hashCode() << 16; + } } } diff --git a/src/arcade/core/util/Matrix.java b/src/arcade/core/util/Matrix.java index 88c0424fe..cc7562216 100644 --- a/src/arcade/core/util/Matrix.java +++ b/src/arcade/core/util/Matrix.java @@ -4,101 +4,107 @@ /** * Container class for dense and sparse matrix representations. - *

- * 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 toSparse(double[][] mat) { ArrayList a = new ArrayList<>(); int n = mat.length; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { - if (mat[i][j] != 0) { a.add(new Value(i, j, mat[i][j])); } + if (mat[i][j] != 0) { + a.add(new Value(i, j, mat[i][j])); + } } } return a; } - + /** * Converts a sparse matrix representation to a dense matrix representation. * - * @param mat the sparse matrix representation - * @return the dense matrix representation + * @param mat the sparse matrix representation + * @return the dense matrix representation */ public static double[][] toDense(ArrayList mat) { int n = 0; for (Value v : mat) { - if (v.i > n) { n = v.i; } - if (v.j > n) { n = v.j; } + if (v.i > n) { + n = v.i; + } + if (v.j > n) { + n = v.j; + } } double[][] a = new double[n + 1][n + 1]; for (Value v : mat) { @@ -106,12 +112,12 @@ public static double[][] toDense(ArrayList mat) { } return a; } - + /** * Inverts a upper triangular matrix. * - * @param mat the upper triangular matrix to invert - * @return the inverted matrix + * @param mat the upper triangular matrix to invert + * @return the inverted matrix */ public static double[][] invertUpper(double[][] mat) { int n = mat.length; @@ -120,24 +126,28 @@ public static double[][] invertUpper(double[][] mat) { for (int i = 0; i < k; i++) { for (int j = 0; j < k; j++) { inv[i][k] = inv[i][k] + inv[i][j] * mat[j][k]; - if (inv[i][k] == -0.0) { inv[i][k] = 0; } + if (inv[i][k] == -0.0) { + inv[i][k] = 0; + } } } for (int j = 0; j < k; j++) { inv[j][k] = -inv[j][k] / mat[k][k]; - if (inv[j][k] == -0.0) { inv[j][k] = 0; } + if (inv[j][k] == -0.0) { + inv[j][k] = 0; + } } - + inv[k][k] = 1.0 / mat[k][k]; } return inv; } - + /** * Inverts a lower triangular matrix. * - * @param mat the lower triangular matrix to invert - * @return the inverted matrix + * @param mat the lower triangular matrix to invert + * @return the inverted matrix */ public static double[][] invertLower(double[][] mat) { int n = mat.length; @@ -146,28 +156,31 @@ public static double[][] invertLower(double[][] mat) { for (int i = 0; i < k; i++) { for (int j = 0; j < k; j++) { inv[k][i] = inv[k][i] + inv[j][i] * mat[k][j]; - if (inv[k][i] == -0.0) { inv[k][i] = 0; } + if (inv[k][i] == -0.0) { + inv[k][i] = 0; + } } } for (int j = 0; j < k; j++) { inv[k][j] = -inv[k][j] / mat[k][k]; - if (inv[k][j] == -0.0) { inv[k][j] = 0; } + if (inv[k][j] == -0.0) { + inv[k][j] = 0; + } } - + inv[k][k] = 1.0 / mat[k][k]; } return inv; } - + /** - * Solves the equation {@code Lx = b} using forward substitution for a - * dense matrix. - *

- * 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 mat, double[] vec) { - mat.sort((v1, v2) -> - (v1.i == v2.i ? Integer.compare(v1.j, v2.j) : (v1.i > v2.i ? 1 : -1))); - + mat.sort((v1, v2) -> (v1.i == v2.i ? Integer.compare(v1.j, v2.j) : (v1.i > v2.i ? 1 : -1))); + int n = vec.length; double[] subbed = new double[n]; double[] diag = new double[n]; - + // Group lower diagonal by row. ArrayList> rowsL = new ArrayList<>(); for (int r = 0; r < n; r++) { @@ -235,12 +245,14 @@ public static double[] forwardSubstitution(ArrayList mat, double[] vec) { for (Value v : mat) { rowsL.get(v.i).add(v); } - + // Get values along diagonal. for (Value v : mat) { - if (v.i == v.j) { diag[v.i] = v.v; } + if (v.i == v.j) { + diag[v.i] = v.v; + } } - + // Iterate only through non-zero entries in the lower diagonal matrix. for (int i = 0; i < n; i++) { ArrayList rowL = rowsL.get(i); @@ -251,30 +263,28 @@ public static double[] forwardSubstitution(ArrayList mat, double[] vec) { val = vec[i] - val; subbed[i] = val / diag[i]; } - + return subbed; } - + /** - * Solves the equation {@code Lx = U} using forward substitution for a - * sparse 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 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 forwardSubstitution(ArrayList mat) { - mat.sort((v1, v2) -> - (v1.i == v2.i ? Integer.compare(v1.j, v2.j) : (v1.i > v2.i ? 1 : -1))); - + mat.sort((v1, v2) -> (v1.i == v2.i ? Integer.compare(v1.j, v2.j) : (v1.i > v2.i ? 1 : -1))); + double[][] upper = getUpper(toDense(mat), true); ArrayList lower = getLower(mat, true); int n = upper.length; double[][] subbed = new double[n][n]; double[] diag = new double[n]; - + // Group lower diagonal by row. ArrayList> rows = new ArrayList<>(); for (int r = 0; r < n; r++) { @@ -283,12 +293,14 @@ public static ArrayList forwardSubstitution(ArrayList mat) { for (Value v : lower) { rows.get(v.i).add(v); } - + // Get values along diagonal. for (Value v : mat) { - if (v.i == v.j) { diag[v.i] = v.v; } + if (v.i == v.j) { + diag[v.i] = v.v; + } } - + // Iterate only through non-zero entries in the lower diagonal matrix. for (int i = 0; i < n; i++) { ArrayList row = rows.get(i); @@ -301,16 +313,16 @@ public static ArrayList forwardSubstitution(ArrayList mat) { subbed[i][j] = val / diag[i]; } } - + return toSparse(subbed); } - + /** * Gets the upper triangular of a dense matrix. * - * @param mat the matrix - * @param strict {@code true} if triangular is strict, {@code false} otherwise - * @return the upper triangular matrix + * @param mat the matrix + * @param strict {@code true} if triangular is strict, {@code false} otherwise + * @return the upper triangular matrix */ public static double[][] getUpper(double[][] mat, boolean strict) { int n = mat.length; @@ -323,13 +335,13 @@ public static double[][] getUpper(double[][] mat, boolean strict) { } return upper; } - + /** * Gets the lower triangular of a dense matrix. * - * @param mat the matrix - * @param strict {@code true} if triangular is strict, {@code false} otherwise - * @return the lower triangular matrix + * @param mat the matrix + * @param strict {@code true} if triangular is strict, {@code false} otherwise + * @return the lower triangular matrix */ public static double[][] getLower(double[][] mat, boolean strict) { int n = mat.length; @@ -342,45 +354,49 @@ public static double[][] getLower(double[][] mat, boolean strict) { } return lower; } - + /** * Gets the upper triangular of a sparse matrix. * - * @param mat the matrix - * @param strict {@code true} if triangular is strict, {@code false} otherwise - * @return the upper triangular matrix + * @param mat the matrix + * @param strict {@code true} if triangular is strict, {@code false} otherwise + * @return the upper triangular matrix */ public static ArrayList getUpper(ArrayList mat, boolean strict) { ArrayList upper = new ArrayList<>(); int off = (strict ? 0 : 1); for (Value v : mat) { - if (v.j > v.i - off) { upper.add(v); } + if (v.j > v.i - off) { + upper.add(v); + } } return upper; } - + /** * Gets the lower triangular of a sparse matrix. * - * @param mat the matrix - * @param strict {@code true} if triangular is strict, {@code false} otherwise - * @return the lower triangular matrix + * @param mat the matrix + * @param strict {@code true} if triangular is strict, {@code false} otherwise + * @return the lower triangular matrix */ public static ArrayList getLower(ArrayList mat, boolean strict) { ArrayList lower = new ArrayList<>(); int off = (strict ? 0 : 1); for (Value v : mat) { - if (v.j < v.i + off) { lower.add(v); } + if (v.j < v.i + off) { + lower.add(v); + } } return lower; } - + /** * Multiplies two dense square matrices. * - * @param matA the first matrix - * @param matB the second matrix - * @return the product of the two matrices + * @param matA the first matrix + * @param matB the second matrix + * @return the product of the two matrices */ public static double[][] multiply(double[][] matA, double[][] matB) { int n = matA.length; @@ -394,13 +410,13 @@ public static double[][] multiply(double[][] matA, double[][] matB) { } return multiplied; } - + /** * Multiplies a dense square matrix and a vector. * - * @param mat the matrix - * @param vec the vector - * @return the product of the matrix and vector + * @param mat the matrix + * @param vec the vector + * @return the product of the matrix and vector */ public static double[] multiply(double[][] mat, double[] vec) { int n = mat.length; @@ -412,52 +428,54 @@ public static double[] multiply(double[][] mat, double[] vec) { } return multiplied; } - + /** * Multiplies a sparse square matrix and a vector. * - * @param mat the matrix - * @param vec the vector - * @return the product of the matrix and vector + * @param mat the matrix + * @param vec the vector + * @return the product of the matrix and vector */ public static double[] multiply(ArrayList mat, double[] vec) { int n = vec.length; double[] multiplied = new double[n]; - + // Iterate through all entries and multiply. for (Value a : mat) { multiplied[a.i] += a.v * vec[a.j]; } - + return multiplied; } - + /** * Multiplies two sparse square matrices. * - * @param matA the first matrix - * @param matB the second matrix - * @return the product of the two matrices + * @param matA the first matrix + * @param matB the second matrix + * @return the product of the two matrices */ public static ArrayList multiply(ArrayList matA, ArrayList matB) { ArrayList multiplied = new ArrayList<>(); ArrayList products = new ArrayList<>(); - + // Iterate through both matrices and calculate products. for (Value a : matA) { for (Value b : matB) { - if (a.j == b.i) { products.add(new Value(a.i, b.j, a.v * b.v)); } + if (a.j == b.i) { + products.add(new Value(a.i, b.j, a.v * b.v)); + } } } - + // Sort products. - products.sort((v1, v2) -> - (v1.i == v2.i ? Integer.compare(v1.j, v2.j) : (v1.i > v2.i ? 1 : -1))); - + products.sort( + (v1, v2) -> (v1.i == v2.i ? Integer.compare(v1.j, v2.j) : (v1.i > v2.i ? 1 : -1))); + int i = 0; int j = 0; double sum = 0; - + // Iterate through products and make summations. Products must be sorted. for (Value p : products) { if (p.i != i || p.j != j) { @@ -468,20 +486,22 @@ public static ArrayList multiply(ArrayList matA, ArrayList } sum += p.v; } - + // Add in last case. Value p = products.get(products.size() - 1); - if (p.i == i && p.j == j) { multiplied.add(new Value(i, j, sum)); } - + if (p.i == i && p.j == j) { + multiplied.add(new Value(i, j, sum)); + } + return multiplied; } - + /** * Adds two vectors. * - * @param vecA the first vector - * @param vecB the second vector - * @return the sum of the two vectors + * @param vecA the first vector + * @param vecB the second vector + * @return the sum of the two vectors */ public static double[] add(double[] vecA, double[] vecB) { int n = vecA.length; @@ -491,13 +511,13 @@ public static double[] add(double[] vecA, double[] vecB) { } return added; } - + /** * Subtracts two vectors. * - * @param vecA the first vector - * @param vecB the second vector - * @return the difference of the two vectors + * @param vecA the first vector + * @param vecB the second vector + * @return the difference of the two vectors */ public static double[] subtract(double[] vecA, double[] vecB) { int n = vecA.length; @@ -507,13 +527,13 @@ public static double[] subtract(double[] vecA, double[] vecB) { } return subtracted; } - + /** * Scales the values in a dense matrix. * - * @param mat the matrix - * @param scale the value to scale by - * @return the scaled matrix + * @param mat the matrix + * @param scale the value to scale by + * @return the scaled matrix */ public static double[][] scale(double[][] mat, double scale) { int n = mat.length; @@ -523,13 +543,13 @@ public static double[][] scale(double[][] mat, double scale) { } return scaled; } - + /** * Scales the values in a dense vector. * - * @param vec the vector - * @param scale the value to scale by - * @return the scaled vector + * @param vec the vector + * @param scale the value to scale by + * @return the scaled vector */ public static double[] scale(double[] vec, double scale) { int n = vec.length; @@ -539,13 +559,13 @@ public static double[] scale(double[] vec, double scale) { } return scaled; } - + /** * Scales the values in a sparse matrix. * - * @param mat the matrix - * @param scale the value to scale by - * @return the scaled matrix + * @param mat the matrix + * @param scale the value to scale by + * @return the scaled matrix */ public static ArrayList scale(ArrayList mat, double scale) { ArrayList scaled = new ArrayList<>(); @@ -554,12 +574,12 @@ public static ArrayList scale(ArrayList mat, double scale) { } return scaled; } - + /** * Normalizes the vector. * - * @param vec the vector - * @return the normalized vector + * @param vec the vector + * @return the normalized vector */ public static double normalize(double[] vec) { double sum = 0; @@ -568,13 +588,13 @@ public static double normalize(double[] vec) { } return Math.sqrt(sum); } - + /** * Calculates dot product of two vectors. * - * @param vecA the first matrix - * @param vecB the second matrix - * @return the dot product of the two vectors + * @param vecA the first matrix + * @param vecB the second matrix + * @return the dot product of the two vectors */ public static double dot(double[] vecA, double[] vecB) { double sum = 0; @@ -583,11 +603,11 @@ public static double dot(double[] vecA, double[] vecB) { } return sum; } - + /** * Converts the vector to a unit vector. * - * @param vec the vector to convert + * @param vec the vector to convert */ public static void unit(double[] vec) { double norm = normalize(vec); diff --git a/src/arcade/core/util/MiniBox.java b/src/arcade/core/util/MiniBox.java index 43bcd5eea..8df210477 100644 --- a/src/arcade/core/util/MiniBox.java +++ b/src/arcade/core/util/MiniBox.java @@ -3,114 +3,152 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import ec.util.MersenneTwisterFast; +import arcade.core.util.distributions.Distribution; +import arcade.core.util.distributions.NormalDistribution; +import arcade.core.util.distributions.NormalFractionalDistribution; +import arcade.core.util.distributions.NormalTruncatedDistribution; +import arcade.core.util.distributions.UniformDistribution; /** * Container that maps a key to a value. - *

- * {@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 keys; - + /** Map of keys to values. */ final HashMap contents; - - /** - * Creates a {@code MiniBox} object. - */ + + /** Creates a {@code MiniBox} object. */ public MiniBox() { keys = new ArrayList<>(); contents = new HashMap<>(); } - + /** * Gets list of keys in the box. * - * @return the list of keys + * @return the list of keys */ - public ArrayList getKeys() { return keys; } - + public ArrayList getKeys() { + return keys; + } + /** * Gets the value for the given key. * - * @param id the key - * @return the value + * @param id the key + * @return the value */ - public String get(String id) { return contents.get(id); } - + public String get(String id) { + return contents.get(id); + } + /** * Gets the value for given key converted to an integer. * - * @param id the key - * @return the value + * @param id the key + * @return the value */ public int getInt(String id) { String s = contents.get(id); return (s == null || !s.matches(NUMBER_REGEX) ? 0 : Double.valueOf(s).intValue()); } - + + /** + * Gets the value for given key converted to a distribution. + * + * @param id the key + * @param random the random number generator + * @return the distribution instance + */ + public Distribution getDistribution(String id, MersenneTwisterFast random) { + String s = contents.get("(DISTRIBUTION)" + TAG_SEPARATOR + id); + + if (s == null) { + return null; + } else if (s.equals("UNIFORM")) { + return new UniformDistribution(id, this, random); + } else if (s.equals("TRUNCATED_NORMAL")) { + return new NormalTruncatedDistribution(id, this, random); + } else if (s.equals("FRACTIONAL_NORMAL")) { + return new NormalFractionalDistribution(id, this, random); + } else if (s.equals("NORMAL")) { + return new NormalDistribution(id, this, random); + } + + return null; + } + /** * Gets the value for given key converted to a double. * - * @param id the key - * @return the value + * @param id the key + * @return the value */ public double getDouble(String id) { String s = contents.get(id); - + if (s != null && s.contains("/")) { String[] split = s.split("/", 2); - double numerator = (!split[0].matches(NUMBER_REGEX) - ? Double.NaN - : Double.parseDouble(split[0])); - double denominator = (!split[1].matches(NUMBER_REGEX) - ? Double.NaN - : Double.parseDouble(split[1])); + double numerator = + (!split[0].matches(NUMBER_REGEX) ? Double.NaN : Double.parseDouble(split[0])); + double denominator = + (!split[1].matches(NUMBER_REGEX) ? Double.NaN : Double.parseDouble(split[1])); return (denominator == 0 ? Double.NaN : numerator / denominator); + } else if (contents.containsKey("(DISTRIBUTION)" + TAG_SEPARATOR + id)) { + return getDistribution(id, new MersenneTwisterFast()).getExpected(); } - + return (s == null || !s.matches(NUMBER_REGEX) ? Double.NaN : Double.parseDouble(s)); } - + /** * Checks if the given key exists. * - * @param id the key - * @return {@code true} if the key exists, {@code false} otherwise + * @param id the key + * @return {@code true} if the key exists, {@code false} otherwise */ - public boolean contains(String id) { return keys.contains(id); } - + public boolean contains(String id) { + return keys.contains(id); + } + /** * Adds a key and integer value pair to the map. * - * @param id the key - * @param val the value + * @param id the key + * @param val the value */ - public void put(String id, int val) { put(id, String.valueOf(val)); } - + public void put(String id, int val) { + put(id, String.valueOf(val)); + } + /** * Adds a key and double value pair to the map. * - * @param id the key - * @param val the value + * @param id the key + * @param val the value */ - public void put(String id, double val) { put(id, String.valueOf(val)); } - + public void put(String id, double val) { + put(id, String.valueOf(val)); + } + /** * Adds a key and value pair to the map. * - * @param id the key - * @param val the value + * @param id the key + * @param val the value */ public void put(String id, String val) { if (!keys.contains(id)) { @@ -118,16 +156,16 @@ public void put(String id, String val) { } contents.put(id, val); } - + /** * Filters keys by the given code. - *

- * 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 allKeys = new HashSet<>(); allKeys.addAll(keys); allKeys.addAll(box.keys); - + for (String key : allKeys) { if (!contents.containsKey(key)) { return false; - } - - if (!box.contents.containsKey(key)) { + } else if (!box.contents.containsKey(key)) { return false; } else if (!contents.get(key).equals(box.get(key))) { return false; } } - + return true; } - + /** * Formats the {@code MiniBox} as a string. * - * @return the string + * @return the string */ public String toString() { String format = "%20s : %s\n"; diff --git a/src/arcade/core/util/Parameter.java b/src/arcade/core/util/Parameter.java deleted file mode 100644 index 9660d6fc8..000000000 --- a/src/arcade/core/util/Parameter.java +++ /dev/null @@ -1,105 +0,0 @@ -package arcade.core.util; - -import java.io.Serializable; -import sim.util.distribution.Normal; -import ec.util.MersenneTwisterFast; - -/** - * Container class for parameter with normal distribution and bound checks. - *

- * 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 distributions; + + /** + * Creates a cell {@code Parameters} instance. + * + *

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 allKeys = new HashSet<>(); + allKeys.addAll(distributions.keySet()); + allKeys.addAll(parameters.distributions.keySet()); + + for (String key : allKeys) { + if (!distributions.containsKey(key)) { + return false; + } else if (!parameters.distributions.containsKey(key)) { + return false; + } else if (!distributions + .get(key) + .getParameters() + .compare(parameters.distributions.get(key).getParameters())) { + return false; + } + } + + return popParameters.compare(parameters.popParameters); + } +} diff --git a/src/arcade/core/util/Solver.java b/src/arcade/core/util/Solver.java index 92d4df39d..019aefff8 100644 --- a/src/arcade/core/util/Solver.java +++ b/src/arcade/core/util/Solver.java @@ -2,102 +2,101 @@ import java.util.ArrayList; import java.util.logging.Logger; +import arcade.core.util.Matrix.Value; import static arcade.core.util.Matrix.*; /** * Static utility class implementing various numerical solvers. - *

- * Implemented solvers include: + * + *

Implemented solvers include: + * *

    - *
  • forward Euler: first-order method for ODEs
  • - *
  • classic Runge–Kutta (RK4): fourth-order method for ODEs
  • - *
  • Cash–Karp: adaptive step size method for ODEs
  • - *
  • successive over-relaxation (SOR): variant of the Gauss–Seidel - * method for solving a linear system of equations
  • + *
  • forward Euler: first-order method for ODEs + *
  • classic Runge–Kutta (RK4): fourth-order method for ODEs + *
  • Cash–Karp: adaptive step size method for ODEs + *
  • successive over-relaxation (SOR): variant of the Gauss–Seidel method for solving a + * linear system of equations *
*/ - 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. - *

- * 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 sparseA = toSparse(mat); - + // Calculate iteration factors double[] c = forwardSubstitution(sparseA, vec); ArrayList t = forwardSubstitution(sparseA); 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(sparseA, xCurr)); error = normalize(r); } - + return xCurr; } - + /** * Finds root using bisection method. - *

- * 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: + * *

    - *
  • {@code TIME_DELAY} = time delay before calling the action
  • + *
  • {@code TIME_DELAY} = time delay before calling the action *
* - * @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. - *

- * 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 populations; - + /** * Creates a {@link Action} for removing cell agents. - *

- * Loaded parameters include: + * + *

Loaded parameters include: + * *

    - *
  • {@code TIME_DELAY} = time delay before calling the action
  • - *
  • {@code INSERT_RADIUS} = grid radius that cells are inserted - * into
  • - *
  • {@code INSERT_NUMBER} = number of cells to insert from each - * population
  • + *
  • {@code TIME_DELAY} = time delay before calling the action + *
  • {@code INSERT_RADIUS} = grid radius that cells are inserted into + *
  • {@code INSERT_NUMBER} = number of cells to insert from each population *
* - * @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 coordinates = sim.locationFactory.getCoordinates(insertRadius, insertDepth); Utilities.shuffleList(coordinates, sim.random); - + // Add cells from each population into insertion area. for (MiniBox population : populations) { int pop = population.getInt("CODE"); - + for (int i = 0; i < insertNumber; i++) { int id = sim.getID(); - + if (coordinates.isEmpty()) { break; } - + Coordinate coord = coordinates.remove(0); PatchLocationContainer locationContainer = new PatchLocationContainer(id, coord); PatchCellContainer cellContainer = sim.cellFactory.createCellForPopulation(id, pop); - + Location location = locationContainer.convert(sim.locationFactory, cellContainer); - PatchCell cell = (PatchCell) cellContainer.convert(sim.cellFactory, location); - + PatchCell cell = + (PatchCell) cellContainer.convert(sim.cellFactory, location, sim.random); + grid.addObject(cell, location); cell.schedule(sim.getSchedule()); } diff --git a/src/arcade/patch/agent/action/PatchActionRemove.java b/src/arcade/patch/agent/action/PatchActionRemove.java index 93906fbb2..5e36aab03 100644 --- a/src/arcade/patch/agent/action/PatchActionRemove.java +++ b/src/arcade/patch/agent/action/PatchActionRemove.java @@ -19,35 +19,33 @@ /** * Implementation of {@link Action} for removing cell agents. - *

- * 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 TIME_DELAY} = time delay before calling the action
  • - *
  • {@code REMOVE_RADIUS} = grid radius that cells are removed - * from
  • + *
  • {@code TIME_DELAY} = time delay before calling the action + *
  • {@code REMOVE_RADIUS} = grid radius that cells are removed from *
* - * @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 coordinates = sim.locationFactory.getCoordinates(removeRadius, removeDepth); - + // Remove all cells in removal area. for (Coordinate coordinate : coordinates) { Bag bag = (Bag) grid.getObjectAt(coordinate.hashCode()); - + if (bag == null) { continue; } - + for (Object obj : bag) { Cell cell = (Cell) obj; Location location = cell.getLocation(); @@ -88,17 +86,17 @@ public void step(SimState simstate) { cell.stop(); } } - + // Bring agents along edge out of quiescence. ArrayList edgeCoordinates = sim.locationFactory.getCoordinates(removeRadius + 1, removeDepth); for (Coordinate coordinate : edgeCoordinates) { Bag bag = (Bag) grid.getObjectAt(coordinate.hashCode()); - + if (bag == null) { continue; } - + for (Object obj : bag) { Cell cell = (Cell) obj; if (cell.getState() == State.QUIESCENT) { diff --git a/src/arcade/patch/agent/cell/PatchCell.java b/src/arcade/patch/agent/cell/PatchCell.java index 9cf3da4da..f37b983d3 100644 --- a/src/arcade/patch/agent/cell/PatchCell.java +++ b/src/arcade/patch/agent/cell/PatchCell.java @@ -15,7 +15,9 @@ import arcade.core.agent.process.ProcessDomain; import arcade.core.env.location.Location; import arcade.core.sim.Simulation; +import arcade.core.util.GrabBag; import arcade.core.util.MiniBox; +import arcade.core.util.Parameters; import arcade.patch.agent.module.PatchModuleApoptosis; import arcade.patch.agent.module.PatchModuleMigration; import arcade.patch.agent.module.PatchModuleProliferation; @@ -30,156 +32,140 @@ /** * Implementation of {@link Cell} for generic tissue cell. - *

- * {@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: + * *

    - *
  • update age
  • - *
  • check lifespan (possible change to apoptotic)
  • - *
  • step metabolism process
  • - *
  • check energy status (possible change to quiescent or necrotic - * depending on {@code ENERGY_THRESHOLD})
  • - *
  • step signaling process
  • - *
  • check if neutral (change to proliferative, migratory, senescent)
  • - *
  • step state-specific module
  • + *
  • update age + *
  • check lifespan (possible change to apoptotic) + *
  • step metabolism process + *
  • check energy status (possible change to quiescent or necrotic depending on {@code + * ENERGY_THRESHOLD}) + *
  • step signaling process + *
  • check if neutral (change to proliferative, migratory, senescent) + *
  • step state-specific module *
- *

- * 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 processes; - + /** Cell parameters. */ - final MiniBox parameters; - + final Parameters parameters; + + /** Cell population links. */ + final GrabBag links; + /** * Creates a {@code PatchCell} agent. - *

- * Loaded parameters include: + * + *

Loaded parameters include: + * *

    - *
  • {@code NECROTIC_FRACTION} = fraction of necrotic cells that - * become apoptotic
  • - *
  • {@code SENESCENT_FRACTION} = fraction of senescent cells that - * become apoptotic
  • - *
  • {@code ENERGY_THRESHOLD} = maximum energy deficit before - * necrosis
  • - *
  • {@code HETEROGENEITY} = variation in cell agent parameters
  • + *
  • {@code NECROTIC_FRACTION} = fraction of necrotic cells that become apoptotic + *
  • {@code SENESCENT_FRACTION} = fraction of senescent cells that become apoptotic + *
  • {@code ENERGY_THRESHOLD} = maximum energy deficit before necrosis + *
  • {@code HETEROGENEITY} = variation in cell agent parameters *
* - * @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. - *

- * 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: + * *

    - *
  • If cell is quiescent, they may exit out of quiescence into undefined - * if there is space in their neighborhood
  • + *
  • If cell is quiescent, they may exit out of quiescence into undefined if there is space in + * their neighborhood *
*/ - 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} - *

- * 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: + * *

    - *
  • Cells are immortal (death age set to maximum)
  • - *
  • Asymmetric division with probability ({@code SYMMETRIC_FRACTION}) of - * producing another stem cell ({@code PatchCellCancerStem}) or a cancerous - * cell ({@code PatchCellCancer})
  • - *
  • No division limit
  • + *
  • Cells are immortal (death age set to maximum) + *
  • Asymmetric division with probability ({@code SYMMETRIC_FRACTION}) of producing another stem + * cell ({@code PatchCellCancerStem}) or a cancerous cell ({@code PatchCellCancer}) + *
  • No division limit *
*/ - public class PatchCellCancerStem extends PatchCellCancer { - /** Fraction of divisions that are symmetric. */ - private final double symmetricFraction; - /** - * Creates a tissue {@code PatchCell} agent. - *

- * Loaded parameters include: - *

    - *
  • {@code SYMMETRIC_FRACTION} = fraction of divisions that are - * symmetric
  • - *
+ * 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} - *

- * 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 popToCriticalVolumes; - - /** Map of population to critical heights [um]. */ - HashMap popToCriticalHeights; - + /** Map of population to parameters. */ - HashMap popToParameters; - - /** Map of population to ages [min]. */ - HashMap popToAges; - - /** Map of population to cell divisions. */ - HashMap popToDivisions; - - /** Map of population to compression tolerance [um]. */ - HashMap popToCompression; - + final HashMap popToParameters; + + /** Map of population to linked populations. */ + final HashMap popToLinks; + /** Map of population to process versions. */ - HashMap> popToProcessVersions; - + final HashMap> popToProcessVersions; + /** Map of population to list of ids. */ public final HashMap> popToIDs; - + /** Map of id to cell. */ public final HashMap cells; - - /** - * Creates a factory for making {@link PatchCell} instances. - */ + + /** Creates a factory for making {@link PatchCell} instances. */ public PatchCellFactory() { cells = new HashMap<>(); - popToCriticalVolumes = new HashMap<>(); - popToCriticalHeights = new HashMap<>(); popToParameters = new HashMap<>(); - popToAges = new HashMap<>(); - popToDivisions = new HashMap<>(); - popToCompression = new HashMap<>(); + popToLinks = new HashMap<>(); popToProcessVersions = new HashMap<>(); popToIDs = new HashMap<>(); } - + @Override public void initialize(Series series, MersenneTwisterFast random) { this.random = random; @@ -87,19 +65,28 @@ public void initialize(Series series, MersenneTwisterFast random) { createCells(series); } } - + + @Override + public MiniBox getParameters(int pop) { + return popToParameters.get(pop); + } + + @Override + public GrabBag getLinks(int pop) { + return popToLinks.get(pop); + } + /** * {@inheritDoc} - *

- * 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 containers = series.loader.loadCells(); - + // Population sizes. HashMap popToSize = new HashMap<>(); for (MiniBox population : series.populations.values()) { @@ -107,7 +94,7 @@ public void loadCells(Series series) { int pop = population.getInt("CODE"); popToSize.put(pop, n); } - + // Map loaded container to factory. for (CellContainer container : containers) { PatchCellContainer cellContainer = (PatchCellContainer) container; @@ -118,105 +105,116 @@ public void loadCells(Series series) { } } } - + /** * {@inheritDoc} - *

- * 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: - *

    - *
  • {@code CELL_VOLUME_MEAN} = cell volume distribution average
  • - *
  • {@code CELL_VOLUME_STDEV} = cell volume distribution standard - * deviation
  • - *
  • {@code CELL_HEIGHT_MEAN} = cell height distribution average
  • - *
  • {@code CELL_HEIGHT_STDEV} = cell height distribution standard - * deviation
  • - *
  • {@code CELL_AGE_MIN} = minimum cell age
  • - *
  • {@code CELL_AGE_MAX} = maximum cell age
  • - *
  • {@code DIVISION_POTENTIAL} = maximum number of divisions
  • - *
  • {@code COMPRESSION_TOLERANCE} = maximum compression - * tolerance
  • - *
+ * 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 keySet = series.populations.keySet(); - + for (String key : keySet) { MiniBox population = series.populations.get(key); int pop = population.getInt("CODE"); popToIDs.put(pop, new HashSet<>()); - - popToCriticalVolumes.put(pop, new Normal(population.getDouble("CELL_VOLUME_MEAN"), - population.getDouble("CELL_VOLUME_STDEV"), random)); - popToCriticalHeights.put(pop, new Normal(population.getDouble("CELL_HEIGHT_MEAN"), - population.getDouble("CELL_HEIGHT_STDEV"), random)); - popToAges.put(pop, new Uniform(population.getDouble("CELL_AGE_MIN"), - population.getDouble("CELL_AGE_MAX"), random)); - popToDivisions.put(pop, population.getInt("DIVISION_POTENTIAL")); - popToCompression.put(pop, population.getInt("COMPRESSION_TOLERANCE")); - + // Set process versions if not specified. MiniBox parameters = series.populations.get(key); - + String metabolismVersionKey = "(PROCESS)" + TAG_SEPARATOR + Domain.METABOLISM.name(); if (!parameters.contains(metabolismVersionKey)) { parameters.put(metabolismVersionKey, "random"); } - + String signalingVersionKey = "(PROCESS)" + TAG_SEPARATOR + Domain.SIGNALING.name(); if (!parameters.contains(signalingVersionKey)) { parameters.put(signalingVersionKey, "random"); } - + popToParameters.put(pop, parameters); + + // Get population links. + MiniBox linksBox = population.filter("(LINK)"); + ArrayList linkKeys = linksBox.getKeys(); + GrabBag links = null; + + if (linkKeys.size() > 0) { + links = new GrabBag(); + for (String linkKey : linkKeys) { + int popLink = series.populations.get(linkKey).getInt("CODE"); + links.add(popLink, linksBox.getDouble(linkKey)); + } + } + + popToLinks.put(pop, links); } } } diff --git a/src/arcade/patch/agent/cell/PatchCellRandom.java b/src/arcade/patch/agent/cell/PatchCellRandom.java new file mode 100644 index 000000000..6498f160d --- /dev/null +++ b/src/arcade/patch/agent/cell/PatchCellRandom.java @@ -0,0 +1,85 @@ +package arcade.patch.agent.cell; + +import sim.engine.SimState; +import ec.util.MersenneTwisterFast; +import arcade.core.agent.cell.CellState; +import arcade.core.env.location.Location; +import arcade.core.sim.Simulation; +import arcade.core.util.GrabBag; +import arcade.core.util.Parameters; +import static arcade.patch.util.PatchEnums.Domain; +import static arcade.patch.util.PatchEnums.State; + +/** + * Extension of {@link PatchCell} for cells with randomly assigned states. + * + *

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: + * *

    - *
  • {@code DEATH_DURATION} = time required for cell death
  • + *
  • {@code DEATH_DURATION} = time required for cell death *
* - * @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. - *

- * 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: + * *

    - *
  • {@code MIGRATION_RATE} = cell migration rate
  • + *
  • {@code MIGRATION_RATE} = cell migration rate *
* - * @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. - *

- * 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: + * *

    - *
  • {@code SYNTHESIS_DURATION} = time required for DNA synthesis
  • + *
  • {@code SYNTHESIS_DURATION} = time required for DNA synthesis *
* - * @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. - *

- * 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: + * *

    - *
  • gets available glucose and oxygen from the environment
  • - *
  • calculates energy consumption (ATP) given cell size and state
  • - *
  • steps the metabolism process (implemented with different complexities) - * to determine changes to energy and volume
  • - *
  • updates glucose and oxygen environment with consumption
  • + *
  • gets available glucose and oxygen from the environment + *
  • calculates energy consumption (ATP) given cell size and state + *
  • steps the metabolism process (implemented with different complexities) to determine changes + * to energy and volume + *
  • updates glucose and oxygen environment with consumption *
- *

- * 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 names; - + /** List of internal amounts [fmol]. */ double[] intAmts; - + /** List of external amounts [fmol]. */ final double[] extAmts; - + /** List of uptake amounts [fmol]. */ final double[] upAmts; - + /** Volume fraction. */ protected double f; - + /** Cell energy [ATP]. */ double energy; - + /** Volume of cell [um3]. */ double volume; - + /** Dry mass of cell [ng]. */ double mass; - + /** Critical cell mass. */ final double critMass; - + /** Energy consumed. */ double energyCons; - + /** Energy required. */ double energyReq; - + /** {@code true} if cell is in proliferative state, {@code false} otherwise. */ protected boolean isProliferative; - + /** {@code true} if cell is in migratory state, {@code false} otherwise. */ protected boolean isMigratory; - + /** * Creates a metabolism {@link PatchProcess} for the given cell. - *

- * Process parameters are specific for the cell population. Loaded - * parameters include: + * + *

Process parameters are specific for the cell population. Loaded parameters include: + * *

    - *
  • {@code BASAL_ENERGY} = basal energy requirement
  • - *
  • {@code PROLIFERATION_ENERGY} = additional energy required for proliferation
  • - *
  • {@code MIGRATION_ENERGY} = additional energy required for migration
  • - *
  • {@code CELL_DENSITY} = cell density
  • - *
  • {@code RATIO_GLUCOSE_BIOMASS} = ratio of glucose to biomass
  • - *
  • {@code OXYGEN_SOLUBILITY_TISSUE} = oxygen solubility in tissue
  • + *
  • {@code BASAL_ENERGY} = basal energy requirement + *
  • {@code PROLIFERATION_ENERGY} = additional energy required for proliferation + *
  • {@code MIGRATION_ENERGY} = additional energy required for migration + *
  • {@code CELL_DENSITY} = cell density + *
  • {@code RATIO_GLUCOSE_BIOMASS} = ratio of glucose to biomass + *
  • {@code OXYGEN_SOLUBILITY_TISSUE} = oxygen solubility in tissue *
- *

- * 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: + * *

    - *
  • cell is dividing and less than double in size
  • - *
  • cell is below critical mass for maintenance
  • + *
  • cell is dividing and less than double in size + *
  • cell is below critical mass for maintenance *
- *

- * {@code PatchProcessMetabolismComplex} will decrease cell mass if: + * + *

{@code PatchProcessMetabolismComplex} will decrease cell mass if: + * *

    - *
  • cell has negative energy indicating insufficient nutrients
  • - *
  • cell is above critical mass for maintenance
  • + *
  • cell has negative energy indicating insufficient nutrients + *
  • cell is above critical mass for maintenance *
- *

- * 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 METABOLIC_PREFERENCE} = preference for glycolysis over - * oxidative phosphorylation
  • - *
  • {@code CONVERSION_FRACTION} = fraction of internal glucose / - * pyruvate converted to mass
  • - *
  • {@code MINIMUM_MASS_FRACTION} = minimum viable cell mass - * fraction
  • - *
  • {@code RATIO_GLUCOSE_PYRUVATE} = preference for glucose over - * pyruvate for mass
  • - *
  • {@code LACTATE_RATE} = rate of lactate production
  • - *
  • {@code AUTOPHAGY_RATE} = rate of autophagy
  • - *
  • {@code GLUCOSE_UPTAKE_RATE} = rate of glucose uptake
  • + *
  • {@code METABOLIC_PREFERENCE} = preference for glycolysis over oxidative phosphorylation + *
  • {@code CONVERSION_FRACTION} = fraction of internal glucose / pyruvate converted to mass + *
  • {@code MINIMUM_MASS_FRACTION} = minimum viable cell mass fraction + *
  • {@code RATIO_GLUCOSE_PYRUVATE} = preference for glucose over pyruvate for mass + *
  • {@code LACTATE_RATE} = rate of lactate production + *
  • {@code AUTOPHAGY_RATE} = rate of autophagy + *
  • {@code GLUCOSE_UPTAKE_RATE} = rate of glucose uptake *
* - * @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. - *

- * {@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: + * *

    - *
  • cell is dividing and less than double in size
  • - *
  • cell is below critical mass for maintenance
  • + *
  • cell is dividing and less than double in size + *
  • cell is below critical mass for maintenance *
- *

- * {@code PatchProcessMetabolismMedium} will decrease cell mass if: + * + *

{@code PatchProcessMetabolismMedium} will decrease cell mass if: + * *

    - *
  • cell has negative energy indicating insufficient nutrients
  • - *
  • cell is above critical mass for maintenance
  • + *
  • cell has negative energy indicating insufficient nutrients + *
  • cell is above critical mass for maintenance *
*/ - 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}. - *

- * 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 METABOLIC_PREFERENCE} = preference for glycolysis over - * oxidative phosphorylation
  • - *
  • {@code CONVERSION_FRACTION} = fraction of internal glucose / - * pyruvate converted to mass
  • - *
  • {@code MINIMUM_MASS_FRACTION} = minimum viable cell mass - * fraction
  • - *
  • {@code AUTOPHAGY_RATE} = rate of autophagy
  • - *
  • {@code ATP_PRODUCTION_RATE} = rate of ATP production
  • + *
  • {@code METABOLIC_PREFERENCE} = preference for glycolysis over oxidative phosphorylation + *
  • {@code CONVERSION_FRACTION} = fraction of internal glucose / pyruvate converted to mass + *
  • {@code MINIMUM_MASS_FRACTION} = minimum viable cell mass fraction + *
  • {@code AUTOPHAGY_RATE} = rate of autophagy + *
  • {@code ATP_PRODUCTION_RATE} = rate of ATP production *
* - * @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. - *

- * {@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 CELL_VOLUME_MEAN} = average cell volume
  • + *
  • {@code CELL_VOLUME} = cell volume *
* - * @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. - *

- * {@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: + * *

    - *
  • {@code CELL_VOLUME_MEAN} = average cell volume
  • - *
  • {@code METABOLIC_PREFERENCE} = preference for glycolysis over - * oxidative phosphorylation
  • - *
  • {@code CONSTANT_GLUCOSE_UPTAKE_RATE} = constant glucose uptake - * rate
  • - *
  • {@code CONSTANT_ATP_PRODUCTION_RATE} = constant ATP production - * rate
  • - *
  • {@code CONSTANT_VOLUME_GROWTH_RATE} = constant volume growth - * rate
  • + *
  • {@code CELL_VOLUME} = cell volume + *
  • {@code METABOLIC_PREFERENCE} = preference for glycolysis over oxidative phosphorylation + *
  • {@code CONSTANT_GLUCOSE_UPTAKE_RATE} = constant glucose uptake rate + *
  • {@code CONSTANT_ATP_PRODUCTION_RATE} = constant ATP production rate + *
  • {@code CONSTANT_VOLUME_GROWTH_RATE} = constant volume growth rate *
* - * @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. - *

- * 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 names; - + /** * Creates a signaling {@link PatchProcess} for the given cell. * - * @param cell the {@link PatchCell} the process is associated with + * @param cell the {@link PatchCell} the process is associated with */ PatchProcessSignaling(PatchCell cell) { super(cell); } - + /** * Creates a {@code PatchProcessSignaling} 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/PatchProcessSignalingComplex.java b/src/arcade/patch/agent/process/PatchProcessSignalingComplex.java index c9c4bf2a5..9c166eeb4 100644 --- a/src/arcade/patch/agent/process/PatchProcessSignalingComplex.java +++ b/src/arcade/patch/agent/process/PatchProcessSignalingComplex.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,187 +13,184 @@ /** * Extension of {@link PatchProcessSignaling} for complex EGFR signaling. - *

- * {@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: + * *

    - *
  • {@code MIGRATORY_THRESHOLD} = threshold fold change in PLCg for - * migration
  • + *
  • {@code MIGRATORY_THRESHOLD} = threshold fold change in PLCg for migration *
* - * @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. - *

- * Uses five regulatory weights: + * + *

Uses five regulatory weights: + * *

    - *
  • wG = increase in TGFa-EGFR phosphorylation by glucose
  • - *
  • wE = decrease in EGFR translation by p-TGFa-EGFR
  • - *
  • wT = increase in TGFa translation by p-TGFa-EGFR
  • - *
  • wP = increase in PLCg activation by p-TGFa-EGFR
  • - *
  • wC = increase in TGFa-EGFR dephosphorylation by active PLCg
  • + *
  • wG = increase in TGFa-EGFR phosphorylation by glucose + *
  • wE = decrease in EGFR translation by p-TGFa-EGFR + *
  • wT = increase in TGFa translation by p-TGFa-EGFR + *
  • wP = increase in PLCg activation by p-TGFa-EGFR + *
  • wC = increase in TGFa-EGFR dephosphorylation by active PLCg *
*/ - 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. - *

- * {@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: + * *

    - *
  • {@code MIGRATORY_THRESHOLD} = threshold fold change in PLCg for - * migration
  • + *
  • {@code MIGRATORY_THRESHOLD} = threshold fold change in PLCg for migration *
* - * @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. - *

- * Uses three regulatory weights: + * + *

Uses three regulatory weights: + * *

    - *
  • wG = increase in TGFa-EGFR phosphorylation by glucose
  • - *
  • wP = increase in PLCg activation by p-TGFa-EGFR
  • - *
  • wC = increase in TGFa-EGFR dephosphorylation by active PLCg
  • + *
  • wG = increase in TGFa-EGFR phosphorylation by glucose + *
  • wP = increase in PLCg activation by p-TGFa-EGFR + *
  • wC = increase in TGFa-EGFR dephosphorylation by active PLCg *
*/ - 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. - *

- * {@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 MIGRATORY_PROBABILITY} = probability of migration instead - * of proliferation
  • + *
  • {@code MIGRATORY_PROBABILITY} = probability of migration instead of proliferation *
* - * @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. - *

- * {@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: + * *

    - *
  • {@code MIGRATORY_THRESHOLD} = threshold fold change in PLCg for - * migration
  • + *
  • {@code MIGRATORY_THRESHOLD} = threshold fold change in PLCg for migration *
* - * @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. - *

- * Uses three regulatory weights: + * + *

Uses three regulatory weights: + * *

    - *
  • wG = increase in TGFa-EGFR by glucose
  • - *
  • wP = increase in PLCg activation by TGFa-EGFR
  • - *
  • wC = decrease in TGFa-EGFR by active PLCg
  • + *
  • wG = increase in TGFa-EGFR by glucose + *
  • wP = increase in PLCg activation by TGFa-EGFR + *
  • wC = decrease in TGFa-EGFR by active PLCg *
*/ - 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. - *

- * 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 layers; - + /** * Creates a {@code Component} object for representing source site cycling. * - * @param series the simulation series - * @param parameters the component parameters dictionary + * @param series the simulation series + * @param parameters the component parameters dictionary */ public PatchComponentCycle(Series series, MiniBox parameters) { layers = new ArrayList<>(); } - - /** - * Specification of arrays and parameters for {@link PatchComponentCycle}. - */ + + /** Specification of arrays and parameters for {@link PatchComponentCycle}. */ protected static class CycleLayer { /** Unique name for layer. */ final String name; - + /** Corresponding site layer instance. */ final SiteLayer siteLayer; - + /** Initial concentration. */ final double initialConcentration; - + /** * Creates a {@code CycleLayer} 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 */ CycleLayer(String name, SiteLayer siteLayer, PatchOperationGenerator generator) { this.name = name; @@ -69,44 +64,49 @@ protected static class CycleLayer { initialConcentration = generator.concentration; } } - + @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) { - CycleLayer cycleLayer = new CycleLayer(layer, siteLayer, - (PatchOperationGenerator) generator); + CycleLayer cycleLayer = + new CycleLayer(layer, siteLayer, (PatchOperationGenerator) generator); layers.add(cycleLayer); } } - + @Override public void step(SimState simstate) { double tick = simstate.schedule.getTime(); double x = tick / 60.0 / 24.0 * 3; - double scale = (Math.tanh((x - Math.floor(x) - 0.5) * SMOOTHING_FACTOR)) - / (2 * Math.tanh(0.5 * SMOOTHING_FACTOR)) + Math.floor(x) + 1.5 - x; - + double scale = + (Math.tanh((x - Math.floor(x) - 0.5) * SMOOTHING_FACTOR)) + / (2 * Math.tanh(0.5 * SMOOTHING_FACTOR)) + + Math.floor(x) + + 1.5 + - x; + for (CycleLayer layer : layers) { layer.siteLayer.concentration = scale * layer.initialConcentration; } diff --git a/src/arcade/patch/env/component/PatchComponentDegrade.java b/src/arcade/patch/env/component/PatchComponentDegrade.java index bc695fd81..35da75184 100644 --- a/src/arcade/patch/env/component/PatchComponentDegrade.java +++ b/src/arcade/patch/env/component/PatchComponentDegrade.java @@ -21,45 +21,44 @@ /** * Implementation of {@link Component} for degrading graph edges. - *

- * 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: + * *

    - *
  • {@code DEGRADATION_INTERVAL} = interval between degradation steps
  • - *
  • {@code DEGRADATION_RATE} = rate of wall thickness degradation
  • - *
  • {@code SHEAR_THRESHOLD} = shear threshold for vessel collapse
  • + *
  • {@code DEGRADATION_INTERVAL} = interval between degradation steps + *
  • {@code DEGRADATION_RATE} = rate of wall thickness degradation + *
  • {@code SHEAR_THRESHOLD} = shear threshold for vessel collapse *
* - * @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 locations = new HashSet<>(); - + // Get set of agent locations from edge span. for (CoordinateXYZ span : edge.span) { locations.add(sites.getLocation(span)); } - + // Get agents at locations. locations.remove(null); Bag agents = grid.getObjectsAtLocations(new ArrayList<>(locations)); - + // If any agents are cancerous, then degrade the wall. for (Object cellObj : agents) { Cell cell = (Cell) cellObj; - + if (cell instanceof PatchCellCancer) { edge.wall -= degradationRate / 60.0; edge.wall = Math.max(MINIMUM_WALL_THICKNESS, edge.wall); - + if (edge.wall <= MINIMUM_WALL_THICKNESS && (edge.shear < shearThreshold || Double.isNaN(edge.shear))) { graph.removeEdge(edge); @@ -120,12 +119,12 @@ public void step(SimState state) { edge.getTo().pressure = Double.NaN; removed = true; } - + break; } } } - + // If any edges are removed, update the graph edges that are ignored. // Otherwise, recalculate calculate stresses. if (removed) { diff --git a/src/arcade/patch/env/component/PatchComponentPulse.java b/src/arcade/patch/env/component/PatchComponentPulse.java index 7513ac1ef..f8bb5a3f7 100644 --- a/src/arcade/patch/env/component/PatchComponentPulse.java +++ b/src/arcade/patch/env/component/PatchComponentPulse.java @@ -17,107 +17,103 @@ /** * Implementation of {@link Component} for pulsing sources. - *

- * 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 layers; - + /** Height of the array (z direction). */ private final int latticeHeight; - + /** Length of the array (x direction). */ private final int latticeLength; - + /** Width of the array (y direction). */ private final int latticeWidth; - + /** Interval between pulses [min]. */ private final double pulseInterval; - + /** Media volume per area [um3/um2]. */ private final double mediaAmount; - + /** Total media volume [um3]. */ private final double mediaVolume; - + /** Volume of individual lattice patch [um3]. */ private final double latticePatchVolume; - + /** Area of individual lattice patch [um2]. */ private final double latticePatchArea; - + /** * Creates a {@code Component} object for representing source site pulses. - *

- * Loaded parameters include: + * + *

Loaded parameters include: + * *

    - *
  • {@code PULSE_INTERVAL} = interval between pulses
  • - *
  • {@code MEDIA_AMOUNT} = media volume per area
  • + *
  • {@code PULSE_INTERVAL} = interval between pulses + *
  • {@code MEDIA_AMOUNT} = media volume per area *
* - * @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. - *

- * 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: + * *

    - *
  • {@code REMODELING_INTERVAL} = interval between remodeling steps
  • - *
  • {@code SCALE_SHEAR} = shear stress scaling
  • - *
  • {@code SCALE_CIRCUM} = circumferential stress scaling
  • - *
  • {@code SCALE_FLOW} = flow rate scaling
  • - *
  • {@code SCALE_METABOLIC} = metabolic demand scaling
  • - *
  • {@code SCALE_TAU} = shear stress contribution to area mass scaling
  • - *
  • {@code SCALE_SIGMA} = circumferential stress contribution to radius scaling
  • + *
  • {@code REMODELING_INTERVAL} = interval between remodeling steps + *
  • {@code SCALE_SHEAR} = shear stress scaling + *
  • {@code SCALE_CIRCUM} = circumferential stress scaling + *
  • {@code SCALE_FLOW} = flow rate scaling + *
  • {@code SCALE_METABOLIC} = metabolic demand scaling + *
  • {@code SCALE_TAU} = shear stress contribution to area mass scaling + *
  • {@code SCALE_SIGMA} = circumferential stress contribution to radius scaling *
* - * @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. - *

- * 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 layers; - + /** 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 {@code Component} object for representing sites. * - * @param series the simulation series + * @param series the simulation series */ public PatchComponentSites(Series series) { layers = new ArrayList<>(); - + latticeLength = series.length; latticeWidth = series.width; latticeHeight = series.height; } - - /** - * Specification of arrays and parameters for {@link PatchComponentSites}. - */ + + /** Specification of arrays and parameters for {@link PatchComponentSites}. */ protected static class SiteLayer { /** Unique name for layer. */ final String name; - + /** Array holding current concentration values. */ final double[][][] current; - + /** Array holding previous concentration values. */ final double[][][] previous; - + /** Array holding changes in concentration values. */ final double[][][] delta; - + /** Maximum concentration. */ double concentration; - + /** Molecule permeability. */ double permeability; - + /** * Creates a {@code SiteLayer} object. * - * @param name the name of the layer - * @param generator the associated generator operation instance + * @param name the name of the layer + * @param generator the associated generator operation instance */ SiteLayer(String name, PatchOperationGenerator generator) { this.name = name; @@ -83,13 +79,13 @@ protected static class SiteLayer { permeability = generator.permeability; } } - + @Override public void schedule(Schedule schedule) { schedule.scheduleOnce(this, Ordering.FIRST.ordinal() - 1); schedule.scheduleRepeating(this, Ordering.COMPONENTS.ordinal(), 1); } - + @Override public void register(Simulation sim, String layer) { Lattice lattice = sim.getLattice(layer); diff --git a/src/arcade/patch/env/component/PatchComponentSitesGraph.java b/src/arcade/patch/env/component/PatchComponentSitesGraph.java index 46e43db4b..f99058c07 100644 --- a/src/arcade/patch/env/component/PatchComponentSitesGraph.java +++ b/src/arcade/patch/env/component/PatchComponentSitesGraph.java @@ -22,151 +22,151 @@ /** * Extension of {@link PatchComponentSites} for graph sites. - *

- * 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: + * *

    - *
  • {@code [ random <#>]} = random roots with {@code <#>} - * randomly spaced roots, randomly assigned as artery or vein
  • - *
  • {@code [ alternate <#>]} = alternating roots with {@code <#>} - * evenly spaced roots, alternating between arteries and veins
  • - *
  • {@code [ single <#>]} = single {@code } root - * placed a distance {@code <#>} percent across the specified border - *
  • {@code [ line <#><#>]} = line {@code } root - * placed a distance {@code <#>} (first number) percent across the specified - * border that spans a distance {@code <#>} (second number) percent across - * the environment in the direction normal to the specified border + *
  • {@code [ random <#>]} = random roots with {@code <#>} randomly spaced roots, + * randomly assigned as artery or vein + *
  • {@code [ alternate <#>]} = alternating roots with {@code <#>} evenly spaced roots, + * alternating between arteries and veins + *
  • {@code [ single <#>]} = single {@code } root placed a distance {@code + * <#>} percent across the specified border + *
  • {@code [ line <#><#>]} = line {@code } root placed a distance {@code + * <#>} (first number) percent across the specified border that spans a distance {@code <#>} + * (second number) percent across the environment in the direction normal to the specified + * border *
- *

- * The border {@code } can be {@code LEFT} (-x direction), {@code RIGHT} - * (+x direction), {@code TOP} (-y direction), or {@code BOTTOM} (+y direction). - * The type {@code } can be {@code A} / {@code a} for an artery or - * {@code V} / {@code v} for a vein. + * + *

The border {@code } can be {@code LEFT} (-x direction), {@code RIGHT} (+x direction), + * {@code TOP} (-y direction), or {@code BOTTOM} (+y direction). The type {@code } can be + * {@code A} / {@code a} for an artery or {@code V} / {@code v} for a vein. */ - public abstract class PatchComponentSitesGraph extends PatchComponentSites { /** Tolerance for difference in internal and external concentrations. */ private static final double DELTA_TOLERANCE = 1E-8; - + /** Maximum number of iterations. */ private static final int MAXIMUM_ITERATIONS = 100; - + /** Minimum flow rate [um3/s]. */ private static final double MINIMUM_FLOW = 2000; - + /** Maximum oxygen partial pressure [mmHg]. */ private static final double MAX_OXYGEN_PARTIAL_PRESSURE = 100; - + /** Graph layout description. */ private final String graphLayout; - + /** Solubility of oxygen in plasma [fmol O2/(um3 mmHg)]. */ private final double oxySoluPlasma; - + /** Solubility of oxygen in tissue [fmol O2/(um3 mmHg)]. */ private final double oxySoluTissue; - + /** Volume of individual lattice patch [um3]. */ private final double latticePatchVolume; - + /** Location factory instance for the simulation. */ final PatchComponentSitesGraphFactory graphFactory; - + /** Graph representing the sites. */ final Graph graph; - + /** * Creates a {@link PatchComponentSites} using graph sites. - *

- * Loaded parameters include: + * + *

Loaded parameters include: + * *

    - *
  • {@code GRAPH_LAYOUT} = graph layout type
  • - *
  • {@code OXYGEN_SOLUBILITY_PLASMA} = solubility of oxygen in plasma
  • - *
  • {@code OXYGEN_SOLUBILITY_TISSUE} = solubility of oxygen in tissue
  • + *
  • {@code GRAPH_LAYOUT} = graph layout type + *
  • {@code OXYGEN_SOLUBILITY_PLASMA} = solubility of oxygen in plasma + *
  • {@code OXYGEN_SOLUBILITY_TISSUE} = solubility of oxygen in tissue *
* - * @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 getSpan(SiteNode from, SiteNode to); - + /** * Checks if given coordinates are within the environment to add to list. * - * @param s the list of valid coordinates - * @param x the coordinate in the x direction - * @param y the coordinate in the y direction - * @param z the coordinate in the z direction + * @param s the list of valid coordinates + * @param x the coordinate in the x direction + * @param y the coordinate in the y direction + * @param z the coordinate in the z direction */ void checkSite(ArrayList s, int x, int y, int z) { if (x >= 0 && x < latticeLength && y >= 0 && y < latticeWidth) { s.add(new CoordinateXYZ(x, y, z)); } } - + /** * Converts the given span coordinate to the corresponding location. * - * @param span the span coordinate - * @return a location object + * @param span the span coordinate + * @return a location object */ abstract Location getLocation(CoordinateXYZ span); - + /** * Initializes graph for representing sites. - *

- * 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 span; - + /** {@code true} if edge as been visited, {@code false} otherwise. */ boolean isVisited; - + /** {@code true} if edge is perfused {@code false} otherwise. */ boolean isPerfused; - + /** {@code true} if edge is ignored, {@code false} otherwise. */ boolean isIgnored; - + /** Edge type. */ final EdgeType type; - + /** Edge resolution level. */ final EdgeLevel level; - + /** Edge tag for iterative remodeling. */ EdgeTag tag; - + /** Internal radius [um]. */ double radius; - + /** Vessel length [um]. */ double length; - + /** Wall thickness [um]. */ double wall; - + /** Shear stress in edge [mmHg]. */ double shear; - + /** Circumferential stress in edge [mmHg]. */ double circum; - + /** Volumetric flow rate in edge [um3/min]. */ double flow; - + /** Cross-sectional area of edge [um2]. */ double area; - + /** Scaled shear stress. */ double shearScaled; - + /** Concentration fraction in edge. */ HashMap fraction; - + /** Concentration fraction transported out. */ HashMap transport; - + /** * Creates a {@link Edge} for graph sites. * - * @param from the node the edge is from - * @param to the node the edge is to - * @param type the edge type - * @param level the graph resolution level + * @param from the node the edge is from + * @param to the node the edge is to + * @param type the edge type + * @param level the graph resolution level */ SiteEdge(Node from, Node to, EdgeType type, EdgeLevel level) { super(from, to); @@ -509,64 +514,74 @@ public static class SiteEdge extends Edge { fraction = new HashMap<>(); transport = new HashMap<>(); } - + @Override - public SiteNode getFrom() { return (SiteNode) from; } - + public SiteNode getFrom() { + return (SiteNode) from; + } + @Override - public SiteNode getTo() { return (SiteNode) to; } - + public SiteNode getTo() { + return (SiteNode) to; + } + /** * Gets the sign type of the radius. * - * @return the edge type sign + * @return the edge type sign */ - public int getSign() { return type.category.sign; } - + public int getSign() { + return type.category.sign; + } + /** * Get the radius of the edge. * - * @return the edge radius + * @return the edge radius */ - public double getRadius() { return radius; } - + public double getRadius() { + return radius; + } + /** * Get the wall thickness of the edge. * - * @return the edge wall thickness + * @return the edge wall thickness */ - public double getWall() { return wall; } + public double getWall() { + return wall; + } } - + /** * Steps through graph to calculate concentrations and partial pressures. * - * @param code the molecule code + * @param code the molecule code */ private void stepGraph(String code) { ArrayList inlets = new ArrayList<>(); - + // Reset calculations in all edges and get list of inlets. for (Object obj : graph.getAllEdges()) { SiteEdge edge = (SiteEdge) obj; SiteNode from = edge.getFrom(); - + if (code.equalsIgnoreCase("OXYGEN")) { from.oxygen = (Double.isNaN(from.oxygen) ? Double.NaN : -1.0); } else { edge.isVisited = edge.isIgnored; edge.fraction.put(code, -1.0); } - + if (from.isRoot && !edge.isIgnored) { inlets.add(from); } } - + ArrayList nextList; LinkedHashSet nextSet; LinkedHashSet currSet = new LinkedHashSet<>(); - + // Assign values to inlet nodes and make first set. for (SiteNode inlet : inlets) { Bag out = graph.getEdgesOut(inlet); @@ -575,7 +590,7 @@ private void stepGraph(String code) { SiteEdge edge = (SiteEdge) obj; SiteNode from = edge.getFrom(); SiteNode to = edge.getTo(); - + if (code.equalsIgnoreCase("OXYGEN")) { from.oxygen = getPartial(edge); nextList = traverseNode(to, code); @@ -588,13 +603,13 @@ private void stepGraph(String code) { } } } - + LinkedHashSet firstSet = currSet; int counter = 0; int stops = 0; int prevSize; int currSize = currSet.size(); - + // Traverse the graph breadth first. while (currSize > 0) { nextSet = new LinkedHashSet<>(); @@ -606,51 +621,51 @@ private void stepGraph(String code) { } nextSet.addAll(nextList); } - + currSet = nextSet; prevSize = currSize; currSize = currSet.size(); - + // Track iterations without change in the size of the node set. if (currSize == prevSize) { counter++; } else { counter = 0; } - + // If the graph cannot be traversed, try eliminating edges. Reset // counter and the starting node set to recalculate flows. if (counter > MAXIMUM_ITERATIONS) { updateTraverse(graph, currSet, false); stops++; - + if (stops > MAXIMUM_ITERATIONS) { updateTraverse(graph, currSet, true); stops = 0; } - + currSet = firstSet; counter = 0; } } } - + /** * Traverses through the graph based on edges. * - * @param node the current node being traversed - * @param code the molecule code - * @return a list of children nodes to traverse + * @param node the current node being traversed + * @param code the molecule code + * @return a list of children nodes to traverse */ private ArrayList traverseEdge(SiteNode node, String code) { ArrayList children = new ArrayList<>(); Bag out = graph.getEdgesOut(node); Bag in = graph.getEdgesIn(node); - + if (in == null) { return children; } - + // Check that all inlet edges have been visited. for (Object obj : in) { SiteEdge edge = (SiteEdge) obj; @@ -659,7 +674,7 @@ private ArrayList traverseEdge(SiteNode node, String code) { return children; } } - + // Calculate total mass in. double mass = 0; for (Object obj : in) { @@ -668,20 +683,20 @@ private ArrayList traverseEdge(SiteNode node, String code) { mass += (edge.fraction.get(code) - edge.transport.get(code)) * edge.flow; } } - + // Set negative input mass to zero. Cause by higher transport out (calculated // from previous fraction in the step) than current fraction (calculated // from upstream consumption. if (mass < 0) { mass = 0; } - + // Update concentration for edge(s) out. For two edges out, the fraction // of mass entering each edge is equivalent to the fraction of total // flow rate for that edge. if (out != null) { double flowOut = 0; - + // Calculate total flow out. for (Object obj : out) { SiteEdge edge = (SiteEdge) obj; @@ -689,7 +704,7 @@ private ArrayList traverseEdge(SiteNode node, String code) { flowOut += edge.flow; } } - + // Assign new fractions. for (Object obj : out) { SiteEdge edge = (SiteEdge) obj; @@ -698,22 +713,22 @@ private ArrayList traverseEdge(SiteNode node, String code) { children.add(edge.getTo()); } } - + return children; } - + /** * Traverse through the graph based on nodes. * - * @param node the current node being traversed - * @param code the molecule code - * @return a list of children nodes to traverse + * @param node the current node being traversed + * @param code the molecule code + * @return a list of children nodes to traverse */ private ArrayList traverseNode(SiteNode node, String code) { ArrayList children = new ArrayList<>(); Bag out = graph.getEdgesOut(node); Bag in = graph.getEdgesIn(node); - + // Check that all inlet nodes have been visited. for (Object obj : in) { SiteEdge edge = (SiteEdge) obj; @@ -722,17 +737,18 @@ private ArrayList traverseNode(SiteNode node, String code) { return children; } } - + // Calculate total mass in. double massIn = 0; for (Object obj : in) { SiteEdge edge = (SiteEdge) obj; if (!edge.isIgnored) { - massIn += edge.flow * getTotal(edge.getFrom().oxygen, oxySoluPlasma) - - edge.transport.get(code); + massIn += + edge.flow * getTotal(edge.getFrom().oxygen, oxySoluPlasma) + - edge.transport.get(code); } } - + // Check for negative mass. if (massIn < 0) { node.oxygen = 0; @@ -746,12 +762,12 @@ private ArrayList traverseNode(SiteNode node, String code) { } return children; } - + final double finalMassIn = massIn; - + if (out != null) { double flowOut = 0; - + // Calculate total flow out. for (Object obj : out) { SiteEdge edge = (SiteEdge) obj; @@ -759,18 +775,18 @@ private ArrayList traverseNode(SiteNode node, String code) { flowOut += edge.flow; } } - + // Solve for oxygen partial pressure. final double finalFlowOut = flowOut; Function func = (p) -> finalFlowOut * getTotal(p, oxySoluPlasma) - finalMassIn; - + // Check for same sign. if (Math.signum(func.f(MAX_OXYGEN_PARTIAL_PRESSURE)) == -1 || finalFlowOut == 0) { node.oxygen = MAX_OXYGEN_PARTIAL_PRESSURE; } else { node.oxygen = Solver.bisection(func, 0, MAX_OXYGEN_PARTIAL_PRESSURE); } - + // Recurse through output edges. for (Object obj : out) { SiteEdge edge = (SiteEdge) obj; @@ -782,7 +798,7 @@ private ArrayList traverseNode(SiteNode node, String code) { SiteEdge e = (SiteEdge) in.objs[0]; node.oxygen = e.getFrom().oxygen; } - + return children; } } diff --git a/src/arcade/patch/env/component/PatchComponentSitesGraphFactory.java b/src/arcade/patch/env/component/PatchComponentSitesGraphFactory.java index e56630f96..e479bd308 100644 --- a/src/arcade/patch/env/component/PatchComponentSitesGraphFactory.java +++ b/src/arcade/patch/env/component/PatchComponentSitesGraphFactory.java @@ -17,350 +17,372 @@ /** * Factory for building a {@link Graph} for {@link PatchComponentSitesGraph}. - *

- * Graph can be initialized in two ways: + * + *

Graph can be initialized in two ways: + * *

    - *
  • pattern layout that matches the structure used by - * {@link PatchComponentSitesPattern}
  • - *
  • root layout grown from a specified root system using motifs
  • + *
  • pattern layout that matches the structure used by {@link PatchComponentSitesPattern} + *
  • root layout grown from a specified root system using motifs *
*/ - 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 caps = getEdgeByType(graph, new EdgeType[] { EdgeType.CAPILLARY }); + ArrayList caps = getEdgeByType(graph, new EdgeType[] {EdgeType.CAPILLARY}); updateRadii(graph, caps, CalculationType.UPSTREAM_PATTERN, random); updateRadii(graph, caps, CalculationType.DOWNSTREAM_PATTERN, random); - + graph.mergeNodes(); - + // Assign pressures. for (Object obj : graph.getAllEdges()) { SiteEdge edge = (SiteEdge) obj; @@ -452,118 +473,122 @@ public Graph initializePatternGraph(MersenneTwisterFast random) { edge.getTo().isRoot = true; } } - + // Assign lengths to edges and set as perfused. for (Object obj : graph.getAllEdges()) { SiteEdge edge = (SiteEdge) obj; edge.length = getLength(edge, EdgeLevel.VARIABLE); edge.isPerfused = true; } - + // Merge segments of the same type in the same direction. mergePatternGraph(graph); - + // Calculate network properties. calculatePressures(graph); - + // Reverse edges that have negative pressure difference. Recalculate // pressure for updated graph if there were edge reversals. boolean reversed = reversePressures(graph); if (reversed) { calculatePressures(graph); } - + calculateThicknesses(graph); calculateStresses(graph); calculateFlows(graph); - + return graph; } - + /** * Merges the edges in the graph with a pattern layout. * - * @param graph the graph instance + * @param graph the graph instance */ private void mergePatternGraph(Graph graph) { LinkedHashSet set = new LinkedHashSet<>(); HashMap scales = new HashMap<>(); - + // Create a set with all objects. for (Object obj : graph.getAllEdges()) { SiteEdge edge = (SiteEdge) obj; set.add(edge); scales.put(edge, 1); } - + int n; - + do { n = set.size(); - + for (SiteEdge edge1 : set) { if (graph.getOutDegree(edge1.getTo()) == 1) { int scale1 = scales.get(edge1); - EdgeDirection dir1 = getDirection( - edge1.getFrom().getX() / scale1, - edge1.getFrom().getY() / scale1, - edge1.getTo().getX() / scale1, - edge1.getTo().getY() / scale1 - ); - + EdgeDirection dir1 = + getDirection( + edge1.getFrom().getX() / scale1, + edge1.getFrom().getY() / scale1, + edge1.getTo().getX() / scale1, + edge1.getTo().getY() / scale1); + SiteEdge edge2 = (SiteEdge) edge1.getEdgesOut().get(0); int scale2 = scales.get(edge2); - EdgeDirection dir2 = getDirection( - edge2.getFrom().getX() / scale2, - edge2.getFrom().getY() / scale2, - edge2.getTo().getX() / scale2, - edge2.getTo().getY() / scale2 - ); - + EdgeDirection dir2 = + getDirection( + edge2.getFrom().getX() / scale2, + edge2.getFrom().getY() / scale2, + edge2.getTo().getX() / scale2, + edge2.getTo().getY() / scale2); + // Join edges that are the same direction and type. if (dir1 == dir2 && edge1.type == edge2.type) { - SiteEdge join = new SiteEdge(edge1.getFrom(), edge2.getTo(), - edge1.type, EdgeLevel.VARIABLE); + SiteEdge join = + new SiteEdge( + edge1.getFrom(), + edge2.getTo(), + edge1.type, + EdgeLevel.VARIABLE); scales.put(join, scale1 + scale2); - + // Set length to be sum and radius to be average of the // two constituent edges. join.length = edge1.length + edge1.length; join.radius = (edge1.radius + edge2.radius) / 2; join.isPerfused = true; - + // Set the node objects. join.setFrom(edge1.getFrom()); join.setTo(edge2.getTo()); - + // Replace the edges in the graph with the joined edge. graph.removeEdge(edge1); graph.removeEdge(edge2); graph.addEdge(join); - + // Update the iteration set. set.remove(edge1); set.remove(edge2); set.add(join); - + break; } } } } while ((n - set.size()) != 0); } - + /** * Initializes graph with edges and nodes in a root layout. * - * @param random the random number generator - * @param graphLayout the specification for layout of roots - * @return a graph instance with root layout + * @param random the random number generator + * @param graphLayout the specification for layout of roots + * @return a graph instance with root layout */ public Graph initializeRootGraph(MersenneTwisterFast random, String graphLayout) { ArrayList roots = parseRoots(graphLayout, random); Graph graph = new Graph(); - + // Iterate through all roots and try to add to the graph. Bag leaves = new Bag(); Utilities.shuffleList(roots, random); @@ -571,12 +596,12 @@ public Graph initializeRootGraph(MersenneTwisterFast random, String graphLayout) Bag bag = addRoot(graph, root.node, root.dir, root.type, root.offsets, random); leaves.addAll(bag); } - + ArrayList arteries = new ArrayList<>(); ArrayList veins = new ArrayList<>(); boolean hasArtery = false; boolean hasVein = false; - + // Iterate through roots and determine which ones were successfully // added. Separate into veins and arteries. for (Root root : roots) { @@ -598,21 +623,21 @@ public Graph initializeRootGraph(MersenneTwisterFast random, String graphLayout) } } } - + // Check that at least one artery root was added. Exit if there is not // at least one artery and one vein. if (!hasArtery || !hasVein) { return new Graph(); } - + // Add motifs from leaves. Bag leaves1 = addMotifs(graph, leaves, EdgeLevel.LEVEL_1, EdgeMotif.TRIPLE, random); Bag leaves2 = addMotifs(graph, leaves1, EdgeLevel.LEVEL_1, EdgeMotif.DOUBLE, random); addMotifs(graph, leaves2, EdgeLevel.LEVEL_1, EdgeMotif.SINGLE, random); - + // Calculate radii, pressure, and shears. updateRootGraph(graph, arteries, veins, EdgeLevel.LEVEL_1, random); - + // Iterative remodeling. int iter = 0; double frac = 1.0; @@ -621,101 +646,105 @@ public Graph initializeRootGraph(MersenneTwisterFast random, String graphLayout) updateRootGraph(graph, arteries, veins, EdgeLevel.LEVEL_1, random); iter++; } - + // Prune network for perfused segments and recalculate properties. refineRootGraph(graph, arteries, veins); - + // Subdivide growth sites and add new motifs. Bag midpoints = subdivideRootGraph(graph, EdgeLevel.LEVEL_1); Bag midpoints1 = addMotifs(graph, midpoints, EdgeLevel.LEVEL_2, EdgeMotif.TRIPLE, random); Bag midpoints2 = addMotifs(graph, midpoints1, EdgeLevel.LEVEL_2, EdgeMotif.DOUBLE, random); addMotifs(graph, midpoints2, EdgeLevel.LEVEL_2, EdgeMotif.SINGLE, random); - + // Calculate radii, pressure, and shears. updateRootGraph(graph, arteries, veins, EdgeLevel.LEVEL_2, random); - + // Prune network for perfused segments and recalculate properties. refineRootGraph(graph, arteries, veins); - + return graph; } - + /** * Updates hemodynamic properties for graph sites with root layouts. * - * @param graph the graph instance - * @param arteries the list of artery edges - * @param veins the list of vein edges - * @param level the graph resolution level - * @param random the random number generator + * @param graph the graph instance + * @param arteries the list of artery edges + * @param veins the list of vein edges + * @param level the graph resolution level + * @param random the random number generator */ - private void updateRootGraph(Graph graph, ArrayList arteries, ArrayList veins, - EdgeLevel level, MersenneTwisterFast random) { + private void updateRootGraph( + Graph graph, + ArrayList arteries, + ArrayList veins, + EdgeLevel level, + MersenneTwisterFast random) { ArrayList list; ArrayList caps = new ArrayList<>(); - + // Store upper level capillaries. if (level != EdgeLevel.LEVEL_1) { - caps = getEdgeByType(graph, new EdgeType[] { EdgeType.CAPILLARY }); + caps = getEdgeByType(graph, new EdgeType[] {EdgeType.CAPILLARY}); for (SiteEdge edge : caps) { graph.removeEdge(edge); } } - + // Get all leaves and update radii. - list = getLeavesByType(graph, new EdgeType[] { EdgeType.ARTERY, EdgeType.VEIN }); + list = getLeavesByType(graph, new EdgeType[] {EdgeType.ARTERY, EdgeType.VEIN}); updateRadii(graph, list, CalculationType.UPSTREAM_ALL); - + // Replace level 1 edges capillaries. if (level != EdgeLevel.LEVEL_1) { for (SiteEdge edge : caps) { graph.addEdge(edge); } } - + addSegments(graph, level, random); addConnections(graph, level, random); - - caps = getEdgeByType(graph, new EdgeType[] { EdgeType.CAPILLARY }); - + + caps = getEdgeByType(graph, new EdgeType[] {EdgeType.CAPILLARY}); + // Get capillaries and arterioles and update radii. switch (level) { case LEVEL_1: - list = getEdgeByType(graph, - new EdgeType[] { EdgeType.CAPILLARY, EdgeType.ARTERIOLE }); + list = + getEdgeByType( + graph, new EdgeType[] {EdgeType.CAPILLARY, EdgeType.ARTERIOLE}); break; case LEVEL_2: - list = getEdgeByType(graph, - new EdgeType[] { EdgeType.ARTERIOLE }, level); + list = getEdgeByType(graph, new EdgeType[] {EdgeType.ARTERIOLE}, level); list.addAll(caps); break; default: break; } - + updateRadii(graph, list, CalculationType.UPSTREAM_ALL); for (SiteEdge cap : caps) { graph.reverseEdge(cap); } - + // Get capillaries and venules and update radii. switch (level) { case LEVEL_1: - list = getEdgeByType(graph, new EdgeType[] { EdgeType.CAPILLARY, EdgeType.VENULE }); + list = getEdgeByType(graph, new EdgeType[] {EdgeType.CAPILLARY, EdgeType.VENULE}); break; case LEVEL_2: - list = getEdgeByType(graph, new EdgeType[] { EdgeType.VENULE }, level); + list = getEdgeByType(graph, new EdgeType[] {EdgeType.VENULE}, level); list.addAll(caps); break; default: break; } - + updateRadii(graph, list, CalculationType.UPSTREAM_ALL); for (SiteEdge cap : caps) { graph.reverseEdge(cap); } - + // Merge nodes. For level 2, separate graph into sub graphs by level. switch (level) { case LEVEL_1: @@ -731,7 +760,7 @@ private void updateRootGraph(Graph graph, ArrayList arteries, ArrayList arteries, ArrayList arteries, ArrayList veins) { // Reverse edges that are veins and venules. - ArrayList reverse = getEdgeByType(graph, - new EdgeType[] { EdgeType.VEIN, EdgeType.VENULE }); + ArrayList reverse = + getEdgeByType(graph, new EdgeType[] {EdgeType.VEIN, EdgeType.VENULE}); for (SiteEdge edge : reverse) { graph.reverseEdge(edge); } - + // Reverse edges that have negative pressure difference. reversePressures(graph); - + // Check for non-connected graph. - ArrayList caps = getEdgeByType(graph, new EdgeType[] { EdgeType.CAPILLARY }); + ArrayList caps = getEdgeByType(graph, new EdgeType[] {EdgeType.CAPILLARY}); if (caps.size() < 1) { graph.clear(); return; } - + // Determine which edges are perfused. checkPerfused(graph, arteries, veins); - + // Remove edges that are not perfused and reset radii. for (Object obj : new Bag(graph.getAllEdges())) { SiteEdge edge = (SiteEdge) obj; @@ -808,63 +837,63 @@ private void refineRootGraph(Graph graph, ArrayList arteries, ArrayList list = getEdgeByType(graph, new EdgeType[] { EdgeType.CAPILLARY }); + ArrayList list = getEdgeByType(graph, new EdgeType[] {EdgeType.CAPILLARY}); updateRadii(graph, list, CalculationType.UPSTREAM_ARTERIES); updateRadii(graph, list, CalculationType.DOWNSTREAM_VEINS); - + // Assign pressures to roots. setRootPressures(arteries, EdgeCategory.ARTERY); setRootPressures(veins, EdgeCategory.VEIN); - + // Recalculate pressure for updated graph. calculatePressures(graph); - + // Reverse edges that have negative pressure difference. Recalculate // pressure for updated graph if there were edge reversals. boolean reversed = reversePressures(graph); if (reversed) { calculatePressures(graph); } - + // Calculate shear and flow. calculateThicknesses(graph); calculateStresses(graph); calculateFlows(graph); } - + /** * Subdivides the graph edges by splitting each edge in half. * - * @param graph the graph instance - * @param level the graph resolution level - * @return the bag of edge midpoint nodes + * @param graph the graph instance + * @param level the graph resolution level + * @return the bag of edge midpoint nodes */ private Bag subdivideRootGraph(Graph graph, EdgeLevel level) { Bag midpoints = new Bag(); Graph g = new Graph(); - + for (Object obj : graph.getAllEdges()) { SiteEdge edge = (SiteEdge) obj; SiteNode from = edge.getFrom(); SiteNode to = edge.getTo(); - + // Calculate mid point. int x = (from.getX() + to.getX()) / 2; int y = (from.getY() + to.getY()) / 2; int z = (from.getZ() + to.getZ()) / 2; SiteNode mid = new SiteNode(x, y, z); - + // Set pressure to average of two nodes. mid.pressure = (from.pressure + to.pressure) / 2; - + // Make edges. For veins and venules, reverse the edges. SiteNode nodeA = null; SiteNode nodeB = null; SiteEdge edge1; SiteEdge edge2; - + switch (edge.type) { case ARTERY: case ARTERIOLE: @@ -880,69 +909,67 @@ private Bag subdivideRootGraph(Graph graph, EdgeLevel level) { default: break; } - + edge1 = new SiteEdge(nodeA, mid, edge.type, level); edge2 = new SiteEdge(mid, nodeB, edge.type, level); - + // Set node objects. edge1.setFrom(nodeA); edge1.setTo(mid); edge2.setFrom(mid); edge2.setTo(nodeB); - + // Set radii for arteriole and venules. if (edge.type == EdgeType.ARTERIOLE || edge.type == EdgeType.VENULE) { edge1.radius = edge.radius; edge2.radius = edge.radius; } - + // Add edges to temporary graph. g.addEdge(edge1); g.addEdge(edge2); - + // Set edges as perfused. edge1.isPerfused = true; edge2.isPerfused = true; - + // For arteries and veins, set midpoint as roots. if (edge.type == EdgeType.ARTERY || edge.type == EdgeType.VEIN) { midpoints.add(edge1); } } - + graph.clear(); graph.update(g); - + return midpoints; } - + /** * Remodels sites based on shear stress. * - * @param graph the graph instance - * @param level the graph resolution level - * @param random the random number generator - * @return the fraction of edges remodeled + * @param graph the graph instance + * @param level the graph resolution level + * @param random the random number generator + * @return the fraction of edges remodeled */ private double remodelRootGraph(Graph graph, EdgeLevel level, MersenneTwisterFast random) { // Remove capillaries, arterioles, and venules. - ArrayList list = getEdgeByType(graph, - new EdgeType[] { - EdgeType.CAPILLARY, - EdgeType.VENULE, - EdgeType.ARTERIOLE - }); + ArrayList list = + getEdgeByType( + graph, + new EdgeType[] {EdgeType.CAPILLARY, EdgeType.VENULE, EdgeType.ARTERIOLE}); for (SiteEdge edge : list) { graph.removeEdge(edge); } - + // Reset tags. Bag allEdges = new Bag(graph.getAllEdges()); for (Object obj : allEdges) { ((SiteEdge) obj).tag = null; } double total = allEdges.numObjs; - + // Tag edges to be removed or added. int count = 0; for (Object obj : allEdges) { @@ -951,7 +978,7 @@ private double remodelRootGraph(Graph graph, EdgeLevel level, MersenneTwisterFas double wG = edge.shearScaled + PROBABILITY_WEIGHT; double wD = 1 - edge.shearScaled - PROBABILITY_WEIGHT; double rand = random.nextDouble(); - + if (rand < wD) { if (graph.getOutDegree(to) == 0 && graph.getInDegree(to) == 0) { edge.tag = EdgeTag.REMOVE; @@ -967,50 +994,63 @@ private double remodelRootGraph(Graph graph, EdgeLevel level, MersenneTwisterFas } } } - + allEdges = new Bag(graph.getAllEdges()); allEdges.shuffle(random); - + if (count == 0) { return 0; } - + // Add or remove tagged edges. for (Object obj : allEdges) { SiteEdge edge = (SiteEdge) obj; if (edge.tag == EdgeTag.ADD && graph.getDegree(edge.getTo()) < 3) { - Bag bag1 = addMotif(graph, edge.getTo(), edge, edge.type, level, - EdgeMotif.TRIPLE, random); - + Bag bag1 = + addMotif( + graph, + edge.getTo(), + edge, + edge.type, + level, + EdgeMotif.TRIPLE, + random); + SiteEdge edge1 = (SiteEdge) bag1.get(0); - Bag bag2 = addMotif(graph, edge1.getTo(), edge, edge.type, level, - EdgeMotif.DOUBLE, random); - + Bag bag2 = + addMotif( + graph, + edge1.getTo(), + edge, + edge.type, + level, + EdgeMotif.DOUBLE, + random); + SiteEdge edge2 = (SiteEdge) bag2.get(0); - addMotif(graph, edge2.getTo(), edge, edge.type, level, - EdgeMotif.SINGLE, random); + addMotif(graph, edge2.getTo(), edge, edge.type, level, EdgeMotif.SINGLE, random); } else if (edge.tag == EdgeTag.REMOVE) { graph.removeEdge(edge); } - + edge.tag = null; edge.radius = 0; } - + return count / total; } - + /** * Parses the layout specification to create root objects. * - * @param layout the layout description - * @param random the random number generator - * @return a list of roots + * @param layout the layout description + * @param random the random number generator + * @return a list of roots */ private ArrayList parseRoots(String layout, MersenneTwisterFast random) { ArrayList roots = new ArrayList<>(); EdgeLevel level = EdgeLevel.LEVEL_1; - + // Find and add random roots. String regexRandom = "(LEFT|RIGHT|TOP|BOTTOM) random (\\d+)"; Matcher matcherRandom = Pattern.compile(regexRandom).matcher(layout); @@ -1024,7 +1064,7 @@ private ArrayList parseRoots(String layout, MersenneTwisterFast random) { roots.add(root); } } - + // Find and add single roots. String regexSingle = "(LEFT|RIGHT|TOP|BOTTOM) single (\\d+)([AVav])"; Matcher matcherSingle = Pattern.compile(regexSingle).matcher(layout); @@ -1034,7 +1074,7 @@ private ArrayList parseRoots(String layout, MersenneTwisterFast random) { EdgeType type = parseType(matcherSingle.group(3)); roots.add(createRoot(border, percent, type, level)); } - + // Find and add alternating roots. String regexAlternate = "(LEFT|RIGHT|TOP|BOTTOM) alternate (\\d+)"; Matcher matcherAlternate = Pattern.compile(regexAlternate).matcher(layout); @@ -1042,14 +1082,14 @@ private ArrayList parseRoots(String layout, MersenneTwisterFast random) { Border border = Border.valueOf(matcherAlternate.group(1)); double n = (Integer.parseInt(matcherAlternate.group(2))); double inc = 100.0 / n; - + for (int i = 0; i < n; i++) { double percent = (i * inc + inc / 2) / 100.0; EdgeType type = (i % 2 == 0 ? EdgeType.ARTERY : EdgeType.VEIN); roots.add(createRoot(border, percent, type, level)); } } - + // Find and add line roots. String regexLine = "(LEFT|RIGHT|TOP|BOTTOM) line (\\d+)([AVav])(\\d+)"; Matcher matcherLine = Pattern.compile(regexLine).matcher(layout); @@ -1062,46 +1102,46 @@ private ArrayList parseRoots(String layout, MersenneTwisterFast random) { root.offsets = createRootOffsets(border, fraction, level, random); roots.add(root); } - + return roots; } - + /** * Adds motifs to graph until no additional motifs can be added. * - * @param graph the graph instance - * @param bag the current bag of active edges - * @param level the graph resolution level - * @param motif the motif code - * @param random the random number generator - * @return the updated bag of active edges + * @param graph the graph instance + * @param bag the current bag of active edges + * @param level the graph resolution level + * @param motif the motif code + * @param random the random number generator + * @return the updated bag of active edges */ - private Bag addMotifs(Graph graph, Bag bag, EdgeLevel level, - EdgeMotif motif, MersenneTwisterFast random) { + private Bag addMotifs( + Graph graph, Bag bag, EdgeLevel level, EdgeMotif motif, MersenneTwisterFast random) { final int numZeros = 50; int delta; int zeros = 0; - + // Keep trying to add tripods until bag size no longer changes. while (zeros < numZeros) { // Create new bag to track new leaves. Bag newBag = new Bag(); - + // Stop loop if there are no objects in the bag. if (bag.numObjs == 0) { return null; } - + // Iterate through each leaf in bag. for (Object obj : bag) { // Get leaf edge from bag. SiteEdge edge = (SiteEdge) obj; SiteNode node = edge.getTo(); - + // Get current direction and add tripod in random direction. newBag.addAll(addMotif(graph, node, edge, edge.type, level, motif, random)); } - + // Calculate change in number of bags. delta = newBag.numObjs - bag.numObjs; if (delta == 0) { @@ -1109,21 +1149,21 @@ private Bag addMotifs(Graph graph, Bag bag, EdgeLevel level, } else { zeros--; } - + // Update bag to new bag of leaves. bag = newBag; bag.shuffle(random); } - + return bag; } - + /** * Adds segments to graph between arteries and veins. * - * @param graph the graph instance - * @param level the graph resolution level - * @param random the random number generator + * @param graph the graph instance + * @param level the graph resolution level + * @param random the random number generator */ private void addSegments(Graph graph, EdgeLevel level, MersenneTwisterFast random) { Bag bag = new Bag(graph.getAllEdges()); @@ -1141,13 +1181,13 @@ private void addSegments(Graph graph, EdgeLevel level, MersenneTwisterFast rando } } } - + /** * Adds connections to graphs between arteries or between veins. * - * @param graph the graph instance - * @param level the graph resolution level - * @param random the random number generator + * @param graph the graph instance + * @param level the graph resolution level + * @param random the random number generator */ private void addConnections(Graph graph, EdgeLevel level, MersenneTwisterFast random) { Bag bag = new Bag(graph.getAllEdges()); @@ -1155,16 +1195,17 @@ private void addConnections(Graph graph, EdgeLevel level, MersenneTwisterFast ra for (Object obj : bag) { SiteEdge edge = (SiteEdge) obj; SiteNode to = edge.getTo(); - + EdgeDirection dir = getDirection(edge, level); EdgeType type = edge.type; if (type != EdgeType.VEIN && type != EdgeType.ARTERY) { continue; } - + if (graph.getOutDegree(to) == 0 && graph.getInDegree(to) == 1) { addConnection(graph, to, dir, type, level, random); - } else if (graph.getInDegree(to) == 1 && graph.getOutDegree(to) == 1 + } else if (graph.getInDegree(to) == 1 + && graph.getOutDegree(to) == 1 && ((SiteEdge) graph.getEdgesOut(to).objs[0]).type == type && ((SiteEdge) graph.getEdgesIn(to).objs[0]).type == type) { addConnection(graph, to, dir, type, level, random); diff --git a/src/arcade/patch/env/component/PatchComponentSitesGraphFactoryRect.java b/src/arcade/patch/env/component/PatchComponentSitesGraphFactoryRect.java index 702a3fe20..75aa944eb 100644 --- a/src/arcade/patch/env/component/PatchComponentSitesGraphFactoryRect.java +++ b/src/arcade/patch/env/component/PatchComponentSitesGraphFactoryRect.java @@ -14,10 +14,10 @@ import static arcade.patch.env.component.PatchComponentSitesGraphUtilities.*; /** - * Concrete implementation of {@link PatchComponentSitesGraphFactory} for - * rectangular geometry. - *

- * For pattern layout, the graph is given by: + * Concrete implementation of {@link PatchComponentSitesGraphFactory} for rectangular geometry. + * + *

For pattern layout, the graph is given by: + * *

  *                         _ _ _ _
  *                       /         \
@@ -33,129 +33,136 @@
  *                      |           |
  *                       \ _ _ _ _ /
  * 
- *

- * For root layouts, each node has eight possible orientations for the edge: - * left, right, up, down, up left, up right, down left, and down right. When - * initializing roots from a border, only certain orientations are possible: + * + *

For root layouts, each node has eight possible orientations for the edge: left, right, up, + * down, up left, up right, down left, and down right. When initializing roots from a border, only + * certain orientations are possible: + * *

    - *
  • left border = right, up right, down right
  • - *
  • right border = left, up left, down left
  • - *
  • top border = down, down right, down left
  • - *
  • bottom border = up, up right, up left
  • + *
  • left border = right, up right, down right + *
  • right border = left, up left, down left + *
  • top border = down, down right, down left + *
  • bottom border = up, up right, up left *
*/ - public class PatchComponentSitesGraphFactoryRect extends PatchComponentSitesGraphFactory { /** List of all possible edge directions. */ - private static final EnumSet EDGE_DIRECTIONS = EnumSet.of( - EdgeDirection.UP, - EdgeDirection.UP_RIGHT, - EdgeDirection.RIGHT, - EdgeDirection.DOWN_RIGHT, - EdgeDirection.DOWN, - EdgeDirection.DOWN_LEFT, - EdgeDirection.LEFT, - EdgeDirection.UP_LEFT - ); - + private static final EnumSet EDGE_DIRECTIONS = + EnumSet.of( + EdgeDirection.UP, + EdgeDirection.UP_RIGHT, + EdgeDirection.RIGHT, + EdgeDirection.DOWN_RIGHT, + EdgeDirection.DOWN, + EdgeDirection.DOWN_LEFT, + EdgeDirection.LEFT, + EdgeDirection.UP_LEFT); + /** Map of edge directions to their reverse direction. */ - private static final EnumSet SINGLE_EDGE_DIRECTIONS = EnumSet.of( - EdgeDirection.UP_RIGHT, - EdgeDirection.DOWN_RIGHT, - EdgeDirection.DOWN_LEFT, - EdgeDirection.UP_LEFT - ); - + private static final EnumSet SINGLE_EDGE_DIRECTIONS = + EnumSet.of( + EdgeDirection.UP_RIGHT, + EdgeDirection.DOWN_RIGHT, + EdgeDirection.DOWN_LEFT, + EdgeDirection.UP_LEFT); + /** Map of edge directions to their reverse direction. */ - private static final EnumMap REVERSE_EDGE_DIRECTIONS - = new EnumMap(EdgeDirection.class) {{ - put(EdgeDirection.UP, EdgeDirection.DOWN); - put(EdgeDirection.UP_RIGHT, EdgeDirection.DOWN_LEFT); - put(EdgeDirection.RIGHT, EdgeDirection.LEFT); - put(EdgeDirection.DOWN_RIGHT, EdgeDirection.UP_LEFT); - put(EdgeDirection.DOWN, EdgeDirection.UP); - put(EdgeDirection.DOWN_LEFT, EdgeDirection.UP_RIGHT); - put(EdgeDirection.LEFT, EdgeDirection.RIGHT); - put(EdgeDirection.UP_LEFT, EdgeDirection.DOWN_RIGHT); - }}; - + private static final EnumMap REVERSE_EDGE_DIRECTIONS = + new EnumMap(EdgeDirection.class) { + { + put(EdgeDirection.UP, EdgeDirection.DOWN); + put(EdgeDirection.UP_RIGHT, EdgeDirection.DOWN_LEFT); + put(EdgeDirection.RIGHT, EdgeDirection.LEFT); + put(EdgeDirection.DOWN_RIGHT, EdgeDirection.UP_LEFT); + put(EdgeDirection.DOWN, EdgeDirection.UP); + put(EdgeDirection.DOWN_LEFT, EdgeDirection.UP_RIGHT); + put(EdgeDirection.LEFT, EdgeDirection.RIGHT); + put(EdgeDirection.UP_LEFT, EdgeDirection.DOWN_RIGHT); + } + }; + /** List of coordinate offsets for each direction. */ - private static final EnumMap OFFSETS - = new EnumMap(EdgeDirection.class) {{ - put(EdgeDirection.UP, new int[] { 0, -1, 0 }); - put(EdgeDirection.UP_RIGHT, new int[] { 1, -1, 0 }); - put(EdgeDirection.RIGHT, new int[] { 1, 0, 0 }); - put(EdgeDirection.DOWN_RIGHT, new int[] { 1, 1, 0 }); - put(EdgeDirection.DOWN, new int[] { 0, 1, 0 }); - put(EdgeDirection.DOWN_LEFT, new int[] { -1, 1, 0 }); - put(EdgeDirection.LEFT, new int[] { -1, 0, 0 }); - put(EdgeDirection.UP_LEFT, new int[] { -1, -1, 0 }); - }}; - + private static final EnumMap OFFSETS = + new EnumMap(EdgeDirection.class) { + { + put(EdgeDirection.UP, new int[] {0, -1, 0}); + put(EdgeDirection.UP_RIGHT, new int[] {1, -1, 0}); + put(EdgeDirection.RIGHT, new int[] {1, 0, 0}); + put(EdgeDirection.DOWN_RIGHT, new int[] {1, 1, 0}); + put(EdgeDirection.DOWN, new int[] {0, 1, 0}); + put(EdgeDirection.DOWN_LEFT, new int[] {-1, 1, 0}); + put(EdgeDirection.LEFT, new int[] {-1, 0, 0}); + put(EdgeDirection.UP_LEFT, new int[] {-1, -1, 0}); + } + }; + /** List of offset directions for root directions. */ - private static final EnumMap ROOT_OFFSETS - = new EnumMap(EdgeDirection.class) {{ - put(EdgeDirection.UP, - new EdgeDirection[] { EdgeDirection.UP_RIGHT, EdgeDirection.UP_LEFT }); - put(EdgeDirection.UP_RIGHT, - new EdgeDirection[] { EdgeDirection.RIGHT, EdgeDirection.UP }); - put(EdgeDirection.RIGHT, - new EdgeDirection[] { EdgeDirection.DOWN_RIGHT, EdgeDirection.UP_RIGHT }); - put(EdgeDirection.DOWN_RIGHT, - new EdgeDirection[] { EdgeDirection.DOWN, EdgeDirection.RIGHT }); - put(EdgeDirection.DOWN, - new EdgeDirection[] { EdgeDirection.DOWN_LEFT, EdgeDirection.DOWN_RIGHT }); - put(EdgeDirection.DOWN_LEFT, - new EdgeDirection[] { EdgeDirection.LEFT, EdgeDirection.DOWN }); - put(EdgeDirection.LEFT, - new EdgeDirection[] { EdgeDirection.UP_LEFT, EdgeDirection.DOWN_LEFT }); - put(EdgeDirection.UP_LEFT, - new EdgeDirection[] { EdgeDirection.UP, EdgeDirection.LEFT }); - }}; - + private static final EnumMap ROOT_OFFSETS = + new EnumMap(EdgeDirection.class) { + { + put( + EdgeDirection.UP, + new EdgeDirection[] {EdgeDirection.UP_RIGHT, EdgeDirection.UP_LEFT}); + put( + EdgeDirection.UP_RIGHT, + new EdgeDirection[] {EdgeDirection.RIGHT, EdgeDirection.UP}); + put( + EdgeDirection.RIGHT, + new EdgeDirection[] {EdgeDirection.DOWN_RIGHT, EdgeDirection.UP_RIGHT}); + put( + EdgeDirection.DOWN_RIGHT, + new EdgeDirection[] {EdgeDirection.DOWN, EdgeDirection.RIGHT}); + put( + EdgeDirection.DOWN, + new EdgeDirection[] { + EdgeDirection.DOWN_LEFT, EdgeDirection.DOWN_RIGHT + }); + put( + EdgeDirection.DOWN_LEFT, + new EdgeDirection[] {EdgeDirection.LEFT, EdgeDirection.DOWN}); + put( + EdgeDirection.LEFT, + new EdgeDirection[] {EdgeDirection.UP_LEFT, EdgeDirection.DOWN_LEFT}); + put( + EdgeDirection.UP_LEFT, + new EdgeDirection[] {EdgeDirection.UP, EdgeDirection.LEFT}); + } + }; + /** Array positions for edge directions. */ - private static final EdgeDirection[][] DIRS = new EdgeDirection[][] { - { - EdgeDirection.UP_LEFT, - EdgeDirection.UP, - EdgeDirection.UP_RIGHT - }, - { - EdgeDirection.LEFT, - EdgeDirection.UNDEFINED, - EdgeDirection.RIGHT - }, - { - EdgeDirection.DOWN_LEFT, - EdgeDirection.DOWN, - EdgeDirection.DOWN_RIGHT - }, - }; - + private static final EdgeDirection[][] DIRS = + new EdgeDirection[][] { + {EdgeDirection.UP_LEFT, EdgeDirection.UP, EdgeDirection.UP_RIGHT}, + {EdgeDirection.LEFT, EdgeDirection.UNDEFINED, EdgeDirection.RIGHT}, + {EdgeDirection.DOWN_LEFT, EdgeDirection.DOWN, EdgeDirection.DOWN_RIGHT}, + }; + /** List of edge lengths. */ private final double[] edgeLengths; - + /** * Creates a {@link PatchComponentSitesGraph} for rectangular geometry. * - * @param series the simulation series + * @param series the simulation series */ public PatchComponentSitesGraphFactoryRect(Series series) { super(series); - edgeLengths = new double[] { series.ds, series.ds * Math.sqrt(2) }; + edgeLengths = new double[] {series.ds, series.ds * Math.sqrt(2)}; } - + @Override - int[] getOffset(EdgeDirection offset) { return OFFSETS.get(offset); } - + int[] getOffset(EdgeDirection offset) { + return OFFSETS.get(offset); + } + /** * Checks if there is an edge in the cross diagonal. * - * @param graph the graph instance - * @param from the node the edge is from - * @param to the node the edge is to - * @param level the graph resolution level - * @return {@code true} if no cross diagonal edge, {@code false} otherwise + * @param graph the graph instance + * @param from the node the edge is from + * @param to the node the edge is to + * @param level the graph resolution level + * @return {@code true} if no cross diagonal edge, {@code false} otherwise */ private boolean checkCross(Graph graph, SiteNode from, SiteNode to, EdgeLevel level) { EdgeDirection dir = getDirection(from, to, level); @@ -171,37 +178,39 @@ private boolean checkCross(Graph graph, SiteNode from, SiteNode to, EdgeLevel le return true; } } - + @Override int calcOffset(int k) { return (latticeHeight - k / 2 + 1 - ((latticeHeight - 1) / 4) % 2) % 2; } - + @Override int calcCol(int i, int offset) { return (i + 4 * offset) % 6; } - + @Override int calcRow(int i, int j, int offset) { return (j + offset + (((i + 4 * offset) / 6 & 1) == 0 ? 0 : 3)) % 6; } - + @Override - boolean checkNode(Node node) { return checkNode(node.getX(), node.getY(), node.getZ()); } - + boolean checkNode(Node node) { + return checkNode(node.getX(), node.getY(), node.getZ()); + } + /** * Checks if the given coordinates are outside bounds of the environment. * - * @param x the x coordinate - * @param y the y coordinate - * @param z the z coordinate - * @return {@code true} if within bounds, {@code false} otherwise + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + * @return {@code true} if within bounds, {@code false} otherwise */ private boolean checkNode(int x, int y, int z) { return !(x < 0 || x > latticeLength || y < 0 || y > latticeWidth); } - + @Override double getLength(SiteEdge edge, EdgeLevel level) { EdgeDirection direction = getDirection(edge, level); @@ -220,44 +229,44 @@ private boolean checkNode(int x, int y, int z) { return Double.NaN; } } - + @Override void createPattern(Graph graph) { ArrayList edges = new ArrayList<>(); - + // Add edges using pattern match layout. for (int k = 0; k < latticeHeight; k += 2) { int offset = calcOffset(k); - + for (int i = 0; i <= latticeLength; i++) { for (int j = 0; j <= latticeWidth; j++) { int col = calcCol(i, offset); int row = calcRow(i, j, offset); - + if (col == 0 && row == 5) { - edges.add(new int[] { i, j, k, i + 1, j, k }); + edges.add(new int[] {i, j, k, i + 1, j, k}); } else if (col == 1 && row == 5) { - edges.add(new int[] { i, j, k, i + 1, j, k }); + edges.add(new int[] {i, j, k, i + 1, j, k}); } else if (col == 2 && row == 5) { - edges.add(new int[] { i, j, k, i + 1, j, k }); + edges.add(new int[] {i, j, k, i + 1, j, k}); } else if (col == 3 && row == 5) { - edges.add(new int[] { i, j, k, i + 1, j, k }); + edges.add(new int[] {i, j, k, i + 1, j, k}); } else if (col == 5 && row == 4) { - edges.add(new int[] { i, j, k, i, j - 1, k }); + edges.add(new int[] {i, j, k, i, j - 1, k}); } else if (col == 5 && row == 0) { - edges.add(new int[] { i, j, k, i, j + 1, k }); + edges.add(new int[] {i, j, k, i, j + 1, k}); } else if (col == 5 && row == 1) { - edges.add(new int[] { i, j, k, i + 1, j + 1, k }); + edges.add(new int[] {i, j, k, i + 1, j + 1, k}); } else if (col == 5 && row == 3) { - edges.add(new int[] { i, j, k, i + 1, j - 1, k }); + edges.add(new int[] {i, j, k, i + 1, j - 1, k}); } else if (col == 4 && row == 5) { - edges.add(new int[] { i, j, k, i + 1, j - 1, k }); - edges.add(new int[] { i, j, k, i + 1, j + 1, k }); + edges.add(new int[] {i, j, k, i + 1, j - 1, k}); + edges.add(new int[] {i, j, k, i + 1, j + 1, k}); } } } } - + // Add all edges within bounds to graph. for (int[] e : edges) { if (checkNode(e[0], e[1], e[2]) && checkNode(e[3], e[4], e[5])) { @@ -266,17 +275,19 @@ void createPattern(Graph graph) { int offset = calcOffset(e[2]); int thresh = latticeLength / 2; thresh += 2 - (calcCol(thresh, offset) + 1) % 6; - + // Add edge to graph. SiteNode from = new SiteNode(e[0], e[1], e[2]); SiteNode to = new SiteNode(e[3], e[4], e[5]); - EdgeType type = (e[0] == thresh ? EdgeType.CAPILLARY - : (e[0] < thresh ? EdgeType.ARTERY : EdgeType.VEIN)); + EdgeType type = + (e[0] == thresh + ? EdgeType.CAPILLARY + : (e[0] < thresh ? EdgeType.ARTERY : EdgeType.VEIN)); SiteEdge edge = new SiteEdge(from, to, type, EdgeLevel.VARIABLE); graph.addEdge(edge); } } - + // Traverse graph from leftmost nodes to identify unnecessary edges. for (int k = 0; k < latticeHeight; k += 2) { for (int j = 0; j <= latticeWidth; j++) { @@ -285,14 +296,14 @@ void createPattern(Graph graph) { } } } - + @Override Root createRoot(Border border, double percent, EdgeType type, EdgeLevel level) { int scale = level.scale; int width = Math.floorDiv(latticeWidth, scale); int length = Math.floorDiv(latticeLength, scale); int c = -1; - + switch (border) { case LEFT: case RIGHT: @@ -305,7 +316,7 @@ Root createRoot(Border border, double percent, EdgeType type, EdgeLevel level) { default: break; } - + switch (border) { case LEFT: return new Root(0, c * scale, type, EdgeDirection.RIGHT); @@ -318,18 +329,18 @@ Root createRoot(Border border, double percent, EdgeType type, EdgeLevel level) { default: break; } - + return null; } - + @Override - EdgeDirection[] createRootOffsets(Border border, double fraction, EdgeLevel level, - MersenneTwisterFast random) { + EdgeDirection[] createRootOffsets( + Border border, double fraction, EdgeLevel level, MersenneTwisterFast random) { int scale = level.scale; int width = Math.floorDiv(latticeWidth, scale); int length = Math.floorDiv(latticeLength, scale); int numOffsets = 0; - + switch (border) { case LEFT: case RIGHT: @@ -342,52 +353,48 @@ EdgeDirection[] createRootOffsets(Border border, double fraction, EdgeLevel leve default: break; } - + EdgeDirection[] directions = null; int index = -1; - + // Get direction list. switch (border) { case LEFT: - directions = new EdgeDirection[] { - EdgeDirection.UP_RIGHT, - EdgeDirection.RIGHT, - EdgeDirection.DOWN_RIGHT - }; + directions = + new EdgeDirection[] { + EdgeDirection.UP_RIGHT, EdgeDirection.RIGHT, EdgeDirection.DOWN_RIGHT + }; index = 1; break; case RIGHT: - directions = new EdgeDirection[] { - EdgeDirection.UP_LEFT, - EdgeDirection.LEFT, - EdgeDirection.DOWN_LEFT - }; + directions = + new EdgeDirection[] { + EdgeDirection.UP_LEFT, EdgeDirection.LEFT, EdgeDirection.DOWN_LEFT + }; index = 1; break; case TOP: - directions = new EdgeDirection[] { - EdgeDirection.DOWN_LEFT, - EdgeDirection.DOWN, - EdgeDirection.DOWN_RIGHT - }; + directions = + new EdgeDirection[] { + EdgeDirection.DOWN_LEFT, EdgeDirection.DOWN, EdgeDirection.DOWN_RIGHT + }; index = 0; break; case BOTTOM: - directions = new EdgeDirection[] { - EdgeDirection.UP_LEFT, - EdgeDirection.UP, - EdgeDirection.UP_RIGHT - }; + directions = + new EdgeDirection[] { + EdgeDirection.UP_LEFT, EdgeDirection.UP, EdgeDirection.UP_RIGHT + }; index = 0; break; default: break; } - + int deviation = 0; EdgeDirection offset = null; EdgeDirection[] offsets = new EdgeDirection[numOffsets]; - + // Iterate through to fill up offsets. for (int i = 0; i < numOffsets; i++) { if (deviation > 0) { @@ -397,45 +404,54 @@ EdgeDirection[] createRootOffsets(Border border, double fraction, EdgeLevel leve } else { offset = directions[random.nextInt(3)]; } - + offsets[i] = offset; deviation += OFFSETS.get(offset)[index]; } - + return offsets; } - + @Override EdgeDirection getDirection(int fromX, int fromY, int toX, int toY) { int dx = (toX - fromX) + 1; int dy = (toY - fromY) + 1; return DIRS[dy][dx]; } - + @Override - Bag addRoot(Graph graph, SiteNode node0, EdgeDirection dir, EdgeType type, - EdgeDirection[] offsets, MersenneTwisterFast random) { + Bag addRoot( + Graph graph, + SiteNode node0, + EdgeDirection dir, + EdgeType type, + EdgeDirection[] offsets, + MersenneTwisterFast random) { Bag bag = new Bag(); EdgeLevel level = EdgeLevel.LEVEL_1; SiteNode node1 = offsetNode(node0, dir, level); boolean checkNode0 = checkNode(node0); boolean checkNode1 = checkNode(node1); - + // Add initial edge in the specified direction. If unable to add it, // then do not add the rest of the tripod. - if (checkNode0 && checkNode1 && graph.getDegree(node0) == 0 && graph.getDegree(node1) == 0 + if (checkNode0 + && checkNode1 + && graph.getDegree(node0) == 0 + && graph.getDegree(node1) == 0 && checkCross(graph, node0, node1, level)) { SiteEdge edge = new SiteEdge(node0, node1, type, level); graph.addEdge(edge); } else { return bag; } - + // Add the two leaves of the tripod if line is 0, otherwise add in the root line. if (offsets == null) { for (EdgeDirection offset : ROOT_OFFSETS.get(dir)) { SiteNode node2 = offsetNode(node1, offset, level); - if (checkNode(node2) && graph.getDegree(node2) == 0 + if (checkNode(node2) + && graph.getDegree(node2) == 0 && checkCross(graph, node1, node2, level)) { SiteEdge edge = new SiteEdge(node1, node2, type, level); graph.addEdge(edge); @@ -445,11 +461,12 @@ && checkCross(graph, node1, node2, level)) { } else { SiteNode currNode = node1; ArrayList edges = new ArrayList<>(); - + // Add segments for given list of offsets. for (EdgeDirection offset : offsets) { SiteNode nextNode = offsetNode(currNode, offset, level); - if (checkNode(nextNode) && graph.getDegree(nextNode) == 0 + if (checkNode(nextNode) + && graph.getDegree(nextNode) == 0 && checkCross(graph, currNode, nextNode, level)) { SiteEdge edge = new SiteEdge(currNode, nextNode, type, level); graph.addEdge(edge); @@ -457,44 +474,53 @@ && checkCross(graph, currNode, nextNode, level)) { currNode = nextNode; } } - + // Shuffle and add tripods off the offset line. Utilities.shuffleList(edges, random); for (SiteEdge edge : edges) { - bag.addAll(addMotif(graph, edge.getTo(), edge, type, level, - EdgeMotif.TRIPLE, random)); + bag.addAll( + addMotif(graph, edge.getTo(), edge, type, level, EdgeMotif.TRIPLE, random)); } } - + return bag; } - + @Override - Bag addMotif(Graph graph, SiteNode node0, SiteEdge edge0, EdgeType type, EdgeLevel level, - EdgeMotif motif, MersenneTwisterFast random) { + Bag addMotif( + Graph graph, + SiteNode node0, + SiteEdge edge0, + EdgeType type, + EdgeLevel level, + EdgeMotif motif, + MersenneTwisterFast random) { // Select new random direction. EdgeDirection dir0 = getDirection(edge0, level); ArrayList validDirections = new ArrayList<>(EDGE_DIRECTIONS); validDirections.remove(REVERSE_EDGE_DIRECTIONS.get(dir0)); EdgeDirection dir = validDirections.get(random.nextInt(validDirections.size())); - + // Make tripod nodes. SiteNode node1 = offsetNode(node0, dir, level); SiteNode node2 = offsetNode(node1, ROOT_OFFSETS.get(dir)[0], level); SiteNode node3 = offsetNode(node1, ROOT_OFFSETS.get(dir)[1], level); - + // Check nodes. boolean checkNode0 = checkNode(node0); boolean checkNode1 = checkNode(node1); boolean checkNode2 = checkNode(node2); boolean checkNode3 = checkNode(node3); - + Bag bag = new Bag(); SiteEdge edge; - + switch (motif) { case TRIPLE: - if (checkNode0 && checkNode1 && checkNode2 && checkNode3 + if (checkNode0 + && checkNode1 + && checkNode2 + && checkNode3 && graph.getDegree(node1) == 0 && graph.getDegree(node2) == 0 && graph.getDegree(node3) == 0 @@ -503,11 +529,11 @@ && checkCross(graph, node1, node2, level) && checkCross(graph, node1, node3, level)) { edge = new SiteEdge(node0, node1, type, level); graph.addEdge(edge); - + edge = new SiteEdge(node1, node2, type, level); graph.addEdge(edge); bag.add(edge); - + edge = new SiteEdge(node1, node3, type, level); graph.addEdge(edge); bag.add(edge); @@ -516,21 +542,25 @@ && checkCross(graph, node1, node3, level)) { } break; case DOUBLE: - if (checkNode0 && checkNode1 && graph.getDegree(node1) == 0 + if (checkNode0 + && checkNode1 + && graph.getDegree(node1) == 0 && checkCross(graph, node0, node1, level)) { ArrayList options = new ArrayList<>(); - - if (checkNode2 && graph.getDegree(node2) == 0 + + if (checkNode2 + && graph.getDegree(node2) == 0 && checkCross(graph, node1, node2, level)) { options.add(node2); } - if (checkNode3 && graph.getDegree(node3) == 0 + if (checkNode3 + && graph.getDegree(node3) == 0 && checkCross(graph, node1, node3, level)) { options.add(node3); } - + Utilities.shuffleList(options, random); - + if (options.size() > 0) { edge = new SiteEdge(node0, node1, type, level); graph.addEdge(edge); @@ -545,7 +575,9 @@ && checkCross(graph, node1, node3, level)) { } break; case SINGLE: - if (SINGLE_EDGE_DIRECTIONS.contains(dir) && checkNode0 && checkNode1 + if (SINGLE_EDGE_DIRECTIONS.contains(dir) + && checkNode0 + && checkNode1 && graph.getDegree(node1) == 0 && checkCross(graph, node0, node1, level)) { edge = new SiteEdge(node0, node1, type, level); @@ -558,29 +590,33 @@ && checkCross(graph, node0, node1, level)) { default: break; } - + return bag; } - + @Override - void addSegment(Graph graph, SiteNode node0, EdgeDirection dir, EdgeLevel level, - MersenneTwisterFast random) { + void addSegment( + Graph graph, + SiteNode node0, + EdgeDirection dir, + EdgeLevel level, + MersenneTwisterFast random) { ArrayList options = new ArrayList<>(); - + // Iterate through all seven direction options. for (EdgeDirection offset : EDGE_DIRECTIONS) { if (offset == REVERSE_EDGE_DIRECTIONS.get(dir)) { continue; } - + SiteNode node1 = offsetNode(node0, offset, level); if (!checkNode(node1)) { continue; } - + SiteEdge edgeOut = null; SiteEdge edgeIn = null; - + // Check edges in and out of proposed node. if (graph.getOutDegree(node1) == 1) { edgeOut = (SiteEdge) graph.getEdgesOut(node1).objs[0]; @@ -598,46 +634,53 @@ void addSegment(Graph graph, SiteNode node0, EdgeDirection dir, EdgeLevel level, edgeIn = null; } } - + if (edgeOut != null || edgeIn != null) { options.add(node1); } } - + Utilities.shuffleList(options, random); - + for (SiteNode node1 : options) { SiteEdge e = new SiteEdge(node0, node1, EdgeType.CAPILLARY, level); - if (graph.getDegree(node0) < 3 && graph.getDegree(node1) < 3 + if (graph.getDegree(node0) < 3 + && graph.getDegree(node1) < 3 && checkCross(graph, node0, node1, level)) { graph.addEdge(e); } } } - + @Override - void addConnection(Graph graph, SiteNode node0, EdgeDirection dir, EdgeType type, - EdgeLevel level, MersenneTwisterFast random) { + void addConnection( + Graph graph, + SiteNode node0, + EdgeDirection dir, + EdgeType type, + EdgeLevel level, + MersenneTwisterFast random) { ArrayList options = new ArrayList<>(); EdgeType connType = (type == EdgeType.ARTERY ? EdgeType.ARTERIOLE : EdgeType.VENULE); - + // Iterate through all seven direction options. for (EdgeDirection offset : EDGE_DIRECTIONS) { if (offset == REVERSE_EDGE_DIRECTIONS.get(dir)) { continue; } - + SiteNode node1 = offsetNode(node0, offset, level); if (!checkNode(node1)) { continue; } - + // Check edges in and out of proposed node. if (graph.getOutDegree(node1) == 1 && graph.getInDegree(node1) == 1) { SiteEdge edgeOut = (SiteEdge) graph.getEdgesOut(node1).objs[0]; SiteEdge edgeIn = (SiteEdge) graph.getEdgesIn(node1).objs[0]; - - if (edgeOut.type == type && edgeIn.type == type + + if (edgeOut.type == type + && edgeIn.type == type && edgeOut.radius <= MAXIMUM_CAPILLARY_RADIUS && edgeIn.radius <= MAXIMUM_CAPILLARY_RADIUS) { path(graph, node1, node0); @@ -647,12 +690,13 @@ void addConnection(Graph graph, SiteNode node0, EdgeDirection dir, EdgeType type } } } - + Utilities.shuffleList(options, random); - + for (SiteNode node1 : options) { SiteEdge e = new SiteEdge(node0, node1, connType, level); - if (graph.getDegree(node0) < 3 && graph.getDegree(node1) < 3 + if (graph.getDegree(node0) < 3 + && graph.getDegree(node1) < 3 && !graph.hasEdge(node0, node1) && checkCross(graph, node0, node1, level)) { graph.addEdge(e); diff --git a/src/arcade/patch/env/component/PatchComponentSitesGraphFactoryTri.java b/src/arcade/patch/env/component/PatchComponentSitesGraphFactoryTri.java index af862acae..4935ec12a 100644 --- a/src/arcade/patch/env/component/PatchComponentSitesGraphFactoryTri.java +++ b/src/arcade/patch/env/component/PatchComponentSitesGraphFactoryTri.java @@ -14,10 +14,10 @@ import static arcade.patch.env.component.PatchComponentSitesGraphUtilities.*; /** - * Concrete implementation of {@link PatchComponentSitesGraphFactory} for - * triangular geometry. - *

- * For pattern layout, the graph is given by: + * Concrete implementation of {@link PatchComponentSitesGraphFactory} for triangular geometry. + * + *

For pattern layout, the graph is given by: + * *

  *                         ___ ___
  *                       /         \
@@ -33,179 +33,196 @@
  *                      \           /
  *                       \ ___ ___ /
  * 
- *

- * For root layouts, each node has six possible orientations for the edge: left, - * right, up left, up right, down left, and down right. When initializing roots - * from a border, only certain orientations are possible: + * + *

For root layouts, each node has six possible orientations for the edge: left, right, up left, + * up right, down left, and down right. When initializing roots from a border, only certain + * orientations are possible: + * *

    - *
  • left border = right, up right, down right
  • - *
  • right border = left, up left, down left
  • - *
  • top border = down right, down left
  • - *
  • bottom border = up right, up left
  • + *
  • left border = right, up right, down right + *
  • right border = left, up left, down left + *
  • top border = down right, down left + *
  • bottom border = up right, up left *
*/ - public class PatchComponentSitesGraphFactoryTri extends PatchComponentSitesGraphFactory { /** List of all possible edge directions. */ - private static final EnumSet EDGE_DIRECTIONS = EnumSet.of( - EdgeDirection.UP_LEFT, - EdgeDirection.UP_RIGHT, - EdgeDirection.RIGHT, - EdgeDirection.DOWN_RIGHT, - EdgeDirection.DOWN_LEFT, - EdgeDirection.LEFT - ); - + private static final EnumSet EDGE_DIRECTIONS = + EnumSet.of( + EdgeDirection.UP_LEFT, + EdgeDirection.UP_RIGHT, + EdgeDirection.RIGHT, + EdgeDirection.DOWN_RIGHT, + EdgeDirection.DOWN_LEFT, + EdgeDirection.LEFT); + /** Map of edge directions to their reverse direction. */ - private static final EnumMap REVERSE_EDGE_DIRECTIONS - = new EnumMap(EdgeDirection.class) {{ - put(EdgeDirection.UP_LEFT, EdgeDirection.DOWN_RIGHT); - put(EdgeDirection.UP_RIGHT, EdgeDirection.DOWN_LEFT); - put(EdgeDirection.RIGHT, EdgeDirection.LEFT); - put(EdgeDirection.DOWN_RIGHT, EdgeDirection.UP_LEFT); - put(EdgeDirection.DOWN_LEFT, EdgeDirection.UP_RIGHT); - put(EdgeDirection.LEFT, EdgeDirection.RIGHT); - }}; - + private static final EnumMap REVERSE_EDGE_DIRECTIONS = + new EnumMap(EdgeDirection.class) { + { + put(EdgeDirection.UP_LEFT, EdgeDirection.DOWN_RIGHT); + put(EdgeDirection.UP_RIGHT, EdgeDirection.DOWN_LEFT); + put(EdgeDirection.RIGHT, EdgeDirection.LEFT); + put(EdgeDirection.DOWN_RIGHT, EdgeDirection.UP_LEFT); + put(EdgeDirection.DOWN_LEFT, EdgeDirection.UP_RIGHT); + put(EdgeDirection.LEFT, EdgeDirection.RIGHT); + } + }; + /** List of coordinate offsets for each direction. */ - private static final EnumMap OFFSETS - = new EnumMap(EdgeDirection.class) {{ - put(EdgeDirection.UP_LEFT, new int[] { -1, -1, 0 }); - put(EdgeDirection.UP_RIGHT, new int[] { 1, -1, 0 }); - put(EdgeDirection.RIGHT, new int[] { 2, 0, 0 }); - put(EdgeDirection.DOWN_RIGHT, new int[] { 1, 1, 0 }); - put(EdgeDirection.DOWN_LEFT, new int[] { -1, 1, 0 }); - put(EdgeDirection.LEFT, new int[] { -2, 0, 0 }); - }}; - + private static final EnumMap OFFSETS = + new EnumMap(EdgeDirection.class) { + { + put(EdgeDirection.UP_LEFT, new int[] {-1, -1, 0}); + put(EdgeDirection.UP_RIGHT, new int[] {1, -1, 0}); + put(EdgeDirection.RIGHT, new int[] {2, 0, 0}); + put(EdgeDirection.DOWN_RIGHT, new int[] {1, 1, 0}); + put(EdgeDirection.DOWN_LEFT, new int[] {-1, 1, 0}); + put(EdgeDirection.LEFT, new int[] {-2, 0, 0}); + } + }; + /** List of offset directions for root directions. */ - private static final EnumMap ROOT_OFFSETS - = new EnumMap(EdgeDirection.class) {{ - put(EdgeDirection.UP_LEFT, - new EdgeDirection[] { EdgeDirection.UP_RIGHT, EdgeDirection.LEFT }); - put(EdgeDirection.UP_RIGHT, - new EdgeDirection[] { EdgeDirection.RIGHT, EdgeDirection.UP_LEFT }); - put(EdgeDirection.RIGHT, - new EdgeDirection[] { EdgeDirection.DOWN_RIGHT, EdgeDirection.UP_RIGHT }); - put(EdgeDirection.DOWN_RIGHT, - new EdgeDirection[] { EdgeDirection.DOWN_LEFT, EdgeDirection.RIGHT }); - put(EdgeDirection.DOWN_LEFT, - new EdgeDirection[] { EdgeDirection.LEFT, EdgeDirection.DOWN_RIGHT }); - put(EdgeDirection.LEFT, - new EdgeDirection[] { EdgeDirection.UP_LEFT, EdgeDirection.DOWN_LEFT }); - }}; - + private static final EnumMap ROOT_OFFSETS = + new EnumMap(EdgeDirection.class) { + { + put( + EdgeDirection.UP_LEFT, + new EdgeDirection[] {EdgeDirection.UP_RIGHT, EdgeDirection.LEFT}); + put( + EdgeDirection.UP_RIGHT, + new EdgeDirection[] {EdgeDirection.RIGHT, EdgeDirection.UP_LEFT}); + put( + EdgeDirection.RIGHT, + new EdgeDirection[] {EdgeDirection.DOWN_RIGHT, EdgeDirection.UP_RIGHT}); + put( + EdgeDirection.DOWN_RIGHT, + new EdgeDirection[] {EdgeDirection.DOWN_LEFT, EdgeDirection.RIGHT}); + put( + EdgeDirection.DOWN_LEFT, + new EdgeDirection[] {EdgeDirection.LEFT, EdgeDirection.DOWN_RIGHT}); + put( + EdgeDirection.LEFT, + new EdgeDirection[] {EdgeDirection.UP_LEFT, EdgeDirection.DOWN_LEFT}); + } + }; + /** Array positions for edge directions. */ - private static final EdgeDirection[][] DIRS = new EdgeDirection[][] { - { + private static final EdgeDirection[][] DIRS = + new EdgeDirection[][] { + { EdgeDirection.UNDEFINED, EdgeDirection.UP_LEFT, EdgeDirection.UNDEFINED, EdgeDirection.UP_RIGHT, EdgeDirection.UNDEFINED - }, - { + }, + { EdgeDirection.LEFT, EdgeDirection.UNDEFINED, EdgeDirection.UNDEFINED, EdgeDirection.UNDEFINED, EdgeDirection.RIGHT - }, - { + }, + { EdgeDirection.UNDEFINED, EdgeDirection.DOWN_LEFT, EdgeDirection.UNDEFINED, EdgeDirection.DOWN_RIGHT, EdgeDirection.UNDEFINED, - } - }; - + } + }; + /** Length of edge. */ private final double edgeLength; - + /** * Creates a {@link PatchComponentSitesGraph} for triangular geometry. * - * @param series the simulation series + * @param series the simulation series */ public PatchComponentSitesGraphFactoryTri(Series series) { super(series); edgeLength = series.ds; } - + @Override - int[] getOffset(EdgeDirection offset) { return OFFSETS.get(offset); } - + int[] getOffset(EdgeDirection offset) { + return OFFSETS.get(offset); + } + @Override int calcOffset(int k) { return (latticeHeight - k / 2 - 1) % 3; } - + @Override int calcCol(int i, int offset) { return (i + 6 * offset) % 9; } - + @Override int calcRow(int i, int j, int offset) { return (j + (((i + 6 * offset) / 9 & 1) == 0 ? 0 : 3)) % 6; } - + @Override - boolean checkNode(Node node) { return checkNode(node.getX(), node.getY(), node.getZ()); } - + boolean checkNode(Node node) { + return checkNode(node.getX(), node.getY(), node.getZ()); + } + /** * Checks if the given coordinates are outside bounds of the environment. * - * @param x the x coordinate - * @param y the y coordinate - * @param z the z coordinate - * @return {@code true} if within bounds, {@code false} otherwise + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + * @return {@code true} if within bounds, {@code false} otherwise */ private boolean checkNode(int x, int y, int z) { return !(x < 0 || x > latticeLength + 1 || y < 0 || y > latticeWidth); } - + @Override double getLength(SiteEdge edge, EdgeLevel level) { return level.scale * edgeLength; } - + @Override void createPattern(Graph graph) { ArrayList edges = new ArrayList<>(); - + // Add edges using pattern match layout. for (int k = 0; k < latticeHeight; k += 2) { int offset = calcOffset(k); - + for (int i = 0; i <= latticeLength; i++) { for (int j = 0; j <= latticeWidth; j++) { int col = calcCol(i, offset); int row = calcRow(i, j, offset); - + if (col == 0 && row == 4) { - edges.add(new int[] { i, j, k, i + 2, j, k }); + edges.add(new int[] {i, j, k, i + 2, j, k}); } else if (col == 5 && row == 1) { - edges.add(new int[] { i, j, k, i + 2, j, k }); + edges.add(new int[] {i, j, k, i + 2, j, k}); } else if (col == 7 && row == 1) { - edges.add(new int[] { i, j, k, i + 2, j, k }); + edges.add(new int[] {i, j, k, i + 2, j, k}); } else if (col == 3 && row == 3) { - edges.add(new int[] { i, j, k, i + 1, j - 1, k }); + edges.add(new int[] {i, j, k, i + 1, j - 1, k}); } else if (col == 4 && row == 2) { - edges.add(new int[] { i, j, k, i + 1, j - 1, k }); + edges.add(new int[] {i, j, k, i + 1, j - 1, k}); } else if (col == 3 && row == 5) { - edges.add(new int[] { i, j, k, i + 1, j + 1, k }); + edges.add(new int[] {i, j, k, i + 1, j + 1, k}); } else if (col == 4 && row == 0) { - edges.add(new int[] { i, j, k, i + 1, j + 1, k }); + edges.add(new int[] {i, j, k, i + 1, j + 1, k}); } else if (col == 2 && row == 4) { - edges.add(new int[] { i, j, k, i + 1, j - 1, k }); - edges.add(new int[] { i, j, k, i + 1, j + 1, k }); + edges.add(new int[] {i, j, k, i + 1, j - 1, k}); + edges.add(new int[] {i, j, k, i + 1, j + 1, k}); } } } } - + // Add all edges within bounds to graph. for (int[] e : edges) { if (checkNode(e[0], e[1], e[2]) && checkNode(e[3], e[4], e[5])) { @@ -214,19 +231,21 @@ void createPattern(Graph graph) { int offset = calcOffset(e[2]); int thresh = (latticeLength + 1) / 2; thresh += 3 - ((calcCol(thresh, offset) + 1) % 9 + 4) % 9; - + // Add edge to graph. SiteNode from = new SiteNode(e[0], e[1], e[2]); SiteNode to = new SiteNode(e[3], e[4], e[5]); - EdgeType type = (e[0] == thresh ? EdgeType.CAPILLARY - : (e[0] < thresh ? EdgeType.ARTERY : EdgeType.VEIN)); + EdgeType type = + (e[0] == thresh + ? EdgeType.CAPILLARY + : (e[0] < thresh ? EdgeType.ARTERY : EdgeType.VEIN)); SiteEdge edge = new SiteEdge(from, to, type, EdgeLevel.VARIABLE); graph.addEdge(edge); } } - + // Traverse graph from leftmost nodes to identify unnecessary edges. - int[] offsets = new int[] { 0, 1, 0 }; + int[] offsets = new int[] {0, 1, 0}; for (int k = 0; k < latticeHeight; k += 2) { int offset = calcOffset(k); int ro = offsets[offset]; @@ -236,14 +255,14 @@ void createPattern(Graph graph) { } } } - + @Override Root createRoot(Border border, double percent, EdgeType type, EdgeLevel level) { int scale = level.scale; int width = Math.floorDiv(latticeWidth, scale); int length = (latticeLength - 2 * scale + 3) / scale; int c = -1; - + switch (border) { case LEFT: case RIGHT: @@ -256,7 +275,7 @@ Root createRoot(Border border, double percent, EdgeType type, EdgeLevel level) { default: break; } - + switch (border) { case LEFT: return new Root((c % 2 == 0 ? 0 : scale), c * scale, type, EdgeDirection.RIGHT); @@ -266,28 +285,36 @@ Root createRoot(Border border, double percent, EdgeType type, EdgeLevel level) { case TOP: // must be even number c = (c % 2 == 0 ? c : c + 1); - return new Root(c * scale, 0, type, (c < (length + 1) / 2 - ? EdgeDirection.DOWN_RIGHT : EdgeDirection.DOWN_LEFT)); + return new Root( + c * scale, + 0, + type, + (c < (length + 1) / 2 + ? EdgeDirection.DOWN_RIGHT + : EdgeDirection.DOWN_LEFT)); case BOTTOM: // must be even number if width is even, odd otherwise c = (width % 2 == 0 ? (c % 2 == 0 ? c : c + 1) : (c % 2 == 0 ? c + 1 : c)); - return new Root(c * scale, width * scale, type, (c < (length + 1) / 2 - ? EdgeDirection.UP_RIGHT : EdgeDirection.UP_LEFT)); + return new Root( + c * scale, + width * scale, + type, + (c < (length + 1) / 2 ? EdgeDirection.UP_RIGHT : EdgeDirection.UP_LEFT)); default: break; } - + return null; } - + @Override - EdgeDirection[] createRootOffsets(Border border, double fraction, EdgeLevel level, - MersenneTwisterFast random) { + EdgeDirection[] createRootOffsets( + Border border, double fraction, EdgeLevel level, MersenneTwisterFast random) { int scale = level.scale; int width = Math.floorDiv(latticeWidth, scale); int length = (latticeLength - 2 * scale + 3) / scale; int numOffsets = 0; - + switch (border) { case LEFT: case RIGHT: @@ -300,50 +327,43 @@ EdgeDirection[] createRootOffsets(Border border, double fraction, EdgeLevel leve default: break; } - + EdgeDirection[] directions = null; int index = -1; - + // Get direction list. switch (border) { case LEFT: - directions = new EdgeDirection[] { - EdgeDirection.UP_RIGHT, - EdgeDirection.RIGHT, - EdgeDirection.DOWN_RIGHT - }; + directions = + new EdgeDirection[] { + EdgeDirection.UP_RIGHT, EdgeDirection.RIGHT, EdgeDirection.DOWN_RIGHT + }; index = 1; break; case RIGHT: - directions = new EdgeDirection[] { - EdgeDirection.UP_LEFT, - EdgeDirection.LEFT, - EdgeDirection.DOWN_LEFT - }; + directions = + new EdgeDirection[] { + EdgeDirection.UP_LEFT, EdgeDirection.LEFT, EdgeDirection.DOWN_LEFT + }; index = 1; break; case TOP: - directions = new EdgeDirection[] { - EdgeDirection.DOWN_RIGHT, - EdgeDirection.DOWN_LEFT - }; + directions = + new EdgeDirection[] {EdgeDirection.DOWN_RIGHT, EdgeDirection.DOWN_LEFT}; index = 0; break; case BOTTOM: - directions = new EdgeDirection[] { - EdgeDirection.UP_RIGHT, - EdgeDirection.UP_LEFT - }; + directions = new EdgeDirection[] {EdgeDirection.UP_RIGHT, EdgeDirection.UP_LEFT}; index = 0; break; default: break; } - + int deviation = 0; EdgeDirection offset = null; EdgeDirection[] offsets = new EdgeDirection[numOffsets]; - + // Iterate through to fill up offsets. for (int i = 0; i < numOffsets; i++) { // Select type of random number generator. Left and right borders @@ -372,33 +392,39 @@ EdgeDirection[] createRootOffsets(Border border, double fraction, EdgeLevel leve default: break; } - + offsets[i] = offset; deviation += OFFSETS.get(offset)[index]; } - + return offsets; } - + @Override EdgeDirection getDirection(int fromX, int fromY, int toX, int toY) { int dx = (toX - fromX) + 2; int dy = (toY - fromY) + 1; return DIRS[dy][dx]; } - + @Override - Bag addRoot(Graph graph, SiteNode node0, EdgeDirection dir, EdgeType type, - EdgeDirection[] offsets, MersenneTwisterFast random) { + Bag addRoot( + Graph graph, + SiteNode node0, + EdgeDirection dir, + EdgeType type, + EdgeDirection[] offsets, + MersenneTwisterFast random) { Bag bag = new Bag(); EdgeLevel level = EdgeLevel.LEVEL_1; SiteNode node1 = offsetNode(node0, dir, level); boolean checkNode0 = checkNode(node0); boolean checkNode1 = checkNode(node1); - + // Add initial edge in the specified direction. If unable to add it, // then do not add the rest of the tripod. - if (checkNode0 && checkNode1 + if (checkNode0 + && checkNode1 && graph.getDegree(node0) == 0 && graph.getDegree(node1) == 0) { SiteEdge edge = new SiteEdge(node0, node1, type, level); @@ -406,7 +432,7 @@ Bag addRoot(Graph graph, SiteNode node0, EdgeDirection dir, EdgeType type, } else { return bag; } - + // Add the two leaves of the tripod if line is 0, otherwise add in the root line. if (offsets == null) { for (EdgeDirection offset : ROOT_OFFSETS.get(dir)) { @@ -420,7 +446,7 @@ Bag addRoot(Graph graph, SiteNode node0, EdgeDirection dir, EdgeType type, } else { SiteNode currNode = node1; ArrayList edges = new ArrayList<>(); - + // Add segments for given list of offsets. for (EdgeDirection offset : offsets) { SiteNode nextNode = offsetNode(currNode, offset, level); @@ -432,54 +458,63 @@ Bag addRoot(Graph graph, SiteNode node0, EdgeDirection dir, EdgeType type, currNode = nextNode; } } - + // Shuffle and add tripods off the offset line. Utilities.shuffleList(edges, random); for (SiteEdge edge : edges) { - bag.addAll(addMotif(graph, edge.getTo(), edge, type, level, - EdgeMotif.TRIPLE, random)); + bag.addAll( + addMotif(graph, edge.getTo(), edge, type, level, EdgeMotif.TRIPLE, random)); } } - + return bag; } - + @Override - Bag addMotif(Graph graph, SiteNode node0, SiteEdge edge0, EdgeType type, EdgeLevel level, - EdgeMotif motif, MersenneTwisterFast random) { + Bag addMotif( + Graph graph, + SiteNode node0, + SiteEdge edge0, + EdgeType type, + EdgeLevel level, + EdgeMotif motif, + MersenneTwisterFast random) { // Select new random direction. EdgeDirection dir0 = getDirection(edge0, level); ArrayList validDirections = new ArrayList<>(EDGE_DIRECTIONS); validDirections.remove(REVERSE_EDGE_DIRECTIONS.get(dir0)); EdgeDirection dir = validDirections.get(random.nextInt(validDirections.size())); - + // Make tripod nodes. SiteNode node1 = offsetNode(node0, dir, level); SiteNode node2 = offsetNode(node1, ROOT_OFFSETS.get(dir)[0], level); SiteNode node3 = offsetNode(node1, ROOT_OFFSETS.get(dir)[1], level); - + // Check nodes. boolean checkNode0 = checkNode(node0); boolean checkNode1 = checkNode(node1); boolean checkNode2 = checkNode(node2); boolean checkNode3 = checkNode(node3); - + Bag bag = new Bag(); SiteEdge edge; - + switch (motif) { case TRIPLE: - if (checkNode0 && checkNode1 && checkNode2 && checkNode3 + if (checkNode0 + && checkNode1 + && checkNode2 + && checkNode3 && graph.getDegree(node1) == 0 && graph.getDegree(node2) == 0 && graph.getDegree(node3) == 0) { edge = new SiteEdge(node0, node1, type, level); graph.addEdge(edge); - + edge = new SiteEdge(node1, node2, type, level); graph.addEdge(edge); bag.add(edge); - + edge = new SiteEdge(node1, node3, type, level); graph.addEdge(edge); bag.add(edge); @@ -490,16 +525,16 @@ Bag addMotif(Graph graph, SiteNode node0, SiteEdge edge0, EdgeType type, EdgeLev case DOUBLE: if (checkNode0 && checkNode1 && graph.getDegree(node1) == 0) { ArrayList options = new ArrayList<>(); - + if (checkNode2 && graph.getDegree(node2) == 0) { options.add(node2); } if (checkNode3 && graph.getDegree(node3) == 0) { options.add(node3); } - + Utilities.shuffleList(options, random); - + if (options.size() > 0) { edge = new SiteEdge(node0, node1, type, level); graph.addEdge(edge); @@ -525,29 +560,33 @@ Bag addMotif(Graph graph, SiteNode node0, SiteEdge edge0, EdgeType type, EdgeLev default: break; } - + return bag; } - + @Override - void addSegment(Graph graph, SiteNode node0, EdgeDirection dir, - EdgeLevel level, MersenneTwisterFast random) { + void addSegment( + Graph graph, + SiteNode node0, + EdgeDirection dir, + EdgeLevel level, + MersenneTwisterFast random) { ArrayList options = new ArrayList<>(); - + // Iterate through all five direction options. for (EdgeDirection offset : EDGE_DIRECTIONS) { if (offset == REVERSE_EDGE_DIRECTIONS.get(dir)) { continue; } - + SiteNode node1 = offsetNode(node0, offset, level); if (!checkNode(node1)) { continue; } - + SiteEdge edgeOut = null; SiteEdge edgeIn = null; - + // Check edges in and out of proposed node. if (graph.getOutDegree(node1) == 1) { edgeOut = (SiteEdge) graph.getEdgesOut(node1).objs[0]; @@ -565,14 +604,14 @@ void addSegment(Graph graph, SiteNode node0, EdgeDirection dir, edgeIn = null; } } - + if (edgeOut != null || edgeIn != null) { options.add(node1); } } - + Utilities.shuffleList(options, random); - + for (SiteNode node1 : options) { SiteEdge e = new SiteEdge(node0, node1, EdgeType.CAPILLARY, level); if (graph.getDegree(node0) < 3 && graph.getDegree(node1) < 3) { @@ -580,30 +619,36 @@ void addSegment(Graph graph, SiteNode node0, EdgeDirection dir, } } } - + @Override - void addConnection(Graph graph, SiteNode node0, EdgeDirection dir, EdgeType type, - EdgeLevel level, MersenneTwisterFast random) { + void addConnection( + Graph graph, + SiteNode node0, + EdgeDirection dir, + EdgeType type, + EdgeLevel level, + MersenneTwisterFast random) { ArrayList options = new ArrayList<>(); EdgeType connType = (type == EdgeType.ARTERY ? EdgeType.ARTERIOLE : EdgeType.VENULE); - + // Iterate through all five direction options. for (EdgeDirection offset : EDGE_DIRECTIONS) { if (offset == REVERSE_EDGE_DIRECTIONS.get(dir)) { continue; } - + SiteNode node1 = offsetNode(node0, offset, level); if (!checkNode(node1)) { continue; } - + // Check edges in and out of proposed node. if (graph.getOutDegree(node1) == 1 && graph.getInDegree(node1) == 1) { SiteEdge edgeOut = (SiteEdge) graph.getEdgesOut(node1).objs[0]; SiteEdge edgeIn = (SiteEdge) graph.getEdgesIn(node1).objs[0]; - - if (edgeOut.type == type && edgeIn.type == type + + if (edgeOut.type == type + && edgeIn.type == type && edgeOut.radius <= MAXIMUM_CAPILLARY_RADIUS && edgeIn.radius <= MAXIMUM_CAPILLARY_RADIUS) { path(graph, node1, node0); @@ -613,12 +658,13 @@ void addConnection(Graph graph, SiteNode node0, EdgeDirection dir, EdgeType type } } } - + Utilities.shuffleList(options, random); - + for (SiteNode node1 : options) { SiteEdge e = new SiteEdge(node0, node1, connType, level); - if (graph.getDegree(node0) < 3 && graph.getDegree(node1) < 3 + if (graph.getDegree(node0) < 3 + && graph.getDegree(node1) < 3 && !graph.hasEdge(node0, node1)) { graph.addEdge(e); } diff --git a/src/arcade/patch/env/component/PatchComponentSitesGraphRect.java b/src/arcade/patch/env/component/PatchComponentSitesGraphRect.java index f674b68a5..ccfcfcb20 100644 --- a/src/arcade/patch/env/component/PatchComponentSitesGraphRect.java +++ b/src/arcade/patch/env/component/PatchComponentSitesGraphRect.java @@ -9,72 +9,63 @@ import arcade.patch.env.location.CoordinateXYZ; import arcade.patch.env.location.PatchLocationRect; -/** - * Extension of {@link PatchComponentSitesGraph} for rectangular geometry. - */ - +/** Extension of {@link PatchComponentSitesGraph} for rectangular geometry. */ public abstract class PatchComponentSitesGraphRect extends PatchComponentSitesGraph { /** * Creates a {@link PatchComponentSitesGraph} for rectangular geometry. * - * @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 PatchComponentSitesGraphRect(Series series, MiniBox parameters, - MersenneTwisterFast random) { + public PatchComponentSitesGraphRect( + Series series, MiniBox parameters, MersenneTwisterFast random) { super(series, parameters, random); } - + @Override public PatchComponentSitesGraphFactory makeGraphFactory(Series series) { return new PatchComponentSitesGraphFactoryRect(series); } - - /** - * Extension of {@link PatchComponentSitesGraphRect} for simple - * hemodynamics. - */ + + /** Extension of {@link PatchComponentSitesGraphRect} for simple hemodynamics. */ public static class Simple extends PatchComponentSitesGraphRect { /** * Creates a {@link PatchComponentSitesGraphRect} with simple step. * - * @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 Simple(Series series, MiniBox parameters, MersenneTwisterFast random) { super(series, parameters, random); } - + @Override public void step(SimState simstate) { super.simpleStep(); } } - - /** - * Extension of {@link PatchComponentSitesGraphRect} for complex - * hemodynamics. - */ + + /** Extension of {@link PatchComponentSitesGraphRect} for complex hemodynamics. */ public static class Complex extends PatchComponentSitesGraphRect { /** * Creates a {@link PatchComponentSitesGraphRect} with complex step. * - * @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 Complex(Series series, MiniBox parameters, MersenneTwisterFast random) { super(series, parameters, random); } - + @Override public void step(SimState simstate) { super.complexStep(simstate.random); } } - + @Override public Location getLocation(CoordinateXYZ span) { CoordinateXYZ coordinate = PatchLocationRect.translate(span); @@ -84,28 +75,28 @@ public Location getLocation(CoordinateXYZ span) { return null; } } - + @Override public ArrayList getSpan(SiteNode from, SiteNode to) { ArrayList s = new ArrayList<>(); - + int z = from.getZ(); int x0 = from.getX(); int y0 = from.getY(); int x1 = to.getX(); int y1 = to.getY(); - + // Calculate deltas. int dX = x1 - x0; int dY = y1 - y0; - + // Check direction of arrow and update deltas to absolute. boolean sX = dX < 0; boolean sY = dY < 0; - + dX = Math.abs(dX); dY = Math.abs(dY); - + if (x0 == x1) { // Check if line is vertical. for (int d = 0; d < dY; d++) { checkSite(s, x0, y0 + (sY ? -(d + 1) : d), z); @@ -126,23 +117,23 @@ public ArrayList getSpan(SiteNode from, SiteNode to) { int starty = y0 - (sY ? 1 : 0); int endx = x1 - (sX ? 0 : 1); int endy = y1 - (sY ? 0 : 1); - + // Calculate new deltas based on squares. int dx = Math.abs(endx - startx); int dy = Math.abs(endy - starty); - + // Initial conditions. int x = startx; int y = starty; int e = dx - dy; - + // Add start square. checkSite(s, x, y, z); - + // Calculate increments. int incX = (x1 > x0 ? 1 : -1); int incY = (y1 > y0 ? 1 : -1); - + // Iterate until the ending square is reached. while (x != endx || y != endy) { if (e > 0) { @@ -152,11 +143,11 @@ public ArrayList getSpan(SiteNode from, SiteNode to) { y += incY; e += 2 * dx; } - + checkSite(s, x, y, z); } } - + return s; } } diff --git a/src/arcade/patch/env/component/PatchComponentSitesGraphTri.java b/src/arcade/patch/env/component/PatchComponentSitesGraphTri.java index 4adc3823e..28d98e9b1 100644 --- a/src/arcade/patch/env/component/PatchComponentSitesGraphTri.java +++ b/src/arcade/patch/env/component/PatchComponentSitesGraphTri.java @@ -10,72 +10,63 @@ import arcade.patch.env.location.CoordinateXYZ; import arcade.patch.env.location.PatchLocationHex; -/** - * Extension of {@link PatchComponentSitesGraph} for triangular geometry. - */ - +/** Extension of {@link PatchComponentSitesGraph} for triangular geometry. */ public abstract class PatchComponentSitesGraphTri extends PatchComponentSitesGraph { /** * Creates a {@link PatchComponentSitesGraph} for triangular geometry. * - * @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 PatchComponentSitesGraphTri(Series series, MiniBox parameters, - MersenneTwisterFast random) { + public PatchComponentSitesGraphTri( + Series series, MiniBox parameters, MersenneTwisterFast random) { super(series, parameters, random); } - + @Override public PatchComponentSitesGraphFactory makeGraphFactory(Series series) { return new PatchComponentSitesGraphFactoryTri(series); } - - /** - * Extension of {@link PatchComponentSitesGraphTri} for simple - * hemodynamics. - */ + + /** Extension of {@link PatchComponentSitesGraphTri} for simple hemodynamics. */ public static class Simple extends PatchComponentSitesGraphTri { /** * Creates a {@link PatchComponentSitesGraphTri} with simple step. * - * @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 Simple(Series series, MiniBox parameters, MersenneTwisterFast random) { super(series, parameters, random); } - + @Override public void step(SimState simstate) { super.simpleStep(); } } - - /** - * Extension of {@link PatchComponentSitesGraphTri} for complex - * hemodynamics. - */ + + /** Extension of {@link PatchComponentSitesGraphTri} for complex hemodynamics. */ public static class Complex extends PatchComponentSitesGraphTri { /** * Creates a {@link PatchComponentSitesGraphTri} with complex step. * - * @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 Complex(Series series, MiniBox parameters, MersenneTwisterFast random) { super(series, parameters, random); } - + @Override public void step(SimState simstate) { super.complexStep(simstate.random); } } - + @Override public Location getLocation(CoordinateXYZ span) { CoordinateUVWZ coordinate = PatchLocationHex.translate(span); @@ -85,28 +76,28 @@ public Location getLocation(CoordinateXYZ span) { return null; } } - + @Override public ArrayList getSpan(SiteNode from, SiteNode to) { ArrayList s = new ArrayList<>(); - + int z = from.getZ(); int x0 = from.getX(); int y0 = from.getY(); int x1 = to.getX(); int y1 = to.getY(); - + // Calculate deltas. int dX = x1 - x0; int dY = y1 - y0; - + // Check direction of arrow and update deltas to absolute. boolean sX = dX < 0; boolean sY = dY < 0; - + dX = Math.abs(dX); dY = Math.abs(dY); - + if (x0 == x1) { // Check if line is vertical. for (int d = 0; d < dY; d++) { checkSite(s, x0 - 1, y0 + (sY ? -(d + 1) : d), z); @@ -132,26 +123,26 @@ public ArrayList getSpan(SiteNode from, SiteNode to) { int starty = y0 - (sY ? 1 : 0); int endx = x1 - (dY < dX ? (sX ? 0 : 2) : 1); int endy = y1 - (sY ? 0 : 1); - + // Calculate new deltas based on triangle. int dx = Math.abs(endx - startx); int dy = Math.abs(endy - starty); - + // Initial conditions. int x = startx; int y = starty; int e = 0; - + // Add start triangle. checkSite(s, x, y, z); - + // Track if triangle is even (point down) or odd (point up). boolean even; - + // Iterate until the ending triangle is reached. while (x != endx || y != endy) { even = ((x + y) & 1) == 0; - + if (e > 3 * dx) { if (!sX && !sY) { if (even) { @@ -223,11 +214,11 @@ public ArrayList getSpan(SiteNode from, SiteNode to) { } } } - + checkSite(s, x, y, z); } } - + return s; } } diff --git a/src/arcade/patch/env/component/PatchComponentSitesGraphUtilities.java b/src/arcade/patch/env/component/PatchComponentSitesGraphUtilities.java index 682908c28..63c6bb050 100644 --- a/src/arcade/patch/env/component/PatchComponentSitesGraphUtilities.java +++ b/src/arcade/patch/env/component/PatchComponentSitesGraphUtilities.java @@ -6,6 +6,7 @@ import sim.util.Bag; import ec.util.MersenneTwisterFast; import arcade.core.util.Graph; +import arcade.core.util.Graph.Strategy; import arcade.core.util.Matrix; import arcade.core.util.Solver; import static arcade.core.util.Graph.Edge; @@ -16,197 +17,189 @@ import static arcade.patch.env.component.PatchComponentSitesGraphFactory.EdgeType; import static arcade.patch.env.component.PatchComponentSitesGraphFactory.Root; -/** - * Container for utility functions used by {@link PatchComponentSitesGraph}. - */ - +/** Container for utility functions used by {@link PatchComponentSitesGraph}. */ abstract class PatchComponentSitesGraphUtilities { /** Calculation types. */ enum CalculationType { /** Code for upstream radius calculation for all edge types. */ - UPSTREAM_ALL(CalculationCategory.UPSTREAM), - + UPSTREAM_ALL(Strategy.UPSTREAM), + /** Code for upstream radius calculation for arteries only. */ - UPSTREAM_ARTERIES(CalculationCategory.UPSTREAM), - + UPSTREAM_ARTERIES(Strategy.UPSTREAM), + /** Code for downstream radius calculation for veins only. */ - DOWNSTREAM_VEINS(CalculationCategory.DOWNSTREAM), - + DOWNSTREAM_VEINS(Strategy.DOWNSTREAM), + /** Code for upstream radius calculation for pattern layout. */ - UPSTREAM_PATTERN(CalculationCategory.UPSTREAM), - + UPSTREAM_PATTERN(Strategy.UPSTREAM), + /** Code for downstream radius calculation for pattern layout. */ - DOWNSTREAM_PATTERN(CalculationCategory.DOWNSTREAM); - + DOWNSTREAM_PATTERN(Strategy.DOWNSTREAM); + /** Calculation category corresponding to the calculation type. */ - final CalculationCategory category; - + final Strategy category; + /** * Creates a {@code CalculationType} instance. * - * @param category the calculation category + * @param category the calculation category */ - CalculationType(CalculationCategory category) { + CalculationType(Strategy category) { this.category = category; } } - - /** Calculation categories. */ - enum CalculationCategory { - /** Code for upstream calculation category. */ - UPSTREAM, - - /** Code for downstream direction category. */ - DOWNSTREAM - } - + /** Initial capillary radius [um]. */ static final double CAPILLARY_RADIUS = 4; - + /** Maximum capillary radius [um]. */ static final double MAXIMUM_CAPILLARY_RADIUS = 20; - + /** Minimum capillary radius [um]. */ static final double MINIMUM_CAPILLARY_RADIUS = 2; - + /** Minimum viable thickness for vessel wall [um]. */ static final double MINIMUM_WALL_THICKNESS = 0.5; - + /** Maximum fraction of wall thickness to radius. */ static final double MAXIMUM_WALL_RADIUS_FRACTION = 0.5; - + /** Viscosity of plasma [mmHg s]. */ static final double PLASMA_VISCOSITY = 0.000009; - + /** Tolerance for difference in radii. */ private static final double DELTA_TOLERANCE = 1E-8; - + /** Height of each layer [um]. */ private static final double LAYER_HEIGHT = 8.7; - + /** Maximum oxygen partial pressure [mmHg]. */ private static final double MAXIMUM_OXYGEN_PRESSURE = 100; - + /** Minimum oxygen partial pressure [mmHg]. */ private static final double MINIMUM_OXYGEN_PRESSURE = 55; - + /** Oxygen partial pressure per radius [mmHg/um]. */ private static final double OXYGEN_PRESSURE_SCALE = 1; - + /** Hemoglobin hill equation exponent. */ private static final double OXYGEN_CURVE_EXP = 2.8275; - + /** Hemoglobin hill equation P50 [mmHg]. */ private static final double OXYGEN_CURVE_P50 = 26.875; - + /** Oxygen saturation in blood [fmol/um3]. */ private static final double OXYGEN_SATURATION = 0.00835; - + /** Exponent for Murray's law. */ private static final double MURRAY_EXPONENT = 2.7; - + /** Minimum flow rate for edge removal [um3/min]. */ private static final double MINIMUM_FLOW_RATE = 1000; - + /** Minimum flow percent for edge removal. */ private static final double MINIMUM_FLOW_PERCENT = 0.01; - + /** * Parses type letter into code. * - * @param type the type letter - * @return the type code + * @param type the type letter + * @return the type code */ static EdgeType parseType(String type) { - return (type.equalsIgnoreCase("A") ? EdgeType.ARTERY - : (type.equalsIgnoreCase("V") ? EdgeType.VEIN : null)); + return ("A".equalsIgnoreCase(type) + ? EdgeType.ARTERY + : ("V".equalsIgnoreCase(type) ? EdgeType.VEIN : null)); } - + /** * Calculates node pressure for a given radius. - *

- * Equation based on the paper: Welter M, Fredrich T, Rinneberg H, and - * Rieger H. (2016). Computational model for tumor oxygenation applied to - * clinical data on breast tumor hemoglobin concentrations suggests vascular - * dilatation and compression. PLOS ONE, 11(8), e0161267. * - * @param radius the radius of the edge - * @param category the edge category - * @return the edge pressure + *

Equation based on the paper: Welter M, Fredrich T, Rinneberg H, and Rieger H. (2016). + * Computational model for tumor oxygenation applied to clinical data on breast tumor hemoglobin + * concentrations suggests vascular dilatation and compression. PLOS ONE, 11(8), + * e0161267. + * + * @param radius the radius of the edge + * @param category the edge category + * @return the edge pressure */ static double calculatePressure(double radius, EdgeCategory category) { return 18 + (89 - 18) / (1 + Math.exp((radius * category.sign + 21) / 16)); } - + /** * Calculates relative viscosity for a given radius. - *

- * Equation based on the paper: Pries AR, Secomb TW, Gessner T, Sperandio - * MB, Gross JF, and Gaehtgens P. (1994). Resistance to blood flow in - * microvessels in vivo. Circulation Research, 75(5), 904-915. * - * @param radius the radius of the edge - * @return the relative viscosity + *

Equation based on the paper: Pries AR, Secomb TW, Gessner T, Sperandio MB, Gross JF, and + * Gaehtgens P. (1994). Resistance to blood flow in microvessels in vivo. Circulation + * Research, 75(5), 904-915. + * + * @param radius the radius of the edge + * @return the relative viscosity */ private static double calculateViscosity(double radius) { double diameter = 2 * radius; - double mu45 = 6 * Math.exp(-0.085 * diameter) + 3.2 - 2.44 - * Math.exp(-0.06 * Math.pow(diameter, 0.645)); + double mu45 = + 6 * Math.exp(-0.085 * diameter) + + 3.2 + - 2.44 * Math.exp(-0.06 * Math.pow(diameter, 0.645)); double fR = Math.pow(diameter / (diameter - 1.1), 2); return (1 + (mu45 - 1) * fR) * fR; } - + /** * Gets flow rate coefficient in units of um3/(mmHg min). * - * @param edge the edge - * @return the flow rate coefficient + * @param edge the edge + * @return the flow rate coefficient */ private static double getCoefficient(SiteEdge edge) { double mu = PLASMA_VISCOSITY * calculateViscosity(edge.radius) / 60; return (Math.PI * Math.pow(edge.radius, 4)) / (8 * mu * edge.length); } - + /** * Gets the oxygen partial pressure for an edge. * - * @param edge the edge - * @return the oxygen partial pressure + * @param edge the edge + * @return the oxygen partial pressure */ static double getPartial(SiteEdge edge) { - return Math.min(MINIMUM_OXYGEN_PRESSURE + OXYGEN_PRESSURE_SCALE * edge.radius, + return Math.min( + MINIMUM_OXYGEN_PRESSURE + OXYGEN_PRESSURE_SCALE * edge.radius, MAXIMUM_OXYGEN_PRESSURE); } - + /** * Gets the oxygen saturation at a given partial pressure. * - * @param pressure the oxygen partial pressure - * @return the oxygen saturation + * @param pressure the oxygen partial pressure + * @return the oxygen saturation */ private static double getSaturation(double pressure) { - return Math.pow(pressure, OXYGEN_CURVE_EXP) / (Math.pow(pressure, OXYGEN_CURVE_EXP) - + Math.pow(OXYGEN_CURVE_P50, OXYGEN_CURVE_EXP)); + return Math.pow(pressure, OXYGEN_CURVE_EXP) + / (Math.pow(pressure, OXYGEN_CURVE_EXP) + + Math.pow(OXYGEN_CURVE_P50, OXYGEN_CURVE_EXP)); } - + /** * Gets the total amount of oxygen in blood (fmol/um3). * - * @param pressure the oxygen partial pressure - * @param solubility the oxygen solubility in blood - * @return the total amount of oxygen + * @param pressure the oxygen partial pressure + * @param solubility the oxygen solubility in blood + * @return the total amount of oxygen */ static double getTotal(double pressure, double solubility) { return OXYGEN_SATURATION * getSaturation(pressure) + solubility * pressure; } - + /** - * Gets the maximum (for arteries) or minimum (for veins) pressure across - * roots. + * Gets the maximum (for arteries) or minimum (for veins) pressure across roots. * - * @param roots the list of roots - * @param type the root type - * @return the root pressure + * @param roots the list of roots + * @param type the root type + * @return the root pressure */ private static double getRootPressure(ArrayList roots, EdgeCategory type) { double pressure = (type == EdgeCategory.ARTERY ? Double.MIN_VALUE : Double.MAX_VALUE); @@ -226,16 +219,15 @@ private static double getRootPressure(ArrayList roots, EdgeCategory type) } return pressure; } - + /** * Sets the pressure of roots. - *

- * Method assumes that the root node has already been set to the correct - * node object. * - * @param roots the list of roots - * @param type the root type - * @return the pressure assigned to the roots + *

Method assumes that the root node has already been set to the correct node object. + * + * @param roots the list of roots + * @param type the root type + * @return the pressure assigned to the roots */ static double setRootPressures(ArrayList roots, EdgeCategory type) { double pressure = getRootPressure(roots, type); @@ -245,13 +237,13 @@ static double setRootPressures(ArrayList roots, EdgeCategory type) { } return pressure; } - + /** * Sets the pressure of leaves. * - * @param graph the graph object - * @param arteryPressure the pressure at the arteries - * @param veinPressure the pressure at the veins + * @param graph the graph object + * @param arteryPressure the pressure at the arteries + * @param veinPressure the pressure at the veins */ static void setLeafPressures(Graph graph, double arteryPressure, double veinPressure) { for (Object obj : graph.getAllEdges()) { @@ -264,12 +256,12 @@ static void setLeafPressures(Graph graph, double arteryPressure, double veinPres } } } - + /** * Reverses edges that have negative pressure differences. * - * @param graph the graph object - * @return {@code true} if any edges were reversed, {@code false} otherwise + * @param graph the graph object + * @return {@code true} if any edges were reversed, {@code false} otherwise */ static boolean reversePressures(Graph graph) { boolean reversed = false; @@ -288,29 +280,29 @@ static boolean reversePressures(Graph graph) { } return reversed; } - + /** * Marks edges that perfused between given arteries and veins. * - * @param graph the graph object - * @param arteries the list of arteries - * @param veins the list of veins + * @param graph the graph object + * @param arteries the list of arteries + * @param veins the list of veins */ static void checkPerfused(Graph graph, ArrayList arteries, ArrayList veins) { // Reset all edges. for (Object obj : graph.getAllEdges()) { ((SiteEdge) obj).isPerfused = false; } - + // Find shortest path (if it exists) between each artery and vein. for (Root artery : arteries) { for (Root vein : veins) { SiteNode start = artery.node; SiteNode end = vein.node; - + // Calculate path distances until the end node is reached. path(graph, start, end); - + // Back calculate shortest path and set as perfused. SiteNode node = end; while (node != null && node != start) { @@ -330,7 +322,7 @@ static void checkPerfused(Graph graph, ArrayList arteries, ArrayList } } } - + // Get perfused edges. ArrayList edges = new ArrayList<>(); for (Object obj : graph.getAllEdges()) { @@ -339,12 +331,12 @@ static void checkPerfused(Graph graph, ArrayList arteries, ArrayList edges.add(edge); } } - + // Traverse starting with the perfused edges. for (SiteEdge edge : edges) { traverse(graph, edge.getTo(), new ArrayList<>()); } - + // Clear previous nodes. for (Object obj : graph.getAllEdges()) { SiteEdge edge = (SiteEdge) obj; @@ -352,29 +344,29 @@ static void checkPerfused(Graph graph, ArrayList arteries, ArrayList edge.getTo().prev = null; } } - + /** * Merges the nodes from one graph with another graph. * - * @param graph1 the first graph object - * @param graph2 the second graph object + * @param graph1 the first graph object + * @param graph2 the second graph object */ static void mergeGraphs(Graph graph1, Graph graph2) { // Merge nodes for subgraph. graph2.mergeNodes(); - + // Merge nodes between subgraphs. for (Object obj : graph1.getAllEdges()) { SiteEdge edge = (SiteEdge) obj; SiteNode node = edge.getTo(); - + Bag in = graph2.getEdgesIn(node); if (in != null) { for (Object inObj : in) { ((SiteEdge) inObj).setTo(node); } } - + Bag out = graph2.getEdgesOut(node); if (out != null) { for (Object outObj : out) { @@ -383,18 +375,18 @@ static void mergeGraphs(Graph graph1, Graph graph2) { } } } - + /** * Calculates pressures at nodes. - *

- * Sets up a system of linear equations for the current graph structure - * using mass balances at each node. * - * @param graph the graph object + *

Sets up a system of linear equations for the current graph structure using mass balances + * at each node. + * + * @param graph the graph object */ static void calculatePressures(Graph graph) { LinkedHashSet set = new LinkedHashSet<>(); - + // Get set of all non-root nodes. for (Object obj : graph.getAllEdges()) { SiteEdge edge = (SiteEdge) obj; @@ -405,7 +397,7 @@ static void calculatePressures(Graph graph) { SiteNode to = edge.getTo(); from.id = -1; to.id = -1; - + if (!from.isRoot && !(graph.getInDegree(from) == 0 && graph.getOutDegree(from) == 1)) { set.add(from); } @@ -413,25 +405,25 @@ static void calculatePressures(Graph graph) { set.add(to); } } - + // Set up system of equations to calculate nodal pressures. int n = set.size(); double[][] mA = new double[n][n]; double[] vB = new double[n]; double[] x0 = new double[n]; - + // Assign id number to each node. int i = 0; for (SiteNode node : set) { node.id = i++; } - + // Populate coefficient matrix and estimate initial pressures as // average of calculated pressure for input and output edges. for (SiteNode node : set) { int id = node.id; double div = 0; - + // Iterate through input edges. Bag in = graph.getEdgesIn(node); if (in != null) { @@ -441,10 +433,10 @@ static void calculatePressures(Graph graph) { continue; } double coeff = getCoefficient(edge); - + mA[id][id] += coeff; SiteNode from = edge.getFrom(); - + if (from.isRoot || from.id == -1) { vB[id] += coeff * from.pressure; } else { @@ -454,7 +446,7 @@ static void calculatePressures(Graph graph) { } } } - + // Iterate through output edges. Bag out = graph.getEdgesOut(node); if (out != null) { @@ -464,10 +456,10 @@ static void calculatePressures(Graph graph) { continue; } double coeff = getCoefficient(edge); - + mA[id][id] += coeff; SiteNode to = edge.getTo(); - + if (to.isRoot || to.id == -1) { vB[id] += coeff * to.pressure; } else { @@ -477,43 +469,43 @@ static void calculatePressures(Graph graph) { } } } - + if (div != 0) { x0[id] /= div; } } - + double[][] sA = Matrix.scale(mA, 1E-7); double[] sB = Matrix.scale(vB, 1E-7); - + // Remove NaN in starting estimates. for (int j = 0; j < n; j++) { if (Double.isNaN(x0[j])) { x0[j] = 0; } } - + // Solve for pressure and update nodes. double[] x = Solver.sor(sA, sB, x0); for (SiteNode node : set) { node.pressure = x[node.id]; } } - + /** * Calculates shear and circumferential stress for all edges. * - * @param graph the graph object + * @param graph the graph object */ static void calculateStresses(Graph graph) { double shearMin = Double.POSITIVE_INFINITY; double shearMax = 0; - + for (Object obj : graph.getAllEdges()) { SiteEdge edge = (SiteEdge) obj; SiteNode to = edge.getTo(); SiteNode from = edge.getFrom(); - + // Calculate shear stress. edge.shear = (edge.radius * Math.abs(to.pressure - from.pressure)) / (2 * edge.length); if (edge.shear > shearMax) { @@ -522,23 +514,22 @@ static void calculateStresses(Graph graph) { if (edge.shear < shearMin) { shearMin = edge.shear; } - + // Calculate circumferential stress. edge.circum = (to.pressure + from.pressure) / 2 * edge.radius / edge.wall; } - + // Scale shear between 0 and 1. for (Object obj : graph.getAllEdges()) { SiteEdge edge = (SiteEdge) obj; edge.shearScaled = (edge.shear - shearMin) / (shearMax - shearMin); } } - + /** - * Calculates flow rate (in um3/min) and area (in um2) - * for all edges. + * Calculates flow rate (in um3/min) and area (in um2) for all edges. * - * @param graph the graph object + * @param graph the graph object */ static void calculateFlows(Graph graph) { for (Object obj : graph.getAllEdges()) { @@ -546,7 +537,7 @@ static void calculateFlows(Graph graph) { SiteNode to = edge.getTo(); SiteNode from = edge.getFrom(); edge.flow = getCoefficient(edge) * (from.pressure - to.pressure); - + // Surface area for edges with diameter less than the layer height is // the surface area of a cylinder with the edge radius and length. // For edges with diameter greater than the height, we assume the vessel @@ -559,11 +550,11 @@ static void calculateFlows(Graph graph) { } } } - + /** * Calculate the wall thickness (in um) for all edges. * - * @param graph the graph object + * @param graph the graph object */ static void calculateThicknesses(Graph graph) { for (Object obj : graph.getAllEdges()) { @@ -572,16 +563,16 @@ static void calculateThicknesses(Graph graph) { edge.wall = d * (0.267 - 0.084 * Math.log10(d)); } } - + /** * Gets in degree for edge in given calculation direction. * - * @param graph the graph object - * @param edge the edge object - * @param dir the calculation direction - * @return the edge in degree + * @param graph the graph object + * @param edge the edge object + * @param dir the calculation direction + * @return the edge in degree */ - private static int getInDegree(Graph graph, SiteEdge edge, CalculationCategory dir) { + private static int getInDegree(Graph graph, SiteEdge edge, Strategy dir) { switch (dir) { case UPSTREAM: return graph.getInDegree(edge.getTo()); @@ -591,16 +582,16 @@ private static int getInDegree(Graph graph, SiteEdge edge, CalculationCategory d return 0; } } - + /** * Gets out degree for edge in given calculation direction. * - * @param graph the graph object - * @param edge the edge object - * @param dir the calculation direction - * @return the edge out degree + * @param graph the graph object + * @param edge the edge object + * @param dir the calculation direction + * @return the edge out degree */ - private static int getOutDegree(Graph graph, SiteEdge edge, CalculationCategory dir) { + private static int getOutDegree(Graph graph, SiteEdge edge, Strategy dir) { switch (dir) { case UPSTREAM: return graph.getOutDegree(edge.getTo()); @@ -610,23 +601,22 @@ private static int getOutDegree(Graph graph, SiteEdge edge, CalculationCategory return 0; } } - + /** * Calculate the radii (in um) using Murray's law. * - * @param graph the graph object - * @param edge the starting edge for the calculation - * @param dir the direction of the calculation - * @param fromcheck the number of edges in to the selected node - * @param tocheck the number of edges out of the selected node - * @return the list of children edges + * @param graph the graph object + * @param edge the starting edge for the calculation + * @param dir the direction of the calculation + * @param fromcheck the number of edges in to the selected node + * @param tocheck the number of edges out of the selected node + * @return the list of children edges */ - private static ArrayList calculateRadius(Graph graph, SiteEdge edge, - CalculationCategory dir, - int fromcheck, int tocheck) { + private static ArrayList calculateRadius( + Graph graph, SiteEdge edge, Strategy dir, int fromcheck, int tocheck) { ArrayList children = new ArrayList<>(); ArrayList list = null; - + switch (dir) { case DOWNSTREAM: list = edge.getEdgesOut(); @@ -637,36 +627,39 @@ private static ArrayList calculateRadius(Graph graph, SiteEdge edge, default: break; } - + // No need to update is there are no edges. if (list == null || list.size() == 0) { return children; } - + // Check for loops. if (edge.isVisited) { return children; } - + // Iterate through all edges and calculate radii and then recurse. for (Edge obj : list) { SiteEdge e = (SiteEdge) obj; int in = getInDegree(graph, e, dir); int out = getOutDegree(graph, e, dir); - + if (in == 1 && out == 1 && edge.radius != 0) { e.radius = edge.radius; } else if (in == fromcheck && out == tocheck) { - ArrayList b = (dir == CalculationCategory.DOWNSTREAM - ? edge.getEdgesOut() : edge.getEdgesIn()); + ArrayList b = + (dir == Strategy.DOWNSTREAM ? edge.getEdgesOut() : edge.getEdgesIn()); double r1 = ((SiteEdge) b.get(0)).radius; double r2 = ((SiteEdge) b.get(1)).radius; - + if (e.radius == 0 && edge.radius != 0) { if (r1 == 0 && r2 != 0) { if (edge.radius > r2) { - e.radius = Math.pow(Math.pow(edge.radius, MURRAY_EXPONENT) - - Math.pow(r2, MURRAY_EXPONENT), 1 / MURRAY_EXPONENT); + e.radius = + Math.pow( + Math.pow(edge.radius, MURRAY_EXPONENT) + - Math.pow(r2, MURRAY_EXPONENT), + 1 / MURRAY_EXPONENT); if (Math.abs(e.radius - r2) < DELTA_TOLERANCE) { e.radius = r2; } @@ -674,8 +667,11 @@ private static ArrayList calculateRadius(Graph graph, SiteEdge edge, e.radius = MINIMUM_CAPILLARY_RADIUS; } } else if (edge.radius < r2) { - e.radius = Math.pow(Math.pow(r2, MURRAY_EXPONENT) - - Math.pow(edge.radius, MURRAY_EXPONENT), 1 / MURRAY_EXPONENT); + e.radius = + Math.pow( + Math.pow(r2, MURRAY_EXPONENT) + - Math.pow(edge.radius, MURRAY_EXPONENT), + 1 / MURRAY_EXPONENT); if (Math.abs(e.radius - edge.radius) < DELTA_TOLERANCE) { e.radius = edge.radius; } @@ -687,8 +683,11 @@ private static ArrayList calculateRadius(Graph graph, SiteEdge edge, } } else if (r1 != 0 && r2 == 0) { if (edge.radius > r1) { - e.radius = Math.pow(Math.pow(edge.radius, MURRAY_EXPONENT) - - Math.pow(r1, MURRAY_EXPONENT), 1 / MURRAY_EXPONENT); + e.radius = + Math.pow( + Math.pow(edge.radius, MURRAY_EXPONENT) + - Math.pow(r1, MURRAY_EXPONENT), + 1 / MURRAY_EXPONENT); if (Math.abs(e.radius - r1) < DELTA_TOLERANCE) { e.radius = r1; } @@ -696,8 +695,11 @@ private static ArrayList calculateRadius(Graph graph, SiteEdge edge, e.radius = MINIMUM_CAPILLARY_RADIUS; } } else if (edge.radius < r1) { - e.radius = Math.pow(Math.pow(r1, MURRAY_EXPONENT) - - Math.pow(edge.radius, MURRAY_EXPONENT), 1 / MURRAY_EXPONENT); + e.radius = + Math.pow( + Math.pow(r1, MURRAY_EXPONENT) + - Math.pow(edge.radius, MURRAY_EXPONENT), + 1 / MURRAY_EXPONENT); if (Math.abs(e.radius - edge.radius) < DELTA_TOLERANCE) { e.radius = edge.radius; } @@ -715,45 +717,45 @@ private static ArrayList calculateRadius(Graph graph, SiteEdge edge, } } } else if (in == tocheck && out == fromcheck) { - ArrayList b = (dir == CalculationCategory.DOWNSTREAM - ? e.getEdgesIn() : e.getEdgesOut()); + ArrayList b = (dir == Strategy.DOWNSTREAM ? e.getEdgesIn() : e.getEdgesOut()); double r1 = ((SiteEdge) b.get(0)).radius; double r2 = ((SiteEdge) b.get(1)).radius; if (r1 != 0 && r2 != 0) { - e.radius = Math.pow(Math.pow(r1, MURRAY_EXPONENT) - + Math.pow(r2, MURRAY_EXPONENT), 1 / MURRAY_EXPONENT); + e.radius = + Math.pow( + Math.pow(r1, MURRAY_EXPONENT) + Math.pow(r2, MURRAY_EXPONENT), + 1 / MURRAY_EXPONENT); } } - + children.add(e); } - + if (edge.radius == 0) { children.clear(); children.add(edge); } else { edge.isVisited = true; } - + return children; } - + /** * Assigns the radii (in um) using Murray's law without splits. * - * @param graph the graph object - * @param edge the starting edge for the calculation - * @param dir the direction of the calculation - * @param fromcheck the number of edges in to the selected node - * @param tocheck the number of edges out of the selected node - * @return the list of children edges + * @param graph the graph object + * @param edge the starting edge for the calculation + * @param dir the direction of the calculation + * @param fromcheck the number of edges in to the selected node + * @param tocheck the number of edges out of the selected node + * @return the list of children edges */ - private static ArrayList assignRadius(Graph graph, SiteEdge edge, - CalculationCategory dir, - int fromcheck, int tocheck) { + private static ArrayList assignRadius( + Graph graph, SiteEdge edge, Strategy dir, int fromcheck, int tocheck) { ArrayList children = new ArrayList<>(); ArrayList list = null; - + switch (dir) { case DOWNSTREAM: list = edge.getEdgesOut(); @@ -764,70 +766,75 @@ private static ArrayList assignRadius(Graph graph, SiteEdge edge, default: break; } - + // No need to update is there are no edges. if (list == null || list.size() == 0) { return children; } - + // Iterate through all edges and calculate radii and then recurse. for (Edge obj : list) { SiteEdge e = (SiteEdge) obj; int in = getInDegree(graph, e, dir); int out = getOutDegree(graph, e, dir); - + if (in == 1 && out == 1 && edge.radius != 0) { e.radius = edge.radius; } else if (in == fromcheck && out == tocheck) { e.radius = edge.radius; } else if (in == tocheck && out == fromcheck) { - ArrayList b = (dir == CalculationCategory.DOWNSTREAM - ? e.getEdgesIn() : e.getEdgesOut()); + ArrayList b = (dir == Strategy.DOWNSTREAM ? e.getEdgesIn() : e.getEdgesOut()); double r1 = ((SiteEdge) b.get(0)).radius; double r2 = ((SiteEdge) b.get(1)).radius; if (r1 != 0 && r2 != 0) { - e.radius = Math.pow(Math.pow(r1, MURRAY_EXPONENT) - + Math.pow(r2, MURRAY_EXPONENT), 1 / MURRAY_EXPONENT); + e.radius = + Math.pow( + Math.pow(r1, MURRAY_EXPONENT) + Math.pow(r2, MURRAY_EXPONENT), + 1 / MURRAY_EXPONENT); } } - + children.add(e); } - + edge.isVisited = true; - + return children; } - + /** * Traverses through the graph and marks visited nodes. * - * @param graph the graph object - * @param gs the graph sites object - * @param node the starting node for the traversal - * @param splitCol the column in the pattern layout - * @param splitRow the row in the pattern layout + * @param graph the graph object + * @param gs the graph sites object + * @param node the starting node for the traversal + * @param splitCol the column in the pattern layout + * @param splitRow the row in the pattern layout */ - static void visit(Graph graph, PatchComponentSitesGraphFactory gs, SiteNode node, - int splitCol, int splitRow) { + static void visit( + Graph graph, + PatchComponentSitesGraphFactory gs, + SiteNode node, + int splitCol, + int splitRow) { Bag bag = graph.getEdgesOut(node); if (bag == null) { return; } - + int i = node.getX(); int j = node.getY(); int offset = gs.calcOffset(node.getZ()); int col = gs.calcCol(i, offset); int row = gs.calcRow(i, j, offset); - + for (Object obj : bag) { SiteEdge edge = (SiteEdge) obj; - + if (edge.isVisited) { continue; } - + // Check for cases where flow network is incomplete. if (col == splitCol && row == splitRow) { if ((edge.getTo().getY() - j) > 0 && j > gs.latticeWidth - 3) { @@ -836,18 +843,18 @@ static void visit(Graph graph, PatchComponentSitesGraphFactory gs, SiteNode node continue; } } - + edge.isVisited = true; visit(graph, gs, edge.getTo(), splitCol, splitRow); } } - + /** * Uses Dijkstra's algorithm to find path between given nodes. * - * @param graph the graph object - * @param start the start node - * @param end the end node + * @param graph the graph object + * @param start the start node + * @param end the end node */ static void path(Graph graph, SiteNode start, SiteNode end) { // Reset all distances. @@ -860,17 +867,17 @@ static void path(Graph graph, SiteNode start, SiteNode end) { from.prev = null; to.prev = null; } - + HashSet settled = new HashSet<>(); HashSet unsettled = new HashSet<>(); - + start.distance = 0; unsettled.add(start); - + while (unsettled.size() != 0) { SiteNode evalNode = null; int lowestDistance = Integer.MAX_VALUE; - + // Get neighboring node with lowest distance. for (SiteNode node : unsettled) { int nodeDistance = node.distance; @@ -879,20 +886,20 @@ static void path(Graph graph, SiteNode start, SiteNode end) { evalNode = node; } } - + // Update queues. unsettled.remove(evalNode); settled.add(evalNode); - + // If end node found, exit from loop. if (evalNode == end) { break; } - + // Get neighboring nodes. Bag bag = graph.getEdgesOut(evalNode); HashSet destinationNodes = new HashSet<>(); - + // Get neighboring nodes that have not yet been settled. if (bag != null) { for (Object obj : bag) { @@ -903,7 +910,7 @@ static void path(Graph graph, SiteNode start, SiteNode end) { } } } - + // Find shortest distance. for (SiteNode destinationNode : destinationNodes) { int newDistance = evalNode.distance + 1; @@ -915,13 +922,13 @@ static void path(Graph graph, SiteNode start, SiteNode end) { } } } - + /** * Traverses through graph to find perfused paths. * - * @param graph the graph object - * @param start the start node - * @param path the list of edges in the path + * @param graph the graph object + * @param start the start node + * @param path the list of edges in the path */ static void traverse(Graph graph, SiteNode start, ArrayList path) { Bag bag = graph.getEdgesOut(start); @@ -930,7 +937,7 @@ static void traverse(Graph graph, SiteNode start, ArrayList path) { } for (Object obj : bag) { SiteEdge edge = (SiteEdge) obj; - + if (edge.isPerfused) { path.add(edge); for (SiteEdge e : path) { @@ -939,57 +946,60 @@ static void traverse(Graph graph, SiteNode start, ArrayList path) { path.remove(edge); continue; } - + path.add(edge); traverse(graph, edge.getTo(), path); path.remove(edge); } } - + /** * Updates radii for the graph using Murray's law without variation. * - * @param graph the graph object - * @param list the list of edges - * @param code the update code + * @param graph the graph object + * @param list the list of edges + * @param code the update code */ static void updateRadii(Graph graph, ArrayList list, CalculationType code) { updateRadii(graph, list, code, null); } - + /** * Updates radii for the graph using Murray's law. - *

- * The graph sites object contains an instance of a random number generator - * in order to ensure simulations with the same random seed are the same. * - * @param graph the graph object - * @param list the list of edges - * @param code the update code - * @param random the random number generator + *

The graph sites object contains an instance of a random number generator in order to + * ensure simulations with the same random seed are the same. + * + * @param graph the graph object + * @param list the list of edges + * @param code the update code + * @param random the random number generator */ - static void updateRadii(Graph graph, ArrayList list, CalculationType code, - MersenneTwisterFast random) { + static void updateRadii( + Graph graph, + ArrayList list, + CalculationType code, + MersenneTwisterFast random) { ArrayList nextList; LinkedHashSet nextSet; LinkedHashSet currSet = new LinkedHashSet<>(); - + // Reset visited. for (Object obj : graph.getAllEdges()) { ((SiteEdge) obj).isVisited = false; } - + // Assign radius to given edges. for (SiteEdge edge : list) { edge.radius = CAPILLARY_RADIUS; - + // For pattern layout, modify capillary radius to introduce variation. if (code == CalculationType.UPSTREAM_PATTERN || code == CalculationType.DOWNSTREAM_PATTERN) { edge.radius *= random.nextDouble() + 0.5; } } - + // Track the upstream edges. for (SiteEdge edge : list) { switch (code) { @@ -1033,7 +1043,7 @@ static void updateRadii(Graph graph, ArrayList list, CalculationType c break; } } - + // Traverse the graph breadth first to assign radii. while (currSet.size() > 0) { nextSet = new LinkedHashSet<>(); @@ -1082,20 +1092,20 @@ static void updateRadii(Graph graph, ArrayList list, CalculationType c currSet = nextSet; } } - + /** * Updates hemodynamic properties in the graph after edges are removed. * - * @param graph the graph object + * @param graph the graph object */ static void updateGraph(Graph graph) { ArrayList list; Graph gCurr = graph; - + do { Graph gNew = new Graph(); list = new ArrayList<>(); - + for (Object obj : new Bag(gCurr.getAllEdges())) { SiteEdge edge = (SiteEdge) obj; SiteNode to = edge.getTo(); @@ -1103,7 +1113,7 @@ static void updateGraph(Graph graph) { if (edge.isIgnored) { continue; } - + // Check for leaves. if (gCurr.getOutDegree(to) == 0 && !to.isRoot) { list.add(edge); @@ -1113,17 +1123,17 @@ static void updateGraph(Graph graph) { gNew.addEdge(edge); } } - + // Update leaves to be ignored. for (SiteEdge edge : list) { edge.isIgnored = true; edge.getFrom().pressure = Double.NaN; edge.getTo().pressure = Double.NaN; } - + gCurr = gNew; } while (list.size() != 0); - + calculatePressures(graph); boolean reversed = reversePressures(graph); if (reversed) { @@ -1131,7 +1141,7 @@ static void updateGraph(Graph graph) { } calculateFlows(graph); calculateStresses(graph); - + // Set oxygen nodes. for (Object obj : graph.getAllEdges()) { SiteEdge edge = (SiteEdge) obj; @@ -1145,24 +1155,23 @@ static void updateGraph(Graph graph) { } } } - + /** - * Iterates through nodes to eliminate low flow edges preventing graph - * traversal. + * Iterates through nodes to eliminate low flow edges preventing graph traversal. * - * @param graph the graph object - * @param nodes the set of nodes - * @param removeMin {@code true} if minimum flow edges should be removed, - * {@code false} otherwise + * @param graph the graph object + * @param nodes the set of nodes + * @param removeMin {@code true} if minimum flow edges should be removed, {@code false} + * otherwise */ static void updateTraverse(Graph graph, LinkedHashSet nodes, boolean removeMin) { double minFlow = Double.MAX_VALUE; SiteEdge minEdge = null; - + for (SiteNode node : nodes) { Bag out = graph.getEdgesOut(node); Bag in = graph.getEdgesIn(node); - + if (out != null) { for (Object obj : out) { SiteEdge edge = (SiteEdge) obj; @@ -1177,7 +1186,7 @@ static void updateTraverse(Graph graph, LinkedHashSet nodes, boolean r } } } - + if (in != null) { for (Object obj : in) { SiteEdge edge = (SiteEdge) obj; @@ -1191,13 +1200,13 @@ static void updateTraverse(Graph graph, LinkedHashSet nodes, boolean r minEdge = edge; } } - + // Check if flow ratio is low for inlet edges. if (in.numObjs == 2) { SiteEdge edge1 = (SiteEdge) in.objs[0]; SiteEdge edge2 = (SiteEdge) in.objs[1]; double totalFlow = edge1.flow + edge2.flow; - + if (edge1.flow / totalFlow < MINIMUM_FLOW_PERCENT) { graph.removeEdge(edge1); edge1.getFrom().pressure = Double.NaN; @@ -1212,7 +1221,7 @@ static void updateTraverse(Graph graph, LinkedHashSet nodes, boolean r } } } - + if (removeMin) { graph.removeEdge(minEdge); minEdge.getFrom().pressure = Double.NaN; @@ -1220,13 +1229,13 @@ static void updateTraverse(Graph graph, LinkedHashSet nodes, boolean r updateGraph(graph); } } - + /** * Gets list of edges of the given types(s). * - * @param graph the graph object - * @param types the list of edge types - * @return a list of edges + * @param graph the graph object + * @param types the list of edge types + * @return a list of edges */ static ArrayList getEdgeByType(Graph graph, EdgeType[] types) { ArrayList list = new ArrayList<>(); @@ -1240,14 +1249,14 @@ static ArrayList getEdgeByType(Graph graph, EdgeType[] types) { } return list; } - + /** * Gets list of edges of the given type(s) for the given level. * - * @param graph the graph object - * @param types the list of edge types - * @param level the graph resolution level - * @return a list of edges + * @param graph the graph object + * @param types the list of edge types + * @param level the graph resolution level + * @return a list of edges */ static ArrayList getEdgeByType(Graph graph, EdgeType[] types, EdgeLevel level) { ArrayList list = new ArrayList<>(); @@ -1261,13 +1270,13 @@ static ArrayList getEdgeByType(Graph graph, EdgeType[] types, EdgeLeve } return list; } - + /** * Gets list of leaves of the given type(s). * - * @param graph the graph object - * @param types the list of edge types - * @return a list of leaves + * @param graph the graph object + * @param types the list of edge types + * @return a list of leaves */ static ArrayList getLeavesByType(Graph graph, EdgeType[] types) { ArrayList list = new ArrayList<>(); diff --git a/src/arcade/patch/env/component/PatchComponentSitesPattern.java b/src/arcade/patch/env/component/PatchComponentSitesPattern.java index 803b7015a..0bff0c75b 100644 --- a/src/arcade/patch/env/component/PatchComponentSitesPattern.java +++ b/src/arcade/patch/env/component/PatchComponentSitesPattern.java @@ -7,178 +7,191 @@ /** * Extension of {@link PatchComponentSites} for pattern sites. - *

- * A repeating pattern of lattice indices are assigned as sites, defined by - * tessellating the "unit cell" of the pattern across the entire lattice. - *

- * The amount of concentration added to each index is the difference between the - * concentration at the index and the source concentration of the molecule. - * Three hemodynamic factors can be optionally included - * ({@code RELATIVE_FRACTION}) with variable weights to reduce the amount of + * + *

A repeating pattern of lattice indices are assigned as sites, defined by tessellating the + * "unit cell" of the pattern across the entire lattice. + * + *

The amount of concentration added to each index is the difference between the concentration at + * the index and the source concentration of the molecule. Three hemodynamic factors can be + * optionally included ({@code RELATIVE_FRACTION}) with variable weights to reduce the amount of * concentration added. + * *

    - *
  • {@code WEIGHT_FLOW} = consumption upstream of a given site
  • - *
  • {@code WEIGHT_LOCAL} = local cell consumption of the molecule at a - * given lattice site
  • - *
  • {@code WEIGHT_GRADIENT} = concentration difference between source and - * a given lattice site
  • + *
  • {@code WEIGHT_FLOW} = consumption upstream of a given site + *
  • {@code WEIGHT_LOCAL} = local cell consumption of the molecule at a given lattice site + *
  • {@code WEIGHT_GRADIENT} = concentration difference between source and a given lattice site *
- *

- * Sites can be damaged by setting the {@code DAMAGE_SCALING} parameter, which - * also reduces the amount of concentration added at each index. + * + *

Sites can be damaged by setting the {@code DAMAGE_SCALING} parameter, which also reduces the + * amount of concentration added at each index. */ - public abstract class PatchComponentSitesPattern extends PatchComponentSites { /** Border directions. */ - enum Border { LEFT, RIGHT, TOP, BOTTOM, UP, DOWN } - + enum Border { + LEFT, + RIGHT, + TOP, + BOTTOM, + UP, + DOWN + } + /** Array holding locations of patterns. */ protected final boolean[][][] patterns; - + /** Array holding locations of pattern pair anchors. */ protected final boolean[][][] anchors; - + /** Array of damage instances for each lattice index. */ protected final double[][][] damageSingle; - + /** Array of damage instances averaged between site pairs. */ protected final double[][][] damageTotal; - + /** Array of damage value multipliers. */ protected final double[][][] damageValues; - + /** Pattern site damage scaling. */ private final double damageScaling; - + /** Relative contribution of hemodynamic factors. */ private final double fraction; - + /** Weight of gradient hemodynamic factor. */ private final double weightGradient; - + /** Weight of flow hemodynamic factor. */ private final double weightFlow; - + /** Weight of local hemodynamic factor. */ private final double weightLocal; - + /** {@code true} if local factor is calculated, {@code false} otherwise. */ private final boolean calculateLocal; - + /** {@code true} if flow factor is calculated, {@code false} otherwise. */ private final boolean calculateFlow; - + /** {@code true} if damage is calculated, {@code false} otherwise. */ private final boolean calculateDamage; - + /** * Creates a {@link PatchComponentSites} using pattern sites. - *

- * Loaded parameters include: + * + *

Loaded parameters include: + * *

    - *
  • {@code RELATIVE_FRACTION} = relative contribution of hemodynamic factors
  • - *
  • {@code WEIGHT_GRADIENT} = weight of gradient hemodynamic factor
  • - *
  • {@code WEIGHT_LOCAL} = weight of local hemodynamic factor
  • - *
  • {@code WEIGHT_FLOW} = weight of flow hemodynamic factor
  • - *
  • {@code DAMAGE_SCALING} = pattern site damage scaling
  • + *
  • {@code RELATIVE_FRACTION} = relative contribution of hemodynamic factors + *
  • {@code WEIGHT_GRADIENT} = weight of gradient hemodynamic factor + *
  • {@code WEIGHT_LOCAL} = weight of local hemodynamic factor + *
  • {@code WEIGHT_FLOW} = weight of flow hemodynamic factor + *
  • {@code DAMAGE_SCALING} = pattern site damage scaling *
* - * @param series the simulation series - * @param parameters the component parameters dictionary + * @param series the simulation series + * @param parameters the component parameters dictionary */ public PatchComponentSitesPattern(Series series, MiniBox parameters) { super(series); - + // Set loaded parameters. fraction = parameters.getDouble("RELATIVE_FRACTION"); weightGradient = parameters.getDouble("WEIGHT_GRADIENT"); weightLocal = parameters.getDouble("WEIGHT_LOCAL"); weightFlow = parameters.getDouble("WEIGHT_FLOW"); damageScaling = parameters.getDouble("DAMAGE_SCALING"); - + // Set booleans. calculateDamage = damageScaling != 0; calculateLocal = weightLocal > 0; calculateFlow = weightFlow > 0; - + // Create and initialize arrays. patterns = new boolean[latticeHeight][latticeLength][latticeWidth]; anchors = new boolean[latticeHeight][latticeLength][latticeWidth]; damageSingle = new double[latticeHeight][latticeLength][latticeWidth]; damageTotal = new double[latticeHeight][latticeLength][latticeWidth]; damageValues = new double[latticeHeight][latticeLength][latticeWidth]; - + initializePatternArray(); initializeDamageArrays(); } - + /** * Gets the underlying pattern sites array. * - * @return the pattern sites array + * @return the pattern sites array */ - public boolean[][][] getPatterns() { return patterns; } - + public boolean[][][] getPatterns() { + return patterns; + } + /** * Gets the underlying pattern anchors array. * - * @return the pattern sites array + * @return the pattern sites array */ - public boolean[][][] getAnchors() { return anchors; } - + public boolean[][][] getAnchors() { + return anchors; + } + /** * Gets the underlying pattern damage array. * - * @return the pattern damage array + * @return the pattern damage array */ - public double[][][] getDamage() { return damageSingle; } - + public double[][][] getDamage() { + return damageSingle; + } + /** - * Calculates the average change in concentration between the two lattice - * indices bordering a capillary. + * Calculates the average change in concentration between the two lattice indices bordering a + * capillary. * - * @param i the index in the x direction - * @param j the index in the y direction - * @param k the index in the z direction - * @param delta the array of concentration changes - * @return the average concentration change + * @param i the index in the x direction + * @param j the index in the y direction + * @param k the index in the z direction + * @param delta the array of concentration changes + * @return the average concentration change */ abstract double calculateAverage(int i, int j, int k, double[][] delta); - + /** * Calculates final change in concentration based on upstream capillaries. * - * @param i the index in the x direction - * @param j the index in the y direction - * @param k the index in the z direction - * @param flow the array of cumulative concentration changes - * @param delta the array of concentration changes - * @param borders the map of border indicators + * @param i the index in the x direction + * @param j the index in the y direction + * @param k the index in the z direction + * @param flow the array of cumulative concentration changes + * @param delta the array of concentration changes + * @param borders the map of border indicators */ - abstract void calculateFlow(int i, int j, int k, double[][] flow, double[][] delta, - EnumMap borders); - + abstract void calculateFlow( + int i, + int j, + int k, + double[][] flow, + double[][] delta, + EnumMap borders); + /** * Calculates average damage between the two indices bordering a capillary. * - * @param i the index in the x direction - * @param j the index in the y direction - * @param k the index in the z direction + * @param i the index in the x direction + * @param j the index in the y direction + * @param k the index in the z direction */ abstract void calculateDamage(int i, int j, int k); - + /** * Initializes sites in pattern array. - *

- * Sites are defined by copying the pattern unit cell across the array. - * Values of 1 and 2 indicate which the two lattice indices that border a - * capillary. + * + *

Sites are defined by copying the pattern unit cell across the array. Values of 1 and 2 + * indicate which the two lattice indices that border a capillary. */ abstract void initializePatternArray(); - - /** - * Initializes damage array to 1.0 (no damage). - */ + + /** Initializes damage array to 1.0 (no damage). */ void initializeDamageArrays() { for (int k = 0; k < latticeHeight; k++) { for (int i = 0; i < latticeLength; i++) { @@ -188,7 +201,7 @@ void initializeDamageArrays() { } } } - + @Override public void step(SimState simstate) { // Iterate through array to calculate damage, if needed. @@ -199,18 +212,18 @@ public void step(SimState simstate) { if (anchors[k][i][j]) { calculateDamage(i, j, k); } - - damageValues[k][i][j] = 1.0 - / Math.exp(damageScaling * damageTotal[k][i][j]); + + damageValues[k][i][j] = + 1.0 / Math.exp(damageScaling * damageTotal[k][i][j]); } } } } - + double[][][] accumulation = new double[latticeHeight][latticeLength][latticeWidth]; double[][][] flow = new double[latticeHeight][latticeLength][latticeWidth]; EnumMap borders = new EnumMap<>(Border.class); - + // Iterate through each layer and each array to assign updates. for (SiteLayer layer : layers) { double[][][] delta = layer.delta; @@ -218,61 +231,65 @@ public void step(SimState simstate) { double[][][] previous = layer.previous; double concentration = layer.concentration; double total = 0; - + // Iterate to calculate accumulation. if (calculateLocal || calculateFlow) { for (int k = 0; k < latticeHeight; k += 2) { for (int i = 0; i < latticeLength; i++) { for (int j = 0; j < latticeWidth; j++) { if (patterns[k][i][j]) { - accumulation[k][i][j] = (previous[k][i][j] - current[k][i][j]) - / concentration; + accumulation[k][i][j] = + (previous[k][i][j] - current[k][i][j]) / concentration; total += accumulation[k][i][j]; } } } } } - + // Iterate through every other layer. for (int k = 0; k < latticeHeight; k += 2) { // Check if on up or down border of environment. borders.put(Border.UP, k == 0); borders.put(Border.DOWN, k == latticeHeight - 1); - + for (int i = 0; i < latticeLength; i++) { // Check if on left or right border of environment. borders.put(Border.LEFT, i == 0); borders.put(Border.RIGHT, i == latticeLength - 1); - + for (int j = 0; j < latticeWidth; j++) { // Check if on top or bottom border of environment. borders.put(Border.TOP, j == 0); borders.put(Border.BOTTOM, j == latticeWidth - 1); - + if (patterns[k][i][j]) { // Calculate flow. if (anchors[k][i][j] && calculateFlow) { calculateFlow(i, j, k, flow[k], accumulation[k], borders); } - + // Calculate weight adjustments. double wg = 1 - current[k][i][j] / concentration; double wl = accumulation[k][i][j]; double wf = (total == 0 ? 0 : -flow[k][i][j] / total); double w = weightGradient * wg + weightLocal * wl + weightFlow * wf; double ww = 1.0 / (1.0 + Math.exp(-w)); - + // Calculate final change. - delta[k][i][j] = Math.max((concentration - previous[k][i][j]) - * (ww * fraction + 1 - fraction) * damageValues[k][i][j], 0); + delta[k][i][j] = + Math.max( + (concentration - previous[k][i][j]) + * (ww * fraction + 1 - fraction) + * damageValues[k][i][j], + 0); } } } } } } - + // TODO add in damage increases for movement into and out of a location // if (sim.getAgents().getNumObjectsAtLocation(newLoc) > 1) { // int zNew = newLoc.getLatZ(); diff --git a/src/arcade/patch/env/component/PatchComponentSitesPatternRect.java b/src/arcade/patch/env/component/PatchComponentSitesPatternRect.java index 288c48312..c180c216c 100644 --- a/src/arcade/patch/env/component/PatchComponentSitesPatternRect.java +++ b/src/arcade/patch/env/component/PatchComponentSitesPatternRect.java @@ -6,8 +6,9 @@ /** * Extension of {@link PatchComponentSitesPattern} for rectangular geometry. - *

- * The pattern unit cell is given by: + * + *

The pattern unit cell is given by: + * *

  *    -------------------------
  *    |   |   |   |   | 1 | 2 |
@@ -24,56 +25,55 @@
  *    -------------------------
  * 
*/ - public class PatchComponentSitesPatternRect extends PatchComponentSitesPattern { /** * Creates a {@link PatchComponentSitesPattern} for rectangular geometry. * - * @param series the simulation series - * @param parameters the component parameters dictionary + * @param series the simulation series + * @param parameters the component parameters dictionary */ public PatchComponentSitesPatternRect(Series series, MiniBox parameters) { super(series, parameters); } - + /** * 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 */ private int calcOffset(int k) { return (latticeHeight - k / 2 + 1 - ((latticeHeight - 1) / 4) % 2) % 2; } - + /** * Calculates column of the rectangular 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 */ private int calcCol(int i, int offset) { return (i + 4 * offset) % 6; } - + /** * Calculates row of the rectangular 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 */ private int calcRow(int i, int j, int offset) { return (j + offset + (((i + 4 * offset) / 6 & 1) == 0 ? 0 : 3)) % 6; } - + @Override double calculateAverage(int i, int j, int k, double[][] delta) { double average = delta[i][j]; int offset = calcOffset(k); - + switch (calcCol(i, offset)) { case 0: case 1: @@ -94,24 +94,30 @@ private int calcRow(int i, int j, int offset) { default: break; } - + return average; } - + @Override - public void calculateFlow(int i, int j, int k, double[][] flow, double[][] delta, - EnumMap borders) { + public void calculateFlow( + int i, + int j, + int k, + double[][] flow, + double[][] delta, + EnumMap borders) { double total = 0; double val = calculateAverage(i, j, k, delta); int offset = calcOffset(k); - + switch (calcCol(i, offset)) { case 0: if (i == 0 || i == 1) { total = val; } else { - total = (flow[i - 1][j] - + flow[i - 1][j + (j == latticeWidth - 1 ? 0 : 1)]) / 2 + val; + total = + (flow[i - 1][j] + flow[i - 1][j + (j == latticeWidth - 1 ? 0 : 1)]) / 2 + + val; } flow[i][j + (borders.get(Border.BOTTOM) ? 0 : 1)] = total; break; @@ -163,15 +169,15 @@ public void calculateFlow(int i, int j, int k, double[][] flow, double[][] delta default: break; } - + flow[i][j] = total; } - + @Override public void calculateDamage(int i, int j, int k) { double total = damageSingle[k][i][j]; int offset = calcOffset(k); - + switch (calcCol(i, offset)) { case 0: case 1: @@ -194,21 +200,21 @@ public void calculateDamage(int i, int j, int k) { default: break; } - + damageTotal[k][i][j] = total; } - + @Override void initializePatternArray() { byte[][] unit = { - { 0, 0, 0, 0, 1, 2 }, - { 0, 0, 0, 0, 0, 1 }, - { 0, 0, 0, 0, 0, 1 }, - { 0, 0, 0, 0, 1, 2 }, - { 1, 1, 1, 1, 1, 0 }, - { 2, 2, 2, 2, 1, 0 } + {0, 0, 0, 0, 1, 2}, + {0, 0, 0, 0, 0, 1}, + {0, 0, 0, 0, 0, 1}, + {0, 0, 0, 0, 1, 2}, + {1, 1, 1, 1, 1, 0}, + {2, 2, 2, 2, 1, 0} }; - + for (int k = 0; k < latticeHeight; k += 2) { int offset = calcOffset(k); for (int i = 0; i < latticeLength; i++) { diff --git a/src/arcade/patch/env/component/PatchComponentSitesPatternTri.java b/src/arcade/patch/env/component/PatchComponentSitesPatternTri.java index fd6d63aed..7d9696c18 100644 --- a/src/arcade/patch/env/component/PatchComponentSitesPatternTri.java +++ b/src/arcade/patch/env/component/PatchComponentSitesPatternTri.java @@ -6,8 +6,9 @@ /** * Extension of {@link PatchComponentSitesPattern} for triangular geometry. - *

- * The pattern unit cell is given by: + * + *

The pattern unit cell is given by: + * *

  *    -----------------------------
  *    \   / \   / \ 2 / \   / \   /
@@ -30,56 +31,55 @@
  *    -----------------------------
  * 
*/ - public class PatchComponentSitesPatternTri extends PatchComponentSitesPattern { /** * Creates a {@link PatchComponentSitesPattern} for triangular geometry. * - * @param series the simulation series - * @param parameters the component parameters dictionary + * @param series the simulation series + * @param parameters the component parameters dictionary */ public PatchComponentSitesPatternTri(Series series, MiniBox parameters) { super(series, parameters); } - + /** * 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 */ private int calcOffset(int k) { return (latticeHeight - k / 2 - 1) % 3; } - + /** * Calculates column of the triangular 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 */ private int calcCol(int i, int offset) { return (i + 6 * offset) % 9; } - + /** * Calculates row of the triangular 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 */ private int calcRow(int i, int j, int offset) { return (j + (((i + 6 * offset) / 9 & 1) == 0 ? 0 : 3)) % 6; } - + @Override double calculateAverage(int i, int j, int k, double[][] delta) { double average = delta[i][j]; int offset = calcOffset(k); - + switch (calcCol(i, offset)) { case 0: case 7: @@ -101,17 +101,22 @@ private int calcRow(int i, int j, int offset) { default: break; } - + return average; } - + @Override - public void calculateFlow(int i, int j, int k, double[][] flow, double[][] delta, - EnumMap borders) { + public void calculateFlow( + int i, + int j, + int k, + double[][] flow, + double[][] delta, + EnumMap borders) { double total = 0; double val = calculateAverage(i, j, k, delta); int offset = calcOffset(k); - + switch (calcCol(i, offset)) { case 0: case 7: @@ -127,8 +132,11 @@ public void calculateFlow(int i, int j, int k, double[][] flow, double[][] delta flow[i + (borders.get(Border.RIGHT) ? 0 : 1)][j] = total; break; case 5: - total = (flow[i - 1][j + (1 - (borders.get(Border.TOP) ? 0 : 1))] - + flow[i - 1][j + (j > latticeWidth - 3 ? 0 : 1)]) / 2 + val; + total = + (flow[i - 1][j + (1 - (borders.get(Border.TOP) ? 0 : 1))] + + flow[i - 1][j + (j > latticeWidth - 3 ? 0 : 1)]) + / 2 + + val; flow[i][j + (borders.get(Border.BOTTOM) ? 0 : 1)] = total; break; case 2: @@ -154,15 +162,15 @@ public void calculateFlow(int i, int j, int k, double[][] flow, double[][] delta default: break; } - + flow[i][j] = total; } - + @Override public void calculateDamage(int i, int j, int k) { double total = damageSingle[k][i][j]; int offset = calcOffset(k); - + switch (calcCol(i, offset)) { case 0: case 7: @@ -185,21 +193,21 @@ public void calculateDamage(int i, int j, int k) { default: break; } - + damageTotal[k][i][j] = total; } - + @Override void initializePatternArray() { byte[][] unit = { - { 0, 0, 0, 1, 2, 1, 0, 1, 0 }, - { 0, 0, 0, 1, 2, 2, 0, 2, 0 }, - { 0, 0, 1, 2, 0, 0, 0, 0, 0 }, - { 1, 1, 2, 0, 0, 0, 0, 0, 0 }, - { 2, 1, 2, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 2, 0, 0, 0, 0, 0 } + {0, 0, 0, 1, 2, 1, 0, 1, 0}, + {0, 0, 0, 1, 2, 2, 0, 2, 0}, + {0, 0, 1, 2, 0, 0, 0, 0, 0}, + {1, 1, 2, 0, 0, 0, 0, 0, 0}, + {2, 1, 2, 0, 0, 0, 0, 0, 0}, + {0, 0, 1, 2, 0, 0, 0, 0, 0} }; - + for (int k = 0; k < latticeHeight; k += 2) { int offset = calcOffset(k); for (int i = 0; i < latticeLength; i++) { diff --git a/src/arcade/patch/env/component/PatchComponentSitesSource.java b/src/arcade/patch/env/component/PatchComponentSitesSource.java index 9a1df1af8..aca20ee71 100644 --- a/src/arcade/patch/env/component/PatchComponentSitesSource.java +++ b/src/arcade/patch/env/component/PatchComponentSitesSource.java @@ -6,111 +6,113 @@ /** * Extension of {@link PatchComponentSites} for source sites. - *

- * Each index in the lattice can be assigned as a source, depending on the - * initial spacings in the x direction (length, {@code X_SPACING}), y direction - * (width, {@code Y_SPACING}), and z direction (height, {@code Z_SPACING}). Each - * spacing can be defined as: + * + *

Each index in the lattice can be assigned as a source, depending on the initial spacings in + * the x direction (length, {@code X_SPACING}), y direction (width, {@code Y_SPACING}), and z + * direction (height, {@code Z_SPACING}). Each spacing can be defined as: + * *

    - *
  • {@code *} = all indices in the lattice
  • - *
  • {@code x} or {@code X} = no indices in the lattice
  • - *
  • {@code *:INC} = all indices in the lattice incremented by INC - * (i = 0, INC, 2*INC, ... , n*INC) where n*INC ≤ lattice size
  • - *
  • {@code INDEX} = only index INDEX
  • - *
  • {@code MIN:MAX} = all indices between MIN and MAX, inclusive
  • - *
  • {@code MIN:INC:MAX} = all indices between MIN and MAX incremented - * by INC (i = MIN, MIN + INC, MIN + 2*INC, ... , MIN + n*INC) where - * MIN + n*INC ≤ MAX
  • + *
  • {@code *} = all indices in the lattice + *
  • {@code x} or {@code X} = no indices in the lattice + *
  • {@code *:INC} = all indices in the lattice incremented by INC (i = 0, INC, 2*INC, ... , + * n*INC) where n*INC ≤ lattice size + *
  • {@code INDEX} = only index INDEX + *
  • {@code MIN:MAX} = all indices between MIN and MAX, inclusive + *
  • {@code MIN:INC:MAX} = all indices between MIN and MAX incremented by INC (i = MIN, MIN + + * INC, MIN + 2*INC, ... , MIN + n*INC) where MIN + n*INC ≤ MAX *
- *

- * Setting all spacings to {@code *} creates a constant source. - * Setting any spacings to {@code x} removes all sites. - *

- * The amount of concentration added to each index is the difference between - * the concentration at the index and the source concentration of the molecule. - * Sites can be damaged by setting the {@code DAMAGE_SCALING} parameter, which - * reduces the amount of concentration added at each index. + * + *

Setting all spacings to {@code *} creates a constant source. Setting any spacings to {@code x} + * removes all sites. + * + *

The amount of concentration added to each index is the difference between the concentration at + * the index and the source concentration of the molecule. Sites can be damaged by setting the + * {@code DAMAGE_SCALING} parameter, which reduces the amount of concentration added at each index. */ - public class PatchComponentSitesSource extends PatchComponentSites { /** Array holding locations of sources. */ private final boolean[][][] sources; - + /** Array of damage instances. */ private final double[][][] damageSingle; - + /** Array of damage value multipliers. */ private final double[][][] damageValues; - + /** Source site damage scaling. */ private final double damageScaling; - + /** Spacing of sources in x direction. */ private final String[] xSpacing; - + /** Spacing of sources in y direction. */ private final String[] ySpacing; - + /** Spacing of sources in z direction. */ private final String[] zSpacing; - + /** {@code true} if damage is calculated, {@code false} otherwise. */ private final boolean calculateDamage; - + /** * Creates a {@link PatchComponentSites} using source sites. - *

- * Loaded parameters include: + * + *

Loaded parameters include: + * *

    - *
  • {@code X_SPACING} = spacing of sources in x direction
  • - *
  • {@code Y_SPACING} = spacing of sources in y direction
  • - *
  • {@code Z_SPACING} = spacing of sources in z direction
  • - *
  • {@code DAMAGE_SCALING} = source site damage scaling
  • + *
  • {@code X_SPACING} = spacing of sources in x direction + *
  • {@code Y_SPACING} = spacing of sources in y direction + *
  • {@code Z_SPACING} = spacing of sources in z direction + *
  • {@code DAMAGE_SCALING} = source site damage scaling *
* - * @param series the simulation series - * @param parameters the component parameters dictionary + * @param series the simulation series + * @param parameters the component parameters dictionary */ public PatchComponentSitesSource(Series series, MiniBox parameters) { super(series); - + // Set loaded parameters. damageScaling = parameters.getDouble("DAMAGE_SCALING"); xSpacing = parameters.get("X_SPACING").split(":"); ySpacing = parameters.get("Y_SPACING").split(":"); zSpacing = parameters.get("Z_SPACING").split(":"); - + // Set boolean. calculateDamage = damageScaling != 0; - + // Create and initialize arrays. sources = new boolean[latticeHeight][latticeLength][latticeWidth]; damageSingle = new double[latticeHeight][latticeLength][latticeWidth]; damageValues = new double[latticeHeight][latticeLength][latticeWidth]; - + initializeSourceArray(); initializeDamageArrays(); } - + /** * Gets the underlying source sites array. * - * @return the source sites array + * @return the source sites array */ - public boolean[][][] getSources() { return sources; } - + public boolean[][][] getSources() { + return sources; + } + /** * Gets the underlying source damage array. * - * @return the source damage array + * @return the source damage array */ - public double[][][] getDamage() { return damageSingle; } - + public double[][][] getDamage() { + return damageSingle; + } + /** * Initializes sites in source array. - *

- * Iterates through each index in the source lattice and assigns it as a - * source site or not, depending on the specified spacings. + * + *

Iterates through each index in the source lattice and assigns it as a source site or not, + * depending on the specified spacings. */ void initializeSourceArray() { for (int k = 0; k < latticeHeight; k++) { @@ -130,10 +132,8 @@ void initializeSourceArray() { } } } - - /** - * Initializes damage array to 1.0 (no damage). - */ + + /** Initializes damage array to 1.0 (no damage). */ void initializeDamageArrays() { for (int k = 0; k < latticeHeight; k++) { for (int i = 0; i < latticeLength; i++) { @@ -143,19 +143,19 @@ void initializeDamageArrays() { } } } - + /** * Checks if a given index is a valid source site. * - * @param spacing the site spacing - * @param index the source site index - * @return {@code true} if the index is valid, {@code false} otherwise + * @param spacing the site spacing + * @param index the source site index + * @return {@code true} if the index is valid, {@code false} otherwise */ boolean checkSourceIndex(String[] spacing, int index) { int min; int max; int inc = 1; - + // Site definition is given as a single value, min-max, or min-inc-max. if (spacing[0].equals("*")) { if (spacing.length == 1) { @@ -176,10 +176,10 @@ boolean checkSourceIndex(String[] spacing, int index) { min = Integer.parseInt(spacing[0]); max = Integer.parseInt(spacing[1]); } - + return index < min || index > max || (index - min) % inc != 0; } - + @Override public void step(SimState simstate) { // Iterate through array to calculate damage, if needed. @@ -188,33 +188,36 @@ public void step(SimState simstate) { for (int i = 0; i < latticeLength; i++) { for (int j = 0; j < latticeWidth; j++) { if (sources[k][i][j]) { - damageValues[k][i][j] = 1.0 - / Math.exp(damageScaling * damageSingle[k][i][j]); + damageValues[k][i][j] = + 1.0 / Math.exp(damageScaling * damageSingle[k][i][j]); } } } } } - + // Iterate through each layer and each array to assign updates. for (SiteLayer layer : layers) { double[][][] delta = layer.delta; double[][][] previous = layer.previous; double concentration = layer.concentration; - + for (int k = 0; k < latticeHeight; k++) { for (int i = 0; i < latticeLength; i++) { for (int j = 0; j < latticeWidth; j++) { if (sources[k][i][j]) { - delta[k][i][j] = Math.max((concentration - previous[k][i][j]) - * damageValues[k][i][j], 0); + delta[k][i][j] = + Math.max( + (concentration - previous[k][i][j]) + * damageValues[k][i][j], + 0); } } } } } } - + // TODO add in damage increases for movement into and out of a location // if (sim.getAgents().getNumObjectsAtLocation(newLoc) > 1) { // int zNew = newLoc.getLatZ(); diff --git a/src/arcade/patch/env/grid/PatchGrid.java b/src/arcade/patch/env/grid/PatchGrid.java index 81a763ed3..599171f5a 100644 --- a/src/arcade/patch/env/grid/PatchGrid.java +++ b/src/arcade/patch/env/grid/PatchGrid.java @@ -10,68 +10,67 @@ /** * Implementation of {@link Grid} for patch models. - *

- * {@code PatchGrid} uses the location hash to map to bags of agents. + * + *

{@code PatchGrid} uses the location hash to map to bags of agents. */ - public class PatchGrid implements Grid { /** Initial bag capacity. */ private static final int INITIAL_CAPACITY = 6; - + /** Map of ID to object. */ final HashMap objects; - + /** Collection of all objects in the grid. */ final Bag allObjects; - - /** - * Creates a {@link Grid} for patch. - */ + + /** Creates a {@link Grid} for patch. */ public PatchGrid() { objects = new HashMap<>(); allObjects = new Bag(); } - + @Override - public Bag getAllObjects() { return allObjects; } - + public Bag getAllObjects() { + return allObjects; + } + @Override public void addObject(Object object, Location location) { int index = location.hashCode(); allObjects.add(object); - + Bag bag = (Bag) objects.get(index); - + if (bag == null) { bag = new Bag(INITIAL_CAPACITY); objects.put(index, bag); } - + bag.add(object); } - + @Override public void removeObject(Object object, Location location) { int index = location.hashCode(); allObjects.remove(object); - + Bag bag = (Bag) objects.get(index); bag.remove(object); - + if (bag.numObjs == 0) { objects.remove(index); } } - + @Override public Object getObjectAt(int index) { return objects.get(index); } - + /** * {@inheritDoc} - *

- * Maintains the old location object. + * + *

Maintains the old location object. */ @Override public void moveObject(Object object, Location fromLocation, Location toLocation) { @@ -79,32 +78,32 @@ public void moveObject(Object object, Location fromLocation, Location toLocation int fromIndex = fromLocation.hashCode(); Bag fromBag = (Bag) objects.get(fromIndex); fromBag.remove(object); - + if (fromBag.numObjs == 0) { objects.remove(fromIndex); } - + // Add to new location. int toIndex = toLocation.hashCode(); Bag toBag = (Bag) objects.get(toIndex); - + if (toBag == null) { toBag = new Bag(INITIAL_CAPACITY); objects.put(toIndex, toBag); } - + toBag.add(object); - + // Update location object. PatchLocation location = (PatchLocation) ((Cell) object).getLocation(); location.update((PatchLocation) toLocation); } - + /** * Gets all objects at a location. * - * @param location the location - * @return a bag of objects at the given location + * @param location the location + * @return a bag of objects at the given location */ public Bag getObjectsAtLocation(Location location) { Bag bag = (Bag) objects.get(location.hashCode()); @@ -114,12 +113,12 @@ public Bag getObjectsAtLocation(Location location) { return bag; } } - + /** * Gets all objects at all the given locations. * - * @param locations the locations - * @return a bag of objects at the given locations + * @param locations the locations + * @return a bag of objects at the given locations */ public Bag getObjectsAtLocations(ArrayList locations) { Bag bag = new Bag(); diff --git a/src/arcade/patch/env/lattice/PatchLattice.java b/src/arcade/patch/env/lattice/PatchLattice.java index 4a94f1818..cd6132cda 100644 --- a/src/arcade/patch/env/lattice/PatchLattice.java +++ b/src/arcade/patch/env/lattice/PatchLattice.java @@ -17,64 +17,64 @@ /** * Abstract implementation of {@link Lattice} for patch models. - *

- * {@code PatchLattice} agents can call two {@link Operation} categories: - * diffusers and generators. Diffusers diffuse values on the underlying array. - * Generators add values to the underlying array. - *

- * General order of rules for the {@code PatchLattice} step: + * + *

{@code PatchLattice} agents can call two {@link Operation} categories: diffusers and + * generators. Diffusers diffuse values on the underlying array. Generators add values to the + * underlying array. + * + *

General order of rules for the {@code PatchLattice} step: + * *

    - *
  • step generator operation
  • - *
  • step diffuser operation
  • + *
  • step generator operation + *
  • step diffuser operation *
*/ - public abstract class PatchLattice implements Lattice { /** Array containing lattice values. */ protected final double[][][] field; - + /** Length of the array (x direction). */ private final int length; - + /** Width of the array (y direction). */ private final int width; - + /** Height of the array (z direction). */ private final int height; - + /** Spatial conversion factor (um/voxel). */ protected final double ds; - + /** Spatial conversion factor in z (um/voxel). */ protected final double dz; - + /** Map of operation categories and {@link Operation} instance. */ protected final Map operations; - + /** Lattice parameters. */ final MiniBox parameters; - + /** * Creates a {@code PatchLattice} environment. * - * @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 ds the spatial scaling (x and y directions) - * @param dz the spatial scaling (z direction) - * @param parameters the dictionary of parameters + * @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 ds the spatial scaling (x and y directions) + * @param dz the spatial scaling (z direction) + * @param parameters the dictionary of parameters */ - public PatchLattice(int length, int width, int height, - double ds, double dz, MiniBox parameters) { + public PatchLattice( + int length, int width, int height, double ds, double dz, MiniBox parameters) { this.length = length; this.width = width; this.height = height; this.ds = ds; this.dz = dz; this.parameters = parameters; - + field = new double[height][length][width]; - + // Add lattice operations. operations = new HashMap<>(); MiniBox operationBox = parameters.filter("(OPERATION)"); @@ -85,48 +85,60 @@ public PatchLattice(int length, int width, int height, operations.put(category, operation); } } - + /** * Makes the specified {@link Operation} object. * - * @param category the operation category - * @param version the operation version - * @return the operation instance + * @param category the operation category + * @param version the operation version + * @return the operation instance */ public abstract Operation makeOperation(Category category, String version); - + @Override - public double[][][] getField() { return field; } - + public double[][][] getField() { + return field; + } + @Override - public int getLength() { return length; } - + public int getLength() { + return length; + } + @Override - public int getWidth() { return width; } - + public int getWidth() { + return width; + } + @Override - public int getHeight() { return height; } - + public int getHeight() { + return height; + } + @Override - public Operation getOperation(OperationCategory category) { return operations.get(category); } - + public Operation getOperation(OperationCategory category) { + return operations.get(category); + } + @Override - public MiniBox getParameters() { return parameters; } - + public MiniBox getParameters() { + return parameters; + } + @Override public void setField(double[][] values, int index) { for (int i = 0; i < values.length; i++) { field[index][i] = values[i].clone(); } } - + @Override public void setField(double[][][] values) { for (int k = 0; k < values.length; k++) { setField(values[k], k); } } - + @Override public void setField(double value) { for (int k = 0; k < height; k++) { @@ -137,7 +149,7 @@ public void setField(double value) { } } } - + @Override public double getTotalValue(Location location) { PatchLocation patchLocation = (PatchLocation) location; @@ -146,16 +158,17 @@ public double getTotalValue(Location location) { .mapToDouble(c -> field[c.z][c.x][c.y]) .sum(); } - + @Override public double getAverageValue(Location location) { PatchLocation patchLocation = (PatchLocation) location; return patchLocation.getSubcoordinates().stream() - .map(e -> (CoordinateXYZ) e) - .mapToDouble(c -> field[c.z][c.x][c.y]) - .sum() / patchLocation.getMaximum(); + .map(e -> (CoordinateXYZ) e) + .mapToDouble(c -> field[c.z][c.x][c.y]) + .sum() + / patchLocation.getMaximum(); } - + @Override public void updateValue(Location location, double fraction) { if (!Double.isNaN(fraction)) { @@ -165,7 +178,7 @@ public void updateValue(Location location, double fraction) { .forEach(c -> field[c.z][c.x][c.y] *= fraction); } } - + @Override public void incrementValue(Location location, double increment) { PatchLocation patchLocation = (PatchLocation) location; @@ -173,7 +186,7 @@ public void incrementValue(Location location, double increment) { .map(e -> (CoordinateXYZ) e) .forEach(c -> field[c.z][c.x][c.y] += increment); } - + @Override public void setValue(Location location, double value) { PatchLocation patchLocation = (PatchLocation) location; @@ -181,22 +194,22 @@ public void setValue(Location location, double value) { .map(e -> (CoordinateXYZ) e) .forEach(c -> field[c.z][c.x][c.y] = value); } - + @Override public void schedule(Schedule schedule) { schedule.scheduleOnce(this, Ordering.FIRST.ordinal()); schedule.scheduleRepeating(this, Ordering.LATTICES.ordinal(), 1); } - + @Override public void step(SimState simstate) { Simulation sim = (Simulation) simstate; - + // Step generator operation, if it exists. if (operations.containsKey(Category.GENERATOR)) { operations.get(Category.GENERATOR).step(simstate.random, sim); } - + // Step diffuser operation, if it exists. if (operations.containsKey(Category.DIFFUSER)) { operations.get(Category.DIFFUSER).step(simstate.random, sim); diff --git a/src/arcade/patch/env/lattice/PatchLatticeFactory.java b/src/arcade/patch/env/lattice/PatchLatticeFactory.java index 3bdffeee2..d3c02f96e 100644 --- a/src/arcade/patch/env/lattice/PatchLatticeFactory.java +++ b/src/arcade/patch/env/lattice/PatchLatticeFactory.java @@ -8,36 +8,34 @@ /** * Implementation of{@link LatticeFactory} for {@link PatchLattice} objects. - *

- * Each lattice is initialized to {@code INITIAL_CONCENTRATION}. + * + *

Each lattice is initialized to {@code INITIAL_CONCENTRATION}. */ - public abstract class PatchLatticeFactory implements LatticeFactory { /** Random number generator instance. */ MersenneTwisterFast random; - + /** Map of id to lattice. */ public final HashMap lattices; - - /** - * Creates a factory for making {@link PatchLattice} instances. - */ + + /** Creates a factory for making {@link PatchLattice} instances. */ public PatchLatticeFactory() { lattices = new HashMap<>(); } - + @Override public void initialize(Series series, MersenneTwisterFast random) { this.random = random; createLattices(series); } - + /** * {@inheritDoc} - *

- * Loaded parameters include: + * + *

Loaded parameters include: + * *

    - *
  • {@code INITIAL_CONCENTRATION} = initial layer concentration
  • + *
  • {@code INITIAL_CONCENTRATION} = initial layer concentration *
*/ @Override @@ -47,30 +45,30 @@ public void createLattices(Series series) { int height = series.height; double ds = series.ds; double dz = series.dz; - + for (String key : series.layers.keySet()) { MiniBox layer = series.layers.get(key); PatchLattice lattice = getLattice(length, width, height, ds, dz, layer); - + // Set initial lattice value. double initialValue = layer.getDouble("INITIAL_CONCENTRATION"); lattice.setField(initialValue); - + lattices.put(key, lattice); } } - + /** * Creates a new {@link PatchLattice} instance. * - * @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 ds the spatial scaling (x and y directions) - * @param dz the spatial scaling (z direction) - * @param parameters the dictionary of parameters - * @return the lattice instance + * @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 ds the spatial scaling (x and y directions) + * @param dz the spatial scaling (z direction) + * @param parameters the dictionary of parameters + * @return the lattice instance */ - public abstract PatchLattice getLattice(int length, int width, int height, - double ds, double dz, MiniBox parameters); + public abstract PatchLattice getLattice( + int length, int width, int height, double ds, double dz, MiniBox parameters); } diff --git a/src/arcade/patch/env/lattice/PatchLatticeFactoryRect.java b/src/arcade/patch/env/lattice/PatchLatticeFactoryRect.java index 65f640203..466e8f7da 100644 --- a/src/arcade/patch/env/lattice/PatchLatticeFactoryRect.java +++ b/src/arcade/patch/env/lattice/PatchLatticeFactoryRect.java @@ -2,20 +2,16 @@ import arcade.core.util.MiniBox; -/** - * Concrete implementation of {@link PatchLatticeFactory} for rectangular - * geometry. - */ - +/** Concrete implementation of {@link PatchLatticeFactory} for rectangular geometry. */ public final class PatchLatticeFactoryRect extends PatchLatticeFactory { - /** - * Creates a factory for making rectangular {@link PatchLattice} instances. - */ - public PatchLatticeFactoryRect() { super(); } - + /** Creates a factory for making rectangular {@link PatchLattice} instances. */ + public PatchLatticeFactoryRect() { + super(); + } + @Override - public PatchLattice getLattice(int length, int width, int height, - double ds, double dz, MiniBox parameters) { + public PatchLattice getLattice( + int length, int width, int height, double ds, double dz, MiniBox parameters) { return new PatchLatticeRect(length, width, height, ds, dz, parameters); } } diff --git a/src/arcade/patch/env/lattice/PatchLatticeFactoryTri.java b/src/arcade/patch/env/lattice/PatchLatticeFactoryTri.java index 52f458de5..ede33c2d4 100644 --- a/src/arcade/patch/env/lattice/PatchLatticeFactoryTri.java +++ b/src/arcade/patch/env/lattice/PatchLatticeFactoryTri.java @@ -2,20 +2,16 @@ import arcade.core.util.MiniBox; -/** - * Concrete implementation of {@link PatchLatticeFactory} for triangular - * geometry. - */ - +/** Concrete implementation of {@link PatchLatticeFactory} for triangular geometry. */ public final class PatchLatticeFactoryTri extends PatchLatticeFactory { - /** - * Creates a factory for making triangular {@link PatchLattice} instances. - */ - public PatchLatticeFactoryTri() { super(); } - + /** Creates a factory for making triangular {@link PatchLattice} instances. */ + public PatchLatticeFactoryTri() { + super(); + } + @Override - public PatchLattice getLattice(int length, int width, int height, - double ds, double dz, MiniBox parameters) { + public PatchLattice getLattice( + int length, int width, int height, double ds, double dz, MiniBox parameters) { return new PatchLatticeTri(length, width, height, ds, dz, parameters); } } diff --git a/src/arcade/patch/env/lattice/PatchLatticeRect.java b/src/arcade/patch/env/lattice/PatchLatticeRect.java index 0a63e4928..d4a68cb0b 100644 --- a/src/arcade/patch/env/lattice/PatchLatticeRect.java +++ b/src/arcade/patch/env/lattice/PatchLatticeRect.java @@ -6,26 +6,23 @@ import arcade.patch.env.operation.PatchOperationGenerator; import arcade.patch.util.PatchEnums.Category; -/** - * Concrete implementation of {@link PatchLattice} for rectangular coordinates. - */ - +/** Concrete implementation of {@link PatchLattice} for rectangular coordinates. */ public class PatchLatticeRect extends PatchLattice { /** * Creates a rectangular {@code PatchLattice} environment. * - * @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 ds the spatial scaling (x and y directions) - * @param dz the spatial scaling (z direction) - * @param parameters the dictionary of parameters + * @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 ds the spatial scaling (x and y directions) + * @param dz the spatial scaling (z direction) + * @param parameters the dictionary of parameters */ - public PatchLatticeRect(int length, int width, int height, - double ds, double dz, MiniBox parameters) { + public PatchLatticeRect( + int length, int width, int height, double ds, double dz, MiniBox parameters) { super(length, width, height, ds, dz, parameters); } - + @Override public Operation makeOperation(Category category, String version) { switch (category) { diff --git a/src/arcade/patch/env/lattice/PatchLatticeTri.java b/src/arcade/patch/env/lattice/PatchLatticeTri.java index 3f5decaba..ae03cb09d 100644 --- a/src/arcade/patch/env/lattice/PatchLatticeTri.java +++ b/src/arcade/patch/env/lattice/PatchLatticeTri.java @@ -6,26 +6,23 @@ import arcade.patch.env.operation.PatchOperationGenerator; import arcade.patch.util.PatchEnums.Category; -/** - * Concrete implementation of {@link PatchLattice} for triangular coordinates. - */ - +/** Concrete implementation of {@link PatchLattice} for triangular coordinates. */ public class PatchLatticeTri extends PatchLattice { /** * Creates a triangular {@code PatchLattice} environment. * - * @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 ds the spatial scaling (x and y directions) - * @param dz the spatial scaling (z direction) - * @param parameters the dictionary of parameters + * @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 ds the spatial scaling (x and y directions) + * @param dz the spatial scaling (z direction) + * @param parameters the dictionary of parameters */ - public PatchLatticeTri(int length, int width, int height, - double ds, double dz, MiniBox parameters) { + public PatchLatticeTri( + int length, int width, int height, double ds, double dz, MiniBox parameters) { super(length, width, height, ds, dz, parameters); } - + @Override public Operation makeOperation(Category category, String version) { switch (category) { diff --git a/src/arcade/patch/env/location/Coordinate.java b/src/arcade/patch/env/location/Coordinate.java index 12b46c52a..ea5f4c527 100644 --- a/src/arcade/patch/env/location/Coordinate.java +++ b/src/arcade/patch/env/location/Coordinate.java @@ -1,41 +1,38 @@ package arcade.patch.env.location; -/** - * Representation of a coordinate. - */ - +/** Representation of a coordinate. */ public abstract class Coordinate { /** Coordinate z value. */ public final int z; - + /** * Creates a {@code Coordinate}. * - * @param z the z coordinate value + * @param z the z coordinate value */ public Coordinate(int z) { this.z = z; } - + /** * Calculates the distance of the coordinate from the center. * - * @return the distance from the center + * @return the distance from the center */ public abstract double calculateDistance(); - + /** * Gets hash based on coordinate. * - * @return the hash + * @return the hash */ public abstract int hashCode(); - + /** * Checks if two coordinates have the same coordinate values. * - * @param obj the coordinate to compare - * @return {@code true} if coordinates are equal, {@code false} otherwise + * @param obj the coordinate to compare + * @return {@code true} if coordinates are equal, {@code false} otherwise */ public abstract boolean equals(Object obj); } diff --git a/src/arcade/patch/env/location/CoordinateUVWZ.java b/src/arcade/patch/env/location/CoordinateUVWZ.java index 41da1da53..560eeaa00 100644 --- a/src/arcade/patch/env/location/CoordinateUVWZ.java +++ b/src/arcade/patch/env/location/CoordinateUVWZ.java @@ -2,28 +2,27 @@ /** * Representation of (u, v, w, z) coordinate. - *

- * Each coordinate is defined by (u, v, w, z) values. Two coordinate objects are - * considered equal if they have matching (u, v, w, z) values. + * + *

Each coordinate is defined by (u, v, w, z) values. Two coordinate objects are considered equal + * if they have matching (u, v, w, z) values. */ - public final class CoordinateUVWZ extends Coordinate { /** Coordinate u value. */ public final int u; - + /** Coordinate v value. */ public final int v; - + /** Coordinate w value. */ public final int w; - + /** * Creates a (u, v, w, z) {@code Coordinate}. * - * @param u the u coordinate value - * @param v the v coordinate value - * @param w the w coordinate value - * @param z the z coordinate value + * @param u the u coordinate value + * @param v the v coordinate value + * @param w the w coordinate value + * @param z the z coordinate value */ public CoordinateUVWZ(int u, int v, int w, int z) { super(z); @@ -31,20 +30,22 @@ public CoordinateUVWZ(int u, int v, int w, int z) { this.v = v; this.w = w; } - + @Override public double calculateDistance() { return (Math.abs(u) + Math.abs(v) + Math.abs(w)) / 2.0; } - + /** * {@inheritDoc} - *

- * Uses (u, v, z) coordinate values to calculate hash. + * + *

Uses (u, v, z) coordinate values to calculate hash. */ @Override - public int hashCode() { return u + (v << 8) + (z << 16); } - + public int hashCode() { + return u + (v << 8) + (z << 16); + } + @Override public boolean equals(Object obj) { if (!(obj instanceof CoordinateUVWZ)) { @@ -53,11 +54,11 @@ public boolean equals(Object obj) { CoordinateUVWZ coordinate = (CoordinateUVWZ) obj; return coordinate.u == u && coordinate.v == v && coordinate.w == w && coordinate.z == z; } - + /** * Returns coordinate as string. * - * @return a string + * @return a string */ public String toString() { return String.format("[%d, %d, %d, %d]", u, v, w, z); diff --git a/src/arcade/patch/env/location/CoordinateXYZ.java b/src/arcade/patch/env/location/CoordinateXYZ.java index 584ffe595..1faee7b84 100644 --- a/src/arcade/patch/env/location/CoordinateXYZ.java +++ b/src/arcade/patch/env/location/CoordinateXYZ.java @@ -2,44 +2,45 @@ /** * Representation of (x, y, z) coordinates. - *

- * Each coordinate is defined by (x, y, z) values. Two coordinate objects are - * considered equal if they have matching (x, y, z) values. + * + *

Each coordinate is defined by (x, y, z) values. Two coordinate objects are considered equal if + * they have matching (x, y, z) values. */ - public final class CoordinateXYZ extends Coordinate { /** Coordinate x value. */ public final int x; - + /** Coordinate y value. */ public final int y; - + /** * Creates an (x, y, z) {@code Coordinate}. * - * @param x the x coordinate value - * @param y the y coordinate value - * @param z the z coordinate value + * @param x the x coordinate value + * @param y the y coordinate value + * @param z the z coordinate value */ public CoordinateXYZ(int x, int y, int z) { super(z); this.x = x; this.y = y; } - + @Override public double calculateDistance() { return Math.sqrt(x * x + y * y); } - + /** * {@inheritDoc} - *

- * Uses (x, y, z) coordinate values to calculate hash. + * + *

Uses (x, y, z) coordinate values to calculate hash. */ @Override - public int hashCode() { return x + (y << 8) + (z << 16); } - + public int hashCode() { + return x + (y << 8) + (z << 16); + } + @Override public boolean equals(Object obj) { if (!(obj instanceof CoordinateXYZ)) { @@ -48,11 +49,11 @@ public boolean equals(Object obj) { CoordinateXYZ coordinate = (CoordinateXYZ) obj; return coordinate.x == x && coordinate.y == y && coordinate.z == z; } - + /** * Returns coordinate as string. * - * @return a string + * @return a string */ public String toString() { return String.format("[%d, %d, %d]", x, y, z); diff --git a/src/arcade/patch/env/location/PatchLocation.java b/src/arcade/patch/env/location/PatchLocation.java index c9c8586a6..b535a0151 100644 --- a/src/arcade/patch/env/location/PatchLocation.java +++ b/src/arcade/patch/env/location/PatchLocation.java @@ -5,65 +5,59 @@ /** * Abstract implementation of {@link Location} for patch models. - *

- * {@code PatchLocation} objects define where agents are within the - * {@link arcade.core.env.grid.Grid} (relative to other agents) and relative to - * the {@link arcade.core.env.lattice.Lattice} (local molecule concentrations). - * Thecoordinate defines the location in the - * {@link arcade.core.env.grid.Grid} while the term subcoordinate(s) + * + *

{@code PatchLocation} objects define where agents are within the {@link + * arcade.core.env.grid.Grid} (relative to other agents) and relative to the {@link + * arcade.core.env.lattice.Lattice} (local molecule concentrations). Thecoordinate defines + * the location in the {@link arcade.core.env.grid.Grid} while the term subcoordinate(s) * defines the location(s) in the {@link arcade.core.env.lattice.Lattice}. - *

- * There may be multiple subcoordinates associated with the same - * coordinate (therefore there may be more than one agent per - * coordinate, but there can only be one agent for a given coordinate / - * subcoordinate pair). For example, in the hexagonal grid, each hexagon has a - * coordinate. Within each hexagon there are six corresponding - * triangular lattice - * subcoordinates. - * There may be multiple agents in a given hexagon, but each cell within that - * hexagon is associated with a specific unique triangle. Therefore, there can - * be no more than six agents per hexagonal patch. - *

- * Regardless of geometry, the center of the model should have - * {@link arcade.core.env.grid.Grid} location coordinate (0,0,0) or (0,0,0,0). - * {@link arcade.core.env.lattice.Lattice} arrays cannot have negative indices, - * so (0,0,0) is located at the top left of the 2D array and the bottom layer of - * the 3D stack. + * + *

There may be multiple subcoordinates associated with the same coordinate + * (therefore there may be more than one agent per coordinate, but there can only be one agent for a + * given coordinate / subcoordinate pair). For example, in the hexagonal grid, each hexagon has a + * coordinate. Within each hexagon there are six corresponding triangular lattice + * subcoordinates. There may be multiple agents in a given hexagon, but each cell within + * that hexagon is associated with a specific unique triangle. Therefore, there can be no more than + * six agents per hexagonal patch. + * + *

Regardless of geometry, the center of the model should have {@link arcade.core.env.grid.Grid} + * location coordinate (0,0,0) or (0,0,0,0). {@link arcade.core.env.lattice.Lattice} arrays cannot + * have negative indices, so (0,0,0) is located at the top left of the 2D array and the bottom layer + * of the 3D stack. */ - public abstract class PatchLocation implements Location { /** Radius of the simulation environment. */ static int radius; - + /** Depth of the simulation environment. */ static int depth; - + /** Radius and margin of the simulation environment. */ static int radiusBounds; - + /** Depth and margin of the simulation environment. */ static int depthBounds; - + /** Height offset for different layers in the simulation. */ static int heightOffset; - + /** Location patch coordinate. */ Coordinate coordinate; - + /** Location subcoordinates. */ ArrayList subcoordinates; - + /** Location offset. */ byte offset; - + /** Allowable movements. */ byte check; - + /** * Creates a {@code PatchLocation} object at given coordinate. * - * @param coordinate the patch coordinate - * @param n the number of patch subcoordinates + * @param coordinate the patch coordinate + * @param n the number of patch subcoordinates */ public PatchLocation(Coordinate coordinate, int n) { this.coordinate = coordinate; @@ -72,92 +66,91 @@ public PatchLocation(Coordinate coordinate, int n) { calculateSubcoordinates(); calculateChecks(); } - + /** * Gets the area of the location. * - * @return the location area + * @return the location area */ public abstract double getArea(); - + /** * Gets the patch coordinate in the {@link arcade.core.env.grid.Grid}. - *

- * These are not necessarily the same as the - * {@link arcade.core.env.lattice.Lattice} coordinates. * - * @return the coordinate + *

These are not necessarily the same as the {@link arcade.core.env.lattice.Lattice} + * coordinates. + * + * @return the coordinate */ - public Coordinate getCoordinate() { return coordinate; } - + public Coordinate getCoordinate() { + return coordinate; + } + /** * Gets the patch subcoordinate in the {@link arcade.core.env.lattice.Lattice}. - *

- * These are not necessarily the same as the - * {@link arcade.core.env.grid.Grid} coordinates. * - * @return the subcoordinate + *

These are not necessarily the same as the {@link arcade.core.env.grid.Grid} coordinates. + * + * @return the subcoordinate */ - public Coordinate getSubcoordinate() { return subcoordinates.get(0); } - + public Coordinate getSubcoordinate() { + return subcoordinates.get(0); + } + /** - * Gets all subcoordinates in the {@link arcade.core.env.lattice.Lattice} that - * correspond to the {@link arcade.core.env.grid.Grid} location. + * Gets all subcoordinates in the {@link arcade.core.env.lattice.Lattice} that correspond to the + * {@link arcade.core.env.grid.Grid} location. * - * @return the array of subcoordinates + * @return the array of subcoordinates */ - public ArrayList getSubcoordinates() { return subcoordinates; } - + public ArrayList getSubcoordinates() { + return subcoordinates; + } + /** - * Gets the {@link arcade.core.env.grid.Grid} coordinate size in the xy - * plane. + * Gets the {@link arcade.core.env.grid.Grid} coordinate size in the xy plane. * - * @return the coordinate size + * @return the coordinate size */ public abstract double getCoordinateSize(); - + /** - * Gets the {@link arcade.core.env.lattice.Lattice} coordinate size in the xy - * plane. + * Gets the {@link arcade.core.env.lattice.Lattice} coordinate size in the xy plane. * - * @return the subcoordinate size + * @return the subcoordinate size */ public abstract double getSubcoordinateSize(); - + /** * Gets the ratio of the {@link arcade.core.env.grid.Grid} z to xy sizes. * - * @return the size ratio + * @return the size ratio */ public abstract double getRatio(); - + /** * Gets the maximum occupancy of a location. * - * @return the maximum occupancy + * @return the maximum occupancy */ public abstract int getMaximum(); - + /** - * Gets the {@link arcade.core.env.grid.Grid} offset relative to the - * {@link arcade.core.env.lattice.Lattice}. + * Gets the {@link arcade.core.env.grid.Grid} offset relative to the {@link + * arcade.core.env.lattice.Lattice}. */ abstract void calculateOffset(); - - /** - * Calculates subcoordinates based on coordinate and offset. - */ + + /** Calculates subcoordinates based on coordinate and offset. */ abstract void calculateSubcoordinates(); - - /** - * Updates the possible moves that can be made. - */ + + /** Updates the possible moves that can be made. */ abstract void calculateChecks(); - + /** * Updates the location coordinates and subcoordinates. * - * @param location the new location + * @param location the new location */ public void update(PatchLocation location) { this.coordinate = location.coordinate; @@ -165,43 +158,47 @@ public void update(PatchLocation location) { this.offset = location.offset; this.check = location.check; } - + /** * Get unique hash based on location coordinate. * - * @return the hash + * @return the hash */ - public int hashCode() { return coordinate.hashCode(); } - + public int hashCode() { + return coordinate.hashCode(); + } + /** * Checks if two locations have the same coordinate. * - * @param obj the location to compare - * @return {@code true} if coordinates are equal, {@code false} otherwise + * @param obj the location to compare + * @return {@code true} if coordinates are equal, {@code false} otherwise */ - public boolean equals(Object obj) { return coordinate.equals(obj); } - + public boolean equals(Object obj) { + return coordinate.equals(obj); + } + /** * Calculates the perimeter of a cell occupying the location. * - * @param fraction the fraction of total volume - * @return the perimeter of the cell + * @param fraction the fraction of total volume + * @return the perimeter of the cell */ public abstract double getPerimeter(double fraction); - + /** * Gets the location of the neighbors to the current location. * - * @return the list of neighbor locations + * @return the list of neighbor locations */ public abstract ArrayList getNeighbors(); - + /** * Performs a left circular offset on the first six bits in a byte. * - * @param b the byte - * @param k the offset - * @return the offset byte + * @param b the byte + * @param k the offset + * @return the offset byte */ byte offsetByte(byte b, int k) { int left = b >> 2 & 0x3F; // left most 6 bits diff --git a/src/arcade/patch/env/location/PatchLocationContainer.java b/src/arcade/patch/env/location/PatchLocationContainer.java index dcc77a1f3..26524ab76 100644 --- a/src/arcade/patch/env/location/PatchLocationContainer.java +++ b/src/arcade/patch/env/location/PatchLocationContainer.java @@ -5,44 +5,42 @@ import arcade.core.env.location.LocationContainer; import arcade.core.env.location.LocationFactory; -/** - * Implementation of {@link LocationContainer} for {@link PatchLocation} - * objects. - */ - +/** Implementation of {@link LocationContainer} for {@link PatchLocation} objects. */ public final class PatchLocationContainer implements LocationContainer { /** Unique location container ID. */ public final int id; - + /** Location coordinate. */ public final Coordinate coordinate; - + /** * Creates a {@code PatchLocationContainer} instance. - *

- * The container does not have any regions. * - * @param id the location ID - * @param coordinate the location coordinate + *

The container does not have any regions. + * + * @param id the location ID + * @param coordinate the location coordinate */ public PatchLocationContainer(int id, Coordinate coordinate) { this.id = id; this.coordinate = coordinate; } - + @Override - public int getID() { return id; } - + public int getID() { + return id; + } + @Override public Location convert(LocationFactory factory, CellContainer cell) { PatchLocation location; - + if (factory instanceof PatchLocationFactoryRect) { location = new PatchLocationRect((CoordinateXYZ) coordinate); } else { location = new PatchLocationHex((CoordinateUVWZ) coordinate); } - + return location; } } diff --git a/src/arcade/patch/env/location/PatchLocationFactory.java b/src/arcade/patch/env/location/PatchLocationFactory.java index 2e796844e..de987db3c 100644 --- a/src/arcade/patch/env/location/PatchLocationFactory.java +++ b/src/arcade/patch/env/location/PatchLocationFactory.java @@ -1,6 +1,7 @@ package arcade.patch.env.location; import java.util.ArrayList; +import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import ec.util.MersenneTwisterFast; @@ -10,30 +11,24 @@ import arcade.core.util.Utilities; import arcade.patch.sim.PatchSeries; -/** - * Implementation of {@link LocationFactory} for {@link PatchLocation} objects. - */ - +/** Implementation of {@link LocationFactory} for {@link PatchLocation} objects. */ public abstract class PatchLocationFactory implements LocationFactory { /** Random number generator instance. */ MersenneTwisterFast random; - + /** Map of id to location. */ public final HashMap locations; - - /** - * Creates a factory for making {@link PatchLocation} instances. - */ + + /** Creates a factory for making {@link PatchLocation} instances. */ public PatchLocationFactory() { locations = new HashMap<>(); } - + /** * {@inheritDoc} - *

- * For series with no loader, a list of available patches are created based - * on population settings. For series with a loader, the specified file is - * loaded into the factory. + * + *

For series with no loader, a list of available patches are created based on population + * settings. For series with a loader, the specified file is loaded into the factory. */ @Override public void initialize(Series series, MersenneTwisterFast random) { @@ -44,33 +39,44 @@ public void initialize(Series series, MersenneTwisterFast random) { createLocations(series); } } - + /** * {@inheritDoc} - *

- * Loaded locations are mapped by their id. + * + *

Loaded locations are mapped by their id. */ @Override public void loadLocations(Series series) { // Load locations. ArrayList containers = series.loader.loadLocations(); - + // Map loaded container to factory. for (LocationContainer container : containers) { PatchLocationContainer locationContainer = (PatchLocationContainer) container; locations.put(locationContainer.id, locationContainer); } } - + @Override public void createLocations(Series series) { PatchSeries patchSeries = (PatchSeries) series; - + // Get all valid coordinates. ArrayList coordinates = getCoordinates(patchSeries.radius, patchSeries.depth); Utilities.shuffleList(coordinates, random); - coordinates.sort(Comparator.comparingDouble(Coordinate::calculateDistance)); - + + // Sort coordinates by distance if initialization scheme is not random. + // For "outward" initialization, locations with distances closer to the + // center are filled first. For "inward" initialization, locations with + // distances further from the center are filled first. + String initialization = patchSeries.patch.get("INITIALIZATION"); + if (!initialization.equalsIgnoreCase("random")) { + coordinates.sort(Comparator.comparingDouble(Coordinate::calculateDistance)); + if (initialization.equalsIgnoreCase("inward")) { + Collections.reverse(coordinates); + } + } + // Create containers for each coordinate. int id = 1; for (Coordinate coordinate : coordinates) { @@ -79,13 +85,13 @@ public void createLocations(Series series) { id++; } } - + /** * Gets all coordinates for the given range. * - * @param radius the bound on the radius - * @param depth the bound on the depth - * @return a list of location coordinates + * @param radius the bound on the radius + * @param depth the bound on the depth + * @return a list of location coordinates */ public abstract ArrayList getCoordinates(int radius, int depth); } diff --git a/src/arcade/patch/env/location/PatchLocationFactoryHex.java b/src/arcade/patch/env/location/PatchLocationFactoryHex.java index 1c1fefcc3..028d77b9f 100644 --- a/src/arcade/patch/env/location/PatchLocationFactoryHex.java +++ b/src/arcade/patch/env/location/PatchLocationFactoryHex.java @@ -3,29 +3,26 @@ import java.util.ArrayList; /** - * Concrete implementation of {@link PatchLocationFactory} for hexagonal - * geometry. - *

- * Cell agents exist on a hexagonal grid and molecules in the environment - * diffuse on a triangular lattice, such that each hexagon corresponds to 6 - * triangles. The hexagonal locations are defined in the (u, v, w, z) coordinate - * space such that (0,0,0,0) is the hexagon in the center of the simulation. The - * triangular locations are defined in the (x, y, z) coordinate space such that - * (0,0,0) is the triangle in the top left of the center slice of the - * simulation. Because environment radius is guaranteed to be even, the top left - * triangle of the corresponding triangular lattices is always pointed down. + * Concrete implementation of {@link PatchLocationFactory} for hexagonal geometry. + * + *

Cell agents exist on a hexagonal grid and molecules in the environment diffuse on a triangular + * lattice, such that each hexagon corresponds to 6 triangles. The hexagonal locations are defined + * in the (u, v, w, z) coordinate space such that (0,0,0,0) is the hexagon in the center of the + * simulation. The triangular locations are defined in the (x, y, z) coordinate space such that + * (0,0,0) is the triangle in the top left of the center slice of the simulation. Because + * environment radius is guaranteed to be even, the top left triangle of the corresponding + * triangular lattices is always pointed down. */ - public final class PatchLocationFactoryHex extends PatchLocationFactory { - /** - * Creates a factory for hexagonal {@link PatchLocation} instances. - */ - public PatchLocationFactoryHex() { super(); } - + /** Creates a factory for hexagonal {@link PatchLocation} instances. */ + public PatchLocationFactoryHex() { + super(); + } + @Override public ArrayList getCoordinates(int radius, int depth) { ArrayList coordinates = new ArrayList<>(); - + for (int u = 1 - radius; u < radius; u++) { for (int v = 1 - radius; v < radius; v++) { for (int w = 1 - radius; w < radius; w++) { @@ -37,7 +34,7 @@ public ArrayList getCoordinates(int radius, int depth) { } } } - + return coordinates; } } diff --git a/src/arcade/patch/env/location/PatchLocationFactoryRect.java b/src/arcade/patch/env/location/PatchLocationFactoryRect.java index 3a9e2130f..e57ee0bc3 100644 --- a/src/arcade/patch/env/location/PatchLocationFactoryRect.java +++ b/src/arcade/patch/env/location/PatchLocationFactoryRect.java @@ -3,27 +3,24 @@ import java.util.ArrayList; /** - * Concrete implementation of {@link PatchLocationFactory} for rectangular - * geometry. - *

- * Cell agents exist on a rectangular grid and molecules in the environment - * diffuse on a smaller rectangular lattice, such that each grid rectangle - * corresponds to 4 lattice rectangles. The rectangular locations are defined in - * the (x, y, z) coordinate space such that (0,0,0) is the rectangle in the - * center of the simulation (for the grid) and the left rectangle of the center + * Concrete implementation of {@link PatchLocationFactory} for rectangular geometry. + * + *

Cell agents exist on a rectangular grid and molecules in the environment diffuse on a smaller + * rectangular lattice, such that each grid rectangle corresponds to 4 lattice rectangles. The + * rectangular locations are defined in the (x, y, z) coordinate space such that (0,0,0) is the + * rectangle in the center of the simulation (for the grid) and the left rectangle of the center * slice (for the lattices). */ - public final class PatchLocationFactoryRect extends PatchLocationFactory { - /** - * Creates a factory for rectangular {@link PatchLocation} instances. - */ - public PatchLocationFactoryRect() { super(); } - + /** Creates a factory for rectangular {@link PatchLocation} instances. */ + public PatchLocationFactoryRect() { + super(); + } + @Override public ArrayList getCoordinates(int radius, int depth) { ArrayList coordinates = new ArrayList<>(); - + for (int x = 1 - radius; x < radius; x++) { for (int y = 1 - radius; y < radius; y++) { for (int z = 1 - depth; z < depth; z++) { @@ -31,7 +28,7 @@ public ArrayList getCoordinates(int radius, int depth) { } } } - + return coordinates; } } diff --git a/src/arcade/patch/env/location/PatchLocationHex.java b/src/arcade/patch/env/location/PatchLocationHex.java index d94720941..1fb3b7a4f 100644 --- a/src/arcade/patch/env/location/PatchLocationHex.java +++ b/src/arcade/patch/env/location/PatchLocationHex.java @@ -6,15 +6,14 @@ import arcade.patch.sim.PatchSeries; /** - * Concrete implementation of {@link PatchLocation} for hexagonal - * {@link arcade.core.env.grid.Grid} to a triangular - * {@link arcade.core.env.lattice.Lattice}. - *

- * {@link arcade.core.env.grid.Grid} coordinates are in terms of (u, v, w) and - * the {@link arcade.core.env.lattice.Lattice} coordinates are in (x, y). - * Hexagons are flat side up. Triangular {@link arcade.core.env.lattice.Lattice} - * subcoordinates are ordered 0 - 5, with 0 at the top center and going - * clockwise around. + * Concrete implementation of {@link PatchLocation} for hexagonal {@link arcade.core.env.grid.Grid} + * to a triangular {@link arcade.core.env.lattice.Lattice}. + * + *

{@link arcade.core.env.grid.Grid} coordinates are in terms of (u, v, w) and the {@link + * arcade.core.env.lattice.Lattice} coordinates are in (x, y). Hexagons are flat side up. Triangular + * {@link arcade.core.env.lattice.Lattice} subcoordinates are ordered 0 - 5, with 0 at the top + * center and going clockwise around. + * *

  *      -------
  *     / \ 0 / \
@@ -24,122 +23,138 @@
  *     \ / 3 \ /
  *      -------
  * 
- * In (u, v, w) coordinates, only coordinates where u + v + w = 0 are valid. For - * simulations with {@code DEPTH} > 0 (3D simulations), each the hexagonal - * grid is offset in one of two directions relative to the triangular lattice. - * Therefore, each cell in a location has six neighboring locations in the same - * layer, three neighboring locations in the layer above, and three neighboring - * locations in the layer below. Simulations with {@code DEPTH} > 1 must - * have a {@code MARGIN} > 0, otherwise the offset location coordinates will - * be associated with lattice coordinates that are out of bounds of the array. + * + * In (u, v, w) coordinates, only coordinates where u + v + w = 0 are valid. For simulations with + * {@code DEPTH} > 0 (3D simulations), each the hexagonal grid is offset in one of two + * directions relative to the triangular lattice. Therefore, each cell in a location has six + * neighboring locations in the same layer, three neighboring locations in the layer above, and + * three neighboring locations in the layer below. Simulations with {@code DEPTH} > 1 must have + * a {@code MARGIN} > 0, otherwise the offset location coordinates will be associated with + * lattice coordinates that are out of bounds of the array. */ - public final class PatchLocationHex extends PatchLocation { /** Size of hexagon patch from side to side [um]. */ private static final double HEX_SIZE = 30.0; - + /** Size of the hexagon patch side [um]. */ private static final double HEX_SIDE = HEX_SIZE / Math.sqrt(3.0); - + /** Height of hexagon patch [um]. */ private static final double HEX_DEPTH = 8.7; - + /** Perimeter of hexagon patch [um]. */ private static final double HEX_PERIMETER = 6 * HEX_SIDE; - + /** Area of hexagon patch [um2]. */ private static final double HEX_AREA = 3.0 / 2.0 / Math.sqrt(3.0) * HEX_SIZE * HEX_SIZE; - + /** Surface area of hexagon patch [um2]. */ private static final double HEX_SURFACE = 2 * HEX_AREA + HEX_DEPTH * HEX_PERIMETER; - + /** Volume of hexagon patch [um3]. */ private static final double HEX_VOLUME = HEX_AREA * HEX_DEPTH; - + /** Ratio of hexagon location height to size. */ private static final double HEX_RATIO = HEX_DEPTH / HEX_SIZE; - + /** Size of the triangle position [um]. */ private static final double TRI_SIZE = HEX_SIDE; - + /** Number of triangular subcoordinates. */ private static final int NUM_SUBCOORDINATES = 6; - + /** Relative triangular subcoordinate offsets in the x direction. */ - private static final byte[] X_OFF = new byte[] { 0, 1, 1, 0, -1, -1 }; - + private static final byte[] X_OFF = new byte[] {0, 1, 1, 0, -1, -1}; + /** Relative triangular subcoordinate offsets in the y direction. */ - private static final byte[] Y_OFF = new byte[] { 0, 0, 1, 1, 1, 0 }; - + private static final byte[] Y_OFF = new byte[] {0, 0, 1, 1, 1, 0}; + /** List of relative hexagonal neighbor locations. */ - private static final byte[] MOVES = new byte[] { - (byte) Integer.parseInt("00100100", 2), // up - (byte) Integer.parseInt("00011000", 2), // down - (byte) Integer.parseInt("01100000", 2), // up left - (byte) Integer.parseInt("10010000", 2), // down right - (byte) Integer.parseInt("01001000", 2), // down left - (byte) Integer.parseInt("10000100", 2), // up right - (byte) Integer.parseInt("00000010", 2), // vert up - (byte) Integer.parseInt("00000001", 2), // vert down - (byte) Integer.parseInt("10000110", 2), // vert up cw 1 - (byte) Integer.parseInt("00100110", 2), // vert up cw 2 - (byte) Integer.parseInt("01100001", 2), // vert down ccw 1 - (byte) Integer.parseInt("00100101", 2), // vert down ccw 2 - }; - + private static final byte[] MOVES = + new byte[] { + (byte) Integer.parseInt("00100100", 2), // up + (byte) Integer.parseInt("00011000", 2), // down + (byte) Integer.parseInt("01100000", 2), // up left + (byte) Integer.parseInt("10010000", 2), // down right + (byte) Integer.parseInt("01001000", 2), // down left + (byte) Integer.parseInt("10000100", 2), // up right + (byte) Integer.parseInt("00000010", 2), // vert up + (byte) Integer.parseInt("00000001", 2), // vert down + (byte) Integer.parseInt("10000110", 2), // vert up cw 1 + (byte) Integer.parseInt("00100110", 2), // vert up cw 2 + (byte) Integer.parseInt("01100001", 2), // vert down ccw 1 + (byte) Integer.parseInt("00100101", 2), // vert down ccw 2 + }; + /** * Creates a {@code PatchLocationHex} object for given coordinates. * - * @param u the coordinate in u direction - * @param v the coordinate in v direction - * @param w the coordinate in w direction - * @param z the coordinate in z direction + * @param u the coordinate in u direction + * @param v the coordinate in v direction + * @param w the coordinate in w direction + * @param z the coordinate in z direction */ public PatchLocationHex(int u, int v, int w, int z) { this(new CoordinateUVWZ(u, v, w, z)); } - + /** * Creates a {@code PatchLocationHex} object at given coordinate. * - * @param coordinate the patch coordinate + * @param coordinate the patch coordinate */ public PatchLocationHex(CoordinateUVWZ coordinate) { super(coordinate, NUM_SUBCOORDINATES); } - + @Override - public double getVolume() { return HEX_VOLUME; } - + public double getVolume() { + return HEX_VOLUME; + } + @Override - public double getSurface() { return HEX_SURFACE; } - + public double getSurface() { + return HEX_SURFACE; + } + @Override - public double getHeight() { return HEX_DEPTH; } - + public double getHeight() { + return HEX_DEPTH; + } + @Override - public double getArea() { return HEX_AREA; } - + public double getArea() { + return HEX_AREA; + } + @Override - public double getCoordinateSize() { return HEX_SIZE; } - + public double getCoordinateSize() { + return HEX_SIZE; + } + @Override - public double getSubcoordinateSize() { return TRI_SIZE; } - + public double getSubcoordinateSize() { + return TRI_SIZE; + } + @Override - public double getRatio() { return HEX_RATIO; } - + public double getRatio() { + return HEX_RATIO; + } + @Override - public int getMaximum() { return NUM_SUBCOORDINATES; } - + public int getMaximum() { + return NUM_SUBCOORDINATES; + } + /** * Updates static configuration variables. - *

- * Environment sizes are not set until the simulation series is created. - * Calculations for coordinates depend on these sizes, so the - * {@code Location} needs to be updated based on the series configuration. * - * @param series the current simulation series + *

Environment sizes are not set until the simulation series is created. Calculations for + * coordinates depend on these sizes, so the {@code Location} needs to be updated based on the + * series configuration. + * + * @param series the current simulation series */ public static void updateConfigs(PatchSeries series) { radius = series.radius; @@ -148,73 +163,72 @@ public static void updateConfigs(PatchSeries series) { depthBounds = series.depthBounds; heightOffset = series.height % 3 - series.height; } - + @Override void calculateOffset() { offset = (byte) ((Math.abs(heightOffset + coordinate.z)) % 3); } - + @Override void calculateSubcoordinates() { CoordinateUVWZ hex = (CoordinateUVWZ) coordinate; - + // Calculate coordinate of top center triangle. int x = 3 * (hex.u + radiusBounds) - 2 + (offset == 2 ? -1 : offset); int y = (hex.w - hex.v) + 2 * radiusBounds - 2 + (offset == 0 ? 0 : 1); int z = depthBounds + hex.z - 1; - + // Set coordinates of triangles clockwise from top center. for (int i = 0; i < NUM_SUBCOORDINATES; i++) { subcoordinates.add(i, new CoordinateXYZ(x + X_OFF[i], y + Y_OFF[i], z)); } } - + /** * {@inheritDoc} - *

- * Each direction of movement ({@code +u, -u, +v, -v, +w, -w, +z, -z}) is - * tracked by each bit within a byte. + * + *

Each direction of movement ({@code +u, -u, +v, -v, +w, -w, +z, -z}) is tracked by each bit + * within a byte. */ @Override void calculateChecks() { CoordinateUVWZ hex = (CoordinateUVWZ) coordinate; - check = (byte) ( - (hex.u == radius - 1 ? 0 : 1 << 7) - + (hex.u == 1 - radius ? 0 : 1 << 6) - + (hex.v == radius - 1 ? 0 : 1 << 5) - + (hex.v == 1 - radius ? 0 : 1 << 4) - + (hex.w == radius - 1 ? 0 : 1 << 3) - + (hex.w == 1 - radius ? 0 : 1 << 2) - + (hex.z == depth - 1 ? 0 : 1 << 1) - + (hex.z == 1 - depth ? 0 : 1 << 0)); + check = + (byte) + ((hex.u == radius - 1 ? 0 : 1 << 7) + + (hex.u == 1 - radius ? 0 : 1 << 6) + + (hex.v == radius - 1 ? 0 : 1 << 5) + + (hex.v == 1 - radius ? 0 : 1 << 4) + + (hex.w == radius - 1 ? 0 : 1 << 3) + + (hex.w == 1 - radius ? 0 : 1 << 2) + + (hex.z == depth - 1 ? 0 : 1 << 1) + + (hex.z == 1 - depth ? 0 : 1 << 0)); } - + /** * {@inheritDoc} - *

- * Estimates the perimeter of cell occupying the hexagonal location. Volume - * fraction used to take fraction of the perimeter of the hexagon. If - * fraction is not 1 (i.e. at least two cells in the location), then two - * additional inner segments are added. + * + *

Estimates the perimeter of cell occupying the hexagonal location. Volume fraction used to + * take fraction of the perimeter of the hexagon. If fraction is not 1 (i.e. at least two cells + * in the location), then two additional inner segments are added. */ @Override public double getPerimeter(double f) { return f * HEX_PERIMETER + (f == 1 ? 0 : 2 * HEX_SIDE); } - + /** * {@inheritDoc} - *

- * We check if a neighbor location is valid by comparing the movement checks - * byte with the neighbor location byte. Neighbor list includes the current - * location. + * + *

We check if a neighbor location is valid by comparing the movement checks byte with the + * neighbor location byte. Neighbor list includes the current location. */ @Override public ArrayList getNeighbors() { CoordinateUVWZ hex = (CoordinateUVWZ) coordinate; ArrayList neighbors = new ArrayList<>(MOVES.length + 1); byte b; - + // Add neighbor locations. for (int i = 0; i < MOVES.length; i++) { // Adjust byte for vertical offset. @@ -223,49 +237,49 @@ public ArrayList getNeighbors() { } else { b = MOVES[i]; } - + // Add location if possible to move there. if ((b & check ^ b) == 0) { - neighbors.add(new PatchLocationHex( - hex.u + (b >> 7 & 1) - (b >> 6 & 1), - hex.v + (b >> 5 & 1) - (b >> 4 & 1), - hex.w + (b >> 3 & 1) - (b >> 2 & 1), - hex.z + (b >> 1 & 1) - (b >> 0 & 1) - )); + neighbors.add( + new PatchLocationHex( + hex.u + (b >> 7 & 1) - (b >> 6 & 1), + hex.v + (b >> 5 & 1) - (b >> 4 & 1), + hex.w + (b >> 3 & 1) - (b >> 2 & 1), + hex.z + (b >> 1 & 1) - (b >> 0 & 1))); } } - + // Add current location. neighbors.add(new PatchLocationHex(hex)); - + return neighbors; } - + @Override public LocationContainer convert(int id) { return new PatchLocationContainer(id, coordinate); } - + /** - * Converts triangular {@link arcade.core.env.lattice.Lattice} coordinates - * into a hexagonal {@link arcade.core.env.grid.Grid} coordinate. + * Converts triangular {@link arcade.core.env.lattice.Lattice} coordinates into a hexagonal + * {@link arcade.core.env.grid.Grid} coordinate. * - * @param coordinate the triangular coordinate - * @return the corresponding hexagonal coordinate + * @param coordinate the triangular coordinate + * @return the corresponding hexagonal coordinate */ public static CoordinateUVWZ translate(CoordinateXYZ coordinate) { int z = coordinate.z - depthBounds + 1; int zo = (byte) ((Math.abs(heightOffset + z)) % 3); - + // Calculate u coordinate. double uu = (coordinate.x - (zo == 2 ? -1 : zo) + 2) / 3.0 - radiusBounds; int u = Math.round(Math.round(uu)); - + // Calculate v and w coordinates based on u. int vw = coordinate.y - 2 * radiusBounds + 2 - (zo == 0 ? 0 : 1); int v = -(int) Math.floor((vw + u) / 2.0); int w = -(u + v); - + // Check if out of bounds. if (Math.abs(v) >= radius || Math.abs(w) >= radius) { return null; diff --git a/src/arcade/patch/env/location/PatchLocationRect.java b/src/arcade/patch/env/location/PatchLocationRect.java index 2863ba39a..527fba4f5 100644 --- a/src/arcade/patch/env/location/PatchLocationRect.java +++ b/src/arcade/patch/env/location/PatchLocationRect.java @@ -6,14 +6,14 @@ import arcade.patch.sim.PatchSeries; /** - * Concrete implementation of {@link PatchLocation} for rectangular - * {@link arcade.core.env.grid.Grid} to a rectangular - * {@link arcade.core.env.lattice.Lattice}. - *

- * {@link arcade.core.env.grid.Grid} coordinates are in terms of (x, y) and the - * {@link arcade.core.env.lattice.Lattice} coordinates are in (a, b). - * Rectangular {@link arcade.core.env.lattice.Lattice} subcoordinates are - * ordered 0 - 3, with 0 at the top left and going clockwise around. + * Concrete implementation of {@link PatchLocation} for rectangular {@link + * arcade.core.env.grid.Grid} to a rectangular {@link arcade.core.env.lattice.Lattice}. + * + *

{@link arcade.core.env.grid.Grid} coordinates are in terms of (x, y) and the {@link + * arcade.core.env.lattice.Lattice} coordinates are in (a, b). Rectangular {@link + * arcade.core.env.lattice.Lattice} subcoordinates are ordered 0 - 3, with 0 at the top left and + * going clockwise around. + * *

  *     ---------
  *     | 0 | 1 |
@@ -21,117 +21,133 @@
  *     | 2 | 3 |
  *     ---------
  * 
- * For simulations with {@code DEPTH} > 0 (3D simulations), each the - * rectangular grid is offset in relative to the rectangular lattice. Therefore, - * each cell in a location has four neighboring locations in the same layer, - * four neighboring locations in the layer above, and four neighboring locations - * in the layer below. Simulations with {@code DEPTH} > 1 must have a - * {@code MARGIN} > 0, otherwise the offset location coordinates will be - * associated with lattice coordinates that are out of bounds of the array. + * + * For simulations with {@code DEPTH} > 0 (3D simulations), each the rectangular grid is offset + * in relative to the rectangular lattice. Therefore, each cell in a location has four neighboring + * locations in the same layer, four neighboring locations in the layer above, and four neighboring + * locations in the layer below. Simulations with {@code DEPTH} > 1 must have a {@code MARGIN} + * > 0, otherwise the offset location coordinates will be associated with lattice coordinates + * that are out of bounds of the array. */ - public final class PatchLocationRect extends PatchLocation { /** Size of rectangle patch from side to side [um]. */ private static final double RECT_SIZE = 30.0; - + /** Height of rectangle patch [um]. */ private static final double RECT_DEPTH = 8.7; - + /** Perimeter of rectangle patch [um]. */ private static final double RECT_PERIMETER = 4 * RECT_SIZE; - + /** Area of rectangle patch [um2]. */ private static final double RECT_AREA = RECT_SIZE * RECT_SIZE; - + /** Surface area of rectangle patch [um2]. */ private static final double RECT_SURFACE = 2 * RECT_AREA + RECT_DEPTH * RECT_PERIMETER; - + /** Volume of rectangle patch [um3]. */ private static final double RECT_VOLUME = RECT_AREA * RECT_DEPTH; - + /** Ratio of rectangle location height to size. */ private static final double RECT_RATIO = RECT_DEPTH / RECT_SIZE; - + /** Size of the subrectangle position [um]. */ private static final double SUBRECT_SIZE = RECT_SIZE / 2.0; - + /** Number of rectangular subcoordinates. */ private static final int NUM_SUBCOORDINATES = 4; - + /** Relative rectangular subcoordinate offsets in the x direction. */ - private static final byte[] X_OFF = new byte[] { 0, 1, 0, 1 }; - + private static final byte[] X_OFF = new byte[] {0, 1, 0, 1}; + /** Relative rectangular subcoordinate offsets in the y direction. */ - private static final byte[] Y_OFF = new byte[] { 0, 0, 1, 1 }; - + private static final byte[] Y_OFF = new byte[] {0, 0, 1, 1}; + /** List of relative rectangular neighbor locations. */ - private static final byte[] MOVES = new byte[] { - (byte) Integer.parseInt("00001000", 2), // up - (byte) Integer.parseInt("00000100", 2), // down - (byte) Integer.parseInt("00100000", 2), // right - (byte) Integer.parseInt("00010000", 2), // left - (byte) Integer.parseInt("00000010", 2), // vert up - (byte) Integer.parseInt("00000001", 2), // vert down - (byte) Integer.parseInt("00010010", 2), // vert up clockwise 1 - (byte) Integer.parseInt("00010110", 2), // vert up clockwise 2 - (byte) Integer.parseInt("00000110", 2), // vert up clockwise 3 - (byte) Integer.parseInt("00010001", 2), // vert down clockwise 1 - (byte) Integer.parseInt("00010101", 2), // vert down clockwise 2 - (byte) Integer.parseInt("00000101", 2), // vert down clockwise 3 - }; - + private static final byte[] MOVES = + new byte[] { + (byte) Integer.parseInt("00001000", 2), // up + (byte) Integer.parseInt("00000100", 2), // down + (byte) Integer.parseInt("00100000", 2), // right + (byte) Integer.parseInt("00010000", 2), // left + (byte) Integer.parseInt("00000010", 2), // vert up + (byte) Integer.parseInt("00000001", 2), // vert down + (byte) Integer.parseInt("00010010", 2), // vert up clockwise 1 + (byte) Integer.parseInt("00010110", 2), // vert up clockwise 2 + (byte) Integer.parseInt("00000110", 2), // vert up clockwise 3 + (byte) Integer.parseInt("00010001", 2), // vert down clockwise 1 + (byte) Integer.parseInt("00010101", 2), // vert down clockwise 2 + (byte) Integer.parseInt("00000101", 2), // vert down clockwise 3 + }; + /** * Creates a {@code PatchLocationRect} object for given coordinates. * - * @param x the coordinate in x direction - * @param y the coordinate in y direction - * @param z the coordinate in z direction + * @param x the coordinate in x direction + * @param y the coordinate in y direction + * @param z the coordinate in z direction */ public PatchLocationRect(int x, int y, int z) { this(new CoordinateXYZ(x, y, z)); } - + /** * Creates a {@code PatchLocationRect} object at given coordinate. * - * @param coordinate the patch coordinate + * @param coordinate the patch coordinate */ public PatchLocationRect(CoordinateXYZ coordinate) { super(coordinate, NUM_SUBCOORDINATES); } - + @Override - public double getVolume() { return RECT_VOLUME; } - + public double getVolume() { + return RECT_VOLUME; + } + @Override - public double getSurface() { return RECT_SURFACE; } - + public double getSurface() { + return RECT_SURFACE; + } + @Override - public double getHeight() { return RECT_DEPTH; } - + public double getHeight() { + return RECT_DEPTH; + } + @Override - public double getArea() { return RECT_AREA; } - + public double getArea() { + return RECT_AREA; + } + @Override - public double getCoordinateSize() { return RECT_SIZE; } - + public double getCoordinateSize() { + return RECT_SIZE; + } + @Override - public double getSubcoordinateSize() { return SUBRECT_SIZE; } - + public double getSubcoordinateSize() { + return SUBRECT_SIZE; + } + @Override - public double getRatio() { return RECT_RATIO; } - + public double getRatio() { + return RECT_RATIO; + } + @Override - public int getMaximum() { return NUM_SUBCOORDINATES; } - + public int getMaximum() { + return NUM_SUBCOORDINATES; + } + /** * Updates static configuration variables. - *

- * Environment sizes are not set until the simulation series is created. - * Calculations for coordinates depend on these sizes, so the - * {@code Location} needs to be updated based on the series configuration. * - * @param series the current simulation series + *

Environment sizes are not set until the simulation series is created. Calculations for + * coordinates depend on these sizes, so the {@code Location} needs to be updated based on the + * series configuration. + * + * @param series the current simulation series */ public static void updateConfigs(PatchSeries series) { radius = series.radius; @@ -140,71 +156,70 @@ public static void updateConfigs(PatchSeries series) { depthBounds = series.depthBounds; heightOffset = series.height % 2 - series.height; } - + @Override void calculateOffset() { offset = (byte) (Math.abs(heightOffset + coordinate.z) % 2); } - + @Override void calculateSubcoordinates() { CoordinateXYZ rect = (CoordinateXYZ) coordinate; - + // Calculate coordinate of top right subrectangle. int x = 2 * (rect.x + radiusBounds - 1) + offset; int y = 2 * (rect.y + radiusBounds - 1) + offset; int z = depthBounds + rect.z - 1; - + // Set coordinates of subrectangles clockwise from top left. for (int i = 0; i < NUM_SUBCOORDINATES; i++) { subcoordinates.add(i, new CoordinateXYZ(x + X_OFF[i], y + Y_OFF[i], z)); } } - + /** * {@inheritDoc} - *

- * Each direction of movement ({@code +x, -x, +y, -y, +z, -z}) is tracked by - * each bit within a byte. + * + *

Each direction of movement ({@code +x, -x, +y, -y, +z, -z}) is tracked by each bit within + * a byte. */ @Override void calculateChecks() { CoordinateXYZ rect = (CoordinateXYZ) coordinate; - check = (byte) ( - (rect.x == radius - 1 ? 0 : 1 << 5) - + (rect.x == 1 - radius ? 0 : 1 << 4) - + (rect.y == radius - 1 ? 0 : 1 << 3) - + (rect.y == 1 - radius ? 0 : 1 << 2) - + (rect.z == depth - 1 ? 0 : 1 << 1) - + (rect.z == 1 - depth ? 0 : 1 << 0)); + check = + (byte) + ((rect.x == radius - 1 ? 0 : 1 << 5) + + (rect.x == 1 - radius ? 0 : 1 << 4) + + (rect.y == radius - 1 ? 0 : 1 << 3) + + (rect.y == 1 - radius ? 0 : 1 << 2) + + (rect.z == depth - 1 ? 0 : 1 << 1) + + (rect.z == 1 - depth ? 0 : 1 << 0)); } - + /** * {@inheritDoc} - *

- * Estimates the perimeter of cell occupying the rectangular location. - * Volume fraction used to take fraction of the perimeter of the rectangle. - * If fraction is not 1 (i.e. at least two cells in the location), then an - * additional inner segment is added. + * + *

Estimates the perimeter of cell occupying the rectangular location. Volume fraction used + * to take fraction of the perimeter of the rectangle. If fraction is not 1 (i.e. at least two + * cells in the location), then an additional inner segment is added. */ @Override public double getPerimeter(double f) { return f * RECT_PERIMETER + (f == 1 ? 0 : RECT_SIZE); } - + /** * {@inheritDoc} - *

- * We check if a neighbor location is valid by comparing the movement checks - * byte with the neighbor location byte. Neighbor list includes the current - * location. + * + *

We check if a neighbor location is valid by comparing the movement checks byte with the + * neighbor location byte. Neighbor list includes the current location. */ @Override public ArrayList getNeighbors() { CoordinateXYZ rect = (CoordinateXYZ) coordinate; ArrayList neighbors = new ArrayList<>(MOVES.length + 1); byte b; - + // Add neighbor locations. for (int i = 0; i < MOVES.length; i++) { // Adjust byte for vertical offset. @@ -213,45 +228,45 @@ public ArrayList getNeighbors() { } else { b = MOVES[i]; } - + // Add location if possible to move there. if ((b & check ^ b) == 0) { - neighbors.add(new PatchLocationRect( - rect.x + (b >> 5 & 1) - (b >> 4 & 1), - rect.y + (b >> 3 & 1) - (b >> 2 & 1), - rect.z + (b >> 1 & 1) - (b >> 0 & 1)) - ); + neighbors.add( + new PatchLocationRect( + rect.x + (b >> 5 & 1) - (b >> 4 & 1), + rect.y + (b >> 3 & 1) - (b >> 2 & 1), + rect.z + (b >> 1 & 1) - (b >> 0 & 1))); } } - + // Add current location. neighbors.add(new PatchLocationRect(rect)); - + return neighbors; } - + @Override public LocationContainer convert(int id) { return new PatchLocationContainer(id, coordinate); } - + /** - * Converts rectangular {@link arcade.core.env.lattice.Lattice} coordinates - * into a rectangular {@link arcade.core.env.grid.Grid} coordinate. + * Converts rectangular {@link arcade.core.env.lattice.Lattice} coordinates into a rectangular + * {@link arcade.core.env.grid.Grid} coordinate. * - * @param coordinate the rectangular coordinate - * @return the corresponding rectangular coordinate + * @param coordinate the rectangular coordinate + * @return the corresponding rectangular coordinate */ public static CoordinateXYZ translate(CoordinateXYZ coordinate) { int z = coordinate.z - depthBounds + 1; int zo = (byte) (Math.abs(heightOffset + z) % 2); - + // Calculate a and b coordinates double xx = (coordinate.x - zo) / 2.0 + 1 - radiusBounds; int x = (int) Math.floor(xx); double yy = (coordinate.y - zo) / 2.0 + 1 - radiusBounds; int y = (int) Math.floor(yy); - + // Check if out of bounds. if (Math.abs(x) >= radius || Math.abs(y) >= radius) { return null; diff --git a/src/arcade/patch/env/operation/PatchOperation.java b/src/arcade/patch/env/operation/PatchOperation.java index 8f8b25ee0..568d4b5b1 100644 --- a/src/arcade/patch/env/operation/PatchOperation.java +++ b/src/arcade/patch/env/operation/PatchOperation.java @@ -3,35 +3,31 @@ import arcade.core.env.operation.Operation; import arcade.patch.env.lattice.PatchLattice; -/** - * Abstract implementation of {@link Operation} for {@link PatchLattice} - * environments. - */ - +/** Abstract implementation of {@link Operation} for {@link PatchLattice} environments. */ public abstract class PatchOperation implements Operation { /** The {@link PatchLattice} the operation is associated with. */ final PatchLattice lattice; - + /** 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 an operation for a {@link PatchLattice} category. * - * @param lattice the {@link PatchLattice} the operation is associated with + * @param lattice the {@link PatchLattice} the operation is associated with */ public PatchOperation(PatchLattice lattice) { // Get sizing. latticeLength = lattice.getLength(); latticeWidth = lattice.getWidth(); latticeHeight = lattice.getHeight(); - + // Set lattices. this.lattice = lattice; } diff --git a/src/arcade/patch/env/operation/PatchOperationDiffuser.java b/src/arcade/patch/env/operation/PatchOperationDiffuser.java index 4fc4f7560..dd22beac5 100644 --- a/src/arcade/patch/env/operation/PatchOperationDiffuser.java +++ b/src/arcade/patch/env/operation/PatchOperationDiffuser.java @@ -9,86 +9,85 @@ /** * Extension of {@link PatchOperation} for diffusion. - *

- * Operation calculates diffusion of concentrations using finite difference - * approximation with given {@code DIFFUSIVITY}. The calculation is repeated per - * second (model tick is one minute). Methods are written to work regardless of - * underlying geometry. Methods extending this operation for a specific geometry - * will need to adjust the multipliers for both the finite difference + * + *

Operation calculates diffusion of concentrations using finite difference approximation with + * given {@code DIFFUSIVITY}. The calculation is repeated per second (model tick is one minute). + * Methods are written to work regardless of underlying geometry. Methods extending this operation + * for a specific geometry will need to adjust the multipliers for both the finite difference * approximation and the pseudo-steady state approximation. */ - public abstract class PatchOperationDiffuser extends PatchOperation { /** Array holding current concentration values. */ public final double[][][] latticeCurrent; - + /** Array holding new concentration values. */ public final double[][][] latticeNew; - + /** Dimensionless rate of diffusion. */ double rate; - + /** Multiplier on axial concentrations. */ double alpha; - + /** Multiplier on previous concentration. */ double beta; - + /** {@code 0} if pseudo-steady state, {@code false} otherwise. */ int adjust; - + /** Diffusivity of molecule [um2/s]. */ final double diffusivity; - + /** Border array for left border (x direction). */ final byte[] leftBorder; - + /** Border array for right border (x direction). */ final byte[] rightBorder; - + /** Border array for top border (y direction). */ final byte[] topBorder; - + /** Border array for bottom border (y direction). */ final byte[] bottomBorder; - + /** Border array for up border (z direction). */ final byte[] upBorder; - + /** Border array for down border (z direction). */ final byte[] downBorder; - + /** * Creates a diffuser {@link PatchOperation} for the given lattice. - *

- * Six border arrays are used to check if an index is located at the - * right/left ({@code LENGTH}, x axis), top/bottom ({@code WIDTH}, y axis), - * and up/down ({@code HEIGHT}, z axis) directions. - *

- * Loaded parameters include: + * + *

Six border arrays are used to check if an index is located at the right/left ({@code + * LENGTH}, x axis), top/bottom ({@code WIDTH}, y axis), and up/down ({@code HEIGHT}, z axis) + * directions. + * + *

Loaded parameters include: + * *

    - *
  • {@code DIFFUSIVITY} = diffusivity of molecule
  • + *
  • {@code DIFFUSIVITY} = diffusivity of molecule *
* - * @param lattice the {@link PatchLattice} the operation is associated with + * @param lattice the {@link PatchLattice} the operation is associated with */ public PatchOperationDiffuser(PatchLattice lattice) { super(lattice); - + // Get diffuser parameters. MiniBox parameters = lattice.getParameters(); diffusivity = parameters.getDouble("diffuser/DIFFUSIVITY"); - + // Set lattice fields. this.latticeCurrent = lattice.getField(); - + if (lattice.getOperation(Category.GENERATOR) != null) { Operation generator = lattice.getOperation(Category.GENERATOR); this.latticeNew = ((PatchOperationGenerator) generator).latticePrevious; } else { this.latticeNew = new double[latticeHeight][latticeLength][latticeWidth]; } - + // Set up border arrays for up and down (z direction). upBorder = new byte[latticeHeight]; downBorder = new byte[latticeHeight]; @@ -96,7 +95,7 @@ public PatchOperationDiffuser(PatchLattice lattice) { upBorder[k] = (byte) (k == latticeHeight - 1 ? 0 : 1); downBorder[k] = (byte) (k == 0 ? 0 : 1); } - + // Set up border arrays for left and right (x direction). leftBorder = new byte[latticeLength]; rightBorder = new byte[latticeLength]; @@ -104,7 +103,7 @@ public PatchOperationDiffuser(PatchLattice lattice) { leftBorder[i] = (byte) (i == 0 ? 0 : 1); rightBorder[i] = (byte) (i == latticeLength - 1 ? 0 : 1); } - + // Set up border arrays for top and bottom (y direction). topBorder = new byte[latticeWidth]; bottomBorder = new byte[latticeWidth]; @@ -113,17 +112,17 @@ public PatchOperationDiffuser(PatchLattice lattice) { bottomBorder[j] = (byte) (j == latticeWidth - 1 ? 0 : 1); } } - + /** * Calculate the sum of neighboring locations in 2D plane. * - * @param i the coordinate in the x axis - * @param j the coordinate in the y axis - * @param field the 2D concentration field - * @return the total concentration in the neighboring locations + * @param i the coordinate in the x axis + * @param j the coordinate in the y axis + * @param field the 2D concentration field + * @return the total concentration in the neighboring locations */ abstract double calcSum(int i, int j, double[][] field); - + @Override public void step(MersenneTwisterFast random, Simulation sim) { if (latticeHeight == 1) { @@ -132,16 +131,14 @@ public void step(MersenneTwisterFast random, Simulation sim) { step3D(); } } - - /** - * Steps the diffuser for 2D simulations. - */ + + /** Steps the diffuser for 2D simulations. */ private void step2D() { double[][] latticeCurrentLayer = latticeCurrent[0]; double[][] latticeNewLayer = latticeNew[0]; double oldConc; double sumConc; - + for (int step = 0; step < 60; step++) { for (int i = 0; i < latticeLength; i++) { for (int j = 0; j < latticeWidth; j++) { @@ -150,43 +147,41 @@ private void step2D() { latticeNewLayer[i][j] = rate * (sumConc - beta * oldConc) + oldConc; } } - + // Set grid values to new grid. lattice.setField(latticeNewLayer, 0); } } - - /** - * Steps the diffuser for 3D simulations. - */ + + /** Steps the diffuser for 3D simulations. */ private void step3D() { double oldConc; double sumConc; int up; int down; - + // Update concentration in each location with step size of 1 second. for (int step = 0; step < 60; step++) { for (int k = 0; k < latticeHeight; k++) { up = k + upBorder[k]; down = k - downBorder[k]; - + for (int i = 0; i < latticeLength; i++) { for (int j = 0; j < latticeWidth; j++) { oldConc = latticeCurrent[k][i][j] * adjust; sumConc = calcSum(i, j, latticeCurrent[k]); - + // Add in up and down neighbors for 3D case. Check if // located at the up (for up) and down (for down) side // of the environment. Includes multiplier since dz =/= dx = dy. sumConc += latticeCurrent[up][i][j] * alpha; sumConc += latticeCurrent[down][i][j] * alpha; - + latticeNew[k][i][j] = rate * (sumConc - beta * oldConc) + oldConc; } } } - + // Set grid values to new grid. lattice.setField(latticeNew); } diff --git a/src/arcade/patch/env/operation/PatchOperationDiffuserRect.java b/src/arcade/patch/env/operation/PatchOperationDiffuserRect.java index db36b1589..02efa2c7b 100644 --- a/src/arcade/patch/env/operation/PatchOperationDiffuserRect.java +++ b/src/arcade/patch/env/operation/PatchOperationDiffuserRect.java @@ -2,31 +2,27 @@ import arcade.patch.env.lattice.PatchLattice; -/** - * Extension of {@link PatchOperationDiffuser} for rectangular lattices. - */ - +/** Extension of {@link PatchOperationDiffuser} for rectangular lattices. */ public class PatchOperationDiffuserRect extends PatchOperationDiffuser { /** * Creates a {@link PatchOperationDiffuser} for rectangular lattices. - *

- * Constructor calculates rate and multipliers for diffusion on the - * rectangular lattice given diffusivity of the molecule. If the finite - * different approximation is not stable, the multipliers are adjusted to - * use a pseudo-steady state approximation. * - * @param lattice the {@link PatchLattice} the operation is associated with - * @param ds the spatial scaling (x and y directions) - * @param dz the spatial scaling (z direction) + *

Constructor calculates rate and multipliers for diffusion on the rectangular lattice given + * diffusivity of the molecule. If the finite different approximation is not stable, the + * multipliers are adjusted to use a pseudo-steady state approximation. + * + * @param lattice the {@link PatchLattice} the operation is associated with + * @param ds the spatial scaling (x and y directions) + * @param dz the spatial scaling (z direction) */ public PatchOperationDiffuserRect(PatchLattice lattice, double ds, double dz) { super(lattice); - + // Calculate dimensionless rate and various multipliers. rate = (diffusivity) / (ds * ds); alpha = (latticeHeight > 1 ? (2 * ds * ds) / (dz * dz) : 0); beta = 4 + 2 * alpha; - + // Determine if solution is stable. If no, adjust for pseudo-steady. double lambda = rate * beta; if (lambda >= 1 | lambda < 0) { @@ -36,7 +32,7 @@ public PatchOperationDiffuserRect(PatchLattice lattice, double ds, double dz) { adjust = 1; } } - + @Override public double calcSum(int i, int j, double[][] field) { // Calculate sum of concentrations of four neighbors. First add left, diff --git a/src/arcade/patch/env/operation/PatchOperationDiffuserTri.java b/src/arcade/patch/env/operation/PatchOperationDiffuserTri.java index 0eda86688..6adeb8585 100644 --- a/src/arcade/patch/env/operation/PatchOperationDiffuserTri.java +++ b/src/arcade/patch/env/operation/PatchOperationDiffuserTri.java @@ -4,39 +4,36 @@ /** * Extension of {@link PatchOperationDiffuser} for triangular lattices. - *

- * Operation also check if the triangle is pointed up or down based on the row - * and column, where the top left of the 2D array at coordinate (0,0) is a - * triangle pointing down. + * + *

Operation also check if the triangle is pointed up or down based on the row and column, where + * the top left of the 2D array at coordinate (0,0) is a triangle pointing down. */ - public class PatchOperationDiffuserTri extends PatchOperationDiffuser { /** Orientation array for triangular geometry. */ private final byte[][] direction; - + /** * Creates a {@link PatchOperationDiffuser} for triangular lattices. - *

- * Constructor calculates rate and multipliers for diffusion on the - * triangular lattice given diffusivity of the molecule. If the finite - * different approximation is not stable, the multipliers are adjusted to - * use a pseudo-steady state approximation. - *

- * The constructor also initializes an orientation lattice indicating which - * direction the triangles are facing. * - * @param lattice the {@link PatchLattice} the operation is associated with - * @param ds the spatial scaling (x and y directions) - * @param dz the spatial scaling (z direction) + *

Constructor calculates rate and multipliers for diffusion on the triangular lattice given + * diffusivity of the molecule. If the finite different approximation is not stable, the + * multipliers are adjusted to use a pseudo-steady state approximation. + * + *

The constructor also initializes an orientation lattice indicating which direction the + * triangles are facing. + * + * @param lattice the {@link PatchLattice} the operation is associated with + * @param ds the spatial scaling (x and y directions) + * @param dz the spatial scaling (z direction) */ public PatchOperationDiffuserTri(PatchLattice lattice, double ds, double dz) { super(lattice); - + // Calculate dimensionless rate and various multipliers. rate = (4 * diffusivity) / (3 * ds * ds); alpha = (latticeHeight > 1 ? (3 * ds * ds) / (2 * dz * dz) : 0); beta = 3 + 2 * alpha; - + // Determine if solution is stable. If no, adjust for pseudo-steady. double lambda = rate * beta; if (lambda >= 1 | lambda < 0) { @@ -45,7 +42,7 @@ public PatchOperationDiffuserTri(PatchLattice lattice, double ds, double dz) { } else { adjust = 1; } - + // Create orientation lattice. direction = new byte[latticeLength][latticeWidth]; for (int i = 0; i < latticeLength; i++) { @@ -59,7 +56,7 @@ public PatchOperationDiffuserTri(PatchLattice lattice, double ds, double dz) { } } } - + @Override public double calcSum(int i, int j, double[][] field) { // Calculate sum of concentrations of three neighbors. First add left @@ -68,10 +65,10 @@ public double calcSum(int i, int j, double[][] field) { double sumConc = 0; sumConc += field[i - leftBorder[i]][j]; sumConc += field[i + rightBorder[i]][j]; - + // Add top or bottom neighbor, depending on orientation. sumConc += field[i][j + direction[i][j]]; - + return sumConc; } } diff --git a/src/arcade/patch/env/operation/PatchOperationGenerator.java b/src/arcade/patch/env/operation/PatchOperationGenerator.java index 11a16804f..452bee547 100644 --- a/src/arcade/patch/env/operation/PatchOperationGenerator.java +++ b/src/arcade/patch/env/operation/PatchOperationGenerator.java @@ -9,53 +9,52 @@ /** * Extension of {@link PatchOperation} for generation. - *

- * Operation updates the associated lattice field with values provided in the - * delta array for a molecule with given {@code CONCENTRATION} and - * {@code PERMEABILITY}. The delta array defaults to zero (no changes to lattice - * field) and can be modified by external classes. Operation is independent of - * underlying geometry. + * + *

Operation updates the associated lattice field with values provided in the delta array for a + * molecule with given {@code CONCENTRATION} and {@code PERMEABILITY}. The delta array defaults to + * zero (no changes to lattice field) and can be modified by external classes. Operation is + * independent of underlying geometry. */ - public class PatchOperationGenerator extends PatchOperation { /** Array holding current concentration values. */ public final double[][][] latticeCurrent; - + /** Array holding previous concentration values. */ public final double[][][] latticePrevious; - + /** Array holding changes in concentration values. */ public final double[][][] latticeDelta; - + /** Maximum concentration. */ public final double concentration; - + /** Molecule permeability. */ public final double permeability; - + /** * Creates a generator {@link PatchOperation} for the given lattice. - *

- * Loaded parameters include: + * + *

Loaded parameters include: + * *

    - *
  • {@code CONCENTRATION} = maximum concentration
  • - *
  • {@code PERMEABILITY} = molecule permeability
  • + *
  • {@code CONCENTRATION} = maximum concentration + *
  • {@code PERMEABILITY} = molecule permeability *
* - * @param lattice the {@link PatchLattice} the operation is associated with + * @param lattice the {@link PatchLattice} the operation is associated with */ public PatchOperationGenerator(PatchLattice lattice) { super(lattice); - + // Get generator parameters. MiniBox parameters = lattice.getParameters(); concentration = parameters.getDouble("generator/CONCENTRATION"); permeability = parameters.getDouble("generator/PERMEABILITY"); - + // Set lattice field. this.latticeCurrent = lattice.getField(); this.latticeDelta = new double[latticeHeight][latticeLength][latticeWidth]; - + if (lattice.getOperation(Category.DIFFUSER) != null) { Operation diffuser = lattice.getOperation(Category.DIFFUSER); this.latticePrevious = ((PatchOperationDiffuser) diffuser).latticeNew; @@ -63,7 +62,7 @@ public PatchOperationGenerator(PatchLattice lattice) { this.latticePrevious = new double[latticeHeight][latticeLength][latticeWidth]; } } - + @Override public void step(MersenneTwisterFast random, Simulation sim) { for (int k = 0; k < latticeHeight; k++) { diff --git a/src/arcade/patch/parameter.patch.xml b/src/arcade/patch/parameter.patch.xml index 48b1d4556..4c64a22bc 100644 --- a/src/arcade/patch/parameter.patch.xml +++ b/src/arcade/patch/parameter.patch.xml @@ -2,19 +2,17 @@ - + - + + - + - - - - - - + + + @@ -22,16 +20,16 @@ - + - + - + - + @@ -50,67 +48,67 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/src/arcade/patch/sim/PatchSeries.java b/src/arcade/patch/sim/PatchSeries.java index 7711e59bf..861002b09 100644 --- a/src/arcade/patch/sim/PatchSeries.java +++ b/src/arcade/patch/sim/PatchSeries.java @@ -8,43 +8,40 @@ import arcade.core.util.MiniBox; import static arcade.core.util.MiniBox.TAG_SEPARATOR; -/** - * Simulation manager for {@link PatchSimulation} instances. - */ - +/** Simulation manager for {@link PatchSimulation} instances. */ public final class PatchSeries extends Series { /** Map of patch settings. */ public MiniBox patch; - + /** Radius of the simulation. */ public final int radius; - + /** Depth of the simulation. */ public final int depth; - + /** Overall radius of the simulation (equal to RADIUS + MARGIN). */ public final int radiusBounds; - - /** - * Overall height of the simulation (equal to 1 if DEPTH = 1, or DEPTH + - * MARGIN otherwise). - */ + + /** Overall height of the simulation (equal to 1 if DEPTH = 1, or DEPTH + MARGIN otherwise). */ public final int depthBounds; - + /** * Creates a {@code Series} object given setup information parsed from XML. * - * @param setupDicts the map of attribute to value for single instance tags - * @param setupLists the map of attribute to value for multiple instance tags - * @param path the path for simulation output - * @param parameters the default parameter values - * @param isVis {@code true} if visualized, {@code false} otherwise + * @param setupDicts the map of attribute to value for single instance tags + * @param setupLists the map of attribute to value for multiple instance tags + * @param path the path for simulation output + * @param parameters the default parameter values + * @param isVis {@code true} if visualized, {@code false} otherwise */ - public PatchSeries(HashMap setupDicts, - HashMap> setupLists, - String path, Box parameters, boolean isVis) { + public PatchSeries( + HashMap setupDicts, + HashMap> setupLists, + String path, + Box parameters, + boolean isVis) { super(setupDicts, setupLists, path, parameters, isVis); - + // Set sizing. MiniBox series = setupDicts.get("series"); this.radius = series.getInt("radius"); @@ -52,169 +49,208 @@ public PatchSeries(HashMap setupDicts, this.radiusBounds = series.getInt("radiusBounds"); this.depthBounds = series.getInt("depthBounds"); } - + @Override protected String getSimClass() { String geometry = patch.get("GEOMETRY").equalsIgnoreCase("HEX") ? "Hex" : "Rect"; return "arcade.patch.sim.PatchSimulation" + geometry; } - + @Override protected String getVisClass() { return "arcade.patch.vis.PatchVisualization"; } - + /** * Initializes series simulation, agents, and environment. * - * @param setupLists the map of attribute to value for multiple instance tags - * @param parameters the default parameter values loaded from {@code parameter.xml} + * @param setupLists the map of attribute to value for multiple instance tags + * @param parameters the default parameter values loaded from {@code parameter.xml} */ @Override protected void initialize(HashMap> setupLists, Box parameters) { // Initialize populations. MiniBox populationDefaults = parameters.getIdValForTag("POPULATION"); + MiniBox populationConversions = parameters.getIdValForTagAtt("POPULATION", "conversion"); ArrayList populationsBox = setupLists.get("populations"); - updatePopulations(populationsBox, populationDefaults, null); - + updatePopulations(populationsBox, populationDefaults, populationConversions); + // Initialize layers. MiniBox layerDefaults = parameters.getIdValForTag("LAYER"); MiniBox layerConversions = parameters.getIdValForTagAtt("LAYER", "conversion"); ArrayList layersBox = setupLists.get("layers"); updateLayers(layersBox, layerDefaults, layerConversions); - + // Add actions. MiniBox actionDefaults = parameters.getIdValForTag("ACTION"); ArrayList actionsBox = setupLists.get("actions"); updateActions(actionsBox, actionDefaults); - + // Add components. MiniBox componentDefaults = parameters.getIdValForTag("COMPONENT"); ArrayList componentsBox = setupLists.get("components"); updateComponents(componentsBox, componentDefaults); - + // Initialize patch. MiniBox patchDefaults = parameters.getIdValForTag("PATCH"); ArrayList patchBox = setupLists.get("patch"); updatePatch(patchBox, patchDefaults); } - + /** * Configures patch model parameters. * - * @param patchBox the patch setup dictionary - * @param patchDefaults the dictionary of default patch parameters + * @param patchBox the patch setup dictionary + * @param patchDefaults the dictionary of default patch parameters */ void updatePatch(ArrayList patchBox, MiniBox patchDefaults) { this.patch = new MiniBox(); - + Box box = new Box(); if (patchBox != null && patchBox.size() == 1 && patchBox.get(0) != null) { box = patchBox.get(0); } - + // Get default parameters and any parameter tags. Box parameters = box.filterBoxByTag("PARAMETER"); MiniBox parameterValues = parameters.getIdValForTagAtt("PARAMETER", "value"); MiniBox parameterScales = parameters.getIdValForTagAtt("PARAMETER", "scale"); - + // Add in parameters. for (String parameter : patchDefaults.getKeys()) { - parseParameter(this.patch, parameter, patchDefaults.get(parameter), - parameterValues, parameterScales); + parseParameter( + this.patch, + parameter, + patchDefaults.get(parameter), + parameterValues, + parameterScales); } - + // Add in constants. MiniBox constants = box.getIdVal(); for (String constantKey : constants.getKeys()) { this.patch.put(constantKey, constants.get(constantKey)); } } - + @Override - protected void updatePopulations(ArrayList populationsBox, MiniBox populationDefaults, - MiniBox populationConversions) { + protected void updatePopulations( + ArrayList populationsBox, + MiniBox populationDefaults, + MiniBox populationConversions) { this.populations = new HashMap<>(); if (populationsBox == null) { return; } - + // Assign codes to each population. int code = 1; - + // Iterate through each setup dictionary to build population settings. for (Box box : populationsBox) { String id = box.getValue("id"); String populationClass = box.getValue("class"); - + // Create new population and update code. MiniBox population = new MiniBox(); population.put("CODE", code++); population.put("CLASS", populationClass); this.populations.put(id, population); - - // Add population init if given. If not given or invalid, set to zero. - int init = (isValidNumber(box, "init") - ? (int) Double.parseDouble(box.getValue("init")) : 0); - population.put("INIT", init); - + + // Add population init if given. If value ends with percentage (%), + // use the PERCENT initialization type instead of the COUNT + // initialization type. If not given or invalid, set to zero. + String initType = "COUNT"; + if (box.getValue("init") != null && box.getValue("init").endsWith("%")) { + box.add("init", box.getValue("init").replace("%", "")); + initType = "PERCENT"; + } + int init = + (isValidNumber(box, "init") + ? (int) Double.parseDouble(box.getValue("init")) + : 0); + population.put(initType, init); + // Get default parameters and any parameter adjustments. Box parameters = box.filterBoxByTag("PARAMETER"); MiniBox parameterValues = parameters.getIdValForTagAtt("PARAMETER", "value"); MiniBox parameterScales = parameters.getIdValForTagAtt("PARAMETER", "scale"); - + + // Apply conversion factors. + for (String convert : populationConversions.getKeys()) { + double conversion = parseConversion(populationConversions.get(convert), ds, dt); + if (parameterScales.contains(convert)) { + parameterScales.put(convert, parameterScales.getDouble(convert) * conversion); + } else { + parameterScales.put(convert, conversion); + } + } + // Add in parameters. Start with value (if given) or default (if not // given). Then apply any scaling. for (String parameter : populationDefaults.getKeys()) { - parseParameter(population, parameter, populationDefaults.get(parameter), - parameterValues, parameterScales); + parseParameter( + population, + parameter, + populationDefaults.get(parameter), + parameterValues, + parameterScales); } - + + // Get list of links, if valid. + MiniBox links = box.filterBoxByTag("LINK").getIdValForTagAtt("LINK", "weight"); + for (String link : links.getKeys()) { + population.put("(LINK)" + TAG_SEPARATOR + link, links.getDouble(link)); + } + // Extract process versions. Box processes = box.filterBoxByTag("PROCESS"); MiniBox processVersions = processes.getIdValForTagAtt("PROCESS", "version"); - for (String process : processes.getKeys()) { String version = processVersions.get(process); population.put("(PROCESS)" + TAG_SEPARATOR + process, version); } } } - + @Override - protected void updateLayers(ArrayList layersBox, MiniBox layerDefaults, - MiniBox layerConversions) { + protected void updateLayers( + ArrayList layersBox, MiniBox layerDefaults, MiniBox layerConversions) { this.layers = new HashMap<>(); if (layersBox == null) { return; } - + // Iterate through each setup dictionary to build layer settings. for (Box box : layersBox) { String id = box.getValue("id"); - + // Create new layer. MiniBox layer = new MiniBox(); this.layers.put(id, layer); - + // Get default parameters and any parameter adjustments. Box parameters = box.filterBoxByTag("PARAMETER"); MiniBox parameterValues = parameters.getIdValForTagAtt("PARAMETER", "value"); MiniBox parameterScales = parameters.getIdValForTagAtt("PARAMETER", "scale"); - + // Add in parameters. Start with value (if given) or default (if not // given). Then apply any scaling. for (String parameter : layerDefaults.getKeys()) { - parseParameter(layer, parameter, layerDefaults.get(parameter), - parameterValues, parameterScales); + parseParameter( + layer, + parameter, + layerDefaults.get(parameter), + parameterValues, + parameterScales); } - + // Apply conversion factors. for (String convert : layerConversions.getKeys()) { double conversion = parseConversion(layerConversions.get(convert), ds, dz, dt); layer.put(convert, layer.getDouble(convert) * conversion); } - + // Get list of operations. HashSet operations = box.filterTags("OPERATION"); for (String operation : operations) { @@ -222,39 +258,43 @@ protected void updateLayers(ArrayList layersBox, MiniBox layerDefaults, } } } - + @Override protected void updateActions(ArrayList actionsBox, MiniBox actionDefaults) { this.actions = new HashMap<>(); if (actionsBox == null) { return; } - + // Iterate through each setup dictionary to build action settings. for (Box box : actionsBox) { String id = box.getValue("id"); String actionClass = box.getValue("class").toLowerCase(); - + // Create new population and update code. MiniBox action = new MiniBox(); this.actions.put(id, action); - + // Filter defaults for parameters specific to action class. action.put("CLASS", actionClass); MiniBox actionClassDefaults = actionDefaults.filter(actionClass); - + // Get default parameters and any parameter adjustments. Box parameters = box.filterBoxByTag("PARAMETER"); MiniBox parameterValues = parameters.getIdValForTagAtt("PARAMETER", "value"); MiniBox parameterScales = parameters.getIdValForTagAtt("PARAMETER", "scale"); - + // Add in parameters. Start with value (if given) or default (if not // given). Then apply any scaling. for (String parameter : actionClassDefaults.getKeys()) { - parseParameter(action, parameter, actionClassDefaults.get(parameter), - parameterValues, parameterScales); + parseParameter( + action, + parameter, + actionClassDefaults.get(parameter), + parameterValues, + parameterScales); } - + // Add list of registered populations. HashSet registers = box.filterTags("REGISTER"); for (String register : registers) { @@ -262,39 +302,43 @@ protected void updateActions(ArrayList actionsBox, MiniBox actionDefaults) } } } - + @Override protected void updateComponents(ArrayList componentsBox, MiniBox componentDefaults) { this.components = new HashMap<>(); if (componentsBox == null) { return; } - + // Iterate through each setup dictionary to build component settings. for (Box box : componentsBox) { String id = box.getValue("id"); String componentClass = box.getValue("class").toLowerCase(); - + // Create new population and update code. MiniBox component = new MiniBox(); this.components.put(id, component); - + // Filter defaults for parameters specific to component class. component.put("CLASS", componentClass); MiniBox componentClassDefaults = componentDefaults.filter(componentClass); - + // Get default parameters and any parameter adjustments. Box parameters = box.filterBoxByTag("PARAMETER"); MiniBox parameterValues = parameters.getIdValForTagAtt("PARAMETER", "value"); MiniBox parameterScales = parameters.getIdValForTagAtt("PARAMETER", "scale"); - + // Add in parameters. Start with value (if given) or default (if not // given). Then apply any scaling. for (String parameter : componentClassDefaults.getKeys()) { - parseParameter(component, parameter, componentClassDefaults.get(parameter), - parameterValues, parameterScales); + parseParameter( + component, + parameter, + componentClassDefaults.get(parameter), + parameterValues, + parameterScales); } - + // Add list of registered layers. HashSet registers = box.filterTags("REGISTER"); for (String register : registers) { diff --git a/src/arcade/patch/sim/PatchSimulation.java b/src/arcade/patch/sim/PatchSimulation.java index 9b6505ad3..172cb3849 100644 --- a/src/arcade/patch/sim/PatchSimulation.java +++ b/src/arcade/patch/sim/PatchSimulation.java @@ -8,11 +8,13 @@ import arcade.core.agent.action.Action; import arcade.core.agent.cell.Cell; 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.Location; import arcade.core.env.location.LocationContainer; +import arcade.core.env.location.LocationFactory; import arcade.core.sim.Series; import arcade.core.sim.Simulation; import arcade.core.util.MiniBox; @@ -23,308 +25,329 @@ import arcade.patch.env.lattice.PatchLatticeFactory; import arcade.patch.env.location.PatchLocationFactory; -/** - * Abstract implementation for patch {@link Simulation} instances. - */ - +/** Abstract implementation for patch {@link Simulation} instances. */ public abstract class PatchSimulation extends SimState implements Simulation { /** {@link arcade.core.sim.Series} object containing this simulation. */ final PatchSeries series; - + /** Random number generator seed for this simulation. */ final int seed; - + /** {@link Grid} containing agents in the simulation. */ Grid grid; - + /** Map of {@link Lattice} objects in the simulation. */ HashMap lattices; - + /** Map of {@link Action} instances in the simulation. */ HashMap actions; - + /** Map of {@link Component} instances in the simulation. */ HashMap components; - + /** Cell ID tracker. */ int id; - + /** Location factory instance for the simulation. */ public final PatchLocationFactory locationFactory; - + /** Cell factory instance for the simulation. */ public final PatchCellFactory cellFactory; - + /** Lattice factory instance for the simulation. */ public final PatchLatticeFactory latticeFactory; - + /** * Simulation instance for a {@link Series} for given random seed. * - * @param seed the random seed for random number generator - * @param series the simulation series + * @param seed the random seed for random number generator + * @param series the simulation series */ public PatchSimulation(long seed, Series series) { super(seed); this.series = (PatchSeries) series; this.seed = (int) seed - Series.SEED_OFFSET; - + this.locationFactory = makeLocationFactory(); this.cellFactory = makeCellFactory(); this.latticeFactory = makeLatticeFactory(); } - + @Override - public final Series getSeries() { return series; } - + public final Series getSeries() { + return series; + } + @Override - public final Schedule getSchedule() { return schedule; } - + public final Schedule getSchedule() { + return schedule; + } + @Override - public final int getSeed() { return seed; } - + public final int getSeed() { + return seed; + } + @Override - public final int getID() { return ++id; } - + public final int getID() { + return ++id; + } + @Override public final ArrayList getCells() { ArrayList cellContainers = new ArrayList<>(); - + for (Object obj : grid.getAllObjects()) { Cell cell = (Cell) obj; cellContainers.add(cell.convert()); } - + return cellContainers; } - + @Override public final ArrayList getLocations() { ArrayList locationContainers = new ArrayList<>(); - + for (Object obj : grid.getAllObjects()) { Cell cell = (Cell) obj; locationContainers.add(cell.getLocation().convert(cell.getID())); } - + return locationContainers; } - + + @Override + public final CellFactory getCellFactory() { + return cellFactory; + } + + @Override + public final LocationFactory getLocationFactory() { + return locationFactory; + } + @Override - public final Grid getGrid() { return grid; } - + public final Grid getGrid() { + return grid; + } + @Override - public final Lattice getLattice(String key) { return lattices.get(key); } - + public final Lattice getLattice(String key) { + return lattices.get(key); + } + @Override - public final Action getAction(String key) { return actions.get(key); } - + public final Action getAction(String key) { + return actions.get(key); + } + @Override - public final Component getComponent(String key) { return components.get(key); } - + public final Component getComponent(String key) { + return components.get(key); + } + /** - * Called at the start of the simulation to set up agents and environment - * and schedule actions and components as needed. + * Called at the start of the simulation to set up agents and environment and schedule actions + * and components as needed. */ @Override public void start() { super.start(); - + // Reset id. id = 0; - + // Equip simulation to loader. if (series.loader != null) { series.loader.equip(this); } - + setupAgents(); setupEnvironment(); - + scheduleActions(); scheduleComponents(); - + // Equip simulation to saver and schedule. if (series.saver != null && !series.isVis) { series.saver.equip(this); doOutput(true); } } - - /** - * Called at the end of the simulation. - */ + + /** Called at the end of the simulation. */ @Override public void finish() { super.finish(); - + // Finalize saver. if (!series.isVis) { doOutput(false); } } - + /** * Creates a factory for locations. * - * @return a {@link Location} factory + * @return a {@link Location} factory */ public abstract PatchLocationFactory makeLocationFactory(); - + /** * Creates a factory for cells. * - * @return a {@link Cell} factory + * @return a {@link Cell} factory */ public abstract PatchCellFactory makeCellFactory(); - + /** * Creates a factory for lattices. * - * @return a {@link Lattice} factory + * @return a {@link Lattice} factory */ public abstract PatchLatticeFactory makeLatticeFactory(); - + /** * Creates an instance of the given action. * - * @param actionClass the name of the action class - * @param parameters the dictionary of action parameters - * @return a {@link Action} instance + * @param actionClass the name of the action class + * @param parameters the dictionary of action parameters + * @return a {@link Action} instance */ public abstract Action makeAction(String actionClass, MiniBox parameters); - + /** * Creates an instance of the given component. * - * @param componentClass the name of the component class - * @param parameters the dictionary of component parameters - * @return a {@link Component} instance + * @param componentClass the name of the component class + * @param parameters the dictionary of component parameters + * @return a {@link Component} instance */ public abstract Component makeComponent(String componentClass, MiniBox parameters); - + @Override public final void setupAgents() { // Initialize grid for agents. grid = new PatchGrid(); - + // Initialize factories. locationFactory.initialize(series, random); cellFactory.initialize(series, random); - + // Iterate through each population to create and schedule cells. for (MiniBox population : series.populations.values()) { int pop = population.getInt("CODE"); HashSet ids = cellFactory.popToIDs.get(pop); - + for (int i : ids) { // Get location and cell containers. LocationContainer locationContainer = locationFactory.locations.get(i); CellContainer cellContainer = cellFactory.cells.get(i); - + // Check that we have enough containers. if (locationContainer == null || cellContainer == null) { break; } - + // Make the location and cell. Location location = locationContainer.convert(locationFactory, cellContainer); - PatchCell cell = (PatchCell) cellContainer.convert(cellFactory, location); - + PatchCell cell = (PatchCell) cellContainer.convert(cellFactory, location, random); + // Add and schedule the cell. grid.addObject(cell, location); cell.schedule(schedule); - + // Update id tracking. id = Math.max(i, id); } } } - + @Override public final void setupEnvironment() { // Initialize lattice map for layers. lattices = new HashMap<>(); - + // Initialize factory. latticeFactory.initialize(series, random); - + // Iterate through each layer to create and schedule lattices. for (String key : series.layers.keySet()) { PatchLattice lattice = latticeFactory.lattices.get(key); - + // Add and schedule the lattice. lattices.put(key, lattice); lattice.schedule(schedule); } } - + @Override public final void scheduleActions() { actions = new HashMap<>(); - + // Create all action instances. for (String actionKey : series.actions.keySet()) { MiniBox actionParameters = series.actions.get(actionKey); String actionClass = actionParameters.get("CLASS"); Action action = makeAction(actionClass, actionParameters); - + if (action == null) { continue; } - + actions.put(actionKey, action); } - + // Register and schedule actions. for (String actionKey : actions.keySet()) { MiniBox actionParameters = series.actions.get(actionKey); Action action = actions.get(actionKey); - + MiniBox registerBox = actionParameters.filter("(REGISTER)"); for (String registerKey : registerBox.getKeys()) { action.register(this, registerKey); } - + action.schedule(schedule); } } - + @Override public final void scheduleComponents() { components = new HashMap<>(); - + // Create all component instances. for (String componentKey : series.components.keySet()) { MiniBox componentParameters = series.components.get(componentKey); String componentClass = componentParameters.get("CLASS"); Component component = makeComponent(componentClass, componentParameters); - + if (component == null) { continue; } - + components.put(componentKey, component); } - + // Register and schedule components. for (String componentKey : components.keySet()) { MiniBox componentParameters = series.components.get(componentKey); Component component = components.get(componentKey); - + MiniBox registerBox = componentParameters.filter("(REGISTER)"); for (String registerKey : registerBox.getKeys()) { component.register(this, registerKey); } - + component.schedule(schedule); } } - + /** * Runs output methods. * - * @param isScheduled {@code true} to schedule output, {@code false} otherwise + * @param isScheduled {@code true} to schedule output, {@code false} otherwise */ public void doOutput(boolean isScheduled) { if (isScheduled) { diff --git a/src/arcade/patch/sim/PatchSimulationHex.java b/src/arcade/patch/sim/PatchSimulationHex.java index 8aed4da5d..6eddf28b5 100644 --- a/src/arcade/patch/sim/PatchSimulationHex.java +++ b/src/arcade/patch/sim/PatchSimulationHex.java @@ -21,37 +21,34 @@ import arcade.patch.env.location.PatchLocationFactoryHex; import arcade.patch.env.location.PatchLocationHex; -/** - * Extension of {@link PatchSimulation} for hexagonal geometry. - */ - +/** Extension of {@link PatchSimulation} for hexagonal geometry. */ public final class PatchSimulationHex extends PatchSimulation { /** * Hexagonal simulation for a {@link Series} for given random seed. * - * @param seed the random seed for random number generator - * @param series the simulation series + * @param seed the random seed for random number generator + * @param series the simulation series */ public PatchSimulationHex(long seed, Series series) { super(seed, series); PatchLocationHex.updateConfigs((PatchSeries) series); } - + @Override public PatchLocationFactory makeLocationFactory() { return new PatchLocationFactoryHex(); } - + @Override public PatchCellFactory makeCellFactory() { return new PatchCellFactory(); } - + @Override public PatchLatticeFactory makeLatticeFactory() { return new PatchLatticeFactoryTri(); } - + @Override public Action makeAction(String actionClass, MiniBox parameters) { switch (actionClass) { @@ -65,7 +62,7 @@ public Action makeAction(String actionClass, MiniBox parameters) { return null; } } - + @Override public Component makeComponent(String componentClass, MiniBox parameters) { switch (componentClass) { diff --git a/src/arcade/patch/sim/PatchSimulationRect.java b/src/arcade/patch/sim/PatchSimulationRect.java index ea614f01b..6623fefec 100644 --- a/src/arcade/patch/sim/PatchSimulationRect.java +++ b/src/arcade/patch/sim/PatchSimulationRect.java @@ -21,37 +21,34 @@ import arcade.patch.env.location.PatchLocationFactoryRect; import arcade.patch.env.location.PatchLocationRect; -/** - * Extension of {@link PatchSimulation} for rectangular geometry. - */ - +/** Extension of {@link PatchSimulation} for rectangular geometry. */ public final class PatchSimulationRect extends PatchSimulation { /** * Rectangular simulation for a {@link Series} for given random seed. * - * @param seed the random seed for random number generator - * @param series the simulation series + * @param seed the random seed for random number generator + * @param series the simulation series */ public PatchSimulationRect(long seed, Series series) { super(seed, series); PatchLocationRect.updateConfigs((PatchSeries) series); } - + @Override public PatchLocationFactory makeLocationFactory() { return new PatchLocationFactoryRect(); } - + @Override public PatchCellFactory makeCellFactory() { return new PatchCellFactory(); } - + @Override public PatchLatticeFactory makeLatticeFactory() { return new PatchLatticeFactoryRect(); } - + @Override public Action makeAction(String actionClass, MiniBox parameters) { switch (actionClass) { @@ -65,7 +62,7 @@ public Action makeAction(String actionClass, MiniBox parameters) { return null; } } - + @Override public Component makeComponent(String componentClass, MiniBox parameters) { switch (componentClass) { diff --git a/src/arcade/patch/sim/input/PatchInputBuilder.java b/src/arcade/patch/sim/input/PatchInputBuilder.java index ac28eb907..10659b0c3 100644 --- a/src/arcade/patch/sim/input/PatchInputBuilder.java +++ b/src/arcade/patch/sim/input/PatchInputBuilder.java @@ -15,41 +15,35 @@ import static arcade.core.util.Box.KEY_SEPARATOR; import static arcade.core.util.MiniBox.TAG_SEPARATOR; -/** - * Custom builder for patch-specific simulation setup XMLs. - */ - +/** Custom builder for patch-specific simulation setup XMLs. */ public final class PatchInputBuilder extends InputBuilder { - /** - * Creates a {@code PatchInputBuilder} instance. - */ + /** Creates a {@code PatchInputBuilder} instance. */ public PatchInputBuilder() { super(); } - + /** * Updates a {@link Box} dictionary with tagged attributes. - *

- * Attributes are added to the last entry in the list of dictionaries. One - * of the attributes must be "id" which is used as the id for the entry. - * Attributes "tag" and "target" are concatenated to the id as - * tag/id:target. * - * @param list the list the box is in - * @param tag the entry tag - * @param atts the attributes to add + *

Attributes are added to the last entry in the list of dictionaries. One of the attributes + * must be "id" which is used as the id for the entry. Attributes "tag" and "target" are + * concatenated to the id as tag/id:target. + * + * @param list the list the box is in + * @param tag the entry tag + * @param atts the attributes to add */ void updateBox(String list, String tag, Attributes atts) { String listName = list + (list.equals("patch") ? "" : "s"); ArrayList lists = setupLists.get(listName); Box box = lists.get(lists.size() - 1); - + int numAtts = atts.getLength(); String id; String module; String process; String operation; - + if (numAtts > 0) { // Entry can have at most one of the following tags. boolean hasModule = atts.getValue("module") != null; @@ -58,22 +52,25 @@ void updateBox(String list, String tag, Attributes atts) { if (hasModule ^ hasProcess ? hasOperation : hasModule) { return; } - + // Get any tags (module or region or term) or target. - module = (atts.getValue("module") == null - ? "" - : atts.getValue("module").toLowerCase() + TAG_SEPARATOR); - process = (atts.getValue("process") == null - ? "" - : atts.getValue("process").toLowerCase() + TAG_SEPARATOR); - operation = (atts.getValue("operation") == null - ? "" - : atts.getValue("operation").toLowerCase() + TAG_SEPARATOR); - + module = + (atts.getValue("module") == null + ? "" + : atts.getValue("module").toLowerCase() + TAG_SEPARATOR); + process = + (atts.getValue("process") == null + ? "" + : atts.getValue("process").toLowerCase() + TAG_SEPARATOR); + operation = + (atts.getValue("operation") == null + ? "" + : atts.getValue("operation").toLowerCase() + TAG_SEPARATOR); + // Create id by combining tags and id. id = operation + module + process + atts.getValue("id"); box.addTag(id, tag.toUpperCase()); - + for (int i = 0; i < numAtts; i++) { String name = atts.getQName(i); switch (name) { @@ -88,11 +85,11 @@ void updateBox(String list, String tag, Attributes atts) { } } } - + @Override public void startElement(String uri, String local, String name, Attributes atts) { LOGGER.fine("start element [ " + name + " ]"); - + switch (name) { case "set": case "series": @@ -119,17 +116,17 @@ public void startElement(String uri, String local, String name, Attributes atts) default: break; } - + String[] split = name.split("\\."); if (split.length == 2) { updateBox(split[0], split[1], atts); } } - + @Override public void endElement(String uri, String local, String name) { LOGGER.fine("end element [ " + name + " ]"); - + if ("series".equals(name)) { processSizing(setupDicts.get("series"), parameters); processPatch(setupDicts.get("series"), setupLists.get("patch").get(0), parameters); @@ -140,21 +137,21 @@ public void endElement(String uri, String local, String name) { setupDicts.put("set", set); } } - + /** * Processes sizing parameter. * - * @param series the series parameters - * @param parameters the default parameters + * @param series the series parameters + * @param parameters the default parameters */ private void processSizing(MiniBox series, Box parameters) { MiniBox defaults = parameters.getIdValForTag("DEFAULT"); - + // Get sizes based on default for selected dimension. int radius = defaults.getInt("RADIUS"); int depth = defaults.getInt("DEPTH"); int margin = defaults.getInt("MARGIN"); - + // Override sizes from specific flags. if (series.contains("radius")) { radius = series.getInt("radius"); @@ -165,67 +162,72 @@ private void processSizing(MiniBox series, Box parameters) { if (series.contains("margin")) { margin = series.getInt("margin"); } - + // Enforce that RADIUS and MARGIN are even, and DEPTH is odd. int radiusUpdated = ((radius & 1) == 0 ? radius : radius + 1); int depthUpdated = ((depth & 1) == 1 ? depth : depth + 1); int marginUpdated = ((margin & 1) == 0 ? margin : margin + 1); - + series.put("radius", radiusUpdated); series.put("depth", depthUpdated); series.put("margin", marginUpdated); } - + /** * Processes sizing based on patch geometry. * - * @param series the series parameters - * @param patch the patch parameters - * @param parameters the default parameters + * @param series the series parameters + * @param patch the patch parameters + * @param parameters the default parameters */ private void processPatch(MiniBox series, Box patch, Box parameters) { MiniBox defaults = parameters.getIdValForTag("PATCH"); - + int radius = series.getInt("radius"); int depth = series.getInt("depth"); int margin = series.getInt("margin"); - + int radiusBounds = radius + margin; int depthBounds = (depth == 1 ? 1 : depth + margin); - + series.put("radiusBounds", radiusBounds); series.put("depthBounds", depthBounds); - + String key = "GEOMETRY"; - String geometry = patch.contains(key) - ? patch.getValue(key + KEY_SEPARATOR + "value") - : defaults.get(key); + String geometry = + patch.contains(key) + ? patch.getValue(key + KEY_SEPARATOR + "value") + : defaults.get(key); geometry = geometry.toUpperCase(); - + PatchLocation location; - + int totalPatches; + if (geometry.equals("RECT")) { series.put("length", 4 * radiusBounds - 2); series.put("width", 4 * radiusBounds - 2); series.put("height", 2 * depthBounds - 1); + totalPatches = (2 * radius - 1) * (2 * radius - 1) * depth; CoordinateXYZ coordinate = new CoordinateXYZ(0, 0, 0); location = new PatchLocationRect(coordinate); } else if (geometry.equals("HEX")) { series.put("length", 6 * radiusBounds - 3); series.put("width", 4 * radiusBounds - 2); series.put("height", 2 * depthBounds - 1); + totalPatches = (1 + 3 * radius * (radius - 1)) * depth; CoordinateUVWZ coordinate = new CoordinateUVWZ(0, 0, 0, 0); location = new PatchLocationHex(coordinate); } else { return; } - + series.put("ds", location.getSubcoordinateSize()); series.put("dz", location.getHeight()); - + patch.add("GRID_VOLUME", String.valueOf(location.getVolume())); patch.add("GRID_AREA", String.valueOf(location.getArea())); patch.add("LATTICE_VOLUME", String.valueOf(location.getVolume() / location.getMaximum())); patch.add("LATTICE_AREA", String.valueOf(location.getArea() / location.getMaximum())); + patch.add("TOTAL_PATCHES", String.valueOf(totalPatches)); } } diff --git a/src/arcade/patch/sim/output/PatchOutputDeserializer.java b/src/arcade/patch/sim/output/PatchOutputDeserializer.java index c9dd0b373..80c1c73f2 100644 --- a/src/arcade/patch/sim/output/PatchOutputDeserializer.java +++ b/src/arcade/patch/sim/output/PatchOutputDeserializer.java @@ -23,52 +23,43 @@ /** * Container class for patch-specific object deserializers. - *

- * Deserializers include: + * + *

Deserializers include: + * *

    - *
  • {@link PatchCellDeserializer} for deserializing {@link PatchCellContainer}
  • - *
  • {@link LocationListDeserializer} for deserializing {@link PatchLocationContainer} - * lists
  • - *
  • {@link CoordinateDeserializer} for deserializing {@link Coordinate}
  • + *
  • {@link PatchCellDeserializer} for deserializing {@link PatchCellContainer} + *
  • {@link LocationListDeserializer} for deserializing {@link PatchLocationContainer} lists + *
  • {@link CoordinateDeserializer} for deserializing {@link Coordinate} *
*/ - public final class PatchOutputDeserializer { - /** - * Hidden utility class constructor. - */ + /** Hidden utility class constructor. */ protected PatchOutputDeserializer() { throw new UnsupportedOperationException(); } - + /** * Creates a {@code Gson} with generic and implementation-specific adaptors. * - * @return a {@code Gson} instance + * @return a {@code Gson} instance */ static Gson makeGSON() { GsonBuilder gsonBuilder = OutputDeserializer.makeGSONBuilder(); - gsonBuilder.registerTypeAdapter(CellContainer.class, - new PatchCellDeserializer()); - gsonBuilder.registerTypeAdapter(PatchCellContainer.class, - new PatchCellDeserializer()); - gsonBuilder.registerTypeAdapter(DEFAULT_LOCATION_TYPE, - new LocationListDeserializer()); - gsonBuilder.registerTypeAdapter(Coordinate.class, - new CoordinateDeserializer()); + gsonBuilder.registerTypeAdapter(CellContainer.class, new PatchCellDeserializer()); + gsonBuilder.registerTypeAdapter(PatchCellContainer.class, new PatchCellDeserializer()); + gsonBuilder.registerTypeAdapter(DEFAULT_LOCATION_TYPE, new LocationListDeserializer()); + gsonBuilder.registerTypeAdapter(Coordinate.class, new CoordinateDeserializer()); return gsonBuilder.create(); } - - /** - * Deserializer for {@link PatchCellContainer} objects. - */ + + /** Deserializer for {@link PatchCellContainer} objects. */ static class PatchCellDeserializer implements JsonDeserializer { @Override - public PatchCellContainer deserialize(JsonElement json, Type typeOfT, - JsonDeserializationContext context) + public PatchCellContainer deserialize( + JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { JsonObject jsonObject = json.getAsJsonObject(); - + int id = jsonObject.get("id").getAsInt(); int parent = jsonObject.get("parent").getAsInt(); int pop = jsonObject.get("pop").getAsInt(); @@ -76,57 +67,62 @@ public PatchCellContainer deserialize(JsonElement json, Type typeOfT, int divisions = jsonObject.get("divisions").getAsInt(); double volume = jsonObject.get("volume").getAsDouble(); double height = jsonObject.get("height").getAsDouble(); - + State state = State.valueOf(jsonObject.get("state").getAsString()); - + JsonArray criticals = jsonObject.get("criticals").getAsJsonArray(); double criticalVolume = criticals.get(0).getAsDouble(); double criticalHeight = criticals.get(1).getAsDouble(); - - 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); } } - - /** - * Deserializer for list of {@link PatchLocationContainer} objects. - */ + + /** Deserializer for list of {@link PatchLocationContainer} objects. */ public static final class LocationListDeserializer implements JsonDeserializer> { @Override - public ArrayList deserialize(JsonElement json, Type typeOfT, - JsonDeserializationContext context) + public ArrayList deserialize( + JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { ArrayList locations = new ArrayList<>(); JsonArray jsonArray = json.getAsJsonArray(); - + for (JsonElement element : jsonArray) { JsonObject location = element.getAsJsonObject(); - + JsonElement coordinateElement = location.get("coordinate"); Coordinate coordinate = context.deserialize(coordinateElement, Coordinate.class); - + for (JsonElement idElement : location.getAsJsonArray("ids")) { int id = idElement.getAsInt(); PatchLocationContainer container = new PatchLocationContainer(id, coordinate); locations.add(container); } } - + return locations; } } - - /** - * Deserializer for {@link Coordinate} objects. - */ + + /** Deserializer for {@link Coordinate} objects. */ static class CoordinateDeserializer implements JsonDeserializer { @Override - public Coordinate deserialize(JsonElement json, Type typeOfT, - JsonDeserializationContext context) + public Coordinate deserialize( + JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { JsonArray jsonArray = json.getAsJsonArray(); - + if (jsonArray.size() == 3) { int x = jsonArray.get(0).getAsInt(); int y = jsonArray.get(1).getAsInt(); @@ -139,7 +135,7 @@ public Coordinate deserialize(JsonElement json, Type typeOfT, int z = jsonArray.get(3).getAsInt(); return new CoordinateUVWZ(u, v, w, z); } - + return null; } } diff --git a/src/arcade/patch/sim/output/PatchOutputLoader.java b/src/arcade/patch/sim/output/PatchOutputLoader.java index 50c8f921e..de57947a7 100644 --- a/src/arcade/patch/sim/output/PatchOutputLoader.java +++ b/src/arcade/patch/sim/output/PatchOutputLoader.java @@ -4,18 +4,19 @@ import arcade.core.sim.Series; import arcade.core.sim.output.OutputLoader; -/** - * Custom loader for patch-specific deserialization. - */ - +/** Custom loader for patch-specific deserialization. */ public final class PatchOutputLoader extends OutputLoader { /** * Creates an {@code PatchOutputLoader} for the series. * - * @param series the simulation series + * @param series the simulation series */ - public PatchOutputLoader(Series series) { super(series); } - + public PatchOutputLoader(Series series) { + super(series); + } + @Override - protected Gson makeGSON() { return PatchOutputDeserializer.makeGSON(); } + protected Gson makeGSON() { + return PatchOutputDeserializer.makeGSON(); + } } diff --git a/src/arcade/patch/sim/output/PatchOutputSaver.java b/src/arcade/patch/sim/output/PatchOutputSaver.java index 47d3fac04..bb442498b 100644 --- a/src/arcade/patch/sim/output/PatchOutputSaver.java +++ b/src/arcade/patch/sim/output/PatchOutputSaver.java @@ -4,18 +4,19 @@ import arcade.core.sim.Series; import arcade.core.sim.output.OutputSaver; -/** - * Custom saver for patch-specific serialization. - */ - +/** Custom saver for patch-specific serialization. */ public final class PatchOutputSaver extends OutputSaver { /** * Creates an {@code PatchOutputSaver} for the series. * - * @param series the simulation series + * @param series the simulation series */ - public PatchOutputSaver(Series series) { super(series); } - + public PatchOutputSaver(Series series) { + super(series); + } + @Override - protected Gson makeGSON() { return PatchOutputSerializer.makeGSON(); } + protected Gson makeGSON() { + return PatchOutputSerializer.makeGSON(); + } } diff --git a/src/arcade/patch/sim/output/PatchOutputSerializer.java b/src/arcade/patch/sim/output/PatchOutputSerializer.java index 904ab98b4..dc27b19ec 100644 --- a/src/arcade/patch/sim/output/PatchOutputSerializer.java +++ b/src/arcade/patch/sim/output/PatchOutputSerializer.java @@ -25,52 +25,45 @@ /** * Container class for patch-specific object serializers. - *

- * Generic serializers include: + * + *

Generic serializers include: + * *

    - *
  • {@link PatchSeriesSerializer} for serializing {@link PatchSeries}
  • - *
  • {@link PatchCellSerializer} for serializing {@link PatchCellContainer}
  • - *
  • {@link LocationListSerializer} for serializing {@link PatchLocationContainer} lists
  • - *
  • {@link CoordinateXYZSerializer} for serializing (x, y, z) {@link Coordinate}
  • - *
  • {@link CoordinateUVWZSerializer} for serializing (u, v, w, z) {@link Coordinate}
  • + *
  • {@link PatchSeriesSerializer} for serializing {@link PatchSeries} + *
  • {@link PatchCellSerializer} for serializing {@link PatchCellContainer} + *
  • {@link LocationListSerializer} for serializing {@link PatchLocationContainer} lists + *
  • {@link CoordinateXYZSerializer} for serializing (x, y, z) {@link Coordinate} + *
  • {@link CoordinateUVWZSerializer} for serializing (u, v, w, z) {@link Coordinate} *
*/ - public final class PatchOutputSerializer { - /** - * Hidden utility class constructor. - */ + /** Hidden utility class constructor. */ protected PatchOutputSerializer() { throw new UnsupportedOperationException(); } - + /** * Creates a {@code Gson} with generic and implementation-specific adaptors. * - * @return a {@code Gson} instance + * @return a {@code Gson} instance */ static Gson makeGSON() { GsonBuilder gsonBuilder = OutputSerializer.makeGSONBuilder(); - gsonBuilder.registerTypeAdapter(PatchSeries.class, - new PatchSeriesSerializer()); - gsonBuilder.registerTypeAdapter(CellContainer.class, - new CellSerializer()); - gsonBuilder.registerTypeAdapter(PatchCellContainer.class, - new PatchCellSerializer()); - gsonBuilder.registerTypeAdapter(DEFAULT_LOCATION_TYPE, - new LocationListSerializer()); - gsonBuilder.registerTypeAdapter(CoordinateXYZ.class, - new CoordinateXYZSerializer()); - gsonBuilder.registerTypeAdapter(CoordinateUVWZ.class, - new CoordinateUVWZSerializer()); + gsonBuilder.registerTypeAdapter(PatchSeries.class, new PatchSeriesSerializer()); + gsonBuilder.registerTypeAdapter(CellContainer.class, new CellSerializer()); + gsonBuilder.registerTypeAdapter(PatchCellContainer.class, new PatchCellSerializer()); + gsonBuilder.registerTypeAdapter(DEFAULT_LOCATION_TYPE, new LocationListSerializer()); + gsonBuilder.registerTypeAdapter(CoordinateXYZ.class, new CoordinateXYZSerializer()); + gsonBuilder.registerTypeAdapter(CoordinateUVWZ.class, new CoordinateUVWZSerializer()); return gsonBuilder.create(); } - + /** * Serializer for {@link PatchSeries} objects. - *

- * The object is first serialized using the generic {@link Series} and - * patch-specific contents are then appended: + * + *

The object is first serialized using the generic {@link Series} and patch-specific + * contents are then appended: + * *

      *     ...
      *     "patch": {
@@ -83,41 +76,41 @@ static Gson makeGSON() {
      */
     static class PatchSeriesSerializer implements JsonSerializer {
         @Override
-        public JsonElement serialize(PatchSeries src, Type typeOfSrc,
-                                     JsonSerializationContext context) {
+        public JsonElement serialize(
+                PatchSeries src, Type typeOfSrc, JsonSerializationContext context) {
             JsonObject json = (JsonObject) context.serialize(src, Series.class);
-            
+
             // Add additional sizing parameters.
             JsonObject sizes = json.get("size").getAsJsonObject();
             sizes.addProperty("radius", src.radius);
             sizes.addProperty("depth", src.depth);
-            
+
             // Add patch parameters.
             JsonElement patch = context.serialize(src.patch);
             json.add("patch", patch);
-            
+
             return json;
         }
     }
-    
+
     /**
      * Serializer for {@link CellContainer} objects.
-     * 

- * Uses serialization for {@link PatchCellContainer}. - *

+ * + *

Uses serialization for {@link PatchCellContainer}. */ static class CellSerializer implements JsonSerializer { @Override - public JsonElement serialize(CellContainer src, Type typeOfSrc, - JsonSerializationContext context) { + public JsonElement serialize( + CellContainer src, Type typeOfSrc, JsonSerializationContext context) { return context.serialize(src, PatchCellContainer.class); } } - + /** * Serializer for {@link PatchCellContainer} objects. - *

- * The container object is formatted as: + * + *

The container object is formatted as: + * *

      *     {
      *         "id": (id),
@@ -134,10 +127,10 @@ public JsonElement serialize(CellContainer src, Type typeOfSrc,
      */
     static class PatchCellSerializer implements JsonSerializer {
         @Override
-        public JsonElement serialize(PatchCellContainer src, Type typeOfSrc,
-                                     JsonSerializationContext context) {
+        public JsonElement serialize(
+                PatchCellContainer src, Type typeOfSrc, JsonSerializationContext context) {
             JsonObject json = new JsonObject();
-            
+
             json.addProperty("id", src.id);
             json.addProperty("parent", src.parent);
             json.addProperty("pop", src.pop);
@@ -146,23 +139,24 @@ public JsonElement serialize(PatchCellContainer src, Type typeOfSrc,
             json.addProperty("state", ((State) src.state).name());
             json.addProperty("volume", src.volume);
             json.addProperty("height", src.height);
-            
+
             JsonArray criticals = new JsonArray();
             criticals.add((int) (100 * src.criticalVolume) / 100.0);
             criticals.add((int) (100 * src.criticalHeight) / 100.0);
             json.add("criticals", criticals);
-            
+
             // TODO: add cycles
-            
+
             return json;
         }
     }
-    
+
     /**
      * Serializer for list of {@link PatchLocationContainer} objects.
-     * 

- * This serializer overrides the {@code LocationListSerializer} defined in - * {@link OutputSerializer}. The container object is formatted as: + * + *

This serializer overrides the {@code LocationListSerializer} defined in {@link + * OutputSerializer}. The container object is formatted as: + * *

      *     [
      *         {
@@ -180,41 +174,44 @@ public JsonElement serialize(PatchCellContainer src, Type typeOfSrc,
     public static final class LocationListSerializer
             implements JsonSerializer> {
         @Override
-        public JsonElement serialize(ArrayList src, Type typeOfSrc,
-                                     JsonSerializationContext context) {
+        public JsonElement serialize(
+                ArrayList src,
+                Type typeOfSrc,
+                JsonSerializationContext context) {
             JsonArray json = new JsonArray();
             HashMap> containerMap = new HashMap<>();
-            
+
             for (LocationContainer locationContainer : src) {
                 PatchLocationContainer container = (PatchLocationContainer) locationContainer;
-                ArrayList ids = containerMap
-                        .computeIfAbsent(container.coordinate, k -> new ArrayList<>());
+                ArrayList ids =
+                        containerMap.computeIfAbsent(container.coordinate, k -> new ArrayList<>());
                 ids.add(container.id);
             }
-            
+
             for (Coordinate coordinate : containerMap.keySet()) {
                 JsonObject location = new JsonObject();
                 location.add("coordinate", context.serialize(coordinate));
                 location.add("ids", context.serialize(containerMap.get(coordinate)));
                 json.add(location);
             }
-            
+
             return json;
         }
     }
-    
+
     /**
      * Serializer for {@link CoordinateXYZ} objects.
-     * 

- * The coordinate object is formatted as: + * + *

The coordinate object is formatted as: + * *

      *     [(x), (y), (z)]
      * 
*/ static class CoordinateXYZSerializer implements JsonSerializer { @Override - public JsonElement serialize(CoordinateXYZ src, Type typeOfSrc, - JsonSerializationContext context) { + public JsonElement serialize( + CoordinateXYZ src, Type typeOfSrc, JsonSerializationContext context) { JsonArray json = new JsonArray(); json.add(src.x); json.add(src.y); @@ -222,19 +219,20 @@ public JsonElement serialize(CoordinateXYZ src, Type typeOfSrc, return json; } } - + /** * Serializer for {@link CoordinateUVWZ} objects. - *

- * The coordinate object is formatted as: + * + *

The coordinate object is formatted as: + * *

      *     [(u), (v), (w), (z)]
      * 
*/ static class CoordinateUVWZSerializer implements JsonSerializer { @Override - public JsonElement serialize(CoordinateUVWZ src, Type typeOfSrc, - JsonSerializationContext context) { + public JsonElement serialize( + CoordinateUVWZ src, Type typeOfSrc, JsonSerializationContext context) { JsonArray json = new JsonArray(); json.add(src.u); json.add(src.v); diff --git a/src/arcade/patch/util/PatchEnums.java b/src/arcade/patch/util/PatchEnums.java index ea5e95f88..12a31655f 100644 --- a/src/arcade/patch/util/PatchEnums.java +++ b/src/arcade/patch/util/PatchEnums.java @@ -7,148 +7,146 @@ /** * Container class for patch-specific enums. - *

- * Implemented enums include: + * + *

Implemented enums include: + * *

    - *
  • {@code Ordering} defining simulation stepping order
  • - *
  • {@code State} defining cell states
  • - *
  • {@code Domain} defining domain for a given process
  • - *
  • {@code Flag} defining state change flags
  • - *
  • {@code Category} defining operation categories
  • + *
  • {@code Ordering} defining simulation stepping order + *
  • {@code State} defining cell states + *
  • {@code Domain} defining domain for a given process + *
  • {@code Flag} defining state change flags + *
  • {@code Category} defining operation categories *
*/ - public final class PatchEnums { - /** - * Hidden utility class constructor. - */ + /** Hidden utility class constructor. */ protected PatchEnums() { throw new UnsupportedOperationException(); } - + /** Stepping order for patch simulations. */ public enum Ordering { /** First stepping order (nothing stepped before). */ FIRST, - + /** Stepping order for first action. */ FIRST_ACTION, - + /** Stepping order for actions. */ ACTIONS, - + /** Stepping order for last action. */ LAST_ACTION, - + /** Stepping order for first cell. */ FIRST_CELL, - + /** Stepping order for cells. */ CELLS, - + /** Stepping order for last cell. */ LAST_CELL, - + /** Stepping order for first component. */ FIRST_COMPONENT, - + /** Stepping order for components. */ COMPONENTS, - + /** Stepping order for last component. */ LAST_COMPONENT, - + /** Stepping order for first lattice. */ FIRST_LATTICE, - + /** Stepping order for lattices. */ LATTICES, - + /** Stepping order for last lattice. */ LAST_LATTICE, - + /** Last stepping order (nothing stepped after). */ LAST, } - + /** Cell state codes for patch simulations. */ public enum State implements CellState { /** Code for undefined state. */ UNDEFINED, - + /** Code for quiescent cells. */ QUIESCENT, - + /** Code for proliferative cells. */ PROLIFERATIVE, - + /** Code for migratory cells. */ MIGRATORY, - + /** Code for apoptotic cells. */ APOPTOTIC, - + /** Code for necrotic cells. */ NECROTIC, - + /** Code for senescent cells. */ SENESCENT; - + /** * Randomly selects a {@code State}. * - * @param rng the random number generator - * @return a random {@code State} + * @param rng the random number generator + * @return a random {@code State} */ public static State random(MersenneTwisterFast rng) { return values()[rng.nextInt(values().length - 1) + 1]; } } - + /** Process domain codes for patch simulations. */ public enum Domain implements ProcessDomain { /** Code for undefined domain. */ UNDEFINED, - + /** Code for metabolism domain. */ METABOLISM, - + /** Code for signaling domain. */ SIGNALING; - + /** * Randomly selects a {@code Domain}. * - * @param rng the random number generator - * @return a random {@code Domain} + * @param rng the random number generator + * @return a random {@code Domain} */ public static Domain random(MersenneTwisterFast rng) { return values()[rng.nextInt(values().length - 1) + 1]; } } - + /** State change flags for patch simulations. */ public enum Flag { /** Code for undefined flag. */ UNDEFINED, - + /** Code for proliferative flag. */ PROLIFERATIVE, - + /** Code for migratory flag. */ MIGRATORY; - + /** * Randomly selects a {@code Flag}. * - * @param rng the random number generator - * @return a random {@code Flag} + * @param rng the random number generator + * @return a random {@code Flag} */ public static Flag random(MersenneTwisterFast rng) { return values()[rng.nextInt(values().length - 1) + 1]; } } - + /** Operation category codes for patch simulations. */ public enum Category implements OperationCategory { /** Code for undefined category. */ @@ -163,8 +161,8 @@ public enum Category implements OperationCategory { /** * Randomly selects a {@code Category}. * - * @param rng the random number generator - * @return a random {@code Operation} + * @param rng the random number generator + * @return a random {@code Operation} */ public static Category random(MersenneTwisterFast rng) { return values()[rng.nextInt(values().length - 1) + 1]; diff --git a/src/arcade/patch/vis/PatchColorMaps.java b/src/arcade/patch/vis/PatchColorMaps.java index 79518d211..e0536e036 100644 --- a/src/arcade/patch/vis/PatchColorMaps.java +++ b/src/arcade/patch/vis/PatchColorMaps.java @@ -7,308 +7,305 @@ /** * Container class for commonly used color maps. - *

- * Uses {@link arcade.core.util.Colors} to define mappings. + * + *

Uses {@link arcade.core.util.Colors} to define mappings. */ - class PatchColorMaps { - /** - * BurgYl colormap from - * CARTOColors. - */ - private static final Color[] BURGUNDY_YELLOW = new Color[] { - new Color(0, 0, 0), - new Color(112, 40, 74), - new Color(156, 63, 93), - new Color(200, 88, 108), - new Color(220, 113, 118), - new Color(238, 138, 130), - new Color(245, 186, 152), - new Color(251, 230, 197), - }; - - /** - * Dark mint colormap from - * CARTOColors. - */ - private static final Color[] DARK_MINT = new Color[] { - new Color(0, 0, 0), - new Color(18, 63, 90), - new Color(35, 93, 114), - new Color(58, 124, 137), - new Color(85, 156, 158), - new Color(123, 188, 176), - new Color(165, 219, 194), - new Color(210, 251, 212), - }; - - /** Color map for cell state. */ - static final Colors MAP_STATE = new Colors( + /** BurgYl colormap from CARTOColors. */ + private static final Color[] BURGUNDY_YELLOW = new Color[] { - new Color(85, 85, 85), // undefined - new Color(115, 175, 72), // quiescent - new Color(204, 80, 62), // proliferative - new Color(29, 105, 150), // migratory - new Color(237, 173, 8), // apoptotic - new Color(225, 124, 5), // necrotic - new Color(95, 70, 144), // senescent - new Color(148, 52, 110), // autotic - } - ); - - /** Color map for cell counts. */ - static final Colors MAP_COUNTS = new Colors( + new Color(0, 0, 0), + new Color(112, 40, 74), + new Color(156, 63, 93), + new Color(200, 88, 108), + new Color(220, 113, 118), + new Color(238, 138, 130), + new Color(245, 186, 152), + new Color(251, 230, 197), + }; + + /** Dark mint colormap from CARTOColors. */ + private static final Color[] DARK_MINT = new Color[] { - new Color(0, 0, 0, 0), - new Color(253, 212, 158), - new Color(253, 187, 132), - new Color(252, 141, 89), - new Color(239, 101, 72), - new Color(215, 48, 31), - new Color(153, 0, 0), - } - ); - + new Color(0, 0, 0), + new Color(18, 63, 90), + new Color(35, 93, 114), + new Color(58, 124, 137), + new Color(85, 156, 158), + new Color(123, 188, 176), + new Color(165, 219, 194), + new Color(210, 251, 212), + }; + + /** Color map for cell state. */ + static final Colors MAP_STATE = + new Colors( + new Color[] { + new Color(85, 85, 85), // undefined + new Color(115, 175, 72), // quiescent + new Color(204, 80, 62), // proliferative + new Color(29, 105, 150), // migratory + new Color(237, 173, 8), // apoptotic + new Color(225, 124, 5), // necrotic + new Color(95, 70, 144), // senescent + new Color(148, 52, 110), // autotic + }); + + /** Color map for cell counts. */ + static final Colors MAP_COUNTS = + new Colors( + new Color[] { + new Color(0, 0, 0, 0), + new Color(253, 212, 158), + new Color(253, 187, 132), + new Color(252, 141, 89), + new Color(239, 101, 72), + new Color(215, 48, 31), + new Color(153, 0, 0), + }); + /** Color map for cell populations. */ - static final Colors MAP_POPULATION = new Colors( - new Color[] { - new Color(0, 0, 0), - new Color(95, 70, 144), - new Color(29, 105, 150), - new Color(56, 166, 165), - new Color(15, 133, 84), - new Color(115, 175, 72), - new Color(237, 173, 8), - new Color(225, 124, 5), - new Color(204, 80, 62), - new Color(148, 52, 110), - }, - new double[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 } - ); - + static final Colors MAP_POPULATION = + new Colors( + new Color[] { + new Color(0, 0, 0), + new Color(95, 70, 144), + new Color(29, 105, 150), + new Color(56, 166, 165), + new Color(15, 133, 84), + new Color(115, 175, 72), + new Color(237, 173, 8), + new Color(225, 124, 5), + new Color(204, 80, 62), + new Color(148, 52, 110), + }, + new double[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}); + /** Color map for cell populations. */ - static final Colors MAP_SITES = new Colors( - new Color[] { - new Color(0, 0, 0, 0), - new Color(100, 100, 100), - new Color(150, 150, 150), - }, - new double[] { 0, 1, 2 } - ); - + static final Colors MAP_SITES = + new Colors( + new Color[] { + new Color(0, 0, 0, 0), new Color(100, 100, 100), new Color(150, 150, 150), + }, + new double[] {0, 1, 2}); + /** Color map for cell populations. */ - static final Colors MAP_DAMAGE = new Colors( - new Color[] { - new Color(0, 0, 0, 0), - new Color(253, 212, 158), - new Color(253, 187, 132), - new Color(252, 141, 89), - new Color(239, 101, 72), - new Color(215, 48, 31), - new Color(153, 0, 0), - }, - new double[] { 0, 5, 10, 15, 20, 25, 30 } - ); - + static final Colors MAP_DAMAGE = + new Colors( + new Color[] { + new Color(0, 0, 0, 0), + new Color(253, 212, 158), + new Color(253, 187, 132), + new Color(252, 141, 89), + new Color(239, 101, 72), + new Color(215, 48, 31), + new Color(153, 0, 0), + }, + new double[] {0, 5, 10, 15, 20, 25, 30}); + /** Colors for edge vessel radius. */ - static final Colors MAP_EDGE_RADIUS = new Colors(new Color[] { - new Color(255, 0, 0), - new Color(180, 0, 0), - new Color(130, 0, 130), - new Color(0, 0, 180), - new Color(0, 0, 255), - }, new double[] { -20, -10, 0, 10, 20 }); - + static final Colors MAP_EDGE_RADIUS = + new Colors( + new Color[] { + new Color(255, 0, 0), + new Color(180, 0, 0), + new Color(130, 0, 130), + new Color(0, 0, 180), + new Color(0, 0, 255), + }, + new double[] {-20, -10, 0, 10, 20}); + /** Colors for edge wall thickness. */ - static final Colors MAP_EDGE_WALL = new Colors(new Color[] { - new Color(0, 100, 0), - new Color(0, 255, 0), - new Color(255, 255, 0) - }, new double[] { 0, 5, 10 }); - + static final Colors MAP_EDGE_WALL = + new Colors( + new Color[] { + new Color(0, 100, 0), new Color(0, 255, 0), new Color(255, 255, 0) + }, + new double[] {0, 5, 10}); + /** Colors for node pressures. */ - static final Colors MAP_NODE_PRESSURE = new Colors(new Color[] { - new Color(255, 255, 255), - new Color(253, 212, 158), - new Color(253, 187, 132), - new Color(252, 141, 89), - new Color(239, 101, 72), - new Color(215, 48, 31), - new Color(153, 0, 0) - }, new double[] { 0, 10, 20, 30, 40, 50, 60 }); - + static final Colors MAP_NODE_PRESSURE = + new Colors( + new Color[] { + new Color(255, 255, 255), + new Color(253, 212, 158), + new Color(253, 187, 132), + new Color(252, 141, 89), + new Color(239, 101, 72), + new Color(215, 48, 31), + new Color(153, 0, 0) + }, + new double[] {0, 10, 20, 30, 40, 50, 60}); + /** Color map for cell age. */ final Colors mapAge; - + /** Color map for cell volume. */ final Colors mapVolume; - + /** Color map for cell height. */ final Colors mapHeight; - + /** Color map for cell energy. */ final Colors mapEnergy; - + /** Color map for cell divisions. */ final Colors mapDivisions; - + /** Color map for glucose concentration. */ final Colors mapGlucose; - + /** Color map for oxygen concentration. */ final Colors mapOxygen; - + /** Color map for TGFa concentration. */ final Colors mapTGFa; - + /** * Creates {@code ColorMaps} for the given series. * - * @param series the simulation series + * @param series the simulation series */ PatchColorMaps(Series series) { double age = 0; for (MiniBox box : series.populations.values()) { - if (box.getDouble("CELL_AGE_MAX") > age) { - age = box.getDouble("CELL_AGE_MAX"); + if (box.getDouble("CELL_AGE") > age) { + age = box.getDouble("CELL_AGE"); } } - - mapAge = new Colors( - new Color(0, 0, 0, 0), - new Color(0, 0, 0, 180), - 0, age); - + + mapAge = new Colors(new Color(0, 0, 0, 0), new Color(0, 0, 0, 180), 0, age); + double volume = 0; for (MiniBox box : series.populations.values()) { - if (box.getDouble("CELL_VOLUME_MEAN") > volume) { - volume = box.getDouble("CELL_VOLUME_MEAN"); + if (box.getDouble("CELL_VOLUME") > volume) { + volume = box.getDouble("CELL_VOLUME"); } } - - mapVolume = new Colors( - BURGUNDY_YELLOW, - new double[] { - 0, - 1. / 7 * volume * 2, - 2. / 7 * volume * 2, - 3. / 7 * volume * 2, - 4. / 7 * volume * 2, - 5. / 7 * volume * 2, - 6. / 7 * volume * 2, - 7. / 7 * volume * 2, - } - ); - + + mapVolume = + new Colors( + BURGUNDY_YELLOW, + new double[] { + 0, + 1. / 7 * volume * 2, + 2. / 7 * volume * 2, + 3. / 7 * volume * 2, + 4. / 7 * volume * 2, + 5. / 7 * volume * 2, + 6. / 7 * volume * 2, + 7. / 7 * volume * 2, + }); + double height = 0; for (MiniBox box : series.populations.values()) { - if (box.getDouble("CELL_HEIGHT_MEAN") > height) { - height = box.getDouble("CELL_HEIGHT_MEAN"); + if (box.getDouble("CELL_HEIGHT") > height) { + height = box.getDouble("CELL_HEIGHT"); } } - - mapHeight = new Colors( - BURGUNDY_YELLOW, - new double[] { - 0, - 1. / 7 * height * 2, - 2. / 7 * height * 2, - 3. / 7 * height * 2, - 4. / 7 * height * 2, - 5. / 7 * height * 2, - 6. / 7 * height * 2, - 7. / 7 * height * 2, - } - ); - + + mapHeight = + new Colors( + BURGUNDY_YELLOW, + new double[] { + 0, + 1. / 7 * height * 2, + 2. / 7 * height * 2, + 3. / 7 * height * 2, + 4. / 7 * height * 2, + 5. / 7 * height * 2, + 6. / 7 * height * 2, + 7. / 7 * height * 2, + }); + double energy = 0; for (MiniBox box : series.populations.values()) { if (box.getDouble("ENERGY_THRESHOLD") > energy) { energy = box.getDouble("ENERGY_THRESHOLD"); } } - - mapEnergy = new Colors( - BURGUNDY_YELLOW, - new double[] { - 0, - 1. / 7 * energy, - 2. / 7 * energy, - 3. / 7 * energy, - 4. / 7 * energy, - 5. / 7 * energy, - 6. / 7 * energy, - energy, - } - ); - + + mapEnergy = + new Colors( + BURGUNDY_YELLOW, + new double[] { + 0, + 1. / 7 * energy, + 2. / 7 * energy, + 3. / 7 * energy, + 4. / 7 * energy, + 5. / 7 * energy, + 6. / 7 * energy, + energy, + }); + double divisions = 0; for (MiniBox box : series.populations.values()) { if (box.getDouble("DIVISION_POTENTIAL") > divisions) { divisions = box.getDouble("DIVISION_POTENTIAL"); } } - - mapDivisions = new Colors( - BURGUNDY_YELLOW, - new double[] { - 0, - 1. / 7 * divisions, - 2. / 7 * divisions, - 3. / 7 * divisions, - 4. / 7 * divisions, - 5. / 7 * divisions, - 6. / 7 * divisions, - divisions, - } - ); - + + mapDivisions = + new Colors( + BURGUNDY_YELLOW, + new double[] { + 0, + 1. / 7 * divisions, + 2. / 7 * divisions, + 3. / 7 * divisions, + 4. / 7 * divisions, + 5. / 7 * divisions, + 6. / 7 * divisions, + divisions, + }); + double glucose = series.layers.get("GLUCOSE").getDouble("generator/CONCENTRATION"); - - mapGlucose = new Colors( - DARK_MINT, - new double[] { - 0, - 1. / 7 * glucose, - 2. / 7 * glucose, - 3. / 7 * glucose, - 4. / 7 * glucose, - 5. / 7 * glucose, - 6. / 7 * glucose, - glucose, - } - ); - + + mapGlucose = + new Colors( + DARK_MINT, + new double[] { + 0, + 1. / 7 * glucose, + 2. / 7 * glucose, + 3. / 7 * glucose, + 4. / 7 * glucose, + 5. / 7 * glucose, + 6. / 7 * glucose, + glucose, + }); + double oxygen = series.layers.get("OXYGEN").getDouble("generator/CONCENTRATION"); - - mapOxygen = new Colors( - DARK_MINT, - new double[] { - 0, - 1. / 7 * oxygen, - 2. / 7 * oxygen, - 3. / 7 * oxygen, - 4. / 7 * oxygen, - 5. / 7 * oxygen, - 6. / 7 * oxygen, - oxygen, - } - ); - + + mapOxygen = + new Colors( + DARK_MINT, + new double[] { + 0, + 1. / 7 * oxygen, + 2. / 7 * oxygen, + 3. / 7 * oxygen, + 4. / 7 * oxygen, + 5. / 7 * oxygen, + 6. / 7 * oxygen, + oxygen, + }); + double tgfa = series.layers.get("TGFA").getDouble("INITIAL_CONCENTRATION"); - - mapTGFa = new Colors( - DARK_MINT, - new double[] { - 0, - 1. / 7 * tgfa, - 2. / 7 * tgfa, - 3. / 7 * tgfa, - 4. / 7 * tgfa, - 5. / 7 * tgfa, - 6. / 7 * tgfa, - tgfa, - } - ); + + mapTGFa = + new Colors( + DARK_MINT, + new double[] { + 0, + 1. / 7 * tgfa, + 2. / 7 * tgfa, + 3. / 7 * tgfa, + 4. / 7 * tgfa, + 5. / 7 * tgfa, + 6. / 7 * tgfa, + tgfa, + }); } } diff --git a/src/arcade/patch/vis/PatchDrawer.java b/src/arcade/patch/vis/PatchDrawer.java index d7e630850..337c2a146 100644 --- a/src/arcade/patch/vis/PatchDrawer.java +++ b/src/arcade/patch/vis/PatchDrawer.java @@ -32,48 +32,64 @@ import arcade.patch.sim.PatchSimulation; import static arcade.patch.vis.PatchColorMaps.*; -/** - * Container for patch-specific {@link Drawer} classes. - */ - +/** Container for patch-specific {@link Drawer} classes. */ public abstract class PatchDrawer extends Drawer { /** Array holding values. */ DoubleGrid2D array; - + /** Graph holding edges. */ Network graph; - + /** Field holding nodes. */ Continuous2D field; - + /** View options for cells. */ - enum CellView { STATE, AGE, VOLUME, HEIGHT, COUNTS, POPULATION, ENERGY, DIVISIONS } - + enum CellView { + STATE, + AGE, + VOLUME, + HEIGHT, + COUNTS, + POPULATION, + ENERGY, + DIVISIONS + } + /** View options for lattices. */ - enum LatticeView { CONCENTRATION, SITES, DAMAGE } - + enum LatticeView { + CONCENTRATION, + SITES, + DAMAGE + } + /** * Creates a {@link Drawer} for patch simulations. * - * @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 depth the depth 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 depth the depth of array (z direction) + * @param map the color map for the array + * @param bounds the size of the drawer within the panel */ - PatchDrawer(Panel panel, String name, int length, int width, int depth, - ColorMap map, Rectangle2D.Double bounds) { + PatchDrawer( + Panel panel, + String name, + int length, + int width, + int depth, + ColorMap map, + Rectangle2D.Double bounds) { super(panel, name, length, width, depth, map, bounds); } - + @Override public Portrayal makePort() { String[] split = name.split(":"); graph = new Network(true); field = new Continuous2D(1.0, 1, 1); - + switch (split[0]) { case "label": return new LabelFieldPortrayal2D(length, width, "", 12); @@ -107,22 +123,20 @@ public Portrayal makePort() { return null; } } - + /** Wrapper for MASON class that changes thickness and color of edges. */ private static class SimpleEdgePortrayal2DGridWrapper extends SimpleEdgePortrayal2D { /** Color for low weights. */ private final Color lowColor = new Color(255, 255, 255, 30); - + /** Color for high weights. */ private final Color highColor = new Color(255, 255, 255, 100); - - /** - * Creates {@code SimpleEdgePortrayal2D} wrapper with no scaling. - */ + + /** Creates {@code SimpleEdgePortrayal2D} wrapper with no scaling. */ SimpleEdgePortrayal2DGridWrapper() { setScaling(NEVER_SCALE); } - + @Override public void draw(Object object, Graphics2D graphics, DrawInfo2D info) { sim.field.network.Edge edge = (sim.field.network.Edge) object; @@ -142,40 +156,40 @@ public void draw(Object object, Graphics2D graphics, DrawInfo2D info) { } super.draw(object, graphics, info); } - + @Override protected double getPositiveWeight(Object object, EdgeDrawInfo2D info) { sim.field.network.Edge edge = (sim.field.network.Edge) object; return (Integer) edge.getInfo(); } } - + /** Wrapper for MASON class that changes edge colors based on weight. */ private static class SimpleEdgePortrayal2DEdgeWrapper extends SimpleEdgePortrayal2D { /** Edge feature to display. */ private final String feature; - + /** * Creates {@code SimpleEdgePortrayal2D} wrapper with rounded edges. * - * @param feature the name of the feature to display + * @param feature the name of the feature to display */ SimpleEdgePortrayal2DEdgeWrapper(String feature) { setShape(SimpleEdgePortrayal2D.SHAPE_LINE_ROUND_ENDS); this.feature = feature; } - + /** * {@inheritDoc} - *

- * Gets color of edge based on drawing code. * - * @return the edge weight + *

Gets color of edge based on drawing code. + * + * @return the edge weight */ protected double getPositiveWeight(Object object, EdgeDrawInfo2D info) { sim.field.network.Edge edge = (sim.field.network.Edge) object; SiteEdge siteEdge = (SiteEdge) (edge.getInfo()); - + if (feature.equalsIgnoreCase("radius")) { return siteEdge.getRadius() / 25 + 0.1; } else if (feature.equalsIgnoreCase("wall")) { @@ -184,12 +198,12 @@ protected double getPositiveWeight(Object object, EdgeDrawInfo2D info) { return 2; } } - + @Override public void draw(Object object, Graphics2D graphics, DrawInfo2D info) { sim.field.network.Edge edge = (sim.field.network.Edge) object; SiteEdge siteEdge = (SiteEdge) (edge.getInfo()); - + if (feature.equalsIgnoreCase("radius")) { fromPaint = MAP_EDGE_RADIUS.getColor(siteEdge.getRadius() * siteEdge.getSign()); } else if (feature.equalsIgnoreCase("wall")) { @@ -200,28 +214,27 @@ public void draw(Object object, Graphics2D graphics, DrawInfo2D info) { } else { fromPaint = new Color(100, 100, 100); } - + toPaint = fromPaint; super.draw(object, graphics, info); - } } - + /** Wrapper for MASON class that change node colors. */ private static class OvalPortrayal2DWrapper extends AbstractShapePortrayal2D { /** Node portrayal scaling. */ private static final double OVAL_SCALE = 0.7; - - /** - * Creates {@code AbstractShapePortrayal2D} wrapper. - */ - OvalPortrayal2DWrapper() { super(); } - + + /** Creates {@code AbstractShapePortrayal2D} wrapper. */ + OvalPortrayal2DWrapper() { + super(); + } + @Override public void draw(Object object, Graphics2D graphics, DrawInfo2D info) { graphics.setPaint(new Color(255, 255, 255)); SiteNode node = (SiteNode) object; - + if (node.getRoot()) { graphics.setPaint(new Color(255, 255, 0)); Rectangle2D.Double draw = info.draw; @@ -236,7 +249,7 @@ public void draw(Object object, Graphics2D graphics, DrawInfo2D info) { if (node.getPressure() <= 0) { graphics.setPaint(new Color(0, 255, 255)); } - + Rectangle2D.Double draw = info.draw; double s = Math.min(draw.width, draw.height) / OVAL_SCALE; final int x = (int) (draw.x - s / 2.0); @@ -246,34 +259,34 @@ public void draw(Object object, Graphics2D graphics, DrawInfo2D info) { graphics.fillOval(x, y, w, h); } } - + /** Wrapper for MASON class that changes font style. */ private static class LabelFieldPortrayal2D extends FieldPortrayal2D { /** General font size. */ static final int FONT_SIZE = 12; - + /** Offset for label. */ static final int OFFSET = 5; - + /** Offset in x direction. */ final double xoffset; - + /** Offset in y direction. */ final double yoffset; - + /** Label font size. */ int fontSize; - + /** Label text. */ String string; - + /** * Creates {@code FieldPortrayal2D} wrapper. * - * @param xoffset the offset in x direction - * @param yoffset the offset in y direction - * @param string the text to draw - * @param fontSize the size of font in points + * @param xoffset the offset in x direction + * @param yoffset the offset in y direction + * @param string the text to draw + * @param fontSize the size of font in points */ LabelFieldPortrayal2D(int xoffset, int yoffset, String string, int fontSize) { super(); @@ -282,7 +295,7 @@ private static class LabelFieldPortrayal2D extends FieldPortrayal2D { this.yoffset = yoffset / 100.0; this.fontSize = fontSize; } - + @Override public void draw(Object object, Graphics2D graphics, DrawInfo2D info) { int x = (int) (info.draw.x + xoffset * info.draw.width + OFFSET); @@ -292,32 +305,31 @@ public void draw(Object object, Graphics2D graphics, DrawInfo2D info) { graphics.drawString(string, x, y); } } - + /** * Adds edges to graph. * - * @param field the field to add nodes to - * @param graph the graph to add edges to - * @param weight the edge weight - * @param x1 the x position of the from node - * @param y1 the y position of the from node - * @param x2 the x position of the to node - * @param y2 the y position of the to node + * @param field the field to add nodes to + * @param graph the graph to add edges to + * @param weight the edge weight + * @param x1 the x position of the from node + * @param y1 the y position of the from node + * @param x2 the x position of the to node + * @param y2 the y position of the to node */ - static void add(Continuous2D field, Network graph, int weight, - int x1, int y1, int x2, int y2) { + static void add(Continuous2D field, Network graph, int weight, int x1, int y1, int x2, int y2) { Double2D a = new Double2D(x1, y1); Double2D b = new Double2D(x2, y2); field.setObjectLocation(a, a); field.setObjectLocation(b, b); graph.addEdge(a, b, weight); } - + /** * Converts a boolean array to a double array. * - * @param fromArray the array to convert - * @param toArray the array to store results + * @param fromArray the array to convert + * @param toArray the array to store results */ static void convert(boolean[][] fromArray, double[][] toArray) { for (int i = 0; i < fromArray.length; i++) { @@ -326,45 +338,48 @@ static void convert(boolean[][] fromArray, double[][] toArray) { } } } - - /** - * Extension of {@link Drawer} for drawing graphs. - */ + + /** Extension of {@link Drawer} for drawing graphs. */ public static class Graph extends PatchDrawer { /** Length of the lattice (x direction). */ private final int length; - + /** Width of the lattice (y direction). */ private final int width; - + /** * Creates a {@code Graph} drawer. * - * @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 offset the offset for array geometry - * @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 offset the offset for array geometry + * @param bounds the size of the drawer within the panel */ - Graph(Panel panel, String name, int length, int width, int offset, - Rectangle2D.Double bounds) { + Graph( + Panel panel, + String name, + int length, + int width, + int offset, + Rectangle2D.Double bounds) { super(panel, name, length, width, 0, null, bounds); this.length = length + offset; this.width = width; field.width = length; field.height = width; } - + @Override public void step(SimState simstate) { PatchSimulation sim = (PatchSimulation) simstate; PatchComponentSitesGraph component = (PatchComponentSitesGraph) sim.getComponent("SITES"); - + field.clear(); graph.clear(); - + // Iterate through all edges in the sites bag. Bag bag = component.getGraph().getAllEdges(); for (Object obj : bag) { @@ -377,34 +392,31 @@ public void step(SimState simstate) { } } } - - /** - * Extension of {@link Drawer} for drawing labels. - */ + + /** Extension of {@link Drawer} for drawing labels. */ public static class Label extends PatchDrawer { /** Label text, timestamp shown if null. */ String string; - + /** * Creates a {@code Label} drawer for the given string. * - * @param panel the panel the drawer is attached to - * @param name the name of the drawer - * @param xoffset the offset in x direction - * @param yoffset the offset in y direction - * @param string the text to draw, set to null to show - * timestamp + * @param panel the panel the drawer is attached to + * @param name the name of the drawer + * @param xoffset the offset in x direction + * @param yoffset the offset in y direction + * @param string the text to draw, set to null to show timestamp */ public Label(Panel panel, String name, int xoffset, int yoffset, String string) { super(panel, name, xoffset, yoffset, 0, null, null); this.string = string; - + LabelFieldPortrayal2D port = (LabelFieldPortrayal2D) this.getPortrayal(); if (string == null) { port.fontSize = 20; } } - + @Override public void step(SimState simstate) { LabelFieldPortrayal2D port = (LabelFieldPortrayal2D) this.getPortrayal(); diff --git a/src/arcade/patch/vis/PatchDrawerHex.java b/src/arcade/patch/vis/PatchDrawerHex.java index 624cb16d7..a20865a63 100644 --- a/src/arcade/patch/vis/PatchDrawerHex.java +++ b/src/arcade/patch/vis/PatchDrawerHex.java @@ -21,50 +21,52 @@ import arcade.patch.sim.PatchSimulation; import static arcade.patch.util.PatchEnums.State; -/** - * Container for patch-specific {@link arcade.core.vis.Drawer} classes for - * hexagonal patches. - */ - +/** Container for patch-specific {@link arcade.core.vis.Drawer} classes for hexagonal patches. */ public abstract class PatchDrawerHex extends PatchDrawer { /** * Creates a {@link PatchDrawer} for hexagonal patch simulations. * - * @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 depth the depth 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 depth the depth of array (z direction) + * @param map the color map for the array + * @param bounds the size of the drawer within the panel */ - PatchDrawerHex(Panel panel, String name, int length, int width, int depth, - ColorMap map, Rectangle2D.Double bounds) { + PatchDrawerHex( + Panel panel, + String name, + int length, + int width, + int depth, + ColorMap map, + Rectangle2D.Double bounds) { super(panel, name, length, width, depth, map, bounds); } - + /** * Creates a {@link PatchDrawer} for hexagonal patch simulations. * - * @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 depth the depth of array (z direction) - * @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 depth the depth of array (z direction) + * @param bounds the size of the drawer within the panel */ - PatchDrawerHex(Panel panel, String name, int length, int width, int depth, - Rectangle2D.Double bounds) { + PatchDrawerHex( + Panel panel, String name, int length, int width, int depth, Rectangle2D.Double bounds) { super(panel, name, length, width, depth, null, bounds); } - + /** * Expands an array to a triangular representation. * - * @param toArr the new empty triangular array - * @param fromArr the original array of values - * @param length the length of the original array - * @param width the width of the original array + * @param toArr the new empty triangular array + * @param fromArr the original array of values + * @param length the length of the original array + * @param width the width of the original array */ private static void expand(double[][] toArr, double[][] fromArr, int length, int width) { for (int i = 0; i < length; i++) { @@ -73,14 +75,14 @@ private static void expand(double[][] toArr, double[][] fromArr, int length, int } } } - + /** * Draws a triangle for a given location with the given value. * - * @param arr the target array - * @param i the coordinate of the triangle in the x direction - * @param j the coordinate of the triangle in the y direction - * @param val the value for the triangle + * @param arr the target array + * @param i the coordinate of the triangle in the x direction + * @param j the coordinate of the triangle in the y direction + * @param val the value for the triangle */ private static void expand(double[][] arr, int i, int j, double val) { int dir = ((i + j) & 1) == 0 ? 0 : 2; @@ -94,54 +96,57 @@ private static void expand(double[][] arr, int i, int j, double val) { arr[i * 3 + 3][j * 3 + dir] = val; arr[i * 3 + 4][j * 3 + dir] = val; } - - /** - * Extension of {@link PatchDrawer} for drawing hexagonal cells. - */ + + /** Extension of {@link PatchDrawer} for drawing hexagonal cells. */ public static class PatchCells extends PatchDrawerHex { /** Length of the lattice (x direction). */ private final int length; - + /** Width of the lattice (y direction). */ private final int width; - + /** Drawing view. */ private final CellView view; - + /** * Creates a {@link PatchDrawer} for drawing hexagonal cells. - *

- * Length and width of the drawer are expanded from given length and - * width of simulation so each index can be drawn as a 3x3 triangle. * - * @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 depth the depth of array (z direction) - * @param map the color map for the array - * @param bounds the size of the drawer within the panel + *

Length and width of the drawer are expanded from given length and width of simulation + * so each index can be drawn as a 3x3 triangle. + * + * @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 depth the depth of array (z direction) + * @param map the color map for the array + * @param bounds the size of the drawer within the panel */ - public PatchCells(Panel panel, String name, - int length, int width, int depth, - ColorMap map, Rectangle2D.Double bounds) { + public PatchCells( + Panel panel, + String name, + int length, + int width, + int depth, + ColorMap map, + Rectangle2D.Double bounds) { super(panel, name, 3 * length + 2, 3 * width, depth, map, bounds); this.length = length; this.width = width; String[] split = name.split(":"); view = CellView.valueOf(split[1]); } - + @Override public void step(SimState simstate) { PatchSimulation sim = (PatchSimulation) simstate; double[][] arr = array.field; double[][] temp = new double[length][width]; double[][] counter = new double[length][width]; - + PatchCell cell; PatchLocation location; - + switch (view) { case STATE: case AGE: @@ -162,23 +167,23 @@ public void step(SimState simstate) { default: break; } - + HashMap indices = new HashMap<>(); - + for (Object obj : sim.getGrid().getAllObjects()) { cell = (PatchCell) obj; location = (PatchLocation) cell.getLocation(); - + if (location.getCoordinate().z == 0) { ArrayList coords = location.getSubcoordinates(); - + int hash = location.hashCode(); int index = -1; if (indices.containsKey(hash)) { index = indices.get(hash); } indices.put(hash, ++index); - + switch (view) { case STATE: case AGE: @@ -212,10 +217,10 @@ public void step(SimState simstate) { case HEIGHT: double volume = cell.getVolume(); double height = cell.getHeight(); - + for (Coordinate coord : coords) { CoordinateXYZ triCoord = (CoordinateXYZ) coord; - + switch (view) { case COUNTS: temp[triCoord.x][triCoord.y]++; @@ -236,7 +241,7 @@ public void step(SimState simstate) { } } } - + switch (view) { case VOLUME: case HEIGHT: @@ -249,44 +254,47 @@ public void step(SimState simstate) { default: break; } - + expand(arr, temp, length, width); } } - - /** - * Extension of {@link PatchDrawer} for drawing hexagonal lattices. - */ + + /** Extension of {@link PatchDrawer} for drawing hexagonal lattices. */ public static class PatchLayers extends PatchDrawerHex { /** Length of the lattice (x direction). */ private final int length; - + /** Width of the lattice (y direction). */ private final int width; - + /** Lattice z index to display. */ private final int index; - + /** Drawing view. */ private final LatticeView view; - + /** Layer key. */ private final String key; - + /** * Creates a {@link PatchDrawer} for drawing hexagonal layers. * - * @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 depth the depth 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 depth the depth of array (z direction) + * @param map the color map for the array + * @param bounds the size of the drawer within the panel */ - public PatchLayers(Panel panel, String name, - int length, int width, int depth, - ColorMap map, Rectangle2D.Double bounds) { + public PatchLayers( + Panel panel, + String name, + int length, + int width, + int depth, + ColorMap map, + Rectangle2D.Double bounds) { super(panel, name, 3 * length + 2, 3 * width, depth, map, bounds); this.length = length; this.width = width; @@ -295,12 +303,12 @@ public PatchLayers(Panel panel, String name, view = LatticeView.valueOf(split[1]); key = (split.length == 3 ? split[2] : null); } - + @Override public void step(SimState simstate) { PatchSimulation sim = (PatchSimulation) simstate; double[][] temp = new double[length][width]; - + switch (view) { case CONCENTRATION: temp = sim.getLattice(key).getField()[index]; @@ -308,7 +316,7 @@ public void step(SimState simstate) { case SITES: case DAMAGE: PatchComponentSites component = (PatchComponentSites) sim.getComponent("SITES"); - + if (component instanceof PatchComponentSitesSource) { PatchComponentSitesSource sites = (PatchComponentSitesSource) component; if (view == LatticeView.SITES) { @@ -332,109 +340,132 @@ public void step(SimState simstate) { default: break; } - + expand(array.field, temp, length, width); } } - - /** - * Extension of {@link PatchDrawer} for drawing hexagonal patches. - */ + + /** Extension of {@link PatchDrawer} for drawing hexagonal patches. */ public static class PatchGrid extends PatchDrawerHex { /** Offsets for hexagons. */ private static final int[][] OFFSETS = { - { 0, 0 }, - { 2, 0 }, - { 3, 1 }, - { 2, 2 }, - { 0, 2 }, - { -1, 1 } + {0, 0}, + {2, 0}, + {3, 1}, + {2, 2}, + {0, 2}, + {-1, 1} }; - + /** Length of the lattice (x direction). */ private final int length; - + /** Width of the lattice (y direction). */ private final int width; - + /** List of patch locations. */ private ArrayList locations; - + /** * Creates a {@code PatchGrid} drawer. - *

- * Length and width of the drawer are expanded from the given length and - * width of the simulation. * - * @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 depth the depth of array (z direction) - * @param bounds the size of the drawer within the panel + *

Length and width of the drawer are expanded from the given length and width of the + * simulation. + * + * @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 depth the depth of array (z direction) + * @param bounds the size of the drawer within the panel */ - PatchGrid(Panel panel, String name, int length, int width, int depth, - Rectangle2D.Double bounds) { + PatchGrid( + Panel panel, + String name, + int length, + int width, + int depth, + Rectangle2D.Double bounds) { super(panel, name, 3 * length + 2, 3 * width, depth, bounds); this.length = length + 1; this.width = width; field.width = this.length; field.height = this.width; } - + @Override public void step(SimState simstate) { PatchSimulation sim = (PatchSimulation) simstate; field.clear(); graph.clear(); - + if (locations == null) { locations = new ArrayList<>(); PatchSeries series = (PatchSeries) sim.getSeries(); PatchLocationFactory factory = new PatchLocationFactoryHex(); ArrayList coordinates = factory.getCoordinates(series.radius, series.depth); - + for (Coordinate coordinate : coordinates) { PatchLocationContainer container = new PatchLocationContainer(0, coordinate); PatchLocation location = (PatchLocation) container.convert(factory, null); locations.add(location); } } - + // Draw triangular grid. for (int i = 0; i <= width; i++) { - add(field, graph, 1, - (i % 2 == 0 ? 0 : 1), i, - (i % 2 == 0 ? length : length - 1), i); + add( + field, + graph, + 1, + (i % 2 == 0 ? 0 : 1), + i, + (i % 2 == 0 ? length : length - 1), + i); } - + for (int i = 0; i <= length - 1; i += 2) { for (int j = 0; j < width; j++) { - add(field, graph, 1, - (j % 2 == 0 ? i : i + 1), j, - (j % 2 == 0 ? i + 1 : i), j + 1); + add( + field, + graph, + 1, + (j % 2 == 0 ? i : i + 1), + j, + (j % 2 == 0 ? i + 1 : i), + j + 1); } } - + for (int i = 1; i <= length; i += 2) { for (int j = 0; j < width; j++) { - add(field, graph, 1, - (j % 2 == 0 ? i + 1 : i), j, - (j % 2 == 0 ? i : i + 1), j + 1); + add( + field, + graph, + 1, + (j % 2 == 0 ? i + 1 : i), + j, + (j % 2 == 0 ? i : i + 1), + j + 1); } } - + // Draw hexagonal agent locations. for (PatchLocation loc : locations) { CoordinateXYZ tri = (CoordinateXYZ) loc.getSubcoordinate(); for (int i = 0; i < 6; i++) { - add(field, graph, 2, - tri.x + OFFSETS[i][0], tri.y + OFFSETS[i][1], - tri.x + OFFSETS[(i + 1) % 6][0], tri.y + OFFSETS[(i + 1) % 6][1]); + add( + field, + graph, + 2, + tri.x + OFFSETS[i][0], + tri.y + OFFSETS[i][1], + tri.x + OFFSETS[(i + 1) % 6][0], + tri.y + OFFSETS[(i + 1) % 6][1]); } } - + // Draw border. int radius = ((PatchSeries) sim.getSeries()).radius; int ind; @@ -442,9 +473,9 @@ public void step(SimState simstate) { for (PatchLocation loc : locations) { CoordinateUVWZ coord = (CoordinateUVWZ) loc.getCoordinate(); CoordinateXYZ subcoord = (CoordinateXYZ) loc.getSubcoordinate(); - + r = (int) ((Math.abs(coord.u) + Math.abs(coord.v) + Math.abs(coord.w)) / 2.0) + 1; - + if (r == radius) { if (coord.u == radius - 1) { ind = 1; @@ -461,18 +492,24 @@ public void step(SimState simstate) { } else { ind = 0; } - - add(field, graph, 3, + + add( + field, + graph, + 3, subcoord.x + OFFSETS[ind][0], subcoord.y + OFFSETS[ind][1], subcoord.x + OFFSETS[(ind + 1) % 6][0], subcoord.y + OFFSETS[(ind + 1) % 6][1]); - add(field, graph, 3, + add( + field, + graph, + 3, subcoord.x + OFFSETS[(ind + 1) % 6][0], subcoord.y + OFFSETS[(ind + 1) % 6][1], subcoord.x + OFFSETS[(ind + 2) % 6][0], subcoord.y + OFFSETS[(ind + 2) % 6][1]); - + if (coord.u == 0 || coord.v == 0 || coord.w == 0) { if (coord.u == 0 && coord.v == radius - 1) { ind = 1; @@ -487,8 +524,11 @@ public void step(SimState simstate) { } else if (coord.w == 0 && coord.v == radius - 1) { ind = 0; } - - add(field, graph, 3, + + add( + field, + graph, + 3, subcoord.x + OFFSETS[ind][0], subcoord.y + OFFSETS[ind][1], subcoord.x + OFFSETS[(ind + 1) % 6][0], diff --git a/src/arcade/patch/vis/PatchDrawerRect.java b/src/arcade/patch/vis/PatchDrawerRect.java index 4aeacde21..0e1c37d01 100644 --- a/src/arcade/patch/vis/PatchDrawerRect.java +++ b/src/arcade/patch/vis/PatchDrawerRect.java @@ -20,86 +20,91 @@ import arcade.patch.sim.PatchSimulation; import static arcade.patch.util.PatchEnums.State; -/** - * Container for patch-specific {@link arcade.core.vis.Drawer} classes for - * rectangular patches. - */ - +/** Container for patch-specific {@link arcade.core.vis.Drawer} classes for rectangular patches. */ public abstract class PatchDrawerRect extends PatchDrawer { /** * Creates a {@link PatchDrawer} for rectangular patch simulations. * - * @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 depth the depth 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 depth the depth of array (z direction) + * @param map the color map for the array + * @param bounds the size of the drawer within the panel */ - PatchDrawerRect(Panel panel, String name, int length, int width, int depth, - ColorMap map, Rectangle2D.Double bounds) { + PatchDrawerRect( + Panel panel, + String name, + int length, + int width, + int depth, + ColorMap map, + Rectangle2D.Double bounds) { super(panel, name, length, width, depth, map, bounds); } - + /** * Creates a {@link PatchDrawer} for rectangular patch simulations. * - * @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 depth the depth of array (z direction) - * @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 depth the depth of array (z direction) + * @param bounds the size of the drawer within the panel */ - PatchDrawerRect(Panel panel, String name, int length, int width, int depth, - Rectangle2D.Double bounds) { + PatchDrawerRect( + Panel panel, String name, int length, int width, int depth, Rectangle2D.Double bounds) { super(panel, name, length, width, depth, null, bounds); } - - /** - * Extension of {@link PatchDrawer} for drawing rectangular cells. - */ + + /** Extension of {@link PatchDrawer} for drawing rectangular cells. */ public static class PatchCells extends PatchDrawerRect { /** Length of the lattice (x direction). */ private final int length; - + /** Width of the lattice (y direction). */ private final int width; - + /** Drawing view. */ private final CellView view; - + /** * Creates a {@link PatchDrawer} for drawing rectangular cells. * - * @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 depth the depth 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 depth the depth of array (z direction) + * @param map the color map for the array + * @param bounds the size of the drawer within the panel */ - public PatchCells(Panel panel, String name, - int length, int width, int depth, - ColorMap map, Rectangle2D.Double bounds) { + public PatchCells( + Panel panel, + String name, + int length, + int width, + int depth, + ColorMap map, + Rectangle2D.Double bounds) { super(panel, name, length, width, depth, map, bounds); this.length = length; this.width = width; String[] split = name.split(":"); view = CellView.valueOf(split[1]); } - + @Override public void step(SimState simstate) { PatchSimulation sim = (PatchSimulation) simstate; double[][] arr = array.field; double[][] counter = new double[length][width]; - + PatchCell cell; PatchLocation location; - + switch (view) { case STATE: case AGE: @@ -120,23 +125,23 @@ public void step(SimState simstate) { default: break; } - + HashMap indices = new HashMap<>(); - + for (Object obj : sim.getGrid().getAllObjects()) { cell = (PatchCell) obj; location = (PatchLocation) cell.getLocation(); - + if (location.getCoordinate().z == 0) { ArrayList coords = location.getSubcoordinates(); - + int hash = location.hashCode(); int index = -1; if (indices.containsKey(hash)) { index = indices.get(hash); } indices.put(hash, ++index); - + switch (view) { case STATE: case AGE: @@ -170,10 +175,10 @@ public void step(SimState simstate) { case HEIGHT: double volume = cell.getVolume(); double height = cell.getHeight(); - + for (Coordinate coord : coords) { CoordinateXYZ rectCoord = (CoordinateXYZ) coord; - + switch (view) { case COUNTS: arr[rectCoord.x][rectCoord.y]++; @@ -194,7 +199,7 @@ public void step(SimState simstate) { } } } - + switch (view) { case VOLUME: case HEIGHT: @@ -209,40 +214,43 @@ public void step(SimState simstate) { } } } - - /** - * Extension of {@link PatchDrawer} for drawing rectangular lattices. - */ + + /** Extension of {@link PatchDrawer} for drawing rectangular lattices. */ public static class PatchLayers extends PatchDrawerRect { /** Length of the lattice (x direction). */ private final int length; - + /** Width of the lattice (y direction). */ private final int width; - + /** Lattice z index to display. */ private final int index; - + /** Drawing view. */ private final LatticeView view; - + /** Layer key. */ private final String key; - + /** * Creates a {@link PatchDrawer} for drawing rectangular layers. * - * @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 depth the depth 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 depth the depth of array (z direction) + * @param map the color map for the array + * @param bounds the size of the drawer within the panel */ - public PatchLayers(Panel panel, String name, - int length, int width, int depth, - ColorMap map, Rectangle2D.Double bounds) { + public PatchLayers( + Panel panel, + String name, + int length, + int width, + int depth, + ColorMap map, + Rectangle2D.Double bounds) { super(panel, name, length, width, depth, map, bounds); this.length = length; this.width = width; @@ -251,12 +259,12 @@ public PatchLayers(Panel panel, String name, view = LatticeView.valueOf(split[1]); key = (split.length == 3 ? split[2] : null); } - + @Override public void step(SimState simstate) { PatchSimulation sim = (PatchSimulation) simstate; double[][] temp = new double[length][width]; - + switch (view) { case CONCENTRATION: temp = sim.getLattice(key).getField()[index]; @@ -264,7 +272,7 @@ public void step(SimState simstate) { case SITES: case DAMAGE: PatchComponentSites component = (PatchComponentSites) sim.getComponent("SITES"); - + if (component instanceof PatchComponentSitesSource) { PatchComponentSitesSource sites = (PatchComponentSitesSource) component; if (view == LatticeView.SITES) { @@ -288,85 +296,93 @@ public void step(SimState simstate) { default: break; } - + array.field = temp; } } - - /** - * Extension of {@link PatchDrawer} for drawing rectangular patches. - */ + + /** Extension of {@link PatchDrawer} for drawing rectangular patches. */ public static class PatchGrid extends PatchDrawerRect { /** Offsets for rectangles. */ - private static final int[][] OFFSETS = { { 0, 0 }, { 2, 0 }, { 2, 2 }, { 0, 2 } }; - + private static final int[][] OFFSETS = {{0, 0}, {2, 0}, {2, 2}, {0, 2}}; + /** Length of the lattice (x direction). */ private final int length; - + /** Width of the lattice (y direction). */ private final int width; - + /** List of patch locations. */ private ArrayList locations; - + /** * Creates a {@code PatchGrid} drawer. * - * @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 depth the depth of array (z direction) - * @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 depth the depth of array (z direction) + * @param bounds the size of the drawer within the panel */ - PatchGrid(Panel panel, String name, int length, int width, int depth, - Rectangle2D.Double bounds) { + PatchGrid( + Panel panel, + String name, + int length, + int width, + int depth, + Rectangle2D.Double bounds) { super(panel, name, length, width, depth, bounds); this.length = length; this.width = width; field.width = this.length; field.height = this.width; } - + @Override public void step(SimState simstate) { PatchSimulation sim = (PatchSimulation) simstate; field.clear(); graph.clear(); - + if (locations == null) { locations = new ArrayList<>(); PatchSeries series = (PatchSeries) sim.getSeries(); PatchLocationFactory factory = new PatchLocationFactoryRect(); ArrayList coordinates = factory.getCoordinates(series.radius, series.depth); - + for (Coordinate coordinate : coordinates) { PatchLocationContainer container = new PatchLocationContainer(0, coordinate); PatchLocation location = (PatchLocation) container.convert(factory, null); locations.add(location); } } - + // Draw rectangular grid. for (int i = 0; i <= width; i++) { add(field, graph, 1, 0, i, length, i); } - + for (int i = 0; i <= length; i++) { add(field, graph, 1, i, 0, i, width); } - + // Draw rectangular agent locations. for (PatchLocation loc : locations) { CoordinateXYZ rect = (CoordinateXYZ) loc.getSubcoordinate(); for (int i = 0; i < 4; i++) { - add(field, graph, 2, - rect.x + OFFSETS[i][0], rect.y + OFFSETS[i][1], - rect.x + OFFSETS[(i + 1) % 4][0], rect.y + OFFSETS[(i + 1) % 4][1]); + add( + field, + graph, + 2, + rect.x + OFFSETS[i][0], + rect.y + OFFSETS[i][1], + rect.x + OFFSETS[(i + 1) % 4][0], + rect.y + OFFSETS[(i + 1) % 4][1]); } } - + // Draw border. int radius = ((PatchSeries) sim.getSeries()).radius; int ind; @@ -374,9 +390,9 @@ public void step(SimState simstate) { for (PatchLocation loc : locations) { CoordinateXYZ coord = (CoordinateXYZ) loc.getCoordinate(); CoordinateXYZ subcoord = (CoordinateXYZ) loc.getSubcoordinate(); - + r = Math.max(Math.abs(coord.x), Math.abs(coord.y)) + 1; - + if (r == radius) { if (coord.x == radius - 1) { ind = 1; @@ -389,13 +405,16 @@ public void step(SimState simstate) { } else { ind = 0; } - - add(field, graph, 3, + + add( + field, + graph, + 3, subcoord.x + OFFSETS[ind][0], subcoord.y + OFFSETS[ind][1], subcoord.x + OFFSETS[(ind + 1) % 4][0], subcoord.y + OFFSETS[(ind + 1) % 4][1]); - + if (Math.abs(coord.x) + 1 == r && Math.abs(coord.y) + 1 == r) { if (coord.x == radius - 1 && coord.y == radius - 1) { ind = 2; @@ -406,8 +425,11 @@ public void step(SimState simstate) { } else if (coord.x == 1 - radius && coord.y == 1 - radius) { ind = 0; } - - add(field, graph, 3, + + add( + field, + graph, + 3, subcoord.x + OFFSETS[ind][0], subcoord.y + OFFSETS[ind][1], subcoord.x + OFFSETS[(ind + 1) % 4][0], diff --git a/src/arcade/patch/vis/PatchVisualization.java b/src/arcade/patch/vis/PatchVisualization.java index 2900909de..0f0032804 100644 --- a/src/arcade/patch/vis/PatchVisualization.java +++ b/src/arcade/patch/vis/PatchVisualization.java @@ -8,47 +8,44 @@ import arcade.core.vis.*; import static arcade.patch.vis.PatchColorMaps.*; -/** - * Extension of {@link Visualization} for patch models. - */ - +/** Extension of {@link Visualization} for patch models. */ public final class PatchVisualization extends Visualization { /** Length of the array (x direction). */ final int length; - + /** Width of the array (y direction). */ final int width; - + /** Height of the array (z direction). */ final int height; - + /** Color maps for the simulation. */ final PatchColorMaps maps; - + /** {@code true} if simulation uses graph sites, {@code false} otherwise. */ final boolean hasGraph; - + /** * Creates a {@link Visualization} for patch simulations. * - * @param sim the simulation instance + * @param sim the simulation instance */ public PatchVisualization(Simulation sim) { super((SimState) sim); - + // Update sizes. Series series = sim.getSeries(); length = series.length; width = series.width; height = series.height; - + // Get color maps. maps = new PatchColorMaps(series); - + // Check simulation sites. hasGraph = series.components.get("SITES").get("CLASS").contains("graph"); } - + @Override public Drawer[] createDrawers() { if (length == width) { @@ -57,147 +54,323 @@ public Drawer[] createDrawers() { return createHexDrawers(); } } - + /** * Creates drawers for visualizing simulations with hexagonal geometry. * - * @return a list of {@link Drawer} instances + * @return a list of {@link Drawer} instances */ Drawer[] createHexDrawers() { int h = 200; int v = 200; - - ArrayList drawers = new ArrayList<>(Arrays.asList( - new PatchDrawerHex.PatchCells(panels[0], "agents:STATE", - length, width, height, MAP_STATE, null), - new PatchDrawerHex.PatchCells(panels[0], "agents:AGE", - length, width, height, maps.mapAge, null), - new PatchDrawerHex.PatchGrid(panels[0], "grid", - length, width, height, null), - new PatchDrawer.Label(panels[0], "label", 0, 0, "CELLS"), - new PatchDrawer.Label(panels[0], "label", 0, 94, null), - - new PatchDrawerHex.PatchLayers(panels[1], "environment:CONCENTRATION:GLUCOSE", - length, width, height, maps.mapGlucose, getBox(0, 0, h, v)), - new PatchDrawerHex.PatchLayers(panels[1], "environment:CONCENTRATION:OXYGEN", - length, width, height, maps.mapOxygen, getBox(0, v, h, v)), - new PatchDrawerHex.PatchLayers(panels[1], "environment:CONCENTRATION:TGFA", - length, width, height, maps.mapTGFa, getBox(0, 2 * v, h, v)), - new PatchDrawer.Label(panels[1], "label", 0, 0, "GLUCOSE"), - new PatchDrawer.Label(panels[1], "label", 0, 33, "OXYGEN"), - new PatchDrawer.Label(panels[1], "label", 0, 67, "TGFα"), - - new PatchDrawerHex.PatchCells(panels[2], "agents:VOLUME", - length, width, height, maps.mapVolume, getBox(0, 0, h, v)), - new PatchDrawerHex.PatchCells(panels[2], "agents:HEIGHT", - length, width, height, maps.mapHeight, getBox(h, 0, h, v)), - new PatchDrawerHex.PatchCells(panels[2], "agents:COUNTS", - length, width, height, MAP_COUNTS, getBox(2 * h, 0, h, v)), - new PatchDrawerHex.PatchCells(panels[2], "agents:POPULATION", - length, width, height, MAP_POPULATION, getBox(3 * h, 0, h, v)), - new PatchDrawerHex.PatchCells(panels[2], "agents:ENERGY", - length, width, height, maps.mapEnergy, getBox(4 * h, 0, h, v)), - new PatchDrawerHex.PatchCells(panels[2], "agents:DIVISIONS", - length, width, height, maps.mapDivisions, getBox(5 * h, 0, h, v)), - new PatchDrawer.Label(panels[2], "label", 0, 0, "VOLUME"), - new PatchDrawer.Label(panels[2], "label", 17, 0, "HEIGHT"), - new PatchDrawer.Label(panels[2], "label", 33, 0, "COUNTS"), - new PatchDrawer.Label(panels[2], "label", 50, 0, "POPULATION"), - new PatchDrawer.Label(panels[2], "label", 67, 0, "ENERGY"), - new PatchDrawer.Label(panels[2], "label", 83, 0, "DIVISIONS"))); - + + ArrayList drawers = + new ArrayList<>( + Arrays.asList( + new PatchDrawerHex.PatchCells( + panels[0], + "agents:STATE", + length, + width, + height, + MAP_STATE, + null), + new PatchDrawerHex.PatchCells( + panels[0], + "agents:AGE", + length, + width, + height, + maps.mapAge, + null), + new PatchDrawerHex.PatchGrid( + panels[0], "grid", length, width, height, null), + new PatchDrawer.Label(panels[0], "label", 0, 0, "CELLS"), + new PatchDrawer.Label(panels[0], "label", 0, 94, null), + new PatchDrawerHex.PatchLayers( + panels[1], + "environment:CONCENTRATION:GLUCOSE", + length, + width, + height, + maps.mapGlucose, + getBox(0, 0, h, v)), + new PatchDrawerHex.PatchLayers( + panels[1], + "environment:CONCENTRATION:OXYGEN", + length, + width, + height, + maps.mapOxygen, + getBox(0, v, h, v)), + new PatchDrawerHex.PatchLayers( + panels[1], + "environment:CONCENTRATION:TGFA", + length, + width, + height, + maps.mapTGFa, + getBox(0, 2 * v, h, v)), + new PatchDrawer.Label(panels[1], "label", 0, 0, "GLUCOSE"), + new PatchDrawer.Label(panels[1], "label", 0, 33, "OXYGEN"), + new PatchDrawer.Label(panels[1], "label", 0, 67, "TGFα"), + new PatchDrawerHex.PatchCells( + panels[2], + "agents:VOLUME", + length, + width, + height, + maps.mapVolume, + getBox(0, 0, h, v)), + new PatchDrawerHex.PatchCells( + panels[2], + "agents:HEIGHT", + length, + width, + height, + maps.mapHeight, + getBox(h, 0, h, v)), + new PatchDrawerHex.PatchCells( + panels[2], + "agents:COUNTS", + length, + width, + height, + MAP_COUNTS, + getBox(2 * h, 0, h, v)), + new PatchDrawerHex.PatchCells( + panels[2], + "agents:POPULATION", + length, + width, + height, + MAP_POPULATION, + getBox(3 * h, 0, h, v)), + new PatchDrawerHex.PatchCells( + panels[2], + "agents:ENERGY", + length, + width, + height, + maps.mapEnergy, + getBox(4 * h, 0, h, v)), + new PatchDrawerHex.PatchCells( + panels[2], + "agents:DIVISIONS", + length, + width, + height, + maps.mapDivisions, + getBox(5 * h, 0, h, v)), + new PatchDrawer.Label(panels[2], "label", 0, 0, "VOLUME"), + new PatchDrawer.Label(panels[2], "label", 17, 0, "HEIGHT"), + new PatchDrawer.Label(panels[2], "label", 33, 0, "COUNTS"), + new PatchDrawer.Label(panels[2], "label", 50, 0, "POPULATION"), + new PatchDrawer.Label(panels[2], "label", 67, 0, "ENERGY"), + new PatchDrawer.Label(panels[2], "label", 83, 0, "DIVISIONS"))); + if (hasGraph) { - drawers.add(new PatchDrawer.Graph(panels[1], "edges:wall", - length, width, 1, getBox(h, 0, 2 * h, 2 * v))); - drawers.add(new PatchDrawer.Graph(panels[1], "edges:radius", - length, width, 1, getBox(h, 0, 2 * h, 2 * v))); - drawers.add(new PatchDrawer.Graph(panels[1], "nodes", - length, width, 1, getBox(h, 0, 2 * h, 2 * v))); + drawers.add( + new PatchDrawer.Graph( + panels[1], "edges:wall", length, width, 1, getBox(h, 0, 2 * h, 2 * v))); + drawers.add( + new PatchDrawer.Graph( + panels[1], + "edges:radius", + length, + width, + 1, + getBox(h, 0, 2 * h, 2 * v))); + drawers.add( + new PatchDrawer.Graph( + panels[1], "nodes", length, width, 1, getBox(h, 0, 2 * h, 2 * v))); } else { - drawers.add(new PatchDrawerHex.PatchLayers(panels[1], "environment:SITES", - length, width, height, MAP_SITES, getBox(h, 0, h, v))); - drawers.add(new PatchDrawerHex.PatchLayers(panels[1], "environment:DAMAGE", - length, width, height, MAP_DAMAGE, getBox(h, v, h, v))); + drawers.add( + new PatchDrawerHex.PatchLayers( + panels[1], + "environment:SITES", + length, + width, + height, + MAP_SITES, + getBox(h, 0, h, v))); + drawers.add( + new PatchDrawerHex.PatchLayers( + panels[1], + "environment:DAMAGE", + length, + width, + height, + MAP_DAMAGE, + getBox(h, v, h, v))); drawers.add(new PatchDrawer.Label(panels[1], "label", 33, 0, "SITES")); drawers.add(new PatchDrawer.Label(panels[1], "label", 33, 33, "DAMAGE")); } - + return drawers.toArray(new Drawer[0]); } - + /** * Creates drawers for visualizing simulations with rectangular geometry. * - * @return a list of {@link Drawer} instances + * @return a list of {@link Drawer} instances */ Drawer[] createRectDrawers() { int h = 200; int v = 200; - - ArrayList drawers = new ArrayList<>(Arrays.asList( - new PatchDrawerRect.PatchCells(panels[0], "agents:STATE", - length, width, height, MAP_STATE, null), - new PatchDrawerRect.PatchCells(panels[0], "agents:AGE", - length, width, height, maps.mapAge, null), - new PatchDrawerRect.PatchGrid(panels[0], "grid", - length, width, height, null), - new PatchDrawer.Label(panels[0], "label", 0, 0, "CELLS"), - new PatchDrawer.Label(panels[0], "label", 0, 94, null), - - new PatchDrawerRect.PatchLayers(panels[1], "environment:CONCENTRATION:GLUCOSE", - length, width, height, maps.mapGlucose, getBox(0, 0, h, v)), - new PatchDrawerRect.PatchLayers(panels[1], "environment:CONCENTRATION:OXYGEN", - length, width, height, maps.mapOxygen, getBox(0, v, h, v)), - new PatchDrawerRect.PatchLayers(panels[1], "environment:CONCENTRATION:TGFA", - length, width, height, maps.mapTGFa, getBox(0, 2 * v, h, v)), - new PatchDrawer.Label(panels[1], "label", 0, 0, "GLUCOSE"), - new PatchDrawer.Label(panels[1], "label", 0, 33, "OXYGEN"), - new PatchDrawer.Label(panels[1], "label", 0, 67, "TGFα"), - - new PatchDrawerRect.PatchCells(panels[2], "agents:VOLUME", - length, width, height, maps.mapVolume, getBox(0, 0, h, v)), - new PatchDrawerRect.PatchCells(panels[2], "agents:HEIGHT", - length, width, height, maps.mapHeight, getBox(h, 0, h, v)), - new PatchDrawerRect.PatchCells(panels[2], "agents:COUNTS", - length, width, height, MAP_COUNTS, getBox(2 * h, 0, h, v)), - new PatchDrawerRect.PatchCells(panels[2], "agents:POPULATION", - length, width, height, MAP_POPULATION, getBox(3 * h, 0, h, v)), - new PatchDrawerRect.PatchCells(panels[2], "agents:ENERGY", - length, width, height, maps.mapEnergy, getBox(4 * h, 0, h, v)), - new PatchDrawerRect.PatchCells(panels[2], "agents:DIVISIONS", - length, width, height, maps.mapDivisions, getBox(5 * h, 0, h, v)), - new PatchDrawer.Label(panels[2], "label", 0, 0, "VOLUME"), - new PatchDrawer.Label(panels[2], "label", 17, 0, "HEIGHT"), - new PatchDrawer.Label(panels[2], "label", 33, 0, "COUNTS"), - new PatchDrawer.Label(panels[2], "label", 50, 0, "POPULATION"), - new PatchDrawer.Label(panels[2], "label", 67, 0, "ENERGY"), - new PatchDrawer.Label(panels[2], "label", 83, 0, "DIVISIONS"))); - + + ArrayList drawers = + new ArrayList<>( + Arrays.asList( + new PatchDrawerRect.PatchCells( + panels[0], + "agents:STATE", + length, + width, + height, + MAP_STATE, + null), + new PatchDrawerRect.PatchCells( + panels[0], + "agents:AGE", + length, + width, + height, + maps.mapAge, + null), + new PatchDrawerRect.PatchGrid( + panels[0], "grid", length, width, height, null), + new PatchDrawer.Label(panels[0], "label", 0, 0, "CELLS"), + new PatchDrawer.Label(panels[0], "label", 0, 94, null), + new PatchDrawerRect.PatchLayers( + panels[1], + "environment:CONCENTRATION:GLUCOSE", + length, + width, + height, + maps.mapGlucose, + getBox(0, 0, h, v)), + new PatchDrawerRect.PatchLayers( + panels[1], + "environment:CONCENTRATION:OXYGEN", + length, + width, + height, + maps.mapOxygen, + getBox(0, v, h, v)), + new PatchDrawerRect.PatchLayers( + panels[1], + "environment:CONCENTRATION:TGFA", + length, + width, + height, + maps.mapTGFa, + getBox(0, 2 * v, h, v)), + new PatchDrawer.Label(panels[1], "label", 0, 0, "GLUCOSE"), + new PatchDrawer.Label(panels[1], "label", 0, 33, "OXYGEN"), + new PatchDrawer.Label(panels[1], "label", 0, 67, "TGFα"), + new PatchDrawerRect.PatchCells( + panels[2], + "agents:VOLUME", + length, + width, + height, + maps.mapVolume, + getBox(0, 0, h, v)), + new PatchDrawerRect.PatchCells( + panels[2], + "agents:HEIGHT", + length, + width, + height, + maps.mapHeight, + getBox(h, 0, h, v)), + new PatchDrawerRect.PatchCells( + panels[2], + "agents:COUNTS", + length, + width, + height, + MAP_COUNTS, + getBox(2 * h, 0, h, v)), + new PatchDrawerRect.PatchCells( + panels[2], + "agents:POPULATION", + length, + width, + height, + MAP_POPULATION, + getBox(3 * h, 0, h, v)), + new PatchDrawerRect.PatchCells( + panels[2], + "agents:ENERGY", + length, + width, + height, + maps.mapEnergy, + getBox(4 * h, 0, h, v)), + new PatchDrawerRect.PatchCells( + panels[2], + "agents:DIVISIONS", + length, + width, + height, + maps.mapDivisions, + getBox(5 * h, 0, h, v)), + new PatchDrawer.Label(panels[2], "label", 0, 0, "VOLUME"), + new PatchDrawer.Label(panels[2], "label", 17, 0, "HEIGHT"), + new PatchDrawer.Label(panels[2], "label", 33, 0, "COUNTS"), + new PatchDrawer.Label(panels[2], "label", 50, 0, "POPULATION"), + new PatchDrawer.Label(panels[2], "label", 67, 0, "ENERGY"), + new PatchDrawer.Label(panels[2], "label", 83, 0, "DIVISIONS"))); + if (hasGraph) { - drawers.add(new PatchDrawer.Graph(panels[1], "edges:wall", - length, width, 0, getBox(h, 0, 2 * h, 2 * v))); - drawers.add(new PatchDrawer.Graph(panels[1], "edges:radius", - length, width, 0, getBox(h, 0, 2 * h, 2 * v))); - drawers.add(new PatchDrawer.Graph(panels[1], "nodes", - length, width, 0, getBox(h, 0, 2 * h, 2 * v))); + drawers.add( + new PatchDrawer.Graph( + panels[1], "edges:wall", length, width, 0, getBox(h, 0, 2 * h, 2 * v))); + drawers.add( + new PatchDrawer.Graph( + panels[1], + "edges:radius", + length, + width, + 0, + getBox(h, 0, 2 * h, 2 * v))); + drawers.add( + new PatchDrawer.Graph( + panels[1], "nodes", length, width, 0, getBox(h, 0, 2 * h, 2 * v))); } else { - drawers.add(new PatchDrawerRect.PatchLayers(panels[1], "environment:SITES", - length, width, height, MAP_SITES, getBox(h, 0, h, v))); - drawers.add(new PatchDrawerRect.PatchLayers(panels[1], "environment:DAMAGE", - length, width, height, MAP_DAMAGE, getBox(h, v, h, v))); + drawers.add( + new PatchDrawerRect.PatchLayers( + panels[1], + "environment:SITES", + length, + width, + height, + MAP_SITES, + getBox(h, 0, h, v))); + drawers.add( + new PatchDrawerRect.PatchLayers( + panels[1], + "environment:DAMAGE", + length, + width, + height, + MAP_DAMAGE, + getBox(h, v, h, v))); drawers.add(new PatchDrawer.Label(panels[1], "label", 33, 0, "SITES")); drawers.add(new PatchDrawer.Label(panels[1], "label", 33, 33, "DAMAGE")); } - + return drawers.toArray(new Drawer[0]); } - + @Override public Panel[] createPanels() { return new Panel[] { - new Panel("[PATCH] Agents", 10, 10, 600, 600, this), - new Panel("[PATCH] Environment", 700, 10, 600, 600, this), - new Panel("[PATCH] Auxiliary", 10, 700, 1200, 200, this), + new Panel("[PATCH] Agents", 10, 10, 600, 600, this), + new Panel("[PATCH] Environment", 700, 10, 600, 600, this), + new Panel("[PATCH] Auxiliary", 10, 700, 1200, 200, this), }; } } diff --git a/src/arcade/potts/PottsARCADE.java b/src/arcade/potts/PottsARCADE.java index fef37f4e6..f3a552e9e 100644 --- a/src/arcade/potts/PottsARCADE.java +++ b/src/arcade/potts/PottsARCADE.java @@ -9,25 +9,28 @@ import arcade.potts.sim.output.PottsOutputLoader; import arcade.potts.sim.output.PottsOutputSaver; -/** - * Implementation of ARCADE for potts models. - */ - +/** Implementation of ARCADE for potts models. */ public final class PottsARCADE extends ARCADE { - /** - * ARCADE model with potts. - */ - public PottsARCADE() { } - + /** ARCADE model with potts. */ + public PottsARCADE() {} + @Override - public String getResource(String s) { return PottsARCADE.class.getResource(s).toString(); } - + public String getResource(String s) { + return PottsARCADE.class.getResource(s).toString(); + } + @Override - public InputBuilder getBuilder() { return new PottsInputBuilder(); } - + public InputBuilder getBuilder() { + return new PottsInputBuilder(); + } + @Override - public OutputLoader getLoader(Series series) { return new PottsOutputLoader(series); } - + public OutputLoader getLoader(Series series) { + return new PottsOutputLoader(series); + } + @Override - public OutputSaver getSaver(Series series) { return new PottsOutputSaver(series); } + public OutputSaver getSaver(Series series) { + return new PottsOutputSaver(series); + } } diff --git a/src/arcade/potts/agent/cell/PottsCell.java b/src/arcade/potts/agent/cell/PottsCell.java index 23e70450b..4dc124f99 100644 --- a/src/arcade/potts/agent/cell/PottsCell.java +++ b/src/arcade/potts/agent/cell/PottsCell.java @@ -4,7 +4,6 @@ import sim.engine.Schedule; import sim.engine.SimState; import sim.engine.Stoppable; -import ec.util.MersenneTwisterFast; import arcade.core.agent.cell.Cell; import arcade.core.agent.cell.CellContainer; import arcade.core.agent.cell.CellState; @@ -13,135 +12,124 @@ import arcade.core.agent.process.ProcessDomain; 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 arcade.potts.agent.module.PottsModule; -import arcade.potts.agent.module.PottsModuleApoptosisSimple; -import arcade.potts.agent.module.PottsModuleAutosis; -import arcade.potts.agent.module.PottsModuleNecrosis; -import arcade.potts.agent.module.PottsModuleProliferationSimple; -import arcade.potts.agent.module.PottsModuleQuiescence; import arcade.potts.env.location.PottsLocation; import static arcade.potts.util.PottsEnums.Ordering; import static arcade.potts.util.PottsEnums.Region; -import static arcade.potts.util.PottsEnums.State; /** * Implementation of {@link Cell} for potts models. - *

- * {@code PottsCell} agents exist in one of five states: quiescent, - * proliferative, apoptotic, necrotic, or autotic. Each state may be further - * divided into relevant phases. - *

- * General order of rules for the {@code PottsCell} step: + * + *

{@code PottsCell} agents exist in one of five states: quiescent, proliferative, apoptotic, + * necrotic, or autotic. Each state may be further divided into relevant phases. + * + *

General order of rules for the {@code PottsCell} step: + * *

    - *
  • update age
  • - *
  • step state module
  • + *
  • update age + *
  • step state module *
- *

- * Cell parameters are tracked using a map between the parameter name and value. - *

- * To integrate with the Potts layer, {@code PottsCell} agents also contain - * critical and target volumes and surfaces. - * Additional parameters specific to each term in the Hamiltonian are tracked + * + *

Cell parameters are tracked using a map between the parameter name and value. + * + *

To integrate with the Potts layer, {@code PottsCell} agents also contain critical and target + * volumes and surfaces. Additional parameters specific to each term in the Hamiltonian are tracked * by the specific Hamiltonian class instance. */ - -public final class PottsCell implements Cell { +public abstract class PottsCell implements Cell { /** Stopper used to stop this agent from being stepped in the schedule. */ Stoppable stopper; - + /** Cell {@link Location} object. */ private final PottsLocation location; - + /** Unique cell ID. */ final int id; - + /** Cell parent ID. */ final int parent; - + /** Cell population index. */ final int pop; - + /** Cell state. */ private CellState state; - + /** Cell age [ticks]. */ - private int age; - + int age; + /** Number of divisions. */ - private int divisions; - + int divisions; + /** {@code true} if the cell has regions, {@code false} otherwise. */ - private final boolean hasRegions; - + final boolean hasRegions; + /** Target cell volume [voxels]. */ private double targetVolume; - + /** Target region cell volumes [voxels]. */ private final EnumMap targetRegionVolumes; - + /** Target cell surface [voxels]. */ private double targetSurface; - + /** Target region cell surfaces [voxels]. */ private final EnumMap targetRegionSurfaces; - + /** Critical volume for cell [voxels]. */ - private final double criticalVolume; - + final double criticalVolume; + /** Critical volumes for cell by region [voxels]. */ - private final EnumMap criticalRegionVolumes; - + final EnumMap criticalRegionVolumes; + /** Critical height for cell [voxels]. */ - private final double criticalHeight; - + final double criticalHeight; + /** Critical heights for cell by region [voxels]. */ - private final EnumMap criticalRegionHeights; - + final EnumMap criticalRegionHeights; + /** Cell state module. */ protected Module module; - + /** Cell parameters. */ - final MiniBox parameters; - + final Parameters parameters; + + /** Cell population links. */ + final GrabBag links; + /** * Creates a {@code PottsCell} 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 hasRegions {@code true} if cell has regions, {@code false} otherwise - * @param parameters the dictionary of parameters - * @param criticalVolume the critical cell volume - * @param criticalHeight the critical cell height - * @param criticalRegionVolumes the map of critical volumes for regions - * @param criticalRegionHeights the map of critical heights for regions + * @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 PottsCell(int id, int parent, int pop, CellState state, int age, int divisions, - Location location, boolean hasRegions, MiniBox parameters, - double criticalVolume, double criticalHeight, - EnumMap criticalRegionVolumes, - EnumMap criticalRegionHeights) { - this.id = id; - this.parent = parent; - this.pop = pop; - this.age = age; - this.divisions = divisions; - this.hasRegions = hasRegions; + public PottsCell( + PottsCellContainer container, Location location, Parameters parameters, GrabBag links) { + this.id = container.id; + this.parent = container.parent; + this.pop = container.pop; + this.age = container.age; + this.divisions = container.divisions; + this.hasRegions = container.regionVoxels != null; this.location = (PottsLocation) location; this.parameters = parameters; - this.criticalVolume = criticalVolume; - this.criticalHeight = criticalHeight; - - setState(state); - + this.links = links; + this.criticalVolume = container.criticalVolume; + this.criticalHeight = container.criticalHeight; + + setState(container.state); + + if (module != null && container.phase != null) { + ((PottsModule) module).setPhase(container.phase); + } + if (hasRegions) { - this.criticalRegionVolumes = criticalRegionVolumes.clone(); - this.criticalRegionHeights = criticalRegionHeights.clone(); + this.criticalRegionVolumes = container.criticalRegionVolumes.clone(); + this.criticalRegionHeights = container.criticalRegionHeights.clone(); this.targetRegionVolumes = new EnumMap<>(Region.class); this.targetRegionSurfaces = new EnumMap<>(Region.class); } else { @@ -151,237 +139,252 @@ public PottsCell(int id, int parent, int pop, CellState state, int age, int divi this.targetRegionSurfaces = null; } } - + @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 null; } - + public Process getProcess(ProcessDomain domain) { + return null; + } + @Override - public MiniBox getParameters() { return parameters; } - + public Parameters getParameters() { + return parameters; + } + /** * Checks if the cell has regions. * - * @return {@code true} if the cell has regions, {@code false} otherwise + * @return {@code true} if the cell has regions, {@code false} otherwise */ - public boolean hasRegions() { return hasRegions; } - + public boolean hasRegions() { + return hasRegions; + } + @Override - public double getVolume() { return location.getVolume(); } - + public double getVolume() { + return location.getVolume(); + } + /** * Gets the cell volume for a region. * - * @param region the region - * @return the cell region volume + * @param region the region + * @return the cell region volume */ public double getVolume(Region region) { return (hasRegions ? location.getVolume(region) : 0); } - + @Override - public double getHeight() { return location.getHeight(); } - + public double getHeight() { + return location.getHeight(); + } + /** * Gets the cell height for a region. * - * @param region the region - * @return the cell region height + * @param region the region + * @return the cell region height */ public double getHeight(Region region) { return (hasRegions ? location.getHeight(region) : 0); } - + /** * Gets the cell surface. * - * @return the cell surface + * @return the cell surface */ - public double getSurface() { return location.getSurface(); } - + public double getSurface() { + return location.getSurface(); + } + /** * Gets the cell surface for a region. * - * @param region the region - * @return the cell region surface + * @param region the region + * @return the cell region surface */ public double getSurface(Region region) { return (hasRegions ? location.getSurface(region) : 0); } - + /** * Gets the target volume. * - * @return the target volume + * @return the target volume */ - public double getTargetVolume() { return targetVolume; } - + public double getTargetVolume() { + return targetVolume; + } + /** * Gets the target volume for a region. * - * @param region the region - * @return the target region volume + * @param region the region + * @return the target region volume */ public double getTargetVolume(Region region) { return (hasRegions && targetRegionVolumes.containsKey(region) ? targetRegionVolumes.get(region) : 0); } - + /** * Gets the target surface. * - * @return the target surface + * @return the target surface */ - public double getTargetSurface() { return targetSurface; } - + public double getTargetSurface() { + return targetSurface; + } + /** * Gets the target surface for a region. * - * @param region the region - * @return the target region surface + * @param region the region + * @return the target region surface */ public double getTargetSurface(Region region) { return (hasRegions && targetRegionSurfaces.containsKey(region) ? targetRegionSurfaces.get(region) : 0); } - + @Override - public double getCriticalVolume() { return criticalVolume; } - + public double getCriticalVolume() { + return criticalVolume; + } + /** * Gets the critical volume for a region. * - * @param region the region - * @return the critical region volume + * @param region the region + * @return the critical region volume */ public double getCriticalVolume(Region region) { return (hasRegions && criticalRegionVolumes.containsKey(region) ? criticalRegionVolumes.get(region) : 0); } - + @Override - public double getCriticalHeight() { return criticalHeight; } - + public double getCriticalHeight() { + return criticalHeight; + } + /** * Gets the critical height for a region. * - * @param region the region - * @return the critical region height + * @param region the region + * @return the critical region height */ public double getCriticalHeight(Region region) { return (hasRegions && criticalRegionHeights.containsKey(region) ? criticalRegionHeights.get(region) : 0); } - - @Override - public void stop() { stopper.stop(); } - + @Override - public PottsCell make(int newID, CellState newState, Location newLocation, - MersenneTwisterFast random) { - divisions++; - return new PottsCell(newID, id, pop, newState, age, divisions, newLocation, - hasRegions, parameters, criticalVolume, criticalHeight, - criticalRegionVolumes, criticalRegionHeights); - } - + public void stop() { + stopper.stop(); + } + @Override - public void setState(CellState state) { - this.state = state; - - switch ((State) state) { - case QUIESCENT: - module = new PottsModuleQuiescence(this); - break; - case PROLIFERATIVE: - module = new PottsModuleProliferationSimple(this); - break; - case APOPTOTIC: - module = new PottsModuleApoptosisSimple(this); - break; - case NECROTIC: - module = new PottsModuleNecrosis(this); - break; - case AUTOTIC: - module = new PottsModuleAutosis(this); - break; - default: - // State must be one of the above cases. - module = null; - break; - } + public void setState(CellState newState) { + this.state = newState; + setStateModule(newState); } - + + /** + * Sets the state module for the cell. + * + * @param newState the cell state + */ + abstract void setStateModule(CellState newState); + @Override public void schedule(Schedule schedule) { stopper = schedule.scheduleRepeating(this, Ordering.CELLS.ordinal(), 1); } - + /** * Initializes the potts arrays with the cell. * - * @param ids the {@link arcade.potts.sim.Potts} array for ids - * @param regions the {@link arcade.potts.sim.Potts} array for regions + * @param ids the {@link arcade.potts.sim.Potts} array for ids + * @param regions the {@link arcade.potts.sim.Potts} array for regions */ public void initialize(int[][][] ids, int[][][] regions) { location.update(id, ids, regions); - + targetVolume = location.getVolume(); targetSurface = location.getSurface(); - + if (!hasRegions) { return; } - + for (Region region : location.getRegions()) { targetRegionVolumes.put(region, location.getVolume(region)); targetRegionSurfaces.put(region, location.getSurface(region)); } } - + /** * Resets the potts arrays with the cell. * - * @param ids the {@link arcade.potts.sim.Potts} array for ids - * @param regions the {@link arcade.potts.sim.Potts} array for regions + * @param ids the {@link arcade.potts.sim.Potts} array for ids + * @param regions the {@link arcade.potts.sim.Potts} array for regions */ public void reset(int[][][] ids, int[][][] regions) { location.update(id, ids, regions); - + targetVolume = criticalVolume; targetSurface = location.convertSurface(targetVolume, criticalHeight); - + if (!hasRegions) { return; } - + for (Region region : location.getRegions()) { double regionHeight = criticalRegionHeights.get(region); double regionVolume = criticalRegionVolumes.get(region); @@ -389,54 +392,54 @@ public void reset(int[][][] ids, int[][][] regions) { targetRegionSurfaces.put(region, location.convertSurface(regionVolume, regionHeight)); } } - + @Override public void step(SimState simstate) { Simulation sim = (Simulation) simstate; - + // Increase age of cell. age++; - + // Step the module for the cell state. module.step(simstate.random, sim); } - + /** * Sets the target volume and surface for the cell. * - * @param volume the target volume - * @param surface the target surface + * @param volume the target volume + * @param surface the target surface */ public void setTargets(double volume, double surface) { targetVolume = volume; targetSurface = surface; } - + /** * Sets the target volume and surface for a region. * - * @param region the region - * @param volume the target volume - * @param surface the target surface + * @param region the region + * @param volume the target volume + * @param surface the target surface */ public void setTargets(Region region, double volume, double surface) { targetRegionVolumes.put(region, volume); targetRegionSurfaces.put(region, surface); } - + /** - * Updates target volume and surface area. When scale is greater than one, - * volume increases by given rate. When scale is less than one, volume - * decreases by given rate. If scale is one, sizes are not changed. + * Updates target volume and surface area. When scale is greater than one, volume increases by + * given rate. When scale is less than one, volume decreases by given rate. If scale is one, + * sizes are not changed. * - * @param rate the rate of change - * @param scale the relative final size scaling + * @param rate the rate of change + * @param scale the relative final size scaling */ public void updateTarget(double rate, double scale) { if (scale == 1) { return; } - + if (hasRegions) { if (scale < 1) { rate = Math.min(rate, targetRegionVolumes.get(Region.DEFAULT)); @@ -444,7 +447,7 @@ public void updateTarget(double rate, double scale) { double updateVolume = targetRegionVolumes.get(Region.DEFAULT) - targetVolume; targetRegionVolumes.put(Region.DEFAULT, updateVolume); } - + if (scale > 1) { targetVolume += rate; targetVolume = Math.min(targetVolume, scale * criticalVolume); @@ -452,51 +455,51 @@ public void updateTarget(double rate, double scale) { targetVolume -= rate; targetVolume = Math.max(targetVolume, scale * criticalVolume); } - + targetSurface = location.convertSurface(targetVolume, criticalHeight); - + if (hasRegions) { double updateVolume = targetRegionVolumes.get(Region.DEFAULT) + targetVolume; targetRegionVolumes.put(Region.DEFAULT, updateVolume); - + double criticalRegionHeight = criticalRegionHeights.get(Region.DEFAULT); double updateSurface = location.convertSurface(updateVolume, criticalRegionHeight); targetRegionSurfaces.put(Region.DEFAULT, updateSurface); } } - + /** * Updates target volume and surface area for a region. - *

- * If the region is the DEFAULT region, then updates are the same as for a - * cell without regions. * - * @param region the region - * @param rate the rate of change - * @param scale the relative final size scaling + *

If the region is the DEFAULT region, then updates are the same as for a cell without + * regions. + * + * @param region the region + * @param rate the rate of change + * @param scale the relative final size scaling */ public void updateTarget(Region region, double rate, double scale) { if (!hasRegions || scale == 1) { return; } - + if (region == Region.DEFAULT) { updateTarget(rate, scale); return; } - + if (scale > 1) { rate = Math.min(rate, targetRegionVolumes.get(Region.DEFAULT)); } - + double criticalRegionVolume = criticalRegionVolumes.get(region); double criticalRegionHeight = criticalRegionHeights.get(region); - + double updateVolume = targetRegionVolumes.get(region); - + double preUpdateVolume = targetRegionVolumes.get(Region.DEFAULT) + updateVolume; targetRegionVolumes.put(Region.DEFAULT, preUpdateVolume); - + if (scale > 1) { updateVolume += rate; updateVolume = Math.min(updateVolume, scale * criticalRegionVolume); @@ -504,19 +507,19 @@ public void updateTarget(Region region, double rate, double scale) { updateVolume -= rate; updateVolume = Math.max(updateVolume, scale * criticalRegionVolume); } - + targetRegionVolumes.put(region, updateVolume); double updateSurface = location.convertSurface(updateVolume, criticalRegionHeight); targetRegionSurfaces.put(region, updateSurface); - + double postUpdateVolume = targetRegionVolumes.get(Region.DEFAULT) - updateVolume; targetRegionVolumes.put(Region.DEFAULT, postUpdateVolume); - + double defaultRegionHeight = criticalRegionHeights.get(Region.DEFAULT); double postUpdateSurface = location.convertSurface(postUpdateVolume, defaultRegionHeight); targetRegionSurfaces.put(Region.DEFAULT, postUpdateSurface); } - + @Override public CellContainer convert() { if (hasRegions) { @@ -524,14 +527,33 @@ public CellContainer convert() { for (Region region : location.getRegions()) { regionVolumes.put(region, (int) location.getVolume(region)); } - - return new PottsCellContainer(id, parent, pop, age, divisions, state, - ((PottsModule) module).getPhase(), (int) getVolume(), regionVolumes, - criticalVolume, criticalHeight, criticalRegionVolumes, criticalRegionHeights); + + return new PottsCellContainer( + id, + parent, + pop, + age, + divisions, + state, + ((PottsModule) module).getPhase(), + (int) getVolume(), + regionVolumes, + criticalVolume, + criticalHeight, + criticalRegionVolumes, + criticalRegionHeights); } else { - return new PottsCellContainer(id, parent, pop, age, divisions, state, - ((PottsModule) module).getPhase(), (int) getVolume(), - criticalVolume, criticalHeight); + return new PottsCellContainer( + id, + parent, + pop, + age, + divisions, + state, + ((PottsModule) module).getPhase(), + (int) getVolume(), + criticalVolume, + criticalHeight); } } } diff --git a/src/arcade/potts/agent/cell/PottsCellContainer.java b/src/arcade/potts/agent/cell/PottsCellContainer.java index 24341ce07..d1a847056 100644 --- a/src/arcade/potts/agent/cell/PottsCellContainer.java +++ b/src/arcade/potts/agent/cell/PottsCellContainer.java @@ -1,110 +1,138 @@ package arcade.potts.agent.cell; import java.util.EnumMap; +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.potts.agent.module.PottsModule; +import arcade.core.util.Parameters; import static arcade.potts.util.PottsEnums.Phase; import static arcade.potts.util.PottsEnums.Region; /** * Implementation of {@link CellContainer} for {@link PottsCell} agents. - *

- * The container can be instantiated for cells with or without regions. Cell - * parameters are drawn from the associated {@link PottsCellFactory} instance - * for the given population. + * + *

The container can be instantiated for cells with or without regions. Cell parameters are drawn + * from the associated {@link PottsCellFactory} instance for the given population. */ - public final class PottsCellContainer 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 [ticks]. */ public final int age; - + /** Number of divisions. */ public final int divisions; - + /** Cell state. */ public final CellState state; - + /** Cell phase. */ public final Phase phase; - + /** Cell size [voxels]. */ public final int voxels; - + /** Cell region sizes [voxels]. */ public final EnumMap regionVoxels; - + /** Critical cell volume [voxels]. */ public final double criticalVolume; - + /** Critical cell height [voxels]. */ public final double criticalHeight; - + /** Critical region cell volumes [voxels]. */ public final EnumMap criticalRegionVolumes; - + /** Critical region cell heights [voxels]. */ public final EnumMap criticalRegionHeights; - + /** * Creates a {@code PottsCellContainer} instance. - *

- * The container does not have any regions. * - * @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 phase the cell phase - * @param voxels the cell size - * @param criticalVolume the critical volume - * @param criticalHeight the critical height + *

The container does not have any regions. + * + * @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 phase the cell phase + * @param voxels the cell size + * @param criticalVolume the critical volume + * @param criticalHeight the critical height */ - public PottsCellContainer(int id, int parent, int pop, int age, int divisions, - CellState state, Phase phase, int voxels, - double criticalVolume, double criticalHeight) { - this(id, parent, pop, age, divisions, state, phase, voxels, - null, criticalVolume, criticalHeight, null, null); + public PottsCellContainer( + int id, + int parent, + int pop, + int age, + int divisions, + CellState state, + Phase phase, + int voxels, + double criticalVolume, + double criticalHeight) { + this( + id, + parent, + pop, + age, + divisions, + state, + phase, + voxels, + null, + criticalVolume, + criticalHeight, + null, + null); } - + /** * Creates a {@code PottsCellContainer} 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 phase the cell phase - * @param voxels the cell size - * @param regionVoxels the cell region sizes - * @param criticalVolume the critical volume - * @param criticalHeight the critical height - * @param criticalRegionVolumes the critical region volumes - * @param criticalRegionHeights the critical surface heights + * @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 phase the cell phase + * @param voxels the cell size + * @param regionVoxels the cell region sizes + * @param criticalVolume the critical volume + * @param criticalHeight the critical height + * @param criticalRegionVolumes the critical region volumes + * @param criticalRegionHeights the critical surface heights */ - public PottsCellContainer(int id, int parent, int pop, int age, int divisions, - CellState state, Phase phase, int voxels, - EnumMap regionVoxels, - double criticalVolume, double criticalHeight, - EnumMap criticalRegionVolumes, - EnumMap criticalRegionHeights) { + public PottsCellContainer( + int id, + int parent, + int pop, + int age, + int divisions, + CellState state, + Phase phase, + int voxels, + EnumMap regionVoxels, + double criticalVolume, + double criticalHeight, + EnumMap criticalRegionVolumes, + EnumMap criticalRegionHeights) { this.id = id; this.parent = parent; this.pop = pop; @@ -119,43 +147,34 @@ public PottsCellContainer(int id, int parent, int pop, int age, int divisions, this.criticalRegionVolumes = criticalRegionVolumes; this.criticalRegionHeights = criticalRegionHeights; } - + @Override - public int getID() { return id; } - + public int getID() { + return id; + } + @Override - public Cell convert(CellFactory factory, Location location) { - return convert((PottsCellFactory) factory, location); + public Cell convert(CellFactory factory, Location location, MersenneTwisterFast random) { + return convert(factory, location, random, null); } - - /** - * Converts the cell container into a {@link PottsCell}. - * - * @param factory the cell factory instance - * @param location the cell location - * @return a {@link PottsCell} instance - */ - private Cell convert(PottsCellFactory 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. - PottsCell cell; - - if (factory.popToRegions.get(pop)) { - cell = new PottsCell(id, parent, pop, state, age, divisions, - location, true, parameters, criticalVolume, criticalHeight, - criticalRegionVolumes, criticalRegionHeights); - } else { - cell = new PottsCell(id, parent, pop, state, age, divisions, - location, false, parameters, criticalVolume, criticalHeight, - null, null); + switch (popParameters.get("CLASS")) { + default: + case "stem": + return new PottsCellStem(this, location, parameters, links); } - - // Update cell module. - PottsModule module = (PottsModule) cell.getModule(); - module.setPhase(phase); - - return cell; } } diff --git a/src/arcade/potts/agent/cell/PottsCellFactory.java b/src/arcade/potts/agent/cell/PottsCellFactory.java index e352c095b..4d040f77a 100644 --- a/src/arcade/potts/agent/cell/PottsCellFactory.java +++ b/src/arcade/potts/agent/cell/PottsCellFactory.java @@ -8,68 +8,53 @@ import ec.util.MersenneTwisterFast; import arcade.core.agent.cell.*; import arcade.core.sim.Series; -import arcade.core.util.Distribution; +import arcade.core.util.GrabBag; import arcade.core.util.MiniBox; +import arcade.core.util.Parameters; import static arcade.potts.util.PottsEnums.Phase; import static arcade.potts.util.PottsEnums.Region; import static arcade.potts.util.PottsEnums.State; /** * Implementation of {@link CellFactory} for {@link PottsCell} 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 PottsCellContainer} to instantiate a {@link PottsCell} - * agent. + * + *

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 + * PottsCellContainer} to instantiate a {@link PottsCell} agent. */ - public final class PottsCellFactory implements CellFactory { /** Random number generator instance. */ MersenneTwisterFast random; - - /** Map of population to critical volumes. */ - HashMap popToCriticalVolumes; - - /** Map of population to critical heights. */ - HashMap popToCriticalHeights; - + /** Map of population to parameters. */ - HashMap popToParameters; - + final HashMap popToParameters; + + /** Map of population to linked populations. */ + final HashMap popToLinks; + /** Map of population to number of regions. */ - HashMap popToRegions; - - /** Map of population to region critical volumes. */ - HashMap> popToCriticalRegionVolumes; - - /** Map of population to region critical heights. */ - HashMap> popToCriticalRegionHeights; - + final HashMap popToRegions; + /** Map of population to list of ids. */ public final HashMap> popToIDs; - + /** Map of id to cell. */ public final HashMap cells; - - /** - * Creates a factory for making {@link PottsCell} instances. - */ + + /** Creates a factory for making {@link PottsCell} instances. */ public PottsCellFactory() { cells = new HashMap<>(); - popToCriticalVolumes = new HashMap<>(); - popToCriticalHeights = new HashMap<>(); popToParameters = new HashMap<>(); + popToLinks = new HashMap<>(); popToRegions = new HashMap<>(); - popToCriticalRegionVolumes = new HashMap<>(); - popToCriticalRegionHeights = new HashMap<>(); popToIDs = new HashMap<>(); } - + /** * {@inheritDoc} - *

- * Regardless of loader, the population settings are parsed to get critical, - * values used for instantiating cells. + * + *

Regardless of loader, the population settings are parsed to get critical, values used for + * instantiating cells. */ @Override public void initialize(Series series, MersenneTwisterFast random) { @@ -81,19 +66,28 @@ public void initialize(Series series, MersenneTwisterFast random) { createCells(series); } } - + + @Override + public MiniBox getParameters(int pop) { + return popToParameters.get(pop); + } + + @Override + public GrabBag getLinks(int pop) { + return popToLinks.get(pop); + } + /** * {@inheritDoc} - *

- * 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 containers = series.loader.loadCells(); - + // Population sizes. HashMap popToSize = new HashMap<>(); for (MiniBox population : series.populations.values()) { @@ -101,7 +95,7 @@ public void loadCells(Series series) { int pop = population.getInt("CODE"); popToSize.put(pop, n); } - + // Map loaded container to factory. for (CellContainer container : containers) { PottsCellContainer cellContainer = (PottsCellContainer) container; @@ -112,126 +106,127 @@ public void loadCells(Series series) { } } } - + /** * {@inheritDoc} - *

- * For each population specified in the given series, containers are created - * until the population size is met. Containers are assigned regions if they - * exist. + * + *

For each population specified in the given series, containers are created until the + * population size is met. Containers are assigned regions if they exist. */ @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 = population.getInt("INIT"); int pop = population.getInt("CODE"); - boolean regions = popToRegions.get(pop); - - Distribution volumes = popToCriticalVolumes.get(pop); - Distribution heights = popToCriticalHeights.get(pop); - EnumMap regionVolumes = popToCriticalRegionVolumes.get(pop); - EnumMap regionHeights = popToCriticalRegionHeights.get(pop); - - for (int i = 0; i < n; i++) { - double criticalVolume = volumes.nextDouble(); - double criticalHeight = heights.nextDouble(); - EnumMap criticalRegionVolumes = null; - EnumMap criticalRegionHeights = null; - - int voxels = (int) Math.round(criticalVolume); - EnumMap regionVoxels = null; - - if (regions) { - regionVoxels = new EnumMap<>(Region.class); - criticalRegionVolumes = new EnumMap<>(Region.class); - criticalRegionHeights = new EnumMap<>(Region.class); - - for (Region region : Region.values()) { - if (region == Region.UNDEFINED) { - continue; - } - - double criticalRegionVolume = regionVolumes.get(region).nextDouble(); - double criticalRegionHeight = regionHeights.get(region).nextDouble(); - - if (region == Region.DEFAULT) { - criticalRegionVolume = criticalVolume; - criticalRegionHeight = criticalHeight; - } - - criticalRegionVolumes.put(region, criticalRegionVolume); - criticalRegionHeights.put(region, criticalRegionHeight); - regionVoxels.put(region, (int) Math.round(criticalRegionVolume)); - } - } - - PottsCellContainer container = new PottsCellContainer(id, 0, pop, 0, 0, - State.PROLIFERATIVE, Phase.PROLIFERATIVE_G1, voxels, regionVoxels, - criticalVolume, criticalHeight, - criticalRegionVolumes, criticalRegionHeights); + + for (int i = 0; i < init; i++) { + PottsCellContainer container = createCellForPopulation(id, pop); cells.put(id, container); - popToIDs.get(container.pop).add(container.id); + 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 + */ + public PottsCellContainer createCellForPopulation(int id, int pop) { + MiniBox population = popToParameters.get(pop); + boolean regions = popToRegions.get(pop); + Parameters parameters = new Parameters(population, null, random); + + double criticalVolume = parameters.getDouble("CRITICAL_VOLUME"); + double criticalHeight = parameters.getDouble("CRITICAL_HEIGHT"); + EnumMap criticalRegionVolumes = null; + EnumMap criticalRegionHeights = null; + + int voxels = (int) Math.round(criticalVolume); + EnumMap regionVoxels = null; + + if (regions) { + regionVoxels = new EnumMap<>(Region.class); + criticalRegionVolumes = new EnumMap<>(Region.class); + criticalRegionHeights = new EnumMap<>(Region.class); + + for (Region region : Region.values()) { + if (region == Region.UNDEFINED) { + continue; + } + + double criticalRegionVolume = parameters.getDouble("CRITICAL_VOLUME_" + region); + double criticalRegionHeight = parameters.getDouble("CRITICAL_HEIGHT_" + region); + + if (region == Region.DEFAULT) { + criticalRegionVolume = criticalVolume; + criticalRegionHeight = criticalHeight; + } + + criticalRegionVolumes.put(region, criticalRegionVolume); + criticalRegionHeights.put(region, criticalRegionHeight); + regionVoxels.put(region, (int) Math.round(criticalRegionVolume)); + } + } + + return new PottsCellContainer( + id, + 0, + pop, + 0, + 0, + State.PROLIFERATIVE, + Phase.PROLIFERATIVE_G1, + voxels, + regionVoxels, + criticalVolume, + criticalHeight, + criticalRegionVolumes, + criticalRegionHeights); + } + /** * 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 keySet = series.populations.keySet(); - + for (String key : keySet) { MiniBox population = series.populations.get(key); int pop = population.getInt("CODE"); popToIDs.put(pop, new HashSet<>()); popToParameters.put(pop, series.populations.get(key)); - - double muVolume = population.getDouble("CRITICAL_VOLUME_MEAN"); - double sigmaVolume = population.getDouble("CRITICAL_VOLUME_STDEV"); - popToCriticalVolumes.put(pop, new Distribution(muVolume, sigmaVolume, random)); - - double muHeight = population.getDouble("CRITICAL_HEIGHT_MEAN"); - double sigmaHeight = population.getDouble("CRITICAL_HEIGHT_STDEV"); - popToCriticalHeights.put(pop, new Distribution(muHeight, sigmaHeight, random)); - - popToRegions.put(pop, false); - + + // Get population links. + MiniBox linksBox = population.filter("(LINK)"); + ArrayList linkKeys = linksBox.getKeys(); + GrabBag links = null; + + if (linkKeys.size() > 0) { + links = new GrabBag(); + for (String linkKey : linkKeys) { + int popLink = series.populations.get(linkKey).getInt("CODE"); + links.add(popLink, linksBox.getDouble(linkKey)); + } + } + + popToLinks.put(pop, links); + // Get regions (if they exist). + popToRegions.put(pop, false); MiniBox regionBox = population.filter("(REGION)"); ArrayList regionKeys = regionBox.getKeys(); - + if (regionKeys.size() > 0) { popToRegions.put(pop, true); - EnumMap criticalRegionVolumes = new EnumMap<>(Region.class); - EnumMap criticalRegionHeights = new EnumMap<>(Region.class); - - for (String regionKey : regionKeys) { - Region region = Region.valueOf(regionKey); - - double muVolumeRegion = - population.getDouble("CRITICAL_VOLUME_MEAN_" + regionKey); - double sigmaVolumeRegion = - population.getDouble("CRITICAL_VOLUME_STDEV_" + regionKey); - criticalRegionVolumes.put(region, - new Distribution(muVolumeRegion, sigmaVolumeRegion, random)); - - double muHeightRegion = - population.getDouble("CRITICAL_HEIGHT_MEAN_" + regionKey); - double sigmaHeightRegion = - population.getDouble("CRITICAL_HEIGHT_STDEV_" + regionKey); - criticalRegionHeights.put(region, - new Distribution(muHeightRegion, sigmaHeightRegion, random)); - } - - popToCriticalRegionVolumes.put(pop, criticalRegionVolumes); - popToCriticalRegionHeights.put(pop, criticalRegionHeights); } } } diff --git a/src/arcade/potts/agent/cell/PottsCellStem.java b/src/arcade/potts/agent/cell/PottsCellStem.java new file mode 100644 index 000000000..6d0d15e4e --- /dev/null +++ b/src/arcade/potts/agent/cell/PottsCellStem.java @@ -0,0 +1,93 @@ +package arcade.potts.agent.cell; + +import java.util.EnumMap; +import ec.util.MersenneTwisterFast; +import arcade.core.agent.cell.CellState; +import arcade.core.env.location.Location; +import arcade.core.util.GrabBag; +import arcade.core.util.Parameters; +import arcade.potts.agent.module.PottsModuleApoptosisSimple; +import arcade.potts.agent.module.PottsModuleAutosis; +import arcade.potts.agent.module.PottsModuleNecrosis; +import arcade.potts.agent.module.PottsModuleProliferationSimple; +import arcade.potts.agent.module.PottsModuleQuiescence; +import static arcade.potts.util.PottsEnums.Region; +import static arcade.potts.util.PottsEnums.State; + +/** + * Extension of {@link PottsCell} for stem cells. + * + *

This is the default cell type for Potts models. + */ +public final class PottsCellStem extends PottsCell { + /** + * Creates a stem {@code PottsCell} agent. + * + * @param container the cell container + * @param location the {@link Location} of the cell + * @param parameters the dictionary of parameters + */ + public PottsCellStem(PottsCellContainer container, Location location, Parameters parameters) { + this(container, location, parameters, null); + } + + /** + * Creates a stem {@code PottsCell} 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 PottsCellStem( + PottsCellContainer container, Location location, Parameters parameters, GrabBag links) { + super(container, location, parameters, links); + } + + @Override + public PottsCellContainer make(int newID, CellState newState, MersenneTwisterFast random) { + divisions++; + + int newPop = links == null ? pop : links.next(random); + + return new PottsCellContainer( + newID, + id, + newPop, + age, + divisions, + newState, + null, + 0, + (hasRegions ? new EnumMap<>(Region.class) : null), + criticalVolume, + criticalHeight, + criticalRegionVolumes, + criticalRegionHeights); + } + + @Override + void setStateModule(CellState newState) { + switch ((State) newState) { + case QUIESCENT: + module = new PottsModuleQuiescence(this); + break; + case PROLIFERATIVE: + module = new PottsModuleProliferationSimple(this); + break; + case APOPTOTIC: + module = new PottsModuleApoptosisSimple(this); + break; + case NECROTIC: + module = new PottsModuleNecrosis(this); + break; + case AUTOTIC: + module = new PottsModuleAutosis(this); + break; + default: + // State must be one of the above cases. + module = null; + break; + } + } +} diff --git a/src/arcade/potts/agent/module/PottsModule.java b/src/arcade/potts/agent/module/PottsModule.java index fec2d00a0..d7073c37a 100644 --- a/src/arcade/potts/agent/module/PottsModule.java +++ b/src/arcade/potts/agent/module/PottsModule.java @@ -8,64 +8,62 @@ /** * Abstract implementation of {@link Module} for {@link PottsCell} agents. - *

- * Each module represents the behaviors of a cell in a given state. Module - * behaviors are further divided by phases, such as the phases of the cell cycle - * for a cell in the proliferative state. + * + *

Each module represents the behaviors of a cell in a given state. Module behaviors are further + * divided by phases, such as the phases of the cell cycle for a cell in the proliferative state. */ - public abstract class PottsModule implements Module { /** The {@link PottsCell} object the module is associated with. */ final PottsCell cell; - + /** Code for module phase. */ Phase phase; - + /** Tracker for number of steps for current phase. */ int currentSteps; - + /** Poisson factory for module. */ PoissonFactory poissonFactory; - + /** * Creates a module for a {@link PottsCell} state. * - * @param cell the {@link PottsCell} object + * @param cell the {@link PottsCell} object */ public PottsModule(PottsCell cell) { this.cell = cell; this.poissonFactory = Poisson::new; } - + /** * Gets the module phase. * - * @return the module phase + * @return the module phase */ - public Phase getPhase() { return phase; } - + public Phase getPhase() { + return phase; + } + /** * Sets the module phase. - *

- * Current steps count is reset to zero. * - * @param phase the module phase + *

Current steps count is reset to zero. + * + * @param phase the module phase */ public void setPhase(Phase phase) { this.phase = phase; this.currentSteps = 0; } - - /** - * A {@code PoissonFactory} object instantiates Poisson distributions. - */ + + /** A {@code PoissonFactory} object instantiates Poisson distributions. */ interface PoissonFactory { /** * Creates instance of Poisson. * - * @param lambda the Poisson distribution lambda - * @param random the random number generator - * @return a Poisson distribution instance + * @param lambda the Poisson distribution lambda + * @param random the random number generator + * @return a Poisson distribution instance */ Poisson createPoisson(double lambda, MersenneTwisterFast random); } diff --git a/src/arcade/potts/agent/module/PottsModuleApoptosis.java b/src/arcade/potts/agent/module/PottsModuleApoptosis.java index a3f9b31a9..08792f1df 100644 --- a/src/arcade/potts/agent/module/PottsModuleApoptosis.java +++ b/src/arcade/potts/agent/module/PottsModuleApoptosis.java @@ -10,27 +10,26 @@ /** * Extension of {@link PottsModule} for apoptosis. - *

- * During apoptosis, cells cycle through early and late phases. Once the cell - * completes the late phase, it is removed from the simulation. + * + *

During apoptosis, cells cycle through early and late phases. Once the cell completes the late + * phase, it is removed from the simulation. */ - public abstract class PottsModuleApoptosis extends PottsModule { /** * Creates an apoptosis {@code Module} for the given {@link PottsCell}. * - * @param cell the {@link PottsCell} the module is associated with + * @param cell the {@link PottsCell} the module is associated with */ public PottsModuleApoptosis(PottsCell cell) { super(cell); setPhase(Phase.APOPTOTIC_EARLY); } - + /** * Calls the step method for the current simple phase. * - * @param random the random number generator - * @param sim the simulation instance + * @param random the random number generator + * @param sim the simulation instance */ public void step(MersenneTwisterFast random, Simulation sim) { switch (phase) { @@ -44,40 +43,40 @@ public void step(MersenneTwisterFast random, Simulation sim) { break; } } - + /** * Performs actions for early apoptosis phase. * - * @param random the random number generator + * @param random the random number generator */ abstract void stepEarly(MersenneTwisterFast random); - + /** * Performs actions for late apoptosis phase. * - * @param random the random number generator - * @param sim the simulation instance + * @param random the random number generator + * @param sim the simulation instance */ abstract void stepLate(MersenneTwisterFast random, Simulation sim); - + /** * Removes a cell from the simulation. - *

- * The location is cleared, along with any regions. The cell is then removed - * from the grid and simulation schedule. * - * @param sim the simulation instance + *

The location is cleared, along with any regions. The cell is then removed from the grid + * and simulation schedule. + * + * @param sim the simulation instance */ void removeCell(Simulation sim) { Potts potts = ((PottsSimulation) sim).getPotts(); - + // Clear the location. ((PottsLocation) cell.getLocation()).clear(potts.ids, potts.regions); - + // Remove the cell from the grid. sim.getGrid().removeObject(cell, null); potts.deregister(cell); - + // Stop stepping the cell. cell.stop(); } diff --git a/src/arcade/potts/agent/module/PottsModuleApoptosisSimple.java b/src/arcade/potts/agent/module/PottsModuleApoptosisSimple.java index 05b59d2b6..d5d3ec4f6 100644 --- a/src/arcade/potts/agent/module/PottsModuleApoptosisSimple.java +++ b/src/arcade/potts/agent/module/PottsModuleApoptosisSimple.java @@ -3,59 +3,52 @@ import sim.util.distribution.Poisson; import ec.util.MersenneTwisterFast; import arcade.core.sim.Simulation; -import arcade.core.util.MiniBox; +import arcade.core.util.Parameters; import arcade.potts.agent.cell.PottsCell; import static arcade.potts.util.PottsEnums.Phase; import static arcade.potts.util.PottsEnums.Region; -/** - * Extension of {@link PottsModuleApoptosis} with Poisson transitions. - */ - +/** Extension of {@link PottsModuleApoptosis} with Poisson transitions. */ public class PottsModuleApoptosisSimple extends PottsModuleApoptosis { - /** Threshold for critical volume size checkpoint. */ - static final double SIZE_CHECKPOINT = 0.95; - /** Target ratio of critical volume for early apoptosis size checkpoint. */ static final double EARLY_SIZE_TARGET = 0.99; - + /** Target ratio of critical volume for late apoptosis size checkpoint. */ static final double LATE_SIZE_TARGET = 0.25; - + /** Event rate for early apoptosis (steps/tick). */ final double rateEarly; - + /** Event rate for late apoptosis (steps/tick). */ final double rateLate; - + /** Steps for early apoptosis (steps). */ final int stepsEarly; - + /** Steps for late apoptosis (steps). */ final int stepsLate; - + /** Rate of cytoplasmic water loss (voxels/tick). */ final double waterLossRate; - + /** Rate of cytoplasmic blebbing (voxels/tick). */ final double cytoBlebbingRate; - + /** Rate of nuclear pyknosis (voxels/tick). */ final double nucleusPyknosisRate; - + /** Rate of nuclear fragmentation (voxels/tick). */ final double nucleusFragmentationRate; - + /** - * Creates a simple apoptosis {@code Module} for the given - * {@link PottsCell}. + * Creates a simple apoptosis {@code Module} for the given {@link PottsCell}. * - * @param cell the {@link PottsCell} the module is associated with + * @param cell the {@link PottsCell} the module is associated with */ public PottsModuleApoptosisSimple(PottsCell cell) { super(cell); - - MiniBox parameters = cell.getParameters(); + + Parameters parameters = cell.getParameters(); rateEarly = parameters.getDouble("apoptosis/RATE_EARLY"); rateLate = parameters.getDouble("apoptosis/RATE_LATE"); stepsEarly = parameters.getInt("apoptosis/STEPS_EARLY"); @@ -65,24 +58,24 @@ public PottsModuleApoptosisSimple(PottsCell cell) { nucleusPyknosisRate = parameters.getDouble("apoptosis/NUCLEUS_PYKNOSIS_RATE"); nucleusFragmentationRate = parameters.getDouble("apoptosis/NUCLEUS_FRAGMENTATION_RATE"); } - + /** * {@inheritDoc} - *

- * Cell decreases in size due to cytoplasmic water loss and nuclear - * pyknosis. Cell will transition to late apoptosis after completing - * {@code STEPS_EARLY} steps at an average rate of {@code RATE_EARLY}. + * + *

Cell decreases in size due to cytoplasmic water loss and nuclear pyknosis. Cell will + * transition to late apoptosis after completing {@code STEPS_EARLY} steps at an average rate of + * {@code RATE_EARLY}. */ @Override void stepEarly(MersenneTwisterFast random) { // Decrease size of cell. cell.updateTarget(waterLossRate, EARLY_SIZE_TARGET); - + // Decrease size of nucleus (if cell has regions). if (cell.hasRegions()) { cell.updateTarget(Region.NUCLEUS, nucleusPyknosisRate, EARLY_SIZE_TARGET); } - + // Check for phase transition. Poisson poisson = poissonFactory.createPoisson(rateEarly, random); currentSteps += poisson.nextInt(); @@ -90,33 +83,28 @@ void stepEarly(MersenneTwisterFast random) { setPhase(Phase.APOPTOTIC_LATE); } } - + /** * {@inheritDoc} - *

- * Cell continues to decrease in size due to cytoplasm blebbing and nuclear - * fragmentation. Cell will complete apoptosis after completing - * {@code STEPS_LATE} steps at an average rate of {@code RATE_LATE} or if - * the total cell volume falls below a threshold of - * {@code APOPTOSIS_CHECKPOINT} times the critical size. Cell must be less - * than {@code LATE_SIZE_CHECKPOINT} times the critical size. + * + *

Cell continues to decrease in size due to cytoplasm blebbing and nuclear fragmentation. + * Cell will complete apoptosis after completing {@code STEPS_LATE} steps at an average rate of + * {@code RATE_LATE}. */ @Override void stepLate(MersenneTwisterFast random, Simulation sim) { // Decrease size of cell. cell.updateTarget(cytoBlebbingRate, LATE_SIZE_TARGET); - boolean sizeCheck = cell.getVolume() <= SIZE_CHECKPOINT - * LATE_SIZE_TARGET * cell.getCriticalVolume(); - + // Decrease size of nucleus (if cell has regions). if (cell.hasRegions()) { cell.updateTarget(Region.NUCLEUS, nucleusFragmentationRate, 0); } - + // Check for completion of late phase. Poisson poisson = poissonFactory.createPoisson(rateLate, random); currentSteps += poisson.nextInt(); - if (currentSteps >= stepsLate && sizeCheck) { + if (currentSteps >= stepsLate) { removeCell(sim); setPhase(Phase.APOPTOSED); } diff --git a/src/arcade/potts/agent/module/PottsModuleAutosis.java b/src/arcade/potts/agent/module/PottsModuleAutosis.java index eb160c34f..24c738dac 100644 --- a/src/arcade/potts/agent/module/PottsModuleAutosis.java +++ b/src/arcade/potts/agent/module/PottsModuleAutosis.java @@ -4,18 +4,17 @@ import arcade.core.sim.Simulation; import arcade.potts.agent.cell.PottsCell; -/** - * Extension of {@link PottsModule} for autosis. - */ - +/** Extension of {@link PottsModule} for autosis. */ public class PottsModuleAutosis extends PottsModule { /** * Creates an autosis {@code Module} for the given {@link PottsCell}. * - * @param cell the {@link PottsCell} the module is associated with + * @param cell the {@link PottsCell} the module is associated with */ - public PottsModuleAutosis(PottsCell cell) { super(cell); } - + public PottsModuleAutosis(PottsCell cell) { + super(cell); + } + @Override - public void step(MersenneTwisterFast random, Simulation sim) { } + public void step(MersenneTwisterFast random, Simulation sim) {} } diff --git a/src/arcade/potts/agent/module/PottsModuleNecrosis.java b/src/arcade/potts/agent/module/PottsModuleNecrosis.java index a35127b84..0fdd0435a 100644 --- a/src/arcade/potts/agent/module/PottsModuleNecrosis.java +++ b/src/arcade/potts/agent/module/PottsModuleNecrosis.java @@ -4,18 +4,17 @@ import arcade.core.sim.Simulation; import arcade.potts.agent.cell.PottsCell; -/** - * Extension of {@link PottsModule} for necrosis. - */ - +/** Extension of {@link PottsModule} for necrosis. */ public class PottsModuleNecrosis extends PottsModule { /** * Creates a necrosis {@code Module} for the given {@link PottsCell}. * - * @param cell the {@link PottsCell} the module is associated with + * @param cell the {@link PottsCell} the module is associated with */ - public PottsModuleNecrosis(PottsCell cell) { super(cell); } - + public PottsModuleNecrosis(PottsCell cell) { + super(cell); + } + @Override - public void step(MersenneTwisterFast random, Simulation sim) { } + public void step(MersenneTwisterFast random, Simulation sim) {} } diff --git a/src/arcade/potts/agent/module/PottsModuleProliferation.java b/src/arcade/potts/agent/module/PottsModuleProliferation.java index e888a881c..c1838e53e 100644 --- a/src/arcade/potts/agent/module/PottsModuleProliferation.java +++ b/src/arcade/potts/agent/module/PottsModuleProliferation.java @@ -1,6 +1,7 @@ package arcade.potts.agent.module; import ec.util.MersenneTwisterFast; +import arcade.core.agent.cell.CellContainer; import arcade.core.env.location.Location; import arcade.core.sim.Simulation; import arcade.potts.agent.cell.PottsCell; @@ -12,27 +13,26 @@ /** * Extension of {@link PottsModule} for proliferation. - *

- * During proliferation, cells cycle through G1, S, G2, and M phases. Once the - * cell complete M phase, it divides to create a new daughter cell. + * + *

During proliferation, cells cycle through G1, S, G2, and M phases. Once the cell complete M + * phase, it divides to create a new daughter cell. */ - public abstract class PottsModuleProliferation extends PottsModule { /** * Creates a proliferation {@code Module} for the given {@link PottsCell}. * - * @param cell the {@link PottsCell} the module is associated with + * @param cell the {@link PottsCell} the module is associated with */ public PottsModuleProliferation(PottsCell cell) { super(cell); setPhase(Phase.PROLIFERATIVE_G1); } - + /** * Calls the step method for the current simple phase. * - * @param random the random number generator - * @param sim the simulation instance + * @param random the random number generator + * @param sim the simulation instance */ public void step(MersenneTwisterFast random, Simulation sim) { switch (phase) { @@ -52,58 +52,61 @@ public void step(MersenneTwisterFast random, Simulation sim) { break; } } - + /** * Performs actions for G1 phase. * - * @param random the random number generator + * @param random the random number generator */ abstract void stepG1(MersenneTwisterFast random); - + /** * Performs actions for S phase. * - * @param random the random number generator + * @param random the random number generator */ abstract void stepS(MersenneTwisterFast random); - + /** * Performs actions for G2 phase. * - * @param random the random number generator + * @param random the random number generator */ abstract void stepG2(MersenneTwisterFast random); - + /** * Performs actions for M phase. * - * @param random the random number generator - * @param sim the simulation instance + * @param random the random number generator + * @param sim the simulation instance */ abstract void stepM(MersenneTwisterFast random, Simulation sim); - + /** * Adds a cell to the simulation. - *

- * The cell location is split, along with any regions. The new cell is - * created, initialized, and added to the schedule. Both cells are reset and - * remain in the proliferative state. * - * @param random the random number generator - * @param sim the simulation instance + *

The cell location is split, along with any regions. The new cell is created, initialized, + * and added to the schedule. Both cells are reset and remain in the proliferative state. + * + * @param random the random number generator + * @param sim the simulation instance */ void addCell(MersenneTwisterFast random, Simulation sim) { Potts potts = ((PottsSimulation) sim).getPotts(); - + // Split current location. Location newLocation = ((PottsLocation) cell.getLocation()).split(random); - + // Reset current cell. cell.reset(potts.ids, potts.regions); - + // Create and schedule new cell. int newID = sim.getID(); - PottsCell newCell = cell.make(newID, State.PROLIFERATIVE, newLocation, random); + CellContainer newContainer = cell.make(newID, State.PROLIFERATIVE, random); + PottsCell newCell = + (PottsCell) + newContainer.convert( + sim.getCellFactory(), newLocation, random, cell.getParameters()); sim.getGrid().addObject(newCell, null); potts.register(newCell); newCell.reset(potts.ids, potts.regions); diff --git a/src/arcade/potts/agent/module/PottsModuleProliferationSimple.java b/src/arcade/potts/agent/module/PottsModuleProliferationSimple.java index 3f7678e54..ea3d50773 100644 --- a/src/arcade/potts/agent/module/PottsModuleProliferationSimple.java +++ b/src/arcade/potts/agent/module/PottsModuleProliferationSimple.java @@ -3,7 +3,7 @@ import sim.util.distribution.Poisson; import ec.util.MersenneTwisterFast; import arcade.core.sim.Simulation; -import arcade.core.util.MiniBox; +import arcade.core.util.Parameters; import arcade.potts.agent.cell.PottsCell; import arcade.potts.env.location.PottsLocations; import arcade.potts.sim.Potts; @@ -12,63 +12,59 @@ import static arcade.potts.util.PottsEnums.Region; import static arcade.potts.util.PottsEnums.State; -/** - * Extension of {@link PottsModuleProliferation} with Poisson transitions. - */ - +/** Extension of {@link PottsModuleProliferation} with Poisson transitions. */ public class PottsModuleProliferationSimple extends PottsModuleProliferation { /** Threshold for critical volume size checkpoint. */ static final double SIZE_CHECKPOINT = 0.95; - + /** Target ratio of critical volume for division size checkpoint. */ static final double SIZE_TARGET = 2; - + /** Event rate for G1 phase (steps/tick). */ final double rateG1; - + /** Event rate for S phase (steps/tick). */ final double rateS; - + /** Event rate for G2 phase (steps/tick). */ final double rateG2; - + /** Event rate for M phase (steps/tick). */ final double rateM; - + /** Steps for G1 phase (steps). */ final int stepsG1; - + /** Steps for S phase (steps). */ final int stepsS; - + /** Steps for G2 phase (steps). */ final int stepsG2; - + /** Steps for M phase (steps). */ final int stepsM; - + /** Overall growth rate for cell (voxels/tick). */ final double cellGrowthRate; - + /** Overall growth rate for nucleus (voxels/tick). */ final double nucleusGrowthRate; - + /** Basal rate of apoptosis (ticks^-1). */ final double basalApoptosisRate; - + /** Fraction of nuclear volume when condensed. */ final double nucleusCondFraction; - + /** - * Creates a simple proliferation {@code Module} for the given - * {@link PottsCell}. + * Creates a simple proliferation {@code Module} for the given {@link PottsCell}. * - * @param cell the {@link PottsCell} the module is associated with + * @param cell the {@link PottsCell} the module is associated with */ public PottsModuleProliferationSimple(PottsCell cell) { super(cell); - - MiniBox parameters = cell.getParameters(); + + Parameters parameters = cell.getParameters(); rateG1 = parameters.getDouble("proliferation/RATE_G1"); rateS = parameters.getDouble("proliferation/RATE_S"); rateG2 = parameters.getDouble("proliferation/RATE_G2"); @@ -82,15 +78,14 @@ public PottsModuleProliferationSimple(PottsCell cell) { basalApoptosisRate = parameters.getDouble("proliferation/BASAL_APOPTOSIS_RATE"); nucleusCondFraction = parameters.getDouble("proliferation/NUCLEUS_CONDENSATION_FRACTION"); } - + /** * {@inheritDoc} - *

- * Cell increases in size toward a target of twice its critical size at a - * rate of {@code CELL_GROWTH_RATE}. Cell will transition to S phase after - * completing {@code STEPS_G1} steps at an average rate of {@code RATE_G1}. - * At each tick, cell may randomly apoptosis at a basal rate of - * {@code BASAL_APOPTOSIS_RATE}. + * + *

Cell increases in size toward a target of twice its critical size at a rate of {@code + * CELL_GROWTH_RATE}. Cell will transition to S phase after completing {@code STEPS_G1} steps at + * an average rate of {@code RATE_G1}. At each tick, cell may randomly apoptosis at a basal rate + * of {@code BASAL_APOPTOSIS_RATE}. */ @Override void stepG1(MersenneTwisterFast random) { @@ -99,16 +94,16 @@ void stepG1(MersenneTwisterFast random) { cell.setState(State.APOPTOTIC); return; } - + // Increase size of cell. cell.updateTarget(cellGrowthRate, SIZE_TARGET); - + // Increase size of nucleus (if cell has regions). if (cell.hasRegions() && cell.getVolume(Region.NUCLEUS) > cell.getCriticalVolume(Region.NUCLEUS)) { cell.updateTarget(Region.NUCLEUS, nucleusGrowthRate, SIZE_TARGET); } - + // Check for phase transition. Poisson poisson = poissonFactory.createPoisson(rateG1, random); currentSteps += poisson.nextInt(); @@ -116,24 +111,24 @@ void stepG1(MersenneTwisterFast random) { setPhase(Phase.PROLIFERATIVE_S); } } - + /** * {@inheritDoc} - *

- * Cell increases in size toward a target of twice its critical size at a - * rate of {@code CELL_GROWTH_RATE}. Cell will transition to G2 phase after - * completing {@code STEPS_S} steps at an average rate of {@code RATE_S}. + * + *

Cell increases in size toward a target of twice its critical size at a rate of {@code + * CELL_GROWTH_RATE}. Cell will transition to G2 phase after completing {@code STEPS_S} steps at + * an average rate of {@code RATE_S}. */ @Override void stepS(MersenneTwisterFast random) { // Increase size of cell. cell.updateTarget(cellGrowthRate, SIZE_TARGET); - + // Increase size of nucleus (if cell has regions). if (cell.hasRegions()) { cell.updateTarget(Region.NUCLEUS, nucleusGrowthRate, SIZE_TARGET); } - + // Check for phase transition. Poisson poisson = poissonFactory.createPoisson(rateS, random); currentSteps += poisson.nextInt(); @@ -141,15 +136,14 @@ void stepS(MersenneTwisterFast random) { setPhase(Phase.PROLIFERATIVE_G2); } } - + /** * {@inheritDoc} - *

- * Cell increases in size toward a target of twice its critical size at a - * rate of {@code CELL_GROWTH_RATE}. Cell will transition to M phase after - * completing {@code STEPS_G2} steps at an average rate of {@code RATE_G2}. - * At each tick, cell may randomly apoptosis at a basal rate of - * {@code BASAL_APOPTOSIS_RATE}. + * + *

Cell increases in size toward a target of twice its critical size at a rate of {@code + * CELL_GROWTH_RATE}. Cell will transition to M phase after completing {@code STEPS_G2} steps at + * an average rate of {@code RATE_G2}. At each tick, cell may randomly apoptosis at a basal rate + * of {@code BASAL_APOPTOSIS_RATE}. */ @Override void stepG2(MersenneTwisterFast random) { @@ -158,20 +152,23 @@ void stepG2(MersenneTwisterFast random) { cell.setState(State.APOPTOTIC); return; } - + // Increase size of cell. cell.updateTarget(cellGrowthRate, SIZE_TARGET); - boolean sizeCheck = cell.getVolume() >= SIZE_CHECKPOINT - * SIZE_TARGET * cell.getCriticalVolume(); - + boolean sizeCheck = + cell.getVolume() >= SIZE_CHECKPOINT * SIZE_TARGET * cell.getCriticalVolume(); + // Increase size of nucleus (if cell has regions). boolean sizeRegionCheck = true; if (cell.hasRegions()) { cell.updateTarget(Region.NUCLEUS, nucleusGrowthRate, SIZE_TARGET); - sizeRegionCheck = cell.getVolume(Region.NUCLEUS) >= SIZE_CHECKPOINT - * SIZE_TARGET * cell.getCriticalVolume(Region.NUCLEUS); + sizeRegionCheck = + cell.getVolume(Region.NUCLEUS) + >= SIZE_CHECKPOINT + * SIZE_TARGET + * cell.getCriticalVolume(Region.NUCLEUS); } - + // Check for phase transition. Poisson poisson = poissonFactory.createPoisson(rateG2, random); currentSteps += poisson.nextInt(); @@ -179,41 +176,44 @@ void stepG2(MersenneTwisterFast random) { setPhase(Phase.PROLIFERATIVE_M); } } - + /** * {@inheritDoc} - *

- * Cell increases in size toward a target of twice its critical size at a - * rate of {@code CELL_GROWTH_RATE}. Cell will complete cell division after - * completing {@code STEPS_M} steps at an average rate of {@code RATE_M}. - * Cell must be greater than {@code SIZE_CHECKPOINT} times the critical - * size. + * + *

Cell increases in size toward a target of twice its critical size at a rate of {@code + * CELL_GROWTH_RATE}. Cell will complete cell division after completing {@code STEPS_M} steps at + * an average rate of {@code RATE_M}. Cell must be greater than {@code SIZE_CHECKPOINT} times + * the critical size. */ @Override void stepM(MersenneTwisterFast random, Simulation sim) { // Increase size of cell. cell.updateTarget(cellGrowthRate, SIZE_TARGET); - + // Update size of nucleus (if cell has regions). if (cell.hasRegions()) { double regionVolume = cell.getVolume(Region.NUCLEUS); double criticalVolume = cell.getCriticalVolume(Region.NUCLEUS); - + if (regionVolume > criticalVolume) { int target = (int) (nucleusCondFraction * criticalVolume); - + Potts potts = ((PottsSimulation) sim).getPotts(); PottsLocations location = (PottsLocations) cell.getLocation(); location.distribute(Region.NUCLEUS, target, random); location.update(cell.getID(), potts.ids, potts.regions); - - cell.setTargets(Region.DEFAULT, cell.getVolume(Region.DEFAULT), + + cell.setTargets( + Region.DEFAULT, + cell.getVolume(Region.DEFAULT), cell.getSurface(Region.DEFAULT)); - cell.setTargets(Region.NUCLEUS, cell.getVolume(Region.NUCLEUS), + cell.setTargets( + Region.NUCLEUS, + cell.getVolume(Region.NUCLEUS), cell.getSurface(Region.NUCLEUS)); } } - + // Check for phase transition. Poisson poisson = poissonFactory.createPoisson(rateM, random); currentSteps += poisson.nextInt(); diff --git a/src/arcade/potts/agent/module/PottsModuleQuiescence.java b/src/arcade/potts/agent/module/PottsModuleQuiescence.java index 30758b39b..9665486e9 100644 --- a/src/arcade/potts/agent/module/PottsModuleQuiescence.java +++ b/src/arcade/potts/agent/module/PottsModuleQuiescence.java @@ -4,18 +4,17 @@ import arcade.core.sim.Simulation; import arcade.potts.agent.cell.PottsCell; -/** - * Extension of {@link PottsModule} for quiescence. - */ - +/** Extension of {@link PottsModule} for quiescence. */ public class PottsModuleQuiescence extends PottsModule { /** * Creates a quiescence {@code Module} for the given {@link PottsCell}. * - * @param cell the {@link PottsCell} the module is associated with + * @param cell the {@link PottsCell} the module is associated with */ - public PottsModuleQuiescence(PottsCell cell) { super(cell); } - + public PottsModuleQuiescence(PottsCell cell) { + super(cell); + } + @Override - public void step(MersenneTwisterFast random, Simulation sim) { } + public void step(MersenneTwisterFast random, Simulation sim) {} } diff --git a/src/arcade/potts/env/grid/PottsGrid.java b/src/arcade/potts/env/grid/PottsGrid.java index 1b165bfea..79b7738fc 100644 --- a/src/arcade/potts/env/grid/PottsGrid.java +++ b/src/arcade/potts/env/grid/PottsGrid.java @@ -8,31 +8,29 @@ /** * Implementation of {@link Grid} for potts models. - *

- * {@code PottsGrid} uses the cell id as the index to map to agents. Index 0 is - * reserved for a {@code null} object representing non-cell voxels in the potts - * layer. + * + *

{@code PottsGrid} uses the cell id as the index to map to agents. Index 0 is reserved for a + * {@code null} object representing non-cell voxels in the potts layer. */ - public final class PottsGrid implements Grid { /** Map of ID to object. */ final HashMap objects; - + /** Collection of all objects in the grid. */ final Bag allObjects; - - /** - * Creates a {@link arcade.core.env.grid.Grid} for potts. - */ + + /** Creates a {@link arcade.core.env.grid.Grid} for potts. */ public PottsGrid() { objects = new HashMap<>(); allObjects = new Bag(); objects.put(0, null); } - + @Override - public Bag getAllObjects() { return allObjects; } - + public Bag getAllObjects() { + return allObjects; + } + @Override public void addObject(Object object, Location location) { if (object == null) { @@ -45,17 +43,17 @@ public void addObject(Object object, Location location) { allObjects.add(object); objects.put(index, object); } - + @Override public void removeObject(Object object, Location location) { int index = ((Cell) object).getID(); allObjects.remove(object); objects.remove(index); } - + @Override - public void moveObject(Object object, Location fromLocation, Location toLocation) { } - + public void moveObject(Object object, Location fromLocation, Location toLocation) {} + @Override public Object getObjectAt(int index) { return objects.get(index); diff --git a/src/arcade/potts/env/location/Location2D.java b/src/arcade/potts/env/location/Location2D.java index 7fe3bfab3..2f39a3a28 100644 --- a/src/arcade/potts/env/location/Location2D.java +++ b/src/arcade/potts/env/location/Location2D.java @@ -7,45 +7,44 @@ /** * Static location methods for 2D. - *

- * Interface defines generalized 2D voxel methods that can be applied for both - * {@link PottsLocation} objects (without regions) and {@link PottsLocations} - * objects (with regions). + * + *

Interface defines generalized 2D voxel methods that can be applied for both {@link + * PottsLocation} objects (without regions) and {@link PottsLocations} objects (with regions). */ - public interface Location2D { /** Equation power for surface area conversion. */ double EQUATION_PARAMETER_N = 0.53312428; - + /** Equation coefficient for surface area conversion. */ double EQUATION_PARAMETER_A = 0.7137145; - + /** Equation offset for surface area conversion. */ double EQUATION_PARAMETER_B = -0.95549169; - + /** List of valid 2D directions. */ - Direction[] DIRECTIONS = new Direction[] { - Direction.YZ_PLANE, - Direction.ZX_PLANE, - Direction.POSITIVE_XY, - Direction.NEGATIVE_XY, - }; - + Direction[] DIRECTIONS = + new Direction[] { + Direction.YZ_PLANE, + Direction.ZX_PLANE, + Direction.POSITIVE_XY, + Direction.NEGATIVE_XY, + }; + /** * Calculate correction factor for surface area conversion. * - * @param volume the volume - * @return the correction factor + * @param volume the volume + * @return the correction factor */ static double getCorrection(double volume) { return EQUATION_PARAMETER_A * Math.pow(volume, EQUATION_PARAMETER_N) + EQUATION_PARAMETER_B; } - + /** * Gets list of neighbors of a given voxel. * - * @param focus the focus voxel - * @return the list of neighbor voxels + * @param focus the focus voxel + * @return the list of neighbor voxels */ static ArrayList getNeighbors(Voxel focus) { ArrayList neighbors = new ArrayList<>(); @@ -55,29 +54,29 @@ static ArrayList getNeighbors(Voxel focus) { } return neighbors; } - + /** * Converts volume and height to surface area. * - * @param volume the volume - * @param height the height - * @return the surface area + * @param volume the volume + * @param height the height + * @return the surface area */ static double convertSurface(double volume, double height) { double surface = 2 * Math.sqrt(Math.PI) * Math.sqrt(volume); double correction = getCorrection(volume); return Math.ceil(surface + correction); } - + /** * Calculates surface of location. * - * @param voxels the list of voxels - * @return the surface + * @param voxels the list of voxels + * @return the surface */ static int calculateSurface(ArrayList voxels) { int surface = 0; - + for (Voxel v : voxels) { for (int i = 0; i < NUMBER_NEIGHBORS; i++) { Voxel voxel = new Voxel(v.x + MOVES_X[i], v.y + MOVES_Y[i], v.z); @@ -86,33 +85,33 @@ static int calculateSurface(ArrayList voxels) { } } } - + return surface; } - + /** * Calculates height of location (z axis). - *

- * Height is always one if there is as least one voxel in the list of - * voxels. Otherwise, height is zero. * - * @param voxels the list of voxels - * @return the height + *

Height is always one if there is as least one voxel in the list of voxels. Otherwise, + * height is zero. + * + * @param voxels the list of voxels + * @return the height */ static int calculateHeight(ArrayList voxels) { return (voxels.size() > 0 ? 1 : 0); } - + /** * Calculates the local change in surface of the location. * - * @param voxels the list of voxels - * @param voxel the voxel the update is centered in - * @return the change in surface + * @param voxels the list of voxels + * @param voxel the voxel the update is centered in + * @return the change in surface */ static int updateSurface(ArrayList voxels, Voxel voxel) { int change = 0; - + for (int i = 0; i < NUMBER_NEIGHBORS; i++) { Voxel v = new Voxel(voxel.x + MOVES_X[i], voxel.y + MOVES_Y[i], voxel.z); if (!voxels.contains(v)) { @@ -121,55 +120,55 @@ static int updateSurface(ArrayList voxels, Voxel voxel) { change--; } } - + return change; } - + /** * Calculates the local change in height of the location. * - * @param voxels the list of voxels - * @param voxel the voxel the update is centered in - * @return the change in height + * @param voxels the list of voxels + * @param voxel the voxel the update is centered in + * @return the change in height */ static int updateHeight(ArrayList voxels, Voxel voxel) { boolean addToEmpty = voxels.size() == 0; boolean removeToEmpty = voxels.size() == 1 && voxels.contains(voxel); return (addToEmpty || removeToEmpty ? 1 : 0); } - + /** * Calculates diameters in each direction. * - * @param voxels the list of voxels - * @param focus the focus voxel - * @return the map of direction to diameter + * @param voxels the list of voxels + * @param focus the focus voxel + * @return the map of direction to diameter */ static HashMap getDiameters(ArrayList voxels, Voxel focus) { HashMap minValueMap = new HashMap<>(); HashMap maxValueMap = new HashMap<>(); HashMap existsMap = new HashMap<>(); - + // Initialized entries into direction maps. for (Direction direction : DIRECTIONS) { minValueMap.put(direction, Integer.MAX_VALUE); maxValueMap.put(direction, Integer.MIN_VALUE); existsMap.put(direction, false); } - + Direction dir; int v; - + // Iterate through all the voxels for the location to update minimum and // maximum values in each direction. for (Voxel voxel : voxels) { int i = voxel.x - focus.x; int j = voxel.y - focus.y; - + // Need to update all directions if at the center. if (i == 0 && j == 0) { v = 0; - + for (Direction direction : DIRECTIONS) { existsMap.put(direction, true); if (v > maxValueMap.get(direction)) { @@ -179,7 +178,7 @@ static HashMap getDiameters(ArrayList voxels, Voxel f minValueMap.put(direction, v); } } - + continue; } else if (j == 0) { dir = Direction.YZ_PLANE; @@ -196,7 +195,7 @@ static HashMap getDiameters(ArrayList voxels, Voxel f } else { continue; } - + existsMap.put(dir, true); if (v > maxValueMap.get(dir)) { maxValueMap.put(dir, v); @@ -205,24 +204,24 @@ static HashMap getDiameters(ArrayList voxels, Voxel f minValueMap.put(dir, v); } } - + HashMap diameterMap = new HashMap<>(); - + // Calculate diameter in each direction. for (Direction direction : DIRECTIONS) { int diameter = maxValueMap.get(direction) - minValueMap.get(direction) + 1; diameterMap.put(direction, existsMap.get(direction) ? diameter : 0); } - + return diameterMap; } - + /** * Selects the slice direction for a given minimum diameter direction. * - * @param direction the direction of the minimum diameter - * @param diameters the list of diameters - * @return the slice direction + * @param direction the direction of the minimum diameter + * @param diameters the list of diameters + * @return the slice direction */ static Direction getSlice(Direction direction, HashMap diameters) { switch (direction) { @@ -238,28 +237,27 @@ static Direction getSlice(Direction direction, HashMap diame return null; } } - + /** * Selects specified number of voxels from a focus voxel. * - * @param voxels the list of voxels - * @param focus the focus voxel - * @param n the number of voxels to select - * @return the list of selected voxels + * @param voxels the list of voxels + * @param focus the focus voxel + * @param n the number of voxels to select + * @return the list of selected voxels */ static ArrayList getSelected(ArrayList voxels, Voxel focus, double n) { ArrayList selected = new ArrayList<>(); double r = Math.sqrt(n / Math.PI); - + // Select voxels within given radius. for (Voxel voxel : voxels) { - double d = Math.sqrt(Math.pow(focus.x - voxel.x, 2) - + Math.pow(focus.y - voxel.y, 2)); + double d = Math.sqrt(Math.pow(focus.x - voxel.x, 2) + Math.pow(focus.y - voxel.y, 2)); if (d < r) { selected.add(voxel); } } - + return selected; } } diff --git a/src/arcade/potts/env/location/Location3D.java b/src/arcade/potts/env/location/Location3D.java index 33ab9ee06..8465fe58f 100644 --- a/src/arcade/potts/env/location/Location3D.java +++ b/src/arcade/potts/env/location/Location3D.java @@ -8,52 +8,51 @@ /** * Static location methods for 3D. - *

- * Interface defines generalized 3D voxel methods that can be applied for both - * {@link PottsLocation} objects (without regions) and {@link PottsLocations} - * objects (with regions). + * + *

Interface defines generalized 3D voxel methods that can be applied for both {@link + * PottsLocation} objects (without regions) and {@link PottsLocations} objects (with regions). */ - public interface Location3D { /** Equation power for surface area conversion. */ double EQUATION_PARAMETER_N = 0.50931200; - + /** Equation coefficient for surface area conversion. */ double EQUATION_PARAMETER_A = 0.79295247; - + /** Equation offset for surface area conversion. */ double EQUATION_PARAMETER_B = -1.54292969; - + /** List of valid 3D directions. */ - Direction[] DIRECTIONS = new Direction[] { - Direction.YZ_PLANE, - Direction.ZX_PLANE, - Direction.XY_PLANE, - Direction.POSITIVE_XY, - Direction.NEGATIVE_XY, - Direction.POSITIVE_YZ, - Direction.NEGATIVE_YZ, - Direction.POSITIVE_ZX, - Direction.NEGATIVE_ZX, - }; - + Direction[] DIRECTIONS = + new Direction[] { + Direction.YZ_PLANE, + Direction.ZX_PLANE, + Direction.XY_PLANE, + Direction.POSITIVE_XY, + Direction.NEGATIVE_XY, + Direction.POSITIVE_YZ, + Direction.NEGATIVE_YZ, + Direction.POSITIVE_ZX, + Direction.NEGATIVE_ZX, + }; + /** * Calculate correction factor for surface area conversion. * - * @param volume the volume - * @param height the height - * @return the correction factor + * @param volume the volume + * @param height the height + * @return the correction factor */ static double getCorrection(double volume, double height) { double vh = volume * height; return EQUATION_PARAMETER_A * Math.pow(vh, EQUATION_PARAMETER_N) + EQUATION_PARAMETER_B; } - + /** * Gets list of neighbors of a given voxel. * - * @param focus the focus voxel - * @return the list of neighbor voxels + * @param focus the focus voxel + * @return the list of neighbor voxels */ static ArrayList getNeighbors(Voxel focus) { ArrayList neighbors = new ArrayList<>(); @@ -63,29 +62,29 @@ static ArrayList getNeighbors(Voxel focus) { } return neighbors; } - + /** * Converts volume and height to surface area. * - * @param volume the volume - * @param height the height - * @return the surface area + * @param volume the volume + * @param height the height + * @return the surface area */ static double convertSurface(double volume, double height) { double surface = 2 * volume / height + 2 * Math.sqrt(Math.PI) * Math.sqrt(volume * height); double correction = getCorrection(volume, height); return Math.ceil(surface + correction); } - + /** * Calculates surface of location. * - * @param voxels the list of voxels - * @return the surface + * @param voxels the list of voxels + * @return the surface */ static int calculateSurface(ArrayList voxels) { int surface = 0; - + for (Voxel v : voxels) { for (int i = 0; i < NUMBER_NEIGHBORS; i++) { Voxel voxel = new Voxel(v.x + MOVES_X[i], v.y + MOVES_Y[i], v.z + MOVES_Z[i]); @@ -94,15 +93,15 @@ static int calculateSurface(ArrayList voxels) { } } } - + return surface; } - + /** * Calculates height of location (z axis). * - * @param voxels the list of voxels - * @return the height + * @param voxels the list of voxels + * @return the height */ static int calculateHeight(ArrayList voxels) { if (voxels.size() == 0) { @@ -112,17 +111,17 @@ static int calculateHeight(ArrayList voxels) { OptionalInt min = voxels.stream().mapToInt(voxel -> voxel.z).min(); return max.getAsInt() - min.getAsInt() + 1; } - + /** * Calculates the local change in surface of the location. * - * @param voxels the list of voxels - * @param voxel the voxel the update is centered in - * @return the change in surface + * @param voxels the list of voxels + * @param voxel the voxel the update is centered in + * @return the change in surface */ static int updateSurface(ArrayList voxels, Voxel voxel) { int change = 0; - + for (int i = 0; i < NUMBER_NEIGHBORS; i++) { Voxel v = new Voxel(voxel.x + MOVES_X[i], voxel.y + MOVES_Y[i], voxel.z + MOVES_Z[i]); if (!voxels.contains(v)) { @@ -131,16 +130,16 @@ static int updateSurface(ArrayList voxels, Voxel voxel) { change--; } } - + return change; } - + /** * Calculates the local change in height of the location. * - * @param voxels the list of voxels - * @param voxel the voxel the update is centered in - * @return the change in height + * @param voxels the list of voxels + * @param voxel the voxel the update is centered in + * @return the change in height */ static int updateHeight(ArrayList voxels, Voxel voxel) { if (voxels.size() == 0) { @@ -149,53 +148,53 @@ static int updateHeight(ArrayList voxels, Voxel voxel) { if (voxels.size() == 1 && voxels.contains(voxel)) { return 1; } - + OptionalInt max = voxels.stream().filter(v -> !v.equals(voxel)).mapToInt(v -> v.z).max(); OptionalInt min = voxels.stream().filter(v -> !v.equals(voxel)).mapToInt(v -> v.z).min(); - + if (voxel.z > max.getAsInt()) { return voxel.z - max.getAsInt(); } if (voxel.z < min.getAsInt()) { return min.getAsInt() - voxel.z; } - + return 0; } - + /** * Calculates diameters in each direction. * - * @param voxels the list of voxels - * @param focus the focus voxel - * @return the map of direction to diameter + * @param voxels the list of voxels + * @param focus the focus voxel + * @return the map of direction to diameter */ static HashMap getDiameters(ArrayList voxels, Voxel focus) { HashMap minValueMap = new HashMap<>(); HashMap maxValueMap = new HashMap<>(); HashMap existsMap = new HashMap<>(); - + // Initialized entries into direction maps. for (Direction direction : DIRECTIONS) { minValueMap.put(direction, Integer.MAX_VALUE); maxValueMap.put(direction, Integer.MIN_VALUE); existsMap.put(direction, false); } - + Direction dir; int v; - + // Iterate through all the voxels for the location to update minimum and // maximum values in each direction. for (Voxel voxel : voxels) { int i = voxel.x - focus.x; int j = voxel.y - focus.y; int k = voxel.z - focus.z; - + // Need to update all directions if at the center. if (i == 0 && j == 0 && k == 0) { v = 0; - + for (Direction direction : DIRECTIONS) { existsMap.put(direction, true); if (v > maxValueMap.get(direction)) { @@ -205,7 +204,7 @@ static HashMap getDiameters(ArrayList voxels, Voxel f minValueMap.put(direction, v); } } - + continue; } else if (j == 0 && k == 0) { dir = Direction.YZ_PLANE; @@ -237,7 +236,7 @@ static HashMap getDiameters(ArrayList voxels, Voxel f } else { continue; } - + existsMap.put(dir, true); if (v > maxValueMap.get(dir)) { maxValueMap.put(dir, v); @@ -246,24 +245,24 @@ static HashMap getDiameters(ArrayList voxels, Voxel f minValueMap.put(dir, v); } } - + HashMap diameterMap = new HashMap<>(); - + // Calculate diameter in each direction. for (Direction direction : DIRECTIONS) { int diameter = maxValueMap.get(direction) - minValueMap.get(direction) + 1; diameterMap.put(direction, existsMap.get(direction) ? diameter : 0); } - + return diameterMap; } - + /** * Selects the slice direction for a given minimum diameter direction. * - * @param direction the direction of the minimum diameter - * @param diameters the list of diameters - * @return the slice direction + * @param direction the direction of the minimum diameter + * @param diameters the list of diameters + * @return the slice direction */ static Direction getSlice(Direction direction, HashMap diameters) { switch (direction) { @@ -313,29 +312,28 @@ static Direction getSlice(Direction direction, HashMap diame return null; } } - + /** * Selects specified number of voxels from a focus voxel. * - * @param voxels the list of voxels - * @param focus the focus voxel - * @param n the number of voxels to select - * @return the list of selected voxels + * @param voxels the list of voxels + * @param focus the focus voxel + * @param n the number of voxels to select + * @return the list of selected voxels */ static ArrayList getSelected(ArrayList voxels, Voxel focus, double n) { ArrayList selected = new ArrayList<>(); double h = calculateHeight(voxels); double r = Math.sqrt(n / h / Math.PI); - + // Select voxels within given radius. for (Voxel voxel : voxels) { - double d = Math.sqrt(Math.pow(focus.x - voxel.x, 2) - + Math.pow(focus.y - voxel.y, 2)); + double d = Math.sqrt(Math.pow(focus.x - voxel.x, 2) + Math.pow(focus.y - voxel.y, 2)); if (d < r) { selected.add(voxel); } } - + return selected; } } diff --git a/src/arcade/potts/env/location/Plane.java b/src/arcade/potts/env/location/Plane.java new file mode 100644 index 000000000..19b9b4bba --- /dev/null +++ b/src/arcade/potts/env/location/Plane.java @@ -0,0 +1,107 @@ +package arcade.potts.env.location; + +import sim.util.Double3D; +import arcade.potts.util.PottsEnums.Direction; + +/** A plane in 3D space. */ +public final class Plane { + /** A point on the plane. */ + public final Voxel referencePoint; + + /** The unit normal vector to the plane. */ + public final Double3D unitNormalVector; + + /** + * Creates a plane from a point and a vector. + * + * @param voxel a point on the plane + * @param normalVector the normal vector to the plane + */ + public Plane(Voxel voxel, Double3D normalVector) { + this.referencePoint = voxel; + this.unitNormalVector = scaleNormalVector(normalVector); + } + + /** + * Creates a plane from a point and a direction. + * + * @param voxel a point on the plane + * @param direction the direction of the plane + */ + public Plane(Voxel voxel, Direction direction) { + this(voxel, direction.vector); + } + + /** + * Determines the magnitude of the normal vector. + * + * @param normalVector the normal vector + * @return the magnitude of the normal vector + */ + static double getNormalVectorMagnitude(Double3D normalVector) { + return Math.sqrt( + normalVector.getX() * normalVector.getX() + + normalVector.getY() * normalVector.getY() + + normalVector.getZ() * normalVector.getZ()); + } + + /** + * Scales the normal vector to a unit vector. + * + * @param normalVector the normal vector + * @return the unit normal vector + */ + static Double3D scaleNormalVector(Double3D normalVector) { + double magnitude = getNormalVectorMagnitude(normalVector); + double scaledX = normalVector.getX() / magnitude; + double scaledY = normalVector.getY() / magnitude; + double scaledZ = normalVector.getZ() / magnitude; + return new Double3D(scaledX, scaledY, scaledZ); + } + + /** + * Determines distance from a point to the plane. + * + *

The distance is positive if the point is on the same side of the plane as the normal + * vector and negative if it is on the opposite side. + * + * @param point the point + * @return the distance from the point to the plane. + */ + public double signedDistanceToPlane(Voxel point) { + return (point.x - referencePoint.x) * unitNormalVector.getX() + + (point.y - referencePoint.y) * unitNormalVector.getY() + + (point.z - referencePoint.z) * unitNormalVector.getZ(); + } + + /** + * Determines if two planes are equal. + * + * @param obj the plane to compare + * @return {@code true} if the planes are equal, {@code false} otherwise + */ + @Override + public boolean equals(Object obj) { + if (obj == null || getClass() != obj.getClass()) { + return false; + } + Plane other = (Plane) obj; + return referencePoint.equals(other.referencePoint) + && unitNormalVector.equals(other.unitNormalVector); + } + + /** + * Returns a hash code for the plane. + * + * @return a hash code for the plane + */ + @Override + public int hashCode() { + int hash = 7; + hash = 31 * hash + referencePoint.hashCode(); + hash = 31 * hash + Double.hashCode(unitNormalVector.getX()); + hash = 31 * hash + Double.hashCode(unitNormalVector.getY()); + hash = 31 * hash + Double.hashCode(unitNormalVector.getZ()); + return hash; + } +} diff --git a/src/arcade/potts/env/location/PottsLocation.java b/src/arcade/potts/env/location/PottsLocation.java index b9c05e7e3..7ba35342b 100644 --- a/src/arcade/potts/env/location/PottsLocation.java +++ b/src/arcade/potts/env/location/PottsLocation.java @@ -13,59 +13,59 @@ /** * Abstract implementation of {@link Location} for potts models. - *

- * {@code PottsLocation} objects manage the a list of associated {@link Voxel} - * objects that comprise the location. These voxels are represented as an array - * in the {@link arcade.potts.sim.Potts} layer and the two representations are - * kept in sync. - *

- * Concrete implementations of {@code PottsLocation} manage the dimensionality - * of the voxels. - *

- * {@code PottsLocation} also provides several general static methods for - * manipulating voxel lists: + * + *

{@code PottsLocation} objects manage the a list of associated {@link Voxel} objects that + * comprise the location. These voxels are represented as an array in the {@link + * arcade.potts.sim.Potts} layer and the two representations are kept in sync. + * + *

Concrete implementations of {@code PottsLocation} manage the dimensionality of the voxels. + * + *

{@code PottsLocation} also provides several general static methods for manipulating voxel + * lists: + * *

    - *
  • Split voxel list along a given direction
  • - *
  • Connect voxels to ensure that each list contains - * connected voxels
  • - *
  • Balance voxels between two lists to ensure they have - * a similar number of voxels
  • - *
  • Check voxels for connectedness
  • + *
  • Split voxel list along a given direction + *
  • Connect voxels to ensure that each list contains connected voxels + *
  • Balance voxels between two lists to ensure they have a similar number of + * voxels + *
  • Check voxels for connectedness *
*/ - public abstract class PottsLocation implements Location { /** Relative difference between split voxel numbers. */ private static final double BALANCE_DIFFERENCE = 0.05; - + /** Relative padding for selecting maximum diameter. */ private static final double DIAMETER_RATIO = 0.9; - + + /** Default probability first voxel list is kept in split function. */ + private static final double DEFAULT_SPLIT_SELECTION_PROBABILITY = 0.5; + /** List of voxels for the location. */ final ArrayList voxels; - + /** Location volume. */ int volume; - + /** Location surface. */ int surface; - + /** Location height. */ int height; - + /** X position of center. */ double cx; - + /** Y position of center. */ double cy; - + /** Z position of center. */ double cz; - + /** * Creates a {@code PottsLocation} for a list of voxels. * - * @param voxels the list of voxels + * @param voxels the list of voxels */ public PottsLocation(ArrayList voxels) { this.voxels = new ArrayList<>(voxels); @@ -74,68 +74,86 @@ public PottsLocation(ArrayList voxels) { this.height = calculateHeight(); calculateCenter(); } - + /** * Gets all voxels. * - * @return the list of voxels + * @return the list of voxels */ - public ArrayList getVoxels() { return new ArrayList<>(voxels); } - + public ArrayList getVoxels() { + return new ArrayList<>(voxels); + } + /** * Gets all voxels for a region. * - * @param region the region - * @return the list of reqion voxels + * @param region the region + * @return the list of reqion voxels */ - public ArrayList getVoxels(Region region) { return new ArrayList<>(); } - + public ArrayList getVoxels(Region region) { + return new ArrayList<>(); + } + /** * Gets a set of regions. * - * @return the set of regions + * @return the set of regions */ - public EnumSet getRegions() { return null; } - + public EnumSet getRegions() { + return null; + } + @Override - public final double getVolume() { return volume; } - + public final double getVolume() { + return volume; + } + /** * Gets the volume of the location for a given region. * - * @param region the region - * @return the location region volume + * @param region the region + * @return the location region volume */ - public double getVolume(Region region) { return getVolume(); } - + public double getVolume(Region region) { + return getVolume(); + } + @Override - public final double getSurface() { return surface; } - + public final double getSurface() { + return surface; + } + /** * Gets the surface area of the location for a given region. * - * @param region the region - * @return the location region surface area + * @param region the region + * @return the location region surface area */ - public double getSurface(Region region) { return getSurface(); } - + public double getSurface(Region region) { + return getSurface(); + } + @Override - public final double getHeight() { return height; } - + public final double getHeight() { + return height; + } + /** * Gets the height of the location for a given region. * - * @param region the region - * @return the location height + * @param region the region + * @return the location height */ - public double getHeight(Region region) { return getHeight(); } - + public double getHeight(Region region) { + return getHeight(); + } + /** * Adds a voxel at the given coordinates. * - * @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 */ public void add(int x, int y, int z) { Voxel voxel = new Voxel(x, y, z); @@ -147,23 +165,25 @@ public void add(int x, int y, int z) { updateCenter(x, y, z, 1); } } - + /** * Adds a voxel at the given coordinates for given region. * - * @param region the voxel region - * @param x the x coordinate - * @param y the y coordinate - * @param z the z coordinate + * @param region the voxel region + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate */ - public void add(Region region, int x, int y, int z) { add(x, y, z); } - + public void add(Region region, int x, int y, int z) { + add(x, y, z); + } + /** * Removes the voxel at the given coordinates. * - * @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 */ public void remove(int x, int y, int z) { Voxel voxel = new Voxel(x, y, z); @@ -175,171 +195,273 @@ public void remove(int x, int y, int z) { updateCenter(x, y, z, -1); } } - + /** * Removes the voxel at the given coordinates for given region. * - * @param region the voxel region - * @param x the x coordinate - * @param y the y coordinate - * @param z the z coordinate + * @param region the voxel region + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate */ - public void remove(Region region, int x, int y, int z) { remove(x, y, z); } - + public void remove(Region region, int x, int y, int z) { + remove(x, y, z); + } + /** * Assigns the voxel at the given coordinates to the given region. * - * @param region the voxel region - * @param voxel the voxel to assign + * @param region the voxel region + * @param voxel the voxel to assign */ - public void assign(Region region, Voxel voxel) { } - + public void assign(Region region, Voxel voxel) {} + /** * Assigns target number of voxels to given region. * - * @param region the region to assign - * @param target the target number of voxels to assign - * @param random the seeded random number generator + * @param region the region to assign + * @param target the target number of voxels to assign + * @param random the seeded random number generator */ - public void distribute(Region region, int target, MersenneTwisterFast random) { } - + public void distribute(Region region, int target, MersenneTwisterFast random) {} + /** * Finds the closest voxel that exists in the location. * - * @param voxel the starting voxel - * @return the closest voxel or the starting voxel if it exists + * @param voxel the starting voxel + * @return the closest voxel or the starting voxel if it exists */ public Voxel adjust(Voxel voxel) { if (voxels.contains(voxel)) { return voxel; } - + int x = voxel.x; int y = voxel.y; int z = voxel.z; - + double minimumDistance = Double.MAX_VALUE; - + for (Voxel v : voxels) { - double distance = Math.sqrt(Math.pow(v.x - x, 2) - + Math.pow(v.y - y, 2) - + Math.pow(v.z - z, 2)); - + double distance = + Math.sqrt(Math.pow(v.x - x, 2) + Math.pow(v.y - y, 2) + Math.pow(v.z - z, 2)); + if (distance < minimumDistance) { minimumDistance = distance; voxel = v; } } - + return voxel; } - + /** * Clears all voxel lists and arrays. * - * @param ids the potts array for ids - * @param regions the potts array for regions + * @param ids the potts array for ids + * @param regions the potts array for regions */ public void clear(int[][][] ids, int[][][] regions) { voxels.forEach(voxel -> ids[voxel.z][voxel.x][voxel.y] = 0); voxels.clear(); } - + /** * Updates the array for the location. * - * @param id the location id - * @param ids the potts array for ids - * @param regions the potts array for regions + * @param id the location id + * @param ids the potts array for ids + * @param regions the potts array for regions */ public void update(int id, int[][][] ids, int[][][] regions) { voxels.forEach(voxel -> ids[voxel.z][voxel.x][voxel.y] = id); } - + /** - * Splits the location voxels into two lists. - *

- * The location are split along the direction with the shortest diameter. - * The lists of locations are guaranteed to be connected, and generally will - * be balanced in size. One of the splits is assigned to the current - * location and the other is returned. + * Splits location voxels into two approximately equal lists. + * + *

The location is split along the direction with the shortest diameter. The lists of + * locations are guaranteed to be connected, and generally will be balanced in size. One of the + * splits is assigned to the current location and the other is returned. * - * @param random the seeded random number generator - * @return a location with the split voxels + * @param random the seeded random number generator + * @return a location with the split voxels */ public Location split(MersenneTwisterFast random) { - // Get center voxel. - Voxel center = getCenter(); - - // Initialize lists of split voxels. + Plane divisionPlane = new Plane(getCenter(), getDirection(random)); + return split(random, divisionPlane, DEFAULT_SPLIT_SELECTION_PROBABILITY); + } + + /** + * Splits location voxels into two lists with given offset. + * + *

The location is split at the point specified by offsets along the direction with the + * shortest diameter. The lists of locations are guaranteed to be connected. One of the splits + * is assigned to the current location and the other is returned. + * + * @param random the seeded random number generator + * @param offsets the percentage offset in each direction for split point + * @return a location with the split voxels + */ + public Location split(MersenneTwisterFast random, ArrayList offsets) { + Plane divisionPlane = new Plane(getOffset(offsets), getDirection(random)); + return split(random, divisionPlane, DEFAULT_SPLIT_SELECTION_PROBABILITY); + } + + /** + * Splits location voxels into two lists with given offset, direction, and probability. + * + *

The location is split at the point specified by offsets along the given direction. The + * lists of locations are guaranteed to be connected. One of the splits is assigned to the + * current location and the other is returned. + * + * @param random the seeded random number generator + * @param offsets the percentage offset in each direction for split point + * @param direction the direction of the split + * @param probability the probability to decide which split to return + * @return a location with the split voxels + */ + public Location split( + MersenneTwisterFast random, + ArrayList offsets, + Direction direction, + Double probability) { + Plane divisionPlane = new Plane(getOffset(offsets), direction); + return split(random, divisionPlane, probability); + } + + /** + * Splits location voxels into two lists. + * + *

The location is split along the provided plane. One of the splits is assigned to the + * current location and the other is returned with the given probability. + * + *

If the plane of division is through the center of the location, the resulting lists are + * guaranteed to be connected, and generally will be balanced in size. If the plane of division + * is not through the center of the location, the resulting lists are guaranteed to be connected + * but will not necessarily be balanced in size. + * + * @param random the seeded random number generator + * @param plane the plane of the split + * @param probability the probability to decide which split to return + * @return a location with the split voxels + */ + public Location split(MersenneTwisterFast random, Plane plane, Double probability) { + // Initialize lists of split voxels ArrayList voxelsA = new ArrayList<>(); ArrayList voxelsB = new ArrayList<>(); - - // Get split direction. - Direction direction = getDirection(random); - splitVoxels(direction, voxels, voxelsA, voxelsB, center, random); - - // Ensure that voxel split is connected and balanced. + + splitVoxels(plane, voxels, voxelsA, voxelsB, random); connectVoxels(voxelsA, voxelsB, this, random); - balanceVoxels(voxelsA, voxelsB, this, random); - - // Select one split to keep for this location and return the other. - if (random.nextDouble() < 0.5) { - return separateVoxels(voxelsA, voxelsB, random); - } else { - return separateVoxels(voxelsB, voxelsA, random); + + Voxel locCenter = getCenter(); + if (plane.referencePoint.equals(locCenter)) { + balanceVoxels(voxelsA, voxelsB, this, random); } + + // Use the user-specified or default probability to determine the split + return random.nextDouble() < probability + ? separateVoxels(voxelsA, voxelsB, random) + : separateVoxels(voxelsB, voxelsA, random); } - + /** * Gets the voxel at the center of the location. - *

- * The center voxel is not guaranteed to exist in the location. If the - * center voxel must exist, use {@code adjust()} to get the closest voxel - * that exists. * - * @return the center voxel, returns {@code null} if there are no voxels + *

The center voxel is not guaranteed to exist in the location. If the center voxel must + * exist, use {@code adjust()} to get the closest voxel that exists. + * + * @return the center voxel, returns {@code null} if there are no voxels */ public Voxel getCenter() { if (voxels.size() == 0) { return null; } - + int x = (int) Math.round(cx); int y = (int) Math.round(cy); int z = (int) Math.round(cz); - + return new Voxel(x, y, z); } - + + /** + * Calculates the voxel at specified offsets from location bounds. + * + *

The voxel position is calculated as percentage offsets using the minimum and maximum + * bounds of the current location in the X, Y, and Z dimensions. Offsets should be passed as + * percentages in the range [0, 100]. Offsets may be given as one percentage N1 (interpreted as + * [x = N, y = N, z = N]), two percentages N1 and N2 (interpreted as [x = N1, y = N2, z = 0]), + * or three percentages N1, N2, and N3 (interpreted as [x = N1, y = N2, z = N3]). + * + *

For example, offsets of [50, 50, 50] will return the voxel located 50% between the minimum + * and maximum in each direction. Note that [50, 50, 50] is not necessarily equivalent to the + * center of the location, which is calculated as the arithmetic mean in each direction. To get + * the center, use {@code getCenter()} instead. + * + *

The voxel is not guaranteed to exist in the location. If the voxel must exist, use {@code + * adjust()} to get the closest voxel that exists. + * + * @param offsets the percentage offset in each direction for split point + * @return the offset voxel, returns {@code null} if there are no voxels + */ + public Voxel getOffset(ArrayList offsets) { + if (voxels.size() == 0) { + return null; + } + + if (offsets == null || offsets.size() == 0 || offsets.size() > 3) { + throw new IllegalArgumentException( + "Offsets must be an ArrayList containing exactly 1, 2 or 3 integers."); + } + + if (offsets.size() == 1) { + offsets.add(offsets.get(0)); + offsets.add(offsets.get(1)); + } else if (offsets.size() == 2) { + offsets.add(0); + } + + int minX = voxels.stream().mapToInt(voxel -> voxel.x).min().getAsInt(); + int maxX = voxels.stream().mapToInt(voxel -> voxel.x).max().getAsInt(); + int minY = voxels.stream().mapToInt(voxel -> voxel.y).min().getAsInt(); + int maxY = voxels.stream().mapToInt(voxel -> voxel.y).max().getAsInt(); + int minZ = voxels.stream().mapToInt(voxel -> voxel.z).min().getAsInt(); + int maxZ = voxels.stream().mapToInt(voxel -> voxel.z).max().getAsInt(); + + int offsetX = (int) Math.round(minX + (maxX - minX) * (offsets.get(0) / 100.0)); + int offsetY = (int) Math.round(minY + (maxY - minY) * (offsets.get(1) / 100.0)); + int offsetZ = (int) Math.round(minZ + (maxZ - minZ) * (offsets.get(2) / 100.0)); + + return new Voxel(offsetX, offsetY, offsetZ); + } + /** * Gets the centroid of the location. - *

- * Note that centroid positions may not be integer values. If a specific - * center voxel is needed, use {@code getCenter()} instead. * - * @return the location centroid + *

Note that centroid positions may not be integer values. If a specific center voxel is + * needed, use {@code getCenter()} instead. + * + * @return the location centroid */ public double[] getCentroid() { - return new double[] { cx, cy, cz }; + return new double[] {cx, cy, cz}; } - + /** * Gets the centroid of the location for the region. - *

- * Note that centroid positions may not be integer values. If a specific - * center voxel is needed, use {@code getCenter()} instead. * - * @param region the voxel region - * @return the location centroid + *

Note that centroid positions may not be integer values. If a specific center voxel is + * needed, use {@code getCenter()} instead. + * + * @param region the voxel region + * @return the location centroid */ public double[] getCentroid(Region region) { return getCentroid(); } - - /** - * Calculates the exact center of the location. - */ + + /** Calculates the exact center of the location. */ void calculateCenter() { if (voxels.size() == 0) { cx = 0; @@ -351,14 +473,14 @@ void calculateCenter() { cz = voxels.stream().mapToDouble(voxel -> voxel.z).sum() / voxels.size(); } } - + /** * Updates the centroid of the location. * - * @param x the x position of the changed voxel - * @param y the y position of the changed voxel - * @param z the z position of the changed voxel - * @param change the direction of change (add = +1, remove = -1) + * @param x the x position of the changed voxel + * @param y the y position of the changed voxel + * @param z the z position of the changed voxel + * @param change the direction of change (add = +1, remove = -1) */ void updateCenter(int x, int y, int z, int change) { if (voxels.size() == 0) { @@ -371,97 +493,97 @@ void updateCenter(int x, int y, int z, int change) { cz = (cz * (volume - change) + change * z) / volume; } } - + /** * Makes a new {@code PottsLocation} with the given voxels. * - * @param voxels the list of voxels - * @return a new {@code PottsLocation} + * @param voxels the list of voxels + * @return a new {@code PottsLocation} */ abstract PottsLocation makeLocation(ArrayList voxels); - + /** * Converts volume and height to surface area. * - * @param volume the volume - * @param height the height - * @return the surface area + * @param volume the volume + * @param height the height + * @return the surface area */ public abstract double convertSurface(double volume, double height); - + /** * Calculates surface of location. * - * @return the surface + * @return the surface */ abstract int calculateSurface(); - + /** * Calculates the local change in surface of the location. * - * @param voxel the voxel the update is centered in - * @return the change in surface + * @param voxel the voxel the update is centered in + * @return the change in surface */ abstract int updateSurface(Voxel voxel); - + /** * Calculates height of location. * - * @return the height + * @return the height */ abstract int calculateHeight(); - + /** * Calculates the local change in height of the location. * - * @param voxel the voxel the update is centered in - * @return the change in height + * @param voxel the voxel the update is centered in + * @return the change in height */ abstract int updateHeight(Voxel voxel); - + /** * Gets list of neighbors of a given voxel. * - * @param focus the focus voxel - * @return the list of neighbor voxels + * @param focus the focus voxel + * @return the list of neighbor voxels */ abstract ArrayList getNeighbors(Voxel focus); - + /** * Calculates diameters in each direction. * - * @return the map of direction to diameter + * @return the map of direction to diameter */ abstract HashMap getDiameters(); - + /** * Selects the slice direction for a given maximum diameter direction. * - * @param direction the direction of the minimum diameter - * @param diameters the list of diameters - * @return the slice direction + * @param direction the direction of the minimum diameter + * @param diameters the list of diameters + * @return the slice direction */ abstract Direction getSlice(Direction direction, HashMap diameters); - + /** * Selects specified number of voxels from a focus voxel. * - * @param focus the focus voxel - * @param n the number of voxels to select - * @return the list of selected voxels + * @param focus the focus voxel + * @param n the number of voxels to select + * @return the list of selected voxels */ abstract ArrayList getSelected(Voxel focus, double n); - + /** - * Gets the direction of the slice. + * Gets the direction of the slice orthagonal to the direction with the smallest diameter. * - * @param random the seeded random number generator - * @return the direction of the slice + * @param random the seeded random number generator + * @return the direction of the slice */ Direction getDirection(MersenneTwisterFast random) { HashMap diameters = getDiameters(); ArrayList directions = new ArrayList<>(); - + // Determine maximum diameter. int diameter; int maximumDiameter = 0; @@ -471,7 +593,7 @@ Direction getDirection(MersenneTwisterFast random) { maximumDiameter = diameter; } } - + // Find all directions with the maximum diameter. for (Direction direction : Direction.values()) { diameter = diameters.getOrDefault(direction, 0); @@ -479,30 +601,29 @@ Direction getDirection(MersenneTwisterFast random) { directions.add(direction); } } - + // Randomly select one direction with the minimum diameter. Direction d = directions.get(random.nextInt(directions.size())); - + // Convert diameter direction to slice direction. return (d == Direction.UNDEFINED ? Direction.random(random) : getSlice(d, diameters)); } - + @Override public LocationContainer convert(int id) { return new PottsLocationContainer(id, getCenter(), voxels); } - + /** - * Separates the voxels in the list between this location and a new - * location. + * Separates the voxels in the list between this location and a new location. * - * @param voxelsA the list of voxels for this location - * @param voxelsB the list of voxels for the split location - * @param random the seeded random number generator - * @return a {@link arcade.core.env.location.Location} object with split voxels + * @param voxelsA the list of voxels for this location + * @param voxelsB the list of voxels for the split location + * @param random the seeded random number generator + * @return a {@link arcade.core.env.location.Location} object with split voxels */ - Location separateVoxels(ArrayList voxelsA, ArrayList voxelsB, - MersenneTwisterFast random) { + Location separateVoxels( + ArrayList voxelsA, ArrayList voxelsB, MersenneTwisterFast random) { voxels.clear(); voxels.addAll(voxelsA); volume = voxels.size(); @@ -511,207 +632,108 @@ Location separateVoxels(ArrayList voxelsA, ArrayList voxelsB, calculateCenter(); return makeLocation(voxelsB); } - + /** - * Splits the voxels in the location along a given direction. + * Splits the voxels in the location into two lists along a given plane. * - * @param direction the direction of the slice - * @param voxels the list of voxels - * @param voxelsA the container list for the first half of the split - * @param voxelsB the container list for the second half of the split - * @param center the center voxel - * @param random the seeded random number generator + *

The voxels are split into two lists based on their position relative to the plane. Voxels + * on the plane are randomly assigned to one of the lists. + * + * @param plane the plane to split the voxels along + * @param voxels the list of voxels to split + * @param voxelsA list of voxels on side of plane the opposite the normal + * @param voxelsB list of voxels on side of plane the same as the normal + * @param random the seeded random number generator */ - static void splitVoxels(Direction direction, ArrayList voxels, - ArrayList voxelsA, ArrayList voxelsB, - Voxel center, MersenneTwisterFast random) { + static void splitVoxels( + Plane plane, + ArrayList voxels, + ArrayList voxelsA, + ArrayList voxelsB, + MersenneTwisterFast random) { for (Voxel voxel : voxels) { - switch (direction) { - case ZX_PLANE: - if (voxel.y < center.y) { - voxelsA.add(voxel); - } else if (voxel.y > center.y) { - voxelsB.add(voxel); - } else { - if (random.nextDouble() > 0.5) { - voxelsA.add(voxel); - } else { - voxelsB.add(voxel); - } - } - break; - case YZ_PLANE: - if (voxel.x < center.x) { - voxelsA.add(voxel); - } else if (voxel.x > center.x) { - voxelsB.add(voxel); - } else { - if (random.nextDouble() > 0.5) { - voxelsA.add(voxel); - } else { - voxelsB.add(voxel); - } - } - break; - case XY_PLANE: - if (voxel.z < center.z) { - voxelsA.add(voxel); - } else if (voxel.z > center.z) { - voxelsB.add(voxel); - } else { - if (random.nextDouble() > 0.5) { - voxelsA.add(voxel); - } else { - voxelsB.add(voxel); - } - } - break; - case NEGATIVE_XY: - if (voxel.x - center.x > center.y - voxel.y) { - voxelsA.add(voxel); - } else if (voxel.x - center.x < center.y - voxel.y) { - voxelsB.add(voxel); - } else { - if (random.nextDouble() > 0.5) { - voxelsA.add(voxel); - } else { - voxelsB.add(voxel); - } - } - break; - case POSITIVE_XY: - if (voxel.x - center.x > voxel.y - center.y) { - voxelsA.add(voxel); - } else if (voxel.x - center.x < voxel.y - center.y) { - voxelsB.add(voxel); - } else { - if (random.nextDouble() > 0.5) { - voxelsA.add(voxel); - } else { - voxelsB.add(voxel); - } - } - break; - case NEGATIVE_YZ: - if (voxel.y - center.y > center.z - voxel.z) { - voxelsA.add(voxel); - } else if (voxel.y - center.y < center.z - voxel.z) { - voxelsB.add(voxel); - } else { - if (random.nextDouble() > 0.5) { - voxelsA.add(voxel); - } else { - voxelsB.add(voxel); - } - } - break; - case POSITIVE_YZ: - if (voxel.y - center.y > voxel.z - center.z) { - voxelsA.add(voxel); - } else if (voxel.y - center.y < voxel.z - center.z) { - voxelsB.add(voxel); - } else { - if (random.nextDouble() > 0.5) { - voxelsA.add(voxel); - } else { - voxelsB.add(voxel); - } - } - break; - case NEGATIVE_ZX: - if (voxel.z - center.z > center.x - voxel.x) { - voxelsA.add(voxel); - } else if (voxel.z - center.z < center.x - voxel.x) { - voxelsB.add(voxel); - } else { - if (random.nextDouble() > 0.5) { - voxelsA.add(voxel); - } else { - voxelsB.add(voxel); - } - } - break; - case POSITIVE_ZX: - if (voxel.z - center.z > voxel.x - center.x) { - voxelsA.add(voxel); - } else if (voxel.z - center.z < voxel.x - center.x) { - voxelsB.add(voxel); - } else { - if (random.nextDouble() > 0.5) { - voxelsA.add(voxel); - } else { - voxelsB.add(voxel); - } - } - break; - default: - break; + double distance = plane.signedDistanceToPlane(voxel); + if (distance < 0) { + voxelsA.add(voxel); + } else if (distance > 0) { + voxelsB.add(voxel); + } else { + if (random.nextDouble() > 0.5) { + voxelsA.add(voxel); + } else { + voxelsB.add(voxel); + } } } } - + /** * Connects voxels in the splits. - *

- * Checks that the voxels in each split are connected. If not, then move the - * unconnected voxels into the other split. * - * @param voxelsA the list for the first half of the split - * @param voxelsB the list for the second half of the split - * @param location the location instance - * @param random the seeded random number generator + *

Checks that the voxels in each split are connected. If not, then move the unconnected + * voxels into the other split. + * + * @param voxelsA the list for the first half of the split + * @param voxelsB the list for the second half of the split + * @param location the location instance + * @param random the seeded random number generator */ - static void connectVoxels(ArrayList voxelsA, ArrayList voxelsB, - PottsLocation location, MersenneTwisterFast random) { + static void connectVoxels( + ArrayList voxelsA, + ArrayList voxelsB, + PottsLocation location, + MersenneTwisterFast random) { // Check that both coordinate lists are simply connected. ArrayList unconnectedA = checkVoxels(voxelsA, location, random, true); ArrayList unconnectedB = checkVoxels(voxelsB, location, random, true); - + // If either coordinate list is not connected, attempt to connect them // by adding in the unconnected coordinates of the other list. while (unconnectedA != null || unconnectedB != null) { ArrayList unconnectedAB; ArrayList unconnectedBA; - + if (unconnectedA != null) { voxelsB.addAll(unconnectedA); } unconnectedBA = checkVoxels(voxelsB, location, random, true); - + if (unconnectedB != null) { voxelsA.addAll(unconnectedB); } unconnectedAB = checkVoxels(voxelsA, location, random, true); - + unconnectedA = unconnectedAB; unconnectedB = unconnectedBA; } } - + /** * Balances voxels in the splits. - *

- * Checks that the number of voxels in each split are within a certain - * difference. If not, then add voxels from the larger split into the - * smaller split such that both splits are still connected. For small split - * sizes, there may not be a valid split that is both connected and within - * the difference; in these cases, connectedness is prioritized and the - * splits are returned not balanced. - * - * @param voxelsA the list for the first half of the split - * @param voxelsB the list for the second half of the split - * @param location the location instance - * @param random the seeded random number generator - */ - static void balanceVoxels(ArrayList voxelsA, ArrayList voxelsB, - PottsLocation location, MersenneTwisterFast random) { + * + *

Checks that the number of voxels in each split are within a certain difference. If not, + * then add voxels from the larger split into the smaller split such that both splits are still + * connected. For small split sizes, there may not be a valid split that is both connected and + * within the difference; in these cases, connectedness is prioritized and the splits are + * returned not balanced. + * + * @param voxelsA the list for the first half of the split + * @param voxelsB the list for the second half of the split + * @param location the location instance + * @param random the seeded random number generator + */ + static void balanceVoxels( + ArrayList voxelsA, + ArrayList voxelsB, + PottsLocation location, + MersenneTwisterFast random) { int nA = voxelsA.size(); int nB = voxelsB.size(); - + while (Math.abs(nA - nB) > Math.ceil((nA + nB) * BALANCE_DIFFERENCE)) { ArrayList fromVoxels; ArrayList toVoxels; - + if (nA > nB) { fromVoxels = voxelsA; toVoxels = voxelsB; @@ -719,7 +741,7 @@ static void balanceVoxels(ArrayList voxelsA, ArrayList voxelsB, fromVoxels = voxelsB; toVoxels = voxelsA; } - + // Get all valid neighbor voxels. LinkedHashSet neighborSet = new LinkedHashSet<>(); for (Voxel voxel : toVoxels) { @@ -730,15 +752,15 @@ static void balanceVoxels(ArrayList voxelsA, ArrayList voxelsB, } } } - + // If one list is empty, add all voxels in other list as neighbors. if (toVoxels.size() == 0) { neighborSet.addAll(fromVoxels); } - + ArrayList neighborList = new ArrayList<>(neighborSet); Utilities.shuffleList(neighborList, random); - + // Select a neighbor to move from one list to the other. boolean added = false; ArrayList invalidCoords = new ArrayList<>(); @@ -746,7 +768,7 @@ static void balanceVoxels(ArrayList voxelsA, ArrayList voxelsB, if (fromVoxels.contains(voxel)) { toVoxels.add(voxel); fromVoxels.remove(voxel); - + // Check that removal of coordinate does not cause the list // to become unconnected. ArrayList unconnected = checkVoxels(fromVoxels, location, random, false); @@ -760,57 +782,59 @@ static void balanceVoxels(ArrayList voxelsA, ArrayList voxelsB, } } } - + if (!added) { toVoxels.addAll(invalidCoords); fromVoxels.removeAll(invalidCoords); connectVoxels(voxelsA, voxelsB, location, random); break; } - + nA = voxelsA.size(); nB = voxelsB.size(); } } - + /** * Checks voxels in the list for connectedness. - *

- * All the connected voxels from a random starting voxel are found and - * marked as visited. If there are no remaining unvisited voxels, then the - * list is fully connected. If there are, then the smaller of the visited or - * unvisited lists is returned. - *

- * Some voxel lists may have more than one unconnected section. - * - * @param voxels the list of voxels - * @param location the location instance - * @param random the seeded random number generator - * @param update {@code true} if list should be updated, {@code false} otherwise - * @return a list of unconnected voxels, {@code null} if list is connected - */ - static ArrayList checkVoxels(ArrayList voxels, PottsLocation location, - MersenneTwisterFast random, boolean update) { + * + *

All the connected voxels from a random starting voxel are found and marked as visited. If + * there are no remaining unvisited voxels, then the list is fully connected. If there are, then + * the smaller of the visited or unvisited lists is returned. + * + *

Some voxel lists may have more than one unconnected section. + * + * @param voxels the list of voxels + * @param location the location instance + * @param random the seeded random number generator + * @param update {@code true} if list should be updated, {@code false} otherwise + * @return a list of unconnected voxels, {@code null} if list is connected + */ + static ArrayList checkVoxels( + ArrayList voxels, + PottsLocation location, + MersenneTwisterFast random, + boolean update) { if (voxels.size() == 0) { return null; } - + ArrayList unvisited = new ArrayList<>(voxels); ArrayList visited = new ArrayList<>(); ArrayList nextList; LinkedHashSet nextSet; LinkedHashSet currSet = new LinkedHashSet<>(); - + currSet.add(unvisited.get(random.nextInt(unvisited.size()))); int currSize = currSet.size(); - + while (currSize > 0) { nextSet = new LinkedHashSet<>(); - + // Iterate through each coordinate in current coordinate set. for (Voxel voxel : currSet) { nextList = new ArrayList<>(); - + // Iterate through each connected direction from current voxel // and add to neighbor list if it exists. ArrayList neighbors = location.getNeighbors(voxel); @@ -819,17 +843,17 @@ static ArrayList checkVoxels(ArrayList voxels, PottsLocation locat nextList.add(neighbor); } } - + // Updated next voxel set with list of neighbors. nextSet.addAll(nextList); visited.add(voxel); unvisited.remove(voxel); } - + currSet = nextSet; currSize = currSet.size(); } - + // If not all coordinates have been visited, then the list of // coordinates is not connected. if (unvisited.size() != 0) { diff --git a/src/arcade/potts/env/location/PottsLocation2D.java b/src/arcade/potts/env/location/PottsLocation2D.java index 28f707d55..0a8fcc986 100644 --- a/src/arcade/potts/env/location/PottsLocation2D.java +++ b/src/arcade/potts/env/location/PottsLocation2D.java @@ -4,63 +4,62 @@ import java.util.HashMap; import static arcade.potts.util.PottsEnums.Direction; -/** - * Concrete implementation of {@link PottsLocation} for 2D. - */ - +/** Concrete implementation of {@link PottsLocation} for 2D. */ public final class PottsLocation2D extends PottsLocation implements Location2D { /** * Creates a 2D {@link PottsLocation} for a list of voxels. * - * @param voxels the list of voxels + * @param voxels the list of voxels */ - public PottsLocation2D(ArrayList voxels) { super(voxels); } - + public PottsLocation2D(ArrayList voxels) { + super(voxels); + } + @Override PottsLocation makeLocation(ArrayList voxels) { return new PottsLocation2D(voxels); } - + @Override ArrayList getNeighbors(Voxel focus) { return Location2D.getNeighbors(focus); } - + @Override public double convertSurface(double volume, double height) { return Location2D.convertSurface(volume, height); } - + @Override int calculateSurface() { return Location2D.calculateSurface(voxels); } - + @Override int calculateHeight() { return Location2D.calculateHeight(voxels); } - + @Override int updateSurface(Voxel voxel) { return Location2D.updateSurface(voxels, voxel); } - + @Override int updateHeight(Voxel voxel) { return Location2D.updateHeight(voxels, voxel); } - + @Override HashMap getDiameters() { return Location2D.getDiameters(voxels, getCenter()); } - + @Override Direction getSlice(Direction direction, HashMap diameters) { return Location2D.getSlice(direction, diameters); } - + @Override ArrayList getSelected(Voxel focus, double n) { return Location2D.getSelected(voxels, focus, n); diff --git a/src/arcade/potts/env/location/PottsLocation3D.java b/src/arcade/potts/env/location/PottsLocation3D.java index 8b26cf045..b9e9c1aec 100644 --- a/src/arcade/potts/env/location/PottsLocation3D.java +++ b/src/arcade/potts/env/location/PottsLocation3D.java @@ -4,63 +4,62 @@ import java.util.HashMap; import static arcade.potts.util.PottsEnums.Direction; -/** - * Concrete implementation of {@link PottsLocation} for 3D. - */ - +/** Concrete implementation of {@link PottsLocation} for 3D. */ public final class PottsLocation3D extends PottsLocation implements Location3D { /** * Creates a 3D {@link PottsLocation} for a list of voxels. * - * @param voxels the list of voxels + * @param voxels the list of voxels */ - public PottsLocation3D(ArrayList voxels) { super(voxels); } - + public PottsLocation3D(ArrayList voxels) { + super(voxels); + } + @Override PottsLocation makeLocation(ArrayList voxels) { return new PottsLocation3D(voxels); } - + @Override ArrayList getNeighbors(Voxel focus) { return Location3D.getNeighbors(focus); } - + @Override public double convertSurface(double volume, double height) { return Location3D.convertSurface(volume, height); } - + @Override int calculateSurface() { return Location3D.calculateSurface(voxels); } - + @Override int calculateHeight() { return Location3D.calculateHeight(voxels); } - + @Override int updateSurface(Voxel voxel) { return Location3D.updateSurface(voxels, voxel); } - + @Override int updateHeight(Voxel voxel) { return Location3D.updateHeight(voxels, voxel); } - + @Override HashMap getDiameters() { return Location3D.getDiameters(voxels, getCenter()); } - + @Override Direction getSlice(Direction direction, HashMap diameters) { return Location3D.getSlice(direction, diameters); } - + @Override ArrayList getSelected(Voxel focus, double n) { return Location3D.getSelected(voxels, focus, n); diff --git a/src/arcade/potts/env/location/PottsLocationContainer.java b/src/arcade/potts/env/location/PottsLocationContainer.java index a62025c65..6e4d7b1bd 100644 --- a/src/arcade/potts/env/location/PottsLocationContainer.java +++ b/src/arcade/potts/env/location/PottsLocationContainer.java @@ -8,129 +8,131 @@ import static arcade.potts.util.PottsEnums.Region; /** - * Implementation of {@link LocationContainer} for {@link PottsLocation} - * objects. - *

- * The container can be instantiated for locations with or without regions. The - * voxels available in a container are not necessarily all used when - * instantiating a {@link Location} instance. Instead, the number of voxels is - * selected based on the associated {@link PottsCellContainer} and + * Implementation of {@link LocationContainer} for {@link PottsLocation} objects. + * + *

The container can be instantiated for locations with or without regions. The voxels available + * in a container are not necessarily all used when instantiating a {@link Location} instance. + * Instead, the number of voxels is selected based on the associated {@link PottsCellContainer} and * {@link PottsLocationFactory} instance. */ - public final class PottsLocationContainer implements LocationContainer { /** Unique location container ID. */ public final int id; - + /** List of all available voxels. */ public final ArrayList allVoxels; - + /** Voxel at center of available voxels. */ public final Voxel center; - + /** Map of region to list of voxels. */ public final EnumMap> regions; - + /** * Creates a {@code PottsLocationContainer} instance. - *

- * The container does not have any regions. * - * @param id the location ID - * @param center the location center - * @param voxels the list of voxels + *

The container does not have any regions. + * + * @param id the location ID + * @param center the location center + * @param voxels the list of voxels */ public PottsLocationContainer(int id, Voxel center, ArrayList voxels) { this(id, center, voxels, null); } - + /** * Creates a {@code PottsLocationContainer} instance. * - * @param id the location ID - * @param center the location center - * @param voxels the list of voxels - * @param regions the list of region voxels + * @param id the location ID + * @param center the location center + * @param voxels the list of voxels + * @param regions the list of region voxels */ - public PottsLocationContainer(int id, Voxel center, ArrayList voxels, - EnumMap> regions) { + public PottsLocationContainer( + int id, + Voxel center, + ArrayList voxels, + EnumMap> regions) { this.id = id; this.center = center; this.allVoxels = voxels; this.regions = regions; } - + @Override - public int getID() { return id; } - + public int getID() { + return id; + } + @Override public Location convert(LocationFactory factory, CellContainer cell) { return convert((PottsLocationFactory) factory, (PottsCellContainer) cell); } - + /** * Converts the location container into a {@link PottsLocation}. * - * @param factory the cell factory instance - * @param cell the cell container - * @return a {@link PottsLocation} instance + * @param factory the cell factory instance + * @param cell the cell container + * @return a {@link PottsLocation} instance */ private Location convert(PottsLocationFactory factory, PottsCellContainer cell) { // Check for 3D. boolean is3D = (factory instanceof PottsLocationFactory3D); - + // Select voxels. int target = cell.voxels; ArrayList voxels = select(target, factory, allVoxels); - + // Make location. PottsLocation location; - + // Add regions. if (cell.regionVoxels != null) { EnumMap regionTargetMap = cell.regionVoxels; location = (is3D ? new PottsLocations3D(voxels) : new PottsLocations2D(voxels)); - + for (Region region : Region.values()) { // TODO add handling of other regions if (region != Region.NUCLEUS) { continue; } - + // Select region voxels. int regTarget = regionTargetMap.get(region); ArrayList allRegVoxels = regions.get(region); ArrayList regVoxels = select(regTarget, factory, allRegVoxels); - + // Assign regions. regVoxels.forEach(voxel -> location.assign(region, voxel)); } } else { location = (is3D ? new PottsLocation3D(voxels) : new PottsLocation2D(voxels)); } - + return location; } - + /** * Selects target number of voxels from list of valid voxels. * - * @param target the target number of voxels - * @param factory the location factory instance - * @param voxels the list of valid voxels - * @return a list of selected voxels + * @param target the target number of voxels + * @param factory the location factory instance + * @param voxels the list of valid voxels + * @return a list of selected voxels */ - private ArrayList select(int target, PottsLocationFactory factory, - ArrayList voxels) { + private ArrayList select( + int target, PottsLocationFactory factory, ArrayList voxels) { ArrayList selected; - + // Select voxels from list of all valid voxels. if (target == voxels.size()) { selected = new ArrayList<>(voxels); } else { selected = factory.getSelected(voxels, center, target); } - + // Add or remove voxels to reach target number. int size = selected.size(); if (size < target) { @@ -138,7 +140,7 @@ private ArrayList select(int target, PottsLocationFactory factory, } else if (size > target) { PottsLocationFactory.decrease(selected, target, factory.random); } - + return selected; } } diff --git a/src/arcade/potts/env/location/PottsLocationFactory.java b/src/arcade/potts/env/location/PottsLocationFactory.java index 2d862d662..fc65e83e3 100644 --- a/src/arcade/potts/env/location/PottsLocationFactory.java +++ b/src/arcade/potts/env/location/PottsLocationFactory.java @@ -14,44 +14,38 @@ /** * Implementation of {@link LocationFactory} for {@link PottsLocation} objects. - *

- * For a given {@link Series}, the factory uses its associated random number - * generator for shuffling voxel lists. The voxel lists a - * {@link PottsLocationContainer} are combined with a - * {@link arcade.potts.agent.cell.PottsCellContainer} to instantiate a - * {@link PottsLocation} object. + * + *

For a given {@link Series}, the factory uses its associated random number generator for + * shuffling voxel lists. The voxel lists a {@link PottsLocationContainer} are combined with a + * {@link arcade.potts.agent.cell.PottsCellContainer} to instantiate a {@link PottsLocation} object. */ - public abstract class PottsLocationFactory implements LocationFactory { /** List of valid (x, y, z) moves. */ static final int[][] VALID_MOVES = { - { -1, 0, 0 }, - { 1, 0, 0 }, - { 0, -1, 0 }, - { 0, 1, 0 }, - { 0, 0, -1 }, - { 0, 0, 1 } + {-1, 0, 0}, + {1, 0, 0}, + {0, -1, 0}, + {0, 1, 0}, + {0, 0, -1}, + {0, 0, 1} }; - + /** Random number generator instance. */ MersenneTwisterFast random; - + /** Map of id to location. */ public final HashMap locations; - - /** - * Creates a factory for making {@link PottsLocation} instances. - */ + + /** Creates a factory for making {@link PottsLocation} instances. */ public PottsLocationFactory() { locations = new HashMap<>(); } - + /** * {@inheritDoc} - *

- * For series with no loader, a list of available centers is created based - * on population settings. For series with a loader, the specified file is - * loaded into the factory. + * + *

For series with no loader, a list of available centers is created based on population + * settings. For series with a loader, the specified file is loaded into the factory. */ @Override public void initialize(Series series, MersenneTwisterFast random) { @@ -62,49 +56,54 @@ public void initialize(Series series, MersenneTwisterFast random) { createLocations(series); } } - + /** * {@inheritDoc} - *

- * Loaded locations are mapped by their id. + * + *

Loaded locations are mapped by their id. */ @Override public void loadLocations(Series series) { // Load locations. ArrayList containers = series.loader.loadLocations(); - + // Map loaded container to factory. for (LocationContainer container : containers) { PottsLocationContainer locationContainer = (PottsLocationContainer) container; locations.put(locationContainer.id, locationContainer); } } - + /** * {@inheritDoc} - *

- * The potts layer is subdivided into a grid of voxel sets. Each of these - * sets is used to create a location container. Note that these sets contain - * more voxels than required for instantiating a location; voxels are - * selected from the center outward until the required number of voxels - * (defined by a cell container) is selected. Containers are assigned - * regions if they exist. + * + *

The potts layer is subdivided into a grid of voxel sets. Each of these sets is used to + * create a location container. Note that these sets contain more voxels than required for + * instantiating a location; voxels are selected from the center outward until the required + * number of voxels (defined by a cell container) is selected. Containers are assigned regions + * if they exist. */ @Override public void createLocations(Series series) { int heightRange = getVoxelsPerHeight(series); int sideRange = getVoxelsPerSide(series, heightRange); - + if (sideRange == 0) { return; } - + // Get center voxels. - ArrayList centers = getCenters(series.length, series.width, series.height, - series.margin, sideRange, heightRange); + ArrayList centers = + getCenters( + series.length, + series.width, + series.height, + series.margin, + sideRange, + heightRange); Utilities.shuffleList(centers, random); centers.sort(Comparator.comparingInt(v -> v.z)); - + // Get regions (if they exist). HashSet regionKeys = new HashSet<>(); for (MiniBox population : series.populations.values()) { @@ -113,12 +112,12 @@ public void createLocations(Series series) { regionKeys.addAll(regionBox.getKeys()); } } - + // Create containers for each center. int id = 1; for (Voxel center : centers) { ArrayList voxels = getPossible(center, sideRange, heightRange); - + // Add regions (if they exist). EnumMap> regions = null; if (regionKeys.size() > 0) { @@ -128,111 +127,109 @@ public void createLocations(Series series) { regions.put(region, getPossible(center, sideRange - 2, heightRange)); } } - + PottsLocationContainer container = new PottsLocationContainer(id, center, voxels, regions); locations.put(id, container); id++; } } - + /** * Converts volume to voxels per square side. * - * @param volume the target volume - * @param height the target height - * @return the voxels per side + * @param volume the target volume + * @param height the target height + * @return the voxels per side */ int convert(double volume, double height) { int sqrt = (int) Math.ceil(Math.sqrt(volume / height)); return sqrt + (sqrt % 2 == 0 ? 1 : 0); } - + /** - * Finds the maximum height range between centers based on critical height. - * The height range is at least one and at most equal to the height of the - * simulation series with two voxel padding. + * Finds the maximum height range between centers based on critical height. The height range is + * at least one and at most equal to the height of the simulation series with two voxel padding. * - * @param series the simulation series - * @return the voxel height range + * @param series the simulation series + * @return the voxel height range */ int getVoxelsPerHeight(Series series) { int heightRange = 1; - + for (MiniBox population : series.populations.values()) { - double criticalHeight = population.getDouble("CRITICAL_HEIGHT_MEAN"); + double criticalHeight = population.getDouble("CRITICAL_HEIGHT"); int voxelsPerHeight = (int) (Math.min(series.height - 2, Math.ceil(criticalHeight))); if (voxelsPerHeight > heightRange) { heightRange = voxelsPerHeight; } } - + return heightRange; } - + /** - * Finds the maximum side range between centers based on critical volume. - * The side range may be zero if no cells can fit in the given simulation - * series and includes a two voxel padding. + * Finds the maximum side range between centers based on critical volume. The side range may be + * zero if no cells can fit in the given simulation series and includes a two voxel padding. * - * @param series the simulation series - * @param heightRange the voxel height range - * @return the voxel sides range + * @param series the simulation series + * @param heightRange the voxel height range + * @return the voxel sides range */ int getVoxelsPerSide(Series series, int heightRange) { int sideRange = 0; - + for (MiniBox population : series.populations.values()) { - double criticalVolume = population.getDouble("CRITICAL_VOLUME_MEAN"); + double criticalVolume = population.getDouble("CRITICAL_VOLUME"); int padding = population.getInt("PADDING"); int voxelsPerSide = convert(2 * criticalVolume, heightRange) + padding; if (voxelsPerSide > sideRange) { sideRange = voxelsPerSide; } } - + return sideRange; } - + /** * Selects specified number of voxels from a focus voxel. * - * @param voxels the list of voxels to select from - * @param focus the focus voxel - * @param n the number of voxels to select - * @return the list of selected voxels + * @param voxels the list of voxels to select from + * @param focus the focus voxel + * @param n the number of voxels to select + * @return the list of selected voxels */ abstract ArrayList getSelected(ArrayList voxels, Voxel focus, double n); - + /** * Gets all possible voxels within given range. * - * @param focus the focus voxel - * @param sideRange the location range per side - * @param heightRange the location range per height - * @return the list of possible voxels + * @param focus the focus voxel + * @param sideRange the location range per side + * @param heightRange the location range per height + * @return the list of possible voxels */ abstract ArrayList getPossible(Voxel focus, int sideRange, int heightRange); - + /** * Gets all centers for the given range. * - * @param length the array length - * @param width the array width - * @param height the array height - * @param margin the location margin - * @param sideRange the location range per side - * @param heightRange the location range per height - * @return the list of center voxels + * @param length the array length + * @param width the array width + * @param height the array height + * @param margin the location margin + * @param sideRange the location range per side + * @param heightRange the location range per height + * @return the list of center voxels */ - abstract ArrayList getCenters(int length, int width, int height, int margin, - int sideRange, int heightRange); - + abstract ArrayList getCenters( + int length, int width, int height, int margin, int sideRange, int heightRange); + /** * Gets list of valid voxels around a given voxel. * - * @param voxel the voxel - * @return the list of valid voxels + * @param voxel the voxel + * @return the list of valid voxels */ static ArrayList getValid(Voxel voxel) { ArrayList valid = new ArrayList<>(); @@ -242,20 +239,23 @@ static ArrayList getValid(Voxel voxel) { } return valid; } - + /** * Increases the number of voxels by adding from given list of voxels. * - * @param allVoxels the list of all possible voxels - * @param voxels the list of selected voxels - * @param target the target number of voxels - * @param random the seeded random number generator + * @param allVoxels the list of all possible voxels + * @param voxels the list of selected voxels + * @param target the target number of voxels + * @param random the seeded random number generator */ - static void increase(ArrayList allVoxels, ArrayList voxels, int target, - MersenneTwisterFast random) { + static void increase( + ArrayList allVoxels, + ArrayList voxels, + int target, + MersenneTwisterFast random) { int size = voxels.size(); HashSet neighbors = new HashSet<>(); - + // Get neighbors. for (Voxel voxel : voxels) { ArrayList allNeighbors = getValid(voxel); @@ -265,7 +265,7 @@ static void increase(ArrayList allVoxels, ArrayList voxels, int ta } } } - + // Add in random neighbors until target size is reached. ArrayList neighborsShuffled = new ArrayList<>(neighbors); Utilities.shuffleList(neighborsShuffled, random); @@ -274,36 +274,36 @@ static void increase(ArrayList allVoxels, ArrayList voxels, int ta voxels.add(neighborsShuffled.get(i)); } } - + /** * Decreases the number of voxels by removing from given list of voxels. * - * @param voxels the list of selected voxels - * @param target the target number of voxels - * @param random the seeded random number generator + * @param voxels the list of selected voxels + * @param target the target number of voxels + * @param random the seeded random number generator */ static void decrease(ArrayList voxels, int target, MersenneTwisterFast random) { int size = voxels.size(); - + // Remove random voxels until target size is reached. ArrayList voxelsShuffled = new ArrayList<>(voxels); Utilities.shuffleList(voxelsShuffled, random); int index = 0; - + for (int i = 0; i < size - target; i++) { // Return if there are no remaining neighbors to remove. if (index == voxelsShuffled.size()) { return; } - + Voxel candidate = voxelsShuffled.get(index++); - + // Always remove if the target number of voxels is one. if (target == 1) { voxels.remove(candidate); continue; } - + // Check candidate. Do not remove a candidate if it has a neighbor // that has only one neighbor (i.e. the candidate is the only connection) ArrayList candidateNeighbors = new ArrayList<>(); @@ -312,20 +312,19 @@ static void decrease(ArrayList voxels, int target, MersenneTwisterFast ra candidateNeighbors.add(neighbor); } } - + // Check neighbors of neighbor list. boolean valid = true; for (Voxel neighbor : candidateNeighbors) { - int count = getValid(neighbor).stream() - .mapToInt(v -> voxels.contains(v) ? 1 : 0) - .sum(); - + int count = + getValid(neighbor).stream().mapToInt(v -> voxels.contains(v) ? 1 : 0).sum(); + if (count == 1) { valid = false; break; } } - + if (valid) { voxels.remove(candidate); } else { diff --git a/src/arcade/potts/env/location/PottsLocationFactory2D.java b/src/arcade/potts/env/location/PottsLocationFactory2D.java index 496711eed..416b107f8 100644 --- a/src/arcade/potts/env/location/PottsLocationFactory2D.java +++ b/src/arcade/potts/env/location/PottsLocationFactory2D.java @@ -2,42 +2,40 @@ import java.util.ArrayList; -/** - * Concrete implementation of {@link PottsLocationFactory} for 2D. - */ - +/** Concrete implementation of {@link PottsLocationFactory} for 2D. */ public final class PottsLocationFactory2D extends PottsLocationFactory { - /** - * Creates a factory for making 2D {@link PottsLocation} instances. - */ - public PottsLocationFactory2D() { super(); } - + /** Creates a factory for making 2D {@link PottsLocation} instances. */ + public PottsLocationFactory2D() { + super(); + } + @Override ArrayList getSelected(ArrayList voxels, Voxel focus, double n) { return Location2D.getSelected(voxels, focus, n); } - + @Override ArrayList getPossible(Voxel focus, int sideRange, int heightRange) { ArrayList voxels = new ArrayList<>(); - + for (int i = 0; i < sideRange; i++) { for (int j = 0; j < sideRange; j++) { - voxels.add(new Voxel( - focus.x + i - (sideRange - 1) / 2, - focus.y + j - (sideRange - 1) / 2, - 0)); + voxels.add( + new Voxel( + focus.x + i - (sideRange - 1) / 2, + focus.y + j - (sideRange - 1) / 2, + 0)); } } - + return voxels; } - + @Override - ArrayList getCenters(int length, int width, int height, int margin, - int sideRange, int heightRange) { + ArrayList getCenters( + int length, int width, int height, int margin, int sideRange, int heightRange) { ArrayList centers = new ArrayList<>(); - + for (int i = 0; i < (length - 2 - 2 * margin) / sideRange; i++) { for (int j = 0; j < (width - 2 - 2 * margin) / sideRange; j++) { int cx = i * sideRange + (sideRange + 1) / 2 + margin; @@ -45,7 +43,7 @@ ArrayList getCenters(int length, int width, int height, int margin, centers.add(new Voxel(cx, cy, 0)); } } - + return centers; } } diff --git a/src/arcade/potts/env/location/PottsLocationFactory3D.java b/src/arcade/potts/env/location/PottsLocationFactory3D.java index 3994b409f..2f3f1ee58 100644 --- a/src/arcade/potts/env/location/PottsLocationFactory3D.java +++ b/src/arcade/potts/env/location/PottsLocationFactory3D.java @@ -2,44 +2,42 @@ import java.util.ArrayList; -/** - * Concrete implementation of {@link PottsLocationFactory} for 3D. - */ - +/** Concrete implementation of {@link PottsLocationFactory} for 3D. */ public final class PottsLocationFactory3D extends PottsLocationFactory { - /** - * Creates a factory for making 3D {@link PottsLocation} instances. - */ - public PottsLocationFactory3D() { super(); } - + /** Creates a factory for making 3D {@link PottsLocation} instances. */ + public PottsLocationFactory3D() { + super(); + } + @Override ArrayList getSelected(ArrayList voxels, Voxel focus, double n) { return Location3D.getSelected(voxels, focus, n); } - + @Override ArrayList getPossible(Voxel focus, int sideRange, int heightRange) { ArrayList voxels = new ArrayList<>(); - + for (int i = 0; i < sideRange; i++) { for (int j = 0; j < sideRange; j++) { for (int k = 0; k < heightRange; k++) { - voxels.add(new Voxel( - focus.x + i - (sideRange - 1) / 2, - focus.y + j - (sideRange - 1) / 2, - focus.z + k - (heightRange - 1) / 2)); + voxels.add( + new Voxel( + focus.x + i - (sideRange - 1) / 2, + focus.y + j - (sideRange - 1) / 2, + focus.z + k - (heightRange - 1) / 2)); } } } - + return voxels; } - + @Override - ArrayList getCenters(int length, int width, int height, int margin, - int sideRange, int heightRange) { + ArrayList getCenters( + int length, int width, int height, int margin, int sideRange, int heightRange) { ArrayList centers = new ArrayList<>(); - + for (int i = 0; i < (length - 2 - 2 * margin) / sideRange; i++) { for (int j = 0; j < (width - 2 - 2 * margin) / sideRange; j++) { for (int k = 0; k < (height - 2) / heightRange; k++) { @@ -50,7 +48,7 @@ ArrayList getCenters(int length, int width, int height, int margin, } } } - + return centers; } } diff --git a/src/arcade/potts/env/location/PottsLocations.java b/src/arcade/potts/env/location/PottsLocations.java index 403aa72c5..1b829e426 100644 --- a/src/arcade/potts/env/location/PottsLocations.java +++ b/src/arcade/potts/env/location/PottsLocations.java @@ -10,154 +10,154 @@ /** * Abstract extension of {@link PottsLocation} for regions. - *

- * {@code PottsLocations} objects manage an additional map of region to - * {@link PottsLocation} objects that manages the specific subsets of voxels for - * each region. - *

- * Concrete implementations of {@code PottsLocations} manage the dimensionality - * of the voxels. - *

- * {@code PottsLocations} also provides several additional general static - * methods for manipulating voxel lists needed for regions: + * + *

{@code PottsLocations} objects manage an additional map of region to {@link PottsLocation} + * objects that manages the specific subsets of voxels for each region. + * + *

Concrete implementations of {@code PottsLocations} manage the dimensionality of the voxels. + * + *

{@code PottsLocations} also provides several additional general static methods for + * manipulating voxel lists needed for regions: + * *

    - *
  • Assign voxels in lists to regions
  • - *
  • Select voxels to assign based on distance
  • + *
  • Assign voxels in lists to regions + *
  • Select voxels to assign based on distance *
*/ - public abstract class PottsLocations extends PottsLocation { /** Map of region to location. */ protected EnumMap locations; - + /** * Creates a {@code PottsLocations} for a list of voxels. * - * @param voxels the list of voxels + * @param voxels the list of voxels */ public PottsLocations(ArrayList voxels) { super(voxels); this.locations = new EnumMap<>(Region.class); - + ArrayList voxelCopy = new ArrayList<>(voxels); locations.put(Region.DEFAULT, makeLocation(voxelCopy)); } - + @Override public ArrayList getVoxels(Region region) { return (locations.containsKey(region) ? new ArrayList<>(locations.get(region).voxels) : new ArrayList<>()); } - + @Override - public EnumSet getRegions() { return EnumSet.copyOf(locations.keySet()); } - + public EnumSet getRegions() { + return EnumSet.copyOf(locations.keySet()); + } + @Override public double getVolume(Region region) { return (locations.containsKey(region) ? locations.get(region).volume : 0); } - + @Override public double getSurface(Region region) { return (locations.containsKey(region) ? locations.get(region).surface : 0); } - + @Override public double getHeight(Region region) { return (locations.containsKey(region) ? locations.get(region).height : 0); } - + @Override public void add(int x, int y, int z) { super.add(x, y, z); locations.get(Region.DEFAULT).add(x, y, z); } - + @Override public void add(Region region, int x, int y, int z) { super.add(x, y, z); - + Voxel voxel = new Voxel(x, y, z); - + for (PottsLocation loc : locations.values()) { if (loc.voxels.contains(voxel)) { return; } } - + if (!locations.containsKey(region)) { locations.put(region, makeLocation(new ArrayList<>())); } - + locations.get(region).add(x, y, z); } - + @Override public void remove(int x, int y, int z) { super.remove(x, y, z); locations.forEach((region, location) -> location.remove(x, y, z)); } - + @Override public void remove(Region region, int x, int y, int z) { Voxel voxel = new Voxel(x, y, z); - + if (locations.containsKey(region) && !locations.get(region).voxels.contains(voxel)) { return; } - + super.remove(x, y, z); - + if (locations.containsKey(region)) { locations.get(region).remove(x, y, z); } } - + @Override public void assign(Region region, Voxel voxel) { Region oldRegion = Region.UNDEFINED; - + // Check all regions for the voxel. for (Region key : locations.keySet()) { if (key != region && locations.get(key).voxels.contains(voxel)) { oldRegion = key; } } - + // Only assign if voxel exists and is assigned to a different region. if (oldRegion == Region.UNDEFINED) { return; } - + // Create new region location if it does not exist. if (!locations.containsKey(region)) { locations.put(region, makeLocation(new ArrayList<>())); } - + locations.get(region).voxels.add(voxel); locations.get(region).volume++; locations.get(region).surface += locations.get(region).updateSurface(voxel); locations.get(region).height += locations.get(region).updateHeight(voxel); locations.get(region).updateCenter(voxel.x, voxel.y, voxel.z, 1); - + locations.get(oldRegion).voxels.remove(voxel); locations.get(oldRegion).volume--; locations.get(oldRegion).surface -= locations.get(oldRegion).updateSurface(voxel); locations.get(oldRegion).height -= locations.get(oldRegion).updateHeight(voxel); locations.get(oldRegion).updateCenter(voxel.x, voxel.y, voxel.z, -1); } - + @Override public void distribute(Region region, int target, MersenneTwisterFast random) { if (region == Region.DEFAULT) { return; } - + PottsLocation defaultLocation = locations.get(Region.DEFAULT); PottsLocation regionLocation = locations.get(region); ArrayList regionVoxels = new ArrayList<>(regionLocation.voxels); - + // Select assignment center from the region voxels, if it exists, // otherwise from default voxels. Voxel center; @@ -169,12 +169,12 @@ public void distribute(Region region, int target, MersenneTwisterFast random) { assign(Region.DEFAULT, voxel); } } - + // Select voxels and make sure they are connected. Remove any that // are not connected. ArrayList selected = getSelected(center, target); checkVoxels(selected, this, random, true); - + // Add or remove voxels to hit the target number. int currentSize = selected.size(); if (currentSize < target) { @@ -182,31 +182,31 @@ public void distribute(Region region, int target, MersenneTwisterFast random) { } else if (currentSize > target) { PottsLocationFactory.decrease(selected, target, random); } - + // Reassign selected voxels. selected.forEach(voxel -> assign(region, voxel)); } - + @Override public void clear(int[][][] ids, int[][][] regions) { for (Voxel voxel : voxels) { ids[voxel.z][voxel.x][voxel.y] = 0; regions[voxel.z][voxel.x][voxel.y] = 0; } - + voxels.clear(); locations.clear(); } - + @Override public void update(int id, int[][][] ids, int[][][] regions) { super.update(id, ids, regions); - + for (Region region : locations.keySet()) { locations.get(region).update(region.ordinal(), regions, null); } } - + @Override public LocationContainer convert(int id) { EnumMap> regions = new EnumMap<>(Region.class); @@ -215,42 +215,42 @@ public LocationContainer convert(int id) { } return new PottsLocationContainer(id, getCenter(), voxels, regions); } - + @Override public double[] getCentroid(Region region) { return (locations.containsKey(region) ? locations.get(region).getCentroid() : null); } - + /** * Makes a new {@code PottsLocations} with the given voxels. * - * @param voxels the list of voxels - * @return a new {@code PottsLocations} + * @param voxels the list of voxels + * @return a new {@code PottsLocations} */ abstract PottsLocations makeLocations(ArrayList voxels); - + /** * Separates voxels in the list between this location and a new location. - *

- * Regions are re-assigned between the two splits. * - * @param voxelsA the list of voxels for this location - * @param voxelsB the list of voxels for the split location - * @param random the seeded random number generator - * @return a {@link arcade.core.env.location.Location} object with split voxels + *

Regions are re-assigned between the two splits. + * + * @param voxelsA the list of voxels for this location + * @param voxelsB the list of voxels for the split location + * @param random the seeded random number generator + * @return a {@link arcade.core.env.location.Location} object with split voxels */ @Override - Location separateVoxels(ArrayList voxelsA, ArrayList voxelsB, - MersenneTwisterFast random) { + Location separateVoxels( + ArrayList voxelsA, ArrayList voxelsB, MersenneTwisterFast random) { PottsLocations splitLocation = makeLocations(voxelsB); EnumMap fractions = new EnumMap<>(Region.class); int total = voxels.size(); - + // Update voxels in current location. for (Region region : locations.keySet()) { // Track fraction of voxels for each region. fractions.put(region, (double) locations.get(region).voxels.size() / total); - + // Assign to default region if in current split (A), otherwise remove // because it is in the new split (B). ArrayList regionVoxels = new ArrayList<>(locations.get(region).voxels); @@ -261,29 +261,29 @@ Location separateVoxels(ArrayList voxelsA, ArrayList voxelsB, remove(voxel.x, voxel.y, voxel.z); } } - + // Create empty regions in split location. if (!splitLocation.locations.containsKey(region)) { splitLocation.locations.put(region, makeLocation(new ArrayList<>())); } } - + // Assign voxel regions. for (Region region : locations.keySet()) { // No assignment for default regions. if (region == Region.DEFAULT) { continue; } - + // Get target number of voxels to assign for current split. int target = (int) (fractions.get(region) * this.volume); this.distribute(region, target, random); - + // Get target number of voxels to assign for new split. int splitTarget = (int) (fractions.get(region) * splitLocation.volume); splitLocation.distribute(region, splitTarget, random); } - + return splitLocation; } } diff --git a/src/arcade/potts/env/location/PottsLocations2D.java b/src/arcade/potts/env/location/PottsLocations2D.java index 27a9afced..7877b24f9 100644 --- a/src/arcade/potts/env/location/PottsLocations2D.java +++ b/src/arcade/potts/env/location/PottsLocations2D.java @@ -5,68 +5,67 @@ import static arcade.potts.util.PottsEnums.Direction; import static arcade.potts.util.PottsEnums.Region; -/** - * Concrete implementation of {@link PottsLocations} for 2D. - */ - +/** Concrete implementation of {@link PottsLocations} for 2D. */ public final class PottsLocations2D extends PottsLocations implements Location2D { /** * Creates a 2D {@link PottsLocation} for a list of voxels. * - * @param voxels the list of voxels + * @param voxels the list of voxels */ - public PottsLocations2D(ArrayList voxels) { super(voxels); } - + public PottsLocations2D(ArrayList voxels) { + super(voxels); + } + @Override PottsLocation makeLocation(ArrayList voxels) { return new PottsLocation2D(voxels); } - + @Override PottsLocations makeLocations(ArrayList voxels) { return new PottsLocations2D(voxels); } - + @Override ArrayList getNeighbors(Voxel focus) { return Location2D.getNeighbors(focus); } - + @Override public double convertSurface(double volume, double height) { return Location2D.convertSurface(volume, height); } - + @Override int calculateSurface() { return Location2D.calculateSurface(voxels); } - + @Override int calculateHeight() { return Location2D.calculateHeight(voxels); } - + @Override int updateSurface(Voxel voxel) { return Location2D.updateSurface(voxels, voxel); } - + @Override int updateHeight(Voxel voxel) { return Location2D.updateHeight(voxels, voxel); } - + @Override HashMap getDiameters() { return Location2D.getDiameters(voxels, getCenter()); } - + @Override Direction getSlice(Direction direction, HashMap diameters) { return Location2D.getSlice(direction, diameters); } - + @Override ArrayList getSelected(Voxel focus, double n) { return Location2D.getSelected(locations.get(Region.DEFAULT).voxels, focus, n); diff --git a/src/arcade/potts/env/location/PottsLocations3D.java b/src/arcade/potts/env/location/PottsLocations3D.java index 29912d275..c6d0b82dc 100644 --- a/src/arcade/potts/env/location/PottsLocations3D.java +++ b/src/arcade/potts/env/location/PottsLocations3D.java @@ -5,68 +5,67 @@ import static arcade.potts.util.PottsEnums.Direction; import static arcade.potts.util.PottsEnums.Region; -/** - * Concrete implementation of {@link PottsLocations} for 3D. - */ - +/** Concrete implementation of {@link PottsLocations} for 3D. */ public final class PottsLocations3D extends PottsLocations implements Location3D { /** * Creates a 3D {@link PottsLocation} for a list of voxels. * - * @param voxels the list of voxels + * @param voxels the list of voxels */ - public PottsLocations3D(ArrayList voxels) { super(voxels); } - + public PottsLocations3D(ArrayList voxels) { + super(voxels); + } + @Override PottsLocation makeLocation(ArrayList voxels) { return new PottsLocation3D(voxels); } - + @Override PottsLocations makeLocations(ArrayList voxels) { return new PottsLocations3D(voxels); } - + @Override ArrayList getNeighbors(Voxel focus) { return Location3D.getNeighbors(focus); } - + @Override public double convertSurface(double volume, double height) { return Location3D.convertSurface(volume, height); } - + @Override int calculateSurface() { return Location3D.calculateSurface(voxels); } - + @Override int calculateHeight() { return Location3D.calculateHeight(voxels); } - + @Override int updateSurface(Voxel voxel) { return Location3D.updateSurface(voxels, voxel); } - + @Override int updateHeight(Voxel voxel) { return Location3D.updateHeight(voxels, voxel); } - + @Override HashMap getDiameters() { return Location3D.getDiameters(voxels, getCenter()); } - + @Override Direction getSlice(Direction direction, HashMap diameters) { return Location3D.getSlice(direction, diameters); } - + @Override ArrayList getSelected(Voxel focus, double n) { return Location3D.getSelected(locations.get(Region.DEFAULT).voxels, focus, n); diff --git a/src/arcade/potts/env/location/Voxel.java b/src/arcade/potts/env/location/Voxel.java index b958ef2a9..c72746b88 100644 --- a/src/arcade/potts/env/location/Voxel.java +++ b/src/arcade/potts/env/location/Voxel.java @@ -4,50 +4,55 @@ /** * Representation of a voxel for locations. - *

- * Each voxel is defined by (x, y, z) coordinates. Two voxels objects are - * considered equal if they have matching (x, y, z) coordinates. + * + *

Each voxel is defined by (x, y, z) coordinates. Two voxels objects are considered equal if + * they have matching (x, y, z) coordinates. */ - public final class Voxel { /** Comparator for voxels. */ - public static final Comparator VOXEL_COMPARATOR = (v1, v2) -> v1.z != v2.z - ? Integer.compare(v1.z, v2.z) : v1.x != v2.x - ? Integer.compare(v1.x, v2.x) : Integer.compare(v1.y, v2.y); - + public static final Comparator VOXEL_COMPARATOR = + (v1, v2) -> + v1.z != v2.z + ? Integer.compare(v1.z, v2.z) + : v1.x != v2.x + ? Integer.compare(v1.x, v2.x) + : Integer.compare(v1.y, v2.y); + /** Voxel x coordinate. */ public final int x; - + /** Voxel y coordinate. */ public final int y; - + /** Voxel z coordinate. */ public final int z; - + /** * Creates a {@code Voxel} at the given coordinates. * - * @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 */ public Voxel(int x, int y, int z) { this.x = x; this.y = y; this.z = z; } - + /** * Gets hash based on (x, y, z) coordinates. * - * @return the hash + * @return the hash */ - public int hashCode() { return x + (y << 8) + (z << 16); } - + public int hashCode() { + return x + (y << 8) + (z << 16); + } + /** * Checks if two locations have the same (x, y, z) coordinates. * - * @param obj the voxel to compare + * @param obj the voxel to compare * @return {@code true} if coordinates are the same, {@code false} otherwise */ public boolean equals(Object obj) { @@ -57,11 +62,11 @@ public boolean equals(Object obj) { Voxel voxel = (Voxel) obj; return voxel.x == x && voxel.y == y && voxel.z == z; } - + /** * Returns voxel as string. * - * @return a string + * @return a string */ public String toString() { return String.format("[%d, %d, %d]", x, y, z); diff --git a/src/arcade/potts/parameter.potts.xml b/src/arcade/potts/parameter.potts.xml index d65180116..df05140d3 100644 --- a/src/arcade/potts/parameter.potts.xml +++ b/src/arcade/potts/parameter.potts.xml @@ -2,59 +2,53 @@ - + - + - + - + - + - + - + - + - - - - - + + + - - - - - + + + - - - - - + + + @@ -68,7 +62,7 @@ - + diff --git a/src/arcade/potts/sim/Potts.java b/src/arcade/potts/sim/Potts.java index e225b2956..a0b46f0db 100644 --- a/src/arcade/potts/sim/Potts.java +++ b/src/arcade/potts/sim/Potts.java @@ -14,84 +14,85 @@ /** * Cellular Potts Model (CPM) implementation. - *

- * The potts layer tracks cells in an array of ids that define the morphology of - * each cell (alongside non-cell areas). The corresponding array of regions - * further defines regions within a given cell. - *

- * The Hamiltonian, which decides which positions in the arrays are flipped, - * consists of a series of terms including: + * + *

The potts layer tracks cells in an array of ids that define the morphology of each cell + * (alongside non-cell areas). The corresponding array of regions further defines regions within a + * given cell. + * + *

The Hamiltonian, which decides which positions in the arrays are flipped, consists of a series + * of terms including: + * *

    - *
  • Cell to cell and cell to non-cell adhesion
  • - *
  • Volume constraint between actual and target volume
  • - *
  • Surface constraint between actual and target surface
  • + *
  • Cell to cell and cell to non-cell adhesion + *
  • Volume constraint between actual and target volume + *
  • Surface constraint between actual and target surface *
*/ - public abstract class Potts implements Steppable { /** Length (x direction) of potts array. */ public final int length; - + /** Width (y direction) of potts array. */ public final int width; - + /** Depth (z direction) of potts array. */ public final int height; - + /** Number of steps in Monte Carlo Step. */ final int steps; - + /** Effective cell temperature. */ final double temperature; - + /** {@code true} if potts is single layer, {@code false} otherwise. */ final boolean isSingle; - + /** {@code true} if cells have regions, {@code false} otherwise. */ final boolean hasRegions; - + /** Potts array for ids. */ public int[][][] ids; - + /** Potts array for regions. */ public int[][][] regions; - + /** Grid holding cells. */ Grid grid; - + /** List of Hamiltonian terms. */ ArrayList hamiltonian; - + /** * Creates a cellular {@code Potts} model. * - * @param series the simulation series + * @param series the simulation series */ public Potts(PottsSeries series) { // Creates potts arrays. ids = new int[series.height][series.length][series.width]; regions = new int[series.height][series.length][series.width]; - + // Ensure a 1 voxel border around to avoid boundary checks. length = series.length - 2; width = series.width - 2; height = (series.height == 1 ? 1 : series.height - 2); - + // Number of Monte Carlo steps double mcs = series.potts.getDouble("MCS"); steps = (int) (mcs * length * width * height); - + // Get temperature. temperature = series.potts.getDouble("TEMPERATURE"); - + // Check if potts is a single layer. isSingle = series.height == 1; - + // Check if there are regions. - hasRegions = series.populations.values().stream() - .map(e -> e.filter("(REGION)").getKeys().size()) - .anyMatch(e -> e > 0); - + hasRegions = + series.populations.values().stream() + .map(e -> e.filter("(REGION)").getKeys().size()) + .anyMatch(e -> e > 0); + // Initialize hamiltonian list. hamiltonian = new ArrayList<>(); if (series.terms != null) { @@ -100,42 +101,42 @@ public Potts(PottsSeries series) { .forEach(h -> hamiltonian.add(h)); } } - + /** * Registers the cell to all Hamiltonian term instances. * - * @param cell the cell instance + * @param cell the cell instance */ public void register(PottsCell cell) { for (Hamiltonian h : hamiltonian) { h.register(cell); } } - + /** * Deregisters the cell from all Hamiltonian term instances. * - * @param cell the cell instance + * @param cell the cell instance */ public void deregister(PottsCell cell) { for (Hamiltonian h : hamiltonian) { h.deregister(cell); } } - + /** * Gets instance of selected Hamiltonian term. * - * @param term the Hamiltonian term - * @param series the simulation series - * @return the Hamiltonian instance + * @param term the Hamiltonian term + * @param series the simulation series + * @return the Hamiltonian instance */ abstract Hamiltonian getHamiltonian(Term term, PottsSeries series); - + /** * Steps through array updates for Monte Carlo step. * - * @param simstate the MASON simulation state + * @param simstate the MASON simulation state */ @Override public void step(SimState simstate) { @@ -144,26 +145,26 @@ public void step(SimState simstate) { int x; int y; int z; - + for (int step = 0; step < steps; step++) { // Get random coordinate for candidate. x = random.nextInt(length) + 1; y = random.nextInt(width) + 1; z = (random.nextInt(height) + 1) * (isSingle ? 0 : 1); r = random.nextDouble(); - + // Check if cell has regions. boolean hasRegionsCell = (ids[z][x][y] != 0 && getCell(ids[z][x][y]).hasRegions()); - + // Get unique targets. HashSet uniqueIDTargets = getUniqueIDs(x, y, z); HashSet uniqueRegionTargets = getUniqueRegions(x, y, z); - + // Check if there are valid unique targets. boolean hasIDTargets = uniqueIDTargets.size() > 0; boolean hasRegionTargets = uniqueRegionTargets.size() > 0; boolean check = simstate.random.nextDouble() < 0.5; - + // Select unique ID or unique region (if they exist). If there is // a unique ID and unique region target, then randomly select. If // there are neither, then skip. @@ -178,21 +179,20 @@ public void step(SimState simstate) { } } } - + /** - * Flips connected voxel from source to target id based on Boltzmann - * probability. + * Flips connected voxel from source to target id based on Boltzmann probability. * - * @param sourceID the id of the source voxel - * @param targetID the id of the target voxel - * @param x the x coordinate - * @param y the y coordinate - * @param z the z coordinate - * @param r a random number + * @param sourceID the id of the source voxel + * @param targetID the id of the target voxel + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + * @param r a random number */ void flip(int sourceID, int targetID, int x, int y, int z, double r) { boolean zero = ids[z][x][y] == 0; - + // Check connectivity of source. if (sourceID > 0) { boolean[][][] neighborhood = getNeighborhood(sourceID, x, y, z); @@ -200,7 +200,7 @@ void flip(int sourceID, int targetID, int x, int y, int z, double r) { if (!candidateConnected) { return; } - + // Check connectivity of regions. if (regions[z][x][y] > Region.DEFAULT.ordinal()) { boolean[][][] rNeighborhood = getNeighborhood(sourceID, regions[z][x][y], x, y, z); @@ -210,7 +210,7 @@ void flip(int sourceID, int targetID, int x, int y, int z, double r) { } } } - + // Check connectivity of target. if (targetID > 0) { boolean[][][] neighborhood = getNeighborhood(targetID, x, y, z); @@ -218,7 +218,7 @@ void flip(int sourceID, int targetID, int x, int y, int z, double r) { if (!targetConnected) { return; } - + // Check connectivity of regions. if (regions[z][x][y] > Region.DEFAULT.ordinal()) { boolean[][][] rNeighborhood = getNeighborhood(targetID, regions[z][x][y], x, y, z); @@ -228,20 +228,20 @@ void flip(int sourceID, int targetID, int x, int y, int z, double r) { } } } - + // Change the voxel. change(sourceID, targetID, x, y, z, r); } - + /** * Calculates energy change to decide if a voxel is flipped. * - * @param sourceID the id of the source voxel - * @param targetID the id of the target voxel - * @param x the x coordinate - * @param y the y coordinate - * @param z the z coordinate - * @param r a random number + * @param sourceID the id of the source voxel + * @param targetID the id of the target voxel + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + * @param r a random number */ void change(int sourceID, int targetID, int x, int y, int z, double r) { // Calculate energy change. @@ -249,7 +249,7 @@ void change(int sourceID, int targetID, int x, int y, int z, double r) { for (Hamiltonian h : hamiltonian) { dH += h.getDelta(sourceID, targetID, x, y, z); } - + // Calculate probability. double p; if (dH < 0) { @@ -257,15 +257,14 @@ void change(int sourceID, int targetID, int x, int y, int z, double r) { } else { p = Math.exp(-dH / temperature); } - + if (r < p) { ids[z][x][y] = targetID; if (hasRegions) { - regions[z][x][y] = (targetID == 0 - ? Region.UNDEFINED.ordinal() - : Region.DEFAULT.ordinal()); + regions[z][x][y] = + (targetID == 0 ? Region.UNDEFINED.ordinal() : Region.DEFAULT.ordinal()); } - + if (sourceID > 0) { ((PottsLocation) getCell(sourceID).getLocation()).remove(x, y, z); } @@ -274,22 +273,21 @@ void change(int sourceID, int targetID, int x, int y, int z, double r) { } } } - + /** - * Flips connected voxel from source to target region based on Boltzmann - * probability. + * Flips connected voxel from source to target region based on Boltzmann probability. * - * @param id the voxel id - * @param sourceRegion the region of the source voxel - * @param targetRegion the region of the target voxel - * @param x the x coordinate - * @param y the y coordinate - * @param z the z coordinate - * @param r a random number + * @param id the voxel id + * @param sourceRegion the region of the source voxel + * @param targetRegion the region of the target voxel + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + * @param r a random number */ void flip(int id, int sourceRegion, int targetRegion, int x, int y, int z, double r) { boolean zero = regions[z][x][y] == Region.DEFAULT.ordinal(); - + // Check connectivity of source. if (sourceRegion > Region.DEFAULT.ordinal()) { boolean[][][] neighborhood = getNeighborhood(id, sourceRegion, x, y, z); @@ -298,7 +296,7 @@ void flip(int id, int sourceRegion, int targetRegion, int x, int y, int z, doubl return; } } - + // Check connectivity of target. if (targetRegion > Region.DEFAULT.ordinal()) { boolean[][][] neighborhood = getNeighborhood(id, targetRegion, x, y, z); @@ -307,21 +305,21 @@ void flip(int id, int sourceRegion, int targetRegion, int x, int y, int z, doubl return; } } - + // Change the voxel region. change(id, sourceRegion, targetRegion, x, y, z, r); } - + /** * Calculates energy change to decide if a voxel region is flipped. * - * @param id the voxel id - * @param sourceRegion the region of the source voxel - * @param targetRegion the region of the target voxel - * @param x the x coordinate - * @param y the y coordinate - * @param z the z coordinate - * @param r a random number + * @param id the voxel id + * @param sourceRegion the region of the source voxel + * @param targetRegion the region of the target voxel + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + * @param r a random number */ void change(int id, int sourceRegion, int targetRegion, int x, int y, int z, double r) { // Calculate energy change. @@ -329,7 +327,7 @@ void change(int id, int sourceRegion, int targetRegion, int x, int y, int z, dou for (Hamiltonian h : hamiltonian) { dH += h.getDelta(id, sourceRegion, targetRegion, x, y, z); } - + // Calculate probability. double p; if (dH < 0) { @@ -337,7 +335,7 @@ void change(int id, int sourceRegion, int targetRegion, int x, int y, int z, dou } else { p = Math.exp(-dH / temperature); } - + if (r < p) { regions[z][x][y] = targetRegion; PottsCell c = getCell(id); @@ -345,12 +343,12 @@ void change(int id, int sourceRegion, int targetRegion, int x, int y, int z, dou ((PottsLocation) c.getLocation()).add(Region.values()[targetRegion], x, y, z); } } - + /** * Gets the {@link PottsCell} object for the given id. * - * @param id the cell id - * @return the {@link PottsCell} object, {@code null} if id is zero + * @param id the cell id + * @return the {@link PottsCell} object, {@code null} if id is zero */ public PottsCell getCell(int id) { if (id > 0) { @@ -359,56 +357,56 @@ public PottsCell getCell(int id) { return null; } } - + /** * Gets neighborhood for the given voxel. * - * @param id the voxel id - * @param x the x coordinate - * @param y the y coordinate - * @param z the z coordinate - * @return {@code true} if simply connected, {@code false} otherwise + * @param id the voxel id + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + * @return {@code true} if simply connected, {@code false} otherwise */ abstract boolean[][][] getNeighborhood(int id, int x, int y, int z); - + /** * Gets neighborhood for the given voxel region. * - * @param id the voxel id - * @param region the voxel region - * @param x the x coordinate - * @param y the y coordinate - * @param z the z coordinate - * @return {@code true} if simply connected, {@code false} otherwise + * @param id the voxel id + * @param region the voxel region + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + * @return {@code true} if simply connected, {@code false} otherwise */ abstract boolean[][][] getNeighborhood(int id, int region, int x, int y, int z); - + /** * Determines connectivity of given neighborhood. * - * @param array the array of neighbors + * @param array the array of neighbors * @param zero {@code true} if location has zero id, {@code false} otherwise - * @return {@code true} if simply connected, {@code false} otherwise + * @return {@code true} if simply connected, {@code false} otherwise */ abstract boolean getConnectivity(boolean[][][] array, boolean zero); - + /** * Gets unique IDs adjacent to given voxel. * - * @param x the x coordinate - * @param y the y coordinate - * @param z the z coordinate - * @return the list of unique IDs + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + * @return the list of unique IDs */ abstract HashSet getUniqueIDs(int x, int y, int z); - + /** * Gets unique regions adjacent to given voxel. * - * @param x the x coordinate - * @param y the y coordinate - * @param z the z coordinate - * @return the list of unique regions + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + * @return the list of unique regions */ abstract HashSet getUniqueRegions(int x, int y, int z); } diff --git a/src/arcade/potts/sim/Potts2D.java b/src/arcade/potts/sim/Potts2D.java index c54e964d5..011d6f850 100644 --- a/src/arcade/potts/sim/Potts2D.java +++ b/src/arcade/potts/sim/Potts2D.java @@ -8,33 +8,32 @@ import arcade.potts.sim.hamiltonian.VolumeHamiltonian; import static arcade.potts.util.PottsEnums.Term; -/** - * Extension of {@link Potts} for 2D. - */ - +/** Extension of {@link Potts} for 2D. */ public final class Potts2D extends Potts { /** Number of neighbors. */ public static final int NUMBER_NEIGHBORS = 4; - + /** List of x direction movements (N, E, S, W). */ - public static final int[] MOVES_X = { 0, 1, 0, -1 }; - + public static final int[] MOVES_X = {0, 1, 0, -1}; + /** List of y direction movements (N, E, S, W). */ - public static final int[] MOVES_Y = { -1, 0, 1, 0 }; - + public static final int[] MOVES_Y = {-1, 0, 1, 0}; + /** List of x direction corner movements (NE, SE, SW, NW). */ - private static final int[] CORNER_X = { 1, 1, -1, -1 }; - + private static final int[] CORNER_X = {1, 1, -1, -1}; + /** List of y direction corner movements (NE, SE, SW, NW). */ - private static final int[] CORNER_Y = { -1, 1, 1, -1 }; - + private static final int[] CORNER_Y = {-1, 1, 1, -1}; + /** * Creates a cellular {@code Potts} model in 2D. * - * @param series the simulation series + * @param series the simulation series */ - public Potts2D(PottsSeries series) { super(series); } - + public Potts2D(PottsSeries series) { + super(series); + } + @Override Hamiltonian getHamiltonian(Term term, PottsSeries series) { switch (term) { @@ -50,7 +49,7 @@ Hamiltonian getHamiltonian(Term term, PottsSeries series) { return null; } } - + @Override boolean[][][] getNeighborhood(int id, int x, int y, int z) { boolean[][] array = new boolean[3][3]; @@ -59,21 +58,22 @@ boolean[][][] getNeighborhood(int id, int x, int y, int z) { array[i][j] = ids[0][i + x - 1][j + y - 1] == id; } } - return new boolean[][][] { array }; + return new boolean[][][] {array}; } - + @Override boolean[][][] getNeighborhood(int id, int region, int x, int y, int z) { boolean[][] array = new boolean[3][3]; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { - array[i][j] = ids[0][i + x - 1][j + y - 1] == id - && regions[0][i + x - 1][j + y - 1] == region; + array[i][j] = + ids[0][i + x - 1][j + y - 1] == id + && regions[0][i + x - 1][j + y - 1] == region; } } - return new boolean[][][] { array }; + return new boolean[][][] {array}; } - + @Override boolean getConnectivity(boolean[][][] array, boolean zero) { boolean[][] subarray = array[0]; @@ -83,7 +83,7 @@ boolean getConnectivity(boolean[][][] array, boolean zero) { links++; } } - + switch (links) { case 1: return true; @@ -97,12 +97,12 @@ boolean getConnectivity(boolean[][][] array, boolean zero) { return false; } } - + /** * Determines simple connectivity for a position with two neighbors. * - * @param subarray the local neighborhood array - * @return {@code true} if simply connected, {@code false} otherwise + * @param subarray the local neighborhood array + * @return {@code true} if simply connected, {@code false} otherwise */ private boolean getConnectivityTwoNeighbors(boolean[][] subarray) { if (subarray[1][2] && subarray[1][0]) { @@ -115,8 +115,9 @@ private boolean getConnectivityTwoNeighbors(boolean[][] subarray) { // Check for corners for (int i = 0; i < NUMBER_NEIGHBORS; i++) { boolean check1 = subarray[1 + MOVES_X[i]][1 + MOVES_Y[i]]; - boolean check2 = subarray[1 + MOVES_X[(i + 1) % NUMBER_NEIGHBORS]] - [1 + MOVES_Y[(i + 1) % NUMBER_NEIGHBORS]]; + boolean check2 = + subarray[1 + MOVES_X[(i + 1) % NUMBER_NEIGHBORS]][ + 1 + MOVES_Y[(i + 1) % NUMBER_NEIGHBORS]]; boolean check3 = subarray[1 + CORNER_X[i]][1 + CORNER_Y[i]]; if (check1 && check2 && check3) { return true; @@ -125,20 +126,22 @@ private boolean getConnectivityTwoNeighbors(boolean[][] subarray) { return false; } } - + /** * Determines simple connectivity for a position with three neighbors. * - * @param subarray the local neighborhood array - * @return {@code true} if simply connected, {@code false} otherwise + * @param subarray the local neighborhood array + * @return {@code true} if simply connected, {@code false} otherwise */ private boolean getConnectivityThreeNeighbors(boolean[][] subarray) { for (int i = 0; i < NUMBER_NEIGHBORS; i++) { if (!subarray[1 + MOVES_X[i]][1 + MOVES_Y[i]]) { - boolean check1 = subarray[1 + CORNER_X[(i + 1) % NUMBER_NEIGHBORS]] - [1 + CORNER_Y[(i + 1) % NUMBER_NEIGHBORS]]; - boolean check2 = subarray[1 + CORNER_X[(i + 2) % NUMBER_NEIGHBORS]] - [1 + CORNER_Y[(i + 2) % NUMBER_NEIGHBORS]]; + boolean check1 = + subarray[1 + CORNER_X[(i + 1) % NUMBER_NEIGHBORS]][ + 1 + CORNER_Y[(i + 1) % NUMBER_NEIGHBORS]]; + boolean check2 = + subarray[1 + CORNER_X[(i + 2) % NUMBER_NEIGHBORS]][ + 1 + CORNER_Y[(i + 2) % NUMBER_NEIGHBORS]]; if (check1 && check2) { return true; } @@ -146,12 +149,12 @@ private boolean getConnectivityThreeNeighbors(boolean[][] subarray) { } return false; } - + @Override HashSet getUniqueIDs(int x, int y, int z) { int id = ids[z][x][y]; HashSet unique = new HashSet<>(); - + for (int i = 0; i < NUMBER_NEIGHBORS; i++) { int neighbor = ids[z][x + MOVES_X[i]][y + MOVES_Y[i]]; if (id != neighbor) { @@ -160,17 +163,17 @@ HashSet getUniqueIDs(int x, int y, int z) { } return unique; } - + @Override HashSet getUniqueRegions(int x, int y, int z) { int id = ids[z][x][y]; int region = regions[z][x][y]; HashSet unique = new HashSet<>(); - + for (int i = 0; i < NUMBER_NEIGHBORS; i++) { int neighborID = ids[z][x + MOVES_X[i]][y + MOVES_Y[i]]; int neighborRegion = regions[z][x + MOVES_X[i]][y + MOVES_Y[i]]; - + if (neighborID != id) { continue; } @@ -178,7 +181,7 @@ HashSet getUniqueRegions(int x, int y, int z) { unique.add(neighborRegion); } } - + return unique; } } diff --git a/src/arcade/potts/sim/Potts3D.java b/src/arcade/potts/sim/Potts3D.java index 048bde5e2..7c4686e8d 100644 --- a/src/arcade/potts/sim/Potts3D.java +++ b/src/arcade/potts/sim/Potts3D.java @@ -11,45 +11,44 @@ import arcade.potts.sim.hamiltonian.VolumeHamiltonian; import static arcade.potts.util.PottsEnums.Term; -/** - * Extension of {@link Potts} for 3D. - */ - +/** Extension of {@link Potts} for 3D. */ public final class Potts3D extends Potts { /** Number of neighbors. */ public static final int NUMBER_NEIGHBORS = 6; - + /** List of x direction movements (N, E, S, W, U, D). */ - public static final int[] MOVES_X = { 0, 1, 0, -1, 0, 0 }; - + public static final int[] MOVES_X = {0, 1, 0, -1, 0, 0}; + /** List of y direction movements (N, E, S, W, U, D). */ - public static final int[] MOVES_Y = { -1, 0, 1, 0, 0, 0 }; - + public static final int[] MOVES_Y = {-1, 0, 1, 0, 0, 0}; + /** List of z direction movements (N, E, S, W, U, D). */ - public static final int[] MOVES_Z = { 0, 0, 0, 0, 1, -1 }; - + public static final int[] MOVES_Z = {0, 0, 0, 0, 1, -1}; + /** Number of neighbors in plane. */ private static final int NUMBER_PLANE = 4; - + /** List of plane movements for first coordinate. */ - private static final int[] PLANE_A = { 0, 1, 0, -1 }; - + private static final int[] PLANE_A = {0, 1, 0, -1}; + /** List of plane movements for second coordinate. */ - private static final int[] PLANE_B = { -1, 0, 1, 0 }; - + private static final int[] PLANE_B = {-1, 0, 1, 0}; + /** List of a direction corner movements. */ - private static final int[] CORNER_A = { 1, 1, -1, -1 }; - + private static final int[] CORNER_A = {1, 1, -1, -1}; + /** List of b direction corner movements. */ - private static final int[] CORNER_B = { -1, 1, 1, -1 }; - + private static final int[] CORNER_B = {-1, 1, 1, -1}; + /** * Creates a cellular {@code Potts} model in 3D. * - * @param series the simulation series + * @param series the simulation series */ - public Potts3D(PottsSeries series) { super(series); } - + public Potts3D(PottsSeries series) { + super(series); + } + @Override Hamiltonian getHamiltonian(Term term, PottsSeries series) { switch (term) { @@ -71,7 +70,7 @@ Hamiltonian getHamiltonian(Term term, PottsSeries series) { return null; } } - + @Override boolean[][][] getNeighborhood(int id, int x, int y, int z) { boolean[][][] array = new boolean[3][3][3]; @@ -84,21 +83,22 @@ boolean[][][] getNeighborhood(int id, int x, int y, int z) { } return array; } - + @Override boolean[][][] getNeighborhood(int id, int region, int x, int y, int z) { boolean[][][] array = new boolean[3][3][3]; for (int k = 0; k < 3; k++) { for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { - array[k][i][j] = ids[k + z - 1][i + x - 1][j + y - 1] == id - && regions[k + z - 1][i + x - 1][j + y - 1] == region; + array[k][i][j] = + ids[k + z - 1][i + x - 1][j + y - 1] == id + && regions[k + z - 1][i + x - 1][j + y - 1] == region; } } } return array; } - + @Override boolean getConnectivity(boolean[][][] array, boolean zero) { int links = 0; @@ -107,7 +107,7 @@ boolean getConnectivity(boolean[][][] array, boolean zero) { links++; } } - + switch (links) { case 1: return true; @@ -125,12 +125,12 @@ boolean getConnectivity(boolean[][][] array, boolean zero) { return false; } } - + /** * Determines simple connectivity for a position with two neighbors. * - * @param array the local neighborhood array - * @return {@code true} if simply connected, {@code false} otherwise + * @param array the local neighborhood array + * @return {@code true} if simply connected, {@code false} otherwise */ private boolean getConnectivityTwoNeighbors(boolean[][][] array) { if (array[1][1][0] && array[1][1][2]) { @@ -147,26 +147,29 @@ private boolean getConnectivityTwoNeighbors(boolean[][][] array) { for (int i = 0; i < NUMBER_PLANE; i++) { // XY plane boolean xy1 = array[1][1 + PLANE_A[i]][1 + PLANE_B[i]]; - boolean xy2 = array[1][1 + PLANE_A[(i + 1) % NUMBER_PLANE]] - [1 + PLANE_B[(i + 1) % NUMBER_PLANE]]; + boolean xy2 = + array[1][1 + PLANE_A[(i + 1) % NUMBER_PLANE]][ + 1 + PLANE_B[(i + 1) % NUMBER_PLANE]]; boolean xy3 = array[1][1 + CORNER_A[i]][1 + CORNER_B[i]]; if (xy1 && xy2 && xy3) { return true; } - + // YZ plane boolean yz1 = array[1 + PLANE_B[i]][1][1 + PLANE_A[i]]; - boolean yz2 = array[1 + PLANE_B[(i + 1) % NUMBER_PLANE]] - [1][1 + PLANE_A[(i + 1) % NUMBER_PLANE]]; + boolean yz2 = + array[1 + PLANE_B[(i + 1) % NUMBER_PLANE]][1][ + 1 + PLANE_A[(i + 1) % NUMBER_PLANE]]; boolean yz3 = array[1 + CORNER_B[i]][1][1 + CORNER_A[i]]; if (yz1 && yz2 && yz3) { return true; } - + // ZX plane boolean zx1 = array[1 + PLANE_A[i]][1 + PLANE_B[i]][1]; - boolean zx2 = array[1 + PLANE_A[(i + 1) % NUMBER_PLANE]] - [1 + PLANE_B[(i + 1) % NUMBER_PLANE]][1]; + boolean zx2 = + array[1 + PLANE_A[(i + 1) % NUMBER_PLANE]][ + 1 + PLANE_B[(i + 1) % NUMBER_PLANE]][1]; boolean zx3 = array[1 + CORNER_A[i]][1 + CORNER_B[i]][1]; if (zx1 && zx2 && zx3) { return true; @@ -175,68 +178,77 @@ private boolean getConnectivityTwoNeighbors(boolean[][][] array) { return false; } } - + /** * Determines simple connectivity for a position with three neighbors. * - * @param array the local neighborhood array - * @return {@code true} if simply connected, {@code false} otherwise + * @param array the local neighborhood array + * @return {@code true} if simply connected, {@code false} otherwise */ private boolean getConnectivityThreeNeighbors(boolean[][][] array) { for (int i = 0; i < NUMBER_PLANE; i++) { // XY plane boolean xy1 = array[1][1 + PLANE_A[i]][1 + PLANE_B[i]]; if (!xy1 && !array[0][1][1] && !array[2][1][1]) { - boolean xy2 = array[1][1 + CORNER_A[(i + 1) % NUMBER_PLANE]] - [1 + CORNER_B[(i + 1) % NUMBER_PLANE]]; - boolean xy3 = array[1][1 + CORNER_A[(i + 2) % NUMBER_PLANE]] - [1 + CORNER_B[(i + 2) % NUMBER_PLANE]]; + boolean xy2 = + array[1][1 + CORNER_A[(i + 1) % NUMBER_PLANE]][ + 1 + CORNER_B[(i + 1) % NUMBER_PLANE]]; + boolean xy3 = + array[1][1 + CORNER_A[(i + 2) % NUMBER_PLANE]][ + 1 + CORNER_B[(i + 2) % NUMBER_PLANE]]; if (xy2 && xy3) { return true; } } - + // YZ plane boolean yz1 = array[1 + PLANE_B[i]][1][1 + PLANE_A[i]]; if (!yz1 && !array[1][0][1] && !array[1][2][1]) { - boolean yz2 = array[1 + CORNER_B[(i + 1) % NUMBER_PLANE]][1] - [1 + CORNER_A[(i + 1) % NUMBER_PLANE]]; - boolean yz3 = array[1 + CORNER_B[(i + 2) % NUMBER_PLANE]][1] - [1 + CORNER_A[(i + 2) % NUMBER_PLANE]]; + boolean yz2 = + array[1 + CORNER_B[(i + 1) % NUMBER_PLANE]][1][ + 1 + CORNER_A[(i + 1) % NUMBER_PLANE]]; + boolean yz3 = + array[1 + CORNER_B[(i + 2) % NUMBER_PLANE]][1][ + 1 + CORNER_A[(i + 2) % NUMBER_PLANE]]; if (yz2 && yz3) { return true; } } - + // ZX plane boolean zx1 = array[1 + PLANE_A[i]][1 + PLANE_B[i]][1]; if (!zx1 && !array[1][1][0] && !array[1][1][2]) { - boolean zx2 = array[1 + CORNER_A[(i + 1) % NUMBER_PLANE]] - [1 + CORNER_B[(i + 1) % NUMBER_PLANE]][1]; - boolean zx3 = array[1 + CORNER_A[(i + 2) % NUMBER_PLANE]] - [1 + CORNER_B[(i + 2) % NUMBER_PLANE]][1]; + boolean zx2 = + array[1 + CORNER_A[(i + 1) % NUMBER_PLANE]][ + 1 + CORNER_B[(i + 1) % NUMBER_PLANE]][1]; + boolean zx3 = + array[1 + CORNER_A[(i + 2) % NUMBER_PLANE]][ + 1 + CORNER_B[(i + 2) % NUMBER_PLANE]][1]; if (zx2 && zx3) { return true; } } - + // XYZ corners boolean xyz1 = array[1][1 + PLANE_A[i]][1 + PLANE_B[i]]; - boolean xyz2 = array[1][1 + PLANE_A[(i + 1) % NUMBER_PLANE]] - [1 + PLANE_B[(i + 1) % NUMBER_PLANE]]; + boolean xyz2 = + array[1][1 + PLANE_A[(i + 1) % NUMBER_PLANE]][ + 1 + PLANE_B[(i + 1) % NUMBER_PLANE]]; if (xyz1 && xyz2) { boolean xyz3 = array[1][1 + CORNER_A[i]][1 + CORNER_B[i]]; - + boolean xyz4a1 = array[0][1 + PLANE_A[i]][1 + PLANE_B[i]]; - boolean xyz4a2 = array[0][1 + PLANE_A[(i + 1) % NUMBER_PLANE]] - [1 + PLANE_B[(i + 1) % NUMBER_PLANE]]; + boolean xyz4a2 = + array[0][1 + PLANE_A[(i + 1) % NUMBER_PLANE]][ + 1 + PLANE_B[(i + 1) % NUMBER_PLANE]]; if (array[0][1][1] && (xyz3 ? (xyz4a1 || xyz4a2) : (xyz4a1 && xyz4a2))) { return true; } - + boolean xyz4b1 = array[2][1 + PLANE_A[i]][1 + PLANE_B[i]]; - boolean xyz4b2 = array[2][1 + PLANE_A[(i + 1) % NUMBER_PLANE]] - [1 + PLANE_B[(i + 1) % NUMBER_PLANE]]; + boolean xyz4b2 = + array[2][1 + PLANE_A[(i + 1) % NUMBER_PLANE]][ + 1 + PLANE_B[(i + 1) % NUMBER_PLANE]]; if (array[2][1][1] && (xyz3 ? (xyz4b1 || xyz4b2) : (xyz4b1 && xyz4b2))) { return true; } @@ -244,12 +256,12 @@ private boolean getConnectivityThreeNeighbors(boolean[][][] array) { } return false; } - + /** * Determines simple connectivity for a position with four neighbors. * - * @param array the local neighborhood array - * @return {@code true} if simply connected, {@code false} otherwise + * @param array the local neighborhood array + * @return {@code true} if simply connected, {@code false} otherwise */ private boolean getConnectivityFourNeighbors(boolean[][][] array) { if (!array[0][1][1] && !array[2][1][1]) { @@ -277,65 +289,74 @@ private boolean getConnectivityFourNeighbors(boolean[][][] array) { boolean[] planeA = new boolean[2]; boolean[] planeB = new boolean[2]; boolean corner = false; - + for (int i = 0; i < NUMBER_PLANE; i++) { // Check for X boolean x1 = array[1 + PLANE_B[i]][1][1 + PLANE_A[i]]; - boolean x2 = array[1 + PLANE_B[(i + 1) % NUMBER_PLANE]] - [1][1 + PLANE_A[(i + 1) % NUMBER_PLANE]]; + boolean x2 = + array[1 + PLANE_B[(i + 1) % NUMBER_PLANE]][1][ + 1 + PLANE_A[(i + 1) % NUMBER_PLANE]]; if (array[1][0][1] && array[1][2][1] && x1 && x2) { - planeA = new boolean[] { - array[1 + PLANE_B[i]][0][1 + PLANE_A[i]], - array[1 + PLANE_B[i]][2][1 + PLANE_A[i]] - }; - planeB = new boolean[] { - array[1 + PLANE_B[(i + 1) % NUMBER_PLANE]][0] - [1 + PLANE_A[(i + 1) % NUMBER_PLANE]], - array[1 + PLANE_B[(i + 1) % NUMBER_PLANE]][2] - [1 + PLANE_A[(i + 1) % NUMBER_PLANE]] - }; + planeA = + new boolean[] { + array[1 + PLANE_B[i]][0][1 + PLANE_A[i]], + array[1 + PLANE_B[i]][2][1 + PLANE_A[i]] + }; + planeB = + new boolean[] { + array[1 + PLANE_B[(i + 1) % NUMBER_PLANE]][0][ + 1 + PLANE_A[(i + 1) % NUMBER_PLANE]], + array[1 + PLANE_B[(i + 1) % NUMBER_PLANE]][2][ + 1 + PLANE_A[(i + 1) % NUMBER_PLANE]] + }; corner = array[1 + CORNER_B[i]][1][1 + CORNER_A[i]]; break; } - + // Check for Y boolean y1 = array[1 + PLANE_A[i]][1 + PLANE_B[i]][1]; - boolean y2 = array[1 + PLANE_A[(i + 1) % NUMBER_PLANE]] - [1 + PLANE_B[(i + 1) % NUMBER_PLANE]][1]; + boolean y2 = + array[1 + PLANE_A[(i + 1) % NUMBER_PLANE]][ + 1 + PLANE_B[(i + 1) % NUMBER_PLANE]][1]; if (array[1][1][0] && array[1][1][2] && y1 && y2) { - planeA = new boolean[] { - array[1 + PLANE_A[i]][1 + PLANE_B[i]][0], - array[1 + PLANE_A[i]][1 + PLANE_B[i]][2] - }; - planeB = new boolean[] { - array[1 + PLANE_A[(i + 1) % NUMBER_PLANE]] - [1 + PLANE_B[(i + 1) % NUMBER_PLANE]][0], - array[1 + PLANE_A[(i + 1) % NUMBER_PLANE]] - [1 + PLANE_B[(i + 1) % NUMBER_PLANE]][2] - }; + planeA = + new boolean[] { + array[1 + PLANE_A[i]][1 + PLANE_B[i]][0], + array[1 + PLANE_A[i]][1 + PLANE_B[i]][2] + }; + planeB = + new boolean[] { + array[1 + PLANE_A[(i + 1) % NUMBER_PLANE]][ + 1 + PLANE_B[(i + 1) % NUMBER_PLANE]][0], + array[1 + PLANE_A[(i + 1) % NUMBER_PLANE]][ + 1 + PLANE_B[(i + 1) % NUMBER_PLANE]][2] + }; corner = array[1 + CORNER_A[i]][1 + CORNER_B[i]][1]; break; } - + // Check for Z boolean z1 = array[1][1 + PLANE_A[i]][1 + PLANE_B[i]]; - boolean z2 = array[1][1 + PLANE_A[(i + 1) % NUMBER_PLANE]] - [1 + PLANE_B[(i + 1) % NUMBER_PLANE]]; + boolean z2 = + array[1][1 + PLANE_A[(i + 1) % NUMBER_PLANE]][ + 1 + PLANE_B[(i + 1) % NUMBER_PLANE]]; if (array[0][1][1] && array[2][1][1] && z1 && z2) { - planeA = new boolean[] { - array[0][1 + PLANE_A[i]][1 + PLANE_B[i]], - array[2][1 + PLANE_A[i]][1 + PLANE_B[i]] - }; - planeB = new boolean[] { - array[0][1 + PLANE_A[(i + 1) % NUMBER_PLANE]] - [1 + PLANE_B[(i + 1) % NUMBER_PLANE]], - array[2][1 + PLANE_A[(i + 1) % NUMBER_PLANE]] - [1 + PLANE_B[(i + 1) % NUMBER_PLANE]] - }; + planeA = + new boolean[] { + array[0][1 + PLANE_A[i]][1 + PLANE_B[i]], + array[2][1 + PLANE_A[i]][1 + PLANE_B[i]] + }; + planeB = + new boolean[] { + array[0][1 + PLANE_A[(i + 1) % NUMBER_PLANE]][ + 1 + PLANE_B[(i + 1) % NUMBER_PLANE]], + array[2][1 + PLANE_A[(i + 1) % NUMBER_PLANE]][ + 1 + PLANE_B[(i + 1) % NUMBER_PLANE]] + }; corner = array[1][1 + CORNER_A[i]][1 + CORNER_B[i]]; } } - + if (planeA[0] && planeA[1] && (planeB[0] || planeB[1] || corner)) { return true; } else if (planeB[0] && planeB[1] && (planeA[0] || planeA[1] || corner)) { @@ -345,19 +366,19 @@ private boolean getConnectivityFourNeighbors(boolean[][][] array) { } } } - + /** * Determines simple connectivity for a position with five neighbors. * - * @param array the local neighborhood array - * @return {@code true} if simply connected, {@code false} otherwise + * @param array the local neighborhood array + * @return {@code true} if simply connected, {@code false} otherwise */ private boolean getConnectivityFiveNeighbors(boolean[][][] array) { boolean[] plane = new boolean[NUMBER_PLANE]; boolean[] corner = new boolean[NUMBER_PLANE]; int nPlane = 0; int nCorner = 0; - + if (!array[0][1][1] || !array[2][1][1]) { // Check XY int z = (array[0][1][1] ? 0 : 2); @@ -398,7 +419,7 @@ private boolean getConnectivityFiveNeighbors(boolean[][][] array) { } } } - + if (nCorner + nPlane < 4) { return false; } else if (nPlane == 4 || nCorner + nPlane > 5) { @@ -423,7 +444,7 @@ private boolean getConnectivityFiveNeighbors(boolean[][][] array) { index = i; } } - + if (isAdjacent) { return !corner[index]; } else { @@ -442,12 +463,12 @@ private boolean getConnectivityFiveNeighbors(boolean[][][] array) { return corner[index] || corner[(index + 3) % NUMBER_PLANE]; } } - + @Override HashSet getUniqueIDs(int x, int y, int z) { int id = ids[z][x][y]; HashSet unique = new HashSet<>(); - + for (int i = 0; i < NUMBER_NEIGHBORS; i++) { int neighbor = ids[z + MOVES_Z[i]][x + MOVES_X[i]][y + MOVES_Y[i]]; if (id != neighbor) { @@ -456,17 +477,17 @@ HashSet getUniqueIDs(int x, int y, int z) { } return unique; } - + @Override HashSet getUniqueRegions(int x, int y, int z) { int id = ids[z][x][y]; int region = regions[z][x][y]; HashSet unique = new HashSet<>(); - + for (int i = 0; i < NUMBER_NEIGHBORS; i++) { int neighborID = ids[z + MOVES_Z[i]][x + MOVES_X[i]][y + MOVES_Y[i]]; int neighborRegion = regions[z + MOVES_Z[i]][x + MOVES_X[i]][y + MOVES_Y[i]]; - + if (neighborID != id) { continue; } @@ -474,7 +495,7 @@ HashSet getUniqueRegions(int x, int y, int z) { unique.add(neighborRegion); } } - + return unique; } } diff --git a/src/arcade/potts/sim/PottsSeries.java b/src/arcade/potts/sim/PottsSeries.java index 5592e8d08..156e508c3 100644 --- a/src/arcade/potts/sim/PottsSeries.java +++ b/src/arcade/potts/sim/PottsSeries.java @@ -9,50 +9,53 @@ import static arcade.core.util.MiniBox.TAG_SEPARATOR; import static arcade.potts.util.PottsEnums.Term; -/** - * Simulation manager for {@link PottsSimulation} instances. - */ - +/** Simulation manager for {@link PottsSimulation} instances. */ public final class PottsSeries extends Series { /** Separator character for targets. */ public static final String TARGET_SEPARATOR = ":"; - + + /** Default cell class. */ + public static final String DEFAULT_CELL_CLASS = "stem"; + /** Map of potts settings. */ public MiniBox potts; - + /** List of Hamiltonian terms. */ public ArrayList terms; - + /** * Creates a {@code Series} object given setup information parsed from XML. * - * @param setupDicts the map of attribute to value for single instance tags - * @param setupLists the map of attribute to value for multiple instance tags - * @param path the path for simulation output - * @param parameters the default parameter values - * @param isVis {@code true} if visualized, {@code false} otherwise + * @param setupDicts the map of attribute to value for single instance tags + * @param setupLists the map of attribute to value for multiple instance tags + * @param path the path for simulation output + * @param parameters the default parameter values + * @param isVis {@code true} if visualized, {@code false} otherwise */ - public PottsSeries(HashMap setupDicts, - HashMap> setupLists, - String path, Box parameters, boolean isVis) { + public PottsSeries( + HashMap setupDicts, + HashMap> setupLists, + String path, + Box parameters, + boolean isVis) { super(setupDicts, setupLists, path, parameters, isVis); } - + @Override protected String getSimClass() { return "arcade.potts.sim.PottsSimulation" + (height > 1 ? "3D" : "2D"); } - + @Override protected String getVisClass() { return "arcade.potts.vis.PottsVisualization"; } - + /** * Initializes series simulation, agents, and environment. * - * @param setupLists the map of attribute to value for multiple instance tags - * @param parameters the default parameter values loaded from {@code parameter.xml} + * @param setupLists the map of attribute to value for multiple instance tags + * @param parameters the default parameter values loaded from {@code parameter.xml} */ @Override protected void initialize(HashMap> setupLists, Box parameters) { @@ -61,98 +64,117 @@ protected void initialize(HashMap> setupLists, Box parame MiniBox populationConversions = parameters.getIdValForTagAtt("POPULATION", "conversion"); ArrayList populationsBox = setupLists.get("populations"); updatePopulations(populationsBox, populationDefaults, populationConversions); - + // Initialize layers. MiniBox layerDefaults = parameters.getIdValForTag("LAYER"); MiniBox layerConversions = parameters.getIdValForTagAtt("LAYER", "conversion"); ArrayList layersBox = setupLists.get("layers"); updateLayers(layersBox, layerDefaults, layerConversions); - + // Add actions. MiniBox actionDefaults = parameters.getIdValForTag("ACTION"); ArrayList actionsBox = setupLists.get("actions"); updateActions(actionsBox, actionDefaults); - + // Add components. MiniBox componentDefaults = parameters.getIdValForTag("COMPONENT"); ArrayList componentsBox = setupLists.get("components"); updateComponents(componentsBox, componentDefaults); - + // Initialize potts. MiniBox pottsDefaults = parameters.getIdValForTag("POTTS"); MiniBox pottsConversions = parameters.getIdValForTagAtt("POTTS", "conversion"); ArrayList pottsBox = setupLists.get("potts"); updatePotts(pottsBox, pottsDefaults, pottsConversions); } - + /** * Calculates potts model parameters. * - * @param pottsBox the potts setup dictionary - * @param pottsDefaults the dictionary of default potts parameters - * @param pottsConversions the dictionary of potts parameter conversions + * @param pottsBox the potts setup dictionary + * @param pottsDefaults the dictionary of default potts parameters + * @param pottsConversions the dictionary of potts parameter conversions */ - void updatePotts(ArrayList pottsBox, MiniBox pottsDefaults, - MiniBox pottsConversions) { + void updatePotts(ArrayList pottsBox, MiniBox pottsDefaults, MiniBox pottsConversions) { this.potts = new MiniBox(); - + Box box = new Box(); if (pottsBox != null && pottsBox.size() == 1 && pottsBox.get(0) != null) { box = pottsBox.get(0); } - + // Get default parameters and any parameter tags. Box parameters = box.filterBoxByTag("PARAMETER"); MiniBox parameterValues = parameters.getIdValForTagAtt("PARAMETER", "value"); MiniBox parameterScales = parameters.getIdValForTagAtt("PARAMETER", "scale"); - + // Add in parameters. Start with value (if given) or default (if not // given). Then apply any scaling. for (String parameter : pottsDefaults.getKeys()) { - parseParameter(this.potts, parameter, pottsDefaults.get(parameter), - parameterValues, parameterScales); - + parseParameter( + this.potts, + parameter, + pottsDefaults.get(parameter), + parameterValues, + parameterScales); + if (parameter.contains(TAG_SEPARATOR)) { for (String pop : populations.keySet()) { - parseParameter(this.potts, parameter + TARGET_SEPARATOR + pop, - this.potts.get(parameter), parameterValues, parameterScales); + parseParameter( + this.potts, + parameter + TARGET_SEPARATOR + pop, + this.potts.get(parameter), + parameterValues, + parameterScales); } } } - + // Add adhesion values for each population and media (*). Values // are set as equal to the default (or adjusted) value, before // any specific values or scaling is applied. for (String source : populations.keySet()) { String adhesion = "adhesion/ADHESION" + TARGET_SEPARATOR + source; - parseParameter(this.potts, adhesion + TARGET_SEPARATOR + "*", - this.potts.get(adhesion), parameterValues, parameterScales); - + parseParameter( + this.potts, + adhesion + TARGET_SEPARATOR + "*", + this.potts.get(adhesion), + parameterValues, + parameterScales); + for (String target : populations.keySet()) { - parseParameter(this.potts, adhesion + TARGET_SEPARATOR + target, - this.potts.get(adhesion), parameterValues, parameterScales); + parseParameter( + this.potts, + adhesion + TARGET_SEPARATOR + target, + this.potts.get(adhesion), + parameterValues, + parameterScales); } } - + // Add adhesion values for each population that has regions. for (String pop : populations.keySet()) { ArrayList regions = populations.get(pop).filter("(REGION)").getKeys(); - + for (String source : regions) { String adhesion = "adhesion/ADHESION_" + source + TARGET_SEPARATOR + pop; - + for (String target : regions) { - parseParameter(this.potts, adhesion + TARGET_SEPARATOR + target, - this.potts.get(adhesion), parameterValues, parameterScales); + parseParameter( + this.potts, + adhesion + TARGET_SEPARATOR + target, + this.potts.get(adhesion), + parameterValues, + parameterScales); } } } - + // Apply conversion factors. for (String convert : pottsConversions.getKeys()) { double conversion = parseConversion(pottsConversions.get(convert), ds, dt); this.potts.put(convert, this.potts.getDouble(convert) * conversion); - + if (convert.contains(TAG_SEPARATOR)) { for (String pop : populations.keySet()) { String convertPop = convert + TARGET_SEPARATOR + pop; @@ -160,87 +182,115 @@ void updatePotts(ArrayList pottsBox, MiniBox pottsDefaults, } } } - + // Get list of terms. this.terms = new ArrayList<>(); for (String term : box.filterTags("TERM")) { terms.add(Term.valueOf(term.toUpperCase())); } } - + @Override - protected void updatePopulations(ArrayList populationsBox, MiniBox populationDefaults, - MiniBox populationConversions) { + protected void updatePopulations( + ArrayList populationsBox, + MiniBox populationDefaults, + MiniBox populationConversions) { this.populations = new HashMap<>(); if (populationsBox == null) { return; } - + // Assign codes to each population. int code = 1; - + // Iterate through each setup dictionary to build population settings. for (Box box : populationsBox) { String id = box.getValue("id"); - + String populationClass = box.getValue("class"); + + if (populationClass == null) { + populationClass = DEFAULT_CELL_CLASS; + } + + // TODO: Use logger to print message when default class is used. + // Create new population and update code. MiniBox population = new MiniBox(); population.put("CODE", code++); + population.put("CLASS", populationClass); this.populations.put(id, population); - + // Add population init if given. If not given or invalid, set to zero. if (box.contains("init") && box.getValue("init").contains(":")) { String[] initString = box.getValue("init").split(":"); - + box.add("init", initString[0]); box.add("padding", initString[1]); - - int padding = (isValidNumber(box, "padding") - ? (int) Double.parseDouble(box.getValue("padding")) : 0); + + int padding = + (isValidNumber(box, "padding") + ? (int) Double.parseDouble(box.getValue("padding")) + : 0); population.put("PADDING", padding); } - - int init = (isValidNumber(box, "init") - ? (int) Double.parseDouble(box.getValue("init")) : 0); + + int init = + (isValidNumber(box, "init") + ? (int) Double.parseDouble(box.getValue("init")) + : 0); population.put("INIT", init); - + // Get default parameters and any parameter adjustments. Box parameters = box.filterBoxByTag("PARAMETER"); MiniBox parameterValues = parameters.getIdValForTagAtt("PARAMETER", "value"); MiniBox parameterScales = parameters.getIdValForTagAtt("PARAMETER", "scale"); - + + // Apply conversion factors. + for (String convert : populationConversions.getKeys()) { + double conversion = parseConversion(populationConversions.get(convert), ds, dt); + if (parameterScales.contains(convert)) { + parameterScales.put(convert, parameterScales.getDouble(convert) * conversion); + } else { + parameterScales.put(convert, conversion); + } + } + // Add in parameters. Start with value (if given) or default (if not // given). Then apply any scaling. for (String parameter : populationDefaults.getKeys()) { - parseParameter(population, parameter, populationDefaults.get(parameter), - parameterValues, parameterScales); + parseParameter( + population, + parameter, + populationDefaults.get(parameter), + parameterValues, + parameterScales); } - + + // Get list of links, if valid. + MiniBox links = box.filterBoxByTag("LINK").getIdValForTagAtt("LINK", "weight"); + for (String link : links.getKeys()) { + population.put("(LINK)" + TAG_SEPARATOR + link, links.getDouble(link)); + } + // Get list of regions, if valid. HashSet regions = box.filterTags("REGION"); for (String region : regions) { population.put("(REGION)" + TAG_SEPARATOR + region, ""); } - - // Apply conversion factors. - for (String convert : populationConversions.getKeys()) { - double conversion = parseConversion(populationConversions.get(convert), ds, dt); - population.put(convert, population.getDouble(convert) * conversion); - } } } - + @Override - protected void updateLayers(ArrayList layersBox, MiniBox layerDefaults, - MiniBox layerConversions) { + protected void updateLayers( + ArrayList layersBox, MiniBox layerDefaults, MiniBox layerConversions) { // TODO } - + @Override protected void updateActions(ArrayList actionsBox, MiniBox actionDefaults) { // TODO } - + @Override protected void updateComponents(ArrayList componentsBox, MiniBox componentDefaults) { // TODO diff --git a/src/arcade/potts/sim/PottsSimulation.java b/src/arcade/potts/sim/PottsSimulation.java index 8ddeebad9..6e47a6b3f 100644 --- a/src/arcade/potts/sim/PottsSimulation.java +++ b/src/arcade/potts/sim/PottsSimulation.java @@ -7,11 +7,13 @@ import arcade.core.agent.action.Action; import arcade.core.agent.cell.Cell; 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.Location; import arcade.core.env.location.LocationContainer; +import arcade.core.env.location.LocationFactory; import arcade.core.sim.Series; import arcade.core.sim.Simulation; import arcade.core.util.MiniBox; @@ -21,234 +23,255 @@ import arcade.potts.env.location.PottsLocationFactory; import static arcade.potts.util.PottsEnums.Ordering; -/** - * Abstract implementation for potts {@link Simulation} instances. - */ - +/** Abstract implementation for potts {@link Simulation} instances. */ public abstract class PottsSimulation extends SimState implements Simulation { /** {@link arcade.core.sim.Series} object containing this simulation. */ final PottsSeries series; - + /** Random number generator seed for this simulation. */ final int seed; - + /** {@link arcade.potts.sim.Potts} object for the simulation. */ Potts potts; - + /** {@link arcade.core.env.grid.Grid} containing agents in the simulation. */ Grid grid; - + /** Cell ID tracker. */ int id; - + /** Cell factory instance for the simulation. */ public final PottsCellFactory cellFactory; - + /** Location factory instance for the simulation. */ public final PottsLocationFactory locationFactory; - + /** * Simulation instance for a {@link Series} for given random seed. * - * @param seed the random seed for random number generator - * @param series the simulation series + * @param seed the random seed for random number generator + * @param series the simulation series */ public PottsSimulation(long seed, Series series) { super(seed); this.series = (PottsSeries) series; this.seed = (int) seed - Series.SEED_OFFSET; - + this.locationFactory = makeLocationFactory(); this.cellFactory = makeCellFactory(); } - + @Override - public final Series getSeries() { return series; } - + public final Series getSeries() { + return series; + } + @Override - public final Schedule getSchedule() { return schedule; } - + public final Schedule getSchedule() { + return schedule; + } + @Override - public final int getSeed() { return seed; } - + public final int getSeed() { + return seed; + } + @Override - public final int getID() { return ++id; } - + public final int getID() { + return ++id; + } + @Override public final ArrayList getCells() { ArrayList cellContainers = new ArrayList<>(); - + for (Object obj : grid.getAllObjects()) { Cell cell = (Cell) obj; cellContainers.add(cell.convert()); } - + return cellContainers; } - + @Override public final ArrayList getLocations() { ArrayList locationContainers = new ArrayList<>(); - + for (Object obj : grid.getAllObjects()) { Cell cell = (Cell) obj; locationContainers.add(cell.getLocation().convert(cell.getID())); } - + return locationContainers; } - + @Override - public final Grid getGrid() { return grid; } - + public final CellFactory getCellFactory() { + return cellFactory; + } + @Override - public final Lattice getLattice(String key) { return null; } - + public final LocationFactory getLocationFactory() { + return locationFactory; + } + + @Override + public final Grid getGrid() { + return grid; + } + @Override - public final Action getAction(String key) { return null; } - + public final Lattice getLattice(String key) { + return null; + } + @Override - public final Component getComponent(String key) { return null; } - + public final Action getAction(String key) { + return null; + } + + @Override + public final Component getComponent(String key) { + return null; + } + /** * Gets {@link Potts} instance for the simulation. * - * @return the potts instance + * @return the potts instance */ - public final Potts getPotts() { return potts; } - + public final Potts getPotts() { + return potts; + } + /** - * Called at the start of the simulation to set up agents and environment - * and schedule actions and components as needed. + * Called at the start of the simulation to set up agents and environment and schedule actions + * and components as needed. */ @Override public void start() { super.start(); - + // Reset id. id = 0; - + // Equip simulation to loader. if (series.loader != null) { series.loader.equip(this); } - + setupPotts(); setupAgents(); setupEnvironment(); - + scheduleActions(); scheduleComponents(); - + // Equip simulation to saver and schedule. if (series.saver != null && !series.isVis) { series.saver.equip(this); doOutput(true); } } - - /** - * Called at the end of the simulation. - */ + + /** Called at the end of the simulation. */ @Override public void finish() { super.finish(); - + // Finalize saver. if (!series.isVis) { doOutput(false); } } - + /** * Creates the {@link arcade.potts.sim.Potts} object for the simulation. * - * @return a {@link arcade.potts.sim.Potts} object + * @return a {@link arcade.potts.sim.Potts} object */ abstract Potts makePotts(); - + /** * Creates a factory for locations. * - * @return a {@link arcade.core.env.location.Location} factory + * @return a {@link arcade.core.env.location.Location} factory */ public abstract PottsLocationFactory makeLocationFactory(); - + /** * Creates a factory for cells. * - * @return a {@link arcade.core.agent.cell.Cell} factory + * @return a {@link arcade.core.agent.cell.Cell} factory */ public abstract PottsCellFactory makeCellFactory(); - - /** - * Sets up the potts layer for the simulation. - */ + + /** Sets up the potts layer for the simulation. */ public final void setupPotts() { potts = makePotts(); schedule.scheduleRepeating(1, Ordering.POTTS.ordinal(), potts); } - + @Override public final void setupAgents() { // Initialize grid for agents. grid = new PottsGrid(); potts.grid = grid; - + // Initialize factories. locationFactory.initialize(series, random); cellFactory.initialize(series, random); - + // Iterate through each population to create agents. for (MiniBox population : series.populations.values()) { int pop = population.getInt("CODE"); HashSet ids = cellFactory.popToIDs.get(pop); - + for (int i : ids) { // Get location and cell containers. LocationContainer locationContainer = locationFactory.locations.get(i); CellContainer cellContainer = cellFactory.cells.get(i); - + // Check that we have enough containers. if (locationContainer == null || cellContainer == null) { break; } - + // Make the location and cell. Location location = locationContainer.convert(locationFactory, cellContainer); - PottsCell cell = (PottsCell) cellContainer.convert(cellFactory, location); - + PottsCell cell = (PottsCell) cellContainer.convert(cellFactory, location, random); + // Add, initialize, and schedule the cell. grid.addObject(cell, null); potts.register(cell); cell.initialize(potts.ids, potts.regions); cell.schedule(schedule); - + // Update id tracking. id = Math.max(i, id); } } } - + @Override public final void setupEnvironment() { // TODO add environment setup (currently not needed) } - + @Override public final void scheduleActions() { // TODO add action scheduling } - + @Override public final void scheduleComponents() { // TODO add component scheduling } - + /** * Runs output methods. * - * @param isScheduled {@code true} to schedule output, {@code false} otherwise + * @param isScheduled {@code true} to schedule output, {@code false} otherwise */ public void doOutput(boolean isScheduled) { if (isScheduled) { diff --git a/src/arcade/potts/sim/PottsSimulation2D.java b/src/arcade/potts/sim/PottsSimulation2D.java index 848d4b407..4c201a0e6 100644 --- a/src/arcade/potts/sim/PottsSimulation2D.java +++ b/src/arcade/potts/sim/PottsSimulation2D.java @@ -5,27 +5,28 @@ import arcade.potts.env.location.PottsLocationFactory; import arcade.potts.env.location.PottsLocationFactory2D; -/** - * Extension of {@link PottsSimulation} for 2D. - */ - +/** Extension of {@link PottsSimulation} for 2D. */ public final class PottsSimulation2D extends PottsSimulation { /** * 2D simulation instance for a {@link Series} for given random seed. * - * @param seed the random seed for random number generator - * @param series the simulation series + * @param seed the random seed for random number generator + * @param series the simulation series */ - public PottsSimulation2D(long seed, Series series) { super(seed, series); } - + public PottsSimulation2D(long seed, Series series) { + super(seed, series); + } + @Override - Potts makePotts() { return new Potts2D(series); } - + Potts makePotts() { + return new Potts2D(series); + } + @Override public PottsLocationFactory makeLocationFactory() { return new PottsLocationFactory2D(); } - + @Override public PottsCellFactory makeCellFactory() { return new PottsCellFactory(); diff --git a/src/arcade/potts/sim/PottsSimulation3D.java b/src/arcade/potts/sim/PottsSimulation3D.java index 1e72ca53d..b5ca5e007 100644 --- a/src/arcade/potts/sim/PottsSimulation3D.java +++ b/src/arcade/potts/sim/PottsSimulation3D.java @@ -5,27 +5,28 @@ import arcade.potts.env.location.PottsLocationFactory; import arcade.potts.env.location.PottsLocationFactory3D; -/** - * Extension of {@link PottsSimulation} for 3D. - */ - +/** Extension of {@link PottsSimulation} for 3D. */ public final class PottsSimulation3D extends PottsSimulation { /** * 3D simulation instance for a {@link Series} for given random seed. * - * @param seed the random seed for random number generator - * @param series the simulation series + * @param seed the random seed for random number generator + * @param series the simulation series */ - public PottsSimulation3D(long seed, Series series) { super(seed, series); } - + public PottsSimulation3D(long seed, Series series) { + super(seed, series); + } + @Override - Potts makePotts() { return new Potts3D(series); } - + Potts makePotts() { + return new Potts3D(series); + } + @Override public PottsLocationFactory makeLocationFactory() { return new PottsLocationFactory3D(); } - + @Override public PottsCellFactory makeCellFactory() { return new PottsCellFactory(); diff --git a/src/arcade/potts/sim/hamiltonian/AdhesionHamiltonian.java b/src/arcade/potts/sim/hamiltonian/AdhesionHamiltonian.java index d11415d28..cdef11d27 100644 --- a/src/arcade/potts/sim/hamiltonian/AdhesionHamiltonian.java +++ b/src/arcade/potts/sim/hamiltonian/AdhesionHamiltonian.java @@ -11,31 +11,28 @@ import static arcade.potts.sim.PottsSeries.TARGET_SEPARATOR; import static arcade.potts.util.PottsEnums.Region; -/** - * Implementation of {@link Hamiltonian} for adhesion energy. - */ - +/** Implementation of {@link Hamiltonian} for adhesion energy. */ public abstract class AdhesionHamiltonian implements Hamiltonian { /** Map of hamiltonian config objects. */ final HashMap configs; - + /** Map of population to adhesion values. */ final HashMap popToAdhesion; - + /** Map of population to adhesion values for regions. */ final HashMap>> popToAdhesionRegion; - + /** Potts array for ids. */ final int[][][] ids; - + /** Potts array for regions. */ final int[][][] regions; - + /** * Creates the adhesion energy term for the {@code Potts} Hamiltonian. * - * @param potts the associated Potts instance - * @param series the associated Series instance + * @param potts the associated Potts instance + * @param series the associated Series instance */ public AdhesionHamiltonian(PottsSeries series, Potts potts) { configs = new HashMap<>(); @@ -43,11 +40,11 @@ public AdhesionHamiltonian(PottsSeries series, Potts potts) { popToAdhesion = new HashMap<>(); popToAdhesionRegion = new HashMap<>(); initialize(series); - + this.ids = potts.ids; this.regions = potts.regions; } - + @Override public void register(PottsCell cell) { int pop = cell.getPop(); @@ -57,18 +54,18 @@ public void register(PottsCell cell) { new AdhesionHamiltonianConfig(cell, adhesion, adhesionRegion); configs.put(cell.getID(), config); } - + @Override public void deregister(PottsCell cell) { configs.remove(cell.getID()); } - + /** * {@inheritDoc} - *

- * Adhesion energy is calculated by summing across adhesion of the given - * voxel to all non-self neighbor voxels. Change in adhesion energy is taken - * as the difference in adhesion energies for the source and target IDs. + * + *

Adhesion energy is calculated by summing across adhesion of the given voxel to all + * non-self neighbor voxels. Change in adhesion energy is taken as the difference in adhesion + * energies for the source and target IDs. */ @Override public double getDelta(int sourceID, int targetID, int x, int y, int z) { @@ -76,14 +73,13 @@ public double getDelta(int sourceID, int targetID, int x, int y, int z) { double target = getAdhesion(targetID, x, y, z); return target - source; } - + /** * {@inheritDoc} - *

- * Adhesion energy is calculated by summing across adhesion of the given - * voxel to all non-same regions with the same ID. Change in adhesion energy - * is taken as the difference in adhesion energies for the source and target - * regions. + * + *

Adhesion energy is calculated by summing across adhesion of the given voxel to all + * non-same regions with the same ID. Change in adhesion energy is taken as the difference in + * adhesion energies for the source and target regions. */ @Override public double getDelta(int id, int sourceRegion, int targetRegion, int x, int y, int z) { @@ -91,80 +87,90 @@ public double getDelta(int id, int sourceRegion, int targetRegion, int x, int y, double target = getAdhesion(id, targetRegion, x, y, z); return target - source; } - + /** * Gets adhesion energy for a given voxel. * - * @param id the voxel id - * @param x the x coordinate - * @param y the y coordinate - * @param z the z coordinate - * @return the energy + * @param id the voxel id + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + * @return the energy */ abstract double getAdhesion(int id, int x, int y, int z); - + /** * Gets adhesion energy for a given voxel region. * - * @param id the voxel id - * @param region the voxel region - * @param x the x coordinate - * @param y the y coordinate - * @param z the z coordinate - * @return the energy + * @param id the voxel id + * @param region the voxel region + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + * @return the energy */ abstract double getAdhesion(int id, int region, int x, int y, int z); - + /** * Initializes parameters for surface hamiltonian term. * - * @param series the series instance + * @param series the series instance */ void initialize(PottsSeries series) { if (series.populations == null) { return; } - + Set keySet = series.populations.keySet(); MiniBox parameters = series.potts; - + for (String key : keySet) { MiniBox population = series.populations.get(key); int pop = population.getInt("CODE"); - + // Get adhesion value. double[] adhesion = new double[keySet.size() + 1]; - adhesion[0] = parameters.getDouble("adhesion/ADHESION" + TARGET_SEPARATOR - + key + TARGET_SEPARATOR + "*"); + adhesion[0] = + parameters.getDouble( + "adhesion/ADHESION" + TARGET_SEPARATOR + key + TARGET_SEPARATOR + "*"); for (String p : keySet) { adhesion[series.populations.get(p).getInt("CODE")] = - parameters.getDouble("adhesion/ADHESION" + TARGET_SEPARATOR - + key + TARGET_SEPARATOR + p); + parameters.getDouble( + "adhesion/ADHESION" + + TARGET_SEPARATOR + + key + + TARGET_SEPARATOR + + p); } - + popToAdhesion.put(pop, adhesion); - + MiniBox regionBox = population.filter("(REGION)"); ArrayList regionKeys = new ArrayList<>(); regionBox.getKeys().forEach(s -> regionKeys.add(Region.valueOf(s))); - + // Get adhesion value for regions. if (regionKeys.size() > 0) { EnumMap> adhesionRegion = new EnumMap<>(Region.class); - + for (Region source : regionKeys) { EnumMap adhesionRegionMap = new EnumMap<>(Region.class); - + for (Region target : regionKeys) { - double regionAdhesion = parameters.getDouble("adhesion/ADHESION_" - + source.name() + TARGET_SEPARATOR + key - + TARGET_SEPARATOR + target.name()); + double regionAdhesion = + parameters.getDouble( + "adhesion/ADHESION_" + + source.name() + + TARGET_SEPARATOR + + key + + TARGET_SEPARATOR + + target.name()); adhesionRegionMap.put(target, regionAdhesion); } adhesionRegion.put(source, adhesionRegionMap); } - + popToAdhesionRegion.put(pop, adhesionRegion); } else { popToAdhesionRegion.put(pop, null); diff --git a/src/arcade/potts/sim/hamiltonian/AdhesionHamiltonian2D.java b/src/arcade/potts/sim/hamiltonian/AdhesionHamiltonian2D.java index 27b34a604..616bf0901 100644 --- a/src/arcade/potts/sim/hamiltonian/AdhesionHamiltonian2D.java +++ b/src/arcade/potts/sim/hamiltonian/AdhesionHamiltonian2D.java @@ -4,27 +4,26 @@ import arcade.potts.sim.PottsSeries; import static arcade.potts.util.PottsEnums.Region; -/** - * Extension of {@link AdhesionHamiltonian} for 2D. - */ - +/** Extension of {@link AdhesionHamiltonian} for 2D. */ public class AdhesionHamiltonian2D extends AdhesionHamiltonian { /** Neighborhood size. */ public static final int NEIGHBORHOOD_SIZE = (3 * 3) - 1; - + /** * Creates the adhesion energy term for {@code Potts} Hamiltonian in 2D. * - * @param series the associated Series instance - * @param potts the associated Potts instance + * @param series the associated Series instance + * @param potts the associated Potts instance */ - public AdhesionHamiltonian2D(PottsSeries series, Potts potts) { super(series, potts); } - + public AdhesionHamiltonian2D(PottsSeries series, Potts potts) { + super(series, potts); + } + @Override double getAdhesion(int id, int x, int y, int z) { double h = 0; AdhesionHamiltonianConfig a = configs.get(id); - + for (int i = x - 1; i <= x + 1; i++) { for (int j = y - 1; j <= y + 1; j++) { if (!(i == x && j == y) && ids[z][i][j] != id) { @@ -34,32 +33,36 @@ public class AdhesionHamiltonian2D extends AdhesionHamiltonian { } else if (b == null) { h += a.getAdhesion(0); } else { - h += (a.getAdhesion(b.cell.getPop()) - + b.getAdhesion(a.cell.getPop())) / 2.0; + h += + (a.getAdhesion(b.cell.getPop()) + b.getAdhesion(a.cell.getPop())) + / 2.0; } } } } - + return h / NEIGHBORHOOD_SIZE; } - + @Override double getAdhesion(int id, int t, int x, int y, int z) { double h = 0; AdhesionHamiltonianConfig c = configs.get(id); Region region = Region.values()[t]; - + for (int i = x - 1; i <= x + 1; i++) { for (int j = y - 1; j <= y + 1; j++) { Region xy = Region.values()[regions[z][i][j]]; - if (!(i == x && j == y) && ids[z][i][j] == id && xy != region - && xy != Region.UNDEFINED && xy != Region.DEFAULT) { + if (!(i == x && j == y) + && ids[z][i][j] == id + && xy != region + && xy != Region.UNDEFINED + && xy != Region.DEFAULT) { h += (c.getAdhesion(region, xy) + c.getAdhesion(xy, region)) / 2.0; } } } - + return h / NEIGHBORHOOD_SIZE; } } diff --git a/src/arcade/potts/sim/hamiltonian/AdhesionHamiltonian3D.java b/src/arcade/potts/sim/hamiltonian/AdhesionHamiltonian3D.java index 9b0a0580c..cb8996c90 100644 --- a/src/arcade/potts/sim/hamiltonian/AdhesionHamiltonian3D.java +++ b/src/arcade/potts/sim/hamiltonian/AdhesionHamiltonian3D.java @@ -4,27 +4,26 @@ import arcade.potts.sim.PottsSeries; import static arcade.potts.util.PottsEnums.Region; -/** - * Extension of {@link AdhesionHamiltonian} for 3D. - */ - +/** Extension of {@link AdhesionHamiltonian} for 3D. */ public class AdhesionHamiltonian3D extends AdhesionHamiltonian { /** Neighborhood size. */ public static final int NEIGHBORHOOD_SIZE = (3 * 3 * 3) - 1; - + /** * Creates the adhesion energy term for {@code Potts} Hamiltonian in 3D. * - * @param series the associated Series instance - * @param potts the associated Potts instance + * @param series the associated Series instance + * @param potts the associated Potts instance */ - public AdhesionHamiltonian3D(PottsSeries series, Potts potts) { super(series, potts); } - + public AdhesionHamiltonian3D(PottsSeries series, Potts potts) { + super(series, potts); + } + @Override double getAdhesion(int id, int x, int y, int z) { double h = 0; AdhesionHamiltonianConfig a = configs.get(id); - + for (int k = z - 1; k <= z + 1; k++) { for (int i = x - 1; i <= x + 1; i++) { for (int j = y - 1; j <= y + 1; j++) { @@ -35,35 +34,40 @@ public class AdhesionHamiltonian3D extends AdhesionHamiltonian { } else if (b == null) { h += a.getAdhesion(0); } else { - h += (a.getAdhesion(b.cell.getPop()) - + b.getAdhesion(a.cell.getPop())) / 2.0; + h += + (a.getAdhesion(b.cell.getPop()) + + b.getAdhesion(a.cell.getPop())) + / 2.0; } } } } } - + return h / NEIGHBORHOOD_SIZE; } - + @Override double getAdhesion(int id, int t, int x, int y, int z) { double h = 0; AdhesionHamiltonianConfig c = configs.get(id); Region region = Region.values()[t]; - + for (int k = z - 1; k <= z + 1; k++) { for (int i = x - 1; i <= x + 1; i++) { for (int j = y - 1; j <= y + 1; j++) { Region xyz = Region.values()[regions[k][i][j]]; - if (!(k == z && i == x && j == y) && ids[k][i][j] == id && region != xyz - && xyz != Region.UNDEFINED && xyz != Region.DEFAULT) { + if (!(k == z && i == x && j == y) + && ids[k][i][j] == id + && region != xyz + && xyz != Region.UNDEFINED + && xyz != Region.DEFAULT) { h += (c.getAdhesion(region, xyz) + c.getAdhesion(xyz, region)) / 2.0; } } } } - + return h / NEIGHBORHOOD_SIZE; } } diff --git a/src/arcade/potts/sim/hamiltonian/AdhesionHamiltonianConfig.java b/src/arcade/potts/sim/hamiltonian/AdhesionHamiltonianConfig.java index ac464dde3..2b9f2018a 100644 --- a/src/arcade/potts/sim/hamiltonian/AdhesionHamiltonianConfig.java +++ b/src/arcade/potts/sim/hamiltonian/AdhesionHamiltonianConfig.java @@ -4,36 +4,35 @@ import arcade.potts.agent.cell.PottsCell; import static arcade.potts.util.PottsEnums.Region; -/** - * Configuration for {@link AdhesionHamiltonian} parameters. - */ - +/** Configuration for {@link AdhesionHamiltonian} parameters. */ class AdhesionHamiltonianConfig { /** Associated {@link PottsCell} instance. */ final PottsCell cell; - + /** Adhesion values for cell. */ final double[] adhesion; - + /** Adhesion values for cell by region. */ final EnumMap> adhesionRegion; - + /** {@code true} if the cell has regions, {@code false} otherwise. */ final boolean hasRegions; - + /** * Creates parameter configuration for {@code AdhesionHamiltonian}. * - * @param cell the associated cell instance - * @param adhesion the list of adhesion values - * @param adhesionRegion the map of adhesion values for regions + * @param cell the associated cell instance + * @param adhesion the list of adhesion values + * @param adhesionRegion the map of adhesion values for regions */ - AdhesionHamiltonianConfig(PottsCell cell, double[] adhesion, - EnumMap> adhesionRegion) { + AdhesionHamiltonianConfig( + PottsCell cell, + double[] adhesion, + EnumMap> adhesionRegion) { this.cell = cell; this.adhesion = adhesion.clone(); this.hasRegions = (adhesionRegion != null) && (adhesionRegion.keySet().size() > 0); - + if (hasRegions) { this.adhesionRegion = new EnumMap<>(Region.class); for (Region region : adhesionRegion.keySet()) { @@ -43,27 +42,28 @@ class AdhesionHamiltonianConfig { this.adhesionRegion = null; } } - + /** * Gets the adhesion to a cell of the given population. * - * @param target the target cell population - * @return the adhesion value + * @param target the target cell population + * @return the adhesion value */ public double getAdhesion(int target) { return adhesion[target]; } - + /** * Gets the adhesion between two regions. * - * @param region1 the first region - * @param region2 the second region - * @return the adhesion value + * @param region1 the first region + * @param region2 the second region + * @return the adhesion value */ public double getAdhesion(Region region1, Region region2) { - return (hasRegions && adhesionRegion.containsKey(region1) - && adhesionRegion.containsKey(region2) + return (hasRegions + && adhesionRegion.containsKey(region1) + && adhesionRegion.containsKey(region2) ? adhesionRegion.get(region1).get(region2) : Double.NaN); } diff --git a/src/arcade/potts/sim/hamiltonian/Hamiltonian.java b/src/arcade/potts/sim/hamiltonian/Hamiltonian.java index 555685442..75f0ab064 100644 --- a/src/arcade/potts/sim/hamiltonian/Hamiltonian.java +++ b/src/arcade/potts/sim/hamiltonian/Hamiltonian.java @@ -4,50 +4,48 @@ /** * A {@code Hamiltonian} object represents a term in a CPM Hamiltonian equation. - *

- * Each {@link arcade.potts.sim.Potts} instance is contains a list of - * {@code Hamiltonian} terms associated with the simulation. For each flip, - * changes in energy for all terms in the list are summed together to get the - * total change in energy. + * + *

Each {@link arcade.potts.sim.Potts} instance is contains a list of {@code Hamiltonian} terms + * associated with the simulation. For each flip, changes in energy for all terms in the list are + * summed together to get the total change in energy. */ - public interface Hamiltonian { /** * Register the configuration for the cell instance. * - * @param cell the cell instance + * @param cell the cell instance */ void register(PottsCell cell); - + /** * Deregister the configuration for the cell instance. * - * @param cell the cell instance + * @param cell the cell instance */ void deregister(PottsCell cell); - + /** * Gets change in energy. * - * @param sourceID the id of the source voxel - * @param targetID the id of the target voxel - * @param x the x coordinate - * @param y the y coordinate - * @param z the z coordinate - * @return the change in energy + * @param sourceID the id of the source voxel + * @param targetID the id of the target voxel + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + * @return the change in energy */ double getDelta(int sourceID, int targetID, int x, int y, int z); - + /** * Gets change in energy for region. * - * @param id the voxel id - * @param sourceRegion the region of the source voxel - * @param targetRegion the region of the source voxel - * @param x the x coordinate - * @param y the y coordinate - * @param z the z coordinate - * @return the change in energy + * @param id the voxel id + * @param sourceRegion the region of the source voxel + * @param targetRegion the region of the source voxel + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + * @return the change in energy */ double getDelta(int id, int sourceRegion, int targetRegion, int x, int y, int z); } diff --git a/src/arcade/potts/sim/hamiltonian/HeightHamiltonian.java b/src/arcade/potts/sim/hamiltonian/HeightHamiltonian.java index 39fb820ce..41d3298d5 100644 --- a/src/arcade/potts/sim/hamiltonian/HeightHamiltonian.java +++ b/src/arcade/potts/sim/hamiltonian/HeightHamiltonian.java @@ -13,24 +13,21 @@ import static arcade.potts.sim.PottsSeries.TARGET_SEPARATOR; import static arcade.potts.util.PottsEnums.Region; -/** - * Implementation of {@link Hamiltonian} for height energy. - */ - +/** Implementation of {@link Hamiltonian} for height energy. */ public class HeightHamiltonian implements Hamiltonian { /** Map of hamiltonian config objects. */ final HashMap configs; - + /** Map of population to lambda values. */ final HashMap popToLambda; - + /** Map of population to lambda values for regions. */ final HashMap> popToLambdasRegion; - + /** * Creates the height energy term for the {@code Potts} Hamiltonian. * - * @param series the associated Series instance + * @param series the associated Series instance */ public HeightHamiltonian(PottsSeries series) { configs = new HashMap<>(); @@ -38,7 +35,7 @@ public HeightHamiltonian(PottsSeries series) { popToLambdasRegion = new HashMap<>(); initialize(series); } - + @Override public void register(PottsCell cell) { int pop = cell.getPop(); @@ -47,19 +44,18 @@ public void register(PottsCell cell) { HeightHamiltonianConfig config = new HeightHamiltonianConfig(cell, lambda, lambdasRegion); configs.put(cell.getID(), config); } - + @Override public void deregister(PottsCell cell) { configs.remove(cell.getID()); } - + /** * {@inheritDoc} - *

- * Height energy is calculated by taking the difference in target and - * proposed height for the given ID. Change in height energy is taken as the - * difference in differences of height energies for the source and target - * IDs when a voxel is removed or added. + * + *

Height energy is calculated by taking the difference in target and proposed height for the + * given ID. Change in height energy is taken as the difference in differences of height + * energies for the source and target IDs when a voxel is removed or added. */ @Override public double getDelta(int sourceID, int targetID, int x, int y, int z) { @@ -68,111 +64,115 @@ public double getDelta(int sourceID, int targetID, int x, int y, int z) { double target = getHeight(targetID, voxel, 1) - getHeight(targetID, voxel, 0); return target + source; } - + /** * {@inheritDoc} - *

- * Height energy is calculated by taking the difference in target and - * proposed height for the given region. Change in height energy is taken as - * the difference in differences of height energies for the source and - * target regions when a voxel is removed or added. + * + *

Height energy is calculated by taking the difference in target and proposed height for the + * given region. Change in height energy is taken as the difference in differences of height + * energies for the source and target regions when a voxel is removed or added. */ @Override public double getDelta(int id, int sourceRegion, int targetRegion, int x, int y, int z) { Voxel voxel = new Voxel(x, y, z); - double source = getHeight(id, voxel, sourceRegion, -1) - - getHeight(id, voxel, sourceRegion, 0); - double target = getHeight(id, voxel, targetRegion, 1) - - getHeight(id, voxel, targetRegion, 0); + double source = + getHeight(id, voxel, sourceRegion, -1) - getHeight(id, voxel, sourceRegion, 0); + double target = + getHeight(id, voxel, targetRegion, 1) - getHeight(id, voxel, targetRegion, 0); return target + source; } - + /** * Gets height energy for a given change in height. * - * @param id the voxel id - * @param voxel the changed voxel - * @param change the change in height - * @return the energy + * @param id the voxel id + * @param voxel the changed voxel + * @param change the change in height + * @return the energy */ double getHeight(int id, Voxel voxel, int change) { if (id == 0) { return 0; } - + HeightHamiltonianConfig config = configs.get(id); - ArrayList voxels = (ArrayList) config.location.getVoxels().stream() - .filter(v -> v.x == voxel.x && v.y == voxel.y) - .collect(Collectors.toList()); - + ArrayList voxels = + (ArrayList) + config.location.getVoxels().stream() + .filter(v -> v.x == voxel.x && v.y == voxel.y) + .collect(Collectors.toList()); + double height = Location3D.calculateHeight(voxels); double targetHeight = config.cell.getCriticalHeight(); double changeHeight = (change == 0 ? 0 : change * Location3D.updateHeight(voxels, voxel)); double lambda = config.getLambda(); - + return lambda * Math.pow((height - targetHeight + changeHeight), 2); } - + /** * Gets height energy for a given change in height for region. * - * @param id the voxel id - * @param voxel the changed voxel - * @param t the voxel region - * @param change the change in height - * @return the energy + * @param id the voxel id + * @param voxel the changed voxel + * @param t the voxel region + * @param change the change in height + * @return the energy */ double getHeight(int id, Voxel voxel, int t, double change) { Region region = Region.values()[t]; - + if (id == 0 || region == Region.DEFAULT) { return 0; } - + HeightHamiltonianConfig config = configs.get(id); - ArrayList voxels = (ArrayList) config.location.getVoxels(region).stream() - .filter(v -> v.x == voxel.x && v.y == voxel.y) - .collect(Collectors.toList()); - + ArrayList voxels = + (ArrayList) + config.location.getVoxels(region).stream() + .filter(v -> v.x == voxel.x && v.y == voxel.y) + .collect(Collectors.toList()); + double height = Location3D.calculateHeight(voxels); double targetHeight = config.cell.getCriticalHeight(region); double changeHeight = (change == 0 ? 0 : change * Location3D.updateHeight(voxels, voxel)); double lambda = config.getLambda(region); - + return lambda * Math.pow((height - targetHeight + changeHeight), 2); } - + /** * Initializes parameters for height hamiltonian term. * - * @param series the series instance + * @param series the series instance */ void initialize(PottsSeries series) { if (series.populations == null) { return; } - + Set keySet = series.populations.keySet(); MiniBox parameters = series.potts; - + for (String key : keySet) { MiniBox population = series.populations.get(key); int pop = population.getInt("CODE"); - + // Get lambda value. double lambda = parameters.getDouble("height/LAMBDA" + TARGET_SEPARATOR + key); popToLambda.put(pop, lambda); - + MiniBox regionBox = population.filter("(REGION)"); ArrayList regionKeys = new ArrayList<>(); regionBox.getKeys().forEach(s -> regionKeys.add(Region.valueOf(s))); - + // Get lambda values for regions. if (regionKeys.size() > 0) { EnumMap lambdasRegion = new EnumMap<>(Region.class); for (Region region : regionKeys) { - double lambdaRegion = parameters.getDouble("height/LAMBDA_" - + region.name() + TARGET_SEPARATOR + key); + double lambdaRegion = + parameters.getDouble( + "height/LAMBDA_" + region.name() + TARGET_SEPARATOR + key); lambdasRegion.put(region, lambdaRegion); } popToLambdasRegion.put(pop, lambdasRegion); diff --git a/src/arcade/potts/sim/hamiltonian/HeightHamiltonianConfig.java b/src/arcade/potts/sim/hamiltonian/HeightHamiltonianConfig.java index ba6a04b79..cf5527cc7 100644 --- a/src/arcade/potts/sim/hamiltonian/HeightHamiltonianConfig.java +++ b/src/arcade/potts/sim/hamiltonian/HeightHamiltonianConfig.java @@ -5,39 +5,36 @@ import arcade.potts.env.location.PottsLocation; import static arcade.potts.util.PottsEnums.Region; -/** - * Configuration for {@link HeightHamiltonian} parameters. - */ - +/** Configuration for {@link HeightHamiltonian} parameters. */ class HeightHamiltonianConfig { /** Associated {@link PottsCell} instance. */ final PottsCell cell; - + /** Associated {@link PottsLocation} instance. */ final PottsLocation location; - + /** Lambda multiplier for cell. */ private final double lambda; - + /** Lambda multipliers for cell by region. */ private final EnumMap lambdasRegion; - + /** {@code true} if the cell has regions, {@code false} otherwise. */ final boolean hasRegions; - + /** * Creates parameter configuration for {@code HeightHamiltonian}. * - * @param cell the associated cell instance - * @param lambda the lambda multiplier - * @param lambdasRegion the map of lambda multiplier for regions + * @param cell the associated cell instance + * @param lambda the lambda multiplier + * @param lambdasRegion the map of lambda multiplier for regions */ HeightHamiltonianConfig(PottsCell cell, double lambda, EnumMap lambdasRegion) { this.cell = cell; this.location = (PottsLocation) cell.getLocation(); this.lambda = lambda; this.hasRegions = (lambdasRegion != null) && (lambdasRegion.keySet().size() > 0); - + if (hasRegions) { this.lambdasRegion = new EnumMap<>(Region.class); for (Region region : lambdasRegion.keySet()) { @@ -47,19 +44,21 @@ class HeightHamiltonianConfig { this.lambdasRegion = null; } } - + /** * Gets the lambda value. * - * @return the lambda value + * @return the lambda value */ - public double getLambda() { return lambda; } - + public double getLambda() { + return lambda; + } + /** * Gets the lambda value for the region. * - * @param region the region - * @return the lambda value + * @param region the region + * @return the lambda value */ public double getLambda(Region region) { return (hasRegions && lambdasRegion.containsKey(region) diff --git a/src/arcade/potts/sim/hamiltonian/JunctionHamiltonian.java b/src/arcade/potts/sim/hamiltonian/JunctionHamiltonian.java index 64a01e4ad..2c072e394 100644 --- a/src/arcade/potts/sim/hamiltonian/JunctionHamiltonian.java +++ b/src/arcade/potts/sim/hamiltonian/JunctionHamiltonian.java @@ -8,34 +8,31 @@ import arcade.potts.sim.PottsSeries; import static arcade.potts.sim.PottsSeries.TARGET_SEPARATOR; -/** - * Implementation of {@link Hamiltonian} for tight junction energy. - */ - +/** Implementation of {@link Hamiltonian} for tight junction energy. */ public class JunctionHamiltonian implements Hamiltonian { /** Map of hamiltonian config objects. */ final HashMap configs; - + /** Map of population to lambda values. */ final HashMap popToLambda; - + /** Potts array for ids. */ final int[][][] ids; - + /** * Creates the junction energy term for the {@code Potts} Hamiltonian. * - * @param series the associated Series instance - * @param potts the associated Potts instance + * @param series the associated Series instance + * @param potts the associated Potts instance */ public JunctionHamiltonian(PottsSeries series, Potts potts) { configs = new HashMap<>(); popToLambda = new HashMap<>(); initialize(series); - + this.ids = potts.ids; } - + @Override public void register(PottsCell cell) { int pop = cell.getPop(); @@ -43,60 +40,60 @@ public void register(PottsCell cell) { JunctionHamiltonianConfig config = new JunctionHamiltonianConfig(lambda); configs.put(cell.getID(), config); } - + @Override public void deregister(PottsCell cell) { configs.remove(cell.getID()); } - + /** * {@inheritDoc} - *

- * Junction energy is calculated only for the case where both the source - * and the target are not media (id =/= 0). + * + *

Junction energy is calculated only for the case where both the source and the target are + * not media (id =/= 0). */ @Override public double getDelta(int sourceID, int targetID, int x, int y, int z) { if (sourceID == 0 || targetID == 0) { return 0; } - + double lambda = configs.get(targetID).getLambda(); - + if (ids[z - 1][x][y] == targetID) { return -lambda; } - + return lambda; } - + /** * {@inheritDoc} - *

- * Junction energy is set to zero. Region voxels do not form junctions. + * + *

Junction energy is set to zero. Region voxels do not form junctions. */ @Override public double getDelta(int id, int sourceRegion, int targetRegion, int x, int y, int z) { return 0; } - + /** * Initializes parameters for junction hamiltonian term. * - * @param series the series instance + * @param series the series instance */ void initialize(PottsSeries series) { if (series.populations == null) { return; } - + Set keySet = series.populations.keySet(); MiniBox parameters = series.potts; - + for (String key : keySet) { MiniBox population = series.populations.get(key); int pop = population.getInt("CODE"); - + // Get lambda value. double lambda = parameters.getDouble("junction/LAMBDA" + TARGET_SEPARATOR + key); popToLambda.put(pop, lambda); diff --git a/src/arcade/potts/sim/hamiltonian/JunctionHamiltonianConfig.java b/src/arcade/potts/sim/hamiltonian/JunctionHamiltonianConfig.java index d20f3958d..cc7a6593b 100644 --- a/src/arcade/potts/sim/hamiltonian/JunctionHamiltonianConfig.java +++ b/src/arcade/potts/sim/hamiltonian/JunctionHamiltonianConfig.java @@ -1,26 +1,25 @@ package arcade.potts.sim.hamiltonian; -/** - * Configuration for {@link JunctionHamiltonian} parameters. - */ - +/** Configuration for {@link JunctionHamiltonian} parameters. */ class JunctionHamiltonianConfig { /** Lambda multiplier for cell. */ private final double lambda; - + /** * Creates parameter configuration for {@code JunctionHamiltonian}. * - * @param lambda the lambda multiplier + * @param lambda the lambda multiplier */ JunctionHamiltonianConfig(double lambda) { this.lambda = lambda; } - + /** * Gets the lambda value. * - * @return the lambda value + * @return the lambda value */ - public double getLambda() { return lambda; } + public double getLambda() { + return lambda; + } } diff --git a/src/arcade/potts/sim/hamiltonian/PersistenceHamiltonian.java b/src/arcade/potts/sim/hamiltonian/PersistenceHamiltonian.java index 67305a0d8..0831bc10d 100644 --- a/src/arcade/potts/sim/hamiltonian/PersistenceHamiltonian.java +++ b/src/arcade/potts/sim/hamiltonian/PersistenceHamiltonian.java @@ -12,30 +12,27 @@ import static arcade.potts.sim.PottsSeries.TARGET_SEPARATOR; import static arcade.potts.util.PottsEnums.Region; -/** - * Implementation of {@link Hamiltonian} for persistence energy. - */ - +/** Implementation of {@link Hamiltonian} for persistence energy. */ public class PersistenceHamiltonian implements Hamiltonian { /** Map of hamiltonian config objects. */ final HashMap configs; - + /** Map of population to lambda values. */ final HashMap popToLambda; - + /** Map of population to decay values. */ final HashMap popToDecay; - + /** Map of population to lambda values for regions. */ final HashMap> popToLambdasRegion; - + /** Volume threshold for scaling vector in z direction. */ double threshold; - + /** * Creates the persistence energy term for the {@code Potts} Hamiltonian. * - * @param series the associated Series instance + * @param series the associated Series instance */ public PersistenceHamiltonian(PottsSeries series) { configs = new HashMap<>(); @@ -44,7 +41,7 @@ public PersistenceHamiltonian(PottsSeries series) { popToLambdasRegion = new HashMap<>(); initialize(series); } - + @Override public void register(PottsCell cell) { int pop = cell.getPop(); @@ -52,23 +49,22 @@ public void register(PottsCell cell) { EnumMap lambdasRegion = popToLambdasRegion.get(pop); double decay = popToDecay.get(pop); PottsLocation loc = (PottsLocation) cell.getLocation(); - PersistenceHamiltonianConfig config = new PersistenceHamiltonianConfig(loc, - lambda, lambdasRegion, decay, threshold); + PersistenceHamiltonianConfig config = + new PersistenceHamiltonianConfig(loc, lambda, lambdasRegion, decay, threshold); configs.put(cell.getID(), config); } - + @Override public void deregister(PottsCell cell) { configs.remove(cell.getID()); } - + /** * {@inheritDoc} - *

- * Persistence energy is calculated by taking the sum of source and target - * persistence energies. Source energy is calculated from displacement when - * a voxel is removed. Target energy is calculated from displacement when a - * voxel is added. + * + *

Persistence energy is calculated by taking the sum of source and target persistence + * energies. Source energy is calculated from displacement when a voxel is removed. Target + * energy is calculated from displacement when a voxel is added. */ @Override public double getDelta(int sourceID, int targetID, int x, int y, int z) { @@ -76,14 +72,13 @@ public double getDelta(int sourceID, int targetID, int x, int y, int z) { double target = getPersistence(targetID, x, y, z, 1); return source + target; } - + /** * {@inheritDoc} - *

- * Persistence energy is calculated by taking the sum of source and target - * persistence energies for the region. Source energy is calculated from - * displacement when a voxel is removed. Target energy is calculated from - * displacement when a voxel is added. + * + *

Persistence energy is calculated by taking the sum of source and target persistence + * energies for the region. Source energy is calculated from displacement when a voxel is + * removed. Target energy is calculated from displacement when a voxel is added. */ @Override public double getDelta(int id, int sourceRegion, int targetRegion, int x, int y, int z) { @@ -91,100 +86,100 @@ public double getDelta(int id, int sourceRegion, int targetRegion, int x, int y, double target = getPersistence(id, targetRegion, x, y, z, 1); return source + target; } - + /** * Gets persistence energy for voxel added or removed. - *

- * Persistence for non-cell voxels is zero. * - * @param id the voxel id - * @param x the x coordinate - * @param y the y coordinate - * @param z the z coordinate - * @param change the direction of change (add = +1, remove = -1) - * @return the energy + *

Persistence for non-cell voxels is zero. + * + * @param id the voxel id + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + * @param change the direction of change (add = +1, remove = -1) + * @return the energy */ double getPersistence(int id, int x, int y, int z, int change) { if (id <= 0) { return 0; } - + PersistenceHamiltonianConfig config = configs.get(id); - + double[] vector = config.getVector(); double[] displacement = config.getDisplacement(x, y, z, change); - + double dot = Matrix.dot(vector, displacement); double lambda = config.getLambda(); - + return -lambda * dot * config.location.getSurface(); } - + /** * Gets the persistence energy for voxel added or removed in a region. - *

- * Persistence for the default region is zero. Calculating persistence for a - * region does not update the target vector or displacement vectors for the - * cell. * - * @param id the voxel id - * @param t the voxel region - * @param x the x coordinate - * @param y the y coordinate - * @param z the z coordinate - * @param change the direction of change (add = +1, remove = -1) - * @return the energy + *

Persistence for the default region is zero. Calculating persistence for a region does not + * update the target vector or displacement vectors for the cell. + * + * @param id the voxel id + * @param t the voxel region + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + * @param change the direction of change (add = +1, remove = -1) + * @return the energy */ double getPersistence(int id, int t, int x, int y, int z, int change) { Region region = Region.values()[t]; if (id == 0 || region == Region.DEFAULT) { return 0; } - + PersistenceHamiltonianConfig config = configs.get(id); double[] displacement = config.getDisplacement(x, y, z, change, region); - + double dot = Matrix.dot(config.vector, displacement); double lambda = config.getLambda(region); - + return -lambda * dot * config.location.getSurface(region); } - + /** * Initializes parameters for persistence hamiltonian term. * - * @param series the series instance + * @param series the series instance */ void initialize(PottsSeries series) { if (series.populations == null) { return; } - + Set keySet = series.populations.keySet(); MiniBox parameters = series.potts; - + for (String key : keySet) { MiniBox population = series.populations.get(key); int pop = population.getInt("CODE"); - + // Get lambda value. double lambda = parameters.getDouble("persistence/LAMBDA" + TARGET_SEPARATOR + key); popToLambda.put(pop, lambda); - + // Get persistence decay rate. double substrate = parameters.getDouble("persistence/DECAY" + TARGET_SEPARATOR + key); popToDecay.put(pop, substrate); - + MiniBox regionBox = population.filter("(REGION)"); ArrayList regionKeys = new ArrayList<>(); regionBox.getKeys().forEach(s -> regionKeys.add(Region.valueOf(s))); - + // Get lambda values for regions. if (regionKeys.size() > 0) { EnumMap lambdasRegion = new EnumMap<>(Region.class); for (Region region : regionKeys) { - double lambdaRegion = parameters.getDouble("persistence/LAMBDA_" - + region.name() + TARGET_SEPARATOR + key); + double lambdaRegion = + parameters.getDouble( + "persistence/LAMBDA_" + region.name() + TARGET_SEPARATOR + key); lambdasRegion.put(region, lambdaRegion); } popToLambdasRegion.put(pop, lambdasRegion); @@ -192,7 +187,7 @@ void initialize(PottsSeries series) { popToLambdasRegion.put(pop, null); } } - + // Set term parameters. threshold = parameters.getDouble("persistence/VOLUME_THRESHOLD"); } diff --git a/src/arcade/potts/sim/hamiltonian/PersistenceHamiltonianConfig.java b/src/arcade/potts/sim/hamiltonian/PersistenceHamiltonianConfig.java index be2dff5a1..6e52ac8b8 100644 --- a/src/arcade/potts/sim/hamiltonian/PersistenceHamiltonianConfig.java +++ b/src/arcade/potts/sim/hamiltonian/PersistenceHamiltonianConfig.java @@ -5,62 +5,62 @@ import arcade.potts.env.location.PottsLocation; import static arcade.potts.util.PottsEnums.Region; -/** - * Configuration for {@link PersistenceHamiltonian} parameters. - */ - +/** Configuration for {@link PersistenceHamiltonian} parameters. */ class PersistenceHamiltonianConfig { /** Default migration unit vector. */ - static final double[] DEFAULT_UNIT_VECTOR = new double[] { 0, 0, 0 }; - + static final double[] DEFAULT_UNIT_VECTOR = new double[] {0, 0, 0}; + /** Associated {@link PottsLocation} instance. */ final PottsLocation location; - + /** Lambda multiplier for cell. */ private final double lambda; - + /** Lambda multipliers for cell by region. */ private final EnumMap lambdasRegion; - + /** Vector decay fraction for location. */ private final double decay; - + /** {@code true} if the cell has regions, {@code false} otherwise. */ final boolean hasRegions; - + /** Volume threshold for scaling vector in z direction. */ final double threshold; - + /** Movement target vector. */ final double[] vector; - + /** Displacement vector. */ final double[] displacement; - + /** Location volume used to check if location has changed. */ private int volumeCheck; - + /** * Creates parameter configuration for {@code PersistenceHamiltonian}. * - * @param location the associated location instance - * @param lambda the lambda multiplier - * @param lambdasRegion the map of lambda multiplier for regions - * @param decay the decay fraction - * @param threshold the volume threshold + * @param location the associated location instance + * @param lambda the lambda multiplier + * @param lambdasRegion the map of lambda multiplier for regions + * @param decay the decay fraction + * @param threshold the volume threshold */ - PersistenceHamiltonianConfig(PottsLocation location, double lambda, - EnumMap lambdasRegion, - double decay, double threshold) { + PersistenceHamiltonianConfig( + PottsLocation location, + double lambda, + EnumMap lambdasRegion, + double decay, + double threshold) { this.location = location; this.lambda = lambda; this.decay = decay; this.threshold = threshold; this.vector = DEFAULT_UNIT_VECTOR.clone(); - this.displacement = new double[] { 0, 0, 0 }; + this.displacement = new double[] {0, 0, 0}; this.volumeCheck = (int) location.getVolume(); this.hasRegions = (lambdasRegion != null) && (lambdasRegion.keySet().size() > 0); - + if (hasRegions) { this.lambdasRegion = new EnumMap<>(Region.class); for (Region region : lambdasRegion.keySet()) { @@ -70,112 +70,115 @@ class PersistenceHamiltonianConfig { this.lambdasRegion = null; } } - + /** * Gets the lambda value. * - * @return the lambda value + * @return the lambda value */ - public double getLambda() { return lambda; } - + public double getLambda() { + return lambda; + } + /** * Gets the lambda value for the region. * - * @param region the region - * @return the lambda value + * @param region the region + * @return the lambda value */ public double getLambda(Region region) { return (hasRegions && lambdasRegion.containsKey(region) ? lambdasRegion.get(region) : Double.NaN); } - + /** * Gets the decay value. * - * @return the decay value + * @return the decay value */ - public double getDecay() { return decay; } - + public double getDecay() { + return decay; + } + /** * Gets the direction unit vector for the location. - *

- * If the location has changed since the last call to this method, the - * vector is updated to be between the previous direction and the most - * recent displacement direction. * - * @return the direction unit vector + *

If the location has changed since the last call to this method, the vector is updated to + * be between the previous direction and the most recent displacement direction. + * + * @return the direction unit vector */ public double[] getVector() { if ((int) location.getVolume() != volumeCheck) { // Update tracked volume to new location volume. volumeCheck = (int) location.getVolume(); - + // Update target. vector[0] = (1 - decay) * vector[0] + decay * displacement[0]; vector[1] = (1 - decay) * vector[1] + decay * displacement[1]; vector[2] = -volumeCheck / threshold; - + // Convert to unit vector. Matrix.unit(vector); } - + return vector; } - + /** * Gets the updated displacement of the center. - *

- * Displacement vector is stored until this method is called again. * - * @param x the x position of the changed voxel - * @param y the y position of the changed voxel - * @param z the z position of the changed voxel - * @param change the direction of change (add = +1, remove = -1) - * @return the displacement unit vector + *

Displacement vector is stored until this method is called again. + * + * @param x the x position of the changed voxel + * @param y the y position of the changed voxel + * @param z the z position of the changed voxel + * @param change the direction of change (add = +1, remove = -1) + * @return the displacement unit vector */ public double[] getDisplacement(int x, int y, int z, int change) { // Get updated volume and current centroid. double volume = location.getVolume() + change; double[] centroid = location.getCentroid(); - + // Calculate displacement. displacement[0] = (change * (x - centroid[0])) / volume; displacement[1] = (change * (y - centroid[1])) / volume; displacement[2] = (change * (z - centroid[2])) / volume; - + // Convert displacement to unit vector. Matrix.unit(displacement); - + return displacement; } - + /** * Gets the updated displacement of the center of a region. - *

- * Calling this method does not update the stored displacement vector. * - * @param x the x position of the changed voxel - * @param y the y position of the changed voxel - * @param z the z position of the changed voxel - * @param change the direction of change (add = +1, remove = -1) - * @param region the region - * @return the displacement unit vector + *

Calling this method does not update the stored displacement vector. + * + * @param x the x position of the changed voxel + * @param y the y position of the changed voxel + * @param z the z position of the changed voxel + * @param change the direction of change (add = +1, remove = -1) + * @param region the region + * @return the displacement unit vector */ public double[] getDisplacement(int x, int y, int z, int change, Region region) { // Get updated volume and current centroid for region. double volume = location.getVolume(region) + change; double[] centroid = location.getCentroid(region); - + // Calculate displacement. double[] disp = new double[3]; disp[0] = (change * (x - centroid[0])) / volume; disp[1] = (change * (y - centroid[1])) / volume; disp[2] = (change * (z - centroid[2])) / volume; - + // Convert displacement to unit vector. Matrix.unit(disp); - + return disp; } } diff --git a/src/arcade/potts/sim/hamiltonian/SubstrateHamiltonian.java b/src/arcade/potts/sim/hamiltonian/SubstrateHamiltonian.java index 915d92494..331c2ee75 100644 --- a/src/arcade/potts/sim/hamiltonian/SubstrateHamiltonian.java +++ b/src/arcade/potts/sim/hamiltonian/SubstrateHamiltonian.java @@ -8,44 +8,41 @@ import arcade.potts.sim.PottsSeries; import static arcade.potts.sim.PottsSeries.TARGET_SEPARATOR; -/** - * Implementation of {@link Hamiltonian} for substrate energy. - */ - +/** Implementation of {@link Hamiltonian} for substrate energy. */ public class SubstrateHamiltonian implements Hamiltonian { /** Number of neighbors considered for substrate adhesion. */ static final int NUMBER_NEIGHBORS = 9; - + /** Scaling at threshold height. */ static final double THRESHOLD_FRACTION = 0.01; - + /** Map of hamiltonian config objects. */ final HashMap configs; - + /** Map of population to substrate adhesion values. */ final HashMap popToSubstrate; - + /** Grid tracking substrate values. */ final int[][] substrates; - + /** Power for scaling substrate energy. */ double power; - + /** * Creates the substrate energy term for the {@code Potts} Hamiltonian. * - * @param series the associated Series instance - * @param potts the associated Potts instance + * @param series the associated Series instance + * @param potts the associated Potts instance */ public SubstrateHamiltonian(PottsSeries series, Potts potts) { configs = new HashMap<>(); popToSubstrate = new HashMap<>(); initialize(series); - + // Create substrate array. substrates = createSubstrate(potts.length + 2, potts.width + 2); } - + @Override public void register(PottsCell cell) { int pop = cell.getPop(); @@ -53,18 +50,18 @@ public void register(PottsCell cell) { SubstrateHamiltonianConfig config = new SubstrateHamiltonianConfig(substrate); configs.put(cell.getID(), config); } - + @Override public void deregister(PottsCell cell) { configs.remove(cell.getID()); } - + /** * {@inheritDoc} - *

- * Substrate energy is calculated by summing across substrate voxels below - * the given voxel. Change in adhesion energy is taken as the difference in - * substrate energies for the source and target IDs. + * + *

Substrate energy is calculated by summing across substrate voxels below the given voxel. + * Change in adhesion energy is taken as the difference in substrate energies for the source and + * target IDs. */ @Override public double getDelta(int sourceID, int targetID, int x, int y, int z) { @@ -72,93 +69,90 @@ public double getDelta(int sourceID, int targetID, int x, int y, int z) { double target = getSubstrate(targetID, x, y, z); return target - source; } - + /** * {@inheritDoc} - *

- * Substrate energy is set to zero. Region voxels cannot adhere to - * substrate. + * + *

Substrate energy is set to zero. Region voxels cannot adhere to substrate. */ @Override public double getDelta(int id, int sourceRegion, int targetRegion, int x, int y, int z) { return 0; } - + /** * Gets substrate energy for a given voxel. - *

- * Substrate is assumed to be located at z = 0. Media (id = 0) returns zero - * for substrate energy. Substrate energy is scaled by distance from z = 0 - * by a power function. * - * @param id the voxel id - * @param x the x coordinate - * @param y the y coordinate - * @param z the z coordinate - * @return the energy + *

Substrate is assumed to be located at z = 0. Media (id = 0) returns zero for substrate + * energy. Substrate energy is scaled by distance from z = 0 by a power function. + * + * @param id the voxel id + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + * @return the energy */ double getSubstrate(int id, int x, int y, int z) { if (id <= 0) { return 0; } - + double substrate = configs.get(id).getSubstrate(); double substrateEnergy = 0; - + for (int i = x - 1; i <= x + 1; i++) { for (int j = y - 1; j <= y + 1; j++) { substrateEnergy -= substrates[i][j]; } } - + substrateEnergy = Math.pow(z, power) * substrateEnergy / NUMBER_NEIGHBORS * substrate; return substrateEnergy; } - + /** * Initializes parameters for substrate hamiltonian term. * - * @param series the series instance + * @param series the series instance */ void initialize(PottsSeries series) { if (series.populations == null) { return; } - + Set keySet = series.populations.keySet(); MiniBox parameters = series.potts; - + for (String key : keySet) { MiniBox population = series.populations.get(key); int pop = population.getInt("CODE"); - + // Get substrate adhesion value. double substrate = parameters.getDouble("substrate/ADHESION" + TARGET_SEPARATOR + key); popToSubstrate.put(pop, substrate); } - + // Set term parameters. double thresholdHeight = parameters.getDouble("substrate/HEIGHT_THRESHOLD"); power = Math.log(THRESHOLD_FRACTION) / Math.log(thresholdHeight); } - + /** * Creates array representing substrate. * - * @param length the length (x direction) of potts array - * @param width the width (y direction) of potts array - * @return the substrate array + * @param length the length (x direction) of potts array + * @param width the width (y direction) of potts array + * @return the substrate array */ int[][] createSubstrate(int length, int width) { int[][] arr = new int[length][width]; - + for (int i = 0; i < length; i++) { for (int j = 0; j < width; j++) { arr[i][j] = 1; } } - + return arr; } - } diff --git a/src/arcade/potts/sim/hamiltonian/SubstrateHamiltonianConfig.java b/src/arcade/potts/sim/hamiltonian/SubstrateHamiltonianConfig.java index 73913edcf..9fab514a8 100644 --- a/src/arcade/potts/sim/hamiltonian/SubstrateHamiltonianConfig.java +++ b/src/arcade/potts/sim/hamiltonian/SubstrateHamiltonianConfig.java @@ -1,26 +1,25 @@ package arcade.potts.sim.hamiltonian; -/** - * Configuration for {@link SubstrateHamiltonian} parameters. - */ - +/** Configuration for {@link SubstrateHamiltonian} parameters. */ class SubstrateHamiltonianConfig { /** Substrate adhesion for cell. */ private final double substrate; - + /** * Creates parameter configuration for {@code SubstrateHamiltonian}. * - * @param substrate the substrate adhesion + * @param substrate the substrate adhesion */ SubstrateHamiltonianConfig(double substrate) { this.substrate = substrate; } - + /** * Gets the substrate value. * - * @return the substrate value + * @return the substrate value */ - public double getSubstrate() { return substrate; } + public double getSubstrate() { + return substrate; + } } diff --git a/src/arcade/potts/sim/hamiltonian/SurfaceHamiltonian.java b/src/arcade/potts/sim/hamiltonian/SurfaceHamiltonian.java index eb2c52e6b..314404cc3 100644 --- a/src/arcade/potts/sim/hamiltonian/SurfaceHamiltonian.java +++ b/src/arcade/potts/sim/hamiltonian/SurfaceHamiltonian.java @@ -11,42 +11,39 @@ import static arcade.potts.sim.PottsSeries.TARGET_SEPARATOR; import static arcade.potts.util.PottsEnums.Region; -/** - * Implementation of {@link Hamiltonian} for surface energy. - */ - +/** Implementation of {@link Hamiltonian} for surface energy. */ public abstract class SurfaceHamiltonian implements Hamiltonian { /** Map of hamiltonian config objects. */ final HashMap configs; - + /** Map of population to lambda values. */ final HashMap popToLambda; - + /** Map of population to lambda values for regions. */ final HashMap> popToLambdasRegion; - + /** Potts array for ids. */ final int[][][] ids; - + /** Potts array for regions. */ final int[][][] regions; - + /** * Creates the surface energy term for the {@code Potts} Hamiltonian. * - * @param series the associated Series instance - * @param potts the associated Potts instance + * @param series the associated Series instance + * @param potts the associated Potts instance */ public SurfaceHamiltonian(PottsSeries series, Potts potts) { configs = new HashMap<>(); popToLambda = new HashMap<>(); popToLambdasRegion = new HashMap<>(); initialize(series); - + this.ids = potts.ids; this.regions = potts.regions; } - + @Override public void register(PottsCell cell) { int pop = cell.getPop(); @@ -55,19 +52,18 @@ public void register(PottsCell cell) { SurfaceHamiltonianConfig config = new SurfaceHamiltonianConfig(cell, lambda, lambdasRegion); configs.put(cell.getID(), config); } - + @Override public void deregister(PottsCell cell) { configs.remove(cell.getID()); } - + /** * {@inheritDoc} - *

- * Surface energy is calculated by taking the difference in target and - * proposed surface for the given ID. Change in surface energy is taken as - * the difference in differences of surface energies for the source and - * target IDs when a voxel is removed or added. + * + *

Surface energy is calculated by taking the difference in target and proposed surface for + * the given ID. Change in surface energy is taken as the difference in differences of surface + * energies for the source and target IDs when a voxel is removed or added. */ @Override public double getDelta(int sourceID, int targetID, int x, int y, int z) { @@ -76,14 +72,13 @@ public double getDelta(int sourceID, int targetID, int x, int y, int z) { double target = getSurface(targetID, changes[1]) - getSurface(targetID, 0); return target + source; } - + /** * {@inheritDoc} - *

- * Surface energy is calculated by taking the difference in target and - * proposed surface for the given region. Change in surface energy is taken - * as the difference in differences of surface energies for the source and - * target regions when a voxel is removed or added. + * + *

Surface energy is calculated by taking the difference in target and proposed surface for + * the given region. Change in surface energy is taken as the difference in differences of + * surface energies for the source and target regions when a voxel is removed or added. */ @Override public double getDelta(int id, int sourceRegion, int targetRegion, int x, int y, int z) { @@ -92,38 +87,38 @@ public double getDelta(int id, int sourceRegion, int targetRegion, int x, int y, double target = getSurface(id, targetRegion, changes[1]) - getSurface(id, targetRegion, 0); return target + source; } - + /** * Calculates change in surface. * - * @param sourceID the id of the source voxel - * @param targetID the id of the target voxel - * @param x the x coordinate - * @param y the y coordinate - * @param z the z coordinate - * @return the list of changes in source and target + * @param sourceID the id of the source voxel + * @param targetID the id of the target voxel + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + * @return the list of changes in source and target */ abstract int[] calculateChange(int sourceID, int targetID, int x, int y, int z); - + /** * Calculates change in surface for region. * - * @param id the voxel id - * @param sourceRegion the id of the source voxel - * @param targetRegion the id of the target voxel - * @param x the x coordinate - * @param y the y coordinate - * @param z the z coordinate - * @return the list of changes in source and target + * @param id the voxel id + * @param sourceRegion the id of the source voxel + * @param targetRegion the id of the target voxel + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + * @return the list of changes in source and target */ abstract int[] calculateChange(int id, int sourceRegion, int targetRegion, int x, int y, int z); - + /** * Gets the surface energy for a given change in surface. * - * @param id the voxel id - * @param change the change in surface - * @return the energy + * @param id the voxel id + * @param change the change in surface + * @return the energy */ double getSurface(int id, int change) { if (id == 0) { @@ -135,14 +130,14 @@ public double getDelta(int id, int sourceRegion, int targetRegion, int x, int y, double lambda = config.getLambda(); return lambda * Math.pow((surface - targetSurface + change), 2); } - + /** * Gets the surface energy for a given change in surface for region. * - * @param id the voxel id - * @param t the voxel region - * @param change the change in surface - * @return the energy + * @param id the voxel id + * @param t the voxel region + * @param change the change in surface + * @return the energy */ double getSurface(int id, int t, int change) { Region region = Region.values()[t]; @@ -155,38 +150,39 @@ public double getDelta(int id, int sourceRegion, int targetRegion, int x, int y, double lambda = config.getLambda(region); return lambda * Math.pow((surface - targetSurface + change), 2); } - + /** * Initializes parameters for surface hamiltonian term. * - * @param series the series instance + * @param series the series instance */ void initialize(PottsSeries series) { if (series.populations == null) { return; } - + Set keySet = series.populations.keySet(); MiniBox parameters = series.potts; - + for (String key : keySet) { MiniBox population = series.populations.get(key); int pop = population.getInt("CODE"); - + // Get lambda value. double lambda = parameters.getDouble("surface/LAMBDA" + TARGET_SEPARATOR + key); popToLambda.put(pop, lambda); - + MiniBox regionBox = population.filter("(REGION)"); ArrayList regionKeys = new ArrayList<>(); regionBox.getKeys().forEach(s -> regionKeys.add(Region.valueOf(s))); - + // Get lambda values for regions. if (regionKeys.size() > 0) { EnumMap lambdasRegion = new EnumMap<>(Region.class); for (Region region : regionKeys) { - double lambdaRegion = parameters.getDouble("surface/LAMBDA_" - + region.name() + TARGET_SEPARATOR + key); + double lambdaRegion = + parameters.getDouble( + "surface/LAMBDA_" + region.name() + TARGET_SEPARATOR + key); lambdasRegion.put(region, lambdaRegion); } popToLambdasRegion.put(pop, lambdasRegion); diff --git a/src/arcade/potts/sim/hamiltonian/SurfaceHamiltonian2D.java b/src/arcade/potts/sim/hamiltonian/SurfaceHamiltonian2D.java index 2832b74be..ed312130a 100644 --- a/src/arcade/potts/sim/hamiltonian/SurfaceHamiltonian2D.java +++ b/src/arcade/potts/sim/hamiltonian/SurfaceHamiltonian2D.java @@ -6,37 +6,36 @@ import static arcade.potts.sim.Potts2D.MOVES_Y; import static arcade.potts.sim.Potts2D.NUMBER_NEIGHBORS; -/** - * Extension of {@link SurfaceHamiltonian} for 2D. - */ - +/** Extension of {@link SurfaceHamiltonian} for 2D. */ public class SurfaceHamiltonian2D extends SurfaceHamiltonian { /** * Creates the surface energy term for the {@code Potts} Hamiltonian in 2D. * - * @param series the associated Series instance - * @param potts the associated Potts instance + * @param series the associated Series instance + * @param potts the associated Potts instance */ - public SurfaceHamiltonian2D(PottsSeries series, Potts potts) { super(series, potts); } - + public SurfaceHamiltonian2D(PottsSeries series, Potts potts) { + super(series, potts); + } + @Override int[] calculateChange(int sourceID, int targetID, int x, int y, int z) { int beforeSource = 0; int afterSource = 0; int beforeTarget = 0; int afterTarget = 0; - + // Iterate through each neighbor. for (int i = 0; i < NUMBER_NEIGHBORS; i++) { int neighbor = ids[z][x + MOVES_X[i]][y + MOVES_Y[i]]; - + if (neighbor != sourceID) { beforeSource++; if (neighbor == targetID) { beforeTarget++; } } - + if (neighbor != targetID) { afterTarget++; if (neighbor == sourceID) { @@ -44,33 +43,33 @@ int[] calculateChange(int sourceID, int targetID, int x, int y, int z) { } } } - + // Save changes to surface. int sourceSurfaceChange = afterSource - beforeSource; int targetSurfaceChange = afterTarget - beforeTarget; - - return new int[] { sourceSurfaceChange, targetSurfaceChange }; + + return new int[] {sourceSurfaceChange, targetSurfaceChange}; } - + @Override int[] calculateChange(int id, int sourceRegion, int targetRegion, int x, int y, int z) { int beforeSource = 0; int afterSource = 0; int beforeTarget = 0; int afterTarget = 0; - + // Iterate through each neighbor. for (int i = 0; i < NUMBER_NEIGHBORS; i++) { int neighborID = ids[z][x + MOVES_X[i]][y + MOVES_Y[i]]; int neighborRegion = regions[z][x + MOVES_X[i]][y + MOVES_Y[i]]; - + if (neighborRegion != sourceRegion || neighborID != id) { beforeSource++; if (neighborRegion == targetRegion && neighborID == id) { beforeTarget++; } } - + if (neighborRegion != targetRegion || neighborID != id) { afterTarget++; if (neighborRegion == sourceRegion && neighborID == id) { @@ -78,11 +77,11 @@ int[] calculateChange(int id, int sourceRegion, int targetRegion, int x, int y, } } } - + // Save changes to surface. int sourceSurfaceChange = afterSource - beforeSource; int targetSurfaceChange = afterTarget - beforeTarget; - - return new int[] { sourceSurfaceChange, targetSurfaceChange }; + + return new int[] {sourceSurfaceChange, targetSurfaceChange}; } } diff --git a/src/arcade/potts/sim/hamiltonian/SurfaceHamiltonian3D.java b/src/arcade/potts/sim/hamiltonian/SurfaceHamiltonian3D.java index 66a38c8e7..b4b1492d3 100644 --- a/src/arcade/potts/sim/hamiltonian/SurfaceHamiltonian3D.java +++ b/src/arcade/potts/sim/hamiltonian/SurfaceHamiltonian3D.java @@ -7,37 +7,36 @@ import static arcade.potts.sim.Potts3D.MOVES_Z; import static arcade.potts.sim.Potts3D.NUMBER_NEIGHBORS; -/** - * Extension of {@link SurfaceHamiltonian} for 3D. - */ - +/** Extension of {@link SurfaceHamiltonian} for 3D. */ public class SurfaceHamiltonian3D extends SurfaceHamiltonian { /** * Creates the surface energy term for the {@code Potts} Hamiltonian in 3D. * - * @param series the associated Series instance - * @param potts the associated Potts instance + * @param series the associated Series instance + * @param potts the associated Potts instance */ - public SurfaceHamiltonian3D(PottsSeries series, Potts potts) { super(series, potts); } - + public SurfaceHamiltonian3D(PottsSeries series, Potts potts) { + super(series, potts); + } + @Override int[] calculateChange(int sourceID, int targetID, int x, int y, int z) { int beforeSource = 0; int afterSource = 0; int beforeTarget = 0; int afterTarget = 0; - + // Iterate through each neighbor. for (int i = 0; i < NUMBER_NEIGHBORS; i++) { int neighbor = ids[z + MOVES_Z[i]][x + MOVES_X[i]][y + MOVES_Y[i]]; - + if (neighbor != sourceID) { beforeSource++; if (neighbor == targetID) { beforeTarget++; } } - + if (neighbor != targetID) { afterTarget++; if (neighbor == sourceID) { @@ -45,33 +44,33 @@ int[] calculateChange(int sourceID, int targetID, int x, int y, int z) { } } } - + // Save changes to surface. int sourceSurfaceChange = afterSource - beforeSource; int targetSurfaceChange = afterTarget - beforeTarget; - - return new int[] { sourceSurfaceChange, targetSurfaceChange }; + + return new int[] {sourceSurfaceChange, targetSurfaceChange}; } - + @Override int[] calculateChange(int id, int sourceRegion, int targetRegion, int x, int y, int z) { int beforeSource = 0; int afterSource = 0; int beforeTarget = 0; int afterTarget = 0; - + // Iterate through each neighbor. for (int i = 0; i < NUMBER_NEIGHBORS; i++) { int neighborID = ids[z + MOVES_Z[i]][x + MOVES_X[i]][y + MOVES_Y[i]]; int neighborRegion = regions[z + MOVES_Z[i]][x + MOVES_X[i]][y + MOVES_Y[i]]; - + if (neighborRegion != sourceRegion || neighborID != id) { beforeSource++; if (neighborRegion == targetRegion && neighborID == id) { beforeTarget++; } } - + if (neighborRegion != targetRegion || neighborID != id) { afterTarget++; if (neighborRegion == sourceRegion && neighborID == id) { @@ -79,11 +78,11 @@ int[] calculateChange(int id, int sourceRegion, int targetRegion, int x, int y, } } } - + // Save changes to surface. int sourceSurfaceChange = afterSource - beforeSource; int targetSurfaceChange = afterTarget - beforeTarget; - - return new int[] { sourceSurfaceChange, targetSurfaceChange }; + + return new int[] {sourceSurfaceChange, targetSurfaceChange}; } } diff --git a/src/arcade/potts/sim/hamiltonian/SurfaceHamiltonianConfig.java b/src/arcade/potts/sim/hamiltonian/SurfaceHamiltonianConfig.java index db1337aa1..4351b1db2 100644 --- a/src/arcade/potts/sim/hamiltonian/SurfaceHamiltonianConfig.java +++ b/src/arcade/potts/sim/hamiltonian/SurfaceHamiltonianConfig.java @@ -4,35 +4,32 @@ import arcade.potts.agent.cell.PottsCell; import static arcade.potts.util.PottsEnums.Region; -/** - * Configuration for {@link SurfaceHamiltonian} parameters. - */ - +/** Configuration for {@link SurfaceHamiltonian} parameters. */ class SurfaceHamiltonianConfig { /** Associated {@link PottsCell} instance. */ final PottsCell cell; - + /** Lambda multiplier for cell. */ private final double lambda; - + /** Lambda multipliers for cell by region. */ private final EnumMap lambdasRegion; - + /** {@code true} if the cell has regions, {@code false} otherwise. */ final boolean hasRegions; - + /** * Creates parameter configuration for {@code SurfaceHamiltonian}. * - * @param cell the associated cell instance - * @param lambda the lambda multiplier - * @param lambdasRegion the map of lambda multiplier for regions + * @param cell the associated cell instance + * @param lambda the lambda multiplier + * @param lambdasRegion the map of lambda multiplier for regions */ SurfaceHamiltonianConfig(PottsCell cell, double lambda, EnumMap lambdasRegion) { this.cell = cell; this.lambda = lambda; this.hasRegions = (lambdasRegion != null) && (lambdasRegion.keySet().size() > 0); - + if (hasRegions) { this.lambdasRegion = new EnumMap<>(Region.class); for (Region region : lambdasRegion.keySet()) { @@ -42,19 +39,21 @@ class SurfaceHamiltonianConfig { this.lambdasRegion = null; } } - + /** * Gets the lambda value. * - * @return the lambda value + * @return the lambda value */ - public double getLambda() { return lambda; } - + public double getLambda() { + return lambda; + } + /** * Gets the lambda value for the region. * - * @param region the region - * @return the lambda value + * @param region the region + * @return the lambda value */ public double getLambda(Region region) { return (hasRegions && lambdasRegion.containsKey(region) diff --git a/src/arcade/potts/sim/hamiltonian/VolumeHamiltonian.java b/src/arcade/potts/sim/hamiltonian/VolumeHamiltonian.java index 4a2b8e1e6..af546248e 100644 --- a/src/arcade/potts/sim/hamiltonian/VolumeHamiltonian.java +++ b/src/arcade/potts/sim/hamiltonian/VolumeHamiltonian.java @@ -10,24 +10,21 @@ import static arcade.potts.sim.PottsSeries.TARGET_SEPARATOR; import static arcade.potts.util.PottsEnums.Region; -/** - * Implementation of {@link Hamiltonian} for volume energy. - */ - +/** Implementation of {@link Hamiltonian} for volume energy. */ public class VolumeHamiltonian implements Hamiltonian { /** Map of hamiltonian config objects. */ final HashMap configs; - + /** Map of population to lambda values. */ final HashMap popToLambda; - + /** Map of population to lambda values for regions. */ final HashMap> popToLambdasRegion; - + /** * Creates the volume energy term for the {@code Potts} Hamiltonian. * - * @param series the associated Series instance + * @param series the associated Series instance */ public VolumeHamiltonian(PottsSeries series) { configs = new HashMap<>(); @@ -35,7 +32,7 @@ public VolumeHamiltonian(PottsSeries series) { popToLambdasRegion = new HashMap<>(); initialize(series); } - + @Override public void register(PottsCell cell) { int pop = cell.getPop(); @@ -44,19 +41,18 @@ public void register(PottsCell cell) { VolumeHamiltonianConfig config = new VolumeHamiltonianConfig(cell, lambda, lambdasRegion); configs.put(cell.getID(), config); } - + @Override public void deregister(PottsCell cell) { configs.remove(cell.getID()); } - + /** * {@inheritDoc} - *

- * Volume energy is calculated by taking the difference in target and - * proposed volume for the given ID. Change in volume energy is taken as the - * difference in differences of volume energies for the source and target - * IDs when a voxel is removed or added. + * + *

Volume energy is calculated by taking the difference in target and proposed volume for the + * given ID. Change in volume energy is taken as the difference in differences of volume + * energies for the source and target IDs when a voxel is removed or added. */ @Override public double getDelta(int sourceID, int targetID, int x, int y, int z) { @@ -64,14 +60,13 @@ public double getDelta(int sourceID, int targetID, int x, int y, int z) { double target = getVolume(targetID, 1) - getVolume(targetID, 0); return target + source; } - + /** * {@inheritDoc} - *

- * Volume energy is calculated by taking the difference in target and - * proposed volume for the given region. Change in volume energy is taken as - * the difference in differences of volume energies for the source and - * target regions when a voxel is removed or added. + * + *

Volume energy is calculated by taking the difference in target and proposed volume for the + * given region. Change in volume energy is taken as the difference in differences of volume + * energies for the source and target regions when a voxel is removed or added. */ @Override public double getDelta(int id, int sourceRegion, int targetRegion, int x, int y, int z) { @@ -79,13 +74,13 @@ public double getDelta(int id, int sourceRegion, int targetRegion, int x, int y, double target = getVolume(id, targetRegion, 1) - getVolume(id, targetRegion, 0); return target + source; } - + /** * Gets volume energy for a given change in volume. * - * @param id the voxel id - * @param change the change in volume - * @return the energy + * @param id the voxel id + * @param change the change in volume + * @return the energy */ double getVolume(int id, int change) { if (id == 0) { @@ -97,14 +92,14 @@ public double getDelta(int id, int sourceRegion, int targetRegion, int x, int y, double lambda = config.getLambda(); return lambda * Math.pow((volume - targetVolume + change), 2); } - + /** * Gets volume energy for a given change in volume for region. * - * @param id the voxel id - * @param t the voxel region - * @param change the change in volume - * @return the energy + * @param id the voxel id + * @param t the voxel region + * @param change the change in volume + * @return the energy */ double getVolume(int id, int t, int change) { Region region = Region.values()[t]; @@ -117,38 +112,39 @@ public double getDelta(int id, int sourceRegion, int targetRegion, int x, int y, double lambda = config.getLambda(region); return lambda * Math.pow((volume - targetVolume + change), 2); } - + /** * Initializes parameters for volume hamiltonian term. * - * @param series the series instance + * @param series the series instance */ void initialize(PottsSeries series) { if (series.populations == null) { return; } - + Set keySet = series.populations.keySet(); MiniBox parameters = series.potts; - + for (String key : keySet) { MiniBox population = series.populations.get(key); int pop = population.getInt("CODE"); - + // Get lambda value. double lambda = parameters.getDouble("volume/LAMBDA" + TARGET_SEPARATOR + key); popToLambda.put(pop, lambda); - + MiniBox regionBox = population.filter("(REGION)"); ArrayList regionKeys = new ArrayList<>(); regionBox.getKeys().forEach(s -> regionKeys.add(Region.valueOf(s))); - + // Get lambda values for regions. if (regionKeys.size() > 0) { EnumMap lambdasRegion = new EnumMap<>(Region.class); for (Region region : regionKeys) { - double lambdaRegion = parameters.getDouble("volume/LAMBDA_" - + region.name() + TARGET_SEPARATOR + key); + double lambdaRegion = + parameters.getDouble( + "volume/LAMBDA_" + region.name() + TARGET_SEPARATOR + key); lambdasRegion.put(region, lambdaRegion); } popToLambdasRegion.put(pop, lambdasRegion); diff --git a/src/arcade/potts/sim/hamiltonian/VolumeHamiltonianConfig.java b/src/arcade/potts/sim/hamiltonian/VolumeHamiltonianConfig.java index b0c812935..ce76fd61e 100644 --- a/src/arcade/potts/sim/hamiltonian/VolumeHamiltonianConfig.java +++ b/src/arcade/potts/sim/hamiltonian/VolumeHamiltonianConfig.java @@ -4,35 +4,32 @@ import arcade.potts.agent.cell.PottsCell; import static arcade.potts.util.PottsEnums.Region; -/** - * Configuration for {@link VolumeHamiltonian} parameters. - */ - +/** Configuration for {@link VolumeHamiltonian} parameters. */ class VolumeHamiltonianConfig { /** Associated {@link PottsCell} instance. */ final PottsCell cell; - + /** Lambda multiplier for cell. */ private final double lambda; - + /** Lambda multipliers for cell by region. */ private final EnumMap lambdasRegion; - + /** {@code true} if the cell has regions, {@code false} otherwise. */ final boolean hasRegions; - + /** * Creates parameter configuration for {@code VolumeHamiltonian}. * - * @param cell the associated cell instance - * @param lambda the lambda multiplier - * @param lambdasRegion the map of lambda multiplier for regions + * @param cell the associated cell instance + * @param lambda the lambda multiplier + * @param lambdasRegion the map of lambda multiplier for regions */ VolumeHamiltonianConfig(PottsCell cell, double lambda, EnumMap lambdasRegion) { this.cell = cell; this.lambda = lambda; this.hasRegions = (lambdasRegion != null) && (lambdasRegion.keySet().size() > 0); - + if (hasRegions) { this.lambdasRegion = new EnumMap<>(Region.class); for (Region region : lambdasRegion.keySet()) { @@ -42,19 +39,21 @@ class VolumeHamiltonianConfig { this.lambdasRegion = null; } } - + /** * Gets the lambda value. * - * @return the lambda value + * @return the lambda value */ - public double getLambda() { return lambda; } - + public double getLambda() { + return lambda; + } + /** * Gets the lambda value for the region. * - * @param region the region - * @return the lambda value + * @param region the region + * @return the lambda value */ public double getLambda(Region region) { return (hasRegions && lambdasRegion.containsKey(region) diff --git a/src/arcade/potts/sim/input/PottsInputBuilder.java b/src/arcade/potts/sim/input/PottsInputBuilder.java index 7f80c6fbc..bb954fb6c 100644 --- a/src/arcade/potts/sim/input/PottsInputBuilder.java +++ b/src/arcade/potts/sim/input/PottsInputBuilder.java @@ -10,40 +10,35 @@ import static arcade.core.util.MiniBox.TAG_SEPARATOR; import static arcade.potts.sim.PottsSeries.TARGET_SEPARATOR; -/** - * Custom builder for potts-specific simulation setup XMLs. - */ - +/** Custom builder for potts-specific simulation setup XMLs. */ public final class PottsInputBuilder extends InputBuilder { + /** Creates a {@code PottsInputBuilder} instance. */ + public PottsInputBuilder() { + super(); + } + /** - * Creates a {@code PottsInputBuilder} instance. - */ - public PottsInputBuilder() { super(); } - - /** - * Updates a {@link arcade.core.util.Box} dictionary with tagged - * attributes. - *

- * Attributes are added to the last entry in the list of dictionaries. One - * of the attributes must be "id" which is used as the id for the entry. - * Attributes "tag" and "target" are concatenated to the id as - * tag/id:target. + * Updates a {@link arcade.core.util.Box} dictionary with tagged attributes. + * + *

Attributes are added to the last entry in the list of dictionaries. One of the attributes + * must be "id" which is used as the id for the entry. Attributes "tag" and "target" are + * concatenated to the id as tag/id:target. * - * @param list the list the box is in - * @param tag the entry tag - * @param atts the attributes to add + * @param list the list the box is in + * @param tag the entry tag + * @param atts the attributes to add */ void updateBox(String list, String tag, Attributes atts) { String listName = list + (list.equals("potts") ? "" : "s"); ArrayList lists = setupLists.get(listName); Box box = lists.get(lists.size() - 1); - + int numAtts = atts.getLength(); String id; String module; String target; String term; - + if (numAtts > 0) { // Entry can have at most one of the following tags: module, term. boolean hasModule = atts.getValue("module") != null; @@ -51,22 +46,25 @@ void updateBox(String list, String tag, Attributes atts) { if (hasModule & hasTerm) { return; } - + // Get any tags (module or term) or target. - term = (atts.getValue("term") == null - ? "" - : atts.getValue("term").toLowerCase() + TAG_SEPARATOR); - module = (atts.getValue("module") == null - ? "" - : atts.getValue("module").toLowerCase() + TAG_SEPARATOR); - target = (atts.getValue("target") == null - ? "" - : TARGET_SEPARATOR + atts.getValue("target")); - + term = + (atts.getValue("term") == null + ? "" + : atts.getValue("term").toLowerCase() + TAG_SEPARATOR); + module = + (atts.getValue("module") == null + ? "" + : atts.getValue("module").toLowerCase() + TAG_SEPARATOR); + target = + (atts.getValue("target") == null + ? "" + : TARGET_SEPARATOR + atts.getValue("target")); + // Create id by combining tags, id, and target. id = module + term + atts.getValue("id") + target; box.addTag(id, tag.toUpperCase()); - + for (int i = 0; i < numAtts; i++) { String name = atts.getQName(i); switch (name) { @@ -81,11 +79,11 @@ void updateBox(String list, String tag, Attributes atts) { } } } - + @Override public void startElement(String uri, String local, String name, Attributes atts) { LOGGER.fine("start element [ " + name + " ]"); - + switch (name) { case "set": case "series": @@ -106,17 +104,17 @@ public void startElement(String uri, String local, String name, Attributes atts) default: break; } - + String[] split = name.split("\\."); if (split.length == 2) { updateBox(split[0], split[1], atts); } } - + @Override public void endElement(String uri, String local, String name) { LOGGER.fine("end element [ " + name + " ]"); - + if ("series".equals(name)) { series.add(new PottsSeries(setupDicts, setupLists, path, parameters, isVis)); MiniBox set = setupDicts.get("set"); diff --git a/src/arcade/potts/sim/output/PottsOutputDeserializer.java b/src/arcade/potts/sim/output/PottsOutputDeserializer.java index 35585b6a4..f58c146cc 100644 --- a/src/arcade/potts/sim/output/PottsOutputDeserializer.java +++ b/src/arcade/potts/sim/output/PottsOutputDeserializer.java @@ -23,153 +23,163 @@ /** * Container class for potts-specific object deserializers. - *

- * Deserializers include: + * + *

Deserializers include: + * *

    - *
  • {@link PottsCellDeserializer} for deserializing {@link PottsCellContainer}
  • - *
  • {@link PottsLocationDeserializer} for deserializing {@link PottsLocationContainer}
  • - *
  • {@link VoxelDeserializer} for deserializing {@link Voxel}
  • + *
  • {@link PottsCellDeserializer} for deserializing {@link PottsCellContainer} + *
  • {@link PottsLocationDeserializer} for deserializing {@link PottsLocationContainer} + *
  • {@link VoxelDeserializer} for deserializing {@link Voxel} *
*/ - public final class PottsOutputDeserializer { - /** - * Hidden utility class constructor. - */ + /** Hidden utility class constructor. */ protected PottsOutputDeserializer() { throw new UnsupportedOperationException(); } - + /** * Creates a {@code Gson} with generic and implementation-specific adaptors. * - * @return a {@code Gson} instance + * @return a {@code Gson} instance */ static Gson makeGSON() { GsonBuilder gsonBuilder = OutputDeserializer.makeGSONBuilder(); - gsonBuilder.registerTypeAdapter(CellContainer.class, - new PottsCellDeserializer()); - gsonBuilder.registerTypeAdapter(PottsCellContainer.class, - new PottsCellDeserializer()); - gsonBuilder.registerTypeAdapter(LocationContainer.class, - new PottsLocationDeserializer()); - gsonBuilder.registerTypeAdapter(PottsLocationContainer.class, - new PottsLocationDeserializer()); - gsonBuilder.registerTypeAdapter(Voxel.class, - new VoxelDeserializer()); + gsonBuilder.registerTypeAdapter(CellContainer.class, new PottsCellDeserializer()); + gsonBuilder.registerTypeAdapter(PottsCellContainer.class, new PottsCellDeserializer()); + gsonBuilder.registerTypeAdapter(LocationContainer.class, new PottsLocationDeserializer()); + gsonBuilder.registerTypeAdapter( + PottsLocationContainer.class, new PottsLocationDeserializer()); + gsonBuilder.registerTypeAdapter(Voxel.class, new VoxelDeserializer()); return gsonBuilder.create(); } - - /** - * Deserializer for {@link PottsCellContainer} objects. - */ + + /** Deserializer for {@link PottsCellContainer} objects. */ static class PottsCellDeserializer implements JsonDeserializer { @Override - public PottsCellContainer deserialize(JsonElement json, Type typeOfT, - JsonDeserializationContext context) + public PottsCellContainer deserialize( + JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { JsonObject jsonObject = json.getAsJsonObject(); - + int id = jsonObject.get("id").getAsInt(); int parent = jsonObject.get("parent").getAsInt(); int pop = jsonObject.get("pop").getAsInt(); int age = jsonObject.get("age").getAsInt(); int divisions = jsonObject.get("divisions").getAsInt(); int voxels = jsonObject.get("voxels").getAsInt(); - + State state = State.valueOf(jsonObject.get("state").getAsString()); Phase phase = Phase.valueOf(jsonObject.get("phase").getAsString()); - + JsonArray criticals = jsonObject.get("criticals").getAsJsonArray(); double criticalVolume = criticals.get(0).getAsDouble(); double criticalHeight = criticals.get(1).getAsDouble(); - + EnumMap regions = new EnumMap<>(Region.class); EnumMap criticalRegionVolumes = new EnumMap<>(Region.class); EnumMap criticalRegionHeights = new EnumMap<>(Region.class); - + if (jsonObject.has("regions")) { JsonArray jsonArray = jsonObject.getAsJsonArray("regions"); for (JsonElement object : jsonArray) { JsonObject regionObject = object.getAsJsonObject(); Region region = Region.valueOf(regionObject.get("region").getAsString()); int regionVoxels = regionObject.get("voxels").getAsInt(); - + JsonArray regionCriticals = regionObject.get("criticals").getAsJsonArray(); criticalRegionVolumes.put(region, regionCriticals.get(0).getAsDouble()); criticalRegionHeights.put(region, regionCriticals.get(1).getAsDouble()); - + regions.put(region, regionVoxels); } } - + PottsCellContainer cell; if (regions.size() == 0) { - cell = new PottsCellContainer(id, parent, pop, age, divisions, state, phase, - voxels, criticalVolume, criticalHeight); + cell = + new PottsCellContainer( + id, + parent, + pop, + age, + divisions, + state, + phase, + voxels, + criticalVolume, + criticalHeight); } else { - cell = new PottsCellContainer(id, parent, pop, age, divisions, state, phase, - voxels, regions, criticalVolume, criticalHeight, - criticalRegionVolumes, criticalRegionHeights); + cell = + new PottsCellContainer( + id, + parent, + pop, + age, + divisions, + state, + phase, + voxels, + regions, + criticalVolume, + criticalHeight, + criticalRegionVolumes, + criticalRegionHeights); } - + return cell; } } - - /** - * Deserializer for {@link PottsLocationContainer} objects. - */ + + /** Deserializer for {@link PottsLocationContainer} objects. */ static class PottsLocationDeserializer implements JsonDeserializer { @Override - public PottsLocationContainer deserialize(JsonElement json, Type typeOfT, - JsonDeserializationContext context) + public PottsLocationContainer deserialize( + JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { JsonObject jsonObject = json.getAsJsonObject(); - + // Parse out id and center voxel. int id = jsonObject.get("id").getAsInt(); Voxel center = context.deserialize(jsonObject.get("center"), Voxel.class); - + // Set up list of all voxels and map for region voxels. ArrayList allVoxels = new ArrayList<>(); EnumMap> regions = new EnumMap<>(Region.class); - + // Parse lists of voxels. JsonArray jsonArray = jsonObject.getAsJsonArray("location"); for (JsonElement object : jsonArray) { JsonObject regionObject = object.getAsJsonObject(); Region region = Region.valueOf(regionObject.get("region").getAsString()); JsonArray voxelArray = regionObject.get("voxels").getAsJsonArray(); - + ArrayList voxels = new ArrayList<>(); for (JsonElement element : voxelArray) { Voxel voxel = context.deserialize(element, Voxel.class); voxels.add(voxel); allVoxels.add(voxel); } - + regions.put(region, voxels); } - + PottsLocationContainer location; if (jsonArray.size() == 1) { location = new PottsLocationContainer(id, center, allVoxels); } else { location = new PottsLocationContainer(id, center, allVoxels, regions); } - + return location; } } - - /** - * Deserializer for {@link Voxel} objects. - */ + + /** Deserializer for {@link Voxel} objects. */ static class VoxelDeserializer implements JsonDeserializer { @Override - public Voxel deserialize(JsonElement json, Type typeOfT, - JsonDeserializationContext context) throws JsonParseException { + public Voxel deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { JsonArray jsonArray = json.getAsJsonArray(); int x = jsonArray.get(0).getAsInt(); int y = jsonArray.get(1).getAsInt(); diff --git a/src/arcade/potts/sim/output/PottsOutputLoader.java b/src/arcade/potts/sim/output/PottsOutputLoader.java index cb5d17d5c..8d564f016 100644 --- a/src/arcade/potts/sim/output/PottsOutputLoader.java +++ b/src/arcade/potts/sim/output/PottsOutputLoader.java @@ -4,18 +4,19 @@ import arcade.core.sim.Series; import arcade.core.sim.output.OutputLoader; -/** - * Custom loader for potts-specific deserialization. - */ - +/** Custom loader for potts-specific deserialization. */ public final class PottsOutputLoader extends OutputLoader { /** * Creates a {@code PottsOutputLoader} for the series. * - * @param series the simulation series + * @param series the simulation series */ - public PottsOutputLoader(Series series) { super(series); } - + public PottsOutputLoader(Series series) { + super(series); + } + @Override - protected Gson makeGSON() { return PottsOutputDeserializer.makeGSON(); } + protected Gson makeGSON() { + return PottsOutputDeserializer.makeGSON(); + } } diff --git a/src/arcade/potts/sim/output/PottsOutputSaver.java b/src/arcade/potts/sim/output/PottsOutputSaver.java index 74f34897d..16c267699 100644 --- a/src/arcade/potts/sim/output/PottsOutputSaver.java +++ b/src/arcade/potts/sim/output/PottsOutputSaver.java @@ -4,18 +4,19 @@ import arcade.core.sim.Series; import arcade.core.sim.output.OutputSaver; -/** - * Custom saver for potts-specific serialization. - */ - +/** Custom saver for potts-specific serialization. */ public final class PottsOutputSaver extends OutputSaver { /** * Creates a {@code PottsOutputSaver} for the series. * - * @param series the simulation series + * @param series the simulation series */ - public PottsOutputSaver(Series series) { super(series); } - + public PottsOutputSaver(Series series) { + super(series); + } + @Override - protected Gson makeGSON() { return PottsOutputSerializer.makeGSON(); } + protected Gson makeGSON() { + return PottsOutputSerializer.makeGSON(); + } } diff --git a/src/arcade/potts/sim/output/PottsOutputSerializer.java b/src/arcade/potts/sim/output/PottsOutputSerializer.java index 12b5fd97c..e8eaacb9b 100644 --- a/src/arcade/potts/sim/output/PottsOutputSerializer.java +++ b/src/arcade/potts/sim/output/PottsOutputSerializer.java @@ -23,51 +23,45 @@ /** * Container class for potts-specific object serializers. - *

- * Generic serializers include: + * + *

Generic serializers include: + * *

    - *
  • {@link PottsSeriesSerializer} for serializing {@link PottsSeries}
  • - *
  • {@link PottsCellSerializer} for serializing {@link PottsCellContainer}
  • - *
  • {@link PottsLocationSerializer} for serializing {@link PottsLocationContainer}
  • - *
  • {@link VoxelSerializer} for serializing {@link Voxel}
  • + *
  • {@link PottsSeriesSerializer} for serializing {@link PottsSeries} + *
  • {@link PottsCellSerializer} for serializing {@link PottsCellContainer} + *
  • {@link PottsLocationSerializer} for serializing {@link PottsLocationContainer} + *
  • {@link VoxelSerializer} for serializing {@link Voxel} *
*/ - public final class PottsOutputSerializer { - /** - * Hidden utility class constructor. - */ + /** Hidden utility class constructor. */ protected PottsOutputSerializer() { throw new UnsupportedOperationException(); } - + /** * Creates a {@code Gson} with generic and implementation-specific adaptors. * - * @return a {@code Gson} instance + * @return a {@code Gson} instance */ static Gson makeGSON() { GsonBuilder gsonBuilder = OutputSerializer.makeGSONBuilder(); - gsonBuilder.registerTypeAdapter(PottsSeries.class, - new PottsSeriesSerializer()); - gsonBuilder.registerTypeAdapter(CellContainer.class, - new CellSerializer()); - gsonBuilder.registerTypeAdapter(PottsCellContainer.class, - new PottsCellSerializer()); - gsonBuilder.registerTypeAdapter(LocationContainer.class, - new LocationSerializer()); - gsonBuilder.registerTypeAdapter(PottsLocationContainer.class, - new PottsLocationSerializer()); - gsonBuilder.registerTypeAdapter(Voxel.class, - new VoxelSerializer()); + gsonBuilder.registerTypeAdapter(PottsSeries.class, new PottsSeriesSerializer()); + gsonBuilder.registerTypeAdapter(CellContainer.class, new CellSerializer()); + gsonBuilder.registerTypeAdapter(PottsCellContainer.class, new PottsCellSerializer()); + gsonBuilder.registerTypeAdapter(LocationContainer.class, new LocationSerializer()); + gsonBuilder.registerTypeAdapter( + PottsLocationContainer.class, new PottsLocationSerializer()); + gsonBuilder.registerTypeAdapter(Voxel.class, new VoxelSerializer()); return gsonBuilder.create(); } - + /** * Serializer for {@link PottsSeries} objects. - *

- * The object is first serialized using the generic {@link Series} and - * potts-specific contents are then appended: + * + *

The object is first serialized using the generic {@link Series} and potts-specific + * contents are then appended: + * *

      *     ...
      *     "potts": {
@@ -80,36 +74,36 @@ static Gson makeGSON() {
      */
     static class PottsSeriesSerializer implements JsonSerializer {
         @Override
-        public JsonElement serialize(PottsSeries src, Type typeOfSrc,
-                                     JsonSerializationContext context) {
+        public JsonElement serialize(
+                PottsSeries src, Type typeOfSrc, JsonSerializationContext context) {
             JsonObject json = (JsonObject) context.serialize(src, Series.class);
-            
+
             // Add potts parameters.
             JsonElement potts = context.serialize(src.potts);
             json.add("potts", potts);
-            
+
             return json;
         }
     }
-    
+
     /**
      * Serializer for {@link CellContainer} objects.
-     * 

- * Uses serialization for {@link PottsCellContainer}. - *

+ * + *

Uses serialization for {@link PottsCellContainer}. */ static class CellSerializer implements JsonSerializer { @Override - public JsonElement serialize(CellContainer src, Type typeOfSrc, - JsonSerializationContext context) { + public JsonElement serialize( + CellContainer src, Type typeOfSrc, JsonSerializationContext context) { return context.serialize(src, PottsCellContainer.class); } } - + /** * Serializer for {@link PottsCellContainer} objects. - *

- * The container object is formatted as: + * + *

The container object is formatted as: + * *

      *     {
      *         "id": (id),
@@ -131,15 +125,15 @@ public JsonElement serialize(CellContainer src, Type typeOfSrc,
      *         ]
      *     }
      * 
- *

- * If there are no regions, the regions array is not included. + * + *

If there are no regions, the regions array is not included. */ static class PottsCellSerializer implements JsonSerializer { @Override - public JsonElement serialize(PottsCellContainer src, Type typeOfSrc, - JsonSerializationContext context) { + public JsonElement serialize( + PottsCellContainer src, Type typeOfSrc, JsonSerializationContext context) { JsonObject json = new JsonObject(); - + json.addProperty("id", src.id); json.addProperty("parent", src.parent); json.addProperty("pop", src.pop); @@ -148,54 +142,54 @@ public JsonElement serialize(PottsCellContainer src, Type typeOfSrc, json.addProperty("state", ((State) src.state).name()); json.addProperty("phase", src.phase.name()); json.addProperty("voxels", src.voxels); - + JsonArray criticals = new JsonArray(); criticals.add((int) (100 * src.criticalVolume) / 100.0); criticals.add((int) (100 * src.criticalHeight) / 100.0); json.add("criticals", criticals); - + if (src.regionVoxels != null) { JsonArray regions = new JsonArray(); for (Region region : src.regionVoxels.keySet()) { JsonObject regionObject = new JsonObject(); regionObject.addProperty("region", region.name()); regionObject.addProperty("voxels", src.regionVoxels.get(region)); - + JsonArray regionCriticals = new JsonArray(); double volume = (int) (100 * src.criticalRegionVolumes.get(region)) / 100.0; double height = (int) (100 * src.criticalRegionHeights.get(region)) / 100.0; regionCriticals.add(volume); regionCriticals.add(height); regionObject.add("criticals", regionCriticals); - + regions.add(regionObject); } - + json.add("regions", regions); } - + return json; } } - + /** * Serializer for {@link LocationContainer} objects. - *

- * Uses serialization for {@link PottsLocationContainer}. - *

+ * + *

Uses serialization for {@link PottsLocationContainer}. */ static class LocationSerializer implements JsonSerializer { @Override - public JsonElement serialize(LocationContainer src, Type typeOfSrc, - JsonSerializationContext context) { + public JsonElement serialize( + LocationContainer src, Type typeOfSrc, JsonSerializationContext context) { return context.serialize(src, PottsLocationContainer.class); } } - + /** * Serializer for {@link PottsLocationContainer} objects. - *

- * The container object is formatted as: + * + *

The container object is formatted as: + * *

      *     {
      *         "id": (id),
@@ -213,67 +207,67 @@ public JsonElement serialize(LocationContainer src, Type typeOfSrc,
      *         ]
      *     }
      * 
- *

- * If there are no regions, all voxels are listed as one region with the - * "UNDEFINED" region name. + * + *

If there are no regions, all voxels are listed as one region with the "UNDEFINED" region + * name. */ static class PottsLocationSerializer implements JsonSerializer { @Override - public JsonElement serialize(PottsLocationContainer src, Type typeOfSrc, - JsonSerializationContext context) { + public JsonElement serialize( + PottsLocationContainer src, Type typeOfSrc, JsonSerializationContext context) { JsonObject json = new JsonObject(); - + json.addProperty("id", src.id); json.add("center", context.serialize(src.center)); - + JsonArray location = new JsonArray(); - + if (src.regions == null) { JsonObject obj = new JsonObject(); JsonArray array = new JsonArray(); - + ArrayList voxels = src.allVoxels; voxels.sort(VOXEL_COMPARATOR); voxels.forEach(voxel -> array.add(context.serialize(voxel))); - + obj.addProperty("region", Region.UNDEFINED.name()); obj.add("voxels", array); - + location.add(obj); } else { for (Region region : src.regions.keySet()) { JsonObject obj = new JsonObject(); JsonArray array = new JsonArray(); - + ArrayList voxels = src.regions.get(region); voxels.sort(VOXEL_COMPARATOR); voxels.forEach(voxel -> array.add(context.serialize(voxel))); - + obj.addProperty("region", region.name()); obj.add("voxels", array); - + location.add(obj); } } - + json.add("location", location); - + return json; } } - + /** * Serializer for {@link Voxel} objects. - *

- * The voxel object is formatted as: + * + *

The voxel object is formatted as: + * *

      *     [(x), (y), (z)]
      * 
*/ static class VoxelSerializer implements JsonSerializer { @Override - public JsonElement serialize(Voxel src, Type typeOfSrc, - JsonSerializationContext context) { + public JsonElement serialize(Voxel src, Type typeOfSrc, JsonSerializationContext context) { JsonArray json = new JsonArray(); json.add(src.x); json.add(src.y); diff --git a/src/arcade/potts/util/PottsEnums.java b/src/arcade/potts/util/PottsEnums.java index ca441cae5..6c0fe90cc 100644 --- a/src/arcade/potts/util/PottsEnums.java +++ b/src/arcade/potts/util/PottsEnums.java @@ -1,211 +1,222 @@ package arcade.potts.util; +import sim.util.Double3D; import ec.util.MersenneTwisterFast; import arcade.core.agent.cell.CellState; import arcade.core.agent.process.ProcessDomain; /** * Container class for potts-specific enums. - *

- * Implemented enums include: + * + *

Implemented enums include: + * *

    - *
  • {@code Ordering} defining simulation stepping order
  • - *
  • {@code State} defining cell states
  • - *
  • {@code Domain} defining domain for a given process
  • - *
  • {@code Region} defining subcellular regions
  • - *
  • {@code Term} defining different potts energy terms
  • - *
  • {@code Phase} defining phase for a given state
  • - *
  • {@code Direction} defining directions in the voxel environment
  • + *
  • {@code Ordering} defining simulation stepping order + *
  • {@code State} defining cell states + *
  • {@code Domain} defining domain for a given process + *
  • {@code Region} defining subcellular regions + *
  • {@code Term} defining different potts energy terms + *
  • {@code Phase} defining phase for a given state + *
  • {@code Direction} defining directions in the voxel environment *
*/ - public final class PottsEnums { - /** - * Hidden utility class constructor. - */ + /** Hidden utility class constructor. */ protected PottsEnums() { throw new UnsupportedOperationException(); } - + /** Stepping order for potts simulations. */ public enum Ordering { /** Stepping order for potts. */ POTTS, - + /** Stepping order for cells. */ CELLS } - + /** Cell state codes for potts simulations. */ public enum State implements CellState { /** Code for undefined state. */ UNDEFINED, - + /** Code for quiescent cells. */ QUIESCENT, - + /** Code for proliferative cells. */ PROLIFERATIVE, - + /** Code for apoptotic cells. */ APOPTOTIC, - + /** Code for necrotic cells. */ NECROTIC, - + /** Code for autotic cells. */ AUTOTIC; - + /** * Randomly selects a {@code State}. * - * @param rng the random number generator - * @return a random {@code State} + * @param rng the random number generator + * @return a random {@code State} */ public static State random(MersenneTwisterFast rng) { return values()[rng.nextInt(values().length - 1) + 1]; } } - + /** Process domain codes for potts simulations. */ public enum Domain implements ProcessDomain { /** Code for undefined domain. */ UNDEFINED } - + /** Cell region codes for potts simulations. */ public enum Region { /** Undefined region. */ UNDEFINED, - + /** Region for cytoplasm. */ DEFAULT, - + /** Region for nucleus. */ NUCLEUS; - + /** * Randomly selects a {@code Region}. * - * @param rng the random number generator - * @return a random {@code Region} + * @param rng the random number generator + * @return a random {@code Region} */ public static Region random(MersenneTwisterFast rng) { return values()[rng.nextInt(values().length - 1) + 1]; } } - + /** Potts energy terms for potts simulations. */ public enum Term { /** Code for undefined term. */ UNDEFINED, - + /** Code for adhesion term. */ ADHESION, - + /** Code for volume term. */ VOLUME, - + /** Code for surface term. */ SURFACE, - + /** Code for height term. */ HEIGHT, - + /** Code for junction term. */ JUNCTION, - + /** Code for substrate term. */ SUBSTRATE, - + /** Code for persistence term. */ PERSISTENCE; - + /** * Randomly selects a {@code Term}. * - * @param rng the random number generator - * @return a random {@code Term} + * @param rng the random number generator + * @return a random {@code Term} */ public static Term random(MersenneTwisterFast rng) { return values()[rng.nextInt(values().length - 1) + 1]; } } - + /** Module phase codes for potts simulations. */ public enum Phase { /** Code for undefined phase. */ UNDEFINED, - + /** Code for proliferative G1 phase. */ PROLIFERATIVE_G1, - + /** Code for proliferative S phase. */ PROLIFERATIVE_S, - + /** Code for proliferative G2 phase. */ PROLIFERATIVE_G2, - + /** Code for proliferative M phase. */ PROLIFERATIVE_M, - + /** Code for early apoptosis phase. */ APOPTOTIC_EARLY, - + /** Code for late apoptosis phase. */ APOPTOTIC_LATE, - + /** Code for apoptosed cell. */ APOPTOSED; - + /** * Randomly selects a {@code Phase}. * - * @param rng the random number generator - * @return a random {@code Phase} + * @param rng the random number generator + * @return a random {@code Phase} */ public static Phase random(MersenneTwisterFast rng) { return values()[rng.nextInt(values().length - 1) + 1]; } } - + /** Location split directions for potts simulations. */ public enum Direction { /** Unspecified direction. */ - UNDEFINED, - + UNDEFINED(null), + /** Direction along the yz plane (y = 0, z = 0). */ - YZ_PLANE, - + YZ_PLANE(new Double3D(1, 0, 0)), + /** Direction along the zx plane (z = 0, x = 0). */ - ZX_PLANE, - + ZX_PLANE(new Double3D(0, 1, 0)), + /** Direction along the xy plane (x = 0, y = 0). */ - XY_PLANE, - + XY_PLANE(new Double3D(0, 0, 1)), + /** Direction along the positive xy axis (x = y, z = 0). */ - POSITIVE_XY, - + POSITIVE_XY(new Double3D(-1, 1, 0)), + /** Direction along the negative xy axis (x = -y, z = 0). */ - NEGATIVE_XY, - + NEGATIVE_XY(new Double3D(-1, -1, 0)), + /** Direction along the positive yz axis (y = z, x = 0). */ - POSITIVE_YZ, - + POSITIVE_YZ(new Double3D(0, -1, 1)), + /** Direction along the negative yz axis (y = -z, x = 0). */ - NEGATIVE_YZ, - + NEGATIVE_YZ(new Double3D(0, -1, -1)), + /** Direction along the positive zx axis (z = x, y = 0). */ - POSITIVE_ZX, - + POSITIVE_ZX(new Double3D(1, 0, -1)), + /** Direction along the negative zx axis (z = -x, y = 0). */ - NEGATIVE_ZX; - + NEGATIVE_ZX(new Double3D(-1, 0, -1)); + + /** The normal vector of the plane in this direction. */ + public final Double3D vector; + + /** + * Creates a new {@code Direction} with the given vector. + * + * @param vector the vector associated with this direction + */ + Direction(Double3D vector) { + this.vector = vector; + } + /** - * Randomly selects a {@code Direction}. + * Randomly selects a {@code Direction}, excluding {@code UNDEFINED}. * - * @param rng the random number generator - * @return a random {@code Direction} + * @param rng the random number generator + * @return a random {@code Direction} */ public static Direction random(MersenneTwisterFast rng) { return values()[rng.nextInt(values().length - 1) + 1]; diff --git a/src/arcade/potts/vis/PottsColorMaps.java b/src/arcade/potts/vis/PottsColorMaps.java index e73e9f94c..4cd69dd48 100644 --- a/src/arcade/potts/vis/PottsColorMaps.java +++ b/src/arcade/potts/vis/PottsColorMaps.java @@ -7,137 +7,145 @@ /** * Container class for commonly used color maps. - *

- * Uses {@link arcade.core.util.Colors} to define mappings. + * + *

Uses {@link arcade.core.util.Colors} to define mappings. */ - public class PottsColorMaps { /** Color map for cell state. */ - static final Colors MAP_STATE = new Colors( - new Color[] { - new Color(0, 0, 0), - // new Color(43, 136, 158), - new Color(115, 175, 72), // proliferative : G1 - new Color(82, 161, 76), // proliferative : S - new Color(48, 147, 80), // proliferative : G2 - new Color(15, 133, 84), // proliferative : M - new Color(237, 173, 8), // apoptosis : early - new Color(119, 87, 4), // apoptosis : late - new Color(99, 67, 4), // apoptosis : apoptosed - // new Color(225, 124, 5), - // new Color(204, 80, 62) - }, - new double[] { 0, 1, 2, 3, 4, 5, 6, 7 } - ); - + static final Colors MAP_STATE = + new Colors( + new Color[] { + new Color(0, 0, 0), + // new Color(43, 136, 158), + new Color(115, 175, 72), // proliferative : G1 + new Color(82, 161, 76), // proliferative : S + new Color(48, 147, 80), // proliferative : G2 + new Color(15, 133, 84), // proliferative : M + new Color(237, 173, 8), // apoptosis : early + new Color(119, 87, 4), // apoptosis : late + new Color(99, 67, 4), // apoptosis : apoptosed + // new Color(225, 124, 5), + // new Color(204, 80, 62) + }, + new double[] {0, 1, 2, 3, 4, 5, 6, 7}); + /** Color map for cell populations. */ - static final Colors MAP_POPULATION = new Colors( - new Color[] { - new Color(0, 0, 0), - new Color(95, 70, 144), - new Color(29, 105, 150), - new Color(56, 166, 165), - new Color(15, 133, 84), - new Color(115, 175, 72), - new Color(237, 173, 8), - new Color(225, 124, 5), - new Color(204, 80, 62), - new Color(148, 52, 110), - }, - new double[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 } - ); - + static final Colors MAP_POPULATION = + new Colors( + new Color[] { + new Color(0, 0, 0), + new Color(95, 70, 144), + new Color(29, 105, 150), + new Color(56, 166, 165), + new Color(15, 133, 84), + new Color(115, 175, 72), + new Color(237, 173, 8), + new Color(225, 124, 5), + new Color(204, 80, 62), + new Color(148, 52, 110), + }, + new double[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}); + /** Color map for cell region overlay. */ - public static final Colors MAP_OVERLAY = new Colors(new Color[] { - new Color(255, 255, 255, 0), - new Color(255, 255, 255, 50), - new Color(255, 255, 255, 100), - }, new double[] { 0, 1, 2 }); - + public static final Colors MAP_OVERLAY = + new Colors( + new Color[] { + new Color(255, 255, 255, 0), + new Color(255, 255, 255, 50), + new Color(255, 255, 255, 100), + }, + new double[] {0, 1, 2}); + /** Color map for cell cytoplasm region. */ - public static final Colors MAP_CYTOPLASM = new Colors(new Color[] { - new Color(0, 0, 0, 0), - new Color(255, 0, 255, 50), - new Color(255, 0, 255, 255), - }, new double[] { 0, 0.1, 1 }); - + public static final Colors MAP_CYTOPLASM = + new Colors( + new Color[] { + new Color(0, 0, 0, 0), + new Color(255, 0, 255, 50), + new Color(255, 0, 255, 255), + }, + new double[] {0, 0.1, 1}); + /** Color map for cell nucleus region. */ - public static final Colors MAP_NUCLEUS = new Colors(new Color[] { - new Color(0, 0, 0, 0), - new Color(0, 255, 255, 50), - new Color(0, 255, 255, 255), - }, new double[] { 0, 0.1, 1 }); - + public static final Colors MAP_NUCLEUS = + new Colors( + new Color[] { + new Color(0, 0, 0, 0), + new Color(0, 255, 255, 50), + new Color(0, 255, 255, 255), + }, + new double[] {0, 0.1, 1}); + /** Color map for cell volume. */ final Colors mapVolume; - + /** Color map for cell height. */ final Colors mapHeight; - + /** * Creates {@code ColorMaps} for the given series. * - * @param series the simulation series + * @param series the simulation series */ PottsColorMaps(Series series) { double volume = 0; for (MiniBox box : series.populations.values()) { - if (box.getDouble("CRITICAL_VOLUME_MEAN") > volume) { - volume = box.getDouble("CRITICAL_VOLUME_MEAN"); + if (box.getDouble("CRITICAL_VOLUME") > volume) { + volume = box.getDouble("CRITICAL_VOLUME"); } } - - mapVolume = new Colors( - new Color[] { - new Color(0, 0, 0), - new Color(112, 40, 74), - new Color(156, 63, 93), - new Color(200, 88, 108), - new Color(220, 113, 118), - new Color(238, 138, 130), - new Color(245, 186, 152), - new Color(251, 230, 197), - }, - new double[] { - 0, - 1. / 7 * volume * 2, - 2. / 7 * volume * 2, - 3. / 7 * volume * 2, - 4. / 7 * volume * 2, - 5. / 7 * volume * 2, - 6. / 7 * volume * 2, - 7. / 7 * volume * 2 - } - ); - + + mapVolume = + new Colors( + new Color[] { + new Color(0, 0, 0), + new Color(112, 40, 74), + new Color(156, 63, 93), + new Color(200, 88, 108), + new Color(220, 113, 118), + new Color(238, 138, 130), + new Color(245, 186, 152), + new Color(251, 230, 197), + }, + new double[] { + 0, + 1. / 7 * volume * 2, + 2. / 7 * volume * 2, + 3. / 7 * volume * 2, + 4. / 7 * volume * 2, + 5. / 7 * volume * 2, + 6. / 7 * volume * 2, + 7. / 7 * volume * 2 + }); + double height = 0; for (MiniBox box : series.populations.values()) { - if (box.getDouble("CRITICAL_HEIGHT_MEAN") > height) { - height = box.getDouble("CRITICAL_HEIGHT_MEAN"); + if (box.getDouble("CRITICAL_HEIGHT") > height) { + height = box.getDouble("CRITICAL_HEIGHT"); } } - - mapHeight = new Colors( - new Color[] { - new Color(0, 0, 0), - new Color(251, 230, 197), - new Color(245, 186, 152), - new Color(238, 138, 130), - new Color(220, 113, 118), - new Color(200, 88, 108), - new Color(156, 63, 93), - new Color(112, 40, 74), - }, - new double[] { - 0, - 1. / 7 * height * 4, - 2. / 7 * height * 4, - 3. / 7 * height * 4, - 4. / 7 * height * 4, - 5. / 7 * height * 4, - 6. / 7 * height * 4, - 7. / 7 * height * 4 - } - ); + + mapHeight = + new Colors( + new Color[] { + new Color(0, 0, 0), + new Color(251, 230, 197), + new Color(245, 186, 152), + new Color(238, 138, 130), + new Color(220, 113, 118), + new Color(200, 88, 108), + new Color(156, 63, 93), + new Color(112, 40, 74), + }, + new double[] { + 0, + 1. / 7 * height * 4, + 2. / 7 * height * 4, + 3. / 7 * height * 4, + 4. / 7 * height * 4, + 5. / 7 * height * 4, + 6. / 7 * height * 4, + 7. / 7 * height * 4 + }); } } diff --git a/src/arcade/potts/vis/PottsDrawer.java b/src/arcade/potts/vis/PottsDrawer.java index 0274cb20f..7010e119f 100644 --- a/src/arcade/potts/vis/PottsDrawer.java +++ b/src/arcade/potts/vis/PottsDrawer.java @@ -25,61 +25,76 @@ import arcade.potts.sim.PottsSimulation; import static arcade.potts.util.PottsEnums.Region; -/** - * Container for potts-specific {@link Drawer} classes. - */ - +/** Container for potts-specific {@link Drawer} classes. */ public abstract class PottsDrawer extends Drawer { /** Array holding values. */ DoubleGrid2D array; - + /** Graph holding edges. */ Network graph; - + /** Field holding nodes. */ Continuous2D field; - + /** Planes for visualization. */ - enum Plane { Z, X, Y } - + enum Plane { + Z, + X, + Y + } + /** View options. */ - enum View { CYTOPLASM, NUCLEUS, OVERLAY, STATE, POPULATION, VOLUME, HEIGHT } - + enum View { + CYTOPLASM, + NUCLEUS, + OVERLAY, + STATE, + POPULATION, + VOLUME, + HEIGHT + } + /** * Creates a {@link Drawer} for potts simulations. * - * @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 depth the depth 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 depth the depth of array (z direction) + * @param map the color map for the array + * @param bounds the size of the drawer within the panel */ - PottsDrawer(Panel panel, String name, int length, int width, int depth, - ColorMap map, Rectangle2D.Double bounds) { + PottsDrawer( + Panel panel, + String name, + int length, + int width, + int depth, + ColorMap map, + Rectangle2D.Double bounds) { super(panel, name, length, width, depth, map, bounds); } - + /** * Creates a {@link Drawer} for potts simulations. * - * @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 depth the depth of array (z direction) - * @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 depth the depth of array (z direction) + * @param bounds the size of the drawer within the panel */ - PottsDrawer(Panel panel, String name, int length, int width, int depth, - Rectangle2D.Double bounds) { + PottsDrawer( + Panel panel, String name, int length, int width, int depth, Rectangle2D.Double bounds) { super(panel, name, length, width, depth, null, bounds); } - + @Override public Portrayal makePort() { String[] split = name.split(":"); - + switch (split[0]) { case "grid": graph = new Network(true); @@ -91,7 +106,7 @@ public Portrayal makePort() { return gridPort; case "agents": Plane plane = (split.length == 3 ? Plane.valueOf(split[2]) : Plane.Z); - + switch (plane) { case X: array = new DoubleGrid2D(height, width, map.defaultValue()); @@ -104,7 +119,7 @@ public Portrayal makePort() { array = new DoubleGrid2D(length, width, map.defaultValue()); break; } - + ValueGridPortrayal2D valuePort = new FastValueGridPortrayal2D(); valuePort.setField(array); valuePort.setMap(map); @@ -113,19 +128,17 @@ public Portrayal makePort() { return null; } } - - /** - * Wrapper for MASON class that modifies edge color. - */ + + /** Wrapper for MASON class that modifies edge color. */ private static class SimpleEdgePortrayal2DGridWrapper extends SimpleEdgePortrayal2D { /** Color for edges. */ private final Color color = new Color(0, 0, 0); - - /** - * Creates {@code SimpleEdgePortrayal2D} wrapper with no scaling. - */ - SimpleEdgePortrayal2DGridWrapper() { setScaling(NEVER_SCALE); } - + + /** Creates {@code SimpleEdgePortrayal2D} wrapper with no scaling. */ + SimpleEdgePortrayal2DGridWrapper() { + setScaling(NEVER_SCALE); + } + @Override public void draw(Object object, Graphics2D graphics, DrawInfo2D info) { shape = SHAPE_THIN_LINE; @@ -133,26 +146,26 @@ public void draw(Object object, Graphics2D graphics, DrawInfo2D info) { toPaint = color; super.draw(object, graphics, info); } - + @Override protected double getPositiveWeight(Object object, EdgeDrawInfo2D info) { sim.field.network.Edge edge = (sim.field.network.Edge) object; return (Integer) edge.getInfo(); } } - + /** * Transposes the array for the given plane. * - * @param array the array to transpose - * @param plane the plane - * @return the transposed array + * @param array the array to transpose + * @param plane the plane + * @return the transposed array */ private static int[][][] transpose(int[][][] array, Plane plane) { int height = array.length; int length = array[0].length; int width = array[0][0].length; - + switch (plane) { case X: int[][][] xarr = new int[length][height][width]; @@ -179,19 +192,19 @@ private static int[][][] transpose(int[][][] array, Plane plane) { return array; } } - + /** * Gets slice of a array for the given plane. * - * @param array the array to slice - * @param plane the plane to slice along - * @return a slice of the array + * @param array the array to slice + * @param plane the plane to slice along + * @return a slice of the array */ private static int[][] slice(int[][][] array, Plane plane) { int height = array.length; int length = array[0].length; int width = array[0][0].length; - + switch (plane) { case X: int[][] planeX = new int[height][width]; @@ -214,69 +227,72 @@ private static int[][] slice(int[][][] array, Plane plane) { return array[(height - 1) / 2]; } } - + /** * Adds edges to graph. * - * @param field the field to add nodes to - * @param graph the graph to add edges to - * @param weight the edge weight - * @param x1 the x position of the from node - * @param y1 the y position of the from node - * @param x2 the x position of the to node - * @param y2 the y position of the to node + * @param field the field to add nodes to + * @param graph the graph to add edges to + * @param weight the edge weight + * @param x1 the x position of the from node + * @param y1 the y position of the from node + * @param x2 the x position of the to node + * @param y2 the y position of the to node */ - private static void add(Continuous2D field, Network graph, int weight, - int x1, int y1, int x2, int y2) { + private static void add( + Continuous2D field, Network graph, int weight, int x1, int y1, int x2, int y2) { Double2D a = new Double2D(x1, y1); Double2D b = new Double2D(x2, y2); field.setObjectLocation(a, a); field.setObjectLocation(b, b); graph.addEdge(a, b, weight); } - - /** - * Extension of {@link PottsDrawer} for drawing cells. - */ + + /** Extension of {@link PottsDrawer} for drawing cells. */ public static class PottsCells extends PottsDrawer { /** Drawing view. */ private final View view; - + /** Drawing plane. */ private final Plane plane; - + /** * Creates a {@link PottsDrawer} for drawing cells. * - * @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 depth the depth 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 depth the depth of array (z direction) + * @param map the color map for the array + * @param bounds the size of the drawer within the panel */ - public PottsCells(Panel panel, String name, - int length, int width, int depth, - ColorMap map, Rectangle2D.Double bounds) { + public PottsCells( + Panel panel, + String name, + int length, + int width, + int depth, + ColorMap map, + Rectangle2D.Double bounds) { super(panel, name, length, width, depth, map, bounds); String[] split = name.split(":"); view = View.valueOf(split[1]); plane = (split.length == 3 ? Plane.valueOf(split[2]) : Plane.Z); } - + @Override public void step(SimState simstate) { PottsSimulation sim = (PottsSimulation) simstate; Grid grid = sim.getGrid(); Potts potts = sim.getPotts(); - + double[][] arr = array.field; - + int[][][] ids = transpose(potts.ids, plane); int[][][] regions = transpose(potts.regions, plane); int index = (ids.length - 1) / 2; - + switch (view) { case CYTOPLASM: drawCytoplasm(arr, ids); @@ -296,45 +312,45 @@ public void step(SimState simstate) { break; } } - + /** * Counts the number of non-target values in the 3x3 neighborhood. * - * @param arr the array of values - * @param target the target value - * @param a the position along the first axis - * @param b the position along the second axis - * @return the count of matching neighbors + * @param arr the array of values + * @param target the target value + * @param a the position along the first axis + * @param b the position along the second axis + * @return the count of matching neighbors */ private int count(int[][] arr, int target, int a, int b) { int n = 9; - + for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { n -= (arr[a + i - 1][b + j - 1] == target ? 1 : 0); } } - + return n; } - + /** * Draws voxels along edges of cytoplasm. * - * @param arr the target array - * @param ids the array of ids + * @param arr the target array + * @param ids the array of ids */ private void drawCytoplasm(double[][] arr, int[][][] ids) { double normalize = 0; - + int cc = ids.length; int aa = ids[0].length; int bb = ids[0][0].length; - + for (int a = 1; a < aa - 1; a++) { for (int b = 1; b < bb - 1; b++) { arr[a][b] = 0; - + if (height == 1) { int id = ids[0][a][b]; if (id == 0) { @@ -350,37 +366,37 @@ private void drawCytoplasm(double[][] arr, int[][][] ids) { arr[a][b] += count(ids[c], id, a, b); } } - + normalize = Math.max(normalize, arr[a][b]); } } - + for (int a = 1; a < aa - 1; a++) { for (int b = 1; b < bb - 1; b++) { arr[a][b] /= normalize; } } } - + /** * Draws voxels along edges of nucleus. * - * @param arr the target array - * @param ids the array of ids - * @param regions the array of regions + * @param arr the target array + * @param ids the array of ids + * @param regions the array of regions */ private void drawNucleus(double[][] arr, int[][][] ids, int[][][] regions) { double normalize = 0; int nucleus = Region.NUCLEUS.ordinal(); - + int cc = ids.length; int aa = ids[0].length; int bb = ids[0][0].length; - + for (int a = 1; a < aa - 1; a++) { for (int b = 1; b < bb - 1; b++) { arr[a][b] = 0; - + if (height == 1) { int id = ids[0][a][b]; int region = regions[0][a][b]; @@ -398,56 +414,56 @@ private void drawNucleus(double[][] arr, int[][][] ids, int[][][] regions) { arr[a][b] += count(regions[c], region, a, b); } } - + normalize = Math.max(normalize, arr[a][b]); } } - + for (int a = 1; a < aa - 1; a++) { for (int b = 1; b < bb - 1; b++) { arr[a][b] /= normalize; } } } - + /** * Draws voxels for region overlay. * - * @param arr the target array - * @param regions the array of regions + * @param arr the target array + * @param regions the array of regions */ private void drawOverlay(double[][] arr, int[][] regions) { int aa = arr.length; int bb = arr[0].length; - + for (int a = 1; a < aa - 1; a++) { for (int b = 1; b < bb - 1; b++) { arr[a][b] = (regions[a][b] > 0 ? regions[a][b] - 1 : 0); } } } - + /** * Draws voxels for given slice and view type. * - * @param arr the target array - * @param ids the array of ids - * @param grid the grid for cell objects + * @param arr the target array + * @param ids the array of ids + * @param grid the grid for cell objects */ private void drawSlice(double[][] arr, int[][] ids, Grid grid) { int aa = arr.length; int bb = arr[0].length; - + for (int a = 1; a < aa - 1; a++) { for (int b = 1; b < bb - 1; b++) { arr[a][b] = 0; - + if (ids[a][b] == 0) { continue; } - + Cell cell = (Cell) grid.getObjectAt(ids[a][b]); - + switch (view) { case STATE: int state = ((PottsModule) cell.getModule()).getPhase().ordinal(); @@ -469,30 +485,33 @@ private void drawSlice(double[][] arr, int[][] ids, Grid grid) { } } } - - /** - * Extension of {@link PottsDrawer} for drawing outlines. - */ + + /** Extension of {@link PottsDrawer} for drawing outlines. */ public static class PottsGrid extends PottsDrawer { /** Drawing plane. */ private final Plane plane; - + /** * Creates a {@link PottsDrawer} for drawing outlines. * - * @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 depth the depth of array (z direction) - * @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 depth the depth of array (z direction) + * @param bounds the size of the drawer within the panel */ - PottsGrid(Panel panel, String name, - int length, int width, int depth, Rectangle2D.Double bounds) { + PottsGrid( + Panel panel, + String name, + int length, + int width, + int depth, + Rectangle2D.Double bounds) { super(panel, name, length, width, depth, bounds); String[] split = name.split(":"); plane = (split.length == 2 ? Plane.valueOf(split[1]) : Plane.Z); - + switch (plane) { case X: field.width = depth; @@ -508,18 +527,18 @@ public static class PottsGrid extends PottsDrawer { field.height = width; } } - + @Override public void step(SimState simstate) { PottsSimulation sim = (PottsSimulation) simstate; field.clear(); graph.clear(); - + int[][] arr = slice(sim.getPotts().ids, plane); - + int aa = arr.length; int bb = arr[0].length; - + for (int a = 1; a < aa - 1; a++) { for (int b = 1; b < bb - 1; b++) { if (arr[a][b] != arr[a][b + 1]) { diff --git a/src/arcade/potts/vis/PottsVisualization.java b/src/arcade/potts/vis/PottsVisualization.java index 77f39d471..9b524964a 100644 --- a/src/arcade/potts/vis/PottsVisualization.java +++ b/src/arcade/potts/vis/PottsVisualization.java @@ -6,60 +6,57 @@ import arcade.core.vis.*; import static arcade.potts.vis.PottsColorMaps.*; -/** - * Extension of {@link Visualization} for potts models. - */ - +/** Extension of {@link Visualization} for potts models. */ public final class PottsVisualization extends Visualization { /** Maximum horizontal size of panel. */ static final int MAX_HORIZONTAL = 600; - + /** Maximum vertical size of panel. */ static final int MAX_VERTICAL = 900; - + /** Length of the array (x direction). */ final int length; - + /** Width of the array (y direction). */ final int width; - + /** Height of the array (z direction). */ final int height; - + /** Color maps for the simulation. */ final PottsColorMaps maps; - + /** Horizontal size of the panels. */ final int horizontal; - + /** Vertical size of the panels. */ final int vertical; - + /** * Creates a {@link Visualization} for potts simulations. * - * @param sim the simulation instance + * @param sim the simulation instance */ public PottsVisualization(Simulation sim) { super((SimState) sim); - + // Update sizes. Series series = sim.getSeries(); length = series.length; width = series.width; height = series.height; - + // Get color maps. maps = new PottsColorMaps(series); - + // Calculate sizing of panels. int horz; int vert; - + if (length != width) { horz = MAX_HORIZONTAL; vert = (int) Math.round((width + .0) / length * MAX_HORIZONTAL); - + if (vert > MAX_VERTICAL) { double frac = (MAX_VERTICAL + .0) / vert; horz = (int) Math.round(horz * frac); @@ -69,11 +66,11 @@ public PottsVisualization(Simulation sim) { horz = MAX_HORIZONTAL; vert = MAX_HORIZONTAL; } - + horizontal = horz; vertical = vert; } - + @Override public Drawer[] createDrawers() { if (height == 1) { @@ -82,171 +79,381 @@ public Drawer[] createDrawers() { return create3DDrawers(); } } - + /** * Creates drawers for visualizing 2D simulations. * - * @return a list of {@link Drawer} instances + * @return a list of {@link Drawer} instances */ Drawer[] create2DDrawers() { int h = horizontal / 2; int v = vertical / 2; - + return new Drawer[] { - new PottsDrawer.PottsCells(panels[0], "agents:CYTOPLASM", - length, width, height, MAP_CYTOPLASM, null), - new PottsDrawer.PottsCells(panels[0], "agents:NUCLEUS", - length, width, height, MAP_NUCLEUS, null), - new PottsDrawer.PottsGrid(panels[0], "grid", - length, width, height, null), - - new PottsDrawer.PottsCells(panels[1], "agents:STATE", - length, width, height, MAP_STATE, getBox(0, 0, h, v)), - new PottsDrawer.PottsCells(panels[1], "agents:POPULATION", - length, width, height, MAP_POPULATION, getBox(h, 0, h, v)), - new PottsDrawer.PottsCells(panels[1], "agents:VOLUME", - length, width, height, maps.mapVolume, getBox(0, v, h, v)), - new PottsDrawer.PottsCells(panels[1], "agents:HEIGHT", - length, width, height, maps.mapHeight, getBox(h, v, h, v)), - - new PottsDrawer.PottsCells(panels[1], "agents:OVERLAY", - length, width, height, MAP_OVERLAY, getBox(0, 0, h, v)), - new PottsDrawer.PottsCells(panels[1], "agents:OVERLAY", - length, width, height, MAP_OVERLAY, getBox(h, 0, h, v)), - new PottsDrawer.PottsCells(panels[1], "agents:OVERLAY", - length, width, height, MAP_OVERLAY, getBox(0, v, h, v)), - new PottsDrawer.PottsCells(panels[1], "agents:OVERLAY", - length, width, height, MAP_OVERLAY, getBox(h, v, h, v)), - - new PottsDrawer.PottsGrid(panels[1], "grid", - length, width, height, getBox(0, 0, h, v)), - new PottsDrawer.PottsGrid(panels[1], "grid", - length, width, height, getBox(h, 0, h, v)), - new PottsDrawer.PottsGrid(panels[1], "grid", - length, width, height, getBox(0, v, h, v)), - new PottsDrawer.PottsGrid(panels[1], "grid", - length, width, height, getBox(h, v, h, v)), + new PottsDrawer.PottsCells( + panels[0], "agents:CYTOPLASM", length, width, height, MAP_CYTOPLASM, null), + new PottsDrawer.PottsCells( + panels[0], "agents:NUCLEUS", length, width, height, MAP_NUCLEUS, null), + new PottsDrawer.PottsGrid(panels[0], "grid", length, width, height, null), + new PottsDrawer.PottsCells( + panels[1], + "agents:STATE", + length, + width, + height, + MAP_STATE, + getBox(0, 0, h, v)), + new PottsDrawer.PottsCells( + panels[1], + "agents:POPULATION", + length, + width, + height, + MAP_POPULATION, + getBox(h, 0, h, v)), + new PottsDrawer.PottsCells( + panels[1], + "agents:VOLUME", + length, + width, + height, + maps.mapVolume, + getBox(0, v, h, v)), + new PottsDrawer.PottsCells( + panels[1], + "agents:HEIGHT", + length, + width, + height, + maps.mapHeight, + getBox(h, v, h, v)), + new PottsDrawer.PottsCells( + panels[1], + "agents:OVERLAY", + length, + width, + height, + MAP_OVERLAY, + getBox(0, 0, h, v)), + new PottsDrawer.PottsCells( + panels[1], + "agents:OVERLAY", + length, + width, + height, + MAP_OVERLAY, + getBox(h, 0, h, v)), + new PottsDrawer.PottsCells( + panels[1], + "agents:OVERLAY", + length, + width, + height, + MAP_OVERLAY, + getBox(0, v, h, v)), + new PottsDrawer.PottsCells( + panels[1], + "agents:OVERLAY", + length, + width, + height, + MAP_OVERLAY, + getBox(h, v, h, v)), + new PottsDrawer.PottsGrid(panels[1], "grid", length, width, height, getBox(0, 0, h, v)), + new PottsDrawer.PottsGrid(panels[1], "grid", length, width, height, getBox(h, 0, h, v)), + new PottsDrawer.PottsGrid(panels[1], "grid", length, width, height, getBox(0, v, h, v)), + new PottsDrawer.PottsGrid(panels[1], "grid", length, width, height, getBox(h, v, h, v)), }; } - + /** * Creates drawers for visualizing 3D simulations. * - * @return a list of {@link Drawer} instances + * @return a list of {@link Drawer} instances */ Drawer[] create3DDrawers() { int h = horizontal / 2; int v = vertical / 2; - + int hh = (int) Math.round((length + .0) / (length + height) * h); int vv = (int) Math.round((width + .0) / (width + height) * v); - + int hx = (int) Math.round((height + .0) / (length + height) * h); int vx = (int) Math.round((height + .0) / (width + height) * v); - + return new Drawer[] { - new PottsDrawer.PottsCells(panels[0], "agents:CYTOPLASM:Z", - length, width, height, MAP_CYTOPLASM, getBox(0, 0, hh * 2, vv * 2)), - new PottsDrawer.PottsCells(panels[0], "agents:CYTOPLASM:X", - length, width, height, MAP_CYTOPLASM, getBox(hh * 2, 0, hx * 2, vv * 2)), - new PottsDrawer.PottsCells(panels[0], "agents:CYTOPLASM:Y", - length, width, height, MAP_CYTOPLASM, getBox(0, vv * 2, hh * 2, vx * 2)), - - new PottsDrawer.PottsCells(panels[0], "agents:NUCLEUS:Z", - length, width, height, MAP_NUCLEUS, getBox(0, 0, hh * 2, vv * 2)), - new PottsDrawer.PottsCells(panels[0], "agents:NUCLEUS:X", - length, width, height, MAP_NUCLEUS, getBox(hh * 2, 0, hx * 2, vv * 2)), - new PottsDrawer.PottsCells(panels[0], "agents:NUCLEUS:Y", - length, width, height, MAP_NUCLEUS, getBox(0, vv * 2, hh * 2, vx * 2)), - - new PottsDrawer.PottsCells(panels[1], "agents:STATE:Z", - length, width, height, MAP_STATE, getBox(0, 0, hh, vv)), - new PottsDrawer.PottsCells(panels[1], "agents:POPULATION:Z", - length, width, height, MAP_POPULATION, getBox(h, 0, hh, vv)), - new PottsDrawer.PottsCells(panels[1], "agents:VOLUME:Z", - length, width, height, maps.mapVolume, getBox(0, v, hh, vv)), - new PottsDrawer.PottsCells(panels[1], "agents:HEIGHT:Z", - length, width, height, maps.mapHeight, getBox(h, v, hh, vv)), - - new PottsDrawer.PottsCells(panels[1], "agents:OVERLAY:Z", - length, width, height, MAP_OVERLAY, getBox(0, 0, hh, vv)), - new PottsDrawer.PottsCells(panels[1], "agents:OVERLAY:Z", - length, width, height, MAP_OVERLAY, getBox(h, 0, hh, vv)), - new PottsDrawer.PottsCells(panels[1], "agents:OVERLAY:Z", - length, width, height, MAP_OVERLAY, getBox(0, v, hh, vv)), - new PottsDrawer.PottsCells(panels[1], "agents:OVERLAY:Z", - length, width, height, MAP_OVERLAY, getBox(h, v, hh, vv)), - - new PottsDrawer.PottsGrid(panels[1], "grid:Z", - length, width, height, getBox(0, 0, hh, vv)), - new PottsDrawer.PottsGrid(panels[1], "grid:Z", - length, width, height, getBox(h, 0, hh, vv)), - new PottsDrawer.PottsGrid(panels[1], "grid:Z", - length, width, height, getBox(0, v, hh, vv)), - new PottsDrawer.PottsGrid(panels[1], "grid:Z", - length, width, height, getBox(h, v, hh, vv)), - - new PottsDrawer.PottsCells(panels[1], "agents:STATE:X", - length, width, height, MAP_STATE, getBox(hh, 0, hx, vv)), - new PottsDrawer.PottsCells(panels[1], "agents:POPULATION:X", - length, width, height, MAP_POPULATION, getBox(h + hh, 0, hx, vv)), - new PottsDrawer.PottsCells(panels[1], "agents:VOLUME:X", - length, width, height, maps.mapVolume, getBox(hh, v, hx, vv)), - new PottsDrawer.PottsCells(panels[1], "agents:HEIGHT:X", - length, width, height, maps.mapHeight, getBox(h + hh, v, hx, vv)), - - new PottsDrawer.PottsCells(panels[1], "agents:OVERLAY:X", - length, width, height, MAP_OVERLAY, getBox(hh, 0, hx, vv)), - new PottsDrawer.PottsCells(panels[1], "agents:OVERLAY:X", - length, width, height, MAP_OVERLAY, getBox(h + hh, 0, hx, vv)), - new PottsDrawer.PottsCells(panels[1], "agents:OVERLAY:X", - length, width, height, MAP_OVERLAY, getBox(hh, v, hx, vv)), - new PottsDrawer.PottsCells(panels[1], "agents:OVERLAY:X", - length, width, height, MAP_OVERLAY, getBox(h + hh, v, hx, vv)), - - new PottsDrawer.PottsGrid(panels[1], "grid:X", - length, width, height, getBox(hh, 0, hx, vv)), - new PottsDrawer.PottsGrid(panels[1], "grid:X", - length, width, height, getBox(h + hh, 0, hx, vv)), - new PottsDrawer.PottsGrid(panels[1], "grid:X", - length, width, height, getBox(hh, v, hx, vv)), - new PottsDrawer.PottsGrid(panels[1], "grid:X", - length, width, height, getBox(h + hh, v, hx, vv)), - - new PottsDrawer.PottsCells(panels[1], "agents:STATE:Y", - length, width, height, MAP_STATE, getBox(0, vv, hh, vx)), - new PottsDrawer.PottsCells(panels[1], "agents:POPULATION:Y", - length, width, height, MAP_POPULATION, getBox(h, vv, hh, vx)), - new PottsDrawer.PottsCells(panels[1], "agents:VOLUME:Y", - length, width, height, maps.mapVolume, getBox(0, v + vv, hh, vx)), - new PottsDrawer.PottsCells(panels[1], "agents:HEIGHT:Y", - length, width, height, maps.mapHeight, getBox(h, v + vv, hh, vx)), - - new PottsDrawer.PottsCells(panels[1], "agents:OVERLAY:Y", - length, width, height, MAP_OVERLAY, getBox(0, vv, hh, vx)), - new PottsDrawer.PottsCells(panels[1], "agents:OVERLAY:Y", - length, width, height, MAP_OVERLAY, getBox(h, vv, hh, vx)), - new PottsDrawer.PottsCells(panels[1], "agents:OVERLAY:Y", - length, width, height, MAP_OVERLAY, getBox(0, v + vv, hh, vx)), - new PottsDrawer.PottsCells(panels[1], "agents:OVERLAY:Y", - length, width, height, MAP_OVERLAY, getBox(h, v + vv, hh, vx)), - - new PottsDrawer.PottsGrid(panels[1], "grid:Y", - length, width, height, getBox(0, vv, hh, vx)), - new PottsDrawer.PottsGrid(panels[1], "grid:Y", - length, width, height, getBox(h, vv, hh, vx)), - new PottsDrawer.PottsGrid(panels[1], "grid:Y", - length, width, height, getBox(0, v + vv, hh, vx)), - new PottsDrawer.PottsGrid(panels[1], "grid:Y", - length, width, height, getBox(h, v + vv, hh, vx)), + new PottsDrawer.PottsCells( + panels[0], + "agents:CYTOPLASM:Z", + length, + width, + height, + MAP_CYTOPLASM, + getBox(0, 0, hh * 2, vv * 2)), + new PottsDrawer.PottsCells( + panels[0], + "agents:CYTOPLASM:X", + length, + width, + height, + MAP_CYTOPLASM, + getBox(hh * 2, 0, hx * 2, vv * 2)), + new PottsDrawer.PottsCells( + panels[0], + "agents:CYTOPLASM:Y", + length, + width, + height, + MAP_CYTOPLASM, + getBox(0, vv * 2, hh * 2, vx * 2)), + new PottsDrawer.PottsCells( + panels[0], + "agents:NUCLEUS:Z", + length, + width, + height, + MAP_NUCLEUS, + getBox(0, 0, hh * 2, vv * 2)), + new PottsDrawer.PottsCells( + panels[0], + "agents:NUCLEUS:X", + length, + width, + height, + MAP_NUCLEUS, + getBox(hh * 2, 0, hx * 2, vv * 2)), + new PottsDrawer.PottsCells( + panels[0], + "agents:NUCLEUS:Y", + length, + width, + height, + MAP_NUCLEUS, + getBox(0, vv * 2, hh * 2, vx * 2)), + new PottsDrawer.PottsCells( + panels[1], + "agents:STATE:Z", + length, + width, + height, + MAP_STATE, + getBox(0, 0, hh, vv)), + new PottsDrawer.PottsCells( + panels[1], + "agents:POPULATION:Z", + length, + width, + height, + MAP_POPULATION, + getBox(h, 0, hh, vv)), + new PottsDrawer.PottsCells( + panels[1], + "agents:VOLUME:Z", + length, + width, + height, + maps.mapVolume, + getBox(0, v, hh, vv)), + new PottsDrawer.PottsCells( + panels[1], + "agents:HEIGHT:Z", + length, + width, + height, + maps.mapHeight, + getBox(h, v, hh, vv)), + new PottsDrawer.PottsCells( + panels[1], + "agents:OVERLAY:Z", + length, + width, + height, + MAP_OVERLAY, + getBox(0, 0, hh, vv)), + new PottsDrawer.PottsCells( + panels[1], + "agents:OVERLAY:Z", + length, + width, + height, + MAP_OVERLAY, + getBox(h, 0, hh, vv)), + new PottsDrawer.PottsCells( + panels[1], + "agents:OVERLAY:Z", + length, + width, + height, + MAP_OVERLAY, + getBox(0, v, hh, vv)), + new PottsDrawer.PottsCells( + panels[1], + "agents:OVERLAY:Z", + length, + width, + height, + MAP_OVERLAY, + getBox(h, v, hh, vv)), + new PottsDrawer.PottsGrid( + panels[1], "grid:Z", length, width, height, getBox(0, 0, hh, vv)), + new PottsDrawer.PottsGrid( + panels[1], "grid:Z", length, width, height, getBox(h, 0, hh, vv)), + new PottsDrawer.PottsGrid( + panels[1], "grid:Z", length, width, height, getBox(0, v, hh, vv)), + new PottsDrawer.PottsGrid( + panels[1], "grid:Z", length, width, height, getBox(h, v, hh, vv)), + new PottsDrawer.PottsCells( + panels[1], + "agents:STATE:X", + length, + width, + height, + MAP_STATE, + getBox(hh, 0, hx, vv)), + new PottsDrawer.PottsCells( + panels[1], + "agents:POPULATION:X", + length, + width, + height, + MAP_POPULATION, + getBox(h + hh, 0, hx, vv)), + new PottsDrawer.PottsCells( + panels[1], + "agents:VOLUME:X", + length, + width, + height, + maps.mapVolume, + getBox(hh, v, hx, vv)), + new PottsDrawer.PottsCells( + panels[1], + "agents:HEIGHT:X", + length, + width, + height, + maps.mapHeight, + getBox(h + hh, v, hx, vv)), + new PottsDrawer.PottsCells( + panels[1], + "agents:OVERLAY:X", + length, + width, + height, + MAP_OVERLAY, + getBox(hh, 0, hx, vv)), + new PottsDrawer.PottsCells( + panels[1], + "agents:OVERLAY:X", + length, + width, + height, + MAP_OVERLAY, + getBox(h + hh, 0, hx, vv)), + new PottsDrawer.PottsCells( + panels[1], + "agents:OVERLAY:X", + length, + width, + height, + MAP_OVERLAY, + getBox(hh, v, hx, vv)), + new PottsDrawer.PottsCells( + panels[1], + "agents:OVERLAY:X", + length, + width, + height, + MAP_OVERLAY, + getBox(h + hh, v, hx, vv)), + new PottsDrawer.PottsGrid( + panels[1], "grid:X", length, width, height, getBox(hh, 0, hx, vv)), + new PottsDrawer.PottsGrid( + panels[1], "grid:X", length, width, height, getBox(h + hh, 0, hx, vv)), + new PottsDrawer.PottsGrid( + panels[1], "grid:X", length, width, height, getBox(hh, v, hx, vv)), + new PottsDrawer.PottsGrid( + panels[1], "grid:X", length, width, height, getBox(h + hh, v, hx, vv)), + new PottsDrawer.PottsCells( + panels[1], + "agents:STATE:Y", + length, + width, + height, + MAP_STATE, + getBox(0, vv, hh, vx)), + new PottsDrawer.PottsCells( + panels[1], + "agents:POPULATION:Y", + length, + width, + height, + MAP_POPULATION, + getBox(h, vv, hh, vx)), + new PottsDrawer.PottsCells( + panels[1], + "agents:VOLUME:Y", + length, + width, + height, + maps.mapVolume, + getBox(0, v + vv, hh, vx)), + new PottsDrawer.PottsCells( + panels[1], + "agents:HEIGHT:Y", + length, + width, + height, + maps.mapHeight, + getBox(h, v + vv, hh, vx)), + new PottsDrawer.PottsCells( + panels[1], + "agents:OVERLAY:Y", + length, + width, + height, + MAP_OVERLAY, + getBox(0, vv, hh, vx)), + new PottsDrawer.PottsCells( + panels[1], + "agents:OVERLAY:Y", + length, + width, + height, + MAP_OVERLAY, + getBox(h, vv, hh, vx)), + new PottsDrawer.PottsCells( + panels[1], + "agents:OVERLAY:Y", + length, + width, + height, + MAP_OVERLAY, + getBox(0, v + vv, hh, vx)), + new PottsDrawer.PottsCells( + panels[1], + "agents:OVERLAY:Y", + length, + width, + height, + MAP_OVERLAY, + getBox(h, v + vv, hh, vx)), + new PottsDrawer.PottsGrid( + panels[1], "grid:Y", length, width, height, getBox(0, vv, hh, vx)), + new PottsDrawer.PottsGrid( + panels[1], "grid:Y", length, width, height, getBox(h, vv, hh, vx)), + new PottsDrawer.PottsGrid( + panels[1], "grid:Y", length, width, height, getBox(0, v + vv, hh, vx)), + new PottsDrawer.PottsGrid( + panels[1], "grid:Y", length, width, height, getBox(h, v + vv, hh, vx)), }; } - + @Override public Panel[] createPanels() { return new Panel[] { - new Panel("[POTTS] Agents", 100, 50, horizontal, vertical, this), - new Panel("[POTTS] Auxiliary", horizontal + 120, 50, horizontal, vertical, this), + new Panel("[POTTS] Agents", 100, 50, horizontal, vertical, this), + new Panel("[POTTS] Auxiliary", horizontal + 120, 50, horizontal, vertical, this), }; } } diff --git a/test/arcade/core/ARCADETest.java b/test/arcade/core/ARCADETest.java index f9b300482..cb9335dad 100644 --- a/test/arcade/core/ARCADETest.java +++ b/test/arcade/core/ARCADETest.java @@ -1,14 +1,13 @@ package arcade.core; -import java.io.File; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; import java.util.logging.Logger; -import org.apache.commons.io.FileUtils; -import org.junit.BeforeClass; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import org.xml.sax.SAXException; import arcade.core.sim.Series; import arcade.core.sim.input.InputBuilder; @@ -16,93 +15,113 @@ import arcade.core.sim.output.OutputSaver; import arcade.core.util.Box; import arcade.core.util.MiniBox; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.core.ARCADETestUtilities.*; public class ARCADETest { - @Rule - public TemporaryFolder folder = new TemporaryFolder(); - private static final String XML = randomString(); - + private static final String PATH = randomString(); - + private static final String IMPLEMENTATION = randomString(); - - @BeforeClass - public static void setFields() { ARCADE.logger = mock(Logger.class); } - + + @BeforeAll + public static void setFields() { + ARCADE.logger = mock(Logger.class); + } + class MockARCADE extends ARCADE { ArrayList seriesList; - - MockARCADE() { } - + + String resource = ""; + + MockARCADE() {} + + MockARCADE(Path path) { + resource = path.toAbsolutePath().toString(); + } + @Override protected String getResource(String s) { - return folder.getRoot().getAbsolutePath() + "/" + s; + return resource + "/" + s; } - + @Override protected InputBuilder getBuilder() { InputBuilder builder = mock(InputBuilder.class); - + try { - doAnswer(invocation -> { - seriesList = new ArrayList<>(); - Series series = mock(Series.class); - seriesList.add(series); - series.isVis = builder.isVis; - return seriesList; - }).when(builder).build(eq(XML)); + doAnswer( + invocation -> { + seriesList = new ArrayList<>(); + Series series = mock(Series.class); + seriesList.add(series); + series.isVis = builder.isVis; + return seriesList; + }) + .when(builder) + .build(eq(XML)); } catch (Exception e) { e.printStackTrace(); } - + return builder; } - + @Override - protected OutputLoader getLoader(Series series) { return mock(OutputLoader.class); } - + protected OutputLoader getLoader(Series series) { + return mock(OutputLoader.class); + } + @Override - protected OutputSaver getSaver(Series series) { return mock(OutputSaver.class); } + protected OutputSaver getSaver(Series series) { + return mock(OutputSaver.class); + } } - - @Test(expected = IllegalArgumentException.class) - public void main_noArgs_throwsException() throws Exception { - String[] args = new String[] { }; - ARCADE.main(args); + + @Test + public void main_noArgs_throwsException() { + assertThrows( + IllegalArgumentException.class, + () -> { + String[] args = new String[] {}; + ARCADE.main(args); + }); } - - @Test(expected = IllegalArgumentException.class) - public void main_invalidType_throwsException() throws Exception { - String[] args = new String[] { "*" }; - ARCADE.main(args); + + @Test + public void main_invalidType_throwsException() { + assertThrows( + IllegalArgumentException.class, + () -> { + String[] args = new String[] {"*"}; + ARCADE.main(args); + }); } - + @Test - public void loadCommands_called_loadsBox() throws IOException, SAXException { - File file = folder.newFile("command." + IMPLEMENTATION + ".xml"); - FileUtils.writeStringToFile(file, - "", "UTF-8"); - - ARCADE arcade = new MockARCADE(); + public void loadCommands_called_loadsBox(@TempDir Path path) throws IOException, SAXException { + Path file = Files.createFile(path.resolve("command." + IMPLEMENTATION + ".xml")); + Files.writeString(file, ""); + + ARCADE arcade = new MockARCADE(path); Box commands = arcade.loadCommands(IMPLEMENTATION); - + assertEquals("POSITION", commands.getTag("ARCADE")); assertEquals("SWITCH", commands.getTag("MOCK")); } - + @Test - public void loadParameters_called_loadsBox() throws IOException, SAXException { - File file = folder.newFile("parameter." + IMPLEMENTATION + ".xml"); - FileUtils.writeStringToFile(file, - "", "UTF-8"); - - ARCADE arcade = new MockARCADE(); + public void loadParameters_called_loadsBox(@TempDir Path path) + throws IOException, SAXException { + Path file = Files.createFile(path.resolve("parameter." + IMPLEMENTATION + ".xml")); + Files.writeString( + file, ""); + + ARCADE arcade = new MockARCADE(path); Box parameters = arcade.loadParameters(IMPLEMENTATION); - + assertEquals("DEFAULT", parameters.getTag("START_SEED")); assertEquals("0", parameters.getValue("START_SEED~value")); assertEquals("DEFAULT", parameters.getTag("END_SEED")); @@ -110,40 +129,44 @@ public void loadParameters_called_loadsBox() throws IOException, SAXException { assertEquals("MOCKPARAMETER", parameters.getTag("MOCK")); assertEquals("MOCK_VALUE", parameters.getValue("MOCK~value")); } - + @Test public void parseArguments_validArguments_parsesArguments() { Box commands = new Box(); - String[] args = new String[] { randomString() }; + String[] args = new String[] {randomString()}; commands.addTag("POSITION_ARG", "POSITION"); ARCADE arcade = new MockARCADE(); MiniBox settings = arcade.parseArguments(args, commands); assertEquals(args[0], settings.get("POSITION_ARG")); } - - @Test(expected = IllegalArgumentException.class) + + @Test public void parseArguments_invalidArguments_parsesArguments() { - Box commands = new Box(); - String[] args = new String[] { }; - commands.addTag("POSITION_ARG", "POSITION"); - ARCADE arcade = new MockARCADE(); - arcade.parseArguments(args, commands); + assertThrows( + IllegalArgumentException.class, + () -> { + Box commands = new Box(); + String[] args = new String[] {}; + commands.addTag("POSITION_ARG", "POSITION"); + ARCADE arcade = new MockARCADE(); + arcade.parseArguments(args, commands); + }); } - + @Test public void buildSeries_noVis_returnsList() throws IOException, SAXException { Box parameters = new Box(); MiniBox settings = new MiniBox(); settings.put("XML", XML); settings.put("PATH", PATH); - + ARCADE arcade = new MockARCADE(); ArrayList series = arcade.buildSeries(parameters, settings); - + assertEquals(1, series.size()); assertFalse(series.get(0).isVis); } - + @Test public void buildSeries_withVis_returnsList() throws IOException, SAXException { Box parameters = new Box(); @@ -151,115 +174,115 @@ public void buildSeries_withVis_returnsList() throws IOException, SAXException { settings.put("XML", XML); settings.put("PATH", PATH); settings.put("VIS", ""); - + ARCADE arcade = new MockARCADE(); ArrayList series = arcade.buildSeries(parameters, settings); - + assertEquals(1, series.size()); assertTrue(series.get(0).isVis); } - + @Test public void buildSeries_withPathSeparator_returnsList() throws IOException, SAXException { Box parameters = new Box(); MiniBox settings = new MiniBox(); settings.put("XML", XML); settings.put("PATH", PATH + "/"); - + ARCADE arcade = new MockARCADE(); ArrayList series = arcade.buildSeries(parameters, settings); - + assertEquals(1, series.size()); assertFalse(series.get(0).isVis); } - + @Test public void runSeries_noVis_runsSim() throws Exception { ArrayList series = new ArrayList<>(); series.add(mock(Series.class)); - + MiniBox settings = new MiniBox(); - + ARCADE arcade = new MockARCADE(); arcade.runSeries(series, settings); - + verify(series.get(0)).runSims(); verify(series.get(0), never()).runVis(); } - + @Test public void runSeries_noVisIsSkipped_skipsSim() throws Exception { ArrayList series = new ArrayList<>(); series.add(mock(Series.class)); series.get(0).isSkipped = true; - + MiniBox settings = new MiniBox(); - + ARCADE arcade = new MockARCADE(); arcade.runSeries(series, settings); - + verify(series.get(0), never()).runSims(); verify(series.get(0), never()).runVis(); } - + @Test public void runSeries_noVis_savesFiles() throws Exception { ArrayList series = new ArrayList<>(); series.add(mock(Series.class)); - + MiniBox settings = new MiniBox(); - + ARCADE arcade = new MockARCADE(); arcade.runSeries(series, settings); - + verify(series.get(0).saver).saveSeries(); } - + @Test public void runSeries_withVis_runsVis() throws Exception { ArrayList series = new ArrayList<>(); series.add(mock(Series.class)); - + MiniBox settings = new MiniBox(); settings.put("VIS", ""); - + ARCADE arcade = new MockARCADE(); arcade.runSeries(series, settings); - + verify(series.get(0), never()).runSims(); verify(series.get(0)).runVis(); } - + @Test public void runSeries_withVisIsSkipped_runsVis() throws Exception { ArrayList series = new ArrayList<>(); series.add(mock(Series.class)); series.get(0).isSkipped = true; - + MiniBox settings = new MiniBox(); settings.put("VIS", ""); - + ARCADE arcade = new MockARCADE(); arcade.runSeries(series, settings); - + verify(series.get(0), never()).runSims(); verify(series.get(0), never()).runVis(); } - + @Test public void runSeries_withVis_savesNothing() throws Exception { ArrayList series = new ArrayList<>(); series.add(mock(Series.class)); - + MiniBox settings = new MiniBox(); settings.put("VIS", ""); - + ARCADE arcade = new MockARCADE(); arcade.runSeries(series, settings); - + assertNull(series.get(0).saver); } - + @Test public void runSeries_multipleSeriesNoVis_runsAll() throws Exception { ArrayList series = new ArrayList<>(); @@ -267,17 +290,17 @@ public void runSeries_multipleSeriesNoVis_runsAll() throws Exception { for (int i = 0; i < n; i++) { series.add(mock(Series.class)); } - + MiniBox settings = new MiniBox(); - + ARCADE arcade = new MockARCADE(); arcade.runSeries(series, settings); - + for (int i = 0; i < n; i++) { verify(series.get(i)).runSims(); } } - + @Test public void runSeries_multipleSeriesWithVis_runsFirst() throws Exception { ArrayList series = new ArrayList<>(); @@ -285,61 +308,61 @@ public void runSeries_multipleSeriesWithVis_runsFirst() throws Exception { for (int i = 0; i < n; i++) { series.add(mock(Series.class)); } - + MiniBox settings = new MiniBox(); settings.put("VIS", ""); - + ARCADE arcade = new MockARCADE(); arcade.runSeries(series, settings); - + verify(series.get(0)).runVis(); for (int i = 1; i < n; i++) { verify(series.get(i), never()).runSims(); } } - + @Test public void runSeries_loadCells_setsBooleans() throws Exception { ArrayList series = new ArrayList<>(); series.add(mock(Series.class)); - + MiniBox settings = new MiniBox(); settings.put("LOADCELLS", ""); - + ARCADE arcade = new MockARCADE(); arcade.runSeries(series, settings); - + assertTrue(series.get(0).loader.loadCells); assertFalse(series.get(0).loader.loadLocations); } - + @Test public void runSeries_loadLocation_setsBooleans() throws Exception { ArrayList series = new ArrayList<>(); series.add(mock(Series.class)); - + MiniBox settings = new MiniBox(); settings.put("LOADLOCATIONS", ""); - + ARCADE arcade = new MockARCADE(); arcade.runSeries(series, settings); - + assertFalse(series.get(0).loader.loadCells); assertTrue(series.get(0).loader.loadLocations); } - + @Test public void runSeries_loadBoth_setsBooleans() throws Exception { ArrayList series = new ArrayList<>(); series.add(mock(Series.class)); - + MiniBox settings = new MiniBox(); settings.put("LOADCELLS", ""); settings.put("LOADLOCATIONS", ""); - + ARCADE arcade = new MockARCADE(); arcade.runSeries(series, settings); - + assertTrue(series.get(0).loader.loadCells); assertTrue(series.get(0).loader.loadLocations); } diff --git a/test/arcade/core/ARCADETestUtilities.java b/test/arcade/core/ARCADETestUtilities.java index 86a5e0407..342e17245 100644 --- a/test/arcade/core/ARCADETestUtilities.java +++ b/test/arcade/core/ARCADETestUtilities.java @@ -4,32 +4,32 @@ public final class ARCADETestUtilities { protected ARCADETestUtilities() { throw new UnsupportedOperationException(); } - + public static int randomSeed() { return randomIntBetween(1, 1000); } - + public static int randomIntBetween(int lower, int upper) { return (int) randomDoubleBetween(lower, upper); } - + public static double randomDoubleBetween(double lower, double upper) { return Math.random() * (upper - lower) + lower; } - + public static String randomString() { int stringSize = 10; String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvxyz"; StringBuilder sb = new StringBuilder(stringSize); - + for (int i = 0; i < stringSize; i++) { int index = (int) (alphabet.length() * Math.random()); sb.append(alphabet.charAt(index)); } - + return sb.toString(); } - + public static String[] randomStringArray(int n) { String[] strings = new String[n]; for (int i = 0; i < n; i++) { diff --git a/test/arcade/core/sim/SeriesTest.java b/test/arcade/core/sim/SeriesTest.java index 3529daba1..5292f2453 100644 --- a/test/arcade/core/sim/SeriesTest.java +++ b/test/arcade/core/sim/SeriesTest.java @@ -3,64 +3,67 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import sim.display.GUIState; import sim.engine.Schedule; import sim.engine.SimState; import sim.engine.Steppable; 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; import arcade.core.util.Box; import arcade.core.util.MiniBox; import arcade.core.vis.*; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.core.ARCADETestUtilities.*; import static arcade.core.sim.Series.SEED_OFFSET; +import static arcade.core.util.MiniBox.TAG_SEPARATOR; public class SeriesTest { - private static final double EPSILON = 1E-8; - + private static final double EPSILON = 1E-5; + private static final double DS = randomDoubleBetween(1, 10); - + private static final double DZ = randomDoubleBetween(1, 10); - + private static final double DT = randomDoubleBetween(0.5, 2); - + private static final Box PARAMETERS = new Box(); - + private static final String TEST_NAME = "DEFAULT_NAME"; - + private static final String TEST_PATH = "/default/path/"; - + private static final int DEFAULT_START_SEED = randomIntBetween(1, 100); - + private static final int DEFAULT_END_SEED = randomIntBetween(1, 100); - + private static final int DEFAULT_TICKS = randomIntBetween(1, 100); - + private static final int DEFAULT_INTERVAL = randomIntBetween(1, 100); - + private static final int DEFAULT_LENGTH = randomIntBetween(1, 100); - + private static final int DEFAULT_WIDTH = randomIntBetween(1, 100); - + private static final int DEFAULT_HEIGHT = randomIntBetween(1, 100); - + private static final int DEFAULT_MARGIN = randomIntBetween(1, 100); - + private static final String SIM_CONSTRUCTOR_CLASS = SimulationMock.class.getName(); - + private static final String VIS_CONSTRUCTOR_CLASS = VisualizationMock.class.getName(); - + private static final HashMap> SETUP_LISTS_MOCK = mock(HashMap.class); - - @BeforeClass + + @BeforeAll public static void setupParameters() { // DEFAULTS PARAMETERS.addTag("START_SEED", "DEFAULT"); @@ -86,139 +89,186 @@ public static void setupParameters() { PARAMETERS.addAtt("DT", "value", "" + DT); PARAMETERS.addAtt("DZ", "value", "" + DZ); } - + private HashMap makeDicts() { HashMap setupDicts = new HashMap<>(); - + MiniBox set = new MiniBox(); setupDicts.put("set", set); - + MiniBox series = new MiniBox(); series.put("name", TEST_NAME); setupDicts.put("series", series); - + return setupDicts; } - + public static class SimulationMock extends SimState implements Simulation { - public SimulationMock(long seed, Series series) { super(seed); } - + public SimulationMock(long seed, Series series) { + super(seed); + } + @Override - public Series getSeries() { return null; } - + public Series getSeries() { + return null; + } + @Override - public Schedule getSchedule() { return null; } - + public Schedule getSchedule() { + return null; + } + @Override - public int getSeed() { return 0; } - + public int getSeed() { + return 0; + } + + @Override + public int getID() { + return 0; + } + + @Override + public Grid getGrid() { + return null; + } + @Override - public int getID() { return 0; } - + public ArrayList getCells() { + return null; + } + @Override - public Grid getGrid() { return null; } - + public ArrayList getLocations() { + return null; + } + @Override - public ArrayList getCells() { return null; } - + public CellFactory getCellFactory() { + return null; + } + @Override - public ArrayList getLocations() { return null; } - + public LocationFactory getLocationFactory() { + return null; + } + @Override - public Lattice getLattice(String key) { return null; } - + public Lattice getLattice(String key) { + return null; + } + @Override - public Action getAction(String key) { return null; } - + public Action getAction(String key) { + return null; + } + @Override - public Component getComponent(String key) { return null; } - + public Component getComponent(String key) { + return null; + } + @Override - public void setupAgents() { } - + public void setupAgents() {} + @Override - public void setupEnvironment() { } - + public void setupEnvironment() {} + @Override - public void scheduleActions() { } - + public void scheduleActions() {} + @Override - public void scheduleComponents() { } + public void scheduleComponents() {} } - + public static class VisualizationMock extends Visualization { - public VisualizationMock(Simulation sim) { super((SimState) sim); } - + public VisualizationMock(Simulation sim) { + super((SimState) sim); + } + @Override - protected Panel[] createPanels() { return new Panel[0]; } - + protected Panel[] createPanels() { + return new Panel[0]; + } + @Override - protected Drawer[] createDrawers() { return new Drawer[0]; } + protected Drawer[] createDrawers() { + return new Drawer[0]; + } } - + static class SeriesMock extends Series { boolean invalidSim; - + boolean invalidVis; - - SeriesMock(HashMap setupDicts, - HashMap> setupLists, - String path, Box parameters, boolean isVis) { + + SeriesMock( + HashMap setupDicts, + HashMap> setupLists, + String path, + Box parameters, + boolean isVis) { super(setupDicts, setupLists, path, parameters, isVis); } - + @Override - protected void initialize(HashMap> setupLists, Box parameters) { } - + protected void initialize(HashMap> setupLists, Box parameters) {} + @Override - protected void updatePopulations(ArrayList populations, MiniBox populationDefaults, - MiniBox populationConversions) { } - + protected void updatePopulations( + ArrayList populations, + MiniBox populationDefaults, + MiniBox populationConversions) {} + @Override - protected void updateLayers(ArrayList layers, MiniBox layerDefaults, - MiniBox layerConversions) { } - + protected void updateLayers( + ArrayList layers, MiniBox layerDefaults, MiniBox layerConversions) {} + @Override - protected void updateActions(ArrayList actions, MiniBox actionDefaults) { } - + protected void updateActions(ArrayList actions, MiniBox actionDefaults) {} + @Override - protected void updateComponents(ArrayList components, MiniBox componentDefaults) { } - + protected void updateComponents(ArrayList components, MiniBox componentDefaults) {} + @Override - protected String getSimClass() { return (invalidSim ? "" : SIM_CONSTRUCTOR_CLASS); } - + protected String getSimClass() { + return (invalidSim ? "" : SIM_CONSTRUCTOR_CLASS); + } + @Override - protected String getVisClass() { return (invalidVis ? "" : VIS_CONSTRUCTOR_CLASS); } + protected String getVisClass() { + return (invalidVis ? "" : VIS_CONSTRUCTOR_CLASS); + } } - + @Test public void constructor_noPrefix_updatesNames() { HashMap setupDicts = makeDicts(); Series series = new SeriesMock(setupDicts, SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false); - + assertEquals(TEST_NAME, series.getName()); assertEquals(TEST_PATH + TEST_NAME, series.getPrefix()); } - + @Test public void constructor_givenPrefix_updatesNames() { HashMap setupDicts = makeDicts(); setupDicts.get("set").put("prefix", "PREFIX_"); Series series = new SeriesMock(setupDicts, SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false); - + assertEquals(TEST_NAME, series.getName()); assertEquals(TEST_PATH + "PREFIX_" + TEST_NAME, series.getPrefix()); } - + @Test public void constructor_seedsNotGiven_usesDefaults() { HashMap setupDicts = makeDicts(); Series series = new SeriesMock(setupDicts, SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false); - + assertEquals(DEFAULT_START_SEED, series.getStartSeed()); assertEquals(DEFAULT_END_SEED, series.getEndSeed()); } - + @Test public void constructor_seedGiven_usesGiven() { int startSeed = randomIntBetween(1, 100); @@ -227,94 +277,95 @@ public void constructor_seedGiven_usesGiven() { setupDicts.get("series").put("start", startSeed); setupDicts.get("series").put("end", endSeed); Series series = new SeriesMock(setupDicts, SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false); - + assertEquals(startSeed, series.getStartSeed()); assertEquals(endSeed, series.getEndSeed()); } - + @Test public void constructor_ticksNotGiven_usesDefault() { HashMap setupDicts = makeDicts(); Series series = new SeriesMock(setupDicts, SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false); - + assertEquals(DEFAULT_TICKS, series.getTicks()); } - + @Test public void constructor_ticksGiven_usesGiven() { int ticks = randomIntBetween(1, 100); HashMap setupDicts = makeDicts(); setupDicts.get("series").put("ticks", ticks); Series series = new SeriesMock(setupDicts, SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false); - + assertEquals(ticks, series.getTicks()); } - + @Test public void constructor_intervalNotGiven_usesDefault() { HashMap setupDicts = makeDicts(); Series series = new SeriesMock(setupDicts, SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false); - + assertEquals(DEFAULT_INTERVAL, series.getInterval()); } - + @Test public void constructor_intervalGiven_usesGiven() { int interval = randomIntBetween(1, 100); HashMap setupDicts = makeDicts(); setupDicts.get("series").put("interval", interval); Series series = new SeriesMock(setupDicts, SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false); - + assertEquals(interval, series.getInterval()); } - + @Test public void constructor_withoutVis_updatesField() { HashMap setupDicts = makeDicts(); Series series = new SeriesMock(setupDicts, SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false); assertFalse(series.isVis); } - + @Test public void constructor_withVis_updatesField() { HashMap setupDicts = makeDicts(); Series series = new SeriesMock(setupDicts, SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, true); assertTrue(series.isVis); } - + @Test public void constructor_sizesNotGiven_usesDefaults() { HashMap setupDicts = makeDicts(); - Series series = spy(new SeriesMock(setupDicts, SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false)); - + Series series = + spy(new SeriesMock(setupDicts, SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false)); + assertEquals(DEFAULT_LENGTH, series.length); assertEquals(DEFAULT_WIDTH, series.width); assertEquals(DEFAULT_HEIGHT, series.height); } - + @Test public void constructor_oneSizeGiven_updatesSizes() { int length = randomIntBetween(0, 100); int width = randomIntBetween(0, 100); int height = randomIntBetween(0, 100); - + HashMap setupDicts; Series series; - + setupDicts = makeDicts(); setupDicts.get("series").put("length", length); series = new SeriesMock(setupDicts, SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false); assertEquals(length, series.length); assertEquals(DEFAULT_WIDTH, series.width); assertEquals(DEFAULT_HEIGHT, series.height); - + setupDicts = makeDicts(); setupDicts.get("series").put("width", width); series = new SeriesMock(setupDicts, SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false); assertEquals(DEFAULT_LENGTH, series.length); assertEquals(width, series.width); assertEquals(DEFAULT_HEIGHT, series.height); - + setupDicts = makeDicts(); setupDicts.get("series").put("height", height); series = new SeriesMock(setupDicts, SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false); @@ -322,16 +373,16 @@ public void constructor_oneSizeGiven_updatesSizes() { assertEquals(DEFAULT_WIDTH, series.width); assertEquals(height, series.height); } - + @Test public void constructor_twoSizesGiven_updatesSizes() { int length = randomIntBetween(0, 100); int width = randomIntBetween(0, 100); int height = randomIntBetween(0, 100); - + HashMap setupDicts; Series series; - + setupDicts = makeDicts(); setupDicts.get("series").put("length", length); setupDicts.get("series").put("width", width); @@ -339,7 +390,7 @@ public void constructor_twoSizesGiven_updatesSizes() { assertEquals(length, series.length); assertEquals(width, series.width); assertEquals(DEFAULT_HEIGHT, series.height); - + setupDicts = makeDicts(); setupDicts.get("series").put("width", width); setupDicts.get("series").put("height", height); @@ -347,7 +398,7 @@ public void constructor_twoSizesGiven_updatesSizes() { assertEquals(DEFAULT_LENGTH, series.length); assertEquals(width, series.width); assertEquals(height, series.height); - + setupDicts = makeDicts(); setupDicts.get("series").put("length", length); setupDicts.get("series").put("height", height); @@ -356,148 +407,148 @@ public void constructor_twoSizesGiven_updatesSizes() { assertEquals(DEFAULT_WIDTH, series.width); assertEquals(height, series.height); } - + @Test public void constructor_allSizesGiven_updatesSizes() { int length = randomIntBetween(0, 100); int width = randomIntBetween(0, 100); int height = randomIntBetween(0, 100); - + HashMap setupDicts = makeDicts(); setupDicts.get("series").put("length", length); setupDicts.get("series").put("width", width); setupDicts.get("series").put("height", height); Series series = new SeriesMock(setupDicts, SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false); - + assertEquals(length, series.length); assertEquals(width, series.width); assertEquals(height, series.height); } - + @Test public void constructor_marginNotGiven_usesDefault() { HashMap setupDicts = makeDicts(); Series series = new SeriesMock(setupDicts, SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false); - + assertEquals(DEFAULT_MARGIN, series.margin, EPSILON); } - + @Test public void constructor_marginGiven_usesGiven() { int margin = randomIntBetween(0, 100); HashMap setupDicts = makeDicts(); setupDicts.get("series").put("margin", margin); Series series = new SeriesMock(setupDicts, SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false); - + assertEquals(margin, series.margin); } - + @Test public void constructor_dsNotGiven_usesDefault() { HashMap setupDicts = makeDicts(); Series series = new SeriesMock(setupDicts, SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false); - + assertEquals(DS, series.ds, EPSILON); } - + @Test public void constructor_dsGiven_usesGiven() { double ds = randomDoubleBetween(0, 100); HashMap setupDicts = makeDicts(); setupDicts.get("series").put("ds", ds); Series series = new SeriesMock(setupDicts, SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false); - + assertEquals(ds, series.ds, EPSILON); } - + @Test public void constructor_dzNotGiven_usesDefault() { HashMap setupDicts = makeDicts(); Series series = new SeriesMock(setupDicts, SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false); - + assertEquals(DZ, series.dz, EPSILON); } - + @Test public void constructor_dzGiven_usesGiven() { double dz = randomDoubleBetween(0, 100); HashMap setupDicts = makeDicts(); setupDicts.get("series").put("dz", dz); Series series = new SeriesMock(setupDicts, SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false); - + assertEquals(dz, series.dz, EPSILON); } - + @Test public void constructor_dtNotGiven_usesDefault() { HashMap setupDicts = makeDicts(); Series series = new SeriesMock(setupDicts, SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false); - + assertEquals(DT, series.dt, EPSILON); } - + @Test public void constructor_dtGiven_usesGiven() { double dt = randomDoubleBetween(0, 100); HashMap setupDicts = makeDicts(); setupDicts.get("series").put("dt", dt); Series series = new SeriesMock(setupDicts, SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false); - + assertEquals(dt, series.dt, EPSILON); } - + @Test public void isValidNumber_noValue_returnsFalse() { Box box = new Box(); assertFalse(Series.isValidNumber(box, "number")); } - + @Test public void isValidNumber_invalidValues_returnsFalse() { - String[] values = new String[] { "-1", "1.", "-1.", "1.5", "-1.5", "1E-2" }; + String[] values = new String[] {"-1", "1.", "-1.", "1.5", "-1.5", "1E-2"}; for (String value : values) { Box box = new Box(); box.add("number", value); assertFalse(Series.isValidNumber(box, "number")); } } - + @Test public void isValidNumber_validValues_returnsTrue() { - String[] values = new String[] { "0", "1", "1E2" }; + String[] values = new String[] {"0", "1", "1E2"}; for (String value : values) { Box box = new Box(); box.add("number", value); assertTrue(Series.isValidNumber(box, "number")); } } - + @Test public void isValidFraction_noValue_returnsFalse() { Box box = new Box(); assertFalse(Series.isValidFraction(box, "number")); } - + @Test public void isValidFraction_invalidValues_returnsFalse() { - String[] values = new String[] { "-0", "-0.0", "-1", "-1.0", "2.0" }; + String[] values = new String[] {"-0", "-0.0", "-1", "-1.0", "2.0"}; for (String value : values) { Box box = new Box(); box.add("number", value); assertFalse(Series.isValidFraction(box, "number")); } } - + @Test public void isValidFraction_validValues_returnsTrue() { - String[] values = new String[] { "0", "0.0", "1", "1.0", "0.5" }; + String[] values = new String[] {"0", "0.0", "1", "1.0", "0.5"}; for (String value : values) { Box box = new Box(); box.add("number", value); assertTrue(Series.isValidFraction(box, "number")); } } - + @Test public void parseParameter_noValueNoScaling_usesDefault() { MiniBox box = new MiniBox(); @@ -508,67 +559,152 @@ public void parseParameter_noValueNoScaling_usesDefault() { Series.parseParameter(box, parameter, "" + defaultParameter, values, scales); assertEquals(defaultParameter, box.getDouble(parameter), EPSILON); } - + @Test - public void parseParameter_withValueOnly_usesDefault() { + public void parseParameter_withValueOnly_usesValue() { MiniBox box = new MiniBox(); String parameter = randomString(); double defaultParameter = randomDoubleBetween(0, 100); MiniBox values = new MiniBox(); MiniBox scales = new MiniBox(); - + double parameterValue = randomDoubleBetween(0, 100); values.put(parameter, parameterValue); - + Series.parseParameter(box, parameter, "" + defaultParameter, values, scales); assertEquals(parameterValue, box.getDouble(parameter), EPSILON); } - + @Test - public void parseParameter_withScaleOnly_usesDefault() { + public void parseParameter_withScaleOnly_usesScaledDefault() { MiniBox box = new MiniBox(); String parameter = randomString(); double defaultParameter = randomDoubleBetween(0, 100); MiniBox values = new MiniBox(); MiniBox scales = new MiniBox(); - + double parameterScale = randomDoubleBetween(0, 100); scales.put(parameter, parameterScale); - + Series.parseParameter(box, parameter, "" + defaultParameter, values, scales); assertEquals(defaultParameter * parameterScale, box.getDouble(parameter), EPSILON); } - + @Test - public void parseParameter_valueAndScale_usesDefault() { + public void parseParameter_valueAndScale_usesScaledValue() { MiniBox box = new MiniBox(); String parameter = randomString(); double defaultParameter = randomDoubleBetween(0, 100); MiniBox values = new MiniBox(); MiniBox scales = new MiniBox(); - + double parameterValue = randomDoubleBetween(0, 100); values.put(parameter, parameterValue); - + double parameterScale = randomDoubleBetween(0, 100); scales.put(parameter, parameterScale); - + Series.parseParameter(box, parameter, "" + defaultParameter, values, scales); assertEquals(parameterValue * parameterScale, box.getDouble(parameter), EPSILON); } - + + @Test + public void parseParameter_noValueOneParameterDistribution_usesDefault() { + MiniBox box = new MiniBox(); + String parameter = randomString(); + String distribution = randomString().toUpperCase(); + + double defaultA = randomDoubleBetween(0, 100); + String defaultCode = String.format("%s(A=%f)", distribution, defaultA); + + MiniBox values = new MiniBox(); + MiniBox scales = new MiniBox(); + + Series.parseParameter(box, parameter, defaultCode, values, scales); + + assertEquals(distribution, box.get("(DISTRIBUTION)" + TAG_SEPARATOR + parameter)); + assertEquals(defaultA, box.getDouble(parameter + "_A"), EPSILON); + } + + @Test + public void parseParameter_noValueTwoParameterDistribution_usesDefault() { + MiniBox box = new MiniBox(); + String parameter = randomString(); + String distribution = randomString().toUpperCase(); + + double defaultA = randomDoubleBetween(0, 100); + double defaultB = randomDoubleBetween(0, 100); + String defaultCode = String.format("%s(A=%f,B=%f)", distribution, defaultA, defaultB); + + MiniBox values = new MiniBox(); + MiniBox scales = new MiniBox(); + + Series.parseParameter(box, parameter, defaultCode, values, scales); + + assertEquals(distribution, box.get("(DISTRIBUTION)" + TAG_SEPARATOR + parameter)); + assertEquals(defaultA, box.getDouble(parameter + "_A"), EPSILON); + assertEquals(defaultB, box.getDouble(parameter + "_B"), EPSILON); + } + + @Test + public void parseParameter_withOneParameterDistributionValue_usesValue() { + MiniBox box = new MiniBox(); + String parameter = randomString(); + String distribution = randomString().toUpperCase(); + + double defaultA = randomDoubleBetween(0, 100); + String defaultCode = String.format("%s(A=%f)", distribution, defaultA); + + MiniBox values = new MiniBox(); + MiniBox scales = new MiniBox(); + + double valueA = randomDoubleBetween(0, 100); + String valueCode = String.format("%s(A=%f)", distribution, valueA); + values.put(parameter, valueCode); + + Series.parseParameter(box, parameter, defaultCode, values, scales); + + assertEquals(distribution, box.get("(DISTRIBUTION)" + TAG_SEPARATOR + parameter)); + assertEquals(valueA, box.getDouble(parameter + "_A"), EPSILON); + } + + @Test + public void parseParameter_withTwoParameterDistributionValue_usesValue() { + MiniBox box = new MiniBox(); + String parameter = randomString(); + String distribution = randomString().toUpperCase(); + + double defaultA = randomDoubleBetween(0, 100); + double defaultB = randomDoubleBetween(0, 100); + String defaultCode = String.format("%s(A=%f,B=%f)", distribution, defaultA, defaultB); + + MiniBox values = new MiniBox(); + MiniBox scales = new MiniBox(); + + double valueA = randomDoubleBetween(0, 100); + double valueB = randomDoubleBetween(0, 100); + String valueCode = String.format("%s(A=%f,B=%f)", distribution, valueA, valueB); + values.put(parameter, valueCode); + + Series.parseParameter(box, parameter, defaultCode, values, scales); + + assertEquals(distribution, box.get("(DISTRIBUTION)" + TAG_SEPARATOR + parameter)); + assertEquals(valueA, box.getDouble(parameter + "_A"), EPSILON); + assertEquals(valueB, box.getDouble(parameter + "_B"), EPSILON); + } + @Test public void parseConversion_invalidConversion_returnsOne() { assertEquals(1, Series.parseConversion(randomString(), DS, DZ, DT), EPSILON); } - + @Test public void parseConversion_noExponent_returnsValue() { assertEquals(DS, Series.parseConversion("DS", DS, DZ, DT), EPSILON); assertEquals(DT, Series.parseConversion("DT", DS, DZ, DT), EPSILON); assertEquals(DZ, Series.parseConversion("DZ", DS, DZ, DT), EPSILON); } - + @Test public void parseConversion_positiveExponent_returnsValue() { int n = randomIntBetween(1, 100); @@ -576,7 +712,7 @@ public void parseConversion_positiveExponent_returnsValue() { assertEquals(Math.pow(DT, n), Series.parseConversion("DT^" + n, DS, DZ, DT), EPSILON); assertEquals(Math.pow(DZ, n), Series.parseConversion("DZ^" + n, DS, DZ, DT), EPSILON); } - + @Test public void parseConversion_negativeExponent_returnsValue() { int n = randomIntBetween(1, 100); @@ -584,7 +720,7 @@ public void parseConversion_negativeExponent_returnsValue() { assertEquals(Math.pow(DT, -n), Series.parseConversion("DT^-" + n, DS, DZ, DT), EPSILON); assertEquals(Math.pow(DZ, -n), Series.parseConversion("DZ^-" + n, DS, DZ, DT), EPSILON); } - + @Test public void parseConversion_multipleTerms_returnsValue() { int n = randomIntBetween(1, 3); @@ -596,7 +732,7 @@ public void parseConversion_multipleTerms_returnsValue() { assertEquals(Math.pow(DT, n * m), Series.parseConversion(dt, DS, DZ, DT), EPSILON); assertEquals(Math.pow(DZ, n * m), Series.parseConversion(dz, DS, DZ, DT), EPSILON); } - + @Test public void parseConversion_twoMixedTerms_returnsValue() { int n1 = randomIntBetween(1, 3); @@ -607,14 +743,32 @@ public void parseConversion_twoMixedTerms_returnsValue() { String dsdz = String.format("DS^%d.DZ^%d", n1, n2); String dzdt = String.format("DZ^%d.DT^%d", n1, n2); String dtdz = String.format("DT^%d.DZ^%d", n1, n2); - assertEquals(Math.pow(DS, n1) * Math.pow(DT, n2), Series.parseConversion(dsdt, DS, DZ, DT), EPSILON); - assertEquals(Math.pow(DT, n1) * Math.pow(DS, n2), Series.parseConversion(dtds, DS, DZ, DT), EPSILON); - assertEquals(Math.pow(DZ, n1) * Math.pow(DS, n2), Series.parseConversion(dzds, DS, DZ, DT), EPSILON); - assertEquals(Math.pow(DS, n1) * Math.pow(DZ, n2), Series.parseConversion(dsdz, DS, DZ, DT), EPSILON); - assertEquals(Math.pow(DZ, n1) * Math.pow(DT, n2), Series.parseConversion(dzdt, DS, DZ, DT), EPSILON); - assertEquals(Math.pow(DT, n1) * Math.pow(DZ, n2), Series.parseConversion(dtdz, DS, DZ, DT), EPSILON); + assertEquals( + Math.pow(DS, n1) * Math.pow(DT, n2), + Series.parseConversion(dsdt, DS, DZ, DT), + EPSILON); + assertEquals( + Math.pow(DT, n1) * Math.pow(DS, n2), + Series.parseConversion(dtds, DS, DZ, DT), + EPSILON); + assertEquals( + Math.pow(DZ, n1) * Math.pow(DS, n2), + Series.parseConversion(dzds, DS, DZ, DT), + EPSILON); + assertEquals( + Math.pow(DS, n1) * Math.pow(DZ, n2), + Series.parseConversion(dsdz, DS, DZ, DT), + EPSILON); + assertEquals( + Math.pow(DZ, n1) * Math.pow(DT, n2), + Series.parseConversion(dzdt, DS, DZ, DT), + EPSILON); + assertEquals( + Math.pow(DT, n1) * Math.pow(DZ, n2), + Series.parseConversion(dtdz, DS, DZ, DT), + EPSILON); } - + @Test public void parseConversion_threeMixedTerms_retrunsValue() { int n1 = randomIntBetween(1, 3); @@ -626,20 +780,32 @@ public void parseConversion_threeMixedTerms_retrunsValue() { String dzdtds = String.format("DZ^%d.DT^%d.DS^%d", n1, n2, n3); String dtdsdz = String.format("DT^%d.DS^%d.DZ^%d", n1, n2, n3); String dtdzds = String.format("DT^%d.DZ^%d.DS^%d", n1, n2, n3); - assertEquals(Math.pow(DS, n1) * Math.pow(DZ, n2) * Math.pow(DT, n3), - Series.parseConversion(dsdzdt, DS, DZ, DT), EPSILON); - assertEquals(Math.pow(DS, n1) * Math.pow(DT, n2) * Math.pow(DZ, n3), - Series.parseConversion(dsdtdz, DS, DZ, DT), EPSILON); - assertEquals(Math.pow(DZ, n1) * Math.pow(DS, n2) * Math.pow(DT, n3), - Series.parseConversion(dzdsdt, DS, DZ, DT), EPSILON); - assertEquals(Math.pow(DZ, n1) * Math.pow(DT, n2) * Math.pow(DS, n3), - Series.parseConversion(dzdtds, DS, DZ, DT), EPSILON); - assertEquals(Math.pow(DT, n1) * Math.pow(DS, n2) * Math.pow(DZ, n3), - Series.parseConversion(dtdsdz, DS, DZ, DT), EPSILON); - assertEquals(Math.pow(DT, n1) * Math.pow(DZ, n2) * Math.pow(DS, n3), - Series.parseConversion(dtdzds, DS, DZ, DT), EPSILON); - } - + assertEquals( + Math.pow(DS, n1) * Math.pow(DZ, n2) * Math.pow(DT, n3), + Series.parseConversion(dsdzdt, DS, DZ, DT), + EPSILON); + assertEquals( + Math.pow(DS, n1) * Math.pow(DT, n2) * Math.pow(DZ, n3), + Series.parseConversion(dsdtdz, DS, DZ, DT), + EPSILON); + assertEquals( + Math.pow(DZ, n1) * Math.pow(DS, n2) * Math.pow(DT, n3), + Series.parseConversion(dzdsdt, DS, DZ, DT), + EPSILON); + assertEquals( + Math.pow(DZ, n1) * Math.pow(DT, n2) * Math.pow(DS, n3), + Series.parseConversion(dzdtds, DS, DZ, DT), + EPSILON); + assertEquals( + Math.pow(DT, n1) * Math.pow(DS, n2) * Math.pow(DZ, n3), + Series.parseConversion(dtdsdz, DS, DZ, DT), + EPSILON); + assertEquals( + Math.pow(DT, n1) * Math.pow(DZ, n2) * Math.pow(DS, n3), + Series.parseConversion(dtdzds, DS, DZ, DT), + EPSILON); + } + @Test public void parseConversion_givenDSDT_retrunsValue() { int n1 = randomIntBetween(1, 3); @@ -651,14 +817,32 @@ public void parseConversion_givenDSDT_retrunsValue() { String dzdtds = String.format("DZ^%d.DT^%d.DS^%d", n1, n2, n3); String dtdsdz = String.format("DT^%d.DS^%d.DZ^%d", n1, n2, n3); String dtdzds = String.format("DT^%d.DZ^%d.DS^%d", n1, n2, n3); - assertEquals(Math.pow(DS, n1 + n2) * Math.pow(DT, n3), Series.parseConversion(dsdzdt, DS, DT), EPSILON); - assertEquals(Math.pow(DS, n1 + n3) * Math.pow(DT, n2), Series.parseConversion(dsdtdz, DS, DT), EPSILON); - assertEquals(Math.pow(DS, n1 + n2) * Math.pow(DT, n3), Series.parseConversion(dzdsdt, DS, DT), EPSILON); - assertEquals(Math.pow(DS, n1 + n3) * Math.pow(DT, n2), Series.parseConversion(dzdtds, DS, DT), EPSILON); - assertEquals(Math.pow(DT, n1) * Math.pow(DS, n2 + n3), Series.parseConversion(dtdsdz, DS, DT), EPSILON); - assertEquals(Math.pow(DT, n1) * Math.pow(DS, n2 + n3), Series.parseConversion(dtdzds, DS, DT), EPSILON); + assertEquals( + Math.pow(DS, n1 + n2) * Math.pow(DT, n3), + Series.parseConversion(dsdzdt, DS, DT), + EPSILON); + assertEquals( + Math.pow(DS, n1 + n3) * Math.pow(DT, n2), + Series.parseConversion(dsdtdz, DS, DT), + EPSILON); + assertEquals( + Math.pow(DS, n1 + n2) * Math.pow(DT, n3), + Series.parseConversion(dzdsdt, DS, DT), + EPSILON); + assertEquals( + Math.pow(DS, n1 + n3) * Math.pow(DT, n2), + Series.parseConversion(dzdtds, DS, DT), + EPSILON); + assertEquals( + Math.pow(DT, n1) * Math.pow(DS, n2 + n3), + Series.parseConversion(dtdsdz, DS, DT), + EPSILON); + assertEquals( + Math.pow(DT, n1) * Math.pow(DS, n2 + n3), + Series.parseConversion(dtdzds, DS, DT), + EPSILON); } - + @Test public void makeConstructors_validClasses_createsConstructors() { Series series = new SeriesMock(makeDicts(), SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false); @@ -666,54 +850,53 @@ public void makeConstructors_validClasses_createsConstructors() { assertEquals(SIM_CONSTRUCTOR_CLASS, series.simCons.getName()); assertEquals(VIS_CONSTRUCTOR_CLASS, series.visCons.getName()); } - + @Test public void makeConstructors_invalidSim_skipsSeries() { - SeriesMock series = new SeriesMock(makeDicts(), SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false); + SeriesMock series = + new SeriesMock(makeDicts(), SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false); series.invalidSim = true; series.makeConstructors(); assertTrue(series.isSkipped); } - + @Test public void makeConstructors_invalidVis_skipsSeries() { - SeriesMock series = new SeriesMock(makeDicts(), SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false); + SeriesMock series = + new SeriesMock(makeDicts(), SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false); series.invalidVis = true; series.makeConstructors(); assertTrue(series.isSkipped); } - + @Test public void makeConstructors_invalidClasses_skipsSeries() { - SeriesMock series = new SeriesMock(makeDicts(), SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false); + SeriesMock series = + new SeriesMock(makeDicts(), SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false); series.invalidSim = true; series.invalidVis = true; series.makeConstructors(); assertTrue(series.isSkipped); } - + @Test public void runSims_fromConstructors_callsMethods() throws Exception { - int[] start = new int[] { 0, 0, 10, 1 }; - int[] end = new int[] { 0, 1, 12, 0 }; - int[] n = new int[] { 1, 2, 3, 0 }; - int[][] seeds = new int[][] { - { 0 }, - { 0, 1 }, - { 10, 11, 12 }, - { } - }; - + int[] start = new int[] {0, 0, 10, 1}; + int[] end = new int[] {0, 1, 12, 0}; + int[] n = new int[] {1, 2, 3, 0}; + int[][] seeds = new int[][] {{0}, {0, 1}, {10, 11, 12}, {}}; + for (int i = 0; i < n.length; i++) { HashMap setupDicts = makeDicts(); setupDicts.get("series").put("start", start[i]); setupDicts.get("series").put("end", end[i]); - Series series = spy(new SeriesMock(setupDicts, SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false)); + Series series = + spy(new SeriesMock(setupDicts, SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false)); doNothing().when(series).runSim(any(SimState.class), any(int.class)); - + series.simCons = spy(series.simCons); series.runSims(); - + verify(series, times(n[i])).runSim(any(SimState.class), any(int.class)); for (int seed : seeds[i]) { verify(series.simCons).newInstance(start[i] + i + SEED_OFFSET, series); @@ -721,108 +904,113 @@ public void runSims_fromConstructors_callsMethods() throws Exception { } } } - + @Test public void runSim_repeatingStep_callsMethods() { HashMap setupDicts = makeDicts(); int ticks = randomIntBetween(1, 100); setupDicts.get("series").put("ticks", ticks); - Series series = spy(new SeriesMock(setupDicts, SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false)); - + Series series = + spy(new SeriesMock(setupDicts, SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false)); + SimState simstate = mock(SimState.class); simstate.schedule = spy(new Schedule()); - simstate.schedule.scheduleRepeating((Steppable) simState -> { }, 1); - + simstate.schedule.scheduleRepeating((Steppable) simState -> {}, 1); + series.runSim(simstate, randomIntBetween(1, 100)); - + verify(simstate).start(); verify(simstate).finish(); verify(simstate.schedule, times(ticks)).step(simstate); verify(simstate.schedule, times(ticks)).getTime(); } - + @Test public void runSim_singleStep_callsMethodsOnce() { HashMap setupDicts = makeDicts(); int ticks = randomIntBetween(1, 100); setupDicts.get("series").put("ticks", ticks + 1); - Series series = spy(new SeriesMock(setupDicts, SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false)); - + Series series = + spy(new SeriesMock(setupDicts, SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false)); + SimState simstate = mock(SimState.class); simstate.schedule = spy(new Schedule()); - simstate.schedule.scheduleOnce(ticks - 1, (Steppable) simState -> { }); - + simstate.schedule.scheduleOnce(ticks - 1, (Steppable) simState -> {}); + series.runSim(simstate, randomIntBetween(1, 100)); - + verify(simstate).start(); verify(simstate).finish(); verify(simstate.schedule, times(2)).step(simstate); verify(simstate.schedule).getTime(); } - + @Test public void runVis_fromConstructors_callsMethods() throws Exception { HashMap setupDicts = makeDicts(); - Series series = spy(new SeriesMock(setupDicts, SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false)); - + Series series = + spy(new SeriesMock(setupDicts, SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false)); + series.simCons = spy(series.simCons); series.visCons = spy(series.visCons); - + Simulation simstate = mock(Simulation.class); - GUIState guistate = spy(mock(GUIState.class)); - + GUIState guistate = mock(GUIState.class); + doReturn(null).when(guistate).createController(); doReturn(simstate).when(series.simCons).newInstance(any(int.class), eq(series)); doReturn(guistate).when(series.visCons).newInstance(any(Simulation.class)); - + System.clearProperty("java.awt.headless"); - + series.runVis(); verify(series.simCons).newInstance(series.getStartSeed() + SEED_OFFSET, series); verify(series.visCons).newInstance(simstate); verify(guistate).createController(); } - + @Test public void runVis_headlessFalse_callsMethods() throws Exception { HashMap setupDicts = makeDicts(); - Series series = spy(new SeriesMock(setupDicts, SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false)); - + Series series = + spy(new SeriesMock(setupDicts, SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false)); + series.simCons = spy(series.simCons); series.visCons = spy(series.visCons); - + Simulation simstate = mock(Simulation.class); - GUIState guistate = spy(mock(GUIState.class)); - + GUIState guistate = mock(GUIState.class); + doReturn(null).when(guistate).createController(); doReturn(simstate).when(series.simCons).newInstance(any(int.class), eq(series)); doReturn(guistate).when(series.visCons).newInstance(any(Simulation.class)); - + System.setProperty("java.awt.headless", "false"); - + series.runVis(); verify(series.simCons).newInstance(series.getStartSeed() + SEED_OFFSET, series); verify(series.visCons).newInstance(simstate); verify(guistate).createController(); } - + @Test public void runVis_headlessTrue_doesNothing() throws Exception { HashMap setupDicts = makeDicts(); - Series series = spy(new SeriesMock(setupDicts, SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false)); - + Series series = + spy(new SeriesMock(setupDicts, SETUP_LISTS_MOCK, TEST_PATH, PARAMETERS, false)); + series.simCons = spy(series.simCons); series.visCons = spy(series.visCons); - + Simulation simstate = mock(Simulation.class); - GUIState guistate = spy(mock(GUIState.class)); - + GUIState guistate = mock(GUIState.class); + doReturn(null).when(guistate).createController(); doReturn(simstate).when(series.simCons).newInstance(any(int.class), eq(series)); doReturn(guistate).when(series.visCons).newInstance(any(Simulation.class)); - + System.setProperty("java.awt.headless", "true"); - + series.runVis(); verify(series.simCons, never()).newInstance(series.getStartSeed() + SEED_OFFSET, series); verify(series.visCons, never()).newInstance(simstate); diff --git a/test/arcade/core/sim/input/InputBuilderTest.java b/test/arcade/core/sim/input/InputBuilderTest.java index 7e6283d08..1530fbc00 100644 --- a/test/arcade/core/sim/input/InputBuilderTest.java +++ b/test/arcade/core/sim/input/InputBuilderTest.java @@ -1,30 +1,26 @@ package arcade.core.sim.input; -import java.io.File; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; import java.util.stream.IntStream; -import org.apache.commons.io.FileUtils; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import arcade.core.sim.Series; import arcade.core.util.Box; import arcade.core.util.MiniBox; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.core.ARCADETestUtilities.*; public class InputBuilderTest { private static final String ATT_QNAME = randomString(); - + private static final String ATT_VALUE = randomString(); - - @Rule - public TemporaryFolder folder = new TemporaryFolder(); - + private static Attributes makeAttributesMock(int n) { Attributes attributes = mock(Attributes.class); doReturn(n).when(attributes).getLength(); @@ -34,153 +30,159 @@ private static Attributes makeAttributesMock(int n) { } return attributes; } - + static class InputBuilderMock extends InputBuilder { - InputBuilderMock() { super(); } - + InputBuilderMock() { + super(); + } + @Override - public void startElement(String uri, String local, String name, Attributes atts) { } - + public void startElement(String uri, String local, String name, Attributes atts) {} + @Override - public void endElement(String uri, String local, String name) { } + public void endElement(String uri, String local, String name) {} } - + @Test public void constructor_called_setsReader() { InputBuilder builder = new InputBuilderMock(); assertNotNull(builder.xmlReader); } - + @Test public void constructor_called_assignsContentHandler() { InputBuilder builder = new InputBuilderMock(); assertTrue(builder.xmlReader.getContentHandler() instanceof InputBuilder); } - + @Test - public void build_validInput_createsEmpty() throws IOException, SAXException { - File file = folder.newFile("build_validInput_createsEmpty.xml"); - FileUtils.writeStringToFile(file, "", "UTF-8"); - + public void build_validInput_createsEmpty(@TempDir Path path) throws IOException, SAXException { + Path file = Files.createFile(path.resolve("build.xml")); + Files.writeString(file, ""); + InputBuilder builder = new InputBuilderMock(); - ArrayList series = builder.build(file.getAbsolutePath()); - + ArrayList series = builder.build(file.toAbsolutePath().toString()); + assertEquals(0, series.size()); } - + @Test - public void build_validInput_createsList() throws IOException, SAXException { - File file = folder.newFile("build_validInput_createsList.xml"); - FileUtils.writeStringToFile(file, "", "UTF-8"); - + public void build_validInput_createsList(@TempDir Path path) throws IOException, SAXException { + Path file = Files.createFile(path.resolve("build.xml")); + Files.writeString(file, ""); + InputBuilder builder = new InputBuilderMock(); - builder.build(file.getAbsolutePath()); - + builder.build(file.toAbsolutePath().toString()); + assertNotNull(builder.series); } - - @Test(expected = SAXException.class) - public void build_invalid_throwsException() throws IOException, SAXException { - File file = folder.newFile("build_invalid_throwsException.xml"); - InputBuilder builder = new InputBuilderMock(); - builder.build(file.getAbsolutePath()); + + @Test + public void build_invalid_throwsException(@TempDir Path path) { + assertThrows( + SAXException.class, + () -> { + Path file = Files.createFile(path.resolve("build.xml")); + InputBuilder builder = new InputBuilderMock(); + builder.build(file.toAbsolutePath().toString()); + }); } - + @Test public void makeMiniBox_validInput_createsContainer() { int n = randomIntBetween(3, 10); InputBuilder builder = mock(InputBuilder.class, CALLS_REAL_METHODS); Attributes attributes = makeAttributesMock(n); MiniBox box = builder.makeMiniBox(attributes); - + MiniBox expected = new MiniBox(); IntStream.range(0, n).forEach(i -> expected.put(ATT_QNAME + i, ATT_VALUE + i)); - + assertTrue(expected.compare(box)); } - + @Test public void makeBox_validInput_createsContainer() { int n = randomIntBetween(3, 10); InputBuilder builder = mock(InputBuilder.class, CALLS_REAL_METHODS); Attributes attributes = makeAttributesMock(n); Box box = builder.makeBox(attributes); - + Box expected = new Box(); IntStream.range(0, n).forEach(i -> expected.add(ATT_QNAME + i, ATT_VALUE + i)); - + assertTrue(expected.compare(box)); } - + @Test public void startPrefixMapping_called_doesNothing() { InputBuilder builder = new InputBuilderMock(); - + String prefix = randomString(); String uri = randomString(); builder.startPrefixMapping(prefix, uri); - + assertNull(builder.setupDicts); assertNull(builder.setupLists); } - + @Test public void endPrefixMapping_called_doesNothing() { InputBuilder builder = new InputBuilderMock(); - + String prefix = randomString(); String uri = randomString(); builder.endPrefixMapping(prefix); - + assertNull(builder.setupDicts); assertNull(builder.setupLists); } - + @Test public void skippedEntity_called_doesNothing() { InputBuilder builder = new InputBuilderMock(); - + String name = randomString(); builder.skippedEntity(name); - + assertNull(builder.setupDicts); assertNull(builder.setupLists); } - + @Test public void characters_called_doesNothing() { InputBuilder builder = new InputBuilderMock(); - + int start = randomIntBetween(1, 10); int length = randomIntBetween(1, 10); char[] ch = new char[start + length]; builder.characters(ch, start, length); - + assertNull(builder.setupDicts); assertNull(builder.setupLists); } - + @Test public void ignorableWhitespace_called_doesNothing() { InputBuilder builder = new InputBuilderMock(); - + int start = randomIntBetween(1, 10); int length = randomIntBetween(1, 10); char[] ch = new char[start + length]; builder.ignorableWhitespace(ch, start, length); - + assertNull(builder.setupDicts); assertNull(builder.setupLists); } - + @Test public void processingInstruction_called_doesNothing() { InputBuilder builder = new InputBuilderMock(); - + String target = randomString(); String data = randomString(); builder.processingInstruction(target, data); - + assertNull(builder.setupDicts); assertNull(builder.setupLists); } diff --git a/test/arcade/core/sim/input/InputLoaderTest.java b/test/arcade/core/sim/input/InputLoaderTest.java index 09bdeba26..f8bdb0836 100644 --- a/test/arcade/core/sim/input/InputLoaderTest.java +++ b/test/arcade/core/sim/input/InputLoaderTest.java @@ -1,91 +1,93 @@ package arcade.core.sim.input; -import java.io.File; import java.io.IOException; -import org.apache.commons.io.FileUtils; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; +import java.nio.file.Files; +import java.nio.file.Path; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import arcade.core.util.Box; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.core.util.MiniBox.TAG_SEPARATOR; public class InputLoaderTest { - @Rule - public TemporaryFolder folder = new TemporaryFolder(); - @Test public void constructor_called_setsReader() { InputLoader loader = new InputLoader(); assertNotNull(loader.xmlReader); } - + @Test public void constructor_called_assignsContentHandler() { InputLoader loader = new InputLoader(); assertTrue(loader.xmlReader.getContentHandler() instanceof InputLoader); } - + @Test - public void load_validInput_createsBox() throws IOException, SAXException { - File file = folder.newFile("load_validInput_createsBox.xml"); - FileUtils.writeStringToFile(file, "", "UTF-8"); - + public void load_validInput_createsBox(@TempDir Path path) throws IOException, SAXException { + Path file = Files.createFile(path.resolve("load.xml")); + Files.writeString(file, ""); + InputLoader loader = new InputLoader(); - loader.load(file.getAbsolutePath()); + loader.load(file.toAbsolutePath().toString()); assertNotNull(loader.box); } - + @Test - public void load_validInputGivenBox_usesBox() throws IOException, SAXException { - File file = folder.newFile("load_validInput_createsBox.xml"); - FileUtils.writeStringToFile(file, "", "UTF-8"); - + public void load_validInputGivenBox_usesBox(@TempDir Path path) + throws IOException, SAXException { + Path file = Files.createFile(path.resolve("load.xml")); + Files.writeString(file, ""); + InputLoader loader = new InputLoader(); Box box = new Box(); - loader.load(file.getAbsolutePath(), box); + loader.load(file.toAbsolutePath().toString(), box); assertNotNull(loader.box); assertSame(box, loader.box); } - + @Test - public void load_validInputNoContents_loadsBox() throws IOException, SAXException { - File file = folder.newFile("load_validInputNoContents_loadsBox.xml"); - FileUtils.writeStringToFile(file, "", "UTF-8"); - + public void load_validInputNoContents_loadsBox(@TempDir Path path) + throws IOException, SAXException { + Path file = Files.createFile(path.resolve("load.xml")); + Files.writeString(file, ""); + InputLoader loader = new InputLoader(); - Box box = loader.load(file.getAbsolutePath()); - + Box box = loader.load(file.toAbsolutePath().toString()); + assertTrue(box.compare(new Box())); } - + @Test - public void load_validInputNoContentsGivenBox_updatesBox() throws IOException, SAXException { - File file = folder.newFile("load_validInputNoContentsGivenBox_updatesBox.xml"); - FileUtils.writeStringToFile(file, "", "UTF-8"); - + public void load_validInputNoContentsGivenBox_updatesBox(@TempDir Path path) + throws IOException, SAXException { + Path file = Files.createFile(path.resolve("load.xml")); + Files.writeString(file, ""); + InputLoader loader = new InputLoader(); Box box = new Box(); - Box updated = loader.load(file.getAbsolutePath(), box); - + Box updated = loader.load(file.toAbsolutePath().toString(), box); + assertSame(updated, box); assertTrue(box.compare(new Box())); } - + @Test - public void load_validInputWithContents_loadsBox() throws IOException, SAXException { - File file = folder.newFile("load_validInputWithContents_loadsBox.xml"); - FileUtils.writeStringToFile(file, "" - + "" - + "" - + "", "UTF-8"); - + public void load_validInputWithContents_loadsBox(@TempDir Path path) + throws IOException, SAXException { + Path file = Files.createFile(path.resolve("load.xml")); + Files.writeString( + file, + "" + + "" + + "" + + ""); + InputLoader loader = new InputLoader(); - Box box = loader.load(file.getAbsolutePath()); - + Box box = loader.load(file.toAbsolutePath().toString()); + Box expected = new Box(); expected.addAtt("id1", "att1", "value11"); expected.addAtt("id1", "att2", "value12"); @@ -93,22 +95,25 @@ public void load_validInputWithContents_loadsBox() throws IOException, SAXExcept expected.addAtt("id2", "att2", "value22"); expected.addTag("id1", "TAG1"); expected.addTag("id2", "TAG2"); - + assertTrue(box.compare(expected)); } - + @Test - public void load_validInputWithContentsGivenBox_updatesBox() throws IOException, SAXException { - File file = folder.newFile("load_validInputWithContents_loadsBox.xml"); - FileUtils.writeStringToFile(file, "" - + "" - + "" - + "", "UTF-8"); - + public void load_validInputWithContentsGivenBox_updatesBox(@TempDir Path path) + throws IOException, SAXException { + Path file = Files.createFile(path.resolve("load.xml")); + Files.writeString( + file, + "" + + "" + + "" + + ""); + InputLoader loader = new InputLoader(); Box box = new Box(); - Box updated = loader.load(file.getAbsolutePath(), box); - + Box updated = loader.load(file.toAbsolutePath().toString(), box); + Box expected = new Box(); expected.addAtt("id1", "att1", "value11"); expected.addAtt("id1", "att2", "value12"); @@ -116,112 +121,120 @@ public void load_validInputWithContentsGivenBox_updatesBox() throws IOException, expected.addAtt("id2", "att2", "value22"); expected.addTag("id1", "TAG1"); expected.addTag("id2", "TAG2"); - + assertSame(updated, box); assertTrue(box.compare(expected)); } - - @Test(expected = SAXException.class) - public void load_invalid_throwsException() throws IOException, SAXException { - File file = folder.newFile("load_invalid_throwsException.xml"); - InputLoader loader = new InputLoader(); - loader.load(file.getAbsolutePath()); + + @Test + public void load_invalid_throwsException(@TempDir Path path) { + assertThrows( + SAXException.class, + () -> { + Path file = Files.createFile(path.resolve("load.xml")); + InputLoader loader = new InputLoader(); + loader.load(file.toAbsolutePath().toString()); + }); } - - @Test(expected = SAXException.class) - public void load_invalidGivenBox_throwsException() throws IOException, SAXException { - File file = folder.newFile("load_invalid_throwsException.xml"); - InputLoader loader = new InputLoader(); - loader.load(file.getAbsolutePath(), new Box()); + + @Test + public void load_invalidGivenBox_throwsException(@TempDir Path path) { + assertThrows( + SAXException.class, + () -> { + Path file = Files.createFile(path.resolve("load.xml")); + InputLoader loader = new InputLoader(); + loader.load(file.toAbsolutePath().toString(), new Box()); + }); } - + @Test public void startElement_noAttributes_doesNothing() { InputLoader loader = mock(InputLoader.class, CALLS_REAL_METHODS); loader.box = new Box(); - + Attributes attributes = mock(Attributes.class); doReturn(0).when(attributes).getLength(); - + loader.startElement("", "", "name", attributes); assertTrue(loader.box.compare(new Box())); } - + @Test public void startElement_hasAttributes_loadsAttributes() { InputLoader loader = mock(InputLoader.class, CALLS_REAL_METHODS); loader.box = new Box(); - + Attributes attributes = mock(Attributes.class); doReturn(3).when(attributes).getLength(); - + doReturn("qname0").when(attributes).getQName(0); doReturn("qname1").when(attributes).getQName(1); doReturn("id").when(attributes).getQName(2); - + doReturn("value0").when(attributes).getValue(0); doReturn("value1").when(attributes).getValue(1); doReturn("attid").when(attributes).getValue(2); - + doReturn("value0").when(attributes).getValue("qname0"); doReturn("value1").when(attributes).getValue("qname1"); doReturn("attid").when(attributes).getValue("id"); - + loader.startElement("", "", "name", attributes); - + Box expected = new Box(); expected.addTag("attid", "NAME"); expected.addAtt("attid", "qname0", "value0"); expected.addAtt("attid", "qname1", "value1"); - + assertTrue(expected.compare(loader.box)); } - + @Test public void startElement_hasTagAttribute_setsTags() { InputLoader loader = mock(InputLoader.class, CALLS_REAL_METHODS); loader.box = new Box(); - + Attributes attributes = mock(Attributes.class); doReturn(3).when(attributes).getLength(); - + doReturn("qname0").when(attributes).getQName(0); doReturn("tag").when(attributes).getQName(1); doReturn("qname2").when(attributes).getQName(2); doReturn("id").when(attributes).getQName(3); - + doReturn("value0").when(attributes).getValue(0); doReturn("value1").when(attributes).getValue(1); doReturn("value2").when(attributes).getValue(2); doReturn("attid").when(attributes).getValue(3); - + doReturn("value0").when(attributes).getValue("qname0"); doReturn("value1").when(attributes).getValue("tag"); doReturn("value2").when(attributes).getValue("qname2"); doReturn("attid").when(attributes).getValue("id"); - + loader.startElement("", "", "name.tag", attributes); - + Box expected = new Box(); expected.addTag("value1" + TAG_SEPARATOR + "attid", "NAME"); expected.addAtt("value1" + TAG_SEPARATOR + "attid", "qname0", "value0"); expected.addAtt("value1" + TAG_SEPARATOR + "attid", "qname2", "value2"); - + assertTrue(expected.compare(loader.box)); } - + @Test public void startElement_invalidTag_doesNothing() { InputLoader loader = mock(InputLoader.class, CALLS_REAL_METHODS); loader.box = new Box(); - + Attributes attributes = mock(Attributes.class); doReturn(1).when(attributes).getLength(); - + doReturn("id").when(attributes).getQName(0); doReturn("attid").when(attributes).getValue(0); doReturn("attid").when(attributes).getValue("id"); - + loader.startElement("", "", "name.tag", attributes); assertTrue(loader.box.compare(new Box())); } diff --git a/test/arcade/core/sim/input/InputParserTest.java b/test/arcade/core/sim/input/InputParserTest.java index 52a078735..1ba47c7c8 100644 --- a/test/arcade/core/sim/input/InputParserTest.java +++ b/test/arcade/core/sim/input/InputParserTest.java @@ -1,19 +1,19 @@ package arcade.core.sim.input; -import org.junit.Test; +import org.junit.jupiter.api.Test; import arcade.core.util.Box; import arcade.core.util.MiniBox; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static arcade.core.ARCADETestUtilities.*; import static arcade.core.sim.input.InputParser.*; public class InputParserTest { private static final String COMMAND_ID_1 = randomString(); - + private static final String COMMAND_ID_2 = randomString(); - + private static final String COMMAND_ID_3 = randomString(); - + @Test public void constructor_called_setsObjects() { InputParser parser = new InputParser(new Box()); @@ -22,104 +22,104 @@ public void constructor_called_setsObjects() { assertNotNull(parser.longToCommand); assertNotNull(parser.positionCommands); } - + @Test public void constructor_invalidTag_skipsTag() { Box box = new Box(); box.addTag(COMMAND_ID_1, "INVALID"); - + InputParser parser = new InputParser(box); - + assertEquals(0, parser.allCommands.size()); assertEquals(0, parser.positionCommands.size()); assertEquals(0, parser.shortToCommand.size()); assertEquals(0, parser.longToCommand.size()); } - + @Test public void constructor_emptyTags_addsCommands() { Box box = new Box(); box.addTag(COMMAND_ID_1, "POSITION"); box.addTag(COMMAND_ID_2, "OPTION"); box.addTag(COMMAND_ID_3, "SWITCH"); - + InputParser parser = new InputParser(box); - + assertEquals(3, parser.allCommands.size()); assertEquals(1, parser.positionCommands.size()); assertEquals(0, parser.shortToCommand.size()); assertEquals(0, parser.longToCommand.size()); } - + @Test public void constructor_withFlags_addsCommands() { String longFlag = randomString(); String shortFlag = randomString(); - + Box box = new Box(); box.addTag(COMMAND_ID_2, "OPTION"); box.addTag(COMMAND_ID_3, "SWITCH"); box.addAtt(COMMAND_ID_2, "long", longFlag); box.addAtt(COMMAND_ID_3, "short", shortFlag); - + InputParser parser = new InputParser(box); - + assertEquals(2, parser.allCommands.size()); assertEquals(0, parser.positionCommands.size()); assertEquals(1, parser.shortToCommand.size()); assertEquals(1, parser.longToCommand.size()); } - + @Test public void constructor_invalidFlag_skipsFlag() { String longFlag = randomString(); String invalidFlag = randomString(); - + Box box = new Box(); box.addTag(COMMAND_ID_1, "OPTION"); box.addAtt(COMMAND_ID_1, "long", longFlag); box.addAtt(COMMAND_ID_1, "invalid", invalidFlag); InputParser parser = new InputParser(box); - + assertEquals(1, parser.allCommands.size()); assertEquals(0, parser.positionCommands.size()); assertEquals(0, parser.shortToCommand.size()); assertEquals(1, parser.longToCommand.size()); } - + @Test public void constructor_emptyTags_assignsTypes() { Box box = new Box(); box.addTag(COMMAND_ID_1, "POSITION"); box.addTag(COMMAND_ID_2, "OPTION"); box.addTag(COMMAND_ID_3, "SWITCH"); - + InputParser parser = new InputParser(box); - + assertEquals(POSITION, parser.allCommands.get(0).type); assertEquals(OPTION, parser.allCommands.get(1).type); assertEquals(SWITCH, parser.allCommands.get(2).type); } - + @Test public void constructor_givenHelp_assignsField() { String helpText1 = randomString(); String helpText2 = randomString(); - + Box box = new Box(); box.addTag(COMMAND_ID_1, "POSITION"); box.addTag(COMMAND_ID_2, "OPTION"); box.addTag(COMMAND_ID_3, "SWITCH"); box.addAtt(COMMAND_ID_1, "help", helpText1); box.addAtt(COMMAND_ID_3, "help", helpText2); - + InputParser parser = new InputParser(box); - + assertEquals(helpText1, parser.allCommands.get(0).help); assertEquals(helpText2, parser.allCommands.get(2).help); assertNull(parser.allCommands.get(1).help); } - + @Test public void constructor_givenDefaultOption_assignsField() { String defaultValue1 = randomString(); @@ -129,7 +129,7 @@ public void constructor_givenDefaultOption_assignsField() { InputParser parser = new InputParser(box); assertEquals(defaultValue1, parser.allCommands.get(0).defaults); } - + @Test public void constructor_givenDefaultSwitch_doesNothing() { Box box = new Box(); @@ -138,7 +138,7 @@ public void constructor_givenDefaultSwitch_doesNothing() { InputParser parser = new InputParser(box); assertNull(parser.allCommands.get(0).defaults); } - + @Test public void constructor_givenDefaultPosition_doesNothing() { Box box = new Box(); @@ -147,373 +147,369 @@ public void constructor_givenDefaultPosition_doesNothing() { InputParser parser = new InputParser(box); assertNull(parser.allCommands.get(0).defaults); } - + @Test public void constructor_givenShortFlagNotPosition_assignsField() { String shortFlag = randomString(); - + Box box = new Box(); box.addTag(COMMAND_ID_1, "OPTION"); box.addTag(COMMAND_ID_2, "SWITCH"); box.addAtt(COMMAND_ID_1, "short", shortFlag); - + InputParser parser = new InputParser(box); - + assertEquals(shortFlag, parser.allCommands.get(0).shortFlag); assertNull(parser.allCommands.get(1).shortFlag); } - + @Test public void constructor_givenLongFlagNotPosition_assignsField() { String longFlag = randomString(); - + Box box = new Box(); box.addTag(COMMAND_ID_1, "OPTION"); box.addTag(COMMAND_ID_2, "SWITCH"); box.addAtt(COMMAND_ID_1, "long", longFlag); - + InputParser parser = new InputParser(box); - + assertEquals(longFlag, parser.allCommands.get(0).longFlag); assertNull(parser.allCommands.get(1).longFlag); } - + @Test public void constructor_givenBothFlagsNotPosition_assignsField() { String shortFlag = randomString(); String longFlag = randomString(); - + Box box = new Box(); box.addTag(COMMAND_ID_1, "OPTION"); box.addTag(COMMAND_ID_2, "SWITCH"); box.addAtt(COMMAND_ID_2, "short", shortFlag); box.addAtt(COMMAND_ID_2, "long", longFlag); - + InputParser parser = new InputParser(box); - + assertEquals(shortFlag, parser.allCommands.get(1).shortFlag); assertEquals(longFlag, parser.allCommands.get(1).longFlag); assertNull(parser.allCommands.get(0).shortFlag); assertNull(parser.allCommands.get(0).longFlag); } - + @Test public void constructor_givenBothFlagsPosition_doesNothing() { String shortFlag = randomString(); String longFlag = randomString(); - + Box box = new Box(); box.addTag(COMMAND_ID_1, "POSITION"); box.addAtt(COMMAND_ID_1, "short", shortFlag); box.addAtt(COMMAND_ID_1, "long", longFlag); - + InputParser parser = new InputParser(box); - + assertNull(parser.allCommands.get(0).shortFlag); assertNull(parser.allCommands.get(0).longFlag); } - + @Test public void parse_noConfigNoArgs_returnsEmpty() { Box box = new Box(); InputParser parser = new InputParser(box); - MiniBox parsed = parser.parse(new String[] { }); + MiniBox parsed = parser.parse(new String[] {}); assertTrue(parsed.compare(new MiniBox())); } - + @Test public void parse_withoutPositionNoArgs_returnsEmpty() { Box box = new Box(); box.addTag(COMMAND_ID_1, "SWITCH"); - + InputParser parser = new InputParser(box); - MiniBox parsed = parser.parse(new String[] { }); + MiniBox parsed = parser.parse(new String[] {}); assertTrue(parsed.compare(new MiniBox())); } - - @Test(expected = IllegalArgumentException.class) + + @Test public void parse_withPositionNoArgs_throwsException() { - Box box = new Box(); - box.addTag(COMMAND_ID_1, "POSITION"); - - InputParser parser = new InputParser(box); - MiniBox parsed = parser.parse(new String[] { }); - assertTrue(parsed.compare(new MiniBox())); + assertThrows( + IllegalArgumentException.class, + () -> { + Box box = new Box(); + box.addTag(COMMAND_ID_1, "POSITION"); + + InputParser parser = new InputParser(box); + MiniBox parsed = parser.parse(new String[] {}); + assertTrue(parsed.compare(new MiniBox())); + }); } - + @Test public void parse_withDefaultsNoArgs_usesDefaults() { String defaultValue = randomString(); Box box = new Box(); box.addTag(COMMAND_ID_1, "OPTION"); box.addAtt(COMMAND_ID_1, "default", defaultValue); - + InputParser parser = new InputParser(box); - MiniBox parsed = parser.parse(new String[] { }); - + MiniBox parsed = parser.parse(new String[] {}); + MiniBox expected = new MiniBox(); expected.put(COMMAND_ID_1, defaultValue); - + assertTrue(parsed.compare(expected)); } - + @Test public void parse_withArgs_updatesValues() { String defaultValue1 = randomString(); String defaultValue2 = randomString(); String newValue = randomString(); String longFlag = randomString(); - + Box box = new Box(); box.addTag(COMMAND_ID_1, "OPTION"); box.addAtt(COMMAND_ID_1, "default", defaultValue1); box.addAtt(COMMAND_ID_1, "long", longFlag); box.addTag(COMMAND_ID_2, "OPTION"); box.addAtt(COMMAND_ID_2, "default", defaultValue2); - + InputParser parser = new InputParser(box); - MiniBox parsed = parser.parse(new String[] { - "--" + longFlag, - newValue - }); - + MiniBox parsed = parser.parse(new String[] {"--" + longFlag, newValue}); + MiniBox expected = new MiniBox(); expected.put(COMMAND_ID_1, newValue); expected.put(COMMAND_ID_2, defaultValue2); - + assertTrue(parsed.compare(expected)); } - + @Test public void addDefaults_onlyPositions_doesNothing() { Box box = new Box(); box.addTag(COMMAND_ID_1, "POSITION"); box.addTag(COMMAND_ID_2, "POSITION"); - + InputParser parser = new InputParser(box); parser.parsed = new MiniBox(); - + parser.addDefaults(); assertTrue(parser.parsed.compare(new MiniBox())); } - + @Test public void addDefaults_noDefaults_doesNothing() { Box box = new Box(); box.addTag(COMMAND_ID_1, "SWITCH"); box.addTag(COMMAND_ID_2, "SWITCH"); box.addTag(COMMAND_ID_3, "OPTION"); - + InputParser parser = new InputParser(box); parser.parsed = new MiniBox(); - + parser.addDefaults(); assertTrue(parser.parsed.compare(new MiniBox())); } - + @Test public void addDefaults_hasDefaults_setsDefaults() { String defaultValue1 = randomString(); String defaultValue2 = randomString(); - + Box box = new Box(); box.addTag(COMMAND_ID_1, "OPTION"); box.addTag(COMMAND_ID_2, "OPTION"); box.addTag(COMMAND_ID_3, "OPTION"); box.addAtt(COMMAND_ID_2, "default", defaultValue1); box.addAtt(COMMAND_ID_3, "default", defaultValue2); - + InputParser parser = new InputParser(box); parser.parsed = new MiniBox(); parser.addDefaults(); - + MiniBox expected = new MiniBox(); expected.put(COMMAND_ID_2, defaultValue1); expected.put(COMMAND_ID_3, defaultValue2); - + assertTrue(parser.parsed.compare(expected)); } - + @Test public void parseArg_givenPositions_parsesArgument() { Box box = new Box(); box.addTag(COMMAND_ID_1, "POSITION"); box.addTag(COMMAND_ID_2, "POSITION"); - - String[] arguments = new String[] { - randomString(), - randomString(), - }; - + + String[] arguments = + new String[] { + randomString(), randomString(), + }; + InputParser parser = new InputParser(box); parser.parsed = new MiniBox(); parser.parseArguments(arguments); - + MiniBox expected = new MiniBox(); expected.put(COMMAND_ID_1, arguments[0]); expected.put(COMMAND_ID_2, arguments[1]); - + assertTrue(parser.parsed.compare(expected)); } - + @Test public void parseArg_givenOptions_parsesArgument() { String shortFlag = randomString(); String longFlag = randomString(); - + Box box = new Box(); box.addTag(COMMAND_ID_1, "OPTION"); box.addAtt(COMMAND_ID_1, "short", shortFlag); box.addTag(COMMAND_ID_2, "OPTION"); box.addAtt(COMMAND_ID_2, "long", longFlag); - - String[] arguments = new String[] { - "--" + longFlag, - randomString(), - "-" + shortFlag, - randomString(), - }; - + + String[] arguments = + new String[] { + "--" + longFlag, randomString(), "-" + shortFlag, randomString(), + }; + InputParser parser = new InputParser(box); parser.parsed = new MiniBox(); parser.parseArguments(arguments); - + MiniBox expected = new MiniBox(); expected.put(COMMAND_ID_1, arguments[3]); expected.put(COMMAND_ID_2, arguments[1]); - + assertTrue(parser.parsed.compare(expected)); } - + @Test public void parseArg_givenSwitches_parsesArgument() { String shortFlag = randomString(); String longFlag = randomString(); - + Box box = new Box(); box.addTag(COMMAND_ID_1, "SWITCH"); box.addAtt(COMMAND_ID_1, "short", shortFlag); box.addTag(COMMAND_ID_2, "SWITCH"); box.addAtt(COMMAND_ID_2, "long", longFlag); box.addTag(COMMAND_ID_3, "SWITCH"); - - String[] arguments = new String[] { - "--" + longFlag, - "-" + shortFlag - }; - + + String[] arguments = new String[] {"--" + longFlag, "-" + shortFlag}; + InputParser parser = new InputParser(box); parser.parsed = new MiniBox(); parser.parseArguments(arguments); - + MiniBox expected = new MiniBox(); expected.put(COMMAND_ID_1, ""); expected.put(COMMAND_ID_2, ""); - + assertTrue(parser.parsed.compare(expected)); } - + @Test public void parsePositionArgument_givenPosition_parsesArgument() { Box box = new Box(); box.addTag(COMMAND_ID_1, "POSITION"); box.addTag(COMMAND_ID_2, "POSITION"); - + InputParser parser = new InputParser(box); parser.parsed = new MiniBox(); parser.positionIndex = 1; - + int index = randomIntBetween(1, 10); String[] arguments = randomStringArray(index + randomIntBetween(1, 10)); arguments[index] = randomString(); parser.parsePositionArgument(arguments, index); - + MiniBox expected = new MiniBox(); expected.put(COMMAND_ID_2, arguments[index]); - + assertTrue(parser.parsed.compare(expected)); assertEquals(2, parser.positionIndex); } - + @Test public void parsePositionArgument_givenPosition_updatesIndex() { Box box = new Box(); box.addTag(COMMAND_ID_1, "POSITION"); box.addTag(COMMAND_ID_2, "POSITION"); - + InputParser parser = new InputParser(box); parser.parsed = new MiniBox(); parser.positionIndex = 1; - + int index = randomIntBetween(1, 10); String[] arguments = randomStringArray(index + randomIntBetween(1, 10)); int newIndex = parser.parsePositionArgument(arguments, index); - + assertEquals(index + 1, newIndex); } - + @Test public void parseFlaggedArgument_givenSwitch_parsesArgument() { Box box = new Box(); box.addTag(COMMAND_ID_1, "SWITCH"); - + InputParser parser = new InputParser(box); parser.parsed = new MiniBox(); - + int index = randomIntBetween(1, 10); String[] arguments = randomStringArray(index + randomIntBetween(1, 10)); parser.parseFlaggedArgument(arguments, index, parser.allCommands.get(0)); - + MiniBox expected = new MiniBox(); expected.put(COMMAND_ID_1, ""); assertTrue(parser.parsed.compare(expected)); } - + @Test public void parseFlaggedArgument_givenSwitch_updatesIndex() { Box box = new Box(); box.addTag(COMMAND_ID_1, "SWITCH"); - + InputParser parser = new InputParser(box); parser.parsed = new MiniBox(); - + int index = randomIntBetween(1, 10); String[] arguments = randomStringArray(index + randomIntBetween(1, 10)); int newIndex = parser.parseFlaggedArgument(arguments, index, parser.allCommands.get(0)); - + assertEquals(index + 1, newIndex); } - + @Test public void parseFlaggedArgument_givenOption_parsesArgument() { Box box = new Box(); box.addTag(COMMAND_ID_1, "OPTION"); - + InputParser parser = new InputParser(box); parser.parsed = new MiniBox(); - + int index = randomIntBetween(1, 10); String[] arguments = randomStringArray(index + randomIntBetween(2, 10)); arguments[index + 1] = arguments[index]; parser.parseFlaggedArgument(arguments, index, parser.allCommands.get(0)); - + MiniBox expected = new MiniBox(); expected.put(COMMAND_ID_1, arguments[index + 1]); assertTrue(parser.parsed.compare(expected)); } - + @Test public void parseFlaggedArgument_givenOption_updatesIndex() { Box box = new Box(); box.addTag(COMMAND_ID_1, "OPTION"); - + InputParser parser = new InputParser(box); parser.parsed = new MiniBox(); - + int index = randomIntBetween(1, 10); String[] arguments = randomStringArray(index + randomIntBetween(2, 10)); int newIndex = parser.parseFlaggedArgument(arguments, index, parser.allCommands.get(0)); - + assertEquals(index + 2, newIndex); } } diff --git a/test/arcade/core/sim/output/OutputDeserializerTest.java b/test/arcade/core/sim/output/OutputDeserializerTest.java index 5f332e14b..34f51a5ef 100644 --- a/test/arcade/core/sim/output/OutputDeserializerTest.java +++ b/test/arcade/core/sim/output/OutputDeserializerTest.java @@ -2,7 +2,7 @@ import java.lang.reflect.Type; import java.util.ArrayList; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonArray; @@ -15,65 +15,65 @@ import com.google.gson.reflect.TypeToken; import arcade.core.agent.cell.CellContainer; import arcade.core.env.location.LocationContainer; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.core.ARCADETestUtilities.*; import static arcade.core.sim.output.OutputDeserializer.*; public class OutputDeserializerTest { - static final JsonDeserializationContext CELL_CONTEXT = new JsonDeserializationContext() { - @Override - public T deserialize(JsonElement json, Type typeOfT) - throws JsonParseException { - JsonObject array = json.getAsJsonObject(); - int id = array.get("id").getAsInt(); - CellContainer container = mock(CellContainer.class); - doReturn(id).when(container).getID(); - return (T) container; - } - }; - - static final JsonDeserializationContext LOCATION_CONTEXT = new JsonDeserializationContext() { - @Override - public T deserialize(JsonElement json, Type typeOfT) - throws JsonParseException { - JsonObject array = json.getAsJsonObject(); - int id = array.get("id").getAsInt(); - LocationContainer container = mock(LocationContainer.class); - doReturn(id).when(container).getID(); - return (T) container; - } - }; - + static final JsonDeserializationContext CELL_CONTEXT = + new JsonDeserializationContext() { + @Override + public T deserialize(JsonElement json, Type typeOfT) throws JsonParseException { + JsonObject array = json.getAsJsonObject(); + int id = array.get("id").getAsInt(); + CellContainer container = mock(CellContainer.class); + doReturn(id).when(container).getID(); + return (T) container; + } + }; + + static final JsonDeserializationContext LOCATION_CONTEXT = + new JsonDeserializationContext() { + @Override + public T deserialize(JsonElement json, Type typeOfT) throws JsonParseException { + JsonObject array = json.getAsJsonObject(); + int id = array.get("id").getAsInt(); + LocationContainer container = mock(LocationContainer.class); + doReturn(id).when(container).getID(); + return (T) container; + } + }; + public static void checkAdaptors(Gson gson) { TypeToken> cellContainerList = - new TypeToken>() { }; + new TypeToken>() {}; assertSame(gson.getAdapter(cellContainerList).getClass(), TreeTypeAdapter.class); - + TypeToken> locationContainerList = - new TypeToken>() { }; + new TypeToken>() {}; assertSame(gson.getAdapter(locationContainerList).getClass(), TreeTypeAdapter.class); } - - @Test(expected = UnsupportedOperationException.class) + + @Test public void constructor_called_throwsException() { - OutputDeserializer deserializer = new OutputDeserializer(); + assertThrows(UnsupportedOperationException.class, OutputDeserializer::new); } - + @Test public void makeGSON_registersAdaptors() { GsonBuilder gsonBuilder = OutputDeserializer.makeGSONBuilder(); Gson gson = gsonBuilder.create(); checkAdaptors(gson); } - + @Test public void deserializer_forCellContainerList_createsObject() { CellListDeserializer deserializer = new CellListDeserializer(); - + int n = randomIntBetween(1, 10); int id0 = randomIntBetween(1, 10); - + StringBuilder string = new StringBuilder("["); for (int i = 0; i < n; i++) { int id = id0 + i; @@ -83,24 +83,25 @@ public void deserializer_forCellContainerList_createsObject() { } } string.append("]"); - + JsonArray json = JsonParser.parseString(string.toString()).getAsJsonArray(); - ArrayList object = deserializer.deserialize(json, CellContainer.class, CELL_CONTEXT); - + ArrayList object = + deserializer.deserialize(json, CellContainer.class, CELL_CONTEXT); + assertEquals(n, object.size()); for (int i = 0; i < n; i++) { int id = id0 + i; assertEquals(id, object.get(i).getID()); } } - + @Test public void deserializer_forLocationContainerList_createsObject() { LocationListDeserializer deserializer = new LocationListDeserializer(); - + int n = randomIntBetween(1, 10); int id0 = randomIntBetween(1, 10); - + StringBuilder string = new StringBuilder("["); for (int i = 0; i < n; i++) { int id = id0 + i; @@ -110,10 +111,11 @@ public void deserializer_forLocationContainerList_createsObject() { } } string.append("]"); - + JsonArray json = JsonParser.parseString(string.toString()).getAsJsonArray(); - ArrayList object = deserializer.deserialize(json, LocationContainer.class, LOCATION_CONTEXT); - + ArrayList object = + deserializer.deserialize(json, LocationContainer.class, LOCATION_CONTEXT); + assertEquals(n, object.size()); for (int i = 0; i < n; i++) { int id = id0 + i; diff --git a/test/arcade/core/sim/output/OutputLoaderTest.java b/test/arcade/core/sim/output/OutputLoaderTest.java index 0599b4869..6ac197bd6 100644 --- a/test/arcade/core/sim/output/OutputLoaderTest.java +++ b/test/arcade/core/sim/output/OutputLoaderTest.java @@ -1,33 +1,33 @@ package arcade.core.sim.output; -import java.io.File; import java.io.IOException; import java.lang.reflect.Field; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; -import org.apache.commons.io.FileUtils; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import com.google.gson.Gson; import arcade.core.agent.cell.CellContainer; import arcade.core.env.location.LocationContainer; import arcade.core.sim.*; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.core.ARCADETestUtilities.*; import static arcade.core.sim.Simulation.*; public class OutputLoaderTest { - @Rule - public TemporaryFolder folder = new TemporaryFolder(); - static class OutputLoaderMock extends OutputLoader { - OutputLoaderMock(Series series) { super(series); } - + OutputLoaderMock(Series series) { + super(series); + } + @Override - protected Gson makeGSON() { return mock(Gson.class); } + protected Gson makeGSON() { + return mock(Gson.class); + } } - + @Test public void constructor_setsFields() { Series series = mock(Series.class); @@ -35,168 +35,171 @@ public void constructor_setsFields() { assertSame(series, loader.series); assertNotNull(loader.gson); } - + @Test - public void equip_noCellsNoLocations_loadsNone() { + public void equip_noCellsNoLocations_loadsNone(@TempDir Path path) { Series series = mock(Series.class); Simulation sim = mock(Simulation.class); - - String prefix = folder.getRoot().getAbsolutePath() + "/equip_noCellsNoLocations_loadsNone"; + + String prefix = path.toAbsolutePath() + "/equip"; + OutputLoader loader = new OutputLoaderMock(series); loader.prefix = prefix; loader.loadCells = false; loader.loadLocations = false; - + loader.equip(sim); assertNull(loader.cellJson); assertNull(loader.locationJson); } - + @Test - public void equip_loadCellsNoLocations_loadsCells() throws IOException { + public void equip_loadCellsNoLocations_loadsCells(@TempDir Path path) throws IOException { Series series = mock(Series.class); Simulation sim = mock(Simulation.class); - - folder.newFile("equip_loadCellsNoLocations_loadsCells.CELLS.json"); - String prefix = folder.getRoot().getAbsolutePath() + "/equip_loadCellsNoLocations_loadsCells"; + + Files.createFile(path.resolve("equip.CELLS.json")); + String prefix = path.toAbsolutePath() + "/equip"; OutputLoader loader = new OutputLoaderMock(series); loader.prefix = prefix; loader.loadCells = true; loader.loadLocations = false; - + loader.equip(sim); assertEquals("", loader.cellJson); assertNull(loader.locationJson); } - + @Test - public void equip_noCellsLoadLocations_loadsLocations() throws IOException { + public void equip_noCellsLoadLocations_loadsLocations(@TempDir Path path) throws IOException { Series series = mock(Series.class); Simulation sim = mock(Simulation.class); - - folder.newFile("equip_noCellsLoadLocations_loadsLocations.LOCATIONS.json"); - String prefix = folder.getRoot().getAbsolutePath() + "/equip_noCellsLoadLocations_loadsLocations"; + + Files.createFile(path.resolve("equip.LOCATIONS.json")); + String prefix = path.toAbsolutePath() + "/equip"; OutputLoader loader = new OutputLoaderMock(series); loader.prefix = prefix; loader.loadCells = false; loader.loadLocations = true; - + loader.equip(sim); assertNull(loader.cellJson); assertEquals("", loader.locationJson); } - + @Test - public void equip_loadCellsLoadLocations_loadsBoth() throws IOException { + public void equip_loadCellsLoadLocations_loadsBoth(@TempDir Path path) throws IOException { Series series = mock(Series.class); Simulation sim = mock(Simulation.class); - - folder.newFile("equip_loadCellsLoadLocations_loadsBoth.CELLS.json"); - folder.newFile("equip_loadCellsLoadLocations_loadsBoth.LOCATIONS.json"); - String prefix = folder.getRoot().getAbsolutePath() + "/equip_loadCellsLoadLocations_loadsBoth"; + + Files.createFile(path.resolve("equip.CELLS.json")); + Files.createFile(path.resolve("equip.LOCATIONS.json")); + String prefix = path.toAbsolutePath() + "/equip"; OutputLoader loader = new OutputLoaderMock(series); loader.prefix = prefix; loader.loadCells = true; loader.loadLocations = true; - + loader.equip(sim); assertEquals("", loader.cellJson); assertEquals("", loader.locationJson); } - + @Test - public void equip_loadBothWithSeed_loadsSeed() throws IOException { + public void equip_loadBothWithSeed_loadsSeed(@TempDir Path path) throws IOException { Series series = mock(Series.class); Simulation sim = mock(Simulation.class); - + int seed = randomSeed(); doReturn(seed).when(sim).getSeed(); - - folder.newFile(String.format("equip_loadBothWithSeed_loadsSeed_%04d.CELLS.json", seed)); - folder.newFile(String.format("equip_loadBothWithSeed_loadsSeed_%04d.LOCATIONS.json", seed)); - - String prefix = folder.getRoot().getAbsolutePath() + "/equip_loadBothWithSeed_loadsSeed_[#]"; + + Files.createFile(path.resolve(String.format("equip_%04d.CELLS.json", seed))); + Files.createFile(path.resolve(String.format("equip_%04d.LOCATIONS.json", seed))); + + String prefix = path.toAbsolutePath() + "/equip_[#]"; OutputLoader loader = new OutputLoaderMock(series); loader.prefix = prefix; loader.loadCells = true; loader.loadLocations = true; - + loader.equip(sim); assertEquals("", loader.cellJson); assertEquals("", loader.locationJson); } - + @Test public void loadCells_called_loadsContents() { OutputLoader loader = mock(OutputLoader.class, CALLS_REAL_METHODS); ArrayList list = new ArrayList<>(); String json = "[]"; - + Gson gson = mock(Gson.class); doReturn(list).when(gson).fromJson(json, DEFAULT_CELL_TYPE); loader.cellJson = json; - + try { Field field = OutputLoader.class.getDeclaredField("gson"); field.setAccessible(true); field.set(loader, gson); - } catch (Exception ignored) { } - + } catch (Exception ignored) { + } + ArrayList loaded = loader.loadCells(); verify(gson).fromJson(loader.cellJson, DEFAULT_CELL_TYPE); assertEquals(list, loaded); } - + @Test public void loadLocations_called_loadsContents() { OutputLoader loader = mock(OutputLoader.class, CALLS_REAL_METHODS); ArrayList list = new ArrayList<>(); String json = "[]"; - + Gson gson = mock(Gson.class); doReturn(list).when(gson).fromJson(json, DEFAULT_LOCATION_TYPE); loader.locationJson = json; - + try { Field field = OutputLoader.class.getDeclaredField("gson"); field.setAccessible(true); field.set(loader, gson); - } catch (Exception ignored) { } - + } catch (Exception ignored) { + } + ArrayList loaded = loader.loadLocations(); verify(gson).fromJson(loader.locationJson, DEFAULT_LOCATION_TYPE); assertSame(list, loaded); } - + @Test - public void read_validPath_loadsFile() throws IOException { + public void read_validPath_loadsFile(@TempDir Path path) throws IOException { String contents = randomString() + "\n" + randomString(); - File file = folder.newFile("read_validPath_loadsFile.json"); - String filepath = file.getAbsolutePath(); - FileUtils.writeStringToFile(file, contents, "UTF-8"); - + Path file = Files.createFile(path.resolve("valid.json")); + String filepath = file.toAbsolutePath().toString(); + Files.writeString(file, contents); + Series series = mock(Series.class); OutputLoader loader = new OutputLoaderMock(series); loader.prefix = ""; loader.loadCells = false; loader.loadLocations = false; String string = loader.read(filepath); - + assertEquals(contents.replace("\n", ""), string); } - + @Test - public void read_invalidPath_returnsNUll() throws IOException { - File file = folder.newFile("read_validPath_loadsFile.json"); - String filepath = file.getAbsolutePath(); - + public void read_invalidPath_returnsNull(@TempDir Path path) throws IOException { + Path file = Files.createFile(path.resolve("valid.json")); + String filepath = file.toAbsolutePath().toString(); + Series series = mock(Series.class); OutputLoader loader = new OutputLoaderMock(series); loader.prefix = ""; loader.loadCells = false; loader.loadLocations = false; String string = loader.read(filepath.replace("valid", "invalid")); - + assertNull(string); } } diff --git a/test/arcade/core/sim/output/OutputSaverTest.java b/test/arcade/core/sim/output/OutputSaverTest.java index 9b95a2391..6dd1c0b6a 100644 --- a/test/arcade/core/sim/output/OutputSaverTest.java +++ b/test/arcade/core/sim/output/OutputSaverTest.java @@ -1,36 +1,36 @@ package arcade.core.sim.output; -import java.io.File; import java.io.IOException; import java.lang.reflect.Field; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; -import org.apache.commons.io.FileUtils; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import com.google.gson.Gson; import sim.engine.Schedule; import sim.engine.SimState; import arcade.core.agent.cell.CellContainer; import arcade.core.env.location.LocationContainer; import arcade.core.sim.*; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.core.ARCADETestUtilities.*; import static arcade.core.sim.Simulation.DEFAULT_CELL_TYPE; import static arcade.core.sim.Simulation.DEFAULT_LOCATION_TYPE; public class OutputSaverTest { - @Rule - public TemporaryFolder folder = new TemporaryFolder(); - static class OutputSaverMock extends OutputSaver { - OutputSaverMock(Series series) { super(series); } - + OutputSaverMock(Series series) { + super(series); + } + @Override - protected Gson makeGSON() { return mock(Gson.class); } + protected Gson makeGSON() { + return mock(Gson.class); + } } - + @Test public void constructor_setsFields() { Series series = mock(Series.class); @@ -38,209 +38,212 @@ public void constructor_setsFields() { assertSame(series, saver.series); assertNotNull(saver.gson); } - + @Test public void equip_givenFirstSimulation_setsPrefix() { Series series = mock(Series.class); OutputSaver saver = new OutputSaverMock(series); - + String prefix = randomString(); doReturn(prefix).when(series).getPrefix(); - + Simulation sim = mock(Simulation.class); int seed = randomSeed(); doReturn(seed).when(sim).getSeed(); - + assertNull(saver.prefix); - + saver.equip(sim); assertEquals(prefix + "_" + String.format("%04d", seed), saver.prefix); } - + @Test public void equip_givenFirstSimulation_setsFields() { Series series = mock(Series.class); OutputSaver saver = new OutputSaverMock(series); - + Simulation sim = mock(Simulation.class); assertNull(saver.sim); saver.equip(sim); assertSame(sim, saver.sim); } - + @Test public void equip_givenSecondSimulation_updatesPrefix() { Series series = mock(Series.class); OutputSaver saver = new OutputSaverMock(series); - + String prefix = randomString(); doReturn(prefix).when(series).getPrefix(); - + Simulation sim1 = mock(Simulation.class); int seed1 = randomSeed(); doReturn(seed1).when(sim1).getSeed(); - + saver.equip(sim1); assertEquals(prefix + "_" + String.format("%04d", seed1), saver.prefix); - + Simulation sim2 = mock(Simulation.class); int seed2 = randomSeed(); doReturn(seed2).when(sim2).getSeed(); - + saver.equip(sim2); assertEquals(prefix + "_" + String.format("%04d", seed2), saver.prefix); } - + @Test public void equip_givenSecondSimulation_updatesFields() { Series series = mock(Series.class); OutputSaver saver = new OutputSaverMock(series); - + Simulation sim1 = mock(Simulation.class); saver.equip(sim1); assertSame(sim1, saver.sim); - + Simulation sim2 = mock(Simulation.class); saver.equip(sim2); assertSame(sim2, saver.sim); } - + @Test public void saveSeries_called_savesContents() { Series series = mock(Series.class); OutputSaver saver = spy(new OutputSaverMock(series)); doNothing().when(saver).write(anyString(), anyString()); - - Gson gson = spy(mock(Gson.class)); + + Gson gson = mock(Gson.class); String contents = randomString(); doReturn(contents).when(gson).toJson(series); - + try { Field field = OutputSaver.class.getDeclaredField("gson"); field.setAccessible(true); field.set(saver, gson); - } catch (Exception ignored) { } - + } catch (Exception ignored) { + } + String prefix = randomString(); doReturn(prefix).when(series).getPrefix(); - + saver.saveSeries(); verify(gson).toJson(series); verify(saver).write(prefix + ".json", contents); } - + @Test public void saveCells_called_savesContents() { ArrayList cells = new ArrayList<>(); Simulation sim = mock(Simulation.class); doReturn(cells).when(sim).getCells(); - + Series series = mock(Series.class); OutputSaver saver = spy(new OutputSaverMock(series)); doNothing().when(saver).write(anyString(), anyString()); saver.sim = sim; - + Gson gson = mock(Gson.class); String contents = randomString(); doReturn(contents).when(gson).toJson(cells, DEFAULT_CELL_TYPE); - + try { Field field = OutputSaver.class.getDeclaredField("gson"); field.setAccessible(true); field.set(saver, gson); - } catch (Exception ignored) { } - + } catch (Exception ignored) { + } + saver.prefix = randomString(); int tick = randomIntBetween(0, 10); - + saver.saveCells(tick); verify(gson).toJson(cells, DEFAULT_CELL_TYPE); verify(saver).write(saver.prefix + String.format("_%06d.CELLS.json", tick), contents); } - + @Test public void saveLocations_called_savesContents() { ArrayList locations = new ArrayList<>(); Simulation sim = mock(Simulation.class); doReturn(locations).when(sim).getCells(); - + Series series = mock(Series.class); OutputSaver saver = spy(new OutputSaverMock(series)); doNothing().when(saver).write(anyString(), anyString()); saver.sim = sim; - + Gson gson = mock(Gson.class); String contents = randomString(); doReturn(contents).when(gson).toJson(locations, DEFAULT_LOCATION_TYPE); - + try { Field field = OutputSaver.class.getDeclaredField("gson"); field.setAccessible(true); field.set(saver, gson); - } catch (Exception ignored) { } - + } catch (Exception ignored) { + } + saver.prefix = randomString(); int tick = randomIntBetween(0, 10); - + saver.saveLocations(tick); verify(gson).toJson(locations, DEFAULT_LOCATION_TYPE); verify(saver).write(saver.prefix + String.format("_%06d.LOCATIONS.json", tick), contents); } - + @Test public void step_singleStep_callsSave() { - OutputSaver saver = spy(mock(OutputSaver.class, CALLS_REAL_METHODS)); + OutputSaver saver = mock(OutputSaver.class, CALLS_REAL_METHODS); doNothing().when(saver).saveCells(anyInt()); doNothing().when(saver).saveLocations(anyInt()); - + SimState simstate = mock(SimState.class); simstate.schedule = mock(Schedule.class); int tick = randomIntBetween(1, 100); doReturn((double) tick).when(simstate.schedule).getTime(); - + saver.prefix = randomString(); - + saver.step(simstate); verify(saver).saveCells(tick); verify(saver).saveLocations(tick); } - + @Test public void schedule_validInput_callsMethod() { - Schedule schedule = spy(mock(Schedule.class)); + Schedule schedule = mock(Schedule.class); OutputSaver saver = mock(OutputSaver.class, CALLS_REAL_METHODS); doReturn(null).when(schedule).scheduleRepeating(anyDouble(), anyInt(), any(), anyDouble()); double interval = randomDoubleBetween(1, 10); saver.schedule(schedule, interval); verify(schedule).scheduleRepeating(Schedule.EPOCH, -1, saver, interval); } - + @Test - public void write_validPath_savesFile() throws IOException { + public void write_validPath_savesFile(@TempDir Path path) throws IOException { String contents = randomString(); - File file = folder.newFile("write_validPath_savesFile.json"); - String filepath = file.getAbsolutePath(); - + Path file = Files.createFile(path.resolve("write_validPath_savesFile.json")); + String filepath = file.toAbsolutePath().toString(); + Series series = mock(Series.class); OutputSaver saver = new OutputSaverMock(series); saver.write(filepath, contents); - - String string = FileUtils.readFileToString(file, "UTF-8"); + + String string = Files.readString(file); assertEquals(contents, string); } - + @Test - public void write_invalidPath_killsSeries() throws IOException { + public void write_invalidPath_killsSeries(@TempDir Path path) throws IOException { String contents = randomString(); - File file = folder.newFile("write_invalidPath_killsSeries.json"); - String filepath = file.getParent(); - + Path file = Files.createFile(path.resolve("write_invalidPath_killsSeries.json")); + String filepath = file.getParent().toString(); + Series series = mock(Series.class); series.isSkipped = false; OutputSaver saver = new OutputSaverMock(series); saver.write(filepath + "/", contents); - - String string = FileUtils.readFileToString(file, "UTF-8"); + + String string = Files.readString(file); assertEquals("", string); assertTrue(saver.series.isSkipped); } diff --git a/test/arcade/core/sim/output/OutputSerializerTest.java b/test/arcade/core/sim/output/OutputSerializerTest.java index 335fedd5a..80104a65c 100644 --- a/test/arcade/core/sim/output/OutputSerializerTest.java +++ b/test/arcade/core/sim/output/OutputSerializerTest.java @@ -4,7 +4,7 @@ import java.lang.reflect.Type; import java.util.ArrayList; import java.util.HashMap; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; @@ -17,205 +17,240 @@ import arcade.core.env.location.LocationContainer; import arcade.core.sim.Series; import arcade.core.util.MiniBox; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.core.ARCADETestUtilities.*; import static arcade.core.sim.output.OutputSerializer.*; public class OutputSerializerTest { - static final JsonSerializationContext CELL_CONTEXT = new JsonSerializationContext() { - @Override - public JsonElement serialize(Object src) { return null; } - - @Override - public JsonElement serialize(Object src, Type typeOfSrc) { - JsonObject object = new JsonObject(); - object.addProperty("id", ((CellContainer) src).getID()); - return object; - } - }; - - static final JsonSerializationContext LOCATION_CONTEXT = new JsonSerializationContext() { - @Override - public JsonElement serialize(Object src) { return null; } - - @Override - public JsonElement serialize(Object src, Type typeOfSrc) { - JsonObject object = new JsonObject(); - object.addProperty("id", ((LocationContainer) src).getID()); - return object; - } - }; - + static final JsonSerializationContext CELL_CONTEXT = + new JsonSerializationContext() { + @Override + public JsonElement serialize(Object src) { + return null; + } + + @Override + public JsonElement serialize(Object src, Type typeOfSrc) { + JsonObject object = new JsonObject(); + object.addProperty("id", ((CellContainer) src).getID()); + return object; + } + }; + + static final JsonSerializationContext LOCATION_CONTEXT = + new JsonSerializationContext() { + @Override + public JsonElement serialize(Object src) { + return null; + } + + @Override + public JsonElement serialize(Object src, Type typeOfSrc) { + JsonObject object = new JsonObject(); + object.addProperty("id", ((LocationContainer) src).getID()); + return object; + } + }; + public static void checkAdaptors(Gson gson) { - TypeToken series = new TypeToken() { }; + TypeToken series = new TypeToken() {}; assertSame(gson.getAdapter(series).getClass(), TreeTypeAdapter.class); - - TypeToken minibox = new TypeToken() { }; + + TypeToken minibox = new TypeToken() {}; assertSame(gson.getAdapter(minibox).getClass(), TreeTypeAdapter.class); - + TypeToken> cellContainerList = - new TypeToken>() { }; + new TypeToken>() {}; assertSame(gson.getAdapter(cellContainerList).getClass(), TreeTypeAdapter.class); - + TypeToken> locationContainerList = - new TypeToken>() { }; + new TypeToken>() {}; assertSame(gson.getAdapter(locationContainerList).getClass(), TreeTypeAdapter.class); } - - @Test(expected = UnsupportedOperationException.class) + + @Test public void constructor_called_throwsException() { - OutputSerializer serializer = new OutputSerializer(); + assertThrows(UnsupportedOperationException.class, OutputSerializer::new); } - + @Test public void makeGSON_registersAdaptors() { GsonBuilder gsonBuilder = OutputSerializer.makeGSONBuilder(); Gson gson = gsonBuilder.create(); checkAdaptors(gson); } - + @Test public void serialize_forMiniBox_createsJSON() { MiniBoxSerializer serializer = new MiniBoxSerializer(); MiniBox box = new MiniBox(); - + String key1 = randomString(); String value1 = randomString(); - + String key2 = randomString(); double value2 = randomDoubleBetween(0, 100); - + String key3 = randomString(); int value3 = randomIntBetween(0, 100); - + box.put(key1, value1); box.put(key2, value2); box.put(key3, value3); - - String expected = "{" - + "\"" + key1 + "\":\"" + value1 + "\"," - + "\"" + key2 + "\":" + value2 + "," - + "\"" + key3 + "\":" + value3 + "" - + "}"; - + + String expected = + "{" + "\"" + key1 + "\":\"" + value1 + "\"," + "\"" + key2 + "\":" + value2 + "," + + "\"" + key3 + "\":" + value3 + "" + "}"; + JsonElement json = serializer.serialize(box, null, null); assertEquals(expected, json.toString()); } - + @Test public void serialize_forSeries_createsJSON() { SeriesSerializer serializer = new SeriesSerializer(); Series series = mock(Series.class); - + double ds = randomDoubleBetween(0, 100); double dt = randomDoubleBetween(0, 100); - + int ticks = randomIntBetween(0, 100); doReturn(ticks).when(series).getTicks(); - + int length = randomIntBetween(0, 100); int width = randomIntBetween(0, 100); int height = randomIntBetween(0, 100); int margin = randomIntBetween(0, 100); - + try { Field lengthField = Series.class.getDeclaredField("length"); lengthField.setAccessible(true); lengthField.setInt(series, length); - + Field widthField = Series.class.getDeclaredField("width"); widthField.setAccessible(true); widthField.setInt(series, width); - + Field heightField = Series.class.getDeclaredField("height"); heightField.setAccessible(true); heightField.setInt(series, height); - + Field marginField = Series.class.getDeclaredField("margin"); marginField.setAccessible(true); marginField.setInt(series, margin); - + Field dsField = Series.class.getDeclaredField("ds"); dsField.setAccessible(true); dsField.setDouble(series, ds); - + Field dtField = Series.class.getDeclaredField("dt"); dtField.setAccessible(true); dtField.setDouble(series, dt); - } catch (Exception ignored) { } - + } catch (Exception ignored) { + } + series.populations = new HashMap<>(); String popA = "a" + randomString(); String popB = "b" + randomString(); - + MiniBox a = new MiniBox(); String keyA = randomString(); String valueA = randomString(); a.put(keyA, valueA); - + MiniBox b = new MiniBox(); String keyB = randomString(); String valueB = randomString(); b.put(keyB, valueB); - + series.populations.put(popA, a); series.populations.put(popB, b); - - JsonSerializationContext context = new JsonSerializationContext() { - @Override - public JsonElement serialize(Object src) { - if (src instanceof MiniBox) { - MiniBox box = (MiniBox) src; - JsonObject json = new JsonObject(); - json.addProperty(box.getKeys().get(0), box.get(box.getKeys().get(0))); - return json; - } - return null; - } - - @Override - public JsonElement serialize(Object src, Type typeOfSrc) { return null; } - }; - - String expected = "{" - + "\"version\":\"" + ARCADE.VERSION + "\"," - + "\"conversions\":{" - + "\"DS\":" + ds + "," - + "\"DT\":" + dt - + "}," - + "\"ticks\":" + ticks + "," - + "\"size\":{" - + "\"length\":" + length + "," - + "\"width\":" + width + "," - + "\"height\":" + height + "," - + "\"margin\":" + margin - + "}," - + "\"populations\":{" - + "\"" + popA + "\":{\"" + keyA + "\":\"" + valueA + "\"}," - + "\"" + popB + "\":{\"" + keyB + "\":\"" + valueB + "\"}" - + "}" - + "}"; - + + JsonSerializationContext context = + new JsonSerializationContext() { + @Override + public JsonElement serialize(Object src) { + if (src instanceof MiniBox) { + MiniBox box = (MiniBox) src; + JsonObject json = new JsonObject(); + json.addProperty(box.getKeys().get(0), box.get(box.getKeys().get(0))); + return json; + } + return null; + } + + @Override + public JsonElement serialize(Object src, Type typeOfSrc) { + return null; + } + }; + + String expected = + "{" + + "\"version\":\"" + + ARCADE.VERSION + + "\"," + + "\"conversions\":{" + + "\"DS\":" + + ds + + "," + + "\"DT\":" + + dt + + "}," + + "\"ticks\":" + + ticks + + "," + + "\"size\":{" + + "\"length\":" + + length + + "," + + "\"width\":" + + width + + "," + + "\"height\":" + + height + + "," + + "\"margin\":" + + margin + + "}," + + "\"populations\":{" + + "\"" + + popA + + "\":{\"" + + keyA + + "\":\"" + + valueA + + "\"}," + + "\"" + + popB + + "\":{\"" + + keyB + + "\":\"" + + valueB + + "\"}" + + "}" + + "}"; + JsonElement json = serializer.serialize(series, null, context); assertEquals(expected, json.toString()); } - + @Test public void serialize_forCellContainerList_createsJSON() { CellListSerializer serializer = new CellListSerializer(); ArrayList cells = new ArrayList<>(); - + int n = randomIntBetween(1, 10); int id0 = randomIntBetween(1, 10); - + for (int i = 0; i < n; i++) { int id = id0 + i; CellContainer cell = mock(CellContainer.class); doReturn(id).when(cell).getID(); cells.add(cell); } - + StringBuilder expected = new StringBuilder("["); for (int i = 0; i < n; i++) { int id = id0 + i; @@ -225,26 +260,26 @@ public void serialize_forCellContainerList_createsJSON() { } } expected.append("]"); - + JsonElement json = serializer.serialize(cells, CellContainer.class, CELL_CONTEXT); assertEquals(expected.toString(), json.toString()); } - + @Test public void serialize_forLocationContainerList_createsJSON() { LocationListSerializer serializer = new LocationListSerializer(); ArrayList locations = new ArrayList<>(); - + int n = randomIntBetween(1, 10); int id0 = randomIntBetween(1, 10); - + for (int i = 0; i < n; i++) { int id = id0 + i; LocationContainer location = mock(LocationContainer.class); doReturn(id).when(location).getID(); locations.add(location); } - + StringBuilder expected = new StringBuilder("["); for (int i = 0; i < n; i++) { int id = id0 + i; @@ -254,8 +289,9 @@ public void serialize_forLocationContainerList_createsJSON() { } } expected.append("]"); - - JsonElement json = serializer.serialize(locations, LocationContainer.class, LOCATION_CONTEXT); + + JsonElement json = + serializer.serialize(locations, LocationContainer.class, LOCATION_CONTEXT); assertEquals(expected.toString(), json.toString()); } } diff --git a/test/arcade/core/util/BoxTest.java b/test/arcade/core/util/BoxTest.java index 91910f654..219900503 100644 --- a/test/arcade/core/util/BoxTest.java +++ b/test/arcade/core/util/BoxTest.java @@ -2,14 +2,14 @@ import java.util.ArrayList; import java.util.HashSet; -import org.junit.Test; -import static org.junit.Assert.*; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; import static arcade.core.ARCADETestUtilities.*; import static arcade.core.util.Box.*; public class BoxTest { private static final int NUMBER_KEYS = 10; - + @Test public void contains_doesContainKey_returnsTrue() { Box box = new Box(); @@ -17,20 +17,20 @@ public void contains_doesContainKey_returnsTrue() { box.add(key, randomString()); assertTrue(box.contains(key)); } - + @Test public void contains_doesNotContainKey_returnsFalse() { Box box = new Box(); String key = randomString(); assertFalse(box.contains(key)); } - + @Test public void getKeys_noKeys_returnsEmpty() { Box box = new Box(); assertEquals(new ArrayList<>(), box.getKeys()); } - + @Test public void getKeys_givenKeys_returnsList() { Box box = new Box(); @@ -40,22 +40,22 @@ public void getKeys_givenKeys_returnsList() { box.addTag("" + i, randomString()); box.add("" + i, randomString()); } - + assertEquals(new HashSet<>(keys), new HashSet<>(box.getKeys())); } - + @Test public void getValue_givenValidKeyNoAttribute_returnsItem() { Box box = new Box(); String id = randomString(); String tag = randomString(); String contents = randomString(); - + box.addTag(id, tag); box.add(id, contents); assertEquals(contents, box.getValue(id)); } - + @Test public void getValue_givenValidKeyWithAttribute_returnsItem() { Box box = new Box(); @@ -63,19 +63,19 @@ public void getValue_givenValidKeyWithAttribute_returnsItem() { String att = randomString(); String tag = randomString(); String contents = randomString(); - + box.addTag(id, tag); box.addAtt(id, att, contents); assertEquals(contents, box.getValue(id + KEY_SEPARATOR + att)); } - + @Test public void getValue_givenInvalidKey_returnsNull() { Box box = new Box(); String id = randomString(); assertNull(box.getValue(id)); } - + @Test public void getTag_givenValidTag_returnsItem() { Box box = new Box(); @@ -84,14 +84,14 @@ public void getTag_givenValidTag_returnsItem() { box.addTag(id, tag); assertEquals(tag, box.getTag(id)); } - + @Test public void getTag_givenInvalidTag_returnsItem() { Box box = new Box(); String id = randomString(); assertNull(box.getValue(id)); } - + @Test public void addTag_newID_updatesContainers() { Box box = new Box(); @@ -102,7 +102,7 @@ public void addTag_newID_updatesContainers() { assertTrue(box.idToTag.contains(id)); assertEquals(tag, box.idToTag.get(id)); } - + @Test public void addTag_existingID_updatesContainers() { Box box = new Box(); @@ -115,7 +115,7 @@ public void addTag_existingID_updatesContainers() { assertTrue(box.idToTag.contains(id)); assertEquals(tag2, box.idToTag.get(id)); } - + @Test public void addAtt_givenValues_updatesContainers() { Box box = new Box(); @@ -126,7 +126,7 @@ public void addAtt_givenValues_updatesContainers() { assertEquals(value, box.idToVal.get(id + KEY_SEPARATOR + att)); assertTrue(box.keys.contains(id)); } - + @Test public void add_givenValues_updatesContainers() { Box box = new Box(); @@ -136,7 +136,7 @@ public void add_givenValues_updatesContainers() { assertEquals(value, box.idToVal.get(id)); assertTrue(box.keys.contains(id)); } - + @Test public void add_givenKeyValues_updatesContainers() { Box box = new Box(); @@ -147,563 +147,561 @@ public void add_givenKeyValues_updatesContainers() { assertEquals(value, box.idToVal.get(id + KEY_SEPARATOR + att)); assertTrue(box.keys.contains(id)); } - + @Test public void getAttValForId_invalidID_returnsEmpty() { Box box = new Box(); - + String id1 = randomString(); String id2 = randomString(); - + String att1 = randomString(); String att2 = randomString(); - + String value1 = randomString(); String value2 = randomString(); - + box.addAtt(id1, att1, value1); box.addAtt(id1, att2, value2); - + MiniBox expected = new MiniBox(); assertTrue(expected.compare(box.getAttValForId(id2))); } - + @Test public void getAttValForId_validID_createsMapping() { Box box = new Box(); - + String id1 = randomString(); String id2 = randomString(); - + String att1 = randomString(); String att2 = randomString(); String att3 = randomString(); - + String value1 = randomString(); String value2 = randomString(); String value3 = randomString(); - + box.addAtt(id1, att1, value1); box.addAtt(id1, att2, value2); box.addAtt(id2, att3, value3); - + MiniBox expected = new MiniBox(); expected.put(att1, value1); expected.put(att2, value2); - + assertTrue(expected.compare(box.getAttValForId(id1))); } - + @Test public void getIdVal_invalid_returnsEmpty() { Box box = new Box(); - + String id1 = randomString(); String id2 = randomString(); - + box.addAtt(id1, randomString(), randomString()); box.addTag(id1, randomString()); box.addAtt(id2, randomString(), randomString()); box.addTag(id2, randomString()); - + MiniBox expected = new MiniBox(); - + assertTrue(expected.compare(box.getIdVal())); } - + @Test public void getIdVal_valid_createsMapping() { Box box = new Box(); - + String id1 = randomString(); String id2 = randomString(); String id3 = randomString(); - + String value1 = randomString(); String value2 = randomString(); - + box.add(id1, value1); box.add(id2, value2); box.addAtt(id3, randomString(), randomString()); box.addTag(id3, randomString()); - + MiniBox expected = new MiniBox(); expected.put(id1, value1); expected.put(id2, value2); - + assertTrue(expected.compare(box.getIdVal())); } - + @Test public void getIdValForTag_validTag_createsMapping() { Box box = new Box(); - + String id1 = randomString(); String id2 = randomString(); String id3 = randomString(); - + String tag1 = randomString(); String tag2 = randomString(); - + String att2 = randomString(); - + String value1 = randomString(); String value2 = randomString(); String value3 = randomString(); String value4 = randomString(); - + box.addTag(id1, tag1); box.addTag(id2, tag2); box.addTag(id3, tag2); - + box.addAtt(id1, "value", value1); box.addAtt(id2, "value", value2); box.addAtt(id3, "value", value3); box.addAtt(id3, att2, value4); - + MiniBox expected = new MiniBox(); expected.put(id2, value2); expected.put(id3, value3); - + assertTrue(expected.compare(box.getIdValForTag(tag2))); } - + @Test public void getIdValForTagAtt_invalidTagAtt_returnsEmpty() { Box box = new Box(); - + String id1 = randomString(); String id2 = randomString(); String id3 = randomString(); - + String tag1 = randomString(); String tag2 = randomString(); - + String att1 = randomString(); String att2 = randomString(); - + String value1 = randomString(); String value2 = randomString(); String value3 = randomString(); String value4 = randomString(); - + box.addTag(id1, tag1); box.addTag(id2, tag2); box.addTag(id3, tag2); - + box.addAtt(id1, att1, value1); box.addAtt(id2, att1, value2); box.addAtt(id3, att1, value3); box.addAtt(id3, att2, value4); - + MiniBox expected = new MiniBox(); assertTrue(expected.compare(box.getIdValForTagAtt(tag1, att2))); } - + @Test public void getIdValForTagAtt_validTagAtt_createsMapping() { Box box = new Box(); - + String id1 = randomString(); String id2 = randomString(); String id3 = randomString(); - + String tag1 = randomString(); String tag2 = randomString(); - + String att1 = randomString(); String att2 = randomString(); - + String value1 = randomString(); String value2 = randomString(); String value3 = randomString(); String value4 = randomString(); - + box.addTag(id1, tag1); box.addTag(id2, tag2); box.addTag(id3, tag2); - + box.addAtt(id1, att1, value1); box.addAtt(id2, att1, value2); box.addAtt(id3, att1, value3); box.addAtt(id3, att2, value4); - + MiniBox expected = new MiniBox(); expected.put(id2, value2); expected.put(id3, value3); - + assertTrue(expected.compare(box.getIdValForTagAtt(tag2, att1))); } - + @Test public void filterBox_noTags_returnsEmpty() { Box box = new Box(); - + String id1 = randomString(); String id2 = randomString(); - + String tag1 = randomString(); String tag2 = randomString(); - + box.addTag(id1, tag2); box.addTag(id2, tag2); - + HashSet filtered = box.filterTags(tag1); - + assertEquals(0, filtered.size()); } - + @Test public void filterBox_withTags_returnsLists() { Box box = new Box(); - + String id1 = randomString(); String id2 = randomString(); String id3 = randomString(); - + String tag1 = randomString(); String tag2 = randomString(); - + box.addTag(id1, tag1); box.addTag(id2, tag2); box.addTag(id3, tag2); - + HashSet filtered = box.filterTags(tag2); - + assertEquals(2, filtered.size()); assertTrue(filtered.contains(id2)); assertTrue(filtered.contains(id3)); } - + @Test public void filterBoxByTag_invalidTag_returnsEmpty() { Box box = new Box(); - + String id1 = randomString(); String id2 = randomString(); String id3 = randomString(); - + String tag1 = randomString(); String tag2 = randomString(); - + String att1 = randomString(); String att2 = randomString(); - + String value1 = randomString(); String value2 = randomString(); String value3 = randomString(); String value4 = randomString(); - + box.addTag(id2, tag2); box.addTag(id3, tag2); - + box.addAtt(id1, att1, value1); box.addAtt(id2, att1, value2); box.addAtt(id3, att1, value3); box.addAtt(id3, att2, value4); - + Box filtered = box.filterBoxByTag(tag1); - + ArrayList keys = new ArrayList<>(); MiniBox idToTag = new MiniBox(); MiniBox idToVal = new MiniBox(); - + assertEquals(keys, filtered.keys); assertTrue(idToTag.compare(filtered.idToTag)); assertTrue(idToVal.compare(filtered.idToVal)); } - + @Test public void filterBoxByTag_validTag_createsMapping() { Box box = new Box(); - + String id1 = randomString(); String id2 = randomString(); String id3 = randomString(); String id4 = randomString(); - + String tag1 = randomString(); String tag2 = randomString(); - + String att1 = randomString(); String att2 = randomString(); - + String value1 = randomString(); String value2 = randomString(); String value3 = randomString(); String value4 = randomString(); - + box.addTag(id1, tag1); box.addTag(id2, tag2); box.addTag(id3, tag2); - + box.addAtt(id1, att1, value1); box.addAtt(id2, att1, value2); box.addAtt(id3, att1, value3); box.addAtt(id3, att2, value4); box.addAtt(id4, att2, value1); - + Box filtered = box.filterBoxByTag(tag2); - + ArrayList keys = new ArrayList<>(); keys.add(id2); keys.add(id3); - + MiniBox idToTag = new MiniBox(); idToTag.put(id2, tag2); idToTag.put(id3, tag2); - + MiniBox idToVal = new MiniBox(); idToVal.put(id2 + KEY_SEPARATOR + att1, value2); idToVal.put(id3 + KEY_SEPARATOR + att1, value3); idToVal.put(id3 + KEY_SEPARATOR + att2, value4); - + assertEquals(keys, filtered.keys); assertTrue(idToTag.compare(filtered.idToTag)); assertTrue(idToVal.compare(filtered.idToVal)); } - + @Test public void filterBoxByAtt_validAtt_createsMapping() { Box box = new Box(); - + String id1 = randomString(); String id2 = randomString(); String id3 = randomString(); - + String tag1 = randomString(); String tag2 = randomString(); - + String att1 = randomString(); String att2 = randomString(); - + String value1 = randomString(); String value2 = randomString(); String value3 = randomString(); String value4 = randomString(); - + box.addTag(id1, tag1); box.addTag(id2, tag2); box.addTag(id3, tag2); - + box.addAtt(id1, att2, value1); box.addAtt(id2, att1, value2); box.addAtt(id3, att1, value3); box.addAtt(id3, att2, value4); - + Box filtered = box.filterBoxByAtt(att2); - + ArrayList keys = new ArrayList<>(); keys.add(id1); keys.add(id3); - + MiniBox idToTag = new MiniBox(); idToTag.put(id1, tag1); idToTag.put(id3, tag2); - + MiniBox idToVal = new MiniBox(); idToVal.put(id1 + KEY_SEPARATOR + att2, value1); idToVal.put(id3 + KEY_SEPARATOR + att1, value3); idToVal.put(id3 + KEY_SEPARATOR + att2, value4); - + assertEquals(keys, filtered.keys); assertTrue(idToTag.compare(filtered.idToTag)); assertTrue(idToVal.compare(filtered.idToVal)); } - + @Test public void compare_sameTagSameValue_returnsTrue() { Box box1 = new Box(); Box box2 = new Box(); - + String id1 = randomString(); String id2 = randomString(); - + String tag1 = randomString(); - + String att1 = randomString(); String att2 = randomString(); - + String value1 = randomString(); String value2 = randomString(); - + box1.addTag(id1, tag1); box2.addTag(id1, tag1); - + box1.addAtt(id1, att1, value1); box2.addAtt(id1, att1, value1); box1.addAtt(id2, att2, value2); box2.addAtt(id2, att2, value2); - + assertTrue(box1.compare(box2)); assertTrue(box2.compare(box1)); } - + @Test public void compare_sameTagDifferentValue_returnsFalse() { Box box1 = new Box(); Box box2 = new Box(); - + String id1 = randomString(); String id2 = randomString(); - + String tag1 = randomString(); - + String att1 = randomString(); String att2 = randomString(); - + String value1 = randomString(); String value2 = randomString(); - + box1.addTag(id1, tag1); box2.addTag(id1, tag1); - + box1.addAtt(id1, att1, value1); box2.addAtt(id1, att1, value1); box1.addAtt(id2, att2, value2); box2.addAtt(id2, att2, value1); - + assertFalse(box1.compare(box2)); assertFalse(box2.compare(box1)); } - + @Test public void compare_differentTagSameValue_returnsFalse() { Box box1 = new Box(); Box box2 = new Box(); - + String id1 = randomString(); String id2 = randomString(); - + String tag1 = randomString(); String tag2 = randomString(); - + String att1 = randomString(); String att2 = randomString(); - + String value1 = randomString(); String value2 = randomString(); - + box1.addTag(id1, tag1); box2.addTag(id1, tag2); - + box1.addAtt(id1, att1, value1); box2.addAtt(id1, att1, value1); box1.addAtt(id2, att2, value2); box2.addAtt(id2, att2, value2); - + assertFalse(box1.compare(box2)); assertFalse(box2.compare(box1)); } - + @Test public void compare_differentTagDifferentValue_returnsFalse() { Box box1 = new Box(); Box box2 = new Box(); - + String id1 = randomString(); String id2 = randomString(); - + String tag1 = randomString(); String tag2 = randomString(); - + String att1 = randomString(); String att2 = randomString(); - + String value1 = randomString(); String value2 = randomString(); - + box1.addTag(id1, tag1); box2.addTag(id1, tag2); - + box1.addAtt(id1, att1, value1); box2.addAtt(id1, att1, value1); box1.addAtt(id2, att2, value2); box2.addAtt(id2, att2, value1); - + assertFalse(box1.compare(box2)); assertFalse(box2.compare(box1)); } - + @Test public void toString_onlyTags_createsJSON() { Box box = new Box(); - + String id1 = randomString(); String id2 = randomString(); - + String tag1 = randomString(); String tag2 = randomString(); - + String att1 = randomString(); String att2 = randomString(); - + String value1 = randomString(); String value2 = randomString(); - + box.addTag(id1, tag1); box.addTag(id2, tag2); - + box.addAtt(id1, att1, value1); box.addAtt(id1, att2, value2); box.addAtt(id2, att1, value1); box.addAtt(id2, att2, value2); - + String str = box.toString(); - String expected = "[" + tag1 + "]" - + id1 + att1 + ":" + value1 + att2 + ":" + value2 - + "[" + tag2 + "]" - + id2 + att1 + ":" + value1 + att2 + ":" + value2; - + String expected = + "[" + tag1 + "]" + id1 + att1 + ":" + value1 + att2 + ":" + value2 + "[" + tag2 + + "]" + id2 + att1 + ":" + value1 + att2 + ":" + value2; + str = str.replaceAll(" ", ""); str = str.replaceAll("\n", ""); str = str.replaceAll("\t", ""); - + assertEquals(expected, str); } - + @Test public void toString_mixedContents_createsJSON() { Box box = new Box(); - + String id1 = randomString(); String id2 = randomString(); String id3 = randomString(); String id4 = randomString(); - + String tag1 = randomString(); String tag2 = randomString(); - + String att1 = randomString(); String att2 = randomString(); - + String value1 = randomString(); String value2 = randomString(); String value3 = randomString(); String value4 = randomString(); - + box.add(id3, value3); box.add(id4, value4); - + box.addTag(id1, tag1); box.addTag(id2, tag2); - + box.addAtt(id1, att1, value1); box.addAtt(id1, att2, value2); box.addAtt(id2, att1, value1); box.addAtt(id2, att2, value2); - + String str = box.toString(); - String expected = id3 + ":" + value3 + id4 + ":" + value4 - + "[" + tag1 + "]" - + id1 + att1 + ":" + value1 + att2 + ":" + value2 - + "[" + tag2 + "]" - + id2 + att1 + ":" + value1 + att2 + ":" + value2; - + String expected = + id3 + ":" + value3 + id4 + ":" + value4 + "[" + tag1 + "]" + id1 + att1 + ":" + + value1 + att2 + ":" + value2 + "[" + tag2 + "]" + id2 + att1 + ":" + + value1 + att2 + ":" + value2; + str = str.replaceAll(" ", ""); str = str.replaceAll("\n", ""); str = str.replaceAll("\t", ""); - + assertEquals(expected, str); } } diff --git a/test/arcade/core/util/ColorsTest.java b/test/arcade/core/util/ColorsTest.java new file mode 100644 index 000000000..4654342f3 --- /dev/null +++ b/test/arcade/core/util/ColorsTest.java @@ -0,0 +1,181 @@ +package arcade.core.util; + +import java.awt.Color; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +public class ColorsTest { + + @Test + public void getColor_calledWithIndices_returnsColors() { + Color[] colorArray = new Color[] {new Color(1, 1, 1, 1), new Color(255, 255, 255, 1)}; + Colors colors = new Colors(colorArray); + assertAll( + () -> assertEquals(colorArray[0], colors.getColor(0)), + () -> assertEquals(colorArray[1], colors.getColor(1))); + } + + @Test + public void getRGB_calledWithIndices_returnsRGB() { + Color[] colorArray = new Color[] {new Color(1, 1, 1, 1), new Color(255, 255, 255, 1)}; + Colors colors = new Colors(colorArray); + assertAll( + () -> assertEquals(colorArray[0].getRGB(), colors.getRGB(0)), + () -> assertEquals(colorArray[1].getRGB(), colors.getRGB(1))); + } + + @Test + public void getColor_calledWithDoubles_returnsRoundedDownColor() { + Color[] colorArray = new Color[] {new Color(1, 1, 1, 1), new Color(255, 255, 255, 1)}; + Colors colors = new Colors(colorArray); + assertAll( + () -> assertEquals(colorArray[0], colors.getColor(0.0)), + () -> assertEquals(colorArray[0], colors.getColor(0.1)), + () -> assertEquals(colorArray[0], colors.getColor(0.49)), + () -> assertEquals(colorArray[0], colors.getColor(0.5)), + () -> assertEquals(colorArray[0], colors.getColor(0.99)), + () -> assertEquals(colorArray[1], colors.getColor(1.1))); + } + + @Test + public void getRGB_calledWithDoubles_returnsRoundedDownColor() { + Color[] colorArray = new Color[] {new Color(1, 1, 1, 1), new Color(255, 255, 255, 1)}; + Colors colors = new Colors(colorArray); + assertAll( + () -> assertEquals(0, colors.getRGB(-1)), + () -> assertEquals(colorArray[0].getRGB(), colors.getRGB(0.5)), + () -> assertEquals(colorArray[0].getRGB(), colors.getRGB(0.99)), + () -> assertEquals(colorArray[1].getRGB(), colors.getRGB(1.1))); + } + + @Test + public void getAlpha_calledWithLevel_returnsCorrectAlpha() { + Color[] colorArray = new Color[] {new Color(1, 1, 1, 1), new Color(255, 255, 255, 255)}; + Colors colors = new Colors(colorArray); + assertAll( + () -> assertEquals(255, colors.getAlpha(1)), + () -> assertEquals(1, colors.getAlpha(0)), + () -> assertEquals(0, colors.getAlpha(-1))); + } + + @Test + public void getRGB_calledWithLevel_returnsCorrectRGB() { + Colors colors = new Colors(new Color(1, 1, 1, 1), new Color(255, 255, 255, 1), 0.0, 1.0); + assertAll( + () -> assertEquals(new Color(255, 255, 255, 1).getRGB(), colors.getRGB(1.0)), + () -> assertEquals(new Color(1, 1, 1, 1).getRGB(), colors.getRGB(0.0))); + } + + @Test + public void getColor_smallerThanDefault_returnsEmptyColor() { + Colors colors = new Colors(new Color(1, 1, 1, 1), new Color(255, 255, 255, 1), 0.0, 1.0); + assertAll( + () -> assertEquals(new Color(0, 0, 0, 0), colors.getColor(-1.0)), + () -> assertEquals(new Color(0, 0, 0, 0), colors.getColor(-1.5)), + () -> assertEquals(new Color(0, 0, 0, 0), colors.getColor(-2.0))); + } + + @Test + public void getColor_calledBetweenMinAndDefault_returnsMinColor() { + Colors colors = new Colors(new Color(1, 1, 1, 1), new Color(255, 255, 255, 1), 0.0, 1.0); + assertAll( + () -> assertEquals(new Color(1, 1, 1, 1), colors.getColor(-0.5)), + () -> assertEquals(new Color(1, 1, 1, 1), colors.getColor(-0.1)), + () -> assertEquals(new Color(1, 1, 1, 1), colors.getColor(0.0))); + } + + @Test + public void getColor_calledLargerThanMax_returnsMaxColor() { + Colors colors = new Colors(new Color(1, 1, 1, 1), new Color(200, 200, 200, 1), 0.0, 1.0); + assertAll( + () -> assertEquals(new Color(200, 200, 200, 1), colors.getColor(1.5)), + () -> assertEquals(new Color(200, 200, 200, 1), colors.getColor(2.0)), + () -> assertEquals(new Color(200, 200, 200, 1), colors.getColor(2.5))); + } + + @Test + public void getColor_calledBetweenMinAndMax_returnsInterpolatedColor() { + Colors colors = new Colors(new Color(1, 1, 1, 1), new Color(201, 201, 201, 1), 0.0, 1.0); + assertAll( + () -> assertEquals(new Color(1, 1, 1, 1), colors.getColor(0.0)), + () -> assertEquals(new Color(51, 51, 51, 1), colors.getColor(0.25)), + () -> assertEquals(new Color(101, 101, 101, 1), colors.getColor(0.5)), + () -> assertEquals(new Color(151, 151, 151, 1), colors.getColor(0.75)), + () -> assertEquals(new Color(201, 201, 201, 1), colors.getColor(1.0))); + } + + @Test + public void getColor_calledWithMod_returnsCorrectColor() { + Colors colors = + new Colors( + new Color[] { + new Color(0, 0, 0, 0), + new Color(100, 100, 100, 0), + new Color(200, 200, 200, 200), + }, + 3); + assertAll( + () -> assertEquals(new Color(0, 0, 0, 0), colors.getColor(3)), + () -> assertEquals(new Color(100, 100, 100, 0), colors.getColor(4)), + () -> assertEquals(new Color(200, 200, 200, 200), colors.getColor(5))); + } + + @Test + public void getColor_NonlinearColorsCalledBetweenMinAndMax_returnsInterpolatedColor() { + Colors colors = + new Colors( + new Color[] { + new Color(0, 0, 0, 0), + new Color(100, 100, 100, 0), + new Color(200, 200, 200, 200), + }, + new double[] {0, 0.1, 1}); + assertAll( + () -> assertEquals(new Color(0, 0, 0, 0), colors.getColor(0)), + () -> assertEquals(new Color(48, 48, 48, 0), colors.getColor(0.05)), + () -> assertEquals(new Color(100, 100, 100, 0), colors.getColor(0.1)), + () -> assertEquals(new Color(150, 150, 150, 100), colors.getColor(0.55)), + () -> assertEquals(new Color(200, 200, 200, 200), colors.getColor(1))); + } + + @Test + public void validLevel_calledWithInvalidLevel_returnsFalse() { + Colors colors = new Colors(new Color(1, 1, 1, 1), new Color(255, 255, 255, 1), 0.0, 1.0); + + assertAll( + () -> assertFalse(colors.validLevel(-1.0)), + () -> assertFalse(colors.validLevel(-0.5)), + () -> assertFalse(colors.validLevel(1.1)), + () -> assertFalse(colors.validLevel(2.0))); + } + + @Test + public void validLevel_calledWithValidLevel_returnsTrue() { + Colors colors = new Colors(new Color(1, 1, 1, 1), new Color(255, 255, 255, 1), 0.0, 1.0); + + assertAll( + () -> assertTrue(colors.validLevel(0.0)), + () -> assertTrue(colors.validLevel(0.5)), + () -> assertTrue(colors.validLevel(1.0))); + } + + @Test + public void defaultValue_called_returnsDefaultValue() { + Colors colorsArray = + new Colors(new Color[] {new Color(1, 1, 1, 1), new Color(255, 255, 255, 1)}); + Colors colorsValues = new Colors(new Color(1, 1, 1, 1), new Color(255, 255, 255, 1), 4, 10); + Colors colorsValueArray = + new Colors( + new Color[] { + new Color(0, 0, 0, 0), + new Color(100, 100, 100, 0), + new Color(200, 200, 200, 200), + }, + new double[] {0, 0.1, 1}); + + assertAll( + () -> assertEquals(-1.0, colorsArray.defaultValue()), + () -> assertEquals(3.0, colorsValues.defaultValue()), + () -> assertEquals(-1.0, colorsValueArray.defaultValue())); + } +} diff --git a/test/arcade/core/util/DistributionTest.java b/test/arcade/core/util/DistributionTest.java deleted file mode 100644 index 2458ecea8..000000000 --- a/test/arcade/core/util/DistributionTest.java +++ /dev/null @@ -1,26 +0,0 @@ -package arcade.core.util; - -import org.junit.Test; -import ec.util.MersenneTwisterFast; -import static org.junit.Assert.*; -import static arcade.core.ARCADETestUtilities.*; - -public class DistributionTest { - @Test - public void nextDouble_called_returnsValid() { - MersenneTwisterFast random = new MersenneTwisterFast(); - double mu = randomDoubleBetween(50, 60); - double sigma = randomDoubleBetween(1, 10); - double maxValue = mu + 2 * sigma; - double minValue = mu - 2 * sigma; - int iterations = 10000; - - Distribution distribution = new Distribution(mu, sigma, random); - - for (int i = 0; i < iterations; i++) { - double value = distribution.nextDouble(); - assertTrue(value >= minValue); - assertTrue(value <= maxValue); - } - } -} diff --git a/test/arcade/core/util/GraphTest.java b/test/arcade/core/util/GraphTest.java new file mode 100644 index 000000000..69eadf12c --- /dev/null +++ b/test/arcade/core/util/GraphTest.java @@ -0,0 +1,865 @@ +package arcade.core.util; + +import java.util.ArrayList; +import java.util.HashSet; +import org.junit.jupiter.api.Test; +import sim.util.Bag; +import arcade.core.util.Graph.Edge; +import arcade.core.util.Graph.Node; +import static org.junit.jupiter.api.Assertions.*; + +public class GraphTest { + @Test + public void nodeConstructor_returnsNode() { + Node node = new Node(1, 5, 3); + + assertAll( + () -> assertEquals(1, node.getX()), + () -> assertEquals(5, node.getY()), + () -> assertEquals(3, node.getZ())); + } + + @Test + public void node_toStringCalled_returnsString() { + Node node = new Node(1, 5, 3); + + assertEquals("(1,5,3)", node.toString()); + } + + @Test + public void node_update_updatesCoordinates() { + Node node = new Node(1, 5, 3); + Node temp = new Node(2, 6, 4); + node.update(temp); + + assertAll( + () -> assertEquals(2, node.getX()), + () -> assertEquals(6, node.getY()), + () -> assertEquals(4, node.getZ())); + } + + @Test + public void node_duplicate_returnsNode() { + Node node = new Node(1, 5, 3); + Node duplicate = node.duplicate(); + + assertAll( + () -> assertEquals(node.getX(), duplicate.getX()), + () -> assertEquals(node.getY(), duplicate.getY()), + () -> assertEquals(node.getZ(), duplicate.getZ())); + } + + @Test + public void node_compareTo_returnsComparison() { + Node node1 = new Node(1, 5, 3); + Node node2 = new Node(1, 5, 3); + Node node3 = new Node(2, 6, 4); + + assertAll( + () -> assertEquals(0, node1.compareTo(node2)), + () -> assertEquals(-1, node1.compareTo(node3)), + () -> assertEquals(1, node3.compareTo(node1))); + } + + @Test + public void node_hashCode_returnsHashCode() { + Node node0 = new Node(1, 2, 3); + Node node1 = new Node(1, 2, 3); + Node node2 = new Node(3, 2, 1); + + assertAll( + () -> assertTrue(node0.equals(node1)), + () -> assertTrue(node1.equals(node0)), + () -> assertTrue(node0.hashCode() == node1.hashCode()), + () -> assertFalse(node0.equals(node2))); + } + + @Test + public void node_equals_returnsEquality() { + Node node1 = new Node(1, 2, 3); + Node node2 = new Node(1, 2, 3); + Node node3 = new Node(3, 2, 1); + Node node4 = new Node(1, 3, 3); + Edge edge = new Edge(node1, node2); + + assertAll( + () -> assertTrue(node1.equals(node2)), + () -> assertFalse(node1.equals(node3)), + () -> assertFalse(node1.equals(node4)), + () -> assertFalse(node1.equals(null)), + () -> assertFalse(node1.equals(edge))); + } + + @Test + public void edgeConstructor_containsReferencesToNodes() { + Node fromNode = new Node(0, 0, 0); + Node toNode = new Node(0, 1, 0); + + Edge edge = new Edge(fromNode, toNode); + + assertAll( + () -> assertEquals(fromNode, edge.getFrom()), + () -> assertEquals(toNode, edge.getTo())); + } + + @Test + public void edge_toStringCalled_returnsString() { + Node fromNode0 = new Node(0, 0, 0); + Node toNode0 = new Node(0, 1, 0); + Node fromNode1 = new Node(1, 0, 0); + Node toNode1 = new Node(1, 1, 0); + + Edge edge0 = new Edge(fromNode0, toNode0); + Edge edge1 = new Edge(fromNode1, toNode1); + + assertAll( + () -> assertEquals("[(0,0,0)~(0,1,0)]", edge0.toString()), + () -> assertEquals("[(1,0,0)~(1,1,0)]", edge1.toString())); + } + + @Test + public void edge_equals() { + Node fromNode0 = new Node(0, 0, 0); + Node toNode0 = new Node(0, 1, 0); + Node fromNode1 = new Node(1, 0, 0); + Node toNode1 = new Node(1, 1, 0); + + Edge edge0 = new Edge(fromNode0, toNode0); + Edge edge1 = new Edge(fromNode1, toNode1); + Edge edge2 = new Edge(fromNode0, toNode0); + + assertAll( + () -> assertTrue(edge0.equals(edge2)), + () -> assertFalse(edge0.equals(edge1)), + () -> assertFalse(edge0.equals(null)), + () -> assertFalse(edge0.equals(fromNode0))); + } + + @Test + public void edge_hashCode() { + Node fromNode0 = new Node(0, 0, 0); + Node toNode0 = new Node(0, 1, 0); + Node fromNode1 = new Node(1, 0, 0); + Node toNode1 = new Node(1, 1, 0); + + Edge edge0 = new Edge(fromNode0, toNode0); + Edge edge1 = new Edge(fromNode1, toNode1); + Edge edge2 = new Edge(fromNode0, toNode0); + + assertAll( + () -> assertTrue(edge0.hashCode() == edge2.hashCode()), + () -> assertFalse(edge0.hashCode() != edge1.hashCode())); + } + + @Test + public void graphConstructor_returnsEmptyGraph() { + Graph graph = new Graph(); + + assertAll( + () -> assertTrue(graph.getAllEdges().isEmpty()), + () -> assertTrue(graph.getAllNodes().isEmpty())); + } + + @Test + public void getAllNodes_returnsExpectedSet() { + Graph graph = new Graph(); + Node node1 = new Node(0, 0, 0); + Node node2 = new Node(0, 1, 0); + Edge edge = new Edge(node1, node2); + + graph.addEdge(edge); + + HashSet expected = new HashSet(); + expected.add(node1); + expected.add(node2); + + HashSet actual = (HashSet) graph.getAllNodes(); + + assertEquals(expected, actual); + } + + @Test + public void addEdge_nodesAdded() { + Graph graph = new Graph(); + Node node1 = new Node(0, 0, 0); + Node node2 = new Node(0, 1, 0); + Edge edge = new Edge(node1, node2); + + graph.addEdge(edge); + + assertAll( + () -> assertTrue(graph.contains(node1)), + () -> assertTrue(graph.contains(node2)), + () -> assertTrue(graph.contains(new Edge(node1, node2)))); + } + + @Test + public void addEdge_WithTwoNodes_edgeAdded() { + Graph graph = new Graph(); + Node node1 = new Node(0, 0, 0); + Node node2 = new Node(0, 1, 0); + + graph.addEdge(node1, node2); + + assertAll( + () -> assertTrue(graph.contains(node1)), + () -> assertTrue(graph.contains(node2)), + () -> assertTrue(graph.contains(new Edge(node1, node2)))); + } + + @Test + public void addEdge_edgeUpdatedWithInAndOutEdges() { + Graph graph = new Graph(); + Node node1 = new Node(0, 0, 0); + Node node2 = new Node(0, 1, 0); + Node node3 = new Node(0, 2, 0); + Node node4 = new Node(0, 3, 0); + Edge edge1 = new Edge(node1, node2); + Edge edge2 = new Edge(node2, node3); + Edge edge3 = new Edge(node3, node4); + Edge edge4 = new Edge(node3, node1); + + graph.addEdge(edge1); + graph.addEdge(edge2); + graph.addEdge(edge3); + graph.addEdge(edge4); + + ArrayList inList = edge2.getEdgesIn(); + ArrayList outList = edge2.getEdgesOut(); + + assertAll( + () -> assertEquals(1, inList.size()), + () -> assertEquals(2, outList.size()), + () -> assertTrue(inList.contains(edge1)), + () -> assertTrue(outList.contains(edge3)), + () -> assertTrue(outList.contains(edge4))); + } + + @Test + public void addEdge_edgeAlreadyExistsInGraph_edgeAdded() { + Graph graph = new Graph(); + Node node1 = new Node(0, 0, 0); + Node node2 = new Node(0, 1, 0); + Node node3 = new Node(0, 2, 0); + Node node4 = new Node(0, 3, 0); + Edge edge1 = new Edge(node1, node2); + Edge edge2 = new Edge(node2, node3); + Edge edge3 = new Edge(node3, node4); + + graph.addEdge(edge1); + graph.addEdge(edge2); + graph.addEdge(edge3); + graph.addEdge(edge2); + + assertAll( + () -> assertTrue(graph.contains(edge1)), + () -> assertTrue(graph.contains(edge2)), + () -> assertTrue(graph.contains(edge3))); + } + + @Test + public void removeEdge_edgeRemovedAndPreservesGraph() { + Graph graph = new Graph(); + Node node1a = new Node(1, 0, 0); + Node node1b = new Node(0, 0, 0); + Node node2 = new Node(0, 1, 0); + Node node3 = new Node(0, 2, 0); + Node node4a = new Node(0, 3, 0); + Node node4b = new Node(1, 3, 0); + Edge edge1a = new Edge(node1a, node2); + Edge edge1b = new Edge(node2, node1b); + Edge edge2 = new Edge(node2, node3); + Edge edge3a = new Edge(node3, node4a); + Edge edge3b = new Edge(node4b, node3); + + graph.addEdge(edge1a); + graph.addEdge(edge1b); + graph.addEdge(edge2); + graph.addEdge(edge3a); + graph.addEdge(edge3b); + graph.removeEdge(edge2); + + assertAll( + () -> assertFalse(graph.contains(edge2)), + () -> assertTrue(graph.contains(node3)), + () -> assertTrue(graph.contains(node1a)), + () -> assertTrue(graph.contains(node1b)), + () -> assertTrue(graph.contains(node2)), + () -> assertTrue(graph.contains(node4a)), + () -> assertTrue(graph.contains(node4b)), + () -> assertTrue(graph.contains(new Edge(node1a, node2))), + () -> assertTrue(graph.contains(new Edge(node2, node1b))), + () -> assertTrue(graph.contains(new Edge(node3, node4a))), + () -> assertTrue(graph.contains(new Edge(node4b, node3)))); + } + + @Test + public void clearEdge_linksRemoved() { + Graph graph = new Graph(); + Node node1 = new Node(0, 0, 0); + Node node2 = new Node(0, 1, 0); + Node node3 = new Node(0, 2, 0); + Node node4 = new Node(0, 3, 0); + Edge edge1 = new Edge(node1, node2); + Edge edge2 = new Edge(node2, node3); + Edge edge3 = new Edge(node3, node4); + + graph.addEdge(edge1); + graph.addEdge(edge2); + graph.addEdge(edge3); + graph.clearEdge(edge2); + + assertAll( + () -> assertTrue(edge2.getEdgesIn().isEmpty()), + () -> assertTrue(edge2.getEdgesOut().isEmpty()), + () -> assertTrue(graph.contains(edge2))); + } + + @Test + public void reverseEdge_reversesEdgeAndRemovesOriginalEdge() { + Graph graph = new Graph(); + Node node1 = new Node(0, 0, 0); + Node node2 = new Node(0, 1, 0); + Edge edge = new Edge(node1, node2); + + graph.addEdge(edge); + graph.reverseEdge(edge); + + assertAll( + () -> assertTrue(graph.contains(new Edge(node2, node1))), + () -> assertFalse(graph.contains(new Edge(node1, node2)))); + } + + @Test + public void mergeNodes_mergesNodes() { + Graph graph = new Graph(); + Node node1 = new Node(0, 0, 0); + Node node2A = new Node(1, 1, 0); + Node node2B = new Node(1, 1, 0); + Node node3 = new Node(2, 2, 0); + + Edge edge1 = new Edge(node1, node2A); + Edge edge2 = new Edge(node2B, node3); + + graph.addEdge(edge1); + graph.addEdge(edge2); + graph.mergeNodes(); + + assertTrue(edge1.getTo() == edge2.getFrom()); + } + + @Test + public void getEdgesOut_returnsEdgesOut() { + Graph graph = new Graph(); + Node node1 = new Node(0, 0, 0); + Node node2 = new Node(1, 1, 0); + Node node3 = new Node(2, 2, 0); + Node node4 = new Node(3, 3, 0); + Node node5 = new Node(4, 4, 0); + Edge edge1 = new Edge(node1, node2); + Edge edge2 = new Edge(node2, node3); + Edge edge3 = new Edge(node2, node4); + Edge edge4 = new Edge(node2, node5); + Edge edge5 = new Edge(node5, node1); + + graph.addEdge(edge1); + graph.addEdge(edge2); + graph.addEdge(edge3); + graph.addEdge(edge4); + graph.addEdge(edge5); + + Bag expectedEdgesOut = new Bag(); + expectedEdgesOut.add(edge2); + expectedEdgesOut.add(edge3); + expectedEdgesOut.add(edge4); + + Bag edgesOut = graph.getEdgesOut(new Node(1, 1, 0)); + + assertAll( + () -> assertTrue(edgesOut.containsAll(expectedEdgesOut)), + () -> assertTrue(expectedEdgesOut.containsAll(edgesOut))); + } + + @Test + public void getEdgesOut_noEdgesOutOfGivenNode_returnsNull() { + Graph graph = new Graph(); + Node node1 = new Node(0, 0, 0); + Node node2 = new Node(1, 1, 0); + Edge edge1 = new Edge(node1, node2); + graph.addEdge(edge1); + + assertNull(graph.getEdgesOut(node2)); + } + + @Test + public void getEdgesIn_returnsEdgesIn() { + Graph graph = new Graph(); + Node node1 = new Node(0, 0, 0); + Node node2 = new Node(1, 1, 0); + Node node3 = new Node(2, 2, 0); + Node node4 = new Node(3, 3, 0); + Node node5 = new Node(4, 4, 0); + Edge edge1 = new Edge(node1, node2); + Edge edge2 = new Edge(node2, node3); + Edge edge3 = new Edge(node2, node4); + Edge edge4 = new Edge(node5, node2); + Edge edge5 = new Edge(node5, node1); + + graph.addEdge(edge1); + graph.addEdge(edge2); + graph.addEdge(edge3); + graph.addEdge(edge4); + graph.addEdge(edge5); + + Bag expectedEdgesIn = new Bag(); + expectedEdgesIn.add(edge1); + expectedEdgesIn.add(edge4); + + Bag edgesIn = graph.getEdgesIn(new Node(1, 1, 0)); + + assertAll( + () -> assertTrue(edgesIn.containsAll(expectedEdgesIn)), + () -> assertTrue(expectedEdgesIn.containsAll(edgesIn))); + } + + @Test + public void getEdgesIn_noEdgesIntoGivenNode_returnsNull() { + Graph graph = new Graph(); + Node node1 = new Node(0, 0, 0); + Node node2 = new Node(1, 1, 0); + Edge edge1 = new Edge(node1, node2); + graph.addEdge(edge1); + + assertNull(graph.getEdgesIn(node1)); + } + + @Test + public void getDegree_returnsCorrectDegree() { + Graph graph = new Graph(); + Node node1 = new Node(0, 0, 0); + Node node2 = new Node(1, 1, 0); + Node node3 = new Node(2, 2, 0); + Edge edge1 = new Edge(node1, node2); + Edge edge2 = new Edge(node2, node3); + + graph.addEdge(edge1); + graph.addEdge(edge2); + + assertAll( + () -> assertEquals(1, graph.getDegree(node1)), + () -> assertEquals(2, graph.getDegree(node2)), + () -> assertEquals(1, graph.getDegree(node3))); + } + + @Test + public void getInDegree_returnsCorrectDegree() { + Graph graph = new Graph(); + Node node1 = new Node(0, 0, 0); + Node node2 = new Node(1, 1, 0); + Node node3 = new Node(2, 2, 0); + Edge edge1 = new Edge(node1, node2); + Edge edge2 = new Edge(node2, node3); + + graph.addEdge(edge1); + graph.addEdge(edge2); + + assertAll( + () -> assertEquals(0, graph.getInDegree(node1)), + () -> assertEquals(1, graph.getInDegree(node2)), + () -> assertEquals(1, graph.getInDegree(node3))); + } + + @Test + public void getOutDegree_returnsCorrectDegree() { + Graph graph = new Graph(); + Node node1 = new Node(0, 0, 0); + Node node2 = new Node(1, 1, 0); + Node node3 = new Node(2, 2, 0); + Edge edge1 = new Edge(node1, node2); + Edge edge2 = new Edge(node2, node3); + + graph.addEdge(edge1); + graph.addEdge(edge2); + + assertAll( + () -> assertEquals(1, graph.getOutDegree(node1)), + () -> assertEquals(1, graph.getOutDegree(node2)), + () -> assertEquals(0, graph.getOutDegree(node3))); + } + + @Test + public void hasEdge_givenExistingEdge_returnsTrue() { + Graph graph = new Graph(); + Node node1 = new Node(0, 0, 0); + Node node2 = new Node(1, 1, 0); + Node node3 = new Node(2, 2, 0); + + Edge edge1 = new Edge(node1, node2); + Edge edge2 = new Edge(node2, node3); + + graph.addEdge(edge1); + graph.addEdge(edge2); + + assertAll( + () -> assertTrue(graph.hasEdge(node1, node2)), + () -> assertTrue(graph.hasEdge(node2, node3))); + } + + @Test + public void hasEdge_givenEdgeNotInGraph_returnsFalse() { + Graph graph = new Graph(); + Node node1 = new Node(0, 0, 0); + Node node2 = new Node(1, 1, 0); + Node node3 = new Node(2, 2, 0); + + Edge edge1 = new Edge(node1, node2); + Edge edge2 = new Edge(node2, node3); + + graph.addEdge(edge1); + graph.addEdge(edge2); + + assertFalse(graph.hasEdge(node3, node1)); + } + + @Test + public void findDownstreamIntersection_returnsIntersectionNode() { + Graph graph = new Graph(); + Node node1 = new Node(0, 0, 0); + Node node2A = new Node(1, 1, 0); + Node node3A = new Node(2, 2, 0); + Node node2B = new Node(-1, -1, 0); + Node node3B = new Node(-2, -2, 0); + Node node4 = new Node(3, 0, 0); + + Edge edge1 = new Edge(node1, node2A); + Edge edge2 = new Edge(node2A, node3A); + Edge edge3 = new Edge(node1, node2B); + Edge edge4 = new Edge(node2B, node3B); + Edge edge5 = new Edge(node3A, node4); + Edge edge6 = new Edge(node3B, node4); + + graph.addEdge(edge1); + graph.addEdge(edge2); + graph.addEdge(edge3); + graph.addEdge(edge4); + graph.addEdge(edge5); + graph.addEdge(edge6); + + Node found1 = graph.findDownstreamIntersection(edge1, edge3); + Node found2 = graph.findDownstreamIntersection(edge3, edge1); + Node found3 = graph.findDownstreamIntersection(edge1, edge1); + + assertAll( + () -> assertEquals(node4, found1), + () -> assertEquals(node4, found2), + () -> assertEquals(node2A, found3)); + } + + @Test + public void findDownstreamIntersection_noIntersection_returnsNull() { + Graph graph = new Graph(); + Node node1 = new Node(0, 0, 0); + Node node2A = new Node(1, 1, 0); + Node node3A = new Node(2, 2, 0); + Node node2B = new Node(-1, -1, 0); + Node node3B = new Node(-2, -2, 0); + + Edge edge1 = new Edge(node1, node2A); + Edge edge2 = new Edge(node2A, node3A); + Edge edge3 = new Edge(node1, node2B); + Edge edge4 = new Edge(node2B, node3B); + + graph.addEdge(edge1); + graph.addEdge(edge2); + graph.addEdge(edge3); + graph.addEdge(edge4); + + Node found1 = graph.findDownstreamIntersection(edge1, edge3); + Node found2 = graph.findDownstreamIntersection(edge2, edge4); + Node found3 = graph.findDownstreamIntersection(edge3, edge1); + Node found4 = graph.findDownstreamIntersection(edge4, edge2); + + assertAll( + () -> assertNull(found1, "No intersection"), + () -> assertNull(found2, "No out edges"), + () -> assertNull(found3, "No intersection"), + () -> assertNull(found4, "No out edges")); + } + + @Test + public void findUpstreamIntersection_returnsIntersectionNode() { + Graph graph = new Graph(); + Node node0 = new Node(-1, 0, 0); + Node node1 = new Node(0, 0, 0); + Node node2A = new Node(1, 1, 0); + Node node3A = new Node(2, 2, 0); + Node node2B = new Node(-1, -1, 0); + Node node3B = new Node(-2, -2, 0); + Node node4 = new Node(3, 0, 0); + + Edge edge0 = new Edge(node0, node1); + Edge edge1 = new Edge(node1, node2A); + Edge edge2 = new Edge(node2A, node3A); + Edge edge3 = new Edge(node1, node2B); + Edge edge4 = new Edge(node2B, node3B); + Edge edge5 = new Edge(node3A, node4); + Edge edge6 = new Edge(node3B, node4); + + graph.addEdge(edge0); + graph.addEdge(edge1); + graph.addEdge(edge2); + graph.addEdge(edge3); + graph.addEdge(edge4); + graph.addEdge(edge5); + graph.addEdge(edge6); + + Node found1 = graph.findUpstreamIntersection(edge5, edge6); + Node found2 = graph.findUpstreamIntersection(edge6, edge5); + Node found3 = graph.findUpstreamIntersection(edge2, edge2); + + assertAll( + () -> assertEquals(node1, found1), + () -> assertEquals(node1, found2), + () -> assertEquals(node2A, found3)); + } + + @Test + public void findDownstreamIntersection_disconnectedCycles_returnsNull() { + Graph graph = new Graph(); + + Node node1A = new Node(0, 0, 0); + Node node2A = new Node(0, 1, 0); + Node node3A = new Node(1, 1, 0); + + Node node1B = new Node(0, 0, 1); + Node node2B = new Node(0, 1, 1); + Node node3B = new Node(1, 1, 1); + + Edge edge1A = new Edge(node1A, node2A); + Edge edge2A = new Edge(node1A, node3A); + Edge edge3A = new Edge(node2A, node1A); + + Edge edge1B = new Edge(node1B, node2B); + Edge edge2B = new Edge(node1B, node3B); + Edge edge3B = new Edge(node2B, node1B); + + graph.addEdge(edge1A); + graph.addEdge(edge2A); + graph.addEdge(edge3A); + + graph.addEdge(edge1B); + graph.addEdge(edge2B); + graph.addEdge(edge3B); + + Node found1 = graph.findDownstreamIntersection(edge1A, edge1B); + assertNull(found1); + } + + @Test + public void findUpstreamIntersection_disconnectedCycles_returnsNull() { + Graph graph = new Graph(); + + Node node1A = new Node(0, 0, 0); + Node node2A = new Node(0, 1, 0); + Node node3A = new Node(1, 1, 0); + + Node node1B = new Node(0, 0, 1); + Node node2B = new Node(0, 1, 1); + Node node3B = new Node(1, 1, 1); + + Edge edge1A = new Edge(node1A, node2A); + Edge edge2A = new Edge(node1A, node3A); + Edge edge3A = new Edge(node2A, node1A); + + Edge edge1B = new Edge(node1B, node2B); + Edge edge2B = new Edge(node1B, node3B); + Edge edge3B = new Edge(node2B, node1B); + + graph.addEdge(edge1A); + graph.addEdge(edge2A); + graph.addEdge(edge3A); + + graph.addEdge(edge1B); + graph.addEdge(edge2B); + graph.addEdge(edge3B); + + Node found1 = graph.findUpstreamIntersection(edge1A, edge1B); + assertNull(found1); + } + + @Test + public void findUpstreamIntersection_noIntersection_returnsNull() { + Graph graph = new Graph(); + + Node node1 = new Node(0, 0, 0); + Node node2A = new Node(1, 1, 0); + Node node3A = new Node(2, 2, 0); + Node node2B = new Node(-1, -1, 0); + Node node3B = new Node(-2, -2, 0); + Node node4 = new Node(3, 0, 0); + + Edge edge1 = new Edge(node1, node2B); + Edge edge2 = new Edge(node2A, node3A); + Edge edge4 = new Edge(node2B, node3B); + Edge edge5 = new Edge(node3A, node4); + Edge edge6 = new Edge(node3B, node4); + + graph.addEdge(edge1); + graph.addEdge(edge2); + graph.addEdge(edge4); + graph.addEdge(edge5); + graph.addEdge(edge6); + + Node found1 = graph.findUpstreamIntersection(edge5, edge6); + Node found2 = graph.findUpstreamIntersection(edge2, edge4); + Node found3 = graph.findUpstreamIntersection(edge6, edge5); + Node found4 = graph.findUpstreamIntersection(edge4, edge2); + + assertAll( + () -> assertNull(found1, "No intersection"), + () -> assertNull(found2, "No in edges"), + () -> assertNull(found3, "No intersection"), + () -> assertNull(found4, "No in edges")); + } + + @Test + public void getSubgraph_filterFunction_returnedFilteredEdges() { + Graph graph = new Graph(); + Node node0 = new Node(-1, 0, 0); + Node node1 = new Node(0, 0, 0); + Node node2A = new Node(1, 1, 0); + Node node3A = new Node(2, 2, 0); + Node node2B = new Node(-1, -1, 0); + Node node3B = new Node(-2, -2, 0); + Node node4 = new Node(3, 0, 0); + + Edge edge0 = new Edge(node0, node1); + Edge edge1 = new Edge(node1, node2A); + Edge edge2 = new Edge(node2A, node3A); + Edge edge3 = new Edge(node1, node2B); + Edge edge4 = new Edge(node2B, node3B); + Edge edge5 = new Edge(node3A, node4); + Edge edge6 = new Edge(node3B, node4); + + graph.addEdge(edge0); + graph.addEdge(edge1); + graph.addEdge(edge2); + graph.addEdge(edge3); + graph.addEdge(edge4); + graph.addEdge(edge5); + graph.addEdge(edge6); + + Graph subgraph = new Graph(); + graph.getSubgraph(subgraph, e -> ((Edge) e).from.getX() == 0); + + assertAll( + () -> assertEquals(subgraph.getAllEdges().numObjs, 2), + () -> assertTrue(subgraph.contains(edge1)), + () -> assertTrue(subgraph.contains(edge3))); + } + + @Test + public void update_updatesGraph() { + Graph graph = new Graph(); + Node node0 = new Node(-1, 0, 0); + Node node1 = new Node(0, 0, 0); + Node node2A = new Node(1, 1, 0); + Node node3A = new Node(2, 2, 0); + Node node2B = new Node(-1, -1, 0); + Node node3B = new Node(-2, -2, 0); + Node node4 = new Node(3, 0, 0); + + Edge edge0 = new Edge(node0, node1); + Edge edge1 = new Edge(node1, node2A); + Edge edge2 = new Edge(node2A, node3A); + Edge edge3 = new Edge(node1, node2B); + Edge edge4 = new Edge(node2B, node3B); + Edge edge5 = new Edge(node3A, node4); + Edge edge6 = new Edge(node3B, node4); + + graph.addEdge(edge0); + graph.addEdge(edge1); + graph.addEdge(edge2); + graph.addEdge(edge3); + + Graph newGraph = new Graph(); + + newGraph.addEdge(edge4); + newGraph.addEdge(edge5); + newGraph.addEdge(edge6); + + graph.update(newGraph); + + assertAll( + () -> assertEquals(graph.getAllEdges().numObjs, 7), + () -> assertTrue(graph.contains(edge0)), + () -> assertTrue(graph.contains(edge1)), + () -> assertTrue(graph.contains(edge2)), + () -> assertTrue(graph.contains(edge3)), + () -> assertTrue(graph.contains(edge4)), + () -> assertTrue(graph.contains(edge5)), + () -> assertTrue(graph.contains(edge6))); + } + + @Test + public void clear_clearsGraph() { + Graph graph = new Graph(); + Node node0 = new Node(-1, 0, 0); + Node node1 = new Node(0, 0, 0); + Node node2A = new Node(1, 1, 0); + Node node3A = new Node(2, 2, 0); + Node node2B = new Node(-1, -1, 0); + Node node3B = new Node(-2, -2, 0); + Node node4 = new Node(3, 0, 0); + + Edge edge0 = new Edge(node0, node1); + Edge edge1 = new Edge(node1, node2A); + Edge edge2 = new Edge(node2A, node3A); + Edge edge3 = new Edge(node1, node2B); + Edge edge4 = new Edge(node2B, node3B); + Edge edge5 = new Edge(node3A, node4); + Edge edge6 = new Edge(node3B, node4); + + graph.addEdge(edge0); + graph.addEdge(edge1); + graph.addEdge(edge2); + graph.addEdge(edge3); + graph.addEdge(edge4); + graph.addEdge(edge5); + graph.addEdge(edge6); + + graph.clear(); + + assertAll( + () -> assertTrue(graph.getAllEdges().isEmpty()), + () -> assertTrue(graph.getAllNodes().isEmpty())); + } + + @Test + public void graph_toString_returnsString() { + Graph graph = new Graph(); + Node node0 = new Node(4, 5, 6); + Node node1 = new Node(5, 5, 6); + Node node2 = new Node(6, 5, 6); + + Edge edge0 = new Edge(node0, node1); + Edge edge1 = new Edge(node1, node2); + + graph.addEdge(edge0); + graph.addEdge(edge1); + + String expected = + "\n" + + "EDGES OUT\n" + + "\n" + + "(4,5,6) : [(4,5,6)~(5,5,6)] \n" + + "(5,5,6) : [(5,5,6)~(6,5,6)] \n" + + "\n" + + "EDGES IN\n" + + "\n" + + "(5,5,6) : [(4,5,6)~(5,5,6)] \n" + + "(6,5,6) : [(5,5,6)~(6,5,6)] \n"; + + assertEquals(expected, graph.toString()); + } +} diff --git a/test/arcade/core/util/MatrixTest.java b/test/arcade/core/util/MatrixTest.java index 0130eae06..93278b3ed 100644 --- a/test/arcade/core/util/MatrixTest.java +++ b/test/arcade/core/util/MatrixTest.java @@ -2,53 +2,60 @@ import java.util.ArrayList; import java.util.Comparator; -import org.junit.BeforeClass; -import org.junit.Test; -import static org.junit.Assert.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; import static arcade.core.util.Matrix.*; public class MatrixTest { private static final double EPSILON = 1E-10; - - private static final double[][] A1D = new double[][] { - { 1, 2, 3, 4, 5 }, - { 6, 7, 8, 9, 10 }, - { 11, 12, 13, 14, 15 }, - { 16, 17, 18, 19, 20 }, - { 21, 22, 23, 24, 25 } - }; - - private static final double[][] A2D = new double[][] { - { 2, 3, 0, 1, 2 }, - { 0, 1, 2, 3, 1 }, - { 0, 3, 1, 1, 0 }, - { 0, 1, 2, 1, 1 }, - { 0, 0, 0, 2, 1 } - }; - - private static final double[][] A3D = new double[][] { - { 1, 0, 4, 3, 0 }, - { 6, 2, 0, 2, 2 }, - { 4, 3, 1, 0, 0 }, - { 2, 3, 2, 1, 0 }, - { 3, 1, 3, 2, 1 } - }; - - private static final double[] B1D = new double[] { 2, 3, 6, 1, 2 }; - + + private static final double[][] A1D = + new double[][] { + {1, 2, 3, 4, 5}, + {6, 7, 8, 9, 10}, + {11, 12, 13, 14, 15}, + {16, 17, 18, 19, 20}, + {21, 22, 23, 24, 25} + }; + + private static final double[][] A2D = + new double[][] { + {2, 3, 0, 1, 2}, + {0, 1, 2, 3, 1}, + {0, 3, 1, 1, 0}, + {0, 1, 2, 1, 1}, + {0, 0, 0, 2, 1} + }; + + private static final double[][] A3D = + new double[][] { + {1, 0, 4, 3, 0}, + {6, 2, 0, 2, 2}, + {4, 3, 1, 0, 0}, + {2, 3, 2, 1, 0}, + {3, 1, 3, 2, 1} + }; + + private static final double[] B1D = new double[] {2, 3, 6, 1, 2}; + private static final ArrayList A1S = new ArrayList<>(); - + private static final ArrayList A2S = new ArrayList<>(); - + private static final ArrayList A3S = new ArrayList<>(); - + private static final ArrayList B1S = new ArrayList<>(); - - public static final Comparator COMPARATOR = (v1, v2) -> v1.i != v2.i - ? Integer.compare(v1.i, v2.i) : v1.j != v2.j - ? Integer.compare(v1.j, v2.j) : Double.compare(v1.v, v2.v); - - @BeforeClass + + public static final Comparator COMPARATOR = + (v1, v2) -> + v1.i != v2.i + ? Integer.compare(v1.i, v2.i) + : v1.j != v2.j + ? Integer.compare(v1.j, v2.j) + : Double.compare(v1.v, v2.v); + + @BeforeAll public static void setupMatrices() { A1S.add(new Value(0, 0, 1)); A1S.add(new Value(0, 1, 2)); @@ -75,7 +82,7 @@ public static void setupMatrices() { A1S.add(new Value(4, 2, 23)); A1S.add(new Value(4, 3, 24)); A1S.add(new Value(4, 4, 25)); - + A2S.add(new Value(0, 0, 2)); A2S.add(new Value(0, 1, 3)); A2S.add(new Value(0, 3, 1)); @@ -93,7 +100,7 @@ public static void setupMatrices() { A2S.add(new Value(3, 4, 1)); A2S.add(new Value(4, 3, 2)); A2S.add(new Value(4, 4, 1)); - + A3S.add(new Value(0, 0, 1)); A3S.add(new Value(0, 2, 4)); A3S.add(new Value(0, 3, 3)); @@ -113,31 +120,32 @@ public static void setupMatrices() { A3S.add(new Value(4, 2, 3)); A3S.add(new Value(4, 3, 2)); A3S.add(new Value(4, 4, 1)); - + B1S.add(new Value(0, 0, 2)); B1S.add(new Value(0, 1, 3)); B1S.add(new Value(0, 2, 6)); B1S.add(new Value(0, 3, 1)); B1S.add(new Value(0, 4, 2)); } - - @Test(expected = UnsupportedOperationException.class) + + @Test public void constructor_called_throwsException() { - Matrix matrix = new Matrix(); + assertThrows(UnsupportedOperationException.class, Matrix::new); } - + @Test public void getUpper_isNotStrictDense_getsMatrix() { - double[][] expected = new double[][] { - { 1, 2, 3, 4, 5 }, - { 0, 7, 8, 9, 10 }, - { 0, 0, 13, 14, 15 }, - { 0, 0, 0, 19, 20 }, - { 0, 0, 0, 0, 25 } - }; + double[][] expected = + new double[][] { + {1, 2, 3, 4, 5}, + {0, 7, 8, 9, 10}, + {0, 0, 13, 14, 15}, + {0, 0, 0, 19, 20}, + {0, 0, 0, 0, 25} + }; assertArrayEquals(expected, getUpper(A1D, false)); } - + @Test public void getUpper_isNotStrictSparse_getsMatrix() { ArrayList expected = new ArrayList<>(); @@ -156,26 +164,27 @@ public void getUpper_isNotStrictSparse_getsMatrix() { expected.add(new Value(3, 3, 19)); expected.add(new Value(3, 4, 20)); expected.add(new Value(4, 4, 25)); - + ArrayList upper = getUpper(A1S, false); upper.sort(COMPARATOR); expected.sort(COMPARATOR); - + assertEquals(expected, upper); } - + @Test public void getUpper_isStrictDense_getsMatrix() { - double[][] expected = new double[][] { - { 0, 2, 3, 4, 5 }, - { 0, 0, 8, 9, 10 }, - { 0, 0, 0, 14, 15 }, - { 0, 0, 0, 0, 20 }, - { 0, 0, 0, 0, 0 } - }; + double[][] expected = + new double[][] { + {0, 2, 3, 4, 5}, + {0, 0, 8, 9, 10}, + {0, 0, 0, 14, 15}, + {0, 0, 0, 0, 20}, + {0, 0, 0, 0, 0} + }; assertArrayEquals(expected, getUpper(A1D, true)); } - + @Test public void getUpper_isStrictSparse_getsMatrix() { ArrayList expected = new ArrayList<>(); @@ -189,26 +198,27 @@ public void getUpper_isStrictSparse_getsMatrix() { expected.add(new Value(2, 3, 14)); expected.add(new Value(2, 4, 15)); expected.add(new Value(3, 4, 20)); - + ArrayList upper = getUpper(A1S, true); upper.sort(COMPARATOR); expected.sort(COMPARATOR); - + assertEquals(expected, upper); } - + @Test public void getLower_isNotStrictDense_getsMatrix() { - double[][] expected = new double[][] { - { 1, 0, 0, 0, 0 }, - { 6, 7, 0, 0, 0 }, - { 11, 12, 13, 0, 0 }, - { 16, 17, 18, 19, 0 }, - { 21, 22, 23, 24, 25 } - }; + double[][] expected = + new double[][] { + {1, 0, 0, 0, 0}, + {6, 7, 0, 0, 0}, + {11, 12, 13, 0, 0}, + {16, 17, 18, 19, 0}, + {21, 22, 23, 24, 25} + }; assertArrayEquals(expected, getLower(A1D, false)); } - + @Test public void getLower_isNotStrictSparse_getsMatrix() { ArrayList expected = new ArrayList<>(); @@ -227,26 +237,27 @@ public void getLower_isNotStrictSparse_getsMatrix() { expected.add(new Value(4, 2, 23)); expected.add(new Value(4, 3, 24)); expected.add(new Value(4, 4, 25)); - + ArrayList lower = getLower(A1S, false); lower.sort(COMPARATOR); expected.sort(COMPARATOR); - + assertEquals(expected, lower); } - + @Test public void getLower_isStrictDense_getsMatrix() { - double[][] expected = new double[][] { - { 0, 0, 0, 0, 0 }, - { 6, 0, 0, 0, 0 }, - { 11, 12, 0, 0, 0 }, - { 16, 17, 18, 0, 0 }, - { 21, 22, 23, 24, 0 } - }; + double[][] expected = + new double[][] { + {0, 0, 0, 0, 0}, + {6, 0, 0, 0, 0}, + {11, 12, 0, 0, 0}, + {16, 17, 18, 0, 0}, + {21, 22, 23, 24, 0} + }; assertArrayEquals(expected, getLower(A1D, true)); } - + @Test public void getLower_isStrictSparse_getsMatrix() { ArrayList expected = new ArrayList<>(); @@ -260,31 +271,32 @@ public void getLower_isStrictSparse_getsMatrix() { expected.add(new Value(4, 1, 22)); expected.add(new Value(4, 2, 23)); expected.add(new Value(4, 3, 24)); - + ArrayList lower = getLower(A1S, true); lower.sort(COMPARATOR); expected.sort(COMPARATOR); - + assertEquals(expected, lower); } - + @Test public void multiply_denseRepresentation_calculatesMatrix() { - double[] multiplyA2B1 = new double[] { 18, 20, 16, 18, 4 }; - double[] multiplyA3B1 = new double[] { 29, 24, 23, 26, 31 }; - double[][] multiplyA2A3 = new double[][] { - { 28, 11, 16, 17, 8 }, - { 23, 18, 11, 7, 3 }, - { 24, 12, 3, 7, 6 }, - { 19, 12, 7, 5, 3 }, - { 7, 7, 7, 4, 1 } - }; - + double[] multiplyA2B1 = new double[] {18, 20, 16, 18, 4}; + double[] multiplyA3B1 = new double[] {29, 24, 23, 26, 31}; + double[][] multiplyA2A3 = + new double[][] { + {28, 11, 16, 17, 8}, + {23, 18, 11, 7, 3}, + {24, 12, 3, 7, 6}, + {19, 12, 7, 5, 3}, + {7, 7, 7, 4, 1} + }; + assertArrayEquals(multiply(A2D, B1D), multiplyA2B1, EPSILON); assertArrayEquals(multiply(A3D, B1D), multiplyA3B1, EPSILON); assertArrayEquals(multiply(A2D, A3D), multiplyA2A3); } - + @Test public void multiply_sparseRepresentation_calculatesMatrix() { ArrayList expected = new ArrayList<>(); @@ -313,65 +325,69 @@ public void multiply_sparseRepresentation_calculatesMatrix() { expected.add(new Value(4, 2, 7)); expected.add(new Value(4, 3, 4)); expected.add(new Value(4, 4, 1)); - + ArrayList multiplied = multiply(A2S, A3S); multiplied.sort(COMPARATOR); expected.sort(COMPARATOR); - + assertEquals(expected, multiplied); } - + @Test public void invertUpper_givenUpper_calculatesInversion() { - double[][] invertUpperA2 = new double[][]{ - { 0.5, -1.5, 3, 1, -0.5 }, - { 0, 1, -2, -1, 0 }, - { 0, 0, 1, -1, 1 }, - { 0, 0, 0, 1, -1 }, - { 0, 0, 0, 0, 1 } - }; - - double[][] invertUpperA3 = new double[][]{ - { 1, 0, -4, -3, 0 }, - { 0, 0.5, 0, -1, -1 }, - { 0, 0, 1, 0, 0 }, - { 0, 0, 0, 1, 0 }, - { 0, 0, 0, 0, 1 } - }; - + double[][] invertUpperA2 = + new double[][] { + {0.5, -1.5, 3, 1, -0.5}, + {0, 1, -2, -1, 0}, + {0, 0, 1, -1, 1}, + {0, 0, 0, 1, -1}, + {0, 0, 0, 0, 1} + }; + + double[][] invertUpperA3 = + new double[][] { + {1, 0, -4, -3, 0}, + {0, 0.5, 0, -1, -1}, + {0, 0, 1, 0, 0}, + {0, 0, 0, 1, 0}, + {0, 0, 0, 0, 1} + }; + assertArrayEquals(invertUpper(A2D), invertUpperA2); assertArrayEquals(invertUpper(A3D), invertUpperA3); } - + @Test public void invertLower_givenLower_calculatesInversion() { - double[][] invertLowerA2 = new double[][]{ - { 0.5, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 0 }, - { 0, -3, 1, 0, 0 }, - { 0, 5, -2, 1, 0 }, - { 0, -10, 4, -2, 1 } - }; - - double[][] invertLowerA3 = new double[][]{ - { 1, 0, 0, 0, 0 }, - { -3, 0.5, 0, 0, 0 }, - { 5, -1.5, 1, 0, 0 }, - { -3, 1.5, -2, 1, 0 }, - { -9, 1, 1, -2, 1 } - }; - + double[][] invertLowerA2 = + new double[][] { + {0.5, 0, 0, 0, 0}, + {0, 1, 0, 0, 0}, + {0, -3, 1, 0, 0}, + {0, 5, -2, 1, 0}, + {0, -10, 4, -2, 1} + }; + + double[][] invertLowerA3 = + new double[][] { + {1, 0, 0, 0, 0}, + {-3, 0.5, 0, 0, 0}, + {5, -1.5, 1, 0, 0}, + {-3, 1.5, -2, 1, 0}, + {-9, 1, 1, -2, 1} + }; + assertArrayEquals(invertLower(A2D), invertLowerA2); assertArrayEquals(invertLower(A3D), invertLowerA3); } - + @Test public void forwardSubstitution_denseGivenLower_solvesEquation() { double[] multiplyInvertA1B1 = multiply(invertLower(A1D), B1D); double[] forwardSubstitutionA1B1 = forwardSubstitution(A1D, B1D); assertArrayEquals(multiplyInvertA1B1, forwardSubstitutionA1B1, EPSILON); } - + @Test public void forwardSubstitution_denseGivenCoefficients_solvesEquation() { double[][] multiplyInvertA1 = multiply(invertLower(A1D), getUpper(A1D, true)); @@ -380,14 +396,14 @@ public void forwardSubstitution_denseGivenCoefficients_solvesEquation() { assertArrayEquals(multiplyInvertA1[i], forwardSubstitutionA1[i], EPSILON); } } - + @Test public void forwardSubstitution_sparseGivenLower_solvesEquation() { double[] multiplyInvertA1B1 = multiply(invertLower(A1D), B1D); double[] forwardSubstitutionA1B1 = forwardSubstitution(A1S, B1D); assertArrayEquals(multiplyInvertA1B1, forwardSubstitutionA1B1, EPSILON); } - + @Test public void forwardSubstitution_sparseGivenCoefficients_solvesEquation() { double[][] multiplyInvertA1 = multiply(invertLower(A1D), getUpper(A1D, true)); diff --git a/test/arcade/core/util/MiniBoxTest.java b/test/arcade/core/util/MiniBoxTest.java index a0c3ea50d..ebeb0eb89 100644 --- a/test/arcade/core/util/MiniBoxTest.java +++ b/test/arcade/core/util/MiniBoxTest.java @@ -3,22 +3,28 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; -import org.junit.Test; -import static org.junit.Assert.*; +import org.junit.jupiter.api.Test; +import ec.util.MersenneTwisterFast; +import arcade.core.util.distributions.Distribution; +import arcade.core.util.distributions.NormalDistribution; +import arcade.core.util.distributions.NormalFractionalDistribution; +import arcade.core.util.distributions.NormalTruncatedDistribution; +import arcade.core.util.distributions.UniformDistribution; +import static org.junit.jupiter.api.Assertions.*; import static arcade.core.ARCADETestUtilities.*; import static arcade.core.util.MiniBox.TAG_SEPARATOR; public class MiniBoxTest { private static final double EPSILON = 1E-10; - + private static final int NUMBER_KEYS = 10; - + @Test public void getKeys_noKeys_returnsEmpty() { MiniBox box = new MiniBox(); assertEquals(new ArrayList<>(), box.getKeys()); } - + @Test public void getKeys_givenKeys_returnsList() { MiniBox box = new MiniBox(); @@ -27,10 +33,10 @@ public void getKeys_givenKeys_returnsList() { keys.add("" + i); box.put("" + i, randomString()); } - + assertEquals(new HashSet<>(keys), new HashSet<>(box.getKeys())); } - + @Test public void get_givenValidKey_returnsItem() { MiniBox box = new MiniBox(); @@ -39,39 +45,38 @@ public void get_givenValidKey_returnsItem() { box.put(key, contents); assertEquals(contents, box.get(key)); } - + @Test public void get_givenInvalidKey_returnsNull() { MiniBox box = new MiniBox(); String key = randomString(); assertNull(box.get(key)); } - + @Test public void getInt_givenValidKeyGivenInteger_returnsValue() { String key = randomString(); - String[] integers = new String[] { "0", "1", "-1" }; - int[] values = new int[] { 0, 1, -1 }; + String[] integers = new String[] {"0", "1", "-1"}; + int[] values = new int[] {0, 1, -1}; for (int i = 0; i < integers.length; i++) { MiniBox box = new MiniBox(); box.put(key, integers[i]); assertEquals(values[i], box.getInt(key)); } } - + @Test public void getInt_givenValidKeyGivenDouble_returnsValue() { String key = randomString(); - String[] integers = new String[] { - "1.0", "-1.0", "-.1", ".1", "1.1", "-1.1", "1.9", "-1.9" }; - int[] values = new int[] { 1, -1, 0, 0, 1, -1, 1, -1 }; + String[] integers = new String[] {"1.0", "-1.0", "-.1", ".1", "1.1", "-1.1", "1.9", "-1.9"}; + int[] values = new int[] {1, -1, 0, 0, 1, -1, 1, -1}; for (int i = 0; i < integers.length; i++) { MiniBox box = new MiniBox(); box.put(key, integers[i]); assertEquals(values[i], box.getInt(key)); } } - + @Test public void getInt_givenInvalidContentsGivenString_returnsZero() { MiniBox box = new MiniBox(); @@ -80,63 +85,64 @@ public void getInt_givenInvalidContentsGivenString_returnsZero() { box.put(key, contents); assertEquals(0, box.getInt(key)); } - + @Test public void getInt_givenInvalidKey_returnsZero() { MiniBox box = new MiniBox(); String key = randomString(); assertEquals(0, box.getInt(key)); } - + @Test public void getDouble_givenValidKeyGivenInteger_returnsValue() { String key = randomString(); - String[] doubles = new String[] { "0", "1", "-1", "1E2", "-1E2", "1E-2", "-1E-2" }; - double[] values = new double[] { 0.0, 1.0, -1.0, 100, -100, 0.01, -0.01 }; + String[] doubles = new String[] {"0", "1", "-1", "1E2", "-1E2", "1E-2", "-1E-2"}; + double[] values = new double[] {0.0, 1.0, -1.0, 100, -100, 0.01, -0.01}; for (int i = 0; i < doubles.length; i++) { MiniBox box = new MiniBox(); box.put(key, doubles[i]); assertEquals(values[i], box.getDouble(key), EPSILON); } } - + @Test public void getDouble_givenValidKeyGivenDouble_returnsValue() { String key = randomString(); - String[] doubles = new String[] { "1.0", "-1.0", "-.1", ".1", - "1.1", "-1.1", "1.9", "-1.9", "1.3E2", "-1.3E2" }; - double[] values = new double[] { 1.0, -1.0, -0.1, 0.1, - 1.1, -1.1, 1.9, -1.9, 130, -130 }; + String[] doubles = + new String[] { + "1.0", "-1.0", "-.1", ".1", "1.1", "-1.1", "1.9", "-1.9", "1.3E2", "-1.3E2" + }; + double[] values = new double[] {1.0, -1.0, -0.1, 0.1, 1.1, -1.1, 1.9, -1.9, 130, -130}; for (int i = 0; i < doubles.length; i++) { MiniBox box = new MiniBox(); box.put(key, doubles[i]); assertEquals(values[i], box.getDouble(key), EPSILON); } } - + @Test public void getDouble_givenValidKeyGivenValidFraction_returnsValue() { String key = randomString(); - String[] doubles = new String[] { "1/2", "3/4", "5E-1/10" }; - double[] values = new double[] { 0.5, 0.75, 0.05 }; + String[] doubles = new String[] {"1/2", "3/4", "5E-1/10"}; + double[] values = new double[] {0.5, 0.75, 0.05}; for (int i = 0; i < doubles.length; i++) { MiniBox box = new MiniBox(); box.put(key, doubles[i]); assertEquals(values[i], box.getDouble(key), EPSILON); } } - + @Test public void getDouble_givenValidKeyGivenInvalidFraction_returnsNaN() { String key = randomString(); - String[] doubles = new String[] { "1/2/3", "/1", "1/" }; + String[] doubles = new String[] {"1/2/3", "/1", "1/"}; for (int i = 0; i < doubles.length; i++) { MiniBox box = new MiniBox(); box.put(key, doubles[i]); assertTrue(Double.isNaN(box.getDouble(key))); } } - + @Test public void getDouble_givenValidKeyGivenZeroFraction_returnsNaN() { MiniBox box = new MiniBox(); @@ -145,7 +151,7 @@ public void getDouble_givenValidKeyGivenZeroFraction_returnsNaN() { box.put(key, contents); assertTrue(Double.isNaN(box.getDouble(key))); } - + @Test public void getDouble_givenInvalidContentsGivenString_returnsNaN() { MiniBox box = new MiniBox(); @@ -154,14 +160,72 @@ public void getDouble_givenInvalidContentsGivenString_returnsNaN() { box.put(key, contents); assertTrue(Double.isNaN(box.getDouble(key))); } - + @Test public void getDouble_givenInvalidKey_returnsNaN() { MiniBox box = new MiniBox(); String key = randomString(); assertTrue(Double.isNaN(box.getDouble(key))); } - + + @Test + public void getDistribution_givenValidKey_returnsDistribution() { + MersenneTwisterFast random = new MersenneTwisterFast(); + String key = randomString(); + String[][] distributions = + new String[][] { + {"UNIFORM", "MIN", "-100", "MAX", "99.5"}, + {"NORMAL", "MU", "100", "SIGMA", "20"}, + {"TRUNCATED_NORMAL", "MU", "10", "SIGMA", "2"}, + {"FRACTIONAL_NORMAL", "MU", "0.5", "SIGMA", "0.2"}, + }; + + Distribution[] expectedDistributions = + new Distribution[] { + new UniformDistribution(-100, 99.5, random), + new NormalDistribution(100, 20, random), + new NormalTruncatedDistribution(10, 2, random), + new NormalFractionalDistribution(0.5, 0.2, random), + }; + + for (int i = 0; i < distributions.length; i++) { + String paramA = distributions[i][1]; + String paramB = distributions[i][3]; + MiniBox box = new MiniBox(); + box.put("(DISTRIBUTION)" + TAG_SEPARATOR + key, distributions[i][0]); + box.put(key + "_" + paramA, distributions[i][2]); + box.put(key + "_" + paramB, distributions[i][4]); + + Distribution expectedDistribution = expectedDistributions[i]; + MiniBox expectedParameters = expectedDistribution.getParameters(); + + Distribution distribution = box.getDistribution(key, random); + MiniBox parameters = distribution.getParameters(); + + assertSame(expectedDistribution.getClass(), distribution.getClass()); + assertEquals(expectedParameters.getDouble(paramA), parameters.getDouble(paramA)); + assertEquals(expectedParameters.getDouble(paramB), parameters.getDouble(paramB)); + } + } + + @Test + public void getDistribution_givenInvalidKey_returnsNull() { + MersenneTwisterFast random = new MersenneTwisterFast(); + MiniBox box = new MiniBox(); + String key = randomString(); + assertNull(box.getDistribution(key, random)); + } + + @Test + public void getDistribution_givenInvalidDistribution_returnsNull() { + MersenneTwisterFast random = new MersenneTwisterFast(); + MiniBox box = new MiniBox(); + String key = randomString(); + String distribution = "INVALID"; + box.put("(DISTRIBUTION)" + TAG_SEPARATOR + key, distribution); + assertNull(box.getDistribution(key, random)); + } + @Test public void contains_doesContainKey_returnsTrue() { MiniBox box = new MiniBox(); @@ -169,14 +233,14 @@ public void contains_doesContainKey_returnsTrue() { box.put(key, randomString()); assertTrue(box.contains(key)); } - + @Test public void contains_doesNotContainKey_returnsFalse() { MiniBox box = new MiniBox(); String key = randomString(); assertFalse(box.contains(key)); } - + @Test public void put_withInteger_updatesContainers() { MiniBox box = new MiniBox(); @@ -187,7 +251,7 @@ public void put_withInteger_updatesContainers() { assertTrue(box.contents.containsKey(key)); assertEquals(value + "", box.contents.get(key)); } - + @Test public void put_withDouble_updatesContainers() { MiniBox box = new MiniBox(); @@ -198,7 +262,7 @@ public void put_withDouble_updatesContainers() { assertTrue(box.contents.containsKey(key)); assertEquals(value + "", box.contents.get(key)); } - + @Test public void put_newKey_updatesContainers() { MiniBox box = new MiniBox(); @@ -209,7 +273,7 @@ public void put_newKey_updatesContainers() { assertTrue(box.contents.containsKey(key)); assertEquals(value, box.contents.get(key)); } - + @Test public void put_existingKey_updatesContainers() { MiniBox box = new MiniBox(); @@ -222,7 +286,7 @@ public void put_existingKey_updatesContainers() { assertTrue(box.contents.containsKey(key)); assertEquals(value2, box.contents.get(key)); } - + @Test public void filter_invalidCode_returnsEmpty() { MiniBox box = new MiniBox(); @@ -230,12 +294,12 @@ public void filter_invalidCode_returnsEmpty() { String key = randomString(); String value = randomString(); box.put(key, value); - + MiniBox filtered = box.filter(code); assertEquals(new ArrayList<>(), filtered.keys); assertEquals(new HashMap<>(), filtered.contents); } - + @Test public void filter_validCode_returnsFiltered() { MiniBox box = new MiniBox(); @@ -246,24 +310,24 @@ public void filter_validCode_returnsFiltered() { String value1 = randomString(); String value2 = randomString(); String value3 = randomString(); - + box.put(key1, value1); box.put(code + TAG_SEPARATOR + key2, value2); box.put(code + TAG_SEPARATOR + key3, value3); - + ArrayList filteredKeys = new ArrayList<>(); filteredKeys.add(key2); filteredKeys.add(key3); - + HashMap filteredMap = new HashMap<>(); filteredMap.put(key2, value2); filteredMap.put(key3, value3); - + MiniBox filtered = box.filter(code); assertEquals(filteredKeys, filtered.keys); assertEquals(filteredMap, filtered.contents); } - + @Test public void filter_multipleCodes_returnsFiltered() { MiniBox box = new MiniBox(); @@ -275,137 +339,137 @@ public void filter_multipleCodes_returnsFiltered() { String value1 = randomString(); String value2 = randomString(); String value3 = randomString(); - + box.put(key1, value1); box.put(code1 + TAG_SEPARATOR + key2, value2); box.put(code2 + TAG_SEPARATOR + key3, value3); - + ArrayList filteredKeys = new ArrayList<>(); filteredKeys.add(key3); - + HashMap filteredMap = new HashMap<>(); filteredMap.put(key3, value3); - + MiniBox filtered = box.filter(code2); assertEquals(filteredKeys, filtered.keys); assertEquals(filteredMap, filtered.contents); } - + @Test public void compare_sameContents_returnsTrue() { MiniBox boxA = new MiniBox(); MiniBox boxB = new MiniBox(); - + String key1 = randomString(); String key2 = randomString(); String value1 = randomString(); String value2 = randomString(); - + boxA.put(key1, value1); boxA.put(key2, value2); boxB.put(key1, value1); boxB.put(key2, value2); - + assertTrue(boxA.compare(boxB)); assertTrue(boxB.compare(boxA)); } - + @Test public void compare_differentKeys_returnsFalse() { MiniBox boxA = new MiniBox(); MiniBox boxB = new MiniBox(); - + String key1 = randomString(); String key2 = randomString(); String value = randomString(); - + boxA.put(key1, value); boxA.put(key2, value); boxB.put(key2, value); - + assertFalse(boxA.compare(boxB)); assertFalse(boxB.compare(boxA)); } - + @Test public void compare_differentContents_returnsFalse() { MiniBox boxA = new MiniBox(); MiniBox boxB = new MiniBox(); - + String key = randomString(); String value1 = randomString(); String value2 = randomString(); - + boxA.put(key, value1); boxB.put(key, value2); - + assertFalse(boxA.compare(boxB)); assertFalse(boxB.compare(boxA)); } - + @Test public void toString_onlyStrings_createsJSON() { MiniBox box = new MiniBox(); - + String key1 = randomString(); String key2 = randomString(); String value1 = randomString(); String value2 = randomString(); - + box.put(key1, value1); box.put(key2, value2); - + String str = box.toString(); String expected = key1 + ":" + value1 + key2 + ":" + value2; - + str = str.replaceAll(" ", ""); str = str.replaceAll("\n", ""); - + assertEquals(expected, str); } - + @Test public void toString_onlyNumbers_createsJSON() { MiniBox box = new MiniBox(); - + String key1 = randomString(); String key2 = randomString(); double value1 = randomDoubleBetween(0, 100); int value2 = randomIntBetween(0, 100); - + box.put(key1, value1); box.put(key2, value2); - + String str = box.toString(); String expected = key1 + ":" + value1 + key2 + ":" + value2; - + str = str.replaceAll(" ", ""); str = str.replaceAll("\n", ""); - + assertEquals(expected, str); } - + @Test public void toString_mixedValues_createsJSON() { MiniBox box = new MiniBox(); - + String key1 = randomString(); String key2 = randomString(); String key3 = randomString(); double value1 = randomDoubleBetween(0, 100); String value2 = randomString(); int value3 = randomIntBetween(0, 100); - + box.put(key1, value1); box.put(key2, value2); box.put(key3, value3); - + String str = box.toString(); String expected = key1 + ":" + value1 + key2 + ":" + value2 + key3 + ":" + value3; - + str = str.replaceAll(" ", ""); str = str.replaceAll("\n", ""); - + assertEquals(expected, str); } } diff --git a/test/arcade/core/util/ParametersTest.java b/test/arcade/core/util/ParametersTest.java new file mode 100644 index 000000000..4aef5bf6d --- /dev/null +++ b/test/arcade/core/util/ParametersTest.java @@ -0,0 +1,402 @@ +package arcade.core.util; + +import java.security.InvalidParameterException; +import java.util.ArrayList; +import java.util.HashMap; +import org.junit.jupiter.api.Test; +import ec.util.MersenneTwisterFast; +import arcade.core.util.distributions.Distribution; +import arcade.core.util.distributions.NormalDistribution; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; +import static arcade.core.ARCADETestUtilities.*; +import static arcade.core.util.MiniBox.TAG_SEPARATOR; + +public class ParametersTest { + private static final MersenneTwisterFast RANDOM = new MersenneTwisterFast(); + + @Test + public void constructor_noDistributionsNoParent_skipsDistributions() { + MiniBox popParameters = new MiniBox(); + + Parameters parameters = new Parameters(popParameters, null, RANDOM); + + assertTrue(parameters.distributions.isEmpty()); + assertSame(popParameters, parameters.popParameters); + } + + @Test + public void constructor_withDistributionsNoParent_usesPopulationDistributions() { + MiniBox popParameters = spy(new MiniBox()); + + String key = randomString(); + popParameters.put("(DISTRIBUTION)" + TAG_SEPARATOR + key, "X"); + Distribution distribution = mock(Distribution.class); + doReturn(distribution).when(popParameters).getDistribution(key, RANDOM); + + Parameters parameters = new Parameters(popParameters, null, RANDOM); + + assertEquals(distribution, parameters.distributions.get(key)); + assertSame(popParameters, parameters.popParameters); + } + + @Test + public void constructor_noDistributionsWithParent_skipsDistributions() { + MiniBox popParameters1 = new MiniBox(); + MiniBox popParameters2 = new MiniBox(); + + Parameters cellParameters = new Parameters(popParameters1, null, RANDOM); + + Parameters parameters = new Parameters(popParameters2, cellParameters, RANDOM); + + assertTrue(parameters.distributions.isEmpty()); + assertSame(popParameters2, parameters.popParameters); + } + + @Test + public void constructor_withDistributionsWithParent_usesParentDistributions() { + MiniBox popParameters1 = spy(new MiniBox()); + MiniBox popParameters2 = new MiniBox(); + + String key = randomString(); + popParameters1.put("(DISTRIBUTION)" + TAG_SEPARATOR + key, "X"); + popParameters2.put("(DISTRIBUTION)" + TAG_SEPARATOR + key, "Y"); + Distribution distribution1 = mock(Distribution.class); + Distribution distribution2 = mock(Distribution.class); + doReturn(distribution1).when(popParameters1).getDistribution(key, RANDOM); + doReturn(distribution2).when(distribution1).rebase(RANDOM); + + Parameters cellParameters = new Parameters(popParameters1, null, RANDOM); + + Parameters parameters = new Parameters(popParameters2, cellParameters, RANDOM); + + assertEquals(distribution2, parameters.distributions.get(key)); + assertSame(popParameters2, parameters.popParameters); + } + + @Test + public void constructor_withDistributionsWithParentDifferentKey_usesPopulationDistributions() { + MiniBox popParameters1 = spy(new MiniBox()); + MiniBox popParameters2 = spy(new MiniBox()); + + String key1 = randomString(); + String key2 = randomString(); + popParameters1.put("(DISTRIBUTION)" + TAG_SEPARATOR + key1, "X"); + popParameters2.put("(DISTRIBUTION)" + TAG_SEPARATOR + key2, "Y"); + Distribution distribution1 = mock(Distribution.class); + Distribution distribution2 = mock(Distribution.class); + doReturn(distribution1).when(popParameters1).getDistribution(key1, RANDOM); + doReturn(distribution2).when(popParameters2).getDistribution(key2, RANDOM); + + Parameters cellParameters = new Parameters(popParameters1, null, RANDOM); + + Parameters parameters = new Parameters(popParameters2, cellParameters, RANDOM); + + assertFalse(parameters.distributions.containsKey(key1)); + assertEquals(distribution2, parameters.distributions.get(key2)); + assertSame(popParameters2, parameters.popParameters); + } + + @Test + public void getDouble_keyHasDistribution_returnsValue() { + MiniBox box = new MiniBox(); + String key = randomString(); + + double value = randomDoubleBetween(0, 100); + Distribution distribution = mock(Distribution.class); + doReturn(value).when(distribution).getDoubleValue(); + + Parameters parameters = new Parameters(box, null, RANDOM); + parameters.distributions.put(key, distribution); + + assertEquals(value, parameters.getDouble(key)); + } + + @Test + public void getDouble_keyDoesNotHaveDistribution_returnsValue() { + MiniBox box = new MiniBox(); + String key = randomString(); + + double value = randomDoubleBetween(0, 100); + box.put(key, value); + + Parameters parameters = new Parameters(box, null, RANDOM); + + assertEquals(value, parameters.getDouble(key)); + } + + @Test + public void getDouble_keyDoesNotExist_throwsException() { + MiniBox box = new MiniBox(); + String key = randomString(); + + Parameters parameters = new Parameters(box, null, RANDOM); + + assertThrows(InvalidParameterException.class, () -> parameters.getDouble(key)); + } + + @Test + public void getInt_keyHasDistribution_returnsValue() { + MiniBox box = new MiniBox(); + String key = randomString(); + + int value = randomIntBetween(0, 100); + Distribution distribution = mock(Distribution.class); + doReturn(value).when(distribution).getIntValue(); + + Parameters parameters = new Parameters(box, null, RANDOM); + parameters.distributions.put(key, distribution); + + assertEquals(value, parameters.getInt(key)); + } + + @Test + public void getInt_keyDoesNotHaveDistribution_returnsValue() { + MiniBox box = new MiniBox(); + String key = randomString(); + + int value = randomIntBetween(0, 100); + box.put(key, value); + + Parameters parameters = new Parameters(box, null, RANDOM); + + assertEquals(value, parameters.getInt(key)); + } + + @Test + public void getInt_keyDoesNotExist_throwsException() { + MiniBox box = new MiniBox(); + String key = randomString(); + + Parameters parameters = new Parameters(box, null, RANDOM); + + assertThrows(InvalidParameterException.class, () -> parameters.getInt(key)); + } + + @Test + public void getDistribution_keyHasDistribution_returnsDistribution() { + MiniBox box = new MiniBox(); + String key = randomString(); + + Distribution distribution = mock(Distribution.class); + Parameters parameters = new Parameters(box, null, RANDOM); + parameters.distributions.put(key, distribution); + + assertSame(distribution, parameters.getDistribution(key)); + } + + @Test + public void getDistribution_keyDoesNotExist_throwsException() { + MiniBox box = new MiniBox(); + String key = randomString(); + + Parameters parameters = new Parameters(box, null, RANDOM); + + assertThrows(InvalidParameterException.class, () -> parameters.getDouble(key)); + } + + @Test + public void filter_invalidCode_returnsEmpty() { + MiniBox box = new MiniBox(); + String code = randomString(); + String key = randomString(); + String value = randomString(); + box.put(key, value); + + Parameters parameters = new Parameters(box, null, RANDOM); + + MiniBox filtered = parameters.filter(code); + assertEquals(new ArrayList<>(), filtered.keys); + assertEquals(new HashMap<>(), filtered.contents); + } + + @Test + public void filter_validCode_returnsFiltered() { + MiniBox box = new MiniBox(); + String code = randomString(); + String key1 = randomString(); + String key2 = randomString(); + String key3 = randomString(); + String value1 = randomString(); + String value2 = randomString(); + String value3 = randomString(); + + box.put(key1, value1); + box.put(code + TAG_SEPARATOR + key2, value2); + box.put(code + TAG_SEPARATOR + key3, value3); + + ArrayList filteredKeys = new ArrayList<>(); + filteredKeys.add(key2); + filteredKeys.add(key3); + + HashMap filteredMap = new HashMap<>(); + filteredMap.put(key2, value2); + filteredMap.put(key3, value3); + + Parameters parameters = new Parameters(box, null, RANDOM); + + MiniBox filtered = parameters.filter(code); + assertEquals(filteredKeys, filtered.keys); + assertEquals(filteredMap, filtered.contents); + } + + @Test + public void filter_multipleCodes_returnsFiltered() { + MiniBox box = new MiniBox(); + String code1 = randomString(); + String code2 = randomString(); + String key1 = randomString(); + String key2 = randomString(); + String key3 = randomString(); + String value1 = randomString(); + String value2 = randomString(); + String value3 = randomString(); + + box.put(key1, value1); + box.put(code1 + TAG_SEPARATOR + key2, value2); + box.put(code2 + TAG_SEPARATOR + key3, value3); + + ArrayList filteredKeys = new ArrayList<>(); + filteredKeys.add(key3); + + HashMap filteredMap = new HashMap<>(); + filteredMap.put(key3, value3); + + Parameters parameters = new Parameters(box, null, RANDOM); + + MiniBox filtered = parameters.filter(code2); + assertEquals(filteredKeys, filtered.keys); + assertEquals(filteredMap, filtered.contents); + } + + @Test + public void compare_sameParametersSameDistributions_returnsTrue() { + MiniBox boxA = new MiniBox(); + MiniBox boxB = new MiniBox(); + + String key = randomString(); + String value = randomString(); + + boxA.put(key, value); + boxB.put(key, value); + + Parameters parametersA = new Parameters(boxA, null, RANDOM); + Parameters parametersB = new Parameters(boxB, null, RANDOM); + + parametersA.distributions.put("PARAM", new NormalDistribution(5, 3, RANDOM)); + parametersB.distributions.put("PARAM", new NormalDistribution(5, 3, RANDOM)); + + assertTrue(parametersA.compare(parametersB)); + assertTrue(parametersB.compare(parametersA)); + } + + @Test + public void compare_sameParametersDifferentDistributionContents_returnsFalse() { + MiniBox boxA = new MiniBox(); + MiniBox boxB = new MiniBox(); + + String key = randomString(); + String value = randomString(); + + boxA.put(key, value); + boxB.put(key, value); + + Parameters parametersA = new Parameters(boxA, null, RANDOM); + Parameters parametersB = new Parameters(boxB, null, RANDOM); + + parametersA.distributions.put("PARAM", new NormalDistribution(5, 3, RANDOM)); + parametersB.distributions.put("PARAM", new NormalDistribution(3, 2, RANDOM)); + + assertFalse(parametersA.compare(parametersB)); + assertFalse(parametersB.compare(parametersA)); + } + + @Test + public void compare_sameParametersDifferentDistributionsKeys_returnsFalse() { + MiniBox boxA = new MiniBox(); + MiniBox boxB = new MiniBox(); + + String key = randomString(); + String value = randomString(); + + boxA.put(key, value); + boxB.put(key, value); + + Parameters parametersA = new Parameters(boxA, null, RANDOM); + Parameters parametersB = new Parameters(boxB, null, RANDOM); + + parametersA.distributions.put("PARAM_A", new NormalDistribution(5, 3, RANDOM)); + parametersB.distributions.put("PARAM_A", new NormalDistribution(5, 3, RANDOM)); + parametersB.distributions.put("PARAM_B", new NormalDistribution(5, 3, RANDOM)); + + assertFalse(parametersA.compare(parametersB)); + assertFalse(parametersB.compare(parametersA)); + } + + @Test + public void compare_differentParametersSameDistributions_returnsFalse() { + MiniBox boxA = new MiniBox(); + MiniBox boxB = new MiniBox(); + + String key = randomString(); + String value1 = randomString(); + String value2 = randomString(); + + boxA.put(key, value1); + boxB.put(key, value2); + + Parameters parametersA = new Parameters(boxA, null, RANDOM); + Parameters parametersB = new Parameters(boxB, null, RANDOM); + + parametersA.distributions.put("PARAM", new NormalDistribution(5, 3, RANDOM)); + parametersB.distributions.put("PARAM", new NormalDistribution(5, 3, RANDOM)); + + assertFalse(parametersA.compare(parametersB)); + assertFalse(parametersB.compare(parametersA)); + } + + @Test + public void compare_differentParametersDifferentDistributionContents_returnsFalse() { + MiniBox boxA = new MiniBox(); + MiniBox boxB = new MiniBox(); + + String key = randomString(); + String value1 = randomString(); + String value2 = randomString(); + + boxA.put(key, value1); + boxB.put(key, value2); + + Parameters parametersA = new Parameters(boxA, null, RANDOM); + Parameters parametersB = new Parameters(boxB, null, RANDOM); + + parametersA.distributions.put("PARAM", new NormalDistribution(5, 3, RANDOM)); + parametersB.distributions.put("PARAM", new NormalDistribution(3, 2, RANDOM)); + + assertFalse(parametersA.compare(parametersB)); + assertFalse(parametersB.compare(parametersA)); + } + + @Test + public void compare_differentParametersDifferentDistributionKeys_returnsFalse() { + MiniBox boxA = new MiniBox(); + MiniBox boxB = new MiniBox(); + + String key = randomString(); + String value1 = randomString(); + String value2 = randomString(); + + boxA.put(key, value1); + boxB.put(key, value2); + + Parameters parametersA = new Parameters(boxA, null, RANDOM); + Parameters parametersB = new Parameters(boxB, null, RANDOM); + + parametersA.distributions.put("PARAM_A", new NormalDistribution(5, 3, RANDOM)); + parametersB.distributions.put("PARAM_A", new NormalDistribution(5, 3, RANDOM)); + parametersB.distributions.put("PARAM_B", new NormalDistribution(5, 3, RANDOM)); + + assertFalse(parametersA.compare(parametersB)); + assertFalse(parametersB.compare(parametersA)); + } +} diff --git a/test/arcade/core/util/SolverTest.java b/test/arcade/core/util/SolverTest.java new file mode 100644 index 000000000..81dcd7ef5 --- /dev/null +++ b/test/arcade/core/util/SolverTest.java @@ -0,0 +1,239 @@ +package arcade.core.util; + +import org.junit.jupiter.api.Test; +import arcade.core.util.Solver.Equations; +import arcade.core.util.Solver.Function; +import static org.junit.jupiter.api.Assertions.*; + +public class SolverTest { + @Test + public void testConstructor__returnsException() { + assertThrows(UnsupportedOperationException.class, Solver::new); + } + + @Test + public void testEuler_simpleEquations_returnsAnswer() { + Equations e = + (t, y) -> { + double[] result = new double[2]; + result[0] = 1; + result[1] = -1; + return result; + }; + double[] y = Solver.euler(e, 0, new double[] {0, 1}, 1, 0.1); + + assertEquals(1, y[0], 0.01); + assertEquals(0.0, y[1], 0.01); + } + + @Test + public void testEuler_complexEquations_returnsAnswer() { + Equations e = + (t, y) -> { + double[] result = new double[2]; + result[0] = -y[0]; + result[1] = y[0]; + return result; + }; + double[] y = Solver.euler(e, 0, new double[] {1, 0}, 1, 0.01); + + assertEquals(Math.exp(-1), y[0], 0.01); + assertEquals(1 - Math.exp(-1), y[1], 0.01); + } + + @Test + public void testRungeKutta_simpleEquations_returnsAnswer() { + Equations e = + (t, y) -> { + double[] result = new double[2]; + result[0] = 1; + result[1] = -1; + return result; + }; + double[] y = Solver.rungeKutta(e, 0, new double[] {0, 1}, 1, 0.1); + + assertEquals(1, y[0], 0.00001); + assertEquals(0.0, y[1], 0.00001); + } + + @Test + public void testRungeKutta_complexEquations_returnsAnswer() { + Equations e = + (t, y) -> { + double[] result = new double[2]; + result[0] = -y[0]; + result[1] = y[0]; + return result; + }; + double[] y = Solver.rungeKutta(e, 0, new double[] {1, 0}, 1, 0.01); + + assertEquals(Math.exp(-1), y[0], 0.0001); + assertEquals(1 - Math.exp(-1), y[1], 0.0001); + } + + @Test + public void testCashKarp_simpleEquations_returnsAnswer() { + Equations e = + (t, y) -> { + double[] result = new double[2]; + result[0] = 1; + result[1] = -1; + return result; + }; + double[] y = Solver.cashKarp(e, 0, new double[] {0, 1}, 1, 0.1); + + assertEquals(1, y[0], 0.00001); + assertEquals(0.0, y[1], 0.00001); + } + + @Test + public void testCashKarp_complexEquations_returnsAnswer() { + Equations e = + (t, y) -> { + double[] result = new double[2]; + result[0] = -y[0]; + result[1] = y[0]; + return result; + }; + double[] y = Solver.cashKarp(e, 0, new double[] {1, 0}, 1, 0.01); + + assertEquals(Math.exp(-1), y[0], 0.00001); + assertEquals(1 - Math.exp(-1), y[1], 0.00001); + } + + @Test + public void testCashKarp_zeroMaximumSteps_returnsInitial() { + Equations e = + (t, y) -> { + double[] result = new double[2]; + result[0] = -y[0]; + result[1] = y[0]; + return result; + }; + double[] y = Solver.cashKarp(e, 0, new double[] {1, 0}, 1, 0.01, 0); + + assertEquals(1, y[0], 0.00001); + assertEquals(0, y[1], 0.00001); + } + + @Test + public void testSOR_denseMatrix_returnsSolution() { + double[][] matA = + new double[][] { + {4, -1, 0, 0}, + {-1, 4, -1, 0}, + {0, -1, 4, -1}, + {0, 0, -1, 3} + }; + double[] b = new double[] {2, 4, 6, 9}; + double[] x = new double[] {0, 1, 2, 3}; + double[] result = Solver.sor(matA, b, x); + + assertEquals(1, result[0], 0.0001); + assertEquals(2, result[1], 0.0001); + assertEquals(3, result[2], 0.0001); + assertEquals(4, result[3], 0.0001); + } + + @Test + public void testSOR_denseSORandZeroMaxIters_returnsInitialGuess() { + double[][] matA = + new double[][] { + {4, -1, 0, 0}, + {-1, 4, -1, 0}, + {0, -1, 4, -1}, + {0, 0, -1, 3} + }; + double[] b = new double[] {2, 4, 6, 9}; + double[] x = new double[] {0, 1, 2, 3}; + double[] result = Solver.sor(matA, b, x, 100, 0, 1E-8); + + assertEquals(x[0], result[0], 0.0001); + assertEquals(x[1], result[1], 0.0001); + assertEquals(x[2], result[2], 0.0001); + assertEquals(x[3], result[3], 0.0001); + } + + @Test + public void testSOR_sparseMatrix_returnsSolution() { + double[][] matA = + new double[][] { + {4, -1, 0, 0}, + {-1, 4, -1, 0}, + {0, -1, 4, -1}, + {0, 0, -1, 3} + }; + double[] b = new double[] {2, 4, 6, 9}; + double[] x = new double[] {0, 1, 2, 3}; + double[] result = Solver.sor(matA, b, x, 3, 10000, 1E-8); + + assertEquals(1, result[0], 0.0001); + assertEquals(2, result[1], 0.0001); + assertEquals(3, result[2], 0.0001); + assertEquals(4, result[3], 0.0001); + } + + @Test + public void testSOR_sparseSORandZeroMaxIters_returnsInitialGuess() { + double[][] matA = + new double[][] { + {4, -1, 0, 0}, + {-1, 4, -1, 0}, + {0, -1, 4, -1}, + {0, 0, -1, 3} + }; + double[] b = new double[] {2, 4, 6, 9}; + double[] x = new double[] {0, 1, 2, 3}; + double[] result = Solver.sor(matA, b, x, 3, 0, 1E-8); + + assertEquals(x[0], result[0], 0.0001); + assertEquals(x[1], result[1], 0.0001); + assertEquals(x[2], result[2], 0.0001); + assertEquals(x[3], result[3], 0.0001); + } + + @Test + public void testBisection_linearFunction_returnsAnswer() { + Function f = (x) -> x - 2; + double result = Solver.bisection(f, 0, 3); + + assertEquals(2, result, 0.0001); + } + + @Test + public void testBisection_exceedsMaxIterations_returnsNan() { + Function f = (x) -> x * x - 2; + double result = Solver.bisection(f, 0, 2, 3); + + assertEquals(Double.NaN, result, 0.001); + } + + @Test + public void testBisection_quadraticFunction_returnsAnswer() { + Function f = (x) -> x * x - 2; + double result = Solver.bisection(f, 0, 2); + + assertEquals(1.41421, result, 0.0001); + } + + @Test + public void testBisection_incorrectBounds_throwsException() { + Function f = (x) -> x * x - 2; + ArithmeticException exception = + assertThrows( + ArithmeticException.class, + () -> { + Solver.bisection(f, 2, 3); + }); + + assertEquals("Bisection cannot find root with given bounds.", exception.getMessage()); + } + + @Test + public void testBisection_quadraticFunctionAndSwappedInputs_returnsAnswer() { + Function f = (x) -> x * x - 2; + double result = Solver.bisection(f, 2, 0); + + assertEquals(1.41421, result, 0.0001); + } +} diff --git a/test/arcade/core/util/UtilitiesTest.java b/test/arcade/core/util/UtilitiesTest.java index ad4fa2e2a..2773043d5 100644 --- a/test/arcade/core/util/UtilitiesTest.java +++ b/test/arcade/core/util/UtilitiesTest.java @@ -2,29 +2,29 @@ import java.util.ArrayList; import java.util.Comparator; -import org.junit.Test; +import org.junit.jupiter.api.Test; import ec.util.MersenneTwisterFast; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static arcade.core.ARCADETestUtilities.*; import static arcade.core.util.Utilities.*; public class UtilitiesTest { private static final double EPSILON = 1E-10; - - @Test(expected = UnsupportedOperationException.class) + + @Test public void constructor_called_throwsException() { - Utilities utilities = new Utilities(); + assertThrows(UnsupportedOperationException.class, Utilities::new); } - + @Test public void copyArray_givenArray_createsDeepCopy() { int x = randomIntBetween(2, 10); int y = randomIntBetween(2, 10); int z = randomIntBetween(2, 10); - + double[][][] fromArray = new double[x][y][z]; double[][][] toArray = new double[x][y][z]; - + // Population the from array. for (int i = 0; i < x; i++) { for (int j = 0; j < y; j++) { @@ -33,9 +33,9 @@ public void copyArray_givenArray_createsDeepCopy() { } } } - + copyArray(fromArray, toArray); - + // Check that contents match. for (int i = 0; i < x; i++) { for (int j = 0; j < y; j++) { @@ -44,7 +44,7 @@ public void copyArray_givenArray_createsDeepCopy() { } } } - + // Check that objects do not match. for (int i = 0; i < x; i++) { for (int j = 0; j < y; j++) { @@ -52,45 +52,45 @@ public void copyArray_givenArray_createsDeepCopy() { } } } - + @Test public void shuffleList_givenRandomNumberGenerator_shufflesList() { int seed = randomIntBetween(1, 1000); MersenneTwisterFast rng = new MersenneTwisterFast(seed); - + ArrayList unshuffledList = new ArrayList<>(); ArrayList shuffledList = new ArrayList<>(); for (int i = 0; i < 100; i++) { unshuffledList.add(i); shuffledList.add(i); } - + shuffleList(shuffledList, rng); - + // Check that shuffled list and unshuffled lists are not the same order. assertNotEquals(unshuffledList, shuffledList); - + // Check that contents of lists are the same. shuffledList.sort(Comparator.comparingInt(integer -> integer)); assertEquals(unshuffledList, shuffledList); } - + @Test public void shuffleList_givenSameSeed_shufflesSame() { int seed = randomIntBetween(1, 1000); MersenneTwisterFast rng1 = new MersenneTwisterFast(seed); MersenneTwisterFast rng2 = new MersenneTwisterFast(seed); - + ArrayList list1 = new ArrayList<>(); ArrayList list2 = new ArrayList<>(); for (int i = 0; i < 100; i++) { list1.add(i); list2.add(i); } - + shuffleList(list1, rng1); shuffleList(list2, rng2); - + // Check that both shuffled lists are the same. assertEquals(list1, list2); } diff --git a/test/arcade/core/util/distributions/BernoulliDistributionTest.java b/test/arcade/core/util/distributions/BernoulliDistributionTest.java new file mode 100644 index 000000000..10ec17c92 --- /dev/null +++ b/test/arcade/core/util/distributions/BernoulliDistributionTest.java @@ -0,0 +1,120 @@ +package arcade.core.util.distributions; + +import org.junit.jupiter.api.Test; +import ec.util.MersenneTwisterFast; +import arcade.core.util.MiniBox; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static arcade.core.ARCADETestUtilities.randomString; + +public class BernoulliDistributionTest { + private static final double EPSILON = 1E-5; + + private static final MersenneTwisterFast RANDOM = new MersenneTwisterFast(); + + @Test + public void constructor_calledWithCode_populatesAttributes() { + double probability = 0.7; + + String name = randomString().toUpperCase(); + MiniBox parameters = new MiniBox(); + parameters.put(name + "_PROBABILITY", probability); + + BernoulliDistribution dist = new BernoulliDistribution(name, parameters, RANDOM); + + assertEquals(probability, dist.probability, EPSILON); + } + + @Test + public void constructor_calledWithParameters_populatesAttributes() { + double probability = 0.7; + + BernoulliDistribution dist = new BernoulliDistribution(probability, RANDOM); + + assertEquals(probability, dist.probability, EPSILON); + } + + @Test + public void getDoubleValue_called_returnsWithinRange() { + double probability = 0.7; + int iterations = 10000; + + for (int i = 0; i < iterations; i++) { + BernoulliDistribution dist = new BernoulliDistribution(probability, RANDOM); + double value = dist.getDoubleValue(); + assertEquals(dist.value, value); + assertTrue(value == 1.0 || value == 0.0); + } + } + + @Test + public void getIntValue_called_returnsWithinRange() { + double probability = 0.7; + int iterations = 10000; + + for (int i = 0; i < iterations; i++) { + BernoulliDistribution dist = new BernoulliDistribution(probability, RANDOM); + int value = dist.getIntValue(); + assertEquals((int) Math.round(dist.value), value); + assertTrue(value == 1 || value == 0); + } + } + + @Test + public void getParameters_called_returnsParameters() { + double probability = 0.7; + + BernoulliDistribution dist = new BernoulliDistribution(probability, RANDOM); + MiniBox parameters = dist.getParameters(); + + assertEquals(probability, parameters.getDouble("PROBABILITY"), EPSILON); + } + + @Test + public void getExpected_called_returnsExpectedValue() { + double probability = 0.7; + + BernoulliDistribution dist = new BernoulliDistribution(probability, RANDOM); + + assertEquals(probability, dist.getExpected()); + } + + @Test + public void nextDouble_called_returnsWithinRange() { + double probability = 0.7; + int iterations = 10000; + + BernoulliDistribution dist = new BernoulliDistribution(probability, RANDOM); + + for (int i = 0; i < iterations; i++) { + double value = dist.nextDouble(); + assertTrue(value == 1.0 || value == 0.0); + } + } + + @Test + public void nextInt_called_returnsWithinRange() { + double probability = 0.7; + int iterations = 10000; + + BernoulliDistribution dist = new BernoulliDistribution(probability, RANDOM); + + for (int i = 0; i < iterations; i++) { + int value = dist.nextInt(); + assertTrue(value == 1 || value == 0); + } + } + + @Test + public void rebase_called_returnsNewDistribution() { + double probability = 0.7; + + BernoulliDistribution oldDist = new BernoulliDistribution(probability, RANDOM); + BernoulliDistribution newDist = (BernoulliDistribution) oldDist.rebase(RANDOM); + + assertAll( + () -> assertEquals(probability, oldDist.probability, EPSILON), + () -> assertEquals(probability, newDist.probability, EPSILON)); + } +} diff --git a/test/arcade/core/util/distributions/NormalDistributionTest.java b/test/arcade/core/util/distributions/NormalDistributionTest.java new file mode 100644 index 000000000..eaff85109 --- /dev/null +++ b/test/arcade/core/util/distributions/NormalDistributionTest.java @@ -0,0 +1,107 @@ +package arcade.core.util.distributions; + +import org.junit.jupiter.api.Test; +import ec.util.MersenneTwisterFast; +import arcade.core.util.MiniBox; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static arcade.core.ARCADETestUtilities.randomString; + +public class NormalDistributionTest { + private static final double EPSILON = 1E-5; + + private static final MersenneTwisterFast RANDOM = new MersenneTwisterFast(); + + @Test + public void constructor_calledWithCode_populatesAttributes() { + double mu = 200; + double sigma = 10; + + String name = randomString().toUpperCase(); + MiniBox parameters = new MiniBox(); + parameters.put(name + "_MU", mu); + parameters.put(name + "_SIGMA", sigma); + + NormalDistribution dist = new NormalDistribution(name, parameters, RANDOM); + + assertAll( + () -> assertEquals(mu, dist.mu, EPSILON), + () -> assertEquals(sigma, dist.sigma, EPSILON)); + } + + @Test + public void constructor_calledWithParameters_populatesAttributes() { + double mu = 200; + double sigma = 10; + + NormalDistribution dist = new NormalDistribution(mu, sigma, RANDOM); + + assertAll( + () -> assertEquals(mu, dist.mu, EPSILON), + () -> assertEquals(sigma, dist.sigma, EPSILON)); + } + + @Test + public void getDoubleValue_called_returnsValue() { + double mu = 0.5; + double sigma = 0.5; + int iterations = 10000; + + for (int i = 0; i < iterations; i++) { + NormalDistribution dist = new NormalDistribution(mu, sigma, RANDOM); + double value = dist.getDoubleValue(); + assertEquals(dist.value, value); + } + } + + @Test + public void getIntValue_called_returnsValue() { + double mu = 0.5; + double sigma = 0.5; + int iterations = 10000; + + for (int i = 0; i < iterations; i++) { + NormalDistribution dist = new NormalDistribution(mu, sigma, RANDOM); + int value = dist.getIntValue(); + assertEquals((int) Math.round(dist.value), value); + } + } + + @Test + public void getParameters_called_returnsParameters() { + double mu = 200; + double sigma = 10; + + NormalDistribution dist = new NormalDistribution(mu, sigma, RANDOM); + MiniBox parameters = dist.getParameters(); + + assertAll( + () -> assertEquals(mu, parameters.getDouble("MU"), EPSILON), + () -> assertEquals(sigma, parameters.getDouble("SIGMA"), EPSILON)); + } + + @Test + public void getExpected_called_returnsExpectedValue() { + double mu = 200; + double sigma = 10; + + NormalDistribution dist = new NormalDistribution(mu, sigma, RANDOM); + + assertEquals(mu, dist.getExpected()); + } + + @Test + public void rebase_called_returnsNewDistribution() { + double mu = 0.2; + double sigma = 0.1; + + NormalDistribution oldDist = new NormalDistribution(mu, sigma, RANDOM); + NormalDistribution newDist = (NormalDistribution) oldDist.rebase(RANDOM); + + assertAll( + () -> assertEquals(mu, oldDist.mu, EPSILON), + () -> assertEquals(sigma, oldDist.sigma, EPSILON), + () -> assertEquals(oldDist.value, newDist.mu, EPSILON), + () -> assertEquals(sigma, newDist.sigma, EPSILON)); + } +} diff --git a/test/arcade/core/util/distributions/NormalFractionalDistributionTest.java b/test/arcade/core/util/distributions/NormalFractionalDistributionTest.java new file mode 100644 index 000000000..20555a714 --- /dev/null +++ b/test/arcade/core/util/distributions/NormalFractionalDistributionTest.java @@ -0,0 +1,169 @@ +package arcade.core.util.distributions; + +import org.junit.jupiter.api.Test; +import ec.util.MersenneTwisterFast; +import arcade.core.util.MiniBox; +import arcade.core.util.exceptions.OutOfBoundsException; +import static org.junit.jupiter.api.Assertions.*; +import static arcade.core.ARCADETestUtilities.*; + +public class NormalFractionalDistributionTest { + private static final double EPSILON = 1E-5; + + private static final MersenneTwisterFast RANDOM = new MersenneTwisterFast(); + + @Test + public void constructor_calledWithCode_populatesAttributes() { + double mu = 0.2; + double sigma = 0.1; + + String name = randomString().toUpperCase(); + MiniBox parameters = new MiniBox(); + parameters.put(name + "_MU", mu); + parameters.put(name + "_SIGMA", sigma); + + NormalFractionalDistribution dist = + new NormalFractionalDistribution(name, parameters, RANDOM); + + assertAll( + () -> assertEquals(mu, dist.mu, EPSILON), + () -> assertEquals(sigma, dist.sigma, EPSILON)); + } + + @Test + public void constructor_calledWithParameters_populatesAttributes() { + double mu = 0.2; + double sigma = 0.1; + + NormalFractionalDistribution dist = new NormalFractionalDistribution(mu, sigma, RANDOM); + + assertAll( + () -> assertEquals(mu, dist.mu, EPSILON), + () -> assertEquals(sigma, dist.sigma, EPSILON)); + } + + @Test + public void constructor_muGreaterThan1_throwsIllegalArgumentException() { + double mu = 2.0; + double sigma = 0.25; + assertThrows( + OutOfBoundsException.class, + () -> new NormalFractionalDistribution(mu, sigma, RANDOM)); + } + + @Test + public void constructor_muLessThan0_throwsIllegalArgumentException() { + double mu = -2.0; + double sigma = 0.25; + assertThrows( + OutOfBoundsException.class, + () -> new NormalFractionalDistribution(mu, sigma, RANDOM)); + } + + @Test + public void getDoubleValue_called_returnsWithinRange() { + double mu = 0.5; + double sigma = 0.5; + double maxValue = 1.0; + double minValue = 0.0; + int iterations = 10000; + + for (int i = 0; i < iterations; i++) { + NormalFractionalDistribution dist = new NormalFractionalDistribution(mu, sigma, RANDOM); + double value = dist.getDoubleValue(); + assertEquals(dist.value, value); + assertTrue(value >= minValue); + assertTrue(value <= maxValue); + } + } + + @Test + public void getIntValue_called_returnsWithinRange() { + double mu = 0.5; + double sigma = 0.5; + int maxValue = 1; + int minValue = 0; + int iterations = 10000; + + for (int i = 0; i < iterations; i++) { + NormalFractionalDistribution dist = new NormalFractionalDistribution(mu, sigma, RANDOM); + int value = dist.getIntValue(); + assertEquals((int) Math.round(dist.value), value); + assertTrue(value >= minValue); + assertTrue(value <= maxValue); + } + } + + @Test + public void getParameters_called_returnsParameters() { + double mu = 0.2; + double sigma = 0.1; + + NormalFractionalDistribution dist = new NormalFractionalDistribution(mu, sigma, RANDOM); + MiniBox parameters = dist.getParameters(); + + assertAll( + () -> assertEquals(mu, parameters.getDouble("MU"), EPSILON), + () -> assertEquals(sigma, parameters.getDouble("SIGMA"), EPSILON)); + } + + @Test + public void getExpected_called_returnsExpectedValue() { + double mu = 0.2; + double sigma = 0.1; + + NormalFractionalDistribution dist = new NormalFractionalDistribution(mu, sigma, RANDOM); + + assertEquals(mu, dist.getExpected()); + } + + @Test + public void nextDouble_called_returnsWithinRange() { + double mu = 0.5; + double sigma = 0.5; + double maxValue = 1.0; + double minValue = 0.0; + int iterations = 10000; + + NormalFractionalDistribution dist = new NormalFractionalDistribution(mu, sigma, RANDOM); + + for (int i = 0; i < iterations; i++) { + double value = dist.nextDouble(); + assertTrue(value >= minValue); + assertTrue(value <= maxValue); + } + } + + @Test + public void nextInt_called_returnsWithinRange() { + double mu = 0.5; + double sigma = 0.5; + int maxValue = 1; + int minValue = 0; + int iterations = 10000; + + NormalFractionalDistribution dist = new NormalFractionalDistribution(mu, sigma, RANDOM); + + for (int i = 0; i < iterations; i++) { + int value = dist.nextInt(); + assertTrue(value >= minValue); + assertTrue(value <= maxValue); + } + } + + @Test + public void rebase_called_returnsNewDistribution() { + double mu = 0.5; + double sigma = 0.1; + + NormalFractionalDistribution oldDist = new NormalFractionalDistribution(mu, sigma, RANDOM); + NormalFractionalDistribution newDist = + (NormalFractionalDistribution) oldDist.rebase(RANDOM); + + assertAll( + () -> assertEquals(mu, oldDist.mu, EPSILON), + () -> assertEquals(sigma, oldDist.sigma, EPSILON), + () -> assertEquals(oldDist.value, newDist.mu, EPSILON), + () -> assertEquals(sigma, newDist.sigma, EPSILON)); + } +} diff --git a/test/arcade/core/util/distributions/NormalTruncatedDistributionTest.java b/test/arcade/core/util/distributions/NormalTruncatedDistributionTest.java new file mode 100644 index 000000000..d00d8cfd5 --- /dev/null +++ b/test/arcade/core/util/distributions/NormalTruncatedDistributionTest.java @@ -0,0 +1,217 @@ +package arcade.core.util.distributions; + +import org.junit.jupiter.api.Test; +import ec.util.MersenneTwisterFast; +import arcade.core.util.MiniBox; +import static org.junit.jupiter.api.Assertions.*; +import static arcade.core.ARCADETestUtilities.randomString; + +public class NormalTruncatedDistributionTest { + private static final double EPSILON = 1E-5; + + private static final MersenneTwisterFast RANDOM = new MersenneTwisterFast(); + + @Test + public void constructor_calledWithCode_populatesAttributes() { + double mu = 4.0; + double sigma = 0.25; + + String name = randomString().toUpperCase(); + MiniBox parameters = new MiniBox(); + parameters.put(name + "_MU", mu); + parameters.put(name + "_SIGMA", sigma); + + NormalTruncatedDistribution dist = + new NormalTruncatedDistribution(name, parameters, RANDOM); + + assertAll( + () -> assertEquals(mu, dist.mu, EPSILON), + () -> assertEquals(sigma, dist.sigma, EPSILON)); + } + + @Test + public void constructor_calledWithParameters_populatesAttributes() { + double mu = 4.0; + double sigma = 0.25; + + NormalTruncatedDistribution dist = new NormalTruncatedDistribution(mu, sigma, RANDOM); + + assertAll( + () -> assertEquals(mu, dist.mu, EPSILON), + () -> assertEquals(sigma, dist.sigma, EPSILON)); + } + + @Test + public void getDoubleValue_positiveMu_returnsWithinRange() { + double mu = 4.0; + double sigma = 1.0; + double maxValue = 6.0; + double minValue = 2.0; + int iterations = 10000; + + for (int i = 0; i < iterations; i++) { + NormalTruncatedDistribution dist = new NormalTruncatedDistribution(mu, sigma, RANDOM); + double value = dist.getDoubleValue(); + assertEquals(dist.value, value); + assertTrue(value >= minValue); + assertTrue(value <= maxValue); + } + } + + @Test + public void getDoubleValue_negativeMu_returnsWithinRange() { + double mu = -4.0; + double sigma = 1.0; + double maxValue = -2.0; + double minValue = -6.0; + int iterations = 10000; + + for (int i = 0; i < iterations; i++) { + NormalTruncatedDistribution dist = new NormalTruncatedDistribution(mu, sigma, RANDOM); + double value = dist.getDoubleValue(); + assertEquals(dist.value, value); + assertTrue(value >= minValue); + assertTrue(value <= maxValue); + } + } + + @Test + public void getIntValue_positiveMu_returnsWithinRange() { + double mu = 4.0; + double sigma = 1.0; + int maxValue = 6; + int minValue = 2; + int iterations = 10000; + + for (int i = 0; i < iterations; i++) { + NormalTruncatedDistribution dist = new NormalTruncatedDistribution(mu, sigma, RANDOM); + int value = dist.getIntValue(); + assertEquals((int) Math.round(dist.value), value); + assertTrue(value >= minValue); + assertTrue(value <= maxValue); + } + } + + @Test + public void getIntValue_negativeMu_returnsWithinRange() { + double mu = -4.0; + double sigma = 1.0; + int maxValue = -2; + int minValue = -6; + int iterations = 10000; + + for (int i = 0; i < iterations; i++) { + NormalTruncatedDistribution dist = new NormalTruncatedDistribution(mu, sigma, RANDOM); + int value = dist.getIntValue(); + assertEquals((int) Math.round(dist.value), value); + assertTrue(value >= minValue); + assertTrue(value <= maxValue); + } + } + + @Test + public void getParameters_called_returnsParameters() { + double mu = 4.0; + double sigma = 0.25; + + NormalTruncatedDistribution dist = new NormalTruncatedDistribution(mu, sigma, RANDOM); + MiniBox parameters = dist.getParameters(); + + assertAll( + () -> assertEquals(mu, parameters.getDouble("MU"), EPSILON), + () -> assertEquals(sigma, parameters.getDouble("SIGMA"), EPSILON)); + } + + @Test + public void getExpected_called_returnsExpectedValue() { + double mu = 4.0; + double sigma = 0.25; + + NormalTruncatedDistribution dist = new NormalTruncatedDistribution(mu, sigma, RANDOM); + + assertEquals(mu, dist.getExpected()); + } + + @Test + public void nextDouble_positiveMu_returnsWithinRange() { + double mu = 4.0; + double sigma = 1.0; + double maxValue = 6.0; + double minValue = 2.0; + int iterations = 10000; + + NormalTruncatedDistribution dist = new NormalTruncatedDistribution(mu, sigma, RANDOM); + + for (int i = 0; i < iterations; i++) { + double value = dist.nextDouble(); + assertTrue(value >= minValue); + assertTrue(value <= maxValue); + } + } + + @Test + public void nextDouble_negativeMu_returnsWithinRange() { + double mu = -4.0; + double sigma = 1.0; + double maxValue = -2.0; + double minValue = -6.0; + int iterations = 10000; + + NormalTruncatedDistribution dist = new NormalTruncatedDistribution(mu, sigma, RANDOM); + + for (int i = 0; i < iterations; i++) { + double value = dist.nextDouble(); + assertTrue(value >= minValue); + assertTrue(value <= maxValue); + } + } + + @Test + public void nextInt_positiveMu_returnsWithinRange() { + double mu = 4.0; + double sigma = 1.0; + int maxValue = 6; + int minValue = 2; + int iterations = 10000; + + NormalTruncatedDistribution dist = new NormalTruncatedDistribution(mu, sigma, RANDOM); + + for (int i = 0; i < iterations; i++) { + int value = dist.nextInt(); + assertTrue(value >= minValue); + assertTrue(value <= maxValue); + } + } + + @Test + public void nextInt_negativeMu_returnsWithinRange() { + double mu = -4.0; + double sigma = 1.0; + int maxValue = -2; + int minValue = -6; + int iterations = 10000; + + NormalTruncatedDistribution dist = new NormalTruncatedDistribution(mu, sigma, RANDOM); + + for (int i = 0; i < iterations; i++) { + int value = dist.nextInt(); + assertTrue(value >= minValue); + assertTrue(value <= maxValue); + } + } + + @Test + public void rebase_called_returnsNewDistribution() { + double mu = 8.0; + double sigma = 2.0; + + NormalTruncatedDistribution oldDist = new NormalTruncatedDistribution(mu, sigma, RANDOM); + NormalTruncatedDistribution newDist = (NormalTruncatedDistribution) oldDist.rebase(RANDOM); + + assertAll( + () -> assertEquals(mu, oldDist.mu, EPSILON), + () -> assertEquals(sigma, oldDist.sigma, EPSILON), + () -> assertEquals(oldDist.value, newDist.mu, EPSILON), + () -> assertEquals(sigma, newDist.sigma, EPSILON)); + } +} diff --git a/test/arcade/core/util/distributions/UniformDistributionTest.java b/test/arcade/core/util/distributions/UniformDistributionTest.java new file mode 100644 index 000000000..34d7e2789 --- /dev/null +++ b/test/arcade/core/util/distributions/UniformDistributionTest.java @@ -0,0 +1,140 @@ +package arcade.core.util.distributions; + +import org.junit.jupiter.api.Test; +import ec.util.MersenneTwisterFast; +import arcade.core.util.MiniBox; +import static org.junit.jupiter.api.Assertions.*; +import static arcade.core.ARCADETestUtilities.randomString; + +public class UniformDistributionTest { + private static final double EPSILON = 1E-5; + + private static final MersenneTwisterFast RANDOM = new MersenneTwisterFast(); + + @Test + public void constructor_calledWithCode_populatesAttributes() { + double min = -100; + double max = 99.5; + + String name = randomString().toUpperCase(); + MiniBox parameters = new MiniBox(); + parameters.put(name + "_MIN", min); + parameters.put(name + "_MAX", max); + + UniformDistribution dist = new UniformDistribution(name, parameters, RANDOM); + + assertAll( + () -> assertEquals(min, dist.min, EPSILON), + () -> assertEquals(max, dist.max, EPSILON)); + } + + @Test + public void constructor_calledWithParameters_populatesAttributes() { + double min = -100; + double max = 99.5; + + UniformDistribution dist = new UniformDistribution(min, max, RANDOM); + + assertAll( + () -> assertEquals(min, dist.min, EPSILON), + () -> assertEquals(max, dist.max, EPSILON)); + } + + @Test + public void getDoubleValue_called_returnsWithinRange() { + double min = -100; + double max = 99.5; + int iterations = 10000; + + for (int i = 0; i < iterations; i++) { + UniformDistribution dist = new UniformDistribution(min, max, RANDOM); + double value = dist.getDoubleValue(); + assertEquals(dist.value, value); + assertTrue(value >= min); + assertTrue(value <= max); + } + } + + @Test + public void getIntValue_called_returnsWithinRange() { + double min = -100; + double max = 99.5; + int iterations = 10000; + + for (int i = 0; i < iterations; i++) { + UniformDistribution dist = new UniformDistribution(min, max, RANDOM); + int value = dist.getIntValue(); + assertEquals((int) Math.round(dist.value), value); + assertTrue(value >= min); + assertTrue(value <= max); + } + } + + @Test + public void getParameters_called_returnsParameters() { + double min = -100; + double max = 99.5; + + UniformDistribution dist = new UniformDistribution(min, max, RANDOM); + MiniBox parameters = dist.getParameters(); + + assertAll( + () -> assertEquals(min, parameters.getDouble("MIN"), EPSILON), + () -> assertEquals(max, parameters.getDouble("MAX"), EPSILON)); + } + + @Test + public void getExpected_called_returnsExpectedValue() { + double min = -100; + double max = 99.5; + + UniformDistribution dist = new UniformDistribution(min, max, RANDOM); + + assertEquals((min + max) / 2, dist.getExpected()); + } + + @Test + public void nextDouble_called_returnsWithinRange() { + double min = -100; + double max = 99.5; + int iterations = 10000; + + UniformDistribution dist = new UniformDistribution(min, max, RANDOM); + + for (int i = 0; i < iterations; i++) { + double value = dist.nextDouble(); + assertTrue(value >= min); + assertTrue(value <= max); + } + } + + @Test + public void nextInt_called_returnsWithinRange() { + double min = -100; + double max = 99.5; + int iterations = 10000; + + UniformDistribution dist = new UniformDistribution(min, max, RANDOM); + + for (int i = 0; i < iterations; i++) { + int value = dist.nextInt(); + assertTrue(value >= min); + assertTrue(value <= max); + } + } + + @Test + public void rebase_called_returnsNewDistribution() { + double min = -100; + double max = 99.5; + + UniformDistribution oldDist = new UniformDistribution(min, max, RANDOM); + UniformDistribution newDist = (UniformDistribution) oldDist.rebase(RANDOM); + + assertAll( + () -> assertEquals(min, oldDist.min, EPSILON), + () -> assertEquals(max, oldDist.max, EPSILON), + () -> assertEquals(min, newDist.min, EPSILON), + () -> assertEquals(max, newDist.max, EPSILON)); + } +} diff --git a/test/arcade/patch/PatchARCADETest.java b/test/arcade/patch/PatchARCADETest.java index 2118a18f4..a82529d1e 100644 --- a/test/arcade/patch/PatchARCADETest.java +++ b/test/arcade/patch/PatchARCADETest.java @@ -1,95 +1,102 @@ package arcade.patch; import java.io.File; -import org.apache.commons.io.FileUtils; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; +import java.nio.file.Files; +import java.nio.file.Path; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import arcade.core.ARCADE; import arcade.core.sim.Series; import arcade.patch.sim.input.PatchInputBuilder; import arcade.patch.sim.output.PatchOutputLoader; import arcade.patch.sim.output.PatchOutputSaver; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; public class PatchARCADETest { static String makeSetup(String name) { return "" - + "" + + "" + ""; } - - @Rule - public TemporaryFolder folder = new TemporaryFolder(); - + @Test - public void main_noVis_savesFiles() throws Exception { + public void main_noVis_savesFiles(@TempDir Path path) throws Exception { String name = "main_noVis_savesFiles"; - File setupFile = folder.newFile("setup.xml"); - FileUtils.writeStringToFile(setupFile, makeSetup(name), "UTF-8"); - - String[] args = new String[] { "patch", setupFile.getPath(), folder.getRoot().getAbsolutePath() }; + Path setupFile = Files.createFile(path.resolve("setup.xml")); + Files.writeString(setupFile, makeSetup(name)); + + String[] args = + new String[] {"patch", setupFile.toString(), path.toAbsolutePath().toString()}; ARCADE.main(args); - - File mainOutput = new File(folder.getRoot() + "/" + name + ".json"); + + File mainOutput = new File(path.toAbsolutePath() + "/" + name + ".json"); assertTrue(mainOutput.exists()); - - String[] timepoints = new String[] { "0000_000000", "0000_000001" }; + + String[] timepoints = new String[] {"0000_000000", "0000_000001"}; for (String tp : timepoints) { - File cellOutput = new File(folder.getRoot() + "/" + name + "_" + tp + ".CELLS.json"); + File cellOutput = + new File(path.toAbsolutePath() + "/" + name + "_" + tp + ".CELLS.json"); assertTrue(cellOutput.exists()); - File locationOutput = new File(folder.getRoot() + "/" + name + "_" + tp + ".LOCATIONS.json"); + File locationOutput = + new File(path.toAbsolutePath() + "/" + name + "_" + tp + ".LOCATIONS.json"); assertTrue(locationOutput.exists()); } } - + @Test - public void main_withVis_savesNothing() throws Exception { + public void main_withVis_savesNothing(@TempDir Path path) throws Exception { String name = "main_withVis_savesNothing"; - File setupFile = folder.newFile("setup.xml"); - FileUtils.writeStringToFile(setupFile, makeSetup(name), "UTF-8"); - + Path setupFile = Files.createFile(path.resolve("setup.xml")); + Files.writeString(setupFile, makeSetup(name)); + System.setProperty("java.awt.headless", "true"); - - String[] args = new String[] { "patch", setupFile.getPath(), folder.getRoot().getAbsolutePath(), "--vis" }; + + String[] args = + new String[] { + "patch", setupFile.toString(), path.toAbsolutePath().toString(), "--vis" + }; ARCADE.main(args); - - File mainOutput = new File(folder.getRoot() + "/" + name + ".json"); + + File mainOutput = new File(path.toAbsolutePath() + "/" + name + ".json"); assertFalse(mainOutput.exists()); - - String[] timepoints = new String[] { "0000_000000", "0000_000001" }; + + String[] timepoints = new String[] {"0000_000000", "0000_000001"}; for (String tp : timepoints) { - File cellOutput = new File(folder.getRoot() + "/" + name + "_" + tp + ".CELLS.json"); + File cellOutput = + new File(path.toAbsolutePath() + "/" + name + "_" + tp + ".CELLS.json"); assertFalse(cellOutput.exists()); - File locationOutput = new File(folder.getRoot() + "/" + name + "_" + tp + ".LOCATIONS.json"); + File locationOutput = + new File(path.toAbsolutePath() + "/" + name + "_" + tp + ".LOCATIONS.json"); assertFalse(locationOutput.exists()); } } - + @Test public void getResource_requiredFiles_returnsResource() { PatchARCADE arcade = new PatchARCADE(); - + String parameterFile = arcade.getResource("parameter.patch.xml"); assertNotNull(parameterFile); - + String commandFile = arcade.getResource("command.patch.xml"); assertNotNull(commandFile); } - + @Test public void getBuilder_called_returnsBuilder() { PatchARCADE arcade = new PatchARCADE(); assertTrue(arcade.getBuilder() instanceof PatchInputBuilder); } - + @Test public void getLoader_called_returnsBuilder() { PatchARCADE arcade = new PatchARCADE(); assertTrue(arcade.getLoader(mock(Series.class)) instanceof PatchOutputLoader); } - + @Test public void getSaver_called_returnsBuilder() { PatchARCADE arcade = new PatchARCADE(); diff --git a/test/arcade/patch/agent/cell/PatchCellFactoryTest.java b/test/arcade/patch/agent/cell/PatchCellFactoryTest.java new file mode 100644 index 000000000..7fc3c5694 --- /dev/null +++ b/test/arcade/patch/agent/cell/PatchCellFactoryTest.java @@ -0,0 +1,256 @@ +package arcade.patch.agent.cell; + +import java.util.HashMap; +import java.util.HashSet; +import org.junit.jupiter.api.Test; +import arcade.core.sim.Series; +import arcade.core.util.MiniBox; +import arcade.patch.sim.PatchSeries; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; +import static arcade.core.ARCADETestUtilities.*; + +public class PatchCellFactoryTest { + private static final double EPSILON = 1E-5; + + static PatchSeries createSeries(int[] init, String[] initTypes) { + PatchSeries series = mock(PatchSeries.class); + series.populations = new HashMap<>(); + + for (int i = 0; i < init.length; i++) { + int pop = i + 1; + MiniBox box = new MiniBox(); + box.put("CODE", pop); + box.put(initTypes[i], init[i]); + series.populations.put("pop" + pop, box); + } + + return series; + } + + @Test + public void createCells_noPopulation_createsEmpty() { + Series series = createSeries(new int[] {}, new String[] {}); + + PatchCellFactory factory = new PatchCellFactory(); + factory.createCells(series); + + assertEquals(0, factory.cells.size()); + assertEquals(0, factory.popToIDs.size()); + } + + @Test + public void createCells_onePopulationInitByCount_createsList() { + int count = randomIntBetween(1, 10); + PatchSeries series = createSeries(new int[] {count}, new String[] {"COUNT"}); + + double volume = randomDoubleBetween(1, 10); + double height = randomDoubleBetween(1, 10); + int age = randomIntBetween(1, 100); + int divisions = randomIntBetween(1, 100); + double compression = randomDoubleBetween(1, 10); + + MiniBox parameters = new MiniBox(); + parameters.put("CELL_VOLUME", volume); + parameters.put("CELL_HEIGHT", height); + parameters.put("CELL_AGE", age); + parameters.put("DIVISION_POTENTIAL", divisions); + parameters.put("COMPRESSION_TOLERANCE", compression); + + PatchCellFactory factory = new PatchCellFactory(); + factory.popToIDs.put(1, new HashSet<>()); + factory.popToParameters.put(1, parameters); + factory.createCells(series); + + assertEquals(count, factory.cells.size()); + assertEquals(count, factory.popToIDs.get(1).size()); + + for (int i : factory.popToIDs.get(1)) { + PatchCellContainer patchCellContainer = factory.cells.get(i); + assertEquals(volume, patchCellContainer.criticalVolume, EPSILON); + assertEquals(height + compression, patchCellContainer.criticalHeight, EPSILON); + assertEquals(age, patchCellContainer.age); + assertEquals(divisions, patchCellContainer.divisions); + } + } + + @Test + public void createCells_onePopulationInitByPercent_createsList() { + int totalPatches = randomIntBetween(10, 90); + int percent = randomIntBetween(1, 99); + int init = (int) Math.round(percent * totalPatches / 100.0); + PatchSeries series = createSeries(new int[] {percent}, new String[] {"PERCENT"}); + + series.patch = new MiniBox(); + series.patch.put("TOTAL_PATCHES", totalPatches); + + double volume = randomDoubleBetween(1, 10); + double height = randomDoubleBetween(1, 10); + int age = randomIntBetween(1, 100); + int divisions = randomIntBetween(1, 100); + double compression = randomDoubleBetween(1, 10); + + MiniBox parameters = new MiniBox(); + parameters.put("CELL_VOLUME", volume); + parameters.put("CELL_HEIGHT", height); + parameters.put("CELL_AGE", age); + parameters.put("DIVISION_POTENTIAL", divisions); + parameters.put("COMPRESSION_TOLERANCE", compression); + + PatchCellFactory factory = new PatchCellFactory(); + factory.popToIDs.put(1, new HashSet<>()); + factory.popToParameters.put(1, parameters); + factory.createCells(series); + + assertEquals(init, factory.cells.size()); + assertEquals(init, factory.popToIDs.get(1).size()); + + for (int i : factory.popToIDs.get(1)) { + PatchCellContainer patchCellContainer = factory.cells.get(i); + assertEquals(volume, patchCellContainer.criticalVolume, EPSILON); + assertEquals(height + compression, patchCellContainer.criticalHeight, EPSILON); + assertEquals(age, patchCellContainer.age); + assertEquals(divisions, patchCellContainer.divisions); + } + } + + @Test + public void createCells_onePopulationInitByPercentOver100_createsList() { + int totalPatches = randomIntBetween(10, 90); + int percent = 200; + PatchSeries series = createSeries(new int[] {percent}, new String[] {"PERCENT"}); + + series.patch = new MiniBox(); + series.patch.put("TOTAL_PATCHES", totalPatches); + + double volume = randomDoubleBetween(1, 10); + double height = randomDoubleBetween(1, 10); + int age = randomIntBetween(1, 100); + int divisions = randomIntBetween(1, 100); + double compression = randomDoubleBetween(1, 10); + + MiniBox parameters = new MiniBox(); + parameters.put("CELL_VOLUME", volume); + parameters.put("CELL_HEIGHT", height); + parameters.put("CELL_AGE", age); + parameters.put("DIVISION_POTENTIAL", divisions); + parameters.put("COMPRESSION_TOLERANCE", compression); + + PatchCellFactory factory = new PatchCellFactory(); + factory.popToIDs.put(1, new HashSet<>()); + factory.popToParameters.put(1, parameters); + factory.createCells(series); + + assertEquals(totalPatches, factory.cells.size()); + assertEquals(totalPatches, factory.popToIDs.get(1).size()); + + for (int i : factory.popToIDs.get(1)) { + PatchCellContainer patchCellContainer = factory.cells.get(i); + assertEquals(volume, patchCellContainer.criticalVolume, EPSILON); + assertEquals(height + compression, patchCellContainer.criticalHeight, EPSILON); + assertEquals(age, patchCellContainer.age); + assertEquals(divisions, patchCellContainer.divisions); + } + } + + @Test + public void createCells_multiplePopulationsMixedInit_createsList() { + int totalPatches = randomIntBetween(10, 90); + int count1 = randomIntBetween(1, 10); + int percent2 = randomIntBetween(40, 50); + int init2 = (int) Math.round(percent2 * totalPatches / 100.0); + int count3 = randomIntBetween(1, 10); + PatchSeries series = + createSeries( + new int[] {count1, percent2, count3}, + new String[] {"COUNT", "PERCENT", "COUNT"}); + + series.patch = new MiniBox(); + series.patch.put("TOTAL_PATCHES", totalPatches); + + double[] volumes = + new double[] { + randomDoubleBetween(1, 10), + randomDoubleBetween(1, 10), + randomDoubleBetween(1, 10), + }; + double[] heights = + new double[] { + randomDoubleBetween(1, 10), + randomDoubleBetween(1, 10), + randomDoubleBetween(1, 10), + }; + int[] ages = + new int[] { + randomIntBetween(1, 100), randomIntBetween(1, 100), randomIntBetween(1, 100), + }; + int[] divisions = + new int[] { + randomIntBetween(1, 100), randomIntBetween(1, 100), randomIntBetween(1, 100), + }; + double[] compressions = + new double[] { + randomDoubleBetween(1, 10), + randomDoubleBetween(1, 10), + randomDoubleBetween(1, 10), + }; + + MiniBox parameters1 = new MiniBox(); + parameters1.put("CELL_VOLUME", volumes[0]); + parameters1.put("CELL_HEIGHT", heights[0]); + parameters1.put("CELL_AGE", ages[0]); + parameters1.put("DIVISION_POTENTIAL", divisions[0]); + parameters1.put("COMPRESSION_TOLERANCE", compressions[0]); + + MiniBox parameters2 = new MiniBox(); + parameters2.put("CELL_VOLUME", volumes[1]); + parameters2.put("CELL_HEIGHT", heights[1]); + parameters2.put("CELL_AGE", ages[1]); + parameters2.put("DIVISION_POTENTIAL", divisions[1]); + parameters2.put("COMPRESSION_TOLERANCE", compressions[1]); + + MiniBox parameters3 = new MiniBox(); + parameters3.put("CELL_VOLUME", volumes[2]); + parameters3.put("CELL_HEIGHT", heights[2]); + parameters3.put("CELL_AGE", ages[2]); + parameters3.put("DIVISION_POTENTIAL", divisions[2]); + parameters3.put("COMPRESSION_TOLERANCE", compressions[2]); + + PatchCellFactory factory = new PatchCellFactory(); + factory.popToIDs.put(1, new HashSet<>()); + factory.popToIDs.put(2, new HashSet<>()); + factory.popToIDs.put(3, new HashSet<>()); + factory.popToParameters.put(1, parameters1); + factory.popToParameters.put(2, parameters2); + factory.popToParameters.put(3, parameters3); + factory.createCells(series); + factory.createCells(series); + + assertEquals(count1 + init2 + count3, factory.cells.size()); + assertEquals(count1, factory.popToIDs.get(1).size()); + assertEquals(init2, factory.popToIDs.get(2).size()); + assertEquals(count3, factory.popToIDs.get(3).size()); + + for (int i : factory.popToIDs.get(1)) { + PatchCellContainer patchCellContainer = factory.cells.get(i); + assertEquals(volumes[0], patchCellContainer.criticalVolume, EPSILON); + assertEquals(heights[0] + compressions[0], patchCellContainer.criticalHeight, EPSILON); + assertEquals(ages[0], patchCellContainer.age); + assertEquals(divisions[0], patchCellContainer.divisions); + } + for (int i : factory.popToIDs.get(2)) { + PatchCellContainer patchCellContainer = factory.cells.get(i); + assertEquals(volumes[1], patchCellContainer.criticalVolume, EPSILON); + assertEquals(heights[1] + compressions[1], patchCellContainer.criticalHeight, EPSILON); + assertEquals(ages[1], patchCellContainer.age); + assertEquals(divisions[1], patchCellContainer.divisions); + } + for (int i : factory.popToIDs.get(3)) { + PatchCellContainer patchCellContainer = factory.cells.get(i); + assertEquals(volumes[2], patchCellContainer.criticalVolume, EPSILON); + assertEquals(heights[2] + compressions[2], patchCellContainer.criticalHeight, EPSILON); + assertEquals(ages[2], patchCellContainer.age); + assertEquals(divisions[2], patchCellContainer.divisions); + } + } +} diff --git a/test/arcade/patch/agent/cell/PatchCellRandomTest.java b/test/arcade/patch/agent/cell/PatchCellRandomTest.java new file mode 100644 index 000000000..22f359411 --- /dev/null +++ b/test/arcade/patch/agent/cell/PatchCellRandomTest.java @@ -0,0 +1,217 @@ +package arcade.patch.agent.cell; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import ec.util.MersenneTwisterFast; +import arcade.core.util.GrabBag; +import arcade.core.util.MiniBox; +import arcade.core.util.Parameters; +import arcade.patch.agent.module.PatchModule; +import arcade.patch.agent.process.PatchProcessMetabolism; +import arcade.patch.env.location.PatchLocation; +import arcade.patch.sim.PatchSimulation; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; +import static arcade.core.ARCADETestUtilities.*; +import static arcade.patch.util.PatchEnums.Domain; +import static arcade.patch.util.PatchEnums.State; + +public class PatchCellRandomTest { + private static final double EPSILON = 1E-8; + + static PatchLocation locationMock; + + static Parameters parametersMock; + + static int cellID = randomIntBetween(1, 10); + + static int cellParent = randomIntBetween(1, 10); + + static int cellPop = randomIntBetween(1, 10); + + static int cellAge = randomIntBetween(1, 1000); + + static int cellDivisions = randomIntBetween(1, 100); + + static double cellVolume = randomDoubleBetween(10, 100); + + static double cellHeight = randomDoubleBetween(10, 100); + + static double cellCriticalVolume = randomDoubleBetween(10, 100); + + static double cellCriticalHeight = randomDoubleBetween(10, 100); + + static State cellState = State.QUIESCENT; + + static PatchCellContainer baseContainer = + new PatchCellContainer( + cellID, + cellParent, + cellPop, + cellAge, + cellDivisions, + cellState, + cellVolume, + cellHeight, + cellCriticalVolume, + cellCriticalHeight); + + @BeforeAll + public static void setupMocks() { + locationMock = mock(PatchLocation.class); + parametersMock = spy(new Parameters(new MiniBox(), null, null)); + doReturn(0.0).when(parametersMock).getDouble(any(String.class)); + doReturn(0).when(parametersMock).getInt(any(String.class)); + } + + @Test + public void make_calledNoLinks_createsContainer() { + double volume = randomDoubleBetween(10, 100); + double height = randomDoubleBetween(10, 100); + double criticalVolume = randomDoubleBetween(10, 100); + double criticalHeight = randomDoubleBetween(10, 100); + State state1 = State.QUIESCENT; + State state2 = State.PROLIFERATIVE; + + PatchCellContainer cellContainer = + new PatchCellContainer( + cellID, + cellParent, + cellPop, + cellAge, + cellDivisions, + state1, + volume, + height, + criticalVolume, + criticalHeight); + PatchCellRandom cell = + new PatchCellRandom(cellContainer, locationMock, parametersMock, null); + + PatchCellContainer container = cell.make(cellID + 1, state2, null); + + assertEquals(cellID + 1, container.id); + assertEquals(cellID, container.parent); + assertEquals(cellPop, container.pop); + assertEquals(cellAge, container.age); + assertEquals(cellDivisions - 1, container.divisions); + assertEquals(cellDivisions - 1, container.divisions); + assertEquals(state2, container.state); + assertEquals(volume, container.volume, EPSILON); + assertEquals(height, container.height, EPSILON); + assertEquals(criticalVolume, container.criticalVolume, EPSILON); + assertEquals(criticalHeight, container.criticalHeight, EPSILON); + } + + @Test + public void make_calledWithLinks_createsContainer() { + double volume = randomDoubleBetween(10, 100); + double height = randomDoubleBetween(10, 100); + double criticalVolume = randomDoubleBetween(10, 100); + double criticalHeight = randomDoubleBetween(10, 100); + State state1 = State.QUIESCENT; + State state2 = State.PROLIFERATIVE; + + int newPop = cellPop + randomIntBetween(1, 10); + GrabBag links = new GrabBag(); + links.add(cellPop, 1); + links.add(newPop, 1); + MersenneTwisterFast random = mock(MersenneTwisterFast.class); + when(random.nextDouble()).thenReturn(0.5); + + PatchCellContainer cellContainer = + new PatchCellContainer( + cellID, + cellParent, + cellPop, + cellAge, + cellDivisions, + state1, + volume, + height, + criticalVolume, + criticalHeight); + + PatchCellRandom cell = + new PatchCellRandom(cellContainer, locationMock, parametersMock, links); + + PatchCellContainer container = cell.make(cellID + 1, state2, random); + + assertEquals(cellID + 1, container.id); + assertEquals(cellID, container.parent); + assertEquals(newPop, container.pop); + assertEquals(cellAge, container.age); + assertEquals(cellDivisions - 1, container.divisions); + assertEquals(cellDivisions - 1, container.divisions); + assertEquals(state2, container.state); + assertEquals(volume, container.volume, EPSILON); + assertEquals(height, container.height, EPSILON); + assertEquals(criticalVolume, container.criticalVolume, EPSILON); + assertEquals(criticalHeight, container.criticalHeight, EPSILON); + } + + @Test + public void step_calledWithUndefinedState_setsRandomState() { + PatchSimulation sim = mock(PatchSimulation.class); + PatchCellRandom cell = + spy(new PatchCellRandom(baseContainer, locationMock, parametersMock)); + PatchModule module = mock(PatchModule.class); + + cell.processes.put(Domain.METABOLISM, mock(PatchProcessMetabolism.class)); + cell.processes.put(Domain.SIGNALING, mock(PatchProcessMetabolism.class)); + + int numValidStates = State.values().length - 1; + + for (int i = 1; i < numValidStates + 1; i++) { + MersenneTwisterFast random = mock(MersenneTwisterFast.class); + doReturn(i - 1).when(random).nextInt(numValidStates); + doAnswer( + invocationOnMock -> { + cell.state = invocationOnMock.getArgument(0); + cell.module = module; + return null; + }) + .when(cell) + .setState(any(State.class)); + + State state = State.values()[i]; + sim.random = random; + cell.setState(State.UNDEFINED); + cell.step(sim); + + assertEquals(state, cell.getState()); + } + } + + @Test + public void step_calledWithDefinedState_keepsDefinedState() { + PatchSimulation sim = mock(PatchSimulation.class); + PatchCellRandom cell = + spy(new PatchCellRandom(baseContainer, locationMock, parametersMock)); + + cell.processes.put(Domain.METABOLISM, mock(PatchProcessMetabolism.class)); + cell.processes.put(Domain.SIGNALING, mock(PatchProcessMetabolism.class)); + + int numValidStates = State.values().length - 1; + + for (int i = 1; i < numValidStates + 1; i++) { + MersenneTwisterFast random = mock(MersenneTwisterFast.class); + doReturn(i).when(random).nextInt(numValidStates); + doAnswer( + invocationOnMock -> { + cell.state = invocationOnMock.getArgument(0); + cell.module = null; + return null; + }) + .when(cell) + .setState(any(State.class)); + + State state = State.values()[i]; + sim.random = random; + cell.setState(state); + cell.step(sim); + + assertEquals(state, cell.getState()); + } + } +} diff --git a/test/arcade/patch/sim/PatchSeriesTest.java b/test/arcade/patch/sim/PatchSeriesTest.java index bddcceba7..357a0e9d8 100644 --- a/test/arcade/patch/sim/PatchSeriesTest.java +++ b/test/arcade/patch/sim/PatchSeriesTest.java @@ -3,76 +3,78 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import arcade.core.util.Box; import arcade.core.util.MiniBox; import arcade.patch.vis.PatchVisualization; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.core.ARCADETestUtilities.*; import static arcade.core.util.MiniBox.TAG_SEPARATOR; public class PatchSeriesTest { private static final double EPSILON = 1E-10; - + private static final double DS = randomDoubleBetween(2, 10); - + private static final double DT = randomDoubleBetween(0.5, 2); - + private static final Box PARAMETERS = new Box(); - - private static final String[] PROCESS_IDS = new String[] { - randomString().toLowerCase(), - randomString().toLowerCase(), - }; - - private static final String[] PATCH_PARAMETER_NAMES = new String[] { - "PATCH_PARAMETER_1", - "PATCH_PARAMETER_2", - "PATCH_PARAMETER_3", - }; - - private static final double[] PATCH_PARAMETER_VALUES = new double[] { - randomDoubleBetween(1, 100), - randomDoubleBetween(1, 100), - randomDoubleBetween(1, 100), - }; - - private static final String[] POPULATION_PARAMETER_NAMES = new String[] { - "POPULATION_PARAMETER_1", - "POPULATION_PARAMETER_2", - PROCESS_IDS[0] + TAG_SEPARATOR + "PROCESS_PARAMETER_11", - PROCESS_IDS[0] + TAG_SEPARATOR + "PROCESS_PARAMETER_12", - PROCESS_IDS[1] + TAG_SEPARATOR + "PROCESS_PARAMETER_21", - }; - - private static final double[] POPULATION_PARAMETER_VALUES = new double[] { - randomDoubleBetween(1, 100), - randomDoubleBetween(1, 100), - randomDoubleBetween(1, 100), - randomDoubleBetween(1, 100), - randomDoubleBetween(1, 100), - }; - + + private static final String[] PROCESS_IDS = + new String[] { + randomString().toLowerCase(), randomString().toLowerCase(), + }; + + private static final String[] PATCH_PARAMETER_NAMES = + new String[] { + "PATCH_PARAMETER_1", "PATCH_PARAMETER_2", "PATCH_PARAMETER_3", + }; + + private static final double[] PATCH_PARAMETER_VALUES = + new double[] { + randomDoubleBetween(1, 100), + randomDoubleBetween(1, 100), + randomDoubleBetween(1, 100), + }; + + private static final String[] POPULATION_PARAMETER_NAMES = + new String[] { + "POPULATION_PARAMETER_1", + "POPULATION_PARAMETER_2", + PROCESS_IDS[0] + TAG_SEPARATOR + "PROCESS_PARAMETER_11", + PROCESS_IDS[0] + TAG_SEPARATOR + "PROCESS_PARAMETER_12", + PROCESS_IDS[1] + TAG_SEPARATOR + "PROCESS_PARAMETER_21", + }; + + private static final double[] POPULATION_PARAMETER_VALUES = + new double[] { + randomDoubleBetween(1, 100), + randomDoubleBetween(1, 100), + randomDoubleBetween(1, 100), + randomDoubleBetween(1, 100), + randomDoubleBetween(1, 100), + }; + private static final String POPULATION_ID_1 = randomString(); - + private static final String POPULATION_ID_2 = randomString(); - + private static final String POPULATION_ID_3 = randomString(); - + private static final MiniBox PATCH = new MiniBox(); - + private static final MiniBox POPULATION = new MiniBox(); - - @BeforeClass + + @BeforeAll public static void setupParameters() { // DEFAULTS PARAMETERS.addTag("DS", "DEFAULT"); PARAMETERS.addTag("DT", "DEFAULT"); PARAMETERS.addAtt("DS", "value", "" + DS); PARAMETERS.addAtt("DT", "value", "" + DT); - + // PATCH for (int i = 0; i < PATCH_PARAMETER_NAMES.length; i++) { PARAMETERS.addTag(PATCH_PARAMETER_NAMES[i], "PATCH"); @@ -82,62 +84,63 @@ public static void setupParameters() { for (String key : potts.getKeys()) { PATCH.put(key, potts.get(key)); } - + // POPULATION for (int i = 0; i < POPULATION_PARAMETER_NAMES.length; i++) { PARAMETERS.addTag(POPULATION_PARAMETER_NAMES[i], "POPULATION"); - PARAMETERS.addAtt(POPULATION_PARAMETER_NAMES[i], "value", "" + POPULATION_PARAMETER_VALUES[i]); + PARAMETERS.addAtt( + POPULATION_PARAMETER_NAMES[i], "value", "" + POPULATION_PARAMETER_VALUES[i]); } MiniBox population = PARAMETERS.getIdValForTag("POPULATION"); for (String key : population.getKeys()) { POPULATION.put(key, population.get(key)); } } - + private HashMap> makeLists() { HashMap> setupLists = new HashMap<>(); - + ArrayList patch = new ArrayList<>(); setupLists.put("patch", patch); - + ArrayList populations = new ArrayList<>(); setupLists.put("populations", populations); - + return setupLists; } - + @Test public void initialize_default_callsMethods() { HashMap> setupLists = makeLists(); PatchSeries series = mock(PatchSeries.class, CALLS_REAL_METHODS); series.initialize(setupLists, PARAMETERS); - + ArrayList patch = setupLists.get("patch"); verify(series).updatePatch(eq(patch), any(MiniBox.class)); - + ArrayList populations = setupLists.get("populations"); - verify(series).updatePopulations(eq(populations), any(MiniBox.class), eq(null)); - + verify(series).updatePopulations(eq(populations), any(MiniBox.class), any(MiniBox.class)); + ArrayList layers = setupLists.get("layers"); verify(series).updateLayers(eq(layers), any(MiniBox.class), any(MiniBox.class)); - + ArrayList actions = setupLists.get("actions"); verify(series).updateActions(eq(actions), any(MiniBox.class)); - + ArrayList components = setupLists.get("components"); verify(series).updateComponents(eq(components), any(MiniBox.class)); } - + private PatchSeries makeSeriesForPatch(Box box) { HashMap> setupLists = makeLists(); PatchSeries series = mock(PatchSeries.class, CALLS_REAL_METHODS); ArrayList patch = setupLists.get("patch"); patch.add(box); - + series.updatePatch(patch, PATCH); return series; } - + @Test public void updatePatch_noSetting_createsBox() { PatchSeries series = mock(PatchSeries.class, CALLS_REAL_METHODS); @@ -145,33 +148,33 @@ public void updatePatch_noSetting_createsBox() { series.updatePatch(null, PATCH); assertNotNull(series.patch); } - + @Test public void updatePatch_noParameters_usesDefaults() { PatchSeries series = makeSeriesForPatch(null); MiniBox box = series.patch; - + for (String parameter : PATCH_PARAMETER_NAMES) { assertEquals(PATCH.get(parameter), box.get(parameter)); } } - + @Test public void updatePatch_givenParameters_updatesValues() { for (String patchParameter1 : PATCH_PARAMETER_NAMES) { for (String patchParameter2 : PATCH_PARAMETER_NAMES) { Box patch = new Box(); - + double value = randomDoubleBetween(1, 100); double scale = randomDoubleBetween(1, 100); patch.addAtt(patchParameter1, "value", "" + value); patch.addTag(patchParameter1, "PARAMETER"); patch.addAtt(patchParameter2, "scale", "" + scale); patch.addTag(patchParameter2, "PARAMETER"); - + PatchSeries series = makeSeriesForPatch(patch); MiniBox box = series.patch; - + for (String parameter : PATCH_PARAMETER_NAMES) { double expected = PATCH.getDouble(parameter); if (parameter.equals(patchParameter1)) { @@ -185,43 +188,43 @@ public void updatePatch_givenParameters_updatesValues() { } } } - + private PatchSeries makeSeriesForPopulation(Box[] boxes) { HashMap> setupLists = makeLists(); PatchSeries series = mock(PatchSeries.class, CALLS_REAL_METHODS); ArrayList populations = setupLists.get("populations"); populations.addAll(Arrays.asList(boxes)); - - series.updatePopulations(populations, POPULATION, null); + + series.updatePopulations(populations, POPULATION, new MiniBox()); return series; } - + @Test public void updatePopulation_noPopulations_createsMap() { PatchSeries series = mock(PatchSeries.class, CALLS_REAL_METHODS); series.updatePopulations(null, POPULATION, new MiniBox()); assertEquals(0, series.populations.size()); } - + @Test public void updatePopulation_onePopulation_createsMap() { - Box[] boxes = new Box[] { new Box() }; + Box[] boxes = new Box[] {new Box()}; boxes[0].add("id", POPULATION_ID_1); PatchSeries series = makeSeriesForPopulation(boxes); - + assertEquals(1, series.populations.size()); assertNotNull(series.populations.get(POPULATION_ID_1)); assertEquals(1, series.populations.get(POPULATION_ID_1).getInt("CODE")); } - + @Test public void updatePopulation_multiplePopulations_createsMap() { - Box[] boxes = new Box[] { new Box(), new Box(), new Box() }; + Box[] boxes = new Box[] {new Box(), new Box(), new Box()}; boxes[0].add("id", POPULATION_ID_1); boxes[1].add("id", POPULATION_ID_2); boxes[2].add("id", POPULATION_ID_3); PatchSeries series = makeSeriesForPopulation(boxes); - + assertEquals(3, series.populations.size()); assertNotNull(series.populations.get(POPULATION_ID_1)); assertNotNull(series.populations.get(POPULATION_ID_2)); @@ -230,62 +233,93 @@ public void updatePopulation_multiplePopulations_createsMap() { assertEquals(2, series.populations.get(POPULATION_ID_2).getInt("CODE")); assertEquals(3, series.populations.get(POPULATION_ID_3).getInt("CODE")); } - + @Test public void updatePopulation_noInit_setsZero() { - Box[] boxes = new Box[] { new Box() }; + Box[] boxes = new Box[] {new Box()}; boxes[0].add("id", POPULATION_ID_1); PatchSeries series = makeSeriesForPopulation(boxes); - + MiniBox box = series.populations.get(POPULATION_ID_1); - assertEquals(0, box.getDouble("INIT"), EPSILON); + assertEquals(0, box.getDouble("COUNT"), EPSILON); } - + @Test - public void updatePopulation_givenInit_setsValue() { - String[] fractions = new String[] { "0", "10", "1E2" }; - int[] values = new int[] { 0, 10, 100 }; - - for (int i = 0; i < fractions.length; i++) { - Box[] boxes = new Box[] { new Box() }; + public void updatePopulation_givenInvalidInit_setsValue() { + String[] invalid = new String[] {"", "a", "5%5", "-2", "5.5%"}; + + for (int i = 0; i < invalid.length; i++) { + Box[] boxes = new Box[] {new Box()}; boxes[0].add("id", POPULATION_ID_1); - boxes[0].add("init", fractions[i]); + boxes[0].add("init", invalid[i]); PatchSeries series = makeSeriesForPopulation(boxes); - + MiniBox box = series.populations.get(POPULATION_ID_1); - assertEquals(values[i], box.getInt("INIT")); + assertEquals(0, box.getInt("COUNT")); } } - + + @Test + public void updatePopulation_givenNumberInit_setsValue() { + String[] numbers = new String[] {"0", "10", "1E2"}; + int[] values = new int[] {0, 10, 100}; + + for (int i = 0; i < numbers.length; i++) { + Box[] boxes = new Box[] {new Box()}; + boxes[0].add("id", POPULATION_ID_1); + boxes[0].add("init", numbers[i]); + PatchSeries series = makeSeriesForPopulation(boxes); + + MiniBox box = series.populations.get(POPULATION_ID_1); + assertEquals(values[i], box.getInt("COUNT")); + } + } + + @Test + public void updatePopulation_givenPercentInit_setsValue() { + String[] percents = new String[] {"0%", "50%", "100%"}; + int[] values = new int[] {0, 50, 100}; + + for (int i = 0; i < percents.length; i++) { + Box[] boxes = new Box[] {new Box()}; + boxes[0].add("id", POPULATION_ID_1); + boxes[0].add("init", percents[i]); + PatchSeries series = makeSeriesForPopulation(boxes); + + MiniBox box = series.populations.get(POPULATION_ID_1); + assertEquals(values[i], box.getInt("PERCENT")); + } + } + @Test public void updatePopulation_noParametersOnePop_usesDefaults() { - Box[] boxes = new Box[] { new Box() }; + Box[] boxes = new Box[] {new Box()}; boxes[0].add("id", POPULATION_ID_1); PatchSeries series = makeSeriesForPopulation(boxes); MiniBox box = series.populations.get(POPULATION_ID_1); - + for (String parameter : POPULATION_PARAMETER_NAMES) { assertEquals(POPULATION.get(parameter), box.get(parameter)); } } - + @Test public void updatePopulation_givenParametersOnePop_updatesValues() { for (String populationParameter1 : POPULATION_PARAMETER_NAMES) { for (String populationParameter2 : POPULATION_PARAMETER_NAMES) { - Box[] boxes = new Box[] { new Box() }; + Box[] boxes = new Box[] {new Box()}; boxes[0].add("id", POPULATION_ID_1); - + double value = randomDoubleBetween(1, 100); double scale = randomDoubleBetween(1, 100); boxes[0].addAtt(populationParameter1, "value", "" + value); boxes[0].addTag(populationParameter1, "PARAMETER"); boxes[0].addAtt(populationParameter2, "scale", "" + scale); boxes[0].addTag(populationParameter2, "PARAMETER"); - + PatchSeries series = makeSeriesForPopulation(boxes); MiniBox box = series.populations.get(POPULATION_ID_1); - + for (String parameter : POPULATION_PARAMETER_NAMES) { double expected = POPULATION.getDouble(parameter); if (parameter.equals(populationParameter1)) { @@ -299,10 +333,10 @@ public void updatePopulation_givenParametersOnePop_updatesValues() { } } } - + @Test public void updatePopulation_noParametersMultiplePops_usesDefaults() { - Box[] boxes = new Box[] { new Box(), new Box(), new Box() }; + Box[] boxes = new Box[] {new Box(), new Box(), new Box()}; boxes[0].add("id", POPULATION_ID_1); boxes[1].add("id", POPULATION_ID_2); boxes[2].add("id", POPULATION_ID_3); @@ -310,39 +344,39 @@ public void updatePopulation_noParametersMultiplePops_usesDefaults() { MiniBox box1 = series.populations.get(POPULATION_ID_1); MiniBox box2 = series.populations.get(POPULATION_ID_2); MiniBox box3 = series.populations.get(POPULATION_ID_3); - + for (String parameter : POPULATION_PARAMETER_NAMES) { assertEquals(POPULATION.get(parameter), box1.get(parameter)); assertEquals(POPULATION.get(parameter), box2.get(parameter)); assertEquals(POPULATION.get(parameter), box3.get(parameter)); } } - + @Test public void updatePopulation_givenParametersMultiplePops_updatesValues() { for (String populationParameter1 : POPULATION_PARAMETER_NAMES) { for (String populationParameter2 : POPULATION_PARAMETER_NAMES) { - Box[] boxes = new Box[] { new Box(), new Box(), new Box() }; + Box[] boxes = new Box[] {new Box(), new Box(), new Box()}; boxes[0].add("id", POPULATION_ID_1); boxes[1].add("id", POPULATION_ID_2); boxes[2].add("id", POPULATION_ID_3); - + double value = randomDoubleBetween(1, 100); double scale = randomDoubleBetween(1, 100); boxes[1].addAtt(populationParameter1, "value", "" + value); boxes[1].addTag(populationParameter1, "PARAMETER"); boxes[1].addAtt(populationParameter2, "scale", "" + scale); boxes[1].addTag(populationParameter2, "PARAMETER"); - + PatchSeries series = makeSeriesForPopulation(boxes); MiniBox box1 = series.populations.get(POPULATION_ID_1); MiniBox box2 = series.populations.get(POPULATION_ID_2); MiniBox box3 = series.populations.get(POPULATION_ID_3); - + for (String parameter : POPULATION_PARAMETER_NAMES) { assertEquals(POPULATION.get(parameter), box1.get(parameter)); assertEquals(POPULATION.get(parameter), box3.get(parameter)); - + double expected = POPULATION.getDouble(parameter); if (parameter.equals(populationParameter1)) { expected = value; @@ -355,50 +389,78 @@ public void updatePopulation_givenParametersMultiplePops_updatesValues() { } } } - + + @Test + public void updatePopulation_withLinks_setsTags() { + double weight11 = randomDoubleBetween(1, 100); + double weight12 = randomDoubleBetween(1, 100); + double weight21 = randomDoubleBetween(1, 100); + + Box[] boxes = new Box[] {new Box(), new Box()}; + + boxes[0].add("id", POPULATION_ID_1); + boxes[0].addAtt(POPULATION_ID_1, "weight", "" + weight11); + boxes[0].addTag(POPULATION_ID_1, "LINK"); + boxes[0].addAtt(POPULATION_ID_2, "weight", "" + weight12); + boxes[0].addTag(POPULATION_ID_2, "LINK"); + + boxes[1].add("id", POPULATION_ID_2); + boxes[1].addAtt(POPULATION_ID_1, "weight", "" + weight21); + boxes[1].addTag(POPULATION_ID_1, "LINK"); + + PatchSeries series = makeSeriesForPopulation(boxes); + + MiniBox box1 = series.populations.get(POPULATION_ID_1); + assertEquals(weight11, box1.getDouble("(LINK)" + TAG_SEPARATOR + POPULATION_ID_1)); + assertEquals(weight12, box1.getDouble("(LINK)" + TAG_SEPARATOR + POPULATION_ID_2)); + + MiniBox box2 = series.populations.get(POPULATION_ID_2); + assertEquals(weight21, box2.getDouble("(LINK)" + TAG_SEPARATOR + POPULATION_ID_1)); + } + @Test public void updatePopulation_withProcesses_setsTags() { - String[] versions = new String[] { - randomString(), - randomString(), - }; - - Box[] boxes = new Box[] { new Box() }; + String[] versions = + new String[] { + randomString(), randomString(), + }; + + Box[] boxes = new Box[] {new Box()}; boxes[0].add("id", POPULATION_ID_1); boxes[0].addTag(PROCESS_IDS[0], "PROCESS"); boxes[0].addAtt(PROCESS_IDS[0], "version", versions[0]); boxes[0].addTag(PROCESS_IDS[1], "PROCESS"); boxes[0].addAtt(PROCESS_IDS[1], "version", versions[1]); - + PatchSeries series = makeSeriesForPopulation(boxes); - + MiniBox box = series.populations.get(POPULATION_ID_1); assertEquals(versions[0], box.get("(PROCESS)" + TAG_SEPARATOR + PROCESS_IDS[0])); assertEquals(versions[1], box.get("(PROCESS)" + TAG_SEPARATOR + PROCESS_IDS[1])); } - + @Test public void getSimClass_givenHex_returnsClass() { String className = PatchSimulationHex.class.getName(); PatchSeries series = mock(PatchSeries.class, CALLS_REAL_METHODS); - + series.patch = new MiniBox(); series.patch.put("GEOMETRY", "Hex"); - + assertEquals(className, series.getSimClass()); } - + @Test public void getSimClass_givenRect_returnsClass() { String className = PatchSimulationRect.class.getName(); PatchSeries series = mock(PatchSeries.class, CALLS_REAL_METHODS); - + series.patch = new MiniBox(); series.patch.put("GEOMETRY", "Rect"); - + assertEquals(className, series.getSimClass()); } - + @Test public void getVisClass_allCases_returnsClass() { String className = PatchVisualization.class.getName(); diff --git a/test/arcade/patch/util/PatchEnumsTest.java b/test/arcade/patch/util/PatchEnumsTest.java index 4564a8d6a..316e955e2 100644 --- a/test/arcade/patch/util/PatchEnumsTest.java +++ b/test/arcade/patch/util/PatchEnumsTest.java @@ -2,34 +2,34 @@ import java.util.ArrayList; import java.util.EnumSet; -import org.junit.Test; +import org.junit.jupiter.api.Test; import ec.util.MersenneTwisterFast; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.patch.util.PatchEnums.Flag; public class PatchEnumsTest { - @Test(expected = UnsupportedOperationException.class) + @Test public void constructor_called_throwsException() { - PatchEnums enums = new PatchEnums(); + assertThrows(UnsupportedOperationException.class, PatchEnums::new); } - + @Test public void Flag_random_returnsFlag() { // Create set of all values. EnumSet enumSet = EnumSet.allOf(Flag.class); enumSet.remove(Flag.UNDEFINED); - + // Create set of all random values. ArrayList enumRandom = new ArrayList<>(); - + int n = Flag.values().length - 1; for (int i = 0; i < n; i++) { MersenneTwisterFast rng = mock(MersenneTwisterFast.class); doReturn(i).when(rng).nextInt(n); enumRandom.add(Flag.random(rng)); } - + // Compare resulting sets. EnumSet enumSetRandom = EnumSet.copyOf(enumRandom); assertEquals(enumSet, enumSetRandom); diff --git a/test/arcade/potts/PottsARCADETest.java b/test/arcade/potts/PottsARCADETest.java index 8f5f1ad0c..c9ac8103d 100644 --- a/test/arcade/potts/PottsARCADETest.java +++ b/test/arcade/potts/PottsARCADETest.java @@ -1,95 +1,102 @@ package arcade.potts; import java.io.File; -import org.apache.commons.io.FileUtils; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; +import java.nio.file.Files; +import java.nio.file.Path; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import arcade.core.ARCADE; import arcade.core.sim.Series; import arcade.potts.sim.input.PottsInputBuilder; import arcade.potts.sim.output.PottsOutputLoader; import arcade.potts.sim.output.PottsOutputSaver; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; public class PottsARCADETest { static String makeSetup(String name) { return "" - + "" + + "" + ""; } - - @Rule - public TemporaryFolder folder = new TemporaryFolder(); - + @Test - public void main_noVis_savesFiles() throws Exception { + public void main_noVis_savesFiles(@TempDir Path path) throws Exception { String name = "main_noVis_savesFiles"; - File setupFile = folder.newFile("setup.xml"); - FileUtils.writeStringToFile(setupFile, makeSetup(name), "UTF-8"); - - String[] args = new String[] { "potts", setupFile.getPath(), folder.getRoot().getAbsolutePath() }; + Path setupFile = Files.createFile(path.resolve("setup.xml")); + Files.writeString(setupFile, makeSetup(name)); + + String[] args = + new String[] {"potts", setupFile.toString(), path.toAbsolutePath().toString()}; ARCADE.main(args); - - File mainOutput = new File(folder.getRoot() + "/" + name + ".json"); + + File mainOutput = new File(path.toAbsolutePath() + "/" + name + ".json"); assertTrue(mainOutput.exists()); - - String[] timepoints = new String[] { "0000_000000", "0000_000001" }; + + String[] timepoints = new String[] {"0000_000000", "0000_000001"}; for (String tp : timepoints) { - File cellOutput = new File(folder.getRoot() + "/" + name + "_" + tp + ".CELLS.json"); + File cellOutput = + new File(path.toAbsolutePath() + "/" + name + "_" + tp + ".CELLS.json"); assertTrue(cellOutput.exists()); - File locationOutput = new File(folder.getRoot() + "/" + name + "_" + tp + ".LOCATIONS.json"); + File locationOutput = + new File(path.toAbsolutePath() + "/" + name + "_" + tp + ".LOCATIONS.json"); assertTrue(locationOutput.exists()); } } - + @Test - public void main_withVis_savesNothing() throws Exception { + public void main_withVis_savesNothing(@TempDir Path path) throws Exception { String name = "main_withVis_savesNothing"; - File setupFile = folder.newFile("setup.xml"); - FileUtils.writeStringToFile(setupFile, makeSetup(name), "UTF-8"); - + Path setupFile = Files.createFile(path.resolve("setup.xml")); + Files.writeString(setupFile, makeSetup(name)); + System.setProperty("java.awt.headless", "true"); - - String[] args = new String[] { "potts", setupFile.getPath(), folder.getRoot().getAbsolutePath(), "--vis" }; + + String[] args = + new String[] { + "potts", setupFile.toString(), path.toAbsolutePath().toString(), "--vis" + }; ARCADE.main(args); - - File mainOutput = new File(folder.getRoot() + "/" + name + ".json"); + + File mainOutput = new File(path.toAbsolutePath() + "/" + name + ".json"); assertFalse(mainOutput.exists()); - - String[] timepoints = new String[] { "0000_000000", "0000_000001" }; + + String[] timepoints = new String[] {"0000_000000", "0000_000001"}; for (String tp : timepoints) { - File cellOutput = new File(folder.getRoot() + "/" + name + "_" + tp + ".CELLS.json"); + File cellOutput = + new File(path.toAbsolutePath() + "/" + name + "_" + tp + ".CELLS.json"); assertFalse(cellOutput.exists()); - File locationOutput = new File(folder.getRoot() + "/" + name + "_" + tp + ".LOCATIONS.json"); + File locationOutput = + new File(path.toAbsolutePath() + "/" + name + "_" + tp + ".LOCATIONS.json"); assertFalse(locationOutput.exists()); } } - + @Test public void getResource_requiredFiles_returnsResource() { PottsARCADE arcade = new PottsARCADE(); - + String parameterFile = arcade.getResource("parameter.potts.xml"); assertNotNull(parameterFile); - + String commandFile = arcade.getResource("command.potts.xml"); assertNotNull(commandFile); } - + @Test public void getBuilder_called_returnsBuilder() { PottsARCADE arcade = new PottsARCADE(); assertTrue(arcade.getBuilder() instanceof PottsInputBuilder); } - + @Test public void getLoader_called_returnsBuilder() { PottsARCADE arcade = new PottsARCADE(); assertTrue(arcade.getLoader(mock(Series.class)) instanceof PottsOutputLoader); } - + @Test public void getSaver_called_returnsBuilder() { PottsARCADE arcade = new PottsARCADE(); diff --git a/test/arcade/potts/agent/cell/PottsCellContainerTest.java b/test/arcade/potts/agent/cell/PottsCellContainerTest.java index 89a4db696..4b389870e 100644 --- a/test/arcade/potts/agent/cell/PottsCellContainerTest.java +++ b/test/arcade/potts/agent/cell/PottsCellContainerTest.java @@ -1,26 +1,27 @@ package arcade.potts.agent.cell; +import java.util.Arrays; import java.util.EnumMap; import java.util.EnumSet; -import org.junit.Test; +import org.junit.jupiter.api.Test; import ec.util.MersenneTwisterFast; import arcade.core.env.location.Location; import arcade.core.util.MiniBox; -import arcade.potts.agent.module.PottsModule; +import arcade.core.util.Parameters; import arcade.potts.env.location.PottsLocation; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.core.ARCADETestUtilities.*; -import static arcade.potts.agent.cell.PottsCellFactoryTest.*; +import static arcade.core.util.MiniBox.TAG_SEPARATOR; import static arcade.potts.util.PottsEnums.Phase; import static arcade.potts.util.PottsEnums.Region; import static arcade.potts.util.PottsEnums.State; public class PottsCellContainerTest { private static final double EPSILON = 1E-10; - - private static final MersenneTwisterFast RANDOM = new MersenneTwisterFast(randomSeed()); - + + private static final MersenneTwisterFast RANDOM = new MersenneTwisterFast(); + @Test public void constructor_noRegions_setsFields() { int id = randomIntBetween(1, 10); @@ -33,10 +34,20 @@ public void constructor_noRegions_setsFields() { int voxels = randomIntBetween(1, 100); double criticalVolume = randomDoubleBetween(0, 100); double criticalHeight = randomDoubleBetween(0, 100); - - PottsCellContainer cellContainer = new PottsCellContainer(id, parent, pop, age, divisions, - state, phase, voxels, criticalVolume, criticalHeight); - + + PottsCellContainer cellContainer = + new PottsCellContainer( + id, + parent, + pop, + age, + divisions, + state, + phase, + voxels, + criticalVolume, + criticalHeight); + assertEquals(id, cellContainer.id); assertEquals(parent, cellContainer.parent); assertEquals(pop, cellContainer.pop); @@ -51,7 +62,7 @@ public void constructor_noRegions_setsFields() { assertNull(cellContainer.criticalRegionVolumes); assertNull(cellContainer.criticalRegionHeights); } - + @Test public void constructor_withRegions_setsFields() { int id = randomIntBetween(1, 10); @@ -67,11 +78,23 @@ public void constructor_withRegions_setsFields() { EnumMap regionVoxels = new EnumMap<>(Region.class); EnumMap criticalRegionVolumes = new EnumMap<>(Region.class); EnumMap criticalRegionHeights = new EnumMap<>(Region.class); - - PottsCellContainer cellContainer = new PottsCellContainer(id, parent, pop, age, divisions, - state, phase, voxels, regionVoxels, criticalVolume, criticalHeight, - criticalRegionVolumes, criticalRegionHeights); - + + PottsCellContainer cellContainer = + new PottsCellContainer( + id, + parent, + pop, + age, + divisions, + state, + phase, + voxels, + regionVoxels, + criticalVolume, + criticalHeight, + criticalRegionVolumes, + criticalRegionHeights); + assertEquals(id, cellContainer.id); assertEquals(parent, cellContainer.parent); assertEquals(pop, cellContainer.pop); @@ -86,37 +109,112 @@ public void constructor_withRegions_setsFields() { assertSame(criticalRegionVolumes, cellContainer.criticalRegionVolumes); assertSame(criticalRegionHeights, cellContainer.criticalRegionHeights); } - + @Test public void getID_called_returnsValue() { int id = randomIntBetween(1, 10); - PottsCellContainer cellContainer = new PottsCellContainer(id, 0, 0, 0, 0, null, null, 0, 0, 0); + PottsCellContainer cellContainer = + new PottsCellContainer(id, 0, 0, 0, 0, null, null, 0, 0, 0); assertEquals(id, cellContainer.getID()); } - + @Test - public void convert_noRegions_createsObject() { + public void convert_noRegionsNoParent_createsObject() { Location location = mock(PottsLocation.class); PottsCellFactory factory = new PottsCellFactory(); - + int cellID = randomIntBetween(1, 10); int cellParent = randomIntBetween(1, 10); int cellPop = randomIntBetween(1, 10); int cellAge = randomIntBetween(1, 100); int cellDivisions = randomIntBetween(1, 100); - State cellState = State.PROLIFERATIVE; - Phase cellPhase = Phase.PROLIFERATIVE_S; + State cellState = State.UNDEFINED; + Phase cellPhase = Phase.UNDEFINED; double criticalVolume = randomDoubleBetween(10, 100); double criticalHeight = randomDoubleBetween(10, 100); - MiniBox parameters = mock(MiniBox.class); - + MiniBox parameters = new MiniBox(); + parameters.put("CLASS", ""); + factory.popToParameters.put(cellPop, parameters); factory.popToRegions.put(cellPop, false); - - PottsCellContainer container = new PottsCellContainer(cellID, cellParent, cellPop, cellAge, - cellDivisions, cellState, cellPhase, 0, null, criticalVolume, criticalHeight, null, null); - PottsCell cell = (PottsCell) container.convert(factory, location); - + + Parameters cellParameters = new Parameters(parameters, null, RANDOM); + + PottsCellContainer container = + new PottsCellContainer( + cellID, + cellParent, + cellPop, + cellAge, + cellDivisions, + cellState, + cellPhase, + 0, + criticalVolume, + criticalHeight); + PottsCell cell = (PottsCell) container.convert(factory, location, RANDOM); + + assertEquals(location, cell.getLocation()); + assertEquals(cellID, cell.getID()); + assertEquals(cellParent, cell.getParent()); + assertEquals(cellPop, cell.getPop()); + assertEquals(cellAge, cell.getAge()); + assertEquals(cellDivisions, cell.getDivisions()); + assertEquals(cellState, cell.getState()); + assertTrue(cellParameters.compare(cell.getParameters())); + assertEquals(criticalVolume, cell.getCriticalVolume(), EPSILON); + assertEquals(criticalHeight, cell.getCriticalHeight(), EPSILON); + assertEquals(0, cell.getTargetVolume(), EPSILON); + assertEquals(0, cell.getTargetSurface(), EPSILON); + } + + @Test + public void convert_noRegionsWithParent_createsObject() { + Location location = mock(PottsLocation.class); + PottsCellFactory factory = new PottsCellFactory(); + + int cellID = randomIntBetween(1, 10); + int cellParent = randomIntBetween(1, 10); + int cellPop = randomIntBetween(1, 10); + int cellAge = randomIntBetween(1, 100); + int cellDivisions = randomIntBetween(1, 100); + State cellState = State.UNDEFINED; + Phase cellPhase = Phase.UNDEFINED; + double criticalVolume = randomDoubleBetween(10, 100); + double criticalHeight = randomDoubleBetween(10, 100); + + MiniBox parametersA = new MiniBox(); + parametersA.put("CLASS", ""); + parametersA.put("(DISTRIBUTION)" + TAG_SEPARATOR + "PARAM", "NORMAL"); + parametersA.put("PARAM_MU", 2); + parametersA.put("PARAM_SIGMA", 4); + + MiniBox parametersB = new MiniBox(); + parametersB.put("CLASS", ""); + parametersB.put("(DISTRIBUTION)" + TAG_SEPARATOR + "PARAM", "NORMAL"); + parametersB.put("PARAM_MU", 5); + parametersB.put("PARAM_SIGMA", 3); + + factory.popToParameters.put(cellPop, parametersB); + factory.popToRegions.put(cellPop, false); + + Parameters parentParameters = new Parameters(parametersA, null, RANDOM); + Parameters cellParameters = new Parameters(parametersB, parentParameters, RANDOM); + + PottsCellContainer container = + new PottsCellContainer( + cellID, + cellParent, + cellPop, + cellAge, + cellDivisions, + cellState, + cellPhase, + 0, + criticalVolume, + criticalHeight); + PottsCell cell = (PottsCell) container.convert(factory, location, RANDOM, parentParameters); + assertEquals(location, cell.getLocation()); assertEquals(cellID, cell.getID()); assertEquals(cellParent, cell.getParent()); @@ -124,44 +222,147 @@ public void convert_noRegions_createsObject() { assertEquals(cellAge, cell.getAge()); assertEquals(cellDivisions, cell.getDivisions()); assertEquals(cellState, cell.getState()); - assertEquals(parameters, cell.getParameters()); - assertEquals(cellPhase, ((PottsModule) cell.getModule()).getPhase()); + assertTrue(cellParameters.compare(cell.getParameters())); assertEquals(criticalVolume, cell.getCriticalVolume(), EPSILON); assertEquals(criticalHeight, cell.getCriticalHeight(), EPSILON); assertEquals(0, cell.getTargetVolume(), EPSILON); assertEquals(0, cell.getTargetSurface(), EPSILON); } - + @Test - public void convert_withRegions_createsObject() { + public void convert_withRegionsNoParent_createsObject() { PottsLocation location = mock(PottsLocation.class); PottsCellFactory factory = new PottsCellFactory(); - + int cellID = randomIntBetween(1, 10); int cellParent = randomIntBetween(1, 10); int cellPop = randomIntBetween(1, 10); int cellAge = randomIntBetween(1, 100); int cellDivisions = randomIntBetween(1, 100); - State cellState = State.PROLIFERATIVE; - Phase cellPhase = Phase.PROLIFERATIVE_S; + State cellState = State.UNDEFINED; + Phase cellPhase = Phase.UNDEFINED; double criticalVolume = randomDoubleBetween(10, 100); double criticalHeight = randomDoubleBetween(10, 100); - MiniBox parameters = mock(MiniBox.class); - + MiniBox parameters = new MiniBox(); + parameters.put("CLASS", ""); + EnumSet regionList = EnumSet.of(Region.NUCLEUS, Region.UNDEFINED); doReturn(regionList).when(location).getRegions(); - - EnumMap criticalRegionVolumes = makeRegionEnumMap(); - EnumMap criticalRegionHeights = makeRegionEnumMap(); - + + EnumMap criticalRegionVolumes = new EnumMap<>(Region.class); + EnumMap criticalRegionHeights = new EnumMap<>(Region.class); + + Arrays.stream(Region.values()) + .forEach(region -> criticalRegionVolumes.put(region, randomDoubleBetween(0, 100))); + Arrays.stream(Region.values()) + .forEach(region -> criticalRegionHeights.put(region, randomDoubleBetween(0, 100))); + factory.popToParameters.put(cellPop, parameters); factory.popToRegions.put(cellPop, true); - - PottsCellContainer container = new PottsCellContainer(cellID, cellParent, cellPop, cellAge, - cellDivisions, cellState, cellPhase, 0, null, criticalVolume, criticalHeight, - criticalRegionVolumes, criticalRegionHeights); - PottsCell cell = (PottsCell) container.convert(factory, location); - + + Parameters cellParameters = new Parameters(parameters, null, RANDOM); + + PottsCellContainer container = + new PottsCellContainer( + cellID, + cellParent, + cellPop, + cellAge, + cellDivisions, + cellState, + cellPhase, + 0, + new EnumMap<>(Region.class), + criticalVolume, + criticalHeight, + criticalRegionVolumes, + criticalRegionHeights); + PottsCell cell = (PottsCell) container.convert(factory, location, RANDOM); + + assertEquals(location, cell.getLocation()); + assertEquals(cellID, cell.getID()); + assertEquals(cellParent, cell.getParent()); + assertEquals(cellPop, cell.getPop()); + assertEquals(cellAge, cell.getAge()); + assertEquals(cellDivisions, cell.getDivisions()); + assertEquals(cellState, cell.getState()); + assertTrue(cellParameters.compare(cell.getParameters())); + assertEquals(criticalVolume, cell.getCriticalVolume(), EPSILON); + assertEquals(criticalHeight, cell.getCriticalHeight(), EPSILON); + assertEquals(0, cell.getTargetVolume(), EPSILON); + assertEquals(0, cell.getTargetSurface(), EPSILON); + + for (Region region : regionList) { + double criticalVolumeRegion = criticalRegionVolumes.get(region); + double criticalHeightRegion = criticalRegionHeights.get(region); + assertEquals(criticalVolumeRegion, cell.getCriticalVolume(region), EPSILON); + assertEquals(criticalHeightRegion, cell.getCriticalHeight(region), EPSILON); + assertEquals(0, cell.getTargetVolume(region), EPSILON); + assertEquals(0, cell.getTargetSurface(region), EPSILON); + } + } + + @Test + public void convert_withRegionsWithParent_createsObject() { + PottsLocation location = mock(PottsLocation.class); + PottsCellFactory factory = new PottsCellFactory(); + + int cellID = randomIntBetween(1, 10); + int cellParent = randomIntBetween(1, 10); + int cellPop = randomIntBetween(1, 10); + int cellAge = randomIntBetween(1, 100); + int cellDivisions = randomIntBetween(1, 100); + State cellState = State.UNDEFINED; + Phase cellPhase = Phase.UNDEFINED; + double criticalVolume = randomDoubleBetween(10, 100); + double criticalHeight = randomDoubleBetween(10, 100); + + MiniBox parametersA = new MiniBox(); + parametersA.put("CLASS", ""); + parametersA.put("(DISTRIBUTION)" + TAG_SEPARATOR + "PARAM", "NORMAL"); + parametersA.put("PARAM_MU", 2); + parametersA.put("PARAM_SIGMA", 4); + + MiniBox parametersB = new MiniBox(); + parametersB.put("CLASS", ""); + parametersB.put("(DISTRIBUTION)" + TAG_SEPARATOR + "PARAM", "NORMAL"); + parametersB.put("PARAM_MU", 5); + parametersB.put("PARAM_SIGMA", 3); + + EnumSet regionList = EnumSet.of(Region.NUCLEUS, Region.UNDEFINED); + doReturn(regionList).when(location).getRegions(); + + EnumMap criticalRegionVolumes = new EnumMap<>(Region.class); + EnumMap criticalRegionHeights = new EnumMap<>(Region.class); + + Arrays.stream(Region.values()) + .forEach(region -> criticalRegionVolumes.put(region, randomDoubleBetween(0, 100))); + Arrays.stream(Region.values()) + .forEach(region -> criticalRegionHeights.put(region, randomDoubleBetween(0, 100))); + + factory.popToParameters.put(cellPop, parametersB); + factory.popToRegions.put(cellPop, true); + + Parameters parentParameters = new Parameters(parametersA, null, RANDOM); + Parameters cellParameters = new Parameters(parametersB, parentParameters, RANDOM); + + PottsCellContainer container = + new PottsCellContainer( + cellID, + cellParent, + cellPop, + cellAge, + cellDivisions, + cellState, + cellPhase, + 0, + new EnumMap<>(Region.class), + criticalVolume, + criticalHeight, + criticalRegionVolumes, + criticalRegionHeights); + PottsCell cell = (PottsCell) container.convert(factory, location, RANDOM, parentParameters); + assertEquals(location, cell.getLocation()); assertEquals(cellID, cell.getID()); assertEquals(cellParent, cell.getParent()); @@ -169,13 +370,12 @@ public void convert_withRegions_createsObject() { assertEquals(cellAge, cell.getAge()); assertEquals(cellDivisions, cell.getDivisions()); assertEquals(cellState, cell.getState()); - assertEquals(parameters, cell.getParameters()); - assertEquals(cellPhase, ((PottsModule) cell.getModule()).getPhase()); + assertTrue(cellParameters.compare(cell.getParameters())); assertEquals(criticalVolume, cell.getCriticalVolume(), EPSILON); assertEquals(criticalHeight, cell.getCriticalHeight(), EPSILON); assertEquals(0, cell.getTargetVolume(), EPSILON); assertEquals(0, cell.getTargetSurface(), EPSILON); - + for (Region region : regionList) { double criticalVolumeRegion = criticalRegionVolumes.get(region); double criticalHeightRegion = criticalRegionHeights.get(region); diff --git a/test/arcade/potts/agent/cell/PottsCellFactoryTest.java b/test/arcade/potts/agent/cell/PottsCellFactoryTest.java index d1076a154..1660ea70b 100644 --- a/test/arcade/potts/agent/cell/PottsCellFactoryTest.java +++ b/test/arcade/potts/agent/cell/PottsCellFactoryTest.java @@ -2,34 +2,32 @@ import java.lang.reflect.Field; import java.util.ArrayList; -import java.util.Arrays; -import java.util.EnumMap; import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; import java.util.stream.IntStream; -import org.junit.Test; +import org.junit.jupiter.api.Test; import ec.util.MersenneTwisterFast; import arcade.core.agent.cell.*; import arcade.core.sim.Series; import arcade.core.sim.output.OutputLoader; -import arcade.core.util.Distribution; +import arcade.core.util.GrabBag; import arcade.core.util.MiniBox; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.core.ARCADETestUtilities.*; import static arcade.core.util.MiniBox.TAG_SEPARATOR; import static arcade.potts.util.PottsEnums.Region; public class PottsCellFactoryTest { - private static final double EPSILON = 1E-10; - + private static final double EPSILON = 1E-5; + final MersenneTwisterFast random = mock(MersenneTwisterFast.class); - + static Series createSeries(int[] init) { Series series = mock(Series.class); series.populations = new HashMap<>(); - + for (int i = 0; i < init.length; i++) { int pop = i + 1; MiniBox box = new MiniBox(); @@ -37,255 +35,285 @@ static Series createSeries(int[] init) { box.put("INIT", init[i]); series.populations.put("pop" + pop, box); } - + return series; } - - static EnumMap makeRegionEnumMap() { - EnumMap map = new EnumMap<>(Region.class); - Arrays.stream(Region.values()).forEach(region -> map.put(region, randomDoubleBetween(0, 100))); - return map; - } - - static Distribution makeDistributionMock(double values) { - Distribution distribution = mock(Distribution.class); - doReturn(values).when(distribution).nextDouble(); - return distribution; - } - - static EnumMap makeRegionDistributionMock(Region[] regions, double[] values) { - EnumMap distributions = new EnumMap<>(Region.class); - for (int i = 0; i < regions.length; i++) { - Region region = regions[i]; - Distribution distribution = makeDistributionMock(values[i]); - distributions.put(region, distribution); - } - return distributions; - } - + @Test public void initialize_noLoading_callsMethod() { PottsCellFactory factory = spy(new PottsCellFactory()); Series series = mock(Series.class); series.loader = null; - + doNothing().when(factory).parseValues(series); doNothing().when(factory).loadCells(series); doNothing().when(factory).createCells(series); - + factory.initialize(series, random); - + verify(factory).parseValues(series); verify(factory, never()).loadCells(series); verify(factory).createCells(series); } - + @Test public void initialize_noLoadingWithLoader_callsMethod() { PottsCellFactory factory = spy(new PottsCellFactory()); Series series = mock(Series.class); series.loader = mock(OutputLoader.class); - + try { Field field = OutputLoader.class.getDeclaredField("loadCells"); field.setAccessible(true); field.set(series.loader, false); - } catch (Exception ignored) { } - + } catch (Exception ignored) { + } + doNothing().when(factory).parseValues(series); doNothing().when(factory).loadCells(series); doNothing().when(factory).createCells(series); - + factory.initialize(series, random); - + verify(factory).parseValues(series); verify(factory, never()).loadCells(series); verify(factory).createCells(series); } - + @Test public void initialize_withLoadingWithLoader_callsMethod() { PottsCellFactory factory = spy(new PottsCellFactory()); Series series = mock(Series.class); series.loader = mock(OutputLoader.class); - + try { Field field = OutputLoader.class.getDeclaredField("loadCells"); field.setAccessible(true); field.set(series.loader, true); - } catch (Exception ignored) { } - + } catch (Exception ignored) { + } + doNothing().when(factory).parseValues(series); doNothing().when(factory).loadCells(series); doNothing().when(factory).createCells(series); - + factory.initialize(series, random); - + verify(factory).parseValues(series); verify(factory).loadCells(series); verify(factory, never()).createCells(series); } - + @Test - public void parseValues_noRegions_updatesLists() { + public void parseValues_noRegionsNoLinks_updatesLists() { Series series = mock(Series.class); series.populations = new HashMap<>(); - - double criticalVolumeMean = randomDoubleBetween(0, 100); - double criticalVolumeStdev = randomDoubleBetween(0, 100); - double criticalHeightMean = randomDoubleBetween(0, 100); - double criticalHeightStdev = randomDoubleBetween(0, 100); - - String[] popKeys = new String[] { "A", "B", "C" }; + + String[] popKeys = new String[] {"A", "B", "C"}; MiniBox[] popParameters = new MiniBox[3]; - + for (int i = 0; i < popKeys.length; i++) { int pop = i + 1; MiniBox population = new MiniBox(); - population.put("CODE", pop); - population.put("CRITICAL_VOLUME_MEAN", criticalVolumeMean + pop); - population.put("CRITICAL_VOLUME_STDEV", criticalVolumeStdev + pop); - population.put("CRITICAL_HEIGHT_MEAN", criticalHeightMean + pop); - population.put("CRITICAL_HEIGHT_STDEV", criticalHeightStdev + pop); - + series.populations.put(popKeys[i], population); popParameters[i] = population; } - + PottsCellFactory factory = new PottsCellFactory(); + factory.random = new MersenneTwisterFast(1); factory.parseValues(series); - + for (int i = 0; i < popKeys.length; i++) { int pop = i + 1; - Distribution volumeDistribution = factory.popToCriticalVolumes.get(pop); - Distribution heightDistribution = factory.popToCriticalHeights.get(pop); - assertEquals(criticalVolumeMean + pop, volumeDistribution.getMu(), EPSILON); - assertEquals(criticalVolumeStdev + pop, volumeDistribution.getSigma(), EPSILON); - assertEquals(criticalHeightMean + pop, heightDistribution.getMu(), EPSILON); - assertEquals(criticalHeightStdev + pop, heightDistribution.getSigma(), EPSILON); assertEquals(new HashSet<>(), factory.popToIDs.get(pop)); assertEquals(popParameters[i], factory.popToParameters.get(pop)); assertFalse(factory.popToRegions.get(pop)); + assertNull(factory.popToLinks.get(pop)); } } - + @Test - public void parseValues_withRegions_updatesLists() { + public void parseValues_noRegionsWithLinks_updatesLists() { Series series = mock(Series.class); series.populations = new HashMap<>(); - - double criticalVolumeMean = randomDoubleBetween(0, 100); - double criticalVolumeStdev = randomDoubleBetween(0, 100); - double criticalHeightMean = randomDoubleBetween(0, 100); - double criticalHeightStdev = randomDoubleBetween(0, 100); - + + String[] popKeys = new String[] {"A", "B", "C"}; + MiniBox[] popParameters = new MiniBox[3]; + int[][] weights = + new int[][] { + { + randomIntBetween(1, 10), randomIntBetween(1, 10), randomIntBetween(1, 10), + }, + { + randomIntBetween(1, 10), randomIntBetween(1, 10), randomIntBetween(1, 10), + }, + { + randomIntBetween(1, 10), randomIntBetween(1, 10), randomIntBetween(1, 10), + } + }; + GrabBag[] links = new GrabBag[] {new GrabBag(), new GrabBag(), new GrabBag()}; + + for (int i = 0; i < popKeys.length; i++) { + int pop = i + 1; + MiniBox population = new MiniBox(); + population.put("CODE", pop); + + series.populations.put(popKeys[i], population); + popParameters[i] = population; + + for (int j = 0; j < popKeys.length; j++) { + links[i].add(j + 1, weights[i][j]); + population.put("(LINK)" + TAG_SEPARATOR + popKeys[j], weights[i][j]); + } + } + + PottsCellFactory factory = new PottsCellFactory(); + factory.random = new MersenneTwisterFast(1); + factory.parseValues(series); + + for (int i = 0; i < popKeys.length; i++) { + int pop = i + 1; + assertEquals(new HashSet<>(), factory.popToIDs.get(pop)); + assertEquals(popParameters[i], factory.popToParameters.get(pop)); + assertFalse(factory.popToRegions.get(pop)); + assertEquals(links[i], factory.popToLinks.get(pop)); + } + } + + @Test + public void parseValues_withRegionsNoLinks_updatesLists() { + Series series = mock(Series.class); + series.populations = new HashMap<>(); + EnumSet regionList = EnumSet.of(Region.DEFAULT, Region.NUCLEUS, Region.UNDEFINED); - - EnumMap criticalRegionVolumeMeans = makeRegionEnumMap(); - EnumMap criticalRegionVolumeStdevs = makeRegionEnumMap(); - EnumMap criticalRegionHeightMeans = makeRegionEnumMap(); - EnumMap criticalRegionHeightStdevs = makeRegionEnumMap(); - - String[] popKeys = new String[] { "A", "B", "C" }; + + String[] popKeys = new String[] {"A", "B", "C"}; MiniBox[] popParameters = new MiniBox[3]; - + for (int i = 0; i < popKeys.length; i++) { int pop = i + 1; MiniBox population = new MiniBox(); - population.put("CODE", pop); - population.put("CRITICAL_VOLUME_MEAN", criticalVolumeMean + pop); - population.put("CRITICAL_VOLUME_STDEV", criticalVolumeStdev + pop); - population.put("CRITICAL_HEIGHT_MEAN", criticalHeightMean + pop); - population.put("CRITICAL_HEIGHT_STDEV", criticalHeightStdev + pop); - + for (Region region : regionList) { population.put("(REGION)" + TAG_SEPARATOR + region, 0); - double criticalRegionVolumeMean = criticalRegionVolumeMeans.get(region); - double criticalRegionVolumeStdev = criticalRegionVolumeStdevs.get(region); - double criticalRegionHeightMean = criticalRegionHeightMeans.get(region); - double criticalRegionHeightStdev = criticalRegionHeightStdevs.get(region); - population.put("CRITICAL_VOLUME_MEAN_" + region, criticalRegionVolumeMean + pop); - population.put("CRITICAL_VOLUME_STDEV_" + region, criticalRegionVolumeStdev + pop); - population.put("CRITICAL_HEIGHT_MEAN_" + region, criticalRegionHeightMean + pop); - population.put("CRITICAL_HEIGHT_STDEV_" + region, criticalRegionHeightStdev + pop); } - + series.populations.put(popKeys[i], population); popParameters[i] = population; } - + PottsCellFactory factory = new PottsCellFactory(); + factory.random = new MersenneTwisterFast(1); factory.parseValues(series); - + for (int i = 0; i < popKeys.length; i++) { int pop = i + 1; - Distribution volumeDistribution = factory.popToCriticalVolumes.get(pop); - Distribution heightDistribution = factory.popToCriticalHeights.get(pop); - assertEquals(criticalVolumeMean + pop, volumeDistribution.getMu(), EPSILON); - assertEquals(criticalVolumeStdev + pop, volumeDistribution.getSigma(), EPSILON); - assertEquals(criticalHeightMean + pop, heightDistribution.getMu(), EPSILON); - assertEquals(criticalHeightStdev + pop, heightDistribution.getSigma(), EPSILON); assertEquals(new HashSet<>(), factory.popToIDs.get(pop)); assertEquals(popParameters[i], factory.popToParameters.get(pop)); assertTrue(factory.popToRegions.get(pop)); - + assertNull(factory.popToLinks.get(pop)); + } + } + + @Test + public void parseValues_withRegionsWithLinks_updatesLists() { + Series series = mock(Series.class); + series.populations = new HashMap<>(); + + EnumSet regionList = EnumSet.of(Region.DEFAULT, Region.NUCLEUS, Region.UNDEFINED); + + String[] popKeys = new String[] {"A", "B", "C"}; + MiniBox[] popParameters = new MiniBox[3]; + int[][] weights = + new int[][] { + { + randomIntBetween(1, 10), randomIntBetween(1, 10), randomIntBetween(1, 10), + }, + { + randomIntBetween(1, 10), randomIntBetween(1, 10), randomIntBetween(1, 10), + }, + { + randomIntBetween(1, 10), randomIntBetween(1, 10), randomIntBetween(1, 10), + } + }; + GrabBag[] links = new GrabBag[] {new GrabBag(), new GrabBag(), new GrabBag()}; + + for (int i = 0; i < popKeys.length; i++) { + int pop = i + 1; + MiniBox population = new MiniBox(); + population.put("CODE", pop); + for (Region region : regionList) { - Distribution regionVolumeDistribution = factory.popToCriticalRegionVolumes.get(pop).get(region); - Distribution regionHeightDistribution = factory.popToCriticalRegionHeights.get(pop).get(region); - double criticalRegionVolumeMean = criticalRegionVolumeMeans.get(region); - double criticalRegionVolumeStdev = criticalRegionVolumeStdevs.get(region); - double criticalRegionHeightMean = criticalRegionHeightMeans.get(region); - double criticalRegionHeightStdev = criticalRegionHeightStdevs.get(region); - assertEquals(criticalRegionVolumeMean + pop, regionVolumeDistribution.getMu(), EPSILON); - assertEquals(criticalRegionVolumeStdev + pop, regionVolumeDistribution.getSigma(), EPSILON); - assertEquals(criticalRegionHeightMean + pop, regionHeightDistribution.getMu(), EPSILON); - assertEquals(criticalRegionHeightStdev + pop, regionHeightDistribution.getSigma(), EPSILON); + population.put("(REGION)" + TAG_SEPARATOR + region, 0); + } + + series.populations.put(popKeys[i], population); + popParameters[i] = population; + + for (int j = 0; j < popKeys.length; j++) { + links[i].add(j + 1, weights[i][j]); + population.put("(LINK)" + TAG_SEPARATOR + popKeys[j], weights[i][j]); } } + + PottsCellFactory factory = new PottsCellFactory(); + factory.random = new MersenneTwisterFast(1); + factory.parseValues(series); + + for (int i = 0; i < popKeys.length; i++) { + int pop = i + 1; + assertEquals(new HashSet<>(), factory.popToIDs.get(pop)); + assertEquals(popParameters[i], factory.popToParameters.get(pop)); + assertTrue(factory.popToRegions.get(pop)); + assertEquals(links[i], factory.popToLinks.get(pop)); + } } - + @Test public void loadCells_givenLoadedValidPops_updatesLists() { int n = randomIntBetween(1, 10); int m = randomIntBetween(1, 10); ArrayList containers = new ArrayList<>(); - + for (int i = 0; i < n; i++) { - PottsCellContainer container = new PottsCellContainer(i, 0, 1, 0, 0, - null, null, randomIntBetween(1, 10), 0, 0); + PottsCellContainer container = + new PottsCellContainer( + i, 0, 1, 0, 0, null, null, randomIntBetween(1, 10), 0, 0); containers.add(container); } - + for (int i = n; i < n + m; i++) { - PottsCellContainer container = new PottsCellContainer(i, 0, 2, 0, 0, - null, null, randomIntBetween(1, 10), 0, 0); + PottsCellContainer container = + new PottsCellContainer( + i, 0, 2, 0, 0, null, null, randomIntBetween(1, 10), 0, 0); containers.add(container); } - + PottsCellFactory factory = new PottsCellFactory(); factory.popToIDs.put(1, new HashSet<>()); factory.popToIDs.put(2, new HashSet<>()); Series series = mock(Series.class); series.loader = mock(OutputLoader.class); - + series.populations = new HashMap<>(); - + MiniBox pop1 = new MiniBox(); pop1.put("CODE", 1); pop1.put("INIT", n); series.populations.put("A", pop1); - + MiniBox pop2 = new MiniBox(); pop2.put("CODE", 2); pop2.put("INIT", m); series.populations.put("B", pop2); - + ArrayList container = new ArrayList<>(); IntStream.range(0, n + m).forEach(i -> container.add(containers.get(i))); doReturn(container).when(series.loader).loadCells(); - + factory.loadCells(series); assertEquals(n + m, factory.cells.size()); assertEquals(n, factory.popToIDs.get(1).size()); @@ -299,79 +327,82 @@ public void loadCells_givenLoadedValidPops_updatesLists() { assertEquals(2, factory.cells.get(i).pop); } } - + @Test public void loadCells_givenLoadedInvalidPops_updatesLists() { int n = randomIntBetween(1, 10); ArrayList containers = new ArrayList<>(); - + for (int i = 0; i < n; i++) { - PottsCellContainer container = new PottsCellContainer(i, 0, 1, 0, 0, - null, null, randomIntBetween(1, 10), 0, 0); + PottsCellContainer container = + new PottsCellContainer( + i, 0, 1, 0, 0, null, null, randomIntBetween(1, 10), 0, 0); containers.add(container); } - + PottsCellFactory factory = new PottsCellFactory(); Series series = mock(Series.class); series.loader = mock(OutputLoader.class); - + series.populations = new HashMap<>(); - + MiniBox pop1 = new MiniBox(); pop1.put("CODE", 1); pop1.put("INIT", n); series.populations.put("A", pop1); - + ArrayList container = new ArrayList<>(); IntStream.range(0, n).forEach(i -> container.add(containers.get(i))); doReturn(container).when(series.loader).loadCells(); - + factory.loadCells(series); assertEquals(0, factory.cells.size()); assertFalse(factory.popToIDs.containsKey(1)); } - + @Test public void loadCells_givenLoadedLimitedInit_updatesLists() { int num = randomIntBetween(1, 10); int n = num + randomIntBetween(1, 10); int m = randomIntBetween(1, 10); ArrayList containers = new ArrayList<>(); - + for (int i = 0; i < n; i++) { - PottsCellContainer container = new PottsCellContainer(i, 0, 1, 0, 0, - null, null, randomIntBetween(1, 10), 0, 0); + PottsCellContainer container = + new PottsCellContainer( + i, 0, 1, 0, 0, null, null, randomIntBetween(1, 10), 0, 0); containers.add(container); } - + for (int i = n; i < n + m; i++) { - PottsCellContainer container = new PottsCellContainer(i, 0, 2, 0, 0, - null, null, randomIntBetween(1, 10), 0, 0); + PottsCellContainer container = + new PottsCellContainer( + i, 0, 2, 0, 0, null, null, randomIntBetween(1, 10), 0, 0); containers.add(container); } - + PottsCellFactory factory = new PottsCellFactory(); factory.popToIDs.put(1, new HashSet<>()); factory.popToIDs.put(2, new HashSet<>()); Series series = mock(Series.class); series.loader = mock(OutputLoader.class); - + series.populations = new HashMap<>(); - + MiniBox pop1 = new MiniBox(); pop1.put("CODE", 1); pop1.put("INIT", num); series.populations.put("A", pop1); - + MiniBox pop2 = new MiniBox(); pop2.put("CODE", 2); pop2.put("INIT", m); series.populations.put("B", pop2); - + ArrayList container = new ArrayList<>(); IntStream.range(0, n + m).forEach(i -> container.add(containers.get(i))); doReturn(container).when(series.loader).loadCells(); - + factory.loadCells(series); assertEquals(num + m, factory.cells.size()); assertEquals(num, factory.popToIDs.get(1).size()); @@ -385,37 +416,40 @@ public void loadCells_givenLoadedLimitedInit_updatesLists() { assertEquals(2, factory.cells.get(i).pop); } } - + @Test public void createCells_noPopulation_createsEmpty() { - Series series = createSeries(new int[] { }); - + Series series = createSeries(new int[] {}); + PottsCellFactory factory = new PottsCellFactory(); factory.createCells(series); - + assertEquals(0, factory.cells.size()); assertEquals(0, factory.popToIDs.size()); } - + @Test public void createCells_onePopulationNoRegions_createsList() { int init = randomIntBetween(1, 10); - Series series = createSeries(new int[] { init }); - + Series series = createSeries(new int[] {init}); + double volume = randomDoubleBetween(1, 10); double height = randomDoubleBetween(1, 10); int voxels = (int) Math.round(volume); - + + MiniBox parameters = new MiniBox(); + parameters.put("CRITICAL_VOLUME", volume); + parameters.put("CRITICAL_HEIGHT", height); + PottsCellFactory factory = new PottsCellFactory(); factory.popToIDs.put(1, new HashSet<>()); + factory.popToParameters.put(1, parameters); factory.popToRegions.put(1, false); - factory.popToCriticalVolumes.put(1, makeDistributionMock(volume)); - factory.popToCriticalHeights.put(1, makeDistributionMock(height)); factory.createCells(series); - + assertEquals(init, factory.cells.size()); assertEquals(init, factory.popToIDs.get(1).size()); - + for (int i : factory.popToIDs.get(1)) { PottsCellContainer pottsCellContainer = factory.cells.get(i); assertEquals(volume, pottsCellContainer.criticalVolume, EPSILON); @@ -423,92 +457,117 @@ public void createCells_onePopulationNoRegions_createsList() { assertEquals(voxels, pottsCellContainer.voxels); } } - + @Test public void createCells_onePopulationWithRegions_createsList() { int init = randomIntBetween(1, 10); - Series series = createSeries(new int[] { init }); - + Series series = createSeries(new int[] {init}); + double volume = randomDoubleBetween(1, 10); double height = randomDoubleBetween(1, 10); int voxels = (int) Math.round(volume); - - Region[] regions = new Region[] { Region.DEFAULT, Region.NUCLEUS }; - double[] regionVolumes = new double[] { Double.NaN, randomDoubleBetween(1, 10) }; - double[] regionHeights = new double[] { Double.NaN, randomDoubleBetween(1, 10) }; - int[] regionVoxels = new int[] { 0, (int) Math.round(regionVolumes[1]) }; - + + double[] regionVolumes = new double[] {Double.NaN, randomDoubleBetween(1, 10)}; + double[] regionHeights = new double[] {Double.NaN, randomDoubleBetween(1, 10)}; + int[] regionVoxels = new int[] {0, (int) Math.round(regionVolumes[1])}; + + MiniBox parameters = new MiniBox(); + parameters.put("CRITICAL_VOLUME", volume); + parameters.put("CRITICAL_HEIGHT", height); + parameters.put("CRITICAL_VOLUME_DEFAULT", regionVolumes[0]); + parameters.put("CRITICAL_HEIGHT_DEFAULT", regionHeights[0]); + parameters.put("CRITICAL_VOLUME_NUCLEUS", regionVolumes[1]); + parameters.put("CRITICAL_HEIGHT_NUCLEUS", regionHeights[1]); + PottsCellFactory factory = new PottsCellFactory(); factory.popToIDs.put(1, new HashSet<>()); + factory.popToParameters.put(1, parameters); factory.popToRegions.put(1, true); - factory.popToCriticalVolumes.put(1, makeDistributionMock(volume)); - factory.popToCriticalHeights.put(1, makeDistributionMock(height)); - factory.popToCriticalRegionVolumes.put(1, makeRegionDistributionMock(regions, regionVolumes)); - factory.popToCriticalRegionHeights.put(1, makeRegionDistributionMock(regions, regionHeights)); factory.createCells(series); - + assertEquals(init, factory.cells.size()); assertEquals(init, factory.popToIDs.get(1).size()); - + for (int i : factory.popToIDs.get(1)) { PottsCellContainer pottsCellContainer = factory.cells.get(i); assertEquals(volume, pottsCellContainer.criticalVolume, EPSILON); assertEquals(height, pottsCellContainer.criticalHeight, EPSILON); assertEquals(voxels, pottsCellContainer.voxels); - - assertEquals(volume, pottsCellContainer.criticalRegionVolumes.get(Region.DEFAULT), EPSILON); - assertEquals(height, pottsCellContainer.criticalRegionHeights.get(Region.DEFAULT), EPSILON); + + assertEquals( + volume, pottsCellContainer.criticalRegionVolumes.get(Region.DEFAULT), EPSILON); + assertEquals( + height, pottsCellContainer.criticalRegionHeights.get(Region.DEFAULT), EPSILON); assertEquals(voxels, (int) pottsCellContainer.regionVoxels.get(Region.DEFAULT)); - - assertEquals(regionVolumes[1], pottsCellContainer.criticalRegionVolumes.get(Region.NUCLEUS), EPSILON); - assertEquals(regionHeights[1], pottsCellContainer.criticalRegionHeights.get(Region.NUCLEUS), EPSILON); - assertEquals(regionVoxels[1], (int) pottsCellContainer.regionVoxels.get(Region.NUCLEUS)); + + assertEquals( + regionVolumes[1], + pottsCellContainer.criticalRegionVolumes.get(Region.NUCLEUS), + EPSILON); + assertEquals( + regionHeights[1], + pottsCellContainer.criticalRegionHeights.get(Region.NUCLEUS), + EPSILON); + assertEquals( + regionVoxels[1], (int) pottsCellContainer.regionVoxels.get(Region.NUCLEUS)); } } - + @Test public void createCells_multiplePopulationsNoRegions_createsList() { int init1 = randomIntBetween(1, 10); int init2 = randomIntBetween(1, 10); int init3 = randomIntBetween(1, 10); - Series series = createSeries(new int[] { init1, init2, init3 }); - - double[] volumes = new double[] { - randomDoubleBetween(1, 10), - randomDoubleBetween(1, 10), - randomDoubleBetween(1, 10), - }; - double[] heights = new double[] { - randomDoubleBetween(1, 10), - randomDoubleBetween(1, 10), - randomDoubleBetween(1, 10), - }; - int[] voxels = new int[] { - (int) Math.round(volumes[0]), - (int) Math.round(volumes[1]), - (int) Math.round(volumes[2]), - }; - + Series series = createSeries(new int[] {init1, init2, init3}); + + double[] volumes = + new double[] { + randomDoubleBetween(1, 10), + randomDoubleBetween(1, 10), + randomDoubleBetween(1, 10), + }; + double[] heights = + new double[] { + randomDoubleBetween(1, 10), + randomDoubleBetween(1, 10), + randomDoubleBetween(1, 10), + }; + int[] voxels = + new int[] { + (int) Math.round(volumes[0]), + (int) Math.round(volumes[1]), + (int) Math.round(volumes[2]), + }; + + MiniBox parameters1 = new MiniBox(); + parameters1.put("CRITICAL_VOLUME", volumes[0]); + parameters1.put("CRITICAL_HEIGHT", heights[0]); + + MiniBox parameters2 = new MiniBox(); + parameters2.put("CRITICAL_VOLUME", volumes[1]); + parameters2.put("CRITICAL_HEIGHT", heights[1]); + + MiniBox parameters3 = new MiniBox(); + parameters3.put("CRITICAL_VOLUME", volumes[2]); + parameters3.put("CRITICAL_HEIGHT", heights[2]); + PottsCellFactory factory = new PottsCellFactory(); factory.popToIDs.put(1, new HashSet<>()); factory.popToIDs.put(2, new HashSet<>()); factory.popToIDs.put(3, new HashSet<>()); + factory.popToParameters.put(1, parameters1); + factory.popToParameters.put(2, parameters2); + factory.popToParameters.put(3, parameters3); factory.popToRegions.put(1, false); factory.popToRegions.put(2, false); factory.popToRegions.put(3, false); - factory.popToCriticalVolumes.put(1, makeDistributionMock(volumes[0])); - factory.popToCriticalVolumes.put(2, makeDistributionMock(volumes[1])); - factory.popToCriticalVolumes.put(3, makeDistributionMock(volumes[2])); - factory.popToCriticalHeights.put(1, makeDistributionMock(heights[0])); - factory.popToCriticalHeights.put(2, makeDistributionMock(heights[1])); - factory.popToCriticalHeights.put(3, makeDistributionMock(heights[2])); factory.createCells(series); - + assertEquals(init1 + init2 + init3, factory.cells.size()); assertEquals(init1, factory.popToIDs.get(1).size()); assertEquals(init2, factory.popToIDs.get(2).size()); assertEquals(init3, factory.popToIDs.get(3).size()); - + for (int i : factory.popToIDs.get(1)) { PottsCellContainer pottsCellContainer = factory.cells.get(i); assertEquals(volumes[0], pottsCellContainer.criticalVolume, EPSILON); diff --git a/test/arcade/potts/agent/cell/PottsCellStemTest.java b/test/arcade/potts/agent/cell/PottsCellStemTest.java new file mode 100644 index 000000000..383ea7a13 --- /dev/null +++ b/test/arcade/potts/agent/cell/PottsCellStemTest.java @@ -0,0 +1,322 @@ +package arcade.potts.agent.cell; + +import java.util.EnumMap; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import ec.util.MersenneTwisterFast; +import arcade.core.util.GrabBag; +import arcade.core.util.MiniBox; +import arcade.core.util.Parameters; +import arcade.potts.agent.module.PottsModuleApoptosis; +import arcade.potts.agent.module.PottsModuleAutosis; +import arcade.potts.agent.module.PottsModuleNecrosis; +import arcade.potts.agent.module.PottsModuleProliferation; +import arcade.potts.agent.module.PottsModuleQuiescence; +import arcade.potts.env.location.PottsLocation; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; +import static arcade.core.ARCADETestUtilities.*; +import static arcade.potts.util.PottsEnums.Phase; +import static arcade.potts.util.PottsEnums.Region; +import static arcade.potts.util.PottsEnums.State; + +public class PottsCellStemTest { + private static final double EPSILON = 1E-8; + + static PottsLocation locationMock; + + static Parameters parametersMock; + + static int cellID = randomIntBetween(1, 10); + + static int cellParent = randomIntBetween(1, 10); + + static int cellPop = randomIntBetween(1, 10); + + static int cellAge = randomIntBetween(1, 1000); + + static int cellDivisions = randomIntBetween(1, 100); + + static double cellCriticalVolume = randomDoubleBetween(10, 100); + + static double cellCriticalHeight = randomDoubleBetween(10, 100); + + static State cellState = State.UNDEFINED; + + static Phase cellPhase = Phase.UNDEFINED; + + static PottsCellContainer baseContainer = + new PottsCellContainer( + cellID, + cellParent, + cellPop, + cellAge, + cellDivisions, + cellState, + cellPhase, + 0, + cellCriticalVolume, + cellCriticalHeight); + + @BeforeAll + public static void setupMocks() { + locationMock = mock(PottsLocation.class); + parametersMock = spy(new Parameters(new MiniBox(), null, null)); + doReturn(0.0).when(parametersMock).getDouble(any(String.class)); + doReturn(0).when(parametersMock).getInt(any(String.class)); + } + + @Test + public void setState_givenState_assignsValue() { + PottsCellStem cell = new PottsCellStem(baseContainer, locationMock, parametersMock); + + cell.setState(State.QUIESCENT); + assertEquals(State.QUIESCENT, cell.getState()); + + cell.setState(State.PROLIFERATIVE); + assertEquals(State.PROLIFERATIVE, cell.getState()); + + cell.setState(State.APOPTOTIC); + assertEquals(State.APOPTOTIC, cell.getState()); + + cell.setState(State.NECROTIC); + assertEquals(State.NECROTIC, cell.getState()); + + cell.setState(State.AUTOTIC); + assertEquals(State.AUTOTIC, cell.getState()); + } + + @Test + public void setState_givenState_updatesModule() { + PottsCellStem cell = new PottsCellStem(baseContainer, locationMock, parametersMock); + + cell.setState(State.QUIESCENT); + assertTrue(cell.module instanceof PottsModuleQuiescence); + + cell.setState(State.PROLIFERATIVE); + assertTrue(cell.module instanceof PottsModuleProliferation); + + cell.setState(State.APOPTOTIC); + assertTrue(cell.module instanceof PottsModuleApoptosis); + + cell.setState(State.NECROTIC); + assertTrue(cell.module instanceof PottsModuleNecrosis); + + cell.setState(State.AUTOTIC); + assertTrue(cell.module instanceof PottsModuleAutosis); + } + + @Test + public void setState_invalidState_setsNull() { + PottsCellStem cell = new PottsCellStem(baseContainer, locationMock, parametersMock); + cell.setState(State.UNDEFINED); + assertNull(cell.getModule()); + } + + @Test + public void make_noRegionsNoLinks_createsContainer() { + double criticalVolume = randomDoubleBetween(10, 100); + double criticalHeight = randomDoubleBetween(10, 100); + State state1 = State.QUIESCENT; + State state2 = State.PROLIFERATIVE; + + PottsCellContainer cellContainer = + new PottsCellContainer( + cellID, + cellParent, + cellPop, + cellAge, + cellDivisions, + state1, + cellPhase, + 0, + criticalVolume, + criticalHeight); + PottsCellStem cell = new PottsCellStem(cellContainer, locationMock, parametersMock); + + PottsCellContainer container = cell.make(cellID + 1, state2, null); + + assertEquals(cellID + 1, container.id); + assertEquals(cellID, container.parent); + assertEquals(cellPop, container.pop); + assertEquals(cellAge, container.age); + assertEquals(cellDivisions + 1, cell.getDivisions()); + assertEquals(cellDivisions + 1, container.divisions); + assertEquals(state2, container.state); + assertNull(container.phase); + assertEquals(0, container.voxels); + assertNull(container.regionVoxels); + assertEquals(criticalVolume, container.criticalVolume, EPSILON); + assertEquals(criticalHeight, container.criticalHeight, EPSILON); + assertNull(container.criticalRegionVolumes); + assertNull(container.criticalRegionHeights); + } + + @Test + public void make_noRegionsHasLinks_createsContainer() { + double criticalVolume = randomDoubleBetween(10, 100); + double criticalHeight = randomDoubleBetween(10, 100); + State state1 = State.QUIESCENT; + State state2 = State.PROLIFERATIVE; + + int newPop = cellPop + randomIntBetween(1, 10); + GrabBag links = new GrabBag(); + links.add(cellPop, 1); + links.add(newPop, 1); + MersenneTwisterFast random = mock(MersenneTwisterFast.class); + when(random.nextDouble()).thenReturn(0.5); + + PottsCellContainer cellContainer = + new PottsCellContainer( + cellID, + cellParent, + cellPop, + cellAge, + cellDivisions, + state1, + cellPhase, + 0, + criticalVolume, + criticalHeight); + PottsCellStem cell = new PottsCellStem(cellContainer, locationMock, parametersMock, links); + + PottsCellContainer container = cell.make(cellID + 1, state2, random); + + assertEquals(cellID + 1, container.id); + assertEquals(cellID, container.parent); + assertEquals(newPop, container.pop); + assertEquals(cellAge, container.age); + assertEquals(cellDivisions + 1, cell.getDivisions()); + assertEquals(cellDivisions + 1, container.divisions); + assertEquals(state2, container.state); + assertNull(container.phase); + assertEquals(0, container.voxels); + assertNull(container.regionVoxels); + assertEquals(criticalVolume, container.criticalVolume, EPSILON); + assertEquals(criticalHeight, container.criticalHeight, EPSILON); + assertNull(container.criticalRegionVolumes); + assertNull(container.criticalRegionHeights); + } + + @Test + public void make_hasRegionsNoLinks_createsContainer() { + double criticalVolume = randomDoubleBetween(10, 100); + double criticalHeight = randomDoubleBetween(10, 100); + State state1 = State.QUIESCENT; + State state2 = State.PROLIFERATIVE; + EnumMap criticalVolumesRegion = new EnumMap<>(Region.class); + EnumMap criticalHeightsRegion = new EnumMap<>(Region.class); + + for (Region region : Region.values()) { + criticalVolumesRegion.put(region, randomDoubleBetween(10, 100)); + criticalHeightsRegion.put(region, randomDoubleBetween(10, 100)); + } + + PottsCellContainer cellContainer = + new PottsCellContainer( + cellID, + cellParent, + cellPop, + cellAge, + cellDivisions, + state1, + cellPhase, + 0, + new EnumMap<>(Region.class), + criticalVolume, + criticalHeight, + criticalVolumesRegion, + criticalHeightsRegion); + PottsCellStem cell = new PottsCellStem(cellContainer, locationMock, parametersMock); + + PottsCellContainer container = cell.make(cellID + 1, state2, null); + + assertEquals(cellID + 1, container.id); + assertEquals(cellID, container.parent); + assertEquals(cellPop, container.pop); + assertEquals(cellAge, container.age); + assertEquals(cellDivisions + 1, cell.getDivisions()); + assertEquals(cellDivisions + 1, container.divisions); + assertEquals(state2, container.state); + assertNull(container.phase); + assertEquals(0, container.voxels); + assertNotNull(container.regionVoxels); + assertEquals(criticalVolume, container.criticalVolume, EPSILON); + assertEquals(criticalHeight, container.criticalHeight, EPSILON); + for (Region region : Region.values()) { + assertEquals( + criticalVolumesRegion.get(region), + container.criticalRegionVolumes.get(region), + EPSILON); + assertEquals( + criticalHeightsRegion.get(region), + container.criticalRegionHeights.get(region), + EPSILON); + } + } + + @Test + public void make_hasRegionsHasLinks_createsContainer() { + double criticalVolume = randomDoubleBetween(10, 100); + double criticalHeight = randomDoubleBetween(10, 100); + State state1 = State.QUIESCENT; + State state2 = State.PROLIFERATIVE; + EnumMap criticalVolumesRegion = new EnumMap<>(Region.class); + EnumMap criticalHeightsRegion = new EnumMap<>(Region.class); + + for (Region region : Region.values()) { + criticalVolumesRegion.put(region, randomDoubleBetween(10, 100)); + criticalHeightsRegion.put(region, randomDoubleBetween(10, 100)); + } + + int newPop = cellPop + randomIntBetween(1, 10); + GrabBag links = new GrabBag(); + links.add(cellPop, 1); + links.add(newPop, 1); + MersenneTwisterFast random = mock(MersenneTwisterFast.class); + when(random.nextDouble()).thenReturn(0.5); + + PottsCellContainer cellContainer = + new PottsCellContainer( + cellID, + cellParent, + cellPop, + cellAge, + cellDivisions, + state1, + cellPhase, + 0, + new EnumMap<>(Region.class), + criticalVolume, + criticalHeight, + criticalVolumesRegion, + criticalHeightsRegion); + + PottsCellStem cell = new PottsCellStem(cellContainer, locationMock, parametersMock, links); + + PottsCellContainer container = cell.make(cellID + 1, state2, random); + + assertEquals(cellID + 1, container.id); + assertEquals(cellID, container.parent); + assertEquals(newPop, container.pop); + assertEquals(cellAge, container.age); + assertEquals(cellDivisions + 1, cell.getDivisions()); + assertEquals(cellDivisions + 1, container.divisions); + assertEquals(state2, container.state); + assertNull(container.phase); + assertEquals(0, container.voxels); + assertNotNull(container.regionVoxels); + assertEquals(criticalVolume, container.criticalVolume, EPSILON); + assertEquals(criticalHeight, container.criticalHeight, EPSILON); + for (Region region : Region.values()) { + assertEquals( + criticalVolumesRegion.get(region), + container.criticalRegionVolumes.get(region), + EPSILON); + assertEquals( + criticalHeightsRegion.get(region), + container.criticalRegionHeights.get(region), + EPSILON); + } + } +} diff --git a/test/arcade/potts/agent/cell/PottsCellTest.java b/test/arcade/potts/agent/cell/PottsCellTest.java index 9a528834a..600155a1a 100644 --- a/test/arcade/potts/agent/cell/PottsCellTest.java +++ b/test/arcade/potts/agent/cell/PottsCellTest.java @@ -1,28 +1,25 @@ package arcade.potts.agent.cell; +import java.util.Arrays; import java.util.EnumMap; import java.util.EnumSet; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import org.mockito.stubbing.Answer; import sim.engine.Schedule; import sim.engine.Stoppable; import ec.util.MersenneTwisterFast; -import arcade.core.agent.module.*; +import arcade.core.agent.cell.CellState; +import arcade.core.agent.module.Module; import arcade.core.env.location.*; import arcade.core.util.MiniBox; +import arcade.core.util.Parameters; import arcade.potts.agent.module.PottsModule; -import arcade.potts.agent.module.PottsModuleApoptosis; -import arcade.potts.agent.module.PottsModuleAutosis; -import arcade.potts.agent.module.PottsModuleNecrosis; -import arcade.potts.agent.module.PottsModuleProliferation; -import arcade.potts.agent.module.PottsModuleQuiescence; import arcade.potts.env.location.PottsLocation; import arcade.potts.sim.PottsSimulation; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.core.ARCADETestUtilities.*; -import static arcade.potts.agent.cell.PottsCellFactoryTest.*; import static arcade.potts.util.PottsEnums.Domain; import static arcade.potts.util.PottsEnums.Ordering; import static arcade.potts.util.PottsEnums.Phase; @@ -31,93 +28,130 @@ public class PottsCellTest { private static final double EPSILON = 1E-8; - + private static final double OFFSET = 0.01; - - private static final MersenneTwisterFast RANDOM = new MersenneTwisterFast(randomSeed()); - + + private static final MersenneTwisterFast RANDOM = new MersenneTwisterFast(); + static EnumMap criticalVolumesRegionMock; - + static EnumMap criticalHeightsRegionMock; - + static PottsLocation locationMock; - + + static Parameters parametersMock; + static int locationVolume; - + static int locationHeight; - + static int locationSurface; - + static EnumMap locationRegionVolumes; - + static EnumMap locationRegionHeights; - + static EnumMap locationRegionSurfaces; - + static int cellID = randomIntBetween(1, 10); - + static int cellParent = randomIntBetween(1, 10); - + static int cellPop = randomIntBetween(1, 10); - + static int cellAge = randomIntBetween(1, 1000); - + static int cellDivisions = randomIntBetween(1, 100); - - static double cellCriticalVolume = randomDoubleBetween(10, 100); - - static double cellCriticalHeight = randomDoubleBetween(10, 100); - + + static double cellCriticalVolume = randomDoubleBetween(30, 40); + + static double cellCriticalHeight = randomDoubleBetween(30, 40); + static State cellState = State.QUIESCENT; - - static PottsCell cellDefault; - - static PottsCell cellWithRegions; - - static PottsCell cellWithoutRegions; - + + static Phase cellPhase = Phase.UNDEFINED; + static EnumSet regionList; - - static MiniBox parametersMock; - - @BeforeClass + + static PottsCell cellWithoutRegions; + + static PottsCell cellWithRegions; + + static PottsCellContainer containerWithoutRegions; + + static PottsCellContainer containerWithRegions; + + static class PottsCellMock extends PottsCell { + PottsCellMock(PottsCellContainer container, Location location, Parameters parameters) { + super(container, location, parameters, null); + } + + @Override + public PottsCellContainer make(int newID, CellState newState, MersenneTwisterFast random) { + return new PottsCellContainer( + newID, + id, + pop, + age, + divisions, + newState, + null, + 0, + (hasRegions ? new EnumMap<>(Region.class) : null), + criticalVolume, + criticalHeight, + criticalRegionVolumes, + criticalRegionHeights); + } + + @Override + void setStateModule(CellState newState) { + module = mock(PottsModule.class); + } + } + + @BeforeAll public static void setupMocks() { - parametersMock = mock(MiniBox.class); + parametersMock = mock(Parameters.class); locationMock = mock(PottsLocation.class); - + regionList = EnumSet.of(Region.DEFAULT, Region.NUCLEUS); when(locationMock.getRegions()).thenReturn(regionList); - - Answer answer = invocation -> { - Double value1 = invocation.getArgument(0); - Double value2 = invocation.getArgument(1); - return value1 * value2; - }; - when(((PottsLocation) locationMock).convertSurface(anyDouble(), anyDouble())).thenAnswer(answer); - + + Answer answer = + invocation -> { + Double value1 = invocation.getArgument(0); + Double value2 = invocation.getArgument(1); + return value1 * value2; + }; + when((locationMock).convertSurface(anyDouble(), anyDouble())).thenAnswer(answer); + locationRegionVolumes = new EnumMap<>(Region.class); locationRegionHeights = new EnumMap<>(Region.class); locationRegionSurfaces = new EnumMap<>(Region.class); - + // Random volumes and surfaces for regions. for (Region region : regionList) { locationRegionVolumes.put(region, randomIntBetween(10, 20)); locationRegionHeights.put(region, randomIntBetween(10, 20)); locationRegionSurfaces.put(region, randomIntBetween(10, 20)); - - when(locationMock.getVolume(region)).thenReturn((double) locationRegionVolumes.get(region)); - when(locationMock.getHeight(region)).thenReturn((double) locationRegionHeights.get(region)); - when(locationMock.getSurface(region)).thenReturn((double) locationRegionSurfaces.get(region)); - + + when(locationMock.getVolume(region)) + .thenReturn((double) locationRegionVolumes.get(region)); + when(locationMock.getHeight(region)) + .thenReturn((double) locationRegionHeights.get(region)); + when(locationMock.getSurface(region)) + .thenReturn((double) locationRegionSurfaces.get(region)); + locationVolume += locationRegionVolumes.get(region); locationHeight += locationRegionHeights.get(region); locationSurface += locationRegionSurfaces.get(region); } - + when(locationMock.getVolume()).thenReturn((double) locationVolume); when(locationMock.getHeight()).thenReturn((double) locationHeight); when(locationMock.getSurface()).thenReturn((double) locationSurface); - + // Region criticals. criticalVolumesRegionMock = new EnumMap<>(Region.class); criticalHeightsRegionMock = new EnumMap<>(Region.class); @@ -125,601 +159,578 @@ public static void setupMocks() { criticalVolumesRegionMock.put(region, (double) locationRegionVolumes.get(region)); criticalHeightsRegionMock.put(region, (double) locationRegionHeights.get(region)); } - - cellDefault = new PottsCell(cellID, cellParent, cellPop, cellState, cellAge, cellDivisions, - locationMock, false, parametersMock, cellCriticalVolume, cellCriticalHeight, - null, null); - cellWithRegions = new PottsCell(cellID, cellParent, 1, cellState, cellAge, cellDivisions, - locationMock, true, parametersMock, cellCriticalVolume, cellCriticalHeight, - criticalVolumesRegionMock, criticalHeightsRegionMock); - cellWithoutRegions = new PottsCell(cellID, cellParent, 1, cellState, cellAge, cellDivisions, - locationMock, false, parametersMock, cellCriticalVolume, cellCriticalHeight, - criticalVolumesRegionMock, criticalHeightsRegionMock); - } - - static PottsCell make(boolean regions) { - return make(locationMock, regions); - } - - static PottsCell make(Location location, boolean regions) { - if (!regions) { - return new PottsCell(cellID, cellParent, cellPop, cellState, cellAge, cellDivisions, - location, false, parametersMock, cellCriticalVolume, cellCriticalHeight, - null, null); - } else { - return new PottsCell(cellID, cellParent, cellPop, cellState, cellAge, cellDivisions, - location, true, parametersMock, cellCriticalVolume, cellCriticalHeight, - criticalVolumesRegionMock, criticalHeightsRegionMock); - } + + containerWithRegions = + new PottsCellContainer( + cellID, + cellParent, + cellPop, + cellAge, + cellDivisions, + cellState, + cellPhase, + 0, + new EnumMap<>(Region.class), + cellCriticalVolume, + cellCriticalHeight, + criticalVolumesRegionMock, + criticalHeightsRegionMock); + + containerWithoutRegions = + new PottsCellContainer( + cellID, + cellParent, + cellPop, + cellAge, + cellDivisions, + cellState, + cellPhase, + 0, + cellCriticalVolume, + cellCriticalHeight); + + cellWithoutRegions = + new PottsCellMock(containerWithoutRegions, locationMock, parametersMock); + cellWithRegions = new PottsCellMock(containerWithRegions, locationMock, parametersMock); } - + @Test public void getID_defaultConstructor_returnsValue() { - assertEquals(cellID, cellDefault.getID()); + assertEquals(cellID, cellWithoutRegions.getID()); } - + @Test public void getParent_defaultConstructor_returnsValue() { - assertEquals(cellParent, cellDefault.getParent()); + assertEquals(cellParent, cellWithoutRegions.getParent()); } - + @Test public void getParent_valueAssigned_returnsValue() { int parent = randomIntBetween(0, 100); - PottsCell cell = new PottsCell(cellID, parent, cellPop, cellState, cellAge, cellDivisions, - locationMock, false, parametersMock, cellCriticalVolume, cellCriticalHeight, - null, null); + PottsCellContainer container = + new PottsCellContainer( + cellID, + parent, + cellPop, + cellAge, + cellDivisions, + cellState, + null, + 0, + null, + cellCriticalVolume, + cellCriticalHeight, + null, + null); + PottsCell cell = new PottsCellMock(container, locationMock, parametersMock); assertEquals(parent, cell.getParent()); } - + @Test public void getPop_defaultConstructor_returnsValue() { - assertEquals(cellPop, cellDefault.getPop()); + assertEquals(cellPop, cellWithoutRegions.getPop()); } - + @Test public void getPop_valueAssigned_returnsValue() { int pop = randomIntBetween(0, 100); - PottsCell cell = new PottsCell(cellID, cellParent, pop, cellState, cellAge, cellDivisions, - locationMock, false, parametersMock, cellCriticalVolume, cellCriticalHeight, - null, null); + PottsCellContainer container = + new PottsCellContainer( + cellID, + cellParent, + pop, + cellAge, + cellDivisions, + cellState, + null, + 0, + null, + cellCriticalVolume, + cellCriticalHeight, + null, + null); + PottsCell cell = new PottsCellMock(container, locationMock, parametersMock); assertEquals(pop, cell.getPop()); } - + @Test public void getState_defaultConstructor_returnsValue() { - assertEquals(cellState, cellDefault.getState()); + assertEquals(cellState, cellWithoutRegions.getState()); } - + @Test public void getState_valueAssigned_returnsValue() { State state = State.random(RANDOM); - PottsCell cell = new PottsCell(cellID, cellParent, cellPop, state, cellAge, cellDivisions, - locationMock, false, parametersMock, cellCriticalVolume, cellCriticalHeight, - null, null); + PottsCellContainer container = + new PottsCellContainer( + cellID, + cellParent, + cellPop, + cellAge, + cellDivisions, + state, + null, + 0, + null, + cellCriticalVolume, + cellCriticalHeight, + null, + null); + PottsCell cell = new PottsCellMock(container, locationMock, parametersMock); assertEquals(state, cell.getState()); } - + @Test public void getAge_defaultConstructor_returnsValue() { - assertEquals(cellAge, cellDefault.getAge()); + assertEquals(cellAge, cellWithoutRegions.getAge()); } - + @Test public void getAge_valueAssigned_returnsValue() { int age = randomIntBetween(0, 100); - PottsCell cell = new PottsCell(cellID, cellParent, cellPop, cellState, age, cellDivisions, - locationMock, false, parametersMock, cellCriticalVolume, cellCriticalHeight, - null, null); + PottsCellContainer container = + new PottsCellContainer( + cellID, + cellParent, + cellPop, + age, + cellDivisions, + cellState, + null, + 0, + null, + cellCriticalVolume, + cellCriticalHeight, + null, + null); + PottsCell cell = new PottsCellMock(container, locationMock, parametersMock); assertEquals(age, cell.getAge()); } - + @Test public void getDivisions_defaultConstructor_returnsValue() { - assertEquals(cellDivisions, cellDefault.getDivisions()); + assertEquals(cellDivisions, cellWithoutRegions.getDivisions()); } - + @Test public void getDivisions_valueAssigned_returnsValue() { int divisions = randomIntBetween(0, 100); - PottsCell cell = new PottsCell(cellID, cellParent, cellPop, cellState, cellAge, divisions, - locationMock, false, parametersMock, cellCriticalVolume, cellCriticalHeight, - null, null); + PottsCellContainer container = + new PottsCellContainer( + cellID, + cellParent, + cellPop, + cellAge, + divisions, + cellState, + null, + 0, + null, + cellCriticalVolume, + cellCriticalHeight, + null, + null); + PottsCell cell = new PottsCellMock(container, locationMock, parametersMock); assertEquals(divisions, cell.getDivisions()); } - + @Test public void hasRegions_withoutRegions_returnsFalse() { assertFalse(cellWithoutRegions.hasRegions()); } - + @Test public void hasRegions_withRegions_returnsTrue() { assertTrue(cellWithRegions.hasRegions()); } - + @Test public void getLocation_defaultConstructor_returnsObject() { - assertSame(locationMock, cellDefault.getLocation()); + assertSame(locationMock, cellWithoutRegions.getLocation()); } - + @Test public void getModule_defaultConstructor_returnsObject() { - assertTrue(cellDefault.getModule() instanceof PottsModule); + assertTrue(cellWithoutRegions.getModule() instanceof PottsModule); } - + @Test public void getProcess_defaultConstructor_returnsNull() { - assertNull(cellDefault.getProcess(Domain.UNDEFINED)); + assertNull(cellWithoutRegions.getProcess(Domain.UNDEFINED)); } - + @Test public void getParameters_defaultConstructor_returnsObject() { - assertSame(parametersMock, cellDefault.getParameters()); + assertSame(parametersMock, cellWithoutRegions.getParameters()); } - + @Test public void getVolume_defaultConstructor_returnsValue() { - assertEquals(locationVolume, (int) cellDefault.getVolume()); + assertEquals(locationVolume, (int) cellWithoutRegions.getVolume()); } - + @Test public void getVolume_validRegions_returnsValue() { for (Region region : regionList) { - assertEquals((int) locationRegionVolumes.get(region), (int) cellWithRegions.getVolume(region)); + assertEquals( + (int) locationRegionVolumes.get(region), + (int) cellWithRegions.getVolume(region)); } } - + @Test public void getVolume_nullRegion_returnsZero() { assertEquals(0, (int) cellWithRegions.getVolume(null)); } - + @Test public void getVolume_noRegions_returnsZero() { for (Region region : regionList) { assertEquals(0, (int) cellWithoutRegions.getVolume(region)); } } - + @Test public void getHeight_defaultConstructor_returnsValue() { - assertEquals(locationHeight, (int) cellDefault.getHeight()); + assertEquals(locationHeight, (int) cellWithoutRegions.getHeight()); } - + @Test public void getHeight_validRegions_returnsValue() { for (Region region : regionList) { - assertEquals((int) locationRegionHeights.get(region), (int) cellWithRegions.getHeight(region)); + assertEquals( + (int) locationRegionHeights.get(region), + (int) cellWithRegions.getHeight(region)); } } - + @Test public void getHeight_nullRegion_returnsZero() { assertEquals(0, (int) cellWithRegions.getHeight(null)); } - + @Test public void getHeight_noRegions_returnsZero() { for (Region region : regionList) { assertEquals(0, (int) cellWithoutRegions.getHeight(region)); } } - + @Test public void getSurface_defaultConstructor_returnsValue() { - assertEquals(locationSurface, (int) cellDefault.getSurface()); + assertEquals(locationSurface, (int) cellWithoutRegions.getSurface()); } - + @Test public void getSurface_validRegions_returnsValue() { for (Region region : regionList) { - assertEquals((int) locationRegionSurfaces.get(region), (int) cellWithRegions.getSurface(region)); + assertEquals( + (int) locationRegionSurfaces.get(region), + (int) cellWithRegions.getSurface(region)); } } - + @Test public void getSurface_nullRegion_returnsZero() { assertEquals(0, (int) cellWithRegions.getSurface(null)); } - + @Test public void getSurface_noRegions_returnsZero() { for (Region region : regionList) { assertEquals(0, (int) cellWithoutRegions.getSurface(region)); } } - + @Test public void getTargetVolume_beforeInitialize_returnsZero() { - assertEquals(0, cellDefault.getTargetVolume(), EPSILON); + assertEquals(0, cellWithoutRegions.getTargetVolume(), EPSILON); } - + @Test public void getTargetVolume_beforeInitializeValidRegion_returnsZero() { for (Region region : regionList) { assertEquals(0, cellWithRegions.getTargetVolume(region), EPSILON); } } - + @Test public void getTargetVolume_beforeInitializeInvalidRegion_returnsZero() { assertEquals(0, cellWithRegions.getTargetVolume(null), EPSILON); } - + @Test public void getTargetVolume_beforeInitializeNoRegions_returnsZero() { for (Region region : regionList) { assertEquals(0, cellWithoutRegions.getTargetVolume(region), EPSILON); } } - + @Test public void getTargetVolume_afterInitialize_returnsValue() { - PottsCell cell = make(false); + PottsCell cell = new PottsCellMock(containerWithoutRegions, locationMock, parametersMock); cell.initialize(null, null); assertEquals(locationVolume, cell.getTargetVolume(), EPSILON); } - + @Test public void getTargetVolume_afterInitializeValidRegion_returnsValue() { - PottsCell cell = make(true); + PottsCell cell = new PottsCellMock(containerWithRegions, locationMock, parametersMock); cell.initialize(null, null); for (Region region : regionList) { assertEquals(locationRegionVolumes.get(region), cell.getTargetVolume(region), EPSILON); } } - + @Test public void getTargetVolume_afterInitializeInvalidRegion_returnsZero() { - PottsCell cell = make(true); + PottsCell cell = new PottsCellMock(containerWithRegions, locationMock, parametersMock); cell.initialize(null, null); assertEquals(0, cell.getTargetVolume(null), EPSILON); assertEquals(0, cell.getTargetVolume(Region.UNDEFINED), EPSILON); } - + @Test public void getTargetVolume_afterInitializeNoRegion_returnsZero() { - PottsCell cell = make(false); + PottsCell cell = new PottsCellMock(containerWithoutRegions, locationMock, parametersMock); cell.initialize(null, null); for (Region region : regionList) { assertEquals(0, cell.getTargetVolume(region), EPSILON); } } - + @Test public void getTargetSurface_beforeInitialize_returnsZero() { - assertEquals(0, cellDefault.getTargetSurface(), EPSILON); + assertEquals(0, cellWithoutRegions.getTargetSurface(), EPSILON); } - + @Test public void getTargetSurface_beforeInitializeValidRegion_returnsZero() { for (Region region : regionList) { assertEquals(0, cellWithRegions.getTargetSurface(region), EPSILON); } } - + @Test public void getTargetSurface_beforeInitializeInvalidRegion_returnsZero() { assertEquals(0, cellWithRegions.getTargetSurface(null), EPSILON); } - + @Test public void getTargetSurface_beforeInitializeNoRegions_returnsZero() { for (Region region : regionList) { assertEquals(0, cellWithoutRegions.getTargetSurface(region), EPSILON); } } - + @Test public void getTargetSurface_afterInitialize_returnsValue() { - PottsCell cell = make(false); + PottsCell cell = new PottsCellMock(containerWithoutRegions, locationMock, parametersMock); cell.initialize(null, null); assertEquals(locationSurface, cell.getTargetSurface(), EPSILON); } - + @Test public void getTargetSurface_afterInitializeValidRegion_returnsValue() { - PottsCell cell = make(true); + PottsCell cell = new PottsCellMock(containerWithRegions, locationMock, parametersMock); cell.initialize(null, null); for (Region region : regionList) { - assertEquals(locationRegionSurfaces.get(region), cell.getTargetSurface(region), EPSILON); + assertEquals( + locationRegionSurfaces.get(region), cell.getTargetSurface(region), EPSILON); } } - + @Test public void getTargetSurface_afterInitializeInvalidRegion_returnsZero() { - PottsCell cell = make(true); + PottsCell cell = new PottsCellMock(containerWithRegions, locationMock, parametersMock); cell.initialize(null, null); assertEquals(0, cell.getTargetSurface(null), EPSILON); assertEquals(0, cell.getTargetSurface(Region.UNDEFINED), EPSILON); } - + @Test public void getTargetSurface_afterInitializeNoRegion_returnsZero() { - PottsCell cell = make(false); + PottsCell cell = new PottsCellMock(containerWithoutRegions, locationMock, parametersMock); cell.initialize(null, null); for (Region region : regionList) { assertEquals(0, cell.getTargetSurface(region), EPSILON); } } - + @Test public void getCriticalVolume_beforeInitialize_returnsValue() { - assertEquals(cellCriticalVolume, cellDefault.getCriticalVolume(), EPSILON); + assertEquals(cellCriticalVolume, cellWithoutRegions.getCriticalVolume(), EPSILON); } - + @Test public void getCriticalVolume_beforeInitializeValidRegion_returnsValue() { for (Region region : regionList) { - assertEquals(locationRegionVolumes.get(region), cellWithRegions.getCriticalVolume(region), EPSILON); + assertEquals( + locationRegionVolumes.get(region), + cellWithRegions.getCriticalVolume(region), + EPSILON); } } - + @Test public void getCriticalVolume_beforeInitializeInvalidRegion_returnsZero() { assertEquals(0, cellWithRegions.getCriticalVolume(null), EPSILON); assertEquals(0, cellWithRegions.getCriticalVolume(Region.UNDEFINED), EPSILON); } - + @Test public void getCriticalVolume_beforeInitializeNoRegions_returnsZero() { for (Region region : regionList) { assertEquals(0, cellWithoutRegions.getCriticalVolume(region), EPSILON); } } - + @Test public void getCriticalVolume_afterInitialize_returnsValue() { - PottsCell cell = make(false); + PottsCell cell = new PottsCellMock(containerWithoutRegions, locationMock, parametersMock); cell.initialize(null, null); assertEquals(cellCriticalVolume, cell.getCriticalVolume(), EPSILON); } - + @Test public void getCriticalVolume_afterInitializeValidRegion_returnsValue() { - PottsCell cell = make(true); + PottsCell cell = new PottsCellMock(containerWithRegions, locationMock, parametersMock); cell.initialize(null, null); for (Region region : regionList) { - assertEquals(locationRegionVolumes.get(region), cell.getCriticalVolume(region), EPSILON); + assertEquals( + locationRegionVolumes.get(region), cell.getCriticalVolume(region), EPSILON); } } - + @Test public void getCriticalVolume_afterInitializeInvalidRegion_returnsZero() { - PottsCell cell = make(true); + PottsCell cell = new PottsCellMock(containerWithRegions, locationMock, parametersMock); cell.initialize(null, null); assertEquals(0, cell.getCriticalVolume(null), EPSILON); } - + @Test public void getCriticalVolume_afterInitializeNoRegion_returnsZero() { - PottsCell cell = make(false); + PottsCell cell = new PottsCellMock(containerWithoutRegions, locationMock, parametersMock); cell.initialize(null, null); for (Region region : regionList) { assertEquals(0, cell.getCriticalVolume(region), EPSILON); } } - + @Test public void getCriticalHeight_beforeInitialize_returnsValue() { - assertEquals(cellCriticalHeight, cellDefault.getCriticalHeight(), EPSILON); + assertEquals(cellCriticalHeight, cellWithoutRegions.getCriticalHeight(), EPSILON); } - + @Test public void getCriticalHeight_beforeInitializeValidRegion_returnsValue() { for (Region region : regionList) { - assertEquals(locationRegionHeights.get(region), cellWithRegions.getCriticalHeight(region), EPSILON); + assertEquals( + locationRegionHeights.get(region), + cellWithRegions.getCriticalHeight(region), + EPSILON); } } - + @Test public void getCriticalHeight_beforeInitializeInvalidRegion_returnsZero() { assertEquals(0, cellWithRegions.getCriticalHeight(null), EPSILON); assertEquals(0, cellWithRegions.getCriticalHeight(Region.UNDEFINED), EPSILON); } - + @Test public void getCriticalHeight_beforeInitializeNoRegions_returnsZero() { for (Region region : regionList) { assertEquals(0, cellWithoutRegions.getCriticalHeight(region), EPSILON); } } - + @Test public void getCriticalHeight_afterInitialize_returnsValue() { - PottsCell cell = make(false); + PottsCell cell = new PottsCellMock(containerWithoutRegions, locationMock, parametersMock); cell.initialize(null, null); assertEquals(cellCriticalHeight, cell.getCriticalHeight(), EPSILON); } - + @Test public void getCriticalHeight_afterInitializeValidRegion_returnsValue() { - PottsCell cell = make(true); + PottsCell cell = new PottsCellMock(containerWithRegions, locationMock, parametersMock); cell.initialize(null, null); for (Region region : regionList) { - assertEquals(locationRegionHeights.get(region), cell.getCriticalHeight(region), EPSILON); + assertEquals( + locationRegionHeights.get(region), cell.getCriticalHeight(region), EPSILON); } } - + @Test public void getCriticalHeight_afterInitializeInvalidRegion_returnsZero() { - PottsCell cell = make(true); + PottsCell cell = new PottsCellMock(containerWithRegions, locationMock, parametersMock); cell.initialize(null, null); assertEquals(0, cell.getCriticalHeight(null), EPSILON); } - + @Test public void getCriticalHeight_afterInitializeNoRegion_returnsZero() { - PottsCell cell = make(false); + PottsCell cell = new PottsCellMock(containerWithoutRegions, locationMock, parametersMock); cell.initialize(null, null); for (Region region : regionList) { assertEquals(0, cell.getCriticalHeight(region), EPSILON); } } - - @Test - public void setState_givenState_assignsValue() { - PottsCell cell = make(false); - - cell.setState(State.QUIESCENT); - assertEquals(State.QUIESCENT, cell.getState()); - - cell.setState(State.PROLIFERATIVE); - assertEquals(State.PROLIFERATIVE, cell.getState()); - - cell.setState(State.APOPTOTIC); - assertEquals(State.APOPTOTIC, cell.getState()); - - cell.setState(State.NECROTIC); - assertEquals(State.NECROTIC, cell.getState()); - - cell.setState(State.AUTOTIC); - assertEquals(State.AUTOTIC, cell.getState()); - } - - @Test - public void setState_givenState_updatesModule() { - PottsCell cell = make(false); - - cell.setState(State.QUIESCENT); - assertTrue(cell.module instanceof PottsModuleQuiescence); - - cell.setState(State.PROLIFERATIVE); - assertTrue(cell.module instanceof PottsModuleProliferation); - - cell.setState(State.APOPTOTIC); - assertTrue(cell.module instanceof PottsModuleApoptosis); - - cell.setState(State.NECROTIC); - assertTrue(cell.module instanceof PottsModuleNecrosis); - - cell.setState(State.AUTOTIC); - assertTrue(cell.module instanceof PottsModuleAutosis); - } - - @Test - public void setState_invalidState_setsNull() { - PottsCell cell = make(false); - cell.setState(State.UNDEFINED); - assertNull(cell.getModule()); - } - + @Test public void stop_called_callsMethod() { - PottsCell cell = make(false); + PottsCell cell = new PottsCellMock(containerWithoutRegions, locationMock, parametersMock); cell.stopper = mock(Stoppable.class); cell.stop(); verify(cell.stopper).stop(); } - - @Test - public void make_noRegions_setsFields() { - double criticalVolume = randomDoubleBetween(10, 100); - double criticalHeight = randomDoubleBetween(10, 100); - MiniBox parameters = mock(MiniBox.class); - Location location1 = mock(PottsLocation.class); - Location location2 = mock(PottsLocation.class); - - PottsCell cell1 = new PottsCell(cellID, cellParent, cellPop, cellState, cellAge, cellDivisions, - location1, false, parameters, criticalVolume, criticalHeight, - null, null); - PottsCell cell2 = cell1.make(cellID + 1, State.QUIESCENT, location2, null); - - assertEquals(cellID + 1, cell2.id); - assertEquals(cellID, cell2.parent); - assertEquals(cellPop, cell2.pop); - assertEquals(cellAge, cell2.getAge()); - assertEquals(cellDivisions + 1, cell1.getDivisions()); - assertEquals(cellDivisions + 1, cell2.getDivisions()); - assertFalse(cell2.hasRegions()); - assertEquals(location2, cell2.getLocation()); - assertEquals(cell2.parameters, parameters); - assertEquals(criticalVolume, cell2.getCriticalVolume(), EPSILON); - assertEquals(criticalHeight, cell2.getCriticalHeight(), EPSILON); - } - - @Test - public void make_hasRegions_setsFields() { - double criticalVolume = randomDoubleBetween(10, 100); - double criticalHeight = randomDoubleBetween(10, 100); - MiniBox parameters = mock(MiniBox.class); - PottsLocation location1 = mock(PottsLocation.class); - PottsLocation location2 = mock(PottsLocation.class); - EnumMap criticalVolumesRegion = new EnumMap<>(Region.class); - EnumMap criticalHeightsRegion = new EnumMap<>(Region.class); - - for (Region region : Region.values()) { - criticalVolumesRegion.put(region, randomDoubleBetween(10, 100)); - criticalHeightsRegion.put(region, randomDoubleBetween(10, 100)); - } - - EnumSet allRegions = EnumSet.allOf(Region.class); - doReturn(allRegions).when(location1).getRegions(); - doReturn(allRegions).when(location2).getRegions(); - - PottsCell cell1 = new PottsCell(cellID, cellParent, cellPop, cellState, cellAge, cellDivisions, - location1, true, parameters, criticalVolume, criticalHeight, - criticalVolumesRegion, criticalHeightsRegion); - PottsCell cell2 = cell1.make(cellID + 1, State.QUIESCENT, location2, null); - - assertEquals(cellID + 1, cell2.id); - assertEquals(cellID, cell2.parent); - assertEquals(cellPop, cell2.pop); - assertEquals(cellAge, cell2.getAge()); - assertEquals(cellDivisions + 1, cell1.getDivisions()); - assertEquals(cellDivisions + 1, cell2.getDivisions()); - assertTrue(cell2.hasRegions()); - assertEquals(location2, cell2.getLocation()); - assertEquals(cell2.parameters, parameters); - assertEquals(criticalVolume, cell2.getCriticalVolume(), EPSILON); - assertEquals(criticalHeight, cell2.getCriticalHeight(), EPSILON); - for (Region region : Region.values()) { - assertEquals(criticalVolumesRegion.get(region), cell2.getCriticalVolume(region), EPSILON); - assertEquals(criticalHeightsRegion.get(region), cell2.getCriticalHeight(region), EPSILON); - } - } - + @Test public void schedule_validInput_callsMethod() { - Schedule schedule = spy(mock(Schedule.class)); - PottsCell cell = make(false); - doReturn(mock(Stoppable.class)).when(schedule).scheduleRepeating(cell, Ordering.CELLS.ordinal(), 1); + Schedule schedule = mock(Schedule.class); + PottsCell cell = new PottsCellMock(containerWithoutRegions, locationMock, parametersMock); + doReturn(mock(Stoppable.class)) + .when(schedule) + .scheduleRepeating(cell, Ordering.CELLS.ordinal(), 1); cell.schedule(schedule); verify(schedule).scheduleRepeating(cell, Ordering.CELLS.ordinal(), 1); } - + @Test public void schedule_validInput_assignStopper() { - Schedule schedule = spy(mock(Schedule.class)); - PottsCell cell = make(false); - doReturn(mock(Stoppable.class)).when(schedule).scheduleRepeating(cell, Ordering.CELLS.ordinal(), 1); + Schedule schedule = mock(Schedule.class); + PottsCell cell = new PottsCellMock(containerWithoutRegions, locationMock, parametersMock); + doReturn(mock(Stoppable.class)) + .when(schedule) + .scheduleRepeating(cell, Ordering.CELLS.ordinal(), 1); cell.schedule(schedule); assertNotNull(cell.stopper); } - + @Test public void initialize_withoutRegions_callsMethod() { PottsLocation location = mock(PottsLocation.class); - PottsCell cell = make(location, false); + PottsCell cell = new PottsCellMock(containerWithoutRegions, location, parametersMock); int[][][] array = new int[1][3][3]; cell.initialize(array, null); - + verify(location).update(cellID, array, null); } - + @Test public void initialize_withRegions_callsMethod() { PottsLocation location = mock(PottsLocation.class); when(location.getRegions()).thenReturn(regionList); - PottsCell cell = make(location, true); + PottsCell cell = new PottsCellMock(containerWithRegions, location, parametersMock); int[][][] array1 = new int[1][3][3]; int[][][] array2 = new int[1][3][3]; cell.initialize(array1, array2); - + verify(location).update(cellID, array1, array2); } - + @Test public void initialize_withoutRegions_updatesTargets() { int volume = randomIntBetween(0, 100); @@ -727,16 +738,16 @@ public void initialize_withoutRegions_updatesTargets() { PottsLocation location = mock(PottsLocation.class); when(location.getVolume()).thenReturn((double) volume); when(location.getSurface()).thenReturn((double) surface); - - PottsCell cell = make(location, false); + + PottsCell cell = new PottsCellMock(containerWithoutRegions, location, parametersMock); cell.initialize(new int[1][3][3], null); - + assertEquals(volume, cell.getTargetVolume(), EPSILON); assertEquals(surface, cell.getTargetSurface(), EPSILON); assertEquals(0, cell.getTargetVolume(Region.DEFAULT), EPSILON); assertEquals(0, cell.getTargetSurface(Region.DEFAULT), EPSILON); } - + @Test public void initialize_withRegions_updatesTargets() { int volume1 = randomIntBetween(0, 100); @@ -751,10 +762,10 @@ public void initialize_withRegions_updatesTargets() { when(location.getVolume(Region.NUCLEUS)).thenReturn((double) volume2); when(location.getSurface(Region.NUCLEUS)).thenReturn((double) surface2); when(location.getRegions()).thenReturn(regionList); - - PottsCell cell = make(location, true); + + PottsCell cell = new PottsCellMock(containerWithRegions, location, parametersMock); cell.initialize(new int[1][3][3], new int[1][3][3]); - + assertEquals(volume1 + volume2, cell.getTargetVolume(), EPSILON); assertEquals(surface1 + surface2, cell.getTargetSurface(), EPSILON); assertEquals(volume1, cell.getTargetVolume(Region.DEFAULT), EPSILON); @@ -764,93 +775,93 @@ public void initialize_withRegions_updatesTargets() { assertEquals(0, cell.getTargetVolume(Region.UNDEFINED), EPSILON); assertEquals(0, cell.getTargetSurface(Region.UNDEFINED), EPSILON); } - + @Test public void reset_withoutRegions_callsMethod() { PottsLocation location = mock(PottsLocation.class); - PottsCell cell = make(location, false); + PottsCell cell = new PottsCellMock(containerWithoutRegions, location, parametersMock); int[][][] array = new int[1][3][3]; cell.initialize(array, null); cell.reset(array, null); - + verify(location, times(2)).update(cellID, array, null); } - + @Test public void reset_withRegions_callsMethod() { PottsLocation location = mock(PottsLocation.class); when(location.getRegions()).thenReturn(regionList); - PottsCell cell = make(location, true); + PottsCell cell = new PottsCellMock(containerWithRegions, location, parametersMock); int[][][] array1 = new int[1][3][3]; int[][][] array2 = new int[1][3][3]; cell.initialize(array1, array2); cell.reset(array1, array2); - + verify(location, times(2)).update(cellID, array1, array2); } - + @Test public void reset_withoutRegions_updatesTargets() { - PottsCell cell = make(false); + PottsCell cell = new PottsCellMock(containerWithoutRegions, locationMock, parametersMock); cell.initialize(new int[1][3][3], new int[1][3][3]); cell.updateTarget(randomDoubleBetween(0, 10), randomDoubleBetween(0, 10)); cell.reset(new int[1][3][3], null); - + assertEquals(cellCriticalVolume, cell.getTargetVolume(), EPSILON); assertEquals(cellCriticalVolume * cellCriticalHeight, cell.getTargetSurface(), EPSILON); assertEquals(0, cell.getTargetVolume(Region.DEFAULT), EPSILON); assertEquals(0, cell.getTargetSurface(Region.DEFAULT), EPSILON); } - + @Test public void reset_withRegions_updatesTargets() { - PottsCell cell = make(true); + PottsCell cell = new PottsCellMock(containerWithRegions, locationMock, parametersMock); cell.initialize(new int[1][3][3], new int[1][3][3]); cell.updateTarget(Region.DEFAULT, randomDoubleBetween(0, 10), randomDoubleBetween(0, 10)); cell.updateTarget(Region.NUCLEUS, randomDoubleBetween(0, 10), randomDoubleBetween(0, 10)); cell.reset(new int[1][3][3], new int[1][3][3]); - + assertEquals(cellCriticalVolume, cell.getTargetVolume(), EPSILON); assertEquals(cellCriticalVolume * cellCriticalHeight, cell.getTargetSurface(), EPSILON); - + double volumeDefault = criticalVolumesRegionMock.get(Region.DEFAULT); double heightDefault = criticalHeightsRegionMock.get(Region.DEFAULT); assertEquals(volumeDefault, cell.getTargetVolume(Region.DEFAULT), EPSILON); assertEquals(volumeDefault * heightDefault, cell.getTargetSurface(Region.DEFAULT), EPSILON); - + double volumeNucleus = criticalVolumesRegionMock.get(Region.NUCLEUS); double heightNucleus = criticalHeightsRegionMock.get(Region.NUCLEUS); assertEquals(volumeNucleus, cell.getTargetVolume(Region.NUCLEUS), EPSILON); assertEquals(volumeNucleus * heightNucleus, cell.getTargetSurface(Region.NUCLEUS), EPSILON); } - + @Test public void step_singleStep_updatesAge() { - PottsCell cell = make(false); + PottsCell cell = new PottsCellMock(containerWithoutRegions, locationMock, parametersMock); PottsSimulation sim = mock(PottsSimulation.class); cell.module = mock(Module.class); - + cell.step(sim); assertEquals(cellAge + 1, cell.getAge(), EPSILON); } - + @Test public void setTargets_noRegions_updateValues() { double targetVolume = randomDoubleBetween(0, 10); double targetSurface = randomDoubleBetween(0, 10); - PottsCell cell = make(false); + PottsCell cell = new PottsCellMock(containerWithoutRegions, locationMock, parametersMock); cell.setTargets(targetVolume, targetSurface); assertEquals(targetVolume, cell.getTargetVolume(), EPSILON); assertEquals(targetSurface, cell.getTargetSurface(), EPSILON); } - + @Test public void setTargets_withRegions_updateValues() { double targetVolume = randomDoubleBetween(0, 10); double targetSurface = randomDoubleBetween(0, 10); - PottsCell cell = make(true); + PottsCell cell = new PottsCellMock(containerWithRegions, locationMock, parametersMock); cell.setTargets(Region.NUCLEUS, targetVolume, targetSurface); - + assertEquals(targetVolume, cell.getTargetVolume(Region.NUCLEUS), EPSILON); assertEquals(targetSurface, cell.getTargetSurface(Region.NUCLEUS), EPSILON); assertEquals(0, cell.getTargetVolume(Region.UNDEFINED), EPSILON); @@ -858,188 +869,210 @@ public void setTargets_withRegions_updateValues() { assertEquals(0, cell.getTargetVolume(Region.DEFAULT), EPSILON); assertEquals(0, cell.getTargetSurface(Region.DEFAULT), EPSILON); } - + @Test public void updateTarget_noScale_doesNothing() { double scale = 1.0; double rate = randomDoubleBetween(0, 100); - - PottsCell cell = make(false); + + PottsCell cell = new PottsCellMock(containerWithoutRegions, locationMock, parametersMock); cell.initialize(null, null); cell.updateTarget(rate, scale); - + assertEquals(locationVolume, cell.getTargetVolume(), EPSILON); assertEquals(locationSurface, cell.getTargetSurface(), EPSILON); } - + @Test public void updateTarget_noRegions_updatesValues() { - double[] scales = new double[] { - randomDoubleBetween(1 + OFFSET, 2), - randomDoubleBetween(1 + OFFSET, 2), - randomDoubleBetween(0, 1 - OFFSET), - randomDoubleBetween(0, 1 - OFFSET), - }; - - double[] rates = new double[] { - randomDoubleBetween(0, scales[0] - 1) * cellCriticalVolume, - randomDoubleBetween(scales[1] - 1, scales[1]) * cellCriticalVolume, - randomDoubleBetween(0, 1 - scales[2]) * cellCriticalVolume, - randomDoubleBetween(1 - scales[3], 2 - scales[3]) * cellCriticalVolume, - }; - - double[] expectedVolumes = new double[] { - cellCriticalVolume + rates[0], - scales[1] * cellCriticalVolume, - cellCriticalVolume - rates[2], - scales[3] * cellCriticalVolume, - }; - + double[] scales = + new double[] { + randomDoubleBetween(1 + OFFSET, 2), + randomDoubleBetween(1 + OFFSET, 2), + randomDoubleBetween(0, 1 - OFFSET), + randomDoubleBetween(0, 1 - OFFSET), + }; + + double[] rates = + new double[] { + randomDoubleBetween(0, scales[0] - 1) * cellCriticalVolume, + randomDoubleBetween(scales[1] - 1, scales[1]) * cellCriticalVolume, + randomDoubleBetween(0, 1 - scales[2]) * cellCriticalVolume, + randomDoubleBetween(1 - scales[3], 2 - scales[3]) * cellCriticalVolume, + }; + + double[] expectedVolumes = + new double[] { + cellCriticalVolume + rates[0], + scales[1] * cellCriticalVolume, + cellCriticalVolume - rates[2], + scales[3] * cellCriticalVolume, + }; + for (int i = 0; i < scales.length; i++) { - PottsCell cell = make(false); + PottsCell cell = + new PottsCellMock(containerWithoutRegions, locationMock, parametersMock); cell.reset(null, null); cell.updateTarget(rates[i], scales[i]); - + double expectedVolume = expectedVolumes[i]; assertEquals(expectedVolume, cell.getTargetVolume(), EPSILON); assertEquals(cellCriticalHeight * expectedVolume, cell.getTargetSurface(), EPSILON); } } - + @Test public void updateTarget_withRegions_updatesValues() { double defaultVolume = criticalVolumesRegionMock.get(Region.DEFAULT); double defaultHeight = criticalHeightsRegionMock.get(Region.DEFAULT); double threshold = defaultVolume / cellCriticalVolume; - - double[] scales = new double[] { - randomDoubleBetween(0, 1 - threshold), - randomDoubleBetween(0, 1 - threshold), - randomDoubleBetween(0, 1 - threshold), - randomDoubleBetween(1 - threshold, 1), - randomDoubleBetween(1 - threshold, 1), - randomDoubleBetween(1 - threshold, 1), - randomDoubleBetween(1 + OFFSET, 2), - randomDoubleBetween(1 + OFFSET, 2), - }; - - double[] rates = new double[] { - randomDoubleBetween(0, threshold) * cellCriticalVolume, - randomDoubleBetween(threshold, 1 - scales[1]) * cellCriticalVolume, - randomDoubleBetween(1 - scales[2], 2 - scales[2]) * cellCriticalVolume, - randomDoubleBetween(0, 1 - scales[3]) * cellCriticalVolume, - randomDoubleBetween(threshold, 2 - scales[4]) * cellCriticalVolume, - randomDoubleBetween(1 - scales[5], threshold) * cellCriticalVolume, - randomDoubleBetween(0, scales[6] - 1) * cellCriticalVolume, - randomDoubleBetween(scales[7] - 1, scales[7]) * cellCriticalVolume, - }; - - double[] expectedVolumes = new double[] { - cellCriticalVolume - rates[0], - cellCriticalVolume - defaultVolume, - cellCriticalVolume - defaultVolume, - cellCriticalVolume - rates[3], - scales[4] * cellCriticalVolume, - scales[5] * cellCriticalVolume, - cellCriticalVolume + rates[6], - scales[7] * cellCriticalVolume, - }; - + + double[] scales = + new double[] { + randomDoubleBetween(0, 1 - threshold), + randomDoubleBetween(0, 1 - threshold), + randomDoubleBetween(0, 1 - threshold), + randomDoubleBetween(1 - threshold, 1), + randomDoubleBetween(1 - threshold, 1), + randomDoubleBetween(1 - threshold, 1), + randomDoubleBetween(1 + OFFSET, 2), + randomDoubleBetween(1 + OFFSET, 2), + }; + + double[] rates = + new double[] { + randomDoubleBetween(0, threshold) * cellCriticalVolume, + randomDoubleBetween(threshold, 1 - scales[1]) * cellCriticalVolume, + randomDoubleBetween(1 - scales[2], 2 - scales[2]) * cellCriticalVolume, + randomDoubleBetween(0, 1 - scales[3]) * cellCriticalVolume, + randomDoubleBetween(threshold, 2 - scales[4]) * cellCriticalVolume, + randomDoubleBetween(1 - scales[5], threshold) * cellCriticalVolume, + randomDoubleBetween(0, scales[6] - 1) * cellCriticalVolume, + randomDoubleBetween(scales[7] - 1, scales[7]) * cellCriticalVolume, + }; + + double[] expectedVolumes = + new double[] { + cellCriticalVolume - rates[0], + cellCriticalVolume - defaultVolume, + cellCriticalVolume - defaultVolume, + cellCriticalVolume - rates[3], + scales[4] * cellCriticalVolume, + scales[5] * cellCriticalVolume, + cellCriticalVolume + rates[6], + scales[7] * cellCriticalVolume, + }; + for (int i = 0; i < scales.length; i++) { - PottsCell cell = make(true); + PottsCell cell = new PottsCellMock(containerWithRegions, locationMock, parametersMock); cell.reset(null, null); cell.updateTarget(rates[i], scales[i]); - + double expectedVolume = expectedVolumes[i]; assertEquals(expectedVolume, cell.getTargetVolume(), EPSILON); assertEquals(cellCriticalHeight * expectedVolume, cell.getTargetSurface(), EPSILON); - + double expectedDefaultVolume = defaultVolume - cellCriticalVolume + expectedVolume; assertEquals(expectedDefaultVolume, cell.getTargetVolume(Region.DEFAULT), EPSILON); - assertEquals(defaultHeight * expectedDefaultVolume, cell.getTargetSurface(Region.DEFAULT), EPSILON); + assertEquals( + defaultHeight * expectedDefaultVolume, + cell.getTargetSurface(Region.DEFAULT), + EPSILON); } } - + @Test public void updateTarget_regionNoScale_doesNothing() { double scale = 1.0; double rate = randomDoubleBetween(0, 100); - - PottsCell cell = make(true); + + PottsCell cell = new PottsCellMock(containerWithRegions, locationMock, parametersMock); cell.initialize(null, null); cell.updateTarget(Region.DEFAULT, rate, scale); - - assertEquals(locationRegionVolumes.get(Region.DEFAULT), cell.getTargetVolume(Region.DEFAULT), EPSILON); - assertEquals(locationRegionSurfaces.get(Region.DEFAULT), cell.getTargetSurface(Region.DEFAULT), EPSILON); + + assertEquals( + locationRegionVolumes.get(Region.DEFAULT), + cell.getTargetVolume(Region.DEFAULT), + EPSILON); + assertEquals( + locationRegionSurfaces.get(Region.DEFAULT), + cell.getTargetSurface(Region.DEFAULT), + EPSILON); } - + @Test public void updateTarget_regionNoRegion_doesNothing() { double scale = randomDoubleBetween(1, 10); double rate = randomDoubleBetween(0, 100); - - PottsCell cell = make(false); + + PottsCell cell = new PottsCellMock(containerWithoutRegions, locationMock, parametersMock); cell.initialize(null, null); cell.updateTarget(Region.DEFAULT, rate, scale); - + assertEquals(0, cell.getTargetVolume(Region.DEFAULT), EPSILON); assertEquals(0, cell.getTargetSurface(Region.DEFAULT), EPSILON); } - + @Test public void updateTarget_defaultRegion_updatesValues() { double defaultVolume = criticalVolumesRegionMock.get(Region.DEFAULT); double defaultHeight = criticalHeightsRegionMock.get(Region.DEFAULT); double threshold = defaultVolume / cellCriticalVolume; - - double[] scales = new double[] { - randomDoubleBetween(0, 1 - threshold), - randomDoubleBetween(0, 1 - threshold), - randomDoubleBetween(0, 1 - threshold), - randomDoubleBetween(1 - threshold, 1), - randomDoubleBetween(1 - threshold, 1), - randomDoubleBetween(1 - threshold, 1), - randomDoubleBetween(1 + OFFSET, 2), - randomDoubleBetween(1 + OFFSET, 2), - }; - - double[] rates = new double[] { - randomDoubleBetween(0, threshold) * cellCriticalVolume, - randomDoubleBetween(threshold, 1 - scales[1]) * cellCriticalVolume, - randomDoubleBetween(1 - scales[2], 2 - scales[2]) * cellCriticalVolume, - randomDoubleBetween(0, 1 - scales[3]) * cellCriticalVolume, - randomDoubleBetween(threshold, 2 - scales[4]) * cellCriticalVolume, - randomDoubleBetween(1 - scales[5], threshold) * cellCriticalVolume, - randomDoubleBetween(0, scales[6] - 1) * cellCriticalVolume, - randomDoubleBetween(scales[7] - 1, scales[7]) * cellCriticalVolume, - }; - - double[] expectedVolumes = new double[] { - cellCriticalVolume - rates[0], - cellCriticalVolume - defaultVolume, - cellCriticalVolume - defaultVolume, - cellCriticalVolume - rates[3], - scales[4] * cellCriticalVolume, - scales[5] * cellCriticalVolume, - cellCriticalVolume + rates[6], - scales[7] * cellCriticalVolume, - }; - + + double[] scales = + new double[] { + randomDoubleBetween(0, 1 - threshold), + randomDoubleBetween(0, 1 - threshold), + randomDoubleBetween(0, 1 - threshold), + randomDoubleBetween(1 - threshold, 1), + randomDoubleBetween(1 - threshold, 1), + randomDoubleBetween(1 - threshold, 1), + randomDoubleBetween(1 + OFFSET, 2), + randomDoubleBetween(1 + OFFSET, 2), + }; + + double[] rates = + new double[] { + randomDoubleBetween(0, threshold) * cellCriticalVolume, + randomDoubleBetween(threshold, 1 - scales[1]) * cellCriticalVolume, + randomDoubleBetween(1 - scales[2], 2 - scales[2]) * cellCriticalVolume, + randomDoubleBetween(0, 1 - scales[3]) * cellCriticalVolume, + randomDoubleBetween(threshold, 2 - scales[4]) * cellCriticalVolume, + randomDoubleBetween(1 - scales[5], threshold) * cellCriticalVolume, + randomDoubleBetween(0, scales[6] - 1) * cellCriticalVolume, + randomDoubleBetween(scales[7] - 1, scales[7]) * cellCriticalVolume, + }; + + double[] expectedVolumes = + new double[] { + cellCriticalVolume - rates[0], + cellCriticalVolume - defaultVolume, + cellCriticalVolume - defaultVolume, + cellCriticalVolume - rates[3], + scales[4] * cellCriticalVolume, + scales[5] * cellCriticalVolume, + cellCriticalVolume + rates[6], + scales[7] * cellCriticalVolume, + }; + for (int i = 0; i < scales.length; i++) { - PottsCell cell = make(true); + PottsCell cell = new PottsCellMock(containerWithRegions, locationMock, parametersMock); cell.reset(null, null); cell.updateTarget(Region.DEFAULT, rates[i], scales[i]); - + double expectedVolume = expectedVolumes[i]; assertEquals(expectedVolume, cell.getTargetVolume(), EPSILON); assertEquals(cellCriticalHeight * expectedVolume, cell.getTargetSurface(), EPSILON); - + double expectedDefaultVolume = defaultVolume - cellCriticalVolume + expectedVolume; assertEquals(expectedDefaultVolume, cell.getTargetVolume(Region.DEFAULT), EPSILON); - assertEquals(defaultHeight * expectedDefaultVolume, cell.getTargetSurface(Region.DEFAULT), EPSILON); + assertEquals( + defaultHeight * expectedDefaultVolume, + cell.getTargetSurface(Region.DEFAULT), + EPSILON); } } - + @Test public void updateTarget_nonDefaultRegion_updatesValues() { double defaultVolume = criticalVolumesRegionMock.get(Region.DEFAULT); @@ -1047,80 +1080,100 @@ public void updateTarget_nonDefaultRegion_updatesValues() { double regionVolume = criticalVolumesRegionMock.get(Region.NUCLEUS); double regionHeight = criticalHeightsRegionMock.get(Region.NUCLEUS); double threshold = defaultVolume / regionVolume; - - double[] scales = new double[] { - randomDoubleBetween(threshold + 1, threshold + 2), - randomDoubleBetween(threshold + 1, threshold + 2), - randomDoubleBetween(threshold + 1, threshold + 2), - randomDoubleBetween(1, threshold + 1), - randomDoubleBetween(1, threshold + 1), - randomDoubleBetween(1, threshold + 1), - randomDoubleBetween(0, 1 - OFFSET), - randomDoubleBetween(0, 1 - OFFSET), - }; - - double[] rates = new double[] { - randomDoubleBetween(0, threshold) * regionVolume, - randomDoubleBetween(threshold, scales[1] - 1) * regionVolume, - randomDoubleBetween(scales[2] - 1, scales[2]) * regionVolume, - randomDoubleBetween(scales[3] - 1, threshold) * regionVolume, - randomDoubleBetween(0, scales[4] - 1) * regionVolume, - randomDoubleBetween(threshold, scales[5]) * regionVolume, - randomDoubleBetween(0, 1 - scales[6]) * regionVolume, - randomDoubleBetween(1 - scales[7], 2 - scales[7]) * regionVolume, - }; - - double[] expectedRegionVolumes = new double[] { - regionVolume + rates[0], - regionVolume + defaultVolume, - regionVolume + defaultVolume, - scales[3] * regionVolume, - regionVolume + rates[4], - scales[5] * regionVolume, - regionVolume - rates[6], - scales[7] * regionVolume, - }; - + + double[] scales = + new double[] { + randomDoubleBetween(threshold + 1, threshold + 2), + randomDoubleBetween(threshold + 1, threshold + 2), + randomDoubleBetween(threshold + 1, threshold + 2), + randomDoubleBetween(1, threshold + 1), + randomDoubleBetween(1, threshold + 1), + randomDoubleBetween(1, threshold + 1), + randomDoubleBetween(0, 1 - OFFSET), + randomDoubleBetween(0, 1 - OFFSET), + }; + + double[] rates = + new double[] { + randomDoubleBetween(0, threshold) * regionVolume, + randomDoubleBetween(threshold, scales[1] - 1) * regionVolume, + randomDoubleBetween(scales[2] - 1, scales[2]) * regionVolume, + randomDoubleBetween(scales[3] - 1, threshold) * regionVolume, + randomDoubleBetween(0, scales[4] - 1) * regionVolume, + randomDoubleBetween(threshold, scales[5]) * regionVolume, + randomDoubleBetween(0, 1 - scales[6]) * regionVolume, + randomDoubleBetween(1 - scales[7], 2 - scales[7]) * regionVolume, + }; + + double[] expectedRegionVolumes = + new double[] { + regionVolume + rates[0], + regionVolume + defaultVolume, + regionVolume + defaultVolume, + scales[3] * regionVolume, + regionVolume + rates[4], + scales[5] * regionVolume, + regionVolume - rates[6], + scales[7] * regionVolume, + }; + for (int i = 0; i < scales.length; i++) { - PottsCell cell = make(true); + PottsCell cell = new PottsCellMock(containerWithRegions, locationMock, parametersMock); cell.reset(null, null); cell.updateTarget(Region.NUCLEUS, rates[i], scales[i]); - + double expectedRegionVolume = expectedRegionVolumes[i]; assertEquals(expectedRegionVolume, cell.getTargetVolume(Region.NUCLEUS), EPSILON); - assertEquals(regionHeight * expectedRegionVolume, cell.getTargetSurface(Region.NUCLEUS), EPSILON); - + assertEquals( + regionHeight * expectedRegionVolume, + cell.getTargetSurface(Region.NUCLEUS), + EPSILON); + double expectedDefaultVolume = defaultVolume + regionVolume - expectedRegionVolume; assertEquals(expectedDefaultVolume, cell.getTargetVolume(Region.DEFAULT), EPSILON); - assertEquals(defaultHeight * expectedDefaultVolume, cell.getTargetSurface(Region.DEFAULT), EPSILON); + assertEquals( + defaultHeight * expectedDefaultVolume, + cell.getTargetSurface(Region.DEFAULT), + EPSILON); } } - + @Test public void convert_noRegions_createsContainer() { Location location = mock(PottsLocation.class); - MiniBox parameters = mock(MiniBox.class); - + Parameters parameters = new Parameters(new MiniBox(), null, null); + int id = randomIntBetween(1, 10); int parent = randomIntBetween(1, 10); int pop = randomIntBetween(1, 10); int age = randomIntBetween(1, 100); int divisions = randomIntBetween(1, 100); - State state = State.PROLIFERATIVE; - Phase phase = Phase.PROLIFERATIVE_S; + State state = State.random(RANDOM); + Phase phase = Phase.random(RANDOM); double criticalVolume = randomDoubleBetween(10, 100); double criticalHeight = randomDoubleBetween(10, 100); - - PottsCell cell = new PottsCell(id, parent, pop, state, age, divisions, location, - false, parameters, criticalVolume, criticalHeight, - null, null); - ((PottsModule) cell.getModule()).setPhase(phase); - + + PottsCellContainer container2 = + new PottsCellContainer( + id, + parent, + pop, + age, + divisions, + state, + phase, + 0, + criticalVolume, + criticalHeight); + PottsCell cell = new PottsCellMock(container2, location, parameters); + + doReturn(phase).when((PottsModule) cell.getModule()).getPhase(); + int voxels = randomIntBetween(1, 100); doReturn((double) voxels).when(location).getVolume(); - + PottsCellContainer container = (PottsCellContainer) cell.convert(); - + assertEquals(id, container.id); assertEquals(parent, container.parent); assertEquals(pop, container.pop); @@ -1135,45 +1188,63 @@ public void convert_noRegions_createsContainer() { assertNull(container.criticalRegionVolumes); assertNull(container.criticalRegionHeights); } - + @Test public void convert_withRegions_createsContainer() { PottsLocation location = mock(PottsLocation.class); - MiniBox parameters = mock(MiniBox.class); - + Parameters parameters = new Parameters(new MiniBox(), null, null); + int id = randomIntBetween(1, 10); int parent = randomIntBetween(1, 10); int pop = randomIntBetween(1, 10); int age = randomIntBetween(1, 100); int divisions = randomIntBetween(1, 100); - State state = State.PROLIFERATIVE; - Phase phase = Phase.PROLIFERATIVE_S; + State state = State.random(RANDOM); + Phase phase = Phase.random(RANDOM); double criticalVolume = randomDoubleBetween(10, 100); double criticalHeight = randomDoubleBetween(10, 100); - + EnumSet regions = EnumSet.of(Region.NUCLEUS, Region.UNDEFINED); doReturn(regions).when(location).getRegions(); - - EnumMap criticalRegionVolumes = makeRegionEnumMap(); - EnumMap criticalRegionHeights = makeRegionEnumMap(); - - PottsCell cell = new PottsCell(id, parent, pop, state, age, divisions, location, true, - parameters, criticalVolume, criticalHeight, - criticalRegionVolumes, criticalRegionHeights); - ((PottsModule) cell.getModule()).setPhase(phase); - + + EnumMap criticalRegionVolumes = new EnumMap<>(Region.class); + EnumMap criticalRegionHeights = new EnumMap<>(Region.class); + + Arrays.stream(Region.values()) + .forEach(region -> criticalRegionVolumes.put(region, randomDoubleBetween(0, 100))); + Arrays.stream(Region.values()) + .forEach(region -> criticalRegionHeights.put(region, randomDoubleBetween(0, 100))); + + PottsCellContainer container2 = + new PottsCellContainer( + id, + parent, + pop, + age, + divisions, + state, + phase, + 0, + new EnumMap<>(Region.class), + criticalVolume, + criticalHeight, + criticalRegionVolumes, + criticalRegionHeights); + PottsCell cell = new PottsCellMock(container2, location, parameters); + doReturn(phase).when((PottsModule) cell.getModule()).getPhase(); + int voxels = randomIntBetween(1, 100); doReturn((double) voxels).when(location).getVolume(); - + EnumMap regionVoxels = new EnumMap<>(Region.class); for (Region region : regions) { int value = randomIntBetween(1, 100); regionVoxels.put(region, value); doReturn((double) value).when(location).getVolume(region); } - + PottsCellContainer container = (PottsCellContainer) cell.convert(); - + assertEquals(id, container.id); assertEquals(parent, container.parent); assertEquals(pop, container.pop); @@ -1184,11 +1255,17 @@ public void convert_withRegions_createsContainer() { assertEquals(voxels, container.voxels); assertEquals(criticalVolume, container.criticalVolume, EPSILON); assertEquals(criticalHeight, container.criticalHeight, EPSILON); - + for (Region region : regions) { assertEquals(regionVoxels.get(region), container.regionVoxels.get(region)); - assertEquals(criticalRegionVolumes.get(region), container.criticalRegionVolumes.get(region), EPSILON); - assertEquals(criticalRegionHeights.get(region), container.criticalRegionHeights.get(region), EPSILON); + assertEquals( + criticalRegionVolumes.get(region), + container.criticalRegionVolumes.get(region), + EPSILON); + assertEquals( + criticalRegionHeights.get(region), + container.criticalRegionHeights.get(region), + EPSILON); } } } diff --git a/test/arcade/potts/agent/module/PottsModuleApoptosisSimpleTest.java b/test/arcade/potts/agent/module/PottsModuleApoptosisSimpleTest.java index 1f5f74511..f7f26c1cd 100644 --- a/test/arcade/potts/agent/module/PottsModuleApoptosisSimpleTest.java +++ b/test/arcade/potts/agent/module/PottsModuleApoptosisSimpleTest.java @@ -1,15 +1,16 @@ package arcade.potts.agent.module; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import sim.util.distribution.Poisson; import ec.util.MersenneTwisterFast; import arcade.core.env.grid.Grid; import arcade.core.util.MiniBox; +import arcade.core.util.Parameters; import arcade.potts.agent.cell.PottsCell; import arcade.potts.sim.Potts; import arcade.potts.sim.PottsSimulation; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.core.ARCADETestUtilities.*; import static arcade.potts.agent.module.PottsModuleApoptosisSimple.*; @@ -18,269 +19,216 @@ public class PottsModuleApoptosisSimpleTest { private static final double EPSILON = 1E-10; - + private static final double R = 1.0; - + private static final int N = 0; - + static MersenneTwisterFast random; - + static Poisson poissonMock; - + static PottsSimulation simMock; - - static PottsCell cellMock; - - static MiniBox parameters; - - @BeforeClass + + static Parameters parameters; + + @BeforeAll public static void setupMocks() { random = mock(MersenneTwisterFast.class); doReturn(R).when(random).nextDouble(); - + poissonMock = mock(Poisson.class); doReturn(N).when(poissonMock).nextInt(); - + simMock = mock(PottsSimulation.class); when(simMock.getPotts()).thenReturn(mock(Potts.class)); when(simMock.getGrid()).thenReturn(mock(Grid.class)); - - cellMock = mock(PottsCell.class); - MiniBox box = mock(MiniBox.class); - doReturn(0.).when(box).getDouble(anyString()); - doReturn(box).when(cellMock).getParameters(); - - parameters = new MiniBox(); - parameters.put("apoptosis/RATE_EARLY", randomDoubleBetween(1, 10)); - parameters.put("apoptosis/RATE_LATE", randomDoubleBetween(1, 10)); - parameters.put("apoptosis/STEPS_EARLY", randomIntBetween(1, 100)); - parameters.put("apoptosis/STEPS_LATE", randomIntBetween(1, 100)); - parameters.put("apoptosis/WATER_LOSS_RATE", randomDoubleBetween(100, 500)); - parameters.put("apoptosis/CYTOPLASMIC_BLEBBING_RATE", randomDoubleBetween(100, 500)); - parameters.put("apoptosis/NUCLEUS_PYKNOSIS_RATE", randomDoubleBetween(0, 100)); - parameters.put("apoptosis/NUCLEUS_FRAGMENTATION_RATE", randomDoubleBetween(0, 100)); + + MiniBox defaults = new MiniBox(); + defaults.put("apoptosis/RATE_EARLY", randomDoubleBetween(1, 10)); + defaults.put("apoptosis/RATE_LATE", randomDoubleBetween(1, 10)); + defaults.put("apoptosis/STEPS_EARLY", randomIntBetween(1, 100)); + defaults.put("apoptosis/STEPS_LATE", randomIntBetween(1, 100)); + defaults.put("apoptosis/WATER_LOSS_RATE", randomDoubleBetween(100, 500)); + defaults.put("apoptosis/CYTOPLASMIC_BLEBBING_RATE", randomDoubleBetween(100, 500)); + defaults.put("apoptosis/NUCLEUS_PYKNOSIS_RATE", randomDoubleBetween(0, 100)); + defaults.put("apoptosis/NUCLEUS_FRAGMENTATION_RATE", randomDoubleBetween(0, 100)); + parameters = new Parameters(defaults, null, random); } - + @Test public void constructor_setsParameters() { PottsCell cell = mock(PottsCell.class); doReturn(parameters).when(cell).getParameters(); PottsModuleApoptosisSimple module = new PottsModuleApoptosisSimple(cell); - + assertEquals(parameters.getDouble("apoptosis/RATE_EARLY"), module.rateEarly, EPSILON); assertEquals(parameters.getDouble("apoptosis/RATE_LATE"), module.rateLate, EPSILON); assertEquals(parameters.getDouble("apoptosis/STEPS_EARLY"), module.stepsEarly, EPSILON); assertEquals(parameters.getDouble("apoptosis/STEPS_LATE"), module.stepsLate, EPSILON); - assertEquals(parameters.getDouble("apoptosis/WATER_LOSS_RATE"), module.waterLossRate, EPSILON); - assertEquals(parameters.getDouble("apoptosis/CYTOPLASMIC_BLEBBING_RATE"), module.cytoBlebbingRate, EPSILON); - assertEquals(parameters.getDouble("apoptosis/NUCLEUS_PYKNOSIS_RATE"), module.nucleusPyknosisRate, EPSILON); - assertEquals(parameters.getDouble("apoptosis/NUCLEUS_FRAGMENTATION_RATE"), - module.nucleusFragmentationRate, EPSILON); + assertEquals( + parameters.getDouble("apoptosis/WATER_LOSS_RATE"), module.waterLossRate, EPSILON); + assertEquals( + parameters.getDouble("apoptosis/CYTOPLASMIC_BLEBBING_RATE"), + module.cytoBlebbingRate, + EPSILON); + assertEquals( + parameters.getDouble("apoptosis/NUCLEUS_PYKNOSIS_RATE"), + module.nucleusPyknosisRate, + EPSILON); + assertEquals( + parameters.getDouble("apoptosis/NUCLEUS_FRAGMENTATION_RATE"), + module.nucleusFragmentationRate, + EPSILON); } - + @Test public void stepEarly_withTransition_updatesPhase() { int steps = randomIntBetween(1, parameters.getInt("apoptosis/STEPS_EARLY")); PottsCell cell = mock(PottsCell.class); doReturn(parameters).when(cell).getParameters(); + PottsModuleApoptosisSimple module = spy(new PottsModuleApoptosisSimple(cell)); module.phase = Phase.APOPTOTIC_EARLY; module.currentSteps = module.stepsEarly - steps; - + Poisson poisson = mock(Poisson.class); doReturn(steps).when(poisson).nextInt(); PoissonFactory poissonFactory = mock(PoissonFactory.class); doReturn(poisson).when(poissonFactory).createPoisson(eq(module.rateEarly), eq(random)); module.poissonFactory = poissonFactory; - + module.stepEarly(random); - + verify(module).setPhase(Phase.APOPTOTIC_LATE); assertEquals(Phase.APOPTOTIC_LATE, module.phase); } - + @Test public void stepEarly_withoutTransition_maintainsPhase() { PottsCell cell = mock(PottsCell.class); doReturn(parameters).when(cell).getParameters(); + PottsModuleApoptosisSimple module = spy(new PottsModuleApoptosisSimple(cell)); module.phase = Phase.APOPTOTIC_EARLY; module.currentSteps = module.stepsEarly; - + Poisson poisson = mock(Poisson.class); doReturn(-1).when(poisson).nextInt(); PoissonFactory poissonFactory = mock(PoissonFactory.class); doReturn(poisson).when(poissonFactory).createPoisson(anyDouble(), eq(random)); module.poissonFactory = poissonFactory; - + module.stepEarly(random); - + verify(module, never()).setPhase(any(Phase.class)); assertEquals(Phase.APOPTOTIC_EARLY, module.phase); } - + @Test public void stepEarly_anyTransition_updatesCell() { PottsCell cell = mock(PottsCell.class); doReturn(parameters).when(cell).getParameters(); PottsModuleApoptosisSimple module = spy(new PottsModuleApoptosisSimple(cell)); - + PoissonFactory poissonFactory = mock(PoissonFactory.class); doReturn(poissonMock).when(poissonFactory).createPoisson(anyDouble(), eq(random)); module.poissonFactory = poissonFactory; - + module.currentSteps = Integer.MAX_VALUE; module.stepEarly(random); module.currentSteps = 0; module.stepEarly(random); - + verify(cell, times(2)).updateTarget(module.waterLossRate, EARLY_SIZE_TARGET); } - + @Test public void stepEarly_anyTransitionWithRegion_updatesCell() { PottsCell cell = mock(PottsCell.class); doReturn(parameters).when(cell).getParameters(); doReturn(true).when(cell).hasRegions(); PottsModuleApoptosisSimple module = spy(new PottsModuleApoptosisSimple(cell)); - + PoissonFactory poissonFactory = mock(PoissonFactory.class); doReturn(poissonMock).when(poissonFactory).createPoisson(anyDouble(), eq(random)); module.poissonFactory = poissonFactory; - + module.currentSteps = Integer.MAX_VALUE; module.stepEarly(random); module.currentSteps = 0; module.stepEarly(random); - - verify(cell, times(2)).updateTarget(Region.NUCLEUS, module.nucleusPyknosisRate, EARLY_SIZE_TARGET); + + verify(cell, times(2)) + .updateTarget(Region.NUCLEUS, module.nucleusPyknosisRate, EARLY_SIZE_TARGET); } - + @Test - public void stepLate_withTransitionNotArrested_updatesPhase() { + public void stepLate_withTransition_updatesPhase() { int steps = randomIntBetween(1, parameters.getInt("apoptosis/STEPS_LATE")); PottsCell cell = mock(PottsCell.class); doReturn(parameters).when(cell).getParameters(); - double volume = randomDoubleBetween(0, 100); - doReturn((volume * SIZE_CHECKPOINT * LATE_SIZE_TARGET) - 1).when(cell).getVolume(); - doReturn(volume).when(cell).getCriticalVolume(); - + PottsModuleApoptosisSimple module = spy(new PottsModuleApoptosisSimple(cell)); module.phase = Phase.APOPTOTIC_LATE; module.currentSteps = module.stepsLate - steps; doNothing().when(module).removeCell(simMock); - + Poisson poisson = mock(Poisson.class); doReturn(steps).when(poisson).nextInt(); PoissonFactory poissonFactory = mock(PoissonFactory.class); doReturn(poisson).when(poissonFactory).createPoisson(eq(module.rateLate), eq(random)); module.poissonFactory = poissonFactory; - + module.stepLate(random, simMock); - + verify(module).removeCell(simMock); verify(module).setPhase(Phase.APOPTOSED); assertEquals(Phase.APOPTOSED, module.phase); } - - @Test - public void stepLate_withoutTransitionNotArrested_maintainsPhase() { - PottsCell cell = mock(PottsCell.class); - doReturn(parameters).when(cell).getParameters(); - double volume = randomDoubleBetween(0, 100); - doReturn((volume * SIZE_CHECKPOINT * LATE_SIZE_TARGET) - 1).when(cell).getVolume(); - doReturn(volume).when(cell).getCriticalVolume(); - - PottsModuleApoptosisSimple module = spy(new PottsModuleApoptosisSimple(cell)); - module.phase = Phase.APOPTOTIC_LATE; - module.currentSteps = module.stepsLate; - doNothing().when(module).removeCell(simMock); - - Poisson poisson = mock(Poisson.class); - doReturn(-1).when(poisson).nextInt(); - PoissonFactory poissonFactory = mock(PoissonFactory.class); - doReturn(poisson).when(poissonFactory).createPoisson(anyDouble(), eq(random)); - module.poissonFactory = poissonFactory; - - module.stepLate(random, simMock); - - verify(module, never()).removeCell(simMock); - verify(module, never()).setPhase(any(Phase.class)); - assertEquals(Phase.APOPTOTIC_LATE, module.phase); - } - - @Test - public void stepLate_withTransitionArrested_maintainsPhase() { - int steps = randomIntBetween(1, parameters.getInt("apoptosis/STEPS_LATE")); - PottsCell cell = mock(PottsCell.class); - doReturn(parameters).when(cell).getParameters(); - double volume = randomDoubleBetween(0, 100); - doReturn((volume * SIZE_CHECKPOINT * LATE_SIZE_TARGET) + 1).when(cell).getVolume(); - doReturn(volume).when(cell).getCriticalVolume(); - - PottsModuleApoptosisSimple module = spy(new PottsModuleApoptosisSimple(cell)); - module.phase = Phase.APOPTOTIC_LATE; - module.currentSteps = module.stepsLate - steps; - doNothing().when(module).removeCell(simMock); - - Poisson poisson = mock(Poisson.class); - doReturn(steps).when(poisson).nextInt(); - PoissonFactory poissonFactory = mock(PoissonFactory.class); - doReturn(poisson).when(poissonFactory).createPoisson(eq(module.rateLate), eq(random)); - module.poissonFactory = poissonFactory; - - module.stepLate(random, simMock); - - verify(module, never()).removeCell(simMock); - verify(module, never()).setPhase(any(Phase.class)); - assertEquals(Phase.APOPTOTIC_LATE, module.phase); - } - + @Test - public void stepLate_withoutTransitionArrested_maintainsPhase() { + public void stepLate_withoutTransition_maintainsPhase() { PottsCell cell = mock(PottsCell.class); doReturn(parameters).when(cell).getParameters(); - double volume = randomDoubleBetween(0, 100); - doReturn((volume * SIZE_CHECKPOINT * LATE_SIZE_TARGET) + 1).when(cell).getVolume(); - doReturn(volume).when(cell).getCriticalVolume(); - + PottsModuleApoptosisSimple module = spy(new PottsModuleApoptosisSimple(cell)); module.phase = Phase.APOPTOTIC_LATE; module.currentSteps = module.stepsLate; doNothing().when(module).removeCell(simMock); - + Poisson poisson = mock(Poisson.class); doReturn(-1).when(poisson).nextInt(); PoissonFactory poissonFactory = mock(PoissonFactory.class); doReturn(poisson).when(poissonFactory).createPoisson(anyDouble(), eq(random)); module.poissonFactory = poissonFactory; - + module.stepLate(random, simMock); - + verify(module, never()).removeCell(simMock); verify(module, never()).setPhase(any(Phase.class)); assertEquals(Phase.APOPTOTIC_LATE, module.phase); } - + @Test public void stepLate_anyTransition_updatesCell() { PottsCell cell = mock(PottsCell.class); doReturn(parameters).when(cell).getParameters(); PottsModuleApoptosisSimple module = spy(new PottsModuleApoptosisSimple(cell)); doNothing().when(module).removeCell(simMock); - + PoissonFactory poissonFactory = mock(PoissonFactory.class); doReturn(poissonMock).when(poissonFactory).createPoisson(anyDouble(), eq(random)); module.poissonFactory = poissonFactory; - + module.currentSteps = Integer.MAX_VALUE; module.stepLate(random, simMock); module.currentSteps = 0; module.stepLate(random, simMock); - + verify(cell, times(2)).updateTarget(module.cytoBlebbingRate, LATE_SIZE_TARGET); } - + @Test public void stepLate_anyTransitionWithRegion_updatesCell() { PottsCell cell = mock(PottsCell.class); @@ -288,16 +236,16 @@ public void stepLate_anyTransitionWithRegion_updatesCell() { doReturn(true).when(cell).hasRegions(); PottsModuleApoptosisSimple module = spy(new PottsModuleApoptosisSimple(cell)); doNothing().when(module).removeCell(simMock); - + PoissonFactory poissonFactory = mock(PoissonFactory.class); doReturn(poissonMock).when(poissonFactory).createPoisson(anyDouble(), eq(random)); module.poissonFactory = poissonFactory; - + module.currentSteps = Integer.MAX_VALUE; module.stepLate(random, simMock); module.currentSteps = 0; module.stepLate(random, simMock); - + verify(cell, times(2)).updateTarget(Region.NUCLEUS, module.nucleusFragmentationRate, 0); } } diff --git a/test/arcade/potts/agent/module/PottsModuleApoptosisTest.java b/test/arcade/potts/agent/module/PottsModuleApoptosisTest.java index 23b75d7e8..6ebdb3ff9 100644 --- a/test/arcade/potts/agent/module/PottsModuleApoptosisTest.java +++ b/test/arcade/potts/agent/module/PottsModuleApoptosisTest.java @@ -1,52 +1,54 @@ package arcade.potts.agent.module; -import org.junit.Test; +import org.junit.jupiter.api.Test; import ec.util.MersenneTwisterFast; import arcade.core.env.grid.Grid; import arcade.core.sim.Simulation; -import arcade.core.util.MiniBox; +import arcade.core.util.Parameters; import arcade.potts.agent.cell.PottsCell; import arcade.potts.env.location.PottsLocation; import arcade.potts.sim.Potts; import arcade.potts.sim.PottsSimulation; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.core.ARCADETestUtilities.*; import static arcade.potts.util.PottsEnums.Phase; public class PottsModuleApoptosisTest { - static MersenneTwisterFast randomMock = new MersenneTwisterFast(randomSeed()); - + static MersenneTwisterFast randomMock = new MersenneTwisterFast(); + static PottsSimulation simMock; - + static PottsCell cellMock; - + static class PottsModuleApoptosisMock extends PottsModuleApoptosis { - PottsModuleApoptosisMock(PottsCell cell) { super(cell); } - + PottsModuleApoptosisMock(PottsCell cell) { + super(cell); + } + @Override void stepEarly(MersenneTwisterFast random) { setPhase(Phase.APOPTOTIC_LATE); } - + @Override void stepLate(MersenneTwisterFast random, Simulation sim) { setPhase(Phase.APOPTOSED); } } - + @Test public void constructor_initializesFactory() { PottsModuleApoptosis module = new PottsModuleApoptosisMock(cellMock); assertNotNull(module.poissonFactory); } - + @Test public void getPhase_defaultConstructor_returnsValue() { PottsModuleApoptosis module = new PottsModuleApoptosisMock(cellMock); assertEquals(Phase.APOPTOTIC_EARLY, module.getPhase()); } - + @Test public void setPhase_givenValue_setsValue() { Phase phase = Phase.random(randomMock); @@ -54,7 +56,7 @@ public void setPhase_givenValue_setsValue() { module.setPhase(phase); assertEquals(phase, module.phase); } - + @Test public void setPhase_givenValue_resetsSteps() { Phase phase = Phase.random(randomMock); @@ -63,62 +65,62 @@ public void setPhase_givenValue_resetsSteps() { module.setPhase(phase); assertEquals(0, module.currentSteps); } - + @Test public void step_givenPhaseEarly_callsMethod() { PottsModuleApoptosis module = spy(new PottsModuleApoptosisMock(cellMock)); module.phase = Phase.APOPTOTIC_EARLY; - + module.step(randomMock, simMock); verify(module).stepEarly(randomMock); verify(module, never()).stepLate(randomMock, simMock); } - + @Test public void step_givenPhaseLate_callsMethod() { PottsModuleApoptosis module = spy(new PottsModuleApoptosisMock(cellMock)); doNothing().when(module).removeCell(simMock); module.phase = Phase.APOPTOTIC_LATE; - + module.step(randomMock, simMock); verify(module).stepLate(randomMock, simMock); verify(module, never()).stepEarly(randomMock); } - + @Test public void step_invalidPhase_doesNothing() { PottsModuleApoptosis module = spy(new PottsModuleApoptosisMock(cellMock)); module.phase = Phase.UNDEFINED; - + module.step(randomMock, simMock); verify(module, never()).stepLate(randomMock, simMock); verify(module, never()).stepEarly(randomMock); } - + @Test public void removeCell_called_removeObject() { PottsCell cell = mock(PottsCell.class); - MiniBox box = mock(MiniBox.class); - doReturn(0.).when(box).getDouble(anyString()); - doReturn(box).when(cell).getParameters(); - + Parameters parameters = mock(Parameters.class); + doReturn(0.).when(parameters).getDouble(anyString()); + doReturn(parameters).when(cell).getParameters(); + PottsLocation location = mock(PottsLocation.class); Potts potts = mock(Potts.class); Grid grid = mock(Grid.class); PottsSimulation sim = mock(PottsSimulation.class); - + int id = randomIntBetween(1, 100); doReturn(potts).when(sim).getPotts(); doReturn(id).when(cell).getID(); doReturn(grid).when(sim).getGrid(); doReturn(location).when(cell).getLocation(); - - potts.ids = new int[][][] { { { } } }; - potts.regions = new int[][][] { { { } } }; - + + potts.ids = new int[][][] {{{}}}; + potts.regions = new int[][][] {{{}}}; + PottsModuleApoptosis module = new PottsModuleApoptosisMock(cell); module.removeCell(sim); - + verify(location).clear(potts.ids, potts.regions); verify(grid).removeObject(cell, null); verify(potts).deregister(cell); diff --git a/test/arcade/potts/agent/module/PottsModuleProliferationSimpleTest.java b/test/arcade/potts/agent/module/PottsModuleProliferationSimpleTest.java index 9ad3f778a..0cee2139c 100644 --- a/test/arcade/potts/agent/module/PottsModuleProliferationSimpleTest.java +++ b/test/arcade/potts/agent/module/PottsModuleProliferationSimpleTest.java @@ -1,15 +1,16 @@ package arcade.potts.agent.module; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import sim.util.distribution.Poisson; import ec.util.MersenneTwisterFast; import arcade.core.util.MiniBox; +import arcade.core.util.Parameters; import arcade.potts.agent.cell.PottsCell; import arcade.potts.env.location.PottsLocations; import arcade.potts.sim.Potts; import arcade.potts.sim.PottsSimulation; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.core.ARCADETestUtilities.*; import static arcade.potts.agent.module.PottsModule.PoissonFactory; @@ -20,55 +21,57 @@ public class PottsModuleProliferationSimpleTest { private static final double EPSILON = 1E-10; - + private static final double R = 1.0; - + private static final int N = 0; - + static MersenneTwisterFast random; - + static Poisson poissonMock; - + static PottsSimulation simMock; - - static MiniBox parameters; - + + static Parameters parameters; + static Potts pottsMock; - - @BeforeClass + + @BeforeAll public static void setupMocks() { random = mock(MersenneTwisterFast.class); doReturn(R).when(random).nextDouble(); - + poissonMock = mock(Poisson.class); doReturn(N).when(poissonMock).nextInt(); - + pottsMock = mock(Potts.class); - + simMock = mock(PottsSimulation.class); doReturn(pottsMock).when(simMock).getPotts(); - - parameters = new MiniBox(); - parameters.put("proliferation/RATE_G1", randomDoubleBetween(1, 10)); - parameters.put("proliferation/RATE_S", randomDoubleBetween(1, 10)); - parameters.put("proliferation/RATE_G2", randomDoubleBetween(1, 10)); - parameters.put("proliferation/RATE_M", randomDoubleBetween(1, 10)); - parameters.put("proliferation/STEPS_G1", randomIntBetween(1, 100)); - parameters.put("proliferation/STEPS_S", randomIntBetween(1, 100)); - parameters.put("proliferation/STEPS_G2", randomIntBetween(1, 100)); - parameters.put("proliferation/STEPS_M", randomIntBetween(1, 100)); - parameters.put("proliferation/CELL_GROWTH_RATE", randomDoubleBetween(1, 100)); - parameters.put("proliferation/NUCLEAR_GROWTH_RATE", randomDoubleBetween(1, 100)); - parameters.put("proliferation/BASAL_APOPTOSIS_RATE", randomDoubleBetween(0, 0.5)); - parameters.put("proliferation/NUCLEUS_CONDENSATION_FRACTION", randomDoubleBetween(0.25, 0.75)); + + MiniBox defaults = new MiniBox(); + defaults.put("proliferation/RATE_G1", randomDoubleBetween(1, 10)); + defaults.put("proliferation/RATE_S", randomDoubleBetween(1, 10)); + defaults.put("proliferation/RATE_G2", randomDoubleBetween(1, 10)); + defaults.put("proliferation/RATE_M", randomDoubleBetween(1, 10)); + defaults.put("proliferation/STEPS_G1", randomIntBetween(1, 100)); + defaults.put("proliferation/STEPS_S", randomIntBetween(1, 100)); + defaults.put("proliferation/STEPS_G2", randomIntBetween(1, 100)); + defaults.put("proliferation/STEPS_M", randomIntBetween(1, 100)); + defaults.put("proliferation/CELL_GROWTH_RATE", randomDoubleBetween(1, 100)); + defaults.put("proliferation/NUCLEUS_GROWTH_RATE", randomDoubleBetween(1, 100)); + defaults.put("proliferation/BASAL_APOPTOSIS_RATE", randomDoubleBetween(0, 0.5)); + defaults.put( + "proliferation/NUCLEUS_CONDENSATION_FRACTION", randomDoubleBetween(0.25, 0.75)); + parameters = new Parameters(defaults, null, random); } - + @Test public void constructor_setsParameters() { PottsCell cell = mock(PottsCell.class); doReturn(parameters).when(cell).getParameters(); PottsModuleProliferationSimple module = new PottsModuleProliferationSimple(cell); - + assertEquals(parameters.getDouble("proliferation/RATE_G1"), module.rateG1, EPSILON); assertEquals(parameters.getDouble("proliferation/RATE_S"), module.rateS, EPSILON); assertEquals(parameters.getDouble("proliferation/RATE_G2"), module.rateG2, EPSILON); @@ -77,13 +80,24 @@ public void constructor_setsParameters() { assertEquals(parameters.getInt("proliferation/STEPS_S"), module.stepsS); assertEquals(parameters.getInt("proliferation/STEPS_G2"), module.stepsG2); assertEquals(parameters.getInt("proliferation/STEPS_M"), module.stepsM); - assertEquals(parameters.getDouble("proliferation/CELL_GROWTH_RATE"), module.cellGrowthRate, EPSILON); - assertEquals(parameters.getDouble("proliferation/NUCLEUS_GROWTH_RATE"), module.nucleusGrowthRate, EPSILON); - assertEquals(parameters.getDouble("proliferation/BASAL_APOPTOSIS_RATE"), module.basalApoptosisRate, EPSILON); - assertEquals(parameters.getDouble("proliferation/NUCLEUS_CONDENSATION_FRACTION"), - module.nucleusCondFraction, EPSILON); + assertEquals( + parameters.getDouble("proliferation/CELL_GROWTH_RATE"), + module.cellGrowthRate, + EPSILON); + assertEquals( + parameters.getDouble("proliferation/NUCLEUS_GROWTH_RATE"), + module.nucleusGrowthRate, + EPSILON); + assertEquals( + parameters.getDouble("proliferation/BASAL_APOPTOSIS_RATE"), + module.basalApoptosisRate, + EPSILON); + assertEquals( + parameters.getDouble("proliferation/NUCLEUS_CONDENSATION_FRACTION"), + module.nucleusCondFraction, + EPSILON); } - + @Test public void stepG1_withStateChange_callsMethods() { PottsCell cell = mock(PottsCell.class); @@ -91,19 +105,19 @@ public void stepG1_withStateChange_callsMethods() { PottsModuleProliferationSimple module = spy(new PottsModuleProliferationSimple(cell)); module.phase = Phase.PROLIFERATIVE_G1; module.currentSteps = Integer.MAX_VALUE; - + MersenneTwisterFast random = mock(MersenneTwisterFast.class); doReturn(module.basalApoptosisRate - EPSILON).when(random).nextDouble(); PoissonFactory poissonFactory = mock(PoissonFactory.class); module.poissonFactory = poissonFactory; - + module.stepG1(random); - + verify(cell).setState(State.APOPTOTIC); verify(poissonFactory, never()).createPoisson(anyDouble(), eq(random)); verify(module, never()).setPhase(any(Phase.class)); } - + @Test public void stepG1_withoutStateChange_callsMethods() { PottsCell cell = mock(PottsCell.class); @@ -111,20 +125,20 @@ public void stepG1_withoutStateChange_callsMethods() { PottsModuleProliferationSimple module = spy(new PottsModuleProliferationSimple(cell)); module.phase = Phase.PROLIFERATIVE_G1; module.currentSteps = Integer.MAX_VALUE; - + MersenneTwisterFast random = mock(MersenneTwisterFast.class); doReturn(module.basalApoptosisRate + EPSILON).when(random).nextDouble(); PoissonFactory poissonFactory = mock(PoissonFactory.class); doReturn(poissonMock).when(poissonFactory).createPoisson(anyDouble(), eq(random)); module.poissonFactory = poissonFactory; - + module.stepG1(random); - + verify(cell, never()).setState(State.APOPTOTIC); verify(poissonFactory).createPoisson(module.rateG1, random); verify(module).setPhase(any(Phase.class)); } - + @Test public void stepG1_withTransition_updatesPhase() { int steps = randomIntBetween(1, parameters.getInt("proliferation/STEPS_G1")); @@ -133,19 +147,19 @@ public void stepG1_withTransition_updatesPhase() { PottsModuleProliferationSimple module = spy(new PottsModuleProliferationSimple(cell)); module.phase = Phase.PROLIFERATIVE_G1; module.currentSteps = module.stepsG1 - steps; - + Poisson poisson = mock(Poisson.class); doReturn(steps).when(poisson).nextInt(); PoissonFactory poissonFactory = mock(PoissonFactory.class); doReturn(poisson).when(poissonFactory).createPoisson(eq(module.rateG1), eq(random)); module.poissonFactory = poissonFactory; - + module.stepG1(random); - + verify(module).setPhase(Phase.PROLIFERATIVE_S); assertEquals(Phase.PROLIFERATIVE_S, module.phase); } - + @Test public void stepG1_withoutTransition_maintainsPhase() { PottsCell cell = mock(PottsCell.class); @@ -153,85 +167,85 @@ public void stepG1_withoutTransition_maintainsPhase() { PottsModuleProliferationSimple module = spy(new PottsModuleProliferationSimple(cell)); module.phase = Phase.PROLIFERATIVE_G1; module.currentSteps = module.stepsG1; - + Poisson poisson = mock(Poisson.class); doReturn(-1).when(poisson).nextInt(); PoissonFactory poissonFactory = mock(PoissonFactory.class); doReturn(poisson).when(poissonFactory).createPoisson(anyDouble(), eq(random)); module.poissonFactory = poissonFactory; - + module.stepG1(random); - + verify(module, never()).setPhase(any(Phase.class)); assertEquals(Phase.PROLIFERATIVE_G1, module.phase); } - + @Test public void stepG1_anyTransition_updatesCell() { PottsCell cell = mock(PottsCell.class); doReturn(parameters).when(cell).getParameters(); PottsModuleProliferationSimple module = spy(new PottsModuleProliferationSimple(cell)); - + PoissonFactory poissonFactory = mock(PoissonFactory.class); doReturn(poissonMock).when(poissonFactory).createPoisson(anyDouble(), eq(random)); module.poissonFactory = poissonFactory; - + module.currentSteps = Integer.MAX_VALUE; module.stepG1(random); module.currentSteps = 0; module.stepG1(random); - + verify(cell, times(2)).updateTarget(module.cellGrowthRate, SIZE_TARGET); } - + @Test public void stepG1_anyTransitionWithRegionOverThreshold_updatesCell() { PottsCell cell = mock(PottsCell.class); doReturn(parameters).when(cell).getParameters(); doReturn(true).when(cell).hasRegions(); - + int criticalVolume = randomIntBetween(100, 1000); doReturn((double) criticalVolume).when(cell).getCriticalVolume(Region.NUCLEUS); doReturn((double) criticalVolume + 1).when(cell).getVolume(Region.NUCLEUS); - + PottsModuleProliferationSimple module = spy(new PottsModuleProliferationSimple(cell)); - + PoissonFactory poissonFactory = mock(PoissonFactory.class); doReturn(poissonMock).when(poissonFactory).createPoisson(anyDouble(), eq(random)); module.poissonFactory = poissonFactory; - + module.currentSteps = Integer.MAX_VALUE; module.stepG1(random); module.currentSteps = 0; module.stepG1(random); - + verify(cell, times(2)).updateTarget(Region.NUCLEUS, module.nucleusGrowthRate, SIZE_TARGET); } - + @Test public void stepG1_anyTransitionWithRegionUnderThreshold_updatesCell() { PottsCell cell = mock(PottsCell.class); doReturn(parameters).when(cell).getParameters(); doReturn(true).when(cell).hasRegions(); - + int criticalVolume = randomIntBetween(100, 1000); doReturn((double) criticalVolume).when(cell).getCriticalVolume(Region.NUCLEUS); doReturn((double) criticalVolume - 1).when(cell).getVolume(Region.NUCLEUS); - + PottsModuleProliferationSimple module = spy(new PottsModuleProliferationSimple(cell)); - + PoissonFactory poissonFactory = mock(PoissonFactory.class); doReturn(poissonMock).when(poissonFactory).createPoisson(anyDouble(), eq(random)); module.poissonFactory = poissonFactory; - + module.currentSteps = Integer.MAX_VALUE; module.stepG1(random); module.currentSteps = 0; module.stepG1(random); - + verify(cell, never()).updateTarget(eq(Region.NUCLEUS), anyDouble(), anyDouble()); } - + @Test public void stepS_withTransition_updatesPhase() { int steps = randomIntBetween(1, parameters.getInt("proliferation/STEPS_S")); @@ -240,19 +254,19 @@ public void stepS_withTransition_updatesPhase() { PottsModuleProliferationSimple module = spy(new PottsModuleProliferationSimple(cell)); module.phase = Phase.PROLIFERATIVE_S; module.currentSteps = module.stepsS - steps; - + Poisson poisson = mock(Poisson.class); doReturn(steps).when(poisson).nextInt(); PoissonFactory poissonFactory = mock(PoissonFactory.class); doReturn(poisson).when(poissonFactory).createPoisson(eq(module.rateS), eq(random)); module.poissonFactory = poissonFactory; - + module.stepS(random); - + verify(module).setPhase(Phase.PROLIFERATIVE_G2); assertEquals(Phase.PROLIFERATIVE_G2, module.phase); } - + @Test public void stepS_withoutTransition_maintainsPhase() { PottsCell cell = mock(PottsCell.class); @@ -260,56 +274,56 @@ public void stepS_withoutTransition_maintainsPhase() { PottsModuleProliferationSimple module = spy(new PottsModuleProliferationSimple(cell)); module.phase = Phase.PROLIFERATIVE_S; module.currentSteps = module.stepsS; - + Poisson poisson = mock(Poisson.class); doReturn(-1).when(poisson).nextInt(); PoissonFactory poissonFactory = mock(PoissonFactory.class); doReturn(poisson).when(poissonFactory).createPoisson(anyDouble(), eq(random)); module.poissonFactory = poissonFactory; - + module.stepS(random); - + verify(module, never()).setPhase(any(Phase.class)); assertEquals(Phase.PROLIFERATIVE_S, module.phase); } - + @Test public void stepS_anyTransition_updatesCell() { PottsCell cell = mock(PottsCell.class); doReturn(parameters).when(cell).getParameters(); PottsModuleProliferationSimple module = spy(new PottsModuleProliferationSimple(cell)); - + PoissonFactory poissonFactory = mock(PoissonFactory.class); doReturn(poissonMock).when(poissonFactory).createPoisson(anyDouble(), eq(random)); module.poissonFactory = poissonFactory; - + module.currentSteps = Integer.MAX_VALUE; module.stepS(random); module.currentSteps = 0; module.stepS(random); - + verify(cell, times(2)).updateTarget(module.cellGrowthRate, SIZE_TARGET); } - + @Test public void stepS_anyTransitionWithRegion_updatesCell() { PottsCell cell = mock(PottsCell.class); doReturn(parameters).when(cell).getParameters(); doReturn(true).when(cell).hasRegions(); PottsModuleProliferationSimple module = spy(new PottsModuleProliferationSimple(cell)); - + PoissonFactory poissonFactory = mock(PoissonFactory.class); doReturn(poissonMock).when(poissonFactory).createPoisson(anyDouble(), eq(random)); module.poissonFactory = poissonFactory; - + module.currentSteps = Integer.MAX_VALUE; module.stepS(random); module.currentSteps = 0; module.stepS(random); - + verify(cell, times(2)).updateTarget(Region.NUCLEUS, module.nucleusGrowthRate, SIZE_TARGET); } - + @Test public void stepG2_withStateChange_callsMethods() { PottsCell cell = mock(PottsCell.class); @@ -317,19 +331,19 @@ public void stepG2_withStateChange_callsMethods() { PottsModuleProliferationSimple module = spy(new PottsModuleProliferationSimple(cell)); module.phase = Phase.PROLIFERATIVE_G2; module.currentSteps = Integer.MAX_VALUE; - + MersenneTwisterFast random = mock(MersenneTwisterFast.class); doReturn(module.basalApoptosisRate - EPSILON).when(random).nextDouble(); PoissonFactory poissonFactory = mock(PoissonFactory.class); module.poissonFactory = poissonFactory; - + module.stepG2(random); - + verify(cell).setState(State.APOPTOTIC); verify(poissonFactory, never()).createPoisson(anyDouble(), eq(random)); verify(module, never()).setPhase(any(Phase.class)); } - + @Test public void stepG2_withoutStateChange_callsMethods() { PottsCell cell = mock(PottsCell.class); @@ -337,20 +351,20 @@ public void stepG2_withoutStateChange_callsMethods() { PottsModuleProliferationSimple module = spy(new PottsModuleProliferationSimple(cell)); module.phase = Phase.PROLIFERATIVE_G2; module.currentSteps = Integer.MAX_VALUE; - + MersenneTwisterFast random = mock(MersenneTwisterFast.class); doReturn(module.basalApoptosisRate + EPSILON).when(random).nextDouble(); PoissonFactory poissonFactory = mock(PoissonFactory.class); doReturn(poissonMock).when(poissonFactory).createPoisson(anyDouble(), eq(random)); module.poissonFactory = poissonFactory; - + module.stepG2(random); - + verify(cell, never()).setState(State.APOPTOTIC); verify(poissonFactory).createPoisson(module.rateG2, random); verify(module).setPhase(any(Phase.class)); } - + @Test public void stepG2_withTransitionNotArrested_updatesPhase() { int steps = randomIntBetween(1, parameters.getInt("proliferation/STEPS_G2")); @@ -359,23 +373,23 @@ public void stepG2_withTransitionNotArrested_updatesPhase() { double volume = randomDoubleBetween(0, 100); doReturn((volume * SIZE_CHECKPOINT * SIZE_TARGET) + 1).when(cell).getVolume(); doReturn(volume).when(cell).getCriticalVolume(); - + PottsModuleProliferationSimple module = spy(new PottsModuleProliferationSimple(cell)); module.phase = Phase.PROLIFERATIVE_G2; module.currentSteps = module.stepsG2 - steps; - + Poisson poisson = mock(Poisson.class); doReturn(steps).when(poisson).nextInt(); PoissonFactory poissonFactory = mock(PoissonFactory.class); doReturn(poisson).when(poissonFactory).createPoisson(eq(module.rateG2), eq(random)); module.poissonFactory = poissonFactory; - + module.stepG2(random); - + verify(module).setPhase(Phase.PROLIFERATIVE_M); assertEquals(Phase.PROLIFERATIVE_M, module.phase); } - + @Test public void stepG2_withoutTransitionNotArrested_maintainsPhase() { PottsCell cell = mock(PottsCell.class); @@ -383,23 +397,23 @@ public void stepG2_withoutTransitionNotArrested_maintainsPhase() { double volume = randomDoubleBetween(0, 100); doReturn((volume * SIZE_CHECKPOINT * SIZE_TARGET) + 1).when(cell).getVolume(); doReturn(volume).when(cell).getCriticalVolume(); - + PottsModuleProliferationSimple module = spy(new PottsModuleProliferationSimple(cell)); module.phase = Phase.PROLIFERATIVE_G2; module.currentSteps = module.stepsG2; - + Poisson poisson = mock(Poisson.class); doReturn(-1).when(poisson).nextInt(); PoissonFactory poissonFactory = mock(PoissonFactory.class); doReturn(poisson).when(poissonFactory).createPoisson(anyDouble(), eq(random)); module.poissonFactory = poissonFactory; - + module.stepG2(random); - + verify(module, never()).setPhase(any(Phase.class)); assertEquals(Phase.PROLIFERATIVE_G2, module.phase); } - + @Test public void stepG2_withTransitionArrested_maintainsPhase() { int steps = randomIntBetween(1, parameters.getInt("proliferation/STEPS_G2")); @@ -408,54 +422,56 @@ public void stepG2_withTransitionArrested_maintainsPhase() { double volume = randomDoubleBetween(0, 100); doReturn((volume * SIZE_CHECKPOINT * SIZE_TARGET) - 1).when(cell).getVolume(); doReturn(volume).when(cell).getCriticalVolume(); - + PottsModuleProliferationSimple module = spy(new PottsModuleProliferationSimple(cell)); module.phase = Phase.PROLIFERATIVE_G2; module.currentSteps = module.stepsG2 - steps; - + Poisson poisson = mock(Poisson.class); doReturn(steps).when(poisson).nextInt(); PoissonFactory poissonFactory = mock(PoissonFactory.class); doReturn(poisson).when(poissonFactory).createPoisson(eq(module.rateG2), eq(random)); module.poissonFactory = poissonFactory; - + module.stepG2(random); - + verify(module, never()).setPhase(any(Phase.class)); assertEquals(Phase.PROLIFERATIVE_G2, module.phase); } - + @Test public void stepG2_withTransitionArrestedRegion_maintainsPhase() { int steps = randomIntBetween(1, parameters.getInt("proliferation/STEPS_G2")); PottsCell cell = mock(PottsCell.class); doReturn(parameters).when(cell).getParameters(); doReturn(true).when(cell).hasRegions(); - + double volume = randomDoubleBetween(0, 100); doReturn((volume * SIZE_CHECKPOINT * SIZE_TARGET) + 1).when(cell).getVolume(); doReturn(volume).when(cell).getCriticalVolume(); - + double regionVolume = randomDoubleBetween(0, 100); - doReturn((regionVolume * SIZE_CHECKPOINT * SIZE_TARGET) - 1).when(cell).getVolume(Region.NUCLEUS); + doReturn((regionVolume * SIZE_CHECKPOINT * SIZE_TARGET) - 1) + .when(cell) + .getVolume(Region.NUCLEUS); doReturn(regionVolume).when(cell).getCriticalVolume(Region.NUCLEUS); - + PottsModuleProliferationSimple module = spy(new PottsModuleProliferationSimple(cell)); module.phase = Phase.PROLIFERATIVE_G2; module.currentSteps = module.stepsG2 - steps; - + Poisson poisson = mock(Poisson.class); doReturn(steps).when(poisson).nextInt(); PoissonFactory poissonFactory = mock(PoissonFactory.class); doReturn(poisson).when(poissonFactory).createPoisson(eq(module.rateG2), eq(random)); module.poissonFactory = poissonFactory; - + module.stepG2(random); - + verify(module, never()).setPhase(any(Phase.class)); assertEquals(Phase.PROLIFERATIVE_G2, module.phase); } - + @Test public void stepM_withoutTransitionArrested_maintainPhase() { PottsCell cell = mock(PottsCell.class); @@ -463,60 +479,60 @@ public void stepM_withoutTransitionArrested_maintainPhase() { double volume = randomDoubleBetween(0, 100); doReturn((volume * SIZE_CHECKPOINT * SIZE_TARGET) - 1).when(cell).getVolume(); doReturn(volume).when(cell).getCriticalVolume(); - + PottsModuleProliferationSimple module = spy(new PottsModuleProliferationSimple(cell)); module.phase = Phase.PROLIFERATIVE_G2; module.currentSteps = module.stepsG2; - + Poisson poisson = mock(Poisson.class); doReturn(-1).when(poisson).nextInt(); PoissonFactory poissonFactory = mock(PoissonFactory.class); doReturn(poisson).when(poissonFactory).createPoisson(anyDouble(), eq(random)); module.poissonFactory = poissonFactory; - + module.stepG2(random); - + verify(module, never()).setPhase(any(Phase.class)); assertEquals(Phase.PROLIFERATIVE_G2, module.phase); } - + @Test public void stepG2_anyTransition_updatesCell() { PottsCell cell = mock(PottsCell.class); doReturn(parameters).when(cell).getParameters(); PottsModuleProliferationSimple module = spy(new PottsModuleProliferationSimple(cell)); - + PoissonFactory poissonFactory = mock(PoissonFactory.class); doReturn(poissonMock).when(poissonFactory).createPoisson(anyDouble(), eq(random)); module.poissonFactory = poissonFactory; - + module.currentSteps = Integer.MAX_VALUE; module.stepG2(random); module.currentSteps = 0; module.stepG2(random); - + verify(cell, times(2)).updateTarget(module.cellGrowthRate, SIZE_TARGET); } - + @Test public void stepG2_anyTransitionWithRegion_updatesCell() { PottsCell cell = mock(PottsCell.class); doReturn(parameters).when(cell).getParameters(); doReturn(true).when(cell).hasRegions(); PottsModuleProliferationSimple module = spy(new PottsModuleProliferationSimple(cell)); - + PoissonFactory poissonFactory = mock(PoissonFactory.class); doReturn(poissonMock).when(poissonFactory).createPoisson(anyDouble(), eq(random)); module.poissonFactory = poissonFactory; - + module.currentSteps = Integer.MAX_VALUE; module.stepG2(random); module.currentSteps = 0; module.stepG2(random); - + verify(cell, times(2)).updateTarget(Region.NUCLEUS, module.nucleusGrowthRate, SIZE_TARGET); } - + @Test public void stepM_withTransition_updatesPhase() { int steps = randomIntBetween(1, parameters.getInt("proliferation/STEPS_M")); @@ -526,20 +542,20 @@ public void stepM_withTransition_updatesPhase() { module.phase = Phase.PROLIFERATIVE_M; module.currentSteps = module.stepsM - steps; doNothing().when(module).addCell(random, simMock); - + Poisson poisson = mock(Poisson.class); doReturn(steps).when(poisson).nextInt(); PoissonFactory poissonFactory = mock(PoissonFactory.class); doReturn(poisson).when(poissonFactory).createPoisson(eq(module.rateM), eq(random)); module.poissonFactory = poissonFactory; - + module.stepM(random, simMock); - + verify(module).addCell(random, simMock); verify(module).setPhase(Phase.PROLIFERATIVE_G1); assertEquals(Phase.PROLIFERATIVE_G1, module.phase); } - + @Test public void stepM_withoutTransition_maintainsPhase() { PottsCell cell = mock(PottsCell.class); @@ -548,39 +564,39 @@ public void stepM_withoutTransition_maintainsPhase() { module.phase = Phase.PROLIFERATIVE_M; module.currentSteps = module.stepsM; doNothing().when(module).addCell(random, simMock); - + Poisson poisson = mock(Poisson.class); doReturn(-1).when(poisson).nextInt(); PoissonFactory poissonFactory = mock(PoissonFactory.class); doReturn(poisson).when(poissonFactory).createPoisson(anyDouble(), eq(random)); module.poissonFactory = poissonFactory; - + module.stepM(random, simMock); - + verify(module, never()).addCell(random, simMock); verify(module, never()).setPhase(any(Phase.class)); assertEquals(Phase.PROLIFERATIVE_M, module.phase); } - + @Test public void stepM_anyTransition_updatesCell() { PottsCell cell = mock(PottsCell.class); doReturn(parameters).when(cell).getParameters(); PottsModuleProliferationSimple module = spy(new PottsModuleProliferationSimple(cell)); doNothing().when(module).addCell(random, simMock); - + PoissonFactory poissonFactory = mock(PoissonFactory.class); doReturn(poissonMock).when(poissonFactory).createPoisson(anyDouble(), eq(random)); module.poissonFactory = poissonFactory; - + module.currentSteps = Integer.MAX_VALUE; module.stepM(random, simMock); module.currentSteps = 0; module.stepM(random, simMock); - + verify(cell, times(2)).updateTarget(module.cellGrowthRate, SIZE_TARGET); } - + @Test public void stepM_withRegionOverThreshold_doesNotUpdateCell() { PottsCell cell = mock(PottsCell.class); @@ -588,40 +604,41 @@ public void stepM_withRegionOverThreshold_doesNotUpdateCell() { doReturn(cellID).when(cell).getID(); doReturn(parameters).when(cell).getParameters(); doReturn(true).when(cell).hasRegions(); - + int criticalVolume = randomIntBetween(100, 1000); doReturn((double) criticalVolume).when(cell).getCriticalVolume(Region.NUCLEUS); doReturn((double) criticalVolume - 1).when(cell).getVolume(Region.NUCLEUS); - + PottsLocations loc = mock(PottsLocations.class); doReturn(loc).when(cell).getLocation(); - + int[][][] ids = new int[0][0][0]; int[][][] regions = new int[0][0][0]; pottsMock.ids = ids; pottsMock.regions = regions; - + PottsModuleProliferationSimple module = spy(new PottsModuleProliferationSimple(cell)); doNothing().when(module).addCell(random, simMock); - + PoissonFactory poissonFactory = mock(PoissonFactory.class); doReturn(poissonMock).when(poissonFactory).createPoisson(anyDouble(), eq(random)); module.poissonFactory = poissonFactory; - + module.currentSteps = Integer.MAX_VALUE; module.stepM(random, simMock); module.currentSteps = 0; module.stepM(random, simMock); - - double nucleusCondFraction = parameters.getDouble("proliferation/NUCLEUS_CONDENSATION_FRACTION"); + + double nucleusCondFraction = + parameters.getDouble("proliferation/NUCLEUS_CONDENSATION_FRACTION"); int target = (int) (nucleusCondFraction * criticalVolume); - + verify(loc, never()).distribute(Region.NUCLEUS, target, random); verify(loc, never()).update(cellID, ids, regions); verify(cell, never()).setTargets(eq(Region.DEFAULT), anyDouble(), anyDouble()); verify(cell, never()).setTargets(eq(Region.NUCLEUS), anyDouble(), anyDouble()); } - + @Test public void stepM_withRegionUnderThreshold_updatesCell() { PottsCell cell = mock(PottsCell.class); @@ -629,34 +646,35 @@ public void stepM_withRegionUnderThreshold_updatesCell() { doReturn(cellID).when(cell).getID(); doReturn(parameters).when(cell).getParameters(); doReturn(true).when(cell).hasRegions(); - + int criticalVolume = randomIntBetween(100, 1000); doReturn((double) criticalVolume).when(cell).getCriticalVolume(Region.NUCLEUS); doReturn((double) criticalVolume + 1).when(cell).getVolume(Region.NUCLEUS); - + PottsLocations loc = mock(PottsLocations.class); doReturn(loc).when(cell).getLocation(); - + int[][][] ids = new int[0][0][0]; int[][][] regions = new int[0][0][0]; pottsMock.ids = ids; pottsMock.regions = regions; - + PottsModuleProliferationSimple module = spy(new PottsModuleProliferationSimple(cell)); doNothing().when(module).addCell(random, simMock); - + PoissonFactory poissonFactory = mock(PoissonFactory.class); doReturn(poissonMock).when(poissonFactory).createPoisson(anyDouble(), eq(random)); module.poissonFactory = poissonFactory; - + module.currentSteps = Integer.MAX_VALUE; module.stepM(random, simMock); module.currentSteps = 0; module.stepM(random, simMock); - - double nucleusCondFraction = parameters.getDouble("proliferation/NUCLEUS_CONDENSATION_FRACTION"); + + double nucleusCondFraction = + parameters.getDouble("proliferation/NUCLEUS_CONDENSATION_FRACTION"); int target = (int) (nucleusCondFraction * criticalVolume); - + verify(loc, times(2)).distribute(Region.NUCLEUS, target, random); verify(loc, times(2)).update(cellID, ids, regions); verify(cell, times(2)).setTargets(eq(Region.DEFAULT), anyDouble(), anyDouble()); diff --git a/test/arcade/potts/agent/module/PottsModuleProliferationTest.java b/test/arcade/potts/agent/module/PottsModuleProliferationTest.java index 0403167d9..cc5400a37 100644 --- a/test/arcade/potts/agent/module/PottsModuleProliferationTest.java +++ b/test/arcade/potts/agent/module/PottsModuleProliferationTest.java @@ -1,64 +1,68 @@ package arcade.potts.agent.module; -import org.junit.Test; +import org.junit.jupiter.api.Test; import sim.engine.Schedule; import ec.util.MersenneTwisterFast; +import arcade.core.agent.cell.CellFactory; import arcade.core.env.grid.Grid; import arcade.core.sim.Simulation; -import arcade.core.util.MiniBox; +import arcade.core.util.Parameters; import arcade.potts.agent.cell.PottsCell; +import arcade.potts.agent.cell.PottsCellContainer; import arcade.potts.env.location.PottsLocation; import arcade.potts.sim.Potts; import arcade.potts.sim.PottsSimulation; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.core.ARCADETestUtilities.*; import static arcade.potts.util.PottsEnums.Phase; import static arcade.potts.util.PottsEnums.State; public class PottsModuleProliferationTest { - static MersenneTwisterFast randomMock = new MersenneTwisterFast(randomSeed()); - + static MersenneTwisterFast randomMock = new MersenneTwisterFast(); + static PottsSimulation simMock = mock(PottsSimulation.class); - + static PottsCell cellMock = mock(PottsCell.class); - + static class PottsModuleProliferationMock extends PottsModuleProliferation { - PottsModuleProliferationMock(PottsCell cell) { super(cell); } - + PottsModuleProliferationMock(PottsCell cell) { + super(cell); + } + @Override void stepG1(MersenneTwisterFast random) { setPhase(Phase.PROLIFERATIVE_S); } - + @Override void stepS(MersenneTwisterFast random) { setPhase(Phase.PROLIFERATIVE_G2); } - + @Override void stepG2(MersenneTwisterFast random) { setPhase(Phase.PROLIFERATIVE_M); } - + @Override void stepM(MersenneTwisterFast random, Simulation sim) { setPhase(Phase.PROLIFERATIVE_G1); } } - + @Test public void constructor_initializesFactory() { PottsModuleProliferationMock module = new PottsModuleProliferationMock(cellMock); assertNotNull(module.poissonFactory); } - + @Test public void getPhase_defaultConstructor_returnsValue() { PottsModuleProliferation module = new PottsModuleProliferationMock(cellMock); assertEquals(Phase.PROLIFERATIVE_G1, module.getPhase()); } - + @Test public void setPhase_givenValue_setsValue() { Phase phase = Phase.random(randomMock); @@ -66,7 +70,7 @@ public void setPhase_givenValue_setsValue() { module.setPhase(phase); assertEquals(phase, module.phase); } - + @Test public void setPhase_givenValue_resetsSteps() { Phase phase = Phase.random(randomMock); @@ -75,102 +79,108 @@ public void setPhase_givenValue_resetsSteps() { module.setPhase(phase); assertEquals(0, module.currentSteps); } - + @Test public void step_givenPhaseG1_callsMethod() { PottsModuleProliferation module = spy(new PottsModuleProliferationMock(cellMock)); module.phase = Phase.PROLIFERATIVE_G1; - + module.step(randomMock, simMock); verify(module).stepG1(randomMock); verify(module, never()).stepS(randomMock); verify(module, never()).stepG2(randomMock); verify(module, never()).stepM(randomMock, simMock); } - + @Test public void step_givenPhaseS_callsMethod() { PottsModuleProliferation module = spy(new PottsModuleProliferationMock(cellMock)); module.phase = Phase.PROLIFERATIVE_S; - + module.step(randomMock, simMock); verify(module).stepS(randomMock); verify(module, never()).stepG1(randomMock); verify(module, never()).stepG2(randomMock); verify(module, never()).stepM(randomMock, simMock); } - + @Test public void step_givenPhaseG2_callsMethod() { PottsModuleProliferation module = spy(new PottsModuleProliferationMock(cellMock)); module.phase = Phase.PROLIFERATIVE_G2; - + module.step(randomMock, simMock); verify(module).stepG2(randomMock); verify(module, never()).stepG1(randomMock); verify(module, never()).stepS(randomMock); verify(module, never()).stepM(randomMock, simMock); } - + @Test public void step_givenPhaseM_callsMethod() { PottsModuleProliferation module = spy(new PottsModuleProliferationMock(cellMock)); doNothing().when(module).addCell(randomMock, simMock); module.phase = Phase.PROLIFERATIVE_M; - + module.step(randomMock, simMock); verify(module).stepM(randomMock, simMock); verify(module, never()).stepG1(randomMock); verify(module, never()).stepS(randomMock); verify(module, never()).stepG2(randomMock); } - + @Test public void step_invalidPhase_doesNothing() { PottsModuleProliferation module = spy(new PottsModuleProliferationMock(cellMock)); module.phase = Phase.UNDEFINED; - + module.step(randomMock, simMock); verify(module, never()).stepG1(randomMock); verify(module, never()).stepS(randomMock); verify(module, never()).stepG2(randomMock); verify(module, never()).stepM(randomMock, simMock); } - + @Test public void addCell_called_addsObject() { PottsCell cell = mock(PottsCell.class); - MiniBox box = mock(MiniBox.class); - doReturn(0.).when(box).getDouble(anyString()); - doReturn(box).when(cell).getParameters(); - + Parameters parameters = mock(Parameters.class); + doReturn(0.).when(parameters).getDouble(anyString()); + doReturn(parameters).when(cell).getParameters(); + PottsLocation location = mock(PottsLocation.class); Potts potts = mock(Potts.class); Grid grid = mock(Grid.class); PottsSimulation sim = mock(PottsSimulation.class); + CellFactory cellFactory = mock(CellFactory.class); Schedule schedule = mock(Schedule.class); - + int id = randomIntBetween(1, 100); doReturn(potts).when(sim).getPotts(); doReturn(id).when(sim).getID(); doReturn(grid).when(sim).getGrid(); doReturn(schedule).when(sim).getSchedule(); - - potts.ids = new int[][][] { { { } } }; - potts.regions = new int[][][] { { { } } }; - + doReturn(cellFactory).when(sim).getCellFactory(); + + potts.ids = new int[][][] {{{}}}; + potts.regions = new int[][][] {{{}}}; + PottsLocation newLocation = mock(PottsLocation.class); + PottsCellContainer newContainer = mock(PottsCellContainer.class); PottsCell newCell = mock(PottsCell.class); - - doReturn(newCell).when(cell).make(eq(id), any(State.class), eq(newLocation), eq(randomMock)); + + doReturn(newContainer).when(cell).make(eq(id), any(State.class), eq(randomMock)); + doReturn(newCell) + .when(newContainer) + .convert(eq(cellFactory), eq(newLocation), eq(randomMock), eq(parameters)); doReturn(location).when(cell).getLocation(); doReturn(newLocation).when(location).split(randomMock); doNothing().when(cell).reset(any(), any()); doNothing().when(newCell).reset(any(), any()); - + PottsModuleProliferation module = new PottsModuleProliferationMock(cell); module.addCell(randomMock, sim); - + verify(cell).reset(potts.ids, potts.regions); verify(newCell).reset(potts.ids, potts.regions); verify(grid).addObject(newCell, null); diff --git a/test/arcade/potts/env/grid/PottsGridTest.java b/test/arcade/potts/env/grid/PottsGridTest.java index bac6a2610..d93fc06d4 100644 --- a/test/arcade/potts/env/grid/PottsGridTest.java +++ b/test/arcade/potts/env/grid/PottsGridTest.java @@ -1,9 +1,9 @@ package arcade.potts.env.grid; -import org.junit.Test; +import org.junit.jupiter.api.Test; import sim.util.Bag; import arcade.core.agent.cell.Cell; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; public class PottsGridTest { @@ -12,13 +12,13 @@ private static Cell createObjectMock(int id) { doReturn(id).when(object).getID(); return object; } - + @Test public void getAllObjects_withoutContents_returnsEmpty() { PottsGrid grid = new PottsGrid(); assertEquals(0, grid.getAllObjects().size()); } - + @Test public void getAllObjects_withContents_returnsContents() { Cell objectA = createObjectMock(1); @@ -30,20 +30,20 @@ public void getAllObjects_withContents_returnsContents() { assertTrue(grid.getAllObjects().contains(objectA)); assertTrue(grid.getAllObjects().contains(objectB)); } - + @Test public void addObject_validID_updatesObject() { Cell object = createObjectMock(1); PottsGrid grid = new PottsGrid(); grid.addObject(object, null); - + Bag allObjects = new Bag(); allObjects.add(object); - + assertEquals(1, grid.allObjects.size()); assertSame(allObjects.get(0), grid.allObjects.get(0)); } - + @Test public void addObject_existingID_doesNothing() { Cell objectA = createObjectMock(1); @@ -51,14 +51,14 @@ public void addObject_existingID_doesNothing() { PottsGrid grid = new PottsGrid(); grid.addObject(objectA, null); grid.addObject(objectB, null); - + Bag allObjects = new Bag(); allObjects.add(objectA); - + assertEquals(1, grid.allObjects.size()); assertSame(allObjects.get(0), grid.allObjects.get(0)); } - + @Test public void addObject_zeroID_doesNothing() { Cell object = createObjectMock(0); @@ -66,14 +66,14 @@ public void addObject_zeroID_doesNothing() { grid.addObject(object, null); assertEquals(0, grid.allObjects.size()); } - + @Test public void addObject_nullObject_doesNothing() { PottsGrid grid = new PottsGrid(); grid.addObject(null, null); assertEquals(0, grid.allObjects.size()); } - + @Test public void removeObject_existingID_updatesObject() { Cell objectA = createObjectMock(1); @@ -82,14 +82,14 @@ public void removeObject_existingID_updatesObject() { grid.addObject(objectA, null); grid.addObject(objectB, null); grid.removeObject(objectA, null); - + Bag allObjects = new Bag(); allObjects.add(objectB); - + assertEquals(1, grid.allObjects.size()); assertSame(allObjects.get(0), grid.allObjects.get(0)); } - + @Test public void removeObject_invalidID_doesNothing() { Cell objectA = createObjectMock(1); @@ -97,14 +97,14 @@ public void removeObject_invalidID_doesNothing() { PottsGrid grid = new PottsGrid(); grid.addObject(objectA, null); grid.removeObject(objectB, null); - + Bag allObjects = new Bag(); allObjects.add(objectA); - + assertEquals(1, grid.allObjects.size()); assertSame(allObjects.get(0), grid.allObjects.get(0)); } - + @Test public void removeObject_zeroID_doesNothing() { Cell object = createObjectMock(0); @@ -112,21 +112,21 @@ public void removeObject_zeroID_doesNothing() { grid.removeObject(object, null); assertEquals(0, grid.allObjects.size()); } - + @Test public void moveObject_anyID_doesNothing() { Cell objectA = createObjectMock(1); PottsGrid grid = new PottsGrid(); grid.addObject(objectA, null); grid.moveObject(objectA, null, null); - + Bag allObjects = new Bag(); allObjects.add(objectA); - + assertEquals(1, grid.allObjects.size()); assertSame(allObjects.get(0), grid.allObjects.get(0)); } - + @Test public void getObjectAt_validID_returnObject() { Cell objectA = createObjectMock(1); @@ -134,17 +134,17 @@ public void getObjectAt_validID_returnObject() { PottsGrid grid = new PottsGrid(); grid.addObject(objectA, null); grid.addObject(objectB, null); - + assertSame(objectA, grid.getObjectAt(1)); assertSame(objectB, grid.getObjectAt(2)); } - + @Test public void getObjectAt_invalidID_returnNull() { PottsGrid grid = new PottsGrid(); assertNull(grid.getObjectAt(1)); } - + @Test public void getObjectAt_zeroID_returnNull() { PottsGrid grid = new PottsGrid(); diff --git a/test/arcade/potts/env/location/Location2DTest.java b/test/arcade/potts/env/location/Location2DTest.java index c1ad6a363..cf1763146 100644 --- a/test/arcade/potts/env/location/Location2DTest.java +++ b/test/arcade/potts/env/location/Location2DTest.java @@ -2,9 +2,9 @@ import java.util.ArrayList; import java.util.HashMap; -import org.junit.BeforeClass; -import org.junit.Test; -import static org.junit.Assert.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; import static arcade.core.ARCADETestUtilities.*; import static arcade.potts.env.location.Voxel.VOXEL_COMPARATOR; import static arcade.potts.util.PottsEnums.Direction; @@ -12,43 +12,44 @@ public class Location2DTest { private static final double EPSILON = 1E-10; - + static ArrayList voxelListForDiameters; - - private static final int[][] VOLUME_SURFACE = new int[][] { - { 1, 4 }, - { 9, 12 }, - { 25, 21 }, - { 45, 29 }, - { 69, 36 }, - { 109, 45 }, - { 145, 52 }, - { 193, 61 }, - { 249, 69 }, - { 305, 77 }, - { 373, 85 }, - { 437, 92 }, - { 517, 100 }, - { 609, 109 }, - { 697, 117 }, - { 793, 124 }, - { 889, 132 }, - { 1005, 140 }, - { 1125, 149 }, - { 1245, 157 }, - { 1369, 164 }, - { 1513, 173 }, - { 1649, 181 }, - { 1789, 188 }, - { 1941, 196 }, - { 2109, 205 }, - { 2285, 213 }, - { 2449, 221 }, - { 2617, 228 }, - { 2809, 237 }, - }; - - @BeforeClass + + private static final int[][] VOLUME_SURFACE = + new int[][] { + {1, 4}, + {9, 12}, + {25, 21}, + {45, 29}, + {69, 36}, + {109, 45}, + {145, 52}, + {193, 61}, + {249, 69}, + {305, 77}, + {373, 85}, + {437, 92}, + {517, 100}, + {609, 109}, + {697, 117}, + {793, 124}, + {889, 132}, + {1005, 140}, + {1125, 149}, + {1245, 157}, + {1369, 164}, + {1513, 173}, + {1649, 181}, + {1789, 188}, + {1941, 196}, + {2109, 205}, + {2285, 213}, + {2449, 221}, + {2617, 228}, + {2809, 237}, + }; + + @BeforeAll public static void setupLists() { voxelListForDiameters = new ArrayList<>(); voxelListForDiameters.add(new Voxel(5, 3, 0)); @@ -62,7 +63,7 @@ public static void setupLists() { voxelListForDiameters.add(new Voxel(8, 5, 0)); voxelListForDiameters.add(new Voxel(8, 6, 0)); } - + @Test public void getNeighbors_givenLocation_returnsList() { ArrayList voxels = new ArrayList<>(); @@ -70,16 +71,16 @@ public void getNeighbors_givenLocation_returnsList() { voxels.add(new Voxel(1, 0, 0)); voxels.add(new Voxel(0, -1, 0)); voxels.add(new Voxel(0, 1, 0)); - + PottsLocation2D loc = new PottsLocation2D(new ArrayList<>()); ArrayList neighbors = loc.getNeighbors(new Voxel(0, 0, 0)); - + voxels.sort(VOXEL_COMPARATOR); neighbors.sort(VOXEL_COMPARATOR); - + assertEquals(voxels, neighbors); } - + @Test public void getNeighbors_givenLocations_returnsList() { ArrayList voxels = new ArrayList<>(); @@ -87,16 +88,16 @@ public void getNeighbors_givenLocations_returnsList() { voxels.add(new Voxel(1, 0, 0)); voxels.add(new Voxel(0, -1, 0)); voxels.add(new Voxel(0, 1, 0)); - + PottsLocations2D loc = new PottsLocations2D(new ArrayList<>()); ArrayList neighbors = loc.getNeighbors(new Voxel(0, 0, 0)); - + voxels.sort(VOXEL_COMPARATOR); neighbors.sort(VOXEL_COMPARATOR); - + assertEquals(voxels, neighbors); } - + @Test public void getDiameters_validLocation_calculatesValues() { PottsLocation2D loc = new PottsLocation2D(voxelListForDiameters); @@ -106,7 +107,7 @@ public void getDiameters_validLocation_calculatesValues() { assertEquals(4, (int) diameters.get(Direction.POSITIVE_XY)); assertEquals(3, (int) diameters.get(Direction.NEGATIVE_XY)); } - + @Test public void getDiameters_invalidLocation_returnsZero() { PottsLocation2D loc = new PottsLocation2D(new ArrayList<>()); @@ -116,7 +117,7 @@ public void getDiameters_invalidLocation_returnsZero() { assertEquals(0, (int) diameters.get(Direction.POSITIVE_XY)); assertEquals(0, (int) diameters.get(Direction.NEGATIVE_XY)); } - + @Test public void getDiameters_validLocations_calculatesValues() { PottsLocations2D loc = new PottsLocations2D(voxelListForDiameters); @@ -126,7 +127,7 @@ public void getDiameters_validLocations_calculatesValues() { assertEquals(4, (int) diameters.get(Direction.POSITIVE_XY)); assertEquals(3, (int) diameters.get(Direction.NEGATIVE_XY)); } - + @Test public void getDiameters_invalidLocations_returnsZero() { PottsLocations2D loc = new PottsLocations2D(new ArrayList<>()); @@ -136,7 +137,7 @@ public void getDiameters_invalidLocations_returnsZero() { assertEquals(0, (int) diameters.get(Direction.POSITIVE_XY)); assertEquals(0, (int) diameters.get(Direction.NEGATIVE_XY)); } - + @Test public void convertSurface_givenLocationValue_calculatesValue() { PottsLocation2D loc = new PottsLocation2D(new ArrayList<>()); @@ -144,7 +145,7 @@ public void convertSurface_givenLocationValue_calculatesValue() { assertEquals(sv[1], loc.convertSurface(sv[0], 1), EPSILON); } } - + @Test public void convertSurface_givenLocationsValue_calculatesValue() { PottsLocations2D loc = new PottsLocations2D(new ArrayList<>()); @@ -152,23 +153,24 @@ public void convertSurface_givenLocationsValue_calculatesValue() { assertEquals(sv[1], loc.convertSurface(sv[0], 1), EPSILON); } } - + @Test public void calculateSurface_emptyList_returnsZero() { PottsLocation2D loc = new PottsLocation2D(new ArrayList<>()); assertEquals(0, loc.calculateSurface()); } - + @Test public void calculateSurface_validVoxels_returnsValue() { - int[] surfaces = new int[] { 4, 6, 8, 8 }; - int[][][] voxelLists = new int[][][] { - { { 1, 1, 0 } }, - { { 1, 1, 0 }, { 2, 1, 0 } }, - { { 1, 1, 0 }, { 2, 1, 0 }, { 1, 2, 0 } }, - { { 1, 1, 0 }, { 2, 1, 0 }, { 1, 2, 0 }, { 2, 2, 0 } }, - }; - + int[] surfaces = new int[] {4, 6, 8, 8}; + int[][][] voxelLists = + new int[][][] { + {{1, 1, 0}}, + {{1, 1, 0}, {2, 1, 0}}, + {{1, 1, 0}, {2, 1, 0}, {1, 2, 0}}, + {{1, 1, 0}, {2, 1, 0}, {1, 2, 0}, {2, 2, 0}}, + }; + for (int i = 0; i < surfaces.length; i++) { ArrayList voxels = new ArrayList<>(); for (int[] v : voxelLists[i]) { @@ -178,23 +180,24 @@ public void calculateSurface_validVoxels_returnsValue() { assertEquals(surfaces[i], loc.calculateSurface()); } } - + @Test public void calculateHeight_emptyList_returnsZero() { PottsLocation2D loc = new PottsLocation2D(new ArrayList<>()); assertEquals(0, loc.calculateHeight()); } - + @Test public void calculateHeight_validVoxels_returnsValue() { - int[] heights = new int[] { 1, 1, 1, 1 }; - int[][][] voxelLists = new int[][][] { - { { 1, 1, 0 } }, - { { 1, 1, 0 }, { 2, 1, 0 } }, - { { 1, 1, 0 }, { 2, 1, 0 }, { 1, 2, 0 } }, - { { 1, 1, 0 }, { 2, 1, 0 }, { 1, 2, 0 }, { 2, 2, 0 } }, - }; - + int[] heights = new int[] {1, 1, 1, 1}; + int[][][] voxelLists = + new int[][][] { + {{1, 1, 0}}, + {{1, 1, 0}, {2, 1, 0}}, + {{1, 1, 0}, {2, 1, 0}, {1, 2, 0}}, + {{1, 1, 0}, {2, 1, 0}, {1, 2, 0}, {2, 2, 0}}, + }; + for (int i = 0; i < heights.length; i++) { ArrayList voxels = new ArrayList<>(); for (int[] v : voxelLists[i]) { @@ -204,18 +207,19 @@ public void calculateHeight_validVoxels_returnsValue() { assertEquals(heights[i], loc.calculateHeight()); } } - + @Test public void updateSurface_voxelAdded_returnsValue() { - int[] surfaces = new int[] { 4, 2, 0, -2, -4 }; - int[][][] voxelLists = new int[][][] { - { }, - { { 0, 1, 0 } }, - { { 0, 1, 0 }, { 1, 0, 0 } }, - { { 0, 1, 0 }, { 1, 0, 0 }, { 2, 1, 0 } }, - { { 0, 1, 0 }, { 1, 0, 0 }, { 2, 1, 0 }, { 1, 2, 0 } }, - }; - + int[] surfaces = new int[] {4, 2, 0, -2, -4}; + int[][][] voxelLists = + new int[][][] { + {}, + {{0, 1, 0}}, + {{0, 1, 0}, {1, 0, 0}}, + {{0, 1, 0}, {1, 0, 0}, {2, 1, 0}}, + {{0, 1, 0}, {1, 0, 0}, {2, 1, 0}, {1, 2, 0}}, + }; + for (int i = 0; i < surfaces.length; i++) { ArrayList voxels = new ArrayList<>(); for (int[] v : voxelLists[i]) { @@ -225,18 +229,19 @@ public void updateSurface_voxelAdded_returnsValue() { assertEquals(surfaces[i], loc.updateSurface(new Voxel(1, 1, 0))); } } - + @Test public void updateSurface_voxelRemoved_returnsValue() { - int[] surfaces = new int[] { 4, 2, 0, -2, -4 }; - int[][][] voxelLists = new int[][][] { - { { 1, 1, 0 } }, - { { 1, 1, 0 }, { 0, 1, 0 } }, - { { 1, 1, 0 }, { 0, 1, 0 }, { 1, 0, 0 } }, - { { 1, 1, 0 }, { 0, 1, 0 }, { 1, 0, 0 }, { 2, 1, 0 } }, - { { 1, 1, 0 }, { 0, 1, 0 }, { 1, 0, 0 }, { 2, 1, 0 }, { 1, 2, 0 } }, - }; - + int[] surfaces = new int[] {4, 2, 0, -2, -4}; + int[][][] voxelLists = + new int[][][] { + {{1, 1, 0}}, + {{1, 1, 0}, {0, 1, 0}}, + {{1, 1, 0}, {0, 1, 0}, {1, 0, 0}}, + {{1, 1, 0}, {0, 1, 0}, {1, 0, 0}, {2, 1, 0}}, + {{1, 1, 0}, {0, 1, 0}, {1, 0, 0}, {2, 1, 0}, {1, 2, 0}}, + }; + for (int i = 0; i < surfaces.length; i++) { ArrayList voxels = new ArrayList<>(); for (int[] v : voxelLists[i]) { @@ -246,18 +251,19 @@ public void updateSurface_voxelRemoved_returnsValue() { assertEquals(surfaces[i], loc.updateSurface(new Voxel(1, 1, 0))); } } - + @Test public void updateHeight_voxelAdded_returnsValue() { - int[] heights = new int[] { 1, 0, 0, 0, 0 }; - int[][][] voxelLists = new int[][][] { - { }, - { { 0, 1, 0 } }, - { { 0, 1, 0 }, { 1, 0, 0 } }, - { { 0, 1, 0 }, { 1, 0, 0 }, { 2, 1, 0 } }, - { { 0, 1, 0 }, { 1, 0, 0 }, { 2, 1, 0 }, { 1, 2, 0 } }, - }; - + int[] heights = new int[] {1, 0, 0, 0, 0}; + int[][][] voxelLists = + new int[][][] { + {}, + {{0, 1, 0}}, + {{0, 1, 0}, {1, 0, 0}}, + {{0, 1, 0}, {1, 0, 0}, {2, 1, 0}}, + {{0, 1, 0}, {1, 0, 0}, {2, 1, 0}, {1, 2, 0}}, + }; + for (int i = 0; i < heights.length; i++) { ArrayList voxels = new ArrayList<>(); for (int[] v : voxelLists[i]) { @@ -267,18 +273,19 @@ public void updateHeight_voxelAdded_returnsValue() { assertEquals(heights[i], loc.updateHeight(new Voxel(1, 1, 0))); } } - + @Test public void updateHeight_voxelRemoved_returnsValue() { - int[] heights = new int[] { 1, 0, 0, 0, 0 }; - int[][][] voxelLists = new int[][][] { - { { 1, 1, 0 } }, - { { 1, 1, 0 }, { 0, 1, 0 } }, - { { 1, 1, 0 }, { 0, 1, 0 }, { 1, 0, 0 } }, - { { 1, 1, 0 }, { 0, 1, 0 }, { 1, 0, 0 }, { 2, 1, 0 } }, - { { 1, 1, 0 }, { 0, 1, 0 }, { 1, 0, 0 }, { 2, 1, 0 }, { 1, 2, 0 } }, - }; - + int[] heights = new int[] {1, 0, 0, 0, 0}; + int[][][] voxelLists = + new int[][][] { + {{1, 1, 0}}, + {{1, 1, 0}, {0, 1, 0}}, + {{1, 1, 0}, {0, 1, 0}, {1, 0, 0}}, + {{1, 1, 0}, {0, 1, 0}, {1, 0, 0}, {2, 1, 0}}, + {{1, 1, 0}, {0, 1, 0}, {1, 0, 0}, {2, 1, 0}, {1, 2, 0}}, + }; + for (int i = 0; i < heights.length; i++) { ArrayList voxels = new ArrayList<>(); for (int[] v : voxelLists[i]) { @@ -288,7 +295,7 @@ public void updateHeight_voxelRemoved_returnsValue() { assertEquals(heights[i], loc.updateHeight(new Voxel(1, 1, 0))); } } - + @Test public void getSlice_givenLocation_returnsValue() { PottsLocation2D loc = new PottsLocation2D(new ArrayList<>()); @@ -297,7 +304,7 @@ public void getSlice_givenLocation_returnsValue() { assertEquals(Direction.POSITIVE_XY, loc.getSlice(Direction.NEGATIVE_XY, null)); assertEquals(Direction.NEGATIVE_XY, loc.getSlice(Direction.POSITIVE_XY, null)); } - + @Test public void getSlice_givenLocations_returnsValue() { PottsLocations2D loc = new PottsLocations2D(new ArrayList<>()); @@ -306,20 +313,20 @@ public void getSlice_givenLocations_returnsValue() { assertEquals(Direction.POSITIVE_XY, loc.getSlice(Direction.NEGATIVE_XY, null)); assertEquals(Direction.NEGATIVE_XY, loc.getSlice(Direction.POSITIVE_XY, null)); } - + @Test public void getSlice_invalidDirection_returnsNull() { PottsLocation2D loc = new PottsLocation2D(new ArrayList<>()); assertNull(loc.getSlice(Direction.UNDEFINED, null)); - + PottsLocations2D locs = new PottsLocations2D(new ArrayList<>()); assertNull(locs.getSlice(Direction.UNDEFINED, null)); } - + @Test public void getSelected_midSizeLocation_returnsList() { ArrayList voxels = new ArrayList<>(); - + int r = 4; int n = 10; for (int i = 0; i < n; i++) { @@ -327,55 +334,55 @@ public void getSelected_midSizeLocation_returnsList() { voxels.add(new Voxel(i - n / 2, j - n / 2, 0)); } } - + PottsLocation2D loc = new PottsLocation2D(voxels); ArrayList selected = loc.getSelected(new Voxel(0, 0, 0), Math.PI * r * r); - + assertTrue(selected.size() < n * n); for (Voxel voxel : selected) { assertTrue(Math.sqrt(Math.pow(voxel.x, 2) + Math.pow(voxel.y, 2)) <= r); } } - + @Test public void getSelected_maxSizeLocation_returnsList() { ArrayList voxels = new ArrayList<>(); - + int n = 10; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { voxels.add(new Voxel(i - n / 2, j - n / 2, 0)); } } - + PottsLocation2D loc = new PottsLocation2D(voxels); ArrayList selected = loc.getSelected(new Voxel(0, 0, 0), Integer.MAX_VALUE); - + assertEquals(selected.size(), n * n); } - + @Test public void getSelected_minSizeLocation_returnsList() { ArrayList voxels = new ArrayList<>(); - + int n = 10; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { voxels.add(new Voxel(i - n / 2, j - n / 2, 0)); } } - + PottsLocation2D loc = new PottsLocation2D(voxels); ArrayList selected = loc.getSelected(new Voxel(0, 0, 0), 0); - + assertEquals(selected.size(), 0); } - + @Test public void getSelected_midSizeLocations_returnsList() { ArrayList voxelsA = new ArrayList<>(); ArrayList voxelsB = new ArrayList<>(); - + int r = 4; int n = 10; for (int i = 0; i < n; i++) { @@ -390,11 +397,11 @@ public void getSelected_midSizeLocations_returnsList() { } } } - + PottsLocations2D loc = new PottsLocations2D(voxelsA); voxelsB.forEach(voxel -> loc.add(Region.UNDEFINED, voxel.x, voxel.y, voxel.z)); ArrayList selected = loc.getSelected(new Voxel(0, 0, 0), Math.PI * r * r); - + assertTrue(selected.size() < voxelsB.size()); for (Voxel voxel : selected) { assertTrue(Math.sqrt(Math.pow(voxel.x, 2) + Math.pow(voxel.y, 2)) <= r); @@ -402,12 +409,12 @@ public void getSelected_midSizeLocations_returnsList() { assertFalse(voxelsB.contains(voxel)); } } - + @Test public void getSelected_maxSizeLocations_returnsList() { ArrayList voxelsA = new ArrayList<>(); ArrayList voxelsB = new ArrayList<>(); - + int n = 10; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { @@ -421,19 +428,19 @@ public void getSelected_maxSizeLocations_returnsList() { } } } - + PottsLocations2D loc = new PottsLocations2D(voxelsA); voxelsB.forEach(voxel -> loc.add(Region.UNDEFINED, voxel.x, voxel.y, voxel.z)); ArrayList selected = loc.getSelected(new Voxel(0, 0, 0), Integer.MAX_VALUE); - + assertEquals(selected.size(), voxelsA.size()); } - + @Test public void getSelected_minSizeLocations_returnsList() { ArrayList voxelsA = new ArrayList<>(); ArrayList voxelsB = new ArrayList<>(); - + int n = 10; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { @@ -447,11 +454,11 @@ public void getSelected_minSizeLocations_returnsList() { } } } - + PottsLocations2D loc = new PottsLocations2D(voxelsA); voxelsB.forEach(voxel -> loc.add(Region.UNDEFINED, voxel.x, voxel.y, voxel.z)); ArrayList selected = loc.getSelected(new Voxel(0, 0, 0), 0); - + assertEquals(selected.size(), 0); } } diff --git a/test/arcade/potts/env/location/Location3DTest.java b/test/arcade/potts/env/location/Location3DTest.java index 753907c21..66aeeb547 100644 --- a/test/arcade/potts/env/location/Location3DTest.java +++ b/test/arcade/potts/env/location/Location3DTest.java @@ -2,9 +2,9 @@ import java.util.ArrayList; import java.util.HashMap; -import org.junit.BeforeClass; -import org.junit.Test; -import static org.junit.Assert.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; import static arcade.core.ARCADETestUtilities.*; import static arcade.potts.env.location.Voxel.VOXEL_COMPARATOR; import static arcade.potts.util.PottsEnums.Direction; @@ -12,500 +12,502 @@ public class Location3DTest { private static final double EPSILON = 1E-10; - + static ArrayList voxelListForDiametersXY; - + static ArrayList voxelListForDiametersYZ; - + static ArrayList voxelListForDiametersZX; - - private static final int[][] VOLUME_SURFACE = new int[][] { - { 1, 1, 5 }, - { 9, 1, 30 }, - { 18, 2, 43 }, - { 25, 1, 71 }, - { 50, 2, 93 }, - { 75, 3, 115 }, - { 45, 1, 118 }, - { 90, 2, 148 }, - { 135, 3, 177 }, - { 180, 4, 207 }, - { 69, 1, 173 }, - { 138, 2, 210 }, - { 207, 3, 246 }, - { 276, 4, 283 }, - { 345, 5, 319 }, - { 109, 1, 263 }, - { 218, 2, 308 }, - { 327, 3, 354 }, - { 436, 4, 400 }, - { 545, 5, 447 }, - { 654, 6, 493 }, - { 145, 1, 342 }, - { 290, 2, 395 }, - { 435, 3, 448 }, - { 580, 4, 501 }, - { 725, 5, 554 }, - { 870, 6, 607 }, - { 1015, 7, 660 }, - { 193, 1, 446 }, - { 386, 2, 507 }, - { 579, 3, 568 }, - { 772, 4, 629 }, - { 965, 5, 691 }, - { 1158, 6, 752 }, - { 1351, 7, 814 }, - { 1544, 8, 875 }, - { 249, 1, 566 }, - { 498, 2, 636 }, - { 747, 3, 705 }, - { 996, 4, 775 }, - { 1245, 5, 845 }, - { 1494, 6, 914 }, - { 1743, 7, 984 }, - { 1992, 8, 1054 }, - { 2241, 9, 1124 }, - { 305, 1, 685 }, - { 610, 2, 762 }, - { 915, 3, 839 }, - { 1220, 4, 917 }, - { 1525, 5, 994 }, - { 1830, 6, 1071 }, - { 2135, 7, 1148 }, - { 2440, 8, 1226 }, - { 2745, 9, 1303 }, - { 3050, 10, 1381 }, - { 373, 1, 830 }, - { 746, 2, 915 }, - { 1119, 3, 1000 }, - { 1492, 4, 1085 }, - { 1865, 5, 1171 }, - { 2238, 6, 1256 }, - { 2611, 7, 1342 }, - { 2984, 8, 1427 }, - { 3357, 9, 1513 }, - { 3730, 10, 1599 }, - { 4103, 11, 1684 }, - { 437, 1, 965 }, - { 874, 2, 1057 }, - { 1311, 3, 1149 }, - { 1748, 4, 1241 }, - { 2185, 5, 1334 }, - { 2622, 6, 1426 }, - { 3059, 7, 1519 }, - { 3496, 8, 1612 }, - { 3933, 9, 1704 }, - { 4370, 10, 1797 }, - { 4807, 11, 1890 }, - { 5244, 12, 1983 }, - { 517, 1, 1133 }, - { 1034, 2, 1233 }, - { 1551, 3, 1333 }, - { 2068, 4, 1434 }, - { 2585, 5, 1534 }, - { 3102, 6, 1635 }, - { 3619, 7, 1736 }, - { 4136, 8, 1837 }, - { 4653, 9, 1938 }, - { 5170, 10, 2038 }, - { 5687, 11, 2139 }, - { 6204, 12, 2240 }, - { 6721, 13, 2341 }, - { 609, 1, 1325 }, - { 1218, 2, 1434 }, - { 1827, 3, 1543 }, - { 2436, 4, 1652 }, - { 3045, 5, 1761 }, - { 3654, 6, 1871 }, - { 4263, 7, 1980 }, - { 4872, 8, 2090 }, - { 5481, 9, 2199 }, - { 6090, 10, 2309 }, - { 6699, 11, 2418 }, - { 7308, 12, 2528 }, - { 7917, 13, 2637 }, - { 8526, 14, 2747 }, - { 697, 1, 1509 }, - { 1394, 2, 1625 }, - { 2091, 3, 1742 }, - { 2788, 4, 1859 }, - { 3485, 5, 1976 }, - { 4182, 6, 2093 }, - { 4879, 7, 2210 }, - { 5576, 8, 2327 }, - { 6273, 9, 2444 }, - { 6970, 10, 2561 }, - { 7667, 11, 2678 }, - { 8364, 12, 2796 }, - { 9061, 13, 2913 }, - { 9758, 14, 3030 }, - { 10455, 15, 3148 }, - { 793, 1, 1709 }, - { 1586, 2, 1833 }, - { 2379, 3, 1957 }, - { 3172, 4, 2082 }, - { 3965, 5, 2207 }, - { 4758, 6, 2331 }, - { 5551, 7, 2456 }, - { 6344, 8, 2581 }, - { 7137, 9, 2706 }, - { 7930, 10, 2831 }, - { 8723, 11, 2956 }, - { 9516, 12, 3082 }, - { 10309, 13, 3207 }, - { 11102, 14, 3332 }, - { 11895, 15, 3457 }, - { 12688, 16, 3583 }, - { 889, 1, 1908 }, - { 1778, 2, 2039 }, - { 2667, 3, 2171 }, - { 3556, 4, 2303 }, - { 4445, 5, 2435 }, - { 5334, 6, 2567 }, - { 6223, 7, 2700 }, - { 7112, 8, 2832 }, - { 8001, 9, 2964 }, - { 8890, 10, 3097 }, - { 9779, 11, 3229 }, - { 10668, 12, 3362 }, - { 11557, 13, 3494 }, - { 12446, 14, 3627 }, - { 13335, 15, 3760 }, - { 14224, 16, 3892 }, - { 15113, 17, 4025 }, - { 1005, 1, 2148 }, - { 2010, 2, 2288 }, - { 3015, 3, 2428 }, - { 4020, 4, 2569 }, - { 5025, 5, 2709 }, - { 6030, 6, 2850 }, - { 7035, 7, 2990 }, - { 8040, 8, 3131 }, - { 9045, 9, 3272 }, - { 10050, 10, 3413 }, - { 11055, 11, 3554 }, - { 12060, 12, 3694 }, - { 13065, 13, 3835 }, - { 14070, 14, 3977 }, - { 15075, 15, 4118 }, - { 16080, 16, 4259 }, - { 17085, 17, 4400 }, - { 18090, 18, 4541 }, - { 1125, 1, 2396 }, - { 2250, 2, 2544 }, - { 3375, 3, 2693 }, - { 4500, 4, 2841 }, - { 5625, 5, 2990 }, - { 6750, 6, 3139 }, - { 7875, 7, 3287 }, - { 9000, 8, 3436 }, - { 10125, 9, 3585 }, - { 11250, 10, 3734 }, - { 12375, 11, 3883 }, - { 13500, 12, 4033 }, - { 14625, 13, 4182 }, - { 15750, 14, 4331 }, - { 16875, 15, 4480 }, - { 18000, 16, 4630 }, - { 19125, 17, 4779 }, - { 20250, 18, 4929 }, - { 21375, 19, 5078 }, - { 1245, 1, 2644 }, - { 2490, 2, 2800 }, - { 3735, 3, 2956 }, - { 4980, 4, 3112 }, - { 6225, 5, 3268 }, - { 7470, 6, 3425 }, - { 8715, 7, 3582 }, - { 9960, 8, 3738 }, - { 11205, 9, 3895 }, - { 12450, 10, 4052 }, - { 13695, 11, 4209 }, - { 14940, 12, 4366 }, - { 16185, 13, 4523 }, - { 17430, 14, 4680 }, - { 18675, 15, 4837 }, - { 19920, 16, 4994 }, - { 21165, 17, 5151 }, - { 22410, 18, 5308 }, - { 23655, 19, 5466 }, - { 24900, 20, 5623 }, - { 1369, 1, 2899 }, - { 2738, 2, 3063 }, - { 4107, 3, 3227 }, - { 5476, 4, 3390 }, - { 6845, 5, 3554 }, - { 8214, 6, 3719 }, - { 9583, 7, 3883 }, - { 10952, 8, 4047 }, - { 12321, 9, 4212 }, - { 13690, 10, 4376 }, - { 15059, 11, 4541 }, - { 16428, 12, 4705 }, - { 17797, 13, 4870 }, - { 19166, 14, 5035 }, - { 20535, 15, 5199 }, - { 21904, 16, 5364 }, - { 23273, 17, 5529 }, - { 24642, 18, 5694 }, - { 26011, 19, 5859 }, - { 27380, 20, 6024 }, - { 28749, 21, 6189 }, - { 1513, 1, 3196 }, - { 3026, 2, 3368 }, - { 4539, 3, 3540 }, - { 6052, 4, 3712 }, - { 7565, 5, 3885 }, - { 9078, 6, 4057 }, - { 10591, 7, 4230 }, - { 12104, 8, 4403 }, - { 13617, 9, 4576 }, - { 15130, 10, 4748 }, - { 16643, 11, 4922 }, - { 18156, 12, 5095 }, - { 19669, 13, 5268 }, - { 21182, 14, 5441 }, - { 22695, 15, 5614 }, - { 24208, 16, 5787 }, - { 25721, 17, 5961 }, - { 27234, 18, 6134 }, - { 28747, 19, 6308 }, - { 30260, 20, 6481 }, - { 31773, 21, 6654 }, - { 33286, 22, 6828 }, - { 1649, 1, 3475 }, - { 3298, 2, 3655 }, - { 4947, 3, 3834 }, - { 6596, 4, 4014 }, - { 8245, 5, 4194 }, - { 9894, 6, 4375 }, - { 11543, 7, 4555 }, - { 13192, 8, 4735 }, - { 14841, 9, 4916 }, - { 16490, 10, 5097 }, - { 18139, 11, 5277 }, - { 19788, 12, 5458 }, - { 21437, 13, 5639 }, - { 23086, 14, 5820 }, - { 24735, 15, 6000 }, - { 26384, 16, 6181 }, - { 28033, 17, 6362 }, - { 29682, 18, 6543 }, - { 31331, 19, 6724 }, - { 32980, 20, 6906 }, - { 34629, 21, 7087 }, - { 36278, 22, 7268 }, - { 37927, 23, 7449 }, - { 1789, 1, 3763 }, - { 3578, 2, 3950 }, - { 5367, 3, 4137 }, - { 7156, 4, 4324 }, - { 8945, 5, 4512 }, - { 10734, 6, 4700 }, - { 12523, 7, 4888 }, - { 14312, 8, 5076 }, - { 16101, 9, 5264 }, - { 17890, 10, 5452 }, - { 19679, 11, 5640 }, - { 21468, 12, 5828 }, - { 23257, 13, 6017 }, - { 25046, 14, 6205 }, - { 26835, 15, 6393 }, - { 28624, 16, 6582 }, - { 30413, 17, 6770 }, - { 32202, 18, 6959 }, - { 33991, 19, 7148 }, - { 35780, 20, 7336 }, - { 37569, 21, 7525 }, - { 39358, 22, 7714 }, - { 41147, 23, 7902 }, - { 42936, 24, 8091 }, - { 1941, 1, 4075 }, - { 3882, 2, 4269 }, - { 5823, 3, 4464 }, - { 7764, 4, 4660 }, - { 9705, 5, 4855 }, - { 11646, 6, 5051 }, - { 13587, 7, 5246 }, - { 15528, 8, 5442 }, - { 17469, 9, 5638 }, - { 19410, 10, 5834 }, - { 21351, 11, 6030 }, - { 23292, 12, 6226 }, - { 25233, 13, 6422 }, - { 27174, 14, 6619 }, - { 29115, 15, 6815 }, - { 31056, 16, 7011 }, - { 32997, 17, 7208 }, - { 34938, 18, 7404 }, - { 36879, 19, 7601 }, - { 38820, 20, 7797 }, - { 40761, 21, 7994 }, - { 42702, 22, 8190 }, - { 44643, 23, 8387 }, - { 46584, 24, 8584 }, - { 48525, 25, 8780 }, - { 2109, 1, 4419 }, - { 4218, 2, 4622 }, - { 6327, 3, 4825 }, - { 8436, 4, 5029 }, - { 10545, 5, 5232 }, - { 12654, 6, 5436 }, - { 14763, 7, 5640 }, - { 16872, 8, 5845 }, - { 18981, 9, 6049 }, - { 21090, 10, 6253 }, - { 23199, 11, 6458 }, - { 25308, 12, 6662 }, - { 27417, 13, 6867 }, - { 29526, 14, 7071 }, - { 31635, 15, 7276 }, - { 33744, 16, 7481 }, - { 35853, 17, 7685 }, - { 37962, 18, 7890 }, - { 40071, 19, 8095 }, - { 42180, 20, 8300 }, - { 44289, 21, 8505 }, - { 46398, 22, 8710 }, - { 48507, 23, 8915 }, - { 50616, 24, 9120 }, - { 52725, 25, 9325 }, - { 54834, 26, 9530 }, - { 2285, 1, 4779 }, - { 4570, 2, 4990 }, - { 6855, 3, 5202 }, - { 9140, 4, 5414 }, - { 11425, 5, 5626 }, - { 13710, 6, 5838 }, - { 15995, 7, 6051 }, - { 18280, 8, 6263 }, - { 20565, 9, 6476 }, - { 22850, 10, 6689 }, - { 25135, 11, 6901 }, - { 27420, 12, 7114 }, - { 29705, 13, 7327 }, - { 31990, 14, 7540 }, - { 34275, 15, 7753 }, - { 36560, 16, 7966 }, - { 38845, 17, 8180 }, - { 41130, 18, 8393 }, - { 43415, 19, 8606 }, - { 45700, 20, 8819 }, - { 47985, 21, 9033 }, - { 50270, 22, 9246 }, - { 52555, 23, 9460 }, - { 54840, 24, 9673 }, - { 57125, 25, 9887 }, - { 59410, 26, 10100 }, - { 61695, 27, 10314 }, - { 2449, 1, 5115 }, - { 4898, 2, 5333 }, - { 7347, 3, 5552 }, - { 9796, 4, 5772 }, - { 12245, 5, 5992 }, - { 14694, 6, 6211 }, - { 17143, 7, 6431 }, - { 19592, 8, 6651 }, - { 22041, 9, 6871 }, - { 24490, 10, 7092 }, - { 26939, 11, 7312 }, - { 29388, 12, 7532 }, - { 31837, 13, 7753 }, - { 34286, 14, 7973 }, - { 36735, 15, 8194 }, - { 39184, 16, 8415 }, - { 41633, 17, 8635 }, - { 44082, 18, 8856 }, - { 46531, 19, 9077 }, - { 48980, 20, 9298 }, - { 51429, 21, 9519 }, - { 53878, 22, 9740 }, - { 56327, 23, 9961 }, - { 58776, 24, 10182 }, - { 61225, 25, 10403 }, - { 63674, 26, 10624 }, - { 66123, 27, 10845 }, - { 68572, 28, 11066 }, - { 2617, 1, 5458 }, - { 5234, 2, 5684 }, - { 7851, 3, 5911 }, - { 10468, 4, 6138 }, - { 13085, 5, 6365 }, - { 15702, 6, 6592 }, - { 18319, 7, 6819 }, - { 20936, 8, 7047 }, - { 23553, 9, 7274 }, - { 26170, 10, 7502 }, - { 28787, 11, 7730 }, - { 31404, 12, 7958 }, - { 34021, 13, 8186 }, - { 36638, 14, 8414 }, - { 39255, 15, 8642 }, - { 41872, 16, 8870 }, - { 44489, 17, 9098 }, - { 47106, 18, 9326 }, - { 49723, 19, 9555 }, - { 52340, 20, 9783 }, - { 54957, 21, 10011 }, - { 57574, 22, 10240 }, - { 60191, 23, 10468 }, - { 62808, 24, 10697 }, - { 65425, 25, 10925 }, - { 68042, 26, 11154 }, - { 70659, 27, 11382 }, - { 73276, 28, 11611 }, - { 75893, 29, 11840 }, - { 2809, 1, 5850 }, - { 5618, 2, 6084 }, - { 8427, 3, 6319 }, - { 11236, 4, 6554 }, - { 14045, 5, 6790 }, - { 16854, 6, 7025 }, - { 19663, 7, 7261 }, - { 22472, 8, 7496 }, - { 25281, 9, 7732 }, - { 28090, 10, 7968 }, - { 30899, 11, 8204 }, - { 33708, 12, 8440 }, - { 36517, 13, 8676 }, - { 39326, 14, 8913 }, - { 42135, 15, 9149 }, - { 44944, 16, 9385 }, - { 47753, 17, 9622 }, - { 50562, 18, 9858 }, - { 53371, 19, 10095 }, - { 56180, 20, 10332 }, - { 58989, 21, 10568 }, - { 61798, 22, 10805 }, - { 64607, 23, 11042 }, - { 67416, 24, 11278 }, - { 70225, 25, 11515 }, - { 73034, 26, 11752 }, - { 75843, 27, 11989 }, - { 78652, 28, 12226 }, - { 81461, 29, 12463 }, - { 84270, 30, 12700 }, - }; - - @BeforeClass + + private static final int[][] VOLUME_SURFACE = + new int[][] { + {1, 1, 5}, + {9, 1, 30}, + {18, 2, 43}, + {25, 1, 71}, + {50, 2, 93}, + {75, 3, 115}, + {45, 1, 118}, + {90, 2, 148}, + {135, 3, 177}, + {180, 4, 207}, + {69, 1, 173}, + {138, 2, 210}, + {207, 3, 246}, + {276, 4, 283}, + {345, 5, 319}, + {109, 1, 263}, + {218, 2, 308}, + {327, 3, 354}, + {436, 4, 400}, + {545, 5, 447}, + {654, 6, 493}, + {145, 1, 342}, + {290, 2, 395}, + {435, 3, 448}, + {580, 4, 501}, + {725, 5, 554}, + {870, 6, 607}, + {1015, 7, 660}, + {193, 1, 446}, + {386, 2, 507}, + {579, 3, 568}, + {772, 4, 629}, + {965, 5, 691}, + {1158, 6, 752}, + {1351, 7, 814}, + {1544, 8, 875}, + {249, 1, 566}, + {498, 2, 636}, + {747, 3, 705}, + {996, 4, 775}, + {1245, 5, 845}, + {1494, 6, 914}, + {1743, 7, 984}, + {1992, 8, 1054}, + {2241, 9, 1124}, + {305, 1, 685}, + {610, 2, 762}, + {915, 3, 839}, + {1220, 4, 917}, + {1525, 5, 994}, + {1830, 6, 1071}, + {2135, 7, 1148}, + {2440, 8, 1226}, + {2745, 9, 1303}, + {3050, 10, 1381}, + {373, 1, 830}, + {746, 2, 915}, + {1119, 3, 1000}, + {1492, 4, 1085}, + {1865, 5, 1171}, + {2238, 6, 1256}, + {2611, 7, 1342}, + {2984, 8, 1427}, + {3357, 9, 1513}, + {3730, 10, 1599}, + {4103, 11, 1684}, + {437, 1, 965}, + {874, 2, 1057}, + {1311, 3, 1149}, + {1748, 4, 1241}, + {2185, 5, 1334}, + {2622, 6, 1426}, + {3059, 7, 1519}, + {3496, 8, 1612}, + {3933, 9, 1704}, + {4370, 10, 1797}, + {4807, 11, 1890}, + {5244, 12, 1983}, + {517, 1, 1133}, + {1034, 2, 1233}, + {1551, 3, 1333}, + {2068, 4, 1434}, + {2585, 5, 1534}, + {3102, 6, 1635}, + {3619, 7, 1736}, + {4136, 8, 1837}, + {4653, 9, 1938}, + {5170, 10, 2038}, + {5687, 11, 2139}, + {6204, 12, 2240}, + {6721, 13, 2341}, + {609, 1, 1325}, + {1218, 2, 1434}, + {1827, 3, 1543}, + {2436, 4, 1652}, + {3045, 5, 1761}, + {3654, 6, 1871}, + {4263, 7, 1980}, + {4872, 8, 2090}, + {5481, 9, 2199}, + {6090, 10, 2309}, + {6699, 11, 2418}, + {7308, 12, 2528}, + {7917, 13, 2637}, + {8526, 14, 2747}, + {697, 1, 1509}, + {1394, 2, 1625}, + {2091, 3, 1742}, + {2788, 4, 1859}, + {3485, 5, 1976}, + {4182, 6, 2093}, + {4879, 7, 2210}, + {5576, 8, 2327}, + {6273, 9, 2444}, + {6970, 10, 2561}, + {7667, 11, 2678}, + {8364, 12, 2796}, + {9061, 13, 2913}, + {9758, 14, 3030}, + {10455, 15, 3148}, + {793, 1, 1709}, + {1586, 2, 1833}, + {2379, 3, 1957}, + {3172, 4, 2082}, + {3965, 5, 2207}, + {4758, 6, 2331}, + {5551, 7, 2456}, + {6344, 8, 2581}, + {7137, 9, 2706}, + {7930, 10, 2831}, + {8723, 11, 2956}, + {9516, 12, 3082}, + {10309, 13, 3207}, + {11102, 14, 3332}, + {11895, 15, 3457}, + {12688, 16, 3583}, + {889, 1, 1908}, + {1778, 2, 2039}, + {2667, 3, 2171}, + {3556, 4, 2303}, + {4445, 5, 2435}, + {5334, 6, 2567}, + {6223, 7, 2700}, + {7112, 8, 2832}, + {8001, 9, 2964}, + {8890, 10, 3097}, + {9779, 11, 3229}, + {10668, 12, 3362}, + {11557, 13, 3494}, + {12446, 14, 3627}, + {13335, 15, 3760}, + {14224, 16, 3892}, + {15113, 17, 4025}, + {1005, 1, 2148}, + {2010, 2, 2288}, + {3015, 3, 2428}, + {4020, 4, 2569}, + {5025, 5, 2709}, + {6030, 6, 2850}, + {7035, 7, 2990}, + {8040, 8, 3131}, + {9045, 9, 3272}, + {10050, 10, 3413}, + {11055, 11, 3554}, + {12060, 12, 3694}, + {13065, 13, 3835}, + {14070, 14, 3977}, + {15075, 15, 4118}, + {16080, 16, 4259}, + {17085, 17, 4400}, + {18090, 18, 4541}, + {1125, 1, 2396}, + {2250, 2, 2544}, + {3375, 3, 2693}, + {4500, 4, 2841}, + {5625, 5, 2990}, + {6750, 6, 3139}, + {7875, 7, 3287}, + {9000, 8, 3436}, + {10125, 9, 3585}, + {11250, 10, 3734}, + {12375, 11, 3883}, + {13500, 12, 4033}, + {14625, 13, 4182}, + {15750, 14, 4331}, + {16875, 15, 4480}, + {18000, 16, 4630}, + {19125, 17, 4779}, + {20250, 18, 4929}, + {21375, 19, 5078}, + {1245, 1, 2644}, + {2490, 2, 2800}, + {3735, 3, 2956}, + {4980, 4, 3112}, + {6225, 5, 3268}, + {7470, 6, 3425}, + {8715, 7, 3582}, + {9960, 8, 3738}, + {11205, 9, 3895}, + {12450, 10, 4052}, + {13695, 11, 4209}, + {14940, 12, 4366}, + {16185, 13, 4523}, + {17430, 14, 4680}, + {18675, 15, 4837}, + {19920, 16, 4994}, + {21165, 17, 5151}, + {22410, 18, 5308}, + {23655, 19, 5466}, + {24900, 20, 5623}, + {1369, 1, 2899}, + {2738, 2, 3063}, + {4107, 3, 3227}, + {5476, 4, 3390}, + {6845, 5, 3554}, + {8214, 6, 3719}, + {9583, 7, 3883}, + {10952, 8, 4047}, + {12321, 9, 4212}, + {13690, 10, 4376}, + {15059, 11, 4541}, + {16428, 12, 4705}, + {17797, 13, 4870}, + {19166, 14, 5035}, + {20535, 15, 5199}, + {21904, 16, 5364}, + {23273, 17, 5529}, + {24642, 18, 5694}, + {26011, 19, 5859}, + {27380, 20, 6024}, + {28749, 21, 6189}, + {1513, 1, 3196}, + {3026, 2, 3368}, + {4539, 3, 3540}, + {6052, 4, 3712}, + {7565, 5, 3885}, + {9078, 6, 4057}, + {10591, 7, 4230}, + {12104, 8, 4403}, + {13617, 9, 4576}, + {15130, 10, 4748}, + {16643, 11, 4922}, + {18156, 12, 5095}, + {19669, 13, 5268}, + {21182, 14, 5441}, + {22695, 15, 5614}, + {24208, 16, 5787}, + {25721, 17, 5961}, + {27234, 18, 6134}, + {28747, 19, 6308}, + {30260, 20, 6481}, + {31773, 21, 6654}, + {33286, 22, 6828}, + {1649, 1, 3475}, + {3298, 2, 3655}, + {4947, 3, 3834}, + {6596, 4, 4014}, + {8245, 5, 4194}, + {9894, 6, 4375}, + {11543, 7, 4555}, + {13192, 8, 4735}, + {14841, 9, 4916}, + {16490, 10, 5097}, + {18139, 11, 5277}, + {19788, 12, 5458}, + {21437, 13, 5639}, + {23086, 14, 5820}, + {24735, 15, 6000}, + {26384, 16, 6181}, + {28033, 17, 6362}, + {29682, 18, 6543}, + {31331, 19, 6724}, + {32980, 20, 6906}, + {34629, 21, 7087}, + {36278, 22, 7268}, + {37927, 23, 7449}, + {1789, 1, 3763}, + {3578, 2, 3950}, + {5367, 3, 4137}, + {7156, 4, 4324}, + {8945, 5, 4512}, + {10734, 6, 4700}, + {12523, 7, 4888}, + {14312, 8, 5076}, + {16101, 9, 5264}, + {17890, 10, 5452}, + {19679, 11, 5640}, + {21468, 12, 5828}, + {23257, 13, 6017}, + {25046, 14, 6205}, + {26835, 15, 6393}, + {28624, 16, 6582}, + {30413, 17, 6770}, + {32202, 18, 6959}, + {33991, 19, 7148}, + {35780, 20, 7336}, + {37569, 21, 7525}, + {39358, 22, 7714}, + {41147, 23, 7902}, + {42936, 24, 8091}, + {1941, 1, 4075}, + {3882, 2, 4269}, + {5823, 3, 4464}, + {7764, 4, 4660}, + {9705, 5, 4855}, + {11646, 6, 5051}, + {13587, 7, 5246}, + {15528, 8, 5442}, + {17469, 9, 5638}, + {19410, 10, 5834}, + {21351, 11, 6030}, + {23292, 12, 6226}, + {25233, 13, 6422}, + {27174, 14, 6619}, + {29115, 15, 6815}, + {31056, 16, 7011}, + {32997, 17, 7208}, + {34938, 18, 7404}, + {36879, 19, 7601}, + {38820, 20, 7797}, + {40761, 21, 7994}, + {42702, 22, 8190}, + {44643, 23, 8387}, + {46584, 24, 8584}, + {48525, 25, 8780}, + {2109, 1, 4419}, + {4218, 2, 4622}, + {6327, 3, 4825}, + {8436, 4, 5029}, + {10545, 5, 5232}, + {12654, 6, 5436}, + {14763, 7, 5640}, + {16872, 8, 5845}, + {18981, 9, 6049}, + {21090, 10, 6253}, + {23199, 11, 6458}, + {25308, 12, 6662}, + {27417, 13, 6867}, + {29526, 14, 7071}, + {31635, 15, 7276}, + {33744, 16, 7481}, + {35853, 17, 7685}, + {37962, 18, 7890}, + {40071, 19, 8095}, + {42180, 20, 8300}, + {44289, 21, 8505}, + {46398, 22, 8710}, + {48507, 23, 8915}, + {50616, 24, 9120}, + {52725, 25, 9325}, + {54834, 26, 9530}, + {2285, 1, 4779}, + {4570, 2, 4990}, + {6855, 3, 5202}, + {9140, 4, 5414}, + {11425, 5, 5626}, + {13710, 6, 5838}, + {15995, 7, 6051}, + {18280, 8, 6263}, + {20565, 9, 6476}, + {22850, 10, 6689}, + {25135, 11, 6901}, + {27420, 12, 7114}, + {29705, 13, 7327}, + {31990, 14, 7540}, + {34275, 15, 7753}, + {36560, 16, 7966}, + {38845, 17, 8180}, + {41130, 18, 8393}, + {43415, 19, 8606}, + {45700, 20, 8819}, + {47985, 21, 9033}, + {50270, 22, 9246}, + {52555, 23, 9460}, + {54840, 24, 9673}, + {57125, 25, 9887}, + {59410, 26, 10100}, + {61695, 27, 10314}, + {2449, 1, 5115}, + {4898, 2, 5333}, + {7347, 3, 5552}, + {9796, 4, 5772}, + {12245, 5, 5992}, + {14694, 6, 6211}, + {17143, 7, 6431}, + {19592, 8, 6651}, + {22041, 9, 6871}, + {24490, 10, 7092}, + {26939, 11, 7312}, + {29388, 12, 7532}, + {31837, 13, 7753}, + {34286, 14, 7973}, + {36735, 15, 8194}, + {39184, 16, 8415}, + {41633, 17, 8635}, + {44082, 18, 8856}, + {46531, 19, 9077}, + {48980, 20, 9298}, + {51429, 21, 9519}, + {53878, 22, 9740}, + {56327, 23, 9961}, + {58776, 24, 10182}, + {61225, 25, 10403}, + {63674, 26, 10624}, + {66123, 27, 10845}, + {68572, 28, 11066}, + {2617, 1, 5458}, + {5234, 2, 5684}, + {7851, 3, 5911}, + {10468, 4, 6138}, + {13085, 5, 6365}, + {15702, 6, 6592}, + {18319, 7, 6819}, + {20936, 8, 7047}, + {23553, 9, 7274}, + {26170, 10, 7502}, + {28787, 11, 7730}, + {31404, 12, 7958}, + {34021, 13, 8186}, + {36638, 14, 8414}, + {39255, 15, 8642}, + {41872, 16, 8870}, + {44489, 17, 9098}, + {47106, 18, 9326}, + {49723, 19, 9555}, + {52340, 20, 9783}, + {54957, 21, 10011}, + {57574, 22, 10240}, + {60191, 23, 10468}, + {62808, 24, 10697}, + {65425, 25, 10925}, + {68042, 26, 11154}, + {70659, 27, 11382}, + {73276, 28, 11611}, + {75893, 29, 11840}, + {2809, 1, 5850}, + {5618, 2, 6084}, + {8427, 3, 6319}, + {11236, 4, 6554}, + {14045, 5, 6790}, + {16854, 6, 7025}, + {19663, 7, 7261}, + {22472, 8, 7496}, + {25281, 9, 7732}, + {28090, 10, 7968}, + {30899, 11, 8204}, + {33708, 12, 8440}, + {36517, 13, 8676}, + {39326, 14, 8913}, + {42135, 15, 9149}, + {44944, 16, 9385}, + {47753, 17, 9622}, + {50562, 18, 9858}, + {53371, 19, 10095}, + {56180, 20, 10332}, + {58989, 21, 10568}, + {61798, 22, 10805}, + {64607, 23, 11042}, + {67416, 24, 11278}, + {70225, 25, 11515}, + {73034, 26, 11752}, + {75843, 27, 11989}, + {78652, 28, 12226}, + {81461, 29, 12463}, + {84270, 30, 12700}, + }; + + @BeforeAll public static void setupLists() { - int[][] diameter = new int[][] { - { 5, 6, 7, 5, 6, 7, 5, 7, 8, 8, 5, 6, 7, 5, 6, 7 }, - { 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 6, 2, 2, 2 }, - { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 2, 2, 2 } - }; - + int[][] diameter = + new int[][] { + {5, 6, 7, 5, 6, 7, 5, 7, 8, 8, 5, 6, 7, 5, 6, 7}, + {3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 6, 2, 2, 2}, + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 2, 2, 2} + }; + voxelListForDiametersXY = new ArrayList<>(); voxelListForDiametersYZ = new ArrayList<>(); voxelListForDiametersZX = new ArrayList<>(); - + for (int i = 0; i < diameter[0].length; i++) { voxelListForDiametersXY.add(new Voxel(diameter[0][i], diameter[1][i], diameter[2][i])); voxelListForDiametersYZ.add(new Voxel(diameter[2][i], diameter[0][i], diameter[1][i])); voxelListForDiametersZX.add(new Voxel(diameter[1][i], diameter[2][i], diameter[0][i])); } } - + @Test public void getNeighbors_givenLocation_returnsList() { ArrayList voxels = new ArrayList<>(); @@ -515,16 +517,16 @@ public void getNeighbors_givenLocation_returnsList() { voxels.add(new Voxel(0, 1, 0)); voxels.add(new Voxel(0, 0, -1)); voxels.add(new Voxel(0, 0, 1)); - + PottsLocation3D loc = new PottsLocation3D(new ArrayList<>()); ArrayList neighbors = loc.getNeighbors(new Voxel(0, 0, 0)); - + voxels.sort(VOXEL_COMPARATOR); neighbors.sort(VOXEL_COMPARATOR); - + assertEquals(voxels, neighbors); } - + @Test public void getNeighbors_givenLocations_returnsList() { ArrayList voxels = new ArrayList<>(); @@ -534,16 +536,16 @@ public void getNeighbors_givenLocations_returnsList() { voxels.add(new Voxel(0, 1, 0)); voxels.add(new Voxel(0, 0, -1)); voxels.add(new Voxel(0, 0, 1)); - + PottsLocations3D loc = new PottsLocations3D(new ArrayList<>()); ArrayList neighbors = loc.getNeighbors(new Voxel(0, 0, 0)); - + voxels.sort(VOXEL_COMPARATOR); neighbors.sort(VOXEL_COMPARATOR); - + assertEquals(voxels, neighbors); } - + @Test public void getDiameters_validLocationXY_calculatesValues() { PottsLocation3D loc = new PottsLocation3D(voxelListForDiametersXY); @@ -553,7 +555,7 @@ public void getDiameters_validLocationXY_calculatesValues() { assertEquals(4, (int) diameters.get(Direction.POSITIVE_XY)); assertEquals(3, (int) diameters.get(Direction.NEGATIVE_XY)); } - + @Test public void getDiameters_invalidLocationXY_returnsZero() { PottsLocation3D loc = new PottsLocation3D(new ArrayList<>()); @@ -563,7 +565,7 @@ public void getDiameters_invalidLocationXY_returnsZero() { assertEquals(0, (int) diameters.get(Direction.POSITIVE_XY)); assertEquals(0, (int) diameters.get(Direction.NEGATIVE_XY)); } - + @Test public void getDiameters_validLocationYZ_calculatesValues() { PottsLocation3D loc = new PottsLocation3D(voxelListForDiametersYZ); @@ -573,7 +575,7 @@ public void getDiameters_validLocationYZ_calculatesValues() { assertEquals(4, (int) diameters.get(Direction.POSITIVE_YZ)); assertEquals(3, (int) diameters.get(Direction.NEGATIVE_YZ)); } - + @Test public void getDiameters_invalidLocationYZ_returnsZero() { PottsLocation3D loc = new PottsLocation3D(new ArrayList<>()); @@ -583,7 +585,7 @@ public void getDiameters_invalidLocationYZ_returnsZero() { assertEquals(0, (int) diameters.get(Direction.POSITIVE_YZ)); assertEquals(0, (int) diameters.get(Direction.NEGATIVE_YZ)); } - + @Test public void getDiameters_validLocationZX_calculatesValues() { PottsLocation3D loc = new PottsLocation3D(voxelListForDiametersZX); @@ -593,7 +595,7 @@ public void getDiameters_validLocationZX_calculatesValues() { assertEquals(4, (int) diameters.get(Direction.POSITIVE_ZX)); assertEquals(3, (int) diameters.get(Direction.NEGATIVE_ZX)); } - + @Test public void getDiameters_invalidLocationZX_returnsZero() { PottsLocation3D loc = new PottsLocation3D(new ArrayList<>()); @@ -603,7 +605,7 @@ public void getDiameters_invalidLocationZX_returnsZero() { assertEquals(0, (int) diameters.get(Direction.POSITIVE_ZX)); assertEquals(0, (int) diameters.get(Direction.NEGATIVE_ZX)); } - + @Test public void getDiameters_validLocationsXY_calculatesValues() { PottsLocations3D loc = new PottsLocations3D(voxelListForDiametersXY); @@ -613,7 +615,7 @@ public void getDiameters_validLocationsXY_calculatesValues() { assertEquals(4, (int) diameters.get(Direction.POSITIVE_XY)); assertEquals(3, (int) diameters.get(Direction.NEGATIVE_XY)); } - + @Test public void getDiameters_invalidLocationsXY_returnsZero() { PottsLocations3D loc = new PottsLocations3D(new ArrayList<>()); @@ -623,7 +625,7 @@ public void getDiameters_invalidLocationsXY_returnsZero() { assertEquals(0, (int) diameters.get(Direction.POSITIVE_XY)); assertEquals(0, (int) diameters.get(Direction.NEGATIVE_XY)); } - + @Test public void getDiameters_validLocationsYZ_calculatesValues() { PottsLocations3D loc = new PottsLocations3D(voxelListForDiametersYZ); @@ -633,7 +635,7 @@ public void getDiameters_validLocationsYZ_calculatesValues() { assertEquals(4, (int) diameters.get(Direction.POSITIVE_YZ)); assertEquals(3, (int) diameters.get(Direction.NEGATIVE_YZ)); } - + @Test public void getDiameters_invalidLocationsYZ_returnsZero() { PottsLocations3D loc = new PottsLocations3D(new ArrayList<>()); @@ -643,7 +645,7 @@ public void getDiameters_invalidLocationsYZ_returnsZero() { assertEquals(0, (int) diameters.get(Direction.POSITIVE_YZ)); assertEquals(0, (int) diameters.get(Direction.NEGATIVE_YZ)); } - + @Test public void getDiameters_validLocationsZX_calculatesValues() { PottsLocations3D loc = new PottsLocations3D(voxelListForDiametersZX); @@ -653,7 +655,7 @@ public void getDiameters_validLocationsZX_calculatesValues() { assertEquals(4, (int) diameters.get(Direction.POSITIVE_ZX)); assertEquals(3, (int) diameters.get(Direction.NEGATIVE_ZX)); } - + @Test public void getDiameters_invalidLocationsZX_returnsZero() { PottsLocations3D loc = new PottsLocations3D(new ArrayList<>()); @@ -663,7 +665,7 @@ public void getDiameters_invalidLocationsZX_returnsZero() { assertEquals(0, (int) diameters.get(Direction.POSITIVE_ZX)); assertEquals(0, (int) diameters.get(Direction.NEGATIVE_ZX)); } - + @Test public void convertSurface_givenLocationValue_calculatesValue() { PottsLocation3D loc = new PottsLocation3D(new ArrayList<>()); @@ -671,7 +673,7 @@ public void convertSurface_givenLocationValue_calculatesValue() { assertEquals(sv[2], loc.convertSurface(sv[0], sv[1]), EPSILON); } } - + @Test public void convertSurface_givenLocationsValue_calculatesValue() { PottsLocations3D loc = new PottsLocations3D(new ArrayList<>()); @@ -679,23 +681,24 @@ public void convertSurface_givenLocationsValue_calculatesValue() { assertEquals(sv[2], loc.convertSurface(sv[0], sv[1]), EPSILON); } } - + @Test public void calculateSurface_emptyList_returnsZero() { PottsLocation3D loc = new PottsLocation3D(new ArrayList<>()); assertEquals(0, loc.calculateSurface()); } - + @Test public void calculateSurface_validVoxels_returnsValue() { - int[] surfaces = new int[] { 6, 10, 14, 18 }; - int[][][] voxelLists = new int[][][] { - { { 1, 1, 0 } }, - { { 1, 1, 0 }, { 1, 1, 1 } }, - { { 1, 1, 0 }, { 1, 1, 1 }, { 1, 2, 0 } }, - { { 1, 1, 0 }, { 1, 1, 1 }, { 1, 2, 0 }, { 2, 1, 1 } }, - }; - + int[] surfaces = new int[] {6, 10, 14, 18}; + int[][][] voxelLists = + new int[][][] { + {{1, 1, 0}}, + {{1, 1, 0}, {1, 1, 1}}, + {{1, 1, 0}, {1, 1, 1}, {1, 2, 0}}, + {{1, 1, 0}, {1, 1, 1}, {1, 2, 0}, {2, 1, 1}}, + }; + for (int i = 0; i < surfaces.length; i++) { ArrayList voxels = new ArrayList<>(); for (int[] v : voxelLists[i]) { @@ -705,23 +708,24 @@ public void calculateSurface_validVoxels_returnsValue() { assertEquals(surfaces[i], loc.calculateSurface()); } } - + @Test public void calculateHeight_emptyList_returnsZero() { PottsLocation3D loc = new PottsLocation3D(new ArrayList<>()); assertEquals(0, loc.calculateHeight()); } - + @Test public void calculateHeight_validVoxels_returnsValue() { - int[] heights = new int[] { 1, 2, 3, 5 }; - int[][][] voxelLists = new int[][][] { - { { 1, 1, 0 } }, - { { 1, 1, 0 }, { 1, 1, 1 } }, - { { 1, 1, 0 }, { 1, 1, 1 }, { 1, 1, 2 } }, - { { 1, 1, 0 }, { 1, 1, 1 }, { 1, 1, 2 }, { 1, 1, 4 } }, - }; - + int[] heights = new int[] {1, 2, 3, 5}; + int[][][] voxelLists = + new int[][][] { + {{1, 1, 0}}, + {{1, 1, 0}, {1, 1, 1}}, + {{1, 1, 0}, {1, 1, 1}, {1, 1, 2}}, + {{1, 1, 0}, {1, 1, 1}, {1, 1, 2}, {1, 1, 4}}, + }; + for (int i = 0; i < heights.length; i++) { ArrayList voxels = new ArrayList<>(); for (int[] v : voxelLists[i]) { @@ -731,18 +735,19 @@ public void calculateHeight_validVoxels_returnsValue() { assertEquals(heights[i], loc.calculateHeight()); } } - + @Test public void updateSurface_voxelAdded_returnsValue() { - int[] surfaces = new int[] { 6, 4, 4, 2, 0 }; - int[][][] voxelLists = new int[][][] { - { }, - { { 1, 1, 1 } }, - { { 1, 1, 1 }, { 1, 0, 1 } }, - { { 1, 1, 1 }, { 1, 0, 1 }, { 1, 0, 0 } }, - { { 1, 1, 1 }, { 1, 0, 1 }, { 1, 0, 0 }, { 1, 2, 0 } }, - }; - + int[] surfaces = new int[] {6, 4, 4, 2, 0}; + int[][][] voxelLists = + new int[][][] { + {}, + {{1, 1, 1}}, + {{1, 1, 1}, {1, 0, 1}}, + {{1, 1, 1}, {1, 0, 1}, {1, 0, 0}}, + {{1, 1, 1}, {1, 0, 1}, {1, 0, 0}, {1, 2, 0}}, + }; + for (int i = 0; i < surfaces.length; i++) { ArrayList voxels = new ArrayList<>(); for (int[] v : voxelLists[i]) { @@ -752,18 +757,21 @@ public void updateSurface_voxelAdded_returnsValue() { assertEquals(surfaces[i], loc.updateSurface(new Voxel(1, 1, 0))); } } - + @Test public void updateSurface_voxelRemoved_returnsValue() { - int[] surfaces = new int[] { 6, 4, 4, 2, 0 }; - int[][][] voxelLists = new int[][][] { - { { 1, 1, 0 }, }, - { { 1, 1, 0 }, { 1, 1, 1 } }, - { { 1, 1, 0 }, { 1, 1, 1 }, { 1, 0, 1 } }, - { { 1, 1, 0 }, { 1, 1, 1 }, { 1, 0, 1 }, { 1, 0, 0 } }, - { { 1, 1, 0 }, { 1, 1, 1 }, { 1, 0, 1 }, { 1, 0, 0 }, { 1, 2, 0 } }, - }; - + int[] surfaces = new int[] {6, 4, 4, 2, 0}; + int[][][] voxelLists = + new int[][][] { + { + {1, 1, 0}, + }, + {{1, 1, 0}, {1, 1, 1}}, + {{1, 1, 0}, {1, 1, 1}, {1, 0, 1}}, + {{1, 1, 0}, {1, 1, 1}, {1, 0, 1}, {1, 0, 0}}, + {{1, 1, 0}, {1, 1, 1}, {1, 0, 1}, {1, 0, 0}, {1, 2, 0}}, + }; + for (int i = 0; i < surfaces.length; i++) { ArrayList voxels = new ArrayList<>(); for (int[] v : voxelLists[i]) { @@ -773,23 +781,24 @@ public void updateSurface_voxelRemoved_returnsValue() { assertEquals(surfaces[i], loc.updateSurface(new Voxel(1, 1, 0))); } } - + @Test public void updateHeight_voxelAdded_returnsValue() { - int[] heights = new int[] { 1, 0, 1, 1, 2, 2, 0, 0, 0, 3 }; - int[][][] voxelLists = new int[][][] { - { }, - { { 0, 0, 2 } }, - { { 0, 0, 1 } }, - { { 0, 0, 3 } }, - { { 0, 0, 0 } }, - { { 0, 0, 4 } }, - { { 0, 0, 2 }, { 0, 0, 3 } }, - { { 0, 0, 2 }, { 0, 0, 1 } }, - { { 0, 0, 1 }, { 0, 0, 2 }, { 0, 0, 3 } }, - { { 0, 0, 5 }, { 0, 0, 6 } }, - }; - + int[] heights = new int[] {1, 0, 1, 1, 2, 2, 0, 0, 0, 3}; + int[][][] voxelLists = + new int[][][] { + {}, + {{0, 0, 2}}, + {{0, 0, 1}}, + {{0, 0, 3}}, + {{0, 0, 0}}, + {{0, 0, 4}}, + {{0, 0, 2}, {0, 0, 3}}, + {{0, 0, 2}, {0, 0, 1}}, + {{0, 0, 1}, {0, 0, 2}, {0, 0, 3}}, + {{0, 0, 5}, {0, 0, 6}}, + }; + for (int i = 0; i < heights.length; i++) { ArrayList voxels = new ArrayList<>(); for (int[] v : voxelLists[i]) { @@ -799,23 +808,24 @@ public void updateHeight_voxelAdded_returnsValue() { assertEquals(heights[i], loc.updateHeight(new Voxel(1, 1, 2))); } } - + @Test public void updateHeight_voxelRemoved_returnsValue() { - int[] heights = new int[] { 1, 0, 1, 1, 2, 2, 0, 0, 0, 3 }; - int[][][] voxelLists = new int[][][] { - { { 1, 1, 2 } }, - { { 1, 1, 2 }, { 0, 0, 2 } }, - { { 1, 1, 2 }, { 0, 0, 1 } }, - { { 1, 1, 2 }, { 0, 0, 3 } }, - { { 1, 1, 2 }, { 0, 0, 0 } }, - { { 1, 1, 2 }, { 0, 0, 4 } }, - { { 1, 1, 2 }, { 0, 0, 2 }, { 0, 0, 3 } }, - { { 1, 1, 2 }, { 0, 0, 2 }, { 0, 0, 1 } }, - { { 1, 1, 2 }, { 0, 0, 1 }, { 0, 0, 2 }, { 0, 0, 3 } }, - { { 1, 1, 2 }, { 0, 0, 5 }, { 0, 0, 6 } }, - }; - + int[] heights = new int[] {1, 0, 1, 1, 2, 2, 0, 0, 0, 3}; + int[][][] voxelLists = + new int[][][] { + {{1, 1, 2}}, + {{1, 1, 2}, {0, 0, 2}}, + {{1, 1, 2}, {0, 0, 1}}, + {{1, 1, 2}, {0, 0, 3}}, + {{1, 1, 2}, {0, 0, 0}}, + {{1, 1, 2}, {0, 0, 4}}, + {{1, 1, 2}, {0, 0, 2}, {0, 0, 3}}, + {{1, 1, 2}, {0, 0, 2}, {0, 0, 1}}, + {{1, 1, 2}, {0, 0, 1}, {0, 0, 2}, {0, 0, 3}}, + {{1, 1, 2}, {0, 0, 5}, {0, 0, 6}}, + }; + for (int i = 0; i < heights.length; i++) { ArrayList voxels = new ArrayList<>(); for (int[] v : voxelLists[i]) { @@ -825,7 +835,7 @@ public void updateHeight_voxelRemoved_returnsValue() { assertEquals(heights[i], loc.updateHeight(new Voxel(1, 1, 2))); } } - + @Test public void getSlice_givenLocationPlane_returnsValue() { PottsLocation3D loc = new PottsLocation3D(new ArrayList<>()); @@ -833,103 +843,103 @@ public void getSlice_givenLocationPlane_returnsValue() { assertEquals(Direction.YZ_PLANE, loc.getSlice(Direction.YZ_PLANE, null)); assertEquals(Direction.ZX_PLANE, loc.getSlice(Direction.ZX_PLANE, null)); } - + @Test public void getSlice_givenLocationPositiveXY_returnsValue() { PottsLocation3D loc = new PottsLocation3D(new ArrayList<>()); - + HashMap diametersA = new HashMap<>(); diametersA.put(Direction.POSITIVE_XY, 1); diametersA.put(Direction.XY_PLANE, 2); - + HashMap diametersB = new HashMap<>(); diametersB.put(Direction.XY_PLANE, 1); diametersB.put(Direction.POSITIVE_XY, 2); - + assertEquals(Direction.XY_PLANE, loc.getSlice(Direction.POSITIVE_XY, diametersA)); assertEquals(Direction.NEGATIVE_XY, loc.getSlice(Direction.POSITIVE_XY, diametersB)); } - + @Test public void getSlice_givenLocationNegativeXY_returnsValue() { PottsLocation3D loc = new PottsLocation3D(new ArrayList<>()); - + HashMap diametersA = new HashMap<>(); diametersA.put(Direction.NEGATIVE_XY, 1); diametersA.put(Direction.XY_PLANE, 2); - + HashMap diametersB = new HashMap<>(); diametersB.put(Direction.XY_PLANE, 1); diametersB.put(Direction.NEGATIVE_XY, 2); - + assertEquals(Direction.XY_PLANE, loc.getSlice(Direction.NEGATIVE_XY, diametersA)); assertEquals(Direction.POSITIVE_XY, loc.getSlice(Direction.NEGATIVE_XY, diametersB)); } - + @Test public void getSlice_givenLocationPositiveYZ_returnsValue() { PottsLocation3D loc = new PottsLocation3D(new ArrayList<>()); - + HashMap diametersA = new HashMap<>(); diametersA.put(Direction.POSITIVE_YZ, 1); diametersA.put(Direction.YZ_PLANE, 2); - + HashMap diametersB = new HashMap<>(); diametersB.put(Direction.YZ_PLANE, 1); diametersB.put(Direction.POSITIVE_YZ, 2); - + assertEquals(Direction.YZ_PLANE, loc.getSlice(Direction.POSITIVE_YZ, diametersA)); assertEquals(Direction.NEGATIVE_YZ, loc.getSlice(Direction.POSITIVE_YZ, diametersB)); } - + @Test public void getSlice_givenLocationNegativeYZ_returnsValue() { PottsLocation3D loc = new PottsLocation3D(new ArrayList<>()); - + HashMap diametersA = new HashMap<>(); diametersA.put(Direction.NEGATIVE_YZ, 1); diametersA.put(Direction.YZ_PLANE, 2); - + HashMap diametersB = new HashMap<>(); diametersB.put(Direction.YZ_PLANE, 1); diametersB.put(Direction.NEGATIVE_YZ, 2); - + assertEquals(Direction.YZ_PLANE, loc.getSlice(Direction.NEGATIVE_YZ, diametersA)); assertEquals(Direction.POSITIVE_YZ, loc.getSlice(Direction.NEGATIVE_YZ, diametersB)); } - + @Test public void getSlice_givenLocationPositiveZX_returnsValue() { PottsLocation3D loc = new PottsLocation3D(new ArrayList<>()); - + HashMap diametersA = new HashMap<>(); diametersA.put(Direction.POSITIVE_ZX, 1); diametersA.put(Direction.ZX_PLANE, 2); - + HashMap diametersB = new HashMap<>(); diametersB.put(Direction.ZX_PLANE, 1); diametersB.put(Direction.POSITIVE_ZX, 2); - + assertEquals(Direction.ZX_PLANE, loc.getSlice(Direction.POSITIVE_ZX, diametersA)); assertEquals(Direction.NEGATIVE_ZX, loc.getSlice(Direction.POSITIVE_ZX, diametersB)); } - + @Test public void getSlice_givenLocationNegativeZX_returnsValue() { PottsLocation3D loc = new PottsLocation3D(new ArrayList<>()); - + HashMap diametersA = new HashMap<>(); diametersA.put(Direction.NEGATIVE_ZX, 1); diametersA.put(Direction.ZX_PLANE, 2); - + HashMap diametersB = new HashMap<>(); diametersB.put(Direction.ZX_PLANE, 1); diametersB.put(Direction.NEGATIVE_ZX, 2); - + assertEquals(Direction.ZX_PLANE, loc.getSlice(Direction.NEGATIVE_ZX, diametersA)); assertEquals(Direction.POSITIVE_ZX, loc.getSlice(Direction.NEGATIVE_ZX, diametersB)); } - + @Test public void getSlice_givenLocationsPlane_returnsValue() { PottsLocations3D loc = new PottsLocations3D(new ArrayList<>()); @@ -937,116 +947,116 @@ public void getSlice_givenLocationsPlane_returnsValue() { assertEquals(Direction.YZ_PLANE, loc.getSlice(Direction.YZ_PLANE, null)); assertEquals(Direction.ZX_PLANE, loc.getSlice(Direction.ZX_PLANE, null)); } - + @Test public void getSlice_givenLocationsPositiveXY_returnsValue() { PottsLocations3D loc = new PottsLocations3D(new ArrayList<>()); - + HashMap diametersA = new HashMap<>(); diametersA.put(Direction.POSITIVE_XY, 1); diametersA.put(Direction.XY_PLANE, 2); - + HashMap diametersB = new HashMap<>(); diametersB.put(Direction.XY_PLANE, 1); diametersB.put(Direction.POSITIVE_XY, 2); - + assertEquals(Direction.XY_PLANE, loc.getSlice(Direction.POSITIVE_XY, diametersA)); assertEquals(Direction.NEGATIVE_XY, loc.getSlice(Direction.POSITIVE_XY, diametersB)); } - + @Test public void getSlice_givenLocationsNegativeXY_returnsValue() { PottsLocations3D loc = new PottsLocations3D(new ArrayList<>()); - + HashMap diametersA = new HashMap<>(); diametersA.put(Direction.NEGATIVE_XY, 1); diametersA.put(Direction.XY_PLANE, 2); - + HashMap diametersB = new HashMap<>(); diametersB.put(Direction.XY_PLANE, 1); diametersB.put(Direction.NEGATIVE_XY, 2); - + assertEquals(Direction.XY_PLANE, loc.getSlice(Direction.NEGATIVE_XY, diametersA)); assertEquals(Direction.POSITIVE_XY, loc.getSlice(Direction.NEGATIVE_XY, diametersB)); } - + @Test public void getSlice_givenLocationsPositiveYZ_returnsValue() { PottsLocations3D loc = new PottsLocations3D(new ArrayList<>()); - + HashMap diametersA = new HashMap<>(); diametersA.put(Direction.POSITIVE_YZ, 1); diametersA.put(Direction.YZ_PLANE, 2); - + HashMap diametersB = new HashMap<>(); diametersB.put(Direction.YZ_PLANE, 1); diametersB.put(Direction.POSITIVE_YZ, 2); - + assertEquals(Direction.YZ_PLANE, loc.getSlice(Direction.POSITIVE_YZ, diametersA)); assertEquals(Direction.NEGATIVE_YZ, loc.getSlice(Direction.POSITIVE_YZ, diametersB)); } - + @Test public void getSlice_givenLocationsNegativeYZ_returnsValue() { PottsLocations3D loc = new PottsLocations3D(new ArrayList<>()); - + HashMap diametersA = new HashMap<>(); diametersA.put(Direction.NEGATIVE_YZ, 1); diametersA.put(Direction.YZ_PLANE, 2); - + HashMap diametersB = new HashMap<>(); diametersB.put(Direction.YZ_PLANE, 1); diametersB.put(Direction.NEGATIVE_YZ, 2); - + assertEquals(Direction.YZ_PLANE, loc.getSlice(Direction.NEGATIVE_YZ, diametersA)); assertEquals(Direction.POSITIVE_YZ, loc.getSlice(Direction.NEGATIVE_YZ, diametersB)); } - + @Test public void getSlice_givenLocationsPositiveZX_returnsValue() { PottsLocations3D loc = new PottsLocations3D(new ArrayList<>()); - + HashMap diametersA = new HashMap<>(); diametersA.put(Direction.POSITIVE_ZX, 1); diametersA.put(Direction.ZX_PLANE, 2); - + HashMap diametersB = new HashMap<>(); diametersB.put(Direction.ZX_PLANE, 1); diametersB.put(Direction.POSITIVE_ZX, 2); - + assertEquals(Direction.ZX_PLANE, loc.getSlice(Direction.POSITIVE_ZX, diametersA)); assertEquals(Direction.NEGATIVE_ZX, loc.getSlice(Direction.POSITIVE_ZX, diametersB)); } - + @Test public void getSlice_givenLocationsNegativeZX_returnsValue() { PottsLocations3D loc = new PottsLocations3D(new ArrayList<>()); - + HashMap diametersA = new HashMap<>(); diametersA.put(Direction.NEGATIVE_ZX, 1); diametersA.put(Direction.ZX_PLANE, 2); - + HashMap diametersB = new HashMap<>(); diametersB.put(Direction.ZX_PLANE, 1); diametersB.put(Direction.NEGATIVE_ZX, 2); - + assertEquals(Direction.ZX_PLANE, loc.getSlice(Direction.NEGATIVE_ZX, diametersA)); assertEquals(Direction.POSITIVE_ZX, loc.getSlice(Direction.NEGATIVE_ZX, diametersB)); } - + @Test public void getSlice_invalidDirection_returnsNull() { PottsLocation3D loc = new PottsLocation3D(new ArrayList<>()); assertNull(loc.getSlice(Direction.UNDEFINED, null)); - + PottsLocations3D locs = new PottsLocations3D(new ArrayList<>()); assertNull(locs.getSlice(Direction.UNDEFINED, null)); } - + @Test public void getSelected_midSizeLocation_returnsList() { ArrayList voxels = new ArrayList<>(); - + int r = 4; int h = 6; int n = 10; @@ -1057,20 +1067,20 @@ public void getSelected_midSizeLocation_returnsList() { } } } - + PottsLocation3D loc = new PottsLocation3D(voxels); ArrayList selected = loc.getSelected(new Voxel(0, 0, 0), Math.PI * r * r * h); - + assertTrue(selected.size() < n * n * h); for (Voxel voxel : selected) { assertTrue(Math.sqrt(Math.pow(voxel.x, 2) + Math.pow(voxel.y, 2)) <= r); } } - + @Test public void getSelected_maxSizeLocation_returnsList() { ArrayList voxels = new ArrayList<>(); - + int h = 6; int n = 10; for (int k = 0; k < h; k++) { @@ -1080,17 +1090,17 @@ public void getSelected_maxSizeLocation_returnsList() { } } } - + PottsLocation3D loc = new PottsLocation3D(voxels); ArrayList selected = loc.getSelected(new Voxel(0, 0, 0), Integer.MAX_VALUE); - + assertEquals(selected.size(), n * n * h); } - + @Test public void getSelected_minSizeLocation_returnsList() { ArrayList voxels = new ArrayList<>(); - + int h = 6; int n = 10; for (int k = 0; k < h; k++) { @@ -1100,18 +1110,18 @@ public void getSelected_minSizeLocation_returnsList() { } } } - + PottsLocation3D loc = new PottsLocation3D(voxels); ArrayList selected = loc.getSelected(new Voxel(0, 0, 0), 0); - + assertEquals(selected.size(), 0); } - + @Test public void getSelected_midSizeLocations_returnsList() { ArrayList voxelsA = new ArrayList<>(); ArrayList voxelsB = new ArrayList<>(); - + int r = 4; int h = 6; int n = 10; @@ -1129,11 +1139,11 @@ public void getSelected_midSizeLocations_returnsList() { } } } - + PottsLocations3D loc = new PottsLocations3D(voxelsA); voxelsB.forEach(voxel -> loc.add(Region.UNDEFINED, voxel.x, voxel.y, voxel.z)); ArrayList selected = loc.getSelected(new Voxel(0, 0, 0), Math.PI * r * r * h); - + assertTrue(selected.size() < voxelsB.size()); for (Voxel voxel : selected) { assertTrue(Math.sqrt(Math.pow(voxel.x, 2) + Math.pow(voxel.y, 2)) <= r); @@ -1141,12 +1151,12 @@ public void getSelected_midSizeLocations_returnsList() { assertFalse(voxelsB.contains(voxel)); } } - + @Test public void getSelected_maxSizeLocations_returnsList() { ArrayList voxelsA = new ArrayList<>(); ArrayList voxelsB = new ArrayList<>(); - + int h = 6; int n = 10; for (int k = 0; k < h; k++) { @@ -1163,19 +1173,19 @@ public void getSelected_maxSizeLocations_returnsList() { } } } - + PottsLocations3D loc = new PottsLocations3D(voxelsA); voxelsB.forEach(voxel -> loc.add(Region.UNDEFINED, voxel.x, voxel.y, voxel.z)); ArrayList selected = loc.getSelected(new Voxel(0, 0, 0), Integer.MAX_VALUE); - + assertEquals(selected.size(), voxelsA.size()); } - + @Test public void getSelected_minSizeLocations_returnsList() { ArrayList voxelsA = new ArrayList<>(); ArrayList voxelsB = new ArrayList<>(); - + int h = 6; int n = 10; for (int k = 0; k < h; k++) { @@ -1192,11 +1202,11 @@ public void getSelected_minSizeLocations_returnsList() { } } } - + PottsLocations3D loc = new PottsLocations3D(voxelsA); voxelsB.forEach(voxel -> loc.add(Region.UNDEFINED, voxel.x, voxel.y, voxel.z)); ArrayList selected = loc.getSelected(new Voxel(0, 0, 0), 0); - + assertEquals(selected.size(), 0); } } diff --git a/test/arcade/potts/env/location/PlaneTest.java b/test/arcade/potts/env/location/PlaneTest.java new file mode 100644 index 000000000..9166c76c5 --- /dev/null +++ b/test/arcade/potts/env/location/PlaneTest.java @@ -0,0 +1,162 @@ +package arcade.potts.env.location; + +import org.junit.jupiter.api.Test; +import sim.util.Double3D; +import static org.junit.jupiter.api.Assertions.*; + +public class PlaneTest { + static final double EPSILON = 0.0001; + + @Test + public void constructor_givenPointAndUnitVector_returnsCorrectPlane() { + Voxel point = new Voxel(1, 2, 3); + Double3D normalVector = new Double3D(1, 0, 0); + Plane plane = new Plane(point, normalVector); + assertEquals(point, plane.referencePoint); + assertEquals(normalVector, plane.unitNormalVector); + } + + @Test + public void constructor_givenPointAndIntegerVector_returnsCorrectPlane() { + Voxel point = new Voxel(1, 2, 3); + Double3D normalVector = new Double3D(2, 2, 1); + + Plane plane = new Plane(point, normalVector); + + double expectedX = normalVector.getX() / 3.0; + double expectedY = normalVector.getY() / 3.0; + double expectedZ = normalVector.getZ() / 3.0; + Double3D expectedUnitNormal = new Double3D(expectedX, expectedY, expectedZ); + assertEquals(point, plane.referencePoint); + assertEquals(expectedUnitNormal, plane.unitNormalVector); + } + + @Test + public void constructor_givenPointAndDoubleVector_returnsCorrectPlane() { + Voxel point = new Voxel(1, 2, 3); + Double3D normalVector = new Double3D(1.5, 1.5, 1); + + Plane plane = new Plane(point, normalVector); + + double expectedX = normalVector.getX() / Math.sqrt(5.5); + double expectedY = normalVector.getY() / Math.sqrt(5.5); + double expectedZ = normalVector.getZ() / Math.sqrt(5.5); + Double3D expectedUnitNormal = new Double3D(expectedX, expectedY, expectedZ); + assertEquals(point, plane.referencePoint); + assertEquals(expectedUnitNormal, plane.unitNormalVector); + } + + @Test + public void getNormalVectorMagnitude_givenNormalVector_returnsCorrectMagnitude() { + double magnitude = Plane.getNormalVectorMagnitude(new Double3D(1, 2, 2)); + assertEquals(3, magnitude, EPSILON); + } + + @Test + public void getNormalVectorMagnitude_givenUnitVector_returnsOne() { + double magnitude = Plane.getNormalVectorMagnitude(new Double3D(1, 0, 0)); + assertEquals(1, magnitude, EPSILON); + } + + @Test + public void scaleNormalVector_givenUnitVector_returnsSameVector() { + Double3D normalVector = new Double3D(1, 0, 0); + Double3D unitNormalVector = Plane.scaleNormalVector(normalVector); + assertEquals(normalVector, unitNormalVector); + } + + @Test + public void scaleNormalVector_givenNonUnitVector_returnsUnitVector() { + Double3D unitNormalVector = Plane.scaleNormalVector(new Double3D(1, 2, 2)); + Double x = 1.0 / 3.0; + Double y = 2.0 / 3.0; + Double z = 2.0 / 3.0; + assertEquals(new Double3D(x, y, z), unitNormalVector); + } + + @Test + public void equals_givenDifferentPlane_returnsFalse() { + Plane plane1 = new Plane(new Voxel(1, 2, 3), new Double3D(4, 5, 6)); + Plane plane2 = new Plane(new Voxel(4, 5, 6), new Double3D(7, 8, 9)); + + assertNotEquals(plane1, plane2); + } + + @Test + public void equals_givenSamePlane_returnsTrue() { + Plane plane1 = new Plane(new Voxel(1, 2, 3), new Double3D(4, 5, 6)); + Plane plane2 = new Plane(new Voxel(1, 2, 3), new Double3D(4, 5, 6)); + + assertEquals(plane1, plane2); + } + + @Test + public void distanceToPlane_givenPointOnPlane_returnsZero() { + Voxel pointOnPlane = new Voxel(0, 0, 0); + Double3D normalVector = new Double3D(1, 0, 0); + Plane plane = new Plane(pointOnPlane, normalVector); + + Voxel pointToTest = new Voxel(0, 0, 0); + + assertEquals(0, plane.signedDistanceToPlane(pointToTest), EPSILON); + } + + @Test + public void distanceToPlane_givenPointOnNormalSideOfPlane_returnsCorrectPositiveDistance() { + Voxel pointOnPlane = new Voxel(0, 0, 0); + Double3D normalVector = new Double3D(1, 0, 0); + Plane plane = new Plane(pointOnPlane, normalVector); + + Voxel pointToTest = new Voxel(1, 1, 1); + + assertEquals(1, plane.signedDistanceToPlane(pointToTest), EPSILON); + } + + @Test + public void distanceToPlane_givenPointOnOppositeSideOfPlane_returnsCorrectNegativeDistance() { + Voxel pointOnPlane = new Voxel(0, 0, 0); + Double3D normalVector = new Double3D(1, 0, 0); + Plane plane = new Plane(pointOnPlane, normalVector); + + Voxel pointToTest = new Voxel(-1, -1, -1); + + assertEquals(-1, plane.signedDistanceToPlane(pointToTest), EPSILON); + } + + @Test + public void signedDistanceToPlane_givenPointOnAxis_returnsCorrectSignedDistance() { + Voxel point = new Voxel(0, 0, 0); + Double3D normalVector = new Double3D(0, 0, 1); + Plane plane = new Plane(point, normalVector); + + Voxel posTestPoint = new Voxel(0, 0, 5); + Voxel negTestPoint = new Voxel(0, 0, -5); + + assertEquals(5.0, plane.signedDistanceToPlane(posTestPoint), EPSILON); + assertEquals(-5.0, plane.signedDistanceToPlane(negTestPoint), EPSILON); + } + + @Test + public void signedDistanceToPlane_givenPointOffAxis_returnsCorrectSignedDistance() { + Voxel point = new Voxel(1, 1, 2); + Double3D normalVector = new Double3D(1, 2, 2); + Plane plane = new Plane(point, normalVector); + + Voxel postestPoint = new Voxel(2, 2, 5); + Voxel negtestPoint = new Voxel(0, 0, -1); + + assertEquals(3.0, plane.signedDistanceToPlane(postestPoint), EPSILON); + assertEquals(-3.0, plane.signedDistanceToPlane(negtestPoint), EPSILON); + } + + @Test + public void hashCode_equalObjects_returnsSameCode() { + Voxel point = new Voxel(1, 2, 3); + Double3D normalVector = new Double3D(4, 5, 6); + + Plane plane1 = new Plane(point, normalVector); + Plane plane2 = new Plane(point, normalVector); + + assertEquals(plane1.hashCode(), plane2.hashCode()); + } +} diff --git a/test/arcade/potts/env/location/PottsLocation2DTest.java b/test/arcade/potts/env/location/PottsLocation2DTest.java index d722c8d3f..81f861ab3 100644 --- a/test/arcade/potts/env/location/PottsLocation2DTest.java +++ b/test/arcade/potts/env/location/PottsLocation2DTest.java @@ -1,42 +1,42 @@ package arcade.potts.env.location; import java.util.ArrayList; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import ec.util.MersenneTwisterFast; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.potts.env.location.Voxel.VOXEL_COMPARATOR; public class PottsLocation2DTest { static MersenneTwisterFast randomDoubleZero; - + static MersenneTwisterFast randomDoubleOne; - + static ArrayList voxelListA; - + static ArrayList voxelListB; - + static ArrayList voxelListC; - + static ArrayList voxelListAC; - + static ArrayList voxelListCA; - + static ArrayList voxelListBC; - + static ArrayList voxelListAB; - - @BeforeClass + + @BeforeAll public static void setupMocks() { randomDoubleZero = mock(MersenneTwisterFast.class); when(randomDoubleZero.nextDouble()).thenReturn(0.0); - + randomDoubleOne = mock(MersenneTwisterFast.class); when(randomDoubleOne.nextDouble()).thenReturn(1.0); } - - @BeforeClass + + @BeforeAll public static void setupLists() { /* * Lattice site shape: @@ -52,47 +52,47 @@ public static void setupLists() { * x . . . . x . x . x x . . x x x . x * x . . . . . . x x x x x . x x x . */ - + voxelListA = new ArrayList<>(); voxelListA.add(new Voxel(0, 0, 0)); voxelListA.add(new Voxel(0, 1, 0)); voxelListA.add(new Voxel(1, 0, 0)); voxelListA.add(new Voxel(0, 2, 0)); - + voxelListB = new ArrayList<>(); voxelListB.add(new Voxel(2, 0, 0)); voxelListB.add(new Voxel(3, 0, 0)); voxelListB.add(new Voxel(3, 1, 0)); - + voxelListC = new ArrayList<>(); voxelListC.add(new Voxel(2, 1, 0)); voxelListC.add(new Voxel(3, 2, 0)); voxelListC.add(new Voxel(4, 2, 0)); - + voxelListAC = new ArrayList<>(voxelListA); voxelListAC.addAll(voxelListC); - + voxelListCA = new ArrayList<>(voxelListC); voxelListCA.addAll(voxelListA); - + voxelListBC = new ArrayList<>(voxelListB); voxelListBC.addAll(voxelListC); - + voxelListAB = new ArrayList<>(voxelListA); voxelListAB.addAll(voxelListB); } - + @Test public void makeLocation_givenList_createsObject() { ArrayList voxels = new ArrayList<>(); voxels.add(new Voxel(0, 0, 0)); PottsLocation2D oldLoc = new PottsLocation2D(new ArrayList<>()); PottsLocation newLoc = oldLoc.makeLocation(voxels); - + assertTrue(newLoc instanceof PottsLocation2D); assertEquals(1, newLoc.voxels.size()); } - + @Test public void checkVoxels_noVoxels_returnsNull() { PottsLocation2D loc = new PottsLocation2D(new ArrayList<>()); @@ -100,7 +100,7 @@ public void checkVoxels_noVoxels_returnsNull() { assertNull(PottsLocation.checkVoxels(voxels, loc, randomDoubleZero, false)); assertNull(PottsLocation.checkVoxels(voxels, loc, randomDoubleZero, true)); } - + @Test public void checkVoxels_connectedVoxels_returnsNull() { PottsLocation2D loc = new PottsLocation2D(new ArrayList<>()); @@ -108,14 +108,14 @@ public void checkVoxels_connectedVoxels_returnsNull() { assertNull(PottsLocation.checkVoxels(voxels, loc, randomDoubleZero, false)); assertNull(PottsLocation.checkVoxels(voxels, loc, randomDoubleZero, true)); } - + @Test public void checkVoxels_unconnectedVoxelsWithoutUpdateLargerVisited_returnsList() { PottsLocation2D loc = new PottsLocation2D(new ArrayList<>()); ArrayList voxels = new ArrayList<>(voxelListAC); assertEquals(voxelListC, PottsLocation.checkVoxels(voxels, loc, randomDoubleZero, false)); } - + @Test public void checkVoxels_unconnectedVoxelsWithoutUpdateLargerUnvisited_returnsList() { PottsLocation2D loc = new PottsLocation2D(new ArrayList<>()); @@ -124,7 +124,7 @@ public void checkVoxels_unconnectedVoxelsWithoutUpdateLargerUnvisited_returnsLis unvisited.add(voxelListC.get(0)); assertEquals(unvisited, PottsLocation.checkVoxels(voxels, loc, randomDoubleZero, false)); } - + @Test public void checkVoxels_unconnectedVoxelsWithUpdateLargerVisited_updatesList() { PottsLocation2D loc = new PottsLocation2D(new ArrayList<>()); @@ -132,21 +132,21 @@ public void checkVoxels_unconnectedVoxelsWithUpdateLargerVisited_updatesList() { assertEquals(voxelListC, PottsLocation.checkVoxels(voxels, loc, randomDoubleZero, true)); assertEquals(voxelListA, voxels); } - + @Test public void checkVoxels_unconnectedVoxelsWithUpdateLargerUnvisited_updatesList() { PottsLocation2D loc = new PottsLocation2D(new ArrayList<>()); ArrayList voxels = new ArrayList<>(voxelListCA); ArrayList unvisited = new ArrayList<>(); unvisited.add(voxelListC.get(0)); - + ArrayList visited = new ArrayList<>(voxelListCA); visited.remove(voxelListC.get(0)); - + assertEquals(unvisited, PottsLocation.checkVoxels(voxels, loc, randomDoubleZero, true)); assertEquals(visited, voxels); } - + @Test public void connectVoxels_bothListsConnected_doesNothing() { PottsLocation2D loc = new PottsLocation2D(new ArrayList<>()); @@ -156,24 +156,24 @@ public void connectVoxels_bothListsConnected_doesNothing() { assertEquals(voxelListA, voxelsA); assertEquals(voxelListB, voxelsB); } - + @Test public void connectVoxels_oneListUnconnected_updatesLists() { PottsLocation2D loc = new PottsLocation2D(new ArrayList<>()); - + ArrayList voxelsA1 = new ArrayList<>(voxelListAC); ArrayList voxelsB1 = new ArrayList<>(voxelListB); PottsLocation.connectVoxels(voxelsA1, voxelsB1, loc, randomDoubleZero); assertEquals(voxelListA, voxelsA1); assertEquals(voxelListBC, voxelsB1); - + ArrayList voxelsA2 = new ArrayList<>(voxelListAC); ArrayList voxelsB2 = new ArrayList<>(voxelListB); PottsLocation.connectVoxels(voxelsB2, voxelsA2, loc, randomDoubleZero); assertEquals(voxelListA, voxelsA2); assertEquals(voxelListBC, voxelsB2); } - + @Test public void balanceVoxels_balancedLists_doesNothing() { PottsLocation2D loc = new PottsLocation2D(new ArrayList<>()); @@ -183,98 +183,98 @@ public void balanceVoxels_balancedLists_doesNothing() { assertEquals(voxelListA, voxelsA); assertEquals(voxelListB, voxelsB); } - + @Test public void balanceVoxels_unbalancedLists_updatesLists() { PottsLocation2D loc = new PottsLocation2D(new ArrayList<>()); ArrayList voxelsA = new ArrayList<>(voxelListAB); ArrayList voxelsB = new ArrayList<>(); - + voxelsA.remove(new Voxel(3, 1, 0)); voxelsB.add(new Voxel(3, 1, 0)); - + PottsLocation.balanceVoxels(voxelsA, voxelsB, loc, randomDoubleZero); - + voxelListA.sort(VOXEL_COMPARATOR); voxelListB.sort(VOXEL_COMPARATOR); voxelsA.sort(VOXEL_COMPARATOR); voxelsB.sort(VOXEL_COMPARATOR); - + assertEquals(voxelListA, voxelsA); assertEquals(voxelListB, voxelsB); } - + @Test public void balanceVoxels_unconnectedLists_updatesLists() { PottsLocation2D loc = new PottsLocation2D(new ArrayList<>()); ArrayList voxelsA = new ArrayList<>(); ArrayList voxelsB = new ArrayList<>(voxelListAC); - + voxelsB.add(new Voxel(1, 1, 0)); voxelsB.add(new Voxel(3, 1, 0)); voxelsB.remove(new Voxel(1, 0, 0)); voxelsA.add(new Voxel(1, 0, 0)); - + PottsLocation.balanceVoxels(voxelsA, voxelsB, loc, randomDoubleZero); - + ArrayList voxelListAX = new ArrayList<>(voxelListA); ArrayList voxelListCX = new ArrayList<>(voxelListC); voxelListAX.add(new Voxel(1, 1, 0)); voxelListCX.add(new Voxel(3, 1, 0)); - + voxelListAX.sort(VOXEL_COMPARATOR); voxelListCX.sort(VOXEL_COMPARATOR); voxelsA.sort(VOXEL_COMPARATOR); voxelsB.sort(VOXEL_COMPARATOR); - + assertEquals(voxelListAX, voxelsA); assertEquals(voxelListCX, voxelsB); } - + @Test public void balanceVoxels_emptyList_updatesLists() { PottsLocation2D loc = new PottsLocation2D(new ArrayList<>()); ArrayList voxelsA = new ArrayList<>(voxelListAB); ArrayList voxelsB = new ArrayList<>(); - + PottsLocation.balanceVoxels(voxelsA, voxelsB, loc, randomDoubleZero); assertTrue(voxelsA.size() != 0); assertTrue(voxelsB.size() != 0); } - + @Test public void split_balanceableLocationRandomZero_returnsList() { PottsLocation2D loc = new PottsLocation2D(voxelListAB); PottsLocation2D split = (PottsLocation2D) loc.split(randomDoubleZero); - + ArrayList locVoxels = new ArrayList<>(voxelListA); locVoxels.remove(new Voxel(1, 0, 0)); - + ArrayList splitVoxels = new ArrayList<>(voxelListB); splitVoxels.add(new Voxel(1, 0, 0)); - + locVoxels.sort(VOXEL_COMPARATOR); loc.voxels.sort(VOXEL_COMPARATOR); splitVoxels.sort(VOXEL_COMPARATOR); split.voxels.sort(VOXEL_COMPARATOR); - + assertEquals(locVoxels, loc.voxels); assertEquals(splitVoxels, split.voxels); } - + @Test public void split_balanceableLocationRandomOne_returnsList() { PottsLocation2D loc = new PottsLocation2D(voxelListAB); PottsLocation2D split = (PottsLocation2D) loc.split(randomDoubleOne); - + ArrayList locVoxels = new ArrayList<>(voxelListB); ArrayList splitVoxels = new ArrayList<>(voxelListA); - + locVoxels.sort(VOXEL_COMPARATOR); loc.voxels.sort(VOXEL_COMPARATOR); splitVoxels.sort(VOXEL_COMPARATOR); split.voxels.sort(VOXEL_COMPARATOR); - + assertEquals(locVoxels, loc.voxels); assertEquals(splitVoxels, split.voxels); } diff --git a/test/arcade/potts/env/location/PottsLocation3DTest.java b/test/arcade/potts/env/location/PottsLocation3DTest.java index 8dd55a7c7..fad9b4548 100644 --- a/test/arcade/potts/env/location/PottsLocation3DTest.java +++ b/test/arcade/potts/env/location/PottsLocation3DTest.java @@ -1,42 +1,42 @@ package arcade.potts.env.location; import java.util.ArrayList; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import ec.util.MersenneTwisterFast; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.potts.env.location.Voxel.VOXEL_COMPARATOR; public class PottsLocation3DTest { static MersenneTwisterFast randomDoubleZero; - + static MersenneTwisterFast randomDoubleOne; - + static ArrayList voxelListA; - + static ArrayList voxelListB; - + static ArrayList voxelListC; - + static ArrayList voxelListAC; - + static ArrayList voxelListCA; - + static ArrayList voxelListBC; - + static ArrayList voxelListAB; - - @BeforeClass + + @BeforeAll public static void setupMocks() { randomDoubleZero = mock(MersenneTwisterFast.class); when(randomDoubleZero.nextDouble()).thenReturn(0.0); - + randomDoubleOne = mock(MersenneTwisterFast.class); when(randomDoubleOne.nextDouble()).thenReturn(1.0); } - - @BeforeClass + + @BeforeAll public static void setupLists() { /* * Lattice site shape: @@ -60,7 +60,7 @@ public static void setupLists() { * . . . . . x . . . . . . . . x . . x * x . . . x x . . . x . . . x x x x x */ - + voxelListA = new ArrayList<>(); voxelListA.add(new Voxel(0, 0, 1)); voxelListA.add(new Voxel(0, 1, 1)); @@ -69,7 +69,7 @@ public static void setupLists() { voxelListA.add(new Voxel(0, 0, 0)); voxelListA.add(new Voxel(1, 0, 0)); voxelListA.add(new Voxel(0, 2, 2)); - + voxelListB = new ArrayList<>(); voxelListB.add(new Voxel(2, 0, 1)); voxelListB.add(new Voxel(3, 0, 1)); @@ -77,38 +77,38 @@ public static void setupLists() { voxelListB.add(new Voxel(3, 1, 2)); voxelListB.add(new Voxel(3, 2, 2)); voxelListB.add(new Voxel(4, 2, 2)); - + voxelListC = new ArrayList<>(); voxelListC.add(new Voxel(2, 1, 1)); voxelListC.add(new Voxel(3, 2, 1)); voxelListC.add(new Voxel(4, 2, 1)); voxelListC.add(new Voxel(2, 1, 0)); voxelListC.add(new Voxel(4, 2, 0)); - + voxelListAC = new ArrayList<>(voxelListA); voxelListAC.addAll(voxelListC); - + voxelListCA = new ArrayList<>(voxelListC); voxelListCA.addAll(voxelListA); - + voxelListBC = new ArrayList<>(voxelListB); voxelListBC.addAll(voxelListC); - + voxelListAB = new ArrayList<>(voxelListA); voxelListAB.addAll(voxelListB); } - + @Test public void makeLocation_givenList_createsObject() { ArrayList voxels = new ArrayList<>(); voxels.add(new Voxel(0, 0, 0)); PottsLocation3D oldLoc = new PottsLocation3D(new ArrayList<>()); PottsLocation newLoc = oldLoc.makeLocation(voxels); - + assertTrue(newLoc instanceof PottsLocation3D); assertEquals(1, newLoc.voxels.size()); } - + @Test public void checkVoxels_noVoxels_returnsNull() { PottsLocation3D loc = new PottsLocation3D(new ArrayList<>()); @@ -116,7 +116,7 @@ public void checkVoxels_noVoxels_returnsNull() { assertNull(PottsLocation.checkVoxels(voxels, loc, randomDoubleZero, false)); assertNull(PottsLocation.checkVoxels(voxels, loc, randomDoubleZero, true)); } - + @Test public void checkVoxels_connectedVoxels_returnsNull() { PottsLocation3D loc = new PottsLocation3D(new ArrayList<>()); @@ -124,14 +124,14 @@ public void checkVoxels_connectedVoxels_returnsNull() { assertNull(PottsLocation.checkVoxels(voxels, loc, randomDoubleZero, false)); assertNull(PottsLocation.checkVoxels(voxels, loc, randomDoubleZero, true)); } - + @Test public void checkVoxels_unconnectedVoxelsWithoutUpdateLargerVisited_returnsList() { PottsLocation3D loc = new PottsLocation3D(new ArrayList<>()); ArrayList voxels = new ArrayList<>(voxelListAC); assertEquals(voxelListC, PottsLocation.checkVoxels(voxels, loc, randomDoubleZero, false)); } - + @Test public void checkVoxels_unconnectedVoxelsWithoutUpdateLargerUnvisited_returnsList() { PottsLocation3D loc = new PottsLocation3D(new ArrayList<>()); @@ -141,7 +141,7 @@ public void checkVoxels_unconnectedVoxelsWithoutUpdateLargerUnvisited_returnsLis unvisited.add(voxelListC.get(3)); assertEquals(unvisited, PottsLocation.checkVoxels(voxels, loc, randomDoubleZero, false)); } - + @Test public void checkVoxels_unconnectedVoxelsWithUpdateLargerVisited_updatesList() { PottsLocation3D loc = new PottsLocation3D(new ArrayList<>()); @@ -149,7 +149,7 @@ public void checkVoxels_unconnectedVoxelsWithUpdateLargerVisited_updatesList() { assertEquals(voxelListC, PottsLocation.checkVoxels(voxels, loc, randomDoubleZero, true)); assertEquals(voxelListA, voxels); } - + @Test public void checkVoxels_unconnectedVoxelsWithUpdateLargerUnvisited_updatesList() { PottsLocation3D loc = new PottsLocation3D(new ArrayList<>()); @@ -157,15 +157,15 @@ public void checkVoxels_unconnectedVoxelsWithUpdateLargerUnvisited_updatesList() ArrayList unvisited = new ArrayList<>(); unvisited.add(voxelListC.get(0)); unvisited.add(voxelListC.get(3)); - + ArrayList visited = new ArrayList<>(voxelListCA); visited.remove(voxelListC.get(0)); visited.remove(voxelListC.get(3)); - + assertEquals(unvisited, PottsLocation.checkVoxels(voxels, loc, randomDoubleZero, true)); assertEquals(visited, voxels); } - + @Test public void connectVoxels_bothListsConnected_doesNothing() { PottsLocation3D loc = new PottsLocation3D(new ArrayList<>()); @@ -175,24 +175,24 @@ public void connectVoxels_bothListsConnected_doesNothing() { assertEquals(voxelListA, voxelsA); assertEquals(voxelListB, voxelsB); } - + @Test public void connectVoxels_oneListUnconnected_updatesLists() { PottsLocation3D loc = new PottsLocation3D(new ArrayList<>()); - + ArrayList voxelsA1 = new ArrayList<>(voxelListAC); ArrayList voxelsB1 = new ArrayList<>(voxelListB); PottsLocation.connectVoxels(voxelsA1, voxelsB1, loc, randomDoubleZero); assertEquals(voxelListA, voxelsA1); assertEquals(voxelListBC, voxelsB1); - + ArrayList voxelsA2 = new ArrayList<>(voxelListAC); ArrayList voxelsB2 = new ArrayList<>(voxelListB); PottsLocation.connectVoxels(voxelsB2, voxelsA2, loc, randomDoubleZero); assertEquals(voxelListA, voxelsA2); assertEquals(voxelListBC, voxelsB2); } - + @Test public void balanceVoxels_balancedLists_doesNothing() { PottsLocation3D loc = new PottsLocation3D(new ArrayList<>()); @@ -202,95 +202,95 @@ public void balanceVoxels_balancedLists_doesNothing() { assertEquals(voxelListA, voxelsA); assertEquals(voxelListB, voxelsB); } - + @Test public void balanceVoxels_unbalancedLists_updatesLists() { PottsLocation3D loc = new PottsLocation3D(new ArrayList<>()); ArrayList voxelsA = new ArrayList<>(voxelListAB); ArrayList voxelsB = new ArrayList<>(); - + voxelsA.remove(new Voxel(3, 2, 2)); voxelsB.add(new Voxel(3, 2, 2)); - + PottsLocation.balanceVoxels(voxelsA, voxelsB, loc, randomDoubleZero); - + voxelListA.sort(VOXEL_COMPARATOR); voxelListB.sort(VOXEL_COMPARATOR); voxelsA.sort(VOXEL_COMPARATOR); voxelsB.sort(VOXEL_COMPARATOR); - + assertEquals(voxelListA, voxelsA); assertEquals(voxelListB, voxelsB); } - + @Test public void balanceVoxels_unconnectedLists_updatesLists() { PottsLocation3D loc = new PottsLocation3D(new ArrayList<>()); ArrayList voxelsA = new ArrayList<>(); ArrayList voxelsB = new ArrayList<>(voxelListAC); - + voxelsB.add(new Voxel(1, 1, 1)); voxelsB.add(new Voxel(3, 1, 1)); voxelsB.remove(new Voxel(1, 0, 1)); voxelsA.add(new Voxel(1, 0, 1)); - + PottsLocation.balanceVoxels(voxelsA, voxelsB, loc, randomDoubleZero); - + ArrayList voxelListAX = new ArrayList<>(voxelListA); ArrayList voxelListCX = new ArrayList<>(voxelListC); voxelListAX.add(new Voxel(1, 1, 1)); voxelListCX.add(new Voxel(3, 1, 1)); - + voxelListAX.sort(VOXEL_COMPARATOR); voxelListCX.sort(VOXEL_COMPARATOR); voxelsA.sort(VOXEL_COMPARATOR); voxelsB.sort(VOXEL_COMPARATOR); - + assertEquals(voxelListAX, voxelsA); assertEquals(voxelListCX, voxelsB); } - + @Test public void balanceVoxels_emptyList_updatesLists() { PottsLocation3D loc = new PottsLocation3D(new ArrayList<>()); ArrayList voxelsA = new ArrayList<>(voxelListAB); ArrayList voxelsB = new ArrayList<>(); - + PottsLocation.balanceVoxels(voxelsA, voxelsB, loc, randomDoubleZero); assertTrue(voxelsA.size() != 0); assertTrue(voxelsB.size() != 0); } - + @Test public void split_balanceableLocationRandomZero_returnsList() { PottsLocation3D loc = new PottsLocation3D(voxelListAB); PottsLocation3D split = (PottsLocation3D) loc.split(randomDoubleZero); - + ArrayList locVoxels = new ArrayList<>(voxelListA); ArrayList splitVoxels = new ArrayList<>(voxelListB); - + locVoxels.sort(VOXEL_COMPARATOR); loc.voxels.sort(VOXEL_COMPARATOR); splitVoxels.sort(VOXEL_COMPARATOR); split.voxels.sort(VOXEL_COMPARATOR); - + assertEquals(locVoxels, loc.voxels); assertEquals(splitVoxels, split.voxels); } - + @Test public void split_balanceableLocationRandomOne_returnsList() { PottsLocation3D loc = new PottsLocation3D(voxelListAB); PottsLocation3D split = (PottsLocation3D) loc.split(randomDoubleOne); - + ArrayList locVoxels = new ArrayList<>(voxelListB); ArrayList splitVoxels = new ArrayList<>(voxelListA); - + locVoxels.sort(VOXEL_COMPARATOR); loc.voxels.sort(VOXEL_COMPARATOR); splitVoxels.sort(VOXEL_COMPARATOR); split.voxels.sort(VOXEL_COMPARATOR); - + assertEquals(locVoxels, loc.voxels); assertEquals(splitVoxels, split.voxels); } diff --git a/test/arcade/potts/env/location/PottsLocationContainerTest.java b/test/arcade/potts/env/location/PottsLocationContainerTest.java index c272e99f9..703413e71 100644 --- a/test/arcade/potts/env/location/PottsLocationContainerTest.java +++ b/test/arcade/potts/env/location/PottsLocationContainerTest.java @@ -3,12 +3,12 @@ import java.util.ArrayList; import java.util.Collections; import java.util.EnumMap; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import ec.util.MersenneTwisterFast; import arcade.core.env.location.Location; import arcade.potts.agent.cell.PottsCellContainer; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.core.ARCADETestUtilities.*; import static arcade.potts.env.location.PottsLocationFactoryTest.PottsLocationFactoryMock; @@ -16,279 +16,318 @@ public class PottsLocationContainerTest { static final PottsLocationFactory FACTORY = new PottsLocationFactoryMock(); - - static final PottsLocationFactory2D FACTORY_2D = mock(PottsLocationFactory2D.class, CALLS_REAL_METHODS); - - static final PottsLocationFactory3D FACTORY_3D = mock(PottsLocationFactory3D.class, CALLS_REAL_METHODS); - - @BeforeClass + + static final PottsLocationFactory2D FACTORY_2D = + mock(PottsLocationFactory2D.class, CALLS_REAL_METHODS); + + static final PottsLocationFactory3D FACTORY_3D = + mock(PottsLocationFactory3D.class, CALLS_REAL_METHODS); + + @BeforeAll public static void setupMocks() { FACTORY.random = mock(MersenneTwisterFast.class); FACTORY_2D.random = mock(MersenneTwisterFast.class); FACTORY_3D.random = mock(MersenneTwisterFast.class); - + doAnswer(invocation -> (int) invocation.getArgument(0) - 1) - .when(FACTORY.random).nextInt(anyInt()); + .when(FACTORY.random) + .nextInt(anyInt()); } - + @Test public void constructor_noRegions_setsFields() { int id = randomIntBetween(1, 10); ArrayList voxels = new ArrayList<>(); Voxel center = new Voxel(0, 0, 0); - + PottsLocationContainer locationContainer = new PottsLocationContainer(id, center, voxels); - + assertEquals(id, locationContainer.id); assertSame(center, locationContainer.center); assertSame(voxels, locationContainer.allVoxels); assertNull(locationContainer.regions); } - + @Test public void constructor_withRegions_setsFields() { int id = randomIntBetween(1, 10); ArrayList voxels = new ArrayList<>(); Voxel center = new Voxel(0, 0, 0); EnumMap> regions = new EnumMap<>(Region.class); - - PottsLocationContainer locationContainer = new PottsLocationContainer(id, center, voxels, regions); - + + PottsLocationContainer locationContainer = + new PottsLocationContainer(id, center, voxels, regions); + assertEquals(id, locationContainer.id); assertSame(center, locationContainer.center); assertSame(voxels, locationContainer.allVoxels); assertSame(regions, locationContainer.regions); } - + @Test public void getID_called_returnsValue() { int id = randomIntBetween(1, 10); PottsLocationContainer locationContainer = new PottsLocationContainer(id, null, null, null); assertEquals(id, locationContainer.getID()); } - + @Test public void convert_noRegions_createsObject() { int n = 100; for (int i = 1; i < n; i++) { Voxel center = new Voxel(0, 0, 0); ArrayList voxels = FACTORY.getPossible(center, n, 1); - PottsCellContainer cellContainer = new PottsCellContainer(0, 0, 0, 0, 0, null, null, i, 0, 0); - PottsLocationContainer locationContainer = new PottsLocationContainer(0, center, voxels, null); - + PottsCellContainer cellContainer = + new PottsCellContainer(0, 0, 0, 0, 0, null, null, i, 0, 0); + PottsLocationContainer locationContainer = + new PottsLocationContainer(0, center, voxels, null); + Location location = locationContainer.convert(FACTORY, cellContainer); assertEquals(i, (int) location.getVolume()); assertTrue(location instanceof PottsLocation); } } - + @Test public void convert_noRegionsEqual_createsObject() { int n = 100; for (int i = 1; i < n; i++) { Voxel center = new Voxel(0, 0, 0); ArrayList voxels = new ArrayList<>(Collections.nCopies(i, new Voxel(0, 0, 0))); - PottsCellContainer cellContainer = new PottsCellContainer(0, 0, 0, 0, 0, null, null, i, 0, 0); - PottsLocationContainer locationContainer = new PottsLocationContainer(0, center, voxels, null); - + PottsCellContainer cellContainer = + new PottsCellContainer(0, 0, 0, 0, 0, null, null, i, 0, 0); + PottsLocationContainer locationContainer = + new PottsLocationContainer(0, center, voxels, null); + Location location = locationContainer.convert(FACTORY, cellContainer); assertEquals(i, (int) location.getVolume()); assertTrue(location instanceof PottsLocation); } } - + @Test public void convert_noRegionsWithIncrease_createsObject() { int n = 20; for (int i = 10; i < n; i++) { Voxel center = new Voxel(-1, 0, 0); ArrayList voxels = FACTORY.getPossible(center, n, 1); - PottsCellContainer cellContainer = new PottsCellContainer(0, 0, 0, 0, 0, null, null, i, 0, 0); - PottsLocationContainer locationContainer = new PottsLocationContainer(0, center, voxels, null); - + PottsCellContainer cellContainer = + new PottsCellContainer(0, 0, 0, 0, 0, null, null, i, 0, 0); + PottsLocationContainer locationContainer = + new PottsLocationContainer(0, center, voxels, null); + Location location = locationContainer.convert(FACTORY, cellContainer); assertEquals(i, (int) location.getVolume()); assertTrue(location instanceof PottsLocation); } } - + @Test public void convert_noRegionsWithDecrease_createsObject() { int n = 20; for (int i = 10; i < n; i++) { Voxel center = new Voxel(1, 0, 0); ArrayList voxels = FACTORY.getPossible(center, n, 1); - PottsCellContainer cellContainer = new PottsCellContainer(0, 0, 0, 0, 0, null, null, i, 0, 0); - PottsLocationContainer locationContainer = new PottsLocationContainer(0, center, voxels, null); - + PottsCellContainer cellContainer = + new PottsCellContainer(0, 0, 0, 0, 0, null, null, i, 0, 0); + PottsLocationContainer locationContainer = + new PottsLocationContainer(0, center, voxels, null); + Location location = locationContainer.convert(FACTORY, cellContainer); assertEquals(i, (int) location.getVolume()); assertTrue(location instanceof PottsLocation); } } - + @Test public void convert_withRegions_createsObject() { int n = 20; for (int i = 10; i < n; i++) { Voxel center = new Voxel(0, 0, 0); ArrayList voxels = FACTORY.getPossible(center, n, 1); - + EnumMap> regionVoxelMap = new EnumMap<>(Region.class); regionVoxelMap.put(Region.DEFAULT, voxels); regionVoxelMap.put(Region.NUCLEUS, voxels); - + EnumMap regionTargetMap = new EnumMap<>(Region.class); regionTargetMap.put(Region.DEFAULT, i); regionTargetMap.put(Region.NUCLEUS, n - i); - PottsCellContainer cellContainer = new PottsCellContainer(0, 0, 0, 0, 0, null, null, - n, regionTargetMap, 0, 0, null, null); - PottsLocationContainer locationContainer = new PottsLocationContainer(0, center, voxels, regionVoxelMap); - + PottsCellContainer cellContainer = + new PottsCellContainer( + 0, 0, 0, 0, 0, null, null, n, regionTargetMap, 0, 0, null, null); + PottsLocationContainer locationContainer = + new PottsLocationContainer(0, center, voxels, regionVoxelMap); + Location location = locationContainer.convert(FACTORY, cellContainer); assertEquals(n, (int) location.getVolume()); assertTrue(location instanceof PottsLocations); - assertEquals(n - i, (int) ((PottsLocations) location).locations.get(Region.NUCLEUS).getVolume()); + assertEquals( + n - i, + (int) ((PottsLocations) location).locations.get(Region.NUCLEUS).getVolume()); } } - + @Test public void convert_withRegionsEqual_createsObject() { int n = 20; for (int i = 10; i < n; i++) { Voxel center = new Voxel(0, 0, 0); ArrayList voxels = new ArrayList<>(Collections.nCopies(n, new Voxel(0, 0, 0))); - + EnumMap> regionVoxelMap = new EnumMap<>(Region.class); - regionVoxelMap.put(Region.DEFAULT, new ArrayList<>(Collections.nCopies(i, new Voxel(0, 0, 0)))); - regionVoxelMap.put(Region.NUCLEUS, new ArrayList<>(Collections.nCopies(n - i, new Voxel(0, 0, 0)))); - + regionVoxelMap.put( + Region.DEFAULT, new ArrayList<>(Collections.nCopies(i, new Voxel(0, 0, 0)))); + regionVoxelMap.put( + Region.NUCLEUS, + new ArrayList<>(Collections.nCopies(n - i, new Voxel(0, 0, 0)))); + EnumMap regionTargetMap = new EnumMap<>(Region.class); regionTargetMap.put(Region.DEFAULT, i); regionTargetMap.put(Region.NUCLEUS, n - i); - PottsCellContainer cellContainer = new PottsCellContainer(0, 0, 0, 0, 0, null, null, - n, regionTargetMap, 0, 0, null, null); - PottsLocationContainer locationContainer = new PottsLocationContainer(0, center, voxels, regionVoxelMap); - + PottsCellContainer cellContainer = + new PottsCellContainer( + 0, 0, 0, 0, 0, null, null, n, regionTargetMap, 0, 0, null, null); + PottsLocationContainer locationContainer = + new PottsLocationContainer(0, center, voxels, regionVoxelMap); + Location location = locationContainer.convert(FACTORY, cellContainer); assertEquals(n, (int) location.getVolume()); assertTrue(location instanceof PottsLocations); - assertEquals(n - i, (int) ((PottsLocations) location).locations.get(Region.NUCLEUS).getVolume()); + assertEquals( + n - i, + (int) ((PottsLocations) location).locations.get(Region.NUCLEUS).getVolume()); } } - + @Test public void convert_withRegionsWithIncrease_createsObject() { int n = 20; for (int i = 10; i < n - 1; i++) { Voxel center = new Voxel(-1, 0, 0); ArrayList voxels = FACTORY.getPossible(center, n, 1); - + EnumMap> regionVoxelMap = new EnumMap<>(Region.class); regionVoxelMap.put(Region.DEFAULT, voxels); regionVoxelMap.put(Region.NUCLEUS, voxels); - + EnumMap regionTargetMap = new EnumMap<>(Region.class); regionTargetMap.put(Region.DEFAULT, i); regionTargetMap.put(Region.NUCLEUS, n - i); - - PottsCellContainer cellContainer = new PottsCellContainer(0, 0, 0, 0, 0, null, null, - n, regionTargetMap, 0, 0, null, null); - PottsLocationContainer locationContainer = new PottsLocationContainer(0, center, voxels, regionVoxelMap); - + + PottsCellContainer cellContainer = + new PottsCellContainer( + 0, 0, 0, 0, 0, null, null, n, regionTargetMap, 0, 0, null, null); + PottsLocationContainer locationContainer = + new PottsLocationContainer(0, center, voxels, regionVoxelMap); + Location location = locationContainer.convert(FACTORY, cellContainer); assertEquals(n, (int) location.getVolume()); assertTrue(location instanceof PottsLocations); - assertEquals(n - i, (int) ((PottsLocations) location).locations.get(Region.NUCLEUS).getVolume()); + assertEquals( + n - i, + (int) ((PottsLocations) location).locations.get(Region.NUCLEUS).getVolume()); } } - + @Test public void convert_withRegionsWithDecrease_createsObject() { int n = 20; for (int i = 10; i < n - 1; i++) { Voxel center = new Voxel(1, 0, 0); ArrayList voxels = FACTORY.getPossible(center, n, 1); - + EnumMap> regionVoxelMap = new EnumMap<>(Region.class); regionVoxelMap.put(Region.DEFAULT, voxels); regionVoxelMap.put(Region.NUCLEUS, voxels); - + EnumMap regionTargetMap = new EnumMap<>(Region.class); regionTargetMap.put(Region.DEFAULT, i); regionTargetMap.put(Region.NUCLEUS, n - i); - - PottsCellContainer cellContainer = new PottsCellContainer(0, 0, 0, 0, 0, null, null, - n, regionTargetMap, 0, 0, null, null); - PottsLocationContainer locationContainer = new PottsLocationContainer(0, center, voxels, regionVoxelMap); - + + PottsCellContainer cellContainer = + new PottsCellContainer( + 0, 0, 0, 0, 0, null, null, n, regionTargetMap, 0, 0, null, null); + PottsLocationContainer locationContainer = + new PottsLocationContainer(0, center, voxels, regionVoxelMap); + Location location = locationContainer.convert(FACTORY, cellContainer); assertEquals(n, (int) location.getVolume()); assertTrue(location instanceof PottsLocations); - assertEquals(n - i, (int) ((PottsLocations) location).locations.get(Region.NUCLEUS).getVolume()); + assertEquals( + n - i, + (int) ((PottsLocations) location).locations.get(Region.NUCLEUS).getVolume()); } } - + @Test public void convert_noRegions2D_createsObject() { Voxel center = new Voxel(0, 0, 0); ArrayList voxels = new ArrayList<>(); - PottsCellContainer cellContainer = new PottsCellContainer(0, 0, 0, 0, 0, null, null, 1, 0, 0); - PottsLocationContainer locationContainer = new PottsLocationContainer(0, center, voxels, null); - + PottsCellContainer cellContainer = + new PottsCellContainer(0, 0, 0, 0, 0, null, null, 1, 0, 0); + PottsLocationContainer locationContainer = + new PottsLocationContainer(0, center, voxels, null); + Location location = locationContainer.convert(FACTORY_2D, cellContainer); assertTrue(location instanceof PottsLocation2D); } - + @Test public void convert_withRegions2D_createsObject() { Voxel center = new Voxel(0, 0, 0); ArrayList voxels = new ArrayList<>(); - + EnumMap> regionVoxelMap = new EnumMap<>(Region.class); regionVoxelMap.put(Region.DEFAULT, voxels); regionVoxelMap.put(Region.NUCLEUS, voxels); - + EnumMap regionTargetMap = new EnumMap<>(Region.class); regionTargetMap.put(Region.DEFAULT, 0); regionTargetMap.put(Region.NUCLEUS, 0); - - PottsCellContainer cellContainer = new PottsCellContainer(0, 0, 0, 0, 0, null, null, - 1, regionTargetMap, 0, 0, null, null); - PottsLocationContainer locationContainer = new PottsLocationContainer(0, center, voxels, regionVoxelMap); - + + PottsCellContainer cellContainer = + new PottsCellContainer( + 0, 0, 0, 0, 0, null, null, 1, regionTargetMap, 0, 0, null, null); + PottsLocationContainer locationContainer = + new PottsLocationContainer(0, center, voxels, regionVoxelMap); + Location location = locationContainer.convert(FACTORY_2D, cellContainer); assertTrue(location instanceof PottsLocations2D); } - + @Test public void convert_noRegions3D_createsObject() { Voxel center = new Voxel(0, 0, 0); ArrayList voxels = new ArrayList<>(); - PottsCellContainer cellContainer = new PottsCellContainer(0, 0, 0, 0, 0, null, null, 1, 0, 0); - PottsLocationContainer locationContainer = new PottsLocationContainer(0, center, voxels, null); - + PottsCellContainer cellContainer = + new PottsCellContainer(0, 0, 0, 0, 0, null, null, 1, 0, 0); + PottsLocationContainer locationContainer = + new PottsLocationContainer(0, center, voxels, null); + Location location = locationContainer.convert(FACTORY_3D, cellContainer); assertTrue(location instanceof PottsLocation3D); } - + @Test public void convert_withRegions3D_createsObject() { Voxel center = new Voxel(0, 0, 0); ArrayList voxels = new ArrayList<>(); - + EnumMap> regionVoxelMap = new EnumMap<>(Region.class); regionVoxelMap.put(Region.DEFAULT, voxels); regionVoxelMap.put(Region.NUCLEUS, voxels); - + EnumMap regionTargetMap = new EnumMap<>(Region.class); regionTargetMap.put(Region.DEFAULT, 0); regionTargetMap.put(Region.NUCLEUS, 0); - - PottsCellContainer cellContainer = new PottsCellContainer(0, 0, 0, 0, 0, null, null, - 1, regionTargetMap, 0, 0, null, null); - PottsLocationContainer locationContainer = new PottsLocationContainer(0, center, voxels, regionVoxelMap); - + + PottsCellContainer cellContainer = + new PottsCellContainer( + 0, 0, 0, 0, 0, null, null, 1, regionTargetMap, 0, 0, null, null); + PottsLocationContainer locationContainer = + new PottsLocationContainer(0, center, voxels, regionVoxelMap); + Location location = locationContainer.convert(FACTORY_3D, cellContainer); assertTrue(location instanceof PottsLocations3D); } diff --git a/test/arcade/potts/env/location/PottsLocationFactory2DTest.java b/test/arcade/potts/env/location/PottsLocationFactory2DTest.java index 5fde50dd0..876156bb8 100644 --- a/test/arcade/potts/env/location/PottsLocationFactory2DTest.java +++ b/test/arcade/potts/env/location/PottsLocationFactory2DTest.java @@ -2,35 +2,35 @@ import java.util.ArrayList; import java.util.HashSet; -import org.junit.Test; +import org.junit.jupiter.api.Test; import ec.util.MersenneTwisterFast; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.core.ARCADETestUtilities.*; import static arcade.potts.env.location.Voxel.VOXEL_COMPARATOR; public class PottsLocationFactory2DTest { static final MersenneTwisterFast RANDOM = mock(MersenneTwisterFast.class); - + @Test public void getPossible_givenZero_createsEmpty() { PottsLocationFactory2D factory = new PottsLocationFactory2D(); ArrayList list = factory.getPossible(new Voxel(0, 0, 0), 0, 0); assertEquals(0, list.size()); } - + @Test public void getPossible_givenSize_createsList() { PottsLocationFactory2D factory = new PottsLocationFactory2D(); - + int x = randomIntBetween(0, 10); int y = randomIntBetween(0, 10); int z = randomIntBetween(0, 10); int s = randomIntBetween(0, 10) * 2 + 1; - + ArrayList list = factory.getPossible(new Voxel(x, y, z), s, 0); assertEquals(s * s, list.size()); - + for (Voxel voxel : list) { assertTrue(voxel.x < x + (s - 1) / 2 + 1); assertTrue(voxel.x > x - (s - 1) / 2 - 1); @@ -39,32 +39,32 @@ public void getPossible_givenSize_createsList() { assertEquals(0, voxel.z); } } - + @Test public void getCenters_threeSideExactEqualSizeNoMargin_createsCenters() { PottsLocationFactory2D factory = new PottsLocationFactory2D(); ArrayList centers = factory.getCenters(8, 8, 1, 0, 3, 0); - + ArrayList expected = new ArrayList<>(); expected.add(new Voxel(2, 2, 0)); expected.add(new Voxel(2, 5, 0)); expected.add(new Voxel(5, 2, 0)); expected.add(new Voxel(5, 5, 0)); - + centers.sort(VOXEL_COMPARATOR); expected.sort(VOXEL_COMPARATOR); - + assertEquals(expected.size(), centers.size()); for (int i = 0; i < expected.size(); i++) { assertEquals(expected.get(i), centers.get(i)); } } - + @Test public void getCenters_threeSideExactUnequalSizeNoMargin_createsCenters() { PottsLocationFactory2D factory = new PottsLocationFactory2D(); ArrayList centers = factory.getCenters(11, 8, 1, 0, 3, 0); - + ArrayList expected = new ArrayList<>(); expected.add(new Voxel(2, 2, 0)); expected.add(new Voxel(2, 5, 0)); @@ -72,112 +72,112 @@ public void getCenters_threeSideExactUnequalSizeNoMargin_createsCenters() { expected.add(new Voxel(5, 5, 0)); expected.add(new Voxel(8, 2, 0)); expected.add(new Voxel(8, 5, 0)); - + centers.sort(VOXEL_COMPARATOR); expected.sort(VOXEL_COMPARATOR); - + assertEquals(expected.size(), centers.size()); for (int i = 0; i < expected.size(); i++) { assertEquals(expected.get(i), centers.get(i)); } } - + @Test public void getCenters_threeSideInexactEqualSizeNoMargin_createsCenters() { PottsLocationFactory2D factory = new PottsLocationFactory2D(); ArrayList centers = factory.getCenters(7, 7, 1, 0, 3, 0); - + ArrayList expected = new ArrayList<>(); expected.add(new Voxel(2, 2, 0)); - + centers.sort(VOXEL_COMPARATOR); expected.sort(VOXEL_COMPARATOR); - + assertEquals(expected.size(), centers.size()); for (int i = 0; i < expected.size(); i++) { assertEquals(expected.get(i), centers.get(i)); } } - + @Test public void getCenters_threeSideInexactUnequalSizeNoMargin_createsCenters() { PottsLocationFactory2D factory = new PottsLocationFactory2D(); ArrayList centers = factory.getCenters(10, 7, 1, 0, 3, 0); - + ArrayList expected = new ArrayList<>(); expected.add(new Voxel(2, 2, 0)); expected.add(new Voxel(5, 2, 0)); - + centers.sort(VOXEL_COMPARATOR); expected.sort(VOXEL_COMPARATOR); - + assertEquals(expected.size(), centers.size()); for (int i = 0; i < expected.size(); i++) { assertEquals(expected.get(i), centers.get(i)); } } - + @Test public void getCenters_threeSideExactWithMargin_createsCenters() { PottsLocationFactory2D factory = new PottsLocationFactory2D(); ArrayList centers = factory.getCenters(14, 11, 1, 3, 3, 0); - + ArrayList expected = new ArrayList<>(); expected.add(new Voxel(5, 5, 0)); expected.add(new Voxel(8, 5, 0)); - + centers.sort(VOXEL_COMPARATOR); expected.sort(VOXEL_COMPARATOR); - + assertEquals(expected.size(), centers.size()); for (int i = 0; i < expected.size(); i++) { assertEquals(expected.get(i), centers.get(i)); } } - + @Test public void getCenters_threeSideInexactWithMargin_createsCenters() { PottsLocationFactory2D factory = new PottsLocationFactory2D(); ArrayList centers = factory.getCenters(13, 10, 1, 2, 3, 0); - + ArrayList expected = new ArrayList<>(); expected.add(new Voxel(4, 4, 0)); expected.add(new Voxel(7, 4, 0)); - + centers.sort(VOXEL_COMPARATOR); expected.sort(VOXEL_COMPARATOR); - + assertEquals(expected.size(), centers.size()); for (int i = 0; i < expected.size(); i++) { assertEquals(expected.get(i), centers.get(i)); } } - + @Test public void getCenters_fiveSideExactEqualSizeNoMargin_createsCenters() { PottsLocationFactory2D factory = new PottsLocationFactory2D(); ArrayList centers = factory.getCenters(12, 12, 1, 0, 5, 0); - + ArrayList expected = new ArrayList<>(); expected.add(new Voxel(3, 3, 0)); expected.add(new Voxel(3, 8, 0)); expected.add(new Voxel(8, 3, 0)); expected.add(new Voxel(8, 8, 0)); - + centers.sort(VOXEL_COMPARATOR); expected.sort(VOXEL_COMPARATOR); - + assertEquals(expected.size(), centers.size()); for (int i = 0; i < expected.size(); i++) { assertEquals(expected.get(i), centers.get(i)); } } - + @Test public void getCenters_fiveSideExactUnequalSizeNoMargin_createsCenters() { PottsLocationFactory2D factory = new PottsLocationFactory2D(); ArrayList centers = factory.getCenters(17, 12, 1, 0, 5, 0); - + ArrayList expected = new ArrayList<>(); expected.add(new Voxel(3, 3, 0)); expected.add(new Voxel(3, 8, 0)); @@ -185,74 +185,74 @@ public void getCenters_fiveSideExactUnequalSizeNoMargin_createsCenters() { expected.add(new Voxel(8, 8, 0)); expected.add(new Voxel(13, 3, 0)); expected.add(new Voxel(13, 8, 0)); - + centers.sort(VOXEL_COMPARATOR); expected.sort(VOXEL_COMPARATOR); - + assertEquals(expected.size(), centers.size()); for (int i = 0; i < expected.size(); i++) { assertEquals(expected.get(i), centers.get(i)); } } - + @Test public void getCenters_fiveSideInexactEqualSizeNoMargin_createsCenters() { PottsLocationFactory2D factory = new PottsLocationFactory2D(); ArrayList centers = factory.getCenters(11, 11, 1, 0, 5, 0); - + ArrayList expected = new ArrayList<>(); expected.add(new Voxel(3, 3, 0)); - + centers.sort(VOXEL_COMPARATOR); expected.sort(VOXEL_COMPARATOR); - + assertEquals(expected.size(), centers.size()); for (int i = 0; i < expected.size(); i++) { assertEquals(expected.get(i), centers.get(i)); } } - + @Test public void getCenters_fiveSideInexactUnequalSizeNoMargin_createsCenters() { PottsLocationFactory2D factory = new PottsLocationFactory2D(); ArrayList centers = factory.getCenters(16, 11, 1, 0, 5, 0); - + ArrayList expected = new ArrayList<>(); expected.add(new Voxel(3, 3, 0)); expected.add(new Voxel(8, 3, 0)); - + centers.sort(VOXEL_COMPARATOR); expected.sort(VOXEL_COMPARATOR); - + assertEquals(expected.size(), centers.size()); for (int i = 0; i < expected.size(); i++) { assertEquals(expected.get(i), centers.get(i)); } } - + @Test public void getCenters_fiveSideExactWithMargin_createsCenters() { PottsLocationFactory2D factory = new PottsLocationFactory2D(); ArrayList centers = factory.getCenters(22, 17, 1, 5, 5, 0); - + ArrayList expected = new ArrayList<>(); expected.add(new Voxel(8, 8, 0)); expected.add(new Voxel(13, 8, 0)); - + centers.sort(VOXEL_COMPARATOR); expected.sort(VOXEL_COMPARATOR); - + assertEquals(expected.size(), centers.size()); for (int i = 0; i < expected.size(); i++) { assertEquals(expected.get(i), centers.get(i)); } } - + @Test public void getCenters_fiveSideInexactWithMargin_createsCenters() { PottsLocationFactory2D factory = new PottsLocationFactory2D(); ArrayList centers = factory.getCenters(23, 19, 1, 2, 5, 0); - + ArrayList expected = new ArrayList<>(); expected.add(new Voxel(5, 5, 0)); expected.add(new Voxel(10, 5, 0)); @@ -260,141 +260,141 @@ public void getCenters_fiveSideInexactWithMargin_createsCenters() { expected.add(new Voxel(5, 10, 0)); expected.add(new Voxel(10, 10, 0)); expected.add(new Voxel(15, 10, 0)); - + centers.sort(VOXEL_COMPARATOR); expected.sort(VOXEL_COMPARATOR); - + assertEquals(expected.size(), centers.size()); for (int i = 0; i < expected.size(); i++) { assertEquals(expected.get(i), centers.get(i)); } } - + @Test public void increase_exactTarget_updatesList() { ArrayList allVoxels = new ArrayList<>(); ArrayList voxels = new ArrayList<>(); - + int n = 10; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { allVoxels.add(new Voxel(i - n / 2, j - n / 2, 0)); } } - + voxels.add(new Voxel(0, 0, 0)); PottsLocationFactory2D.increase(allVoxels, voxels, 5, RANDOM); - + ArrayList expected = new ArrayList<>(); expected.add(new Voxel(0, 0, 0)); expected.add(new Voxel(1, 0, 0)); expected.add(new Voxel(-1, 0, 0)); expected.add(new Voxel(0, -1, 0)); expected.add(new Voxel(0, 1, 0)); - + voxels.sort(VOXEL_COMPARATOR); expected.sort(VOXEL_COMPARATOR); - + assertEquals(expected, voxels); } - + @Test public void increase_inexactTarget_updatesList() { ArrayList allVoxels = new ArrayList<>(); ArrayList voxels = new ArrayList<>(); - + int n = 10; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { allVoxels.add(new Voxel(i - n / 2, j - n / 2, 0)); } } - + voxels.add(new Voxel(0, 0, 0)); PottsLocationFactory2D.increase(allVoxels, voxels, 4, RANDOM); - + HashSet expected = new HashSet<>(); expected.add(new Voxel(0, 0, 0)); expected.add(new Voxel(1, 0, 0)); expected.add(new Voxel(-1, 0, 0)); expected.add(new Voxel(0, -1, 0)); expected.add(new Voxel(0, 1, 0)); - + assertEquals(4, voxels.size()); assertTrue(expected.containsAll(voxels)); } - + @Test public void increase_invalidTarget_addsValid() { ArrayList allVoxels = new ArrayList<>(); ArrayList voxels = new ArrayList<>(); - + int n = 10; for (int i = 0; i < n; i++) { allVoxels.add(new Voxel(i - n / 2, 0, 0)); } - + voxels.add(new Voxel(0, 0, 0)); PottsLocationFactory2D.increase(allVoxels, voxels, 5, RANDOM); - + ArrayList expected = new ArrayList<>(); expected.add(new Voxel(0, 0, 0)); expected.add(new Voxel(1, 0, 0)); expected.add(new Voxel(-1, 0, 0)); - + voxels.sort(VOXEL_COMPARATOR); expected.sort(VOXEL_COMPARATOR); - + assertEquals(expected, voxels); } - + @Test public void decrease_exactTarget_updatesList() { ArrayList voxels = new ArrayList<>(); - + voxels.add(new Voxel(0, 0, 0)); voxels.add(new Voxel(1, 0, 0)); voxels.add(new Voxel(-1, 0, 0)); voxels.add(new Voxel(0, -1, 0)); voxels.add(new Voxel(0, 1, 0)); PottsLocationFactory2D.decrease(voxels, 1, RANDOM); - + ArrayList expected = new ArrayList<>(); expected.add(new Voxel(0, 0, 0)); - + voxels.sort(VOXEL_COMPARATOR); expected.sort(VOXEL_COMPARATOR); - + assertEquals(expected, voxels); } - + @Test public void decrease_inexactTarget_updatesList() { ArrayList voxels = new ArrayList<>(); - + voxels.add(new Voxel(0, 0, 0)); voxels.add(new Voxel(1, 0, 0)); voxels.add(new Voxel(-1, 0, 0)); voxels.add(new Voxel(0, -1, 0)); voxels.add(new Voxel(0, 1, 0)); PottsLocationFactory2D.decrease(voxels, 3, RANDOM); - + HashSet expected = new HashSet<>(); expected.add(new Voxel(0, 0, 0)); expected.add(new Voxel(1, 0, 0)); expected.add(new Voxel(-1, 0, 0)); expected.add(new Voxel(0, -1, 0)); expected.add(new Voxel(0, 1, 0)); - + assertEquals(3, voxels.size()); assertTrue(expected.contains(new Voxel(0, 0, 0))); assertTrue(expected.containsAll(voxels)); } - + @Test public void decrease_unconnectedTarget_updatesList() { ArrayList voxels = new ArrayList<>(); - + voxels.add(new Voxel(0, 0, 0)); voxels.add(new Voxel(1, 0, 0)); voxels.add(new Voxel(-1, 0, 0)); @@ -404,52 +404,55 @@ public void decrease_unconnectedTarget_updatesList() { voxels.add(new Voxel(-1, -1, 0)); voxels.add(new Voxel(1, -1, 0)); voxels.add(new Voxel(-1, 1, 0)); - + PottsLocationFactory2D.decrease(voxels, 7, RANDOM); - - int[][] corners = new int[][] { - { -1, -1 }, - { 1, -1 }, - { 1, 1 }, - { -1, 1 }, - }; - - int[][] sides = new int[][] { - { 0, -1 }, - { 1, 0 }, - { 0, 1 }, - { -1, 0 }, - }; - + + int[][] corners = + new int[][] { + {-1, -1}, + {1, -1}, + {1, 1}, + {-1, 1}, + }; + + int[][] sides = + new int[][] { + {0, -1}, + {1, 0}, + {0, 1}, + {-1, 0}, + }; + for (int i = 0; i < corners.length; i++) { if (voxels.contains(new Voxel(corners[i][0], corners[i][1], 0))) { boolean checkA = voxels.contains(new Voxel(sides[i][0], sides[i][1], 0)); - boolean checkB = voxels.contains(new Voxel(sides[(i + 1) % 4][0], sides[(i + 1) % 4][1], 0)); + boolean checkB = + voxels.contains(new Voxel(sides[(i + 1) % 4][0], sides[(i + 1) % 4][1], 0)); assertTrue(checkA || checkB); } } } - + @Test public void decrease_invalidTarget_updatesList() { ArrayList voxels = new ArrayList<>(); - + voxels.add(new Voxel(0, 0, 0)); voxels.add(new Voxel(1, 0, 0)); voxels.add(new Voxel(2, 0, 0)); voxels.add(new Voxel(3, 0, 0)); voxels.add(new Voxel(4, 0, 0)); PottsLocationFactory2D.decrease(voxels, 2, RANDOM); - + ArrayList expected = new ArrayList<>(); expected.add(new Voxel(0, 0, 0)); expected.add(new Voxel(1, 0, 0)); expected.add(new Voxel(3, 0, 0)); expected.add(new Voxel(4, 0, 0)); - + voxels.sort(VOXEL_COMPARATOR); expected.sort(VOXEL_COMPARATOR); - + assertEquals(expected, voxels); } } diff --git a/test/arcade/potts/env/location/PottsLocationFactory3DTest.java b/test/arcade/potts/env/location/PottsLocationFactory3DTest.java index 744c03166..8416b4406 100644 --- a/test/arcade/potts/env/location/PottsLocationFactory3DTest.java +++ b/test/arcade/potts/env/location/PottsLocationFactory3DTest.java @@ -2,36 +2,36 @@ import java.util.ArrayList; import java.util.HashSet; -import org.junit.Test; +import org.junit.jupiter.api.Test; import ec.util.MersenneTwisterFast; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.core.ARCADETestUtilities.*; import static arcade.potts.env.location.Voxel.VOXEL_COMPARATOR; public class PottsLocationFactory3DTest { static final MersenneTwisterFast RANDOM = mock(MersenneTwisterFast.class); - + @Test public void getPossible_givenZero_createsEmpty() { PottsLocationFactory3D factory = new PottsLocationFactory3D(); ArrayList list = factory.getPossible(new Voxel(0, 0, 0), 0, 0); assertEquals(0, list.size()); } - + @Test public void getPossible_givenSize_createsList() { PottsLocationFactory3D factory = new PottsLocationFactory3D(); - + int x = randomIntBetween(0, 10); int y = randomIntBetween(0, 10); int z = randomIntBetween(0, 10); int s = randomIntBetween(0, 10) * 2 + 1; int h = randomIntBetween(0, 10) * 2 + 1; - + ArrayList list = factory.getPossible(new Voxel(x, y, z), s, h); assertEquals(s * s * h, list.size()); - + for (Voxel voxel : list) { assertTrue(voxel.x < x + (s - 1) / 2 + 1); assertTrue(voxel.x > x - (s - 1) / 2 - 1); @@ -41,12 +41,12 @@ public void getPossible_givenSize_createsList() { assertTrue(voxel.z > z - (h - 1) / 2 - 1); } } - + @Test public void getCenters_threeSideExactEqualSizeNoMargin_createsCenters() { PottsLocationFactory3D factory = new PottsLocationFactory3D(); ArrayList centers = factory.getCenters(8, 8, 8, 0, 3, 3); - + ArrayList expected = new ArrayList<>(); expected.add(new Voxel(2, 2, 2)); expected.add(new Voxel(2, 5, 2)); @@ -56,21 +56,21 @@ public void getCenters_threeSideExactEqualSizeNoMargin_createsCenters() { expected.add(new Voxel(2, 5, 5)); expected.add(new Voxel(5, 2, 5)); expected.add(new Voxel(5, 5, 5)); - + centers.sort(VOXEL_COMPARATOR); expected.sort(VOXEL_COMPARATOR); - + assertEquals(expected.size(), centers.size()); for (int i = 0; i < expected.size(); i++) { assertEquals(expected.get(i), centers.get(i)); } } - + @Test public void getCenters_threeSideExactUnequalSizeNoMargin_createsCenters() { PottsLocationFactory3D factory = new PottsLocationFactory3D(); ArrayList centers = factory.getCenters(11, 8, 5, 0, 3, 3); - + ArrayList expected = new ArrayList<>(); expected.add(new Voxel(2, 2, 2)); expected.add(new Voxel(2, 5, 2)); @@ -78,38 +78,38 @@ public void getCenters_threeSideExactUnequalSizeNoMargin_createsCenters() { expected.add(new Voxel(5, 5, 2)); expected.add(new Voxel(8, 2, 2)); expected.add(new Voxel(8, 5, 2)); - + centers.sort(VOXEL_COMPARATOR); expected.sort(VOXEL_COMPARATOR); - + assertEquals(expected.size(), centers.size()); for (int i = 0; i < expected.size(); i++) { assertEquals(expected.get(i), centers.get(i)); } } - + @Test public void getCenters_threeSideInexactEqualSizeNoMargin_createsCenters() { PottsLocationFactory3D factory = new PottsLocationFactory3D(); ArrayList centers = factory.getCenters(7, 7, 7, 0, 3, 3); - + ArrayList expected = new ArrayList<>(); expected.add(new Voxel(2, 2, 2)); - + centers.sort(VOXEL_COMPARATOR); expected.sort(VOXEL_COMPARATOR); - + assertEquals(expected.size(), centers.size()); for (int i = 0; i < expected.size(); i++) { assertEquals(expected.get(i), centers.get(i)); } } - + @Test public void getCenters_threeSideInexactUnequalSizeNoMargin_createsCenters() { PottsLocationFactory3D factory = new PottsLocationFactory3D(); ArrayList centers = factory.getCenters(10, 7, 13, 0, 3, 3); - + ArrayList expected = new ArrayList<>(); expected.add(new Voxel(2, 2, 2)); expected.add(new Voxel(5, 2, 2)); @@ -117,61 +117,61 @@ public void getCenters_threeSideInexactUnequalSizeNoMargin_createsCenters() { expected.add(new Voxel(5, 2, 5)); expected.add(new Voxel(2, 2, 8)); expected.add(new Voxel(5, 2, 8)); - + centers.sort(VOXEL_COMPARATOR); expected.sort(VOXEL_COMPARATOR); - + assertEquals(expected.size(), centers.size()); for (int i = 0; i < expected.size(); i++) { assertEquals(expected.get(i), centers.get(i)); } } - + @Test public void getCenters_threeSideExactWithMargin_createsCenters() { PottsLocationFactory3D factory = new PottsLocationFactory3D(); ArrayList centers = factory.getCenters(14, 11, 8, 3, 3, 3); - + ArrayList expected = new ArrayList<>(); expected.add(new Voxel(5, 5, 2)); expected.add(new Voxel(8, 5, 2)); expected.add(new Voxel(5, 5, 5)); expected.add(new Voxel(8, 5, 5)); - + centers.sort(VOXEL_COMPARATOR); expected.sort(VOXEL_COMPARATOR); - + assertEquals(expected.size(), centers.size()); for (int i = 0; i < expected.size(); i++) { assertEquals(expected.get(i), centers.get(i)); } } - + @Test public void getCenters_threeSideInexactWithMargin_createsCenters() { PottsLocationFactory3D factory = new PottsLocationFactory3D(); ArrayList centers = factory.getCenters(13, 10, 8, 2, 3, 3); - + ArrayList expected = new ArrayList<>(); expected.add(new Voxel(4, 4, 2)); expected.add(new Voxel(7, 4, 2)); expected.add(new Voxel(4, 4, 5)); expected.add(new Voxel(7, 4, 5)); - + centers.sort(VOXEL_COMPARATOR); expected.sort(VOXEL_COMPARATOR); - + assertEquals(expected.size(), centers.size()); for (int i = 0; i < expected.size(); i++) { assertEquals(expected.get(i), centers.get(i)); } } - + @Test public void getCenters_fiveSideExactEqualSizeNoMargin_createsCenters() { PottsLocationFactory3D factory = new PottsLocationFactory3D(); ArrayList centers = factory.getCenters(12, 12, 12, 0, 5, 5); - + ArrayList expected = new ArrayList<>(); expected.add(new Voxel(3, 3, 3)); expected.add(new Voxel(3, 8, 3)); @@ -181,21 +181,21 @@ public void getCenters_fiveSideExactEqualSizeNoMargin_createsCenters() { expected.add(new Voxel(3, 8, 8)); expected.add(new Voxel(8, 3, 8)); expected.add(new Voxel(8, 8, 8)); - + centers.sort(VOXEL_COMPARATOR); expected.sort(VOXEL_COMPARATOR); - + assertEquals(expected.size(), centers.size()); for (int i = 0; i < expected.size(); i++) { assertEquals(expected.get(i), centers.get(i)); } } - + @Test public void getCenters_fiveSideExactUnequalSizeNoMargin_createsCenters() { PottsLocationFactory3D factory = new PottsLocationFactory3D(); ArrayList centers = factory.getCenters(17, 12, 7, 0, 5, 5); - + ArrayList expected = new ArrayList<>(); expected.add(new Voxel(3, 3, 3)); expected.add(new Voxel(3, 8, 3)); @@ -203,76 +203,76 @@ public void getCenters_fiveSideExactUnequalSizeNoMargin_createsCenters() { expected.add(new Voxel(8, 8, 3)); expected.add(new Voxel(13, 3, 3)); expected.add(new Voxel(13, 8, 3)); - + centers.sort(VOXEL_COMPARATOR); expected.sort(VOXEL_COMPARATOR); - + assertEquals(expected.size(), centers.size()); for (int i = 0; i < expected.size(); i++) { assertEquals(expected.get(i), centers.get(i)); } } - + @Test public void getCenters_fiveSideInexactEqualSizeNoMargin_createsCenters() { PottsLocationFactory3D factory = new PottsLocationFactory3D(); ArrayList centers = factory.getCenters(11, 11, 11, 0, 5, 5); - + ArrayList expected = new ArrayList<>(); expected.add(new Voxel(3, 3, 3)); - + centers.sort(VOXEL_COMPARATOR); expected.sort(VOXEL_COMPARATOR); - + assertEquals(expected.size(), centers.size()); for (int i = 0; i < expected.size(); i++) { assertEquals(expected.get(i), centers.get(i)); } } - + @Test public void getCenters_fiveSideInexactUnequalSizeNoMargin_createsCenters() { PottsLocationFactory3D factory = new PottsLocationFactory3D(); ArrayList centers = factory.getCenters(16, 11, 9, 0, 5, 5); - + ArrayList expected = new ArrayList<>(); expected.add(new Voxel(3, 3, 3)); expected.add(new Voxel(8, 3, 3)); - + centers.sort(VOXEL_COMPARATOR); expected.sort(VOXEL_COMPARATOR); - + assertEquals(expected.size(), centers.size()); for (int i = 0; i < expected.size(); i++) { assertEquals(expected.get(i), centers.get(i)); } } - + @Test public void getCenters_fiveSideExactWithMargin_createsCenters() { PottsLocationFactory3D factory = new PottsLocationFactory3D(); ArrayList centers = factory.getCenters(22, 17, 12, 5, 5, 5); - + ArrayList expected = new ArrayList<>(); expected.add(new Voxel(8, 8, 3)); expected.add(new Voxel(13, 8, 3)); expected.add(new Voxel(8, 8, 8)); expected.add(new Voxel(13, 8, 8)); - + centers.sort(VOXEL_COMPARATOR); expected.sort(VOXEL_COMPARATOR); - + assertEquals(expected.size(), centers.size()); for (int i = 0; i < expected.size(); i++) { assertEquals(expected.get(i), centers.get(i)); } } - + @Test public void getCenters_fiveSideInexactWithMargin_createsCenters() { PottsLocationFactory3D factory = new PottsLocationFactory3D(); ArrayList centers = factory.getCenters(23, 19, 12, 2, 5, 5); - + ArrayList expected = new ArrayList<>(); expected.add(new Voxel(5, 5, 3)); expected.add(new Voxel(10, 5, 3)); @@ -286,41 +286,41 @@ public void getCenters_fiveSideInexactWithMargin_createsCenters() { expected.add(new Voxel(5, 10, 8)); expected.add(new Voxel(10, 10, 8)); expected.add(new Voxel(15, 10, 8)); - + centers.sort(VOXEL_COMPARATOR); expected.sort(VOXEL_COMPARATOR); - + assertEquals(expected.size(), centers.size()); for (int i = 0; i < expected.size(); i++) { assertEquals(expected.get(i), centers.get(i)); } } - + @Test public void getCenters_threeHeightAllLayersNoMargin_createsCenters() { PottsLocationFactory3D factory = new PottsLocationFactory3D(); ArrayList centers = factory.getCenters(8, 8, 3, 0, 3, 1); - + ArrayList expected = new ArrayList<>(); expected.add(new Voxel(2, 2, 1)); expected.add(new Voxel(2, 5, 1)); expected.add(new Voxel(5, 2, 1)); expected.add(new Voxel(5, 5, 1)); - + centers.sort(VOXEL_COMPARATOR); expected.sort(VOXEL_COMPARATOR); - + assertEquals(expected.size(), centers.size()); for (int i = 0; i < expected.size(); i++) { assertEquals(expected.get(i), centers.get(i)); } } - + @Test public void getCenters_fiveHeightAllLayersNoMargin_createsCenters() { PottsLocationFactory3D factory = new PottsLocationFactory3D(); ArrayList centers = factory.getCenters(8, 8, 5, 0, 3, 1); - + ArrayList expected = new ArrayList<>(); expected.add(new Voxel(2, 2, 1)); expected.add(new Voxel(2, 5, 1)); @@ -334,61 +334,61 @@ public void getCenters_fiveHeightAllLayersNoMargin_createsCenters() { expected.add(new Voxel(2, 5, 3)); expected.add(new Voxel(5, 2, 3)); expected.add(new Voxel(5, 5, 3)); - + centers.sort(VOXEL_COMPARATOR); expected.sort(VOXEL_COMPARATOR); - + assertEquals(expected.size(), centers.size()); for (int i = 0; i < expected.size(); i++) { assertEquals(expected.get(i), centers.get(i)); } } - + @Test public void getCenters_fiveHeightUnfilledLayersNoMargin_createsCenters() { PottsLocationFactory3D factory = new PottsLocationFactory3D(); ArrayList centers = factory.getCenters(8, 8, 5, 0, 3, 2); - + ArrayList expected = new ArrayList<>(); expected.add(new Voxel(2, 2, 1)); expected.add(new Voxel(2, 5, 1)); expected.add(new Voxel(5, 2, 1)); expected.add(new Voxel(5, 5, 1)); - + centers.sort(VOXEL_COMPARATOR); expected.sort(VOXEL_COMPARATOR); - + assertEquals(expected.size(), centers.size()); for (int i = 0; i < expected.size(); i++) { assertEquals(expected.get(i), centers.get(i)); } } - + @Test public void getCenters_fiveHeightFilledLayersNoMargin_createsCenters() { PottsLocationFactory3D factory = new PottsLocationFactory3D(); ArrayList centers = factory.getCenters(8, 8, 5, 0, 3, 3); - + ArrayList expected = new ArrayList<>(); expected.add(new Voxel(2, 2, 2)); expected.add(new Voxel(2, 5, 2)); expected.add(new Voxel(5, 2, 2)); expected.add(new Voxel(5, 5, 2)); - + centers.sort(VOXEL_COMPARATOR); expected.sort(VOXEL_COMPARATOR); - + assertEquals(expected.size(), centers.size()); for (int i = 0; i < expected.size(); i++) { assertEquals(expected.get(i), centers.get(i)); } } - + @Test public void getCenters_sevenHeightAllLayersNoMargin_createsCenters() { PottsLocationFactory3D factory = new PottsLocationFactory3D(); ArrayList centers = factory.getCenters(8, 8, 7, 0, 3, 1); - + ArrayList expected = new ArrayList<>(); for (int i = 1; i < 6; i++) { expected.add(new Voxel(2, 2, i)); @@ -396,21 +396,21 @@ public void getCenters_sevenHeightAllLayersNoMargin_createsCenters() { expected.add(new Voxel(5, 2, i)); expected.add(new Voxel(5, 5, i)); } - + centers.sort(VOXEL_COMPARATOR); expected.sort(VOXEL_COMPARATOR); - + assertEquals(expected.size(), centers.size()); for (int i = 0; i < expected.size(); i++) { assertEquals(expected.get(i), centers.get(i)); } } - + @Test public void getCenters_sevenHeightUnfilledLayersNoMargin_createsCenters() { PottsLocationFactory3D factory = new PottsLocationFactory3D(); ArrayList centers = factory.getCenters(8, 8, 7, 0, 3, 2); - + ArrayList expected = new ArrayList<>(); expected.add(new Voxel(2, 2, 1)); expected.add(new Voxel(2, 5, 1)); @@ -420,41 +420,41 @@ public void getCenters_sevenHeightUnfilledLayersNoMargin_createsCenters() { expected.add(new Voxel(2, 5, 3)); expected.add(new Voxel(5, 2, 3)); expected.add(new Voxel(5, 5, 3)); - + centers.sort(VOXEL_COMPARATOR); expected.sort(VOXEL_COMPARATOR); - + assertEquals(expected.size(), centers.size()); for (int i = 0; i < expected.size(); i++) { assertEquals(expected.get(i), centers.get(i)); } } - + @Test public void getCenters_sevenHeightFilledLayersNoMargin_createsCenters() { PottsLocationFactory3D factory = new PottsLocationFactory3D(); ArrayList centers = factory.getCenters(8, 8, 7, 0, 3, 5); - + ArrayList expected = new ArrayList<>(); expected.add(new Voxel(2, 2, 3)); expected.add(new Voxel(2, 5, 3)); expected.add(new Voxel(5, 2, 3)); expected.add(new Voxel(5, 5, 3)); - + centers.sort(VOXEL_COMPARATOR); expected.sort(VOXEL_COMPARATOR); - + assertEquals(expected.size(), centers.size()); for (int i = 0; i < expected.size(); i++) { assertEquals(expected.get(i), centers.get(i)); } } - + @Test public void increase_exactTarget_updatesList() { ArrayList allVoxels = new ArrayList<>(); ArrayList voxels = new ArrayList<>(); - + int n = 10; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { @@ -463,10 +463,10 @@ public void increase_exactTarget_updatesList() { } } } - + voxels.add(new Voxel(0, 0, 0)); PottsLocationFactory3D.increase(allVoxels, voxels, 7, RANDOM); - + ArrayList expected = new ArrayList<>(); expected.add(new Voxel(0, 0, 0)); expected.add(new Voxel(1, 0, 0)); @@ -475,18 +475,18 @@ public void increase_exactTarget_updatesList() { expected.add(new Voxel(0, 1, 0)); expected.add(new Voxel(0, 0, 1)); expected.add(new Voxel(0, 0, -1)); - + voxels.sort(VOXEL_COMPARATOR); expected.sort(VOXEL_COMPARATOR); - + assertEquals(expected, voxels); } - + @Test public void increase_inexactTarget_updatesList() { ArrayList allVoxels = new ArrayList<>(); ArrayList voxels = new ArrayList<>(); - + int n = 10; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { @@ -495,10 +495,10 @@ public void increase_inexactTarget_updatesList() { } } } - + voxels.add(new Voxel(0, 0, 0)); PottsLocationFactory3D.increase(allVoxels, voxels, 6, RANDOM); - + HashSet expected = new HashSet<>(); expected.add(new Voxel(0, 0, 0)); expected.add(new Voxel(1, 0, 0)); @@ -507,43 +507,43 @@ public void increase_inexactTarget_updatesList() { expected.add(new Voxel(0, 1, 0)); expected.add(new Voxel(0, 0, 1)); expected.add(new Voxel(0, 0, -1)); - + assertEquals(6, voxels.size()); assertTrue(expected.containsAll(voxels)); } - + @Test public void increase_invalidTarget_addsValid() { ArrayList allVoxels = new ArrayList<>(); ArrayList voxels = new ArrayList<>(); - + int n = 10; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { allVoxels.add(new Voxel(i - n / 2, j - n / 2, 0)); } } - + voxels.add(new Voxel(0, 0, 0)); PottsLocationFactory3D.increase(allVoxels, voxels, 7, RANDOM); - + ArrayList expected = new ArrayList<>(); expected.add(new Voxel(0, 0, 0)); expected.add(new Voxel(1, 0, 0)); expected.add(new Voxel(-1, 0, 0)); expected.add(new Voxel(0, -1, 0)); expected.add(new Voxel(0, 1, 0)); - + voxels.sort(VOXEL_COMPARATOR); expected.sort(VOXEL_COMPARATOR); - + assertEquals(expected, voxels); } - + @Test public void decrease_exactTarget_updatesList() { ArrayList voxels = new ArrayList<>(); - + voxels.add(new Voxel(0, 0, 0)); voxels.add(new Voxel(1, 0, 0)); voxels.add(new Voxel(-1, 0, 0)); @@ -552,20 +552,20 @@ public void decrease_exactTarget_updatesList() { voxels.add(new Voxel(0, 0, 1)); voxels.add(new Voxel(0, 0, -1)); PottsLocationFactory3D.decrease(voxels, 1, RANDOM); - + ArrayList expected = new ArrayList<>(); expected.add(new Voxel(0, 0, 0)); - + voxels.sort(VOXEL_COMPARATOR); expected.sort(VOXEL_COMPARATOR); - + assertEquals(expected, voxels); } - + @Test public void decrease_inexactTarget_updatesList() { ArrayList voxels = new ArrayList<>(); - + voxels.add(new Voxel(0, 0, 0)); voxels.add(new Voxel(1, 0, 0)); voxels.add(new Voxel(-1, 0, 0)); @@ -574,7 +574,7 @@ public void decrease_inexactTarget_updatesList() { voxels.add(new Voxel(0, 0, 1)); voxels.add(new Voxel(0, 0, -1)); PottsLocationFactory3D.decrease(voxels, 4, RANDOM); - + HashSet expected = new HashSet<>(); expected.add(new Voxel(0, 0, 0)); expected.add(new Voxel(1, 0, 0)); @@ -583,16 +583,16 @@ public void decrease_inexactTarget_updatesList() { expected.add(new Voxel(0, 1, 0)); expected.add(new Voxel(0, 0, 1)); expected.add(new Voxel(0, 0, -1)); - + assertEquals(4, voxels.size()); assertTrue(expected.contains(new Voxel(0, 0, 0))); assertTrue(expected.containsAll(voxels)); } - + @Test public void decrease_unconnectedTarget_updatesList() { ArrayList voxels = new ArrayList<>(); - + voxels.add(new Voxel(0, 0, 0)); voxels.add(new Voxel(1, 0, 0)); voxels.add(new Voxel(-1, 0, 0)); @@ -602,48 +602,51 @@ public void decrease_unconnectedTarget_updatesList() { voxels.add(new Voxel(-1, -1, 0)); voxels.add(new Voxel(1, -1, 0)); voxels.add(new Voxel(-1, 1, 0)); - + voxels.add(new Voxel(0, 0, -1)); voxels.add(new Voxel(1, 0, -1)); voxels.add(new Voxel(-1, 0, -1)); voxels.add(new Voxel(0, -1, -1)); voxels.add(new Voxel(0, 1, -1)); - + voxels.add(new Voxel(0, 0, 1)); voxels.add(new Voxel(1, 0, 1)); voxels.add(new Voxel(-1, 0, 1)); voxels.add(new Voxel(0, -1, 1)); voxels.add(new Voxel(0, 1, 1)); - + PottsLocationFactory3D.decrease(voxels, 17, RANDOM); - - int[][] corners = new int[][] { - { -1, -1 }, - { 1, -1 }, - { 1, 1 }, - { -1, 1 }, - }; - - int[][] sides = new int[][] { - { 0, -1 }, - { 1, 0 }, - { 0, 1 }, - { -1, 0 }, - }; - + + int[][] corners = + new int[][] { + {-1, -1}, + {1, -1}, + {1, 1}, + {-1, 1}, + }; + + int[][] sides = + new int[][] { + {0, -1}, + {1, 0}, + {0, 1}, + {-1, 0}, + }; + for (int i = 0; i < corners.length; i++) { if (voxels.contains(new Voxel(corners[i][0], corners[i][1], 0))) { boolean checkA = voxels.contains(new Voxel(sides[i][0], sides[i][1], 0)); - boolean checkB = voxels.contains(new Voxel(sides[(i + 1) % 4][0], sides[(i + 1) % 4][1], 0)); + boolean checkB = + voxels.contains(new Voxel(sides[(i + 1) % 4][0], sides[(i + 1) % 4][1], 0)); assertTrue(checkA || checkB); } } } - + @Test public void decrease_invalidTarget_updatesList() { ArrayList voxels = new ArrayList<>(); - + voxels.add(new Voxel(2, 0, 1)); voxels.add(new Voxel(1, 0, 1)); voxels.add(new Voxel(0, 0, 1)); @@ -652,16 +655,16 @@ public void decrease_invalidTarget_updatesList() { voxels.add(new Voxel(1, 0, -1)); voxels.add(new Voxel(2, 0, -1)); PottsLocationFactory3D.decrease(voxels, 3, RANDOM); - + ArrayList expected = new ArrayList<>(); expected.add(new Voxel(2, 0, 1)); expected.add(new Voxel(1, 0, 1)); expected.add(new Voxel(1, 0, -1)); expected.add(new Voxel(2, 0, -1)); - + voxels.sort(VOXEL_COMPARATOR); expected.sort(VOXEL_COMPARATOR); - + assertEquals(expected, voxels); } } diff --git a/test/arcade/potts/env/location/PottsLocationFactoryTest.java b/test/arcade/potts/env/location/PottsLocationFactoryTest.java index 0f4fce32f..5c36adbac 100644 --- a/test/arcade/potts/env/location/PottsLocationFactoryTest.java +++ b/test/arcade/potts/env/location/PottsLocationFactoryTest.java @@ -4,13 +4,13 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.stream.IntStream; -import org.junit.Test; +import org.junit.jupiter.api.Test; import ec.util.MersenneTwisterFast; import arcade.core.env.location.*; import arcade.core.sim.Series; import arcade.core.sim.output.OutputLoader; import arcade.core.util.MiniBox; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.core.ARCADETestUtilities.*; import static arcade.core.util.MiniBox.TAG_SEPARATOR; @@ -18,50 +18,53 @@ public class PottsLocationFactoryTest { final MersenneTwisterFast random = mock(MersenneTwisterFast.class); - - static Series createSeries(int length, int width, int height, - double[] volumes, double[] heights) { + + static Series createSeries( + int length, int width, int height, double[] volumes, double[] heights) { return createSeries(length, width, height, 0, volumes, heights); } - - static Series createSeries(int length, int width, int height, int margin, - double[] volumes, double[] heights) { + + static Series createSeries( + int length, int width, int height, int margin, double[] volumes, double[] heights) { Series series = mock(Series.class); series.populations = new HashMap<>(); - + try { Field lengthField = Series.class.getDeclaredField("length"); lengthField.setAccessible(true); lengthField.setInt(series, length); - + Field widthField = Series.class.getDeclaredField("width"); widthField.setAccessible(true); widthField.setInt(series, width); - + Field heightField = Series.class.getDeclaredField("height"); heightField.setAccessible(true); heightField.setInt(series, height); - + Field marginField = Series.class.getDeclaredField("margin"); marginField.setAccessible(true); marginField.setInt(series, margin); - } catch (Exception ignored) { } - + } catch (Exception ignored) { + } + for (int i = 0; i < volumes.length; i++) { int pop = i + 1; MiniBox box = new MiniBox(); box.put("CODE", pop); - box.put("CRITICAL_VOLUME_MEAN", volumes[i]); - box.put("CRITICAL_HEIGHT_MEAN", heights[i]); + box.put("CRITICAL_VOLUME", volumes[i]); + box.put("CRITICAL_HEIGHT", heights[i]); series.populations.put("pop" + pop, box); } - + return series; } - + static class PottsLocationFactoryMock extends PottsLocationFactory { - PottsLocationFactoryMock() { super(); } - + PottsLocationFactoryMock() { + super(); + } + @Override ArrayList getSelected(ArrayList voxels, Voxel focus, double n) { ArrayList selected = new ArrayList<>(); @@ -70,7 +73,7 @@ ArrayList getSelected(ArrayList voxels, Voxel focus, double n) { } return selected; } - + @Override ArrayList getPossible(Voxel focus, int s, int h) { ArrayList possible = new ArrayList<>(); @@ -83,7 +86,7 @@ ArrayList getPossible(Voxel focus, int s, int h) { } return possible; } - + @Override ArrayList getCenters(int length, int width, int height, int margin, int s, int h) { ArrayList centers = new ArrayList<>(); @@ -97,64 +100,66 @@ ArrayList getCenters(int length, int width, int height, int margin, int s return centers; } } - + @Test public void initialize_noLoading_callsMethod() { PottsLocationFactory factory = spy(new PottsLocationFactoryMock()); Series series = mock(Series.class); series.loader = null; - + doNothing().when(factory).loadLocations(series); doNothing().when(factory).createLocations(series); - + factory.initialize(series, random); - + verify(factory).createLocations(series); verify(factory, never()).loadLocations(series); } - + @Test public void initialize_noLoadingWithLoader_callsMethod() { PottsLocationFactory factory = spy(new PottsLocationFactoryMock()); Series series = mock(Series.class); series.loader = mock(OutputLoader.class); - + try { Field field = OutputLoader.class.getDeclaredField("loadLocations"); field.setAccessible(true); field.set(series.loader, false); - } catch (Exception ignored) { } - + } catch (Exception ignored) { + } + doNothing().when(factory).loadLocations(series); doNothing().when(factory).createLocations(series); - + factory.initialize(series, random); - + verify(factory).createLocations(series); verify(factory, never()).loadLocations(series); } - + @Test public void initialize_withLoadingWithLoader_callsMethod() { PottsLocationFactory factory = spy(new PottsLocationFactoryMock()); Series series = mock(Series.class); series.loader = mock(OutputLoader.class); - + try { Field field = OutputLoader.class.getDeclaredField("loadLocations"); field.setAccessible(true); field.set(series.loader, true); - } catch (Exception ignored) { } - + } catch (Exception ignored) { + } + doNothing().when(factory).loadLocations(series); doNothing().when(factory).createLocations(series); - + factory.initialize(series, random); - + verify(factory, never()).createLocations(series); verify(factory).loadLocations(series); } - + @Test public void loadLocations_givenLoaded_updatesList() { int n = randomIntBetween(1, 100); @@ -166,19 +171,20 @@ public void loadLocations_givenLoaded_updatesList() { voxels.add(new Voxel(i, 0, 0)); voxels.add(new Voxel(0, i, 0)); voxels.add(new Voxel(0, 0, i)); - PottsLocationContainer container = new PottsLocationContainer(i, new Voxel(i, i, i), voxels, null); + PottsLocationContainer container = + new PottsLocationContainer(i, new Voxel(i, i, i), voxels, null); containers.add(container); allVoxels.add(voxels); } - + PottsLocationFactoryMock factory = new PottsLocationFactoryMock(); Series series = mock(Series.class); series.loader = mock(OutputLoader.class); - + ArrayList container = new ArrayList<>(); IntStream.range(0, n).forEach(i -> container.add(containers.get(i))); doReturn(container).when(series.loader).loadLocations(); - + factory.loadLocations(series); assertEquals(n, factory.locations.size()); for (int i = 0; i < n; i++) { @@ -187,17 +193,17 @@ public void loadLocations_givenLoaded_updatesList() { assertEquals(allVoxels.get(i), pottsLocationContainer.allVoxels); } } - + @Test public void createLocations_noPopulation_createsEmpty() { - Series series = createSeries(0, 0, 0, new double[] { }, new double[] { }); - + Series series = createSeries(0, 0, 0, new double[] {}, new double[] {}); + PottsLocationFactoryMock factory = new PottsLocationFactoryMock(); factory.createLocations(series); - + assertEquals(0, factory.locations.size()); } - + @Test public void createLocations_noRegions_createsList() { int length = randomIntBetween(1, 10); @@ -206,14 +212,15 @@ public void createLocations_noRegions_createsList() { int margin = randomIntBetween(1, 10); int s = randomIntBetween(1, 10); int h = randomIntBetween(1, 10); - Series series = createSeries(length, width, height, margin, new double[] { 0 }, new double[] { 0 }); - + Series series = + createSeries(length, width, height, margin, new double[] {0}, new double[] {0}); + PottsLocationFactoryMock factory = spy(new PottsLocationFactoryMock()); factory.random = random; doReturn(h).when(factory).getVoxelsPerHeight(series); doReturn(s).when(factory).getVoxelsPerSide(series, h); factory.createLocations(series); - + assertEquals(length * width * height, factory.locations.values().size()); for (PottsLocationContainer container : factory.locations.values()) { assertTrue(container.center.x <= length + s + margin); @@ -225,7 +232,7 @@ public void createLocations_noRegions_createsList() { assertEquals(s * s * h, container.allVoxels.size()); } } - + @Test public void createLocations_withRegions_createsList() { int length = randomIntBetween(1, 10); @@ -235,17 +242,18 @@ public void createLocations_withRegions_createsList() { int s = randomIntBetween(3, 10); int h = randomIntBetween(1, 10); int padding = 2; - Series series = createSeries(length, width, height, margin, new double[] { 0 }, new double[] { 0 }); - + Series series = + createSeries(length, width, height, margin, new double[] {0}, new double[] {0}); + series.populations.get("pop1").put("(REGION)" + TAG_SEPARATOR + "DEFAULT", 0.0); series.populations.get("pop1").put("(REGION)" + TAG_SEPARATOR + "NUCLEUS", 0.0); - + PottsLocationFactoryMock factory = spy(new PottsLocationFactoryMock()); factory.random = random; doReturn(h).when(factory).getVoxelsPerHeight(series); doReturn(s).when(factory).getVoxelsPerSide(series, h); factory.createLocations(series); - + assertEquals(length * width * height, factory.locations.values().size()); for (PottsLocationContainer container : factory.locations.values()) { assertTrue(container.center.x <= length + s + margin); @@ -256,9 +264,13 @@ public void createLocations_withRegions_createsList() { assertTrue(container.center.z >= h); assertEquals(s * s * h, container.allVoxels.size()); assertEquals(2, container.regions.size()); - assertEquals((s - padding) * (s - padding) * h, container.regions.get(Region.DEFAULT).size()); - assertEquals((s - padding) * (s - padding) * h, container.regions.get(Region.NUCLEUS).size()); - + assertEquals( + (s - padding) * (s - padding) * h, + container.regions.get(Region.DEFAULT).size()); + assertEquals( + (s - padding) * (s - padding) * h, + container.regions.get(Region.NUCLEUS).size()); + for (Voxel voxel : container.regions.get(Region.DEFAULT)) { assertTrue(voxel.x <= s - padding); assertTrue(voxel.x >= 0); @@ -267,7 +279,7 @@ public void createLocations_withRegions_createsList() { assertTrue(voxel.z <= h); assertTrue(voxel.z >= 0); } - + for (Voxel voxel : container.regions.get(Region.NUCLEUS)) { assertTrue(voxel.x <= s - padding); assertTrue(voxel.x >= 0); @@ -278,7 +290,7 @@ public void createLocations_withRegions_createsList() { } } } - + @Test public void convert_exactOddSides_calculateValue() { PottsLocationFactory factory = new PottsLocationFactoryMock(); @@ -288,7 +300,7 @@ public void convert_exactOddSides_calculateValue() { assertEquals(5, factory.convert(5 * 5 * h, h)); assertEquals(7, factory.convert(7 * 7 * h, h)); } - + @Test public void convert_exactEvenSides_calculateValue() { PottsLocationFactory factory = new PottsLocationFactoryMock(); @@ -298,7 +310,7 @@ public void convert_exactEvenSides_calculateValue() { assertEquals(7, factory.convert(6 * 6 * h, h)); assertEquals(9, factory.convert(8 * 8 * h, h)); } - + @Test public void convert_inexactOddSides_calculateValue() { PottsLocationFactory factory = new PottsLocationFactoryMock(); @@ -308,7 +320,7 @@ public void convert_inexactOddSides_calculateValue() { assertEquals(7, factory.convert(5 * 5 * h + 1, h)); assertEquals(9, factory.convert(7 * 7 * h + 1, h)); } - + @Test public void convert_inexactEvenSides_calculateValue() { PottsLocationFactory factory = new PottsLocationFactoryMock(); @@ -318,85 +330,85 @@ public void convert_inexactEvenSides_calculateValue() { assertEquals(7, factory.convert(6 * 6 * h - 1, h)); assertEquals(9, factory.convert(8 * 8 * h - 1, h)); } - + @Test public void getVoxelsPerHeight_minimumHeight_returnsOne() { int n = randomIntBetween(3, 10); double[] heights = new double[n]; int seriesHeight = 0; - + Series series = createSeries(0, 0, seriesHeight, new double[n], heights); PottsLocationFactory factory = new PottsLocationFactoryMock(); int h = factory.getVoxelsPerHeight(series); - + assertEquals(1, h); } - + @Test public void getVoxelsPerHeight_cellHeight_returnsValue() { int n = randomIntBetween(3, 10); double[] heights = new double[n]; int seriesHeight = 100 * n + 2; int maxHeight = 0; - + for (int i = 0; i < n; i++) { heights[i] = randomIntBetween(1, 100); maxHeight = (int) Math.max(maxHeight, heights[i]); } - + Series series = createSeries(0, 0, seriesHeight, new double[n], heights); PottsLocationFactory factory = new PottsLocationFactoryMock(); int h = factory.getVoxelsPerHeight(series); - + assertEquals(maxHeight, h); } - + @Test public void getVoxelsPerHeight_fractionalHeight_returnsValue() { int n = randomIntBetween(3, 10); double[] heights = new double[n]; int seriesHeight = 100 * n + 2; int maxHeight = 0; - + for (int i = 0; i < n; i++) { heights[i] = randomDoubleBetween(1, 100); maxHeight = (int) Math.max(maxHeight, Math.ceil(heights[i])); } - + Series series = createSeries(0, 0, seriesHeight, new double[n], heights); PottsLocationFactory factory = new PottsLocationFactoryMock(); int h = factory.getVoxelsPerHeight(series); - + assertEquals(maxHeight, h); } - + @Test public void getVoxelsPerHeight_seriesHeight_returnsValue() { int n = randomIntBetween(3, 10); double[] heights = new double[n]; int padding = 2; int seriesHeight = randomIntBetween(3, 10) + padding; - + for (int i = 0; i < n; i++) { heights[i] = randomIntBetween(seriesHeight + 1, 100); } - + Series series = createSeries(0, 0, seriesHeight, new double[n], heights); PottsLocationFactory factory = new PottsLocationFactoryMock(); int h = factory.getVoxelsPerHeight(series); - + assertEquals(seriesHeight - padding, h); } - + @Test public void getVoxelsPerSide_noPopulations_returnsZero() { Series series = createSeries(0, 0, 0, new double[0], new double[0]); PottsLocationFactory factory = new PottsLocationFactoryMock(); int s = factory.getVoxelsPerSide(series, 0); - + assertEquals(0, s); } - + @Test public void getVoxelsPerSide_noPadding_returnsValue() { int h = randomIntBetween(3, 10); @@ -404,20 +416,20 @@ public void getVoxelsPerSide_noPadding_returnsValue() { double[] volumes = new double[n]; int padding = 0; int maxVolume = 0; - + for (int i = 0; i < n; i++) { int v = (randomIntBetween(2, 10) * 2 + 1); volumes[i] = v * v * h / 2.0; maxVolume = Math.max(maxVolume, v); } - + Series series = createSeries(0, 0, 0, volumes, new double[n]); PottsLocationFactory factory = new PottsLocationFactoryMock(); int s = factory.getVoxelsPerSide(series, h); - + assertEquals(maxVolume + padding, s); } - + @Test public void getVoxelsPerSide_withPadding_returnsValue() { int h = randomIntBetween(3, 10); @@ -425,27 +437,27 @@ public void getVoxelsPerSide_withPadding_returnsValue() { double[] volumes = new double[n]; int[] paddings = new int[n]; int maxVolume = 0; - + for (int i = 0; i < n; i++) { int v = (randomIntBetween(2, 10) * 2 + 1); volumes[i] = v * v * h / 2.0; - + int p = randomIntBetween(2, 10); paddings[i] = p; maxVolume = Math.max(maxVolume, v + p); } - + Series series = createSeries(0, 0, 0, volumes, new double[n]); - + for (int i = 0; i < n; i++) { int pop = i + 1; MiniBox box = series.populations.get("pop" + pop); box.put("PADDING", paddings[i]); } - + PottsLocationFactory factory = new PottsLocationFactoryMock(); int s = factory.getVoxelsPerSide(series, h); - + assertEquals(maxVolume, s); } } diff --git a/test/arcade/potts/env/location/PottsLocationTest.java b/test/arcade/potts/env/location/PottsLocationTest.java index 839f4499d..320bdf7fc 100644 --- a/test/arcade/potts/env/location/PottsLocationTest.java +++ b/test/arcade/potts/env/location/PottsLocationTest.java @@ -1,11 +1,15 @@ package arcade.potts.env.location; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import sim.util.Double3D; import ec.util.MersenneTwisterFast; -import static org.junit.Assert.*; +import arcade.potts.util.PottsEnums.Direction; +import arcade.potts.util.PottsEnums.Region; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.core.ARCADETestUtilities.*; import static arcade.potts.env.location.Voxel.VOXEL_COMPARATOR; @@ -14,42 +18,42 @@ public class PottsLocationTest { private static final double EPSILON = 1E-10; - + static MersenneTwisterFast randomDoubleZero; - + static MersenneTwisterFast randomDoubleOne; - + static final int LOCATION_SURFACE = randomIntBetween(0, 100); - + static final int LOCATION_HEIGHT = randomIntBetween(0, 100); - + static final int DELTA_SURFACE = randomIntBetween(1, 10); - + static final int DELTA_HEIGHT = randomIntBetween(1, 10); - + static ArrayList voxelListForAddRemove; - + static ArrayList voxelListA; - + static ArrayList voxelListB; - + static ArrayList voxelListAB; - - @BeforeClass + + @BeforeAll public static void setupMocks() { randomDoubleZero = mock(MersenneTwisterFast.class); when(randomDoubleZero.nextDouble()).thenReturn(0.0); - + randomDoubleOne = mock(MersenneTwisterFast.class); when(randomDoubleOne.nextDouble()).thenReturn(1.0); } - - @BeforeClass + + @BeforeAll public static void setupLists() { voxelListForAddRemove = new ArrayList<>(); voxelListForAddRemove.add(new Voxel(0, 0, 0)); voxelListForAddRemove.add(new Voxel(1, 0, 0)); - + /* * Lattice site shape: * @@ -64,59 +68,73 @@ public static void setupLists() { * x . . x * x . */ - + voxelListA = new ArrayList<>(); voxelListA.add(new Voxel(0, 0, 1)); voxelListA.add(new Voxel(0, 1, 1)); voxelListA.add(new Voxel(1, 0, 1)); voxelListA.add(new Voxel(0, 2, 1)); - + voxelListB = new ArrayList<>(); voxelListB.add(new Voxel(2, 0, 1)); voxelListB.add(new Voxel(3, 0, 1)); voxelListB.add(new Voxel(3, 1, 1)); - + voxelListAB = new ArrayList<>(voxelListA); voxelListAB.addAll(voxelListB); } - + static class PottsLocationMock extends PottsLocation { HashMap diameterMap; - - PottsLocationMock(ArrayList voxels) { super(voxels); } - + + PottsLocationMock(ArrayList voxels) { + super(voxels); + } + @Override - PottsLocation makeLocation(ArrayList voxels) { return new PottsLocationMock(voxels); } - + PottsLocation makeLocation(ArrayList voxels) { + return new PottsLocationMock(voxels); + } + @Override - public double convertSurface(double volume, double height) { return 0; } - + public double convertSurface(double volume, double height) { + return 0; + } + @Override - int calculateSurface() { return surface + LOCATION_SURFACE; } - + int calculateSurface() { + return surface + LOCATION_SURFACE; + } + @Override - int calculateHeight() { return height + LOCATION_HEIGHT; } - + int calculateHeight() { + return height + LOCATION_HEIGHT; + } + @Override - int updateSurface(Voxel voxel) { return DELTA_SURFACE; } - + int updateSurface(Voxel voxel) { + return DELTA_SURFACE; + } + @Override - int updateHeight(Voxel voxel) { return DELTA_HEIGHT; } - + int updateHeight(Voxel voxel) { + return DELTA_HEIGHT; + } + @Override ArrayList getNeighbors(Voxel voxel) { int num = 6; - int[] x = { 0, 1, 0, -1, 0, 0 }; - int[] y = { -1, 0, 1, 0, 0, 0 }; - int[] z = { 0, 0, 0, 0, 1, -1 }; - + int[] x = {0, 1, 0, -1, 0, 0}; + int[] y = {-1, 0, 1, 0, 0, 0}; + int[] z = {0, 0, 0, 0, 1, -1}; + ArrayList neighbors = new ArrayList<>(); for (int i = 0; i < num; i++) { neighbors.add(new Voxel(voxel.x + x[i], voxel.y + y[i], voxel.z + z[i])); } return neighbors; } - + @Override HashMap getDiameters() { if (diameterMap != null) { @@ -125,10 +143,10 @@ HashMap getDiameters() { this.diameterMap = new HashMap<>(); diameterMap.put(Direction.YZ_PLANE, 1); } - + return diameterMap; } - + @Override Direction getSlice(Direction direction, HashMap diameters) { switch (direction) { @@ -144,11 +162,13 @@ Direction getSlice(Direction direction, HashMap diameters) { return null; } } - + @Override - ArrayList getSelected(Voxel center, double n) { return new ArrayList<>(); } + ArrayList getSelected(Voxel center, double n) { + return new ArrayList<>(); + } } - + @Test public void constructor_called_setsSizes() { PottsLocationMock loc = new PottsLocationMock(voxelListAB); @@ -156,137 +176,137 @@ public void constructor_called_setsSizes() { assertEquals(LOCATION_SURFACE, loc.surface); assertEquals(LOCATION_HEIGHT, loc.height); } - + @Test public void constructor_called_setsCenter() { PottsLocationMock loc = new PottsLocationMock(voxelListAB); - + double cx = 0; double cy = 0; double cz = 0; - + for (Voxel v : voxelListAB) { cx += v.x; cy += v.y; cz += v.z; } - + int n = voxelListAB.size(); - + assertEquals(cx / n, loc.cx, EPSILON); assertEquals(cy / n, loc.cy, EPSILON); assertEquals(cz / n, loc.cz, EPSILON); } - + @Test public void getVoxels_noVoxels_returnsEmpty() { PottsLocationMock loc = new PottsLocationMock(new ArrayList<>()); assertEquals(0, loc.getVoxels().size()); } - + @Test public void getVoxels_hasVoxels_returnsList() { ArrayList voxels = new ArrayList<>(); - + int n = randomIntBetween(1, 100); for (int i = 0; i < n; i++) { voxels.add(new Voxel(i, i, i)); } - + PottsLocationMock loc = new PottsLocationMock(voxels); ArrayList voxelList = loc.getVoxels(); - + assertNotSame(loc.voxels, voxelList); voxelList.sort(VOXEL_COMPARATOR); voxels.sort(VOXEL_COMPARATOR); assertEquals(voxels, voxelList); } - + @Test public void getVoxels_noVoxelsRegion_returnsEmpty() { PottsLocationMock loc = new PottsLocationMock(new ArrayList<>()); assertEquals(0, loc.getVoxels(Region.DEFAULT).size()); } - + @Test public void getVoxels_hasVoxelsRegion_returnsEmpty() { ArrayList voxels = new ArrayList<>(); - + int n = randomIntBetween(1, 100); for (int i = 0; i < n; i++) { voxels.add(new Voxel(i, i, i)); } - + PottsLocationMock loc = new PottsLocationMock(voxels); assertEquals(0, loc.getVoxels(Region.DEFAULT).size()); } - + @Test public void getRegions_noRegions_returnsNull() { PottsLocationMock loc = new PottsLocationMock(new ArrayList<>()); assertNull(loc.getRegions()); } - + @Test public void getVolume_hasVoxels_returnsValue() { PottsLocationMock loc = new PottsLocationMock(new ArrayList<>()); loc.add(0, 0, 0); assertEquals(1, (int) loc.getVolume()); } - + @Test public void getVolume_noVoxels_returnsValue() { PottsLocationMock loc = new PottsLocationMock(new ArrayList<>()); assertEquals(0, (int) loc.getVolume()); } - + @Test public void getVolume_givenRegion_returnsValue() { PottsLocationMock loc = new PottsLocationMock(new ArrayList<>()); loc.add(0, 0, 0); assertEquals(1, (int) loc.getVolume(Region.DEFAULT)); } - + @Test public void getSurface_hasVoxels_returnsValue() { PottsLocationMock loc = new PottsLocationMock(new ArrayList<>()); loc.add(0, 0, 0); assertEquals(LOCATION_SURFACE + DELTA_SURFACE, (int) loc.getSurface()); } - + @Test public void getSurface_noVoxels_returnsValue() { PottsLocationMock loc = new PottsLocationMock(new ArrayList<>()); assertEquals(LOCATION_SURFACE, (int) loc.getSurface()); } - + @Test public void getSurface_givenRegion_returnsValue() { PottsLocationMock loc = new PottsLocationMock(new ArrayList<>()); loc.add(0, 0, 0); assertEquals(LOCATION_SURFACE + DELTA_SURFACE, (int) loc.getSurface(Region.DEFAULT)); } - + @Test public void getHeight_hasVoxels_returnsValue() { PottsLocationMock loc = new PottsLocationMock(new ArrayList<>()); loc.add(0, 0, 0); assertEquals(LOCATION_HEIGHT + DELTA_HEIGHT, (int) loc.getHeight()); } - + @Test public void getHeight_noVoxels_returnsValue() { PottsLocationMock loc = new PottsLocationMock(new ArrayList<>()); assertEquals(LOCATION_HEIGHT, (int) loc.getHeight()); } - + @Test public void getHeight_givenRegion_returnsValue() { PottsLocationMock loc = new PottsLocationMock(new ArrayList<>()); loc.add(0, 0, 0); assertEquals(LOCATION_HEIGHT + DELTA_HEIGHT, (int) loc.getHeight(Region.DEFAULT)); } - + @Test public void add_newVoxel_updatesList() { PottsLocationMock loc = new PottsLocationMock(new ArrayList<>()); @@ -294,45 +314,45 @@ public void add_newVoxel_updatesList() { loc.add(1, 0, 0); assertEquals(voxelListForAddRemove, loc.voxels); } - + @Test public void add_newVoxel_updatesVolume() { PottsLocationMock loc = new PottsLocationMock(new ArrayList<>()); loc.add(0, 0, 0); assertEquals(1, loc.volume); } - + @Test public void add_newVoxel_updatesSurface() { PottsLocationMock loc = new PottsLocationMock(new ArrayList<>()); loc.add(0, 0, 0); assertEquals(LOCATION_SURFACE + DELTA_SURFACE, loc.surface); } - + @Test public void add_newVoxel_updatesHeight() { PottsLocationMock loc = new PottsLocationMock(new ArrayList<>()); loc.add(0, 0, 0); assertEquals(LOCATION_HEIGHT + DELTA_HEIGHT, loc.height); } - + @Test public void add_newVoxel_updatesCenter() { ArrayList voxels = new ArrayList<>(); - + voxels.add(new Voxel(1, 4, 1)); voxels.add(new Voxel(2, 3, 0)); voxels.add(new Voxel(2, 2, 2)); voxels.add(new Voxel(3, 3, 1)); - + PottsLocationMock loc = new PottsLocationMock(voxels); loc.add(1, 1, 1); - + assertEquals(9. / 5, loc.cx, EPSILON); assertEquals(13. / 5, loc.cy, EPSILON); assertEquals(5. / 5, loc.cz, EPSILON); } - + @Test public void add_firstVoxel_setsCenter() { PottsLocationMock loc = new PottsLocationMock(new ArrayList<>()); @@ -344,7 +364,7 @@ public void add_firstVoxel_setsCenter() { assertEquals(cy, loc.cy, EPSILON); assertEquals(cz, loc.cz, EPSILON); } - + @Test public void add_existingVoxel_doesNothing() { PottsLocationMock loc = new PottsLocationMock(new ArrayList<>()); @@ -353,7 +373,7 @@ public void add_existingVoxel_doesNothing() { loc.add(0, 0, 0); assertEquals(voxelListForAddRemove, loc.voxels); } - + @Test public void add_newVoxelWithRegion_updatesList() { PottsLocationMock loc = new PottsLocationMock(new ArrayList<>()); @@ -361,28 +381,28 @@ public void add_newVoxelWithRegion_updatesList() { loc.add(Region.UNDEFINED, 1, 0, 0); assertEquals(voxelListForAddRemove, loc.voxels); } - + @Test public void add_newVoxelWithRegion_updatesVolume() { PottsLocationMock loc = new PottsLocationMock(new ArrayList<>()); loc.add(Region.DEFAULT, 0, 0, 0); assertEquals(1, loc.volume); } - + @Test public void add_newVoxelWithRegion_updatesSurface() { PottsLocationMock loc = new PottsLocationMock(new ArrayList<>()); loc.add(Region.DEFAULT, 0, 0, 0); assertEquals(LOCATION_SURFACE + DELTA_SURFACE, loc.surface); } - + @Test public void add_newVoxelWithRegion_updatesHeight() { PottsLocationMock loc = new PottsLocationMock(new ArrayList<>()); loc.add(Region.DEFAULT, 0, 0, 0); assertEquals(LOCATION_HEIGHT + DELTA_HEIGHT, loc.height); } - + @Test public void add_existingVoxelWithRegion_doesNothing() { PottsLocationMock loc = new PottsLocationMock(new ArrayList<>()); @@ -391,7 +411,7 @@ public void add_existingVoxelWithRegion_doesNothing() { loc.add(Region.NUCLEUS, 0, 0, 0); assertEquals(voxelListForAddRemove, loc.voxels); } - + @Test public void remove_existingVoxel_updatesList() { PottsLocationMock loc = new PottsLocationMock(voxelListForAddRemove); @@ -400,45 +420,45 @@ public void remove_existingVoxel_updatesList() { loc.remove(0, 0, 0); assertEquals(voxelsRemoved, loc.voxels); } - + @Test public void remove_existingVoxel_updatesVolume() { PottsLocationMock loc = new PottsLocationMock(voxelListForAddRemove); loc.remove(0, 0, 0); assertEquals(1, loc.volume); } - + @Test public void remove_existingVoxel_updatesSurface() { PottsLocationMock loc = new PottsLocationMock(voxelListForAddRemove); loc.remove(0, 0, 0); assertEquals(LOCATION_SURFACE - DELTA_SURFACE, loc.surface); } - + @Test public void remove_existingVoxel_updatesHeight() { PottsLocationMock loc = new PottsLocationMock(voxelListForAddRemove); loc.remove(0, 0, 0); assertEquals(LOCATION_HEIGHT - DELTA_HEIGHT, loc.height); } - + @Test public void remove_existingVoxel_updatesCenter() { ArrayList voxels = new ArrayList<>(); - + voxels.add(new Voxel(1, 4, 1)); voxels.add(new Voxel(2, 3, 0)); voxels.add(new Voxel(2, 2, 2)); voxels.add(new Voxel(3, 3, 1)); - + PottsLocationMock loc = new PottsLocationMock(voxels); loc.remove(1, 4, 1); - + assertEquals(7. / 3, loc.cx, EPSILON); assertEquals(8. / 3, loc.cy, EPSILON); assertEquals(3. / 3, loc.cz, EPSILON); } - + @Test public void remove_allVoxels_returnsEmptyList() { PottsLocationMock loc = new PottsLocationMock(voxelListForAddRemove); @@ -446,7 +466,7 @@ public void remove_allVoxels_returnsEmptyList() { loc.remove(1, 0, 0); assertEquals(new ArrayList<>(), loc.voxels); } - + @Test public void remove_allVoxels_updatesCenter() { PottsLocationMock loc = new PottsLocationMock(voxelListForAddRemove); @@ -456,14 +476,14 @@ public void remove_allVoxels_updatesCenter() { assertEquals(0, loc.cy, EPSILON); assertEquals(0, loc.cz, EPSILON); } - + @Test public void remove_missingVoxel_doesNothing() { PottsLocationMock loc = new PottsLocationMock(new ArrayList<>()); loc.remove(0, 0, 0); assertEquals(new ArrayList<>(), loc.voxels); } - + @Test public void remove_existingVoxelWithRegion_updatesList() { PottsLocationMock loc = new PottsLocationMock(voxelListForAddRemove); @@ -472,28 +492,28 @@ public void remove_existingVoxelWithRegion_updatesList() { loc.remove(Region.DEFAULT, 0, 0, 0); assertEquals(voxelsRemoved, loc.voxels); } - + @Test public void remove_existingVoxelWithRegion_updatesVolume() { PottsLocationMock loc = new PottsLocationMock(voxelListForAddRemove); loc.remove(Region.DEFAULT, 0, 0, 0); assertEquals(1, loc.volume); } - + @Test public void remove_existingVoxelWithRegion_updatesSurface() { PottsLocationMock loc = new PottsLocationMock(voxelListForAddRemove); loc.remove(Region.DEFAULT, 0, 0, 0); assertEquals(LOCATION_SURFACE - DELTA_SURFACE, loc.surface); } - + @Test public void remove_existingVoxelWithRegion_updatesHeight() { PottsLocationMock loc = new PottsLocationMock(voxelListForAddRemove); loc.remove(Region.DEFAULT, 0, 0, 0); assertEquals(LOCATION_HEIGHT - DELTA_HEIGHT, loc.height); } - + @Test public void remove_allVoxelsWithRegion_returnsEmptyList() { PottsLocationMock loc = new PottsLocationMock(voxelListForAddRemove); @@ -501,40 +521,40 @@ public void remove_allVoxelsWithRegion_returnsEmptyList() { loc.remove(Region.UNDEFINED, 1, 0, 0); assertEquals(new ArrayList<>(), loc.voxels); } - + @Test public void remove_missingVoxelWithRegion_doesNothing() { PottsLocationMock loc = new PottsLocationMock(new ArrayList<>()); loc.remove(Region.DEFAULT, 0, 0, 0); assertEquals(new ArrayList<>(), loc.voxels); } - + @Test public void assign_anyVoxel_doesNothing() { PottsLocationMock loc = new PottsLocationMock(voxelListForAddRemove); loc.assign(Region.DEFAULT, new Voxel(0, 0, 0)); assertEquals(voxelListForAddRemove, loc.voxels); } - + @Test public void distribute_anyTarget_doesNothing() { PottsLocationMock loc = new PottsLocationMock(voxelListForAddRemove); loc.distribute(Region.DEFAULT, 1, randomDoubleOne); assertEquals(voxelListForAddRemove, loc.voxels); } - + @Test public void adjust_voxelExists_returnsVoxel() { ArrayList voxels = new ArrayList<>(); voxels.add(new Voxel(0, 0, 0)); PottsLocationMock loc = new PottsLocationMock(voxels); - + Voxel voxel = new Voxel(0, 0, 0); Voxel adjusted = loc.adjust(voxel); - + assertEquals(voxel, adjusted); } - + @Test public void adjust_voxelDoesNotExist_returnsClosestVoxel() { ArrayList voxels = new ArrayList<>(); @@ -542,42 +562,42 @@ public void adjust_voxelDoesNotExist_returnsClosestVoxel() { voxels.add(new Voxel(0, 2, 3)); voxels.add(new Voxel(2, 1, 0)); PottsLocationMock loc = new PottsLocationMock(voxels); - + Voxel voxel = new Voxel(1, 2, 3); Voxel adjusted = loc.adjust(voxel); Voxel expected = new Voxel(0, 2, 3); - + assertEquals(expected, adjusted); } - + @Test public void clear_hasVoxels_updatesArray() { PottsLocationMock loc = new PottsLocationMock(voxelListForAddRemove); - int[][][] array = new int[][][] { { { 1, 0, 0 }, { 1, 0, 0 } } }; + int[][][] array = new int[][][] {{{1, 0, 0}, {1, 0, 0}}}; loc.clear(array, null); - - assertArrayEquals(new int[] { 0, 0, 0 }, array[0][0]); - assertArrayEquals(new int[] { 0, 0, 0 }, array[0][1]); + + assertArrayEquals(new int[] {0, 0, 0}, array[0][0]); + assertArrayEquals(new int[] {0, 0, 0}, array[0][1]); } - + @Test public void clear_hasVoxels_updatesLists() { PottsLocationMock loc = new PottsLocationMock(voxelListForAddRemove); loc.clear(new int[1][3][3], new int[1][3][3]); assertEquals(0, loc.voxels.size()); } - + @Test public void update_validID_updatesArray() { - int[][][] array = new int[][][] { { { 0, 1, 2 } } }; + int[][][] array = new int[][][] {{{0, 1, 2}}}; ArrayList voxels = new ArrayList<>(); voxels.add(new Voxel(0, 1, 0)); PottsLocationMock loc = new PottsLocationMock(voxels); - + loc.update(3, array, null); - assertArrayEquals(new int[] { 0, 3, 2 }, array[0][0]); + assertArrayEquals(new int[] {0, 3, 2}, array[0][0]); } - + @Test public void getCenter_hasVoxels_calculatesValue() { ArrayList voxels = new ArrayList<>(); @@ -586,19 +606,96 @@ public void getCenter_hasVoxels_calculatesValue() { voxels.add(new Voxel(2, 2, 2)); voxels.add(new Voxel(2, 3, 3)); PottsLocationMock loc = new PottsLocationMock(voxels); - + assertEquals(5 / 4., loc.cx, EPSILON); assertEquals(7 / 4., loc.cy, EPSILON); assertEquals(8 / 4., loc.cz, EPSILON); assertEquals(new Voxel(1, 2, 2), loc.getCenter()); } - + @Test public void getCenter_noVoxels_returnsNull() { PottsLocationMock loc = new PottsLocationMock(new ArrayList<>()); assertNull(loc.getCenter()); } - + + @Test + public void getOffset_noVoxels_returnsNull() { + PottsLocationMock loc = new PottsLocationMock(new ArrayList<>()); + assertNull(loc.getOffset(null)); + } + + @Test + public void getOffset_oneOffset_returnsValue() { + ArrayList voxels = new ArrayList<>(); + voxels.add(new Voxel(0, 100, 200)); + voxels.add(new Voxel(100, 200, 300)); + PottsLocationMock loc = new PottsLocationMock(voxels); + ArrayList offsets = new ArrayList<>(Arrays.asList(25)); + assertEquals(new Voxel(25, 125, 225), loc.getOffset(offsets)); + } + + @Test + public void getOffset_twoOffsets_returnsValue() { + ArrayList voxels = new ArrayList<>(); + voxels.add(new Voxel(0, 100, 200)); + voxels.add(new Voxel(100, 200, 300)); + PottsLocationMock loc = new PottsLocationMock(voxels); + ArrayList offsets = new ArrayList<>(Arrays.asList(33, 66)); + assertEquals(new Voxel(33, 166, 200), loc.getOffset(offsets)); + } + + @Test + public void getOffset_threeOffsets_returnsValue() { + ArrayList voxels = new ArrayList<>(); + voxels.add(new Voxel(0, 100, 200)); + voxels.add(new Voxel(100, 200, 300)); + PottsLocationMock loc = new PottsLocationMock(voxels); + ArrayList offsets = new ArrayList<>(Arrays.asList(50, 50, 50)); + assertEquals(new Voxel(50, 150, 250), loc.getOffset(offsets)); + } + + @Test + public void getOffset_noOffsets_raisesException() { + assertThrows( + IllegalArgumentException.class, + () -> { + ArrayList voxels = new ArrayList<>(); + voxels.add(new Voxel(0, 100, 200)); + voxels.add(new Voxel(100, 200, 300)); + PottsLocationMock loc = new PottsLocationMock(voxels); + ArrayList offsets = new ArrayList<>(); + loc.getOffset(offsets); + }); + } + + @Test + public void getOffset_invalidOffsets_raisesException() { + assertThrows( + IllegalArgumentException.class, + () -> { + ArrayList voxels = new ArrayList<>(); + voxels.add(new Voxel(0, 100, 200)); + voxels.add(new Voxel(100, 200, 300)); + PottsLocationMock loc = new PottsLocationMock(voxels); + ArrayList offsets = new ArrayList<>(Arrays.asList(0, 0, 0, 0)); + loc.getOffset(offsets); + }); + } + + @Test() + public void getOffset_nullOffsets_raisesException() { + assertThrows( + IllegalArgumentException.class, + () -> { + ArrayList voxels = new ArrayList<>(); + voxels.add(new Voxel(0, 100, 200)); + voxels.add(new Voxel(100, 200, 300)); + PottsLocationMock loc = new PottsLocationMock(voxels); + loc.getOffset(null); + }); + } + @Test public void getCentroid_hasVoxels_returnsArray() { ArrayList voxels = new ArrayList<>(); @@ -607,26 +704,26 @@ public void getCentroid_hasVoxels_returnsArray() { voxels.add(new Voxel(2, 2, 2)); voxels.add(new Voxel(2, 3, 3)); PottsLocationMock loc = new PottsLocationMock(voxels); - + double[] centroid = loc.getCentroid(); - + assertEquals(5 / 4., centroid[0], EPSILON); assertEquals(7 / 4., centroid[1], EPSILON); assertEquals(8 / 4., centroid[2], EPSILON); } - + @Test public void getCentroid_noVoxels_returnsZeros() { ArrayList voxels = new ArrayList<>(); PottsLocationMock loc = new PottsLocationMock(voxels); - + double[] centroid = loc.getCentroid(); - + assertEquals(0, centroid[0], EPSILON); assertEquals(0, centroid[1], EPSILON); assertEquals(0, centroid[2], EPSILON); } - + @Test public void getCentroid_hasVoxelsWithRegion_returnsArray() { ArrayList voxels = new ArrayList<>(); @@ -635,41 +732,41 @@ public void getCentroid_hasVoxelsWithRegion_returnsArray() { voxels.add(new Voxel(2, 2, 2)); voxels.add(new Voxel(2, 3, 3)); PottsLocationMock loc = new PottsLocationMock(voxels); - + double[] centroid = loc.getCentroid(Region.DEFAULT); - + assertEquals(5 / 4., centroid[0], EPSILON); assertEquals(7 / 4., centroid[1], EPSILON); assertEquals(8 / 4., centroid[2], EPSILON); } - + @Test public void getCentroid_noVoxelsWithRegion_returnsZeros() { ArrayList voxels = new ArrayList<>(); PottsLocationMock loc = new PottsLocationMock(voxels); - + double[] centroid = loc.getCentroid(Region.DEFAULT); - + assertEquals(0, centroid[0], EPSILON); assertEquals(0, centroid[1], EPSILON); assertEquals(0, centroid[2], EPSILON); } - + @Test public void getDirection_oneMaximumDiameter_returnsValue() { PottsLocationMock loc = new PottsLocationMock(new ArrayList<>()); MersenneTwisterFast random = mock(MersenneTwisterFast.class); when(random.nextInt(1)).thenReturn(0); - + HashMap diameters = new HashMap<>(); diameters.put(Direction.XY_PLANE, 50); diameters.put(Direction.POSITIVE_XY, 89); diameters.put(Direction.NEGATIVE_ZX, 100); loc.diameterMap = diameters; - + assertEquals(Direction.POSITIVE_YZ, loc.getDirection(random)); } - + @Test public void getDirection_multipleMaximumDiameters_returnsValueBasedOnRandom() { ArrayList voxels = new ArrayList<>(); @@ -677,42 +774,42 @@ public void getDirection_multipleMaximumDiameters_returnsValueBasedOnRandom() { PottsLocationMock loc = new PottsLocationMock(voxels); MersenneTwisterFast random = mock(MersenneTwisterFast.class); when(random.nextInt(3)).thenReturn(1).thenReturn(0).thenReturn(2); - + HashMap diameters = new HashMap<>(); diameters.put(Direction.YZ_PLANE, 50); diameters.put(Direction.XY_PLANE, 90); diameters.put(Direction.POSITIVE_XY, 95); diameters.put(Direction.NEGATIVE_ZX, 100); loc.diameterMap = diameters; - + assertEquals(Direction.YZ_PLANE, loc.getDirection(random)); assertEquals(Direction.NEGATIVE_YZ, loc.getDirection(random)); assertEquals(Direction.POSITIVE_YZ, loc.getDirection(random)); } - + @Test public void getDirection_zeroDiameters_returnsRandomValue() { for (int i = 0; i < 100; i++) { PottsLocationMock loc = new PottsLocationMock(new ArrayList<>()); MersenneTwisterFast random = mock(MersenneTwisterFast.class); when(random.nextInt(1)).thenReturn(0); - + HashMap diameters = new HashMap<>(); diameters.put(Direction.XY_PLANE, 0); diameters.put(Direction.POSITIVE_XY, 0); diameters.put(Direction.NEGATIVE_ZX, 0); loc.diameterMap = diameters; - + Direction direction = loc.getDirection(random); assertNotNull(direction); assertNotEquals(Direction.UNDEFINED, direction); } } - + @Test public void convert_createsContainer() { int locationID = randomIntBetween(1, 10); - + ArrayList voxels = new ArrayList<>(); int n = randomIntBetween(1, 10); for (int i = 0; i < 2 * n; i++) { @@ -720,17 +817,17 @@ public void convert_createsContainer() { voxels.add(new Voxel(i, j, 0)); } } - + PottsLocationMock location = new PottsLocationMock(voxels); - + PottsLocationContainer container = (PottsLocationContainer) location.convert(locationID); - + assertEquals(locationID, container.id); assertEquals(new Voxel(n, n, 0), container.center); assertEquals(voxels, container.allVoxels); assertNull(container.regions); } - + private ArrayList prepSplit() { ArrayList voxels = new ArrayList<>(); voxels.add(new Voxel(0, 0, 0)); @@ -742,57 +839,49 @@ private ArrayList prepSplit() { voxels.add(new Voxel(2, 2, 0)); return voxels; } - - @Test - public void splitVoxels_invalidDirection_doesNothing() { - ArrayList voxels = prepSplit(); - PottsLocationMock loc = new PottsLocationMock(voxels); - ArrayList voxelsA = new ArrayList<>(); - ArrayList voxelsB = new ArrayList<>(); - - PottsLocation.splitVoxels(Direction.UNDEFINED, voxels, voxelsA, voxelsB, loc.getCenter(), randomDoubleZero); - assertEquals(0, voxelsA.size()); - assertEquals(0, voxelsB.size()); - } - + @Test public void splitVoxels_YZPlaneDirectionRandomZero_updatesLists() { ArrayList voxels = prepSplit(); PottsLocationMock loc = new PottsLocationMock(voxels); - + ArrayList voxelsA = new ArrayList<>(); ArrayList voxelsB = new ArrayList<>(); ArrayList voxelsASplit = new ArrayList<>(); ArrayList voxelsBSplit = new ArrayList<>(); - + voxelsASplit.add(new Voxel(0, 0, 0)); voxelsASplit.add(new Voxel(0, 1, 1)); voxelsASplit.add(new Voxel(0, 2, 1)); + voxelsBSplit.add(new Voxel(1, 0, 2)); voxelsBSplit.add(new Voxel(1, 1, 1)); voxelsBSplit.add(new Voxel(2, 2, 2)); voxelsBSplit.add(new Voxel(2, 2, 0)); - - PottsLocation.splitVoxels(Direction.YZ_PLANE, voxels, voxelsA, voxelsB, loc.getCenter(), randomDoubleZero); + + Voxel center = loc.getCenter(); + Plane yzPlane = new Plane(center, Direction.YZ_PLANE); + + PottsLocation.splitVoxels(yzPlane, voxels, voxelsA, voxelsB, randomDoubleZero); assertEquals(voxelsASplit, voxelsA); assertEquals(voxelsBSplit, voxelsB); - + voxelsA.clear(); voxelsB.clear(); voxelsASplit.clear(); voxelsBSplit.clear(); } - + @Test public void splitVoxels_ZXPlaneDirectionRandomZero_updatesLists() { ArrayList voxels = prepSplit(); PottsLocationMock loc = new PottsLocationMock(voxels); - + ArrayList voxelsA = new ArrayList<>(); ArrayList voxelsB = new ArrayList<>(); ArrayList voxelsASplit = new ArrayList<>(); ArrayList voxelsBSplit = new ArrayList<>(); - + voxelsASplit.add(new Voxel(0, 0, 0)); voxelsBSplit.add(new Voxel(0, 1, 1)); voxelsBSplit.add(new Voxel(0, 2, 1)); @@ -800,22 +889,25 @@ public void splitVoxels_ZXPlaneDirectionRandomZero_updatesLists() { voxelsBSplit.add(new Voxel(1, 1, 1)); voxelsBSplit.add(new Voxel(2, 2, 2)); voxelsBSplit.add(new Voxel(2, 2, 0)); - - PottsLocation.splitVoxels(Direction.ZX_PLANE, voxels, voxelsA, voxelsB, loc.getCenter(), randomDoubleZero); + + Voxel center = loc.getCenter(); + Plane zxPlane = new Plane(center, Direction.ZX_PLANE); + + PottsLocation.splitVoxels(zxPlane, voxels, voxelsA, voxelsB, randomDoubleZero); assertEquals(voxelsASplit, voxelsA); assertEquals(voxelsBSplit, voxelsB); } - + @Test public void splitVoxels_XYPlaneDirectionRandomZero_updatesLists() { ArrayList voxels = prepSplit(); PottsLocationMock loc = new PottsLocationMock(voxels); - + ArrayList voxelsA = new ArrayList<>(); ArrayList voxelsB = new ArrayList<>(); ArrayList voxelsASplit = new ArrayList<>(); ArrayList voxelsBSplit = new ArrayList<>(); - + voxelsASplit.add(new Voxel(0, 0, 0)); voxelsBSplit.add(new Voxel(0, 1, 1)); voxelsBSplit.add(new Voxel(0, 2, 1)); @@ -823,22 +915,25 @@ public void splitVoxels_XYPlaneDirectionRandomZero_updatesLists() { voxelsBSplit.add(new Voxel(1, 1, 1)); voxelsBSplit.add(new Voxel(2, 2, 2)); voxelsASplit.add(new Voxel(2, 2, 0)); - - PottsLocation.splitVoxels(Direction.XY_PLANE, voxels, voxelsA, voxelsB, loc.getCenter(), randomDoubleZero); + + Voxel center = loc.getCenter(); + Plane xyPlane = new Plane(center, Direction.XY_PLANE); + + PottsLocation.splitVoxels(xyPlane, voxels, voxelsA, voxelsB, randomDoubleZero); assertEquals(voxelsASplit, voxelsA); assertEquals(voxelsBSplit, voxelsB); } - + @Test public void splitVoxels_negativeXYDirectionRandomZero_updatesLists() { ArrayList voxels = prepSplit(); PottsLocationMock loc = new PottsLocationMock(voxels); - + ArrayList voxelsA = new ArrayList<>(); ArrayList voxelsB = new ArrayList<>(); ArrayList voxelsASplit = new ArrayList<>(); ArrayList voxelsBSplit = new ArrayList<>(); - + voxelsBSplit.add(new Voxel(0, 0, 0)); voxelsBSplit.add(new Voxel(0, 1, 1)); voxelsBSplit.add(new Voxel(0, 2, 1)); @@ -846,22 +941,25 @@ public void splitVoxels_negativeXYDirectionRandomZero_updatesLists() { voxelsBSplit.add(new Voxel(1, 1, 1)); voxelsASplit.add(new Voxel(2, 2, 2)); voxelsASplit.add(new Voxel(2, 2, 0)); - - PottsLocation.splitVoxels(Direction.NEGATIVE_XY, voxels, voxelsA, voxelsB, loc.getCenter(), randomDoubleZero); + + Voxel center = loc.getCenter(); + Plane negativeXYPlane = new Plane(center, Direction.NEGATIVE_XY); + + PottsLocation.splitVoxels(negativeXYPlane, voxels, voxelsA, voxelsB, randomDoubleZero); assertEquals(voxelsASplit, voxelsA); assertEquals(voxelsBSplit, voxelsB); } - + @Test public void splitVoxels_positiveXYDirectionRandomZero_updatesLists() { ArrayList voxels = prepSplit(); PottsLocationMock loc = new PottsLocationMock(voxels); - + ArrayList voxelsA = new ArrayList<>(); ArrayList voxelsB = new ArrayList<>(); ArrayList voxelsASplit = new ArrayList<>(); ArrayList voxelsBSplit = new ArrayList<>(); - + voxelsBSplit.add(new Voxel(0, 0, 0)); voxelsBSplit.add(new Voxel(0, 1, 1)); voxelsBSplit.add(new Voxel(0, 2, 1)); @@ -869,22 +967,25 @@ public void splitVoxels_positiveXYDirectionRandomZero_updatesLists() { voxelsBSplit.add(new Voxel(1, 1, 1)); voxelsBSplit.add(new Voxel(2, 2, 2)); voxelsBSplit.add(new Voxel(2, 2, 0)); - - PottsLocation.splitVoxels(Direction.POSITIVE_XY, voxels, voxelsA, voxelsB, loc.getCenter(), randomDoubleZero); + + Voxel center = loc.getCenter(); + Plane positiveXYPlane = new Plane(center, Direction.POSITIVE_XY); + + PottsLocation.splitVoxels(positiveXYPlane, voxels, voxelsA, voxelsB, randomDoubleZero); assertEquals(voxelsASplit, voxelsA); assertEquals(voxelsBSplit, voxelsB); } - + @Test public void splitVoxels_negativeYZDirectionRandomZero_updatesLists() { ArrayList voxels = prepSplit(); PottsLocationMock loc = new PottsLocationMock(voxels); - + ArrayList voxelsA = new ArrayList<>(); ArrayList voxelsB = new ArrayList<>(); ArrayList voxelsASplit = new ArrayList<>(); ArrayList voxelsBSplit = new ArrayList<>(); - + voxelsBSplit.add(new Voxel(0, 0, 0)); voxelsBSplit.add(new Voxel(0, 1, 1)); voxelsASplit.add(new Voxel(0, 2, 1)); @@ -892,22 +993,25 @@ public void splitVoxels_negativeYZDirectionRandomZero_updatesLists() { voxelsBSplit.add(new Voxel(1, 1, 1)); voxelsASplit.add(new Voxel(2, 2, 2)); voxelsBSplit.add(new Voxel(2, 2, 0)); - - PottsLocation.splitVoxels(Direction.NEGATIVE_YZ, voxels, voxelsA, voxelsB, loc.getCenter(), randomDoubleZero); + + Voxel center = loc.getCenter(); + Plane negativeYZPlane = new Plane(center, Direction.NEGATIVE_YZ); + + PottsLocation.splitVoxels(negativeYZPlane, voxels, voxelsA, voxelsB, randomDoubleZero); assertEquals(voxelsASplit, voxelsA); assertEquals(voxelsBSplit, voxelsB); } - + @Test public void splitVoxels_positiveYZDirectionRandomZero_updatesLists() { ArrayList voxels = prepSplit(); PottsLocationMock loc = new PottsLocationMock(voxels); - + ArrayList voxelsA = new ArrayList<>(); ArrayList voxelsB = new ArrayList<>(); ArrayList voxelsASplit = new ArrayList<>(); ArrayList voxelsBSplit = new ArrayList<>(); - + voxelsBSplit.add(new Voxel(0, 0, 0)); voxelsBSplit.add(new Voxel(0, 1, 1)); voxelsASplit.add(new Voxel(0, 2, 1)); @@ -915,22 +1019,25 @@ public void splitVoxels_positiveYZDirectionRandomZero_updatesLists() { voxelsBSplit.add(new Voxel(1, 1, 1)); voxelsBSplit.add(new Voxel(2, 2, 2)); voxelsASplit.add(new Voxel(2, 2, 0)); - - PottsLocation.splitVoxels(Direction.POSITIVE_YZ, voxels, voxelsA, voxelsB, loc.getCenter(), randomDoubleZero); + + Voxel center = loc.getCenter(); + Plane positiveYZPlane = new Plane(center, Direction.POSITIVE_YZ); + + PottsLocation.splitVoxels(positiveYZPlane, voxels, voxelsA, voxelsB, randomDoubleZero); assertEquals(voxelsASplit, voxelsA); assertEquals(voxelsBSplit, voxelsB); } - + @Test public void splitVoxels_negativeZXDirectionRandomZero_updatesLists() { ArrayList voxels = prepSplit(); PottsLocationMock loc = new PottsLocationMock(voxels); - + ArrayList voxelsA = new ArrayList<>(); ArrayList voxelsB = new ArrayList<>(); ArrayList voxelsASplit = new ArrayList<>(); ArrayList voxelsBSplit = new ArrayList<>(); - + voxelsBSplit.add(new Voxel(0, 0, 0)); voxelsBSplit.add(new Voxel(0, 1, 1)); voxelsBSplit.add(new Voxel(0, 2, 1)); @@ -938,22 +1045,25 @@ public void splitVoxels_negativeZXDirectionRandomZero_updatesLists() { voxelsBSplit.add(new Voxel(1, 1, 1)); voxelsASplit.add(new Voxel(2, 2, 2)); voxelsBSplit.add(new Voxel(2, 2, 0)); - - PottsLocation.splitVoxels(Direction.NEGATIVE_ZX, voxels, voxelsA, voxelsB, loc.getCenter(), randomDoubleZero); + + Voxel center = loc.getCenter(); + Plane negativeZXPlane = new Plane(center, Direction.NEGATIVE_ZX); + + PottsLocation.splitVoxels(negativeZXPlane, voxels, voxelsA, voxelsB, randomDoubleZero); assertEquals(voxelsASplit, voxelsA); assertEquals(voxelsBSplit, voxelsB); } - + @Test public void splitVoxels_positiveZXDirectionRandomZero_updatesLists() { ArrayList voxels = prepSplit(); PottsLocationMock loc = new PottsLocationMock(voxels); - + ArrayList voxelsA = new ArrayList<>(); ArrayList voxelsB = new ArrayList<>(); ArrayList voxelsASplit = new ArrayList<>(); ArrayList voxelsBSplit = new ArrayList<>(); - + voxelsBSplit.add(new Voxel(0, 0, 0)); voxelsASplit.add(new Voxel(0, 1, 1)); voxelsASplit.add(new Voxel(0, 2, 1)); @@ -961,22 +1071,25 @@ public void splitVoxels_positiveZXDirectionRandomZero_updatesLists() { voxelsBSplit.add(new Voxel(1, 1, 1)); voxelsBSplit.add(new Voxel(2, 2, 2)); voxelsBSplit.add(new Voxel(2, 2, 0)); - - PottsLocation.splitVoxels(Direction.POSITIVE_ZX, voxels, voxelsA, voxelsB, loc.getCenter(), randomDoubleZero); + + Voxel center = loc.getCenter(); + Plane positiveZXPlane = new Plane(center, Direction.POSITIVE_ZX); + + PottsLocation.splitVoxels(positiveZXPlane, voxels, voxelsA, voxelsB, randomDoubleZero); assertEquals(voxelsASplit, voxelsA); assertEquals(voxelsBSplit, voxelsB); } - + @Test public void splitVoxels_YZPlaneDirectionRandomOne_updatesLists() { ArrayList voxels = prepSplit(); PottsLocationMock loc = new PottsLocationMock(voxels); - + ArrayList voxelsA = new ArrayList<>(); ArrayList voxelsB = new ArrayList<>(); ArrayList voxelsASplit = new ArrayList<>(); ArrayList voxelsBSplit = new ArrayList<>(); - + voxelsASplit.add(new Voxel(0, 0, 0)); voxelsASplit.add(new Voxel(0, 1, 1)); voxelsASplit.add(new Voxel(0, 2, 1)); @@ -984,22 +1097,25 @@ public void splitVoxels_YZPlaneDirectionRandomOne_updatesLists() { voxelsASplit.add(new Voxel(1, 1, 1)); voxelsBSplit.add(new Voxel(2, 2, 2)); voxelsBSplit.add(new Voxel(2, 2, 0)); - - PottsLocation.splitVoxels(Direction.YZ_PLANE, voxels, voxelsA, voxelsB, loc.getCenter(), randomDoubleOne); + + Voxel center = loc.getCenter(); + Plane yzPlane = new Plane(center, Direction.YZ_PLANE); + + PottsLocation.splitVoxels(yzPlane, voxels, voxelsA, voxelsB, randomDoubleOne); assertEquals(voxelsASplit, voxelsA); assertEquals(voxelsBSplit, voxelsB); } - + @Test public void splitVoxels_ZXPlaneDirectionRandomOne_updatesLists() { ArrayList voxels = prepSplit(); PottsLocationMock loc = new PottsLocationMock(voxels); - + ArrayList voxelsA = new ArrayList<>(); ArrayList voxelsB = new ArrayList<>(); ArrayList voxelsASplit = new ArrayList<>(); ArrayList voxelsBSplit = new ArrayList<>(); - + voxelsASplit.add(new Voxel(0, 0, 0)); voxelsASplit.add(new Voxel(0, 1, 1)); voxelsBSplit.add(new Voxel(0, 2, 1)); @@ -1007,22 +1123,25 @@ public void splitVoxels_ZXPlaneDirectionRandomOne_updatesLists() { voxelsASplit.add(new Voxel(1, 1, 1)); voxelsBSplit.add(new Voxel(2, 2, 2)); voxelsBSplit.add(new Voxel(2, 2, 0)); - - PottsLocation.splitVoxels(Direction.ZX_PLANE, voxels, voxelsA, voxelsB, loc.getCenter(), randomDoubleOne); + + Voxel center = loc.getCenter(); + Plane zxPlane = new Plane(center, Direction.ZX_PLANE); + + PottsLocation.splitVoxels(zxPlane, voxels, voxelsA, voxelsB, randomDoubleOne); assertEquals(voxelsASplit, voxelsA); assertEquals(voxelsBSplit, voxelsB); } - + @Test public void splitVoxels_XYPlaneDirectionRandomOne_updatesLists() { ArrayList voxels = prepSplit(); PottsLocationMock loc = new PottsLocationMock(voxels); - + ArrayList voxelsA = new ArrayList<>(); ArrayList voxelsB = new ArrayList<>(); ArrayList voxelsASplit = new ArrayList<>(); ArrayList voxelsBSplit = new ArrayList<>(); - + voxelsASplit.add(new Voxel(0, 0, 0)); voxelsASplit.add(new Voxel(0, 1, 1)); voxelsASplit.add(new Voxel(0, 2, 1)); @@ -1030,22 +1149,25 @@ public void splitVoxels_XYPlaneDirectionRandomOne_updatesLists() { voxelsASplit.add(new Voxel(1, 1, 1)); voxelsBSplit.add(new Voxel(2, 2, 2)); voxelsASplit.add(new Voxel(2, 2, 0)); - - PottsLocation.splitVoxels(Direction.XY_PLANE, voxels, voxelsA, voxelsB, loc.getCenter(), randomDoubleOne); + + Voxel center = loc.getCenter(); + Plane xyPlane = new Plane(center, Direction.XY_PLANE); + + PottsLocation.splitVoxels(xyPlane, voxels, voxelsA, voxelsB, randomDoubleOne); assertEquals(voxelsASplit, voxelsA); assertEquals(voxelsBSplit, voxelsB); } - + @Test public void splitVoxels_negativeXYDirectionRandomOne_updatesLists() { ArrayList voxels = prepSplit(); PottsLocationMock loc = new PottsLocationMock(voxels); - + ArrayList voxelsA = new ArrayList<>(); ArrayList voxelsB = new ArrayList<>(); ArrayList voxelsASplit = new ArrayList<>(); ArrayList voxelsBSplit = new ArrayList<>(); - + voxelsBSplit.add(new Voxel(0, 0, 0)); voxelsBSplit.add(new Voxel(0, 1, 1)); voxelsASplit.add(new Voxel(0, 2, 1)); @@ -1053,22 +1175,25 @@ public void splitVoxels_negativeXYDirectionRandomOne_updatesLists() { voxelsASplit.add(new Voxel(1, 1, 1)); voxelsASplit.add(new Voxel(2, 2, 2)); voxelsASplit.add(new Voxel(2, 2, 0)); - - PottsLocation.splitVoxels(Direction.NEGATIVE_XY, voxels, voxelsA, voxelsB, loc.getCenter(), randomDoubleOne); + + Voxel center = loc.getCenter(); + Plane negativeXYPlane = new Plane(center, Direction.NEGATIVE_XY); + + PottsLocation.splitVoxels(negativeXYPlane, voxels, voxelsA, voxelsB, randomDoubleOne); assertEquals(voxelsASplit, voxelsA); assertEquals(voxelsBSplit, voxelsB); } - + @Test public void splitVoxels_positiveXYDirectionRandomOne_updatesLists() { ArrayList voxels = prepSplit(); PottsLocationMock loc = new PottsLocationMock(voxels); - + ArrayList voxelsA = new ArrayList<>(); ArrayList voxelsB = new ArrayList<>(); ArrayList voxelsASplit = new ArrayList<>(); ArrayList voxelsBSplit = new ArrayList<>(); - + voxelsASplit.add(new Voxel(0, 0, 0)); voxelsBSplit.add(new Voxel(0, 1, 1)); voxelsBSplit.add(new Voxel(0, 2, 1)); @@ -1076,22 +1201,25 @@ public void splitVoxels_positiveXYDirectionRandomOne_updatesLists() { voxelsASplit.add(new Voxel(1, 1, 1)); voxelsASplit.add(new Voxel(2, 2, 2)); voxelsASplit.add(new Voxel(2, 2, 0)); - - PottsLocation.splitVoxels(Direction.POSITIVE_XY, voxels, voxelsA, voxelsB, loc.getCenter(), randomDoubleOne); + + Voxel center = loc.getCenter(); + Plane positiveXYPlane = new Plane(center, Direction.POSITIVE_XY); + + PottsLocation.splitVoxels(positiveXYPlane, voxels, voxelsA, voxelsB, randomDoubleOne); assertEquals(voxelsASplit, voxelsA); assertEquals(voxelsBSplit, voxelsB); } - + @Test public void splitVoxels_negativeYZDirectionRandomOne_updatesLists() { ArrayList voxels = prepSplit(); PottsLocationMock loc = new PottsLocationMock(voxels); - + ArrayList voxelsA = new ArrayList<>(); ArrayList voxelsB = new ArrayList<>(); ArrayList voxelsASplit = new ArrayList<>(); ArrayList voxelsBSplit = new ArrayList<>(); - + voxelsBSplit.add(new Voxel(0, 0, 0)); voxelsASplit.add(new Voxel(0, 1, 1)); voxelsASplit.add(new Voxel(0, 2, 1)); @@ -1099,22 +1227,25 @@ public void splitVoxels_negativeYZDirectionRandomOne_updatesLists() { voxelsASplit.add(new Voxel(1, 1, 1)); voxelsASplit.add(new Voxel(2, 2, 2)); voxelsASplit.add(new Voxel(2, 2, 0)); - - PottsLocation.splitVoxels(Direction.NEGATIVE_YZ, voxels, voxelsA, voxelsB, loc.getCenter(), randomDoubleOne); + + Voxel center = loc.getCenter(); + Plane negativeYZPlane = new Plane(center, Direction.NEGATIVE_YZ); + + PottsLocation.splitVoxels(negativeYZPlane, voxels, voxelsA, voxelsB, randomDoubleOne); assertEquals(voxelsASplit, voxelsA); assertEquals(voxelsBSplit, voxelsB); } - + @Test public void splitVoxels_positiveYZDirectionRandomOne_updatesLists() { ArrayList voxels = prepSplit(); PottsLocationMock loc = new PottsLocationMock(voxels); - + ArrayList voxelsA = new ArrayList<>(); ArrayList voxelsB = new ArrayList<>(); ArrayList voxelsASplit = new ArrayList<>(); ArrayList voxelsBSplit = new ArrayList<>(); - + voxelsASplit.add(new Voxel(0, 0, 0)); voxelsASplit.add(new Voxel(0, 1, 1)); voxelsASplit.add(new Voxel(0, 2, 1)); @@ -1122,22 +1253,25 @@ public void splitVoxels_positiveYZDirectionRandomOne_updatesLists() { voxelsASplit.add(new Voxel(1, 1, 1)); voxelsASplit.add(new Voxel(2, 2, 2)); voxelsASplit.add(new Voxel(2, 2, 0)); - - PottsLocation.splitVoxels(Direction.POSITIVE_YZ, voxels, voxelsA, voxelsB, loc.getCenter(), randomDoubleOne); + + Voxel center = loc.getCenter(); + Plane positiveYZPlane = new Plane(center, Direction.POSITIVE_YZ); + + PottsLocation.splitVoxels(positiveYZPlane, voxels, voxelsA, voxelsB, randomDoubleOne); assertEquals(voxelsASplit, voxelsA); assertEquals(voxelsBSplit, voxelsB); } - + @Test public void splitVoxels_negativeZXDirectionRandomOne_updatesLists() { ArrayList voxels = prepSplit(); PottsLocationMock loc = new PottsLocationMock(voxels); - + ArrayList voxelsA = new ArrayList<>(); ArrayList voxelsB = new ArrayList<>(); ArrayList voxelsASplit = new ArrayList<>(); ArrayList voxelsBSplit = new ArrayList<>(); - + voxelsBSplit.add(new Voxel(0, 0, 0)); voxelsBSplit.add(new Voxel(0, 1, 1)); voxelsBSplit.add(new Voxel(0, 2, 1)); @@ -1145,22 +1279,25 @@ public void splitVoxels_negativeZXDirectionRandomOne_updatesLists() { voxelsASplit.add(new Voxel(1, 1, 1)); voxelsASplit.add(new Voxel(2, 2, 2)); voxelsASplit.add(new Voxel(2, 2, 0)); - - PottsLocation.splitVoxels(Direction.NEGATIVE_ZX, voxels, voxelsA, voxelsB, loc.getCenter(), randomDoubleOne); + + Voxel center = loc.getCenter(); + Plane negativeZXPlane = new Plane(center, Direction.NEGATIVE_ZX); + + PottsLocation.splitVoxels(negativeZXPlane, voxels, voxelsA, voxelsB, randomDoubleOne); assertEquals(voxelsASplit, voxelsA); assertEquals(voxelsBSplit, voxelsB); } - + @Test public void splitVoxels_positiveZXDirectionRandomOne_updatesLists() { ArrayList voxels = prepSplit(); PottsLocationMock loc = new PottsLocationMock(voxels); - + ArrayList voxelsA = new ArrayList<>(); ArrayList voxelsB = new ArrayList<>(); ArrayList voxelsASplit = new ArrayList<>(); ArrayList voxelsBSplit = new ArrayList<>(); - + voxelsASplit.add(new Voxel(0, 0, 0)); voxelsASplit.add(new Voxel(0, 1, 1)); voxelsASplit.add(new Voxel(0, 2, 1)); @@ -1168,57 +1305,65 @@ public void splitVoxels_positiveZXDirectionRandomOne_updatesLists() { voxelsASplit.add(new Voxel(1, 1, 1)); voxelsASplit.add(new Voxel(2, 2, 2)); voxelsBSplit.add(new Voxel(2, 2, 0)); - - PottsLocation.splitVoxels(Direction.POSITIVE_ZX, voxels, voxelsA, voxelsB, loc.getCenter(), randomDoubleOne); + + Voxel center = loc.getCenter(); + Plane positiveZXPlane = new Plane(center, Direction.POSITIVE_ZX); + + PottsLocation.splitVoxels(positiveZXPlane, voxels, voxelsA, voxelsB, randomDoubleOne); assertEquals(voxelsASplit, voxelsA); assertEquals(voxelsBSplit, voxelsB); } - + @Test public void separateVoxels_validLists_updatesLists() { PottsLocationMock loc = new PottsLocationMock(voxelListAB); - PottsLocation split = (PottsLocation) loc.separateVoxels(voxelListA, voxelListB, randomDoubleZero); - + PottsLocation split = + (PottsLocation) loc.separateVoxels(voxelListA, voxelListB, randomDoubleZero); + ArrayList locVoxels = new ArrayList<>(voxelListA); ArrayList splitVoxels = new ArrayList<>(voxelListB); - + locVoxels.sort(VOXEL_COMPARATOR); loc.voxels.sort(VOXEL_COMPARATOR); splitVoxels.sort(VOXEL_COMPARATOR); split.voxels.sort(VOXEL_COMPARATOR); - + assertEquals(locVoxels, loc.voxels); assertEquals(splitVoxels, split.voxels); } - + @Test public void separateVoxels_validLists_updatesVolumes() { PottsLocationMock loc = new PottsLocationMock(voxelListAB); - PottsLocation split = (PottsLocation) loc.separateVoxels(voxelListA, voxelListB, randomDoubleZero); + PottsLocation split = + (PottsLocation) loc.separateVoxels(voxelListA, voxelListB, randomDoubleZero); assertEquals(voxelListA.size(), loc.volume); assertEquals(voxelListB.size(), split.volume); } - + @Test public void separateVoxels_validLists_updatesSurfaces() { PottsLocationMock loc = new PottsLocationMock(voxelListAB); - PottsLocation split = (PottsLocation) loc.separateVoxels(voxelListA, voxelListB, randomDoubleZero); + PottsLocation split = + (PottsLocation) loc.separateVoxels(voxelListA, voxelListB, randomDoubleZero); assertEquals(LOCATION_SURFACE + LOCATION_SURFACE, loc.surface); assertEquals(LOCATION_SURFACE, split.surface); } - + @Test public void separateVoxels_validLists_updatesHeights() { PottsLocationMock loc = new PottsLocationMock(voxelListAB); - PottsLocation split = (PottsLocation) loc.separateVoxels(voxelListA, voxelListB, randomDoubleZero); + PottsLocation split = + (PottsLocation) loc.separateVoxels(voxelListA, voxelListB, randomDoubleZero); assertEquals(LOCATION_HEIGHT + LOCATION_HEIGHT, loc.height); assertEquals(LOCATION_HEIGHT, split.height); } - + @Test public void separateVoxels_validLists_updatesCenter() { PottsLocationMock loc = new PottsLocationMock(voxelListAB); - PottsLocation split = (PottsLocation) loc.separateVoxels(voxelListA, voxelListB, randomDoubleZero); + PottsLocation split = + (PottsLocation) loc.separateVoxels(voxelListA, voxelListB, randomDoubleZero); assertEquals(1. / 4, loc.cx, EPSILON); assertEquals(3. / 4, loc.cy, EPSILON); assertEquals(4. / 4, loc.cz, EPSILON); @@ -1226,18 +1371,243 @@ public void separateVoxels_validLists_updatesCenter() { assertEquals(1. / 3, split.cy, EPSILON); assertEquals(3. / 3, split.cz, EPSILON); } - + + @Test + public void split_noOffsetsNoDirection_splitsVoxelsCorrectly() { + ArrayList voxels = new ArrayList<>(); + + // Create a 2x2x2 cuboid of voxels + for (int x = 0; x < 2; x++) { + for (int y = 0; y < 2; y++) { + for (int z = 0; z < 2; z++) { + voxels.add(new Voxel(x, y, z)); + } + } + } + + ArrayList splitVoxels = new ArrayList<>(); + ArrayList locVoxels = new ArrayList<>(); + for (Voxel voxel : voxels) { + if (voxel.y >= 1) { + splitVoxels.add(voxel); + } else { + locVoxels.add(voxel); + } + } + + PottsLocation loc = new PottsLocationMock(voxels); + PottsLocation split = (PottsLocation) loc.split(randomDoubleZero); + + locVoxels.sort(VOXEL_COMPARATOR); + loc.voxels.sort(VOXEL_COMPARATOR); + splitVoxels.sort(VOXEL_COMPARATOR); + split.voxels.sort(VOXEL_COMPARATOR); + + assertEquals(locVoxels, loc.voxels); + assertEquals(splitVoxels, split.voxels); + } + + @Test + public void split_withOffsetsNoDirection_splitsVoxelsCorrectly() { + ArrayList voxels = new ArrayList<>(); + ArrayList locVoxels = new ArrayList<>(); + ArrayList splitVoxels = new ArrayList<>(); + + // Create a 5x5x5 cuboid of voxels + for (int x = 0; x < 5; x++) { + for (int y = 0; y < 5; y++) { + for (int z = 0; z < 5; z++) { + voxels.add(new Voxel(x, y, z)); + } + } + } + + ArrayList offsets = new ArrayList<>(); + offsets.add(20); // split centered at x = 1 + offsets.add(20); // split centered at y = 1 + offsets.add(20); // split centered at x = 1 + + for (Voxel voxel : voxels) { + if (voxel.y >= 1) { + splitVoxels.add(voxel); + } else { + locVoxels.add(voxel); + } + } + + PottsLocation location = new PottsLocationMock(voxels); + PottsLocation splitLocation = (PottsLocation) location.split(randomDoubleZero, offsets); + + locVoxels.sort(VOXEL_COMPARATOR); + location.voxels.sort(VOXEL_COMPARATOR); + splitVoxels.sort(VOXEL_COMPARATOR); + splitLocation.voxels.sort(VOXEL_COMPARATOR); + + assertEquals(locVoxels, location.voxels); + assertEquals(splitVoxels, splitLocation.voxels); + } + @Test - public void split_randomZero_callsMethods() { - PottsLocation spy = spy(new PottsLocationMock(voxelListAB)); - spy.split(randomDoubleZero); - verify(spy).separateVoxels(any(ArrayList.class), any(ArrayList.class), eq(randomDoubleZero)); + public void split_withOffsetsWithDirectionWithProbability_splitsVoxelsCorrectly() { + ArrayList voxels = new ArrayList<>(); + ArrayList locVoxels = new ArrayList<>(); + ArrayList splitVoxels = new ArrayList<>(); + + // Create a 5x5x5 cuboid of voxels + for (int x = 0; x < 5; x++) { + for (int y = 0; y < 5; y++) { + for (int z = 0; z < 5; z++) { + voxels.add(new Voxel(x, y, z)); + } + } + } + + ArrayList offsets = new ArrayList<>(); + offsets.add(50); // split centered at x = 2 + offsets.add(75); // split centered at y = 3 + offsets.add(100); // split centered at z = 1 + + for (Voxel voxel : voxels) { + if (voxel.x - voxel.y + 1 > 0) { + locVoxels.add(voxel); + } else if ((voxel.x - voxel.y + 1) <= 0) { + splitVoxels.add(voxel); + } else { + // distance == 0 + // Since randomDoubleZero.nextDouble() == 0.0, and 0.0 > 0.5 is false + splitVoxels.add(voxel); + } + } + + PottsLocation location = new PottsLocationMock(voxels); + double probability = 0.5; + PottsLocation splitLocation = + (PottsLocation) + location.split( + randomDoubleZero, offsets, Direction.POSITIVE_XY, probability); + + locVoxels.sort(VOXEL_COMPARATOR); + location.voxels.sort(VOXEL_COMPARATOR); + splitVoxels.sort(VOXEL_COMPARATOR); + splitLocation.voxels.sort(VOXEL_COMPARATOR); + + assertEquals(locVoxels, location.voxels); + assertEquals(splitVoxels, splitLocation.voxels); } - + @Test - public void split_randomOne_callsMethods() { - PottsLocation spy = spy(new PottsLocationMock(voxelListAB)); - spy.split(randomDoubleOne); - verify(spy).separateVoxels(any(ArrayList.class), any(ArrayList.class), eq(randomDoubleOne)); + public void split_withOffsetsWithXYDirectionWithProbability_splitsVoxelsCorrectly() { + ArrayList voxels = new ArrayList<>(); + + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + for (int k = 0; k < 3; k++) { + voxels.add(new Voxel(i, j, k)); + } + } + } + + ArrayList locVoxels = new ArrayList<>(); + locVoxels.add(new Voxel(0, 2, 0)); + locVoxels.add(new Voxel(0, 2, 1)); + locVoxels.add(new Voxel(0, 2, 2)); + ArrayList splitVoxels = new ArrayList<>(voxels); + splitVoxels.removeAll(locVoxels); + + PottsLocation loc = new PottsLocationMock(voxels); + Direction direction = Direction.POSITIVE_XY; + double probability = 0.0; + + ArrayList offsets = new ArrayList<>(Arrays.asList(0, 100, 50)); + PottsLocation split = + (PottsLocation) loc.split(randomDoubleZero, offsets, direction, probability); + + locVoxels.sort(VOXEL_COMPARATOR); + loc.voxels.sort(VOXEL_COMPARATOR); + splitVoxels.sort(VOXEL_COMPARATOR); + split.voxels.sort(VOXEL_COMPARATOR); + + assertEquals(locVoxels, loc.voxels); + assertEquals(splitVoxels, split.voxels); + } + + @Test + public void split_withOffsetsWithZXDirectionWithProbability_splitsVoxelsCorrectly() { + ArrayList voxels = new ArrayList<>(); + + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + for (int k = 0; k < 3; k++) { + voxels.add(new Voxel(i, j, k)); + } + } + } + + ArrayList splitVoxels = new ArrayList<>(); + splitVoxels.add(new Voxel(0, 0, 2)); + splitVoxels.add(new Voxel(0, 1, 2)); + splitVoxels.add(new Voxel(0, 2, 2)); + ArrayList locVoxels = new ArrayList<>(voxels); + locVoxels.removeAll(splitVoxels); + + PottsLocation loc = new PottsLocationMock(voxels); + Direction direction = Direction.POSITIVE_ZX; + double probability = 0.0; + + ArrayList offsets = new ArrayList<>(Arrays.asList(0, 100, 50)); + PottsLocation split = + (PottsLocation) loc.split(randomDoubleZero, offsets, direction, probability); + + locVoxels.sort(VOXEL_COMPARATOR); + loc.voxels.sort(VOXEL_COMPARATOR); + splitVoxels.sort(VOXEL_COMPARATOR); + split.voxels.sort(VOXEL_COMPARATOR); + + assertEquals(locVoxels, loc.voxels); + assertEquals(splitVoxels, split.voxels); + } + + @Test + public void split_withOddAnglePlaneThroughPoint_splitsVoxelsCorrectly() { + ArrayList voxels = new ArrayList<>(); + ArrayList locVoxels = new ArrayList<>(); + ArrayList splitVoxels = new ArrayList<>(); + + // Create a 3x3x3 grid of voxels (total of 27 voxels) + for (int x = 0; x < 3; x++) { + for (int y = 0; y < 3; y++) { + for (int z = 0; z < 3; z++) { + voxels.add(new Voxel(x, y, z)); + } + } + } + + // Plane with normal vector (1, 2, 3) passing through point (1, 2, 1) + // Plane equation: x + 2y + 3z = 8 + Voxel planePoint = new Voxel(1, 2, 1); + Double3D normalVector = new Double3D(1, 2, 3); + Plane plane = new Plane(planePoint, normalVector); + + for (Voxel voxel : voxels) { + int value = voxel.x + 2 * voxel.y + 3 * voxel.z; + if (value < 8) { + locVoxels.add(voxel); + } else { + splitVoxels.add(voxel); + } + } + + PottsLocation loc = new PottsLocationMock(voxels); + double probability = 1.0; + + PottsLocation split = (PottsLocation) loc.split(randomDoubleZero, plane, probability); + + locVoxels.sort(VOXEL_COMPARATOR); + loc.voxels.sort(VOXEL_COMPARATOR); + splitVoxels.sort(VOXEL_COMPARATOR); + split.voxels.sort(VOXEL_COMPARATOR); + + assertEquals(locVoxels, loc.voxels); + assertEquals(splitVoxels, split.voxels); } } diff --git a/test/arcade/potts/env/location/PottsLocations2DTest.java b/test/arcade/potts/env/location/PottsLocations2DTest.java index 238ab2a8b..79cc8e3fe 100644 --- a/test/arcade/potts/env/location/PottsLocations2DTest.java +++ b/test/arcade/potts/env/location/PottsLocations2DTest.java @@ -1,102 +1,106 @@ package arcade.potts.env.location; import java.util.ArrayList; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import ec.util.MersenneTwisterFast; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.potts.util.PottsEnums.Region; public class PottsLocations2DTest { static MersenneTwisterFast randomDoubleZero; - + static MersenneTwisterFast randomDoubleOne; - - @BeforeClass + + @BeforeAll public static void setupMocks() { randomDoubleZero = mock(MersenneTwisterFast.class); when(randomDoubleZero.nextDouble()).thenReturn(0.0); - + randomDoubleOne = mock(MersenneTwisterFast.class); when(randomDoubleOne.nextDouble()).thenReturn(1.0); } - + @Test public void makeLocation_givenList_createsObject() { ArrayList voxels = new ArrayList<>(); voxels.add(new Voxel(0, 0, 0)); PottsLocations2D oldLoc = new PottsLocations2D(new ArrayList<>()); PottsLocation newLoc = oldLoc.makeLocation(voxels); - + assertTrue(newLoc instanceof PottsLocation2D); assertEquals(1, newLoc.voxels.size()); } - + @Test public void makeLocations_givenList_createsObject() { ArrayList voxels = new ArrayList<>(); voxels.add(new Voxel(0, 0, 0)); PottsLocations2D oldLoc = new PottsLocations2D(new ArrayList<>()); PottsLocations newLoc = oldLoc.makeLocations(voxels); - + assertTrue(newLoc instanceof PottsLocations2D); assertEquals(1, newLoc.voxels.size()); } - + @Test public void assignVoxels_defaultVoxelsOnly_updatesLists() { - int[] targets = new int[] { 4, 5, 6 }; - + int[] targets = new int[] {4, 5, 6}; + for (int target : targets) { PottsLocations2D loc = new PottsLocations2D(new ArrayList<>()); loc.locations.put(Region.NUCLEUS, new PottsLocation2D(new ArrayList<>())); - + int n = 3; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { loc.add(i, j, 0); } } - + loc.distribute(Region.NUCLEUS, target, randomDoubleZero); - + assertEquals(n * n, loc.voxels.size()); - assertEquals(n * n, loc.locations.get(Region.DEFAULT).voxels.size() - + loc.locations.get(Region.NUCLEUS).voxels.size()); - + assertEquals( + n * n, + loc.locations.get(Region.DEFAULT).voxels.size() + + loc.locations.get(Region.NUCLEUS).voxels.size()); + int sizeDefault = loc.locations.get(Region.DEFAULT).voxels.size(); int sizeRegion = loc.locations.get(Region.NUCLEUS).voxels.size(); - + assertEquals(n * n - target, sizeDefault); assertEquals(target, sizeRegion); } } - + @Test public void assignVoxels_includesRegionVoxels_updatesLists() { - int[] targets = new int[] { 4, 5, 6 }; - + int[] targets = new int[] {4, 5, 6}; + for (int target : targets) { PottsLocations2D loc = new PottsLocations2D(new ArrayList<>()); loc.locations.put(Region.NUCLEUS, new PottsLocation2D(new ArrayList<>())); - + int n = 3; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { loc.add(Region.NUCLEUS, i, j, 0); } } - + loc.distribute(Region.NUCLEUS, target, randomDoubleZero); - + assertEquals(n * n, loc.voxels.size()); - assertEquals(n * n, loc.locations.get(Region.DEFAULT).voxels.size() - + loc.locations.get(Region.NUCLEUS).voxels.size()); - + assertEquals( + n * n, + loc.locations.get(Region.DEFAULT).voxels.size() + + loc.locations.get(Region.NUCLEUS).voxels.size()); + int sizeDefault = loc.locations.get(Region.DEFAULT).voxels.size(); int sizeRegion = loc.locations.get(Region.NUCLEUS).voxels.size(); - + assertEquals(n * n - target, sizeDefault); assertEquals(target, sizeRegion); } diff --git a/test/arcade/potts/env/location/PottsLocations3DTest.java b/test/arcade/potts/env/location/PottsLocations3DTest.java index 632132f1d..3deb347f1 100644 --- a/test/arcade/potts/env/location/PottsLocations3DTest.java +++ b/test/arcade/potts/env/location/PottsLocations3DTest.java @@ -1,57 +1,57 @@ package arcade.potts.env.location; import java.util.ArrayList; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import ec.util.MersenneTwisterFast; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.potts.util.PottsEnums.Region; public class PottsLocations3DTest { static MersenneTwisterFast randomDoubleZero; - + static MersenneTwisterFast randomDoubleOne; - - @BeforeClass + + @BeforeAll public static void setupMocks() { randomDoubleZero = mock(MersenneTwisterFast.class); when(randomDoubleZero.nextDouble()).thenReturn(0.0); - + randomDoubleOne = mock(MersenneTwisterFast.class); when(randomDoubleOne.nextDouble()).thenReturn(1.0); } - + @Test public void makeLocation_givenList_createsObject() { ArrayList voxels = new ArrayList<>(); voxels.add(new Voxel(0, 0, 0)); PottsLocations3D oldLoc = new PottsLocations3D(new ArrayList<>()); PottsLocation newLoc = oldLoc.makeLocation(voxels); - + assertTrue(newLoc instanceof PottsLocation3D); assertEquals(1, newLoc.voxels.size()); } - + @Test public void makeLocations_givenList_createsObject() { ArrayList voxels = new ArrayList<>(); voxels.add(new Voxel(0, 0, 0)); PottsLocations3D oldLoc = new PottsLocations3D(new ArrayList<>()); PottsLocations newLoc = oldLoc.makeLocations(voxels); - + assertTrue(newLoc instanceof PottsLocations3D); assertEquals(1, newLoc.voxels.size()); } - + @Test public void assignVoxels_defaultVoxelsOnly_updatesLists() { - int[] targets = new int[] { 14, 15, 16 }; - + int[] targets = new int[] {14, 15, 16}; + for (int target : targets) { PottsLocations3D loc = new PottsLocations3D(new ArrayList<>()); loc.locations.put(Region.NUCLEUS, new PottsLocation3D(new ArrayList<>())); - + int n = 3; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { @@ -60,29 +60,31 @@ public void assignVoxels_defaultVoxelsOnly_updatesLists() { } } } - + loc.distribute(Region.NUCLEUS, target, randomDoubleZero); - + assertEquals(n * n * n, loc.voxels.size()); - assertEquals(n * n * n, loc.locations.get(Region.DEFAULT).voxels.size() - + loc.locations.get(Region.NUCLEUS).voxels.size()); - + assertEquals( + n * n * n, + loc.locations.get(Region.DEFAULT).voxels.size() + + loc.locations.get(Region.NUCLEUS).voxels.size()); + int sizeDefault = loc.locations.get(Region.DEFAULT).voxels.size(); int sizeRegion = loc.locations.get(Region.NUCLEUS).voxels.size(); - + assertEquals(n * n * n - target, sizeDefault); assertEquals(target, sizeRegion); } } - + @Test public void assignVoxels_includesRegionVoxels_updatesLists() { - int[] targets = new int[] { 14, 15, 16 }; - + int[] targets = new int[] {14, 15, 16}; + for (int target : targets) { PottsLocations3D loc = new PottsLocations3D(new ArrayList<>()); loc.locations.put(Region.NUCLEUS, new PottsLocation3D(new ArrayList<>())); - + int n = 3; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { @@ -91,16 +93,18 @@ public void assignVoxels_includesRegionVoxels_updatesLists() { } } } - + loc.distribute(Region.NUCLEUS, target, randomDoubleZero); - + assertEquals(n * n * n, loc.voxels.size()); - assertEquals(n * n * n, loc.locations.get(Region.DEFAULT).voxels.size() - + loc.locations.get(Region.NUCLEUS).voxels.size()); - + assertEquals( + n * n * n, + loc.locations.get(Region.DEFAULT).voxels.size() + + loc.locations.get(Region.NUCLEUS).voxels.size()); + int sizeDefault = loc.locations.get(Region.DEFAULT).voxels.size(); int sizeRegion = loc.locations.get(Region.NUCLEUS).voxels.size(); - + assertEquals(n * n * n - target, sizeDefault); assertEquals(target, sizeRegion); } diff --git a/test/arcade/potts/env/location/PottsLocationsTest.java b/test/arcade/potts/env/location/PottsLocationsTest.java index e7c84a5d1..6c082948a 100644 --- a/test/arcade/potts/env/location/PottsLocationsTest.java +++ b/test/arcade/potts/env/location/PottsLocationsTest.java @@ -3,10 +3,10 @@ import java.util.ArrayList; import java.util.EnumMap; import java.util.HashMap; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import ec.util.MersenneTwisterFast; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.core.ARCADETestUtilities.*; import static arcade.potts.env.location.PottsLocationTest.*; @@ -16,138 +16,154 @@ public class PottsLocationsTest { private static final double EPSILON = 1E-10; - + static MersenneTwisterFast randomDoubleZero; - + static MersenneTwisterFast randomDoubleOne; - + static ArrayList voxelListForVolumeSurfaceHeight; - + static ArrayList voxelListForMultipleRegionsA; - + static ArrayList voxelListForMultipleRegionsB; - + static ArrayList voxelListForMultipleRegions; - + static ArrayList voxelListForAddRemove; - + static ArrayList voxelListForRegionAddRemove; - + static ArrayList voxelListSingle; - + static ArrayList voxelListDouble; - + static ArrayList voxelListA; - + static ArrayList voxelListB; - + static ArrayList voxelListAB; - + static final int LOCATIONS_SURFACE = randomIntBetween(0, 100); - + static final int LOCATIONS_HEIGHT = randomIntBetween(0, 100); - - @BeforeClass + + @BeforeAll public static void setupMocks() { randomDoubleZero = mock(MersenneTwisterFast.class); when(randomDoubleZero.nextDouble()).thenReturn(0.0); - + randomDoubleOne = mock(MersenneTwisterFast.class); when(randomDoubleOne.nextDouble()).thenReturn(1.0); } - - @BeforeClass + + @BeforeAll public static void setupLists() { voxelListForVolumeSurfaceHeight = new ArrayList<>(); voxelListForVolumeSurfaceHeight.add(new Voxel(0, 0, 0)); - + voxelListForMultipleRegionsA = new ArrayList<>(); voxelListForMultipleRegionsA.add(new Voxel(0, 0, 0)); voxelListForMultipleRegionsA.add(new Voxel(0, 1, 0)); voxelListForMultipleRegionsA.add(new Voxel(0, 2, 0)); voxelListForMultipleRegionsA.add(new Voxel(1, 0, 0)); - + voxelListForMultipleRegionsB = new ArrayList<>(); voxelListForMultipleRegionsB.add(new Voxel(1, 2, 0)); voxelListForMultipleRegionsB.add(new Voxel(2, 0, 0)); voxelListForMultipleRegionsB.add(new Voxel(2, 1, 0)); voxelListForMultipleRegionsB.add(new Voxel(2, 2, 0)); - + voxelListForMultipleRegions = new ArrayList<>(); voxelListForMultipleRegions.addAll(voxelListForMultipleRegionsA); voxelListForMultipleRegions.addAll(voxelListForMultipleRegionsB); - + voxelListForAddRemove = new ArrayList<>(); voxelListForAddRemove.add(new Voxel(0, 0, 0)); voxelListForAddRemove.add(new Voxel(1, 0, 0)); - + voxelListForRegionAddRemove = new ArrayList<>(); voxelListForRegionAddRemove.add(new Voxel(1, 1, 0)); - + voxelListSingle = new ArrayList<>(); voxelListSingle.add(new Voxel(0, 0, 0)); - + voxelListDouble = new ArrayList<>(); voxelListDouble.add(new Voxel(0, 0, 0)); voxelListDouble.add(new Voxel(1, 1, 0)); - + voxelListA = new ArrayList<>(); voxelListA.add(new Voxel(0, 0, 0)); voxelListA.add(new Voxel(0, 1, 0)); voxelListA.add(new Voxel(1, 0, 0)); voxelListA.add(new Voxel(0, 2, 0)); - + voxelListB = new ArrayList<>(); voxelListB.add(new Voxel(2, 0, 0)); voxelListB.add(new Voxel(3, 0, 0)); voxelListB.add(new Voxel(3, 1, 0)); - + voxelListAB = new ArrayList<>(voxelListA); voxelListAB.addAll(voxelListB); } - + static class PottsLocationsMock extends PottsLocations { - PottsLocationsMock(ArrayList voxels) { super(voxels); } - + PottsLocationsMock(ArrayList voxels) { + super(voxels); + } + @Override - PottsLocation makeLocation(ArrayList voxels) { return new PottsLocationMock(voxels); } - + PottsLocation makeLocation(ArrayList voxels) { + return new PottsLocationMock(voxels); + } + @Override - PottsLocations makeLocations(ArrayList voxels) { return new PottsLocationsMock(voxels); } - + PottsLocations makeLocations(ArrayList voxels) { + return new PottsLocationsMock(voxels); + } + @Override - public double convertSurface(double volume, double height) { return 0; } - + public double convertSurface(double volume, double height) { + return 0; + } + @Override - int calculateSurface() { return LOCATIONS_SURFACE; } - + int calculateSurface() { + return LOCATIONS_SURFACE; + } + @Override - int calculateHeight() { return LOCATIONS_HEIGHT; } - + int calculateHeight() { + return LOCATIONS_HEIGHT; + } + @Override - int updateSurface(Voxel voxel) { return DELTA_SURFACE; } - + int updateSurface(Voxel voxel) { + return DELTA_SURFACE; + } + @Override - int updateHeight(Voxel voxel) { return DELTA_HEIGHT; } - + int updateHeight(Voxel voxel) { + return DELTA_HEIGHT; + } + @Override ArrayList getNeighbors(Voxel voxel) { int num = 6; - int[] x = { 0, 1, 0, -1, 0, 0 }; - int[] y = { -1, 0, 1, 0, 0, 0 }; - int[] z = { 0, 0, 0, 0, 1, -1 }; - + int[] x = {0, 1, 0, -1, 0, 0}; + int[] y = {-1, 0, 1, 0, 0, 0}; + int[] z = {0, 0, 0, 0, 1, -1}; + ArrayList neighbors = new ArrayList<>(); for (int i = 0; i < num; i++) { neighbors.add(new Voxel(voxel.x + x[i], voxel.y + y[i], voxel.z + z[i])); } return neighbors; } - + @Override HashMap getDiameters() { HashMap diameters = new HashMap<>(); - + if (voxels.size() == 0) { diameters.put(Direction.XY_PLANE, 1); diameters.put(Direction.POSITIVE_XY, 2); @@ -159,10 +175,10 @@ HashMap getDiameters() { diameters.put(Direction.POSITIVE_XY, 1); diameters.put(Direction.NEGATIVE_ZX, 1); } - + return diameters; } - + @Override Direction getSlice(Direction direction, HashMap diameters) { switch (direction) { @@ -178,7 +194,7 @@ Direction getSlice(Direction direction, HashMap diameters) { return null; } } - + @Override ArrayList getSelected(Voxel center, double n) { ArrayList selected = new ArrayList<>(); @@ -186,45 +202,45 @@ ArrayList getSelected(Voxel center, double n) { return selected; } } - + @Test public void getVoxels_invalidRegion_returnsEmpty() { ArrayList voxels = new ArrayList<>(); - + int n = randomIntBetween(1, 100); for (int i = 0; i < n; i++) { voxels.add(new Voxel(i, i, i)); } - + PottsLocationsMock loc = new PottsLocationsMock(voxels); assertEquals(0, loc.getVoxels(Region.NUCLEUS).size()); } - + @Test public void getVoxels_validRegion_returnsEmpty() { ArrayList voxels = new ArrayList<>(); - + int n = randomIntBetween(1, 100); for (int i = 0; i < n; i++) { voxels.add(new Voxel(i, i, i)); } - + PottsLocationsMock loc = new PottsLocationsMock(voxels); ArrayList voxelList = loc.getVoxels(Region.DEFAULT); - + assertNotSame(loc.voxels, voxelList); voxelList.sort(VOXEL_COMPARATOR); voxels.sort(VOXEL_COMPARATOR); assertEquals(voxels, voxelList); } - + @Test public void getRegions_regionsNotAssigned_returnsOne() { PottsLocationsMock loc = new PottsLocationsMock(new ArrayList<>()); assertEquals(1, loc.getRegions().size()); assertTrue(loc.getRegions().contains(Region.DEFAULT)); } - + @Test public void getRegions_regionsAssigned_returnsGiven() { PottsLocationsMock loc = new PottsLocationsMock(new ArrayList<>()); @@ -235,20 +251,20 @@ public void getRegions_regionsAssigned_returnsGiven() { assertTrue(loc.getRegions().contains(Region.UNDEFINED)); assertTrue(loc.getRegions().contains(Region.NUCLEUS)); } - + @Test public void getVolume_validRegion_returnsValue() { PottsLocationsMock loc = new PottsLocationsMock(voxelListForVolumeSurfaceHeight); assertEquals(1, (int) loc.getVolume()); assertEquals(1, (int) loc.getVolume(Region.DEFAULT)); } - + @Test public void getVolume_invalidRegion_returnsZero() { PottsLocationsMock loc = new PottsLocationsMock(voxelListForVolumeSurfaceHeight); assertEquals(0, (int) loc.getVolume(null)); } - + @Test public void getVolume_multipleRegions_returnsValue() { PottsLocationsMock loc = new PottsLocationsMock(voxelListForMultipleRegions); @@ -257,20 +273,20 @@ public void getVolume_multipleRegions_returnsValue() { assertEquals(8, (int) loc.getVolume(Region.DEFAULT)); assertEquals(1, (int) loc.getVolume(Region.UNDEFINED)); } - + @Test public void getSurface_validRegion_returnsValue() { PottsLocationsMock loc = new PottsLocationsMock(voxelListForVolumeSurfaceHeight); assertEquals(LOCATIONS_SURFACE, (int) loc.getSurface()); assertEquals(LOCATION_SURFACE, (int) loc.getSurface(Region.DEFAULT)); } - + @Test public void getSurface_invalidRegion_returnsZero() { PottsLocationsMock loc = new PottsLocationsMock(voxelListForVolumeSurfaceHeight); assertEquals(0, (int) loc.getSurface(null)); } - + @Test public void getSurface_multipleRegions_returnsValue() { PottsLocationsMock loc = new PottsLocationsMock(voxelListForMultipleRegions); @@ -279,20 +295,20 @@ public void getSurface_multipleRegions_returnsValue() { assertEquals(LOCATION_SURFACE, (int) loc.getSurface(Region.DEFAULT)); assertEquals(LOCATION_SURFACE + DELTA_SURFACE, (int) loc.getSurface(Region.UNDEFINED)); } - + @Test public void getHeight_validRegion_returnsValue() { PottsLocationsMock loc = new PottsLocationsMock(voxelListForVolumeSurfaceHeight); assertEquals(LOCATIONS_HEIGHT, (int) loc.getHeight()); assertEquals(LOCATION_HEIGHT, (int) loc.getHeight(Region.DEFAULT)); } - + @Test public void getHeight_invalidRegion_returnsZero() { PottsLocationsMock loc = new PottsLocationsMock(voxelListForVolumeSurfaceHeight); assertEquals(0, (int) loc.getHeight(null)); } - + @Test public void getHeight_multipleRegions_returnsValue() { PottsLocationsMock loc = new PottsLocationsMock(voxelListForMultipleRegions); @@ -301,7 +317,7 @@ public void getHeight_multipleRegions_returnsValue() { assertEquals(LOCATION_HEIGHT, (int) loc.getHeight(Region.DEFAULT)); assertEquals(LOCATION_HEIGHT + DELTA_HEIGHT, (int) loc.getHeight(Region.UNDEFINED)); } - + @Test public void add_newVoxelNoRegion_updatesLists() { PottsLocationsMock loc = new PottsLocationsMock(new ArrayList<>()); @@ -310,7 +326,7 @@ public void add_newVoxelNoRegion_updatesLists() { assertEquals(voxelListForAddRemove, loc.voxels); assertEquals(voxelListForAddRemove, loc.locations.get(Region.DEFAULT).voxels); } - + @Test public void add_newVoxelNoRegion_updatesVolumes() { PottsLocationsMock loc = new PottsLocationsMock(new ArrayList<>()); @@ -319,16 +335,17 @@ public void add_newVoxelNoRegion_updatesVolumes() { assertEquals(2, loc.volume); assertEquals(2, loc.locations.get(Region.DEFAULT).volume); } - + @Test public void add_newVoxelNoRegion_updatesSurfaces() { PottsLocationsMock loc = new PottsLocationsMock(new ArrayList<>()); loc.add(0, 0, 0); loc.add(1, 0, 0); assertEquals(LOCATIONS_SURFACE + 2 * DELTA_SURFACE, loc.surface); - assertEquals(LOCATION_SURFACE + 2 * DELTA_SURFACE, loc.locations.get(Region.DEFAULT).surface); + assertEquals( + LOCATION_SURFACE + 2 * DELTA_SURFACE, loc.locations.get(Region.DEFAULT).surface); } - + @Test public void add_newVoxelNoRegion_updatesHeights() { PottsLocationsMock loc = new PottsLocationsMock(new ArrayList<>()); @@ -337,7 +354,7 @@ public void add_newVoxelNoRegion_updatesHeights() { assertEquals(LOCATIONS_HEIGHT + 2 * DELTA_HEIGHT, loc.height); assertEquals(LOCATION_HEIGHT + 2 * DELTA_HEIGHT, loc.locations.get(Region.DEFAULT).height); } - + @Test public void add_existingVoxelNoRegion_doesNothing() { PottsLocationsMock loc = new PottsLocationsMock(new ArrayList<>()); @@ -347,7 +364,7 @@ public void add_existingVoxelNoRegion_doesNothing() { assertEquals(voxelListForAddRemove, loc.voxels); assertEquals(voxelListForAddRemove, loc.locations.get(Region.DEFAULT).voxels); } - + @Test public void add_newVoxelWithRegion_createsLists() { PottsLocationsMock loc = new PottsLocationsMock(voxelListSingle); @@ -356,7 +373,7 @@ public void add_newVoxelWithRegion_createsLists() { assertEquals(voxelListSingle, loc.locations.get(Region.DEFAULT).voxels); assertEquals(voxelListForRegionAddRemove, loc.locations.get(Region.UNDEFINED).voxels); } - + @Test public void add_newVoxelWithRegion_updatesVolumes() { PottsLocationsMock loc = new PottsLocationsMock(voxelListSingle); @@ -365,7 +382,7 @@ public void add_newVoxelWithRegion_updatesVolumes() { assertEquals(1, loc.locations.get(Region.DEFAULT).volume); assertEquals(1, loc.locations.get(Region.UNDEFINED).volume); } - + @Test public void add_newVoxelWithRegion_updatesSurfaces() { PottsLocationsMock loc = new PottsLocationsMock(voxelListSingle); @@ -374,7 +391,7 @@ public void add_newVoxelWithRegion_updatesSurfaces() { assertEquals(LOCATION_SURFACE, loc.locations.get(Region.DEFAULT).surface); assertEquals(LOCATION_SURFACE + DELTA_SURFACE, loc.locations.get(Region.UNDEFINED).surface); } - + @Test public void add_newVoxelWithRegion_updatesHeights() { PottsLocationsMock loc = new PottsLocationsMock(voxelListSingle); @@ -383,7 +400,7 @@ public void add_newVoxelWithRegion_updatesHeights() { assertEquals(LOCATION_HEIGHT, loc.locations.get(Region.DEFAULT).height); assertEquals(LOCATION_HEIGHT + DELTA_HEIGHT, loc.locations.get(Region.UNDEFINED).height); } - + @Test public void add_existingVoxelWithRegion_doesNothing() { PottsLocationsMock loc = new PottsLocationsMock(voxelListSingle); @@ -392,7 +409,7 @@ public void add_existingVoxelWithRegion_doesNothing() { assertEquals(voxelListSingle, loc.locations.get(Region.DEFAULT).voxels); assertNull(loc.locations.get(Region.UNDEFINED)); } - + @Test public void remove_existingVoxelNoRegion_updatesList() { PottsLocationsMock loc = new PottsLocationsMock(voxelListForAddRemove); @@ -402,7 +419,7 @@ public void remove_existingVoxelNoRegion_updatesList() { assertEquals(voxelsRemoved, loc.voxels); assertEquals(voxelsRemoved, loc.locations.get(Region.DEFAULT).voxels); } - + @Test public void remove_existingVoxelNoRegion_updatesVolumes() { PottsLocationsMock loc = new PottsLocationsMock(voxelListForAddRemove); @@ -410,7 +427,7 @@ public void remove_existingVoxelNoRegion_updatesVolumes() { assertEquals(1, loc.volume); assertEquals(1, loc.locations.get(Region.DEFAULT).volume); } - + @Test public void remove_existingVoxelNoRegion_updatesSurfaces() { PottsLocationsMock loc = new PottsLocationsMock(voxelListForAddRemove); @@ -418,7 +435,7 @@ public void remove_existingVoxelNoRegion_updatesSurfaces() { assertEquals(LOCATIONS_SURFACE - DELTA_SURFACE, loc.surface); assertEquals(LOCATION_SURFACE - DELTA_SURFACE, loc.locations.get(Region.DEFAULT).surface); } - + @Test public void remove_existingVoxelNoRegion_updatesHeights() { PottsLocationsMock loc = new PottsLocationsMock(voxelListForAddRemove); @@ -426,7 +443,7 @@ public void remove_existingVoxelNoRegion_updatesHeights() { assertEquals(LOCATIONS_HEIGHT - DELTA_HEIGHT, loc.height); assertEquals(LOCATION_HEIGHT - DELTA_HEIGHT, loc.locations.get(Region.DEFAULT).height); } - + @Test public void remove_allVoxelsNoRegion_returnsEmptyList() { PottsLocationsMock loc = new PottsLocationsMock(voxelListForAddRemove); @@ -435,7 +452,7 @@ public void remove_allVoxelsNoRegion_returnsEmptyList() { assertEquals(new ArrayList<>(), loc.voxels); assertEquals(new ArrayList<>(), loc.locations.get(Region.DEFAULT).voxels); } - + @Test public void remove_missingVoxelNoRegion_doesNothing() { PottsLocationsMock loc = new PottsLocationsMock(new ArrayList<>()); @@ -443,30 +460,30 @@ public void remove_missingVoxelNoRegion_doesNothing() { assertEquals(new ArrayList<>(), loc.voxels); assertEquals(new ArrayList<>(), loc.locations.get(Region.DEFAULT).voxels); } - + @Test public void remove_existingVoxelWithRegion_updatesList() { PottsLocationsMock loc = new PottsLocationsMock(voxelListForRegionAddRemove); loc.add(Region.UNDEFINED, 0, 0, 0); loc.add(Region.UNDEFINED, 1, 0, 0); - + ArrayList voxelsRemoved = new ArrayList<>(); voxelsRemoved.add(new Voxel(1, 1, 0)); voxelsRemoved.add(new Voxel(1, 0, 0)); - + ArrayList voxelsRemoved1 = new ArrayList<>(); voxelsRemoved1.add(new Voxel(1, 1, 0)); - + ArrayList voxelsRemoved2 = new ArrayList<>(); voxelsRemoved2.add(new Voxel(1, 0, 0)); - + loc.remove(Region.UNDEFINED, 0, 0, 0); - + assertEquals(voxelsRemoved, loc.voxels); assertEquals(voxelsRemoved1, loc.locations.get(Region.DEFAULT).voxels); assertEquals(voxelsRemoved2, loc.locations.get(Region.UNDEFINED).voxels); } - + @Test public void remove_existingVoxelWithRegion_updatesVolumes() { PottsLocationsMock loc = new PottsLocationsMock(voxelListForRegionAddRemove); @@ -477,7 +494,7 @@ public void remove_existingVoxelWithRegion_updatesVolumes() { assertEquals(1, loc.locations.get(Region.DEFAULT).volume); assertEquals(1, loc.locations.get(Region.UNDEFINED).volume); } - + @Test public void remove_existingVoxelWithRegion_updatesSurfaces() { PottsLocationsMock loc = new PottsLocationsMock(voxelListForRegionAddRemove); @@ -486,9 +503,11 @@ public void remove_existingVoxelWithRegion_updatesSurfaces() { loc.remove(Region.UNDEFINED, 0, 0, 0); assertEquals(LOCATIONS_SURFACE + 2 * DELTA_SURFACE - DELTA_SURFACE, loc.surface); assertEquals(LOCATION_SURFACE, loc.locations.get(Region.DEFAULT).surface); - assertEquals(LOCATION_SURFACE + 2 * DELTA_SURFACE - DELTA_SURFACE, loc.locations.get(Region.UNDEFINED).surface); + assertEquals( + LOCATION_SURFACE + 2 * DELTA_SURFACE - DELTA_SURFACE, + loc.locations.get(Region.UNDEFINED).surface); } - + @Test public void remove_existingVoxelWithRegion_updatesHeights() { PottsLocationsMock loc = new PottsLocationsMock(voxelListForRegionAddRemove); @@ -497,34 +516,36 @@ public void remove_existingVoxelWithRegion_updatesHeights() { loc.remove(Region.UNDEFINED, 0, 0, 0); assertEquals(LOCATIONS_HEIGHT + 2 * DELTA_HEIGHT - DELTA_HEIGHT, loc.height); assertEquals(LOCATION_HEIGHT, loc.locations.get(Region.DEFAULT).height); - assertEquals(LOCATION_HEIGHT + 2 * DELTA_HEIGHT - DELTA_HEIGHT, loc.locations.get(Region.UNDEFINED).height); + assertEquals( + LOCATION_HEIGHT + 2 * DELTA_HEIGHT - DELTA_HEIGHT, + loc.locations.get(Region.UNDEFINED).height); } - + @Test public void remove_alternateVoxelWithRegion_doesNothing() { PottsLocationsMock loc = new PottsLocationsMock(voxelListForRegionAddRemove); loc.add(Region.UNDEFINED, 0, 0, 0); loc.add(Region.UNDEFINED, 1, 0, 0); - + ArrayList voxelsRemoved = new ArrayList<>(); voxelsRemoved.add(new Voxel(1, 1, 0)); voxelsRemoved.add(new Voxel(0, 0, 0)); voxelsRemoved.add(new Voxel(1, 0, 0)); - + ArrayList voxelsRemoved1 = new ArrayList<>(); voxelsRemoved1.add(new Voxel(1, 1, 0)); - + ArrayList voxelsRemoved2 = new ArrayList<>(); voxelsRemoved2.add(new Voxel(0, 0, 0)); voxelsRemoved2.add(new Voxel(1, 0, 0)); - + loc.remove(Region.UNDEFINED, 1, 1, 0); - + assertEquals(voxelsRemoved, loc.voxels); assertEquals(voxelsRemoved1, loc.locations.get(Region.DEFAULT).voxels); assertEquals(voxelsRemoved2, loc.locations.get(Region.UNDEFINED).voxels); } - + @Test public void remove_allVoxelsWithRegion_returnsEmptyList() { PottsLocationsMock loc = new PottsLocationsMock(voxelListForRegionAddRemove); @@ -536,7 +557,7 @@ public void remove_allVoxelsWithRegion_returnsEmptyList() { assertEquals(voxelListForRegionAddRemove, loc.locations.get(Region.DEFAULT).voxels); assertEquals(new ArrayList<>(), loc.locations.get(Region.UNDEFINED).voxels); } - + @Test public void remove_missingVoxelWithRegion_doesNothing() { PottsLocationsMock loc = new PottsLocationsMock(voxelListForRegionAddRemove); @@ -545,78 +566,82 @@ public void remove_missingVoxelWithRegion_doesNothing() { assertEquals(voxelListForRegionAddRemove, loc.locations.get(Region.DEFAULT).voxels); assertNull(loc.locations.get(Region.UNDEFINED)); } - + @Test public void assign_existingVoxelSameRegion_doesNothing() { PottsLocationsMock location = new PottsLocationsMock(new ArrayList<>()); ArrayList voxelDefault = new ArrayList<>(); ArrayList voxelAdditional = new ArrayList<>(); - + voxelDefault.add(new Voxel(0, 0, 0)); voxelAdditional.add(new Voxel(1, 0, 0)); - + location.add(Region.DEFAULT, 0, 0, 0); location.add(Region.UNDEFINED, 1, 0, 0); - + location.assign(Region.DEFAULT, new Voxel(0, 0, 0)); assertEquals(voxelDefault, location.locations.get(Region.DEFAULT).voxels); assertEquals(voxelAdditional, location.locations.get(Region.UNDEFINED).voxels); } - + @Test public void assign_existingVoxelDifferentRegion_updatesRegions() { PottsLocationsMock location = new PottsLocationsMock(new ArrayList<>()); ArrayList voxelDefault = new ArrayList<>(); ArrayList voxelAdditional = new ArrayList<>(); ArrayList voxelUpdated = new ArrayList<>(); - + voxelDefault.add(new Voxel(0, 0, 0)); voxelAdditional.add(new Voxel(1, 0, 0)); - + voxelUpdated.addAll(voxelAdditional); voxelUpdated.addAll(voxelDefault); - + location.add(Region.DEFAULT, 0, 0, 0); location.add(Region.UNDEFINED, 1, 0, 0); location.assign(Region.UNDEFINED, new Voxel(0, 0, 0)); - + assertEquals(new ArrayList<>(), location.locations.get(Region.DEFAULT).voxels); assertEquals(voxelUpdated, location.locations.get(Region.UNDEFINED).voxels); } - + @Test public void assign_existingVoxelDifferentRegion_updatesVolumes() { PottsLocationsMock location = new PottsLocationsMock(new ArrayList<>()); location.add(Region.DEFAULT, 0, 0, 0); location.add(Region.UNDEFINED, 1, 0, 0); location.assign(Region.UNDEFINED, new Voxel(0, 0, 0)); - + assertEquals(0, location.locations.get(Region.DEFAULT).volume); assertEquals(2, location.locations.get(Region.UNDEFINED).volume); } - + @Test public void assign_existingVoxelDifferentRegion_updatesSurfaces() { PottsLocationsMock location = new PottsLocationsMock(new ArrayList<>()); location.add(Region.DEFAULT, 0, 0, 0); location.add(Region.UNDEFINED, 1, 0, 0); location.assign(Region.UNDEFINED, new Voxel(0, 0, 0)); - + assertEquals(LOCATION_SURFACE, location.locations.get(Region.DEFAULT).surface); - assertEquals(LOCATION_SURFACE + 2 * DELTA_SURFACE, location.locations.get(Region.UNDEFINED).surface); + assertEquals( + LOCATION_SURFACE + 2 * DELTA_SURFACE, + location.locations.get(Region.UNDEFINED).surface); } - + @Test public void assign_existingVoxelDifferentRegion_updatesHeights() { PottsLocationsMock location = new PottsLocationsMock(new ArrayList<>()); location.add(Region.DEFAULT, 0, 0, 0); location.add(Region.UNDEFINED, 1, 0, 0); location.assign(Region.UNDEFINED, new Voxel(0, 0, 0)); - + assertEquals(LOCATION_HEIGHT, location.locations.get(Region.DEFAULT).height); - assertEquals(LOCATION_HEIGHT + 2 * DELTA_HEIGHT, location.locations.get(Region.UNDEFINED).height); + assertEquals( + LOCATION_HEIGHT + 2 * DELTA_HEIGHT, + location.locations.get(Region.UNDEFINED).height); } - + @Test public void assign_existingVoxelDifferentRegion_updatesCenters() { PottsLocationsMock location = new PottsLocationsMock(new ArrayList<>()); @@ -624,162 +649,165 @@ public void assign_existingVoxelDifferentRegion_updatesCenters() { location.add(Region.DEFAULT, 4, 5, 6); location.add(Region.UNDEFINED, 7, 8, 9); location.assign(Region.UNDEFINED, new Voxel(4, 5, 6)); - + assertEquals(12 / 3., location.cx, EPSILON); assertEquals(15 / 3., location.cy, EPSILON); assertEquals(18 / 3., location.cz, EPSILON); - + assertEquals(1, location.locations.get(Region.DEFAULT).cx, EPSILON); assertEquals(2, location.locations.get(Region.DEFAULT).cy, EPSILON); assertEquals(3, location.locations.get(Region.DEFAULT).cz, EPSILON); - + assertEquals(11 / 2., location.locations.get(Region.UNDEFINED).cx, EPSILON); assertEquals(13 / 2., location.locations.get(Region.UNDEFINED).cy, EPSILON); assertEquals(15 / 2., location.locations.get(Region.UNDEFINED).cz, EPSILON); } - + @Test public void assign_existingVoxelNewRegion_updatesRegions() { PottsLocationsMock location = new PottsLocationsMock(new ArrayList<>()); ArrayList voxelDefault = new ArrayList<>(); - + voxelDefault.add(new Voxel(0, 0, 0)); - + location.add(Region.DEFAULT, 0, 0, 0); location.assign(Region.UNDEFINED, new Voxel(0, 0, 0)); - + assertEquals(new ArrayList<>(), location.locations.get(Region.DEFAULT).voxels); assertEquals(voxelDefault, location.locations.get(Region.UNDEFINED).voxels); } - + @Test public void assign_existingVoxelNewRegion_updatesVolumes() { PottsLocationsMock location = new PottsLocationsMock(new ArrayList<>()); location.add(Region.DEFAULT, 0, 0, 0); location.assign(Region.UNDEFINED, new Voxel(0, 0, 0)); - + assertEquals(0, location.locations.get(Region.DEFAULT).volume); assertEquals(1, location.locations.get(Region.UNDEFINED).volume); } - + @Test public void assign_existingVoxelNewRegion_updatesSurfaces() { PottsLocationsMock location = new PottsLocationsMock(new ArrayList<>()); location.add(Region.DEFAULT, 0, 0, 0); location.assign(Region.UNDEFINED, new Voxel(0, 0, 0)); - + assertEquals(LOCATION_SURFACE, location.locations.get(Region.DEFAULT).surface); - assertEquals(LOCATION_SURFACE + DELTA_SURFACE, location.locations.get(Region.UNDEFINED).surface); + assertEquals( + LOCATION_SURFACE + DELTA_SURFACE, location.locations.get(Region.UNDEFINED).surface); } - + @Test public void assign_existingVoxelNewRegion_updatesHeights() { PottsLocationsMock location = new PottsLocationsMock(new ArrayList<>()); location.add(Region.DEFAULT, 0, 0, 0); location.assign(Region.UNDEFINED, new Voxel(0, 0, 0)); - + assertEquals(LOCATION_HEIGHT, location.locations.get(Region.DEFAULT).height); - assertEquals(LOCATION_HEIGHT + DELTA_HEIGHT, location.locations.get(Region.UNDEFINED).height); + assertEquals( + LOCATION_HEIGHT + DELTA_HEIGHT, location.locations.get(Region.UNDEFINED).height); } - + @Test public void assign_existingVoxelNewRegion_updatesCenters() { PottsLocationsMock location = new PottsLocationsMock(new ArrayList<>()); location.add(Region.DEFAULT, 1, 2, 3); location.add(Region.DEFAULT, 4, 5, 6); location.assign(Region.UNDEFINED, new Voxel(1, 2, 3)); - + assertEquals(5 / 2., location.cx, EPSILON); assertEquals(7 / 2., location.cy, EPSILON); assertEquals(9 / 2., location.cz, EPSILON); - + assertEquals(4, location.locations.get(Region.DEFAULT).cx, EPSILON); assertEquals(5, location.locations.get(Region.DEFAULT).cy, EPSILON); assertEquals(6, location.locations.get(Region.DEFAULT).cz, EPSILON); - + assertEquals(1, location.locations.get(Region.UNDEFINED).cx, EPSILON); assertEquals(2, location.locations.get(Region.UNDEFINED).cy, EPSILON); assertEquals(3, location.locations.get(Region.UNDEFINED).cz, EPSILON); } - + @Test public void assign_missingVoxel_doesNothing() { PottsLocationsMock location = new PottsLocationsMock(new ArrayList<>()); ArrayList voxelDefault = new ArrayList<>(); ArrayList voxelAdditional = new ArrayList<>(); - + voxelDefault.add(new Voxel(0, 0, 0)); voxelAdditional.add(new Voxel(1, 0, 0)); - + location.add(Region.DEFAULT, 0, 0, 0); location.add(Region.UNDEFINED, 1, 0, 0); - + location.assign(Region.DEFAULT, new Voxel(2, 0, 0)); assertEquals(voxelDefault, location.locations.get(Region.DEFAULT).voxels); assertEquals(voxelAdditional, location.locations.get(Region.UNDEFINED).voxels); } - + @Test public void distribute_defaultRegion_doesNothing() { PottsLocationsMock loc = new PottsLocationsMock(new ArrayList<>()); - + for (Voxel v : voxelListForMultipleRegions) { loc.add(Region.UNDEFINED, v.x, v.y, v.z); } - + int target = randomIntBetween(1, voxelListForMultipleRegions.size()); loc.distribute(Region.DEFAULT, target, randomDoubleZero); - + ArrayList locVoxels = new ArrayList<>(voxelListForMultipleRegions); ArrayList defaultVoxels = new ArrayList<>(loc.locations.get(Region.DEFAULT).voxels); ArrayList regionVoxels = new ArrayList<>(loc.locations.get(Region.UNDEFINED).voxels); - + locVoxels.sort(VOXEL_COMPARATOR); regionVoxels.sort(VOXEL_COMPARATOR); - + assertEquals(locVoxels, regionVoxels); assertEquals(0, defaultVoxels.size()); } - + @Test public void clear_hasVoxels_updatesArray() { PottsLocationsMock location = new PottsLocationsMock(voxelListForAddRemove); - int[][][] ids = new int[][][] { { { 1, 0, 0 }, { 1, 0, 0 } } }; - int[][][] regions = new int[][][] { { { -1, 0, 0 }, { -2, 0, 0 } } }; + int[][][] ids = new int[][][] {{{1, 0, 0}, {1, 0, 0}}}; + int[][][] regions = new int[][][] {{{-1, 0, 0}, {-2, 0, 0}}}; location.clear(ids, regions); - - assertArrayEquals(new int[] { 0, 0, 0 }, ids[0][0]); - assertArrayEquals(new int[] { 0, 0, 0 }, ids[0][1]); - assertArrayEquals(new int[] { 0, 0, 0 }, regions[0][0]); - assertArrayEquals(new int[] { 0, 0, 0 }, regions[0][1]); + + assertArrayEquals(new int[] {0, 0, 0}, ids[0][0]); + assertArrayEquals(new int[] {0, 0, 0}, ids[0][1]); + assertArrayEquals(new int[] {0, 0, 0}, regions[0][0]); + assertArrayEquals(new int[] {0, 0, 0}, regions[0][1]); } - + @Test public void clear_hasVoxels_updatesLists() { PottsLocationsMock location = new PottsLocationsMock(voxelListForAddRemove); location.clear(new int[1][3][3], new int[1][3][3]); assertEquals(0, location.locations.size()); } - + @Test public void update_validRegion_updatesArrays() { - int[][][] ids = new int[][][] { { { 0, 1, 2 } } }; - int[][][] regions = new int[][][] { { { 0, 0, 0 } } }; - + int[][][] ids = new int[][][] {{{0, 1, 2}}}; + int[][][] regions = new int[][][] {{{0, 0, 0}}}; + ArrayList voxels = new ArrayList<>(); voxels.add(new Voxel(0, 1, 0)); PottsLocationsMock loc = new PottsLocationsMock(voxels); loc.add(Region.UNDEFINED, 0, 0, 0); - + loc.update(3, ids, regions); - assertArrayEquals(new int[] { 3, 3, 2 }, ids[0][0]); - assertArrayEquals(new int[] { Region.UNDEFINED.ordinal(), Region.DEFAULT.ordinal(), 0 }, regions[0][0]); + assertArrayEquals(new int[] {3, 3, 2}, ids[0][0]); + assertArrayEquals( + new int[] {Region.UNDEFINED.ordinal(), Region.DEFAULT.ordinal(), 0}, regions[0][0]); } - + @Test public void convert_createsContainer() { int locationID = randomIntBetween(1, 10); - + ArrayList voxels = new ArrayList<>(); int n = randomIntBetween(1, 10); for (int i = 0; i < 2 * n; i++) { @@ -787,9 +815,9 @@ public void convert_createsContainer() { voxels.add(new Voxel(i, j, 0)); } } - + PottsLocationsMock location = new PottsLocationsMock(voxels); - + EnumMap> regions = new EnumMap<>(Region.class); regions.put(Region.DEFAULT, new ArrayList<>()); regions.put(Region.NUCLEUS, new ArrayList<>()); @@ -803,15 +831,15 @@ public void convert_createsContainer() { } } } - + PottsLocationContainer container = (PottsLocationContainer) location.convert(locationID); - + assertEquals(locationID, container.id); assertEquals(new Voxel(n, n, 0), container.center); assertEquals(voxels, container.allVoxels); assertEquals(regions, container.regions); } - + @Test public void getCentroid_validRegion_returnsArray() { ArrayList voxels = new ArrayList<>(); @@ -820,20 +848,20 @@ public void getCentroid_validRegion_returnsArray() { voxels.add(new Voxel(2, 2, 2)); voxels.add(new Voxel(2, 3, 3)); PottsLocationsMock loc = new PottsLocationsMock(voxels); - + double[] centroid = loc.getCentroid(Region.DEFAULT); - + assertEquals(5 / 4., centroid[0], EPSILON); assertEquals(7 / 4., centroid[1], EPSILON); assertEquals(8 / 4., centroid[2], EPSILON); } - + @Test public void getCentroid_invalidRegion_returnsNull() { PottsLocationsMock loc = new PottsLocationsMock(new ArrayList<>()); assertNull(loc.getCentroid(null)); } - + @Test public void getCentroid_multipleRegions_returnsValue() { PottsLocationsMock loc = new PottsLocationsMock(new ArrayList<>()); @@ -841,86 +869,95 @@ public void getCentroid_multipleRegions_returnsValue() { loc.add(Region.UNDEFINED, 1, 1, 2); loc.add(Region.UNDEFINED, 2, 2, 2); loc.add(Region.UNDEFINED, 2, 3, 3); - + double[] centroidDefault = loc.getCentroid(Region.DEFAULT); - + assertEquals(0, centroidDefault[0], EPSILON); assertEquals(1, centroidDefault[1], EPSILON); assertEquals(1, centroidDefault[2], EPSILON); - + double[] centroidUndefined = loc.getCentroid(Region.UNDEFINED); - + assertEquals(5 / 3., centroidUndefined[0], EPSILON); assertEquals(6 / 3., centroidUndefined[1], EPSILON); assertEquals(7 / 3., centroidUndefined[2], EPSILON); } - + @Test public void separateVoxels_validListsNoRegions_updatesLists() { PottsLocationsMock loc = new PottsLocationsMock(voxelListAB); - PottsLocations split = (PottsLocations) loc.separateVoxels(voxelListA, voxelListB, randomDoubleZero); - + PottsLocations split = + (PottsLocations) loc.separateVoxels(voxelListA, voxelListB, randomDoubleZero); + ArrayList locVoxels = new ArrayList<>(voxelListA); ArrayList splitVoxels = new ArrayList<>(voxelListB); - + locVoxels.sort(VOXEL_COMPARATOR); loc.voxels.sort(VOXEL_COMPARATOR); splitVoxels.sort(VOXEL_COMPARATOR); split.voxels.sort(VOXEL_COMPARATOR); - + assertEquals(locVoxels, loc.voxels); assertEquals(splitVoxels, split.voxels); } - + @Test public void separateVoxels_validListsNoRegions_updatesVolumes() { PottsLocationsMock loc = new PottsLocationsMock(voxelListAB); - PottsLocations split = (PottsLocations) loc.separateVoxels(voxelListA, voxelListB, randomDoubleZero); + PottsLocations split = + (PottsLocations) loc.separateVoxels(voxelListA, voxelListB, randomDoubleZero); assertEquals(4, loc.volume); assertEquals(3, split.volume); } - + @Test public void separateVoxels_validListsNoRegions_updatesSurfaces() { PottsLocationsMock loc = new PottsLocationsMock(voxelListAB); - PottsLocations split = (PottsLocations) loc.separateVoxels(voxelListA, voxelListB, randomDoubleZero); + PottsLocations split = + (PottsLocations) loc.separateVoxels(voxelListA, voxelListB, randomDoubleZero); assertEquals(LOCATIONS_SURFACE - 3 * DELTA_SURFACE, loc.surface); assertEquals(LOCATIONS_SURFACE, split.surface); } - + @Test public void separateVoxels_validListsWithRegions_updatesLists() { PottsLocationsMock loc = new PottsLocationsMock(voxelListForMultipleRegionsA); - + loc.add(Region.UNDEFINED, 1, 2, 0); loc.add(Region.UNDEFINED, 2, 0, 0); loc.add(Region.UNDEFINED, 2, 1, 0); loc.add(Region.UNDEFINED, 2, 2, 0); - - PottsLocations split = (PottsLocations) loc.separateVoxels(voxelListForMultipleRegionsA, - voxelListForMultipleRegionsB, randomDoubleZero); - + + PottsLocations split = + (PottsLocations) + loc.separateVoxels( + voxelListForMultipleRegionsA, + voxelListForMultipleRegionsB, + randomDoubleZero); + ArrayList locVoxels = new ArrayList<>(voxelListForMultipleRegionsA); ArrayList splitVoxels = new ArrayList<>(voxelListForMultipleRegionsB); - - ArrayList locRegionVoxels = new ArrayList<>(loc.locations.get(Region.DEFAULT).voxels); + + ArrayList locRegionVoxels = + new ArrayList<>(loc.locations.get(Region.DEFAULT).voxels); locRegionVoxels.addAll(loc.locations.get(Region.UNDEFINED).voxels); - - ArrayList splitRegionVoxels = new ArrayList<>(split.locations.get(Region.DEFAULT).voxels); + + ArrayList splitRegionVoxels = + new ArrayList<>(split.locations.get(Region.DEFAULT).voxels); splitRegionVoxels.addAll(split.locations.get(Region.UNDEFINED).voxels); - + locVoxels.sort(VOXEL_COMPARATOR); loc.voxels.sort(VOXEL_COMPARATOR); locRegionVoxels.sort(VOXEL_COMPARATOR); splitVoxels.sort(VOXEL_COMPARATOR); split.voxels.sort(VOXEL_COMPARATOR); splitRegionVoxels.sort(VOXEL_COMPARATOR); - + assertEquals(locVoxels, loc.voxels); assertEquals(splitVoxels, split.voxels); assertEquals(locVoxels, locRegionVoxels); assertEquals(splitVoxels, splitRegionVoxels); - + assertEquals(2, loc.locations.get(Region.DEFAULT).voxels.size()); assertEquals(2, loc.locations.get(Region.UNDEFINED).voxels.size()); assertEquals(2, split.locations.get(Region.DEFAULT).voxels.size()); diff --git a/test/arcade/potts/env/location/VoxelTest.java b/test/arcade/potts/env/location/VoxelTest.java index 389aea098..9e2f25b4a 100644 --- a/test/arcade/potts/env/location/VoxelTest.java +++ b/test/arcade/potts/env/location/VoxelTest.java @@ -1,7 +1,7 @@ package arcade.potts.env.location; -import org.junit.Test; -import static org.junit.Assert.*; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; import static arcade.core.ARCADETestUtilities.*; public class VoxelTest { @@ -13,7 +13,7 @@ public void hashCode_validObject_returnCode() { Voxel voxel = new Voxel(x, y, z); assertEquals(x + y * (int) Math.pow(2, 8) + z * (int) Math.pow(2, 16), voxel.hashCode()); } - + @Test public void equals_validEqualObject_returnsTrue() { int x = randomIntBetween(0, 100); @@ -24,7 +24,7 @@ public void equals_validEqualObject_returnsTrue() { assertEquals(voxel1, voxel2); assertEquals(voxel2, voxel1); } - + @Test public void equals_validUnequalObject_returnsFalse() { int x = randomIntBetween(0, 100); @@ -35,7 +35,7 @@ public void equals_validUnequalObject_returnsFalse() { assertNotEquals(voxel1, voxel2); assertNotEquals(voxel2, voxel1); } - + @Test public void equals_invalidObject_returnsFalse() { int x = randomIntBetween(0, 100); @@ -45,7 +45,7 @@ public void equals_invalidObject_returnsFalse() { Object object = x; assertNotEquals(voxel, object); } - + @Test public void toString_validObject_returnsValue() { int x = randomIntBetween(0, 100); diff --git a/test/arcade/potts/sim/Potts2DTest.java b/test/arcade/potts/sim/Potts2DTest.java index 6e30d11a9..e17010713 100644 --- a/test/arcade/potts/sim/Potts2DTest.java +++ b/test/arcade/potts/sim/Potts2DTest.java @@ -1,63 +1,66 @@ package arcade.potts.sim; import java.util.HashSet; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import arcade.potts.sim.hamiltonian.AdhesionHamiltonian2D; import arcade.potts.sim.hamiltonian.Hamiltonian; import arcade.potts.sim.hamiltonian.PersistenceHamiltonian; import arcade.potts.sim.hamiltonian.SurfaceHamiltonian2D; import arcade.potts.sim.hamiltonian.VolumeHamiltonian; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static arcade.potts.sim.PottsTest.*; import static arcade.potts.util.PottsEnums.Region; import static arcade.potts.util.PottsEnums.Term; public class Potts2DTest { static Potts2D potts; - - private static final double[][] AREA_MCS = new double[][] { - { 1, 0.6842640 }, { 9, 1.2501410 }, { 25, 1.8321450 }, - { 45, 2.3367460 }, { 69, 2.8135120 }, { 109, 3.4554160 }, - { 145, 3.9405750 }, { 193, 4.5044520 }, { 249, 5.0824390 }, - { 305, 5.6006040 }, { 373, 6.1715790 }, { 437, 6.6647040 }, - { 517, 7.2345420 }, { 609, 7.8396430 }, { 697, 8.3784780 }, - { 793, 8.9301870 }, { 889, 9.4506170 }, { 1005, 10.044628 }, - { 1125, 10.625359 }, { 1245, 11.176999 }, { 1369, 11.720781 }, - { 1513, 12.323346 }, { 1649, 12.867588 }, { 1789, 13.405737 }, - { 1941, 13.967562 }, { 2109, 14.564444 }, { 2285, 15.165712 }, - { 2449, 15.706243 }, { 2617, 16.242202 }, { 2809, 16.834856 }, - }; - - @BeforeClass + + private static final double[][] AREA_MCS = + new double[][] { + {1, 0.6842640}, {9, 1.2501410}, {25, 1.8321450}, + {45, 2.3367460}, {69, 2.8135120}, {109, 3.4554160}, + {145, 3.9405750}, {193, 4.5044520}, {249, 5.0824390}, + {305, 5.6006040}, {373, 6.1715790}, {437, 6.6647040}, + {517, 7.2345420}, {609, 7.8396430}, {697, 8.3784780}, + {793, 8.9301870}, {889, 9.4506170}, {1005, 10.044628}, + {1125, 10.625359}, {1245, 11.176999}, {1369, 11.720781}, + {1513, 12.323346}, {1649, 12.867588}, {1789, 13.405737}, + {1941, 13.967562}, {2109, 14.564444}, {2285, 15.165712}, + {2449, 15.706243}, {2617, 16.242202}, {2809, 16.834856}, + }; + + @BeforeAll public static void setupGrid() { PottsSeries series = makeSeries(); potts = new Potts2D(series); - - potts.ids = new int[][][] { - { - { 0, 0, 0, 0, 0, 0 }, - { 0, 1, 1, 3, 3, 0 }, - { 0, 1, 1, 3, 3, 0 }, - { 0, 2, 2, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - } - }; - + + potts.ids = + new int[][][] { + { + {0, 0, 0, 0, 0, 0}, + {0, 1, 1, 3, 3, 0}, + {0, 1, 1, 3, 3, 0}, + {0, 2, 2, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + } + }; + int d = Region.DEFAULT.ordinal(); int n = Region.NUCLEUS.ordinal(); - - potts.regions = new int[][][] { - { - { 0, 0, 0, 0, 0, 0 }, - { 0, d, d, d, 0, 0 }, - { 0, 0, n, n, 0, 0 }, - { 0, d, d, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - } - }; + + potts.regions = + new int[][][] { + { + {0, 0, 0, 0, 0, 0}, + {0, d, d, d, 0, 0}, + {0, 0, n, n, 0, 0}, + {0, d, d, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + } + }; } - + private static boolean[][][] duplicate(boolean[][][] array) { boolean[][][] duplicated = new boolean[1][3][3]; for (int i = 0; i < 3; i++) { @@ -65,7 +68,7 @@ private static boolean[][][] duplicate(boolean[][][] array) { } return duplicated; } - + private static boolean[][][] combine(boolean[][][] base, int[] combo, int[][] links) { boolean[][][] array = duplicate(base); for (int i : combo) { @@ -73,183 +76,219 @@ private static boolean[][][] combine(boolean[][][] base, int[] combo, int[][] li } return array; } - + private static boolean[][][] rotate(boolean[][][] array, int rotations) { boolean[][][] rotated = duplicate(array); - + for (int rotation = 0; rotation < rotations; rotation++) { for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { rotated[0][i][j] = array[0][j][2 - i]; } } - + array = duplicate(rotated); } - + return rotated; } - + @Test public void getHamiltonian_validTerm_instantiatesObject() { PottsSeries series = makeSeries(1, 1, 1, 1, 1); Potts2D potts2D = new Potts2D(series); - + Hamiltonian h; - + h = potts2D.getHamiltonian(Term.ADHESION, series); assertTrue(h instanceof AdhesionHamiltonian2D); - + h = potts2D.getHamiltonian(Term.VOLUME, series); assertTrue(h instanceof VolumeHamiltonian); - + h = potts2D.getHamiltonian(Term.SURFACE, series); assertTrue(h instanceof SurfaceHamiltonian2D); - + h = potts2D.getHamiltonian(Term.PERSISTENCE, series); assertTrue(h instanceof PersistenceHamiltonian); } - + @Test public void getHamiltonian_invalidTerm_returnsNull() { PottsSeries series = makeSeries(1, 1, 1, 1, 1); Potts2D potts2D = new Potts2D(series); - + Hamiltonian h; - + h = potts2D.getHamiltonian(Term.SUBSTRATE, series); assertNull(h); - + h = potts2D.getHamiltonian(Term.HEIGHT, series); assertNull(h); - + h = potts2D.getHamiltonian(Term.JUNCTION, series); assertNull(h); - + h = potts2D.getHamiltonian(Term.UNDEFINED, series); assertNull(h); } - + @Test public void getNeighborhood_givenID_createsArray() { boolean[][][] array1 = potts.getNeighborhood(1, 2, 2, 0); - assertArrayEquals(new boolean[] { true, true, false }, array1[0][0]); - assertArrayEquals(new boolean[] { true, true, false }, array1[0][1]); - assertArrayEquals(new boolean[] { false, false, false }, array1[0][2]); - + assertArrayEquals(new boolean[] {true, true, false}, array1[0][0]); + assertArrayEquals(new boolean[] {true, true, false}, array1[0][1]); + assertArrayEquals(new boolean[] {false, false, false}, array1[0][2]); + boolean[][][] array2 = potts.getNeighborhood(2, 2, 2, 0); - assertArrayEquals(new boolean[] { false, false, false }, array2[0][0]); - assertArrayEquals(new boolean[] { false, false, false }, array2[0][1]); - assertArrayEquals(new boolean[] { true, true, false }, array2[0][2]); - + assertArrayEquals(new boolean[] {false, false, false}, array2[0][0]); + assertArrayEquals(new boolean[] {false, false, false}, array2[0][1]); + assertArrayEquals(new boolean[] {true, true, false}, array2[0][2]); + boolean[][][] array3 = potts.getNeighborhood(3, 2, 2, 0); - assertArrayEquals(new boolean[] { false, false, true }, array3[0][0]); - assertArrayEquals(new boolean[] { false, false, true }, array3[0][1]); - assertArrayEquals(new boolean[] { false, false, false }, array3[0][2]); + assertArrayEquals(new boolean[] {false, false, true}, array3[0][0]); + assertArrayEquals(new boolean[] {false, false, true}, array3[0][1]); + assertArrayEquals(new boolean[] {false, false, false}, array3[0][2]); } - + @Test public void getNeighborhood_givenRegion_createsArray() { boolean[][][] array1 = potts.getNeighborhood(1, Region.DEFAULT.ordinal(), 2, 2, 0); - assertArrayEquals(new boolean[] { true, true, false }, array1[0][0]); - assertArrayEquals(new boolean[] { false, false, false }, array1[0][1]); - assertArrayEquals(new boolean[] { false, false, false }, array1[0][2]); - + assertArrayEquals(new boolean[] {true, true, false}, array1[0][0]); + assertArrayEquals(new boolean[] {false, false, false}, array1[0][1]); + assertArrayEquals(new boolean[] {false, false, false}, array1[0][2]); + boolean[][][] array2 = potts.getNeighborhood(1, Region.NUCLEUS.ordinal(), 2, 2, 0); - assertArrayEquals(new boolean[] { false, false, false }, array2[0][0]); - assertArrayEquals(new boolean[] { false, true, false }, array2[0][1]); - assertArrayEquals(new boolean[] { false, false, false }, array2[0][2]); + assertArrayEquals(new boolean[] {false, false, false}, array2[0][0]); + assertArrayEquals(new boolean[] {false, true, false}, array2[0][1]); + assertArrayEquals(new boolean[] {false, false, false}, array2[0][2]); } - + private HashSet checkUniqueID(Potts2D potts2D, int[][] ids) { - potts2D.ids = new int[][][] { ids }; + potts2D.ids = new int[][][] {ids}; return potts2D.getUniqueIDs(1, 1, 0); } - + @Test public void getUniqueIDs_validVoxel_returnsList() { PottsSeries series = makeSeries(); Potts2D pottsMock = new Potts2D(series); HashSet unique = new HashSet<>(); - + unique.add(1); - assertEquals(unique, checkUniqueID(pottsMock, new int[][] { - { 0, 1, 0 }, - { 0, 0, 0 }, - { 0, 0, 0 } })); - + assertEquals( + unique, + checkUniqueID( + pottsMock, + new int[][] { + {0, 1, 0}, + {0, 0, 0}, + {0, 0, 0} + })); + unique.clear(); unique.add(0); - assertEquals(unique, checkUniqueID(pottsMock, new int[][] { - { 0, 1, 0 }, - { 0, 1, 0 }, - { 0, 0, 0 } })); - + assertEquals( + unique, + checkUniqueID( + pottsMock, + new int[][] { + {0, 1, 0}, + {0, 1, 0}, + {0, 0, 0} + })); + unique.clear(); - assertEquals(unique, checkUniqueID(pottsMock, new int[][] { - { 1, 0, 1 }, - { 0, 0, 0 }, - { 1, 0, 1 } })); + assertEquals( + unique, + checkUniqueID( + pottsMock, + new int[][] { + {1, 0, 1}, + {0, 0, 0}, + {1, 0, 1} + })); } - + private HashSet checkUniqueRegion(Potts2D potts2D, int[][] ids, int[][] regions) { - potts2D.ids = new int[][][] { ids }; - potts2D.regions = new int[][][] { regions }; + potts2D.ids = new int[][][] {ids}; + potts2D.regions = new int[][][] {regions}; return potts2D.getUniqueRegions(1, 1, 0); } - + @Test public void getUniqueRegions_validVoxel_returnsList() { PottsSeries series = makeSeries(); Potts2D pottsMock = new Potts2D(series); HashSet unique = new HashSet<>(); - - assertEquals(unique, checkUniqueRegion(pottsMock, - new int[][] { - { 0, 0, 0 }, - { 0, 1, 0 }, - { 0, 0, 0 } }, - new int[][] { - { 0, 0, 0 }, - { 0, -1, 0 }, - { 0, 0, 0 } })); - - assertEquals(unique, checkUniqueRegion(pottsMock, - new int[][] { - { 1, 1, 1 }, - { 1, 1, 1 }, - { 1, 1, 1 } }, - new int[][] { - { -2, -1, -2 }, - { -1, -1, -1 }, - { -2, -1, -2 } })); - + + assertEquals( + unique, + checkUniqueRegion( + pottsMock, + new int[][] { + {0, 0, 0}, + {0, 1, 0}, + {0, 0, 0} + }, + new int[][] { + {0, 0, 0}, + {0, -1, 0}, + {0, 0, 0} + })); + + assertEquals( + unique, + checkUniqueRegion( + pottsMock, + new int[][] { + {1, 1, 1}, + {1, 1, 1}, + {1, 1, 1} + }, + new int[][] { + {-2, -1, -2}, + {-1, -1, -1}, + {-2, -1, -2} + })); + unique.add(-2); - assertEquals(unique, checkUniqueRegion(pottsMock, - new int[][] { - { 0, 1, 0 }, - { 1, 1, 2 }, - { 0, 2, 0 } }, - new int[][] { - { 0, -1, 0 }, - { -2, -1, -4 }, - { 0, -3, 0 } })); + assertEquals( + unique, + checkUniqueRegion( + pottsMock, + new int[][] { + {0, 1, 0}, + {1, 1, 2}, + {0, 2, 0} + }, + new int[][] { + {0, -1, 0}, + {-2, -1, -4}, + {0, -3, 0} + })); } - + /* ------------------------------------------------------------------------- * CONNECTIVITY FOR ZERO (0) NEIGHBORS * * If there are zero neighbors, then the voxel is never connected. ------------------------------------------------------------------------- */ - + @Test public void getConnectivity_zeroNeighbors_returnsFalse() { - assertFalse(potts.getConnectivity(new boolean[][][] { { - { false, false, false }, - { false, true, false }, - { false, false, false } } }, false)); + assertFalse( + potts.getConnectivity( + new boolean[][][] { + { + {false, false, false}, + {false, true, false}, + {false, false, false} + } + }, + false)); } - + /* ------------------------------------------------------------------------- * CONNECTIVITY FOR ONE (1) NEIGHBOR * @@ -257,13 +296,16 @@ public void getConnectivity_zeroNeighbors_returnsFalse() { * * If there is only one neighbor, the voxel is always connected. ------------------------------------------------------------------------- */ - - private static final boolean[][][] BASE_ONE_NEIGHBOR = new boolean[][][] { { - { false, true, false }, - { false, true, false }, - { false, false, false } - } }; - + + private static final boolean[][][] BASE_ONE_NEIGHBOR = + new boolean[][][] { + { + {false, true, false}, + {false, true, false}, + {false, false, false} + } + }; + @Test public void getConnectivity_oneNeighbor_returnsTrue() { for (int rotation = 0; rotation < 4; rotation++) { @@ -271,7 +313,7 @@ public void getConnectivity_oneNeighbor_returnsTrue() { assertTrue(potts.getConnectivity(array, false)); } } - + /* ------------------------------------------------------------------------- * CONNECTIVITY FOR TWO (2) NEIGHBORS * @@ -282,28 +324,35 @@ public void getConnectivity_oneNeighbor_returnsTrue() { * If there are two adjacent neighbors, the voxel is connected if there is * a link in the shared corner. ------------------------------------------------------------------------- */ - - private static final boolean[][][] BASE_TWO_NEIGHBORS_OPPOSITE = new boolean[][][] { { - { false, true, false }, - { false, true, false }, - { false, true, false } - } }; - - private static final boolean[][][] BASE_TWO_NEIGHBORS_ADJACENT = new boolean[][][] { { - { false, true, false }, - { true, true, false }, - { false, false, false } - } }; - - private static final int[][] LINKS_TWO_NEIGHBORS_ADJACENT = new int[][] { - { 0 }, // X - { 0 }, // Y - }; - - private static final int[][] COMBOS_TWO_NEIGHBORS_ADJACENT_ZERO_LINKS = new int[][] { { } }; - - private static final int[][] COMBOS_TWO_NEIGHBORS_ADJACENT_ONE_LINK = new int[][] { { 0 } }; - + + private static final boolean[][][] BASE_TWO_NEIGHBORS_OPPOSITE = + new boolean[][][] { + { + {false, true, false}, + {false, true, false}, + {false, true, false} + } + }; + + private static final boolean[][][] BASE_TWO_NEIGHBORS_ADJACENT = + new boolean[][][] { + { + {false, true, false}, + {true, true, false}, + {false, false, false} + } + }; + + private static final int[][] LINKS_TWO_NEIGHBORS_ADJACENT = + new int[][] { + {0}, // X + {0}, // Y + }; + + private static final int[][] COMBOS_TWO_NEIGHBORS_ADJACENT_ZERO_LINKS = new int[][] {{}}; + + private static final int[][] COMBOS_TWO_NEIGHBORS_ADJACENT_ONE_LINK = new int[][] {{0}}; + @Test public void getConnectivity_twoNeighborsOpposite_returnsFalse() { for (int rotation = 0; rotation < 2; rotation++) { @@ -311,29 +360,39 @@ public void getConnectivity_twoNeighborsOpposite_returnsFalse() { assertFalse(potts.getConnectivity(array, false)); } } - + @Test public void getConnectivity_twoNeighborsAdjacentZeroLink_returnsFalse() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_TWO_NEIGHBORS_ADJACENT_ZERO_LINKS) { - boolean[][][] array = rotate(combine(BASE_TWO_NEIGHBORS_ADJACENT, - combo, LINKS_TWO_NEIGHBORS_ADJACENT), rotation); + boolean[][][] array = + rotate( + combine( + BASE_TWO_NEIGHBORS_ADJACENT, + combo, + LINKS_TWO_NEIGHBORS_ADJACENT), + rotation); assertFalse(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_twoNeighborsAdjacentOneLink_returnsTrue() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_TWO_NEIGHBORS_ADJACENT_ONE_LINK) { - boolean[][][] array = rotate(combine(BASE_TWO_NEIGHBORS_ADJACENT, - combo, LINKS_TWO_NEIGHBORS_ADJACENT), rotation); + boolean[][][] array = + rotate( + combine( + BASE_TWO_NEIGHBORS_ADJACENT, + combo, + LINKS_TWO_NEIGHBORS_ADJACENT), + rotation); assertTrue(potts.getConnectivity(array, false)); } } } - + /* ------------------------------------------------------------------------- * CONNECTIVITY FOR THREE (3) NEIGHBORS * @@ -345,62 +404,73 @@ public void getConnectivity_twoNeighborsAdjacentOneLink_returnsTrue() { * 1 link | 2 combos | unconnected * 2 links | 1 combo | connected ------------------------------------------------------------------------- */ - - private static final boolean[][][] BASE_THREE_NEIGHBORS = new boolean[][][] { { - { false, true, false }, - { true, true, false }, - { false, true, false } - } }; - - private static final int[][] LINKS_THREE_NEIGHBORS = new int[][] { - { 0, 2 }, // X - { 0, 0 }, // Y - }; - - private static final int[][] COMBOS_THREE_NEIGHBORS_ZERO_LINKS = new int[][] { { } }; - - private static final int[][] COMBOS_THREE_NEIGHBORS_ONE_LINK = new int[][] { - { 0 }, - { 1 }, - }; - - private static final int[][] COMBOS_THREE_NEIGHBORS_TWO_LINKS = new int[][] { - { 0, 1 }, - }; - + + private static final boolean[][][] BASE_THREE_NEIGHBORS = + new boolean[][][] { + { + {false, true, false}, + {true, true, false}, + {false, true, false} + } + }; + + private static final int[][] LINKS_THREE_NEIGHBORS = + new int[][] { + {0, 2}, // X + {0, 0}, // Y + }; + + private static final int[][] COMBOS_THREE_NEIGHBORS_ZERO_LINKS = new int[][] {{}}; + + private static final int[][] COMBOS_THREE_NEIGHBORS_ONE_LINK = + new int[][] { + {0}, {1}, + }; + + private static final int[][] COMBOS_THREE_NEIGHBORS_TWO_LINKS = + new int[][] { + {0, 1}, + }; + @Test public void getConnectivity_threeNeighborsZeroLinks_returnsFalse() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_THREE_NEIGHBORS_ZERO_LINKS) { - boolean[][][] array = rotate(combine(BASE_THREE_NEIGHBORS, - combo, LINKS_THREE_NEIGHBORS), rotation); + boolean[][][] array = + rotate( + combine(BASE_THREE_NEIGHBORS, combo, LINKS_THREE_NEIGHBORS), + rotation); assertFalse(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_threeNeighborsOneLink_returnsFalse() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_THREE_NEIGHBORS_ONE_LINK) { - boolean[][][] array = rotate(combine(BASE_THREE_NEIGHBORS, - combo, LINKS_THREE_NEIGHBORS), rotation); + boolean[][][] array = + rotate( + combine(BASE_THREE_NEIGHBORS, combo, LINKS_THREE_NEIGHBORS), + rotation); assertFalse(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_threeNeighborsPlaneXYTwoLinks_returnsTrue() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_THREE_NEIGHBORS_TWO_LINKS) { - boolean[][][] array = rotate(combine(BASE_THREE_NEIGHBORS, - combo, LINKS_THREE_NEIGHBORS), rotation); + boolean[][][] array = + rotate( + combine(BASE_THREE_NEIGHBORS, combo, LINKS_THREE_NEIGHBORS), + rotation); assertTrue(potts.getConnectivity(array, false)); } } } - + /* ------------------------------------------------------------------------- * CONNECTIVITY FOR FOUR (4) NEIGHBORS * @@ -408,20 +478,32 @@ public void getConnectivity_threeNeighborsPlaneXYTwoLinks_returnsTrue() { * depends on the ID of the voxel. Only ID = 0 is considered connected; * all other ID values are unconnected. ------------------------------------------------------------------------- */ - + @Test public void getConnectivity_fourNeighborsNonZeroID_returnsFalse() { - assertFalse(potts.getConnectivity(new boolean[][][] { { - { false, true, false }, - { true, true, true }, - { false, true, false } } }, false)); + assertFalse( + potts.getConnectivity( + new boolean[][][] { + { + {false, true, false}, + {true, true, true}, + {false, true, false} + } + }, + false)); } - + @Test public void getConnectivity_fourNeighborsZeroID_returnsTrue() { - assertTrue(potts.getConnectivity(new boolean[][][] { { - { false, true, false }, - { true, true, true }, - { false, true, false } } }, true)); + assertTrue( + potts.getConnectivity( + new boolean[][][] { + { + {false, true, false}, + {true, true, true}, + {false, true, false} + } + }, + true)); } } diff --git a/test/arcade/potts/sim/Potts3DTest.java b/test/arcade/potts/sim/Potts3DTest.java index 8a319fc2b..1cda3803e 100644 --- a/test/arcade/potts/sim/Potts3DTest.java +++ b/test/arcade/potts/sim/Potts3DTest.java @@ -1,8 +1,8 @@ package arcade.potts.sim; import java.util.HashSet; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import arcade.potts.sim.hamiltonian.AdhesionHamiltonian3D; import arcade.potts.sim.hamiltonian.Hamiltonian; import arcade.potts.sim.hamiltonian.HeightHamiltonian; @@ -11,120 +11,127 @@ import arcade.potts.sim.hamiltonian.SubstrateHamiltonian; import arcade.potts.sim.hamiltonian.SurfaceHamiltonian3D; import arcade.potts.sim.hamiltonian.VolumeHamiltonian; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static arcade.potts.sim.PottsTest.*; import static arcade.potts.util.PottsEnums.Region; import static arcade.potts.util.PottsEnums.Term; public class Potts3DTest { static Potts3D potts; - - private static final double[][] VOLUME_MCS = new double[][] { - { 19669, 13, 4.441502 }, { 1586, 2, 1.000000 }, { 12688, 16, 4.703909 }, - { 17430, 14, 4.553762 }, { 11055, 11, 3.770773 }, { 14224, 16, 4.771082 }, - { 20250, 18, 5.307441 }, { 3730, 10, 3.109355 }, { 33286, 22, 6.269841 }, - { 2185, 5, 1.926825 }, { 8364, 12, 3.817978 }, { 36638, 14, 4.993200 }, - { 34938, 18, 5.674056 }, { 73034, 26, 7.519614 }, { 9779, 11, 3.712390 }, - { 4539, 3, 1.555123 }, { 14694, 6, 2.784049 }, { 1, 1, 1.000000 }, - { 32997, 17, 5.466454 }, { 45700, 20, 6.197381 }, { 16872, 8, 3.336015 }, - { 3578, 2, 1.143097 }, { 6223, 7, 2.714233 }, { 3050, 10, 3.028743 }, - { 10468, 4, 2.095892 }, { 16643, 11, 3.971434 }, { 78652, 28, 7.883265 }, - { 1778, 2, 1.019109 }, { 15059, 11, 3.921524 }, { 81461, 29, 8.061169 }, - { 21437, 13, 4.489470 }, { 32980, 20, 5.956613 }, { 1369, 1, 1.000000 }, - { 46398, 22, 6.526960 }, { 3485, 5, 2.057350 }, { 48980, 20, 6.249687 }, - { 21904, 16, 5.032787 }, { 5481, 9, 3.080511 }, { 870, 6, 1.891372 }, - { 16428, 12, 4.157828 }, { 84270, 30, 8.236625 }, { 44082, 18, 5.837273 }, - { 68572, 28, 7.755204 }, { 39255, 15, 5.224730 }, { 18139, 11, 4.014838 }, - { 5476, 4, 1.913844 }, { 52340, 20, 6.300139 }, { 19788, 12, 4.256130 }, - }; - - enum Axis { X_AXIS, Y_AXIS, Z_AXIS } - - @BeforeClass + + private static final double[][] VOLUME_MCS = + new double[][] { + {19669, 13, 4.441502}, {1586, 2, 1.000000}, {12688, 16, 4.703909}, + {17430, 14, 4.553762}, {11055, 11, 3.770773}, {14224, 16, 4.771082}, + {20250, 18, 5.307441}, {3730, 10, 3.109355}, {33286, 22, 6.269841}, + {2185, 5, 1.926825}, {8364, 12, 3.817978}, {36638, 14, 4.993200}, + {34938, 18, 5.674056}, {73034, 26, 7.519614}, {9779, 11, 3.712390}, + {4539, 3, 1.555123}, {14694, 6, 2.784049}, {1, 1, 1.000000}, + {32997, 17, 5.466454}, {45700, 20, 6.197381}, {16872, 8, 3.336015}, + {3578, 2, 1.143097}, {6223, 7, 2.714233}, {3050, 10, 3.028743}, + {10468, 4, 2.095892}, {16643, 11, 3.971434}, {78652, 28, 7.883265}, + {1778, 2, 1.019109}, {15059, 11, 3.921524}, {81461, 29, 8.061169}, + {21437, 13, 4.489470}, {32980, 20, 5.956613}, {1369, 1, 1.000000}, + {46398, 22, 6.526960}, {3485, 5, 2.057350}, {48980, 20, 6.249687}, + {21904, 16, 5.032787}, {5481, 9, 3.080511}, {870, 6, 1.891372}, + {16428, 12, 4.157828}, {84270, 30, 8.236625}, {44082, 18, 5.837273}, + {68572, 28, 7.755204}, {39255, 15, 5.224730}, {18139, 11, 4.014838}, + {5476, 4, 1.913844}, {52340, 20, 6.300139}, {19788, 12, 4.256130}, + }; + + enum Axis { + X_AXIS, + Y_AXIS, + Z_AXIS + } + + @BeforeAll public static void setupGrid() { PottsSeries series = makeSeries(); potts = new Potts3D(series); - - potts.ids = new int[][][] { - { - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - }, - { - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 3, 0 }, - { 0, 0, 1, 3, 3, 0 }, - { 0, 2, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - }, - { - { 0, 0, 0, 0, 0, 0 }, - { 0, 1, 1, 3, 3, 0 }, - { 0, 1, 1, 3, 3, 0 }, - { 0, 2, 2, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - }, - { - { 0, 0, 0, 0, 0, 0 }, - { 0, 1, 1, 0, 0, 0 }, - { 0, 1, 2, 0, 3, 0 }, - { 0, 2, 2, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - }, - { - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - }, - }; - + + potts.ids = + new int[][][] { + { + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + }, + { + {0, 0, 0, 0, 0, 0}, + {0, 0, 1, 0, 3, 0}, + {0, 0, 1, 3, 3, 0}, + {0, 2, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + }, + { + {0, 0, 0, 0, 0, 0}, + {0, 1, 1, 3, 3, 0}, + {0, 1, 1, 3, 3, 0}, + {0, 2, 2, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + }, + { + {0, 0, 0, 0, 0, 0}, + {0, 1, 1, 0, 0, 0}, + {0, 1, 2, 0, 3, 0}, + {0, 2, 2, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + }, + { + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + }, + }; + int d = Region.DEFAULT.ordinal(); int n = Region.NUCLEUS.ordinal(); - - potts.regions = new int[][][] { - { - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - }, - { - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, d, 0, d, 0 }, - { 0, 0, d, d, d, 0 }, - { 0, d, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - }, - { - { 0, 0, 0, 0, 0, 0 }, - { 0, d, d, d, 0, 0 }, - { 0, 0, n, n, 0, 0 }, - { 0, d, d, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - }, - { - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, d, 0, 0, 0 }, - { 0, 0, n, 0, d, 0 }, - { 0, d, d, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - }, - { - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - }, - }; + + potts.regions = + new int[][][] { + { + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + }, + { + {0, 0, 0, 0, 0, 0}, + {0, 0, d, 0, d, 0}, + {0, 0, d, d, d, 0}, + {0, d, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + }, + { + {0, 0, 0, 0, 0, 0}, + {0, d, d, d, 0, 0}, + {0, 0, n, n, 0, 0}, + {0, d, d, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + }, + { + {0, 0, 0, 0, 0, 0}, + {0, 0, d, 0, 0, 0}, + {0, 0, n, 0, d, 0}, + {0, d, d, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + }, + { + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + }, + }; } - + private static boolean[][][] duplicate(boolean[][][] array) { boolean[][][] duplicated = new boolean[3][3][3]; for (int k = 0; k < 3; k++) { @@ -134,7 +141,7 @@ private static boolean[][][] duplicate(boolean[][][] array) { } return duplicated; } - + private static boolean[][][] combine(boolean[][][] base, int[] combo, int[][] links) { boolean[][][] array = duplicate(base); for (int i : combo) { @@ -142,10 +149,10 @@ private static boolean[][][] combine(boolean[][][] base, int[] combo, int[][] li } return array; } - + private static boolean[][][] rotate(boolean[][][] array, Axis axis, int rotations) { boolean[][][] rotated = duplicate(array); - + for (int rotation = 0; rotation < rotations; rotation++) { for (int k = 0; k < 3; k++) { for (int i = 0; i < 3; i++) { @@ -166,16 +173,16 @@ private static boolean[][][] rotate(boolean[][][] array, Axis axis, int rotation } } } - + array = duplicate(rotated); } - + return rotated; } - + private static boolean[][][] rotate(boolean[][][] array, int rotations) { boolean[][][] rotated = duplicate(array); - + for (int rotation = 0; rotation < rotations; rotation++) { for (int k = 0; k < 3; k++) { for (int i = 0; i < 3; i++) { @@ -184,357 +191,387 @@ private static boolean[][][] rotate(boolean[][][] array, int rotations) { } } } - + array = duplicate(rotated); } - + return rotated; } - + private static void populate(int[][] array, int n, int k) { int index = 0; int[] s = new int[k]; - + for (int i = 0; i < k; i++) { s[i] = i; } - + array[index++] = s.clone(); - - for (;;) { + + for (; ; ) { int ii = k - 1; for (int i = k - 1; i >= 0 && s[i] == n - k + i; i--) { ii--; } - + if (ii < 0) { break; } - + s[ii]++; for (++ii; ii < k; ii++) { s[ii] = s[ii - 1] + 1; } - + array[index++] = s.clone(); } } - + @Test public void getHamiltonian_validTerm_instantiatesObject() { PottsSeries series = makeSeries(1, 1, 1, 1, 1); Potts3D potts3D = new Potts3D(series); - + Hamiltonian h; - + h = potts3D.getHamiltonian(Term.ADHESION, series); assertTrue(h instanceof AdhesionHamiltonian3D); - + h = potts3D.getHamiltonian(Term.VOLUME, series); assertTrue(h instanceof VolumeHamiltonian); - + h = potts3D.getHamiltonian(Term.SURFACE, series); assertTrue(h instanceof SurfaceHamiltonian3D); - + h = potts3D.getHamiltonian(Term.HEIGHT, series); assertTrue(h instanceof HeightHamiltonian); - + h = potts3D.getHamiltonian(Term.JUNCTION, series); assertTrue(h instanceof JunctionHamiltonian); - + h = potts3D.getHamiltonian(Term.SUBSTRATE, series); assertTrue(h instanceof SubstrateHamiltonian); - + h = potts3D.getHamiltonian(Term.PERSISTENCE, series); assertTrue(h instanceof PersistenceHamiltonian); } - + @Test public void getHamiltonian_invalidTerm_returnsNull() { PottsSeries series = makeSeries(1, 1, 1, 1, 1); Potts3D potts3D = new Potts3D(series); - + Hamiltonian h; - + h = potts3D.getHamiltonian(Term.UNDEFINED, series); assertNull(h); } - + @Test public void getNeighborhood_givenID_createsArray() { boolean[][][] array1 = potts.getNeighborhood(1, 2, 2, 2); - assertArrayEquals(new boolean[] { false, true, false }, array1[0][0]); - assertArrayEquals(new boolean[] { false, true, false }, array1[0][1]); - assertArrayEquals(new boolean[] { false, false, false }, array1[0][2]); - assertArrayEquals(new boolean[] { true, true, false }, array1[1][0]); - assertArrayEquals(new boolean[] { true, true, false }, array1[1][1]); - assertArrayEquals(new boolean[] { false, false, false }, array1[1][2]); - assertArrayEquals(new boolean[] { true, true, false }, array1[2][0]); - assertArrayEquals(new boolean[] { true, false, false }, array1[2][1]); - assertArrayEquals(new boolean[] { false, false, false }, array1[2][2]); - + assertArrayEquals(new boolean[] {false, true, false}, array1[0][0]); + assertArrayEquals(new boolean[] {false, true, false}, array1[0][1]); + assertArrayEquals(new boolean[] {false, false, false}, array1[0][2]); + assertArrayEquals(new boolean[] {true, true, false}, array1[1][0]); + assertArrayEquals(new boolean[] {true, true, false}, array1[1][1]); + assertArrayEquals(new boolean[] {false, false, false}, array1[1][2]); + assertArrayEquals(new boolean[] {true, true, false}, array1[2][0]); + assertArrayEquals(new boolean[] {true, false, false}, array1[2][1]); + assertArrayEquals(new boolean[] {false, false, false}, array1[2][2]); + boolean[][][] array2 = potts.getNeighborhood(2, 2, 2, 2); - assertArrayEquals(new boolean[] { false, false, false }, array2[0][0]); - assertArrayEquals(new boolean[] { false, false, false }, array2[0][1]); - assertArrayEquals(new boolean[] { true, false, false }, array2[0][2]); - assertArrayEquals(new boolean[] { false, false, false }, array2[1][0]); - assertArrayEquals(new boolean[] { false, false, false }, array2[1][1]); - assertArrayEquals(new boolean[] { true, true, false }, array2[1][2]); - assertArrayEquals(new boolean[] { false, false, false }, array2[2][0]); - assertArrayEquals(new boolean[] { false, true, false }, array2[2][1]); - assertArrayEquals(new boolean[] { true, true, false }, array2[2][2]); - + assertArrayEquals(new boolean[] {false, false, false}, array2[0][0]); + assertArrayEquals(new boolean[] {false, false, false}, array2[0][1]); + assertArrayEquals(new boolean[] {true, false, false}, array2[0][2]); + assertArrayEquals(new boolean[] {false, false, false}, array2[1][0]); + assertArrayEquals(new boolean[] {false, false, false}, array2[1][1]); + assertArrayEquals(new boolean[] {true, true, false}, array2[1][2]); + assertArrayEquals(new boolean[] {false, false, false}, array2[2][0]); + assertArrayEquals(new boolean[] {false, true, false}, array2[2][1]); + assertArrayEquals(new boolean[] {true, true, false}, array2[2][2]); + boolean[][][] array3 = potts.getNeighborhood(3, 2, 2, 2); - assertArrayEquals(new boolean[] { false, false, false }, array3[0][0]); - assertArrayEquals(new boolean[] { false, false, true }, array3[0][1]); - assertArrayEquals(new boolean[] { false, false, false }, array3[0][2]); - assertArrayEquals(new boolean[] { false, false, true }, array3[1][0]); - assertArrayEquals(new boolean[] { false, false, true }, array3[1][1]); - assertArrayEquals(new boolean[] { false, false, false }, array3[1][2]); - assertArrayEquals(new boolean[] { false, false, false }, array3[2][0]); - assertArrayEquals(new boolean[] { false, false, false }, array3[2][1]); - assertArrayEquals(new boolean[] { false, false, false }, array3[2][2]); - } - + assertArrayEquals(new boolean[] {false, false, false}, array3[0][0]); + assertArrayEquals(new boolean[] {false, false, true}, array3[0][1]); + assertArrayEquals(new boolean[] {false, false, false}, array3[0][2]); + assertArrayEquals(new boolean[] {false, false, true}, array3[1][0]); + assertArrayEquals(new boolean[] {false, false, true}, array3[1][1]); + assertArrayEquals(new boolean[] {false, false, false}, array3[1][2]); + assertArrayEquals(new boolean[] {false, false, false}, array3[2][0]); + assertArrayEquals(new boolean[] {false, false, false}, array3[2][1]); + assertArrayEquals(new boolean[] {false, false, false}, array3[2][2]); + } + @Test public void getNeighborhood_givenRegion_createsArray() { boolean[][][] array1 = potts.getNeighborhood(1, Region.DEFAULT.ordinal(), 2, 2, 2); - assertArrayEquals(new boolean[] { false, true, false }, array1[0][0]); - assertArrayEquals(new boolean[] { false, true, false }, array1[0][1]); - assertArrayEquals(new boolean[] { false, false, false }, array1[0][2]); - assertArrayEquals(new boolean[] { true, true, false }, array1[1][0]); - assertArrayEquals(new boolean[] { false, false, false }, array1[1][1]); - assertArrayEquals(new boolean[] { false, false, false }, array1[1][2]); - assertArrayEquals(new boolean[] { false, true, false }, array1[2][0]); - assertArrayEquals(new boolean[] { false, false, false }, array1[2][1]); - assertArrayEquals(new boolean[] { false, false, false }, array1[2][2]); - + assertArrayEquals(new boolean[] {false, true, false}, array1[0][0]); + assertArrayEquals(new boolean[] {false, true, false}, array1[0][1]); + assertArrayEquals(new boolean[] {false, false, false}, array1[0][2]); + assertArrayEquals(new boolean[] {true, true, false}, array1[1][0]); + assertArrayEquals(new boolean[] {false, false, false}, array1[1][1]); + assertArrayEquals(new boolean[] {false, false, false}, array1[1][2]); + assertArrayEquals(new boolean[] {false, true, false}, array1[2][0]); + assertArrayEquals(new boolean[] {false, false, false}, array1[2][1]); + assertArrayEquals(new boolean[] {false, false, false}, array1[2][2]); + boolean[][][] array2 = potts.getNeighborhood(1, Region.NUCLEUS.ordinal(), 2, 2, 2); - assertArrayEquals(new boolean[] { false, false, false }, array2[0][0]); - assertArrayEquals(new boolean[] { false, false, false }, array2[0][1]); - assertArrayEquals(new boolean[] { false, false, false }, array2[0][2]); - assertArrayEquals(new boolean[] { false, false, false }, array2[1][0]); - assertArrayEquals(new boolean[] { false, true, false }, array2[1][1]); - assertArrayEquals(new boolean[] { false, false, false }, array2[1][2]); - assertArrayEquals(new boolean[] { false, false, false }, array2[2][0]); - assertArrayEquals(new boolean[] { false, false, false }, array2[2][1]); - assertArrayEquals(new boolean[] { false, false, false }, array2[2][2]); - } - + assertArrayEquals(new boolean[] {false, false, false}, array2[0][0]); + assertArrayEquals(new boolean[] {false, false, false}, array2[0][1]); + assertArrayEquals(new boolean[] {false, false, false}, array2[0][2]); + assertArrayEquals(new boolean[] {false, false, false}, array2[1][0]); + assertArrayEquals(new boolean[] {false, true, false}, array2[1][1]); + assertArrayEquals(new boolean[] {false, false, false}, array2[1][2]); + assertArrayEquals(new boolean[] {false, false, false}, array2[2][0]); + assertArrayEquals(new boolean[] {false, false, false}, array2[2][1]); + assertArrayEquals(new boolean[] {false, false, false}, array2[2][2]); + } + private HashSet checkUniqueID(Potts3D potts3D, int[][][] ids) { potts3D.ids = ids; return potts3D.getUniqueIDs(1, 1, 1); } - + @Test public void getUniqueIDs_validVoxel_returnsList() { PottsSeries series = makeSeries(); Potts3D pottsMock = new Potts3D(series); HashSet unique = new HashSet<>(); - + unique.add(1); - assertEquals(unique, checkUniqueID(pottsMock, new int[][][] { - { - { 0, 0, 0 }, - { 0, 1, 0 }, - { 0, 0, 0 } - }, - { - { 0, 0, 0 }, - { 0, 0, 0 }, - { 0, 0, 0 } - }, - { - { 0, 0, 0 }, - { 0, 0, 0 }, - { 0, 0, 0 } - } - })); - + assertEquals( + unique, + checkUniqueID( + pottsMock, + new int[][][] { + { + {0, 0, 0}, + {0, 1, 0}, + {0, 0, 0} + }, + { + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0} + }, + { + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0} + } + })); + unique.clear(); unique.add(0); - assertEquals(unique, checkUniqueID(pottsMock, new int[][][] { - { - { 0, 0, 0 }, - { 0, 0, 0 }, - { 0, 0, 0 } - }, - { - { 0, 1, 0 }, - { 0, 1, 0 }, - { 0, 0, 0 } - }, - { - { 0, 0, 0 }, - { 0, 0, 0 }, - { 0, 0, 0 } - } - })); - + assertEquals( + unique, + checkUniqueID( + pottsMock, + new int[][][] { + { + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0} + }, + { + {0, 1, 0}, + {0, 1, 0}, + {0, 0, 0} + }, + { + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0} + } + })); + unique.clear(); - assertEquals(unique, checkUniqueID(pottsMock, new int[][][] { - { - { 1, 1, 1 }, - { 1, 0, 1 }, - { 1, 1, 1 } - }, - { - { 1, 0, 1 }, - { 0, 0, 0 }, - { 1, 0, 1 } - }, - { - { 1, 1, 1 }, - { 1, 0, 1 }, - { 1, 1, 1 } - } - })); + assertEquals( + unique, + checkUniqueID( + pottsMock, + new int[][][] { + { + {1, 1, 1}, + {1, 0, 1}, + {1, 1, 1} + }, + { + {1, 0, 1}, + {0, 0, 0}, + {1, 0, 1} + }, + { + {1, 1, 1}, + {1, 0, 1}, + {1, 1, 1} + } + })); } - + private HashSet checkUniqueRegion(Potts3D potts3D, int[][][] ids, int[][][] regions) { potts3D.ids = ids; potts3D.regions = regions; return potts3D.getUniqueRegions(1, 1, 1); } - + @Test public void getUniqueRegions_validVoxel_returnsList() { PottsSeries series = makeSeries(); Potts3D pottsMock = new Potts3D(series); HashSet unique = new HashSet<>(); - - assertEquals(unique, checkUniqueRegion(pottsMock, new int[][][] { - { - { 0, 0, 0 }, - { 0, 1, 0 }, - { 0, 0, 0 } - }, - { - { 0, 0, 0 }, - { 0, 0, 0 }, - { 0, 0, 0 } - }, - { - { 0, 0, 0 }, - { 0, 0, 0 }, - { 0, 0, 0 } - } - }, new int[][][] { - { - { 0, 0, 0 }, - { 0, -1, 0 }, - { 0, 0, 0 } - }, - { - { 0, 0, 0 }, - { 0, 0, 0 }, - { 0, 0, 0 } - }, - { - { 0, 0, 0 }, - { 0, 0, 0 }, - { 0, 0, 0 } - } - })); - - assertEquals(unique, checkUniqueRegion(pottsMock, new int[][][] { - { - { 1, 1, 1 }, - { 1, 1, 1 }, - { 1, 1, 1 } - }, - { - { 1, 1, 1 }, - { 1, 1, 1 }, - { 1, 1, 1 } - }, - { - { 1, 1, 1 }, - { 1, 1, 1 }, - { 1, 1, 1 } - } - }, new int[][][] { - { - { -2, -2, -2 }, - { -2, -1, -2 }, - { -2, -2, -2 } - }, - { - { -2, -1, -2 }, - { -1, -1, -1 }, - { -2, -1, -2 } - }, - { - { -2, -2, -2 }, - { -2, -1, -2 }, - { -2, -2, -2 } - } - })); - + + assertEquals( + unique, + checkUniqueRegion( + pottsMock, + new int[][][] { + { + {0, 0, 0}, + {0, 1, 0}, + {0, 0, 0} + }, + { + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0} + }, + { + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0} + } + }, + new int[][][] { + { + {0, 0, 0}, + {0, -1, 0}, + {0, 0, 0} + }, + { + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0} + }, + { + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0} + } + })); + + assertEquals( + unique, + checkUniqueRegion( + pottsMock, + new int[][][] { + { + {1, 1, 1}, + {1, 1, 1}, + {1, 1, 1} + }, + { + {1, 1, 1}, + {1, 1, 1}, + {1, 1, 1} + }, + { + {1, 1, 1}, + {1, 1, 1}, + {1, 1, 1} + } + }, + new int[][][] { + { + {-2, -2, -2}, + {-2, -1, -2}, + {-2, -2, -2} + }, + { + {-2, -1, -2}, + {-1, -1, -1}, + {-2, -1, -2} + }, + { + {-2, -2, -2}, + {-2, -1, -2}, + {-2, -2, -2} + } + })); + unique.add(-2); unique.add(-5); - assertEquals(unique, checkUniqueRegion(pottsMock, new int[][][] { - { - { 0, 0, 0 }, - { 0, 1, 0 }, - { 0, 0, 0 } - }, - { - { 0, 1, 0 }, - { 1, 1, 2 }, - { 0, 2, 0 } - }, - { - { 0, 0, 0 }, - { 0, 2, 0 }, - { 0, 0, 0 } - } - }, new int[][][] { - { - { 0, 0, 0 }, - { 0, -5, 0 }, - { 0, 0, 0 } - }, - { - { 0, -1, 0 }, - { -2, -1, -4 }, - { 0, -3, 0 } - }, - { - { 0, 0, 0 }, - { 0, -6, 0 }, - { 0, 0, 0 } - } - })); + assertEquals( + unique, + checkUniqueRegion( + pottsMock, + new int[][][] { + { + {0, 0, 0}, + {0, 1, 0}, + {0, 0, 0} + }, + { + {0, 1, 0}, + {1, 1, 2}, + {0, 2, 0} + }, + { + {0, 0, 0}, + {0, 2, 0}, + {0, 0, 0} + } + }, + new int[][][] { + { + {0, 0, 0}, + {0, -5, 0}, + {0, 0, 0} + }, + { + {0, -1, 0}, + {-2, -1, -4}, + {0, -3, 0} + }, + { + {0, 0, 0}, + {0, -6, 0}, + {0, 0, 0} + } + })); } - + /* ------------------------------------------------------------------------- * CONNECTIVITY FOR ZERO (0) NEIGHBORS * * If there are zero neighbors, then the voxel is never connected. ------------------------------------------------------------------------- */ - + @Test public void getConnectivity_zeroNeighbors_returnsFalse() { - assertFalse(potts.getConnectivity(new boolean[][][] { - { - { false, false, false }, - { false, false, false }, - { false, false, false } - }, - { - { false, false, false }, - { false, true, false }, - { false, false, false } - }, - { - { false, false, false }, - { false, false, false }, - { false, false, false } - } - }, false)); + assertFalse( + potts.getConnectivity( + new boolean[][][] { + { + {false, false, false}, + {false, false, false}, + {false, false, false} + }, + { + {false, false, false}, + {false, true, false}, + {false, false, false} + }, + { + {false, false, false}, + {false, false, false}, + {false, false, false} + } + }, + false)); } - + /* ------------------------------------------------------------------------- * CONNECTIVITY FOR ONE (1) NEIGHBOR * @@ -542,25 +579,26 @@ public void getConnectivity_zeroNeighbors_returnsFalse() { * * If there is only one neighbor, the voxel is always connected. ------------------------------------------------------------------------- */ - - private static final boolean[][][] BASE_ONE_NEIGHBOR = new boolean[][][] { - { - { false, false, false }, - { false, false, false }, - { false, false, false } - }, - { - { false, true, false }, - { false, true, false }, - { false, false, false } - }, - { - { false, false, false }, - { false, false, false }, - { false, false, false } - } - }; - + + private static final boolean[][][] BASE_ONE_NEIGHBOR = + new boolean[][][] { + { + {false, false, false}, + {false, false, false}, + {false, false, false} + }, + { + {false, true, false}, + {false, true, false}, + {false, false, false} + }, + { + {false, false, false}, + {false, false, false}, + {false, false, false} + } + }; + @Test public void getConnectivity_oneNeighbor_returnsTrue() { for (int rotation = 0; rotation < 6; rotation++) { @@ -568,7 +606,7 @@ public void getConnectivity_oneNeighbor_returnsTrue() { assertTrue(potts.getConnectivity(array, false)); } } - + /* ------------------------------------------------------------------------- * CONNECTIVITY FOR TWO (2) NEIGHBORS * @@ -580,101 +618,108 @@ public void getConnectivity_oneNeighbor_returnsTrue() { * If there are two adjacent neighbors, the voxel is connected if there is * a link in the shared corner. ------------------------------------------------------------------------- */ - - private static final boolean[][][] BASE_TWO_NEIGHBORS_OPPOSITE = new boolean[][][] { - { - { false, false, false }, - { false, false, false }, - { false, false, false } - }, - { - { false, true, false }, - { false, true, false }, - { false, true, false } - }, - { - { false, false, false }, - { false, false, false }, - { false, false, false } - } - }; - - private static final boolean[][][] BASE_TWO_NEIGHBORS_ADJACENT_XY = new boolean[][][] { - { - { false, false, false }, - { false, false, false }, - { false, false, false } - }, - { - { false, true, false }, - { true, true, false }, - { false, false, false } - }, - { - { false, false, false }, - { false, false, false }, - { false, false, false } - } - }; - - private static final boolean[][][] BASE_TWO_NEIGHBORS_ADJACENT_YZ = new boolean[][][] { - { - { false, false, false }, - { false, true, false }, - { false, false, false } - }, - { - { false, false, false }, - { true, true, false }, - { false, false, false } - }, - { - { false, false, false }, - { false, false, false }, - { false, false, false } - } - }; - - private static final boolean[][][] BASE_TWO_NEIGHBORS_ADJACENT_ZX = new boolean[][][] { - { - { false, false, false }, - { false, true, false }, - { false, false, false } - }, - { - { false, true, false }, - { false, true, false }, - { false, false, false } - }, - { - { false, false, false }, - { false, false, false }, - { false, false, false } - } - }; - - private static final int[][] LINKS_TWO_NEIGHBORS_ADJACENT_XY = new int[][] { - { 1 }, // Z - { 0 }, // X - { 0 }, // Y - }; - - private static final int[][] LINKS_TWO_NEIGHBORS_ADJACENT_YZ = new int[][] { - { 0 }, // Z - { 1 }, // X - { 0 }, // Y - }; - - private static final int[][] LINKS_TWO_NEIGHBORS_ADJACENT_ZX = new int[][] { - { 0 }, // Z - { 0 }, // X - { 1 }, // Y - }; - - private static final int[][] COMBOS_TWO_NEIGHBORS_ADJACENT_ZERO_LINKS = new int[][] { { } }; - - private static final int[][] COMBOS_TWO_NEIGHBORS_ADJACENT_ONE_LINK = new int[][] { { 0 } }; - + + private static final boolean[][][] BASE_TWO_NEIGHBORS_OPPOSITE = + new boolean[][][] { + { + {false, false, false}, + {false, false, false}, + {false, false, false} + }, + { + {false, true, false}, + {false, true, false}, + {false, true, false} + }, + { + {false, false, false}, + {false, false, false}, + {false, false, false} + } + }; + + private static final boolean[][][] BASE_TWO_NEIGHBORS_ADJACENT_XY = + new boolean[][][] { + { + {false, false, false}, + {false, false, false}, + {false, false, false} + }, + { + {false, true, false}, + {true, true, false}, + {false, false, false} + }, + { + {false, false, false}, + {false, false, false}, + {false, false, false} + } + }; + + private static final boolean[][][] BASE_TWO_NEIGHBORS_ADJACENT_YZ = + new boolean[][][] { + { + {false, false, false}, + {false, true, false}, + {false, false, false} + }, + { + {false, false, false}, + {true, true, false}, + {false, false, false} + }, + { + {false, false, false}, + {false, false, false}, + {false, false, false} + } + }; + + private static final boolean[][][] BASE_TWO_NEIGHBORS_ADJACENT_ZX = + new boolean[][][] { + { + {false, false, false}, + {false, true, false}, + {false, false, false} + }, + { + {false, true, false}, + {false, true, false}, + {false, false, false} + }, + { + {false, false, false}, + {false, false, false}, + {false, false, false} + } + }; + + private static final int[][] LINKS_TWO_NEIGHBORS_ADJACENT_XY = + new int[][] { + {1}, // Z + {0}, // X + {0}, // Y + }; + + private static final int[][] LINKS_TWO_NEIGHBORS_ADJACENT_YZ = + new int[][] { + {0}, // Z + {1}, // X + {0}, // Y + }; + + private static final int[][] LINKS_TWO_NEIGHBORS_ADJACENT_ZX = + new int[][] { + {0}, // Z + {0}, // X + {1}, // Y + }; + + private static final int[][] COMBOS_TWO_NEIGHBORS_ADJACENT_ZERO_LINKS = new int[][] {{}}; + + private static final int[][] COMBOS_TWO_NEIGHBORS_ADJACENT_ONE_LINK = new int[][] {{0}}; + @Test public void getConnectivity_twoNeighborsOpposite_returnsFalse() { for (int rotation = 0; rotation < 3; rotation++) { @@ -682,73 +727,109 @@ public void getConnectivity_twoNeighborsOpposite_returnsFalse() { assertFalse(potts.getConnectivity(array, false)); } } - + @Test public void getConnectivity_twoNeighborsAdjacentXYZeroLinks_returnsFalse() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_TWO_NEIGHBORS_ADJACENT_ZERO_LINKS) { - boolean[][][] array = rotate(combine(BASE_TWO_NEIGHBORS_ADJACENT_XY, - combo, LINKS_TWO_NEIGHBORS_ADJACENT_XY), Axis.Z_AXIS, rotation); + boolean[][][] array = + rotate( + combine( + BASE_TWO_NEIGHBORS_ADJACENT_XY, + combo, + LINKS_TWO_NEIGHBORS_ADJACENT_XY), + Axis.Z_AXIS, + rotation); assertFalse(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_twoNeighborsAdjacentYZZeroLinks_returnsFalse() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_TWO_NEIGHBORS_ADJACENT_ZERO_LINKS) { - boolean[][][] array = rotate(combine(BASE_TWO_NEIGHBORS_ADJACENT_YZ, - combo, LINKS_TWO_NEIGHBORS_ADJACENT_YZ), Axis.X_AXIS, rotation); + boolean[][][] array = + rotate( + combine( + BASE_TWO_NEIGHBORS_ADJACENT_YZ, + combo, + LINKS_TWO_NEIGHBORS_ADJACENT_YZ), + Axis.X_AXIS, + rotation); assertFalse(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_twoNeighborsAdjacentZXZeroLinks_returnsFalse() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_TWO_NEIGHBORS_ADJACENT_ZERO_LINKS) { - boolean[][][] array = rotate(combine(BASE_TWO_NEIGHBORS_ADJACENT_ZX, - combo, LINKS_TWO_NEIGHBORS_ADJACENT_ZX), Axis.Y_AXIS, rotation); + boolean[][][] array = + rotate( + combine( + BASE_TWO_NEIGHBORS_ADJACENT_ZX, + combo, + LINKS_TWO_NEIGHBORS_ADJACENT_ZX), + Axis.Y_AXIS, + rotation); assertFalse(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_twoNeighborsAdjacentXYOneLink_returnsTrue() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_TWO_NEIGHBORS_ADJACENT_ONE_LINK) { - boolean[][][] array = rotate(combine(BASE_TWO_NEIGHBORS_ADJACENT_XY, - combo, LINKS_TWO_NEIGHBORS_ADJACENT_XY), Axis.Z_AXIS, rotation); + boolean[][][] array = + rotate( + combine( + BASE_TWO_NEIGHBORS_ADJACENT_XY, + combo, + LINKS_TWO_NEIGHBORS_ADJACENT_XY), + Axis.Z_AXIS, + rotation); assertTrue(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_twoNeighborsAdjacentYZOneLink_returnsTrue() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_TWO_NEIGHBORS_ADJACENT_ONE_LINK) { - boolean[][][] array = rotate(combine(BASE_TWO_NEIGHBORS_ADJACENT_YZ, - combo, LINKS_TWO_NEIGHBORS_ADJACENT_YZ), Axis.X_AXIS, rotation); + boolean[][][] array = + rotate( + combine( + BASE_TWO_NEIGHBORS_ADJACENT_YZ, + combo, + LINKS_TWO_NEIGHBORS_ADJACENT_YZ), + Axis.X_AXIS, + rotation); assertTrue(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_twoNeighborsAdjacentZXOneLink_returnsTrue() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_TWO_NEIGHBORS_ADJACENT_ONE_LINK) { - boolean[][][] array = rotate(combine(BASE_TWO_NEIGHBORS_ADJACENT_ZX, - combo, LINKS_TWO_NEIGHBORS_ADJACENT_ZX), Axis.Y_AXIS, rotation); + boolean[][][] array = + rotate( + combine( + BASE_TWO_NEIGHBORS_ADJACENT_ZX, + combo, + LINKS_TWO_NEIGHBORS_ADJACENT_ZX), + Axis.Y_AXIS, + rotation); assertTrue(potts.getConnectivity(array, false)); } } } - + /* ------------------------------------------------------------------------- * CONNECTIVITY FOR THREE (3) NEIGHBORS * @@ -766,315 +847,429 @@ public void getConnectivity_twoNeighborsAdjacentZXOneLink_returnsTrue() { * 2 links | 3 combos | connected * 3 links | 1 combo | connected ------------------------------------------------------------------------- */ - - private static final boolean[][][] BASE_THREE_NEIGHBORS_PLANE_XY = new boolean[][][] { - { - { false, true, false }, - { true, false, false }, - { false, true, false } - }, - { - { false, true, false }, - { true, true, false }, - { false, true, false } - }, - { - { false, true, false }, - { true, false, false }, - { false, true, false } - } - }; - - private static final boolean[][][] BASE_THREE_NEIGHBORS_PLANE_YZ = new boolean[][][] { - { - { false, true, false }, - { false, true, false }, - { false, true, false } - }, - { - { true, false, false }, - { true, true, false }, - { true, false, false } - }, - { - { false, true, false }, - { false, true, false }, - { false, true, false } - } - }; - - private static final boolean[][][] BASE_THREE_NEIGHBORS_PLANE_ZX = new boolean[][][] { - { - { false, false, false }, - { true, true, true }, - { false, false, false } - }, - { - { true, true, true }, - { false, true, false }, - { false, false, false } - }, - { - { false, false, false }, - { true, true, true }, - { false, false, false } - } - }; - - private static final boolean[][][] BASE_THREE_NEIGHBORS_CORNER_A = new boolean[][][] { - { - { false, false, false }, - { false, true, false }, - { false, false, false } - }, - { - { false, true, false }, - { true, true, false }, - { false, false, false } - }, - { - { false, false, false }, - { false, false, false }, - { false, false, false } - } - }; - - private static final boolean[][][] BASE_THREE_NEIGHBORS_CORNER_B = new boolean[][][] { - { - { false, false, false }, - { false, false, false }, - { false, false, false } - }, - { - { false, true, false }, - { true, true, false }, - { false, false, false } - }, - { - { false, false, false }, - { false, true, false }, - { false, false, false } - } - }; - - private static final int[][] LINKS_THREE_NEIGHBORS_PLANE_XY = new int[][] { - { 1, 1 }, // Z - { 0, 2 }, // X - { 0, 0 }, // Y - }; - - private static final int[][] LINKS_THREE_NEIGHBORS_PLANE_YZ = new int[][] { - { 0, 2 }, // Z - { 1, 1 }, // X - { 0, 0 }, // Y - }; - - private static final int[][] LINKS_THREE_NEIGHBORS_PLANE_ZX = new int[][] { - { 0, 2 }, // Z - { 0, 0 }, // X - { 1, 1 }, // Y - }; - - private static final int[][] LINKS_THREE_NEIGHBORS_CORNER_A = new int[][] { - { 0, 0, 1 }, // Z - { 0, 1, 0 }, // X - { 1, 0, 0 }, // Y - }; - - private static final int[][] LINKS_THREE_NEIGHBORS_CORNER_B = new int[][] { - { 2, 2, 1 }, // Z - { 0, 1, 0 }, // X - { 1, 0, 0 }, // Y - }; - - private static final int[][] COMBOS_THREE_NEIGHBORS_PLANE_ZERO_LINKS = new int[][] { { } }; - - private static final int[][] COMBOS_THREE_NEIGHBORS_PLANE_ONE_LINK = new int[][] { - { 0 }, - { 1 }, - }; - - private static final int[][] COMBOS_THREE_NEIGHBORS_PLANE_TWO_LINKS = new int[][] { - { 0, 1 }, - }; - - private static final int[][] COMBOS_THREE_NEIGHBORS_CORNER_ZERO_LINKS = new int[][] { { } }; - - private static final int[][] COMBOS_THREE_NEIGHBORS_CORNER_ONE_LINK = new int[][] { - { 0 }, - { 1 }, - { 2 }, - }; - - private static final int[][] COMBOS_THREE_NEIGHBORS_CORNER_TWO_LINKS = new int[][] { - { 0, 1 }, - { 0, 2 }, - { 1, 2 }, - }; - - private static final int[][] COMBOS_THREE_NEIGHBORS_CORNER_THREE_LINKS = new int[][] { - { 0, 1, 2 }, - }; - + + private static final boolean[][][] BASE_THREE_NEIGHBORS_PLANE_XY = + new boolean[][][] { + { + {false, true, false}, + {true, false, false}, + {false, true, false} + }, + { + {false, true, false}, + {true, true, false}, + {false, true, false} + }, + { + {false, true, false}, + {true, false, false}, + {false, true, false} + } + }; + + private static final boolean[][][] BASE_THREE_NEIGHBORS_PLANE_YZ = + new boolean[][][] { + { + {false, true, false}, + {false, true, false}, + {false, true, false} + }, + { + {true, false, false}, + {true, true, false}, + {true, false, false} + }, + { + {false, true, false}, + {false, true, false}, + {false, true, false} + } + }; + + private static final boolean[][][] BASE_THREE_NEIGHBORS_PLANE_ZX = + new boolean[][][] { + { + {false, false, false}, + {true, true, true}, + {false, false, false} + }, + { + {true, true, true}, + {false, true, false}, + {false, false, false} + }, + { + {false, false, false}, + {true, true, true}, + {false, false, false} + } + }; + + private static final boolean[][][] BASE_THREE_NEIGHBORS_CORNER_A = + new boolean[][][] { + { + {false, false, false}, + {false, true, false}, + {false, false, false} + }, + { + {false, true, false}, + {true, true, false}, + {false, false, false} + }, + { + {false, false, false}, + {false, false, false}, + {false, false, false} + } + }; + + private static final boolean[][][] BASE_THREE_NEIGHBORS_CORNER_B = + new boolean[][][] { + { + {false, false, false}, + {false, false, false}, + {false, false, false} + }, + { + {false, true, false}, + {true, true, false}, + {false, false, false} + }, + { + {false, false, false}, + {false, true, false}, + {false, false, false} + } + }; + + private static final int[][] LINKS_THREE_NEIGHBORS_PLANE_XY = + new int[][] { + {1, 1}, // Z + {0, 2}, // X + {0, 0}, // Y + }; + + private static final int[][] LINKS_THREE_NEIGHBORS_PLANE_YZ = + new int[][] { + {0, 2}, // Z + {1, 1}, // X + {0, 0}, // Y + }; + + private static final int[][] LINKS_THREE_NEIGHBORS_PLANE_ZX = + new int[][] { + {0, 2}, // Z + {0, 0}, // X + {1, 1}, // Y + }; + + private static final int[][] LINKS_THREE_NEIGHBORS_CORNER_A = + new int[][] { + {0, 0, 1}, // Z + {0, 1, 0}, // X + {1, 0, 0}, // Y + }; + + private static final int[][] LINKS_THREE_NEIGHBORS_CORNER_B = + new int[][] { + {2, 2, 1}, // Z + {0, 1, 0}, // X + {1, 0, 0}, // Y + }; + + private static final int[][] COMBOS_THREE_NEIGHBORS_PLANE_ZERO_LINKS = new int[][] {{}}; + + private static final int[][] COMBOS_THREE_NEIGHBORS_PLANE_ONE_LINK = + new int[][] { + {0}, {1}, + }; + + private static final int[][] COMBOS_THREE_NEIGHBORS_PLANE_TWO_LINKS = + new int[][] { + {0, 1}, + }; + + private static final int[][] COMBOS_THREE_NEIGHBORS_CORNER_ZERO_LINKS = new int[][] {{}}; + + private static final int[][] COMBOS_THREE_NEIGHBORS_CORNER_ONE_LINK = + new int[][] { + {0}, {1}, {2}, + }; + + private static final int[][] COMBOS_THREE_NEIGHBORS_CORNER_TWO_LINKS = + new int[][] { + {0, 1}, + {0, 2}, + {1, 2}, + }; + + private static final int[][] COMBOS_THREE_NEIGHBORS_CORNER_THREE_LINKS = + new int[][] { + {0, 1, 2}, + }; + @Test public void getConnectivity_threeNeighborsPlaneXYZeroLinks_returnsFalse() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_THREE_NEIGHBORS_PLANE_ZERO_LINKS) { - boolean[][][] array = rotate(combine(BASE_THREE_NEIGHBORS_PLANE_XY, - combo, LINKS_THREE_NEIGHBORS_PLANE_XY), Axis.Z_AXIS, rotation); + boolean[][][] array = + rotate( + combine( + BASE_THREE_NEIGHBORS_PLANE_XY, + combo, + LINKS_THREE_NEIGHBORS_PLANE_XY), + Axis.Z_AXIS, + rotation); assertFalse(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_threeNeighborsPlaneYZZeroLinks_returnsFalse() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_THREE_NEIGHBORS_PLANE_ZERO_LINKS) { - boolean[][][] array = rotate(combine(BASE_THREE_NEIGHBORS_PLANE_YZ, - combo, LINKS_THREE_NEIGHBORS_PLANE_YZ), Axis.X_AXIS, rotation); + boolean[][][] array = + rotate( + combine( + BASE_THREE_NEIGHBORS_PLANE_YZ, + combo, + LINKS_THREE_NEIGHBORS_PLANE_YZ), + Axis.X_AXIS, + rotation); assertFalse(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_threeNeighborsPlaneZXZeroLinks_returnsFalse() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_THREE_NEIGHBORS_PLANE_ZERO_LINKS) { - boolean[][][] array = rotate(combine(BASE_THREE_NEIGHBORS_PLANE_ZX, - combo, LINKS_THREE_NEIGHBORS_PLANE_ZX), Axis.Y_AXIS, rotation); + boolean[][][] array = + rotate( + combine( + BASE_THREE_NEIGHBORS_PLANE_ZX, + combo, + LINKS_THREE_NEIGHBORS_PLANE_ZX), + Axis.Y_AXIS, + rotation); assertFalse(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_threeNeighborsPlaneXYOneLink_returnsFalse() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_THREE_NEIGHBORS_PLANE_ONE_LINK) { - boolean[][][] array = rotate(combine(BASE_THREE_NEIGHBORS_PLANE_XY, - combo, LINKS_THREE_NEIGHBORS_PLANE_XY), Axis.Z_AXIS, rotation); + boolean[][][] array = + rotate( + combine( + BASE_THREE_NEIGHBORS_PLANE_XY, + combo, + LINKS_THREE_NEIGHBORS_PLANE_XY), + Axis.Z_AXIS, + rotation); assertFalse(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_threeNeighborsPlaneYZOneLink_returnsFalse() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_THREE_NEIGHBORS_PLANE_ONE_LINK) { - boolean[][][] array = rotate(combine(BASE_THREE_NEIGHBORS_PLANE_YZ, - combo, LINKS_THREE_NEIGHBORS_PLANE_YZ), Axis.X_AXIS, rotation); + boolean[][][] array = + rotate( + combine( + BASE_THREE_NEIGHBORS_PLANE_YZ, + combo, + LINKS_THREE_NEIGHBORS_PLANE_YZ), + Axis.X_AXIS, + rotation); assertFalse(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_threeNeighborsPlaneZXOneLink_returnsFalse() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_THREE_NEIGHBORS_PLANE_ONE_LINK) { - boolean[][][] array = rotate(combine(BASE_THREE_NEIGHBORS_PLANE_ZX, - combo, LINKS_THREE_NEIGHBORS_PLANE_ZX), Axis.Y_AXIS, rotation); + boolean[][][] array = + rotate( + combine( + BASE_THREE_NEIGHBORS_PLANE_ZX, + combo, + LINKS_THREE_NEIGHBORS_PLANE_ZX), + Axis.Y_AXIS, + rotation); assertFalse(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_threeNeighborsPlaneXYTwoLinks_returnsTrue() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_THREE_NEIGHBORS_PLANE_TWO_LINKS) { - boolean[][][] array = rotate(combine(BASE_THREE_NEIGHBORS_PLANE_XY, - combo, LINKS_THREE_NEIGHBORS_PLANE_XY), Axis.Z_AXIS, rotation); + boolean[][][] array = + rotate( + combine( + BASE_THREE_NEIGHBORS_PLANE_XY, + combo, + LINKS_THREE_NEIGHBORS_PLANE_XY), + Axis.Z_AXIS, + rotation); assertTrue(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_threeNeighborsPlaneYZTwoLinks_returnsTrue() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_THREE_NEIGHBORS_PLANE_TWO_LINKS) { - boolean[][][] array = rotate(combine(BASE_THREE_NEIGHBORS_PLANE_YZ, - combo, LINKS_THREE_NEIGHBORS_PLANE_YZ), Axis.X_AXIS, rotation); + boolean[][][] array = + rotate( + combine( + BASE_THREE_NEIGHBORS_PLANE_YZ, + combo, + LINKS_THREE_NEIGHBORS_PLANE_YZ), + Axis.X_AXIS, + rotation); assertTrue(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_threeNeighborsPlaneZXTwoLinks_returnsTrue() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_THREE_NEIGHBORS_PLANE_TWO_LINKS) { - boolean[][][] array = rotate(combine(BASE_THREE_NEIGHBORS_PLANE_ZX, - combo, LINKS_THREE_NEIGHBORS_PLANE_ZX), Axis.Y_AXIS, rotation); + boolean[][][] array = + rotate( + combine( + BASE_THREE_NEIGHBORS_PLANE_ZX, + combo, + LINKS_THREE_NEIGHBORS_PLANE_ZX), + Axis.Y_AXIS, + rotation); assertTrue(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_threeNeighborsCornerZeroLinks_returnsFalse() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_THREE_NEIGHBORS_CORNER_ZERO_LINKS) { - boolean[][][] arrayA = rotate(combine(BASE_THREE_NEIGHBORS_CORNER_A, - combo, LINKS_THREE_NEIGHBORS_CORNER_A), Axis.Z_AXIS, rotation); + boolean[][][] arrayA = + rotate( + combine( + BASE_THREE_NEIGHBORS_CORNER_A, + combo, + LINKS_THREE_NEIGHBORS_CORNER_A), + Axis.Z_AXIS, + rotation); assertFalse(potts.getConnectivity(arrayA, false)); - - boolean[][][] arrayB = rotate(combine(BASE_THREE_NEIGHBORS_CORNER_B, - combo, LINKS_THREE_NEIGHBORS_CORNER_B), Axis.Z_AXIS, rotation); + + boolean[][][] arrayB = + rotate( + combine( + BASE_THREE_NEIGHBORS_CORNER_B, + combo, + LINKS_THREE_NEIGHBORS_CORNER_B), + Axis.Z_AXIS, + rotation); assertFalse(potts.getConnectivity(arrayB, false)); } } } - + @Test public void getConnectivity_threeNeighborsCornerOneLink_returnsFalse() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_THREE_NEIGHBORS_CORNER_ONE_LINK) { - boolean[][][] arrayA = rotate(combine(BASE_THREE_NEIGHBORS_CORNER_A, - combo, LINKS_THREE_NEIGHBORS_CORNER_A), Axis.Z_AXIS, rotation); + boolean[][][] arrayA = + rotate( + combine( + BASE_THREE_NEIGHBORS_CORNER_A, + combo, + LINKS_THREE_NEIGHBORS_CORNER_A), + Axis.Z_AXIS, + rotation); assertFalse(potts.getConnectivity(arrayA, false)); - - boolean[][][] arrayB = rotate(combine(BASE_THREE_NEIGHBORS_CORNER_B, - combo, LINKS_THREE_NEIGHBORS_CORNER_B), Axis.Z_AXIS, rotation); + + boolean[][][] arrayB = + rotate( + combine( + BASE_THREE_NEIGHBORS_CORNER_B, + combo, + LINKS_THREE_NEIGHBORS_CORNER_B), + Axis.Z_AXIS, + rotation); assertFalse(potts.getConnectivity(arrayB, false)); } } } - + @Test public void getConnectivity_threeNeighborsCornerTwoLinks_returnsTrue() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_THREE_NEIGHBORS_CORNER_TWO_LINKS) { - boolean[][][] arrayA = rotate(combine(BASE_THREE_NEIGHBORS_CORNER_A, - combo, LINKS_THREE_NEIGHBORS_CORNER_A), Axis.Z_AXIS, rotation); + boolean[][][] arrayA = + rotate( + combine( + BASE_THREE_NEIGHBORS_CORNER_A, + combo, + LINKS_THREE_NEIGHBORS_CORNER_A), + Axis.Z_AXIS, + rotation); assertTrue(potts.getConnectivity(arrayA, false)); - - boolean[][][] arrayB = rotate(combine(BASE_THREE_NEIGHBORS_CORNER_B, - combo, LINKS_THREE_NEIGHBORS_CORNER_B), Axis.Z_AXIS, rotation); + + boolean[][][] arrayB = + rotate( + combine( + BASE_THREE_NEIGHBORS_CORNER_B, + combo, + LINKS_THREE_NEIGHBORS_CORNER_B), + Axis.Z_AXIS, + rotation); assertTrue(potts.getConnectivity(arrayB, false)); } } } - + @Test public void getConnectivity_threeNeighborsCornerThreeLinks_returnsTrue() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_THREE_NEIGHBORS_CORNER_THREE_LINKS) { - boolean[][][] arrayA = rotate(combine(BASE_THREE_NEIGHBORS_CORNER_A, - combo, LINKS_THREE_NEIGHBORS_CORNER_A), Axis.Z_AXIS, rotation); + boolean[][][] arrayA = + rotate( + combine( + BASE_THREE_NEIGHBORS_CORNER_A, + combo, + LINKS_THREE_NEIGHBORS_CORNER_A), + Axis.Z_AXIS, + rotation); assertTrue(potts.getConnectivity(arrayA, false)); - - boolean[][][] arrayB = rotate(combine(BASE_THREE_NEIGHBORS_CORNER_B, - combo, LINKS_THREE_NEIGHBORS_CORNER_B), Axis.Z_AXIS, rotation); + + boolean[][][] arrayB = + rotate( + combine( + BASE_THREE_NEIGHBORS_CORNER_B, + combo, + LINKS_THREE_NEIGHBORS_CORNER_B), + Axis.Z_AXIS, + rotation); assertTrue(potts.getConnectivity(arrayB, false)); } } } - + /* ------------------------------------------------------------------------- * CONNECTIVITY FOR FOUR (4) NEIGHBORS * @@ -1097,547 +1292,688 @@ public void getConnectivity_threeNeighborsCornerThreeLinks_returnsTrue() { * 4 links | 5 combos | connected * 5 links | 1 combo | connected ------------------------------------------------------------------------- */ - - private static final boolean[][][] BASE_FOUR_NEIGHBORS_PLANE_XY = new boolean[][][] { - { - { false, false, false }, - { false, false, false }, - { false, false, false } - }, - { - { false, true, false }, - { true, true, true }, - { false, true, false } - }, - { - { false, false, false }, - { false, false, false }, - { false, false, false } - } - }; - - private static final boolean[][][] BASE_FOUR_NEIGHBORS_PLANE_YZ = new boolean[][][] { - { - { false, false, false }, - { false, true, false }, - { false, false, false } - }, - { - { false, false, false }, - { true, true, true }, - { false, false, false } - }, - { - { false, false, false }, - { false, true, false }, - { false, false, false } - } - }; - - private static final boolean[][][] BASE_FOUR_NEIGHBORS_PLANE_ZX = new boolean[][][] { - { - { false, false, false }, - { false, true, false }, - { false, false, false } - }, - { - { false, true, false }, - { false, true, false }, - { false, true, false } - }, - { - { false, false, false }, - { false, true, false }, - { false, false, false } - } - }; - - private static final boolean[][][] BASE_FOUR_NEIGHBORS_AXIS_X = new boolean[][][] { - { - { false, false, false }, - { false, true, false }, - { false, false, false } - }, - { - { false, true, false }, - { true, true, false }, - { false, true, false } - }, - { - { false, false, false }, - { false, false, false }, - { false, false, false } - } - }; - - private static final boolean[][][] BASE_FOUR_NEIGHBORS_AXIS_Y = new boolean[][][] { - { - { false, false, false }, - { false, true, false }, - { false, false, false } - }, - { - { false, true, false }, - { true, true, true }, - { false, false, false } - }, - { - { false, false, false }, - { false, false, false }, - { false, false, false } - } - }; - - private static final boolean[][][] BASE_FOUR_NEIGHBORS_AXIS_Z = new boolean[][][] { - { - { false, false, false }, - { false, true, false }, - { false, false, false } - }, - { - { false, true, false }, - { true, true, false }, - { false, false, false } - }, - { - { false, false, false }, - { false, true, false }, - { false, false, false } - } - }; - - private static final int[][] LINKS_FOUR_NEIGHBORS_PLANE_XY = new int[][] { - { 1, 1, 1, 1 }, // Z - { 0, 0, 2, 2 }, // X - { 0, 2, 0, 2 }, // Y - }; - - private static final int[][] LINKS_FOUR_NEIGHBORS_PLANE_YZ = new int[][] { - { 0, 0, 2, 2 }, // Z - { 1, 1, 1, 1 }, // X - { 0, 2, 0, 2 }, // Y - }; - - private static final int[][] LINKS_FOUR_NEIGHBORS_PLANE_ZX = new int[][] { - { 0, 0, 2, 2 }, // Z - { 0, 2, 0, 2 }, // Y - { 1, 1, 1, 1 }, // X - }; - - private static final int[][] LINKS_FOUR_NEIGHBORS_AXIS_X = new int[][] { - { 0, 0, 1, 1, 0 }, // Z - { 0, 2, 0, 2, 1 }, // X - { 1, 1, 0, 0, 0 }, // Y - }; - - private static final int[][] LINKS_FOUR_NEIGHBORS_AXIS_Y = new int[][] { - { 0, 0, 1, 1, 0 }, // Z - { 1, 1, 0, 0, 0 }, // X - { 0, 2, 0, 2, 1 }, // Y - }; - - private static final int[][] LINKS_FOUR_NEIGHBORS_AXIS_Z = new int[][] { - { 0, 2, 0, 2, 1 }, // Z - { 0, 0, 1, 1, 0 }, // X - { 1, 1, 0, 0, 0 }, // Y - }; - - private static final int[][] COMBOS_FOUR_NEIGHBORS_PLANE_ZERO_LINKS = new int[][] { { } }; - - private static final int[][] COMBOS_FOUR_NEIGHBORS_PLANE_ONE_LINK = new int[][] { - { 0 }, - { 1 }, - { 2 }, - { 3 }, - }; - - private static final int[][] COMBOS_FOUR_NEIGHBORS_PLANE_TWO_LINKS = new int[][] { - { 0, 1 }, - { 0, 2 }, - { 0, 3 }, - { 1, 2 }, - { 1, 3 }, - { 2, 3 }, - }; - - private static final int[][] COMBOS_FOUR_NEIGHBORS_PLANE_THREE_LINKS = new int[][] { - { 0, 1, 2 }, - { 0, 1, 3 }, - { 0, 2, 3 }, - { 1, 2, 3 }, - }; - - private static final int[][] COMBOS_FOUR_NEIGHBORS_PLANE_FOUR_LINKS = new int[][] { - { 0, 1, 2, 3 }, - }; - - private static final int[][] COMBOS_FOUR_NEIGHBORS_AXIS_ZERO_LINKS = new int[][] { { } }; - - private static final int[][] COMBOS_FOUR_NEIGHBORS_AXIS_ONE_LINK = new int[][] { - { 0 }, - { 1 }, - { 2 }, - { 3 }, - { 4 }, - }; - - private static final int[][] COMBOS_FOUR_NEIGHBORS_AXIS_TWO_LINKS = new int[][] { - { 0, 1 }, - { 0, 2 }, - { 0, 3 }, - { 0, 4 }, - { 1, 2 }, - { 1, 3 }, - { 1, 4 }, - { 2, 3 }, - { 2, 4 }, - { 3, 4 }, - }; - - private static final int[][] COMBOS_FOUR_NEIGHBORS_AXIS_THREE_LINKS_VALID = new int[][] { - { 0, 1, 2 }, - { 0, 1, 3 }, - { 2, 3, 0 }, - { 2, 3, 1 }, - { 4, 0, 1 }, - { 4, 2, 3 }, - { 4, 0, 3 }, - { 4, 1, 2 }, - }; - - private static final int[][] COMBOS_FOUR_NEIGHBORS_AXIS_THREE_LINKS_INVALID = new int[][] { - { 4, 0, 2 }, - { 4, 1, 3 }, - }; - - private static final int[][] COMBOS_FOUR_NEIGHBORS_AXIS_FOUR_LINKS = new int[][] { - { 0, 1, 2, 3 }, - { 0, 1, 2, 4 }, - { 1, 2, 3, 4 }, - { 2, 3, 0, 4 }, - { 3, 0, 1, 4 }, - }; - - private static final int[][] COMBOS_FOUR_NEIGHBORS_AXIS_FIVE_LINKS = new int[][] { - { 0, 1, 2, 3, 4 }, - }; - + + private static final boolean[][][] BASE_FOUR_NEIGHBORS_PLANE_XY = + new boolean[][][] { + { + {false, false, false}, + {false, false, false}, + {false, false, false} + }, + { + {false, true, false}, + {true, true, true}, + {false, true, false} + }, + { + {false, false, false}, + {false, false, false}, + {false, false, false} + } + }; + + private static final boolean[][][] BASE_FOUR_NEIGHBORS_PLANE_YZ = + new boolean[][][] { + { + {false, false, false}, + {false, true, false}, + {false, false, false} + }, + { + {false, false, false}, + {true, true, true}, + {false, false, false} + }, + { + {false, false, false}, + {false, true, false}, + {false, false, false} + } + }; + + private static final boolean[][][] BASE_FOUR_NEIGHBORS_PLANE_ZX = + new boolean[][][] { + { + {false, false, false}, + {false, true, false}, + {false, false, false} + }, + { + {false, true, false}, + {false, true, false}, + {false, true, false} + }, + { + {false, false, false}, + {false, true, false}, + {false, false, false} + } + }; + + private static final boolean[][][] BASE_FOUR_NEIGHBORS_AXIS_X = + new boolean[][][] { + { + {false, false, false}, + {false, true, false}, + {false, false, false} + }, + { + {false, true, false}, + {true, true, false}, + {false, true, false} + }, + { + {false, false, false}, + {false, false, false}, + {false, false, false} + } + }; + + private static final boolean[][][] BASE_FOUR_NEIGHBORS_AXIS_Y = + new boolean[][][] { + { + {false, false, false}, + {false, true, false}, + {false, false, false} + }, + { + {false, true, false}, + {true, true, true}, + {false, false, false} + }, + { + {false, false, false}, + {false, false, false}, + {false, false, false} + } + }; + + private static final boolean[][][] BASE_FOUR_NEIGHBORS_AXIS_Z = + new boolean[][][] { + { + {false, false, false}, + {false, true, false}, + {false, false, false} + }, + { + {false, true, false}, + {true, true, false}, + {false, false, false} + }, + { + {false, false, false}, + {false, true, false}, + {false, false, false} + } + }; + + private static final int[][] LINKS_FOUR_NEIGHBORS_PLANE_XY = + new int[][] { + {1, 1, 1, 1}, // Z + {0, 0, 2, 2}, // X + {0, 2, 0, 2}, // Y + }; + + private static final int[][] LINKS_FOUR_NEIGHBORS_PLANE_YZ = + new int[][] { + {0, 0, 2, 2}, // Z + {1, 1, 1, 1}, // X + {0, 2, 0, 2}, // Y + }; + + private static final int[][] LINKS_FOUR_NEIGHBORS_PLANE_ZX = + new int[][] { + {0, 0, 2, 2}, // Z + {0, 2, 0, 2}, // Y + {1, 1, 1, 1}, // X + }; + + private static final int[][] LINKS_FOUR_NEIGHBORS_AXIS_X = + new int[][] { + {0, 0, 1, 1, 0}, // Z + {0, 2, 0, 2, 1}, // X + {1, 1, 0, 0, 0}, // Y + }; + + private static final int[][] LINKS_FOUR_NEIGHBORS_AXIS_Y = + new int[][] { + {0, 0, 1, 1, 0}, // Z + {1, 1, 0, 0, 0}, // X + {0, 2, 0, 2, 1}, // Y + }; + + private static final int[][] LINKS_FOUR_NEIGHBORS_AXIS_Z = + new int[][] { + {0, 2, 0, 2, 1}, // Z + {0, 0, 1, 1, 0}, // X + {1, 1, 0, 0, 0}, // Y + }; + + private static final int[][] COMBOS_FOUR_NEIGHBORS_PLANE_ZERO_LINKS = new int[][] {{}}; + + private static final int[][] COMBOS_FOUR_NEIGHBORS_PLANE_ONE_LINK = + new int[][] { + {0}, {1}, {2}, {3}, + }; + + private static final int[][] COMBOS_FOUR_NEIGHBORS_PLANE_TWO_LINKS = + new int[][] { + {0, 1}, + {0, 2}, + {0, 3}, + {1, 2}, + {1, 3}, + {2, 3}, + }; + + private static final int[][] COMBOS_FOUR_NEIGHBORS_PLANE_THREE_LINKS = + new int[][] { + {0, 1, 2}, + {0, 1, 3}, + {0, 2, 3}, + {1, 2, 3}, + }; + + private static final int[][] COMBOS_FOUR_NEIGHBORS_PLANE_FOUR_LINKS = + new int[][] { + {0, 1, 2, 3}, + }; + + private static final int[][] COMBOS_FOUR_NEIGHBORS_AXIS_ZERO_LINKS = new int[][] {{}}; + + private static final int[][] COMBOS_FOUR_NEIGHBORS_AXIS_ONE_LINK = + new int[][] { + {0}, {1}, {2}, {3}, {4}, + }; + + private static final int[][] COMBOS_FOUR_NEIGHBORS_AXIS_TWO_LINKS = + new int[][] { + {0, 1}, + {0, 2}, + {0, 3}, + {0, 4}, + {1, 2}, + {1, 3}, + {1, 4}, + {2, 3}, + {2, 4}, + {3, 4}, + }; + + private static final int[][] COMBOS_FOUR_NEIGHBORS_AXIS_THREE_LINKS_VALID = + new int[][] { + {0, 1, 2}, + {0, 1, 3}, + {2, 3, 0}, + {2, 3, 1}, + {4, 0, 1}, + {4, 2, 3}, + {4, 0, 3}, + {4, 1, 2}, + }; + + private static final int[][] COMBOS_FOUR_NEIGHBORS_AXIS_THREE_LINKS_INVALID = + new int[][] { + {4, 0, 2}, + {4, 1, 3}, + }; + + private static final int[][] COMBOS_FOUR_NEIGHBORS_AXIS_FOUR_LINKS = + new int[][] { + {0, 1, 2, 3}, + {0, 1, 2, 4}, + {1, 2, 3, 4}, + {2, 3, 0, 4}, + {3, 0, 1, 4}, + }; + + private static final int[][] COMBOS_FOUR_NEIGHBORS_AXIS_FIVE_LINKS = + new int[][] { + {0, 1, 2, 3, 4}, + }; + @Test public void getConnectivity_fourNeighborsPlaneZeroLinks_returnsFalse() { for (int[] combo : COMBOS_FOUR_NEIGHBORS_PLANE_ZERO_LINKS) { - boolean[][][] arrayXY = combine(BASE_FOUR_NEIGHBORS_PLANE_XY, - combo, LINKS_FOUR_NEIGHBORS_PLANE_XY); + boolean[][][] arrayXY = + combine(BASE_FOUR_NEIGHBORS_PLANE_XY, combo, LINKS_FOUR_NEIGHBORS_PLANE_XY); assertFalse(potts.getConnectivity(arrayXY, false)); - - boolean[][][] arrayYZ = combine(BASE_FOUR_NEIGHBORS_PLANE_YZ, - combo, LINKS_FOUR_NEIGHBORS_PLANE_YZ); + + boolean[][][] arrayYZ = + combine(BASE_FOUR_NEIGHBORS_PLANE_YZ, combo, LINKS_FOUR_NEIGHBORS_PLANE_YZ); assertFalse(potts.getConnectivity(arrayYZ, false)); - - boolean[][][] arrayZX = combine(BASE_FOUR_NEIGHBORS_PLANE_ZX, - combo, LINKS_FOUR_NEIGHBORS_PLANE_ZX); + + boolean[][][] arrayZX = + combine(BASE_FOUR_NEIGHBORS_PLANE_ZX, combo, LINKS_FOUR_NEIGHBORS_PLANE_ZX); assertFalse(potts.getConnectivity(arrayZX, false)); } } - + @Test public void getConnectivity_fourNeighborsPlaneOneLink_returnsFalse() { for (int[] combo : COMBOS_FOUR_NEIGHBORS_PLANE_ONE_LINK) { - boolean[][][] arrayXY = combine(BASE_FOUR_NEIGHBORS_PLANE_XY, - combo, LINKS_FOUR_NEIGHBORS_PLANE_XY); + boolean[][][] arrayXY = + combine(BASE_FOUR_NEIGHBORS_PLANE_XY, combo, LINKS_FOUR_NEIGHBORS_PLANE_XY); assertFalse(potts.getConnectivity(arrayXY, false)); - - boolean[][][] arrayYZ = combine(BASE_FOUR_NEIGHBORS_PLANE_YZ, - combo, LINKS_FOUR_NEIGHBORS_PLANE_YZ); + + boolean[][][] arrayYZ = + combine(BASE_FOUR_NEIGHBORS_PLANE_YZ, combo, LINKS_FOUR_NEIGHBORS_PLANE_YZ); assertFalse(potts.getConnectivity(arrayYZ, false)); - - boolean[][][] arrayZX = combine(BASE_FOUR_NEIGHBORS_PLANE_ZX, - combo, LINKS_FOUR_NEIGHBORS_PLANE_ZX); + + boolean[][][] arrayZX = + combine(BASE_FOUR_NEIGHBORS_PLANE_ZX, combo, LINKS_FOUR_NEIGHBORS_PLANE_ZX); assertFalse(potts.getConnectivity(arrayZX, false)); } } - + @Test public void getConnectivity_fourNeighborsPlaneTwoLinks_returnsFalse() { for (int[] combo : COMBOS_FOUR_NEIGHBORS_PLANE_TWO_LINKS) { - boolean[][][] arrayXY = combine(BASE_FOUR_NEIGHBORS_PLANE_XY, - combo, LINKS_FOUR_NEIGHBORS_PLANE_XY); + boolean[][][] arrayXY = + combine(BASE_FOUR_NEIGHBORS_PLANE_XY, combo, LINKS_FOUR_NEIGHBORS_PLANE_XY); assertFalse(potts.getConnectivity(arrayXY, false)); - - boolean[][][] arrayYZ = combine(BASE_FOUR_NEIGHBORS_PLANE_YZ, - combo, LINKS_FOUR_NEIGHBORS_PLANE_YZ); + + boolean[][][] arrayYZ = + combine(BASE_FOUR_NEIGHBORS_PLANE_YZ, combo, LINKS_FOUR_NEIGHBORS_PLANE_YZ); assertFalse(potts.getConnectivity(arrayYZ, false)); - - boolean[][][] arrayZX = combine(BASE_FOUR_NEIGHBORS_PLANE_ZX, - combo, LINKS_FOUR_NEIGHBORS_PLANE_ZX); + + boolean[][][] arrayZX = + combine(BASE_FOUR_NEIGHBORS_PLANE_ZX, combo, LINKS_FOUR_NEIGHBORS_PLANE_ZX); assertFalse(potts.getConnectivity(arrayZX, false)); } } - + @Test public void getConnectivity_fourNeighborsPlaneThreeLinks_returnsTrue() { for (int[] combo : COMBOS_FOUR_NEIGHBORS_PLANE_THREE_LINKS) { - boolean[][][] arrayXY = combine(BASE_FOUR_NEIGHBORS_PLANE_XY, - combo, LINKS_FOUR_NEIGHBORS_PLANE_XY); + boolean[][][] arrayXY = + combine(BASE_FOUR_NEIGHBORS_PLANE_XY, combo, LINKS_FOUR_NEIGHBORS_PLANE_XY); assertTrue(potts.getConnectivity(arrayXY, false)); - - boolean[][][] arrayYZ = combine(BASE_FOUR_NEIGHBORS_PLANE_YZ, - combo, LINKS_FOUR_NEIGHBORS_PLANE_YZ); + + boolean[][][] arrayYZ = + combine(BASE_FOUR_NEIGHBORS_PLANE_YZ, combo, LINKS_FOUR_NEIGHBORS_PLANE_YZ); assertTrue(potts.getConnectivity(arrayYZ, false)); - - boolean[][][] arrayZX = combine(BASE_FOUR_NEIGHBORS_PLANE_ZX, - combo, LINKS_FOUR_NEIGHBORS_PLANE_ZX); + + boolean[][][] arrayZX = + combine(BASE_FOUR_NEIGHBORS_PLANE_ZX, combo, LINKS_FOUR_NEIGHBORS_PLANE_ZX); assertTrue(potts.getConnectivity(arrayZX, false)); } } - + @Test public void getConnectivity_fourNeighborsPlaneFourLinks_returnsTrue() { for (int[] combo : COMBOS_FOUR_NEIGHBORS_PLANE_FOUR_LINKS) { - boolean[][][] arrayXY = combine(BASE_FOUR_NEIGHBORS_PLANE_XY, - combo, LINKS_FOUR_NEIGHBORS_PLANE_XY); + boolean[][][] arrayXY = + combine(BASE_FOUR_NEIGHBORS_PLANE_XY, combo, LINKS_FOUR_NEIGHBORS_PLANE_XY); assertTrue(potts.getConnectivity(arrayXY, false)); - - boolean[][][] arrayYZ = combine(BASE_FOUR_NEIGHBORS_PLANE_YZ, - combo, LINKS_FOUR_NEIGHBORS_PLANE_YZ); + + boolean[][][] arrayYZ = + combine(BASE_FOUR_NEIGHBORS_PLANE_YZ, combo, LINKS_FOUR_NEIGHBORS_PLANE_YZ); assertTrue(potts.getConnectivity(arrayYZ, false)); - - boolean[][][] arrayZX = combine(BASE_FOUR_NEIGHBORS_PLANE_ZX, - combo, LINKS_FOUR_NEIGHBORS_PLANE_ZX); + + boolean[][][] arrayZX = + combine(BASE_FOUR_NEIGHBORS_PLANE_ZX, combo, LINKS_FOUR_NEIGHBORS_PLANE_ZX); assertTrue(potts.getConnectivity(arrayZX, false)); } } - + @Test public void getConnectivity_fourNeighborsAxisXZeroLinks_returnsFalse() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_FOUR_NEIGHBORS_AXIS_ZERO_LINKS) { - boolean[][][] array = rotate(combine(BASE_FOUR_NEIGHBORS_AXIS_X, - combo, LINKS_FOUR_NEIGHBORS_AXIS_X), Axis.X_AXIS, rotation); + boolean[][][] array = + rotate( + combine( + BASE_FOUR_NEIGHBORS_AXIS_X, + combo, + LINKS_FOUR_NEIGHBORS_AXIS_X), + Axis.X_AXIS, + rotation); assertFalse(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_fourNeighborsAxisYZeroLinks_returnsFalse() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_FOUR_NEIGHBORS_AXIS_ZERO_LINKS) { - boolean[][][] array = rotate(combine(BASE_FOUR_NEIGHBORS_AXIS_Y, - combo, LINKS_FOUR_NEIGHBORS_AXIS_Y), Axis.Y_AXIS, rotation); + boolean[][][] array = + rotate( + combine( + BASE_FOUR_NEIGHBORS_AXIS_Y, + combo, + LINKS_FOUR_NEIGHBORS_AXIS_Y), + Axis.Y_AXIS, + rotation); assertFalse(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_fourNeighborsAxisZZeroLinks_returnsFalse() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_FOUR_NEIGHBORS_AXIS_ZERO_LINKS) { - boolean[][][] array = rotate(combine(BASE_FOUR_NEIGHBORS_AXIS_Z, - combo, LINKS_FOUR_NEIGHBORS_AXIS_Z), Axis.Z_AXIS, rotation); + boolean[][][] array = + rotate( + combine( + BASE_FOUR_NEIGHBORS_AXIS_Z, + combo, + LINKS_FOUR_NEIGHBORS_AXIS_Z), + Axis.Z_AXIS, + rotation); assertFalse(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_fourNeighborsAxisXOneLink_returnsFalse() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_FOUR_NEIGHBORS_AXIS_ONE_LINK) { - boolean[][][] array = rotate(combine(BASE_FOUR_NEIGHBORS_AXIS_X, - combo, LINKS_FOUR_NEIGHBORS_AXIS_X), Axis.X_AXIS, rotation); + boolean[][][] array = + rotate( + combine( + BASE_FOUR_NEIGHBORS_AXIS_X, + combo, + LINKS_FOUR_NEIGHBORS_AXIS_X), + Axis.X_AXIS, + rotation); assertFalse(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_fourNeighborsAxisYOneLink_returnsFalse() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_FOUR_NEIGHBORS_AXIS_ONE_LINK) { - boolean[][][] array = rotate(combine(BASE_FOUR_NEIGHBORS_AXIS_Y, - combo, LINKS_FOUR_NEIGHBORS_AXIS_Y), Axis.Y_AXIS, rotation); + boolean[][][] array = + rotate( + combine( + BASE_FOUR_NEIGHBORS_AXIS_Y, + combo, + LINKS_FOUR_NEIGHBORS_AXIS_Y), + Axis.Y_AXIS, + rotation); assertFalse(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_fourNeighborsAxisZOneLink_returnsFalse() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_FOUR_NEIGHBORS_AXIS_ONE_LINK) { - boolean[][][] array = rotate(combine(BASE_FOUR_NEIGHBORS_AXIS_Z, - combo, LINKS_FOUR_NEIGHBORS_AXIS_Z), Axis.Z_AXIS, rotation); + boolean[][][] array = + rotate( + combine( + BASE_FOUR_NEIGHBORS_AXIS_Z, + combo, + LINKS_FOUR_NEIGHBORS_AXIS_Z), + Axis.Z_AXIS, + rotation); assertFalse(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_fourNeighborsAxisXTwoLinks_returnsFalse() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_FOUR_NEIGHBORS_AXIS_TWO_LINKS) { - boolean[][][] array = rotate(combine(BASE_FOUR_NEIGHBORS_AXIS_X, - combo, LINKS_FOUR_NEIGHBORS_AXIS_X), Axis.X_AXIS, rotation); + boolean[][][] array = + rotate( + combine( + BASE_FOUR_NEIGHBORS_AXIS_X, + combo, + LINKS_FOUR_NEIGHBORS_AXIS_X), + Axis.X_AXIS, + rotation); assertFalse(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_fourNeighborsAxisYTwoLinks_returnsFalse() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_FOUR_NEIGHBORS_AXIS_TWO_LINKS) { - boolean[][][] array = rotate(combine(BASE_FOUR_NEIGHBORS_AXIS_Y, - combo, LINKS_FOUR_NEIGHBORS_AXIS_Y), Axis.Y_AXIS, rotation); + boolean[][][] array = + rotate( + combine( + BASE_FOUR_NEIGHBORS_AXIS_Y, + combo, + LINKS_FOUR_NEIGHBORS_AXIS_Y), + Axis.Y_AXIS, + rotation); assertFalse(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_fourNeighborsAxisZTwoLinks_returnsFalse() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_FOUR_NEIGHBORS_AXIS_TWO_LINKS) { - boolean[][][] array = rotate(combine(BASE_FOUR_NEIGHBORS_AXIS_Z, - combo, LINKS_FOUR_NEIGHBORS_AXIS_Z), Axis.Z_AXIS, rotation); + boolean[][][] array = + rotate( + combine( + BASE_FOUR_NEIGHBORS_AXIS_Z, + combo, + LINKS_FOUR_NEIGHBORS_AXIS_Z), + Axis.Z_AXIS, + rotation); assertFalse(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_fourNeighborsAxisXThreeLinksValid_returnsTrue() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_FOUR_NEIGHBORS_AXIS_THREE_LINKS_VALID) { - boolean[][][] array = rotate(combine(BASE_FOUR_NEIGHBORS_AXIS_X, - combo, LINKS_FOUR_NEIGHBORS_AXIS_X), Axis.X_AXIS, rotation); + boolean[][][] array = + rotate( + combine( + BASE_FOUR_NEIGHBORS_AXIS_X, + combo, + LINKS_FOUR_NEIGHBORS_AXIS_X), + Axis.X_AXIS, + rotation); assertTrue(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_fourNeighborsAxisYThreeLinksValid_returnsTrue() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_FOUR_NEIGHBORS_AXIS_THREE_LINKS_VALID) { - boolean[][][] array = rotate(combine(BASE_FOUR_NEIGHBORS_AXIS_Y, - combo, LINKS_FOUR_NEIGHBORS_AXIS_Y), Axis.Y_AXIS, rotation); + boolean[][][] array = + rotate( + combine( + BASE_FOUR_NEIGHBORS_AXIS_Y, + combo, + LINKS_FOUR_NEIGHBORS_AXIS_Y), + Axis.Y_AXIS, + rotation); assertTrue(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_fourNeighborsAxisZThreeLinksValid_returnsTrue() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_FOUR_NEIGHBORS_AXIS_THREE_LINKS_VALID) { - boolean[][][] array = rotate(combine(BASE_FOUR_NEIGHBORS_AXIS_Z, - combo, LINKS_FOUR_NEIGHBORS_AXIS_Z), Axis.Z_AXIS, rotation); + boolean[][][] array = + rotate( + combine( + BASE_FOUR_NEIGHBORS_AXIS_Z, + combo, + LINKS_FOUR_NEIGHBORS_AXIS_Z), + Axis.Z_AXIS, + rotation); assertTrue(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_fourNeighborsAxisXThreeLinksInvalid_returnsFalse() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_FOUR_NEIGHBORS_AXIS_THREE_LINKS_INVALID) { - boolean[][][] array = rotate(combine(BASE_FOUR_NEIGHBORS_AXIS_X, - combo, LINKS_FOUR_NEIGHBORS_AXIS_X), Axis.X_AXIS, rotation); + boolean[][][] array = + rotate( + combine( + BASE_FOUR_NEIGHBORS_AXIS_X, + combo, + LINKS_FOUR_NEIGHBORS_AXIS_X), + Axis.X_AXIS, + rotation); assertFalse(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_fourNeighborsAxisYThreeLinksInvalid_returnsFalse() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_FOUR_NEIGHBORS_AXIS_THREE_LINKS_INVALID) { - boolean[][][] array = rotate(combine(BASE_FOUR_NEIGHBORS_AXIS_Y, - combo, LINKS_FOUR_NEIGHBORS_AXIS_Y), Axis.Y_AXIS, rotation); + boolean[][][] array = + rotate( + combine( + BASE_FOUR_NEIGHBORS_AXIS_Y, + combo, + LINKS_FOUR_NEIGHBORS_AXIS_Y), + Axis.Y_AXIS, + rotation); assertFalse(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_fourNeighborsAxisZThreeLinksInvalid_returnsFalse() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_FOUR_NEIGHBORS_AXIS_THREE_LINKS_INVALID) { - boolean[][][] array = rotate(combine(BASE_FOUR_NEIGHBORS_AXIS_Z, - combo, LINKS_FOUR_NEIGHBORS_AXIS_Z), Axis.Z_AXIS, rotation); + boolean[][][] array = + rotate( + combine( + BASE_FOUR_NEIGHBORS_AXIS_Z, + combo, + LINKS_FOUR_NEIGHBORS_AXIS_Z), + Axis.Z_AXIS, + rotation); assertFalse(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_fourNeighborsAxisXFourLinks_returnsTrue() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_FOUR_NEIGHBORS_AXIS_FOUR_LINKS) { - boolean[][][] array = rotate(combine(BASE_FOUR_NEIGHBORS_AXIS_X, - combo, LINKS_FOUR_NEIGHBORS_AXIS_X), Axis.X_AXIS, rotation); + boolean[][][] array = + rotate( + combine( + BASE_FOUR_NEIGHBORS_AXIS_X, + combo, + LINKS_FOUR_NEIGHBORS_AXIS_X), + Axis.X_AXIS, + rotation); assertTrue(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_fourNeighborsAxisYFourLinks_returnsTrue() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_FOUR_NEIGHBORS_AXIS_FOUR_LINKS) { - boolean[][][] array = rotate(combine(BASE_FOUR_NEIGHBORS_AXIS_Y, - combo, LINKS_FOUR_NEIGHBORS_AXIS_Y), Axis.Y_AXIS, rotation); + boolean[][][] array = + rotate( + combine( + BASE_FOUR_NEIGHBORS_AXIS_Y, + combo, + LINKS_FOUR_NEIGHBORS_AXIS_Y), + Axis.Y_AXIS, + rotation); assertTrue(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_fourNeighborsAxisZFourLinks_returnsTrue() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_FOUR_NEIGHBORS_AXIS_FOUR_LINKS) { - boolean[][][] array = rotate(combine(BASE_FOUR_NEIGHBORS_AXIS_Z, - combo, LINKS_FOUR_NEIGHBORS_AXIS_Z), Axis.Z_AXIS, rotation); + boolean[][][] array = + rotate( + combine( + BASE_FOUR_NEIGHBORS_AXIS_Z, + combo, + LINKS_FOUR_NEIGHBORS_AXIS_Z), + Axis.Z_AXIS, + rotation); assertTrue(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_fourNeighborsAxisXFiveLinks_returnsTrue() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_FOUR_NEIGHBORS_AXIS_FIVE_LINKS) { - boolean[][][] array = rotate(combine(BASE_FOUR_NEIGHBORS_AXIS_X, - combo, LINKS_FOUR_NEIGHBORS_AXIS_X), Axis.X_AXIS, rotation); + boolean[][][] array = + rotate( + combine( + BASE_FOUR_NEIGHBORS_AXIS_X, + combo, + LINKS_FOUR_NEIGHBORS_AXIS_X), + Axis.X_AXIS, + rotation); assertTrue(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_fourNeighborsAxisYFiveLinks_returnsTrue() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_FOUR_NEIGHBORS_AXIS_FIVE_LINKS) { - boolean[][][] array = rotate(combine(BASE_FOUR_NEIGHBORS_AXIS_Y, - combo, LINKS_FOUR_NEIGHBORS_AXIS_Y), Axis.Y_AXIS, rotation); + boolean[][][] array = + rotate( + combine( + BASE_FOUR_NEIGHBORS_AXIS_Y, + combo, + LINKS_FOUR_NEIGHBORS_AXIS_Y), + Axis.Y_AXIS, + rotation); assertTrue(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_fourNeighborsAxisZFiveLinks_returnsTrue() { for (int rotation = 0; rotation < 4; rotation++) { for (int[] combo : COMBOS_FOUR_NEIGHBORS_AXIS_FIVE_LINKS) { - boolean[][][] array = rotate(combine(BASE_FOUR_NEIGHBORS_AXIS_Z, - combo, LINKS_FOUR_NEIGHBORS_AXIS_Z), Axis.Z_AXIS, rotation); + boolean[][][] array = + rotate( + combine( + BASE_FOUR_NEIGHBORS_AXIS_Z, + combo, + LINKS_FOUR_NEIGHBORS_AXIS_Z), + Axis.Z_AXIS, + rotation); assertTrue(potts.getConnectivity(array, false)); } } } - + /* ------------------------------------------------------------------------- * CONNECTIVITY FOR FIVE (5) NEIGHBORS * @@ -1655,128 +1991,136 @@ public void getConnectivity_fourNeighborsAxisZFiveLinks_returnsTrue() { * 7 links | 8 combos | connected * 8 links | 1 combo | connected ------------------------------------------------------------------------- */ - - private static final boolean[][][] BASE_FIVE_NEIGHBORS = new boolean[][][] { - { - { false, false, false }, - { false, true, false }, - { false, false, false } - }, - { - { false, true, false }, - { true, true, true }, - { false, true, false } - }, - { - { false, false, false }, - { false, false, false }, - { false, false, false } - } - }; - - private static final int[][] LINKS_FIVE_NEIGHBORS = new int[][] { - { 0, 0, 0, 0, 1, 1, 1, 1 }, // Z - { 0, 1, 1, 2, 0, 0, 2, 2 }, // X - { 1, 0, 2, 1, 0, 2, 0, 2 }, // Y - }; - - private static final int[][] COMBOS_FIVE_NEIGHBORS_ZERO_LINKS = new int[][] { { } }; - + + private static final boolean[][][] BASE_FIVE_NEIGHBORS = + new boolean[][][] { + { + {false, false, false}, + {false, true, false}, + {false, false, false} + }, + { + {false, true, false}, + {true, true, true}, + {false, true, false} + }, + { + {false, false, false}, + {false, false, false}, + {false, false, false} + } + }; + + private static final int[][] LINKS_FIVE_NEIGHBORS = + new int[][] { + {0, 0, 0, 0, 1, 1, 1, 1}, // Z + {0, 1, 1, 2, 0, 0, 2, 2}, // X + {1, 0, 2, 1, 0, 2, 0, 2}, // Y + }; + + private static final int[][] COMBOS_FIVE_NEIGHBORS_ZERO_LINKS = new int[][] {{}}; + private static final int[][] COMBOS_FIVE_NEIGHBORS_ONE_LINK = new int[8][1]; - + private static final int[][] COMBOS_FIVE_NEIGHBORS_TWO_LINKS = new int[28][2]; - + private static final int[][] COMBOS_FIVE_NEIGHBORS_THREE_LINKS = new int[56][3]; - - private static final int[][] COMBOS_FIVE_NEIGHBORS_FOUR_LINKS_VALID = new int[][] { - // 4 plane - { 0, 1, 2, 3 }, - - // 2 plane, 2 corner - { 0, 3, 4, 7 }, - { 0, 3, 5, 6 }, - { 0, 3, 4, 5 }, - { 0, 3, 6, 7 }, - { 1, 2, 4, 7 }, - { 1, 2, 5, 6 }, - { 1, 2, 4, 6 }, - { 1, 2, 5, 7 }, - }; - - private static final int[][] COMBOS_FIVE_NEIGHBORS_FOUR_LINKS_INVALID = new int[][] { - // 4 corner - { 4, 5, 6, 7 }, - - // 2 plane, 2 corner - { 0, 3, 4, 6 }, - { 0, 3, 5, 7 }, - { 1, 2, 4, 5 }, - { 1, 2, 6, 7 }, - }; - - private static final int[][] COMBOS_FIVE_NEIGHBORS_FOUR_LINKS_VALID_SYMMETRY = new int[][] { - // 3 corners, 1 plane - { 4, 5, 6, 0 }, - { 4, 5, 6, 1 }, - { 4, 5, 6, 2 }, - { 4, 5, 6, 3 }, - - // 3 plane, 1 corner - { 0, 1, 2, 6 }, - { 0, 1, 2, 7 }, - - // 2 plane, 2 corner - { 0, 1, 5, 7 }, - { 0, 1, 5, 6 }, - { 0, 1, 6, 7 }, - }; - - private static final int[][] COMBOS_FIVE_NEIGHBORS_FOUR_LINKS_INVALID_SYMMETRY = new int[][] { - // 3 plane, 1 corner - { 0, 1, 2, 4 }, - { 0, 1, 2, 5 }, - - // 2 plane, 2 corner - { 0, 1, 4, 5 }, - { 0, 1, 4, 6 }, - { 0, 1, 4, 7 }, - }; - - private static final int[][] COMBOS_FIVE_NEIGHBORS_FIVE_LINKS_VALID_SYMMETRY = new int[][] { - // 4 plane, 1 corner - { 0, 1, 2, 3, 4 }, - - // 3 plane, 2 corner - { 0, 1, 2, 4, 6 }, - { 0, 1, 2, 4, 7 }, - { 0, 1, 2, 5, 6 }, - { 0, 1, 2, 5, 7 }, - { 0, 1, 2, 6, 7 }, - - // 2 plane, 3 corner - { 4, 5, 6, 0, 1 }, - { 4, 5, 6, 0, 2 }, - { 4, 5, 6, 0, 3 }, - { 4, 5, 6, 1, 2 }, - { 4, 5, 6, 1, 3 }, - { 4, 5, 6, 2, 3 }, - - // 1 plane, 4 corner - { 0, 4, 5, 6, 7 }, - }; - - private static final int[][] COMBOS_FIVE_NEIGHBORS_FIVE_LINKS_INVALID_SYMMETRY = new int[][] { - // 3 plane, 2 corner - { 0, 1, 2, 4, 5 }, - }; - + + private static final int[][] COMBOS_FIVE_NEIGHBORS_FOUR_LINKS_VALID = + new int[][] { + // 4 plane + {0, 1, 2, 3}, + + // 2 plane, 2 corner + {0, 3, 4, 7}, + {0, 3, 5, 6}, + {0, 3, 4, 5}, + {0, 3, 6, 7}, + {1, 2, 4, 7}, + {1, 2, 5, 6}, + {1, 2, 4, 6}, + {1, 2, 5, 7}, + }; + + private static final int[][] COMBOS_FIVE_NEIGHBORS_FOUR_LINKS_INVALID = + new int[][] { + // 4 corner + {4, 5, 6, 7}, + + // 2 plane, 2 corner + {0, 3, 4, 6}, + {0, 3, 5, 7}, + {1, 2, 4, 5}, + {1, 2, 6, 7}, + }; + + private static final int[][] COMBOS_FIVE_NEIGHBORS_FOUR_LINKS_VALID_SYMMETRY = + new int[][] { + // 3 corners, 1 plane + {4, 5, 6, 0}, + {4, 5, 6, 1}, + {4, 5, 6, 2}, + {4, 5, 6, 3}, + + // 3 plane, 1 corner + {0, 1, 2, 6}, + {0, 1, 2, 7}, + + // 2 plane, 2 corner + {0, 1, 5, 7}, + {0, 1, 5, 6}, + {0, 1, 6, 7}, + }; + + private static final int[][] COMBOS_FIVE_NEIGHBORS_FOUR_LINKS_INVALID_SYMMETRY = + new int[][] { + // 3 plane, 1 corner + {0, 1, 2, 4}, + {0, 1, 2, 5}, + + // 2 plane, 2 corner + {0, 1, 4, 5}, + {0, 1, 4, 6}, + {0, 1, 4, 7}, + }; + + private static final int[][] COMBOS_FIVE_NEIGHBORS_FIVE_LINKS_VALID_SYMMETRY = + new int[][] { + // 4 plane, 1 corner + {0, 1, 2, 3, 4}, + + // 3 plane, 2 corner + {0, 1, 2, 4, 6}, + {0, 1, 2, 4, 7}, + {0, 1, 2, 5, 6}, + {0, 1, 2, 5, 7}, + {0, 1, 2, 6, 7}, + + // 2 plane, 3 corner + {4, 5, 6, 0, 1}, + {4, 5, 6, 0, 2}, + {4, 5, 6, 0, 3}, + {4, 5, 6, 1, 2}, + {4, 5, 6, 1, 3}, + {4, 5, 6, 2, 3}, + + // 1 plane, 4 corner + {0, 4, 5, 6, 7}, + }; + + private static final int[][] COMBOS_FIVE_NEIGHBORS_FIVE_LINKS_INVALID_SYMMETRY = + new int[][] { + // 3 plane, 2 corner + {0, 1, 2, 4, 5}, + }; + private static final int[][] COMBOS_FIVE_NEIGHBORS_SIX_LINKS = new int[28][6]; - + private static final int[][] COMBOS_FIVE_NEIGHBORS_SEVEN_LINKS = new int[8][6]; - + private static final int[][] COMBOS_FIVE_NEIGHBORS_EIGHT_LINKS = new int[1][6]; - - @BeforeClass + + @BeforeAll public static void createFiveNeighborCombos() { populate(COMBOS_FIVE_NEIGHBORS_ONE_LINK, 8, 1); populate(COMBOS_FIVE_NEIGHBORS_TWO_LINKS, 8, 2); @@ -1785,158 +2129,190 @@ public static void createFiveNeighborCombos() { populate(COMBOS_FIVE_NEIGHBORS_SEVEN_LINKS, 8, 7); populate(COMBOS_FIVE_NEIGHBORS_EIGHT_LINKS, 8, 8); } - + @Test public void getConnectivity_fiveNeighborsZeroLinks_returnsFalse() { for (int rotation = 0; rotation < 6; rotation++) { for (int[] combo : COMBOS_FIVE_NEIGHBORS_ZERO_LINKS) { - boolean[][][] array = rotate(combine(BASE_FIVE_NEIGHBORS, - combo, LINKS_FIVE_NEIGHBORS), rotation); + boolean[][][] array = + rotate(combine(BASE_FIVE_NEIGHBORS, combo, LINKS_FIVE_NEIGHBORS), rotation); assertFalse(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_fiveNeighborsOneLink_returnsFalse() { for (int rotation = 0; rotation < 6; rotation++) { for (int[] combo : COMBOS_FIVE_NEIGHBORS_ONE_LINK) { - boolean[][][] array = rotate(combine(BASE_FIVE_NEIGHBORS, - combo, LINKS_FIVE_NEIGHBORS), rotation); + boolean[][][] array = + rotate(combine(BASE_FIVE_NEIGHBORS, combo, LINKS_FIVE_NEIGHBORS), rotation); assertFalse(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_fiveNeighborsTwoLinks_returnsFalse() { for (int rotation = 0; rotation < 6; rotation++) { for (int[] combo : COMBOS_FIVE_NEIGHBORS_TWO_LINKS) { - boolean[][][] array = rotate(combine(BASE_FIVE_NEIGHBORS, - combo, LINKS_FIVE_NEIGHBORS), rotation); + boolean[][][] array = + rotate(combine(BASE_FIVE_NEIGHBORS, combo, LINKS_FIVE_NEIGHBORS), rotation); assertFalse(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_fiveNeighborsThreeLinks_returnsFalse() { for (int rotation = 0; rotation < 6; rotation++) { for (int[] combo : COMBOS_FIVE_NEIGHBORS_THREE_LINKS) { - boolean[][][] array = rotate(combine(BASE_FIVE_NEIGHBORS, - combo, LINKS_FIVE_NEIGHBORS), rotation); + boolean[][][] array = + rotate(combine(BASE_FIVE_NEIGHBORS, combo, LINKS_FIVE_NEIGHBORS), rotation); assertFalse(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_fiveNeighborsFourLinksValid_returnsTrue() { for (int rotation = 0; rotation < 6; rotation++) { for (int[] combo : COMBOS_FIVE_NEIGHBORS_FOUR_LINKS_VALID) { - boolean[][][] array = rotate(combine(BASE_FIVE_NEIGHBORS, - combo, LINKS_FIVE_NEIGHBORS), rotation); + boolean[][][] array = + rotate(combine(BASE_FIVE_NEIGHBORS, combo, LINKS_FIVE_NEIGHBORS), rotation); assertTrue(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_fiveNeighborsFourLinksInvalid_returnsFalse() { for (int rotation = 0; rotation < 6; rotation++) { for (int[] combo : COMBOS_FIVE_NEIGHBORS_FOUR_LINKS_INVALID) { - boolean[][][] array = rotate(combine(BASE_FIVE_NEIGHBORS, - combo, LINKS_FIVE_NEIGHBORS), rotation); + boolean[][][] array = + rotate(combine(BASE_FIVE_NEIGHBORS, combo, LINKS_FIVE_NEIGHBORS), rotation); assertFalse(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_fiveNeighborsFourLinksValidSymmetry_returnsTrue() { for (int rotation = 0; rotation < 6; rotation++) { for (int symmetry = 0; symmetry < 4; symmetry++) { for (int[] combo : COMBOS_FIVE_NEIGHBORS_FOUR_LINKS_VALID_SYMMETRY) { - boolean[][][] array = rotate(rotate(combine(BASE_FIVE_NEIGHBORS, - combo, LINKS_FIVE_NEIGHBORS), Axis.Z_AXIS, symmetry), rotation); + boolean[][][] array = + rotate( + rotate( + combine( + BASE_FIVE_NEIGHBORS, + combo, + LINKS_FIVE_NEIGHBORS), + Axis.Z_AXIS, + symmetry), + rotation); assertTrue(potts.getConnectivity(array, false)); } } } } - + @Test public void getConnectivity_fiveNeighborsFourLinksInvalidSymmetry_returnsFalse() { for (int rotation = 0; rotation < 6; rotation++) { for (int symmetry = 0; symmetry < 4; symmetry++) { for (int[] combo : COMBOS_FIVE_NEIGHBORS_FOUR_LINKS_INVALID_SYMMETRY) { - boolean[][][] array = rotate(rotate(combine(BASE_FIVE_NEIGHBORS, - combo, LINKS_FIVE_NEIGHBORS), Axis.Z_AXIS, symmetry), rotation); + boolean[][][] array = + rotate( + rotate( + combine( + BASE_FIVE_NEIGHBORS, + combo, + LINKS_FIVE_NEIGHBORS), + Axis.Z_AXIS, + symmetry), + rotation); assertFalse(potts.getConnectivity(array, false)); } } } } - + @Test public void getConnectivity_fiveNeighborsFiveLinksValidSymmetry_returnsTrue() { for (int rotation = 0; rotation < 6; rotation++) { for (int symmetry = 0; symmetry < 4; symmetry++) { for (int[] combo : COMBOS_FIVE_NEIGHBORS_FIVE_LINKS_VALID_SYMMETRY) { - boolean[][][] array = rotate(rotate(combine(BASE_FIVE_NEIGHBORS, - combo, LINKS_FIVE_NEIGHBORS), Axis.Z_AXIS, symmetry), rotation); + boolean[][][] array = + rotate( + rotate( + combine( + BASE_FIVE_NEIGHBORS, + combo, + LINKS_FIVE_NEIGHBORS), + Axis.Z_AXIS, + symmetry), + rotation); assertTrue(potts.getConnectivity(array, false)); } } } } - + @Test public void getConnectivity_fiveNeighborsFiveLinksInvalidSymmetry_returnsFalse() { for (int rotation = 0; rotation < 6; rotation++) { for (int symmetry = 0; symmetry < 4; symmetry++) { for (int[] combo : COMBOS_FIVE_NEIGHBORS_FIVE_LINKS_INVALID_SYMMETRY) { - boolean[][][] array = rotate(rotate(combine(BASE_FIVE_NEIGHBORS, - combo, LINKS_FIVE_NEIGHBORS), Axis.Z_AXIS, symmetry), rotation); + boolean[][][] array = + rotate( + rotate( + combine( + BASE_FIVE_NEIGHBORS, + combo, + LINKS_FIVE_NEIGHBORS), + Axis.Z_AXIS, + symmetry), + rotation); assertFalse(potts.getConnectivity(array, false)); } } } } - + @Test public void getConnectivity_fiveNeighborsSixLinks_returnsTrue() { for (int rotation = 0; rotation < 6; rotation++) { for (int[] combo : COMBOS_FIVE_NEIGHBORS_SIX_LINKS) { - boolean[][][] array = rotate(combine(BASE_FIVE_NEIGHBORS, - combo, LINKS_FIVE_NEIGHBORS), rotation); + boolean[][][] array = + rotate(combine(BASE_FIVE_NEIGHBORS, combo, LINKS_FIVE_NEIGHBORS), rotation); assertTrue(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_fiveNeighborsSevenLinks_returnsTrue() { for (int rotation = 0; rotation < 6; rotation++) { for (int[] combo : COMBOS_FIVE_NEIGHBORS_SEVEN_LINKS) { - boolean[][][] array = rotate(combine(BASE_FIVE_NEIGHBORS, - combo, LINKS_FIVE_NEIGHBORS), rotation); + boolean[][][] array = + rotate(combine(BASE_FIVE_NEIGHBORS, combo, LINKS_FIVE_NEIGHBORS), rotation); assertTrue(potts.getConnectivity(array, false)); } } } - + @Test public void getConnectivity_fiveNeighborsEightLinks_returnsTrue() { for (int rotation = 0; rotation < 6; rotation++) { for (int[] combo : COMBOS_FIVE_NEIGHBORS_EIGHT_LINKS) { - boolean[][][] array = rotate(combine(BASE_FIVE_NEIGHBORS, - combo, LINKS_FIVE_NEIGHBORS), rotation); + boolean[][][] array = + rotate(combine(BASE_FIVE_NEIGHBORS, combo, LINKS_FIVE_NEIGHBORS), rotation); assertTrue(potts.getConnectivity(array, false)); } } } - + /* ------------------------------------------------------------------------- * CONNECTIVITY FOR SIX (6) NEIGHBORS * @@ -1944,46 +2320,52 @@ public void getConnectivity_fiveNeighborsEightLinks_returnsTrue() { * depends on the ID of the voxel. Only ID = 0 is considered connected; * all other ID values are unconnected. ------------------------------------------------------------------------- */ - + @Test public void getConnectivity_sixNeighborsNonZeroID_returnsFalse() { - assertFalse(potts.getConnectivity(new boolean[][][] { - { - { false, false, false }, - { false, true, false }, - { false, false, false } - }, - { - { false, true, false }, - { true, true, true }, - { false, true, false } - }, - { - { false, false, false }, - { false, true, false }, - { false, false, false } - } - }, false)); + assertFalse( + potts.getConnectivity( + new boolean[][][] { + { + {false, false, false}, + {false, true, false}, + {false, false, false} + }, + { + {false, true, false}, + {true, true, true}, + {false, true, false} + }, + { + {false, false, false}, + {false, true, false}, + {false, false, false} + } + }, + false)); } - + @Test public void getConnectivity_sixNeighborsZeroID_returnsTrue() { - assertTrue(potts.getConnectivity(new boolean[][][] { - { - { false, false, false }, - { false, true, false }, - { false, false, false } - }, - { - { false, true, false }, - { true, true, true }, - { false, true, false } - }, - { - { false, false, false }, - { false, true, false }, - { false, false, false } - } - }, true)); + assertTrue( + potts.getConnectivity( + new boolean[][][] { + { + {false, false, false}, + {false, true, false}, + {false, false, false} + }, + { + {false, true, false}, + {true, true, true}, + {false, true, false} + }, + { + {false, false, false}, + {false, true, false}, + {false, false, false} + } + }, + true)); } } diff --git a/test/arcade/potts/sim/PottsSeriesTest.java b/test/arcade/potts/sim/PottsSeriesTest.java index 2b5b32ba1..2359984ab 100644 --- a/test/arcade/potts/sim/PottsSeriesTest.java +++ b/test/arcade/potts/sim/PottsSeriesTest.java @@ -4,132 +4,143 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import ec.util.MersenneTwisterFast; import arcade.core.sim.Series; import arcade.core.util.Box; import arcade.core.util.MiniBox; import arcade.potts.vis.PottsVisualization; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.core.ARCADETestUtilities.*; import static arcade.core.util.MiniBox.TAG_SEPARATOR; +import static arcade.potts.sim.PottsSeries.DEFAULT_CELL_CLASS; import static arcade.potts.sim.PottsSeries.TARGET_SEPARATOR; import static arcade.potts.util.PottsEnums.Term; public class PottsSeriesTest { private static final double EPSILON = 1E-10; - + private static final double DS = randomDoubleBetween(2, 10); - + private static final double DT = randomDoubleBetween(0.5, 2); - + private static final Box PARAMETERS = new Box(); - - private static final String[] REGION_IDS = new String[] { - randomString().toUpperCase(), - randomString().toUpperCase(), - }; - - private static final String[] MODULE_IDS = new String[] { - randomString().toLowerCase(), - randomString().toLowerCase(), - }; - - private static final String[] TERM_IDS = new String[] { - randomString().toLowerCase(), - randomString().toLowerCase(), - }; - + + private static final String[] REGION_IDS = + new String[] { + randomString().toUpperCase(), randomString().toUpperCase(), + }; + + private static final String[] MODULE_IDS = + new String[] { + randomString().toLowerCase(), randomString().toLowerCase(), + }; + + private static final String[] TERM_IDS = + new String[] { + randomString().toLowerCase(), randomString().toLowerCase(), + }; + private static final String TERM_ADHESION_PARAMETER = "adhesion" + TAG_SEPARATOR + "ADHESION"; - - private static final String[] POTTS_PARAMETER_NAMES = new String[] { - TERM_ADHESION_PARAMETER, - TERM_ADHESION_PARAMETER + "_" + REGION_IDS[0], - TERM_ADHESION_PARAMETER + "_" + REGION_IDS[1], - "POTTS_PARAMETER_1", - "POTTS_PARAMETER_2", - "POTTS_PARAMETER_3", - TERM_IDS[0] + TAG_SEPARATOR + "TERM_PARAMETER_11", - TERM_IDS[0] + TAG_SEPARATOR + "TERM_PARAMETER_12", - TERM_IDS[1] + TAG_SEPARATOR + "TERM_PARAMETER_21", - TERM_IDS[0] + TAG_SEPARATOR + "TERM_PARAMETER_11_" + REGION_IDS[1], - TERM_IDS[1] + TAG_SEPARATOR + "TERM_PARAMETER_11_" + REGION_IDS[0], - }; - - private static final String[] POTTS_PARAMETER_TERM_NAMES = new String[] { - POTTS_PARAMETER_NAMES[6], - POTTS_PARAMETER_NAMES[7], - POTTS_PARAMETER_NAMES[8], - POTTS_PARAMETER_NAMES[9], - POTTS_PARAMETER_NAMES[10], - }; - - private static final double[] POTTS_PARAMETER_VALUES = new double[] { - randomIntBetween(1, 100), - randomIntBetween(1, 100), - randomIntBetween(1, 100), - randomIntBetween(1, 100), - randomIntBetween(1, 100), - randomIntBetween(1, 100), - randomIntBetween(1, 100), - randomIntBetween(1, 100), - randomIntBetween(1, 100), - randomIntBetween(1, 100), - randomIntBetween(1, 100), - }; - + + private static final String[] POTTS_PARAMETER_NAMES = + new String[] { + TERM_ADHESION_PARAMETER, + TERM_ADHESION_PARAMETER + "_" + REGION_IDS[0], + TERM_ADHESION_PARAMETER + "_" + REGION_IDS[1], + "POTTS_PARAMETER_1", + "POTTS_PARAMETER_2", + "POTTS_PARAMETER_3", + TERM_IDS[0] + TAG_SEPARATOR + "TERM_PARAMETER_11", + TERM_IDS[0] + TAG_SEPARATOR + "TERM_PARAMETER_12", + TERM_IDS[1] + TAG_SEPARATOR + "TERM_PARAMETER_21", + TERM_IDS[0] + TAG_SEPARATOR + "TERM_PARAMETER_11_" + REGION_IDS[1], + TERM_IDS[1] + TAG_SEPARATOR + "TERM_PARAMETER_11_" + REGION_IDS[0], + }; + + private static final String[] POTTS_PARAMETER_TERM_NAMES = + new String[] { + POTTS_PARAMETER_NAMES[6], + POTTS_PARAMETER_NAMES[7], + POTTS_PARAMETER_NAMES[8], + POTTS_PARAMETER_NAMES[9], + POTTS_PARAMETER_NAMES[10], + }; + + private static final double[] POTTS_PARAMETER_VALUES = + new double[] { + randomIntBetween(1, 100), + randomIntBetween(1, 100), + randomIntBetween(1, 100), + randomIntBetween(1, 100), + randomIntBetween(1, 100), + randomIntBetween(1, 100), + randomIntBetween(1, 100), + randomIntBetween(1, 100), + randomIntBetween(1, 100), + randomIntBetween(1, 100), + randomIntBetween(1, 100), + }; + private static final int POTTS_PARAMETER_COUNT = POTTS_PARAMETER_NAMES.length; - - private static final String[] POPULATION_PARAMETER_NAMES = new String[] { - "POPULATION_PARAMETER_1", - "POPULATION_PARAMETER_2", - MODULE_IDS[0] + TAG_SEPARATOR + "MODULE_PARAMETER_11", - MODULE_IDS[0] + TAG_SEPARATOR + "MODULE_PARAMETER_12", - MODULE_IDS[1] + TAG_SEPARATOR + "MODULE_PARAMETER_21", - REGION_IDS[0] + TAG_SEPARATOR + "POPULATION_PARAMETER_1", - REGION_IDS[0] + TAG_SEPARATOR + "POPULATION_PARAMETER_2", - REGION_IDS[1] + TAG_SEPARATOR + "POPULATION_PARAMETER_1", - REGION_IDS[1] + TAG_SEPARATOR + "POPULATION_PARAMETER_2", - }; - - private static final double[] POPULATION_PARAMETER_VALUES = new double[] { - randomDoubleBetween(1, 100), - randomDoubleBetween(1, 100), - randomDoubleBetween(1, 100), - randomDoubleBetween(1, 100), - randomDoubleBetween(1, 100), - randomDoubleBetween(1, 100), - randomDoubleBetween(1, 100), - randomDoubleBetween(1, 100), - randomDoubleBetween(1, 100), - }; - + + private static final String[] POPULATION_PARAMETER_NAMES = + new String[] { + "POPULATION_PARAMETER_1", + "POPULATION_PARAMETER_2", + MODULE_IDS[0] + TAG_SEPARATOR + "MODULE_PARAMETER_11", + MODULE_IDS[0] + TAG_SEPARATOR + "MODULE_PARAMETER_12", + MODULE_IDS[1] + TAG_SEPARATOR + "MODULE_PARAMETER_21", + REGION_IDS[0] + TAG_SEPARATOR + "POPULATION_PARAMETER_1", + REGION_IDS[0] + TAG_SEPARATOR + "POPULATION_PARAMETER_2", + REGION_IDS[1] + TAG_SEPARATOR + "POPULATION_PARAMETER_1", + REGION_IDS[1] + TAG_SEPARATOR + "POPULATION_PARAMETER_2", + }; + + private static final double[] POPULATION_PARAMETER_VALUES = + new double[] { + randomDoubleBetween(1, 100), + randomDoubleBetween(1, 100), + randomDoubleBetween(1, 100), + randomDoubleBetween(1, 100), + randomDoubleBetween(1, 100), + randomDoubleBetween(1, 100), + randomDoubleBetween(1, 100), + randomDoubleBetween(1, 100), + randomDoubleBetween(1, 100), + }; + private static final String POPULATION_ID_1 = randomString(); - + + private static final String POPULATION_CLASS_1 = randomString(); + private static final String POPULATION_ID_2 = randomString(); - + + private static final String POPULATION_CLASS_2 = randomString(); + private static final String POPULATION_ID_3 = randomString(); - - private static final String[] POPULATION_KEYS = new String[] { - POPULATION_ID_1, - POPULATION_ID_2, - POPULATION_ID_3, - }; - + + private static final String POPULATION_CLASS_3 = randomString(); + + private static final String[] POPULATION_KEYS = + new String[] { + POPULATION_ID_1, POPULATION_ID_2, POPULATION_ID_3, + }; + private static final MiniBox POTTS = new MiniBox(); - + private static final MiniBox POPULATION = new MiniBox(); - - @BeforeClass + + @BeforeAll public static void setupParameters() { // DEFAULTS PARAMETERS.addTag("DS", "DEFAULT"); PARAMETERS.addTag("DT", "DEFAULT"); PARAMETERS.addAtt("DS", "value", "" + DS); PARAMETERS.addAtt("DT", "value", "" + DT); - + // POTTS for (int i = 0; i < POTTS_PARAMETER_COUNT; i++) { PARAMETERS.addTag(POTTS_PARAMETER_NAMES[i], "POTTS"); @@ -139,30 +150,31 @@ public static void setupParameters() { for (String key : potts.getKeys()) { POTTS.put(key, potts.get(key)); } - + // POPULATION for (int i = 0; i < POPULATION_PARAMETER_NAMES.length; i++) { PARAMETERS.addTag(POPULATION_PARAMETER_NAMES[i], "POPULATION"); - PARAMETERS.addAtt(POPULATION_PARAMETER_NAMES[i], "value", "" + POPULATION_PARAMETER_VALUES[i]); + PARAMETERS.addAtt( + POPULATION_PARAMETER_NAMES[i], "value", "" + POPULATION_PARAMETER_VALUES[i]); } MiniBox population = PARAMETERS.getIdValForTag("POPULATION"); for (String key : population.getKeys()) { POPULATION.put(key, population.get(key)); } } - + private HashMap> makeLists() { HashMap> setupLists = new HashMap<>(); - + ArrayList potts = new ArrayList<>(); setupLists.put("potts", potts); - + ArrayList populations = new ArrayList<>(); setupLists.put("populations", populations); - + return setupLists; } - + private HashMap makePopulations() { HashMap populations = new HashMap<>(); for (String population : POPULATION_KEYS) { @@ -170,54 +182,55 @@ private HashMap makePopulations() { } return populations; } - + @Test public void initialize_default_callsMethods() { HashMap> setupLists = makeLists(); PottsSeries series = mock(PottsSeries.class, CALLS_REAL_METHODS); series.initialize(setupLists, PARAMETERS); - + ArrayList potts = setupLists.get("potts"); verify(series).updatePotts(eq(potts), any(MiniBox.class), any(MiniBox.class)); - + ArrayList populations = setupLists.get("populations"); verify(series).updatePopulations(eq(populations), any(MiniBox.class), any(MiniBox.class)); - + ArrayList layers = setupLists.get("layers"); verify(series).updateLayers(eq(layers), any(MiniBox.class), any(MiniBox.class)); - + ArrayList actions = setupLists.get("actions"); verify(series).updateActions(eq(actions), any(MiniBox.class)); - + ArrayList components = setupLists.get("components"); verify(series).updateComponents(eq(components), any(MiniBox.class)); } - + private PottsSeries makeSeriesForPotts(Box box) { return makeSeriesForPotts(box, new MiniBox()); } - + private PottsSeries makeSeriesForPotts(Box box, MiniBox conversion) { HashMap> setupLists = makeLists(); PottsSeries series = mock(PottsSeries.class, CALLS_REAL_METHODS); ArrayList potts = setupLists.get("potts"); potts.add(box); series.populations = makePopulations(); - + try { Field dsField = Series.class.getDeclaredField("ds"); dsField.setAccessible(true); dsField.setDouble(series, DS); - + Field dtField = Series.class.getDeclaredField("dt"); dtField.setAccessible(true); dtField.setDouble(series, DT); - } catch (Exception ignored) { } - + } catch (Exception ignored) { + } + series.updatePotts(potts, POTTS, conversion); return series; } - + @Test public void updatePotts_noSetting_createsBox() { PottsSeries series = mock(PottsSeries.class, CALLS_REAL_METHODS); @@ -225,33 +238,33 @@ public void updatePotts_noSetting_createsBox() { series.updatePotts(null, POTTS, new MiniBox()); assertNotNull(series.potts); } - + @Test public void updatePotts_noParameters_usesDefaults() { PottsSeries series = makeSeriesForPotts(null); MiniBox box = series.potts; - + for (String parameter : POTTS_PARAMETER_NAMES) { assertEquals(POTTS.get(parameter), box.get(parameter)); } } - + @Test public void updatePotts_givenParameters_updatesValues() { for (String pottsParameter1 : POTTS_PARAMETER_NAMES) { for (String pottsParameter2 : POTTS_PARAMETER_NAMES) { Box potts = new Box(); - + double value = randomDoubleBetween(1, 100); double scale = randomDoubleBetween(1, 100); potts.addAtt(pottsParameter1, "value", "" + value); potts.addTag(pottsParameter1, "PARAMETER"); potts.addAtt(pottsParameter2, "scale", "" + scale); potts.addTag(pottsParameter2, "PARAMETER"); - + PottsSeries series = makeSeriesForPotts(potts); MiniBox box = series.potts; - + for (String parameter : POTTS_PARAMETER_NAMES) { double expected = POTTS.getDouble(parameter); if (parameter.equals(pottsParameter1)) { @@ -265,35 +278,35 @@ public void updatePotts_givenParameters_updatesValues() { } } } - + @Test public void updatePotts_noParameters_assignsTargets() { PottsSeries series = makeSeriesForPotts(null); MiniBox box = series.potts; - + for (String pop : POPULATION_KEYS) { for (String parameter : POTTS_PARAMETER_TERM_NAMES) { assertEquals(POTTS.get(parameter), box.get(parameter + TARGET_SEPARATOR + pop)); } } } - + @Test public void updatePotts_givenParameters_assignsTargets() { for (String pottsParameter1 : POTTS_PARAMETER_TERM_NAMES) { for (String pottsParameter2 : POTTS_PARAMETER_TERM_NAMES) { Box potts = new Box(); - + double value = randomDoubleBetween(1, 100); double scale = randomDoubleBetween(1, 100); potts.addAtt(pottsParameter1, "value", "" + value); potts.addTag(pottsParameter1, "PARAMETER"); potts.addAtt(pottsParameter2, "scale", "" + scale); potts.addTag(pottsParameter2, "PARAMETER"); - + PottsSeries series = makeSeriesForPotts(potts); MiniBox box = series.potts; - + for (String parameter : POTTS_PARAMETER_TERM_NAMES) { double expected = POTTS.getDouble(parameter); if (parameter.equals(pottsParameter1)) { @@ -302,15 +315,18 @@ public void updatePotts_givenParameters_assignsTargets() { if (parameter.equals(pottsParameter2)) { expected *= scale; } - + for (String pop : POPULATION_KEYS) { - assertEquals(expected, box.getDouble(parameter + TARGET_SEPARATOR + pop), EPSILON); + assertEquals( + expected, + box.getDouble(parameter + TARGET_SEPARATOR + pop), + EPSILON); } } } } } - + @Test public void updatePotts_givenPopulationParameters_updatesValues() { for (String pottsParameter1 : POTTS_PARAMETER_TERM_NAMES) { @@ -320,27 +336,39 @@ public void updatePotts_givenPopulationParameters_updatesValues() { Box potts = new Box(); double value = randomDoubleBetween(1, 100); double scale = randomDoubleBetween(1, 100); - potts.addAtt(pottsParameter1 + TARGET_SEPARATOR + pottsPop1, "value", "" + value); + potts.addAtt( + pottsParameter1 + TARGET_SEPARATOR + pottsPop1, + "value", + "" + value); potts.addTag(pottsParameter1 + TARGET_SEPARATOR + pottsPop1, "PARAMETER"); - potts.addAtt(pottsParameter2 + TARGET_SEPARATOR + pottsPop2, "scale", "" + scale); + potts.addAtt( + pottsParameter2 + TARGET_SEPARATOR + pottsPop2, + "scale", + "" + scale); potts.addTag(pottsParameter2 + TARGET_SEPARATOR + pottsPop2, "PARAMETER"); - + PottsSeries series = makeSeriesForPotts(potts); MiniBox box = series.potts; - + for (String parameter : POTTS_PARAMETER_TERM_NAMES) { for (String pop : POPULATION_KEYS) { double expected = POTTS.getDouble(parameter); - + if (parameter.equals(pottsParameter1) && pop.equals(pottsPop1)) { expected = value; } if (parameter.equals(pottsParameter2) && pop.equals(pottsPop2)) { expected *= scale; } - - assertEquals(POTTS.getDouble(parameter), box.getDouble(parameter), EPSILON); - assertEquals(expected, box.getDouble(parameter + TARGET_SEPARATOR + pop), EPSILON); + + assertEquals( + POTTS.getDouble(parameter), + box.getDouble(parameter), + EPSILON); + assertEquals( + expected, + box.getDouble(parameter + TARGET_SEPARATOR + pop), + EPSILON); } } } @@ -348,17 +376,17 @@ public void updatePotts_givenPopulationParameters_updatesValues() { } } } - + @Test public void updatePotts_withConversion_convertsValue() { MiniBox conversion = new MiniBox(); String convertedParameter = POTTS_PARAMETER_NAMES[3]; conversion.put(convertedParameter, "DT"); - + Box potts = new Box(); PottsSeries series = makeSeriesForPotts(potts, conversion); MiniBox box = series.potts; - + for (String parameter : POTTS_PARAMETER_NAMES) { double expected = POTTS.getDouble(parameter); if (parameter.equals(convertedParameter)) { @@ -367,18 +395,18 @@ public void updatePotts_withConversion_convertsValue() { assertEquals(expected, box.getDouble(parameter), EPSILON); } } - + @Test public void updatePotts_withTermConversion_convertsValue() { MiniBox conversion = new MiniBox(); int i = randomIntBetween(0, POTTS_PARAMETER_TERM_NAMES.length); String convertedParameter = POTTS_PARAMETER_TERM_NAMES[i]; conversion.put(convertedParameter, "DT"); - + Box potts = new Box(); PottsSeries series = makeSeriesForPotts(potts, conversion); MiniBox box = series.potts; - + for (String pop : POPULATION_KEYS) { for (String parameter : POTTS_PARAMETER_TERM_NAMES) { double expected = POTTS.getDouble(parameter); @@ -389,49 +417,53 @@ public void updatePotts_withTermConversion_convertsValue() { } } } - + @Test public void updatePotts_noAdhesion_usesDefaults() { PottsSeries series = makeSeriesForPotts(null); MiniBox box = series.potts; double adhesion = POTTS.getDouble(TERM_ADHESION_PARAMETER); - + assertEquals(adhesion, box.getDouble(TERM_ADHESION_PARAMETER), EPSILON); - + for (String source : POPULATION_KEYS) { String adhesionSource = TERM_ADHESION_PARAMETER + TARGET_SEPARATOR + source; assertEquals(adhesion, box.getDouble(adhesionSource), EPSILON); assertEquals(adhesion, box.getDouble(adhesionSource + TARGET_SEPARATOR + "*"), EPSILON); - + for (String target : POPULATION_KEYS) { String adhesionTarget = adhesionSource + TARGET_SEPARATOR + target; assertEquals(adhesion, box.getDouble(adhesionTarget), EPSILON); } } } - + @Test public void updatePotts_givenAdhesion_updateValues() { String[] pops = new String[POPULATION_KEYS.length + 1]; System.arraycopy(POPULATION_KEYS, 0, pops, 0, POPULATION_KEYS.length); pops[POPULATION_KEYS.length] = "*"; - + for (String pop1 : pops) { for (String pop2 : pops) { Box potts = new Box(); - + double value = randomDoubleBetween(1, 100); double scale = randomDoubleBetween(1, 100); - potts.addAtt(TERM_ADHESION_PARAMETER + TARGET_SEPARATOR + pop1, "value", "" + value); + potts.addAtt( + TERM_ADHESION_PARAMETER + TARGET_SEPARATOR + pop1, "value", "" + value); potts.addTag(TERM_ADHESION_PARAMETER + TARGET_SEPARATOR + pop1, "PARAMETER"); - potts.addAtt(TERM_ADHESION_PARAMETER + TARGET_SEPARATOR - + pop1 + TARGET_SEPARATOR + pop2, "scale", "" + scale); - potts.addTag(TERM_ADHESION_PARAMETER + TARGET_SEPARATOR - + pop1 + TARGET_SEPARATOR + pop2, "PARAMETER"); - + potts.addAtt( + TERM_ADHESION_PARAMETER + TARGET_SEPARATOR + pop1 + TARGET_SEPARATOR + pop2, + "scale", + "" + scale); + potts.addTag( + TERM_ADHESION_PARAMETER + TARGET_SEPARATOR + pop1 + TARGET_SEPARATOR + pop2, + "PARAMETER"); + PottsSeries series = makeSeriesForPotts(potts); MiniBox box = series.potts; - + for (String source : POPULATION_KEYS) { double expected1 = POTTS.getDouble(TERM_ADHESION_PARAMETER); if (source.equals(pop1)) { @@ -439,7 +471,7 @@ public void updatePotts_givenAdhesion_updateValues() { } String adhesionSource = TERM_ADHESION_PARAMETER + TARGET_SEPARATOR + source; assertEquals(expected1, box.getDouble(adhesionSource), EPSILON); - + for (String target : pops) { double expected2 = expected1; if (source.equals(pop1) && target.equals(pop2)) { @@ -452,73 +484,77 @@ public void updatePotts_givenAdhesion_updateValues() { } } } - + @Test public void updatePotts_withRegionsNoAdhesion_usesDefaults() { HashMap> setupLists = makeLists(); PottsSeries series = mock(PottsSeries.class, CALLS_REAL_METHODS); - + series.populations = makePopulations(); String key = POPULATION_KEYS[randomIntBetween(0, POPULATION_KEYS.length)]; MiniBox popBox = series.populations.get(key); popBox.put("(REGION)" + TAG_SEPARATOR + REGION_IDS[0], 0); popBox.put("(REGION)" + TAG_SEPARATOR + REGION_IDS[1], 0); - + series.updatePotts(setupLists.get("potts"), POTTS, new MiniBox()); MiniBox box = series.potts; - + for (String source : REGION_IDS) { double adhesion = POTTS.getDouble(TERM_ADHESION_PARAMETER + "_" + source); assertEquals(adhesion, box.getDouble(TERM_ADHESION_PARAMETER + "_" + source), EPSILON); - + String adhesionSource = TERM_ADHESION_PARAMETER + "_" + source + TARGET_SEPARATOR + key; assertEquals(adhesion, box.getDouble(adhesionSource), EPSILON); - + for (String target : REGION_IDS) { String adhesionTarget = adhesionSource + TARGET_SEPARATOR + target; assertEquals(adhesion, box.getDouble(adhesionTarget), EPSILON); } } } - + @Test public void updatePotts_withRegionsGivenAdhesion_updateValues() { String key = POPULATION_KEYS[randomIntBetween(0, POPULATION_KEYS.length)]; - + for (String region1 : REGION_IDS) { for (String region2 : REGION_IDS) { Box potts = new Box(); - + String adhesion = TERM_ADHESION_PARAMETER + "_" + region1; double value = randomDoubleBetween(1, 100); double scale = randomDoubleBetween(1, 100); potts.addAtt(adhesion + TARGET_SEPARATOR + key, "value", "" + value); potts.addTag(adhesion + TARGET_SEPARATOR + key, "PARAMETER"); - potts.addAtt(adhesion + TARGET_SEPARATOR - + key + TARGET_SEPARATOR + region2, "scale", "" + scale); - potts.addTag(adhesion + TARGET_SEPARATOR - + key + TARGET_SEPARATOR + region2, "PARAMETER"); - + potts.addAtt( + adhesion + TARGET_SEPARATOR + key + TARGET_SEPARATOR + region2, + "scale", + "" + scale); + potts.addTag( + adhesion + TARGET_SEPARATOR + key + TARGET_SEPARATOR + region2, + "PARAMETER"); + HashMap> setupLists = makeLists(); PottsSeries series = mock(PottsSeries.class, CALLS_REAL_METHODS); - + series.populations = makePopulations(); MiniBox popBox = series.populations.get(key); popBox.put("(REGION)" + TAG_SEPARATOR + REGION_IDS[0], 0); popBox.put("(REGION)" + TAG_SEPARATOR + REGION_IDS[1], 0); - + setupLists.get("potts").add(potts); series.updatePotts(setupLists.get("potts"), POTTS, new MiniBox()); MiniBox box = series.potts; - + for (String source : REGION_IDS) { double expected1 = POTTS.getDouble(TERM_ADHESION_PARAMETER + "_" + source); if (source.equals(region1)) { expected1 = value; } - String adhesionSource = TERM_ADHESION_PARAMETER + "_" + source + TARGET_SEPARATOR + key; + String adhesionSource = + TERM_ADHESION_PARAMETER + "_" + source + TARGET_SEPARATOR + key; assertEquals(expected1, box.getDouble(adhesionSource), EPSILON); - + for (String target : REGION_IDS) { double expected2 = expected1; if (source.equals(region1) && target.equals(region2)) { @@ -531,7 +567,7 @@ public void updatePotts_withRegionsGivenAdhesion_updateValues() { } } } - + @Test public void updatePotts_noTerms_createsList() { PottsSeries series = mock(PottsSeries.class, CALLS_REAL_METHODS); @@ -539,82 +575,118 @@ public void updatePotts_noTerms_createsList() { series.updatePotts(null, POTTS, new MiniBox()); assertNotNull(series.terms); } - + @Test public void updatePotts_withTerms_createsList() { HashMap> setupLists = makeLists(); PottsSeries series = mock(PottsSeries.class, CALLS_REAL_METHODS); series.populations = new HashMap<>(); ArrayList potts = setupLists.get("potts"); - + Box box = new Box(); potts.add(box); - + MersenneTwisterFast random = new MersenneTwisterFast(); Term term1 = Term.random(random); Term term2 = Term.random(random); - + box.addTag(term1.name(), "TERM"); box.addTag(term2.name(), "TERM"); - + series.updatePotts(potts, POTTS, new MiniBox()); - + int n = (term1.equals(term2) ? 1 : 2); assertEquals(n, series.terms.size()); assertTrue(series.terms.contains(term1)); assertTrue(series.terms.contains(term2)); } - + private PottsSeries makeSeriesForPopulation(Box[] boxes) { return makeSeriesForPopulation(boxes, new MiniBox()); } - + private PottsSeries makeSeriesForPopulation(Box[] boxes, MiniBox conversion) { HashMap> setupLists = makeLists(); PottsSeries series = mock(PottsSeries.class, CALLS_REAL_METHODS); ArrayList populations = setupLists.get("populations"); populations.addAll(Arrays.asList(boxes)); - + try { Field dsField = Series.class.getDeclaredField("ds"); dsField.setAccessible(true); dsField.setDouble(series, DS); - + Field dtField = Series.class.getDeclaredField("dt"); dtField.setAccessible(true); dtField.setDouble(series, DT); - } catch (Exception ignored) { } - + } catch (Exception ignored) { + } + series.updatePopulations(populations, POPULATION, conversion); return series; } - + @Test public void updatePopulation_noPopulations_createsMap() { PottsSeries series = mock(PottsSeries.class, CALLS_REAL_METHODS); series.updatePopulations(null, POPULATION, new MiniBox()); assertEquals(0, series.populations.size()); } - + @Test public void updatePopulation_onePopulation_createsMap() { - Box[] boxes = new Box[] { new Box() }; + Box[] boxes = new Box[] {new Box()}; boxes[0].add("id", POPULATION_ID_1); PottsSeries series = makeSeriesForPopulation(boxes); - assertEquals(1, series.populations.size()); assertNotNull(series.populations.get(POPULATION_ID_1)); assertEquals(1, series.populations.get(POPULATION_ID_1).getInt("CODE")); + assertEquals(DEFAULT_CELL_CLASS, series.populations.get(POPULATION_ID_1).get("CLASS")); } - + + @Test + public void updatePopulation_onePopulationWithClass_createsMap() { + Box[] boxes = new Box[] {new Box()}; + boxes[0].add("id", POPULATION_ID_1); + boxes[0].add("class", POPULATION_CLASS_1); + PottsSeries series = makeSeriesForPopulation(boxes); + assertEquals(1, series.populations.size()); + assertNotNull(series.populations.get(POPULATION_ID_1)); + assertEquals(1, series.populations.get(POPULATION_ID_1).getInt("CODE")); + assertEquals(POPULATION_CLASS_1, series.populations.get(POPULATION_ID_1).get("CLASS")); + } + @Test public void updatePopulation_multiplePopulations_createsMap() { - Box[] boxes = new Box[] { new Box(), new Box(), new Box() }; + Box[] boxes = new Box[] {new Box(), new Box(), new Box()}; + boxes[0].add("id", POPULATION_ID_1); + boxes[1].add("id", POPULATION_ID_2); + boxes[2].add("id", POPULATION_ID_3); + PottsSeries series = makeSeriesForPopulation(boxes); + + assertEquals(3, series.populations.size()); + assertNotNull(series.populations.get(POPULATION_ID_1)); + assertNotNull(series.populations.get(POPULATION_ID_2)); + assertNotNull(series.populations.get(POPULATION_ID_3)); + assertEquals(1, series.populations.get(POPULATION_ID_1).getInt("CODE")); + assertEquals(2, series.populations.get(POPULATION_ID_2).getInt("CODE")); + assertEquals(3, series.populations.get(POPULATION_ID_3).getInt("CODE")); + assertEquals(DEFAULT_CELL_CLASS, series.populations.get(POPULATION_ID_1).get("CLASS")); + assertEquals(DEFAULT_CELL_CLASS, series.populations.get(POPULATION_ID_2).get("CLASS")); + assertEquals(DEFAULT_CELL_CLASS, series.populations.get(POPULATION_ID_3).get("CLASS")); + } + + @Test + public void updatePopulation_multiplePopulationsWithClass_createsMap() { + Box[] boxes = new Box[] {new Box(), new Box(), new Box()}; boxes[0].add("id", POPULATION_ID_1); + boxes[0].add("class", POPULATION_CLASS_1); boxes[1].add("id", POPULATION_ID_2); + boxes[1].add("class", POPULATION_CLASS_2); boxes[2].add("id", POPULATION_ID_3); + boxes[2].add("class", POPULATION_CLASS_3); PottsSeries series = makeSeriesForPopulation(boxes); - + assertEquals(3, series.populations.size()); assertNotNull(series.populations.get(POPULATION_ID_1)); assertNotNull(series.populations.get(POPULATION_ID_2)); @@ -622,131 +694,162 @@ public void updatePopulation_multiplePopulations_createsMap() { assertEquals(1, series.populations.get(POPULATION_ID_1).getInt("CODE")); assertEquals(2, series.populations.get(POPULATION_ID_2).getInt("CODE")); assertEquals(3, series.populations.get(POPULATION_ID_3).getInt("CODE")); + assertEquals(POPULATION_CLASS_1, series.populations.get(POPULATION_ID_1).get("CLASS")); + assertEquals(POPULATION_CLASS_2, series.populations.get(POPULATION_ID_2).get("CLASS")); + assertEquals(POPULATION_CLASS_3, series.populations.get(POPULATION_ID_3).get("CLASS")); } - + @Test public void updatePopulation_noInit_setsZero() { - Box[] boxes = new Box[] { new Box() }; + Box[] boxes = new Box[] {new Box()}; boxes[0].add("id", POPULATION_ID_1); PottsSeries series = makeSeriesForPopulation(boxes); - + MiniBox box = series.populations.get(POPULATION_ID_1); assertEquals(0, box.getDouble("INIT"), EPSILON); } - + @Test public void updatePopulation_givenValidInit_setsValue() { - String[] fractions = new String[] { "0", "10", "1E2" }; - int[] values = new int[] { 0, 10, 100 }; - + String[] fractions = new String[] {"0", "10", "1E2"}; + int[] values = new int[] {0, 10, 100}; + for (int i = 0; i < fractions.length; i++) { - Box[] boxes = new Box[] { new Box() }; + Box[] boxes = new Box[] {new Box()}; boxes[0].add("id", POPULATION_ID_1); boxes[0].add("init", fractions[i]); PottsSeries series = makeSeriesForPopulation(boxes); - + MiniBox box = series.populations.get(POPULATION_ID_1); assertEquals(values[i], box.getInt("INIT")); } } - + @Test public void updatePopulation_givenInvalidInit_setsZero() { - String[] fractions = new String[] { "1.1", "-1" }; - + String[] fractions = new String[] {"1.1", "-1"}; + for (String fraction : fractions) { - Box[] boxes = new Box[] { new Box() }; + Box[] boxes = new Box[] {new Box()}; boxes[0].add("id", POPULATION_ID_1); boxes[0].add("init", fraction); PottsSeries series = makeSeriesForPopulation(boxes); - + MiniBox box = series.populations.get(POPULATION_ID_1); assertEquals(0, box.getDouble("INIT"), EPSILON); } } - + @Test public void updatePopulation_givenValidPadding_setsValue() { - String[] fractions = new String[] { "0", "10", "1E2" }; - String[] paddings = new String[] { "0", "10", "1E2" }; - int[] values = new int[] { 0, 10, 100 }; - + String[] fractions = new String[] {"0", "10", "1E2"}; + String[] paddings = new String[] {"0", "10", "1E2"}; + int[] values = new int[] {0, 10, 100}; + for (int i = 0; i < fractions.length; i++) { for (int j = 0; j < paddings.length; j++) { - Box[] boxes = new Box[] { new Box() }; + Box[] boxes = new Box[] {new Box()}; boxes[0].add("id", POPULATION_ID_1); boxes[0].add("init", fractions[i] + ":" + paddings[j]); PottsSeries series = makeSeriesForPopulation(boxes); - + MiniBox box = series.populations.get(POPULATION_ID_1); assertEquals(values[i], box.getInt("INIT")); assertEquals(values[j], box.getInt("PADDING")); } } } - + @Test public void updatePopulation_givenInvalidPadding_setsZero() { - String[] fractions = new String[] { "0", "10", "1E2" }; - String[] paddings = new String[] { "1.1", "-1" }; - int[] values = new int[] { 0, 10, 100 }; - + String[] fractions = new String[] {"0", "10", "1E2"}; + String[] paddings = new String[] {"1.1", "-1"}; + int[] values = new int[] {0, 10, 100}; + for (int i = 0; i < fractions.length; i++) { for (String padding : paddings) { - Box[] boxes = new Box[] { new Box() }; + Box[] boxes = new Box[] {new Box()}; boxes[0].add("id", POPULATION_ID_1); boxes[0].add("init", fractions[i] + ":" + padding); PottsSeries series = makeSeriesForPopulation(boxes); - + MiniBox box = series.populations.get(POPULATION_ID_1); assertEquals(values[i], box.getInt("INIT")); assertEquals(0, box.getInt("PADDING")); } } } - + + @Test + public void updatePopulation_withLinks_setsTags() { + double weight11 = randomDoubleBetween(1, 100); + double weight12 = randomDoubleBetween(1, 100); + double weight21 = randomDoubleBetween(1, 100); + + Box[] boxes = new Box[] {new Box(), new Box()}; + + boxes[0].add("id", POPULATION_ID_1); + boxes[0].addAtt(POPULATION_ID_1, "weight", "" + weight11); + boxes[0].addTag(POPULATION_ID_1, "LINK"); + boxes[0].addAtt(POPULATION_ID_2, "weight", "" + weight12); + boxes[0].addTag(POPULATION_ID_2, "LINK"); + + boxes[1].add("id", POPULATION_ID_2); + boxes[1].addAtt(POPULATION_ID_1, "weight", "" + weight21); + boxes[1].addTag(POPULATION_ID_1, "LINK"); + + PottsSeries series = makeSeriesForPopulation(boxes); + + MiniBox box1 = series.populations.get(POPULATION_ID_1); + assertEquals(weight11, box1.getDouble("(LINK)" + TAG_SEPARATOR + POPULATION_ID_1)); + assertEquals(weight12, box1.getDouble("(LINK)" + TAG_SEPARATOR + POPULATION_ID_2)); + + MiniBox box2 = series.populations.get(POPULATION_ID_2); + assertEquals(weight21, box2.getDouble("(LINK)" + TAG_SEPARATOR + POPULATION_ID_1)); + } + @Test public void updatePopulation_withRegions_setsTags() { - Box[] boxes = new Box[] { new Box() }; + Box[] boxes = new Box[] {new Box()}; boxes[0].add("id", POPULATION_ID_1); boxes[0].addTag(REGION_IDS[0], "REGION"); - + PottsSeries series = makeSeriesForPopulation(boxes); MiniBox box = series.populations.get(POPULATION_ID_1); - + assertEquals("", box.get("(REGION)" + TAG_SEPARATOR + REGION_IDS[0])); assertFalse(box.contains("(REGION)" + TAG_SEPARATOR + REGION_IDS[1])); } - + @Test public void updatePopulation_noParametersOnePop_usesDefaults() { - Box[] boxes = new Box[] { new Box() }; + Box[] boxes = new Box[] {new Box()}; boxes[0].add("id", POPULATION_ID_1); PottsSeries series = makeSeriesForPopulation(boxes); MiniBox box = series.populations.get(POPULATION_ID_1); - + for (String parameter : POPULATION_PARAMETER_NAMES) { assertEquals(POPULATION.get(parameter), box.get(parameter)); } } - + @Test public void updatePopulation_givenParametersOnePop_updatesValues() { for (String populationParameter1 : POPULATION_PARAMETER_NAMES) { for (String populationParameter2 : POPULATION_PARAMETER_NAMES) { - Box[] boxes = new Box[] { new Box() }; + Box[] boxes = new Box[] {new Box()}; boxes[0].add("id", POPULATION_ID_1); - + double value = randomDoubleBetween(1, 100); double scale = randomDoubleBetween(1, 100); boxes[0].addAtt(populationParameter1, "value", "" + value); boxes[0].addTag(populationParameter1, "PARAMETER"); boxes[0].addAtt(populationParameter2, "scale", "" + scale); boxes[0].addTag(populationParameter2, "PARAMETER"); - + PottsSeries series = makeSeriesForPopulation(boxes); MiniBox box = series.populations.get(POPULATION_ID_1); - + for (String parameter : POPULATION_PARAMETER_NAMES) { double expected = POPULATION.getDouble(parameter); if (parameter.equals(populationParameter1)) { @@ -760,10 +863,10 @@ public void updatePopulation_givenParametersOnePop_updatesValues() { } } } - + @Test public void updatePopulation_noParametersMultiplePops_usesDefaults() { - Box[] boxes = new Box[] { new Box(), new Box(), new Box() }; + Box[] boxes = new Box[] {new Box(), new Box(), new Box()}; boxes[0].add("id", POPULATION_ID_1); boxes[1].add("id", POPULATION_ID_2); boxes[2].add("id", POPULATION_ID_3); @@ -771,39 +874,39 @@ public void updatePopulation_noParametersMultiplePops_usesDefaults() { MiniBox box1 = series.populations.get(POPULATION_ID_1); MiniBox box2 = series.populations.get(POPULATION_ID_2); MiniBox box3 = series.populations.get(POPULATION_ID_3); - + for (String parameter : POPULATION_PARAMETER_NAMES) { assertEquals(POPULATION.get(parameter), box1.get(parameter)); assertEquals(POPULATION.get(parameter), box2.get(parameter)); assertEquals(POPULATION.get(parameter), box3.get(parameter)); } } - + @Test public void updatePopulation_givenParametersMultiplePops_updatesValues() { for (String populationParameter1 : POPULATION_PARAMETER_NAMES) { for (String populationParameter2 : POPULATION_PARAMETER_NAMES) { - Box[] boxes = new Box[] { new Box(), new Box(), new Box() }; + Box[] boxes = new Box[] {new Box(), new Box(), new Box()}; boxes[0].add("id", POPULATION_ID_1); boxes[1].add("id", POPULATION_ID_2); boxes[2].add("id", POPULATION_ID_3); - + double value = randomDoubleBetween(1, 100); double scale = randomDoubleBetween(1, 100); boxes[1].addAtt(populationParameter1, "value", "" + value); boxes[1].addTag(populationParameter1, "PARAMETER"); boxes[1].addAtt(populationParameter2, "scale", "" + scale); boxes[1].addTag(populationParameter2, "PARAMETER"); - + PottsSeries series = makeSeriesForPopulation(boxes); MiniBox box1 = series.populations.get(POPULATION_ID_1); MiniBox box2 = series.populations.get(POPULATION_ID_2); MiniBox box3 = series.populations.get(POPULATION_ID_3); - + for (String parameter : POPULATION_PARAMETER_NAMES) { assertEquals(POPULATION.get(parameter), box1.get(parameter)); assertEquals(POPULATION.get(parameter), box3.get(parameter)); - + double expected = POPULATION.getDouble(parameter); if (parameter.equals(populationParameter1)) { expected = value; @@ -816,19 +919,19 @@ public void updatePopulation_givenParametersMultiplePops_updatesValues() { } } } - + @Test public void updatePopulation_withConversionOnePop_convertsValue() { MiniBox conversion = new MiniBox(); int i = randomIntBetween(0, POPULATION_PARAMETER_NAMES.length); String convertedParameter = POPULATION_PARAMETER_NAMES[i]; conversion.put(convertedParameter, "DS"); - - Box[] boxes = new Box[] { new Box() }; + + Box[] boxes = new Box[] {new Box()}; boxes[0].add("id", POPULATION_ID_1); PottsSeries series = makeSeriesForPopulation(boxes, conversion); MiniBox box = series.populations.get(POPULATION_ID_1); - + for (String parameter : POPULATION_PARAMETER_NAMES) { double expected = POPULATION.getDouble(parameter); if (parameter.equals(convertedParameter)) { @@ -837,15 +940,15 @@ public void updatePopulation_withConversionOnePop_convertsValue() { assertEquals(expected, box.getDouble(parameter), EPSILON); } } - + @Test public void updatePopulation_withConversionMultiplePops_convertsValue() { MiniBox conversion = new MiniBox(); int i = randomIntBetween(0, POPULATION_PARAMETER_NAMES.length); String convertedParameter = POPULATION_PARAMETER_NAMES[i]; conversion.put(convertedParameter, "DS"); - - Box[] boxes = new Box[] { new Box(), new Box(), new Box() }; + + Box[] boxes = new Box[] {new Box(), new Box(), new Box()}; boxes[0].add("id", POPULATION_ID_1); boxes[1].add("id", POPULATION_ID_2); boxes[2].add("id", POPULATION_ID_3); @@ -853,7 +956,7 @@ public void updatePopulation_withConversionMultiplePops_convertsValue() { MiniBox box1 = series.populations.get(POPULATION_ID_1); MiniBox box2 = series.populations.get(POPULATION_ID_2); MiniBox box3 = series.populations.get(POPULATION_ID_3); - + for (String parameter : POPULATION_PARAMETER_NAMES) { double expected = POPULATION.getDouble(parameter); if (parameter.equals(convertedParameter)) { @@ -864,35 +967,62 @@ public void updatePopulation_withConversionMultiplePops_convertsValue() { assertEquals(expected, box3.getDouble(parameter), EPSILON); } } - + + @Test + public void updatePopulation_withConversionAndScale_convertsValue() { + MiniBox conversion = new MiniBox(); + int i = randomIntBetween(0, POPULATION_PARAMETER_NAMES.length); + String convertedParameter = POPULATION_PARAMETER_NAMES[i]; + conversion.put(convertedParameter, "DS"); + + double scale = randomDoubleBetween(1, 100); + + Box[] boxes = new Box[] {new Box()}; + boxes[0].add("id", POPULATION_ID_1); + boxes[0].addAtt(convertedParameter, "scale", "" + scale); + boxes[0].addTag(convertedParameter, "PARAMETER"); + PottsSeries series = makeSeriesForPopulation(boxes, conversion); + MiniBox box = series.populations.get(POPULATION_ID_1); + + for (String parameter : POPULATION_PARAMETER_NAMES) { + double expected = POPULATION.getDouble(parameter); + if (parameter.equals(convertedParameter)) { + expected *= DS * scale; + } + assertEquals(expected, box.getDouble(parameter), EPSILON); + } + } + @Test public void getSimClass_given2D_returnsClass() { String className = PottsSimulation2D.class.getName(); PottsSeries series = mock(PottsSeries.class, CALLS_REAL_METHODS); - + try { Field field = Series.class.getDeclaredField("height"); field.setAccessible(true); field.setInt(series, 1); - } catch (Exception ignored) { } - + } catch (Exception ignored) { + } + assertEquals(className, series.getSimClass()); } - + @Test public void getSimClass_given3D_returnsClass() { String className = PottsSimulation3D.class.getName(); PottsSeries series = mock(PottsSeries.class, CALLS_REAL_METHODS); - + try { Field field = Series.class.getDeclaredField("height"); field.setAccessible(true); field.setInt(series, 3); - } catch (Exception ignored) { } - + } catch (Exception ignored) { + } + assertEquals(className, series.getSimClass()); } - + @Test public void getVisClass_allCases_returnsClass() { String className = PottsVisualization.class.getName(); diff --git a/test/arcade/potts/sim/PottsSimulation2DTest.java b/test/arcade/potts/sim/PottsSimulation2DTest.java index 24d3a4baa..71e967e49 100644 --- a/test/arcade/potts/sim/PottsSimulation2DTest.java +++ b/test/arcade/potts/sim/PottsSimulation2DTest.java @@ -1,13 +1,13 @@ package arcade.potts.sim; import java.util.HashMap; -import org.junit.Test; +import org.junit.jupiter.api.Test; import arcade.core.agent.cell.*; import arcade.core.env.location.*; import arcade.core.util.MiniBox; import arcade.potts.agent.cell.PottsCellFactory; import arcade.potts.env.location.PottsLocationFactory2D; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.potts.sim.PottsSimulationTest.RANDOM_SEED; @@ -21,7 +21,7 @@ public void makePotts_mockSeries_initializesPotts() { Potts potts = sim.makePotts(); assertTrue(potts instanceof Potts2D); } - + @Test public void makeLocationFactory_createsFactory() { PottsSeries series = mock(PottsSeries.class); @@ -30,7 +30,7 @@ public void makeLocationFactory_createsFactory() { LocationFactory factory = sim.makeLocationFactory(); assertTrue(factory instanceof PottsLocationFactory2D); } - + @Test public void makeCellFactory_createsFactory() { PottsSeries series = mock(PottsSeries.class); diff --git a/test/arcade/potts/sim/PottsSimulation3DTest.java b/test/arcade/potts/sim/PottsSimulation3DTest.java index 595150a68..e399fd00c 100644 --- a/test/arcade/potts/sim/PottsSimulation3DTest.java +++ b/test/arcade/potts/sim/PottsSimulation3DTest.java @@ -1,13 +1,13 @@ package arcade.potts.sim; import java.util.HashMap; -import org.junit.Test; +import org.junit.jupiter.api.Test; import arcade.core.agent.cell.*; import arcade.core.env.location.*; import arcade.core.util.MiniBox; import arcade.potts.agent.cell.PottsCellFactory; import arcade.potts.env.location.PottsLocationFactory3D; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.potts.sim.PottsSimulationTest.RANDOM_SEED; @@ -21,7 +21,7 @@ public void makePotts_mockSeries_initializesPotts() { Potts potts = sim.makePotts(); assertTrue(potts instanceof Potts3D); } - + @Test public void makeLocationFactory_createsFactory() { PottsSeries series = mock(PottsSeries.class); @@ -30,7 +30,7 @@ public void makeLocationFactory_createsFactory() { LocationFactory factory = sim.makeLocationFactory(); assertTrue(factory instanceof PottsLocationFactory3D); } - + @Test public void makeCellFactory_createsFactory() { PottsSeries series = mock(PottsSeries.class); diff --git a/test/arcade/potts/sim/PottsSimulationTest.java b/test/arcade/potts/sim/PottsSimulationTest.java index 221798904..68a121e4c 100644 --- a/test/arcade/potts/sim/PottsSimulationTest.java +++ b/test/arcade/potts/sim/PottsSimulationTest.java @@ -4,8 +4,8 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import sim.engine.Schedule; import sim.util.Bag; import ec.util.MersenneTwisterFast; @@ -22,7 +22,7 @@ import arcade.potts.env.location.PottsLocationContainer; import arcade.potts.env.location.PottsLocationFactory; import arcade.potts.env.location.Voxel; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.core.ARCADETestUtilities.*; import static arcade.core.sim.Series.SEED_OFFSET; @@ -31,237 +31,291 @@ public class PottsSimulationTest { static final long RANDOM_SEED = randomSeed(); - + private static final int TOTAL_LOCATIONS = 6; - + static Series seriesZeroPop; - + static Series seriesOnePop; - + static Series seriesMultiPop; - + static Series seriesNullCell; - + static Series seriesNullLocation; - + static Series seriesNullBoth; - + static Series createSeries(int[] pops, String[] keys) { Series series = mock(PottsSeries.class); HashMap populations = new HashMap<>(); - + for (int i = 0; i < pops.length; i++) { MiniBox population = new MiniBox(); population.put("CODE", pops[i]); population.put("ADHESION:*", randomDoubleBetween(0, 100)); populations.put(keys[i], population); - + for (String key : keys) { population.put("ADHESION" + TARGET_SEPARATOR + key, randomDoubleBetween(0, 100)); } } - + series.populations = populations; - + return series; } - - @BeforeClass + + @BeforeAll public static void setupSeries() { // Zero populations. seriesZeroPop = createSeries(new int[0], new String[0]); - + // One population. - seriesOnePop = createSeries(new int[] { 1 }, new String[] { "A" }); + seriesOnePop = createSeries(new int[] {1}, new String[] {"A"}); seriesOnePop.populations.get("A").put("INIT", 5.); - + // Multiple populations. - seriesMultiPop = createSeries(new int[] { 1, 2, 3 }, new String[] { "B", "C", "D" }); + seriesMultiPop = createSeries(new int[] {1, 2, 3}, new String[] {"B", "C", "D"}); seriesMultiPop.populations.get("B").put("INIT", 3); seriesMultiPop.populations.get("C").put("INIT", 1); seriesMultiPop.populations.get("D").put("INIT", 2); - + // Invalid populations. - seriesNullCell = createSeries(new int[] { 1 }, new String[] { "A" }); + seriesNullCell = createSeries(new int[] {1}, new String[] {"A"}); seriesNullCell.populations.get("A").put("INIT", 2); - - seriesNullLocation = createSeries(new int[] { 1 }, new String[] { "A" }); + + seriesNullLocation = createSeries(new int[] {1}, new String[] {"A"}); seriesNullLocation.populations.get("A").put("INIT", 2); - - seriesNullBoth = createSeries(new int[] { 1 }, new String[] { "A" }); + + seriesNullBoth = createSeries(new int[] {1}, new String[] {"A"}); seriesNullBoth.populations.get("A").put("INIT", 2); } - + static class PottsSimulationMock extends PottsSimulation { - private final HashMap> locationMap = new HashMap<>(); - - private final HashMap> cellContainerMap = new HashMap<>(); - - private final HashMap> locationContainerMap = new HashMap<>(); - - PottsSimulationMock(long seed, Series series) { super(seed, series); } - + private final HashMap> locationMap = + new HashMap<>(); + + private final HashMap> cellContainerMap = + new HashMap<>(); + + private final HashMap> locationContainerMap = + new HashMap<>(); + + PottsSimulationMock(long seed, Series series) { + super(seed, series); + } + @Override - public Potts makePotts() { return mock(Potts.class); } - - private void mockLocations(PottsLocationFactory factory, MiniBox pop, - int n, int m, MersenneTwisterFast random) { + public Potts makePotts() { + return mock(Potts.class); + } + + private void mockLocations( + PottsLocationFactory factory, + MiniBox pop, + int n, + int m, + MersenneTwisterFast random) { HashMap idToLocation = new HashMap<>(); locationMap.put(pop, idToLocation); - + HashMap idToCellContainer = new HashMap<>(); cellContainerMap.put(pop, idToCellContainer); - + HashMap idToLocationContainer = new HashMap<>(); locationContainerMap.put(pop, idToLocationContainer); - + for (int i = 0; i < n; i++) { int id = i + m + 1; PottsLocation loc = mock(PottsLocation.class); PottsLocationContainer locationContainer = mock(PottsLocationContainer.class); CellContainer cellContainer = mock(PottsCellContainer.class); - + idToLocation.put(id, loc); idToCellContainer.put(id, cellContainer); idToLocationContainer.put(id, locationContainer); - + factory.locations.put(id, locationContainer); doReturn(new Voxel(id, id, id)).when(loc).getCenter(); doReturn(loc).when(locationContainer).convert(factory, cellContainer); } } - + @Override public PottsLocationFactory makeLocationFactory() { PottsLocationFactory factory = mock(PottsLocationFactory.class); - + try { Field locationField = PottsLocationFactory.class.getDeclaredField("locations"); locationField.setAccessible(true); locationField.set(factory, new HashMap()); - } catch (Exception ignored) { } - - doAnswer(invocation -> { - mockLocations(factory, seriesOnePop.populations.get("A"), 5, 0, random); - return null; - }).when(factory).initialize(seriesOnePop, random); - - doAnswer(invocation -> { - mockLocations(factory, seriesMultiPop.populations.get("B"), 3, 0, random); - mockLocations(factory, seriesMultiPop.populations.get("C"), 1, 3, random); - mockLocations(factory, seriesMultiPop.populations.get("D"), 2, 4, random); - return null; - }).when(factory).initialize(seriesMultiPop, random); - - doAnswer(invocation -> { - mockLocations(factory, seriesNullCell.populations.get("A"), 2, 0, random); - return null; - }).when(factory).initialize(seriesNullCell, random); - - doAnswer(invocation -> { - mockLocations(factory, seriesNullLocation.populations.get("A"), 2, 0, random); - factory.locations.remove(2); - return null; - }).when(factory).initialize(seriesNullLocation, random); - - doAnswer(invocation -> { - mockLocations(factory, seriesNullBoth.populations.get("A"), 2, 0, random); - factory.locations.remove(2); - return null; - }).when(factory).initialize(seriesNullBoth, random); - + } catch (Exception ignored) { + } + + doAnswer( + invocation -> { + mockLocations( + factory, seriesOnePop.populations.get("A"), 5, 0, random); + return null; + }) + .when(factory) + .initialize(seriesOnePop, random); + + doAnswer( + invocation -> { + mockLocations( + factory, seriesMultiPop.populations.get("B"), 3, 0, random); + mockLocations( + factory, seriesMultiPop.populations.get("C"), 1, 3, random); + mockLocations( + factory, seriesMultiPop.populations.get("D"), 2, 4, random); + return null; + }) + .when(factory) + .initialize(seriesMultiPop, random); + + doAnswer( + invocation -> { + mockLocations( + factory, seriesNullCell.populations.get("A"), 2, 0, random); + return null; + }) + .when(factory) + .initialize(seriesNullCell, random); + + doAnswer( + invocation -> { + mockLocations( + factory, + seriesNullLocation.populations.get("A"), + 2, + 0, + random); + factory.locations.remove(2); + return null; + }) + .when(factory) + .initialize(seriesNullLocation, random); + + doAnswer( + invocation -> { + mockLocations( + factory, seriesNullBoth.populations.get("A"), 2, 0, random); + factory.locations.remove(2); + return null; + }) + .when(factory) + .initialize(seriesNullBoth, random); + return factory; } - + private void mockCells(PottsCellFactory factory, Series series, String code, int n, int m) { MiniBox pop = series.populations.get(code); HashSet ids = new HashSet<>(); - + for (int i = 0; i < n; i++) { int id = i + m + 1; PottsCell cell = mock(PottsCell.class); Location loc = locationMap.get(pop).get(id); CellContainer container = cellContainerMap.get(pop).get(id); ids.add(id); - + factory.cells.put(id, (PottsCellContainer) container); doReturn(id).when(cell).getID(); doReturn(pop.getInt("CODE")).when(cell).getPop(); doReturn(loc).when(cell).getLocation(); - doReturn(cell).when(container).convert(factory, loc); + doReturn(cell).when(container).convert(factory, loc, random); } - + factory.popToIDs.put(pop.getInt("CODE"), ids); } - + @Override public PottsCellFactory makeCellFactory() { PottsCellFactory factory = mock(PottsCellFactory.class); - + try { Field cellField = PottsCellFactory.class.getDeclaredField("cells"); cellField.setAccessible(true); cellField.set(factory, new HashMap()); - + Field popField = PottsCellFactory.class.getDeclaredField("popToIDs"); popField.setAccessible(true); popField.set(factory, new HashMap>()); - } catch (Exception ignored) { } - - doAnswer(invocation -> { - mockCells(factory, seriesOnePop, "A", 5, 0); - return null; - }).when(factory).initialize(seriesOnePop, random); - - doAnswer(invocation -> { - mockCells(factory, seriesMultiPop, "B", 3, 0); - mockCells(factory, seriesMultiPop, "C", 1, 3); - mockCells(factory, seriesMultiPop, "D", 2, 4); - return null; - }).when(factory).initialize(seriesMultiPop, random); - - doAnswer(invocation -> { - mockCells(factory, seriesNullCell, "A", 2, 0); - factory.cells.remove(2); - return null; - }).when(factory).initialize(seriesNullCell, random); - - doAnswer(invocation -> { - mockCells(factory, seriesNullLocation, "A", 2, 0); - return null; - }).when(factory).initialize(seriesNullLocation, random); - - doAnswer(invocation -> { - mockCells(factory, seriesNullBoth, "A", 2, 0); - factory.cells.remove(2); - return null; - }).when(factory).initialize(seriesNullBoth, random); - + } catch (Exception ignored) { + } + + doAnswer( + invocation -> { + mockCells(factory, seriesOnePop, "A", 5, 0); + return null; + }) + .when(factory) + .initialize(seriesOnePop, random); + + doAnswer( + invocation -> { + mockCells(factory, seriesMultiPop, "B", 3, 0); + mockCells(factory, seriesMultiPop, "C", 1, 3); + mockCells(factory, seriesMultiPop, "D", 2, 4); + return null; + }) + .when(factory) + .initialize(seriesMultiPop, random); + + doAnswer( + invocation -> { + mockCells(factory, seriesNullCell, "A", 2, 0); + factory.cells.remove(2); + return null; + }) + .when(factory) + .initialize(seriesNullCell, random); + + doAnswer( + invocation -> { + mockCells(factory, seriesNullLocation, "A", 2, 0); + return null; + }) + .when(factory) + .initialize(seriesNullLocation, random); + + doAnswer( + invocation -> { + mockCells(factory, seriesNullBoth, "A", 2, 0); + factory.cells.remove(2); + return null; + }) + .when(factory) + .initialize(seriesNullBoth, random); + return factory; } } - + @Test public void getSeries_initialized_returnsObject() { Series series = mock(PottsSeries.class); PottsSimulationMock sim = new PottsSimulationMock(RANDOM_SEED, series); assertEquals(series, sim.getSeries()); } - + @Test public void getSchedule_initialized_returnsObject() { Series series = mock(PottsSeries.class); PottsSimulationMock sim = new PottsSimulationMock(RANDOM_SEED, series); assertEquals(sim.schedule, sim.getSchedule()); } - + @Test public void getSeed_initialized_returnsValue() { Series series = mock(PottsSeries.class); PottsSimulationMock sim = new PottsSimulationMock(RANDOM_SEED + SEED_OFFSET, series); assertEquals(RANDOM_SEED, sim.getSeed()); } - + @Test public void getID_initialized_incrementsValue() { Series series = mock(PottsSeries.class); @@ -270,7 +324,7 @@ public void getID_initialized_incrementsValue() { assertEquals(2, sim.getID()); assertEquals(3, sim.getID()); } - + @Test public void getID_started_resetsValues() { PottsSimulationMock sim = new PottsSimulationMock(RANDOM_SEED, seriesZeroPop); @@ -281,132 +335,132 @@ public void getID_started_resetsValues() { sim.start(); assertEquals(1, sim.getID()); } - + @Test public void getCells_givenList_returnsContainers() { PottsSimulation sim = mock(PottsSimulation.class, CALLS_REAL_METHODS); sim.grid = mock(Grid.class); - + Bag objects = new Bag(); ArrayList cellContainers = new ArrayList<>(); doReturn(objects).when(sim.grid).getAllObjects(); - + int n = randomIntBetween(5, 10); for (int i = 0; i < n; i++) { Cell cell = mock(Cell.class); CellContainer cellContainer = mock(CellContainer.class); doReturn(i).when(cell).getID(); doReturn(cellContainer).when(cell).convert(); - + objects.add(cell); cellContainers.add(cellContainer); } - + assertEquals(cellContainers, sim.getCells()); } - + @Test public void getLocations_givenList_returnsContainers() { PottsSimulation sim = mock(PottsSimulation.class, CALLS_REAL_METHODS); sim.grid = mock(Grid.class); - + Bag objects = new Bag(); ArrayList locationContainers = new ArrayList<>(); - + doReturn(objects).when(sim.grid).getAllObjects(); - + int n = randomIntBetween(5, 10); for (int i = 0; i < n; i++) { Cell cell = mock(Cell.class); Location location = mock(Location.class); LocationContainer locationContainer = mock(LocationContainer.class); - + doReturn(i).when(cell).getID(); doReturn(location).when(cell).getLocation(); doReturn(locationContainer).when(location).convert(i); - + objects.add(cell); locationContainers.add(locationContainer); } - + assertEquals(locationContainers, sim.getLocations()); } - + @Test public void getPotts_initialized_returnsNull() { Series series = mock(PottsSeries.class); PottsSimulationMock sim = new PottsSimulationMock(RANDOM_SEED, series); assertNull(sim.getPotts()); } - + @Test public void getGrid_initialized_returnsNull() { Series series = mock(PottsSeries.class); PottsSimulationMock sim = new PottsSimulationMock(RANDOM_SEED, series); assertNull(sim.getGrid()); } - + @Test public void getLattice_initialized_returnsNull() { Series series = mock(PottsSeries.class); PottsSimulationMock sim = new PottsSimulationMock(RANDOM_SEED, series); assertNull(sim.getLattice("")); } - + @Test public void start_called_callsMethods() { Series series = createSeries(new int[0], new String[0]); PottsSimulationMock sim = spy(new PottsSimulationMock(RANDOM_SEED, series)); doNothing().when(sim).doOutput(anyBoolean()); sim.start(); - + verify(sim).setupPotts(); verify(sim).setupAgents(); verify(sim).setupEnvironment(); verify(sim).scheduleActions(); verify(sim).scheduleComponents(); } - + @Test public void start_isVis_skipsSaver() { Series series = createSeries(new int[0], new String[0]); series.saver = mock(OutputSaver.class); series.isVis = true; - + PottsSimulationMock sim = spy(new PottsSimulationMock(RANDOM_SEED, series)); doNothing().when(sim).doOutput(anyBoolean()); sim.start(); - + verify(sim, never()).doOutput(true); verify(series.saver, never()).equip(sim); } - + @Test public void start_notVis_setsSaver() { Series series = createSeries(new int[0], new String[0]); series.saver = mock(OutputSaver.class); series.isVis = false; - + PottsSimulationMock sim = spy(new PottsSimulationMock(RANDOM_SEED, series)); doNothing().when(sim).doOutput(anyBoolean()); sim.start(); - + verify(sim).doOutput(true); verify(series.saver).equip(sim); } - + @Test public void start_notNull_setsLoader() { Series series = createSeries(new int[0], new String[0]); series.loader = mock(OutputLoader.class); - + PottsSimulationMock sim = spy(new PottsSimulationMock(RANDOM_SEED, series)); doNothing().when(sim).doOutput(anyBoolean()); sim.start(); - + verify(series.loader).equip(sim); } - + @Test public void finish_isVis_callsMethods() { Series series = createSeries(new int[0], new String[0]); @@ -414,10 +468,10 @@ public void finish_isVis_callsMethods() { PottsSimulationMock sim = spy(new PottsSimulationMock(RANDOM_SEED, series)); doNothing().when(sim).doOutput(anyBoolean()); sim.finish(); - + verify(sim, never()).doOutput(false); } - + @Test public void finish_isNotVis_callsMethods() { Series series = createSeries(new int[0], new String[0]); @@ -425,10 +479,10 @@ public void finish_isNotVis_callsMethods() { PottsSimulationMock sim = spy(new PottsSimulationMock(RANDOM_SEED, series)); doNothing().when(sim).doOutput(anyBoolean()); sim.finish(); - + verify(sim).doOutput(false); } - + @Test public void setupPotts_mockSeries_initializesPotts() { Series series = mock(PottsSeries.class); @@ -436,7 +490,7 @@ public void setupPotts_mockSeries_initializesPotts() { sim.setupPotts(); assertNotNull(sim.potts); } - + @Test public void setupPotts_mockSeries_schedulesPotts() { Series series = mock(PottsSeries.class); @@ -446,7 +500,7 @@ public void setupPotts_mockSeries_schedulesPotts() { sim.setupPotts(); verify(sim.schedule).scheduleRepeating(1, Ordering.POTTS.ordinal(), sim.potts); } - + @Test public void setupAgents_anyPopulation_setsPotts() { PottsSimulationMock sim = new PottsSimulationMock(RANDOM_SEED, seriesZeroPop); @@ -454,7 +508,7 @@ public void setupAgents_anyPopulation_setsPotts() { sim.setupAgents(); assertEquals(sim.grid, sim.potts.grid); } - + @Test public void setupAgents_zeroPopulations_initializesGrid() { PottsSimulationMock sim = new PottsSimulationMock(RANDOM_SEED, seriesZeroPop); @@ -462,7 +516,7 @@ public void setupAgents_zeroPopulations_initializesGrid() { sim.setupAgents(); assertNotNull(sim.grid); } - + @Test public void setupAgents_zeroPopulations_createsNoAgents() { PottsSimulationMock sim = new PottsSimulationMock(RANDOM_SEED, seriesZeroPop); @@ -470,15 +524,15 @@ public void setupAgents_zeroPopulations_createsNoAgents() { sim.setupAgents(); assertEquals(0, sim.grid.getAllObjects().numObjs); } - + @Test public void setupAgents_onePopulation_createsAgents() { PottsSimulationMock sim = new PottsSimulationMock(RANDOM_SEED, seriesOnePop); sim.potts = mock(Potts.class); sim.setupAgents(); assertEquals(TOTAL_LOCATIONS - 1, sim.grid.getAllObjects().numObjs); - - int[] pops = new int[] { 1, 1, 1, 1, 1 }; + + int[] pops = new int[] {1, 1, 1, 1, 1}; for (int i = 0; i < TOTAL_LOCATIONS - 1; i++) { int id = i + 1; Cell cell = (Cell) sim.grid.getObjectAt(id); @@ -486,32 +540,32 @@ public void setupAgents_onePopulation_createsAgents() { assertEquals(pops[i], cell.getPop()); assertEquals(new Voxel(id, id, id), ((PottsLocation) cell.getLocation()).getCenter()); } - + assertNull(sim.grid.getObjectAt(6)); assertEquals(TOTAL_LOCATIONS, sim.getID()); } - + @Test public void setupAgents_onePopulation_callMethods() { PottsSimulationMock sim = spy(new PottsSimulationMock(RANDOM_SEED, seriesOnePop)); sim.potts = mock(Potts.class); sim.setupAgents(); - + for (Object obj : sim.grid.getAllObjects()) { verify((PottsCell) obj).initialize(sim.potts.ids, sim.potts.regions); verify((Cell) obj).schedule(sim.schedule); verify(sim.potts).register((PottsCell) obj); } } - + @Test public void setupAgents_multiplePopulations_createsAgents() { PottsSimulationMock sim = new PottsSimulationMock(RANDOM_SEED, seriesMultiPop); sim.potts = mock(Potts.class); sim.setupAgents(); assertEquals(TOTAL_LOCATIONS, sim.grid.getAllObjects().numObjs); - - int[] pops = new int[] { 1, 1, 1, 2, 3, 3 }; + + int[] pops = new int[] {1, 1, 1, 2, 3, 3}; for (int i = 0; i < TOTAL_LOCATIONS; i++) { int id = i + 1; Cell cell = (Cell) sim.grid.getObjectAt(id); @@ -519,23 +573,23 @@ public void setupAgents_multiplePopulations_createsAgents() { assertEquals(pops[i], cell.getPop()); assertEquals(new Voxel(id, id, id), ((PottsLocation) cell.getLocation()).getCenter()); } - + assertEquals(TOTAL_LOCATIONS + 1, sim.getID()); } - + @Test public void setupAgents_multiplePopulations_callMethods() { PottsSimulationMock sim = spy(new PottsSimulationMock(RANDOM_SEED, seriesMultiPop)); sim.potts = mock(Potts.class); sim.setupAgents(); - + for (Object obj : sim.grid.getAllObjects()) { verify((PottsCell) obj).initialize(sim.potts.ids, sim.potts.regions); verify((PottsCell) obj).schedule(sim.schedule); verify(sim.potts).register((PottsCell) obj); } } - + @Test public void setupAgents_insufficientLocations_excludesExtra() { PottsSimulationMock sim = spy(new PottsSimulationMock(RANDOM_SEED, seriesNullLocation)); @@ -544,7 +598,7 @@ public void setupAgents_insufficientLocations_excludesExtra() { assertEquals(1, sim.grid.getAllObjects().numObjs); assertEquals(2, sim.getID()); } - + @Test public void setupAgents_insufficientCells_excludesExtra() { PottsSimulationMock sim = spy(new PottsSimulationMock(RANDOM_SEED, seriesNullCell)); @@ -553,7 +607,7 @@ public void setupAgents_insufficientCells_excludesExtra() { assertEquals(1, sim.grid.getAllObjects().numObjs); assertEquals(2, sim.getID()); } - + @Test public void setupAgents_insufficientBoth_excludesExtra() { PottsSimulationMock sim = spy(new PottsSimulationMock(RANDOM_SEED, seriesNullBoth)); @@ -562,39 +616,39 @@ public void setupAgents_insufficientBoth_excludesExtra() { assertEquals(1, sim.grid.getAllObjects().numObjs); assertEquals(2, sim.getID()); } - + @Test public void doOutput_isScheduled_schedulesOutput() { Series series = mock(PottsSeries.class); Schedule schedule = mock(Schedule.class); OutputSaver saver = mock(OutputSaver.class); - + PottsSimulation sim = new PottsSimulationMock(RANDOM_SEED, series); sim.series.saver = saver; sim.schedule = schedule; - + int interval = randomIntBetween(1, 100); doReturn(interval).when(series).getInterval(); - + sim.doOutput(true); verify(saver).schedule(schedule, interval); verify(saver, never()).saveCells(anyInt()); verify(saver, never()).saveLocations(anyInt()); } - + @Test public void doOutput_isNotScheduled_savesOutput() { Series series = mock(PottsSeries.class); Schedule schedule = mock(Schedule.class); OutputSaver saver = mock(OutputSaver.class); - + PottsSimulation sim = new PottsSimulationMock(RANDOM_SEED, series); sim.series.saver = saver; sim.schedule = schedule; - + double time = randomDoubleBetween(1, 100); doReturn(time).when(sim.schedule).getTime(); - + sim.doOutput(false); verify(saver, never()).schedule(eq(schedule), anyDouble()); verify(saver).saveCells((int) time + 1); diff --git a/test/arcade/potts/sim/PottsTest.java b/test/arcade/potts/sim/PottsTest.java index a3edd008a..04c61d693 100644 --- a/test/arcade/potts/sim/PottsTest.java +++ b/test/arcade/potts/sim/PottsTest.java @@ -4,7 +4,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; -import org.junit.Test; +import org.junit.jupiter.api.Test; import sim.engine.SimState; import ec.util.MersenneTwisterFast; import arcade.core.agent.cell.Cell; @@ -15,7 +15,7 @@ import arcade.potts.agent.cell.PottsCell; import arcade.potts.env.location.PottsLocation; import arcade.potts.sim.hamiltonian.Hamiltonian; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.core.ARCADETestUtilities.*; import static arcade.core.util.MiniBox.TAG_SEPARATOR; @@ -24,40 +24,42 @@ public class PottsTest { private static final double EPSILON = 1E-10; - + private static final double TEMPERATURE = 10; - + private static final double R = randomDoubleBetween(0, 1); - + private static final double R_PLUS = Math.exp(-3 / TEMPERATURE) + EPSILON; - + private static final double R_MINUS = Math.exp(-3 / TEMPERATURE) - EPSILON; - + static class PottsMock extends Potts { - PottsMock(PottsSeries series) { super(series); } - + PottsMock(PottsSeries series) { + super(series); + } + @Override Hamiltonian getHamiltonian(Term term, PottsSeries series) { Hamiltonian hamiltonian = mock(Hamiltonian.class); doReturn(term.name()).when(hamiltonian).toString(); return hamiltonian; } - + @Override boolean[][][] getNeighborhood(int id, int x, int y, int z) { - return new boolean[][][] { { { x != 0 } } }; + return new boolean[][][] {{{x != 0}}}; } - + @Override boolean[][][] getNeighborhood(int id, int region, int x, int y, int z) { - return new boolean[][][] { { { y != 0 } } }; + return new boolean[][][] {{{y != 0}}}; } - + @Override boolean getConnectivity(boolean[][][] array, boolean zero) { return array[0][0][0]; } - + @Override HashSet getUniqueIDs(int x, int y, int z) { HashSet set = new HashSet<>(); @@ -67,7 +69,7 @@ HashSet getUniqueIDs(int x, int y, int z) { } return set; } - + @Override HashSet getUniqueRegions(int x, int y, int z) { HashSet set = new HashSet<>(); @@ -78,7 +80,7 @@ HashSet getUniqueRegions(int x, int y, int z) { return set; } } - + static PottsSeries makeSeries() { PottsSeries series = mock(PottsSeries.class); series.potts = mock(MiniBox.class); @@ -86,76 +88,80 @@ static PottsSeries makeSeries() { doReturn(1.0).when(series.potts).getDouble("MCS"); return series; } - + static PottsSeries makeSeries(int length, int width, int height) { return makeSeries(length, width, height, 1, 1); } - + static PottsSeries makeSeries(int length, int width, int height, double ds, double dt) { PottsSeries series = makeSeries(); series.terms = new ArrayList<>(); - + try { Field lengthField = Series.class.getDeclaredField("length"); lengthField.setAccessible(true); lengthField.setInt(series, length); - + Field widthField = Series.class.getDeclaredField("width"); widthField.setAccessible(true); widthField.setInt(series, width); - + Field heightField = Series.class.getDeclaredField("height"); heightField.setAccessible(true); heightField.setInt(series, height); - + Field dsField = Series.class.getDeclaredField("ds"); dsField.setAccessible(true); dsField.setDouble(series, ds); - + Field dtField = Series.class.getDeclaredField("dt"); dtField.setAccessible(true); dtField.setDouble(series, dt); - } catch (Exception ignored) { } - + } catch (Exception ignored) { + } + return series; } - + static PottsMock makeFlipMock() { PottsSeries series = makeSeries(4, 4, 1); PottsMock spy = spy(new PottsMock(series)); - + spy.regions[0][0][0] = Region.NUCLEUS.ordinal(); spy.regions[0][0][1] = Region.NUCLEUS.ordinal(); spy.regions[0][1][0] = Region.NUCLEUS.ordinal(); spy.regions[0][1][1] = Region.NUCLEUS.ordinal(); - + doNothing().when(spy).change(anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyDouble()); - doNothing().when(spy).change(anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyDouble()); + doNothing() + .when(spy) + .change(anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyDouble()); return spy; } - + static PottsMock makeChangeMock(int source, int target, double[] values, boolean hasRegions) { Grid grid = mock(Grid.class); PottsSeries series = makeSeries(3, 3, 1); PottsMock spy = spy(new PottsMock(series)); spy.grid = grid; - + try { Field regionField = Potts.class.getDeclaredField("hasRegions"); regionField.setAccessible(true); regionField.setBoolean(spy, hasRegions); - + Field tempField = Potts.class.getDeclaredField("temperature"); tempField.setAccessible(true); tempField.setDouble(spy, TEMPERATURE); - } catch (Exception ignored) { } - + } catch (Exception ignored) { + } + for (double v : values) { Hamiltonian hamiltonian = mock(Hamiltonian.class); doReturn(v).when(hamiltonian).getDelta(source, target, 0, 0, 0); spy.hamiltonian.add(hamiltonian); } - + if (source != 0) { Cell cellSource = mock(PottsCell.class); Location locationSource = mock(PottsLocation.class); @@ -163,7 +169,7 @@ static PottsMock makeChangeMock(int source, int target, double[] values, boolean doReturn(cellSource).when(spy).getCell(source); doReturn(cellSource).when(grid).getObjectAt(source); } - + if (target != 0) { Cell cellTarget = mock(PottsCell.class); Location locationTarget = mock(PottsLocation.class); @@ -171,48 +177,49 @@ static PottsMock makeChangeMock(int source, int target, double[] values, boolean doReturn(cellTarget).when(spy).getCell(target); doReturn(cellTarget).when(grid).getObjectAt(target); } - + return spy; } - + static PottsMock makeChangeMock(int source, int target, double[] values) { Grid grid = mock(Grid.class); PottsSeries series = makeSeries(3, 3, 1); PottsMock spy = spy(new PottsMock(series)); spy.grid = grid; - + try { Field tempField = Potts.class.getDeclaredField("temperature"); tempField.setAccessible(true); tempField.setDouble(spy, TEMPERATURE); - } catch (Exception ignored) { } - + } catch (Exception ignored) { + } + for (double v : values) { Hamiltonian hamiltonian = mock(Hamiltonian.class); doReturn(v).when(hamiltonian).getDelta(1, source, target, 0, 0, 0); spy.hamiltonian.add(hamiltonian); } - + Cell cellSource = mock(PottsCell.class); Location locationSource = mock(PottsLocation.class); doReturn(locationSource).when(cellSource).getLocation(); doReturn(cellSource).when(spy).getCell(1); doReturn(cellSource).when(grid).getObjectAt(1); - + return spy; } - + @Test public void constructor_2D_assignsValues() { int length = randomIntBetween(1, 100); int width = randomIntBetween(1, 100); PottsSeries series = makeSeries(length + 2, width + 2, 1); PottsMock pottsMock = new PottsMock(series); - + assertEquals(length, pottsMock.length); assertEquals(width, pottsMock.width); assertEquals(1, pottsMock.height); - + assertEquals(1, pottsMock.ids.length); assertEquals(1, pottsMock.regions.length); assertEquals(length + 2, pottsMock.ids[0].length); @@ -220,18 +227,18 @@ public void constructor_2D_assignsValues() { assertEquals(width + 2, pottsMock.ids[0][0].length); assertEquals(width + 2, pottsMock.regions[0][0].length); } - + @Test public void constructor_3D_assignsValues() { int length = randomIntBetween(1, 100); int width = randomIntBetween(1, 100); PottsSeries series = makeSeries(length + 2, width + 2, 4); PottsMock pottsMock = new PottsMock(series); - + assertEquals(length, pottsMock.length); assertEquals(width, pottsMock.width); assertEquals(2, pottsMock.height); - + assertEquals(4, pottsMock.ids.length); assertEquals(4, pottsMock.regions.length); assertEquals(length + 2, pottsMock.ids[0].length); @@ -239,7 +246,7 @@ public void constructor_3D_assignsValues() { assertEquals(width + 2, pottsMock.ids[0][0].length); assertEquals(width + 2, pottsMock.regions[0][0].length); } - + @Test public void constructor_givenSeries_setsFields() { int length = randomIntBetween(1, 100); @@ -249,63 +256,63 @@ public void constructor_givenSeries_setsFields() { double mcs = randomDoubleBetween(0, 10); double ds = randomDoubleBetween(2, 10); double dt = randomDoubleBetween(2, 10); - + PottsSeries series = makeSeries(length, width, height, ds, dt); series.potts = new MiniBox(); series.potts.put("TEMPERATURE", temperature); series.potts.put("MCS", mcs); - + PottsMock pottsMock = new PottsMock(series); - + assertEquals((int) (mcs * (length - 2) * (width - 2) * (height - 2)), pottsMock.steps); assertEquals(temperature, pottsMock.temperature, EPSILON); } - + @Test public void constructor_noPopulations_setsFalse() { PottsSeries series = makeSeries(0, 0, 0); series.populations = new HashMap<>(); - + PottsMock pottsMock = new PottsMock(series); assertFalse(pottsMock.hasRegions); } - + @Test public void constructor_noRegions_setsFalse() { PottsSeries series = makeSeries(0, 0, 0); series.populations = new HashMap<>(); - + MiniBox popA = new MiniBox(); MiniBox popB = new MiniBox(); MiniBox popC = new MiniBox(); - + series.populations.put("A", popA); series.populations.put("B", popB); series.populations.put("C", popC); - + PottsMock pottsMock = new PottsMock(series); assertFalse(pottsMock.hasRegions); } - + @Test public void constructor_withRegions_setsTrue() { PottsSeries series = makeSeries(0, 0, 0); series.populations = new HashMap<>(); - + MiniBox popA = new MiniBox(); MiniBox popB = new MiniBox(); MiniBox popC = new MiniBox(); - + series.populations.put("A", popA); series.populations.put("B", popB); series.populations.put("C", popC); - + popB.put("(REGION)" + TAG_SEPARATOR + "X", "0"); - + PottsMock pottsMock = new PottsMock(series); assertTrue(pottsMock.hasRegions); } - + @Test public void constructor_withoutTerms_createEmpty() { PottsSeries series = makeSeries(0, 0, 0); @@ -313,11 +320,11 @@ public void constructor_withoutTerms_createEmpty() { assertNotNull(pottsMock.hamiltonian); assertEquals(0, pottsMock.hamiltonian.size()); } - + @Test public void constructor_withTerms_createsList() { PottsSeries series = makeSeries(0, 0, 0); - + int n = randomIntBetween(3, 10); ArrayList terms = new ArrayList<>(); for (int i = 0; i < n; i++) { @@ -325,109 +332,113 @@ public void constructor_withTerms_createsList() { doReturn("term" + i).when(term).name(); terms.add(term); } - + series.terms = terms; PottsMock pottsMock = spy(new PottsMock(series)); - + assertEquals(n, pottsMock.hamiltonian.size()); for (int i = 0; i < n; i++) { String termName = terms.get(i).name(); assertEquals(termName, pottsMock.hamiltonian.get(i).toString()); } } - + @Test public void register_called_callsMethods() { PottsSeries series = makeSeries(0, 0, 0); PottsMock pottsMock = new PottsMock(series); ArrayList hamiltonian = new ArrayList<>(); - + int n = randomIntBetween(3, 10); for (int i = 0; i < n; i++) { Hamiltonian h = mock(Hamiltonian.class); pottsMock.hamiltonian.add(h); hamiltonian.add(h); } - + PottsCell cell = mock(PottsCell.class); pottsMock.register(cell); - + for (int i = 0; i < n; i++) { verify(hamiltonian.get(i)).register(cell); } } - + @Test public void deregister_called_callsMethods() { PottsSeries series = makeSeries(0, 0, 0); PottsMock pottsMock = new PottsMock(series); ArrayList hamiltonian = new ArrayList<>(); - + int n = randomIntBetween(3, 10); for (int i = 0; i < n; i++) { Hamiltonian h = mock(Hamiltonian.class); pottsMock.hamiltonian.add(h); hamiltonian.add(h); } - + PottsCell cell = mock(PottsCell.class); pottsMock.deregister(cell); - + for (int i = 0; i < n; i++) { verify(hamiltonian.get(i)).deregister(cell); } } - + @Test public void step_2D_callsMethods() { MersenneTwisterFast random = new MersenneTwisterFast(1); SimState simstate = mock(SimState.class); simstate.random = random; - + int length = randomIntBetween(3, 10); int width = randomIntBetween(3, 10); - + PottsSeries series = makeSeries(length, width, 1); PottsMock spy = spy(new PottsMock(series)); int steps = spy.length * spy.width * spy.height; - + spy.step(simstate); - verify(spy, times(steps)).getUniqueIDs( - intThat(i -> i < length - 1 && i > 0), - intThat(i -> i < width - 1 && i > 0), - eq(0)); - verify(spy, times(steps)).getUniqueRegions( - intThat(i -> i < length - 1 && i > 0), - intThat(i -> i < width - 1 && i > 0), - eq(0)); + verify(spy, times(steps)) + .getUniqueIDs( + intThat(i -> i < length - 1 && i > 0), + intThat(i -> i < width - 1 && i > 0), + eq(0)); + verify(spy, times(steps)) + .getUniqueRegions( + intThat(i -> i < length - 1 && i > 0), + intThat(i -> i < width - 1 && i > 0), + eq(0)); } - + @Test public void step_3D_callsMethods() { MersenneTwisterFast random = new MersenneTwisterFast(1); SimState simstate = mock(SimState.class); simstate.random = random; - + int length = randomIntBetween(3, 10); int width = randomIntBetween(3, 10); int height = randomIntBetween(4, 10); - + PottsSeries series = makeSeries(length, width, height); - + PottsMock spy = spy(new PottsMock(series)); int steps = spy.length * spy.width * spy.height; - + spy.step(simstate); - verify(spy, times(steps)).getUniqueIDs( - intThat(i -> i < length - 1 && i > 0), - intThat(i -> i < width - 1 && i > 0), - intThat(i -> i < height - 1 && i > 0)); - verify(spy, times(steps)).getUniqueRegions( - intThat(i -> i < length - 1 && i > 0), - intThat(i -> i < width - 1 && i > 0), - intThat(i -> i < height - 1 && i > 0)); + verify(spy, times(steps)) + .getUniqueIDs( + intThat(i -> i < length - 1 && i > 0), + intThat(i -> i < width - 1 && i > 0), + intThat(i -> i < height - 1 && i > 0)); + verify(spy, times(steps)) + .getUniqueRegions( + intThat(i -> i < length - 1 && i > 0), + intThat(i -> i < width - 1 && i > 0), + intThat(i -> i < height - 1 && i > 0)); } - + @Test public void step_uniqueIDsHasNoRegions_callsMethods() { MersenneTwisterFast random = mock(MersenneTwisterFast.class); @@ -436,24 +447,27 @@ public void step_uniqueIDsHasNoRegions_callsMethods() { doReturn(R).when(random).nextDouble(); SimState simstate = mock(SimState.class); simstate.random = random; - + PottsSeries series = makeSeries(3, 3, 1); - + PottsMock spy = spy(new PottsMock(series)); spy.ids[0][0][0] = 1; - + PottsCell cell = mock(PottsCell.class); doReturn(false).when(cell).hasRegions(); doReturn(cell).when(spy).getCell(1); - + doNothing().when(spy).flip(anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyDouble()); - doNothing().when(spy).flip(anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyDouble()); - + doNothing() + .when(spy) + .flip(anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyDouble()); + spy.step(simstate); verify(spy).flip(1, 1, 0, 0, 0, R); - verify(spy, never()).flip(anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyDouble()); + verify(spy, never()) + .flip(anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyDouble()); } - + @Test public void step_uniqueIDsHasRegions_callsMethods() { MersenneTwisterFast random = mock(MersenneTwisterFast.class); @@ -462,24 +476,27 @@ public void step_uniqueIDsHasRegions_callsMethods() { doReturn(R).when(random).nextDouble(); SimState simstate = mock(SimState.class); simstate.random = random; - + PottsSeries series = makeSeries(3, 3, 1); - + PottsMock spy = spy(new PottsMock(series)); spy.ids[0][0][0] = 1; - + PottsCell cell = mock(PottsCell.class); doReturn(true).when(cell).hasRegions(); doReturn(cell).when(spy).getCell(1); - + doNothing().when(spy).flip(anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyDouble()); - doNothing().when(spy).flip(anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyDouble()); - + doNothing() + .when(spy) + .flip(anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyDouble()); + spy.step(simstate); verify(spy).flip(1, 1, 0, 0, 0, R); - verify(spy, never()).flip(anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyDouble()); + verify(spy, never()) + .flip(anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyDouble()); } - + @Test public void step_uniqueRegionsHasNoRegions_callsMethods() { MersenneTwisterFast random = mock(MersenneTwisterFast.class); @@ -488,25 +505,28 @@ public void step_uniqueRegionsHasNoRegions_callsMethods() { doReturn(R).when(random).nextDouble(); SimState simstate = mock(SimState.class); simstate.random = random; - + PottsSeries series = makeSeries(3, 3, 1); - + PottsMock spy = spy(new PottsMock(series)); spy.ids[0][1][0] = 1; spy.regions[0][1][0] = Region.DEFAULT.ordinal(); - + PottsCell cell = mock(PottsCell.class); doReturn(false).when(cell).hasRegions(); doReturn(cell).when(spy).getCell(1); - + doNothing().when(spy).flip(anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyDouble()); - doNothing().when(spy).flip(anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyDouble()); - + doNothing() + .when(spy) + .flip(anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyDouble()); + spy.step(simstate); verify(spy, never()).flip(anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyDouble()); - verify(spy, never()).flip(anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyDouble()); + verify(spy, never()) + .flip(anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyDouble()); } - + @Test public void step_uniqueRegionsHasRegions_callsMethods() { MersenneTwisterFast random = mock(MersenneTwisterFast.class); @@ -515,25 +535,27 @@ public void step_uniqueRegionsHasRegions_callsMethods() { doReturn(R).when(random).nextDouble(); SimState simstate = mock(SimState.class); simstate.random = random; - + PottsSeries series = makeSeries(3, 3, 1); - + PottsMock spy = spy(new PottsMock(series)); spy.ids[0][1][0] = 1; spy.regions[0][1][0] = Region.DEFAULT.ordinal(); - + PottsCell cell = mock(PottsCell.class); doReturn(true).when(cell).hasRegions(); doReturn(cell).when(spy).getCell(1); - + doNothing().when(spy).flip(anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyDouble()); - doNothing().when(spy).flip(anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyDouble()); - + doNothing() + .when(spy) + .flip(anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyDouble()); + spy.step(simstate); verify(spy, never()).flip(anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyDouble()); verify(spy).flip(1, Region.DEFAULT.ordinal(), Region.NUCLEUS.ordinal(), 1, 0, 0, R); } - + @Test public void flip_unconnectedSourceID_returns() { PottsMock spy = makeFlipMock(); @@ -541,7 +563,7 @@ public void flip_unconnectedSourceID_returns() { verify(spy).getNeighborhood(1, 0, 0, 0); verify(spy, never()).change(anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), eq(R)); } - + @Test public void flip_unconnectedSourceIDNeighbor_returns() { PottsMock spy = makeFlipMock(); @@ -550,7 +572,7 @@ public void flip_unconnectedSourceIDNeighbor_returns() { verify(spy).getNeighborhood(1, 0, 0, 0); verify(spy, never()).change(anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), eq(R)); } - + @Test public void flip_connectedSourceUnconnectedSourceRegion_returns() { PottsMock spy = makeFlipMock(); @@ -559,7 +581,7 @@ public void flip_connectedSourceUnconnectedSourceRegion_returns() { verify(spy).getNeighborhood(1, Region.NUCLEUS.ordinal(), 1, 0, 0); verify(spy, never()).change(anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), eq(R)); } - + @Test public void flip_connectedSourceConnectedSourceRegion_completes() { PottsMock spy = makeFlipMock(); @@ -568,7 +590,7 @@ public void flip_connectedSourceConnectedSourceRegion_completes() { verify(spy).getNeighborhood(1, Region.NUCLEUS.ordinal(), 1, 1, 0); verify(spy).change(anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), eq(R)); } - + @Test public void flip_connectedSourceDefaultRegion_completes() { PottsMock spy = makeFlipMock(); @@ -578,7 +600,7 @@ public void flip_connectedSourceDefaultRegion_completes() { verify(spy, never()).getNeighborhood(1, Region.DEFAULT.ordinal(), 1, 1, 0); verify(spy).change(anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), eq(R)); } - + @Test public void flip_unconnectedTargetID_returns() { PottsMock spy = makeFlipMock(); @@ -586,7 +608,7 @@ public void flip_unconnectedTargetID_returns() { verify(spy).getNeighborhood(2, 0, 0, 0); verify(spy, never()).change(anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), eq(R)); } - + @Test public void flip_unconnectedTargetIDNeighbor_returns() { PottsMock spy = makeFlipMock(); @@ -595,7 +617,7 @@ public void flip_unconnectedTargetIDNeighbor_returns() { verify(spy).getNeighborhood(2, 0, 0, 0); verify(spy, never()).change(anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), eq(R)); } - + @Test public void flip_connectedTargetUnconnectedTargetRegion_returns() { PottsMock spy = makeFlipMock(); @@ -604,7 +626,7 @@ public void flip_connectedTargetUnconnectedTargetRegion_returns() { verify(spy).getNeighborhood(2, Region.NUCLEUS.ordinal(), 1, 0, 0); verify(spy, never()).change(anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), eq(R)); } - + @Test public void flip_connectedTargetConnectedTargetRegion_completes() { PottsMock spy = makeFlipMock(); @@ -613,7 +635,7 @@ public void flip_connectedTargetConnectedTargetRegion_completes() { verify(spy).getNeighborhood(2, Region.NUCLEUS.ordinal(), 1, 1, 0); verify(spy).change(anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), eq(R)); } - + @Test public void flip_connectedTargetDefaultRegion_completes() { PottsMock spy = makeFlipMock(); @@ -623,7 +645,7 @@ public void flip_connectedTargetDefaultRegion_completes() { verify(spy, never()).getNeighborhood(2, Region.DEFAULT.ordinal(), 1, 1, 0); verify(spy).change(anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), eq(R)); } - + @Test public void flip_connectedSourceZeroFalse_returns() { PottsMock spy = makeFlipMock(); @@ -631,7 +653,7 @@ public void flip_connectedSourceZeroFalse_returns() { spy.flip(1, 0, 0, 0, 0, R); verify(spy).getConnectivity(any(), eq(false)); } - + @Test public void flip_connectedSourceZeroTrue_completes() { PottsMock spy = makeFlipMock(); @@ -639,7 +661,7 @@ public void flip_connectedSourceZeroTrue_completes() { spy.flip(1, 0, 0, 0, 0, R); verify(spy).getConnectivity(any(), eq(true)); } - + @Test public void flip_connectedTargetZeroFalse_returns() { PottsMock spy = makeFlipMock(); @@ -647,7 +669,7 @@ public void flip_connectedTargetZeroFalse_returns() { spy.flip(0, 1, 0, 0, 0, R); verify(spy).getConnectivity(any(), eq(false)); } - + @Test public void flip_connectedTargetZeroTrue_completes() { PottsMock spy = makeFlipMock(); @@ -655,22 +677,22 @@ public void flip_connectedTargetZeroTrue_completes() { spy.flip(0, 1, 0, 0, 0, R); verify(spy).getConnectivity(any(), eq(true)); } - + @Test public void change_zeros_callsMethods() { int id1 = randomIntBetween(1, 10); int id2 = randomIntBetween(1, 10); - PottsMock spy = makeChangeMock(id1, id2, new double[] { 0, 0, 0 }, false); + PottsMock spy = makeChangeMock(id1, id2, new double[] {0, 0, 0}, false); spy.change(id1, id2, 0, 0, 0, 1); - + for (Hamiltonian h : spy.hamiltonian) { verify(h).getDelta(id1, id2, 0, 0, 0); } } - + @Test public void change_negativeEnergyZeroSourceNonzeroTargetRegions_updatesFields() { - PottsMock spy = makeChangeMock(0, 1, new double[] { 1, -1, -1 }, true); + PottsMock spy = makeChangeMock(0, 1, new double[] {1, -1, -1}, true); spy.ids[0][0][0] = 0; spy.regions[0][0][0] = Region.UNDEFINED.ordinal(); spy.change(0, 1, 0, 0, 0, 0); @@ -678,10 +700,10 @@ public void change_negativeEnergyZeroSourceNonzeroTargetRegions_updatesFields() assertEquals(Region.DEFAULT.ordinal(), spy.regions[0][0][0]); verify(((PottsLocation) ((Cell) spy.grid.getObjectAt(1)).getLocation())).add(0, 0, 0); } - + @Test public void change_negativeEnergyNonzeroSourceZeroTargetRegions_updatesFields() { - PottsMock spy = makeChangeMock(1, 0, new double[] { 1, -1, -1 }, true); + PottsMock spy = makeChangeMock(1, 0, new double[] {1, -1, -1}, true); spy.ids[0][0][0] = 1; spy.regions[0][0][0] = Region.DEFAULT.ordinal(); spy.change(1, 0, 0, 0, 0, 0); @@ -689,10 +711,10 @@ public void change_negativeEnergyNonzeroSourceZeroTargetRegions_updatesFields() assertEquals(Region.UNDEFINED.ordinal(), spy.regions[0][0][0]); verify(((PottsLocation) ((Cell) spy.grid.getObjectAt(1)).getLocation())).remove(0, 0, 0); } - + @Test public void change_negativeEnergyNonzeroSourceNonzeroTargetRegions_updatesFields() { - PottsMock spy = makeChangeMock(1, 2, new double[] { 1, -1, -1 }, true); + PottsMock spy = makeChangeMock(1, 2, new double[] {1, -1, -1}, true); spy.ids[0][0][0] = 1; spy.regions[0][0][0] = Region.DEFAULT.ordinal(); spy.change(1, 2, 0, 0, 0, 0); @@ -701,64 +723,68 @@ public void change_negativeEnergyNonzeroSourceNonzeroTargetRegions_updatesFields verify(((PottsLocation) ((Cell) spy.grid.getObjectAt(2)).getLocation())).add(0, 0, 0); verify(((PottsLocation) ((Cell) spy.grid.getObjectAt(1)).getLocation())).remove(0, 0, 0); } - + @Test public void change_positiveEnergyZeroSourceNonzeroTargetRegions_updatesFields() { - PottsMock spy = makeChangeMock(0, 1, new double[] { -1, 1, 3 }, true); + PottsMock spy = makeChangeMock(0, 1, new double[] {-1, 1, 3}, true); spy.ids[0][0][0] = 0; spy.regions[0][0][0] = Region.UNDEFINED.ordinal(); - + spy.change(0, 1, 0, 0, 0, R_PLUS); assertEquals(0, spy.ids[0][0][0]); assertEquals(Region.UNDEFINED.ordinal(), spy.regions[0][0][0]); - verify(((PottsLocation) ((Cell) spy.grid.getObjectAt(1)).getLocation()), never()).add(0, 0, 0); - + verify(((PottsLocation) ((Cell) spy.grid.getObjectAt(1)).getLocation()), never()) + .add(0, 0, 0); + spy.change(0, 1, 0, 0, 0, R_MINUS); assertEquals(1, spy.ids[0][0][0]); assertEquals(Region.DEFAULT.ordinal(), spy.regions[0][0][0]); Cell cell2 = (Cell) spy.grid.getObjectAt(1); verify((PottsLocation) cell2.getLocation()).add(0, 0, 0); } - + @Test public void change_positiveEnergyNonzeroSourceZeroTargetRegions_updatesFields() { - PottsMock spy = makeChangeMock(1, 0, new double[] { -1, 1, 3 }, true); + PottsMock spy = makeChangeMock(1, 0, new double[] {-1, 1, 3}, true); spy.ids[0][0][0] = 1; spy.regions[0][0][0] = Region.DEFAULT.ordinal(); - + spy.change(1, 0, 0, 0, 0, R_PLUS); assertEquals(1, spy.ids[0][0][0]); assertEquals(Region.DEFAULT.ordinal(), spy.regions[0][0][0]); - verify(((PottsLocation) ((Cell) spy.grid.getObjectAt(1)).getLocation()), never()).remove(0, 0, 0); - + verify(((PottsLocation) ((Cell) spy.grid.getObjectAt(1)).getLocation()), never()) + .remove(0, 0, 0); + spy.change(1, 0, 0, 0, 0, R_MINUS); assertEquals(0, spy.ids[0][0][0]); assertEquals(Region.UNDEFINED.ordinal(), spy.regions[0][0][0]); verify(((PottsLocation) ((Cell) spy.grid.getObjectAt(1)).getLocation())).remove(0, 0, 0); } - + @Test public void change_positiveEnergyNonzeroSourceNonzeroTargetRegions_updatesFields() { - PottsMock spy = makeChangeMock(1, 2, new double[] { -1, 1, 3 }, true); + PottsMock spy = makeChangeMock(1, 2, new double[] {-1, 1, 3}, true); spy.ids[0][0][0] = 1; spy.regions[0][0][0] = Region.DEFAULT.ordinal(); - + spy.change(1, 2, 0, 0, 0, R_PLUS); assertEquals(1, spy.ids[0][0][0]); assertEquals(Region.DEFAULT.ordinal(), spy.regions[0][0][0]); - verify(((PottsLocation) ((Cell) spy.grid.getObjectAt(1)).getLocation()), never()).remove(0, 0, 0); - verify(((PottsLocation) ((Cell) spy.grid.getObjectAt(2)).getLocation()), never()).add(0, 0, 0); - + verify(((PottsLocation) ((Cell) spy.grid.getObjectAt(1)).getLocation()), never()) + .remove(0, 0, 0); + verify(((PottsLocation) ((Cell) spy.grid.getObjectAt(2)).getLocation()), never()) + .add(0, 0, 0); + spy.change(1, 2, 0, 0, 0, R_MINUS); assertEquals(2, spy.ids[0][0][0]); assertEquals(Region.DEFAULT.ordinal(), spy.regions[0][0][0]); verify(((PottsLocation) ((Cell) spy.grid.getObjectAt(1)).getLocation())).remove(0, 0, 0); verify(((PottsLocation) ((Cell) spy.grid.getObjectAt(2)).getLocation())).add(0, 0, 0); } - + @Test public void change_negativeEnergyZeroSourceNonzeroTargetNoRegions_updatesFields() { - PottsMock spy = makeChangeMock(0, 1, new double[] { 1, -1, -1 }, false); + PottsMock spy = makeChangeMock(0, 1, new double[] {1, -1, -1}, false); spy.ids[0][0][0] = 0; spy.regions[0][0][0] = Region.UNDEFINED.ordinal(); spy.change(0, 1, 0, 0, 0, 0); @@ -766,10 +792,10 @@ public void change_negativeEnergyZeroSourceNonzeroTargetNoRegions_updatesFields( assertEquals(Region.UNDEFINED.ordinal(), spy.regions[0][0][0]); verify(((PottsLocation) ((Cell) spy.grid.getObjectAt(1)).getLocation())).add(0, 0, 0); } - + @Test public void change_negativeEnergyNonzeroSourceZeroTargetNoRegions_updatesFields() { - PottsMock spy = makeChangeMock(1, 0, new double[] { 1, -1, -1 }, false); + PottsMock spy = makeChangeMock(1, 0, new double[] {1, -1, -1}, false); spy.ids[0][0][0] = 1; spy.regions[0][0][0] = Region.UNDEFINED.ordinal(); spy.change(1, 0, 0, 0, 0, 0); @@ -777,10 +803,10 @@ public void change_negativeEnergyNonzeroSourceZeroTargetNoRegions_updatesFields( assertEquals(Region.UNDEFINED.ordinal(), spy.regions[0][0][0]); verify(((PottsLocation) ((Cell) spy.grid.getObjectAt(1)).getLocation())).remove(0, 0, 0); } - + @Test public void change_negativeEnergyNonzeroSourceNonzeroTargetNoRegions_updatesFields() { - PottsMock spy = makeChangeMock(1, 2, new double[] { 1, -1, -1 }, false); + PottsMock spy = makeChangeMock(1, 2, new double[] {1, -1, -1}, false); spy.ids[0][0][0] = 1; spy.regions[0][0][0] = Region.UNDEFINED.ordinal(); spy.change(1, 2, 0, 0, 0, 0); @@ -789,68 +815,73 @@ public void change_negativeEnergyNonzeroSourceNonzeroTargetNoRegions_updatesFiel verify(((PottsLocation) ((Cell) spy.grid.getObjectAt(2)).getLocation())).add(0, 0, 0); verify(((PottsLocation) ((Cell) spy.grid.getObjectAt(1)).getLocation())).remove(0, 0, 0); } - + @Test public void change_positiveEnergyZeroSourceNonzeroTargetNoRegions_updatesFields() { - PottsMock spy = makeChangeMock(0, 1, new double[] { -1, 1, 3 }, false); + PottsMock spy = makeChangeMock(0, 1, new double[] {-1, 1, 3}, false); spy.ids[0][0][0] = 0; spy.regions[0][0][0] = Region.UNDEFINED.ordinal(); - + spy.change(0, 1, 0, 0, 0, R_PLUS); assertEquals(0, spy.ids[0][0][0]); assertEquals(Region.UNDEFINED.ordinal(), spy.regions[0][0][0]); - verify(((PottsLocation) ((Cell) spy.grid.getObjectAt(1)).getLocation()), never()).add(0, 0, 0); - + verify(((PottsLocation) ((Cell) spy.grid.getObjectAt(1)).getLocation()), never()) + .add(0, 0, 0); + spy.change(0, 1, 0, 0, 0, R_MINUS); assertEquals(1, spy.ids[0][0][0]); assertEquals(Region.UNDEFINED.ordinal(), spy.regions[0][0][0]); verify(((PottsLocation) ((Cell) spy.grid.getObjectAt(1)).getLocation())).add(0, 0, 0); } - + @Test public void change_positiveEnergyNonzeroSourceZeroTargetNoRegions_updatesFields() { - PottsMock spy = makeChangeMock(1, 0, new double[] { -1, 1, 3 }, false); + PottsMock spy = makeChangeMock(1, 0, new double[] {-1, 1, 3}, false); spy.ids[0][0][0] = 1; spy.regions[0][0][0] = Region.UNDEFINED.ordinal(); - + spy.change(1, 0, 0, 0, 0, R_PLUS); assertEquals(1, spy.ids[0][0][0]); assertEquals(Region.UNDEFINED.ordinal(), spy.regions[0][0][0]); - verify(((PottsLocation) ((Cell) spy.grid.getObjectAt(1)).getLocation()), never()).remove(0, 0, 0); - + verify(((PottsLocation) ((Cell) spy.grid.getObjectAt(1)).getLocation()), never()) + .remove(0, 0, 0); + spy.change(1, 0, 0, 0, 0, R_MINUS); assertEquals(0, spy.ids[0][0][0]); assertEquals(Region.UNDEFINED.ordinal(), spy.regions[0][0][0]); verify(((PottsLocation) ((Cell) spy.grid.getObjectAt(1)).getLocation())).remove(0, 0, 0); } - + @Test public void change_positiveEnergyNonzeroSourceNonzeroTargetNoRegions_updatesFields() { - PottsMock spy = makeChangeMock(1, 2, new double[] { -1, 1, 3 }, false); + PottsMock spy = makeChangeMock(1, 2, new double[] {-1, 1, 3}, false); spy.ids[0][0][0] = 1; spy.regions[0][0][0] = Region.UNDEFINED.ordinal(); - + spy.change(1, 2, 0, 0, 0, R_PLUS); assertEquals(1, spy.ids[0][0][0]); assertEquals(Region.UNDEFINED.ordinal(), spy.regions[0][0][0]); - verify(((PottsLocation) ((Cell) spy.grid.getObjectAt(1)).getLocation()), never()).remove(0, 0, 0); - verify(((PottsLocation) ((Cell) spy.grid.getObjectAt(2)).getLocation()), never()).add(0, 0, 0); - + verify(((PottsLocation) ((Cell) spy.grid.getObjectAt(1)).getLocation()), never()) + .remove(0, 0, 0); + verify(((PottsLocation) ((Cell) spy.grid.getObjectAt(2)).getLocation()), never()) + .add(0, 0, 0); + spy.change(1, 2, 0, 0, 0, R_MINUS); assertEquals(2, spy.ids[0][0][0]); assertEquals(Region.UNDEFINED.ordinal(), spy.regions[0][0][0]); verify(((PottsLocation) ((Cell) spy.grid.getObjectAt(1)).getLocation())).remove(0, 0, 0); verify(((PottsLocation) ((Cell) spy.grid.getObjectAt(2)).getLocation())).add(0, 0, 0); } - + @Test public void flip_unconnectedSourceRegion_returns() { PottsMock spy = makeFlipMock(); spy.flip(1, Region.NUCLEUS.ordinal(), Region.UNDEFINED.ordinal(), 1, 0, 0, R); verify(spy).getNeighborhood(1, Region.NUCLEUS.ordinal(), 1, 0, 0); - verify(spy, never()).change(anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), eq(R)); + verify(spy, never()) + .change(anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), eq(R)); } - + @Test public void flip_connectedSourceRegion_completes() { PottsMock spy = makeFlipMock(); @@ -858,15 +889,16 @@ public void flip_connectedSourceRegion_completes() { verify(spy).getNeighborhood(1, Region.NUCLEUS.ordinal(), 1, 1, 0); verify(spy).change(anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), eq(R)); } - + @Test public void flip_unconnectedTargetRegion_returns() { PottsMock spy = makeFlipMock(); spy.flip(1, Region.UNDEFINED.ordinal(), Region.NUCLEUS.ordinal(), 1, 0, 0, R); verify(spy).getNeighborhood(1, Region.NUCLEUS.ordinal(), 1, 0, 0); - verify(spy, never()).change(anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), eq(R)); + verify(spy, never()) + .change(anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), eq(R)); } - + @Test public void flip_connectedTargetRegion_completes() { PottsMock spy = makeFlipMock(); @@ -874,7 +906,7 @@ public void flip_connectedTargetRegion_completes() { verify(spy).getNeighborhood(1, Region.NUCLEUS.ordinal(), 1, 1, 0); verify(spy).change(anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), eq(R)); } - + @Test public void flip_connectedSourceRegionZeroFalse_returns() { PottsMock spy = makeFlipMock(); @@ -882,7 +914,7 @@ public void flip_connectedSourceRegionZeroFalse_returns() { spy.flip(1, Region.NUCLEUS.ordinal(), Region.UNDEFINED.ordinal(), 0, 0, 0, R); verify(spy).getConnectivity(any(), eq(false)); } - + @Test public void flip_connectedSourceRegionZeroTrue_completes() { PottsMock spy = makeFlipMock(); @@ -890,7 +922,7 @@ public void flip_connectedSourceRegionZeroTrue_completes() { spy.flip(1, Region.NUCLEUS.ordinal(), Region.UNDEFINED.ordinal(), 0, 0, 0, R); verify(spy).getConnectivity(any(), eq(true)); } - + @Test public void flip_connectedTargetRegionZeroFalse_returns() { PottsMock spy = makeFlipMock(); @@ -898,7 +930,7 @@ public void flip_connectedTargetRegionZeroFalse_returns() { spy.flip(1, Region.NUCLEUS.ordinal(), Region.UNDEFINED.ordinal(), 0, 0, 0, R); verify(spy).getConnectivity(any(), eq(false)); } - + @Test public void flip_connectedTargetRegionZeroTrue_completes() { PottsMock spy = makeFlipMock(); @@ -906,57 +938,71 @@ public void flip_connectedTargetRegionZeroTrue_completes() { spy.flip(1, Region.NUCLEUS.ordinal(), Region.UNDEFINED.ordinal(), 0, 0, 0, R); verify(spy).getConnectivity(any(), eq(true)); } - + @Test public void change_zerosRegions_callsMethods() { int region1 = randomIntBetween(1, 10); int region2 = randomIntBetween(1, 10); - PottsMock spy = makeChangeMock(region1, region2, new double[] { 0, 0, 0 }); + PottsMock spy = makeChangeMock(region1, region2, new double[] {0, 0, 0}); spy.change(1, region1, region2, 0, 0, 0, 1); for (Hamiltonian h : spy.hamiltonian) { verify(h).getDelta(1, region1, region2, 0, 0, 0); } } - + @Test public void change_negativeEnergyRegions_updatesFields() { - PottsMock spy = makeChangeMock(Region.DEFAULT.ordinal(), Region.NUCLEUS.ordinal(), new double[] { 1, -1, -1 }); + PottsMock spy = + makeChangeMock( + Region.DEFAULT.ordinal(), + Region.NUCLEUS.ordinal(), + new double[] {1, -1, -1}); spy.ids[0][0][0] = 1; spy.regions[0][0][0] = Region.DEFAULT.ordinal(); Grid grid = spy.grid; - + spy.change(1, Region.DEFAULT.ordinal(), Region.NUCLEUS.ordinal(), 0, 0, 0, 0); assertEquals(Region.NUCLEUS.ordinal(), spy.regions[0][0][0]); - verify(((PottsLocation) ((Cell) grid.getObjectAt(1)).getLocation())).remove(Region.DEFAULT, 0, 0, 0); - verify(((PottsLocation) ((Cell) grid.getObjectAt(1)).getLocation())).add(Region.NUCLEUS, 0, 0, 0); + verify(((PottsLocation) ((Cell) grid.getObjectAt(1)).getLocation())) + .remove(Region.DEFAULT, 0, 0, 0); + verify(((PottsLocation) ((Cell) grid.getObjectAt(1)).getLocation())) + .add(Region.NUCLEUS, 0, 0, 0); } - + @Test public void change_positiveEnergyRegions_updatesFields() { - PottsMock spy = makeChangeMock(Region.DEFAULT.ordinal(), Region.NUCLEUS.ordinal(), new double[] { -1, 1, 3 }); + PottsMock spy = + makeChangeMock( + Region.DEFAULT.ordinal(), + Region.NUCLEUS.ordinal(), + new double[] {-1, 1, 3}); spy.ids[0][0][0] = 1; spy.regions[0][0][0] = Region.DEFAULT.ordinal(); Grid grid = spy.grid; - + spy.change(1, Region.DEFAULT.ordinal(), Region.NUCLEUS.ordinal(), 0, 0, 0, R_PLUS); assertEquals(Region.DEFAULT.ordinal(), spy.regions[0][0][0]); - verify(((PottsLocation) ((Cell) grid.getObjectAt(1)).getLocation()), never()).remove(Region.DEFAULT, 0, 0, 0); - verify(((PottsLocation) ((Cell) grid.getObjectAt(1)).getLocation()), never()).add(Region.NUCLEUS, 0, 0, 0); - + verify(((PottsLocation) ((Cell) grid.getObjectAt(1)).getLocation()), never()) + .remove(Region.DEFAULT, 0, 0, 0); + verify(((PottsLocation) ((Cell) grid.getObjectAt(1)).getLocation()), never()) + .add(Region.NUCLEUS, 0, 0, 0); + spy.change(1, Region.DEFAULT.ordinal(), Region.NUCLEUS.ordinal(), 0, 0, 0, R_MINUS); assertEquals(Region.NUCLEUS.ordinal(), spy.regions[0][0][0]); - verify(((PottsLocation) ((Cell) grid.getObjectAt(1)).getLocation())).remove(Region.DEFAULT, 0, 0, 0); - verify(((PottsLocation) ((Cell) grid.getObjectAt(1)).getLocation())).add(Region.NUCLEUS, 0, 0, 0); + verify(((PottsLocation) ((Cell) grid.getObjectAt(1)).getLocation())) + .remove(Region.DEFAULT, 0, 0, 0); + verify(((PottsLocation) ((Cell) grid.getObjectAt(1)).getLocation())) + .add(Region.NUCLEUS, 0, 0, 0); } - + @Test public void getCell_validID_returnsObject() { PottsSeries series = makeSeries(1, 1, 1); PottsMock potts = new PottsMock(series); - + Grid grid = mock(Grid.class); potts.grid = grid; - + int n = randomIntBetween(3, 10); Cell[] cells = new Cell[n]; for (int i = 0; i < n; i++) { @@ -964,21 +1010,21 @@ public void getCell_validID_returnsObject() { when(grid.getObjectAt(i + 1)).thenReturn(c); cells[i] = c; } - + assertEquals(cells[0], potts.getCell(1)); assertEquals(cells[1], potts.getCell(2)); assertEquals(cells[2], potts.getCell(3)); } - + @Test public void getCell_invalidID_returnsNull() { PottsSeries series = makeSeries(1, 1, 1); PottsMock potts = new PottsMock(series); - + Grid grid = mock(Grid.class); potts.grid = grid; when(grid.getObjectAt(0)).thenReturn(null); - + assertNull(potts.getCell(0)); assertNull(potts.getCell(-1)); } diff --git a/test/arcade/potts/sim/hamiltonian/AdhesionHamiltonian2DTest.java b/test/arcade/potts/sim/hamiltonian/AdhesionHamiltonian2DTest.java index ff3bb8713..f5c664119 100644 --- a/test/arcade/potts/sim/hamiltonian/AdhesionHamiltonian2DTest.java +++ b/test/arcade/potts/sim/hamiltonian/AdhesionHamiltonian2DTest.java @@ -1,141 +1,163 @@ package arcade.potts.sim.hamiltonian; import java.lang.reflect.Field; -import org.junit.Test; +import org.junit.jupiter.api.Test; import arcade.potts.agent.cell.PottsCell; import arcade.potts.sim.Potts; import arcade.potts.sim.PottsSeries; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.potts.sim.hamiltonian.AdhesionHamiltonian2D.NEIGHBORHOOD_SIZE; import static arcade.potts.util.PottsEnums.Region; public class AdhesionHamiltonian2DTest { private static final double EPSILON = 1E-10; - + static final int REGION_DEFAULT = Region.DEFAULT.ordinal(); - + static final int REGION_NUCLEUS = Region.NUCLEUS.ordinal(); - + static Potts makePottsMock() { Potts potts = mock(Potts.class); - - potts.ids = new int[][][] { - { - { 0, 0, 0, 0, 0, 0 }, - { 0, 1, 1, 3, 3, 0 }, - { 0, 1, 1, 3, 3, 0 }, - { 0, 2, 2, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - } - }; - + + potts.ids = + new int[][][] { + { + {0, 0, 0, 0, 0, 0}, + {0, 1, 1, 3, 3, 0}, + {0, 1, 1, 3, 3, 0}, + {0, 2, 2, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + } + }; + int d = REGION_DEFAULT; int n = REGION_NUCLEUS; - - potts.regions = new int[][][] { - { - { 0, 0, 0, 0, 0, 0 }, - { 0, d, d, d, 0, 0 }, - { 0, 0, n, n, 0, 0 }, - { 0, d, d, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - } - }; - + + potts.regions = + new int[][][] { + { + {0, 0, 0, 0, 0, 0}, + {0, d, d, d, 0, 0}, + {0, 0, n, n, 0, 0}, + {0, d, d, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + } + }; + return potts; } - + @Test public void getAdhesion_validIDs_calculatesValue() { Potts potts = makePottsMock(); AdhesionHamiltonian2D ah = new AdhesionHamiltonian2D(mock(PottsSeries.class), potts); - - double[][] adhesions = new double[][] { - { Double.NaN, Double.NaN, Double.NaN }, - { 1, 2, 3 }, - { 4, 5, 6 } - }; + + double[][] adhesions = + new double[][] { + {Double.NaN, Double.NaN, Double.NaN}, + {1, 2, 3}, + {4, 5, 6} + }; double adhesion = (adhesions[1][2] + adhesions[2][1]) / 2; - + PottsCell cell1 = mock(PottsCell.class); doReturn(1).when(cell1).getPop(); - + PottsCell cell2 = mock(PottsCell.class); doReturn(2).when(cell2).getPop(); - + PottsCell cell3 = mock(PottsCell.class); doReturn(1).when(cell3).getPop(); - + AdhesionHamiltonianConfig config1 = mock(AdhesionHamiltonianConfig.class); AdhesionHamiltonianConfig config2 = mock(AdhesionHamiltonianConfig.class); AdhesionHamiltonianConfig config3 = mock(AdhesionHamiltonianConfig.class); - + try { Field cellField = AdhesionHamiltonianConfig.class.getDeclaredField("cell"); cellField.setAccessible(true); cellField.set(config1, cell1); cellField.set(config2, cell2); cellField.set(config3, cell3); - } catch (Exception ignored) { } - + } catch (Exception ignored) { + } + doReturn(adhesions[1][0]).when(config1).getAdhesion(0); doReturn(adhesions[1][1]).when(config1).getAdhesion(1); doReturn(adhesions[1][2]).when(config1).getAdhesion(2); - + doReturn(adhesions[2][0]).when(config2).getAdhesion(0); doReturn(adhesions[2][1]).when(config2).getAdhesion(1); doReturn(adhesions[2][2]).when(config2).getAdhesion(2); - + doReturn(adhesions[1][0]).when(config3).getAdhesion(0); doReturn(adhesions[1][1]).when(config3).getAdhesion(1); doReturn(adhesions[1][2]).when(config3).getAdhesion(2); - + ah.configs.put(1, config1); ah.configs.put(2, config2); ah.configs.put(3, config3); - - assertEquals(adhesions[1][0] * 5 + adhesions[2][0] * 2, - ah.getAdhesion(0, 2, 2, 0) * NEIGHBORHOOD_SIZE, EPSILON); - assertEquals(adhesions[1][0] + adhesion * 2 + adhesions[1][1] * 2, - ah.getAdhesion(1, 2, 2, 0) * NEIGHBORHOOD_SIZE, EPSILON); - assertEquals(adhesions[2][0] * 1 + adhesion * 5, - ah.getAdhesion(2, 2, 2, 0) * NEIGHBORHOOD_SIZE, EPSILON); - assertEquals(adhesions[1][0] + adhesion * 2 + adhesions[1][1] * 3, - ah.getAdhesion(3, 2, 2, 0) * NEIGHBORHOOD_SIZE, EPSILON); + + assertEquals( + adhesions[1][0] * 5 + adhesions[2][0] * 2, + ah.getAdhesion(0, 2, 2, 0) * NEIGHBORHOOD_SIZE, + EPSILON); + assertEquals( + adhesions[1][0] + adhesion * 2 + adhesions[1][1] * 2, + ah.getAdhesion(1, 2, 2, 0) * NEIGHBORHOOD_SIZE, + EPSILON); + assertEquals( + adhesions[2][0] * 1 + adhesion * 5, + ah.getAdhesion(2, 2, 2, 0) * NEIGHBORHOOD_SIZE, + EPSILON); + assertEquals( + adhesions[1][0] + adhesion * 2 + adhesions[1][1] * 3, + ah.getAdhesion(3, 2, 2, 0) * NEIGHBORHOOD_SIZE, + EPSILON); } - + @Test public void getAdhesion_validRegions_calculateValue() { Potts potts = makePottsMock(); AdhesionHamiltonian2D ah = new AdhesionHamiltonian2D(mock(PottsSeries.class), potts); - - double[][] subadhesions = new double[][] { - { Double.NaN, Double.NaN, Double.NaN }, - { Double.NaN, Double.NaN, 1 }, - { Double.NaN, 2, Double.NaN }, - }; - - double subadhesion = (subadhesions[REGION_DEFAULT][REGION_NUCLEUS] - + subadhesions[REGION_NUCLEUS][REGION_DEFAULT]) / 2; - + + double[][] subadhesions = + new double[][] { + {Double.NaN, Double.NaN, Double.NaN}, + {Double.NaN, Double.NaN, 1}, + {Double.NaN, 2, Double.NaN}, + }; + + double subadhesion = + (subadhesions[REGION_DEFAULT][REGION_NUCLEUS] + + subadhesions[REGION_NUCLEUS][REGION_DEFAULT]) + / 2; + PottsCell cell = mock(PottsCell.class); AdhesionHamiltonianConfig config = mock(AdhesionHamiltonianConfig.class); try { Field cellField = AdhesionHamiltonianConfig.class.getDeclaredField("cell"); cellField.setAccessible(true); cellField.set(config, cell); - } catch (Exception ignored) { } - - doAnswer(invocation -> { - int a = ((Region) invocation.getArgument(0)).ordinal(); - int b = ((Region) invocation.getArgument(1)).ordinal(); - return subadhesions[a][b]; - }).when(config).getAdhesion(any(Region.class), any(Region.class)); - + } catch (Exception ignored) { + } + + doAnswer( + invocation -> { + int a = ((Region) invocation.getArgument(0)).ordinal(); + int b = ((Region) invocation.getArgument(1)).ordinal(); + return subadhesions[a][b]; + }) + .when(config) + .getAdhesion(any(Region.class), any(Region.class)); + ah.configs.put(1, config); - - assertEquals(subadhesion / NEIGHBORHOOD_SIZE, ah.getAdhesion(1, REGION_DEFAULT, 1, 2, 0), EPSILON); + + assertEquals( + subadhesion / NEIGHBORHOOD_SIZE, + ah.getAdhesion(1, REGION_DEFAULT, 1, 2, 0), + EPSILON); assertEquals(0, ah.getAdhesion(1, REGION_NUCLEUS, 2, 2, 0), EPSILON); } } diff --git a/test/arcade/potts/sim/hamiltonian/AdhesionHamiltonian3DTest.java b/test/arcade/potts/sim/hamiltonian/AdhesionHamiltonian3DTest.java index e0ecab8a1..fbc1d3649 100644 --- a/test/arcade/potts/sim/hamiltonian/AdhesionHamiltonian3DTest.java +++ b/test/arcade/potts/sim/hamiltonian/AdhesionHamiltonian3DTest.java @@ -1,197 +1,219 @@ package arcade.potts.sim.hamiltonian; import java.lang.reflect.Field; -import org.junit.Test; +import org.junit.jupiter.api.Test; import arcade.potts.agent.cell.PottsCell; import arcade.potts.sim.Potts; import arcade.potts.sim.PottsSeries; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.potts.sim.hamiltonian.AdhesionHamiltonian3D.NEIGHBORHOOD_SIZE; import static arcade.potts.util.PottsEnums.Region; public class AdhesionHamiltonian3DTest { private static final double EPSILON = 1E-10; - + static final int REGION_DEFAULT = Region.DEFAULT.ordinal(); - + static final int REGION_NUCLEUS = Region.NUCLEUS.ordinal(); - + static Potts makePottsMock() { Potts potts = mock(Potts.class); - - potts.ids = new int[][][] { - { - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - }, - { - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 3, 0 }, - { 0, 0, 1, 3, 3, 0 }, - { 0, 2, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - }, - { - { 0, 0, 0, 0, 0, 0 }, - { 0, 1, 1, 3, 3, 0 }, - { 0, 1, 1, 3, 3, 0 }, - { 0, 2, 2, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - }, - { - { 0, 0, 0, 0, 0, 0 }, - { 0, 1, 1, 0, 0, 0 }, - { 0, 1, 2, 0, 3, 0 }, - { 0, 2, 2, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - }, - { - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - }, - }; - + + potts.ids = + new int[][][] { + { + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + }, + { + {0, 0, 0, 0, 0, 0}, + {0, 0, 1, 0, 3, 0}, + {0, 0, 1, 3, 3, 0}, + {0, 2, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + }, + { + {0, 0, 0, 0, 0, 0}, + {0, 1, 1, 3, 3, 0}, + {0, 1, 1, 3, 3, 0}, + {0, 2, 2, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + }, + { + {0, 0, 0, 0, 0, 0}, + {0, 1, 1, 0, 0, 0}, + {0, 1, 2, 0, 3, 0}, + {0, 2, 2, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + }, + { + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + }, + }; + int d = REGION_DEFAULT; int n = REGION_NUCLEUS; - - potts.regions = new int[][][] { - { - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - }, - { - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, d, 0, d, 0 }, - { 0, 0, d, d, d, 0 }, - { 0, d, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - }, - { - { 0, 0, 0, 0, 0, 0 }, - { 0, d, d, d, 0, 0 }, - { 0, 0, n, n, 0, 0 }, - { 0, d, d, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - }, - { - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, d, 0, 0, 0 }, - { 0, 0, n, 0, d, 0 }, - { 0, d, d, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - }, - { - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - }, - }; - + + potts.regions = + new int[][][] { + { + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + }, + { + {0, 0, 0, 0, 0, 0}, + {0, 0, d, 0, d, 0}, + {0, 0, d, d, d, 0}, + {0, d, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + }, + { + {0, 0, 0, 0, 0, 0}, + {0, d, d, d, 0, 0}, + {0, 0, n, n, 0, 0}, + {0, d, d, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + }, + { + {0, 0, 0, 0, 0, 0}, + {0, 0, d, 0, 0, 0}, + {0, 0, n, 0, d, 0}, + {0, d, d, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + }, + { + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + }, + }; + return potts; } - + @Test public void getAdhesion_validIDs_calculatesValue() { Potts potts = makePottsMock(); AdhesionHamiltonian3D ah = new AdhesionHamiltonian3D(mock(PottsSeries.class), potts); - - double[][] adhesions = new double[][] { - { Double.NaN, Double.NaN, Double.NaN }, - { 1, 2, 3 }, - { 4, 5, 6 } - }; + + double[][] adhesions = + new double[][] { + {Double.NaN, Double.NaN, Double.NaN}, + {1, 2, 3}, + {4, 5, 6} + }; double adhesion = (adhesions[1][2] + adhesions[2][1]) / 2; - + PottsCell cell1 = mock(PottsCell.class); doReturn(1).when(cell1).getPop(); - + PottsCell cell2 = mock(PottsCell.class); doReturn(2).when(cell2).getPop(); - + PottsCell cell3 = mock(PottsCell.class); doReturn(1).when(cell3).getPop(); - + AdhesionHamiltonianConfig config1 = mock(AdhesionHamiltonianConfig.class); AdhesionHamiltonianConfig config2 = mock(AdhesionHamiltonianConfig.class); AdhesionHamiltonianConfig config3 = mock(AdhesionHamiltonianConfig.class); - + try { Field cellField = AdhesionHamiltonianConfig.class.getDeclaredField("cell"); cellField.setAccessible(true); cellField.set(config1, cell1); cellField.set(config2, cell2); cellField.set(config3, cell3); - } catch (Exception ignored) { } - + } catch (Exception ignored) { + } + doReturn(adhesions[1][0]).when(config1).getAdhesion(0); doReturn(adhesions[1][1]).when(config1).getAdhesion(1); doReturn(adhesions[1][2]).when(config1).getAdhesion(2); - + doReturn(adhesions[2][0]).when(config2).getAdhesion(0); doReturn(adhesions[2][1]).when(config2).getAdhesion(1); doReturn(adhesions[2][2]).when(config2).getAdhesion(2); - + doReturn(adhesions[1][0]).when(config3).getAdhesion(0); doReturn(adhesions[1][1]).when(config3).getAdhesion(1); doReturn(adhesions[1][2]).when(config3).getAdhesion(2); - + ah.configs.put(1, config1); ah.configs.put(2, config2); ah.configs.put(3, config3); - - assertEquals(adhesions[1][0] * 11 + adhesions[2][0] * 6, - ah.getAdhesion(0, 2, 2, 2) * NEIGHBORHOOD_SIZE, EPSILON); - assertEquals(adhesions[1][0] * 9 + adhesion * 6 + adhesions[1][1] * 3, - ah.getAdhesion(1, 2, 2, 2) * NEIGHBORHOOD_SIZE, EPSILON); - assertEquals(adhesions[2][0] * 8 + adhesion * 12, - ah.getAdhesion(2, 2, 2, 2) * NEIGHBORHOOD_SIZE, EPSILON); - assertEquals(adhesions[1][0] * 9 + adhesion * 6 + adhesions[1][1] * 8, - ah.getAdhesion(3, 2, 2, 2) * NEIGHBORHOOD_SIZE, EPSILON); + + assertEquals( + adhesions[1][0] * 11 + adhesions[2][0] * 6, + ah.getAdhesion(0, 2, 2, 2) * NEIGHBORHOOD_SIZE, + EPSILON); + assertEquals( + adhesions[1][0] * 9 + adhesion * 6 + adhesions[1][1] * 3, + ah.getAdhesion(1, 2, 2, 2) * NEIGHBORHOOD_SIZE, + EPSILON); + assertEquals( + adhesions[2][0] * 8 + adhesion * 12, + ah.getAdhesion(2, 2, 2, 2) * NEIGHBORHOOD_SIZE, + EPSILON); + assertEquals( + adhesions[1][0] * 9 + adhesion * 6 + adhesions[1][1] * 8, + ah.getAdhesion(3, 2, 2, 2) * NEIGHBORHOOD_SIZE, + EPSILON); } - + @Test public void getAdhesion_validRegions_calculateValue() { Potts potts = makePottsMock(); AdhesionHamiltonian3D ah = new AdhesionHamiltonian3D(mock(PottsSeries.class), potts); - - double[][] subadhesions = new double[][] { - { Double.NaN, Double.NaN, Double.NaN }, - { Double.NaN, Double.NaN, 1 }, - { Double.NaN, 2, Double.NaN }, - }; - - double subadhesion = (subadhesions[REGION_DEFAULT][REGION_NUCLEUS] - + subadhesions[REGION_NUCLEUS][REGION_DEFAULT]) / 2; - + + double[][] subadhesions = + new double[][] { + {Double.NaN, Double.NaN, Double.NaN}, + {Double.NaN, Double.NaN, 1}, + {Double.NaN, 2, Double.NaN}, + }; + + double subadhesion = + (subadhesions[REGION_DEFAULT][REGION_NUCLEUS] + + subadhesions[REGION_NUCLEUS][REGION_DEFAULT]) + / 2; + PottsCell cell = mock(PottsCell.class); AdhesionHamiltonianConfig config = mock(AdhesionHamiltonianConfig.class); try { Field cellField = AdhesionHamiltonianConfig.class.getDeclaredField("cell"); cellField.setAccessible(true); cellField.set(config, cell); - } catch (Exception ignored) { } - - doAnswer(invocation -> { - int a = ((Region) invocation.getArgument(0)).ordinal(); - int b = ((Region) invocation.getArgument(1)).ordinal(); - return subadhesions[a][b]; - }).when(config).getAdhesion(any(Region.class), any(Region.class)); - + } catch (Exception ignored) { + } + + doAnswer( + invocation -> { + int a = ((Region) invocation.getArgument(0)).ordinal(); + int b = ((Region) invocation.getArgument(1)).ordinal(); + return subadhesions[a][b]; + }) + .when(config) + .getAdhesion(any(Region.class), any(Region.class)); + ah.configs.put(1, config); - - assertEquals(subadhesion / NEIGHBORHOOD_SIZE, ah.getAdhesion(1, REGION_DEFAULT, 1, 2, 2), EPSILON); + + assertEquals( + subadhesion / NEIGHBORHOOD_SIZE, + ah.getAdhesion(1, REGION_DEFAULT, 1, 2, 2), + EPSILON); assertEquals(0, ah.getAdhesion(1, REGION_NUCLEUS, 1, 2, 2), EPSILON); } } diff --git a/test/arcade/potts/sim/hamiltonian/AdhesionHamiltonianConfigTest.java b/test/arcade/potts/sim/hamiltonian/AdhesionHamiltonianConfigTest.java index fce99c3dd..b878bd8a9 100644 --- a/test/arcade/potts/sim/hamiltonian/AdhesionHamiltonianConfigTest.java +++ b/test/arcade/potts/sim/hamiltonian/AdhesionHamiltonianConfigTest.java @@ -2,16 +2,16 @@ import java.util.EnumMap; import java.util.EnumSet; -import org.junit.Test; +import org.junit.jupiter.api.Test; import arcade.potts.agent.cell.PottsCell; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.core.ARCADETestUtilities.*; import static arcade.potts.util.PottsEnums.Region; public class AdhesionHamiltonianConfigTest { private static final double EPSILON = 1E-10; - + static EnumMap makeRegionMap(EnumSet regions) { EnumMap map = new EnumMap<>(Region.class); for (Region region : regions) { @@ -19,118 +19,126 @@ static EnumMap makeRegionMap(EnumSet regions) { } return map; } - + @Test public void constructor_called_setsFields() { PottsCell cell = mock(PottsCell.class); - double[] adhesion = new double[] { randomDoubleBetween(1, 100) }; + double[] adhesion = new double[] {randomDoubleBetween(1, 100)}; AdhesionHamiltonianConfig ahc = new AdhesionHamiltonianConfig(cell, adhesion, null); assertEquals(cell, ahc.cell); assertFalse(ahc.hasRegions); } - + @Test public void constructor_emptyRegions_setsFields() { PottsCell cell = mock(PottsCell.class); - double[] adhesion = new double[] { randomDoubleBetween(1, 100) }; + double[] adhesion = new double[] {randomDoubleBetween(1, 100)}; EnumMap> adhesionRegion = new EnumMap<>(Region.class); - - AdhesionHamiltonianConfig ahc = new AdhesionHamiltonianConfig(cell, adhesion, adhesionRegion); + + AdhesionHamiltonianConfig ahc = + new AdhesionHamiltonianConfig(cell, adhesion, adhesionRegion); assertEquals(cell, ahc.cell); assertFalse(ahc.hasRegions); } - + @Test public void constructor_hasRegions_setsFields() { PottsCell cell = mock(PottsCell.class); - double[] adhesion = new double[] { randomDoubleBetween(1, 100) }; + double[] adhesion = new double[] {randomDoubleBetween(1, 100)}; EnumMap> adhesionRegion = new EnumMap<>(Region.class); adhesionRegion.put(Region.UNDEFINED, new EnumMap<>(Region.class)); - - AdhesionHamiltonianConfig ahc = new AdhesionHamiltonianConfig(cell, adhesion, adhesionRegion); + + AdhesionHamiltonianConfig ahc = + new AdhesionHamiltonianConfig(cell, adhesion, adhesionRegion); assertEquals(cell, ahc.cell); assertTrue(ahc.hasRegions); } - + @Test public void getAdhesion_givenPop_returnsValue() { - double[] adhesion = new double[] { - randomDoubleBetween(1, 100), - randomDoubleBetween(1, 100), - randomDoubleBetween(1, 100) - }; + double[] adhesion = + new double[] { + randomDoubleBetween(1, 100), + randomDoubleBetween(1, 100), + randomDoubleBetween(1, 100) + }; AdhesionHamiltonianConfig ahc = new AdhesionHamiltonianConfig(null, adhesion, null); - + assertEquals(adhesion[0], ahc.getAdhesion(0), EPSILON); assertEquals(adhesion[1], ahc.getAdhesion(1), EPSILON); assertEquals(adhesion[2], ahc.getAdhesion(2), EPSILON); } - + @Test public void getAdhesion_validRegions_returnsValue() { EnumSet regions = EnumSet.of(Region.DEFAULT, Region.NUCLEUS); - + EnumMap defaultAdhesion = makeRegionMap(regions); EnumMap nucleusAdhesion = makeRegionMap(regions); - + EnumMap> adhesionRegion = new EnumMap<>(Region.class); adhesionRegion.put(Region.DEFAULT, defaultAdhesion); adhesionRegion.put(Region.NUCLEUS, nucleusAdhesion); - - AdhesionHamiltonianConfig ahc = new AdhesionHamiltonianConfig(null, new double[] { }, adhesionRegion); - + + AdhesionHamiltonianConfig ahc = + new AdhesionHamiltonianConfig(null, new double[] {}, adhesionRegion); + for (Region target : regions) { - assertEquals(defaultAdhesion.get(target), ahc.getAdhesion(Region.DEFAULT, target), EPSILON); - assertEquals(nucleusAdhesion.get(target), ahc.getAdhesion(Region.NUCLEUS, target), EPSILON); + assertEquals( + defaultAdhesion.get(target), ahc.getAdhesion(Region.DEFAULT, target), EPSILON); + assertEquals( + nucleusAdhesion.get(target), ahc.getAdhesion(Region.NUCLEUS, target), EPSILON); } } - + @Test public void getAdhesion_nullRegions_returnsNaN() { EnumSet regions = EnumSet.of(Region.DEFAULT, Region.NUCLEUS); - + EnumMap defaultAdhesion = makeRegionMap(regions); EnumMap nucleusAdhesion = makeRegionMap(regions); - + EnumMap> adhesionRegion = new EnumMap<>(Region.class); adhesionRegion.put(Region.DEFAULT, defaultAdhesion); adhesionRegion.put(Region.NUCLEUS, nucleusAdhesion); - - AdhesionHamiltonianConfig ahc = new AdhesionHamiltonianConfig(null, new double[] { }, adhesionRegion); - + + AdhesionHamiltonianConfig ahc = + new AdhesionHamiltonianConfig(null, new double[] {}, adhesionRegion); + assertEquals(Double.NaN, ahc.getAdhesion(null, null), EPSILON); for (Region region : regions) { assertEquals(Double.NaN, ahc.getAdhesion(region, null), EPSILON); assertEquals(Double.NaN, ahc.getAdhesion(null, region), EPSILON); } } - + @Test public void getAdhesion_invalidRegions_returnsNaN() { EnumSet regions = EnumSet.of(Region.DEFAULT, Region.NUCLEUS); - + EnumMap defaultAdhesion = makeRegionMap(regions); EnumMap nucleusAdhesion = makeRegionMap(regions); - + EnumMap> adhesionRegion = new EnumMap<>(Region.class); adhesionRegion.put(Region.DEFAULT, defaultAdhesion); adhesionRegion.put(Region.NUCLEUS, nucleusAdhesion); - - AdhesionHamiltonianConfig ahc = new AdhesionHamiltonianConfig(null, new double[] { }, adhesionRegion); - + + AdhesionHamiltonianConfig ahc = + new AdhesionHamiltonianConfig(null, new double[] {}, adhesionRegion); + assertEquals(Double.NaN, ahc.getAdhesion(Region.UNDEFINED, Region.UNDEFINED), EPSILON); for (Region region : regions) { assertEquals(Double.NaN, ahc.getAdhesion(region, Region.UNDEFINED), EPSILON); assertEquals(Double.NaN, ahc.getAdhesion(Region.UNDEFINED, region), EPSILON); } } - + @Test public void getAdhesion_noRegions_returnsNaN() { EnumSet regions = EnumSet.of(Region.DEFAULT, Region.NUCLEUS); - - AdhesionHamiltonianConfig ahc = new AdhesionHamiltonianConfig(null, new double[] { }, null); - + + AdhesionHamiltonianConfig ahc = new AdhesionHamiltonianConfig(null, new double[] {}, null); + for (Region region : regions) { for (Region target : regions) { assertEquals(Double.NaN, ahc.getAdhesion(region, target), EPSILON); diff --git a/test/arcade/potts/sim/hamiltonian/AdhesionHamiltonianTest.java b/test/arcade/potts/sim/hamiltonian/AdhesionHamiltonianTest.java index 6fa98db82..f213239b6 100644 --- a/test/arcade/potts/sim/hamiltonian/AdhesionHamiltonianTest.java +++ b/test/arcade/potts/sim/hamiltonian/AdhesionHamiltonianTest.java @@ -2,12 +2,12 @@ import java.util.EnumMap; import java.util.HashMap; -import org.junit.Test; +import org.junit.jupiter.api.Test; import arcade.core.util.MiniBox; import arcade.potts.agent.cell.PottsCell; import arcade.potts.sim.Potts; import arcade.potts.sim.PottsSeries; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.core.ARCADETestUtilities.*; import static arcade.core.util.MiniBox.TAG_SEPARATOR; @@ -16,37 +16,40 @@ public class AdhesionHamiltonianTest { private static final double EPSILON = 1E-10; - + private static final double[] ADHESION_ID = { - 0, - randomDoubleBetween(0, 10), - randomDoubleBetween(0, 10) + 0, randomDoubleBetween(0, 10), randomDoubleBetween(0, 10) }; - + private static final double[] ADHESION_REGION = { - 0, - randomDoubleBetween(0, 10), - randomDoubleBetween(0, 10) + 0, randomDoubleBetween(0, 10), randomDoubleBetween(0, 10) }; - + static class AdhesionHamiltonianMock extends AdhesionHamiltonian { - AdhesionHamiltonianMock(PottsSeries series, Potts potts) { super(series, potts); } - + AdhesionHamiltonianMock(PottsSeries series, Potts potts) { + super(series, potts); + } + @Override - double getAdhesion(int id, int x, int y, int z) { return ADHESION_ID[id]; } - + double getAdhesion(int id, int x, int y, int z) { + return ADHESION_ID[id]; + } + @Override - double getAdhesion(int id, int region, int x, int y, int z) { return ADHESION_REGION[region]; } + double getAdhesion(int id, int region, int x, int y, int z) { + return ADHESION_REGION[region]; + } } - + @Test public void constructor_called_initializesMaps() { - AdhesionHamiltonianMock ahm = new AdhesionHamiltonianMock(mock(PottsSeries.class), mock(Potts.class)); + AdhesionHamiltonianMock ahm = + new AdhesionHamiltonianMock(mock(PottsSeries.class), mock(Potts.class)); assertNotNull(ahm.configs); assertNotNull(ahm.popToAdhesion); assertNotNull(ahm.popToAdhesionRegion); } - + @Test public void constructor_called_setsArrays() { Potts potts = mock(Potts.class); @@ -54,78 +57,117 @@ public void constructor_called_setsArrays() { int[][][] regions = new int[0][0][0]; potts.ids = ids; potts.regions = regions; - + AdhesionHamiltonianMock ahm = new AdhesionHamiltonianMock(mock(PottsSeries.class), potts); - + assertSame(ids, ahm.ids); assertSame(regions, ahm.regions); } - + @Test public void constructor_called_setsConfig() { - AdhesionHamiltonianMock ahm = new AdhesionHamiltonianMock(mock(PottsSeries.class), mock(Potts.class)); + AdhesionHamiltonianMock ahm = + new AdhesionHamiltonianMock(mock(PottsSeries.class), mock(Potts.class)); assertEquals(1, ahm.configs.size()); assertNull(ahm.configs.get(0)); } - + @Test public void constructor_called_initializesParameters() { PottsSeries series = mock(PottsSeries.class); - + series.potts = new MiniBox(); series.populations = new HashMap<>(); - + String key1 = randomString(); MiniBox population1 = new MiniBox(); population1.put("CODE", 1); series.populations.put(key1, population1); - + String key2 = randomString(); MiniBox population2 = new MiniBox(); population2.put("CODE", 2); population2.put("(REGION)" + TAG_SEPARATOR + Region.DEFAULT.name(), 0); population2.put("(REGION)" + TAG_SEPARATOR + Region.NUCLEUS.name(), 0); series.populations.put(key2, population2); - - double[] adhesion1 = new double[] { - randomDoubleBetween(1, 100), - randomDoubleBetween(1, 100), - randomDoubleBetween(1, 100), - }; - double[] adhesion2 = new double[] { - randomDoubleBetween(1, 100), - randomDoubleBetween(1, 100), - randomDoubleBetween(1, 100), - }; - - series.potts.put("adhesion/ADHESION" + TARGET_SEPARATOR + key1 + TARGET_SEPARATOR + "*", adhesion1[0]); - series.potts.put("adhesion/ADHESION" + TARGET_SEPARATOR + key1 + TARGET_SEPARATOR + key1, adhesion1[1]); - series.potts.put("adhesion/ADHESION" + TARGET_SEPARATOR + key1 + TARGET_SEPARATOR + key2, adhesion1[2]); - - series.potts.put("adhesion/ADHESION" + TARGET_SEPARATOR + key2 + TARGET_SEPARATOR + "*", adhesion2[0]); - series.potts.put("adhesion/ADHESION" + TARGET_SEPARATOR + key2 + TARGET_SEPARATOR + key1, adhesion2[1]); - series.potts.put("adhesion/ADHESION" + TARGET_SEPARATOR + key2 + TARGET_SEPARATOR + key2, adhesion2[2]); - - double[] adhesionDefault = new double[] { - randomDoubleBetween(1, 100), - randomDoubleBetween(1, 100), - }; - double[] adhesionNucleus = new double[] { - randomDoubleBetween(1, 100), - randomDoubleBetween(1, 100), - }; - - series.potts.put("adhesion/ADHESION_" + Region.DEFAULT.name() + TARGET_SEPARATOR - + key2 + TARGET_SEPARATOR + Region.DEFAULT.name(), adhesionDefault[0]); - series.potts.put("adhesion/ADHESION_" + Region.DEFAULT.name() + TARGET_SEPARATOR - + key2 + TARGET_SEPARATOR + Region.NUCLEUS.name(), adhesionDefault[1]); - series.potts.put("adhesion/ADHESION_" + Region.NUCLEUS.name() + TARGET_SEPARATOR - + key2 + TARGET_SEPARATOR + Region.DEFAULT.name(), adhesionNucleus[0]); - series.potts.put("adhesion/ADHESION_" + Region.NUCLEUS.name() + TARGET_SEPARATOR - + key2 + TARGET_SEPARATOR + Region.NUCLEUS.name(), adhesionNucleus[1]); - + + double[] adhesion1 = + new double[] { + randomDoubleBetween(1, 100), + randomDoubleBetween(1, 100), + randomDoubleBetween(1, 100), + }; + double[] adhesion2 = + new double[] { + randomDoubleBetween(1, 100), + randomDoubleBetween(1, 100), + randomDoubleBetween(1, 100), + }; + + series.potts.put( + "adhesion/ADHESION" + TARGET_SEPARATOR + key1 + TARGET_SEPARATOR + "*", + adhesion1[0]); + series.potts.put( + "adhesion/ADHESION" + TARGET_SEPARATOR + key1 + TARGET_SEPARATOR + key1, + adhesion1[1]); + series.potts.put( + "adhesion/ADHESION" + TARGET_SEPARATOR + key1 + TARGET_SEPARATOR + key2, + adhesion1[2]); + + series.potts.put( + "adhesion/ADHESION" + TARGET_SEPARATOR + key2 + TARGET_SEPARATOR + "*", + adhesion2[0]); + series.potts.put( + "adhesion/ADHESION" + TARGET_SEPARATOR + key2 + TARGET_SEPARATOR + key1, + adhesion2[1]); + series.potts.put( + "adhesion/ADHESION" + TARGET_SEPARATOR + key2 + TARGET_SEPARATOR + key2, + adhesion2[2]); + + double[] adhesionDefault = + new double[] { + randomDoubleBetween(1, 100), randomDoubleBetween(1, 100), + }; + double[] adhesionNucleus = + new double[] { + randomDoubleBetween(1, 100), randomDoubleBetween(1, 100), + }; + + series.potts.put( + "adhesion/ADHESION_" + + Region.DEFAULT.name() + + TARGET_SEPARATOR + + key2 + + TARGET_SEPARATOR + + Region.DEFAULT.name(), + adhesionDefault[0]); + series.potts.put( + "adhesion/ADHESION_" + + Region.DEFAULT.name() + + TARGET_SEPARATOR + + key2 + + TARGET_SEPARATOR + + Region.NUCLEUS.name(), + adhesionDefault[1]); + series.potts.put( + "adhesion/ADHESION_" + + Region.NUCLEUS.name() + + TARGET_SEPARATOR + + key2 + + TARGET_SEPARATOR + + Region.DEFAULT.name(), + adhesionNucleus[0]); + series.potts.put( + "adhesion/ADHESION_" + + Region.NUCLEUS.name() + + TARGET_SEPARATOR + + key2 + + TARGET_SEPARATOR + + Region.NUCLEUS.name(), + adhesionNucleus[1]); + AdhesionHamiltonianMock ahm = new AdhesionHamiltonianMock(series, mock(Potts.class)); - + assertEquals(2, ahm.popToAdhesion.size()); assertTrue(ahm.popToAdhesion.containsKey(1)); assertTrue(ahm.popToAdhesion.containsKey(2)); @@ -136,106 +178,124 @@ public void constructor_called_initializesParameters() { assertEquals(adhesion2[1], ahm.popToAdhesion.get(2)[1], EPSILON); assertEquals(adhesion2[2], ahm.popToAdhesion.get(2)[2], EPSILON); assertNull(ahm.popToAdhesionRegion.get(1)); - assertEquals(adhesionDefault[0], - ahm.popToAdhesionRegion.get(2).get(Region.DEFAULT).get(Region.DEFAULT), EPSILON); - assertEquals(adhesionDefault[1], - ahm.popToAdhesionRegion.get(2).get(Region.DEFAULT).get(Region.NUCLEUS), EPSILON); - assertEquals(adhesionNucleus[0], - ahm.popToAdhesionRegion.get(2).get(Region.NUCLEUS).get(Region.DEFAULT), EPSILON); - assertEquals(adhesionNucleus[1], - ahm.popToAdhesionRegion.get(2).get(Region.NUCLEUS).get(Region.NUCLEUS), EPSILON); + assertEquals( + adhesionDefault[0], + ahm.popToAdhesionRegion.get(2).get(Region.DEFAULT).get(Region.DEFAULT), + EPSILON); + assertEquals( + adhesionDefault[1], + ahm.popToAdhesionRegion.get(2).get(Region.DEFAULT).get(Region.NUCLEUS), + EPSILON); + assertEquals( + adhesionNucleus[0], + ahm.popToAdhesionRegion.get(2).get(Region.NUCLEUS).get(Region.DEFAULT), + EPSILON); + assertEquals( + adhesionNucleus[1], + ahm.popToAdhesionRegion.get(2).get(Region.NUCLEUS).get(Region.NUCLEUS), + EPSILON); } - + @Test public void register_noRegions_addsConfig() { - AdhesionHamiltonianMock ahm = new AdhesionHamiltonianMock(mock(PottsSeries.class), mock(Potts.class)); + AdhesionHamiltonianMock ahm = + new AdhesionHamiltonianMock(mock(PottsSeries.class), mock(Potts.class)); PottsCell cell = mock(PottsCell.class); - + int id = randomIntBetween(1, 10); int pop = randomIntBetween(1, 10); - + doReturn(id).when(cell).getID(); doReturn(pop).when(cell).getPop(); - - double[] adhesion = new double[] { - randomDoubleBetween(1, 100), - randomDoubleBetween(1, 100), - }; + + double[] adhesion = + new double[] { + randomDoubleBetween(1, 100), randomDoubleBetween(1, 100), + }; EnumMap> adhesionRegion = null; ahm.popToAdhesion.put(pop, adhesion); ahm.popToAdhesionRegion.put(pop, adhesionRegion); - + ahm.register(cell); AdhesionHamiltonianConfig config = ahm.configs.get(id); - + assertNotNull(config); assertEquals(cell, config.cell); assertEquals(adhesion[0], config.getAdhesion(0), EPSILON); assertEquals(adhesion[1], config.getAdhesion(1), EPSILON); assertEquals(Double.NaN, config.getAdhesion(Region.UNDEFINED, Region.UNDEFINED), EPSILON); } - + @Test public void register_withRegions_addsConfig() { - AdhesionHamiltonianMock ahm = new AdhesionHamiltonianMock(mock(PottsSeries.class), mock(Potts.class)); + AdhesionHamiltonianMock ahm = + new AdhesionHamiltonianMock(mock(PottsSeries.class), mock(Potts.class)); PottsCell cell = mock(PottsCell.class); - + int id = randomIntBetween(1, 10); int pop = randomIntBetween(1, 10); - + doReturn(id).when(cell).getID(); doReturn(pop).when(cell).getPop(); - - double[] adhesion = new double[] { - randomDoubleBetween(1, 100), - randomDoubleBetween(1, 100), - }; + + double[] adhesion = + new double[] { + randomDoubleBetween(1, 100), randomDoubleBetween(1, 100), + }; EnumMap adhesionNucleus = new EnumMap<>(Region.class); adhesionNucleus.put(Region.NUCLEUS, randomDoubleBetween(1, 100)); - + EnumMap> adhesionRegion = new EnumMap<>(Region.class); adhesionRegion.put(Region.NUCLEUS, adhesionNucleus); - + ahm.popToAdhesion.put(pop, adhesion); ahm.popToAdhesionRegion.put(pop, adhesionRegion); - + ahm.register(cell); AdhesionHamiltonianConfig config = ahm.configs.get(id); - + assertNotNull(config); assertEquals(cell, config.cell); assertEquals(adhesion[0], config.getAdhesion(0), EPSILON); assertEquals(adhesion[1], config.getAdhesion(1), EPSILON); - assertEquals(adhesionNucleus.get(Region.NUCLEUS), config.getAdhesion(Region.NUCLEUS, Region.NUCLEUS), EPSILON); + assertEquals( + adhesionNucleus.get(Region.NUCLEUS), + config.getAdhesion(Region.NUCLEUS, Region.NUCLEUS), + EPSILON); } - + @Test public void deregister_exists_removesConfig() { - AdhesionHamiltonianMock ahm = new AdhesionHamiltonianMock(mock(PottsSeries.class), mock(Potts.class)); + AdhesionHamiltonianMock ahm = + new AdhesionHamiltonianMock(mock(PottsSeries.class), mock(Potts.class)); PottsCell cell = mock(PottsCell.class); - + int id = randomIntBetween(1, 10); doReturn(id).when(cell).getID(); - + AdhesionHamiltonianConfig config = mock(AdhesionHamiltonianConfig.class); ahm.configs.put(id, config); - + ahm.deregister(cell); - + assertFalse(ahm.configs.containsKey(id)); } - + @Test public void getDelta_validIDs_calculatesValue() { - AdhesionHamiltonianMock ahm = new AdhesionHamiltonianMock(mock(PottsSeries.class), mock(Potts.class)); + AdhesionHamiltonianMock ahm = + new AdhesionHamiltonianMock(mock(PottsSeries.class), mock(Potts.class)); assertEquals(ADHESION_ID[1] - ADHESION_ID[2], ahm.getDelta(2, 1, 0, 0, 0), EPSILON); assertEquals(ADHESION_ID[2] - ADHESION_ID[1], ahm.getDelta(1, 2, 0, 0, 0), EPSILON); } - + @Test public void getDelta_validRegions_calculatesValue() { - AdhesionHamiltonianMock ahm = new AdhesionHamiltonianMock(mock(PottsSeries.class), mock(Potts.class)); - assertEquals(ADHESION_REGION[1] - ADHESION_REGION[2], ahm.getDelta(1, 2, 1, 0, 0, 0), EPSILON); - assertEquals(ADHESION_REGION[2] - ADHESION_REGION[1], ahm.getDelta(1, 1, 2, 0, 0, 0), EPSILON); + AdhesionHamiltonianMock ahm = + new AdhesionHamiltonianMock(mock(PottsSeries.class), mock(Potts.class)); + assertEquals( + ADHESION_REGION[1] - ADHESION_REGION[2], ahm.getDelta(1, 2, 1, 0, 0, 0), EPSILON); + assertEquals( + ADHESION_REGION[2] - ADHESION_REGION[1], ahm.getDelta(1, 1, 2, 0, 0, 0), EPSILON); } } diff --git a/test/arcade/potts/sim/hamiltonian/HeightHamiltonianConfigTest.java b/test/arcade/potts/sim/hamiltonian/HeightHamiltonianConfigTest.java index b2842ee8f..e29ed9ad0 100644 --- a/test/arcade/potts/sim/hamiltonian/HeightHamiltonianConfigTest.java +++ b/test/arcade/potts/sim/hamiltonian/HeightHamiltonianConfigTest.java @@ -1,42 +1,42 @@ package arcade.potts.sim.hamiltonian; import java.util.EnumMap; -import org.junit.Test; +import org.junit.jupiter.api.Test; import arcade.potts.agent.cell.PottsCell; import arcade.potts.env.location.PottsLocation; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.core.ARCADETestUtilities.*; import static arcade.potts.util.PottsEnums.Region; public class HeightHamiltonianConfigTest { private static final double EPSILON = 1E-10; - + @Test public void constructor_noRegions_setsFields() { PottsCell cell = mock(PottsCell.class); PottsLocation location = mock(PottsLocation.class); doReturn(location).when(cell).getLocation(); - + HeightHamiltonianConfig hhc = new HeightHamiltonianConfig(cell, 0, null); assertEquals(cell, hhc.cell); assertEquals(location, hhc.location); assertFalse(hhc.hasRegions); } - + @Test public void constructor_emptyRegions_setsFields() { PottsCell cell = mock(PottsCell.class); PottsLocation location = mock(PottsLocation.class); doReturn(location).when(cell).getLocation(); EnumMap lambdasRegion = new EnumMap<>(Region.class); - + HeightHamiltonianConfig hhc = new HeightHamiltonianConfig(cell, 0, lambdasRegion); assertEquals(cell, hhc.cell); assertEquals(location, hhc.location); assertFalse(hhc.hasRegions); } - + @Test public void constructor_hasRegions_setsFields() { PottsCell cell = mock(PottsCell.class); @@ -44,13 +44,13 @@ public void constructor_hasRegions_setsFields() { doReturn(location).when(cell).getLocation(); EnumMap lambdasRegion = new EnumMap<>(Region.class); lambdasRegion.put(Region.UNDEFINED, randomDoubleBetween(1, 100)); - + HeightHamiltonianConfig hhc = new HeightHamiltonianConfig(cell, 0, lambdasRegion); assertEquals(cell, hhc.cell); assertEquals(location, hhc.location); assertTrue(hhc.hasRegions); } - + @Test public void getLambda_noRegion_returnsValue() { PottsCell cell = mock(PottsCell.class); @@ -58,37 +58,37 @@ public void getLambda_noRegion_returnsValue() { HeightHamiltonianConfig hhc = new HeightHamiltonianConfig(cell, lambda, null); assertEquals(lambda, hhc.getLambda(), EPSILON); } - + @Test public void getLambda_validRegions_returnsValue() { PottsCell cell = mock(PottsCell.class); double lambda = randomDoubleBetween(1, 100); - + EnumMap lambdasRegion = new EnumMap<>(Region.class); lambdasRegion.put(Region.DEFAULT, randomDoubleBetween(0, 100)); lambdasRegion.put(Region.NUCLEUS, randomDoubleBetween(0, 100)); - + HeightHamiltonianConfig hhc = new HeightHamiltonianConfig(cell, lambda, lambdasRegion); - + assertEquals(lambdasRegion.get(Region.DEFAULT), hhc.getLambda(Region.DEFAULT), EPSILON); assertEquals(lambdasRegion.get(Region.NUCLEUS), hhc.getLambda(Region.NUCLEUS), EPSILON); } - + @Test public void getLambda_invalidRegions_returnsNaN() { PottsCell cell = mock(PottsCell.class); double lambda = randomDoubleBetween(1, 100); - + EnumMap lambdasRegion = new EnumMap<>(Region.class); lambdasRegion.put(Region.DEFAULT, randomDoubleBetween(0, 100)); lambdasRegion.put(Region.NUCLEUS, randomDoubleBetween(0, 100)); - + HeightHamiltonianConfig hhc = new HeightHamiltonianConfig(cell, lambda, lambdasRegion); - + assertEquals(Double.NaN, hhc.getLambda(null), EPSILON); assertEquals(Double.NaN, hhc.getLambda(Region.UNDEFINED), EPSILON); } - + @Test public void getLambda_nullRegion_returnsNaN() { PottsCell cell = mock(PottsCell.class); diff --git a/test/arcade/potts/sim/hamiltonian/HeightHamiltonianTest.java b/test/arcade/potts/sim/hamiltonian/HeightHamiltonianTest.java index c2d353ae4..1db748328 100644 --- a/test/arcade/potts/sim/hamiltonian/HeightHamiltonianTest.java +++ b/test/arcade/potts/sim/hamiltonian/HeightHamiltonianTest.java @@ -4,13 +4,13 @@ import java.util.ArrayList; import java.util.EnumMap; import java.util.HashMap; -import org.junit.Test; +import org.junit.jupiter.api.Test; import arcade.core.util.MiniBox; import arcade.potts.agent.cell.PottsCell; import arcade.potts.env.location.PottsLocation; import arcade.potts.env.location.Voxel; import arcade.potts.sim.PottsSeries; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.core.ARCADETestUtilities.*; import static arcade.core.util.MiniBox.TAG_SEPARATOR; @@ -19,7 +19,7 @@ public class HeightHamiltonianTest { private static final double EPSILON = 1E-10; - + @Test public void constructor_called_initializesMaps() { HeightHamiltonian hh = new HeightHamiltonian(mock(PottsSeries.class)); @@ -27,20 +27,20 @@ public void constructor_called_initializesMaps() { assertNotNull(hh.popToLambda); assertNotNull(hh.popToLambdasRegion); } - + @Test public void constructor_called_initializesParameters() { PottsSeries series = mock(PottsSeries.class); - + series.potts = new MiniBox(); series.populations = new HashMap<>(); - + String key1 = randomString(); int code1 = randomIntBetween(1, 10); MiniBox population1 = new MiniBox(); population1.put("CODE", code1); series.populations.put(key1, population1); - + String key2 = randomString(); int code2 = code1 + randomIntBetween(1, 10); MiniBox population2 = new MiniBox(); @@ -48,20 +48,22 @@ public void constructor_called_initializesParameters() { population2.put("(REGION)" + TAG_SEPARATOR + Region.DEFAULT.name(), 0); population2.put("(REGION)" + TAG_SEPARATOR + Region.NUCLEUS.name(), 0); series.populations.put(key2, population2); - + double lambda1 = randomDoubleBetween(1, 100); double lambda2 = randomDoubleBetween(1, 100); - + series.potts.put("height/LAMBDA" + TARGET_SEPARATOR + key1, lambda1); series.potts.put("height/LAMBDA" + TARGET_SEPARATOR + key2, lambda2); - + double lambdaNucleus = randomDoubleBetween(1, 100); double lambdaDefault = randomDoubleBetween(1, 100); - series.potts.put("height/LAMBDA_" + Region.DEFAULT.name() + TARGET_SEPARATOR + key2, lambdaDefault); - series.potts.put("height/LAMBDA_" + Region.NUCLEUS.name() + TARGET_SEPARATOR + key2, lambdaNucleus); - + series.potts.put( + "height/LAMBDA_" + Region.DEFAULT.name() + TARGET_SEPARATOR + key2, lambdaDefault); + series.potts.put( + "height/LAMBDA_" + Region.NUCLEUS.name() + TARGET_SEPARATOR + key2, lambdaNucleus); + HeightHamiltonian hh = new HeightHamiltonian(series); - + assertEquals(2, hh.popToLambda.size()); assertTrue(hh.popToLambda.containsKey(code1)); assertTrue(hh.popToLambda.containsKey(code2)); @@ -71,137 +73,147 @@ public void constructor_called_initializesParameters() { assertEquals(lambdaDefault, hh.popToLambdasRegion.get(code2).get(Region.DEFAULT), EPSILON); assertEquals(lambdaNucleus, hh.popToLambdasRegion.get(code2).get(Region.NUCLEUS), EPSILON); } - + @Test public void register_noRegions_addsConfig() { HeightHamiltonian hh = new HeightHamiltonian(mock(PottsSeries.class)); PottsCell cell = mock(PottsCell.class); - + int id = randomIntBetween(1, 10); int pop = randomIntBetween(1, 10); - + doReturn(id).when(cell).getID(); doReturn(pop).when(cell).getPop(); - + double lambda = randomDoubleBetween(1, 100); EnumMap lambdasRegion = null; hh.popToLambda.put(pop, lambda); hh.popToLambdasRegion.put(pop, lambdasRegion); - + hh.register(cell); HeightHamiltonianConfig config = hh.configs.get(id); - + assertNotNull(config); assertEquals(cell, config.cell); assertEquals(lambda, config.getLambda(), EPSILON); assertEquals(Double.NaN, config.getLambda(Region.UNDEFINED), EPSILON); } - + @Test public void register_withRegions_addsConfig() { HeightHamiltonian hh = new HeightHamiltonian(mock(PottsSeries.class)); PottsCell cell = mock(PottsCell.class); - + int id = randomIntBetween(1, 10); int pop = randomIntBetween(1, 10); - + doReturn(id).when(cell).getID(); doReturn(pop).when(cell).getPop(); - + double lambda = randomDoubleBetween(1, 100); double lambdaNucleus = randomDoubleBetween(1, 100); EnumMap lambdasRegion = new EnumMap<>(Region.class); lambdasRegion.put(Region.NUCLEUS, lambdaNucleus); - + hh.popToLambda.put(pop, lambda); hh.popToLambdasRegion.put(pop, lambdasRegion); - + hh.register(cell); HeightHamiltonianConfig config = hh.configs.get(id); - + assertNotNull(config); assertEquals(cell, config.cell); assertEquals(lambda, config.getLambda(), EPSILON); assertEquals(lambdaNucleus, config.getLambda(Region.NUCLEUS), EPSILON); } - + @Test public void deregister_exists_removesConfig() { HeightHamiltonian hh = new HeightHamiltonian(mock(PottsSeries.class)); PottsCell cell = mock(PottsCell.class); - + int id = randomIntBetween(1, 10); doReturn(id).when(cell).getID(); - + HeightHamiltonianConfig config = mock(HeightHamiltonianConfig.class); hh.configs.put(id, config); - + hh.deregister(cell); - + assertFalse(hh.configs.containsKey(id)); } - + @Test public void getDelta_validIDs_calculatesValue() { HeightHamiltonian hh = spy(new HeightHamiltonian(mock(PottsSeries.class))); Voxel voxel = new Voxel(0, 0, 0); int id1 = randomIntBetween(1, 100); int id2 = id1 + randomIntBetween(1, 10); - + double cell1 = randomDoubleBetween(1, 100); doReturn(cell1).when(hh).getHeight(id1, voxel, 0); - + double cell1plus1 = randomDoubleBetween(1, 100); doReturn(cell1plus1).when(hh).getHeight(id1, voxel, 1); - + double cell1minus1 = randomDoubleBetween(1, 100); doReturn(cell1minus1).when(hh).getHeight(id1, voxel, -1); - + double cell2 = randomDoubleBetween(1, 100); doReturn(cell2).when(hh).getHeight(id2, voxel, 0); - + double cell2plus1 = randomDoubleBetween(1, 100); doReturn(cell2plus1).when(hh).getHeight(id2, voxel, 1); - + double cell2minus1 = randomDoubleBetween(1, 100); doReturn(cell2minus1).when(hh).getHeight(id2, voxel, -1); - - assertEquals((cell1minus1 - cell1 + cell2plus1 - cell2), hh.getDelta(id1, id2, 0, 0, 0), EPSILON); - assertEquals((cell2minus1 - cell2 + cell1plus1 - cell1), hh.getDelta(id2, id1, 0, 0, 0), EPSILON); + + assertEquals( + (cell1minus1 - cell1 + cell2plus1 - cell2), + hh.getDelta(id1, id2, 0, 0, 0), + EPSILON); + assertEquals( + (cell2minus1 - cell2 + cell1plus1 - cell1), + hh.getDelta(id2, id1, 0, 0, 0), + EPSILON); } - + @Test public void getDelta_validRegions_calculatesValue() { HeightHamiltonian hh = spy(new HeightHamiltonian(mock(PottsSeries.class))); Voxel voxel = new Voxel(0, 0, 0); int id = randomIntBetween(1, 100); - + double region = randomDoubleBetween(1, 100); doReturn(0.0).when(hh).getHeight(id, voxel, Region.DEFAULT.ordinal(), 0); doReturn(region).when(hh).getHeight(id, voxel, Region.NUCLEUS.ordinal(), 0); - + double regionplus1 = randomDoubleBetween(1, 100); doReturn(0.0).when(hh).getHeight(id, voxel, Region.DEFAULT.ordinal(), 1); doReturn(regionplus1).when(hh).getHeight(id, voxel, Region.NUCLEUS.ordinal(), 1); - + double regionminus1 = randomDoubleBetween(1, 100); doReturn(0.0).when(hh).getHeight(id, voxel, Region.DEFAULT.ordinal(), -1); doReturn(regionminus1).when(hh).getHeight(id, voxel, Region.NUCLEUS.ordinal(), -1); - - assertEquals((regionplus1 - region), - hh.getDelta(id, Region.DEFAULT.ordinal(), Region.NUCLEUS.ordinal(), 0, 0, 0), EPSILON); - assertEquals((regionminus1 - region), - hh.getDelta(id, Region.NUCLEUS.ordinal(), Region.DEFAULT.ordinal(), 0, 0, 0), EPSILON); + + assertEquals( + (regionplus1 - region), + hh.getDelta(id, Region.DEFAULT.ordinal(), Region.NUCLEUS.ordinal(), 0, 0, 0), + EPSILON); + assertEquals( + (regionminus1 - region), + hh.getDelta(id, Region.NUCLEUS.ordinal(), Region.DEFAULT.ordinal(), 0, 0, 0), + EPSILON); } - + @Test public void getHeight_validID_calculatesValue() { HeightHamiltonian hh = new HeightHamiltonian(mock(PottsSeries.class)); int id = randomIntBetween(1, 100); - + int height = randomIntBetween(10, 20); double criticalHeight = randomDoubleBetween(10, 20); - + ArrayList voxels = new ArrayList<>(); voxels.add(new Voxel(0, 0, 0)); voxels.add(new Voxel(0, 0, 1)); @@ -210,50 +222,61 @@ public void getHeight_validID_calculatesValue() { voxels.add(new Voxel(1, 0, 0)); voxels.add(new Voxel(1, 1, 0)); voxels.add(new Voxel(1, 1, 2)); - + PottsCell cell = mock(PottsCell.class); PottsLocation location = mock(PottsLocation.class); doReturn(criticalHeight).when(cell).getCriticalHeight(); doReturn(voxels).when(location).getVoxels(); - + HeightHamiltonianConfig config = mock(HeightHamiltonianConfig.class); - + try { Field cellField = HeightHamiltonianConfig.class.getDeclaredField("cell"); cellField.setAccessible(true); cellField.set(config, cell); - + Field locationField = HeightHamiltonianConfig.class.getDeclaredField("location"); locationField.setAccessible(true); locationField.set(config, location); - } catch (Exception ignored) { } - + } catch (Exception ignored) { + } + double lambda = randomDoubleBetween(10, 100); doReturn(lambda).when(config).getLambda(); - + hh.configs.put(id, config); - - assertEquals(lambda * Math.pow(height - criticalHeight, 2), - hh.getHeight(id, new Voxel(0, 0, 0), 0), EPSILON); - assertEquals(lambda * Math.pow(3 - criticalHeight, 2), - hh.getHeight(id, new Voxel(1, 1, 1), 1), EPSILON); - assertEquals(lambda * Math.pow(3 - criticalHeight, 2), - hh.getHeight(id, new Voxel(1, 1, 1), -1), EPSILON); - assertEquals(lambda * Math.pow(height - criticalHeight + 1, 2), - hh.getHeight(id, new Voxel(0, 0, height), 1), EPSILON); - assertEquals(lambda * Math.pow(height - criticalHeight - 1, 2), - hh.getHeight(id, new Voxel(0, 0, 0), -1), EPSILON); + + assertEquals( + lambda * Math.pow(height - criticalHeight, 2), + hh.getHeight(id, new Voxel(0, 0, 0), 0), + EPSILON); + assertEquals( + lambda * Math.pow(3 - criticalHeight, 2), + hh.getHeight(id, new Voxel(1, 1, 1), 1), + EPSILON); + assertEquals( + lambda * Math.pow(3 - criticalHeight, 2), + hh.getHeight(id, new Voxel(1, 1, 1), -1), + EPSILON); + assertEquals( + lambda * Math.pow(height - criticalHeight + 1, 2), + hh.getHeight(id, new Voxel(0, 0, height), 1), + EPSILON); + assertEquals( + lambda * Math.pow(height - criticalHeight - 1, 2), + hh.getHeight(id, new Voxel(0, 0, 0), -1), + EPSILON); } - + @Test public void getHeight_validRegions_calculatesValue() { HeightHamiltonian hh = new HeightHamiltonian(mock(PottsSeries.class)); int id = randomIntBetween(1, 100); Region region = Region.NUCLEUS; - + int height = randomIntBetween(10, 20); double criticalHeight = randomDoubleBetween(10, 20); - + ArrayList voxels = new ArrayList<>(); voxels.add(new Voxel(0, 0, 0)); voxels.add(new Voxel(0, 0, 1)); @@ -262,41 +285,52 @@ public void getHeight_validRegions_calculatesValue() { voxels.add(new Voxel(1, 0, 0)); voxels.add(new Voxel(1, 1, 0)); voxels.add(new Voxel(1, 1, 2)); - + PottsCell cell = mock(PottsCell.class); PottsLocation location = mock(PottsLocation.class); doReturn(criticalHeight).when(cell).getCriticalHeight(region); doReturn(voxels).when(location).getVoxels(region); - + HeightHamiltonianConfig config = mock(HeightHamiltonianConfig.class); - + try { Field cellField = HeightHamiltonianConfig.class.getDeclaredField("cell"); cellField.setAccessible(true); cellField.set(config, cell); - + Field locationField = HeightHamiltonianConfig.class.getDeclaredField("location"); locationField.setAccessible(true); locationField.set(config, location); - } catch (Exception ignored) { } - + } catch (Exception ignored) { + } + double lambda = randomDoubleBetween(10, 100); doReturn(lambda).when(config).getLambda(region); - + hh.configs.put(id, config); - - assertEquals(lambda * Math.pow(height - criticalHeight, 2), - hh.getHeight(id, new Voxel(0, 0, 0), region.ordinal(), 0), EPSILON); - assertEquals(lambda * Math.pow(3 - criticalHeight, 2), - hh.getHeight(id, new Voxel(1, 1, 1), region.ordinal(), 1), EPSILON); - assertEquals(lambda * Math.pow(3 - criticalHeight, 2), - hh.getHeight(id, new Voxel(1, 1, 1), region.ordinal(), -1), EPSILON); - assertEquals(lambda * Math.pow(height - criticalHeight + 1, 2), - hh.getHeight(id, new Voxel(0, 0, height), region.ordinal(), 1), EPSILON); - assertEquals(lambda * Math.pow(height - criticalHeight - 1, 2), - hh.getHeight(id, new Voxel(0, 0, 0), region.ordinal(), -1), EPSILON); + + assertEquals( + lambda * Math.pow(height - criticalHeight, 2), + hh.getHeight(id, new Voxel(0, 0, 0), region.ordinal(), 0), + EPSILON); + assertEquals( + lambda * Math.pow(3 - criticalHeight, 2), + hh.getHeight(id, new Voxel(1, 1, 1), region.ordinal(), 1), + EPSILON); + assertEquals( + lambda * Math.pow(3 - criticalHeight, 2), + hh.getHeight(id, new Voxel(1, 1, 1), region.ordinal(), -1), + EPSILON); + assertEquals( + lambda * Math.pow(height - criticalHeight + 1, 2), + hh.getHeight(id, new Voxel(0, 0, height), region.ordinal(), 1), + EPSILON); + assertEquals( + lambda * Math.pow(height - criticalHeight - 1, 2), + hh.getHeight(id, new Voxel(0, 0, 0), region.ordinal(), -1), + EPSILON); } - + @Test public void getHeight_zeroID_returnsZero() { HeightHamiltonian hh = new HeightHamiltonian(mock(PottsSeries.class)); @@ -305,7 +339,7 @@ public void getHeight_zeroID_returnsZero() { assertEquals(0, hh.getHeight(0, voxel, 0), EPSILON); assertEquals(0, hh.getHeight(0, voxel, -1), EPSILON); } - + @Test public void getHeight_defaultRegion_returnsZero() { HeightHamiltonian hh = new HeightHamiltonian(mock(PottsSeries.class)); diff --git a/test/arcade/potts/sim/hamiltonian/JunctionHamiltonianConfigTest.java b/test/arcade/potts/sim/hamiltonian/JunctionHamiltonianConfigTest.java index 7c7581e94..851dab785 100644 --- a/test/arcade/potts/sim/hamiltonian/JunctionHamiltonianConfigTest.java +++ b/test/arcade/potts/sim/hamiltonian/JunctionHamiltonianConfigTest.java @@ -1,12 +1,12 @@ package arcade.potts.sim.hamiltonian; -import org.junit.Test; -import static org.junit.Assert.*; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; import static arcade.core.ARCADETestUtilities.*; public class JunctionHamiltonianConfigTest { private static final double EPSILON = 1E-10; - + @Test public void getLambda_called_returnsValue() { double lambda = randomDoubleBetween(1, 100); diff --git a/test/arcade/potts/sim/hamiltonian/JunctionHamiltonianTest.java b/test/arcade/potts/sim/hamiltonian/JunctionHamiltonianTest.java index 3a5d08c4e..9b0e18156 100644 --- a/test/arcade/potts/sim/hamiltonian/JunctionHamiltonianTest.java +++ b/test/arcade/potts/sim/hamiltonian/JunctionHamiltonianTest.java @@ -1,12 +1,12 @@ package arcade.potts.sim.hamiltonian; import java.util.HashMap; -import org.junit.Test; +import org.junit.jupiter.api.Test; import arcade.core.util.MiniBox; import arcade.potts.agent.cell.PottsCell; import arcade.potts.sim.Potts; import arcade.potts.sim.PottsSeries; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.core.ARCADETestUtilities.*; import static arcade.potts.sim.PottsSeries.TARGET_SEPARATOR; @@ -14,184 +14,193 @@ public class JunctionHamiltonianTest { private static final double EPSILON = 1E-5; - + @Test public void constructor_called_initializesMaps() { - JunctionHamiltonian jh = new JunctionHamiltonian(mock(PottsSeries.class), mock(Potts.class)); + JunctionHamiltonian jh = + new JunctionHamiltonian(mock(PottsSeries.class), mock(Potts.class)); assertNotNull(jh.configs); assertNotNull(jh.popToLambda); } - + @Test public void constructor_called_setsArrays() { Potts potts = mock(Potts.class); int[][][] ids = new int[0][0][0]; potts.ids = ids; - + JunctionHamiltonian jh = new JunctionHamiltonian(mock(PottsSeries.class), potts); - + assertSame(ids, jh.ids); } - + @Test public void constructor_called_initializesParameters() { PottsSeries series = mock(PottsSeries.class); - + series.potts = new MiniBox(); series.populations = new HashMap<>(); - + String key1 = randomString(); int code1 = randomIntBetween(1, 10); MiniBox population1 = new MiniBox(); population1.put("CODE", code1); series.populations.put(key1, population1); - + String key2 = randomString(); int code2 = code1 + randomIntBetween(1, 10); MiniBox population2 = new MiniBox(); population2.put("CODE", code2); series.populations.put(key2, population2); - + double lambda1 = randomDoubleBetween(1, 100); double lambda2 = randomDoubleBetween(1, 100); - + series.potts.put("junction/LAMBDA" + TARGET_SEPARATOR + key1, lambda1); series.potts.put("junction/LAMBDA" + TARGET_SEPARATOR + key2, lambda2); - + JunctionHamiltonian jh = new JunctionHamiltonian(series, mock(Potts.class)); - + assertEquals(2, jh.popToLambda.size()); assertTrue(jh.popToLambda.containsKey(code1)); assertTrue(jh.popToLambda.containsKey(code2)); assertEquals(lambda1, jh.popToLambda.get(code1), EPSILON); assertEquals(lambda2, jh.popToLambda.get(code2), EPSILON); } - + @Test public void register_givenCell_addsConfig() { - JunctionHamiltonian jh = new JunctionHamiltonian(mock(PottsSeries.class), mock(Potts.class)); + JunctionHamiltonian jh = + new JunctionHamiltonian(mock(PottsSeries.class), mock(Potts.class)); PottsCell cell = mock(PottsCell.class); - + int id = randomIntBetween(1, 10); int pop = randomIntBetween(1, 10); - + doReturn(id).when(cell).getID(); doReturn(pop).when(cell).getPop(); - + double lambda = randomDoubleBetween(1, 100); jh.popToLambda.put(pop, lambda); - + jh.register(cell); JunctionHamiltonianConfig config = jh.configs.get(id); - + assertNotNull(config); assertEquals(lambda, config.getLambda(), EPSILON); } - + @Test public void deregister_exists_removesConfig() { - JunctionHamiltonian jh = new JunctionHamiltonian(mock(PottsSeries.class), mock(Potts.class)); + JunctionHamiltonian jh = + new JunctionHamiltonian(mock(PottsSeries.class), mock(Potts.class)); PottsCell cell = mock(PottsCell.class); - + int id = randomIntBetween(1, 10); doReturn(id).when(cell).getID(); - + JunctionHamiltonianConfig config = mock(JunctionHamiltonianConfig.class); jh.configs.put(id, config); - + jh.deregister(cell); - + assertFalse(jh.configs.containsKey(id)); } - + @Test public void getDelta_validIDsTargetMatch_calculatesValue() { int id1 = randomIntBetween(1, 100); int id2 = id1 + randomIntBetween(1, 100); - + Potts potts = mock(Potts.class); - potts.ids = new int[][][] { - { - { 0, 0, 0, 0 }, - { 0, 0, id1, 0 }, - { 0, 0, 0, 0 }, - }, - { - { 0, 0, 0, 0 }, - { 0, 0, id2, 0 }, - { 0, 0, 0, 0 }, - }, - }; - + potts.ids = + new int[][][] { + { + {0, 0, 0, 0}, + {0, 0, id1, 0}, + {0, 0, 0, 0}, + }, + { + {0, 0, 0, 0}, + {0, 0, id2, 0}, + {0, 0, 0, 0}, + }, + }; + JunctionHamiltonianConfig config = mock(JunctionHamiltonianConfig.class); double lambda = randomDoubleBetween(10, 100); doReturn(lambda).when(config).getLambda(); - + JunctionHamiltonian jh = new JunctionHamiltonian(mock(PottsSeries.class), potts); - + jh.configs.put(id1, config); - + double delta = jh.getDelta(id2, id1, 1, 2, 1); assertEquals(-lambda, delta, EPSILON); } - + @Test public void getDelta_validIDsSourceMatch_calculatesValue() { int id1 = randomIntBetween(1, 100); int id2 = id1 + randomIntBetween(1, 100); - + Potts potts = mock(Potts.class); - potts.ids = new int[][][] { - { - { 0, 0, 0, 0 }, - { 0, 0, id2, 0 }, - { 0, 0, 0, 0 }, - }, - { - { 0, 0, 0, 0 }, - { 0, 0, id2, 0 }, - { 0, 0, 0, 0 }, - }, - }; - + potts.ids = + new int[][][] { + { + {0, 0, 0, 0}, + {0, 0, id2, 0}, + {0, 0, 0, 0}, + }, + { + {0, 0, 0, 0}, + {0, 0, id2, 0}, + {0, 0, 0, 0}, + }, + }; + JunctionHamiltonianConfig config = mock(JunctionHamiltonianConfig.class); double lambda = randomDoubleBetween(10, 100); doReturn(lambda).when(config).getLambda(); - + JunctionHamiltonian jh = new JunctionHamiltonian(mock(PottsSeries.class), potts); - + jh.configs.put(id1, config); - + double delta = jh.getDelta(id2, id1, 1, 2, 1); assertEquals(lambda, delta, EPSILON); } - + @Test public void getDelta_invalidIDs_returnsZeros() { int id1 = randomIntBetween(1, 100); int id2 = id1 + randomIntBetween(1, 100); - - JunctionHamiltonian jh = new JunctionHamiltonian(mock(PottsSeries.class), mock(Potts.class)); - + + JunctionHamiltonian jh = + new JunctionHamiltonian(mock(PottsSeries.class), mock(Potts.class)); + double delta1 = jh.getDelta(0, 0, 0, 0, 0); assertEquals(0, delta1, EPSILON); - + double delta2 = jh.getDelta(id1, 0, 0, 0, 0); assertEquals(0, delta2, EPSILON); - + double delta3 = jh.getDelta(0, id2, 0, 0, 0); assertEquals(0, delta3, EPSILON); } - + @Test public void getDelta_validRegions_returnsZero() { - JunctionHamiltonian jh = new JunctionHamiltonian(mock(PottsSeries.class), mock(Potts.class)); + JunctionHamiltonian jh = + new JunctionHamiltonian(mock(PottsSeries.class), mock(Potts.class)); int id = randomIntBetween(1, 100); - - double delta1 = jh.getDelta(id, Region.DEFAULT.ordinal(), Region.NUCLEUS.ordinal(), 0, 0, 0); + + double delta1 = + jh.getDelta(id, Region.DEFAULT.ordinal(), Region.NUCLEUS.ordinal(), 0, 0, 0); assertEquals(0, delta1, EPSILON); - - double delta2 = jh.getDelta(id, Region.NUCLEUS.ordinal(), Region.DEFAULT.ordinal(), 0, 0, 0); + + double delta2 = + jh.getDelta(id, Region.NUCLEUS.ordinal(), Region.DEFAULT.ordinal(), 0, 0, 0); assertEquals(0, delta2, EPSILON); } } diff --git a/test/arcade/potts/sim/hamiltonian/PersistenceHamiltonianConfigTest.java b/test/arcade/potts/sim/hamiltonian/PersistenceHamiltonianConfigTest.java index 6e742e35f..5ced8f339 100644 --- a/test/arcade/potts/sim/hamiltonian/PersistenceHamiltonianConfigTest.java +++ b/test/arcade/potts/sim/hamiltonian/PersistenceHamiltonianConfigTest.java @@ -1,340 +1,386 @@ package arcade.potts.sim.hamiltonian; import java.util.EnumMap; -import org.junit.Test; +import org.junit.jupiter.api.Test; import arcade.potts.env.location.PottsLocation; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.core.ARCADETestUtilities.*; import static arcade.potts.util.PottsEnums.Region; public class PersistenceHamiltonianConfigTest { private static final double EPSILON = 1E-10; - + @Test public void constructor_noRegions_setsFields() { PottsLocation location = mock(PottsLocation.class); - - PersistenceHamiltonianConfig phc = new PersistenceHamiltonianConfig(location, 0, null, 0, 0); + + PersistenceHamiltonianConfig phc = + new PersistenceHamiltonianConfig(location, 0, null, 0, 0); assertEquals(location, phc.location); assertNotNull(phc.vector); assertNotNull(phc.displacement); assertFalse(phc.hasRegions); } - + @Test public void constructor_emptyRegions_setsFields() { PottsLocation location = mock(PottsLocation.class); EnumMap lambdasRegion = new EnumMap<>(Region.class); - - PersistenceHamiltonianConfig phc = new PersistenceHamiltonianConfig(location, 0, lambdasRegion, 0, 0); + + PersistenceHamiltonianConfig phc = + new PersistenceHamiltonianConfig(location, 0, lambdasRegion, 0, 0); assertEquals(location, phc.location); assertNotNull(phc.vector); assertNotNull(phc.displacement); assertFalse(phc.hasRegions); } - + @Test public void constructor_hasRegions_setsFields() { PottsLocation location = mock(PottsLocation.class); EnumMap lambdasRegion = new EnumMap<>(Region.class); lambdasRegion.put(Region.UNDEFINED, randomDoubleBetween(1, 100)); - - PersistenceHamiltonianConfig phc = new PersistenceHamiltonianConfig(location, 0, lambdasRegion, 0, 0); + + PersistenceHamiltonianConfig phc = + new PersistenceHamiltonianConfig(location, 0, lambdasRegion, 0, 0); assertEquals(location, phc.location); assertNotNull(phc.vector); assertNotNull(phc.displacement); assertTrue(phc.hasRegions); } - + @Test public void constructor_called_initializesVectors() { PottsLocation location = mock(PottsLocation.class); - PersistenceHamiltonianConfig phc = new PersistenceHamiltonianConfig(location, 0, null, 0, 0); + PersistenceHamiltonianConfig phc = + new PersistenceHamiltonianConfig(location, 0, null, 0, 0); assertNotSame(PersistenceHamiltonianConfig.DEFAULT_UNIT_VECTOR, phc.vector); assertArrayEquals(PersistenceHamiltonianConfig.DEFAULT_UNIT_VECTOR, phc.vector, EPSILON); - assertArrayEquals(new double[] { 0, 0, 0 }, phc.displacement, EPSILON); + assertArrayEquals(new double[] {0, 0, 0}, phc.displacement, EPSILON); } - + @Test public void getLambda_noRegion_returnsValue() { PottsLocation location = mock(PottsLocation.class); double lambda = randomDoubleBetween(1, 100); - PersistenceHamiltonianConfig phc = new PersistenceHamiltonianConfig(location, lambda, null, 0, 0); + PersistenceHamiltonianConfig phc = + new PersistenceHamiltonianConfig(location, lambda, null, 0, 0); assertEquals(lambda, phc.getLambda(), EPSILON); } - + @Test public void getLambda_validRegions_returnsValue() { PottsLocation location = mock(PottsLocation.class); double lambda = randomDoubleBetween(1, 100); - + EnumMap lambdasRegion = new EnumMap<>(Region.class); lambdasRegion.put(Region.DEFAULT, randomDoubleBetween(0, 100)); lambdasRegion.put(Region.NUCLEUS, randomDoubleBetween(0, 100)); - - PersistenceHamiltonianConfig phc = new PersistenceHamiltonianConfig(location, lambda, lambdasRegion, 0, 0); - + + PersistenceHamiltonianConfig phc = + new PersistenceHamiltonianConfig(location, lambda, lambdasRegion, 0, 0); + assertEquals(lambdasRegion.get(Region.DEFAULT), phc.getLambda(Region.DEFAULT), EPSILON); assertEquals(lambdasRegion.get(Region.NUCLEUS), phc.getLambda(Region.NUCLEUS), EPSILON); } - + @Test public void getLambda_invalidRegions_returnsNaN() { PottsLocation location = mock(PottsLocation.class); double lambda = randomDoubleBetween(1, 100); - + EnumMap lambdasRegion = new EnumMap<>(Region.class); lambdasRegion.put(Region.DEFAULT, randomDoubleBetween(0, 100)); lambdasRegion.put(Region.NUCLEUS, randomDoubleBetween(0, 100)); - - PersistenceHamiltonianConfig phc = new PersistenceHamiltonianConfig(location, lambda, lambdasRegion, 0, 0); - + + PersistenceHamiltonianConfig phc = + new PersistenceHamiltonianConfig(location, lambda, lambdasRegion, 0, 0); + assertEquals(Double.NaN, phc.getLambda(null), EPSILON); assertEquals(Double.NaN, phc.getLambda(Region.UNDEFINED), EPSILON); } - + @Test public void getLambda_nullRegion_returnsNaN() { PottsLocation location = mock(PottsLocation.class); double lambda = randomDoubleBetween(1, 100); - PersistenceHamiltonianConfig phc = new PersistenceHamiltonianConfig(location, lambda, null, 0, 0); + PersistenceHamiltonianConfig phc = + new PersistenceHamiltonianConfig(location, lambda, null, 0, 0); assertEquals(Double.NaN, phc.getLambda(Region.DEFAULT), EPSILON); assertEquals(Double.NaN, phc.getLambda(Region.NUCLEUS), EPSILON); } - + @Test public void getDecay_called_returnsValue() { PottsLocation location = mock(PottsLocation.class); double decay = randomDoubleBetween(1, 100); - PersistenceHamiltonianConfig phc = new PersistenceHamiltonianConfig(location, 0, null, decay, 0); + PersistenceHamiltonianConfig phc = + new PersistenceHamiltonianConfig(location, 0, null, decay, 0); assertEquals(decay, phc.getDecay(), EPSILON); } - + @Test public void getVector_noChange_returnsVector() { PottsLocation location = mock(PottsLocation.class); int volume = randomIntBetween(10, 100); doReturn((double) volume).when(location).getVolume(); - + double decay = randomDoubleBetween(0, 1); - PersistenceHamiltonianConfig phc = new PersistenceHamiltonianConfig(location, 0, null, decay, 0); - + PersistenceHamiltonianConfig phc = + new PersistenceHamiltonianConfig(location, 0, null, decay, 0); + double dx = randomDoubleBetween(1, 10); double dy = randomDoubleBetween(1, 10); double dz = randomDoubleBetween(1, 10); - + phc.displacement[0] = dx; phc.displacement[1] = dy; phc.displacement[2] = dz; - + double[] vector = phc.getVector(); assertArrayEquals(PersistenceHamiltonianConfig.DEFAULT_UNIT_VECTOR, vector, EPSILON); } - + @Test public void getVector_locationChanged_returnsVector() { PottsLocation location = mock(PottsLocation.class); int volume = randomIntBetween(10, 100); doReturn((double) volume).when(location).getVolume(); - + double decay = randomDoubleBetween(0, 1); double threshold = randomDoubleBetween(1, 100); - PersistenceHamiltonianConfig phc = new PersistenceHamiltonianConfig(location, 0, null, decay, threshold); - + PersistenceHamiltonianConfig phc = + new PersistenceHamiltonianConfig(location, 0, null, decay, threshold); + int newVolume = volume + randomIntBetween(1, 10); doReturn((double) newVolume).when(location).getVolume(); - + double dx = randomDoubleBetween(1, 10); double dy = randomDoubleBetween(1, 10); double dz = randomDoubleBetween(1, 10); - + phc.displacement[0] = dx; phc.displacement[1] = dy; phc.displacement[2] = dz; - + double[] defaultVector = PersistenceHamiltonianConfig.DEFAULT_UNIT_VECTOR; double[] vector = phc.getVector(); - - double[] expected = new double[] { - (1 - decay) * defaultVector[0] + decay * dx, - (1 - decay) * defaultVector[1] + decay * dy, - -newVolume / threshold, - }; - - double norm = Math.sqrt(expected[0] * expected[0] + expected[1] * expected[1] + expected[2] * expected[2]); - + + double[] expected = + new double[] { + (1 - decay) * defaultVector[0] + decay * dx, + (1 - decay) * defaultVector[1] + decay * dy, + -newVolume / threshold, + }; + + double norm = + Math.sqrt( + expected[0] * expected[0] + + expected[1] * expected[1] + + expected[2] * expected[2]); + expected[0] /= norm; expected[1] /= norm; expected[2] /= norm; - + assertArrayEquals(expected, vector, EPSILON); } - + @Test public void getDisplacement_voxelAdded_updatesVector() { PottsLocation location = mock(PottsLocation.class); int volume = randomIntBetween(10, 100); - double[] centroid = new double[] { - randomDoubleBetween(1, 100), - randomDoubleBetween(1, 100), - randomDoubleBetween(1, 100), - }; - + double[] centroid = + new double[] { + randomDoubleBetween(1, 100), + randomDoubleBetween(1, 100), + randomDoubleBetween(1, 100), + }; + doReturn((double) volume).when(location).getVolume(); doReturn(centroid).when(location).getCentroid(); - - PersistenceHamiltonianConfig phc = new PersistenceHamiltonianConfig(location, 0, null, 0, 0); - + + PersistenceHamiltonianConfig phc = + new PersistenceHamiltonianConfig(location, 0, null, 0, 0); + int x = randomIntBetween(1, 10); int y = randomIntBetween(1, 10); int z = randomIntBetween(1, 10); - + phc.getDisplacement(x, y, z, 1); - - double[] expected = new double[] { - (x - centroid[0]) / (volume + 1), - (y - centroid[1]) / (volume + 1), - (z - centroid[2]) / (volume + 1), - }; - - double norm = Math.sqrt(expected[0] * expected[0] + expected[1] * expected[1] + expected[2] * expected[2]); - + + double[] expected = + new double[] { + (x - centroid[0]) / (volume + 1), + (y - centroid[1]) / (volume + 1), + (z - centroid[2]) / (volume + 1), + }; + + double norm = + Math.sqrt( + expected[0] * expected[0] + + expected[1] * expected[1] + + expected[2] * expected[2]); + expected[0] /= norm; expected[1] /= norm; expected[2] /= norm; - + assertArrayEquals(expected, phc.displacement, EPSILON); } - + @Test public void getDisplacement_voxelRemoved_updatesVector() { PottsLocation location = mock(PottsLocation.class); int volume = randomIntBetween(10, 100); - double[] centroid = new double[] { - randomDoubleBetween(1, 100), - randomDoubleBetween(1, 100), - randomDoubleBetween(1, 100), - }; - + double[] centroid = + new double[] { + randomDoubleBetween(1, 100), + randomDoubleBetween(1, 100), + randomDoubleBetween(1, 100), + }; + doReturn((double) volume).when(location).getVolume(); doReturn(centroid).when(location).getCentroid(); - - PersistenceHamiltonianConfig phc = new PersistenceHamiltonianConfig(location, 0, null, 0, 0); - + + PersistenceHamiltonianConfig phc = + new PersistenceHamiltonianConfig(location, 0, null, 0, 0); + int x = randomIntBetween(1, 10); int y = randomIntBetween(1, 10); int z = randomIntBetween(1, 10); - + phc.getDisplacement(x, y, z, -1); - - double[] expected = new double[] { - (centroid[0] - x) / (volume - 1), - (centroid[1] - y) / (volume - 1), - (centroid[2] - z) / (volume - 1), - }; - - double norm = Math.sqrt(expected[0] * expected[0] + expected[1] * expected[1] + expected[2] * expected[2]); - + + double[] expected = + new double[] { + (centroid[0] - x) / (volume - 1), + (centroid[1] - y) / (volume - 1), + (centroid[2] - z) / (volume - 1), + }; + + double norm = + Math.sqrt( + expected[0] * expected[0] + + expected[1] * expected[1] + + expected[2] * expected[2]); + expected[0] /= norm; expected[1] /= norm; expected[2] /= norm; - + assertArrayEquals(expected, phc.displacement, EPSILON); } - + @Test public void getDisplacement_voxelAddedRegion_returnsVector() { PottsLocation location = mock(PottsLocation.class); int volume = randomIntBetween(10, 100); - double[] centroid = new double[] { - randomDoubleBetween(1, 100), - randomDoubleBetween(1, 100), - randomDoubleBetween(1, 100), - }; - + double[] centroid = + new double[] { + randomDoubleBetween(1, 100), + randomDoubleBetween(1, 100), + randomDoubleBetween(1, 100), + }; + Region region = Region.NUCLEUS; doReturn((double) volume).when(location).getVolume(region); doReturn(centroid).when(location).getCentroid(region); - - PersistenceHamiltonianConfig phc = new PersistenceHamiltonianConfig(location, 0, null, 0, 0); - - double[] displacement = new double[] { - randomDoubleBetween(1, 10), - randomDoubleBetween(1, 10), - randomDoubleBetween(1, 10), - }; - + + PersistenceHamiltonianConfig phc = + new PersistenceHamiltonianConfig(location, 0, null, 0, 0); + + double[] displacement = + new double[] { + randomDoubleBetween(1, 10), + randomDoubleBetween(1, 10), + randomDoubleBetween(1, 10), + }; + phc.displacement[0] = displacement[0]; phc.displacement[1] = displacement[1]; phc.displacement[2] = displacement[2]; - + int x = randomIntBetween(1, 10); int y = randomIntBetween(1, 10); int z = randomIntBetween(1, 10); - + double[] regionDisplacement = phc.getDisplacement(x, y, z, 1, region); - - double[] expected = new double[] { - (x - centroid[0]) / (volume + 1), - (y - centroid[1]) / (volume + 1), - (z - centroid[2]) / (volume + 1), - }; - - double norm = Math.sqrt(expected[0] * expected[0] + expected[1] * expected[1] + expected[2] * expected[2]); - + + double[] expected = + new double[] { + (x - centroid[0]) / (volume + 1), + (y - centroid[1]) / (volume + 1), + (z - centroid[2]) / (volume + 1), + }; + + double norm = + Math.sqrt( + expected[0] * expected[0] + + expected[1] * expected[1] + + expected[2] * expected[2]); + expected[0] /= norm; expected[1] /= norm; expected[2] /= norm; - + assertArrayEquals(expected, regionDisplacement, EPSILON); assertArrayEquals(displacement, phc.displacement, EPSILON); } - + @Test public void getDisplacement_voxelRemovedRegion_returnsVector() { PottsLocation location = mock(PottsLocation.class); int volume = randomIntBetween(10, 100); - double[] centroid = new double[] { - randomDoubleBetween(1, 100), - randomDoubleBetween(1, 100), - randomDoubleBetween(1, 100), - }; - + double[] centroid = + new double[] { + randomDoubleBetween(1, 100), + randomDoubleBetween(1, 100), + randomDoubleBetween(1, 100), + }; + Region region = Region.NUCLEUS; doReturn((double) volume).when(location).getVolume(region); doReturn(centroid).when(location).getCentroid(region); - - PersistenceHamiltonianConfig phc = new PersistenceHamiltonianConfig(location, 0, null, 0, 0); - - double[] displacement = new double[] { - randomDoubleBetween(1, 10), - randomDoubleBetween(1, 10), - randomDoubleBetween(1, 10), - }; - + + PersistenceHamiltonianConfig phc = + new PersistenceHamiltonianConfig(location, 0, null, 0, 0); + + double[] displacement = + new double[] { + randomDoubleBetween(1, 10), + randomDoubleBetween(1, 10), + randomDoubleBetween(1, 10), + }; + phc.displacement[0] = displacement[0]; phc.displacement[1] = displacement[1]; phc.displacement[2] = displacement[2]; - + int x = randomIntBetween(1, 10); int y = randomIntBetween(1, 10); int z = randomIntBetween(1, 10); - + double[] regionDisplacement = phc.getDisplacement(x, y, z, -1, region); - - double[] expected = new double[] { - (centroid[0] - x) / (volume - 1), - (centroid[1] - y) / (volume - 1), - (centroid[2] - z) / (volume - 1), - }; - - double norm = Math.sqrt(expected[0] * expected[0] + expected[1] * expected[1] + expected[2] * expected[2]); - + + double[] expected = + new double[] { + (centroid[0] - x) / (volume - 1), + (centroid[1] - y) / (volume - 1), + (centroid[2] - z) / (volume - 1), + }; + + double norm = + Math.sqrt( + expected[0] * expected[0] + + expected[1] * expected[1] + + expected[2] * expected[2]); + expected[0] /= norm; expected[1] /= norm; expected[2] /= norm; - + assertArrayEquals(expected, regionDisplacement, EPSILON); assertArrayEquals(displacement, phc.displacement, EPSILON); } diff --git a/test/arcade/potts/sim/hamiltonian/PersistenceHamiltonianTest.java b/test/arcade/potts/sim/hamiltonian/PersistenceHamiltonianTest.java index a231cef05..b6253ca41 100644 --- a/test/arcade/potts/sim/hamiltonian/PersistenceHamiltonianTest.java +++ b/test/arcade/potts/sim/hamiltonian/PersistenceHamiltonianTest.java @@ -3,13 +3,13 @@ import java.lang.reflect.Field; import java.util.EnumMap; import java.util.HashMap; -import org.junit.Test; +import org.junit.jupiter.api.Test; import arcade.core.util.Matrix; import arcade.core.util.MiniBox; import arcade.potts.agent.cell.PottsCell; import arcade.potts.env.location.PottsLocation; import arcade.potts.sim.PottsSeries; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.core.ARCADETestUtilities.*; import static arcade.core.util.MiniBox.TAG_SEPARATOR; @@ -18,7 +18,7 @@ public class PersistenceHamiltonianTest { private static final double EPSILON = 1E-10; - + @Test public void constructor_called_initializesMaps() { PersistenceHamiltonian ph = new PersistenceHamiltonian(mock(PottsSeries.class)); @@ -27,20 +27,20 @@ public void constructor_called_initializesMaps() { assertNotNull(ph.popToDecay); assertNotNull(ph.popToLambdasRegion); } - + @Test public void constructor_called_initializesParameters() { PottsSeries series = mock(PottsSeries.class); - + series.potts = new MiniBox(); series.populations = new HashMap<>(); - + String key1 = randomString(); int code1 = randomIntBetween(1, 10); MiniBox population1 = new MiniBox(); population1.put("CODE", code1); series.populations.put(key1, population1); - + String key2 = randomString(); int code2 = code1 + randomIntBetween(1, 10); MiniBox population2 = new MiniBox(); @@ -48,30 +48,34 @@ public void constructor_called_initializesParameters() { population2.put("(REGION)" + TAG_SEPARATOR + Region.DEFAULT.name(), 0); population2.put("(REGION)" + TAG_SEPARATOR + Region.NUCLEUS.name(), 0); series.populations.put(key2, population2); - + double lambda1 = randomDoubleBetween(1, 100); double lambda2 = randomDoubleBetween(1, 100); - + series.potts.put("persistence/LAMBDA" + TARGET_SEPARATOR + key1, lambda1); series.potts.put("persistence/LAMBDA" + TARGET_SEPARATOR + key2, lambda2); - + double decay1 = randomDoubleBetween(1, 100); double decay2 = randomDoubleBetween(1, 100); - + series.potts.put("persistence/DECAY" + TARGET_SEPARATOR + key1, decay1); series.potts.put("persistence/DECAY" + TARGET_SEPARATOR + key2, decay2); - + double volumeThreshold = randomDoubleBetween(1, 10); - + series.potts.put("persistence/VOLUME_THRESHOLD", volumeThreshold); - + double lambdaNucleus = randomDoubleBetween(1, 100); double lambdaDefault = randomDoubleBetween(1, 100); - series.potts.put("persistence/LAMBDA_" + Region.DEFAULT.name() + TARGET_SEPARATOR + key2, lambdaDefault); - series.potts.put("persistence/LAMBDA_" + Region.NUCLEUS.name() + TARGET_SEPARATOR + key2, lambdaNucleus); - + series.potts.put( + "persistence/LAMBDA_" + Region.DEFAULT.name() + TARGET_SEPARATOR + key2, + lambdaDefault); + series.potts.put( + "persistence/LAMBDA_" + Region.NUCLEUS.name() + TARGET_SEPARATOR + key2, + lambdaNucleus); + PersistenceHamiltonian ph = new PersistenceHamiltonian(series); - + assertEquals(2, ph.popToLambda.size()); assertTrue(ph.popToLambda.containsKey(code1)); assertTrue(ph.popToLambda.containsKey(code2)); @@ -85,69 +89,69 @@ public void constructor_called_initializesParameters() { assertEquals(lambdaDefault, ph.popToLambdasRegion.get(code2).get(Region.DEFAULT), EPSILON); assertEquals(lambdaNucleus, ph.popToLambdasRegion.get(code2).get(Region.NUCLEUS), EPSILON); } - + @Test public void register_noRegions_addsConfig() { PersistenceHamiltonian ph = new PersistenceHamiltonian(mock(PottsSeries.class)); PottsCell cell = mock(PottsCell.class); PottsLocation location = mock(PottsLocation.class); - + int id = randomIntBetween(1, 10); int pop = randomIntBetween(1, 10); - + doReturn(id).when(cell).getID(); doReturn(pop).when(cell).getPop(); doReturn(location).when(cell).getLocation(); - + double lambda = randomDoubleBetween(1, 100); ph.popToLambda.put(pop, lambda); - + double decay = randomDoubleBetween(1, 100); ph.popToDecay.put(pop, decay); - + double threshold = randomDoubleBetween(1, 100); ph.threshold = threshold; - + ph.register(cell); PersistenceHamiltonianConfig config = ph.configs.get(id); - + assertNotNull(config); assertEquals(location, config.location); assertEquals(lambda, config.getLambda(), EPSILON); assertEquals(decay, config.getDecay(), EPSILON); assertEquals(threshold, config.threshold, EPSILON); } - + @Test public void register_withRegions_addsConfig() { PersistenceHamiltonian ph = new PersistenceHamiltonian(mock(PottsSeries.class)); PottsCell cell = mock(PottsCell.class); PottsLocation location = mock(PottsLocation.class); - + int id = randomIntBetween(1, 10); int pop = randomIntBetween(1, 10); - + doReturn(id).when(cell).getID(); doReturn(pop).when(cell).getPop(); doReturn(location).when(cell).getLocation(); - + double lambda = randomDoubleBetween(1, 100); ph.popToLambda.put(pop, lambda); - + double lambdaNucleus = randomDoubleBetween(1, 100); EnumMap lambdasRegion = new EnumMap<>(Region.class); lambdasRegion.put(Region.NUCLEUS, lambdaNucleus); ph.popToLambdasRegion.put(pop, lambdasRegion); - + double decay = randomDoubleBetween(1, 100); ph.popToDecay.put(pop, decay); - + double threshold = randomDoubleBetween(1, 100); ph.threshold = threshold; - + ph.register(cell); PersistenceHamiltonianConfig config = ph.configs.get(id); - + assertNotNull(config); assertEquals(location, config.location); assertEquals(lambda, config.getLambda(), EPSILON); @@ -155,256 +159,277 @@ public void register_withRegions_addsConfig() { assertEquals(decay, config.getDecay(), EPSILON); assertEquals(threshold, config.threshold, EPSILON); } - + @Test public void deregister_exists_removesConfig() { PersistenceHamiltonian ph = new PersistenceHamiltonian(mock(PottsSeries.class)); PottsCell cell = mock(PottsCell.class); - + int id = randomIntBetween(1, 10); doReturn(id).when(cell).getID(); - + PersistenceHamiltonianConfig config = mock(PersistenceHamiltonianConfig.class); ph.configs.put(id, config); - + ph.deregister(cell); - + assertFalse(ph.configs.containsKey(id)); } - + @Test public void getDelta_validIDs_calculatesValue() { PersistenceHamiltonian ph = spy(new PersistenceHamiltonian(mock(PottsSeries.class))); int id1 = randomIntBetween(1, 100); int id2 = id1 + randomIntBetween(1, 10); - + double persistence1minus = randomDoubleBetween(10, 100); doReturn(persistence1minus).when(ph).getPersistence(id1, 0, 0, 0, -1); - + double persistence1plus = randomDoubleBetween(10, 100); doReturn(persistence1plus).when(ph).getPersistence(id1, 0, 0, 0, 1); - + double persistence2minus = randomDoubleBetween(10, 100); doReturn(persistence2minus).when(ph).getPersistence(id2, 0, 0, 0, -1); - + double persistence2plus = randomDoubleBetween(10, 100); doReturn(persistence2plus).when(ph).getPersistence(id2, 0, 0, 0, 1); - + assertEquals(persistence1minus + persistence2plus, ph.getDelta(id1, id2, 0, 0, 0), EPSILON); assertEquals(persistence2minus + persistence1plus, ph.getDelta(id2, id1, 0, 0, 0), EPSILON); } - + @Test public void getDelta_validRegions_returnsZero() { PersistenceHamiltonian ph = spy(new PersistenceHamiltonian(mock(PottsSeries.class))); int id = randomIntBetween(1, 100); int region1 = Region.DEFAULT.ordinal(); int region2 = Region.NUCLEUS.ordinal(); - + double persistence1minus = randomDoubleBetween(10, 100); doReturn(persistence1minus).when(ph).getPersistence(id, region1, 0, 0, 0, -1); - + double persistence1plus = randomDoubleBetween(10, 100); doReturn(persistence1plus).when(ph).getPersistence(id, region1, 0, 0, 0, 1); - + double persistence2minus = randomDoubleBetween(10, 100); doReturn(persistence2minus).when(ph).getPersistence(id, region2, 0, 0, 0, -1); - + double persistence2plus = randomDoubleBetween(10, 100); doReturn(persistence2plus).when(ph).getPersistence(id, region2, 0, 0, 0, 1); - - assertEquals(persistence1minus + persistence2plus, ph.getDelta(id, region1, region2, 0, 0, 0), EPSILON); - assertEquals(persistence2minus + persistence1plus, ph.getDelta(id, region2, region1, 0, 0, 0), EPSILON); + + assertEquals( + persistence1minus + persistence2plus, + ph.getDelta(id, region1, region2, 0, 0, 0), + EPSILON); + assertEquals( + persistence2minus + persistence1plus, + ph.getDelta(id, region2, region1, 0, 0, 0), + EPSILON); } - + @Test public void getPersistence_validID_updatesVector() { PersistenceHamiltonian ph = new PersistenceHamiltonian(mock(PottsSeries.class)); int id = randomIntBetween(1, 100); - + PottsLocation location = mock(PottsLocation.class); int surface = randomIntBetween(1, 100); doReturn((double) surface).when(location).getSurface(); int volume = randomIntBetween(1, 100); doReturn((double) volume).when(location).getVolume(); - - PersistenceHamiltonianConfig config = spy(new PersistenceHamiltonianConfig( - location, 0, null, 1, 1)); - + + PersistenceHamiltonianConfig config = + spy(new PersistenceHamiltonianConfig(location, 0, null, 1, 1)); + try { Field volumeField = PersistenceHamiltonianConfig.class.getDeclaredField("volumeCheck"); volumeField.setAccessible(true); volumeField.set(config, volume + 1); - } catch (Exception ignored) { } - + } catch (Exception ignored) { + } + config.vector[0] = randomDoubleBetween(1, 10); config.vector[1] = randomDoubleBetween(1, 10); config.vector[2] = randomDoubleBetween(1, 10); - - double[] initialDisplacement = new double[] { - randomDoubleBetween(1, 10), - randomDoubleBetween(1, 10), - randomDoubleBetween(1, 10), - }; - + + double[] initialDisplacement = + new double[] { + randomDoubleBetween(1, 10), + randomDoubleBetween(1, 10), + randomDoubleBetween(1, 10), + }; + config.displacement[0] = initialDisplacement[0]; config.displacement[1] = initialDisplacement[1]; config.displacement[2] = initialDisplacement[2]; - - double[] finalDisplacement = new double[] { - randomDoubleBetween(1, 10), - randomDoubleBetween(1, 10), - randomDoubleBetween(1, 10), - }; - - doAnswer(invocation -> { - config.displacement[0] = finalDisplacement[0]; - config.displacement[1] = finalDisplacement[1]; - config.displacement[2] = finalDisplacement[2]; - return finalDisplacement; - }).when(config).getDisplacement(0, 0, 0, 0); + + double[] finalDisplacement = + new double[] { + randomDoubleBetween(1, 10), + randomDoubleBetween(1, 10), + randomDoubleBetween(1, 10), + }; + + doAnswer( + invocation -> { + config.displacement[0] = finalDisplacement[0]; + config.displacement[1] = finalDisplacement[1]; + config.displacement[2] = finalDisplacement[2]; + return finalDisplacement; + }) + .when(config) + .getDisplacement(0, 0, 0, 0); ph.configs.put(id, config); - + ph.getPersistence(id, 0, 0, 0, 0); - - double[] expected = new double[] { - initialDisplacement[0], - initialDisplacement[1], - -volume, - }; + + double[] expected = + new double[] { + initialDisplacement[0], initialDisplacement[1], -volume, + }; Matrix.unit(expected); - + assertEquals(expected[0], config.vector[0], EPSILON); assertEquals(expected[1], config.vector[1], EPSILON); assertEquals(expected[2], config.vector[2], EPSILON); } - + @Test public void getPersistence_validID_returnsValue() { PersistenceHamiltonian ph = new PersistenceHamiltonian(mock(PottsSeries.class)); int id = randomIntBetween(1, 100); - + PottsLocation location = mock(PottsLocation.class); int surface = randomIntBetween(1, 100); doReturn((double) surface).when(location).getSurface(); - + PersistenceHamiltonianConfig config = mock(PersistenceHamiltonianConfig.class); - + try { Field locationField = PersistenceHamiltonianConfig.class.getDeclaredField("location"); locationField.setAccessible(true); locationField.set(config, location); - } catch (Exception ignored) { } - - double[] vector1 = new double[] { - randomDoubleBetween(1, 10), - randomDoubleBetween(1, 10), - randomDoubleBetween(1, 10), - }; - - double[] vector2 = new double[] { - randomDoubleBetween(1, 10), - randomDoubleBetween(1, 10), - randomDoubleBetween(1, 10), - }; - + } catch (Exception ignored) { + } + + double[] vector1 = + new double[] { + randomDoubleBetween(1, 10), + randomDoubleBetween(1, 10), + randomDoubleBetween(1, 10), + }; + + double[] vector2 = + new double[] { + randomDoubleBetween(1, 10), + randomDoubleBetween(1, 10), + randomDoubleBetween(1, 10), + }; + int x = randomIntBetween(1, 10); int y = randomIntBetween(1, 10); int z = randomIntBetween(1, 10); int change = randomIntBetween(1, 10); - + doReturn(vector1).when(config).getVector(); doReturn(vector2).when(config).getDisplacement(x, y, z, change); - + double lambda = randomDoubleBetween(1, 100); doReturn(lambda).when(config).getLambda(); - + ph.configs.put(id, config); - + double dot = vector1[0] * vector2[0] + vector1[1] * vector2[1] + vector1[2] * vector2[2]; double expected = -lambda * dot * surface; - + assertEquals(expected, ph.getPersistence(id, x, y, z, change), EPSILON); } - + @Test public void getPersistence_validRegions_returnsValue() { PersistenceHamiltonian ph = new PersistenceHamiltonian(mock(PottsSeries.class)); int id = randomIntBetween(1, 100); - + PottsLocation location = mock(PottsLocation.class); Region region = Region.NUCLEUS; int surface = randomIntBetween(1, 100); doReturn((double) surface).when(location).getSurface(region); - + PersistenceHamiltonianConfig config = mock(PersistenceHamiltonianConfig.class); - - double[] vector = new double[] { - randomDoubleBetween(1, 10), - randomDoubleBetween(1, 10), - randomDoubleBetween(1, 10), - }; - - double[] displacement = new double[] { - randomDoubleBetween(1, 10), - randomDoubleBetween(1, 10), - randomDoubleBetween(1, 10), - }; - + + double[] vector = + new double[] { + randomDoubleBetween(1, 10), + randomDoubleBetween(1, 10), + randomDoubleBetween(1, 10), + }; + + double[] displacement = + new double[] { + randomDoubleBetween(1, 10), + randomDoubleBetween(1, 10), + randomDoubleBetween(1, 10), + }; + try { Field locationField = PersistenceHamiltonianConfig.class.getDeclaredField("location"); locationField.setAccessible(true); locationField.set(config, location); - + Field vectorField = PersistenceHamiltonianConfig.class.getDeclaredField("vector"); vectorField.setAccessible(true); vectorField.set(config, vector); - - Field displacementField = PersistenceHamiltonianConfig.class.getDeclaredField("displacement"); + + Field displacementField = + PersistenceHamiltonianConfig.class.getDeclaredField("displacement"); displacementField.setAccessible(true); displacementField.set(config, displacement); - } catch (Exception ignored) { } - - double[] vector1 = new double[] { - randomDoubleBetween(1, 10), - randomDoubleBetween(1, 10), - randomDoubleBetween(1, 10), - }; - - double[] vector2 = new double[] { - randomDoubleBetween(1, 10), - randomDoubleBetween(1, 10), - randomDoubleBetween(1, 10), - }; - - double[] vector3 = new double[] { - randomDoubleBetween(1, 10), - randomDoubleBetween(1, 10), - randomDoubleBetween(1, 10), - }; - + } catch (Exception ignored) { + } + + double[] vector1 = + new double[] { + randomDoubleBetween(1, 10), + randomDoubleBetween(1, 10), + randomDoubleBetween(1, 10), + }; + + double[] vector2 = + new double[] { + randomDoubleBetween(1, 10), + randomDoubleBetween(1, 10), + randomDoubleBetween(1, 10), + }; + + double[] vector3 = + new double[] { + randomDoubleBetween(1, 10), + randomDoubleBetween(1, 10), + randomDoubleBetween(1, 10), + }; + int x = randomIntBetween(1, 10); int y = randomIntBetween(1, 10); int z = randomIntBetween(1, 10); int change = randomIntBetween(1, 10); - + doReturn(vector1).when(config).getVector(); doReturn(vector2).when(config).getDisplacement(x, y, z, change); doReturn(vector3).when(config).getDisplacement(x, y, z, change, region); - + double lambda = randomDoubleBetween(1, 100); doReturn(lambda).when(config).getLambda(region); - + ph.configs.put(id, config); - + double dot = vector3[0] * vector[0] + vector3[1] * vector[1] + vector3[2] * vector[2]; double expected = -lambda * dot * surface; - + assertEquals(expected, ph.getPersistence(id, region.ordinal(), x, y, z, change), EPSILON); assertArrayEquals(vector, config.vector, EPSILON); assertArrayEquals(displacement, config.displacement, EPSILON); } - + @Test public void getPersistence_defaultRegion_returnsZero() { PersistenceHamiltonian ph = new PersistenceHamiltonian(mock(PottsSeries.class)); @@ -414,7 +439,7 @@ public void getPersistence_defaultRegion_returnsZero() { assertEquals(0, ph.getPersistence(id, Region.DEFAULT.ordinal(), 1, 1, 1, 1), EPSILON); assertEquals(0, ph.getPersistence(id, Region.DEFAULT.ordinal(), 1, 1, 1, -1), EPSILON); } - + @Test public void getPersistence_invalidID_returnsZero() { PersistenceHamiltonian ph = new PersistenceHamiltonian(mock(PottsSeries.class)); diff --git a/test/arcade/potts/sim/hamiltonian/SubstrateHamiltonianConfigTest.java b/test/arcade/potts/sim/hamiltonian/SubstrateHamiltonianConfigTest.java index 208b776e3..4a4ffc411 100644 --- a/test/arcade/potts/sim/hamiltonian/SubstrateHamiltonianConfigTest.java +++ b/test/arcade/potts/sim/hamiltonian/SubstrateHamiltonianConfigTest.java @@ -1,12 +1,12 @@ package arcade.potts.sim.hamiltonian; -import org.junit.Test; -import static org.junit.Assert.*; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; import static arcade.core.ARCADETestUtilities.*; public class SubstrateHamiltonianConfigTest { private static final double EPSILON = 1E-10; - + @Test public void getSubstrate_called_returnsValue() { double substrate = randomDoubleBetween(1, 100); diff --git a/test/arcade/potts/sim/hamiltonian/SubstrateHamiltonianTest.java b/test/arcade/potts/sim/hamiltonian/SubstrateHamiltonianTest.java index 0ad00903a..2eb79abcf 100644 --- a/test/arcade/potts/sim/hamiltonian/SubstrateHamiltonianTest.java +++ b/test/arcade/potts/sim/hamiltonian/SubstrateHamiltonianTest.java @@ -3,12 +3,12 @@ import java.lang.reflect.Field; import java.util.Arrays; import java.util.HashMap; -import org.junit.Test; +import org.junit.jupiter.api.Test; import arcade.core.util.MiniBox; import arcade.potts.agent.cell.PottsCell; import arcade.potts.sim.Potts; import arcade.potts.sim.PottsSeries; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.core.ARCADETestUtilities.*; import static arcade.potts.sim.PottsSeries.TARGET_SEPARATOR; @@ -16,73 +16,76 @@ public class SubstrateHamiltonianTest { private static final double EPSILON = 1E-5; - + @Test public void constructor_called_initializesMaps() { - SubstrateHamiltonian sh = new SubstrateHamiltonian(mock(PottsSeries.class), mock(Potts.class)); + SubstrateHamiltonian sh = + new SubstrateHamiltonian(mock(PottsSeries.class), mock(Potts.class)); assertNotNull(sh.configs); assertNotNull(sh.popToSubstrate); } - + @Test public void constructor_called_createsArray() { int length = randomIntBetween(10, 100); int width = randomIntBetween(10, 100); Potts potts = mock(Potts.class); - + try { Field lengthField = Potts.class.getDeclaredField("length"); lengthField.setAccessible(true); lengthField.setInt(potts, length); - + Field widthField = Potts.class.getDeclaredField("width"); widthField.setAccessible(true); widthField.setInt(potts, width); - } catch (Exception ignored) { } - + } catch (Exception ignored) { + } + SubstrateHamiltonian sh = new SubstrateHamiltonian(mock(PottsSeries.class), potts); - + assertEquals(length + 2, sh.substrates.length); assertEquals(width + 2, sh.substrates[0].length); - + for (int[] row : sh.substrates) { int[] unique = Arrays.stream(row).distinct().toArray(); - assertArrayEquals(new int[] { 1 }, unique); + assertArrayEquals(new int[] {1}, unique); } } - + @Test public void constructor_called_initializesParameters() { PottsSeries series = mock(PottsSeries.class); - + series.potts = new MiniBox(); series.populations = new HashMap<>(); - + String key1 = randomString(); int code1 = randomIntBetween(1, 10); MiniBox population1 = new MiniBox(); population1.put("CODE", code1); series.populations.put(key1, population1); - + String key2 = randomString(); int code2 = code1 + randomIntBetween(1, 10); MiniBox population2 = new MiniBox(); population2.put("CODE", code2); series.populations.put(key2, population2); - + double substrate1 = randomDoubleBetween(1, 100); double substrate2 = randomDoubleBetween(1, 100); - + series.potts.put("substrate/ADHESION" + TARGET_SEPARATOR + key1, substrate1); series.potts.put("substrate/ADHESION" + TARGET_SEPARATOR + key2, substrate2); - + double power = randomDoubleBetween(1, 10); - double heightThreshold = Math.exp(Math.log(SubstrateHamiltonian.THRESHOLD_FRACTION) / power); - + double heightThreshold = + Math.exp(Math.log(SubstrateHamiltonian.THRESHOLD_FRACTION) / power); + series.potts.put("substrate/HEIGHT_THRESHOLD", heightThreshold); - + SubstrateHamiltonian sh = new SubstrateHamiltonian(series, mock(Potts.class)); - + assertEquals(2, sh.popToSubstrate.size()); assertTrue(sh.popToSubstrate.containsKey(code1)); assertTrue(sh.popToSubstrate.containsKey(code2)); @@ -90,107 +93,116 @@ public void constructor_called_initializesParameters() { assertEquals(substrate2, sh.popToSubstrate.get(code2), EPSILON); assertEquals(power, sh.power, EPSILON); } - + @Test public void register_givenCell_addsConfig() { - SubstrateHamiltonian sh = new SubstrateHamiltonian(mock(PottsSeries.class), mock(Potts.class)); + SubstrateHamiltonian sh = + new SubstrateHamiltonian(mock(PottsSeries.class), mock(Potts.class)); PottsCell cell = mock(PottsCell.class); - + int id = randomIntBetween(1, 10); int pop = randomIntBetween(1, 10); - + doReturn(id).when(cell).getID(); doReturn(pop).when(cell).getPop(); - + double substrate = randomDoubleBetween(1, 100); sh.popToSubstrate.put(pop, substrate); - + sh.register(cell); SubstrateHamiltonianConfig config = sh.configs.get(id); - + assertNotNull(config); assertEquals(substrate, config.getSubstrate(), EPSILON); } - + @Test public void deregister_exists_removesConfig() { - SubstrateHamiltonian sh = new SubstrateHamiltonian(mock(PottsSeries.class), mock(Potts.class)); + SubstrateHamiltonian sh = + new SubstrateHamiltonian(mock(PottsSeries.class), mock(Potts.class)); PottsCell cell = mock(PottsCell.class); - + int id = randomIntBetween(1, 10); doReturn(id).when(cell).getID(); - + SubstrateHamiltonianConfig config = mock(SubstrateHamiltonianConfig.class); sh.configs.put(id, config); - + sh.deregister(cell); - + assertFalse(sh.configs.containsKey(id)); } - + @Test public void getDelta_validIDs_calculatesValue() { - SubstrateHamiltonian sh = spy(new SubstrateHamiltonian(mock(PottsSeries.class), mock(Potts.class))); + SubstrateHamiltonian sh = + spy(new SubstrateHamiltonian(mock(PottsSeries.class), mock(Potts.class))); int id1 = randomIntBetween(1, 100); int id2 = id1 + randomIntBetween(1, 10); - + double substrate1 = randomDoubleBetween(10, 100); doReturn(substrate1).when(sh).getSubstrate(id1, 0, 0, 0); - + double substrate2 = randomDoubleBetween(10, 100); doReturn(substrate2).when(sh).getSubstrate(id2, 0, 0, 0); - + assertEquals(substrate2 - substrate1, sh.getDelta(id1, id2, 0, 0, 0), EPSILON); assertEquals(substrate1 - substrate2, sh.getDelta(id2, id1, 0, 0, 0), EPSILON); } - + @Test public void getDelta_validRegions_returnsZero() { - SubstrateHamiltonian sh = new SubstrateHamiltonian(mock(PottsSeries.class), mock(Potts.class)); + SubstrateHamiltonian sh = + new SubstrateHamiltonian(mock(PottsSeries.class), mock(Potts.class)); int id = randomIntBetween(1, 100); - - double delta1 = sh.getDelta(id, Region.DEFAULT.ordinal(), Region.NUCLEUS.ordinal(), 0, 0, 0); + + double delta1 = + sh.getDelta(id, Region.DEFAULT.ordinal(), Region.NUCLEUS.ordinal(), 0, 0, 0); assertEquals(0, delta1, EPSILON); - - double delta2 = sh.getDelta(id, Region.NUCLEUS.ordinal(), Region.DEFAULT.ordinal(), 0, 0, 0); + + double delta2 = + sh.getDelta(id, Region.NUCLEUS.ordinal(), Region.DEFAULT.ordinal(), 0, 0, 0); assertEquals(0, delta2, EPSILON); } - + @Test public void getSubstrate_validID_returnsValue() { Potts potts = mock(Potts.class); int id = randomIntBetween(1, 100); - + try { Field lengthField = Potts.class.getDeclaredField("length"); lengthField.setAccessible(true); lengthField.setInt(potts, 3); - + Field widthField = Potts.class.getDeclaredField("width"); widthField.setAccessible(true); widthField.setInt(potts, 3); - } catch (Exception ignored) { } - + } catch (Exception ignored) { + } + double power = randomDoubleBetween(1, 5); - + SubstrateHamiltonian sh = new SubstrateHamiltonian(mock(PottsSeries.class), potts); sh.power = power; - + SubstrateHamiltonianConfig config = mock(SubstrateHamiltonianConfig.class); double substrate = randomDoubleBetween(10, 20); doReturn(substrate).when(config).getSubstrate(); - + sh.configs.put(id, config); - + double scale = -9. / SubstrateHamiltonian.NUMBER_NEIGHBORS; assertEquals(scale * substrate, sh.getSubstrate(id, 1, 1, 1), EPSILON); assertEquals(scale * substrate * Math.pow(2, power), sh.getSubstrate(id, 1, 1, 2), EPSILON); - assertEquals(scale * substrate * Math.pow(10, power), sh.getSubstrate(id, 1, 1, 10), EPSILON); + assertEquals( + scale * substrate * Math.pow(10, power), sh.getSubstrate(id, 1, 1, 10), EPSILON); } - + @Test public void getSubstrate_invalidID_returnsZero() { - SubstrateHamiltonian sh = new SubstrateHamiltonian(mock(PottsSeries.class), mock(Potts.class)); + SubstrateHamiltonian sh = + new SubstrateHamiltonian(mock(PottsSeries.class), mock(Potts.class)); assertEquals(0, sh.getSubstrate(0, 1, 1, 1), EPSILON); assertEquals(0, sh.getSubstrate(-1, 1, 1, 1), EPSILON); } diff --git a/test/arcade/potts/sim/hamiltonian/SurfaceHamiltonian2DTest.java b/test/arcade/potts/sim/hamiltonian/SurfaceHamiltonian2DTest.java index 9420ecb95..4fab89830 100644 --- a/test/arcade/potts/sim/hamiltonian/SurfaceHamiltonian2DTest.java +++ b/test/arcade/potts/sim/hamiltonian/SurfaceHamiltonian2DTest.java @@ -1,61 +1,65 @@ package arcade.potts.sim.hamiltonian; -import org.junit.Test; +import org.junit.jupiter.api.Test; import arcade.potts.sim.Potts; import arcade.potts.sim.PottsSeries; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.potts.util.PottsEnums.Region; public class SurfaceHamiltonian2DTest { static final int REGION_DEFAULT = Region.DEFAULT.ordinal(); - + static final int REGION_NUCLEUS = Region.NUCLEUS.ordinal(); - + static Potts makePottsMock() { Potts potts = mock(Potts.class); - - potts.ids = new int[][][] { - { - { 0, 0, 0, 0, 0, 0 }, - { 0, 1, 1, 3, 3, 0 }, - { 0, 1, 1, 3, 3, 0 }, - { 0, 2, 2, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - } - }; - + + potts.ids = + new int[][][] { + { + {0, 0, 0, 0, 0, 0}, + {0, 1, 1, 3, 3, 0}, + {0, 1, 1, 3, 3, 0}, + {0, 2, 2, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + } + }; + int d = REGION_DEFAULT; int n = REGION_NUCLEUS; - - potts.regions = new int[][][] { - { - { 0, 0, 0, 0, 0, 0 }, - { 0, d, d, d, 0, 0 }, - { 0, 0, n, n, 0, 0 }, - { 0, d, d, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - } - }; - + + potts.regions = + new int[][][] { + { + {0, 0, 0, 0, 0, 0}, + {0, d, d, d, 0, 0}, + {0, 0, n, n, 0, 0}, + {0, d, d, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + } + }; + return potts; } - + @Test public void calculateChange_validIDs_calculatesValue() { Potts potts = makePottsMock(); SurfaceHamiltonian2D sh = new SurfaceHamiltonian2D(mock(PottsSeries.class), potts); - - assertArrayEquals(new int[] { 0, 2 }, sh.calculateChange(1, 2, 2, 2, 0)); - assertArrayEquals(new int[] { 0, 2 }, sh.calculateChange(1, 3, 2, 2, 0)); + + assertArrayEquals(new int[] {0, 2}, sh.calculateChange(1, 2, 2, 2, 0)); + assertArrayEquals(new int[] {0, 2}, sh.calculateChange(1, 3, 2, 2, 0)); } - + @Test public void calculateChange_validRegions_calculatesValue() { Potts potts = makePottsMock(); SurfaceHamiltonian2D sh = new SurfaceHamiltonian2D(mock(PottsSeries.class), potts); - - assertArrayEquals(new int[] { -4, 2 }, sh.calculateChange(1, REGION_NUCLEUS, REGION_DEFAULT, 2, 2, 0)); - assertArrayEquals(new int[] { -2, 2 }, sh.calculateChange(1, REGION_DEFAULT, REGION_NUCLEUS, 2, 1, 0)); + + assertArrayEquals( + new int[] {-4, 2}, sh.calculateChange(1, REGION_NUCLEUS, REGION_DEFAULT, 2, 2, 0)); + assertArrayEquals( + new int[] {-2, 2}, sh.calculateChange(1, REGION_DEFAULT, REGION_NUCLEUS, 2, 1, 0)); } } diff --git a/test/arcade/potts/sim/hamiltonian/SurfaceHamiltonian3DTest.java b/test/arcade/potts/sim/hamiltonian/SurfaceHamiltonian3DTest.java index cbe5011d4..bb9874265 100644 --- a/test/arcade/potts/sim/hamiltonian/SurfaceHamiltonian3DTest.java +++ b/test/arcade/potts/sim/hamiltonian/SurfaceHamiltonian3DTest.java @@ -1,117 +1,121 @@ package arcade.potts.sim.hamiltonian; -import org.junit.Test; +import org.junit.jupiter.api.Test; import arcade.potts.sim.Potts; import arcade.potts.sim.PottsSeries; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.potts.util.PottsEnums.Region; public class SurfaceHamiltonian3DTest { static final int REGION_DEFAULT = Region.DEFAULT.ordinal(); - + static final int REGION_NUCLEUS = Region.NUCLEUS.ordinal(); - + static Potts makePottsMock() { Potts potts = mock(Potts.class); - - potts.ids = new int[][][] { - { - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - }, - { - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 0, 3, 0 }, - { 0, 0, 1, 3, 3, 0 }, - { 0, 2, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - }, - { - { 0, 0, 0, 0, 0, 0 }, - { 0, 1, 1, 3, 3, 0 }, - { 0, 1, 1, 3, 3, 0 }, - { 0, 2, 2, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - }, - { - { 0, 0, 0, 0, 0, 0 }, - { 0, 1, 1, 0, 0, 0 }, - { 0, 1, 2, 0, 3, 0 }, - { 0, 2, 2, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - }, - { - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - }, - }; - + + potts.ids = + new int[][][] { + { + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + }, + { + {0, 0, 0, 0, 0, 0}, + {0, 0, 1, 0, 3, 0}, + {0, 0, 1, 3, 3, 0}, + {0, 2, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + }, + { + {0, 0, 0, 0, 0, 0}, + {0, 1, 1, 3, 3, 0}, + {0, 1, 1, 3, 3, 0}, + {0, 2, 2, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + }, + { + {0, 0, 0, 0, 0, 0}, + {0, 1, 1, 0, 0, 0}, + {0, 1, 2, 0, 3, 0}, + {0, 2, 2, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + }, + { + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + }, + }; + int d = REGION_DEFAULT; int n = REGION_NUCLEUS; - - potts.regions = new int[][][] { - { - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - }, - { - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, d, 0, d, 0 }, - { 0, 0, d, d, d, 0 }, - { 0, d, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - }, - { - { 0, 0, 0, 0, 0, 0 }, - { 0, d, d, d, 0, 0 }, - { 0, 0, n, n, 0, 0 }, - { 0, d, d, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - }, - { - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, d, 0, 0, 0 }, - { 0, 0, n, 0, d, 0 }, - { 0, d, d, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - }, - { - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0 }, - }, - }; - + + potts.regions = + new int[][][] { + { + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + }, + { + {0, 0, 0, 0, 0, 0}, + {0, 0, d, 0, d, 0}, + {0, 0, d, d, d, 0}, + {0, d, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + }, + { + {0, 0, 0, 0, 0, 0}, + {0, d, d, d, 0, 0}, + {0, 0, n, n, 0, 0}, + {0, d, d, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + }, + { + {0, 0, 0, 0, 0, 0}, + {0, 0, d, 0, 0, 0}, + {0, 0, n, 0, d, 0}, + {0, d, d, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + }, + { + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + }, + }; + return potts; } - + @Test public void calculateChange_validIDs_calculatesValue() { Potts potts = makePottsMock(); SurfaceHamiltonian3D sh = new SurfaceHamiltonian3D(mock(PottsSeries.class), potts); - - assertArrayEquals(new int[] { 0, 2 }, sh.calculateChange(1, 2, 2, 2, 2)); - assertArrayEquals(new int[] { 0, 4 }, sh.calculateChange(1, 3, 2, 2, 2)); + + assertArrayEquals(new int[] {0, 2}, sh.calculateChange(1, 2, 2, 2, 2)); + assertArrayEquals(new int[] {0, 4}, sh.calculateChange(1, 3, 2, 2, 2)); } - + @Test public void calculateChange_validRegions_calculatesValue() { Potts potts = makePottsMock(); SurfaceHamiltonian3D sh = new SurfaceHamiltonian3D(mock(PottsSeries.class), potts); - - assertArrayEquals(new int[] { -6, 2 }, sh.calculateChange(1, REGION_NUCLEUS, REGION_DEFAULT, 2, 2, 2)); - assertArrayEquals(new int[] { -4, 4 }, sh.calculateChange(1, REGION_DEFAULT, REGION_NUCLEUS, 2, 2, 1)); + + assertArrayEquals( + new int[] {-6, 2}, sh.calculateChange(1, REGION_NUCLEUS, REGION_DEFAULT, 2, 2, 2)); + assertArrayEquals( + new int[] {-4, 4}, sh.calculateChange(1, REGION_DEFAULT, REGION_NUCLEUS, 2, 2, 1)); } } diff --git a/test/arcade/potts/sim/hamiltonian/SurfaceHamiltonianConfigTest.java b/test/arcade/potts/sim/hamiltonian/SurfaceHamiltonianConfigTest.java index 3734a566b..691e62c83 100644 --- a/test/arcade/potts/sim/hamiltonian/SurfaceHamiltonianConfigTest.java +++ b/test/arcade/potts/sim/hamiltonian/SurfaceHamiltonianConfigTest.java @@ -1,81 +1,81 @@ package arcade.potts.sim.hamiltonian; import java.util.EnumMap; -import org.junit.Test; +import org.junit.jupiter.api.Test; import arcade.potts.agent.cell.PottsCell; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.core.ARCADETestUtilities.*; import static arcade.potts.util.PottsEnums.Region; public class SurfaceHamiltonianConfigTest { private static final double EPSILON = 1E-10; - + @Test public void constructor_noRegions_setsFields() { PottsCell cell = mock(PottsCell.class); - + SurfaceHamiltonianConfig shc = new SurfaceHamiltonianConfig(cell, 0, null); assertEquals(cell, shc.cell); assertFalse(shc.hasRegions); } - + @Test public void constructor_emptyRegions_setsFields() { PottsCell cell = mock(PottsCell.class); EnumMap lambdasRegion = new EnumMap<>(Region.class); - + SurfaceHamiltonianConfig shc = new SurfaceHamiltonianConfig(cell, 0, lambdasRegion); assertEquals(cell, shc.cell); assertFalse(shc.hasRegions); } - + @Test public void constructor_hasRegions_setsFields() { PottsCell cell = mock(PottsCell.class); EnumMap lambdasRegion = new EnumMap<>(Region.class); lambdasRegion.put(Region.UNDEFINED, randomDoubleBetween(1, 100)); - + SurfaceHamiltonianConfig shc = new SurfaceHamiltonianConfig(cell, 0, lambdasRegion); assertEquals(cell, shc.cell); assertTrue(shc.hasRegions); } - + @Test public void getLambda_noRegion_returnsValue() { double lambda = randomDoubleBetween(1, 100); SurfaceHamiltonianConfig shc = new SurfaceHamiltonianConfig(null, lambda, null); assertEquals(lambda, shc.getLambda(), EPSILON); } - + @Test public void getLambda_validRegions_returnsValue() { double lambda = randomDoubleBetween(1, 100); - + EnumMap lambdasRegion = new EnumMap<>(Region.class); lambdasRegion.put(Region.DEFAULT, randomDoubleBetween(0, 100)); lambdasRegion.put(Region.NUCLEUS, randomDoubleBetween(0, 100)); - + SurfaceHamiltonianConfig shc = new SurfaceHamiltonianConfig(null, lambda, lambdasRegion); - + assertEquals(lambdasRegion.get(Region.DEFAULT), shc.getLambda(Region.DEFAULT), EPSILON); assertEquals(lambdasRegion.get(Region.NUCLEUS), shc.getLambda(Region.NUCLEUS), EPSILON); } - + @Test public void getLambda_invalidRegions_returnsNaN() { double lambda = randomDoubleBetween(1, 100); - + EnumMap lambdasRegion = new EnumMap<>(Region.class); lambdasRegion.put(Region.DEFAULT, randomDoubleBetween(0, 100)); lambdasRegion.put(Region.NUCLEUS, randomDoubleBetween(0, 100)); - + SurfaceHamiltonianConfig shc = new SurfaceHamiltonianConfig(null, lambda, lambdasRegion); - + assertEquals(Double.NaN, shc.getLambda(null), EPSILON); assertEquals(Double.NaN, shc.getLambda(Region.UNDEFINED), EPSILON); } - + @Test public void getLambda_nullRegion_returnsNaN() { double lambda = randomDoubleBetween(1, 100); diff --git a/test/arcade/potts/sim/hamiltonian/SurfaceHamiltonianTest.java b/test/arcade/potts/sim/hamiltonian/SurfaceHamiltonianTest.java index 867728d48..f314dca8f 100644 --- a/test/arcade/potts/sim/hamiltonian/SurfaceHamiltonianTest.java +++ b/test/arcade/potts/sim/hamiltonian/SurfaceHamiltonianTest.java @@ -3,12 +3,12 @@ import java.lang.reflect.Field; import java.util.EnumMap; import java.util.HashMap; -import org.junit.Test; +import org.junit.jupiter.api.Test; import arcade.core.util.MiniBox; import arcade.potts.agent.cell.PottsCell; import arcade.potts.sim.Potts; import arcade.potts.sim.PottsSeries; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.core.ARCADETestUtilities.*; import static arcade.core.util.MiniBox.TAG_SEPARATOR; @@ -17,33 +17,36 @@ public class SurfaceHamiltonianTest { private static final double EPSILON = 1E-10; - + static class SurfaceHamiltonianMock extends SurfaceHamiltonian { - SurfaceHamiltonianMock(PottsSeries series, Potts potts) { super(series, potts); } - + SurfaceHamiltonianMock(PottsSeries series, Potts potts) { + super(series, potts); + } + @Override int[] calculateChange(int sourceID, int targetID, int x, int y, int z) { - return new int[] { (targetID > sourceID ? 1 : -1), (sourceID > targetID ? 1 : -1) }; + return new int[] {(targetID > sourceID ? 1 : -1), (sourceID > targetID ? 1 : -1)}; } - + @Override int[] calculateChange(int id, int sourceRegion, int targetRegion, int x, int y, int z) { if (sourceRegion == Region.DEFAULT.ordinal()) { - return new int[] { 2, 2 }; + return new int[] {2, 2}; } else { - return new int[] { -3, -3 }; + return new int[] {-3, -3}; } } } - + @Test public void constructor_called_initializesMaps() { - SurfaceHamiltonianMock shm = new SurfaceHamiltonianMock(mock(PottsSeries.class), mock(Potts.class)); + SurfaceHamiltonianMock shm = + new SurfaceHamiltonianMock(mock(PottsSeries.class), mock(Potts.class)); assertNotNull(shm.configs); assertNotNull(shm.popToLambda); assertNotNull(shm.popToLambdasRegion); } - + @Test public void constructor_called_setsArrays() { Potts potts = mock(Potts.class); @@ -51,26 +54,26 @@ public void constructor_called_setsArrays() { int[][][] regions = new int[0][0][0]; potts.ids = ids; potts.regions = regions; - + SurfaceHamiltonianMock shm = new SurfaceHamiltonianMock(mock(PottsSeries.class), potts); - + assertSame(ids, shm.ids); assertSame(regions, shm.regions); } - + @Test public void constructor_called_initializesParameters() { PottsSeries series = mock(PottsSeries.class); - + series.potts = new MiniBox(); series.populations = new HashMap<>(); - + String key1 = randomString(); int code1 = randomIntBetween(1, 10); MiniBox population1 = new MiniBox(); population1.put("CODE", code1); series.populations.put(key1, population1); - + String key2 = randomString(); int code2 = code1 + randomIntBetween(1, 10); MiniBox population2 = new MiniBox(); @@ -78,20 +81,22 @@ public void constructor_called_initializesParameters() { population2.put("(REGION)" + TAG_SEPARATOR + Region.DEFAULT.name(), 0); population2.put("(REGION)" + TAG_SEPARATOR + Region.NUCLEUS.name(), 0); series.populations.put(key2, population2); - + double lambda1 = randomDoubleBetween(1, 100); double lambda2 = randomDoubleBetween(1, 100); - + series.potts.put("surface/LAMBDA" + TARGET_SEPARATOR + key1, lambda1); series.potts.put("surface/LAMBDA" + TARGET_SEPARATOR + key2, lambda2); - + double lambdaNucleus = randomDoubleBetween(1, 100); double lambdaDefault = randomDoubleBetween(1, 100); - series.potts.put("surface/LAMBDA_" + Region.DEFAULT.name() + TARGET_SEPARATOR + key2, lambdaDefault); - series.potts.put("surface/LAMBDA_" + Region.NUCLEUS.name() + TARGET_SEPARATOR + key2, lambdaNucleus); - + series.potts.put( + "surface/LAMBDA_" + Region.DEFAULT.name() + TARGET_SEPARATOR + key2, lambdaDefault); + series.potts.put( + "surface/LAMBDA_" + Region.NUCLEUS.name() + TARGET_SEPARATOR + key2, lambdaNucleus); + SurfaceHamiltonianMock shm = new SurfaceHamiltonianMock(series, mock(Potts.class)); - + assertEquals(2, shm.popToLambda.size()); assertTrue(shm.popToLambda.containsKey(code1)); assertTrue(shm.popToLambda.containsKey(code2)); @@ -101,196 +106,225 @@ public void constructor_called_initializesParameters() { assertEquals(lambdaDefault, shm.popToLambdasRegion.get(code2).get(Region.DEFAULT), EPSILON); assertEquals(lambdaNucleus, shm.popToLambdasRegion.get(code2).get(Region.NUCLEUS), EPSILON); } - + @Test public void register_noRegions_addsConfig() { - SurfaceHamiltonianMock shm = new SurfaceHamiltonianMock(mock(PottsSeries.class), mock(Potts.class)); + SurfaceHamiltonianMock shm = + new SurfaceHamiltonianMock(mock(PottsSeries.class), mock(Potts.class)); PottsCell cell = mock(PottsCell.class); - + int id = randomIntBetween(1, 10); int pop = randomIntBetween(1, 10); - + doReturn(id).when(cell).getID(); doReturn(pop).when(cell).getPop(); - + double lambda = randomDoubleBetween(1, 100); EnumMap lambdasRegion = null; shm.popToLambda.put(pop, lambda); shm.popToLambdasRegion.put(pop, lambdasRegion); - + shm.register(cell); SurfaceHamiltonianConfig config = shm.configs.get(id); - + assertNotNull(config); assertEquals(cell, config.cell); assertEquals(lambda, config.getLambda(), EPSILON); assertEquals(Double.NaN, config.getLambda(Region.UNDEFINED), EPSILON); } - + @Test public void register_withRegions_addsConfig() { - SurfaceHamiltonianMock shm = new SurfaceHamiltonianMock(mock(PottsSeries.class), mock(Potts.class)); + SurfaceHamiltonianMock shm = + new SurfaceHamiltonianMock(mock(PottsSeries.class), mock(Potts.class)); PottsCell cell = mock(PottsCell.class); - + int id = randomIntBetween(1, 10); int pop = randomIntBetween(1, 10); - + doReturn(id).when(cell).getID(); doReturn(pop).when(cell).getPop(); - + double lambda = randomDoubleBetween(1, 100); double lambdaNucleus = randomDoubleBetween(1, 100); EnumMap lambdasRegion = new EnumMap<>(Region.class); lambdasRegion.put(Region.NUCLEUS, lambdaNucleus); - + shm.popToLambda.put(pop, lambda); shm.popToLambdasRegion.put(pop, lambdasRegion); - + shm.register(cell); SurfaceHamiltonianConfig config = shm.configs.get(id); - + assertNotNull(config); assertEquals(cell, config.cell); assertEquals(lambda, config.getLambda(), EPSILON); assertEquals(lambdaNucleus, config.getLambda(Region.NUCLEUS), EPSILON); } - + @Test public void deregister_exists_removesConfig() { - SurfaceHamiltonianMock shm = new SurfaceHamiltonianMock(mock(PottsSeries.class), mock(Potts.class)); + SurfaceHamiltonianMock shm = + new SurfaceHamiltonianMock(mock(PottsSeries.class), mock(Potts.class)); PottsCell cell = mock(PottsCell.class); - + int id = randomIntBetween(1, 10); doReturn(id).when(cell).getID(); - + SurfaceHamiltonianConfig config = mock(SurfaceHamiltonianConfig.class); shm.configs.put(id, config); - + shm.deregister(cell); - + assertFalse(shm.configs.containsKey(id)); } - + @Test public void getDelta_validIDs_calculatesValue() { - SurfaceHamiltonianMock shm = spy(new SurfaceHamiltonianMock(mock(PottsSeries.class), mock(Potts.class))); + SurfaceHamiltonianMock shm = + spy(new SurfaceHamiltonianMock(mock(PottsSeries.class), mock(Potts.class))); int id1 = randomIntBetween(1, 100); int id2 = id1 + randomIntBetween(1, 10); - + double cell1 = randomDoubleBetween(1, 100); doReturn(cell1).when(shm).getSurface(id1, 0); - + double cell1plus1 = randomDoubleBetween(1, 100); doReturn(cell1plus1).when(shm).getSurface(id1, 1); - + double cell2 = randomDoubleBetween(1, 100); doReturn(cell2).when(shm).getSurface(id2, 0); - + double cell2minus1 = randomDoubleBetween(1, 100); doReturn(cell2minus1).when(shm).getSurface(id2, -1); - - assertEquals((cell1plus1 - cell1 + cell2minus1 - cell2), shm.getDelta(id1, id2, 0, 0, 0), EPSILON); - assertEquals((cell2minus1 - cell2 + cell1plus1 - cell1), shm.getDelta(id2, id1, 0, 0, 0), EPSILON); + + assertEquals( + (cell1plus1 - cell1 + cell2minus1 - cell2), + shm.getDelta(id1, id2, 0, 0, 0), + EPSILON); + assertEquals( + (cell2minus1 - cell2 + cell1plus1 - cell1), + shm.getDelta(id2, id1, 0, 0, 0), + EPSILON); } - + @Test public void getDelta_validRegions_calculatesValue() { - SurfaceHamiltonianMock shm = spy(new SurfaceHamiltonianMock(mock(PottsSeries.class), mock(Potts.class))); + SurfaceHamiltonianMock shm = + spy(new SurfaceHamiltonianMock(mock(PottsSeries.class), mock(Potts.class))); int id = randomIntBetween(1, 100); - + double region = randomDoubleBetween(1, 100); doReturn(0.0).when(shm).getSurface(id, Region.DEFAULT.ordinal(), 0); doReturn(region).when(shm).getSurface(id, Region.NUCLEUS.ordinal(), 0); - + double regionminus3 = randomDoubleBetween(1, 100); doReturn(0.0).when(shm).getSurface(id, Region.DEFAULT.ordinal(), -3); doReturn(regionminus3).when(shm).getSurface(id, Region.NUCLEUS.ordinal(), -3); - + double regionplus2 = randomDoubleBetween(1, 100); doReturn(0.0).when(shm).getSurface(id, Region.DEFAULT.ordinal(), 2); doReturn(regionplus2).when(shm).getSurface(id, Region.NUCLEUS.ordinal(), 2); - - assertEquals((regionminus3 - region), - shm.getDelta(id, Region.NUCLEUS.ordinal(), Region.DEFAULT.ordinal(), 0, 0, 0), EPSILON); - assertEquals((regionplus2 - region), - shm.getDelta(id, Region.DEFAULT.ordinal(), Region.NUCLEUS.ordinal(), 0, 0, 0), EPSILON); + + assertEquals( + (regionminus3 - region), + shm.getDelta(id, Region.NUCLEUS.ordinal(), Region.DEFAULT.ordinal(), 0, 0, 0), + EPSILON); + assertEquals( + (regionplus2 - region), + shm.getDelta(id, Region.DEFAULT.ordinal(), Region.NUCLEUS.ordinal(), 0, 0, 0), + EPSILON); } - + @Test public void getSurface_validIDs_calculatesValue() { - SurfaceHamiltonianMock shm = new SurfaceHamiltonianMock(mock(PottsSeries.class), mock(Potts.class)); + SurfaceHamiltonianMock shm = + new SurfaceHamiltonianMock(mock(PottsSeries.class), mock(Potts.class)); int id = randomIntBetween(1, 100); - + int surface = randomIntBetween(10, 20); double targetSurface = randomDoubleBetween(10, 20); - + PottsCell cell = mock(PottsCell.class); doReturn((double) surface).when(cell).getSurface(); doReturn(targetSurface).when(cell).getTargetSurface(); - + SurfaceHamiltonianConfig config = mock(SurfaceHamiltonianConfig.class); - + try { Field cellField = SurfaceHamiltonianConfig.class.getDeclaredField("cell"); cellField.setAccessible(true); cellField.set(config, cell); - } catch (Exception ignored) { } - + } catch (Exception ignored) { + } + double lambda = randomDoubleBetween(10, 100); doReturn(lambda).when(config).getLambda(); - + shm.configs.put(id, config); - + assertEquals(lambda * Math.pow(surface - targetSurface, 2), shm.getSurface(id, 0), EPSILON); - assertEquals(lambda * Math.pow(surface - targetSurface + 1, 2), shm.getSurface(id, 1), EPSILON); - assertEquals(lambda * Math.pow(surface - targetSurface - 1, 2), shm.getSurface(id, -1), EPSILON); + assertEquals( + lambda * Math.pow(surface - targetSurface + 1, 2), shm.getSurface(id, 1), EPSILON); + assertEquals( + lambda * Math.pow(surface - targetSurface - 1, 2), shm.getSurface(id, -1), EPSILON); } - + @Test public void getSurface_validRegions_calculatesValue() { - SurfaceHamiltonianMock shm = new SurfaceHamiltonianMock(mock(PottsSeries.class), mock(Potts.class)); + SurfaceHamiltonianMock shm = + new SurfaceHamiltonianMock(mock(PottsSeries.class), mock(Potts.class)); int id = randomIntBetween(1, 100); Region region = Region.NUCLEUS; - + int surface = randomIntBetween(10, 20); double targetSurface = randomDoubleBetween(10, 20); - + PottsCell cell = mock(PottsCell.class); doReturn((double) surface).when(cell).getSurface(region); doReturn(targetSurface).when(cell).getTargetSurface(region); - + SurfaceHamiltonianConfig config = mock(SurfaceHamiltonianConfig.class); - + try { Field cellField = SurfaceHamiltonianConfig.class.getDeclaredField("cell"); cellField.setAccessible(true); cellField.set(config, cell); - } catch (Exception ignored) { } - + } catch (Exception ignored) { + } + double lambda = randomDoubleBetween(10, 100); doReturn(lambda).when(config).getLambda(region); - + shm.configs.put(id, config); - - assertEquals(lambda * Math.pow(surface - targetSurface, 2), - shm.getSurface(id, region.ordinal(), 0), EPSILON); - assertEquals(lambda * Math.pow(surface - targetSurface + 1, 2), - shm.getSurface(id, region.ordinal(), 1), EPSILON); - assertEquals(lambda * Math.pow(surface - targetSurface - 1, 2), - shm.getSurface(id, region.ordinal(), -1), EPSILON); + + assertEquals( + lambda * Math.pow(surface - targetSurface, 2), + shm.getSurface(id, region.ordinal(), 0), + EPSILON); + assertEquals( + lambda * Math.pow(surface - targetSurface + 1, 2), + shm.getSurface(id, region.ordinal(), 1), + EPSILON); + assertEquals( + lambda * Math.pow(surface - targetSurface - 1, 2), + shm.getSurface(id, region.ordinal(), -1), + EPSILON); } - + @Test public void getSurface_zeroID_returnsZero() { - SurfaceHamiltonianMock shm = new SurfaceHamiltonianMock(mock(PottsSeries.class), mock(Potts.class)); + SurfaceHamiltonianMock shm = + new SurfaceHamiltonianMock(mock(PottsSeries.class), mock(Potts.class)); assertEquals(0, shm.getSurface(0, 1), EPSILON); assertEquals(0, shm.getSurface(0, 0), EPSILON); assertEquals(0, shm.getSurface(0, -1), EPSILON); } - + @Test public void getSurface_defaultRegion_returnsZero() { - SurfaceHamiltonianMock shm = new SurfaceHamiltonianMock(mock(PottsSeries.class), mock(Potts.class)); + SurfaceHamiltonianMock shm = + new SurfaceHamiltonianMock(mock(PottsSeries.class), mock(Potts.class)); int id = randomIntBetween(1, 100); assertEquals(0, shm.getSurface(0, Region.DEFAULT.ordinal(), 1), EPSILON); assertEquals(0, shm.getSurface(0, Region.DEFAULT.ordinal(), 0), EPSILON); diff --git a/test/arcade/potts/sim/hamiltonian/VolumeHamiltonianConfigTest.java b/test/arcade/potts/sim/hamiltonian/VolumeHamiltonianConfigTest.java index 60b83237d..01681bf57 100644 --- a/test/arcade/potts/sim/hamiltonian/VolumeHamiltonianConfigTest.java +++ b/test/arcade/potts/sim/hamiltonian/VolumeHamiltonianConfigTest.java @@ -1,81 +1,81 @@ package arcade.potts.sim.hamiltonian; import java.util.EnumMap; -import org.junit.Test; +import org.junit.jupiter.api.Test; import arcade.potts.agent.cell.PottsCell; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.core.ARCADETestUtilities.*; import static arcade.potts.util.PottsEnums.Region; public class VolumeHamiltonianConfigTest { private static final double EPSILON = 1E-10; - + @Test public void constructor_noRegions_setsFields() { PottsCell cell = mock(PottsCell.class); - + VolumeHamiltonianConfig vhc = new VolumeHamiltonianConfig(cell, 0, null); assertEquals(cell, vhc.cell); assertFalse(vhc.hasRegions); } - + @Test public void constructor_emptyRegions_setsFields() { PottsCell cell = mock(PottsCell.class); EnumMap lambdasRegion = new EnumMap<>(Region.class); - + VolumeHamiltonianConfig vhc = new VolumeHamiltonianConfig(cell, 0, lambdasRegion); assertEquals(cell, vhc.cell); assertFalse(vhc.hasRegions); } - + @Test public void constructor_hasRegions_setsFields() { PottsCell cell = mock(PottsCell.class); EnumMap lambdasRegion = new EnumMap<>(Region.class); lambdasRegion.put(Region.UNDEFINED, randomDoubleBetween(1, 100)); - + VolumeHamiltonianConfig vhc = new VolumeHamiltonianConfig(cell, 0, lambdasRegion); assertEquals(cell, vhc.cell); assertTrue(vhc.hasRegions); } - + @Test public void getLambda_noRegion_returnsValue() { double lambda = randomDoubleBetween(1, 100); VolumeHamiltonianConfig vhc = new VolumeHamiltonianConfig(null, lambda, null); assertEquals(lambda, vhc.getLambda(), EPSILON); } - + @Test public void getLambda_validRegions_returnsValue() { double lambda = randomDoubleBetween(1, 100); - + EnumMap lambdasRegion = new EnumMap<>(Region.class); lambdasRegion.put(Region.DEFAULT, randomDoubleBetween(0, 100)); lambdasRegion.put(Region.NUCLEUS, randomDoubleBetween(0, 100)); - + VolumeHamiltonianConfig vhc = new VolumeHamiltonianConfig(null, lambda, lambdasRegion); - + assertEquals(lambdasRegion.get(Region.DEFAULT), vhc.getLambda(Region.DEFAULT), EPSILON); assertEquals(lambdasRegion.get(Region.NUCLEUS), vhc.getLambda(Region.NUCLEUS), EPSILON); } - + @Test public void getLambda_invalidRegions_returnsNaN() { double lambda = randomDoubleBetween(1, 100); - + EnumMap lambdasRegion = new EnumMap<>(Region.class); lambdasRegion.put(Region.DEFAULT, randomDoubleBetween(0, 100)); lambdasRegion.put(Region.NUCLEUS, randomDoubleBetween(0, 100)); - + VolumeHamiltonianConfig vhc = new VolumeHamiltonianConfig(null, lambda, lambdasRegion); - + assertEquals(Double.NaN, vhc.getLambda(null), EPSILON); assertEquals(Double.NaN, vhc.getLambda(Region.UNDEFINED), EPSILON); } - + @Test public void getLambda_nullRegion_returnsNaN() { double lambda = randomDoubleBetween(1, 100); diff --git a/test/arcade/potts/sim/hamiltonian/VolumeHamiltonianTest.java b/test/arcade/potts/sim/hamiltonian/VolumeHamiltonianTest.java index 8be9e74ca..64a0334ec 100644 --- a/test/arcade/potts/sim/hamiltonian/VolumeHamiltonianTest.java +++ b/test/arcade/potts/sim/hamiltonian/VolumeHamiltonianTest.java @@ -3,11 +3,11 @@ import java.lang.reflect.Field; import java.util.EnumMap; import java.util.HashMap; -import org.junit.Test; +import org.junit.jupiter.api.Test; import arcade.core.util.MiniBox; import arcade.potts.agent.cell.PottsCell; import arcade.potts.sim.PottsSeries; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.core.ARCADETestUtilities.*; import static arcade.core.util.MiniBox.TAG_SEPARATOR; @@ -16,7 +16,7 @@ public class VolumeHamiltonianTest { private static final double EPSILON = 1E-10; - + @Test public void constructor_called_initializesMaps() { VolumeHamiltonian vh = new VolumeHamiltonian(mock(PottsSeries.class)); @@ -24,20 +24,20 @@ public void constructor_called_initializesMaps() { assertNotNull(vh.popToLambda); assertNotNull(vh.popToLambdasRegion); } - + @Test public void constructor_called_initializesParameters() { PottsSeries series = mock(PottsSeries.class); - + series.potts = new MiniBox(); series.populations = new HashMap<>(); - + String key1 = randomString(); int code1 = randomIntBetween(1, 10); MiniBox population1 = new MiniBox(); population1.put("CODE", code1); series.populations.put(key1, population1); - + String key2 = randomString(); int code2 = code1 + randomIntBetween(1, 10); MiniBox population2 = new MiniBox(); @@ -45,20 +45,22 @@ public void constructor_called_initializesParameters() { population2.put("(REGION)" + TAG_SEPARATOR + Region.DEFAULT.name(), 0); population2.put("(REGION)" + TAG_SEPARATOR + Region.NUCLEUS.name(), 0); series.populations.put(key2, population2); - + double lambda1 = randomDoubleBetween(1, 100); double lambda2 = randomDoubleBetween(1, 100); - + series.potts.put("volume/LAMBDA" + TARGET_SEPARATOR + key1, lambda1); series.potts.put("volume/LAMBDA" + TARGET_SEPARATOR + key2, lambda2); - + double lambdaNucleus = randomDoubleBetween(1, 100); double lambdaDefault = randomDoubleBetween(1, 100); - series.potts.put("volume/LAMBDA_" + Region.DEFAULT.name() + TARGET_SEPARATOR + key2, lambdaDefault); - series.potts.put("volume/LAMBDA_" + Region.NUCLEUS.name() + TARGET_SEPARATOR + key2, lambdaNucleus); - + series.potts.put( + "volume/LAMBDA_" + Region.DEFAULT.name() + TARGET_SEPARATOR + key2, lambdaDefault); + series.potts.put( + "volume/LAMBDA_" + Region.NUCLEUS.name() + TARGET_SEPARATOR + key2, lambdaNucleus); + VolumeHamiltonian vh = new VolumeHamiltonian(series); - + assertEquals(2, vh.popToLambda.size()); assertTrue(vh.popToLambda.containsKey(code1)); assertTrue(vh.popToLambda.containsKey(code2)); @@ -68,191 +70,210 @@ public void constructor_called_initializesParameters() { assertEquals(lambdaDefault, vh.popToLambdasRegion.get(code2).get(Region.DEFAULT), EPSILON); assertEquals(lambdaNucleus, vh.popToLambdasRegion.get(code2).get(Region.NUCLEUS), EPSILON); } - + @Test public void register_noRegions_addsConfig() { VolumeHamiltonian vh = new VolumeHamiltonian(mock(PottsSeries.class)); PottsCell cell = mock(PottsCell.class); - + int id = randomIntBetween(1, 10); int pop = randomIntBetween(1, 10); - + doReturn(id).when(cell).getID(); doReturn(pop).when(cell).getPop(); - + double lambda = randomDoubleBetween(1, 100); EnumMap lambdasRegion = null; vh.popToLambda.put(pop, lambda); vh.popToLambdasRegion.put(pop, lambdasRegion); - + vh.register(cell); VolumeHamiltonianConfig config = vh.configs.get(id); - + assertNotNull(config); assertEquals(cell, config.cell); assertEquals(lambda, config.getLambda(), EPSILON); assertEquals(Double.NaN, config.getLambda(Region.UNDEFINED), EPSILON); } - + @Test public void register_withRegions_addsConfig() { VolumeHamiltonian vh = new VolumeHamiltonian(mock(PottsSeries.class)); PottsCell cell = mock(PottsCell.class); - + int id = randomIntBetween(1, 10); int pop = randomIntBetween(1, 10); - + doReturn(id).when(cell).getID(); doReturn(pop).when(cell).getPop(); - + double lambda = randomDoubleBetween(1, 100); double lambdaNucleus = randomDoubleBetween(1, 100); EnumMap lambdasRegion = new EnumMap<>(Region.class); lambdasRegion.put(Region.NUCLEUS, lambdaNucleus); - + vh.popToLambda.put(pop, lambda); vh.popToLambdasRegion.put(pop, lambdasRegion); - + vh.register(cell); VolumeHamiltonianConfig config = vh.configs.get(id); - + assertNotNull(config); assertEquals(cell, config.cell); assertEquals(lambda, config.getLambda(), EPSILON); assertEquals(lambdaNucleus, config.getLambda(Region.NUCLEUS), EPSILON); } - + @Test public void deregister_exists_removesConfig() { VolumeHamiltonian vh = new VolumeHamiltonian(mock(PottsSeries.class)); PottsCell cell = mock(PottsCell.class); - + int id = randomIntBetween(1, 10); doReturn(id).when(cell).getID(); - + VolumeHamiltonianConfig config = mock(VolumeHamiltonianConfig.class); vh.configs.put(id, config); - + vh.deregister(cell); - + assertFalse(vh.configs.containsKey(id)); } - + @Test public void getDelta_validIDs_calculatesValue() { VolumeHamiltonian vh = spy(new VolumeHamiltonian(mock(PottsSeries.class))); int id1 = randomIntBetween(1, 100); int id2 = id1 + randomIntBetween(1, 10); - + double cell1 = randomDoubleBetween(1, 100); doReturn(cell1).when(vh).getVolume(id1, 0); - + double cell1plus1 = randomDoubleBetween(1, 100); doReturn(cell1plus1).when(vh).getVolume(id1, 1); - + double cell1minus1 = randomDoubleBetween(1, 100); doReturn(cell1minus1).when(vh).getVolume(id1, -1); - + double cell2 = randomDoubleBetween(1, 100); doReturn(cell2).when(vh).getVolume(id2, 0); - + double cell2plus1 = randomDoubleBetween(1, 100); doReturn(cell2plus1).when(vh).getVolume(id2, 1); - + double cell2minus1 = randomDoubleBetween(1, 100); doReturn(cell2minus1).when(vh).getVolume(id2, -1); - - assertEquals((cell1minus1 - cell1 + cell2plus1 - cell2), vh.getDelta(id1, id2, 0, 0, 0), EPSILON); - assertEquals((cell2minus1 - cell2 + cell1plus1 - cell1), vh.getDelta(id2, id1, 0, 0, 0), EPSILON); + + assertEquals( + (cell1minus1 - cell1 + cell2plus1 - cell2), + vh.getDelta(id1, id2, 0, 0, 0), + EPSILON); + assertEquals( + (cell2minus1 - cell2 + cell1plus1 - cell1), + vh.getDelta(id2, id1, 0, 0, 0), + EPSILON); } - + @Test public void getDelta_validRegions_calculatesValue() { VolumeHamiltonian vh = spy(new VolumeHamiltonian(mock(PottsSeries.class))); int id = randomIntBetween(1, 100); - + double region = randomDoubleBetween(1, 100); doReturn(0.0).when(vh).getVolume(id, Region.DEFAULT.ordinal(), 0); doReturn(region).when(vh).getVolume(id, Region.NUCLEUS.ordinal(), 0); - + double regionplus1 = randomDoubleBetween(1, 100); doReturn(0.0).when(vh).getVolume(id, Region.DEFAULT.ordinal(), 1); doReturn(regionplus1).when(vh).getVolume(id, Region.NUCLEUS.ordinal(), 1); - + double regionminus1 = randomDoubleBetween(1, 100); doReturn(0.0).when(vh).getVolume(id, Region.DEFAULT.ordinal(), -1); doReturn(regionminus1).when(vh).getVolume(id, Region.NUCLEUS.ordinal(), -1); - - assertEquals((regionplus1 - region), - vh.getDelta(id, Region.DEFAULT.ordinal(), Region.NUCLEUS.ordinal(), 0, 0, 0), EPSILON); - assertEquals((regionminus1 - region), - vh.getDelta(id, Region.NUCLEUS.ordinal(), Region.DEFAULT.ordinal(), 0, 0, 0), EPSILON); + + assertEquals( + (regionplus1 - region), + vh.getDelta(id, Region.DEFAULT.ordinal(), Region.NUCLEUS.ordinal(), 0, 0, 0), + EPSILON); + assertEquals( + (regionminus1 - region), + vh.getDelta(id, Region.NUCLEUS.ordinal(), Region.DEFAULT.ordinal(), 0, 0, 0), + EPSILON); } - + @Test public void getVolume_validID_calculatesValue() { VolumeHamiltonian vh = new VolumeHamiltonian(mock(PottsSeries.class)); int id = randomIntBetween(1, 100); - + int volume = randomIntBetween(10, 20); double targetVolume = randomDoubleBetween(10, 20); - + PottsCell cell = mock(PottsCell.class); doReturn((double) volume).when(cell).getVolume(); doReturn(targetVolume).when(cell).getTargetVolume(); - + VolumeHamiltonianConfig config = mock(VolumeHamiltonianConfig.class); - + try { Field cellField = VolumeHamiltonianConfig.class.getDeclaredField("cell"); cellField.setAccessible(true); cellField.set(config, cell); - } catch (Exception ignored) { } - + } catch (Exception ignored) { + } + double lambda = randomDoubleBetween(10, 100); doReturn(lambda).when(config).getLambda(); - + vh.configs.put(id, config); - + assertEquals(lambda * Math.pow(volume - targetVolume, 2), vh.getVolume(id, 0), EPSILON); assertEquals(lambda * Math.pow(volume - targetVolume + 1, 2), vh.getVolume(id, 1), EPSILON); - assertEquals(lambda * Math.pow(volume - targetVolume - 1, 2), vh.getVolume(id, -1), EPSILON); + assertEquals( + lambda * Math.pow(volume - targetVolume - 1, 2), vh.getVolume(id, -1), EPSILON); } - + @Test public void getVolume_validRegions_calculatesValue() { VolumeHamiltonian vh = new VolumeHamiltonian(mock(PottsSeries.class)); int id = randomIntBetween(1, 100); Region region = Region.NUCLEUS; - + int volume = randomIntBetween(10, 20); double targetVolume = randomDoubleBetween(10, 20); - + PottsCell cell = mock(PottsCell.class); doReturn((double) volume).when(cell).getVolume(region); doReturn(targetVolume).when(cell).getTargetVolume(region); - + VolumeHamiltonianConfig config = mock(VolumeHamiltonianConfig.class); - + try { Field cellField = VolumeHamiltonianConfig.class.getDeclaredField("cell"); cellField.setAccessible(true); cellField.set(config, cell); - } catch (Exception ignored) { } - + } catch (Exception ignored) { + } + double lambda = randomDoubleBetween(10, 100); doReturn(lambda).when(config).getLambda(region); - + vh.configs.put(id, config); - - assertEquals(lambda * Math.pow(volume - targetVolume, 2), - vh.getVolume(id, region.ordinal(), 0), EPSILON); - assertEquals(lambda * Math.pow(volume - targetVolume + 1, 2), - vh.getVolume(id, region.ordinal(), 1), EPSILON); - assertEquals(lambda * Math.pow(volume - targetVolume - 1, 2), - vh.getVolume(id, region.ordinal(), -1), EPSILON); + + assertEquals( + lambda * Math.pow(volume - targetVolume, 2), + vh.getVolume(id, region.ordinal(), 0), + EPSILON); + assertEquals( + lambda * Math.pow(volume - targetVolume + 1, 2), + vh.getVolume(id, region.ordinal(), 1), + EPSILON); + assertEquals( + lambda * Math.pow(volume - targetVolume - 1, 2), + vh.getVolume(id, region.ordinal(), -1), + EPSILON); } - + @Test public void getVolume_zeroID_returnsZero() { VolumeHamiltonian vh = new VolumeHamiltonian(mock(PottsSeries.class)); @@ -260,7 +281,7 @@ public void getVolume_zeroID_returnsZero() { assertEquals(0, vh.getVolume(0, 0), EPSILON); assertEquals(0, vh.getVolume(0, -1), EPSILON); } - + @Test public void getVolume_defaultRegion_returnsZero() { VolumeHamiltonian vh = new VolumeHamiltonian(mock(PottsSeries.class)); diff --git a/test/arcade/potts/sim/input/PottsInputBuilderTest.java b/test/arcade/potts/sim/input/PottsInputBuilderTest.java index f0c229aa2..5c794a201 100644 --- a/test/arcade/potts/sim/input/PottsInputBuilderTest.java +++ b/test/arcade/potts/sim/input/PottsInputBuilderTest.java @@ -3,13 +3,11 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.stream.IntStream; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; +import org.junit.jupiter.api.Test; import org.xml.sax.Attributes; import arcade.core.util.Box; import arcade.core.util.MiniBox; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.core.ARCADETestUtilities.*; import static arcade.core.util.MiniBox.TAG_SEPARATOR; @@ -17,16 +15,13 @@ public class PottsInputBuilderTest { private static final String ATT_QNAME = randomString(); - + private static final String ATT_VALUE = randomString(); - + private static final String LIST_NAME = randomString(); - + private static final String TAG_NAME = randomString(); - - @Rule - public TemporaryFolder folder = new TemporaryFolder(); - + private static Attributes makeAttributesMock(int n) { Attributes attributes = mock(Attributes.class); doReturn(n).when(attributes).getLength(); @@ -36,7 +31,7 @@ private static Attributes makeAttributesMock(int n) { } return attributes; } - + private HashMap> makeSetupLists(int n) { HashMap> setupLists = new HashMap<>(); ArrayList boxes = new ArrayList<>(); @@ -44,58 +39,58 @@ private HashMap> makeSetupLists(int n) { setupLists.put(LIST_NAME + "s", boxes); return setupLists; } - + private Box makeExpected(String id, int n) { Box expected = new Box(); expected.addTag(id, TAG_NAME.toUpperCase()); IntStream.range(0, n).forEach(i -> expected.addAtt(id, ATT_QNAME + i, ATT_VALUE + i)); return expected; } - + @Test public void updateBox_noAtts_updatesContainer() { int nLists = randomIntBetween(1, 10); - + PottsInputBuilder builder = mock(PottsInputBuilder.class, CALLS_REAL_METHODS); builder.setupLists = makeSetupLists(nLists); - + Attributes attributes = makeAttributesMock(0); builder.updateBox(LIST_NAME, TAG_NAME, attributes); - + Box expected = new Box(); assertTrue(expected.compare(builder.setupLists.get(LIST_NAME + "s").get(nLists - 1))); } - + @Test public void updateBox_noTags_updatesContainer() { int nLists = randomIntBetween(1, 10); int nAtts = randomIntBetween(1, 10); String id = randomString(); - + PottsInputBuilder builder = mock(PottsInputBuilder.class, CALLS_REAL_METHODS); builder.setupLists = makeSetupLists(nLists); - + Attributes attributes = makeAttributesMock(nAtts + 1); doReturn("id").when(attributes).getQName(nAtts); doReturn(id).when(attributes).getValue(nAtts); doReturn(id).when(attributes).getValue("id"); - + builder.updateBox(LIST_NAME, TAG_NAME, attributes); - + Box expected = makeExpected(id, nAtts); assertTrue(expected.compare(builder.setupLists.get(LIST_NAME + "s").get(nLists - 1))); } - + @Test public void updateBox_withModuleTagOnly_updatesContainer() { int nLists = randomIntBetween(1, 10); int nAtts = randomIntBetween(1, 10); String id = randomString(); String module = randomString(); - + PottsInputBuilder builder = mock(PottsInputBuilder.class, CALLS_REAL_METHODS); builder.setupLists = makeSetupLists(nLists); - + Attributes attributes = makeAttributesMock(nAtts + 2); doReturn("id").when(attributes).getQName(nAtts); doReturn(id).when(attributes).getValue(nAtts); @@ -103,23 +98,23 @@ public void updateBox_withModuleTagOnly_updatesContainer() { doReturn("module").when(attributes).getQName(nAtts + 1); doReturn(module.toUpperCase()).when(attributes).getValue(nAtts + 1); doReturn(module.toUpperCase()).when(attributes).getValue("module"); - + builder.updateBox(LIST_NAME, TAG_NAME, attributes); - + Box expected = makeExpected(module.toLowerCase() + TAG_SEPARATOR + id, nAtts); assertTrue(expected.compare(builder.setupLists.get(LIST_NAME + "s").get(nLists - 1))); } - + @Test public void updateBox_withTermTagOnly_updatesContainer() { int nLists = randomIntBetween(1, 10); int nAtts = randomIntBetween(1, 10); String id = randomString(); String term = randomString(); - + PottsInputBuilder builder = mock(PottsInputBuilder.class, CALLS_REAL_METHODS); builder.setupLists = makeSetupLists(nLists); - + Attributes attributes = makeAttributesMock(nAtts + 2); doReturn("id").when(attributes).getQName(nAtts); doReturn(id).when(attributes).getValue(nAtts); @@ -127,13 +122,13 @@ public void updateBox_withTermTagOnly_updatesContainer() { doReturn("term").when(attributes).getQName(nAtts + 1); doReturn(term.toUpperCase()).when(attributes).getValue(nAtts + 1); doReturn(term.toUpperCase()).when(attributes).getValue("term"); - + builder.updateBox(LIST_NAME, TAG_NAME, attributes); - + Box expected = makeExpected(term.toLowerCase() + TAG_SEPARATOR + id, nAtts); assertTrue(expected.compare(builder.setupLists.get(LIST_NAME + "s").get(nLists - 1))); } - + @Test public void updateBox_withTarget_updatesContainer() { int nLists = randomIntBetween(1, 10); @@ -141,10 +136,10 @@ public void updateBox_withTarget_updatesContainer() { String id = randomString(); String term = randomString(); String target = randomString(); - + PottsInputBuilder builder = mock(PottsInputBuilder.class, CALLS_REAL_METHODS); builder.setupLists = makeSetupLists(nLists); - + Attributes attributes = makeAttributesMock(nAtts + 2); doReturn("id").when(attributes).getQName(nAtts); doReturn(id).when(attributes).getValue(nAtts); @@ -155,13 +150,15 @@ public void updateBox_withTarget_updatesContainer() { doReturn("target").when(attributes).getQName(nAtts + 2); doReturn(target).when(attributes).getValue(nAtts + 2); doReturn(target).when(attributes).getValue("target"); - + builder.updateBox(LIST_NAME, TAG_NAME, attributes); - - Box expected = makeExpected(term.toLowerCase() + TAG_SEPARATOR + id + TARGET_SEPARATOR + target, nAtts); + + Box expected = + makeExpected( + term.toLowerCase() + TAG_SEPARATOR + id + TARGET_SEPARATOR + target, nAtts); assertTrue(expected.compare(builder.setupLists.get(LIST_NAME + "s").get(nLists - 1))); } - + @Test public void updateBox_withModuleAndTerm_doesNothing() { int nLists = randomIntBetween(1, 10); @@ -169,10 +166,10 @@ public void updateBox_withModuleAndTerm_doesNothing() { String id = randomString(); String module = randomString(); String term = randomString(); - + PottsInputBuilder builder = mock(PottsInputBuilder.class, CALLS_REAL_METHODS); builder.setupLists = makeSetupLists(nLists); - + Attributes attributes = makeAttributesMock(nAtts + 3); doReturn("id").when(attributes).getQName(nAtts); doReturn(id).when(attributes).getValue(nAtts); @@ -183,13 +180,13 @@ public void updateBox_withModuleAndTerm_doesNothing() { doReturn("term").when(attributes).getQName(nAtts + 2); doReturn(term).when(attributes).getValue(nAtts + 2); doReturn(term).when(attributes).getValue("term"); - + builder.updateBox(LIST_NAME, TAG_NAME, attributes); - + Box expected = new Box(); assertTrue(expected.compare(builder.setupLists.get(LIST_NAME + "s").get(nLists - 1))); } - + @Test public void updateBox_withRegionModuleAndTerm_doesNothing() { int nLists = randomIntBetween(1, 10); @@ -198,10 +195,10 @@ public void updateBox_withRegionModuleAndTerm_doesNothing() { String region = randomString(); String module = randomString(); String term = randomString(); - + PottsInputBuilder builder = mock(PottsInputBuilder.class, CALLS_REAL_METHODS); builder.setupLists = makeSetupLists(nLists); - + Attributes attributes = makeAttributesMock(nAtts + 4); doReturn("id").when(attributes).getQName(nAtts); doReturn(id).when(attributes).getValue(nAtts); @@ -215,93 +212,93 @@ public void updateBox_withRegionModuleAndTerm_doesNothing() { doReturn("term").when(attributes).getQName(nAtts + 3); doReturn(term).when(attributes).getValue(nAtts + 3); doReturn(term).when(attributes).getValue("term"); - + builder.updateBox(LIST_NAME, TAG_NAME, attributes); - + Box expected = new Box(); assertTrue(expected.compare(builder.setupLists.get(LIST_NAME + "s").get(nLists - 1))); } - + @Test public void startElement_givenSet_addsDict() { PottsInputBuilder builder = mock(PottsInputBuilder.class, CALLS_REAL_METHODS); builder.setupDicts = new HashMap<>(); - + int n = randomIntBetween(1, 10); Attributes attributes = makeAttributesMock(n); builder.startElement("", "", "set", attributes); - + MiniBox expected = new MiniBox(); IntStream.range(0, n).forEach(i -> expected.put(ATT_QNAME + i, ATT_VALUE + i)); - + assertTrue(builder.setupDicts.containsKey("set")); assertTrue(expected.compare(builder.setupDicts.get("set"))); } - + @Test public void startElement_givenSeries_addsDict() { PottsInputBuilder builder = mock(PottsInputBuilder.class, CALLS_REAL_METHODS); builder.setupDicts = new HashMap<>(); - + int n = randomIntBetween(1, 10); Attributes attributes = makeAttributesMock(n); builder.startElement("", "", "series", attributes); - + MiniBox expected = new MiniBox(); IntStream.range(0, n).forEach(i -> expected.put(ATT_QNAME + i, ATT_VALUE + i)); - + assertTrue(builder.setupDicts.containsKey("series")); assertTrue(expected.compare(builder.setupDicts.get("series"))); } - + @Test public void startElement_givenPopulations_addsList() { PottsInputBuilder builder = mock(PottsInputBuilder.class, CALLS_REAL_METHODS); builder.setupLists = new HashMap<>(); - + Attributes attributes = makeAttributesMock(randomIntBetween(1, 10)); builder.startElement("", "", "populations", attributes); - + assertTrue(builder.setupLists.containsKey("populations")); assertEquals(0, builder.setupLists.get("populations").size()); } - + @Test public void startElement_givenPotts_addsList() { PottsInputBuilder builder = mock(PottsInputBuilder.class, CALLS_REAL_METHODS); builder.setupLists = new HashMap<>(); - + Attributes attributes = makeAttributesMock(randomIntBetween(1, 10)); builder.startElement("", "", "potts", attributes); - + assertTrue(builder.setupLists.containsKey("potts")); assertEquals(1, builder.setupLists.get("potts").size()); } - + @Test public void startElement_givenPopulation_addsListEntry() { PottsInputBuilder builder = mock(PottsInputBuilder.class, CALLS_REAL_METHODS); builder.setupLists = new HashMap<>(); builder.setupLists.put("populations", new ArrayList<>()); - + int n = randomIntBetween(1, 10); Attributes attributes = makeAttributesMock(n); builder.startElement("", "", "population", attributes); - + Box expected = new Box(); IntStream.range(0, n).forEach(i -> expected.add(ATT_QNAME + i, ATT_VALUE + i)); - + assertEquals(1, builder.setupLists.get("populations").size()); assertTrue(expected.compare(builder.setupLists.get("populations").get(0))); } - + @Test public void startElement_givenPottsColon_updatesBox() { PottsInputBuilder builder = mock(PottsInputBuilder.class, CALLS_REAL_METHODS); builder.setupLists = new HashMap<>(); builder.setupLists.put("potts", new ArrayList<>()); builder.setupLists.get("potts").add(new Box()); - + String id = randomString(); String tag = randomString(); int n = randomIntBetween(1, 10); @@ -310,21 +307,21 @@ public void startElement_givenPottsColon_updatesBox() { doReturn(id).when(attributes).getValue(n); doReturn(id).when(attributes).getValue("id"); builder.startElement("", "", "potts." + tag, attributes); - + Box expected = new Box(); expected.addTag(id, tag.toUpperCase()); IntStream.range(0, n).forEach(i -> expected.addAtt(id, ATT_QNAME + i, ATT_VALUE + i)); - + assertTrue(expected.compare(builder.setupLists.get("potts").get(0))); } - + @Test public void startElement_givenColon_updatesBox() { PottsInputBuilder builder = mock(PottsInputBuilder.class, CALLS_REAL_METHODS); builder.setupLists = new HashMap<>(); builder.setupLists.put(LIST_NAME + "s", new ArrayList<>()); builder.setupLists.get(LIST_NAME + "s").add(new Box()); - + String id = randomString(); String tag = randomString(); int n = randomIntBetween(1, 10); @@ -333,14 +330,14 @@ public void startElement_givenColon_updatesBox() { doReturn(id).when(attributes).getValue(n); doReturn(id).when(attributes).getValue("id"); builder.startElement("", "", LIST_NAME + "." + tag, attributes); - + Box expected = new Box(); expected.addTag(id, tag.toUpperCase()); IntStream.range(0, n).forEach(i -> expected.addAtt(id, ATT_QNAME + i, ATT_VALUE + i)); - + assertTrue(expected.compare(builder.setupLists.get(LIST_NAME + "s").get(0))); } - + @Test public void endElement_givenSeries_createsSeries() { PottsInputBuilder builder = mock(PottsInputBuilder.class, CALLS_REAL_METHODS); @@ -348,14 +345,14 @@ public void endElement_givenSeries_createsSeries() { builder.setupDicts = new HashMap<>(); builder.setupLists = new HashMap<>(); builder.parameters = new Box(); - + builder.setupDicts.put("set", new MiniBox()); builder.setupDicts.put("series", new MiniBox()); - + builder.endElement("", "", "series"); assertEquals(1, builder.series.size()); } - + @Test public void endElement_givenSeries_resetsDicts() { PottsInputBuilder builder = mock(PottsInputBuilder.class, CALLS_REAL_METHODS); @@ -363,15 +360,15 @@ public void endElement_givenSeries_resetsDicts() { builder.setupDicts = new HashMap<>(); builder.setupLists = new HashMap<>(); builder.parameters = new Box(); - + MiniBox set = new MiniBox(); - + builder.setupLists.put(LIST_NAME, new ArrayList<>()); builder.setupDicts.put("set", set); builder.setupDicts.put("series", new MiniBox()); - + builder.endElement("", "", "series"); - + assertEquals(1, builder.setupDicts.size()); assertEquals(set, builder.setupDicts.get("set")); assertEquals(0, builder.setupLists.size()); diff --git a/test/arcade/potts/sim/output/PottsOutputDeserializerTest.java b/test/arcade/potts/sim/output/PottsOutputDeserializerTest.java index 4f354324f..6b5430aa3 100644 --- a/test/arcade/potts/sim/output/PottsOutputDeserializerTest.java +++ b/test/arcade/potts/sim/output/PottsOutputDeserializerTest.java @@ -2,7 +2,7 @@ import java.lang.reflect.Type; import java.util.ArrayList; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.google.gson.Gson; import com.google.gson.JsonArray; import com.google.gson.JsonDeserializationContext; @@ -18,7 +18,7 @@ import arcade.potts.agent.cell.PottsCellContainer; import arcade.potts.env.location.PottsLocationContainer; import arcade.potts.env.location.Voxel; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.core.ARCADETestUtilities.*; import static arcade.potts.env.location.Voxel.VOXEL_COMPARATOR; @@ -29,70 +29,71 @@ public class PottsOutputDeserializerTest { private static final double EPSILON = 1E-10; - - private static final MersenneTwisterFast RANDOM = new MersenneTwisterFast(randomSeed()); - - static final JsonDeserializationContext CELL_CONTEXT = new JsonDeserializationContext() { - @Override - public T deserialize(JsonElement json, Type typeOfT) - throws JsonParseException { - JsonObject array = json.getAsJsonObject(); - int id = array.get("id").getAsInt(); - CellContainer container = mock(CellContainer.class); - doReturn(id).when(container).getID(); - return (T) container; - } - }; - - static final JsonDeserializationContext LOCATION_CONTEXT = new JsonDeserializationContext() { - @Override - public T deserialize(JsonElement json, Type typeOfT) - throws JsonParseException { - if (typeOfT == Voxel.class) { - VoxelDeserializer deserializer = new VoxelDeserializer(); - return (T) deserializer.deserialize(json, typeOfT, null); - } else { - JsonObject array = json.getAsJsonObject(); - int id = array.get("id").getAsInt(); - LocationContainer container = mock(LocationContainer.class); - doReturn(id).when(container).getID(); - return (T) container; - } - } - }; - + + private static final MersenneTwisterFast RANDOM = new MersenneTwisterFast(); + + static final JsonDeserializationContext CELL_CONTEXT = + new JsonDeserializationContext() { + @Override + public T deserialize(JsonElement json, Type typeOfT) throws JsonParseException { + JsonObject array = json.getAsJsonObject(); + int id = array.get("id").getAsInt(); + CellContainer container = mock(CellContainer.class); + doReturn(id).when(container).getID(); + return (T) container; + } + }; + + static final JsonDeserializationContext LOCATION_CONTEXT = + new JsonDeserializationContext() { + @Override + public T deserialize(JsonElement json, Type typeOfT) throws JsonParseException { + if (typeOfT == Voxel.class) { + VoxelDeserializer deserializer = new VoxelDeserializer(); + return (T) deserializer.deserialize(json, typeOfT, null); + } else { + JsonObject array = json.getAsJsonObject(); + int id = array.get("id").getAsInt(); + LocationContainer container = mock(LocationContainer.class); + doReturn(id).when(container).getID(); + return (T) container; + } + } + }; + public static void checkAdaptors(Gson gson) { - TypeToken cell = new TypeToken() { }; + TypeToken cell = new TypeToken() {}; assertSame(gson.getAdapter(cell).getClass(), TreeTypeAdapter.class); - - TypeToken pottsCell = new TypeToken() { }; + + TypeToken pottsCell = new TypeToken() {}; assertSame(gson.getAdapter(pottsCell).getClass(), TreeTypeAdapter.class); - - TypeToken voxel = new TypeToken() { }; + + TypeToken voxel = new TypeToken() {}; assertSame(gson.getAdapter(voxel).getClass(), TreeTypeAdapter.class); - - TypeToken location = new TypeToken() { }; + + TypeToken location = new TypeToken() {}; assertSame(gson.getAdapter(location).getClass(), TreeTypeAdapter.class); - - TypeToken pottsLocation = new TypeToken() { }; + + TypeToken pottsLocation = + new TypeToken() {}; assertSame(gson.getAdapter(pottsLocation).getClass(), TreeTypeAdapter.class); } - - @Test(expected = UnsupportedOperationException.class) + + @Test public void constructor_called_throwsException() { - PottsOutputDeserializer deserializer = new PottsOutputDeserializer(); + assertThrows(UnsupportedOperationException.class, PottsOutputDeserializer::new); } - + @Test public void makeGSON_registersAdaptors() { Gson gson = PottsOutputDeserializer.makeGSON(); checkAdaptors(gson); } - + @Test public void deserializer_forCellNoRegion_createObject() { PottsCellDeserializer deserializer = new PottsCellDeserializer(); - + int id = randomIntBetween(1, 100); int parent = randomIntBetween(1, 100); int pop = randomIntBetween(1, 100); @@ -103,22 +104,38 @@ public void deserializer_forCellNoRegion_createObject() { int voxels = randomIntBetween(1, 100); int criticalVolume = randomIntBetween(1, 100); int criticalHeight = randomIntBetween(1, 100); - - String string = "{" - + "\"id\": " + id - + ",\"parent\": " + parent - + ",\"pop\": " + pop - + ",\"age\": " + age - + ",\"divisions\": " + divisions - + ",\"state\":\"" + state.name() + "\"" - + ",\"phase\":\"" + phase.name() + "\"" - + ",\"voxels\": " + voxels - + ",\"criticals\":[" + criticalVolume + "," + criticalHeight + "]" - + "}"; - + + String string = + "{" + + "\"id\": " + + id + + ",\"parent\": " + + parent + + ",\"pop\": " + + pop + + ",\"age\": " + + age + + ",\"divisions\": " + + divisions + + ",\"state\":\"" + + state.name() + + "\"" + + ",\"phase\":\"" + + phase.name() + + "\"" + + ",\"voxels\": " + + voxels + + ",\"criticals\":[" + + criticalVolume + + "," + + criticalHeight + + "]" + + "}"; + JsonObject json = JsonParser.parseString(string).getAsJsonObject(); - PottsCellContainer object = deserializer.deserialize(json, PottsCellContainer.class, CELL_CONTEXT); - + PottsCellContainer object = + deserializer.deserialize(json, PottsCellContainer.class, CELL_CONTEXT); + assertEquals(id, object.id); assertEquals(parent, object.parent); assertEquals(pop, object.pop); @@ -133,11 +150,11 @@ public void deserializer_forCellNoRegion_createObject() { assertNull(object.criticalRegionVolumes); assertNull(object.criticalRegionHeights); } - + @Test public void deserializer_forCellWithRegions_createObject() { PottsCellDeserializer deserializer = new PottsCellDeserializer(); - + int id = randomIntBetween(1, 100); int parent = randomIntBetween(1, 100); int pop = randomIntBetween(1, 100); @@ -148,7 +165,7 @@ public void deserializer_forCellWithRegions_createObject() { int voxels = randomIntBetween(1, 100); int criticalVolume = randomIntBetween(1, 100); int criticalHeight = randomIntBetween(1, 100); - + Region region1 = Region.DEFAULT; Region region2 = Region.NUCLEUS; int regionVoxels1 = randomIntBetween(1, 100); @@ -157,32 +174,60 @@ public void deserializer_forCellWithRegions_createObject() { int criticalRegionHeight1 = randomIntBetween(1, 100); int criticalRegionVolume2 = randomIntBetween(1, 100); int criticalRegionHeight2 = randomIntBetween(1, 100); - - String string = "{" - + "\"id\": " + id - + ",\"parent\": " + parent - + ",\"pop\": " + pop - + ",\"age\": " + age - + ",\"divisions\": " + divisions - + ",\"state\":\"" + state.name() + "\"" - + ",\"phase\": \"" + phase.name() + "\"" - + ",\"voxels\": " + voxels - + ",\"criticals\":[" + criticalVolume + "," + criticalHeight + "]" - + ",\"regions\":[" - + "{\"region\":" + region1.name() - + ",\"voxels\":" + regionVoxels1 - + ",\"criticals\":[" + criticalRegionVolume1 + "," + criticalRegionHeight1 + "]" - + "}," - + "{\"region\":" + region2.name() - + ",\"voxels\":" + regionVoxels2 - + ",\"criticals\":[" + criticalRegionVolume2 + "," + criticalRegionHeight2 + "]" - + "}" - + "]" - + "}"; - + + String string = + "{" + + "\"id\": " + + id + + ",\"parent\": " + + parent + + ",\"pop\": " + + pop + + ",\"age\": " + + age + + ",\"divisions\": " + + divisions + + ",\"state\":\"" + + state.name() + + "\"" + + ",\"phase\": \"" + + phase.name() + + "\"" + + ",\"voxels\": " + + voxels + + ",\"criticals\":[" + + criticalVolume + + "," + + criticalHeight + + "]" + + ",\"regions\":[" + + "{\"region\":" + + region1.name() + + ",\"voxels\":" + + regionVoxels1 + + ",\"criticals\":[" + + criticalRegionVolume1 + + "," + + criticalRegionHeight1 + + "]" + + "}," + + "{\"region\":" + + region2.name() + + ",\"voxels\":" + + regionVoxels2 + + ",\"criticals\":[" + + criticalRegionVolume2 + + "," + + criticalRegionHeight2 + + "]" + + "}" + + "]" + + "}"; + JsonObject json = JsonParser.parseString(string).getAsJsonObject(); - PottsCellContainer object = deserializer.deserialize(json, PottsCellContainer.class, CELL_CONTEXT); - + PottsCellContainer object = + deserializer.deserialize(json, PottsCellContainer.class, CELL_CONTEXT); + assertEquals(id, object.id); assertEquals(parent, object.parent); assertEquals(pop, object.pop); @@ -200,136 +245,204 @@ public void deserializer_forCellWithRegions_createObject() { assertEquals(criticalRegionVolume2, object.criticalRegionVolumes.get(region2), EPSILON); assertEquals(criticalRegionHeight2, object.criticalRegionHeights.get(region2), EPSILON); } - + @Test public void deserializer_forLocationNoRegion_createObject() { PottsLocationDeserializer deserializer = new PottsLocationDeserializer(); - + Region region = Region.UNDEFINED; int id = randomIntBetween(1, 100); - Voxel center = new Voxel(randomIntBetween(1, 100), randomIntBetween(1, 100), randomIntBetween(1, 100)); - + Voxel center = + new Voxel( + randomIntBetween(1, 100), + randomIntBetween(1, 100), + randomIntBetween(1, 100)); + int x1 = randomIntBetween(1, 100); int y1 = randomIntBetween(1, 100); int z1 = randomIntBetween(1, 100); - + int x2 = x1 + randomIntBetween(1, 100); int y2 = y1 + randomIntBetween(1, 100); int z2 = z1 + randomIntBetween(1, 100); - - String string = "{\"id\": " + id - + ",\"center\":[" + center.x + "," + center.y + "," + center.z + "]" - + ",\"location\":[" - + "{\"region\":" + region.name() + ",\"voxels\":[" - + "[" + x1 + "," + y1 + "," + z1 + "]," - + "[" + x2 + "," + y2 + "," + z2 + "]" - + "]}]}"; - + + String string = + "{\"id\": " + + id + + ",\"center\":[" + + center.x + + "," + + center.y + + "," + + center.z + + "]" + + ",\"location\":[" + + "{\"region\":" + + region.name() + + ",\"voxels\":[" + + "[" + + x1 + + "," + + y1 + + "," + + z1 + + "]," + + "[" + + x2 + + "," + + y2 + + "," + + z2 + + "]" + + "]}]}"; + ArrayList expected = new ArrayList<>(); expected.add(new Voxel(x1, y1, z1)); expected.add(new Voxel(x2, y2, z2)); - + JsonObject json = JsonParser.parseString(string).getAsJsonObject(); - PottsLocationContainer object = deserializer.deserialize(json, PottsLocationContainer.class, LOCATION_CONTEXT); - + PottsLocationContainer object = + deserializer.deserialize(json, PottsLocationContainer.class, LOCATION_CONTEXT); + assertEquals(id, object.id); assertEquals(center, object.center); assertNull(object.regions); - + ArrayList voxels = object.allVoxels; voxels.sort(VOXEL_COMPARATOR); expected.sort(VOXEL_COMPARATOR); assertEquals(expected, voxels); } - + @Test public void deserializer_forLocationWithRegion_createObject() { PottsLocationDeserializer deserializer = new PottsLocationDeserializer(); - + int id = randomIntBetween(1, 100); - Voxel center = new Voxel(randomIntBetween(1, 100), randomIntBetween(1, 100), randomIntBetween(1, 100)); - + Voxel center = + new Voxel( + randomIntBetween(1, 100), + randomIntBetween(1, 100), + randomIntBetween(1, 100)); + int x1 = randomIntBetween(1, 100); int y1 = randomIntBetween(1, 100); int z1 = randomIntBetween(1, 100); - + int x2 = x1 + randomIntBetween(1, 100); int y2 = y1 + randomIntBetween(1, 100); int z2 = z1 + randomIntBetween(1, 100); - + int x3 = x2 + randomIntBetween(1, 100); int y3 = y2 + randomIntBetween(1, 100); int z3 = z2 + randomIntBetween(1, 100); - + int x4 = x3 + randomIntBetween(1, 100); int y4 = y3 + randomIntBetween(1, 100); int z4 = z3 + randomIntBetween(1, 100); - + Region region1 = Region.DEFAULT; Region region2 = Region.NUCLEUS; - - String string = "{\"id\": " + id - + ",\"center\":[" + center.x + "," + center.y + "," + center.z + "]" - + ",\"location\":[" - + "{\"region\":" + region1.name() + ",\"voxels\":[" - + "[" + x1 + "," + y1 + "," + z1 + "]," - + "[" + x2 + "," + y2 + "," + z2 + "]" - + "]}," - + "{\"region\":" + region2.name() + ",\"voxels\":[" - + "[" + x3 + "," + y3 + "," + z3 + "]," - + "[" + x4 + "," + y4 + "," + z4 + "]" - + "]}]}"; - + + String string = + "{\"id\": " + + id + + ",\"center\":[" + + center.x + + "," + + center.y + + "," + + center.z + + "]" + + ",\"location\":[" + + "{\"region\":" + + region1.name() + + ",\"voxels\":[" + + "[" + + x1 + + "," + + y1 + + "," + + z1 + + "]," + + "[" + + x2 + + "," + + y2 + + "," + + z2 + + "]" + + "]}," + + "{\"region\":" + + region2.name() + + ",\"voxels\":[" + + "[" + + x3 + + "," + + y3 + + "," + + z3 + + "]," + + "[" + + x4 + + "," + + y4 + + "," + + z4 + + "]" + + "]}]}"; + ArrayList expected = new ArrayList<>(); expected.add(new Voxel(x1, y1, z1)); expected.add(new Voxel(x2, y2, z2)); expected.add(new Voxel(x3, y3, z3)); expected.add(new Voxel(x4, y4, z4)); - + ArrayList expected1 = new ArrayList<>(); expected1.add(new Voxel(x1, y1, z1)); expected1.add(new Voxel(x2, y2, z2)); - + ArrayList expected2 = new ArrayList<>(); expected2.add(new Voxel(x3, y3, z3)); expected2.add(new Voxel(x4, y4, z4)); - + JsonObject json = JsonParser.parseString(string).getAsJsonObject(); - PottsLocationContainer object = deserializer.deserialize(json, PottsLocationContainer.class, LOCATION_CONTEXT); - + PottsLocationContainer object = + deserializer.deserialize(json, PottsLocationContainer.class, LOCATION_CONTEXT); + assertEquals(id, object.id); assertEquals(center, object.center); - + assertTrue(object.regions.containsKey(region1)); assertTrue(object.regions.containsKey(region2)); - + ArrayList voxels = object.allVoxels; voxels.sort(VOXEL_COMPARATOR); expected.sort(VOXEL_COMPARATOR); assertEquals(expected, voxels); - + ArrayList voxels1 = object.regions.get(region1); voxels1.sort(VOXEL_COMPARATOR); expected1.sort(VOXEL_COMPARATOR); assertEquals(expected1, voxels1); - + ArrayList voxels2 = object.regions.get(region2); voxels2.sort(VOXEL_COMPARATOR); expected2.sort(VOXEL_COMPARATOR); assertEquals(expected2, voxels2); } - + @Test public void deserializer_forVoxel_createObject() { VoxelDeserializer deserializer = new VoxelDeserializer(); - + int x = randomIntBetween(1, 100); int y = randomIntBetween(1, 100); int z = randomIntBetween(1, 100); String string = "[" + x + "," + y + "," + z + "]"; - + Voxel expected = new Voxel(x, y, z); - + JsonArray json = JsonParser.parseString(string).getAsJsonArray(); Voxel object = deserializer.deserialize(json, Voxel.class, null); assertEquals(expected, object); diff --git a/test/arcade/potts/sim/output/PottsOutputLoaderTest.java b/test/arcade/potts/sim/output/PottsOutputLoaderTest.java index 75cafaeac..889c38cd7 100644 --- a/test/arcade/potts/sim/output/PottsOutputLoaderTest.java +++ b/test/arcade/potts/sim/output/PottsOutputLoaderTest.java @@ -1,6 +1,6 @@ package arcade.potts.sim.output; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.google.gson.Gson; import arcade.core.sim.Series; import arcade.core.sim.output.OutputDeserializerTest; diff --git a/test/arcade/potts/sim/output/PottsOutputSaverTest.java b/test/arcade/potts/sim/output/PottsOutputSaverTest.java index efaac4778..c40bc8487 100644 --- a/test/arcade/potts/sim/output/PottsOutputSaverTest.java +++ b/test/arcade/potts/sim/output/PottsOutputSaverTest.java @@ -1,6 +1,6 @@ package arcade.potts.sim.output; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.google.gson.Gson; import arcade.core.sim.Series; import arcade.core.sim.output.OutputSerializerTest; diff --git a/test/arcade/potts/sim/output/PottsOutputSerializerTest.java b/test/arcade/potts/sim/output/PottsOutputSerializerTest.java index 850fdeed3..3b4fc0a94 100644 --- a/test/arcade/potts/sim/output/PottsOutputSerializerTest.java +++ b/test/arcade/potts/sim/output/PottsOutputSerializerTest.java @@ -3,7 +3,7 @@ import java.lang.reflect.Type; import java.util.ArrayList; import java.util.EnumMap; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.google.gson.Gson; import com.google.gson.JsonArray; import com.google.gson.JsonElement; @@ -19,7 +19,7 @@ import arcade.potts.env.location.PottsLocationContainer; import arcade.potts.env.location.Voxel; import arcade.potts.sim.PottsSeries; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.core.ARCADETestUtilities.*; import static arcade.potts.sim.output.PottsOutputSerializer.*; @@ -28,117 +28,131 @@ import static arcade.potts.util.PottsEnums.State; public class PottsOutputSerializerTest { - private static final MersenneTwisterFast RANDOM = new MersenneTwisterFast(randomIntBetween(1, 1000)); - - static final JsonSerializationContext LOCATION_CONTEXT = new JsonSerializationContext() { - @Override - public JsonElement serialize(Object src) { - Voxel voxel = (Voxel) src; - JsonArray json = new JsonArray(); - json.add(voxel.x + "|" + voxel.y + "|" + voxel.z); - return json; - } - - @Override - public JsonElement serialize(Object src, Type typeOfSrc) { return null; } - }; - + private static final MersenneTwisterFast RANDOM = + new MersenneTwisterFast(randomIntBetween(1, 1000)); + + static final JsonSerializationContext LOCATION_CONTEXT = + new JsonSerializationContext() { + @Override + public JsonElement serialize(Object src) { + Voxel voxel = (Voxel) src; + JsonArray json = new JsonArray(); + json.add(voxel.x + "|" + voxel.y + "|" + voxel.z); + return json; + } + + @Override + public JsonElement serialize(Object src, Type typeOfSrc) { + return null; + } + }; + public static void checkAdaptors(Gson gson) { - TypeToken series = new TypeToken() { }; + TypeToken series = new TypeToken() {}; assertSame(gson.getAdapter(series).getClass(), TreeTypeAdapter.class); - - TypeToken cellContainer = new TypeToken() { }; + + TypeToken cellContainer = new TypeToken() {}; assertSame(gson.getAdapter(cellContainer).getClass(), TreeTypeAdapter.class); - - TypeToken cell = new TypeToken() { }; + + TypeToken cell = new TypeToken() {}; assertSame(gson.getAdapter(cell).getClass(), TreeTypeAdapter.class); - - TypeToken locationContainer = new TypeToken() { }; + + TypeToken locationContainer = new TypeToken() {}; assertSame(gson.getAdapter(locationContainer).getClass(), TreeTypeAdapter.class); - - TypeToken location = new TypeToken() { }; + + TypeToken location = new TypeToken() {}; assertSame(gson.getAdapter(location).getClass(), TreeTypeAdapter.class); - - TypeToken voxel = new TypeToken() { }; + + TypeToken voxel = new TypeToken() {}; assertSame(gson.getAdapter(voxel).getClass(), TreeTypeAdapter.class); } - - @Test(expected = UnsupportedOperationException.class) + + @Test public void constructor_called_throwsException() { - PottsOutputSerializer serializer = new PottsOutputSerializer(); + assertThrows(UnsupportedOperationException.class, PottsOutputSerializer::new); } - + @Test public void makeGSON_registersAdaptors() { Gson gson = PottsOutputSerializer.makeGSON(); checkAdaptors(gson); } - + @Test public void serialize_forSeries_createsJSON() { PottsSeriesSerializer serializer = new PottsSeriesSerializer(); PottsSeries series = mock(PottsSeries.class); - + series.potts = new MiniBox(); - + String key1 = randomString(); String value1 = randomString(); series.potts.put(key1, value1); - + String key2 = randomString(); int value2 = randomIntBetween(0, 10); series.potts.put(key2, value2); - - JsonSerializationContext context = new JsonSerializationContext() { - @Override - public JsonElement serialize(Object src) { - if (src instanceof MiniBox) { - MiniBox box = (MiniBox) src; - JsonObject json = new JsonObject(); - json.addProperty(box.getKeys().get(0), box.get(box.getKeys().get(0))); - json.addProperty(box.getKeys().get(1), box.getInt(box.getKeys().get(1))); - return json; - } - return null; - } - - @Override - public JsonElement serialize(Object src, Type typeOfSrc) { - JsonObject json = new JsonObject(); - json.addProperty("SERIES", "SERIES"); - return json; - } - }; - - String expected = "{" - + "\"SERIES\":\"SERIES\"," - + "\"potts\":{" - + "\"" + key1 + "\":\"" + value1 + "\"," - + "\"" + key2 + "\":" + value2 - + "}" - + "}"; - + + JsonSerializationContext context = + new JsonSerializationContext() { + @Override + public JsonElement serialize(Object src) { + if (src instanceof MiniBox) { + MiniBox box = (MiniBox) src; + JsonObject json = new JsonObject(); + json.addProperty(box.getKeys().get(0), box.get(box.getKeys().get(0))); + json.addProperty( + box.getKeys().get(1), box.getInt(box.getKeys().get(1))); + return json; + } + return null; + } + + @Override + public JsonElement serialize(Object src, Type typeOfSrc) { + JsonObject json = new JsonObject(); + json.addProperty("SERIES", "SERIES"); + return json; + } + }; + + String expected = + "{" + + "\"SERIES\":\"SERIES\"," + + "\"potts\":{" + + "\"" + + key1 + + "\":\"" + + value1 + + "\"," + + "\"" + + key2 + + "\":" + + value2 + + "}" + + "}"; + JsonElement json = serializer.serialize(series, null, context); assertEquals(expected, json.toString()); } - + @Test public void serialize_forCellContainer_passesCall() { CellContainer cellContainer = mock(CellContainer.class); JsonSerializationContext context = mock(JsonSerializationContext.class); JsonElement expected = mock(JsonElement.class); doReturn(expected).when(context).serialize(cellContainer, PottsCellContainer.class); - + CellSerializer serializer = new CellSerializer(); JsonElement jsonElement = serializer.serialize(cellContainer, null, context); - + assertSame(expected, jsonElement); } - + @Test public void serialize_forCellNoRegion_createsJSON() { PottsCellSerializer serializer = new PottsCellSerializer(); - + int id = randomIntBetween(1, 100); int parent = randomIntBetween(1, 100); int pop = randomIntBetween(1, 100); @@ -149,30 +163,64 @@ public void serialize_forCellNoRegion_createsJSON() { int voxels = randomIntBetween(1, 100); int criticalVolume = randomIntBetween(1, 100); int criticalHeight = randomIntBetween(1, 100); - - PottsCellContainer cellContainer = new PottsCellContainer(id, parent, pop, age, divisions, - state, phase, voxels, null, criticalVolume, criticalHeight, null, null); - - String expected = "{" - + "\"id\":" + id + "," - + "\"parent\":" + parent + "," - + "\"pop\":" + pop + "," - + "\"age\":" + age + "," - + "\"divisions\":" + divisions + "," - + "\"state\":\"" + state.name() + "\"," - + "\"phase\":\"" + phase.name() + "\"," - + "\"voxels\":" + voxels + "," - + "\"criticals\":[" + criticalVolume + ".0," + criticalHeight + ".0]" - + "}"; - + + PottsCellContainer cellContainer = + new PottsCellContainer( + id, + parent, + pop, + age, + divisions, + state, + phase, + voxels, + null, + criticalVolume, + criticalHeight, + null, + null); + + String expected = + "{" + + "\"id\":" + + id + + "," + + "\"parent\":" + + parent + + "," + + "\"pop\":" + + pop + + "," + + "\"age\":" + + age + + "," + + "\"divisions\":" + + divisions + + "," + + "\"state\":\"" + + state.name() + + "\"," + + "\"phase\":\"" + + phase.name() + + "\"," + + "\"voxels\":" + + voxels + + "," + + "\"criticals\":[" + + criticalVolume + + ".0," + + criticalHeight + + ".0]" + + "}"; + JsonElement json = serializer.serialize(cellContainer, null, null); assertEquals(expected, json.toString()); } - + @Test public void serialize_forCellWithRegion_createsJSON() { PottsCellSerializer serializer = new PottsCellSerializer(); - + int id = randomIntBetween(1, 100); int parent = randomIntBetween(1, 100); int pop = randomIntBetween(1, 100); @@ -183,7 +231,7 @@ public void serialize_forCellWithRegion_createsJSON() { int voxels = randomIntBetween(1, 100); int criticalVolume = randomIntBetween(1, 100); int criticalHeight = randomIntBetween(1, 100); - + Region region1 = Region.DEFAULT; Region region2 = Region.NUCLEUS; int regionVoxels1 = randomIntBetween(1, 100); @@ -192,168 +240,276 @@ public void serialize_forCellWithRegion_createsJSON() { int criticalRegionHeight1 = randomIntBetween(1, 100); int criticalRegionVolume2 = randomIntBetween(1, 100); int criticalRegionHeight2 = randomIntBetween(1, 100); - + EnumMap regionVoxels = new EnumMap<>(Region.class); regionVoxels.put(region1, regionVoxels1); regionVoxels.put(region2, regionVoxels2); - + EnumMap criticalRegionVolumes = new EnumMap<>(Region.class); criticalRegionVolumes.put(region1, (double) criticalRegionVolume1); criticalRegionVolumes.put(region2, (double) criticalRegionVolume2); - + EnumMap criticalRegionHeights = new EnumMap<>(Region.class); criticalRegionHeights.put(region1, (double) criticalRegionHeight1); criticalRegionHeights.put(region2, (double) criticalRegionHeight2); - - PottsCellContainer cellContainer = new PottsCellContainer(id, parent, pop, age, divisions, - state, phase, voxels, regionVoxels, criticalVolume, criticalHeight, - criticalRegionVolumes, criticalRegionHeights); - - String expected = "{" - + "\"id\":" + id + "," - + "\"parent\":" + parent + "," - + "\"pop\":" + pop + "," - + "\"age\":" + age + "," - + "\"divisions\":" + divisions + "," - + "\"state\":\"" + state.name() + "\"," - + "\"phase\":\"" + phase.name() + "\"," - + "\"voxels\":" + voxels + "," - + "\"criticals\":[" + criticalVolume + ".0," + criticalHeight + ".0]," - + "\"regions\":[" - + "{\"region\":\"DEFAULT\"," - + "\"voxels\":" + regionVoxels1 + "," - + "\"criticals\":[" + criticalRegionVolume1 + ".0," + criticalRegionHeight1 + ".0]" - + "}," - + "{\"region\":\"NUCLEUS\"," - + "\"voxels\":" + regionVoxels2 + "," - + "\"criticals\":[" + criticalRegionVolume2 + ".0," + criticalRegionHeight2 + ".0]" - + "}]" - + "}"; - + + PottsCellContainer cellContainer = + new PottsCellContainer( + id, + parent, + pop, + age, + divisions, + state, + phase, + voxels, + regionVoxels, + criticalVolume, + criticalHeight, + criticalRegionVolumes, + criticalRegionHeights); + + String expected = + "{" + + "\"id\":" + + id + + "," + + "\"parent\":" + + parent + + "," + + "\"pop\":" + + pop + + "," + + "\"age\":" + + age + + "," + + "\"divisions\":" + + divisions + + "," + + "\"state\":\"" + + state.name() + + "\"," + + "\"phase\":\"" + + phase.name() + + "\"," + + "\"voxels\":" + + voxels + + "," + + "\"criticals\":[" + + criticalVolume + + ".0," + + criticalHeight + + ".0]," + + "\"regions\":[" + + "{\"region\":\"DEFAULT\"," + + "\"voxels\":" + + regionVoxels1 + + "," + + "\"criticals\":[" + + criticalRegionVolume1 + + ".0," + + criticalRegionHeight1 + + ".0]" + + "}," + + "{\"region\":\"NUCLEUS\"," + + "\"voxels\":" + + regionVoxels2 + + "," + + "\"criticals\":[" + + criticalRegionVolume2 + + ".0," + + criticalRegionHeight2 + + ".0]" + + "}]" + + "}"; + JsonElement json = serializer.serialize(cellContainer, null, null); assertEquals(expected, json.toString()); } - + @Test public void serialize_forLocationContainer_passesCall() { LocationContainer locationContainer = mock(LocationContainer.class); JsonSerializationContext context = mock(JsonSerializationContext.class); JsonElement expected = mock(JsonElement.class); doReturn(expected).when(context).serialize(locationContainer, PottsLocationContainer.class); - + LocationSerializer serializer = new LocationSerializer(); JsonElement jsonElement = serializer.serialize(locationContainer, null, context); - + assertSame(expected, jsonElement); } - + @Test public void serialize_forLocationNoRegion_createJSON() { PottsLocationSerializer serializer = new PottsLocationSerializer(); - + int id = randomIntBetween(1, 100); - Voxel center = new Voxel(randomIntBetween(1, 100), randomIntBetween(1, 100), randomIntBetween(1, 100)); - + Voxel center = + new Voxel( + randomIntBetween(1, 100), + randomIntBetween(1, 100), + randomIntBetween(1, 100)); + int x1 = randomIntBetween(1, 100); int y1 = randomIntBetween(1, 100); int z1 = randomIntBetween(1, 100); - + int x2 = x1 + randomIntBetween(1, 100); int y2 = y1 + randomIntBetween(1, 100); int z2 = z1 + randomIntBetween(1, 100); - + ArrayList voxels = new ArrayList<>(); voxels.add(new Voxel(x1, y1, z1)); voxels.add(new Voxel(x2, y2, z2)); - + PottsLocationContainer locationContainer = new PottsLocationContainer(id, center, voxels); - - String expected = "{" - + "\"id\":" + id + "," - + "\"center\":[\"" + center.x + "|" + center.y + "|" + center.z + "\"]," - + "\"location\":[" - + "{\"region\":\"UNDEFINED\",\"voxels\":[" - + "[\"" + x1 + "|" + y1 + "|" + z1 + "\"]," - + "[\"" + x2 + "|" + y2 + "|" + z2 + "\"]" - + "]}" - + "]}"; - + + String expected = + "{" + + "\"id\":" + + id + + "," + + "\"center\":[\"" + + center.x + + "|" + + center.y + + "|" + + center.z + + "\"]," + + "\"location\":[" + + "{\"region\":\"UNDEFINED\",\"voxels\":[" + + "[\"" + + x1 + + "|" + + y1 + + "|" + + z1 + + "\"]," + + "[\"" + + x2 + + "|" + + y2 + + "|" + + z2 + + "\"]" + + "]}" + + "]}"; + JsonElement json = serializer.serialize(locationContainer, null, LOCATION_CONTEXT); assertEquals(expected, json.toString()); } - + @Test public void serialize_forLocationWithRegion_createJSON() { PottsLocationSerializer serializer = new PottsLocationSerializer(); - + int id = randomIntBetween(1, 100); - Voxel center = new Voxel(randomIntBetween(1, 100), randomIntBetween(1, 100), randomIntBetween(1, 100)); - + Voxel center = + new Voxel( + randomIntBetween(1, 100), + randomIntBetween(1, 100), + randomIntBetween(1, 100)); + int x1 = randomIntBetween(1, 100); int y1 = randomIntBetween(1, 100); int z1 = randomIntBetween(1, 100); - + int x2 = x1 + randomIntBetween(1, 100); int y2 = y1 + randomIntBetween(1, 100); int z2 = z1 + randomIntBetween(1, 100); - + int x3 = x2 + randomIntBetween(1, 100); int y3 = y2 + randomIntBetween(1, 100); int z3 = z2 + randomIntBetween(1, 100); - + int x4 = x3 + randomIntBetween(1, 100); int y4 = y3 + randomIntBetween(1, 100); int z4 = z3 + randomIntBetween(1, 100); - + ArrayList voxels = new ArrayList<>(); voxels.add(new Voxel(x1, y1, z1)); voxels.add(new Voxel(x2, y2, z2)); voxels.add(new Voxel(x3, y3, z3)); voxels.add(new Voxel(x4, y4, z4)); - + ArrayList region1 = new ArrayList<>(); region1.add(new Voxel(x1, y1, z1)); region1.add(new Voxel(x2, y2, z2)); - + ArrayList region2 = new ArrayList<>(); region2.add(new Voxel(x3, y3, z3)); region2.add(new Voxel(x4, y4, z4)); - + EnumMap> regions = new EnumMap<>(Region.class); regions.put(Region.DEFAULT, region1); regions.put(Region.NUCLEUS, region2); - - PottsLocationContainer locationContainer = new PottsLocationContainer(id, center, voxels, regions); - - String expected = "{" - + "\"id\":" + id + "," - + "\"center\":[\"" + center.x + "|" + center.y + "|" + center.z + "\"]," - + "\"location\":[" - + "{\"region\":\"DEFAULT\",\"voxels\":[" - + "[\"" + x1 + "|" + y1 + "|" + z1 + "\"]," - + "[\"" + x2 + "|" + y2 + "|" + z2 + "\"]" - + "]}," - + "{\"region\":\"NUCLEUS\",\"voxels\":[" - + "[\"" + x3 + "|" + y3 + "|" + z3 + "\"]," - + "[\"" + x4 + "|" + y4 + "|" + z4 + "\"]" - + "]}" - + "]}"; - + + PottsLocationContainer locationContainer = + new PottsLocationContainer(id, center, voxels, regions); + + String expected = + "{" + + "\"id\":" + + id + + "," + + "\"center\":[\"" + + center.x + + "|" + + center.y + + "|" + + center.z + + "\"]," + + "\"location\":[" + + "{\"region\":\"DEFAULT\",\"voxels\":[" + + "[\"" + + x1 + + "|" + + y1 + + "|" + + z1 + + "\"]," + + "[\"" + + x2 + + "|" + + y2 + + "|" + + z2 + + "\"]" + + "]}," + + "{\"region\":\"NUCLEUS\",\"voxels\":[" + + "[\"" + + x3 + + "|" + + y3 + + "|" + + z3 + + "\"]," + + "[\"" + + x4 + + "|" + + y4 + + "|" + + z4 + + "\"]" + + "]}" + + "]}"; + JsonElement json = serializer.serialize(locationContainer, null, LOCATION_CONTEXT); assertEquals(expected, json.toString()); } - + @Test public void serialize_forVoxel_createsJSON() { VoxelSerializer serializer = new VoxelSerializer(); - + int x = randomIntBetween(1, 100); int y = randomIntBetween(1, 100); int z = randomIntBetween(1, 100); Voxel voxel = new Voxel(x, y, z); - + String expected = "[" + x + "," + y + "," + z + "]"; - + JsonElement json = serializer.serialize(voxel, null, null); assertEquals(expected, json.toString()); } diff --git a/test/arcade/potts/util/PottsEnumsTest.java b/test/arcade/potts/util/PottsEnumsTest.java index 963f3a239..8189aea7d 100644 --- a/test/arcade/potts/util/PottsEnumsTest.java +++ b/test/arcade/potts/util/PottsEnumsTest.java @@ -2,78 +2,78 @@ import java.util.ArrayList; import java.util.EnumSet; -import org.junit.Test; +import org.junit.jupiter.api.Test; import ec.util.MersenneTwisterFast; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static arcade.potts.util.PottsEnums.Direction; import static arcade.potts.util.PottsEnums.Phase; import static arcade.potts.util.PottsEnums.Term; public class PottsEnumsTest { - @Test(expected = UnsupportedOperationException.class) + @Test public void constructor_called_throwsException() { - PottsEnums enums = new PottsEnums(); + assertThrows(UnsupportedOperationException.class, PottsEnums::new); } - + @Test public void Phase_random_returnsPhase() { // Create set of all values. EnumSet enumSet = EnumSet.allOf(Phase.class); enumSet.remove(Phase.UNDEFINED); - + // Create set of all random values. ArrayList enumRandom = new ArrayList<>(); - + int n = Phase.values().length - 1; for (int i = 0; i < n; i++) { MersenneTwisterFast rng = mock(MersenneTwisterFast.class); doReturn(i).when(rng).nextInt(n); enumRandom.add(Phase.random(rng)); } - + // Compare resulting sets. EnumSet enumSetRandom = EnumSet.copyOf(enumRandom); assertEquals(enumSet, enumSetRandom); } - + @Test public void Term_random_returnsTerm() { // Create set of all values. EnumSet enumSet = EnumSet.allOf(Term.class); enumSet.remove(Term.UNDEFINED); - + // Create set of all random values. ArrayList enumRandom = new ArrayList<>(); - + int n = Term.values().length - 1; for (int i = 0; i < n; i++) { MersenneTwisterFast rng = mock(MersenneTwisterFast.class); doReturn(i).when(rng).nextInt(n); enumRandom.add(Term.random(rng)); } - + // Compare resulting sets. EnumSet enumSetRandom = EnumSet.copyOf(enumRandom); assertEquals(enumSet, enumSetRandom); } - + @Test public void Direction_random_returnsDirection() { // Create set of all values. EnumSet enumSet = EnumSet.allOf(Direction.class); enumSet.remove(Direction.UNDEFINED); - + // Create set of all random values. ArrayList enumRandom = new ArrayList<>(); - + int n = Direction.values().length - 1; for (int i = 0; i < n; i++) { MersenneTwisterFast rng = mock(MersenneTwisterFast.class); doReturn(i).when(rng).nextInt(n); enumRandom.add(Direction.random(rng)); } - + // Compare resulting sets. EnumSet enumSetRandom = EnumSet.copyOf(enumRandom); assertEquals(enumSet, enumSetRandom);