From 7e85f3076a9a3670317cc5e6cf9050a54762acb3 Mon Sep 17 00:00:00 2001 From: David Legg Date: Fri, 12 Jul 2024 17:45:37 -0700 Subject: [PATCH 1/4] Add InstantClock and VariableInstantClock support Adds "Instant" counterparts to Clock and VariableClock, which report absolute times as Java instants, but still step time according to an Aerie duration. Also adds some minimal interoperability between absolute and relative clocks, and some useful derivations including comparisons. Using these, also adds a global Instant-based clock to Resources, along with exposing both the duration- and instant-based clocks as resources. In doing so, we add a new parameter for the plan's start time to Resources.init(). This in turn required refactoring some unit tests, and I took the opportunity to clean up the test construction a little bit as well. This revealed a way to correctly initialize Resources, i.e., to call Resources.init() exactly once per initialization of each test model. As a result, I refactored the clock handling to remove the awkward reinitialization pattern, since that pattern was added to handle test code. --- .../contrib/streamline/core/Resources.java | 31 ++++++---- .../streamline/modeling/Registrar.java | 6 +- .../modeling/clocks/InstantClock.java | 24 ++++++++ .../clocks/InstantClockResources.java | 56 +++++++++++++++++++ .../modeling/clocks/VariableInstantClock.java | 19 +++++++ .../clocks/VariableInstantClockEffects.java | 33 +++++++++++ .../clocks/VariableInstantClockResources.java | 42 ++++++++++++++ .../streamline/core/CellRefV2Test.java | 20 ++++--- .../debugging/DependenciesTest.java | 26 ++++++--- .../discrete/DiscreteEffectsTest.java | 9 ++- .../modeling/discrete/PrecomputedTest.java | 7 ++- .../modeling/polynomial/ComparisonsTest.java | 33 ++++++----- .../LinearBoundaryConsistencySolverTest.java | 40 ++++++++----- .../modeling/polynomial/PrecomputedTest.java | 8 ++- .../jpl/aerie/streamline_demo/Mission.java | 6 +- 15 files changed, 291 insertions(+), 69 deletions(-) create mode 100644 contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/InstantClock.java create mode 100644 contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/InstantClockResources.java create mode 100644 contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/VariableInstantClock.java create mode 100644 contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/VariableInstantClockEffects.java create mode 100644 contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/VariableInstantClockResources.java 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); From 6d30dd1a117cb1a067049a1e1c92741fa8600a79 Mon Sep 17 00:00:00 2001 From: David Legg Date: Tue, 29 Oct 2024 18:22:10 -0700 Subject: [PATCH 2/4] Add SimulationClockTest --- .../modeling/clocks/InstantClock.java | 2 + .../modeling/clocks/SimulationClockTest.java | 66 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/SimulationClockTest.java 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 index e6c866fd23..e00bb5b323 100644 --- 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 @@ -18,6 +18,8 @@ public InstantClock step(Duration t) { return new InstantClock(addToInstant(extract, t)); } + // TODO - this method belongs somewhere else... + // Making it package-private at least lets us move it later without dependency issues outside the library. static Duration durationBetween(Instant start, Instant end) { return Duration.of(ChronoUnit.MICROS.between(start, end), Duration.MICROSECONDS); } diff --git a/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/SimulationClockTest.java b/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/SimulationClockTest.java new file mode 100644 index 0000000000..6efac343e7 --- /dev/null +++ b/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/SimulationClockTest.java @@ -0,0 +1,66 @@ +package gov.nasa.jpl.aerie.contrib.streamline.modeling.clocks; + +import gov.nasa.jpl.aerie.contrib.streamline.core.Resources; +import gov.nasa.jpl.aerie.merlin.framework.junit.MerlinExtension; +import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.extension.ExtendWith; + +import java.time.Instant; +import java.time.temporal.ChronoUnit; + +import static gov.nasa.jpl.aerie.contrib.streamline.core.Resources.*; +import static gov.nasa.jpl.aerie.merlin.framework.ModelActions.delay; +import static gov.nasa.jpl.aerie.merlin.protocol.types.Duration.HOUR; +import static gov.nasa.jpl.aerie.merlin.protocol.types.Duration.ZERO; +import static org.junit.jupiter.api.Assertions.assertEquals; + +@ExtendWith(MerlinExtension.class) +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class SimulationClockTest { + // This time is unlikely to be a hard-coded default anywhere + public static final Instant PLAN_START = Instant.parse("2020-01-02T03:04:05Z"); + + public SimulationClockTest() { + Resources.init(PLAN_START); + } + + @Test + public void relative_clock_starts_at_zero() { + assertEquals(ZERO, currentTime()); + assertEquals(ZERO, currentValue(simulationClock())); + } + + @Test + public void absolute_clock_starts_at_plan_start() { + assertEquals(PLAN_START, currentInstant()); + assertEquals(PLAN_START, currentValue(absoluteClock())); + } + + @Test + public void relative_clock_advances_at_unit_rate() { + delay(1, HOUR); + assertEquals(Duration.of(1, HOUR), currentTime()); + assertEquals(Duration.of(1, HOUR), currentValue(simulationClock())); + delay(1, HOUR); + assertEquals(Duration.of(2, HOUR), currentTime()); + assertEquals(Duration.of(2, HOUR), currentValue(simulationClock())); + delay(1, HOUR); + assertEquals(Duration.of(3, HOUR), currentTime()); + assertEquals(Duration.of(3, HOUR), currentValue(simulationClock())); + } + + @Test + public void absolute_clock_advances_at_unit_rate() { + delay(1, HOUR); + assertEquals(PLAN_START.plus(1, ChronoUnit.HOURS), currentInstant()); + assertEquals(PLAN_START.plus(1, ChronoUnit.HOURS), currentValue(absoluteClock())); + delay(1, HOUR); + assertEquals(PLAN_START.plus(2, ChronoUnit.HOURS), currentInstant()); + assertEquals(PLAN_START.plus(2, ChronoUnit.HOURS), currentValue(absoluteClock())); + delay(1, HOUR); + assertEquals(PLAN_START.plus(3, ChronoUnit.HOURS), currentInstant()); + assertEquals(PLAN_START.plus(3, ChronoUnit.HOURS), currentValue(absoluteClock())); + } +} From 70f5acd960f5e6ef4e4d37be70e295c5c2fd8840 Mon Sep 17 00:00:00 2001 From: David Legg Date: Mon, 27 Jan 2025 13:48:38 -0800 Subject: [PATCH 3/4] Refactor streamline init Refactors streamline's init process, centralizing singletons and initialization into StreamlineSystem. --- .../contrib/streamline/StreamlineSystem.java | 52 ++++++++++++++++ .../contrib/streamline/core/Resources.java | 34 +---------- .../contrib/streamline/debugging/Logging.java | 10 +-- .../contrib/streamline/debugging/Tracing.java | 7 +-- .../streamline/modeling/Registrar.java | 2 - .../streamline/modeling/Registration.java | 18 ++++++ .../polynomial/PolynomialEffects.java | 10 +-- .../streamline/core/CellRefV2Test.java | 7 ++- .../discrete/DiscreteEffectsTest.java | 10 +-- .../modeling/discrete/PrecomputedTest.java | 61 ++++++++++--------- .../modeling/polynomial/ComparisonsTest.java | 29 +++++---- .../LinearBoundaryConsistencySolverTest.java | 18 +++--- .../modeling/polynomial/PrecomputedTest.java | 48 ++++++++------- 13 files changed, 175 insertions(+), 131 deletions(-) create mode 100644 contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/StreamlineSystem.java create mode 100644 contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/Registration.java diff --git a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/StreamlineSystem.java b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/StreamlineSystem.java new file mode 100644 index 0000000000..ce01dc155f --- /dev/null +++ b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/StreamlineSystem.java @@ -0,0 +1,52 @@ +package gov.nasa.jpl.aerie.contrib.streamline; + +import gov.nasa.jpl.aerie.contrib.streamline.core.Resource; +import gov.nasa.jpl.aerie.contrib.streamline.debugging.Logging; +import gov.nasa.jpl.aerie.contrib.streamline.modeling.Registrar; +import gov.nasa.jpl.aerie.contrib.streamline.modeling.Registration; +import gov.nasa.jpl.aerie.contrib.streamline.modeling.clocks.Clock; +import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; + +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.clocks.Clock.clock; +import static gov.nasa.jpl.aerie.merlin.protocol.types.Duration.ZERO; + +public final class StreamlineSystem { + private static Resource CLOCK; + + private StreamlineSystem() {} + + /** + * Initialize all streamline singletons. + * This method should be called once as the first step of creating a model. + *

+ * This will call the following subordinate initialization methods: + *

    + *
  • {@link Logging#init}
  • + *
  • {@link Registration#init}
  • + *
+ * as well as initialize the singletons contained within this class. + *

+ */ + public static void init( + final gov.nasa.jpl.aerie.merlin.framework.Registrar baseRegistrar, + final Registrar.ErrorBehavior errorBehavior) { + CLOCK = resource(clock(ZERO)); + Logging.init(baseRegistrar); + Registration.init(baseRegistrar, errorBehavior); + } + + /** + * Variation on {@link StreamlineSystem#init} for unit testing. + * Fills in most arguments with defaults suitable for testing. + */ + public static void testInit( + final gov.nasa.jpl.aerie.merlin.framework.Registrar baseRegistrar) { + init(baseRegistrar, Registrar.ErrorBehavior.Throw); + } + + public static Duration currentTime() { + return currentValue(CLOCK); + } +} 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..16110ca182 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,8 +1,7 @@ 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.StreamlineSystem; 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; @@ -19,7 +18,6 @@ import static gov.nasa.jpl.aerie.contrib.streamline.core.Reactions.wheneverDynamicsChange; 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.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; @@ -30,32 +28,6 @@ public final class Resources { private Resources() {} - /** - * Ensure that Resources are initialized. - * - *

- * This method needs to be called during simulation initialization. - * This method is idempotent; calling it multiple times is the same as calling it once. - *

- */ - public static void init() { - currentTime(); - } - - // 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)); - 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); - } - } - public static D currentData(Resource resource) { return data(resource.getDynamics()); } @@ -96,10 +68,10 @@ public static > V value(ErrorCatching> d */ public static > Condition dynamicsChange(Resource resource) { final var startingDynamics = resource.getDynamics(); - final Duration startTime = currentTime(); + final Duration startTime = StreamlineSystem.currentTime(); Condition result = (positive, atEarliest, atLatest) -> { var currentDynamics = resource.getDynamics(); - var elapsedTime = currentTime().minus(startTime); + var elapsedTime = StreamlineSystem.currentTime().minus(startTime); boolean haveChanged = startingDynamics.match( start -> currentDynamics.match( current -> !current.data().equals(start.data().step(elapsedTime)) || diff --git a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/debugging/Logging.java b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/debugging/Logging.java index f9741e8047..8d30374efb 100644 --- a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/debugging/Logging.java +++ b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/debugging/Logging.java @@ -14,14 +14,10 @@ private Logging() {} /** * Initialize the primary logger. - * This is called when constructing a {@link gov.nasa.jpl.aerie.contrib.streamline.modeling.Registrar}, - * and does not need to be called directly by the model. + * This is called by {@link gov.nasa.jpl.aerie.contrib.streamline.StreamlineSystem#init} + * and should not be called by the model directly. */ public static void init(final Registrar registrar) { - if (LOGGER == null) { - LOGGER = new Logger(registrar); - } else { - LOGGER.warning("Attempting to re-initialize primary logger. This attempt is being ignored."); - } + LOGGER = new Logger(registrar); } } diff --git a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/debugging/Tracing.java b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/debugging/Tracing.java index 5a954aeaf1..0ec30328e7 100644 --- a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/debugging/Tracing.java +++ b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/debugging/Tracing.java @@ -1,5 +1,6 @@ package gov.nasa.jpl.aerie.contrib.streamline.debugging; +import gov.nasa.jpl.aerie.contrib.streamline.StreamlineSystem; import gov.nasa.jpl.aerie.contrib.streamline.core.MutableResource; import gov.nasa.jpl.aerie.contrib.streamline.core.Dynamics; import gov.nasa.jpl.aerie.contrib.streamline.core.DynamicsEffect; @@ -12,8 +13,6 @@ import java.util.Stack; import java.util.function.Supplier; -import static gov.nasa.jpl.aerie.contrib.streamline.core.Resources.currentTime; - /** * Functions for debugging resources by tracing their calculation. */ @@ -90,9 +89,9 @@ public static Supplier trace(Supplier name, Supplier T traceAction(Supplier name, Supplier action) { activeTracePoints.push(name.get()); - System.out.printf("TRACE: %s - %s start...%n", currentTime(), formatStack()); + System.out.printf("TRACE: %s - %s start...%n", StreamlineSystem.currentTime(), formatStack()); T result = action.get(); - System.out.printf("TRACE: %s - %s: %s%n", currentTime(), formatStack(), result); + System.out.printf("TRACE: %s - %s: %s%n", StreamlineSystem.currentTime(), formatStack(), result); activeTracePoints.pop(); return result; } 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..b2d7a3d9f2 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 @@ -55,8 +55,6 @@ public enum ErrorBehavior { } public Registrar(final gov.nasa.jpl.aerie.merlin.framework.Registrar baseRegistrar, final ErrorBehavior errorBehavior) { - Resources.init(); - Logging.init(baseRegistrar); this.baseRegistrar = baseRegistrar; this.errorBehavior = errorBehavior; diff --git a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/Registration.java b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/Registration.java new file mode 100644 index 0000000000..3ae7174abc --- /dev/null +++ b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/Registration.java @@ -0,0 +1,18 @@ +package gov.nasa.jpl.aerie.contrib.streamline.modeling; + +public final class Registration { + private Registration() {} + + public static Registrar REGISTRAR; + + /** + * Initialize the primary registrar. + * This is called by {@link gov.nasa.jpl.aerie.contrib.streamline.StreamlineSystem#init} + * and should not be called by the model directly. + */ + public static void init( + final gov.nasa.jpl.aerie.merlin.framework.Registrar baseRegistrar, + final Registrar.ErrorBehavior errorBehavior) { + REGISTRAR = new Registrar(baseRegistrar, errorBehavior); + } +} diff --git a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/polynomial/PolynomialEffects.java b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/polynomial/PolynomialEffects.java index 366567ea90..51f5b539b6 100644 --- a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/polynomial/PolynomialEffects.java +++ b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/polynomial/PolynomialEffects.java @@ -1,6 +1,6 @@ package gov.nasa.jpl.aerie.contrib.streamline.modeling.polynomial; -import gov.nasa.jpl.aerie.contrib.streamline.core.Resources; +import gov.nasa.jpl.aerie.contrib.streamline.StreamlineSystem; import gov.nasa.jpl.aerie.contrib.streamline.core.MutableResource; import gov.nasa.jpl.aerie.contrib.streamline.unit_aware.StandardUnits; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; @@ -94,9 +94,9 @@ public static void restore(MutableResource resource, double rate, Du private static void withConsumableEffects(String verb, MutableResource resource, Polynomial profile, Runnable action) { resource.emit(name(effect($ -> $.subtract(profile)), "Start %s according to profile %s", verb, profile)); - final Duration start = Resources.currentTime(); + final Duration start = StreamlineSystem.currentTime(); action.run(); - final Duration elapsedTime = Resources.currentTime().minus(start); + final Duration elapsedTime = StreamlineSystem.currentTime().minus(start); // Nullify ongoing effects by adding a profile with the same behavior, // but with an initial value of 0 final Polynomial steppedProfile = profile.step(elapsedTime); @@ -158,9 +158,9 @@ public static void providing(MutableResource resource, double amount private static void withNonConsumableEffect(String verb, MutableResource resource, Polynomial profile, Runnable action) { resource.emit(name(effect($ -> $.subtract(profile)), "Start %s profile %s", verb, profile)); - final Duration start = Resources.currentTime(); + final Duration start = StreamlineSystem.currentTime(); action.run(); - final Duration elapsedTime = Resources.currentTime().minus(start); + final Duration elapsedTime = StreamlineSystem.currentTime().minus(start); // Reset by adding a counteracting profile final Polynomial counteractingProfile = profile.step(elapsedTime); resource.emit(name(effect($ -> $.add(counteractingProfile)), 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..6560420136 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 @@ -1,5 +1,6 @@ package gov.nasa.jpl.aerie.contrib.streamline.core; +import gov.nasa.jpl.aerie.contrib.streamline.StreamlineSystem; 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; @@ -27,7 +28,7 @@ class MutableResourceTest { @TestInstance(Lifecycle.PER_CLASS) class NonCommutingEffects { public NonCommutingEffects(final Registrar registrar) { - Resources.init(); + StreamlineSystem.testInit(registrar); } private final MutableResource> cell = MutableResource.resource(discrete(42), noncommutingEffects()); @@ -66,7 +67,7 @@ void throws_exception_when_concurrent_effects_are_applied() { @TestInstance(Lifecycle.PER_CLASS) class CommutingEffects { public CommutingEffects(final Registrar registrar) { - Resources.init(); + StreamlineSystem.testInit(registrar); } private final MutableResource> cell = MutableResource.resource(discrete(42), commutingEffects()); @@ -109,7 +110,7 @@ void applies_concurrent_effects_in_any_order() { @TestInstance(Lifecycle.PER_CLASS) class AutoEffects { public AutoEffects(final Registrar registrar) { - Resources.init(); + StreamlineSystem.testInit(registrar); } private final MutableResource> cell = MutableResource.resource(discrete(42), autoEffects()); 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..899f4f6a10 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 @@ -1,5 +1,6 @@ package gov.nasa.jpl.aerie.contrib.streamline.modeling.discrete; +import gov.nasa.jpl.aerie.contrib.streamline.StreamlineSystem; import gov.nasa.jpl.aerie.contrib.streamline.core.MutableResource; import gov.nasa.jpl.aerie.contrib.streamline.core.ErrorCatching; import gov.nasa.jpl.aerie.contrib.streamline.core.Resources; @@ -14,7 +15,6 @@ import org.junit.jupiter.api.extension.ExtendWith; 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; import static gov.nasa.jpl.aerie.contrib.streamline.modeling.discrete.Discrete.discrete; import static gov.nasa.jpl.aerie.contrib.streamline.modeling.discrete.DiscreteEffects.*; @@ -41,7 +41,7 @@ @TestInstance(Lifecycle.PER_CLASS) class DiscreteEffectsTest { public DiscreteEffectsTest(final Registrar registrar) { - Resources.init(); + StreamlineSystem.testInit(registrar); } private final MutableResource> settable = resource(discrete(42)); @@ -162,12 +162,12 @@ void using_decreases_value_while_action_is_running() { @Test void using_runs_synchronously() { - Duration start = currentTime(); + Duration start = StreamlineSystem.currentTime(); using(nonconsumable, 3.14, () -> { - assertEquals(start, currentTime()); + assertEquals(start, StreamlineSystem.currentTime()); delay(MINUTE); }); - assertEquals(start.plus(MINUTE), currentTime()); + assertEquals(start.plus(MINUTE), StreamlineSystem.currentTime()); } @Test 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..eeb6ba0596 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 @@ -1,5 +1,6 @@ package gov.nasa.jpl.aerie.contrib.streamline.modeling.discrete; +import gov.nasa.jpl.aerie.contrib.streamline.StreamlineSystem; 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; @@ -27,11 +28,32 @@ @TestInstance(Lifecycle.PER_CLASS) public class PrecomputedTest { public PrecomputedTest(final Registrar registrar) { - Resources.init(); + StreamlineSystem.testInit(registrar); + precomputedAsAConstant = precomputed(4, new TreeMap<>()); + precomputedWithOneTransitionInFuture = precomputed(0, new TreeMap<>(Map.of(MINUTE, 10))); + precomputedWithOneTransitionInPast = precomputed(0, new TreeMap<>(Map.of(duration(-1, MINUTE), 10))); + precomputedWithMultipleTransitionsInFuture = precomputed(0, new TreeMap<>(Map.of( + duration(2, MINUTE), 5, + duration(5, MINUTE), 10, + duration(6, MINUTE), 15))); + precomputedWithMultipleTransitionsInPast = precomputed(0, new TreeMap<>(Map.of( + duration(-2, MINUTE), 5, + duration(-5, MINUTE), 10, + duration(-6, MINUTE), 15))); + precomputedWithTransitionsInPastAndFuture = precomputed(0, new TreeMap<>(Map.of( + duration(-5, MINUTE), 25, + duration(-2, MINUTE), 5, + duration(5, MINUTE), 10, + duration(6, MINUTE), 15))); + precomputedWithInstantKeys = precomputed(0, new TreeMap<>(Map.of( + Instant.parse("2023-10-17T23:55:00Z"), 25, + Instant.parse("2023-10-17T23:58:00Z"), 5, + Instant.parse("2023-10-18T00:05:00Z"), 10, + Instant.parse("2023-10-18T00:06:00Z"), 15)), + Instant.parse("2023-10-18T00:00:00Z")); } - final Resource> precomputedAsAConstant = - precomputed(4, new TreeMap<>()); + final Resource> precomputedAsAConstant; @Test void precomputed_with_no_transitions_uses_default_value_forever() { assertEquals(4, currentValue(precomputedAsAConstant)); @@ -41,8 +63,7 @@ void precomputed_with_no_transitions_uses_default_value_forever() { assertEquals(4, currentValue(precomputedAsAConstant)); } - final Resource> precomputedWithOneTransitionInFuture = - precomputed(0, new TreeMap<>(Map.of(MINUTE, 10))); + final Resource> precomputedWithOneTransitionInFuture; @Test void precomputed_with_transition_in_future_changes_at_that_time() { assertEquals(0, currentValue(precomputedWithOneTransitionInFuture)); @@ -53,8 +74,7 @@ void precomputed_with_transition_in_future_changes_at_that_time() { assertEquals(10, currentValue(precomputedWithOneTransitionInFuture)); } - final Resource> precomputedWithOneTransitionInPast = - precomputed(0, new TreeMap<>(Map.of(duration(-1, MINUTE), 10))); + final Resource> precomputedWithOneTransitionInPast; @Test void precomputed_with_transition_in_past_uses_that_value_forever() { assertEquals(10, currentValue(precomputedWithOneTransitionInPast)); @@ -64,11 +84,7 @@ void precomputed_with_transition_in_past_uses_that_value_forever() { assertEquals(10, currentValue(precomputedWithOneTransitionInPast)); } - final Resource> precomputedWithMultipleTransitionsInFuture = - precomputed(0, new TreeMap<>(Map.of( - duration(2, MINUTE), 5, - duration(5, MINUTE), 10, - duration(6, MINUTE), 15))); + final Resource> precomputedWithMultipleTransitionsInFuture; @Test void precomputed_with_multiple_transitions_in_future_goes_through_each_in_turn() { assertEquals(0, currentValue(precomputedWithMultipleTransitionsInFuture)); @@ -81,11 +97,7 @@ void precomputed_with_multiple_transitions_in_future_goes_through_each_in_turn() assertEquals(15, currentValue(precomputedWithMultipleTransitionsInFuture)); } - final Resource> precomputedWithMultipleTransitionsInPast = - precomputed(0, new TreeMap<>(Map.of( - duration(-2, MINUTE), 5, - duration(-5, MINUTE), 10, - duration(-6, MINUTE), 15))); + final Resource> precomputedWithMultipleTransitionsInPast; @Test void precomputed_with_multiple_transition_in_past_uses_last_value_forever() { assertEquals(5, currentValue(precomputedWithMultipleTransitionsInPast)); @@ -95,12 +107,7 @@ void precomputed_with_multiple_transition_in_past_uses_last_value_forever() { assertEquals(5, currentValue(precomputedWithMultipleTransitionsInPast)); } - final Resource> precomputedWithTransitionsInPastAndFuture = - precomputed(0, new TreeMap<>(Map.of( - duration(-5, MINUTE), 25, - duration(-2, MINUTE), 5, - duration(5, MINUTE), 10, - duration(6, MINUTE), 15))); + final Resource> precomputedWithTransitionsInPastAndFuture; @Test void precomputed_with_transitions_in_past_and_future_chooses_starting_value_and_changes_later() { assertEquals(5, currentValue(precomputedWithTransitionsInPastAndFuture)); @@ -112,13 +119,7 @@ void precomputed_with_transitions_in_past_and_future_chooses_starting_value_and_ assertEquals(15, currentValue(precomputedWithTransitionsInPastAndFuture)); } - final Resource> precomputedWithInstantKeys = - precomputed(0, new TreeMap<>(Map.of( - Instant.parse("2023-10-17T23:55:00Z"), 25, - Instant.parse("2023-10-17T23:58:00Z"), 5, - Instant.parse("2023-10-18T00:05:00Z"), 10, - Instant.parse("2023-10-18T00:06:00Z"), 15)), - Instant.parse("2023-10-18T00:00:00Z")); + final Resource> precomputedWithInstantKeys; @Test void precomputed_with_instant_keys_behaves_identically_to_equivalent_duration_offsets() { assertEquals(5, currentValue(precomputedWithInstantKeys)); 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..d58eec0d4b 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 @@ -1,5 +1,6 @@ package gov.nasa.jpl.aerie.contrib.streamline.modeling.polynomial; +import gov.nasa.jpl.aerie.contrib.streamline.StreamlineSystem; import gov.nasa.jpl.aerie.contrib.streamline.core.MutableResource; import gov.nasa.jpl.aerie.contrib.streamline.core.Expiry; import gov.nasa.jpl.aerie.contrib.streamline.core.Resource; @@ -29,21 +30,23 @@ @TestInstance(Lifecycle.PER_CLASS) public class ComparisonsTest { public ComparisonsTest(final Registrar registrar) { - Resources.init(); + StreamlineSystem.testInit(registrar); + + p = resource(polynomial(0)); + q = resource(polynomial(0)); + 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 MutableResource p = resource(polynomial(0)); - private final MutableResource 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); - - 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..010bcf5684 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 @@ -1,7 +1,9 @@ package gov.nasa.jpl.aerie.contrib.streamline.modeling.polynomial; +import gov.nasa.jpl.aerie.contrib.streamline.StreamlineSystem; import gov.nasa.jpl.aerie.contrib.streamline.core.*; import gov.nasa.jpl.aerie.contrib.streamline.modeling.polynomial.LinearBoundaryConsistencySolver.Domain; +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.Nested; @@ -28,8 +30,8 @@ class SingleVariableSingleConstraint { MutableResource driver = resource(polynomial(10)); Resource result; - public SingleVariableSingleConstraint() { - Resources.init(); + public SingleVariableSingleConstraint(final Registrar registrar) { + StreamlineSystem.testInit(registrar); var solver = new LinearBoundaryConsistencySolver("SingleVariableSingleConstraint"); var v = solver.variable("v", Domain::upperBound); @@ -70,8 +72,8 @@ class SingleVariableMultipleConstraint { MutableResource upperBound = resource(polynomial(30)); Resource result; - public SingleVariableMultipleConstraint() { - Resources.init(); + public SingleVariableMultipleConstraint(final Registrar registrar) { + StreamlineSystem.testInit(registrar); var solver = new LinearBoundaryConsistencySolver("SingleVariableMultipleConstraint"); var v = solver.variable("v", Domain::lowerBound); @@ -144,8 +146,8 @@ class ScalingConstraint { MutableResource driver = resource(polynomial(10)); Resource result; - public ScalingConstraint() { - Resources.init(); + public ScalingConstraint(final Registrar registrar) { + StreamlineSystem.testInit(registrar); var solver = new LinearBoundaryConsistencySolver("ScalingConstraint"); var v = solver.variable("v", Domain::upperBound); @@ -175,8 +177,8 @@ class MultipleVariables { MutableResource upperBoundOnC = resource(polynomial(5)); Resource a, b, c; - public MultipleVariables() { - Resources.init(); + public MultipleVariables(final Registrar registrar) { + StreamlineSystem.testInit(registrar); 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..502e18d0b5 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 @@ -1,5 +1,6 @@ package gov.nasa.jpl.aerie.contrib.streamline.modeling.polynomial; +import gov.nasa.jpl.aerie.contrib.streamline.StreamlineSystem; 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; @@ -25,11 +26,27 @@ @TestInstance(Lifecycle.PER_CLASS) public class PrecomputedTest { public PrecomputedTest(final Registrar registrar) { - Resources.init(); + StreamlineSystem.testInit(registrar); + + precomputedAsConstantInPast = precomputed(new TreeMap<>(Map.of(duration(-1, MINUTE), 4.0))); + precomputedAsConstantInFuture = precomputed(new TreeMap<>(Map.of(duration(2, HOUR), 4.0))); + precomputedWithSingleInteriorSegmentInPast = precomputed(new TreeMap<>(Map.of( + duration(-100, SECOND), 0.0, + duration(-50, SECOND), 5.0))); + precomputedWithSingleInteriorSegmentInFuture = precomputed(new TreeMap<>(Map.of( + duration(50, SECOND), 0.0, + duration(100, SECOND), 5.0))); + precomputedStartingInInterior = precomputed(new TreeMap<>(Map.of( + duration(-50, SECOND), 0.0, + duration(50, SECOND), 10.0))); + precomputedWithMultipleSegments = precomputed(new TreeMap<>(Map.of( + duration(-50, SECOND), 0.0, + duration(50, SECOND), 10.0, + duration(60, SECOND), 30.0, + duration(90, SECOND), -30.0))); } - final Resource precomputedAsConstantInPast = - precomputed(new TreeMap<>(Map.of(duration(-1, MINUTE), 4.0))); + final Resource precomputedAsConstantInPast; @Test void precomputed_with_single_point_in_past_extrapolates_that_value_forever() { assertValueEquals(4.0, precomputedAsConstantInPast); @@ -39,8 +56,7 @@ void precomputed_with_single_point_in_past_extrapolates_that_value_forever() { assertValueEquals(4.0, precomputedAsConstantInPast); } - final Resource precomputedAsConstantInFuture = - precomputed(new TreeMap<>(Map.of(duration(2, HOUR), 4.0))); + final Resource precomputedAsConstantInFuture; @Test void precomputed_with_single_point_in_future_extrapolates_that_value_forever() { assertValueEquals(4.0, precomputedAsConstantInFuture); @@ -54,10 +70,7 @@ void precomputed_with_single_point_in_future_extrapolates_that_value_forever() { assertValueEquals(4.0, precomputedAsConstantInFuture); } - final Resource precomputedWithSingleInteriorSegmentInPast = - precomputed(new TreeMap<>(Map.of( - duration(-100, SECOND), 0.0, - duration(-50, SECOND), 5.0))); + final Resource precomputedWithSingleInteriorSegmentInPast; @Test void precomputed_with_single_interior_segment_in_past_extrapolates_final_value() { assertValueEquals(5.0, precomputedWithSingleInteriorSegmentInPast); @@ -67,10 +80,7 @@ void precomputed_with_single_interior_segment_in_past_extrapolates_final_value() assertValueEquals(5.0, precomputedWithSingleInteriorSegmentInPast); } - final Resource precomputedWithSingleInteriorSegmentInFuture = - precomputed(new TreeMap<>(Map.of( - duration(50, SECOND), 0.0, - duration(100, SECOND), 5.0))); + final Resource precomputedWithSingleInteriorSegmentInFuture; @Test void precomputed_with_single_interior_segment_in_future_interpolates_that_segment() { assertValueEquals(0.0, precomputedWithSingleInteriorSegmentInFuture); @@ -90,10 +100,7 @@ void precomputed_with_single_interior_segment_in_future_interpolates_that_segmen assertValueEquals(5.0, precomputedWithSingleInteriorSegmentInFuture); } - final Resource precomputedStartingInInterior = - precomputed(new TreeMap<>(Map.of( - duration(-50, SECOND), 0.0, - duration(50, SECOND), 10.0))); + final Resource precomputedStartingInInterior; void precomputed_starting_in_interior_interpolates_over_full_segment() { assertValueEquals(5.0, precomputedStartingInInterior); delay(10, SECOND); @@ -110,12 +117,7 @@ void precomputed_starting_in_interior_interpolates_over_full_segment() { assertValueEquals(10.0, precomputedStartingInInterior); } - final Resource precomputedWithMultipleSegments = - precomputed(new TreeMap<>(Map.of( - duration(-50, SECOND), 0.0, - duration(50, SECOND), 10.0, - duration(60, SECOND), 30.0, - duration(90, SECOND), -30.0))); + final Resource precomputedWithMultipleSegments; @Test void precomputed_with_multiple_segments_interpolates_each_segment_independently() { assertValueEquals(5.0, precomputedWithMultipleSegments); From dcc723be510f51dccaf359451ae5b4b50009ba5c Mon Sep 17 00:00:00 2001 From: David Legg Date: Mon, 27 Jan 2025 16:12:53 -0800 Subject: [PATCH 4/4] Expose global absolute clock Using the absolute-timed InstantClock, add a new global simulation clock created by StreamlineSystem.init. Also, refactor the arguments to StreamlineSystem.init into an InitArgs object with an accompanying builder. This lets us write a "testBuilder" constructor that fills in as many init args with defaults as it can, while letting us override parameters if needed. This pattern will extend well if we need to add more parameters in the future. Using the global simulation clock, removes the "plan start time" parameter from the overload of DiscreteResources.precomputed that uses Instant keys. This guarantees that absolute-timed precomputed resources are synced with the global clock. This also creates a name collision with the version of precomputed that uses Duration keys, so the one with Instant keys was renamed to precomputed$. --- .../contrib/streamline/StreamlineSystem.java | 101 ++++++++++++++---- .../modeling/discrete/DiscreteResources.java | 12 ++- .../streamline/core/CellRefV2Test.java | 7 +- .../debugging/DependenciesTest.java | 6 +- .../modeling/clocks/SimulationClockTest.java | 13 ++- .../discrete/DiscreteEffectsTest.java | 2 +- .../modeling/discrete/PrecomputedTest.java | 21 ++-- .../modeling/polynomial/ComparisonsTest.java | 2 +- .../LinearBoundaryConsistencySolverTest.java | 8 +- .../modeling/polynomial/PrecomputedTest.java | 2 +- .../jpl/aerie/streamline_demo/Mission.java | 19 +++- 11 files changed, 140 insertions(+), 53 deletions(-) diff --git a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/StreamlineSystem.java b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/StreamlineSystem.java index ce01dc155f..ae5e1c456a 100644 --- a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/StreamlineSystem.java +++ b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/StreamlineSystem.java @@ -5,18 +5,81 @@ import gov.nasa.jpl.aerie.contrib.streamline.modeling.Registrar; import gov.nasa.jpl.aerie.contrib.streamline.modeling.Registration; import gov.nasa.jpl.aerie.contrib.streamline.modeling.clocks.Clock; +import gov.nasa.jpl.aerie.contrib.streamline.modeling.clocks.ClockResources; +import gov.nasa.jpl.aerie.contrib.streamline.modeling.clocks.InstantClock; +import gov.nasa.jpl.aerie.contrib.streamline.modeling.clocks.InstantClockResources; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; -import static gov.nasa.jpl.aerie.contrib.streamline.core.MutableResource.resource; +import java.time.Instant; +import java.util.Objects; + import static gov.nasa.jpl.aerie.contrib.streamline.core.Resources.currentValue; -import static gov.nasa.jpl.aerie.contrib.streamline.modeling.clocks.Clock.clock; -import static gov.nasa.jpl.aerie.merlin.protocol.types.Duration.ZERO; public final class StreamlineSystem { private static Resource CLOCK; + private static Resource ABSOLUTE_CLOCK; private StreamlineSystem() {} + /** + * Arguments required for {@link StreamlineSystem#init}, packaged into an object for easier handling. + *

+ * Can be constructed directly, or through {@link InitArgs#builder}. + *

+ */ + public record InitArgs( + gov.nasa.jpl.aerie.merlin.framework.Registrar baseRegistrar, + Registrar.ErrorBehavior errorBehavior, + Instant planStart) { + /** + * Returns a blank {@link Builder}. + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Returns a {@link Builder} with some fields set to defaults generally appropriate for testing. + */ + public static Builder testBuilder() { + return builder() + .errorBehavior(Registrar.ErrorBehavior.Throw) + .planStart(Instant.EPOCH); + } + + public static class Builder { + private gov.nasa.jpl.aerie.merlin.framework.Registrar baseRegistrar; + private Registrar.ErrorBehavior errorBehavior; + private Instant planStart; + + private Builder() {} + + public Builder baseRegistrar(final gov.nasa.jpl.aerie.merlin.framework.Registrar baseRegistrar) { + this.baseRegistrar = baseRegistrar; + return this; + } + + public Builder errorBehavior(final Registrar.ErrorBehavior errorBehavior) { + this.errorBehavior = errorBehavior; + return this; + } + + public Builder planStart(final Instant planStart) { + this.planStart = planStart; + return this; + } + + public InitArgs build() { + return new InitArgs( + Objects.requireNonNull(baseRegistrar, "baseRegistrar must be set"), + Objects.requireNonNull(errorBehavior, "errorBehavior must be set"), + Objects.requireNonNull(planStart, "planStart must be set") + ); + } + } + + } + /** * Initialize all streamline singletons. * This method should be called once as the first step of creating a model. @@ -29,24 +92,26 @@ private StreamlineSystem() {} * as well as initialize the singletons contained within this class. *

*/ - public static void init( - final gov.nasa.jpl.aerie.merlin.framework.Registrar baseRegistrar, - final Registrar.ErrorBehavior errorBehavior) { - CLOCK = resource(clock(ZERO)); - Logging.init(baseRegistrar); - Registration.init(baseRegistrar, errorBehavior); - } - - /** - * Variation on {@link StreamlineSystem#init} for unit testing. - * Fills in most arguments with defaults suitable for testing. - */ - public static void testInit( - final gov.nasa.jpl.aerie.merlin.framework.Registrar baseRegistrar) { - init(baseRegistrar, Registrar.ErrorBehavior.Throw); + public static void init(InitArgs args) { + CLOCK = ClockResources.clock(); + ABSOLUTE_CLOCK = InstantClockResources.absoluteClock(args.planStart); + Logging.init(args.baseRegistrar); + Registration.init(args.baseRegistrar, args.errorBehavior); } public static Duration currentTime() { return currentValue(CLOCK); } + + public static Resource simulationClock() { + return CLOCK; + } + + public static Instant currentInstant() { + return currentValue(ABSOLUTE_CLOCK); + } + + public static Resource absoluteClock() { + return ABSOLUTE_CLOCK; + } } diff --git a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/discrete/DiscreteResources.java b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/discrete/DiscreteResources.java index 5a54a9a229..80c7816e54 100644 --- a/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/discrete/DiscreteResources.java +++ b/contrib/src/main/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/discrete/DiscreteResources.java @@ -19,6 +19,8 @@ import java.util.function.BiPredicate; import java.util.function.Supplier; +import static gov.nasa.jpl.aerie.contrib.streamline.StreamlineSystem.currentInstant; +import static gov.nasa.jpl.aerie.contrib.streamline.StreamlineSystem.simulationClock; import static gov.nasa.jpl.aerie.contrib.streamline.core.CellRefV2.autoEffects; import static gov.nasa.jpl.aerie.contrib.streamline.core.CellRefV2.testing; import static gov.nasa.jpl.aerie.contrib.streamline.core.Expiring.expiring; @@ -121,10 +123,9 @@ public static > Resource> sampled * Resource value is the value associated with the greatest key in segments not exceeding * the current simulation time, or valueBeforeFirstEntry if every key exceeds current simulation time. */ - public static Resource> precomputed( + public static Resource> precomputed$( final V valueBeforeFirstEntry, final NavigableMap segments) { - var clock = clock(); - return signalling(bind(clock, (Clock clock$) -> { + return signalling(bind(simulationClock(), (Clock clock$) -> { var t = clock$.extract(); var entry = segments.floorEntry(t); var value = entry == null ? valueBeforeFirstEntry : entry.getValue(); @@ -139,14 +140,15 @@ public static Resource> precomputed( * the current simulation time, or valueBeforeFirstEntry if every key exceeds current simulation time. */ public static Resource> precomputed( - final V valueBeforeFirstEntry, final NavigableMap segments, final Instant simulationStartTime) { + final V valueBeforeFirstEntry, final NavigableMap segments) { + var simulationStartTime = currentInstant(); var segmentsUsingDurationKeys = new TreeMap(); for (var entry : segments.entrySet()) { segmentsUsingDurationKeys.put( Duration.of(ChronoUnit.MICROS.between(simulationStartTime, entry.getKey()), Duration.MICROSECONDS), entry.getValue()); } - return precomputed(valueBeforeFirstEntry, segmentsUsingDurationKeys); + return precomputed$(valueBeforeFirstEntry, segmentsUsingDurationKeys); } /** 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 b2daebffc3..d6bd2d4a22 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 @@ -1,6 +1,7 @@ package gov.nasa.jpl.aerie.contrib.streamline.core; import gov.nasa.jpl.aerie.contrib.streamline.StreamlineSystem; +import gov.nasa.jpl.aerie.contrib.streamline.StreamlineSystem.InitArgs; 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; @@ -28,7 +29,7 @@ class MutableResourceTest { @TestInstance(Lifecycle.PER_CLASS) class NonCommutingEffects { public NonCommutingEffects(final Registrar registrar) { - StreamlineSystem.testInit(registrar); + StreamlineSystem.init(InitArgs.testBuilder().baseRegistrar(registrar).build()); cell = MutableResource.resource(discrete(42), noncommutingEffects()); } @@ -69,7 +70,7 @@ void throws_exception_when_concurrent_effects_are_applied() { @TestInstance(Lifecycle.PER_CLASS) class CommutingEffects { public CommutingEffects(final Registrar registrar) { - StreamlineSystem.testInit(registrar); + StreamlineSystem.init(InitArgs.testBuilder().baseRegistrar(registrar).build()); cell = MutableResource.resource(discrete(42), commutingEffects()); } @@ -114,7 +115,7 @@ void applies_concurrent_effects_in_any_order() { @TestInstance(Lifecycle.PER_CLASS) class AutoEffects { public AutoEffects(final Registrar registrar) { - StreamlineSystem.testInit(registrar); + StreamlineSystem.init(InitArgs.testBuilder().baseRegistrar(registrar).build()); cell = MutableResource.resource(discrete(42), autoEffects()); } 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 75ea39427a..69e66d1483 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,10 +1,12 @@ package gov.nasa.jpl.aerie.contrib.streamline.debugging; +import gov.nasa.jpl.aerie.contrib.streamline.StreamlineSystem; 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; +import gov.nasa.jpl.aerie.merlin.framework.Registrar; import gov.nasa.jpl.aerie.merlin.framework.junit.MerlinExtension; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -23,8 +25,8 @@ @ExtendWith(MerlinExtension.class) @TestInstance(TestInstance.Lifecycle.PER_CLASS) class DependenciesTest { - public DependenciesTest() { - Resources.init(Instant.EPOCH); + public DependenciesTest(final Registrar registrar) { + StreamlineSystem.init(StreamlineSystem.InitArgs.testBuilder().baseRegistrar(registrar).build()); constantTrue = DiscreteResources.constant(true); constant1234 = constant(1234); diff --git a/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/SimulationClockTest.java b/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/SimulationClockTest.java index 6efac343e7..c8b77a2ede 100644 --- a/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/SimulationClockTest.java +++ b/contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/modeling/clocks/SimulationClockTest.java @@ -1,6 +1,7 @@ package gov.nasa.jpl.aerie.contrib.streamline.modeling.clocks; -import gov.nasa.jpl.aerie.contrib.streamline.core.Resources; +import gov.nasa.jpl.aerie.contrib.streamline.StreamlineSystem; +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; @@ -10,7 +11,8 @@ import java.time.Instant; import java.time.temporal.ChronoUnit; -import static gov.nasa.jpl.aerie.contrib.streamline.core.Resources.*; +import static gov.nasa.jpl.aerie.contrib.streamline.StreamlineSystem.*; +import static gov.nasa.jpl.aerie.contrib.streamline.core.Resources.currentValue; import static gov.nasa.jpl.aerie.merlin.framework.ModelActions.delay; import static gov.nasa.jpl.aerie.merlin.protocol.types.Duration.HOUR; import static gov.nasa.jpl.aerie.merlin.protocol.types.Duration.ZERO; @@ -22,8 +24,11 @@ public class SimulationClockTest { // This time is unlikely to be a hard-coded default anywhere public static final Instant PLAN_START = Instant.parse("2020-01-02T03:04:05Z"); - public SimulationClockTest() { - Resources.init(PLAN_START); + public SimulationClockTest(final Registrar registrar) { + StreamlineSystem.init(InitArgs.testBuilder() + .baseRegistrar(registrar) + .planStart(PLAN_START) + .build()); } @Test 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 899f4f6a10..245cd3a896 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 @@ -41,7 +41,7 @@ @TestInstance(Lifecycle.PER_CLASS) class DiscreteEffectsTest { public DiscreteEffectsTest(final Registrar registrar) { - StreamlineSystem.testInit(registrar); + StreamlineSystem.init(StreamlineSystem.InitArgs.testBuilder().baseRegistrar(registrar).build()); } 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 eeb6ba0596..497b0d3be9 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 @@ -17,6 +17,7 @@ import static gov.nasa.jpl.aerie.contrib.streamline.core.Resources.currentValue; import static gov.nasa.jpl.aerie.contrib.streamline.modeling.discrete.DiscreteResources.precomputed; +import static gov.nasa.jpl.aerie.contrib.streamline.modeling.discrete.DiscreteResources.precomputed$; import static gov.nasa.jpl.aerie.merlin.framework.ModelActions.delay; import static gov.nasa.jpl.aerie.merlin.protocol.types.Duration.*; import static org.junit.jupiter.api.Assertions.*; @@ -28,19 +29,22 @@ @TestInstance(Lifecycle.PER_CLASS) public class PrecomputedTest { public PrecomputedTest(final Registrar registrar) { - StreamlineSystem.testInit(registrar); - precomputedAsAConstant = precomputed(4, new TreeMap<>()); - precomputedWithOneTransitionInFuture = precomputed(0, new TreeMap<>(Map.of(MINUTE, 10))); - precomputedWithOneTransitionInPast = precomputed(0, new TreeMap<>(Map.of(duration(-1, MINUTE), 10))); - precomputedWithMultipleTransitionsInFuture = precomputed(0, new TreeMap<>(Map.of( + StreamlineSystem.init(StreamlineSystem.InitArgs.testBuilder() + .baseRegistrar(registrar) + .planStart(Instant.parse("2023-10-18T00:00:00Z")) + .build()); + precomputedAsAConstant = precomputed$(4, new TreeMap<>()); + precomputedWithOneTransitionInFuture = precomputed$(0, new TreeMap<>(Map.of(MINUTE, 10))); + precomputedWithOneTransitionInPast = precomputed$(0, new TreeMap<>(Map.of(duration(-1, MINUTE), 10))); + precomputedWithMultipleTransitionsInFuture = precomputed$(0, new TreeMap<>(Map.of( duration(2, MINUTE), 5, duration(5, MINUTE), 10, duration(6, MINUTE), 15))); - precomputedWithMultipleTransitionsInPast = precomputed(0, new TreeMap<>(Map.of( + precomputedWithMultipleTransitionsInPast = precomputed$(0, new TreeMap<>(Map.of( duration(-2, MINUTE), 5, duration(-5, MINUTE), 10, duration(-6, MINUTE), 15))); - precomputedWithTransitionsInPastAndFuture = precomputed(0, new TreeMap<>(Map.of( + precomputedWithTransitionsInPastAndFuture = precomputed$(0, new TreeMap<>(Map.of( duration(-5, MINUTE), 25, duration(-2, MINUTE), 5, duration(5, MINUTE), 10, @@ -49,8 +53,7 @@ public PrecomputedTest(final Registrar registrar) { Instant.parse("2023-10-17T23:55:00Z"), 25, Instant.parse("2023-10-17T23:58:00Z"), 5, Instant.parse("2023-10-18T00:05:00Z"), 10, - Instant.parse("2023-10-18T00:06:00Z"), 15)), - Instant.parse("2023-10-18T00:00:00Z")); + Instant.parse("2023-10-18T00:06:00Z"), 15))); } 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 d58eec0d4b..c0ce64b096 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 @@ -30,7 +30,7 @@ @TestInstance(Lifecycle.PER_CLASS) public class ComparisonsTest { public ComparisonsTest(final Registrar registrar) { - StreamlineSystem.testInit(registrar); + StreamlineSystem.init(StreamlineSystem.InitArgs.testBuilder().baseRegistrar(registrar).build()); p = resource(polynomial(0)); q = resource(polynomial(0)); 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 f542f731af..612586ccc1 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 @@ -31,7 +31,7 @@ class SingleVariableSingleConstraint { Resource result; public SingleVariableSingleConstraint(final Registrar registrar) { - StreamlineSystem.testInit(registrar); + StreamlineSystem.init(StreamlineSystem.InitArgs.testBuilder().baseRegistrar(registrar).build()); driver = resource(polynomial(10)); @@ -73,7 +73,7 @@ class SingleVariableMultipleConstraint { Resource result; public SingleVariableMultipleConstraint(final Registrar registrar) { - StreamlineSystem.testInit(registrar); + StreamlineSystem.init(StreamlineSystem.InitArgs.testBuilder().baseRegistrar(registrar).build()); lowerBound1 = resource(polynomial(10)); lowerBound2 = resource(polynomial(20)); @@ -151,7 +151,7 @@ class ScalingConstraint { Resource result; public ScalingConstraint(final Registrar registrar) { - StreamlineSystem.testInit(registrar); + StreamlineSystem.init(StreamlineSystem.InitArgs.testBuilder().baseRegistrar(registrar).build()); driver = resource(polynomial(10)); @@ -183,7 +183,7 @@ class MultipleVariables { Resource a, b, c; public MultipleVariables(final Registrar registrar) { - StreamlineSystem.testInit(registrar); + StreamlineSystem.init(StreamlineSystem.InitArgs.testBuilder().baseRegistrar(registrar).build()); upperBound = resource(polynomial(10)); upperBoundOnC = resource(polynomial(5)); 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 502e18d0b5..849f40a84d 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 @@ -26,7 +26,7 @@ @TestInstance(Lifecycle.PER_CLASS) public class PrecomputedTest { public PrecomputedTest(final Registrar registrar) { - StreamlineSystem.testInit(registrar); + StreamlineSystem.init(StreamlineSystem.InitArgs.testBuilder().baseRegistrar(registrar).build()); precomputedAsConstantInPast = precomputed(new TreeMap<>(Map.of(duration(-1, MINUTE), 4.0))); precomputedAsConstantInFuture = precomputed(new TreeMap<>(Map.of(duration(2, HOUR), 4.0))); 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 a1d32e971a..03bc47e965 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 @@ -1,24 +1,33 @@ package gov.nasa.jpl.aerie.streamline_demo; +import gov.nasa.jpl.aerie.contrib.streamline.StreamlineSystem; +import gov.nasa.jpl.aerie.contrib.streamline.StreamlineSystem.InitArgs; import gov.nasa.jpl.aerie.contrib.streamline.core.Resource; import gov.nasa.jpl.aerie.contrib.streamline.debugging.Profiling; import gov.nasa.jpl.aerie.contrib.streamline.modeling.Registrar; +import gov.nasa.jpl.aerie.contrib.streamline.modeling.Registration; import gov.nasa.jpl.aerie.merlin.framework.ModelActions; import java.time.Instant; +import static gov.nasa.jpl.aerie.contrib.streamline.modeling.Registration.REGISTRAR; + 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$, Instant planStart, final Configuration config) { - var registrar = new Registrar(registrar$, planStart, Registrar.ErrorBehavior.Log); - if (config.traceResources) registrar.setTrace(); + StreamlineSystem.init(InitArgs.builder() + .baseRegistrar(registrar$) + .planStart(planStart) + .errorBehavior(Registrar.ErrorBehavior.Log) + .build()); + if (config.traceResources) REGISTRAR.setTrace(); if (config.profileResources) Resource.profileAllResources(); - dataModel = new DataModel(registrar, config); - errorTestingModel = new ErrorTestingModel(registrar, config); - approximationModel = new ApproximationModel(registrar, config); + dataModel = new DataModel(REGISTRAR, config); + errorTestingModel = new ErrorTestingModel(REGISTRAR, config); + approximationModel = new ApproximationModel(REGISTRAR, config); if (config.profilingDumpTime.isPositive()) { ModelActions.defer(config.profilingDumpTime, Profiling::dump); }