diff --git a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/core/Resources.java b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/core/Resources.java
index 087815118a..c0e72fcea0 100644
--- a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/core/Resources.java
+++ b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/core/Resources.java
@@ -1,11 +1,13 @@
package gov.nasa.jpl.aerie.contrib.streamline.core;
import gov.nasa.jpl.aerie.contrib.streamline.modeling.clocks.Clock;
+import gov.nasa.jpl.aerie.contrib.streamline.modeling.clocks.InstantClock;
import gov.nasa.jpl.aerie.merlin.framework.Condition;
import gov.nasa.jpl.aerie.merlin.framework.Scoped;
import gov.nasa.jpl.aerie.merlin.protocol.types.Duration;
import gov.nasa.jpl.aerie.merlin.protocol.types.Unit;
+import java.time.Instant;
import java.util.Collection;
import java.util.Objects;
import java.util.Optional;
@@ -20,6 +22,7 @@
import static gov.nasa.jpl.aerie.contrib.streamline.debugging.Dependencies.addDependency;
import static gov.nasa.jpl.aerie.contrib.streamline.debugging.Naming.*;
import static gov.nasa.jpl.aerie.contrib.streamline.modeling.clocks.Clock.clock;
+import static gov.nasa.jpl.aerie.contrib.streamline.modeling.clocks.InstantClockResources.addToInstant;
import static gov.nasa.jpl.aerie.merlin.framework.ModelActions.*;
import static gov.nasa.jpl.aerie.merlin.protocol.types.Duration.ZERO;
import static gov.nasa.jpl.aerie.contrib.streamline.modeling.discrete.Discrete.discrete;
@@ -38,22 +41,26 @@ private Resources() {}
* This method is idempotent; calling it multiple times is the same as calling it once.
*
*/
- public static void init() {
- currentTime();
+ public static void init(Instant planStart) {
+ CLOCK = resource(clock(ZERO));
+ ABSOLUTE_CLOCK = name(addToInstant(planStart, CLOCK), "Global Absolute Simulation Clock");
}
// TODO if Aerie provides either a `getElapsedTime` method or dynamic allocation of Cells, we can avoid this mutable static variable
- private static Resource CLOCK = resource(clock(ZERO));
+ private static Resource CLOCK;
+ private static Resource ABSOLUTE_CLOCK;
public static Duration currentTime() {
- try {
- return currentValue(CLOCK);
- } catch (Scoped.EmptyDynamicCellException | IllegalArgumentException e) {
- // If we're running unit tests, several simulations can happen without reloading the Resources class.
- // In that case, we'll have discarded the clock resource we were using, and get the above exception.
- // REVIEW: Is there a cleaner way to make sure this resource gets (re-)initialized?
- CLOCK = resource(clock(ZERO));
- return currentValue(CLOCK);
- }
+ return currentValue(CLOCK);
+ }
+ public static Instant currentInstant() {
+ return currentValue(ABSOLUTE_CLOCK);
+ }
+
+ public static Resource simulationClock() {
+ return CLOCK;
+ }
+ public static Resource absoluteClock() {
+ return ABSOLUTE_CLOCK;
}
public static D currentData(Resource resource) {
diff --git a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/Registrar.java b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/Registrar.java
index a8ab5ecce3..77545fc939 100644
--- a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/Registrar.java
+++ b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/Registrar.java
@@ -15,6 +15,8 @@
import gov.nasa.jpl.aerie.merlin.protocol.types.RealDynamics;
import gov.nasa.jpl.aerie.merlin.protocol.types.Unit;
+import java.time.Instant;
+
import static gov.nasa.jpl.aerie.contrib.streamline.core.Reactions.whenever;
import static gov.nasa.jpl.aerie.contrib.streamline.core.Resources.currentData;
import static gov.nasa.jpl.aerie.contrib.streamline.core.Resources.currentValue;
@@ -54,8 +56,8 @@ public enum ErrorBehavior {
Throw
}
- public Registrar(final gov.nasa.jpl.aerie.merlin.framework.Registrar baseRegistrar, final ErrorBehavior errorBehavior) {
- Resources.init();
+ public Registrar(final gov.nasa.jpl.aerie.merlin.framework.Registrar baseRegistrar, final Instant planStart, final ErrorBehavior errorBehavior) {
+ Resources.init(planStart);
Logging.init(baseRegistrar);
this.baseRegistrar = baseRegistrar;
this.errorBehavior = errorBehavior;
diff --git a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/InstantClock.java b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/InstantClock.java
new file mode 100644
index 0000000000..e6c866fd23
--- /dev/null
+++ b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/InstantClock.java
@@ -0,0 +1,24 @@
+package gov.nasa.jpl.aerie.contrib.streamline.modeling.clocks;
+
+import gov.nasa.jpl.aerie.contrib.streamline.core.Dynamics;
+import gov.nasa.jpl.aerie.merlin.protocol.types.Duration;
+
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+
+import static gov.nasa.jpl.aerie.merlin.protocol.types.Duration.addToInstant;
+
+/**
+ * A variation on {@link Clock} that represents an absolute {@link Instant}
+ * instead of a relative {@link Duration}.
+ */
+public record InstantClock(Instant extract) implements Dynamics {
+ @Override
+ public InstantClock step(Duration t) {
+ return new InstantClock(addToInstant(extract, t));
+ }
+
+ static Duration durationBetween(Instant start, Instant end) {
+ return Duration.of(ChronoUnit.MICROS.between(start, end), Duration.MICROSECONDS);
+ }
+}
diff --git a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/InstantClockResources.java b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/InstantClockResources.java
new file mode 100644
index 0000000000..204ef2c3c2
--- /dev/null
+++ b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/InstantClockResources.java
@@ -0,0 +1,56 @@
+package gov.nasa.jpl.aerie.contrib.streamline.modeling.clocks;
+
+import gov.nasa.jpl.aerie.contrib.streamline.core.*;
+import gov.nasa.jpl.aerie.contrib.streamline.core.monads.ResourceMonad;
+import gov.nasa.jpl.aerie.contrib.streamline.modeling.discrete.Discrete;
+import gov.nasa.jpl.aerie.merlin.protocol.types.Duration;
+
+import java.time.Instant;
+
+import static gov.nasa.jpl.aerie.contrib.streamline.core.MutableResource.resource;
+import static gov.nasa.jpl.aerie.contrib.streamline.core.monads.ResourceMonad.map;
+import static gov.nasa.jpl.aerie.contrib.streamline.debugging.Naming.name;
+import static gov.nasa.jpl.aerie.contrib.streamline.modeling.discrete.DiscreteResources.constant;
+
+public class InstantClockResources {
+ /**
+ * Create an absolute clock that starts now at the given start time.
+ */
+ public static MutableResource absoluteClock(Instant startTime) {
+ return resource(new InstantClock(startTime));
+ }
+
+ public static Resource addToInstant(Instant zeroTime, Resource relativeClock) {
+ return addToInstant(constant(zeroTime), relativeClock);
+ }
+
+ public static Resource addToInstant(Resource> zeroTime, Resource relativeClock) {
+ return name(
+ map(zeroTime, relativeClock, (zero, clock) ->
+ new InstantClock(Duration.addToInstant(zero.extract(), clock.extract()))),
+ "%s + %s",
+ zeroTime,
+ relativeClock);
+ }
+
+ public static Resource relativeTo(Resource clock, Resource> zeroTime) {
+ return name(ResourceMonad.map(clock, zeroTime, (c, t) -> new Clock(InstantClock.durationBetween(t.extract(), c.extract()))),
+ "%s relative to %s", clock, zeroTime);
+ }
+
+ public static Resource> lessThan(Resource clock, Resource> threshold) {
+ return ClockResources.lessThan(relativeTo(clock, threshold), constant(Duration.ZERO));
+ }
+
+ public static Resource> lessThanOrEquals(Resource clock, Resource> threshold) {
+ return ClockResources.lessThanOrEquals(relativeTo(clock, threshold), constant(Duration.ZERO));
+ }
+
+ public static Resource> greaterThan(Resource clock, Resource> threshold) {
+ return ClockResources.greaterThan(relativeTo(clock, threshold), constant(Duration.ZERO));
+ }
+
+ public static Resource> greaterThanOrEquals(Resource clock, Resource> threshold) {
+ return ClockResources.greaterThanOrEquals(relativeTo(clock, threshold), constant(Duration.ZERO));
+ }
+}
diff --git a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/VariableInstantClock.java b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/VariableInstantClock.java
new file mode 100644
index 0000000000..7915396af3
--- /dev/null
+++ b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/VariableInstantClock.java
@@ -0,0 +1,19 @@
+package gov.nasa.jpl.aerie.contrib.streamline.modeling.clocks;
+
+import gov.nasa.jpl.aerie.contrib.streamline.core.Dynamics;
+import gov.nasa.jpl.aerie.merlin.protocol.types.Duration;
+
+import java.time.Instant;
+
+import static gov.nasa.jpl.aerie.merlin.protocol.types.Duration.addToInstant;
+
+/**
+ * A variation on {@link VariableClock} that represents an absolute {@link Instant}
+ * instead of a relative {@link Duration}.
+ */
+public record VariableInstantClock(Instant extract, int multiplier) implements Dynamics {
+ @Override
+ public VariableInstantClock step(Duration t) {
+ return new VariableInstantClock(addToInstant(extract, t.times(multiplier)), multiplier);
+ }
+}
diff --git a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/VariableInstantClockEffects.java b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/VariableInstantClockEffects.java
new file mode 100644
index 0000000000..019a31ee4c
--- /dev/null
+++ b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/VariableInstantClockEffects.java
@@ -0,0 +1,33 @@
+package gov.nasa.jpl.aerie.contrib.streamline.modeling.clocks;
+
+import gov.nasa.jpl.aerie.contrib.streamline.core.MutableResource;
+
+import java.time.Instant;
+
+import static gov.nasa.jpl.aerie.contrib.streamline.core.monads.DynamicsMonad.effect;
+import static gov.nasa.jpl.aerie.contrib.streamline.debugging.Naming.name;
+
+public final class VariableInstantClockEffects {
+ private VariableInstantClockEffects() {}
+
+ /**
+ * Stop the clock without affecting the current time.
+ */
+ public static void pause(MutableResource clock) {
+ clock.emit("Pause", effect($ -> new VariableInstantClock($.extract(), 0)));
+ }
+
+ /**
+ * Start the clock without affecting the current time.
+ */
+ public static void start(MutableResource clock) {
+ clock.emit("Start", effect($ -> new VariableInstantClock($.extract(), 1)));
+ }
+
+ /**
+ * Reset the clock to the given time, without affecting how fast it's running.
+ */
+ public static void reset(MutableResource clock, Instant newTime) {
+ clock.emit(name(effect($ -> new VariableInstantClock(newTime, $.multiplier())), "Reset to %s", newTime));
+ }
+}
diff --git a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/VariableInstantClockResources.java b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/VariableInstantClockResources.java
new file mode 100644
index 0000000000..83df2de990
--- /dev/null
+++ b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/VariableInstantClockResources.java
@@ -0,0 +1,42 @@
+package gov.nasa.jpl.aerie.contrib.streamline.modeling.clocks;
+
+import gov.nasa.jpl.aerie.contrib.streamline.core.Resource;
+import gov.nasa.jpl.aerie.contrib.streamline.modeling.discrete.Discrete;
+import gov.nasa.jpl.aerie.merlin.protocol.types.Duration;
+
+import java.time.Instant;
+
+import static gov.nasa.jpl.aerie.contrib.streamline.core.monads.ResourceMonad.map;
+import static gov.nasa.jpl.aerie.contrib.streamline.debugging.Naming.name;
+import static gov.nasa.jpl.aerie.contrib.streamline.modeling.clocks.InstantClock.durationBetween;
+import static gov.nasa.jpl.aerie.contrib.streamline.modeling.discrete.DiscreteResources.constant;
+
+public final class VariableInstantClockResources {
+ private VariableInstantClockResources() {}
+
+ public static Resource relativeTo(Resource clock, Resource> zeroTime) {
+ return name(map(clock, zeroTime, (c, t) ->
+ new VariableClock(durationBetween(c.extract(), t.extract()), c.multiplier())),
+ "%s relative to %s", clock, zeroTime);
+ }
+
+ public static Resource> lessThan(Resource clock, Resource> threshold) {
+ return VariableClockResources.lessThan(relativeTo(clock, threshold), constant(Duration.ZERO));
+ }
+
+ public static Resource> lessThanOrEquals(Resource clock, Resource> threshold) {
+ return VariableClockResources.lessThanOrEquals(relativeTo(clock, threshold), constant(Duration.ZERO));
+ }
+
+ public static Resource> greaterThan(Resource clock, Resource> threshold) {
+ return VariableClockResources.greaterThan(relativeTo(clock, threshold), constant(Duration.ZERO));
+ }
+
+ public static Resource> greaterThanOrEquals(Resource clock, Resource> threshold) {
+ return VariableClockResources.greaterThanOrEquals(relativeTo(clock, threshold), constant(Duration.ZERO));
+ }
+
+ public static Resource between(Resource start, Resource end) {
+ return map(start, end, (s, e) -> new VariableClock(durationBetween(s.extract(), e.extract()), e.multiplier() - s.multiplier()));
+ }
+}
diff --git a/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/core/CellRefV2Test.java b/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/core/CellRefV2Test.java
index c77bb601c8..1a626b6fda 100644
--- a/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/core/CellRefV2Test.java
+++ b/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/core/CellRefV2Test.java
@@ -9,10 +9,11 @@
import org.junit.jupiter.api.TestInstance.Lifecycle;
import org.junit.jupiter.api.extension.ExtendWith;
+import java.time.Instant;
+
import static gov.nasa.jpl.aerie.contrib.streamline.core.CellRefV2.autoEffects;
import static gov.nasa.jpl.aerie.contrib.streamline.core.CellRefV2.commutingEffects;
import static gov.nasa.jpl.aerie.contrib.streamline.core.CellRefV2.noncommutingEffects;
-import static gov.nasa.jpl.aerie.contrib.streamline.core.MutableResource.resource;
import static gov.nasa.jpl.aerie.contrib.streamline.core.Resources.currentValue;
import static gov.nasa.jpl.aerie.contrib.streamline.modeling.discrete.Discrete.discrete;
import static gov.nasa.jpl.aerie.contrib.streamline.modeling.discrete.monads.DiscreteDynamicsMonad.effect;
@@ -27,10 +28,11 @@ class MutableResourceTest {
@TestInstance(Lifecycle.PER_CLASS)
class NonCommutingEffects {
public NonCommutingEffects(final Registrar registrar) {
- Resources.init();
+ Resources.init(Instant.EPOCH);
+ cell = MutableResource.resource(discrete(42), noncommutingEffects());
}
- private final MutableResource> cell = MutableResource.resource(discrete(42), noncommutingEffects());
+ private final MutableResource> cell;
@Test
void gets_initial_value_if_no_effects_are_emitted() {
@@ -66,10 +68,11 @@ void throws_exception_when_concurrent_effects_are_applied() {
@TestInstance(Lifecycle.PER_CLASS)
class CommutingEffects {
public CommutingEffects(final Registrar registrar) {
- Resources.init();
+ Resources.init(Instant.EPOCH);
+ cell = MutableResource.resource(discrete(42), commutingEffects());
}
- private final MutableResource> cell = MutableResource.resource(discrete(42), commutingEffects());
+ private final MutableResource> cell;
@Test
void gets_initial_value_if_no_effects_are_emitted() {
@@ -108,11 +111,12 @@ void applies_concurrent_effects_in_any_order() {
@ExtendWith(MerlinExtension.class)
@TestInstance(Lifecycle.PER_CLASS)
class AutoEffects {
- public AutoEffects(final Registrar registrar) {
- Resources.init();
+ public AutoEffects() {
+ Resources.init(Instant.EPOCH);
+ cell = MutableResource.resource(discrete(42), autoEffects());
}
- private final MutableResource> cell = MutableResource.resource(discrete(42), autoEffects());
+ private final MutableResource> cell;
@Test
void gets_initial_value_if_no_effects_are_emitted() {
diff --git a/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/debugging/DependenciesTest.java b/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/debugging/DependenciesTest.java
index 8014216f63..75ea39427a 100644
--- a/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/debugging/DependenciesTest.java
+++ b/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/debugging/DependenciesTest.java
@@ -1,7 +1,7 @@
package gov.nasa.jpl.aerie.contrib.streamline.debugging;
-import gov.nasa.jpl.aerie.contrib.streamline.core.MutableResource;
import gov.nasa.jpl.aerie.contrib.streamline.core.Resource;
+import gov.nasa.jpl.aerie.contrib.streamline.core.Resources;
import gov.nasa.jpl.aerie.contrib.streamline.modeling.discrete.Discrete;
import gov.nasa.jpl.aerie.contrib.streamline.modeling.discrete.DiscreteResources;
import gov.nasa.jpl.aerie.contrib.streamline.modeling.polynomial.Polynomial;
@@ -11,6 +11,8 @@
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.extension.ExtendWith;
+import java.time.Instant;
+
import static gov.nasa.jpl.aerie.contrib.streamline.core.MutableResource.resource;
import static gov.nasa.jpl.aerie.contrib.streamline.core.monads.ResourceMonad.*;
import static gov.nasa.jpl.aerie.contrib.streamline.modeling.polynomial.Polynomial.polynomial;
@@ -21,12 +23,22 @@
@ExtendWith(MerlinExtension.class)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class DependenciesTest {
- Resource> constantTrue = DiscreteResources.constant(true);
- Resource constant1234 = constant(1234);
- Resource constant5678 = constant(5678);
- Resource polynomialCell = resource(polynomial(1));
- Resource derived = map(constantTrue, constant1234, constant5678,
- (b, x, y) -> b.extract() ? x : y);
+ public DependenciesTest() {
+ Resources.init(Instant.EPOCH);
+
+ constantTrue = DiscreteResources.constant(true);
+ constant1234 = constant(1234);
+ constant5678 = constant(5678);
+ polynomialCell = resource(polynomial(1));
+ derived = map(constantTrue, constant1234, constant5678,
+ (b, x, y) -> b.extract() ? x : y);
+ }
+
+ Resource> constantTrue;
+ Resource constant1234;
+ Resource constant5678;
+ Resource polynomialCell;
+ Resource derived;
@Test
void constants_are_named_by_their_value() {
diff --git a/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/discrete/DiscreteEffectsTest.java b/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/discrete/DiscreteEffectsTest.java
index 49d4a953e8..ea30dd871a 100644
--- a/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/discrete/DiscreteEffectsTest.java
+++ b/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/discrete/DiscreteEffectsTest.java
@@ -5,7 +5,6 @@
import gov.nasa.jpl.aerie.contrib.streamline.core.Resources;
import gov.nasa.jpl.aerie.contrib.streamline.modeling.clocks.Clock;
import gov.nasa.jpl.aerie.contrib.streamline.unit_aware.UnitAware;
-import gov.nasa.jpl.aerie.merlin.framework.Registrar;
import gov.nasa.jpl.aerie.merlin.framework.junit.MerlinExtension;
import gov.nasa.jpl.aerie.merlin.protocol.types.Duration;
import org.junit.jupiter.api.Test;
@@ -13,6 +12,8 @@
import org.junit.jupiter.api.TestInstance.Lifecycle;
import org.junit.jupiter.api.extension.ExtendWith;
+import java.time.Instant;
+
import static gov.nasa.jpl.aerie.contrib.streamline.core.MutableResource.resource;
import static gov.nasa.jpl.aerie.contrib.streamline.core.Resources.currentTime;
import static gov.nasa.jpl.aerie.contrib.streamline.core.Resources.currentValue;
@@ -40,8 +41,10 @@
@ExtendWith(MerlinExtension.class)
@TestInstance(Lifecycle.PER_CLASS)
class DiscreteEffectsTest {
- public DiscreteEffectsTest(final Registrar registrar) {
- Resources.init();
+ {
+ // We need to initialize this up front, so we can use in-line initializers for other resources after.
+ // I think in-line initializers for the other resources make the tests easier to read.
+ Resources.init(Instant.EPOCH);
}
private final MutableResource> settable = resource(discrete(42));
diff --git a/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/discrete/PrecomputedTest.java b/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/discrete/PrecomputedTest.java
index 3849203bf5..d0d8bd733b 100644
--- a/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/discrete/PrecomputedTest.java
+++ b/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/discrete/PrecomputedTest.java
@@ -2,7 +2,6 @@
import gov.nasa.jpl.aerie.contrib.streamline.core.Resource;
import gov.nasa.jpl.aerie.contrib.streamline.core.Resources;
-import gov.nasa.jpl.aerie.merlin.framework.Registrar;
import gov.nasa.jpl.aerie.merlin.framework.junit.MerlinExtension;
import gov.nasa.jpl.aerie.merlin.protocol.types.Duration;
import org.junit.jupiter.api.Test;
@@ -26,8 +25,10 @@
@ExtendWith(MerlinExtension.class)
@TestInstance(Lifecycle.PER_CLASS)
public class PrecomputedTest {
- public PrecomputedTest(final Registrar registrar) {
- Resources.init();
+ {
+ // We need to initialize this up front, so we can use in-line initializers for other resources after.
+ // I think in-line initializers for the other resources make the tests easier to read.
+ Resources.init(Instant.EPOCH);
}
final Resource> precomputedAsAConstant =
diff --git a/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/polynomial/ComparisonsTest.java b/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/polynomial/ComparisonsTest.java
index a7cad57998..67a3e109e9 100644
--- a/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/polynomial/ComparisonsTest.java
+++ b/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/polynomial/ComparisonsTest.java
@@ -5,7 +5,6 @@
import gov.nasa.jpl.aerie.contrib.streamline.core.Resource;
import gov.nasa.jpl.aerie.contrib.streamline.core.Resources;
import gov.nasa.jpl.aerie.contrib.streamline.modeling.discrete.Discrete;
-import gov.nasa.jpl.aerie.merlin.framework.Registrar;
import gov.nasa.jpl.aerie.merlin.framework.junit.MerlinExtension;
import gov.nasa.jpl.aerie.merlin.protocol.types.Duration;
import org.junit.jupiter.api.Test;
@@ -13,6 +12,8 @@
import org.junit.jupiter.api.TestInstance.Lifecycle;
import org.junit.jupiter.api.extension.ExtendWith;
+import java.time.Instant;
+
import static gov.nasa.jpl.aerie.contrib.streamline.core.MutableResource.resource;
import static gov.nasa.jpl.aerie.contrib.streamline.core.MutableResource.set;
import static gov.nasa.jpl.aerie.contrib.streamline.core.Resources.currentData;
@@ -28,22 +29,26 @@
@ExtendWith(MerlinExtension.class)
@TestInstance(Lifecycle.PER_CLASS)
public class ComparisonsTest {
- public ComparisonsTest(final Registrar registrar) {
- Resources.init();
- }
+ public ComparisonsTest() {
+ Resources.init(Instant.EPOCH);
- private final MutableResource p = resource(polynomial(0));
- private final MutableResource q = resource(polynomial(0));
+ p = resource(polynomial(0));
+ q = resource(polynomial(0));
- private final Resource> p_lt_q = lessThan(p, q);
- private final Resource> p_lte_q = lessThanOrEquals(p, q);
- private final Resource> p_gt_q = greaterThan(p, q);
- private final Resource> p_gte_q = greaterThanOrEquals(p, q);
+ p_lt_q = lessThan(p, q);
+ p_lte_q = lessThanOrEquals(p, q);
+ p_gt_q = greaterThan(p, q);
+ p_gte_q = greaterThanOrEquals(p, q);
+
+ min_p_q = min(p, q);
+ min_q_p = min(q, p);
+ max_p_q = max(p, q);
+ max_q_p = max(q, p);
+ }
- private final Resource min_p_q = min(p, q);
- private final Resource min_q_p = min(q, p);
- private final Resource max_p_q = max(p, q);
- private final Resource max_q_p = max(q, p);
+ private final MutableResource p, q;
+ private final Resource> p_lt_q, p_lte_q, p_gt_q, p_gte_q;
+ private final Resource min_p_q, min_q_p, max_p_q, max_q_p;
@Test
void comparing_distinct_constants() {
diff --git a/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/polynomial/LinearBoundaryConsistencySolverTest.java b/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/polynomial/LinearBoundaryConsistencySolverTest.java
index eceec5b70e..254fa93ff7 100644
--- a/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/polynomial/LinearBoundaryConsistencySolverTest.java
+++ b/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/polynomial/LinearBoundaryConsistencySolverTest.java
@@ -10,6 +10,8 @@
import org.junit.jupiter.api.TestInstance.Lifecycle;
import org.junit.jupiter.api.extension.ExtendWith;
+import java.time.Instant;
+
import static gov.nasa.jpl.aerie.contrib.streamline.core.MutableResource.*;
import static gov.nasa.jpl.aerie.contrib.streamline.core.Resources.currentData;
import static gov.nasa.jpl.aerie.contrib.streamline.modeling.polynomial.LinearBoundaryConsistencySolver.Comparison.*;
@@ -25,11 +27,13 @@ class LinearBoundaryConsistencySolverTest {
@ExtendWith(MerlinExtension.class)
@TestInstance(Lifecycle.PER_CLASS)
class SingleVariableSingleConstraint {
- MutableResource driver = resource(polynomial(10));
+ MutableResource driver;
Resource result;
- public SingleVariableSingleConstraint() {
- Resources.init();
+ SingleVariableSingleConstraint() {
+ Resources.init(Instant.EPOCH);
+
+ driver = resource(polynomial(10));
var solver = new LinearBoundaryConsistencySolver("SingleVariableSingleConstraint");
var v = solver.variable("v", Domain::upperBound);
@@ -65,13 +69,15 @@ void results_evolve_with_time() {
@ExtendWith(MerlinExtension.class)
@TestInstance(Lifecycle.PER_CLASS)
class SingleVariableMultipleConstraint {
- MutableResource lowerBound1 = resource(polynomial(10));
- MutableResource lowerBound2 = resource(polynomial(20));
- MutableResource upperBound = resource(polynomial(30));
+ MutableResource lowerBound1, lowerBound2, upperBound;
Resource result;
- public SingleVariableMultipleConstraint() {
- Resources.init();
+ SingleVariableMultipleConstraint() {
+ Resources.init(Instant.EPOCH);
+
+ lowerBound1 = resource(polynomial(10));
+ lowerBound2 = resource(polynomial(20));
+ upperBound = resource(polynomial(30));
var solver = new LinearBoundaryConsistencySolver("SingleVariableMultipleConstraint");
var v = solver.variable("v", Domain::lowerBound);
@@ -141,11 +147,13 @@ void failures_are_cleared_if_problem_becomes_feasible_again() {
@ExtendWith(MerlinExtension.class)
@TestInstance(Lifecycle.PER_CLASS)
class ScalingConstraint {
- MutableResource driver = resource(polynomial(10));
+ MutableResource driver;
Resource result;
- public ScalingConstraint() {
- Resources.init();
+ ScalingConstraint() {
+ Resources.init(Instant.EPOCH);
+
+ driver = resource(polynomial(10));
var solver = new LinearBoundaryConsistencySolver("ScalingConstraint");
var v = solver.variable("v", Domain::upperBound);
@@ -171,12 +179,14 @@ void scaling_is_respected_for_later_solutions() {
@ExtendWith(MerlinExtension.class)
@TestInstance(Lifecycle.PER_CLASS)
class MultipleVariables {
- MutableResource upperBound = resource(polynomial(10));
- MutableResource upperBoundOnC = resource(polynomial(5));
+ MutableResource upperBound, upperBoundOnC;
Resource a, b, c;
- public MultipleVariables() {
- Resources.init();
+ MultipleVariables() {
+ Resources.init(Instant.EPOCH);
+
+ upperBound = resource(polynomial(10));
+ upperBoundOnC = resource(polynomial(5));
var solver = new LinearBoundaryConsistencySolver("MultipleVariablesSingleConstraint");
var a = solver.variable("a", Domain::upperBound);
diff --git a/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/polynomial/PrecomputedTest.java b/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/polynomial/PrecomputedTest.java
index 47427baf17..54122c6581 100644
--- a/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/polynomial/PrecomputedTest.java
+++ b/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/polynomial/PrecomputedTest.java
@@ -2,13 +2,13 @@
import gov.nasa.jpl.aerie.contrib.streamline.core.Resource;
import gov.nasa.jpl.aerie.contrib.streamline.core.Resources;
-import gov.nasa.jpl.aerie.merlin.framework.Registrar;
import gov.nasa.jpl.aerie.merlin.framework.junit.MerlinExtension;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestInstance.Lifecycle;
import org.junit.jupiter.api.extension.ExtendWith;
+import java.time.Instant;
import java.util.Map;
import java.util.TreeMap;
@@ -24,8 +24,10 @@
@ExtendWith(MerlinExtension.class)
@TestInstance(Lifecycle.PER_CLASS)
public class PrecomputedTest {
- public PrecomputedTest(final Registrar registrar) {
- Resources.init();
+ {
+ // We need to initialize this up front, so we can use in-line initializers for other resources after.
+ // I think in-line initializers for the other resources make the tests easier to read.
+ Resources.init(Instant.EPOCH);
}
final Resource precomputedAsConstantInPast =
diff --git a/examples/streamline-demo/src/main/java/gov/nasa/jpl/aerie/streamline_demo/Mission.java b/examples/streamline-demo/src/main/java/gov/nasa/jpl/aerie/streamline_demo/Mission.java
index ece739efba..a1d32e971a 100644
--- a/examples/streamline-demo/src/main/java/gov/nasa/jpl/aerie/streamline_demo/Mission.java
+++ b/examples/streamline-demo/src/main/java/gov/nasa/jpl/aerie/streamline_demo/Mission.java
@@ -5,13 +5,15 @@
import gov.nasa.jpl.aerie.contrib.streamline.modeling.Registrar;
import gov.nasa.jpl.aerie.merlin.framework.ModelActions;
+import java.time.Instant;
+
public final class Mission {
public final DataModel dataModel;
public final ErrorTestingModel errorTestingModel;
public final ApproximationModel approximationModel;
- public Mission(final gov.nasa.jpl.aerie.merlin.framework.Registrar registrar$, final Configuration config) {
- var registrar = new Registrar(registrar$, Registrar.ErrorBehavior.Log);
+ public Mission(final gov.nasa.jpl.aerie.merlin.framework.Registrar registrar$, Instant planStart, final Configuration config) {
+ var registrar = new Registrar(registrar$, planStart, Registrar.ErrorBehavior.Log);
if (config.traceResources) registrar.setTrace();
if (config.profileResources) Resource.profileAllResources();
dataModel = new DataModel(registrar, config);