diff --git a/gcm4/src/main/java/nucleus/NucleusError.java b/gcm4/src/main/java/nucleus/NucleusError.java index b51e12dca..6e7e78d9f 100644 --- a/gcm4/src/main/java/nucleus/NucleusError.java +++ b/gcm4/src/main/java/nucleus/NucleusError.java @@ -33,11 +33,13 @@ public enum NucleusError implements ContractError { LABLER_GENERATED_LABEL_WITH_INCORRECT_ID("Event labler generated a label with an incorrect event labeler id"), LABLER_GENERATED_LABEL_WITH_INCORRECT_PRIMARY_KEY("Event labler generated a label with an incorrect primary key"), MISSING_PLUGIN("A plugin is missing"), + NEGATIVE_START_TIME("Simulation start time is negative"), NEGATIVE_THREAD_COUNT("Negative thread count"), NON_EXISTANT_SCEANARIO_PROGRESS("The scenario progress file does not exist, but is required when continuation from progress file is chosen"), NULL_ACTOR_CONTEXT_CONSUMER("Null actor context consumer"), NULL_REPORT_CONTEXT_CONSUMER("Null report context consumer"), NULL_ACTOR_ID("Null actor id"), + NULL_BASE_DATE("Null base date"), NULL_DATA_MANAGER("Null data manager"), NULL_DATA_VIEW("Null data view"), NULL_DATA_MANAGER_CLASS("Null data manager class"), @@ -71,6 +73,7 @@ public enum NucleusError implements ContractError { NULL_SCENARIO_ID("Null scenario id"), NULL_SCENARIO_PROGRESS_FILE("Null scenario progress file"), NULL_SIMULATION_CONTEXT("Null simulation context"), + NULL_SIMULATION_TIME("Null simulation time"), PAST_PLANNING_TIME("Plan execution time is in the past"), PLUGIN_INITIALIZATION_CLOSED("Plugin context is no longer valid"), REPEATED_EXECUTION("Attempted repeat execution of simulation engine"), diff --git a/gcm4/src/main/java/nucleus/Simulation.java b/gcm4/src/main/java/nucleus/Simulation.java index fd46fcbc5..f9c5c51ac 100644 --- a/gcm4/src/main/java/nucleus/Simulation.java +++ b/gcm4/src/main/java/nucleus/Simulation.java @@ -125,6 +125,23 @@ public Builder setOutputConsumer(Consumer outputConsumer) { return this; } + /** + * Set the simulation time. Defaults to the current date and a start + * time of zero. + * + * @throws ContractException + *
  • {@link NucleusError#NULL_SIMULATION_TIME} if the + * simulation time is null + * + */ + public Builder setSimulationTime(SimulationTime simulationTime) { + if (simulationTime == null) { + throw new ContractException(NucleusError.NULL_SIMULATION_TIME); + } + data.simulationTime = simulationTime; + return this; + } + /** * Adds a plugin initializer to this builder for inclusion in the * simulation @@ -167,6 +184,7 @@ private static enum Planner { private static class Data { private List plugins = new ArrayList<>(); private Consumer outputConsumer; + private SimulationTime simulationTime = SimulationTime.builder().build(); } /** @@ -622,6 +640,8 @@ public void execute() { throw new ContractException(NucleusError.REPEATED_EXECUTION); } started = true; + + time = data.simulationTime.getStartTime(); // set the output consumer outputConsumer = data.outputConsumer; @@ -1141,8 +1161,8 @@ protected void releaseObservationEventForDataManager(final Event event) { if (event == null) { throw new ContractException(NucleusError.NULL_EVENT); } - - if(!dataManagerQueueActive) { + + if (!dataManagerQueueActive) { throw new ContractException(NucleusError.OBSERVATION_EVENT_IMPROPER_RELEASE); } @@ -1181,7 +1201,7 @@ protected void releaseMutationEventForDataManager(final Event event) { if (event == null) { throw new ContractException(NucleusError.NULL_EVENT); } - + if (focalReportId != null) { throw new ContractException(NucleusError.REPORT_ATTEMPTING_MUTATION, focalReportId); } diff --git a/gcm4/src/main/java/nucleus/SimulationTime.java b/gcm4/src/main/java/nucleus/SimulationTime.java new file mode 100644 index 000000000..2c7a65c99 --- /dev/null +++ b/gcm4/src/main/java/nucleus/SimulationTime.java @@ -0,0 +1,99 @@ +package nucleus; + +import java.time.LocalDate; + +import net.jcip.annotations.Immutable; +import util.errors.ContractException; + +/** + * An immutable data class that holds 1) the base date aligned to simulation + * time zero and 2) the simulation start time as a floating point number of + * days. + * + * + * + */ +@Immutable +public class SimulationTime { + + private static class Data { + private double startTime = 0; + private LocalDate baseDate = LocalDate.now(); + } + + private final Data data; + + private SimulationTime(Data data) { + this.data = data; + } + + public static Builder builder() { + return new Builder(); + } + + /** + * Builder class for SimulationTime + * + */ + public static class Builder { + private Data data = new Data(); + + public SimulationTime build() { + try { + + return new SimulationTime(data); + } finally { + data = new Data(); + } + } + + /** + * Sets the time (floating point days) of simulation start. Defaults to + * zero. + * + * @throws ContractException + *
  • {@linkplain NucleusError#NEGATIVE_START_TIME} if the + * start time is negative
  • + */ + public Builder setStartTime(double startTime) { + if (startTime < 0) { + throw new ContractException(NucleusError.NEGATIVE_START_TIME); + } + data.startTime = startTime; + return this; + } + + /** + * Sets the base date that synchronizes with simulation time zero. + * Defaults to the current date. + * + * @throws ContractException + *
  • {@linkplain NucleusError#NULL_BASE_DATE} if the base + * date is null
  • + */ + public Builder setBaseDate(LocalDate localDate) { + if (localDate == null) { + throw new ContractException(NucleusError.NULL_BASE_DATE); + } + data.baseDate = localDate; + return this; + } + } + + /** + * Returns the time (floating point days) of simulation start. + * + */ + public double getStartTime() { + return data.startTime; + } + + /** + * Returns the base date that synchronizes with simulation time zero. + * + */ + public LocalDate getBaseDate() { + return data.baseDate; + } + +}