use of org.orekit.time.FieldAbsoluteDate in project Orekit by CS-SI.
the class FieldEventState method findRoot.
/**
* Find a root in a bracketing interval.
*
* <p> When calling this method one of the following must be true. Either ga == 0, gb
* == 0, (ga < 0 and gb > 0), or (ga > 0 and gb < 0).
*
* @param interpolator that covers the interval.
* @param ta earliest possible time for root.
* @param ga g(ta).
* @param tb latest possible time for root.
* @param gb g(tb).
* @return if a zero crossing was found.
* @throws OrekitException if the event detector throws one
*/
private boolean findRoot(final FieldOrekitStepInterpolator<T> interpolator, final FieldAbsoluteDate<T> ta, final T ga, final FieldAbsoluteDate<T> tb, final T gb) throws OrekitException {
final T zero = ga.getField().getZero();
// check there appears to be a root in [ta, tb]
check(ga.getReal() == 0.0 || gb.getReal() == 0.0 || (ga.getReal() > 0.0 && gb.getReal() < 0.0) || (ga.getReal() < 0.0 && gb.getReal() > 0.0));
final T convergence = detector.getThreshold();
final int maxIterationCount = detector.getMaxIterationCount();
final BracketedUnivariateSolver<UnivariateFunction> solver = new BracketingNthOrderBrentSolver(0, convergence.getReal(), 0, 5);
// event time, just at or before the actual root.
FieldAbsoluteDate<T> beforeRootT = null;
T beforeRootG = zero.add(Double.NaN);
// time on the other side of the root.
// Initialized the the loop below executes once.
FieldAbsoluteDate<T> afterRootT = ta;
T afterRootG = zero;
// the ga == 0.0 case is handled by the loop below
if (ta.equals(tb)) {
// both non-zero but times are the same. Probably due to reset state
beforeRootT = ta;
beforeRootG = ga;
afterRootT = shiftedBy(beforeRootT, convergence);
afterRootG = g(interpolator.getInterpolatedState(afterRootT));
} else if (ga.getReal() != 0.0 && gb.getReal() == 0.0) {
// hard: ga != 0.0 and gb == 0.0
// look past gb by up to convergence to find next sign
// throw an exception if g(t) = 0.0 in [tb, tb + convergence]
beforeRootT = tb;
beforeRootG = gb;
afterRootT = shiftedBy(beforeRootT, convergence);
afterRootG = g(interpolator.getInterpolatedState(afterRootT));
} else if (ga.getReal() != 0.0) {
final T newGa = g(interpolator.getInterpolatedState(ta));
if (ga.getReal() > 0 != newGa.getReal() > 0) {
// both non-zero, step sign change at ta, possibly due to reset state
beforeRootT = ta;
beforeRootG = newGa;
afterRootT = minTime(shiftedBy(beforeRootT, convergence), tb);
afterRootG = g(interpolator.getInterpolatedState(afterRootT));
}
}
// loop to skip through "fake" roots, i.e. where g(t) = g'(t) = 0.0
// executed once if we didn't hit a special case above
FieldAbsoluteDate<T> loopT = ta;
T loopG = ga;
while ((afterRootG.getReal() == 0.0 || afterRootG.getReal() > 0.0 == g0Positive) && strictlyAfter(afterRootT, tb)) {
if (loopG.getReal() == 0.0) {
// ga == 0.0 and gb may or may not be 0.0
// handle the root at ta first
beforeRootT = loopT;
beforeRootG = loopG;
afterRootT = minTime(shiftedBy(beforeRootT, convergence), tb);
afterRootG = g(interpolator.getInterpolatedState(afterRootT));
} else {
// both non-zero, the usual case, use a root finder.
try {
// time zero for evaluating the function f. Needs to be final
final FieldAbsoluteDate<T> fT0 = loopT;
final UnivariateFunction f = dt -> {
try {
return g(interpolator.getInterpolatedState(fT0.shiftedBy(dt))).getReal();
} catch (OrekitException oe) {
throw new OrekitExceptionWrapper(oe);
}
};
// tb as a double for use in f
final T tbDouble = tb.durationFrom(fT0);
if (forward) {
final Interval interval = solver.solveInterval(maxIterationCount, f, 0, tbDouble.getReal());
beforeRootT = fT0.shiftedBy(interval.getLeftAbscissa());
beforeRootG = zero.add(interval.getLeftValue());
afterRootT = fT0.shiftedBy(interval.getRightAbscissa());
afterRootG = zero.add(interval.getRightValue());
} else {
final Interval interval = solver.solveInterval(maxIterationCount, f, tbDouble.getReal(), 0);
beforeRootT = fT0.shiftedBy(interval.getRightAbscissa());
beforeRootG = zero.add(interval.getRightValue());
afterRootT = fT0.shiftedBy(interval.getLeftAbscissa());
afterRootG = zero.add(interval.getLeftValue());
}
} catch (OrekitExceptionWrapper oew) {
throw oew.getException();
}
}
// assume tolerance is 1 ulp
if (beforeRootT.equals(afterRootT)) {
afterRootT = nextAfter(afterRootT);
afterRootG = g(interpolator.getInterpolatedState(afterRootT));
}
// check loop is making some progress
check((forward && afterRootT.compareTo(beforeRootT) > 0) || (!forward && afterRootT.compareTo(beforeRootT) < 0));
// setup next iteration
loopT = afterRootT;
loopG = afterRootG;
}
// figure out the result of root finding, and return accordingly
if (afterRootG.getReal() == 0.0 || afterRootG.getReal() > 0.0 == g0Positive) {
// loop gave up and didn't find any crossing within this step
return false;
} else {
// real crossing
check(beforeRootT != null && !Double.isNaN(beforeRootG.getReal()));
// variation direction, with respect to the integration direction
increasing = !g0Positive;
pendingEventTime = beforeRootT;
stopTime = beforeRootG.getReal() == 0.0 ? beforeRootT : afterRootT;
pendingEvent = true;
afterEvent = afterRootT;
afterG = afterRootG;
// check increasing set correctly
check(afterG.getReal() > 0 == increasing);
check(increasing == gb.getReal() >= ga.getReal());
return true;
}
}
use of org.orekit.time.FieldAbsoluteDate in project Orekit by CS-SI.
the class Geoid method getIntersectionPoint.
/**
* {@inheritDoc}
*
* <p> The intersection point is computed using a line search along the
* specified line. This is accurate when the geoid is slowly varying.
*/
@Override
public <T extends RealFieldElement<T>> FieldGeodeticPoint<T> getIntersectionPoint(final FieldLine<T> lineInFrame, final FieldVector3D<T> closeInFrame, final Frame frame, final FieldAbsoluteDate<T> date) throws OrekitException {
final Field<T> field = date.getField();
/*
* It is assumed that the geoid is slowly varying over it's entire
* surface. Therefore there will one local intersection.
*/
// transform to body frame
final Frame bodyFrame = this.getBodyFrame();
final FieldTransform<T> frameToBody = frame.getTransformTo(bodyFrame, date);
final FieldVector3D<T> close = frameToBody.transformPosition(closeInFrame);
final FieldLine<T> lineInBodyFrame = frameToBody.transformLine(lineInFrame);
// set the line's direction so the solved for value is always positive
final FieldLine<T> line;
if (lineInBodyFrame.getAbscissa(close).getReal() < 0) {
line = lineInBodyFrame.revert();
} else {
line = lineInBodyFrame;
}
final ReferenceEllipsoid ellipsoid = this.getEllipsoid();
// calculate end points
// distance from line to center of earth, squared
final T d2 = line.pointAt(0.0).getNormSq();
// the minimum abscissa, squared
final double n = ellipsoid.getPolarRadius() + MIN_UNDULATION;
final T minAbscissa2 = d2.negate().add(n * n);
// smaller end point of the interval = 0.0 or intersection with
// min_undulation sphere
final T lowPoint = minAbscissa2.getReal() < 0 ? field.getZero() : minAbscissa2.sqrt();
// the maximum abscissa, squared
final double x = ellipsoid.getEquatorialRadius() + MAX_UNDULATION;
final T maxAbscissa2 = d2.negate().add(x * x);
// larger end point of the interval
final T highPoint = maxAbscissa2.sqrt();
// line search function
final RealFieldUnivariateFunction<T> heightFunction = z -> {
try {
final FieldGeodeticPoint<T> geodetic = transform(line.pointAt(z), bodyFrame, date);
return geodetic.getAltitude();
} catch (OrekitException e) {
// due to frame transform -> re-throw
throw new RuntimeException(e);
}
};
// compute answer
if (maxAbscissa2.getReal() < 0) {
// ray does not pierce bounding sphere -> no possible intersection
return null;
}
// solve line search problem to find the intersection
final FieldBracketingNthOrderBrentSolver<T> solver = new FieldBracketingNthOrderBrentSolver<>(field.getZero().add(1.0e-14), field.getZero().add(1.0e-6), field.getZero().add(1.0e-15), 5);
try {
final T abscissa = solver.solve(MAX_EVALUATIONS, heightFunction, lowPoint, highPoint, AllowedSolution.ANY_SIDE);
// return intersection point
return this.transform(line.pointAt(abscissa), bodyFrame, date);
} catch (MathRuntimeException e) {
// no intersection
return null;
}
}
use of org.orekit.time.FieldAbsoluteDate in project Orekit by CS-SI.
the class EOPHistory method interpolate.
/**
* Interpolate a single EOP component.
* <p>
* This method should be called <em>only</em> when {@link #hasDataFor(AbsoluteDate)} returns true.
* </p>
* @param date interpolation date
* @param aDate interpolation date, as an {@link AbsoluteDate}
* @param selector selector for EOP entry component
* @param <T> type of the field elements
* @return interpolated value
*/
private <T extends RealFieldElement<T>> T interpolate(final FieldAbsoluteDate<T> date, final AbsoluteDate aDate, final Function<EOPEntry, Double> selector) {
try {
final FieldHermiteInterpolator<T> interpolator = new FieldHermiteInterpolator<>();
final T[] y = MathArrays.buildArray(date.getField(), 1);
final T zero = date.getField().getZero();
// here, we attempt to get a constant date,
final FieldAbsoluteDate<T> central = new FieldAbsoluteDate<>(aDate, zero);
// for example removing derivatives
// if T was DerivativeStructure
getNeighbors(aDate).forEach(entry -> {
y[0] = zero.add(selector.apply(entry));
interpolator.addSamplePoint(central.durationFrom(entry.getDate()).negate(), y);
});
// here, we introduce derivatives again (in DerivativeStructure case)
return interpolator.value(date.durationFrom(central))[0];
} catch (TimeStampedCacheException tce) {
// this should not happen because of date check performed by caller
throw new OrekitInternalError(tce);
}
}
use of org.orekit.time.FieldAbsoluteDate in project Orekit by CS-SI.
the class EOPHistory method getPoleCorrection.
/**
* Get the pole IERS Reference Pole correction.
* <p>The data provided comes from the IERS files. It is smoothed data.</p>
* @param date date at which the correction is desired
* @param <T> type of the field elements
* @return pole correction ({@link PoleCorrection#NULL_CORRECTION
* PoleCorrection.NULL_CORRECTION} if date is outside covered range)
*/
public <T extends RealFieldElement<T>> FieldPoleCorrection<T> getPoleCorrection(final FieldAbsoluteDate<T> date) {
final AbsoluteDate aDate = date.toAbsoluteDate();
// check if there is data for date
if (!this.hasDataFor(aDate)) {
// no EOP data available for this date, we use a default null correction
if (tidalCorrection == null) {
return new FieldPoleCorrection<>(date.getField().getZero(), date.getField().getZero());
} else {
final T[] correction = tidalCorrection.value(date);
return new FieldPoleCorrection<>(correction[0], correction[1]);
}
}
// we have EOP data for date -> interpolate correction
final T[] interpolated = interpolate(date, aDate, entry -> entry.getX(), entry -> entry.getY());
if (tidalCorrection != null) {
final T[] correction = tidalCorrection.value(date);
interpolated[0] = interpolated[0].add(correction[0]);
interpolated[1] = interpolated[1].add(correction[1]);
}
return new FieldPoleCorrection<>(interpolated[0], interpolated[1]);
}
use of org.orekit.time.FieldAbsoluteDate in project Orekit by CS-SI.
the class EOPHistory method getLOD.
/**
* Get the LoD (Length of Day) value.
* <p>The data provided comes from the IERS files. It is smoothed data.</p>
* @param date date at which the value is desired
* @param <T> type of the filed elements
* @return LoD in seconds (0 if date is outside covered range)
* @since 9.0
*/
public <T extends RealFieldElement<T>> T getLOD(final FieldAbsoluteDate<T> date) {
final AbsoluteDate aDate = date.toAbsoluteDate();
// check if there is data for date
if (!this.hasDataFor(aDate)) {
// no EOP data available for this date, we use a default null correction
return (tidalCorrection == null) ? date.getField().getZero() : tidalCorrection.value(date)[3];
}
// we have EOP data for date -> interpolate correction
T interpolated = interpolate(date, aDate, entry -> entry.getLOD());
if (tidalCorrection != null) {
interpolated = interpolated.add(tidalCorrection.value(date)[3]);
}
return interpolated;
}
Aggregations