T
- The type returned by the evaluator.public abstract class Evaluator<T> extends Object implements IEvaluator1<T>, IIsTimeVarying
IEvaluator1
, making all interface methods and
properties abstract.
This is an example class which organizes user input to create an evaluator to perform a simple vector computation. The user provides a coefficient and a vector, and the evaluator multiplies the vector's magnitude by the coefficient.
public class ExampleComputation {
/**
* Here is a coefficient which the user specifies for the computation.
*/
public double UserCoefficient = 1.0;
/**
* Here is a vector which the user can modify to analyze different vectors which may vary with time.
*/
public Vector UserVector = new VectorFixed(Axes.getRoot(), new Cartesian(4.2, 0.0, -1.3));
/**
* This method takes the user's data above and creates an IEvaluator to perform the calculation.
* Notice that a {@link VectorEvaluator} is required for the calculation. The {@link EvaluatorGroup}
* provides a way to reuse an identical {@link VectorEvaluator} if it already exists or creates a new
* instance if it does not.
*
* @param group The repository of existing evaluators.
* @return A generic evaluator which can be used to compute the desired vector operation.
*/
public final IEvaluator1<Double> getEvaluator(EvaluatorGroup group) {
if (group == null) {
throw new ArgumentNullException("group");
}
// Use the Evaluator group to optimize the behavior of the Evaluators used in this one.
return group.createEvaluator(getEvaluatorCallback);
}
private IEvaluator1<Double> createEvaluator(EvaluatorGroup group) {
// By using the getEvaluator methods on other components, its easy to make
// new Evaluators based on existing Evaluators.
VectorEvaluator componentEvaluator = UserVector.getEvaluator(group);
return new MyEvaluator(group, UserCoefficient, componentEvaluator);
}
private final EvaluatorGroup.Callback0<IEvaluator1<Double>> getEvaluatorCallback = EvaluatorGroup.Callback0.of(this::createEvaluator);
/**
* Here the implementation of the evaluator is defined and encapsulated.
*/
private static final class MyEvaluator extends Evaluator<Double> {
/**
* A constructor takes parameters from the GetEvaluator method, ensuring that it only uses
* objects which cannot be changed from outside the evaluator. If such an object is needed
* as a parameter, it should be copied to a new instance.
*
* @param group The group that contains this evaluator.
* @param coefficient A scalar coefficient.
* @param vectorEvaluator A vector evaluator to include in a simple computation.
*/
public MyEvaluator(EvaluatorGroup group, double coefficient, VectorEvaluator vectorEvaluator) {
super(group);
m_coefficient = coefficient;
m_vectorEvaluator = vectorEvaluator;
}
/**
* This constructor provides a way to copy this instance of the evaluator to other threads.
* This is called by the clone method.
*
* @param existingInstance An existing instance.
* @param context The context in which to make a copy.
*/
private MyEvaluator(MyEvaluator existingInstance, CopyContext context) {
super(existingInstance, context);
m_coefficient = existingInstance.m_coefficient;
m_vectorEvaluator = existingInstance.m_vectorEvaluator;
updateEvaluatorReferences(context);
}
/**
* This method is used by {@link EvaluatorGroup} to update the evaluator references held
* by this evaluator. If two evaluators share a third, the two evaluators will be updated to
* refer to a caching wrapper for that third evaluator.
*
* @param context The context that specifies the reference mapping.
*/
@Override
public void updateEvaluatorReferences(CopyContext context) {
// Call updateReference on any Evaluators used in this one
m_vectorEvaluator = context.updateReference(m_vectorEvaluator);
}
/**
* Copy this evaluator.
*
* @param context The context in which to make a copy.
* @return A copy of this instance.
*/
@Override
public Object clone(CopyContext context) {
return new MyEvaluator(this, context);
}
/**
* This property provides a way of determining if multiple threads can call this instance
* simultaneously or whether it needs to be copied.
*/
@Override
public boolean getIsThreadSafe() {
// Check whether the vector evaluator used in the calculation is threadsafe.
// If any Evaluators used in this one are not threadsafe, this one is not threadsafe.
return m_vectorEvaluator.getIsThreadSafe();
}
/**
* This property determines if this Evaluator result
* changes depending on the time at which it is evaluated.
*/
@Override
public boolean getIsTimeVarying() {
return m_vectorEvaluator.getIsTimeVarying();
}
/**
* This method provides a way to check whether there are any times where the evaluator cannot
* provide a value.
*
* @param date A date to check.
* @return True if a value can be computed for the given date.
*/
@Override
public boolean isAvailable(JulianDate date) {
return m_vectorEvaluator.isAvailable(date);
}
/**
* This provides a collection of time intervals when this evaluator can produce a value.
* This should consist of an intersection of the AvailabilityIntervals of any Evaluators used
* in this one. In general, this will be an infinite span of time unless there is only a
* limited set of data. For instance, if the ephemeris source used in an Evaluator is only
* available for a range of dates, the valid timespan will be represented by the
* AvailabilityIntervals.
*
* @param consideredIntervals The intervals for which to consider availability.
*/
@Override
public TimeIntervalCollection getAvailabilityIntervals(TimeIntervalCollection consideredIntervals) {
return m_vectorEvaluator.getAvailabilityIntervals(consideredIntervals);
}
/**
* This is the actual calculation which we want to produce. Given a particular date, calculate
* the value of the result. After this evaluator is created, the result produced by
* the evaluator should not change even if the user changes {@link #UserCoefficient}
* or {@link #UserVector}.
*
* @param date The time at which to calculate the desired value.
* @return The resulting value.
*/
@Override
public Double evaluate(JulianDate date) {
// Evaluate the vector's magnitude
double vectorMagnitude = m_vectorEvaluator.evaluate(date).getMagnitude();
// Multiply that magnitude by the user specified coefficient
return m_coefficient * vectorMagnitude;
}
/**
* Return a {@link CachingEvaluator} which caches the value produced by this one.
* This allows the {@link EvaluatorGroup} to optimize performance when one evaluator
* is called multiple times at a particular {@link JulianDate}.
*
* @return An evaluator which caches the value of this one.
*/
@Override
public IEvaluator getCachingWrapper() {
return new CachingEvaluator<Double>(this);
}
/**
* Releases any resources associated with this instance.
*
* @param disposing {@code true} to release both managed and unmanaged resources;
* {@code false} to release only unmanaged resources.
*/
@Override
protected void dispose(boolean disposing) {
if (disposing) {
m_vectorEvaluator.dispose();
}
}
private final double m_coefficient;
private VectorEvaluator m_vectorEvaluator;
}
/**
* Here is an example of how to perform the computation.
*/
public static void example() {
// Create the computation
ExampleComputation computation = new ExampleComputation();
// Provide user data to the computation
computation.UserCoefficient = 42.0;
computation.UserVector = new VectorFixed(Axes.getRoot(), new Cartesian(3.14, 15.0, -9.2));
// Since this is a very simple computation, a group does not already exist.
// So, create a new one.
EvaluatorGroup newGroup = new EvaluatorGroup();
// Get the evaluator for the computation using the group.
IEvaluator1<Double> evaluator = computation.getEvaluator(newGroup);
// Then call the Evaluate method to calculate the value at the specified time.
double valueOne = evaluator.evaluate(TimeConstants.J2000);
// What happens if we change the value of the coefficient?
computation.UserCoefficient = -2.1;
// Evaluating the same evaluator will produce the same value even though the coefficient has changed!
double valueTwo = evaluator.evaluate(TimeConstants.J2000);
// To perform the computation with the current user values, get a new evaluator from the GetEvaluator method.
// Note that, since we have not changed the vector parameter, the use of the same EvaluatorGroup will
// ensure that the same VectorEvaluator is reused in the computation rather than creating a new one.
IEvaluator1<Double> newEvaluator = computation.getEvaluator(newGroup);
double newValue = newEvaluator.evaluate(TimeConstants.J2000);
System.out.println("The first calculation is: " + valueOne);
System.out.println("The second calculation is: " + valueTwo);
System.out.println("The new value is: " + newValue);
}
}
Modifier | Constructor and Description |
---|---|
protected |
Evaluator(Evaluator<T> existingInstance,
CopyContext context)
Initializes a new instance as a copy of an existing instance.
|
protected |
Evaluator(EvaluatorGroup group)
Initializes a new instance.
|
Modifier and Type | Method and Description |
---|---|
abstract Object |
clone(CopyContext context)
Clones this object using the specified context.
|
void |
dispose()
Releases any resources associated with this instance.
|
protected abstract void |
dispose(boolean disposing)
Releases any resources associated with this instance.
|
abstract T |
evaluate(JulianDate date)
Evaluates the function.
|
DateMotionCollection1<T> |
evaluate(JulianDate start,
JulianDate stop,
Duration step)
Evaluates this evaluator at a specified fixed step over the specified interval.
|
DateMotionCollection1<T> |
evaluate(JulianDate start,
JulianDate stop,
Duration step,
ITrackCalculationProgress tracker)
Evaluates this evaluator at a specified fixed step over the specified interval.
|
DateMotionCollection1<T> |
evaluate(TimeInterval interval,
Duration step)
Evaluates this evaluator at a specified fixed step over the specified interval.
|
DateMotionCollection1<T> |
evaluate(TimeInterval interval,
Duration step,
ITrackCalculationProgress tracker)
Evaluates this evaluator at a specified fixed step over the specified interval.
|
TimeIntervalCollection |
getAvailabilityIntervals()
Gets a
TimeIntervalCollection over which data is available. |
abstract TimeIntervalCollection |
getAvailabilityIntervals(TimeIntervalCollection consideredIntervals)
Gets the intervals over which data is available.
|
IEvaluator |
getCachingWrapper()
Gets a version of this evaluator that caches the previously computed value so that if it is evaluated
twice at the same date the computation is done only once.
|
EvaluatorGroup |
getGroup()
Gets the group that contains this evaluator.
|
abstract boolean |
getIsThreadSafe()
Gets a value indicating whether the methods on this instance are safe to call from
multiple threads simultaneously.
|
abstract boolean |
getIsTimeVarying()
Gets a value indicating whether or not the value of this evaluator changes with time.
|
abstract boolean |
isAvailable(JulianDate date)
Determines if valid data is available for the given
JulianDate . |
abstract void |
updateEvaluatorReferences(CopyContext context)
Updates the evaluator references held by this object using the reference-to-reference
mapping in the specified
CopyContext . |
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
close
protected Evaluator(@Nonnull EvaluatorGroup group)
group
- The group that contains this evaluator.ArgumentNullException
- Thrown when group
is null
.protected Evaluator(@Nonnull Evaluator<T> existingInstance, @Nonnull CopyContext context)
See ICloneWithContext.clone(CopyContext)
for more information about how to implement this constructor
in a derived class.
existingInstance
- The existing instance to copy.context
- A CopyContext
that controls the depth of the copy.ArgumentNullException
- Thrown when existingInstance
or context
is null
.public abstract void updateEvaluatorReferences(CopyContext context)
CopyContext
.
The following example shows how to implement this method for an evaluator that contains a nested evaluator:
@Override
public final void updateEvaluatorReferences(CopyContext context) {
m_nestedEvaluator = context.updateReference(m_nestedEvaluator);
}
This method is called by EvaluatorGroup
and usually does not need to be
called directly by users. EvaluatorGroup
uses this method to replace references
to shared evaluators with references to caching versions of the evaluators.
To implement this method, call CopyContext.updateReference(T)
on each evaluator reference
held by your evaluator and assign the return value back to the field.
updateEvaluatorReferences
in interface IEvaluator
context
- The context that specifies the reference mapping.public abstract Object clone(CopyContext context)
This method should be implemented to call a copy constructor on the class of the
object being cloned. The copy constructor should take the CopyContext
as a parameter
in addition to the existing instance to copy. The copy constructor should first call
CopyContext.addObjectMapping(T, T)
to identify the newly constructed instance
as a copy of the existing instance. It should then copy all fields, using
CopyContext.updateReference(T)
to copy any reference fields.
A typical implementation of ICloneWithContext
:
public static class MyClass implements ICloneWithContext {
public MyClass(MyClass existingInstance, CopyContext context) {
context.addObjectMapping(existingInstance, this);
someReference = context.updateReference(existingInstance.someReference);
}
@Override
public final Object clone(CopyContext context) {
return new MyClass(this, context);
}
private Object someReference;
}
In general, all fields that are reference types should be copied with a call to
CopyContext.updateReference(T)
. There are a couple of exceptions:
If one of these exceptions applies, the CopyContext
should be given an opportunity
to update the reference before the reference is copied explicitly. Use
CopyContext.updateReference(T)
to update the reference. If CopyContext.updateReference(T)
returns
the original object, indicating that the context does not have a replacement registered,
then copy the object manually by invoking a Clone method, a copy constructor, or by manually
constructing a new instance and copying the values.
alwaysCopy = context.updateReference(existingInstance.alwaysCopy);
if (existingInstance.alwaysCopy != null && alwaysCopy == existingInstance.alwaysCopy) {
alwaysCopy = (AlwaysCopy) existingInstance.alwaysCopy.clone(context);
}
If you are implementing an evaluator (a class that implements IEvaluator
), the
IEvaluator.updateEvaluatorReferences(agi.foundation.infrastructure.CopyContext)
method shares some responsibilities with the
copy context constructor. Code duplication can be avoided by doing the following:
CopyContext.updateReference(T)
. You should still call CopyContext.updateReference(T)
on any references to
non-evaluators.
IEvaluator.updateEvaluatorReferences(agi.foundation.infrastructure.CopyContext)
as the last line in the constructor and pass it the
same CopyContext
passed to the constructor.
IEvaluator.updateEvaluatorReferences(agi.foundation.infrastructure.CopyContext)
as normal. See the reference documentation for
IEvaluator.updateEvaluatorReferences(agi.foundation.infrastructure.CopyContext)
for more information on implementing that method.
public MyClass(MyClass existingInstance, CopyContext context) {
super(existingInstance, context);
someReference = context.updateReference(existingInstance.someReference);
evaluatorReference = existingInstance.evaluatorReference;
updateEvaluatorReferences(context);
}
@Override
public void updateEvaluatorReferences(CopyContext context) {
evaluatorReference = context.updateReference(evaluatorReference);
}
@Override
public Object clone(CopyContext context) {
return new MyClass(this, context);
}
private Object someReference;
private IEvaluator evaluatorReference;
clone
in interface ICloneWithContext
context
- The context to use to perform the copy.public final void dispose()
dispose
in interface IDisposable
protected abstract void dispose(boolean disposing)
disposing
- true
to release both managed and unmanaged resources;
false
to release only unmanaged resources.public abstract TimeIntervalCollection getAvailabilityIntervals(TimeIntervalCollection consideredIntervals)
getAvailabilityIntervals
in interface IAvailability
consideredIntervals
- The intervals over which availability information is needed. Note that the returned availability
intervals may indicate availability outside of these intervals of consideration.public abstract boolean isAvailable(@Nonnull JulianDate date)
JulianDate
.isAvailable
in interface IAvailability
date
- The date for which to check availability.true
if valid data is available for this date; otherwise false
.public abstract boolean getIsTimeVarying()
false
, the evaluator is assumed to return the same value for any
input JulianDate
.getIsTimeVarying
in interface IIsTimeVarying
public abstract boolean getIsThreadSafe()
If this property is true
, all methods and properties are guaranteed to be thread safe.
Conceptually, an object that returns true
for this method acts as if there is a lock
protecting each method and property such that only one thread at a time can be inside any method or
property in the class. In reality, such locks are generally not used and are in fact discouraged. However,
the user must not experience any exceptions or inconsistent behavior that would not be experienced if such
locks were used.
If this property is false
, the behavior when using this class from multiple threads
simultaneously is undefined and may include inconsistent results and exceptions. Clients wishing to use
multiple threads should call CopyForAnotherThread.copy(T)
to get a separate instance of the
object for each thread.
getIsThreadSafe
in interface IThreadAware
public final EvaluatorGroup getGroup()
getGroup
in interface IEvaluator
public IEvaluator getCachingWrapper()
This method is called by EvaluatorGroup
to create a caching version of an evaluator
that is shared between multiple computations.
To implement this method in your own evaluator, construct and return a caching version of the evaluator's base class.
For example, if your evaluator implements IEvaluator1
directly, return an instance of
CachingEvaluator
. In many cases, such as when implementing a PointEvaluator
this method does not need to be overridden because the default implementation returns an appropriate
caching wrapper already. If you do not want the last value computed by your evaluator to ever be cached, or
if your evaluator does its own caching internally, this method can return this
.
Shows an example implementation in an evaluator that implements IEvaluator1
directly, where T is double.
@Override
public IEvaluator getCachingWrapper() {
return new CachingEvaluator<Double>(this);
}
getCachingWrapper
in interface IEvaluator
this
should be returned by this method.public abstract T evaluate(@Nonnull JulianDate date)
For information about the specific function evaluated by this evaluator, see the documentation for the method that was used to create this evaluator.
Once created, an evaluator will ignore changes made to the object(s) from which it was created.
In other words, this method will always return the same result for a given JulianDate
regardless of changes made to other objects in the system. You should create a new evaluator
after making changes to definitional objects in order for those changes to be reflected in the results.
evaluate
in interface IEvaluator1<T>
date
- The value with which to evaluate the function.public final TimeIntervalCollection getAvailabilityIntervals()
TimeIntervalCollection
over which data is available.
If the availability interval is infinite, this returns
Infinite
(get
).
It is recommended that you call Evaluator.isAvailable(agi.foundation.time.JulianDate)
to determine availability instead of
calling this method and checking for yourself.
@Nonnull public final DateMotionCollection1<T> evaluate(@Nonnull JulianDate start, @Nonnull JulianDate stop, @Nonnull Duration step)
This method takes advantage of the ThreadingPolicy
to improve performance.
The first date in the returned collection will be start
. The last date
in the collection will be stop
, so the difference between the
second-to-last date and the last date may be less than step
.
Also, these dates will always be present in the returned collection even if the duration
between them is less than step
.
start
- The start of the interval over which to evaluate.stop
- The end of the interval over which to evaluate.step
- The step size with which to sample this evaluator.public final DateMotionCollection1<T> evaluate(@Nonnull JulianDate start, @Nonnull JulianDate stop, @Nonnull Duration step, @Nullable ITrackCalculationProgress tracker)
This method takes advantage of the ThreadingPolicy
to improve performance.
The first date in the returned collection will be start
. The last date
in the collection will be stop
, so the difference between the
second-to-last date and the last date may be less than step
.
Also, these dates will always be present in the returned collection even if the duration
between them is less than step
.
start
- The start of the interval over which to evaluate.stop
- The end of the interval over which to evaluate.step
- The step size with which to sample this evaluator.tracker
- The object to which progress is reported and that is able to cancel this operation before it is complete, or null
.null
if the evaluation was canceled.@Nonnull public final DateMotionCollection1<T> evaluate(@Nonnull TimeInterval interval, @Nonnull Duration step)
This method takes advantage of the ThreadingPolicy
to improve performance.
If the start date of the interval is included in the interval
(IsStartIncluded
(get
)), the first date in the collection will be
the start date of the interval. If it is not included, the first date in the collection
will be step
seconds later. If the stop date of the interval is
included in the interval (IsStopIncluded
(get
)), the last date in the
collection will be the stop date of the interval. If it is not included, the last date
in the collection will be up to step
seconds before the stop date.
If neither the start nor stop date are included, and the interval is shorter than
step
, the returned collection will be empty.
interval
- The interval over which to evaluate.step
- The step size with which to sample this evaluator.public final DateMotionCollection1<T> evaluate(@Nonnull TimeInterval interval, @Nonnull Duration step, @Nullable ITrackCalculationProgress tracker)
This method takes advantage of the ThreadingPolicy
to improve performance.
If the start date of the interval is included in the interval
(IsStartIncluded
(get
)), the first date in the collection will be
the start date of the interval. If it is not included, the first date in the collection
will be step
seconds later. If the stop date of the interval is
included in the interval (IsStopIncluded
(get
)), the last date in the
collection will be the stop date of the interval. If it is not included, the last date
in the collection will be up to step
seconds before the stop date.
If neither the start nor stop date are included, and the interval is shorter than
step
, the returned collection will be empty.
interval
- The interval over which to evaluate.step
- The step size with which to sample this evaluator.tracker
- The object to which progress is reported and that is able to cancel this operation before it is complete, or null
.null
if the evaluation was canceled.