Skip to main content

Enumerated and Derived Resources

In addition to our on-board camera, let's imagine that we also have an instrument on-board that is continuously collecting data, say a magnetometer, based on a data collection mode. Perhaps at especially interesting times in the mission, the magnetometer is placed in a high rate collection mode and at other times remains in a low rate collection mode. For our model, we want to be able to track the collection mode over time along with the associated data collection rate of that mode.

The first thing we'll do to accomplish this is create a Java enumeration called MagDataCollectionMode that gives us the list of available collection modes along with a mapping of those modes to data collection rates using enum fields. We will also add a getter method to get the data rate based on the mode. Let's say that we have three modes, OFF, LOW_RATE, and HIGH_RATE with values 0.0, 500.0, and 5000.0, respectively. After coding this up, our enum should look like this:

package missionmodel;

public enum MagDataCollectionMode {
OFF(0.0), // kbps
LOW_RATE(500.0), // kbps
HIGH_RATE(5000.0); // kbps

private final double magDataRate;

MagDataCollectionMode(double magDataRate) {
this.magDataRate = magDataRate;
}

public double getDataRate() {
return magDataRate;
}
}

With our enumeration built, we can now add a couple of new resources to our DataModel class. The first resource, which we'll call MagDataMode, will track the current data collection mode for the magnetometer. Declare this resource as a discrete MutableResource of type MagDataCollectionMode

public MutableResource<Discrete<MagDataCollectionMode>> MagDataMode;

and then add the following lines of code to the constructor to initialize the resource to OFF and register it with the UI.

MagDataMode = resource(discrete(MagDataCollectionMode.OFF));
registrar.discrete("MagDataMode",MagDataMode, new EnumValueMapper<>(MagDataCollectionMode.class));

As you can see, declaring and defining this resource was not much different than when we built RecordingRate except instead of referencing the Double type, we are referencing our enumerated type MagDataCollectionMode.

Another resource we can add is one to track the numerical value of the data collection rate of the magnetometer, which is based on the collection mode. In other words, we can derive the value of the rate from the mode. Since we are deriving this value and don't intend to emit effects directly onto this resource, we can declare it as a discrete Resource of type Double instead of a MutableResource.

public Resource<Discrete<Double>> MagDataRate; // bps

When we go to define this resource in the constructor, we need to tell the resource to get its value by mapping the MagDataMode to its corresponding rate. A special static method in the DiscreteResourceMonad class called map() allows us to define a function that operates on the value of a resource to get a derived resource value. In this case, that function is simply the getter function we added to the MagDataCollectionMode. The resulting definition and registration code for MagDataRate then becomes

MagDataRate = map(MagDataMode, MagDataCollectionMode::getDataRate);
registrar.discrete("MagDataRate", MagDataRate, new DoubleValueMapper());
tip

If your IDE is struggling to find the map() function, the associated import statement is

import static gov.nasa.jpl.aerie.contrib.streamline.modeling.discrete.monads.DiscreteResourceMonad.map;
info

Instead of deriving a resource value from a function using map(), there are a number of static methods in the DiscreteResources class, which you can use to add(), multiply(), divide(), etc. resources. For example, you could have a Total resource that simple used add() to sum some resources together.