From 655d766fe364e76022d4358e5be1b87f46547bec Mon Sep 17 00:00:00 2001 From: Sebastien Dinot Date: Mon, 30 Oct 2023 11:16:14 +0100 Subject: [PATCH 001/359] Fix #1250 https://gitlab.orekit.org/orekit/orekit/-/issues/1250 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4936424f97..fc85b0bc17 100644 --- a/pom.xml +++ b/pom.xml @@ -1101,7 +1101,7 @@ - 1C + 0.5C @{argLine} -Xmx2048m From af061980048e8648b95004899937163c93d593b2 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Mon, 30 Oct 2023 20:12:42 +0100 Subject: [PATCH 002/359] Fixed wrong class diagram. --- src/design/data-filtering-class-diagram.puml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/design/data-filtering-class-diagram.puml b/src/design/data-filtering-class-diagram.puml index a2db1c3abc..3e51d2544c 100644 --- a/src/design/data-filtering-class-diagram.puml +++ b/src/design/data-filtering-class-diagram.puml @@ -63,15 +63,15 @@ DataFilter <|-- GzipFilter DataFilter <|-- UnixFilter - UnixFilter --> DataSource.Opener : creates - GzipFilter --> DataSource.Opener : creates + UnixFilter --> Opener : creates + GzipFilter --> Opener : creates } package files.rinex #DDEBD8 { class HatanakaCompressFilter DataFilter <|-- HatanakaCompressFilter - DataSource.Opener <-left- HatanakaCompressFilter : creates + Opener <-left- HatanakaCompressFilter : creates } } From 176f9ec900db982b11d2b80638a790d7bf5ee37e Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Tue, 31 Oct 2023 11:12:31 +0100 Subject: [PATCH 003/359] Fixed checkstyle problems. --- .../propagation/FieldSpacecraftState.java | 38 +++++++++---------- .../orekit/propagation/SpacecraftState.java | 36 +++++++++--------- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/src/main/java/org/orekit/propagation/FieldSpacecraftState.java b/src/main/java/org/orekit/propagation/FieldSpacecraftState.java index 6e8aa1fd12..7f237778ba 100644 --- a/src/main/java/org/orekit/propagation/FieldSpacecraftState.java +++ b/src/main/java/org/orekit/propagation/FieldSpacecraftState.java @@ -720,14 +720,14 @@ public FieldOrbit getOrbit() throws OrekitIllegalStateException { /** {@inheritDoc} */ @Override public FieldAbsoluteDate getDate() { - return (isOrbitDefined()) ? orbit.getDate() : absPva.getDate(); + return isOrbitDefined() ? orbit.getDate() : absPva.getDate(); } /** Get the defining frame. * @return the frame in which state is defined */ public Frame getFrame() { - return (isOrbitDefined()) ? orbit.getFrame() : absPva.getFrame(); + return isOrbitDefined() ? orbit.getFrame() : absPva.getFrame(); } @@ -892,7 +892,7 @@ public FieldStaticTransform toStaticTransform() { * state contains an absolute position-velocity-acceleration rather than an orbit */ public T getMu() { - return (isOrbitDefined()) ? orbit.getMu() : absPva.getDate().getField().getZero().add(Double.NaN); + return isOrbitDefined() ? orbit.getMu() : absPva.getDate().getField().getZero().add(Double.NaN); } /** Get the Keplerian period. @@ -903,7 +903,7 @@ public T getMu() { * than an orbit */ public T getKeplerianPeriod() { - return (isOrbitDefined()) ? orbit.getKeplerianPeriod() : absPva.getDate().getField().getZero().add(Double.NaN); + return isOrbitDefined() ? orbit.getKeplerianPeriod() : absPva.getDate().getField().getZero().add(Double.NaN); } /** Get the Keplerian mean motion. @@ -914,7 +914,7 @@ public T getKeplerianPeriod() { * than an orbit */ public T getKeplerianMeanMotion() { - return (isOrbitDefined()) ? orbit.getKeplerianMeanMotion() : absPva.getDate().getField().getZero().add(Double.NaN); + return isOrbitDefined() ? orbit.getKeplerianMeanMotion() : absPva.getDate().getField().getZero().add(Double.NaN); } /** Get the semi-major axis. @@ -923,7 +923,7 @@ public T getKeplerianMeanMotion() { * than an orbit */ public T getA() { - return (isOrbitDefined()) ? orbit.getA() : absPva.getDate().getField().getZero().add(Double.NaN); + return isOrbitDefined() ? orbit.getA() : absPva.getDate().getField().getZero().add(Double.NaN); } /** Get the first component of the eccentricity vector (as per equinoctial parameters). @@ -933,7 +933,7 @@ public T getA() { * @see #getE() */ public T getEquinoctialEx() { - return (isOrbitDefined()) ? orbit.getEquinoctialEx() : absPva.getDate().getField().getZero().add(Double.NaN); + return isOrbitDefined() ? orbit.getEquinoctialEx() : absPva.getDate().getField().getZero().add(Double.NaN); } /** Get the second component of the eccentricity vector (as per equinoctial parameters). @@ -943,7 +943,7 @@ public T getEquinoctialEx() { * @see #getE() */ public T getEquinoctialEy() { - return (isOrbitDefined()) ? orbit.getEquinoctialEy() : absPva.getDate().getField().getZero().add(Double.NaN); + return isOrbitDefined() ? orbit.getEquinoctialEy() : absPva.getDate().getField().getZero().add(Double.NaN); } /** Get the first component of the inclination vector (as per equinoctial parameters). @@ -953,7 +953,7 @@ public T getEquinoctialEy() { * @see #getI() */ public T getHx() { - return (isOrbitDefined()) ? orbit.getHx() : absPva.getDate().getField().getZero().add(Double.NaN); + return isOrbitDefined() ? orbit.getHx() : absPva.getDate().getField().getZero().add(Double.NaN); } /** Get the second component of the inclination vector (as per equinoctial parameters). @@ -963,7 +963,7 @@ public T getHx() { * @see #getI() */ public T getHy() { - return (isOrbitDefined()) ? orbit.getHy() : absPva.getDate().getField().getZero().add(Double.NaN); + return isOrbitDefined() ? orbit.getHy() : absPva.getDate().getField().getZero().add(Double.NaN); } /** Get the true latitude argument (as per equinoctial parameters). @@ -974,7 +974,7 @@ public T getHy() { * @see #getLM() */ public T getLv() { - return (isOrbitDefined()) ? orbit.getLv() : absPva.getDate().getField().getZero().add(Double.NaN); + return isOrbitDefined() ? orbit.getLv() : absPva.getDate().getField().getZero().add(Double.NaN); } /** Get the eccentric latitude argument (as per equinoctial parameters). @@ -985,7 +985,7 @@ public T getLv() { * @see #getLM() */ public T getLE() { - return (isOrbitDefined()) ? orbit.getLE() : absPva.getDate().getField().getZero().add(Double.NaN); + return isOrbitDefined() ? orbit.getLE() : absPva.getDate().getField().getZero().add(Double.NaN); } /** Get the mean longitude argument (as per equinoctial parameters). @@ -996,7 +996,7 @@ public T getLE() { * @see #getLE() */ public T getLM() { - return (isOrbitDefined()) ? orbit.getLM() : absPva.getDate().getField().getZero().add(Double.NaN); + return isOrbitDefined() ? orbit.getLM() : absPva.getDate().getField().getZero().add(Double.NaN); } // Additional orbital elements @@ -1009,7 +1009,7 @@ public T getLM() { * @see #getEquinoctialEy() */ public T getE() { - return (isOrbitDefined()) ? orbit.getE() : absPva.getDate().getField().getZero().add(Double.NaN); + return isOrbitDefined() ? orbit.getE() : absPva.getDate().getField().getZero().add(Double.NaN); } /** Get the inclination. @@ -1018,7 +1018,7 @@ public T getE() { * @see #getHy() */ public T getI() { - return (isOrbitDefined()) ? orbit.getI() : absPva.getDate().getField().getZero().add(Double.NaN); + return isOrbitDefined() ? orbit.getI() : absPva.getDate().getField().getZero().add(Double.NaN); } /** Get the position in orbit definition frame. @@ -1026,7 +1026,7 @@ public T getI() { * @since 12.0 */ public FieldVector3D getPosition() { - return (isOrbitDefined()) ? orbit.getPosition() : absPva.getPosition(); + return isOrbitDefined() ? orbit.getPosition() : absPva.getPosition(); } /** Get the {@link TimeStampedFieldPVCoordinates} in orbit definition frame. @@ -1040,7 +1040,7 @@ public FieldVector3D getPosition() { * @return pvCoordinates in orbit definition frame */ public TimeStampedFieldPVCoordinates getPVCoordinates() { - return (isOrbitDefined()) ? orbit.getPVCoordinates() : absPva.getPVCoordinates(); + return isOrbitDefined() ? orbit.getPVCoordinates() : absPva.getPVCoordinates(); } /** Get the position in given output frame. @@ -1050,7 +1050,7 @@ public TimeStampedFieldPVCoordinates getPVCoordinates() { * @see #getPVCoordinates(Frame) */ public FieldVector3D getPosition(final Frame outputFrame) { - return (isOrbitDefined()) ? orbit.getPosition(outputFrame) : absPva.getPosition(outputFrame); + return isOrbitDefined() ? orbit.getPosition(outputFrame) : absPva.getPosition(outputFrame); } /** Get the {@link TimeStampedFieldPVCoordinates} in given output frame. @@ -1065,7 +1065,7 @@ public FieldVector3D getPosition(final Frame outputFrame) { * @return pvCoordinates in orbit definition frame */ public TimeStampedFieldPVCoordinates getPVCoordinates(final Frame outputFrame) { - return (isOrbitDefined()) ? orbit.getPVCoordinates(outputFrame) : absPva.getPVCoordinates(outputFrame); + return isOrbitDefined() ? orbit.getPVCoordinates(outputFrame) : absPva.getPVCoordinates(outputFrame); } /** Get the attitude. diff --git a/src/main/java/org/orekit/propagation/SpacecraftState.java b/src/main/java/org/orekit/propagation/SpacecraftState.java index 14e975f9c6..dc1f416715 100644 --- a/src/main/java/org/orekit/propagation/SpacecraftState.java +++ b/src/main/java/org/orekit/propagation/SpacecraftState.java @@ -603,7 +603,7 @@ public AbsoluteDate getDate() { * @return the frame in which state is defined */ public Frame getFrame() { - return (isOrbitDefined()) ? orbit.getFrame() : absPva.getFrame(); + return isOrbitDefined() ? orbit.getFrame() : absPva.getFrame(); } /** Check if an additional state is available. @@ -769,7 +769,7 @@ public StaticTransform toStaticTransform() { * state contains an absolute position-velocity-acceleration rather than an orbit */ public double getMu() { - return (isOrbitDefined()) ? orbit.getMu() : Double.NaN; + return isOrbitDefined() ? orbit.getMu() : Double.NaN; } /** Get the Keplerian period. @@ -780,7 +780,7 @@ public double getMu() { * than an orbit */ public double getKeplerianPeriod() { - return (isOrbitDefined()) ? orbit.getKeplerianPeriod() : Double.NaN; + return isOrbitDefined() ? orbit.getKeplerianPeriod() : Double.NaN; } /** Get the Keplerian mean motion. @@ -791,7 +791,7 @@ public double getKeplerianPeriod() { * than an orbit */ public double getKeplerianMeanMotion() { - return (isOrbitDefined()) ? orbit.getKeplerianMeanMotion() : Double.NaN; + return isOrbitDefined() ? orbit.getKeplerianMeanMotion() : Double.NaN; } /** Get the semi-major axis. @@ -800,7 +800,7 @@ public double getKeplerianMeanMotion() { * than an orbit */ public double getA() { - return (isOrbitDefined()) ? orbit.getA() : Double.NaN; + return isOrbitDefined() ? orbit.getA() : Double.NaN; } /** Get the first component of the eccentricity vector (as per equinoctial parameters). @@ -810,7 +810,7 @@ public double getA() { * @see #getE() */ public double getEquinoctialEx() { - return (isOrbitDefined()) ? orbit.getEquinoctialEx() : Double.NaN; + return isOrbitDefined() ? orbit.getEquinoctialEx() : Double.NaN; } /** Get the second component of the eccentricity vector (as per equinoctial parameters). @@ -820,7 +820,7 @@ public double getEquinoctialEx() { * @see #getE() */ public double getEquinoctialEy() { - return (isOrbitDefined()) ? orbit.getEquinoctialEy() : Double.NaN; + return isOrbitDefined() ? orbit.getEquinoctialEy() : Double.NaN; } /** Get the first component of the inclination vector (as per equinoctial parameters). @@ -830,7 +830,7 @@ public double getEquinoctialEy() { * @see #getI() */ public double getHx() { - return (isOrbitDefined()) ? orbit.getHx() : Double.NaN; + return isOrbitDefined() ? orbit.getHx() : Double.NaN; } /** Get the second component of the inclination vector (as per equinoctial parameters). @@ -840,7 +840,7 @@ public double getHx() { * @see #getI() */ public double getHy() { - return (isOrbitDefined()) ? orbit.getHy() : Double.NaN; + return isOrbitDefined() ? orbit.getHy() : Double.NaN; } /** Get the true latitude argument (as per equinoctial parameters). @@ -851,7 +851,7 @@ public double getHy() { * @see #getLM() */ public double getLv() { - return (isOrbitDefined()) ? orbit.getLv() : Double.NaN; + return isOrbitDefined() ? orbit.getLv() : Double.NaN; } /** Get the eccentric latitude argument (as per equinoctial parameters). @@ -862,7 +862,7 @@ public double getLv() { * @see #getLM() */ public double getLE() { - return (isOrbitDefined()) ? orbit.getLE() : Double.NaN; + return isOrbitDefined() ? orbit.getLE() : Double.NaN; } /** Get the mean longitude argument (as per equinoctial parameters). @@ -873,7 +873,7 @@ public double getLE() { * @see #getLE() */ public double getLM() { - return (isOrbitDefined()) ? orbit.getLM() : Double.NaN; + return isOrbitDefined() ? orbit.getLM() : Double.NaN; } // Additional orbital elements @@ -886,7 +886,7 @@ public double getLM() { * @see #getEquinoctialEy() */ public double getE() { - return (isOrbitDefined()) ? orbit.getE() : Double.NaN; + return isOrbitDefined() ? orbit.getE() : Double.NaN; } /** Get the inclination. @@ -895,7 +895,7 @@ public double getE() { * @see #getHy() */ public double getI() { - return (isOrbitDefined()) ? orbit.getI() : Double.NaN; + return isOrbitDefined() ? orbit.getI() : Double.NaN; } /** Get the position in orbit definition frame. @@ -904,7 +904,7 @@ public double getI() { * @see #getPVCoordinates() */ public Vector3D getPosition() { - return (isOrbitDefined()) ? orbit.getPosition() : absPva.getPosition(); + return isOrbitDefined() ? orbit.getPosition() : absPva.getPosition(); } /** Get the {@link TimeStampedPVCoordinates} in orbit definition frame. @@ -918,7 +918,7 @@ public Vector3D getPosition() { * @return pvCoordinates in orbit definition frame */ public TimeStampedPVCoordinates getPVCoordinates() { - return (isOrbitDefined()) ? orbit.getPVCoordinates() : absPva.getPVCoordinates(); + return isOrbitDefined() ? orbit.getPVCoordinates() : absPva.getPVCoordinates(); } /** Get the position in given output frame. @@ -928,7 +928,7 @@ public TimeStampedPVCoordinates getPVCoordinates() { * @see #getPVCoordinates(Frame) */ public Vector3D getPosition(final Frame outputFrame) { - return (isOrbitDefined()) ? orbit.getPosition(outputFrame) : absPva.getPosition(outputFrame); + return isOrbitDefined() ? orbit.getPosition(outputFrame) : absPva.getPosition(outputFrame); } /** Get the {@link TimeStampedPVCoordinates} in given output frame. @@ -943,7 +943,7 @@ public Vector3D getPosition(final Frame outputFrame) { * @return pvCoordinates in orbit definition frame */ public TimeStampedPVCoordinates getPVCoordinates(final Frame outputFrame) { - return (isOrbitDefined()) ? orbit.getPVCoordinates(outputFrame) : absPva.getPVCoordinates(outputFrame); + return isOrbitDefined() ? orbit.getPVCoordinates(outputFrame) : absPva.getPVCoordinates(outputFrame); } /** Get the attitude. From a04acae16a2215cb293f471a4695d57ec692650d Mon Sep 17 00:00:00 2001 From: Hank Grabowski Date: Thu, 2 Nov 2023 00:08:53 -0400 Subject: [PATCH 004/359] Fix issue #1252 by cleaning up Test Threadpools on completion. --- .../java/org/orekit/gnss/metric/ntrip/NtripClient.java | 1 + .../atmosphere/data/CssiSpaceWeatherLoaderTest.java | 10 ++++++++++ .../MarshallSolarActivityFutureEstimationTest.java | 10 ++++++++++ .../time/TimeStampedDoubleHermiteInterpolatorTest.java | 9 +++++++++ .../time/TimeStampedFieldHermiteInterpolatorTest.java | 9 +++++++++ 5 files changed, 39 insertions(+) diff --git a/src/main/java/org/orekit/gnss/metric/ntrip/NtripClient.java b/src/main/java/org/orekit/gnss/metric/ntrip/NtripClient.java index d357152eef..939129534c 100644 --- a/src/main/java/org/orekit/gnss/metric/ntrip/NtripClient.java +++ b/src/main/java/org/orekit/gnss/metric/ntrip/NtripClient.java @@ -459,6 +459,7 @@ public void stopStreaming(final int time) { try { // wait for proper ending + executorService.shutdown(); executorService.awaitTermination(time, TimeUnit.MILLISECONDS); } catch (InterruptedException ie) { // Restore interrupted state... diff --git a/src/test/java/org/orekit/models/earth/atmosphere/data/CssiSpaceWeatherLoaderTest.java b/src/test/java/org/orekit/models/earth/atmosphere/data/CssiSpaceWeatherLoaderTest.java index 5ac8bf934d..594f647ca3 100644 --- a/src/test/java/org/orekit/models/earth/atmosphere/data/CssiSpaceWeatherLoaderTest.java +++ b/src/test/java/org/orekit/models/earth/atmosphere/data/CssiSpaceWeatherLoaderTest.java @@ -32,6 +32,7 @@ import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; @@ -411,6 +412,15 @@ void testIssue1072() { final AbsoluteDate currentDate = dates.get(i); Assertions.assertEquals(weatherData.get24HoursKp(currentDate), sortedComputedResults.get(i)); } + + try { + // wait for proper ending + service.shutdown(); + service.awaitTermination(5, TimeUnit.SECONDS); + } catch (InterruptedException ie) { + // Restore interrupted state... + Thread.currentThread().interrupt(); + } } catch (Exception e) { // Should not fail diff --git a/src/test/java/org/orekit/models/earth/atmosphere/data/MarshallSolarActivityFutureEstimationTest.java b/src/test/java/org/orekit/models/earth/atmosphere/data/MarshallSolarActivityFutureEstimationTest.java index d8fc2904ce..91f0bbb85a 100644 --- a/src/test/java/org/orekit/models/earth/atmosphere/data/MarshallSolarActivityFutureEstimationTest.java +++ b/src/test/java/org/orekit/models/earth/atmosphere/data/MarshallSolarActivityFutureEstimationTest.java @@ -71,6 +71,7 @@ import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; @@ -657,6 +658,15 @@ void testIssue1072() { final AbsoluteDate currentDate = dates.get(i); Assertions.assertEquals(weatherData.get24HoursKp(currentDate), sortedComputedResults.get(i)); } + + try { + // wait for proper ending + service.shutdown(); + service.awaitTermination(5, TimeUnit.SECONDS); + } catch (InterruptedException ie) { + // Restore interrupted state... + Thread.currentThread().interrupt(); + } } catch (Exception e) { // Should not fail diff --git a/src/test/java/org/orekit/time/TimeStampedDoubleHermiteInterpolatorTest.java b/src/test/java/org/orekit/time/TimeStampedDoubleHermiteInterpolatorTest.java index 7399f1420a..0cd89665fc 100644 --- a/src/test/java/org/orekit/time/TimeStampedDoubleHermiteInterpolatorTest.java +++ b/src/test/java/org/orekit/time/TimeStampedDoubleHermiteInterpolatorTest.java @@ -10,6 +10,7 @@ import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; class TimeStampedDoubleHermiteInterpolatorTest { @@ -60,6 +61,14 @@ void testIssue1164() throws InterruptedException { // Sum of 1*1 + 2*2 + 3*3 + ... final int expectedSum = sampleSize * (sampleSize + 1) * (2 * sampleSize + 1) / 6; Assertions.assertEquals(expectedSum, sum.get()); + try { + // wait for proper ending + service.shutdown(); + service.awaitTermination(5, TimeUnit.SECONDS); + } catch (InterruptedException ie) { + // Restore interrupted state... + Thread.currentThread().interrupt(); + } } /** Custom class for multi threading testing purpose */ diff --git a/src/test/java/org/orekit/time/TimeStampedFieldHermiteInterpolatorTest.java b/src/test/java/org/orekit/time/TimeStampedFieldHermiteInterpolatorTest.java index d926972cf8..a546356d20 100644 --- a/src/test/java/org/orekit/time/TimeStampedFieldHermiteInterpolatorTest.java +++ b/src/test/java/org/orekit/time/TimeStampedFieldHermiteInterpolatorTest.java @@ -29,6 +29,7 @@ import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; class TimeStampedFieldHermiteInterpolatorTest { @@ -82,6 +83,14 @@ void testIssue1164() throws InterruptedException { // Sum of 1*1 + 2*2 + 3*3 + ... final int expectedSum = sampleSize * (sampleSize + 1) * (2 * sampleSize + 1) / 6; Assertions.assertEquals(expectedSum, sum.get()); + try { + // wait for proper ending + service.shutdown(); + service.awaitTermination(5, TimeUnit.SECONDS); + } catch (InterruptedException ie) { + // Restore interrupted state... + Thread.currentThread().interrupt(); + } } /** Custom class for multi threading testing purpose */ From 2a7c1042d9f715fc4fef7d77cf6d9cc0a13a70b8 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Fri, 3 Nov 2023 10:42:21 +0100 Subject: [PATCH 005/359] Documentation typo. --- src/site/markdown/data/filtering.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/site/markdown/data/filtering.md b/src/site/markdown/data/filtering.md index ba1911fe4f..b793436b41 100644 --- a/src/site/markdown/data/filtering.md +++ b/src/site/markdown/data/filtering.md @@ -49,11 +49,11 @@ by the `FiltersManager.applyRelevantFilters` method as needed, each one reading underlying stack element and providing filtered data to the next element upward. In the `DataProvidersManager` case, if at the end the name part of the `DataSource` matches the -name that the`DataLoader` instance expects, then the data stream of the top of the stack is opened. +name that the `DataLoader` instance expects, then the data stream of the top of the stack is opened. This is were the lazy opening occurs, and it generally ends up with all the intermediate bytes or characters streams being opened as well. The opened stream is then passed to the `DataLoader` to be parsed. If on the other hand the name part of the `DataSource` does not match the name that the -`DataLoader` instance expects, then neither the data stream is *not* opened, the full stack is discarded +`DataLoader` instance expects, then the data stream is *not* opened, the full stack is discarded and the next resource/file from the `DataProvider` is considered for filtering and loading. In the explicit loading case, application can decide on its own to open or discard the top From bb86d24dfda999e2e2f5e154501e9358df31a15a Mon Sep 17 00:00:00 2001 From: Bryan Cazabonne Date: Wed, 8 Nov 2023 21:36:56 +0100 Subject: [PATCH 006/359] Prepared next development cycle. --- build.xml | 2 +- pom.xml | 2 +- src/changes/changes.xml | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/build.xml b/build.xml index 811831194a..458a80cd39 100644 --- a/build.xml +++ b/build.xml @@ -2,7 +2,7 @@ - + diff --git a/pom.xml b/pom.xml index c878802edc..6ba9982894 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.orekit orekit jar - 12.0 + 12.1-SNAPSHOT OREKIT http://www.orekit.org/ diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 40f076bcc2..079086c8cd 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -20,6 +20,8 @@ Orekit Changes + + + + Added translation of error messages in Catalan language. + 0 and e < 1 or hyperbolic with a < 0 and e > 1, a = {0}, e = {1} +ORBIT_A_E_MISMATCH_WITH_CONIC_TYPE = l''òrbita hauria de ser el·líptica amb a > 0 i e < 1 o, més aviat, hiperbòlica amb a < 0 i e > 1, a = {0}, e = {1} + +# true anomaly {0} out of hyperbolic range (e = {1}, {2} < v < {3}) +ORBIT_ANOMALY_OUT_OF_HYPERBOLIC_RANGE = l''anomalia verdadera {0} està fora del rang per l''òrbita hiperbòlica (e = {1}, {2} < v < {3}) + +# hyperbolic orbits cannot be handled as {0} instances +HYPERBOLIC_ORBIT_NOT_HANDLED_AS = les òrbites hiperbòliques no poden ser casos de {0} + +# invalid preamble field in CCSDS date: {0} +CCSDS_DATE_INVALID_PREAMBLE_FIELD = camp de preàmbul invàlid en una data CCSDS : {0} + +# invalid time field length in CCSDS date: {0}, expected {1} +CCSDS_DATE_INVALID_LENGTH_TIME_FIELD = longitud invàlidq pel camp data en una data CCSDS : {0} en comptes del valor esperat {1} + +# missing agency epoch in CCSDS date +CCSDS_DATE_MISSING_AGENCY_EPOCH = falta agencia de l''època de referència específica en una data CCSDS + +# missing mandatory key {0} in CCSDS file {1} +CCSDS_MISSING_KEYWORD = falta paraula clau {0} en el fitxer CCSDS {1} + +# key {0} is not allowed in format version {1} +CCSDS_KEYWORD_NOT_ALLOWED_IN_VERSION = la paraula clau {0} no està permesa en la versió {1} del format + +# unexpected keyword in CCSDS line number {0} of file {1}:\n{2} +CCSDS_UNEXPECTED_KEYWORD = paraula clau inesperada en la linea {0} del fitxer CCSDS {1}:\n{2} + +# the central body gravitational coefficient cannot be retrieved from the ODM +CCSDS_UNKNOWN_GM = el coeficient gravitacional del cos central no es pot recuperar del ODM + +# there is no spacecraft mass associated with this ODM file +CCSDS_UNKNOWN_SPACECRAFT_MASS = no hi ha massa de satèl·lit asociada a aquest fitxer ODM + +# no IERS conventions have been set before parsing +CCSDS_UNKNOWN_CONVENTIONS = no s''ha inicialitzat cap convenció IERS abans de la lectura + +# frame {0} is not valid in this CCSDS file context +CCSDS_INVALID_FRAME = el sistema de referència {0} no és vàlid en aquest context de fitxer CCSDS + +# this LVLH local orbital frame uses a different definition, please use LVLH_CCSDS instead +CCSDS_DIFFERENT_LVLH_DEFINITION = aquest punt de referència local LVLH utilitza una definició diferent, utilitzi el punt de referència LVLH_CCSDS en el seu lloc + +# inconsistent time systems: {0} ≠ {1} +CCSDS_INCONSISTENT_TIME_SYSTEMS = sistemes temporals inconsistents: {0} ≠ {1} + +# No CCSDS TDM keyword was found at line {0} of file {1}:\n{2} +CCSDS_TDM_KEYWORD_NOT_FOUND = no s''ha trobat la paraula clau per CCSDS TDM en la linea {0} del fitxer {1}:\n{2} + +# no Range Units converter configured for parsing Tracking Data Message +CCSDS_TDM_MISSING_RANGE_UNITS_CONVERTER = no s''ha trobat cap convertidor d''unitats de pseudo-distància configurat per la lectura dels missatges de seguimient de dades (« Tracking Data Message ») + +# Time system should have already been set before line {0} of file {1} +CCSDS_TIME_SYSTEM_NOT_READ_YET = el sistema temporal hauria d''haver sigut inicialitzat abans de la linea {0} del fitxer {1} + +# cannot estimate precession without proper derivatives +CANNOT_ESTIMATE_PRECESSION_WITHOUT_PROPER_DERIVATIVES = impossible d''estimar la precisió sense les derivades correctes + +# name "{0}" is already used for an additional state +ADDITIONAL_STATE_NAME_ALREADY_IN_USE = el nombre "{0}" ja s''està utilitzant per un estat adicional + +# reset state not allowed +NON_RESETABLE_STATE = reinicialització de l''estat no autoritzada + +# Cannot compute Newcomb operators for sigma > rho ({0} > {1}) +DSST_NEWCOMB_OPERATORS_COMPUTATION = no es pueden calcular els operadors de Newcomb amb sigma ({0}) > rho ({1}) + +# Cannot compute the Vmns coefficient with m > n ({0} > {1}) +DSST_VMNS_COEFFICIENT_ERROR_MS = no es pueden calcular els coeficients Vmns amb m > n ({0} > {1}) + +# inconsistent shadow computation: entry = {0} whereas exit = {1} +DSST_SPR_SHADOW_INCONSISTENT = càlcul de sombra incoherent : entrada = {0} mentres que sortida = {1} + +# The current orbit has an eccentricity ({0} > 0.5). DSST needs an unimplemented time dependent numerical method to compute the averaged rates +DSST_ECC_NO_NUMERICAL_AVERAGING_METHOD = l''òrbita té una excentricitat ({0} > 0.5). DSST necessita per calcular les derivades mesurades un mètode numèric dependent del temps que no està implementat + +# unsupported sp3 file version {0} +SP3_UNSUPPORTED_VERSION = versió de format sp3 {0} no reconeguda + +# invalid header entry {0} "{1}" in file {2} (format version {3}) +SP3_INVALID_HEADER_ENTRY = + +# version "{0}" supports only up to {1} satellites, found {2} in file {3} +SP3_TOO_MANY_SATELLITES_FOR_VERSION = + +# found {0} epochs in file {1}, expected {2} +SP3_NUMBER_OF_EPOCH_MISMATCH = s''han trobat {0} èpoques en el fitxer {1} en comptes de {2} + +# cannot splice sp3 files with incompatible metadata +SP3_INCOMPATIBLE_FILE_METADATA = impossible d''adjuntar els fitxers sp3 tenint metadata diferent + +# cannot splice sp3 files with incompatible satellite metadata for satellite {0} +SP3_INCOMPATIBLE_SATELLITE_MEDATADA = impossible d''adjuntar els fitxers sp3 tenint metadata del satèl·lit {0} diferent + +# STK coordinate system "{0}" is invalid or not yet supported +STK_INVALID_OR_UNSUPPORTED_COORDINATE_SYSTEM = el sistema de coordenades "{0}" de STK és invàlid o no s''ha implementat encara + +# STK coordinate system "{0}" has not been mapped to an Orekit frame +STK_UNMAPPED_COORDINATE_SYSTEM = el sistema de coordenades "{0}" de STK encara no ha estat mapejat a una estructura Orekit + +# unexpected end of STK file (after line {0}) +STK_UNEXPECTED_END_OF_FILE = final inesperat d''un fitxer STK (després de la linea {0}) + +# unsupported clock file version {0} +CLOCK_FILE_UNSUPPORTED_VERSION = versió de l''arxiu de rellotge {0} no reconeguda + +# version {0} from file {1} is not supported, supported version: {2} +UNSUPPORTED_FILE_FORMAT_VERSION = versió {0} del fitxer {1} no s''ha tingut en compte, versions tingudes en compte: {2} + +# non-existent geomagnetic model {0} for year {1} +NON_EXISTENT_GEOMAGNETIC_MODEL = no existeix el fitxer del model geomagnètic {0} per l''any {1} + +# geomagnetic model {0} with epoch {1} does not support time transformation, no secular variation coefficients defined +UNSUPPORTED_TIME_TRANSFORM = el model geomagnètic {0} en l''època {1} no té en coñpte les transformacions temporals, no hi ha definit cap coefficient de variació secular + +# time transformation of geomagnetic model {0} with epoch {1} is outside its validity range: {2} != [{3}, {4}] +OUT_OF_RANGE_TIME_TRANSFORM = la transformació temporal del model geomagnètic {0} en l''època {1} està fora del domini de validesa: {2} != [{3}, {4}] + +# not enough data (sample size = {0}) +NOT_ENOUGH_DATA = no hi ha dades suficients (mida de la mostra = {0}) + +# too small number of cached neighbors: {0} (must be at least {1}) +NOT_ENOUGH_CACHED_NEIGHBORS = número de veïns emmagatzemada massa petit : {0} (deu ser almenys {1}) + +# no cached entries +NO_CACHED_ENTRIES = cap entrada emmagatzemada + +# generated entries not sorted: {0} > {1} by {2,number,0.0##############E0} s +NON_CHRONOLOGICALLY_SORTED_ENTRIES = les entrades generades no estan ordenades: {0} > {1} de {2,number,0.0##############E0} segons + +# no data generated around date: {0} +NO_DATA_GENERATED = cap dada generada al voltant de la data: {0} + +# unable to generate new data before {0}, but data is requested for {1} which is {2,number,0.0##############E0} s before +UNABLE_TO_GENERATE_NEW_DATA_BEFORE = no es pot generar noves dades abans de {0}, les dades solicitades per {1} són de {2,number,0.0##############E0} segons abans + +# unable to generate new data after {0}, but data is requested for {1} which is {2,number,0.0##############E0} s after +UNABLE_TO_GENERATE_NEW_DATA_AFTER = no es poden generar noves dades després de {0}, les dades sol·licitades per a {1} són de {2,number,0.0##############E0} segonds després + +# unable to compute hyperbolic eccentric anomaly from the mean anomaly after {0} iterations +UNABLE_TO_COMPUTE_HYPERBOLIC_ECCENTRIC_ANOMALY = després de {0} iteracins no s''ha aconseguit calcular l''anomalia excèntrica hiperbòlica a partir de l''anomalia mitjana + +# unable to compute mean orbit from osculating orbit after {0} iterations +UNABLE_TO_COMPUTE_DSST_MEAN_PARAMETERS = no es pot calcular l''òrbita mitjana a partir de l''òrbita osculating al cap de {0} iteracions + +# derivation order {0} is out of range +OUT_OF_RANGE_DERIVATION_ORDER = l''ordre de derivació {0} està fora del rang + +# orbit type {0} not allowed here, allowed types: {1} +ORBIT_TYPE_NOT_ALLOWED = tipus d''òrbita {0} no permesa, els tipus permesos són: {1} + +# non pseudo-inertial frame {0} is not suitable as reference for inertial forces +NON_PSEUDO_INERTIAL_FRAME_NOT_SUITABLE_AS_REFERENCE_FOR_INERTIAL_FORCES = sistema de referència no pseudo-inèrcial {0} no és adeqüat com referència per a les forces inercials + +# method not available in the absence of a central body +METHOD_NOT_AVAILABLE_WITHOUT_CENTRAL_BODY = mètode no disponible en absència d''un cos central + +# operation not available between frames {0} and {1} +INCOMPATIBLE_FRAMES = operació no disponible entre els sistemes de referència {0} i {1} + +# orbit not defined, state rather contains an absolute position-velocity-acceleration +UNDEFINED_ORBIT = òrbita no definida, l''estat conté més aviat una posició-velocitat-acceleració absoluta + +# absolute position-velocity-acceleration not defined, state rather contains an orbit +UNDEFINED_ABSOLUTE_PVCOORDINATES = posició-velocitat-acceleració absoluta no definida, l''estat conté més aviat una òrbita + +# an inertial force model has to be used when propagating in non-inertial frame {0} +INERTIAL_FORCE_MODEL_MISSING = és necesari un model de força inercial per propagar en un sistema de refèrencia no inercial {0} + +# no SEM almanac file found +NO_SEM_ALMANAC_AVAILABLE = no s''ha trobat fitxer d''almanacs SEM + +# file {0} is not a supported SEM almanac file +NOT_A_SUPPORTED_SEM_ALMANAC_FILE = el fitxer {0} no es reconeix com fitxer vàlid d''almanacs SEM + +# no Yuma almanac file found +NO_YUMA_ALMANAC_AVAILABLE = no es troba el fitxer d''almanacs Yuma + +# file {0} is not a supported Yuma almanac file +NOT_A_SUPPORTED_YUMA_ALMANAC_FILE = el fitxer {0} no es reconeix com fitxer vàlid d''almanacs Yuma + +# only {0} GNSS orbits are provided while {1} are needed to compute the DOP +NOT_ENOUGH_GNSS_FOR_DOP = tan sols s''han especificat {0} òrbites GNSS i es necessiten {1} per calcular el DOP + +# use of time system {0} in CCSDS files requires an additional ICD and is not implemented in Orekit +CCSDS_TIME_SYSTEM_NOT_IMPLEMENTED = per utilitzar el sistema temporal {0} en els fitxers CCSDS es necessita un ICD adicional i no està disponible en Orekit + +# unknown attitude type {0} +CCSDS_UNKNOWN_ATTITUDE_TYPE = tipus d''orientació {0} desconeguda + +# incomplete data +CCSDS_INCOMPLETE_DATA = dades incompletes + +# invalid rotation sequence {0} at line {1} of file {2} +CCSDS_INVALID_ROTATION_SEQUENCE = sequència de rotació {0} invàlida en la linea {1} del fitxer {2} + +# element set type {0} ({1}) is not supported yet +CCSDS_UNSUPPORTED_ELEMENT_SET_TYPE = encara no hi ha suport pel tipus d''elements {0} ({1}) + +# retrograde factor not supported in element set {0} +CCSDS_UNSUPPORTED_RETROGRADE_EQUINOCTIAL = factor retrògrad sense suport en el tipus d''elements {0} + +# wrong number of units for maneuver {0} +CCSDS_MANEUVER_UNITS_WRONG_NB_COMPONENTS = número incorrecte d''unitats per la maniobra {0} + +# missing time field for maneuver {0} +CCSDS_MANEUVER_MISSING_TIME = falta camp temporal per la maniobra {0} + +# attitude type {0} and rate type {1} calls for {2} states, got {3} +CCSDS_INCONSISTENT_NUMBER_OF_ATTITUDE_STATES = el tipus d''orientació {0} i el tipus de velocitat {1} necessiten {2} estats, però {3} s''han donat + +# incompatible keys {0} and {1} should not both be used +CCSDS_INCOMPATIBLE_KEYS_BOTH_USED = les claus incompatibles {0} i {1} no s''haurien d''utilitzar juntes + +# sensor index {0} is already used +CCSDS_SENSOR_INDEX_ALREADY_USED = índex de captor {0} ja utilitzat + +# missing sensor index {0} +CCSDS_MISSING_SENSOR_INDEX = falta l''índex de captor {0} + +# inconsistent number of elements: expected {0}, got {1} +INCONSISTENT_NUMBER_OF_ELEMENTS = número d''elements incoherents: esperats {0}, donats {1} + +# Creating an aggregate propagator requires at least one constituent propagator, but none were provided. +NOT_ENOUGH_PROPAGATORS = per crear un propagador combinat es necesita al menys un propagador, però no s''en ha especificat cap + +# Creating an aggregate attitude provider requires at least one constituent attitude provider, but none were provided. +NOT_ENOUGH_ATTITUDE_PROVIDERS = la creació d''un proveïdor d''actitud agregat necessita al menys un proveïdor d''actitud, però no se n''ha previst cap + +# argument {0} cannot be null +NULL_ARGUMENT = l''entrada {0} no pot ser nul·la + +# value {0} not found in {1} +VALUE_NOT_FOUND = no es troba el valor {0} en {1} + +# Klobuchar coefficients α or β could not be loaded from {0} +KLOBUCHAR_ALPHA_BETA_NOT_LOADED = els coeficients Klobuchar α o β no s''han pogut carregar de {0} + +# Klobuchar coefficients α or β not available for date {0} +KLOBUCHAR_ALPHA_BETA_NOT_AVAILABLE_FOR_DATE = falten els coeficients Klobuchar α o β per la data {0} + +# file {0} does not contain Klobuchar coefficients α or β +NO_KLOBUCHAR_ALPHA_BETA_IN_FILE = el fitxer {0} no conté els coeficients Klobuchar α o β + +# no reference date set for parameter {0} +NO_REFERENCE_DATE_FOR_PARAMETER = la data de referència per el paràmetre {0} no està inicialitzada + +# station {0} not found, known stations: {1} +STATION_NOT_FOUND = no es troba l''estació {0}, estaciones conegudes: {1} + +# unknown satellite system {0} +UNKNOWN_SATELLITE_SYSTEM = sistema de satèl·lits desconeguts {0} + +# unknown time system {0} +UNKNOWN_TIME_SYSTEM = sistema de temps desconegut {0} + +# unknown UTC Id {0} +UNKNOWN_UTC_ID = identificador UTC {0} desconegut + +# unknown clock data type {0} +UNKNOWN_CLOCK_DATA_TYPE = tipus de dades de rellotge desconegudes {0} + +# unknown satellite antenna code {0} +UNKNOWN_SATELLITE_ANTENNA_CODE = codi d''antena de satèl·lit desconegut {0} + +# frequency {0} is not supported by antenna {1} +UNSUPPORTED_FREQUENCY_FOR_ANTENNA = frequència {0} no presa en compte per l''antena {1} + +# cannot find satellite {0} in satellite system {1} +CANNOT_FIND_SATELLITE_IN_SYSTEM = no es pot trobar el satèl·lit {0} en el sistema de satèl·lits {1} + +# unknown RINEX frequency {0} in file {1}, line {2} +UNKNOWN_RINEX_FREQUENCY = frequència RINEX desconeguda en el fitxer {1}, linea {2} + +# mismatched frequencies in file {0}, line {1} (expected {2}, got {3}) +MISMATCHED_FREQUENCIES = frequències incoherents en el fitxer {0}, linea {1} (s''esperava {2} i s''ha trobat {3}) + +# wrong parsing type for file {0} +WRONG_PARSING_TYPE = tipus d''anàlisis incorrecte pel fitxer {0} + +# wrong number of columns in file {0}, line {1} (expected {2} columns, got {3} columns) +WRONG_COLUMNS_NUMBER = número de columnes erròni en el fitxer {0}, linea {1} (s''esperavan {2} columnes i s''han trobat {3}) + +# unsupported format for file {0} +UNSUPPORTED_FILE_FORMAT = format no reconegut pel fitxer {0} + +# incomplete header in file {0} +INCOMPLETE_HEADER = capçalera incompleta en el fitxer {0} + +# inconsistent number of satellites in line {0}, file {1}: observation with {2} satellites and number of max satellites is {3} +INCONSISTENT_NUMBER_OF_SATS = número incoherent de satèl·lits en la linea {0}, fitxer {1}: observació amb {2} satèl·lits, no obstant el número màxim de satèl·lits és {3} + +# the satellite system {3} from line {0}, file {1} is not consistent with the Rinex Satellite System {2} in header +INCONSISTENT_SATELLITE_SYSTEM = el sistema de satèl·lits {3} en la linea {0}, fitxer {1} no és coherent amb el Sistema de Satèl·lits Rinex {2} en la capçalera + +# no propagator configured +NO_PROPAGATOR_CONFIGURED = cap propagador ha estat configurat + +# dimension {0} is inconsistent with parameters list: {1} +DIMENSION_INCONSISTENT_WITH_PARAMETERS = la dimensió {0} no és coherent amb la llista de paràmetres: {1} + +# file {0} is not a supported Unix-compressed file +NOT_A_SUPPORTED_UNIX_COMPRESSED_FILE = el fitxer {0} no respecta el format Unix-compressed reconegut + +# unexpected end of file {0} +UNEXPECTED_END_OF_FILE = fi inesperada del fitxer {0} + +# file {0} is corrupted +CORRUPTED_FILE = l''arxiu {0} està fet malbé + +# Vienna coefficients ah or aw or zh or zw could not be loaded from {0} +VIENNA_ACOEF_OR_ZENITH_DELAY_NOT_LOADED = els coeficients ah o aw o zh o zw del model de Viena no han pogut carregar-se des de {0} + +# Vienna coefficients ah or aw or zh or zw not available for date {0} +VIENNA_ACOEF_OR_ZENITH_DELAY_NOT_AVAILABLE_FOR_DATE = els coeficients ah o aw o zh o zw del model de Viena no estan disponibles per la data {0} + +# file {0} does not contain Vienna coefficients ah, aw, zh or zw +NO_VIENNA_ACOEF_OR_ZENITH_DELAY_IN_FILE = el fitxer {0} no conté els coeficients ah o aw o zh o zw del model de Viena + +# irregular or incomplete grid in file {0} +IRREGULAR_OR_INCOMPLETE_GRID = quadrícula irregular o incompleta en el fitxer {0} + +# invalid satellite system {0} +INVALID_SATELLITE_SYSTEM = el sistema de satèl·lits {0} no és vàlid + +# IONEX files {0} does not contain TEC data for date {1} +NO_TEC_DATA_IN_FILES_FOR_DATE = els fitxers IONEX {0} no conté dades TEC per la data {1} + +# number of maps {0} is inconsistent with header specification: {1} +INCONSISTENT_NUMBER_OF_TEC_MAPS_IN_FILE = el número de mapes {0} no és coherent amb l''especificació de la capçalera {1} + +# file {0} does not contain latitude or longitude bondaries in its header section +NO_LATITUDE_LONGITUDE_BONDARIES_IN_IONEX_HEADER = el fitxer {0} no conté límits de latitud o longitud en la secció de la capçalera + +# file {0} does not contain epoch of first or last map in its header section +NO_EPOCH_IN_IONEX_HEADER = el fitxer {0} no conté èpoques del primer o últim mapa en la secció de la capçalera + +# The first column of itrf-versions.conf is a plain prefix that is matched against the +# name of each loaded file. It should not contain any regular expression syntax or +# directory components, i.e. \"/\" or \"\\\". Actual value: \"{0}\". +ITRF_VERSIONS_PREFIX_ONLY = la primera columna del fitxer itrf-versions.conf és un prèfix simple que es compara als noms de cada un dels fitxers carregats. No hauria contenir cap expresió racional ni cap separador de directori, per exemple: \"/\" o \"\\\". El valor real és: \"{0}\". + +# cannot compute aiming direction at singular point: latitude = {0}, longitude = {1} +CANNOT_COMPUTE_AIMING_AT_SINGULAR_POINT = no es pot calcular la direcció objectiu en el punt singular latitud = {0}, longitud = {1} + +# STEC integration did not converge +STEC_INTEGRATION_DID_NOT_CONVERGE = l''integració STEC no ha arribat a la convergència + +# MODIP grid not be loaded from {0} +MODIP_GRID_NOT_LOADED = no s''ha pogut carregar la quadrícula MODIP des de {0} + +# NeQuick coefficient f2 or fm3 not be loaded from {0} +NEQUICK_F2_FM3_NOT_LOADED = impossible de carregar els coeficients NeQuick f2 y fm3 des de {0} + +# file {0} is not a supported Hatanaka-compressed file +NOT_A_SUPPORTED_HATANAKA_COMPRESSED_FILE = no es reconeix el fitxer {0} com fitxer comprimit per el mètodo de Hatanaka + +# Cannot compute around {0} +CANNOT_COMPUTE_LAGRANGIAN = no es poden realitzar els calculs al voltant de {0} + +# The trajectory does not cross XZ Plane, it will not result in a Halo Orbit +TRAJECTORY_NOT_CROSSING_XZPLANE = la trajectoria no intersecciona amb el Pla XZ, no pot derivar en una òrbita Halo + +# The multiple shooting problem is underconstrained : {0} free variables, {1} constraints +MULTIPLE_SHOOTING_UNDERCONSTRAINED = el problema multiple-shooting no té suficients restriccions: {0} variables lliures, {1} restriccions + +# invalid measurement types {0} and {1} for the combination of measurements {2} +INVALID_MEASUREMENT_TYPES_FOR_COMBINATION_OF_MEASUREMENTS = tipus de mesures {0} i {1} incompatibles per la combinació de mesures {2} + +# frequencies {0} and {1} are incompatibles for the {2} combination +INCOMPATIBLE_FREQUENCIES_FOR_COMBINATION_OF_MEASUREMENTS = les frequències {0} i {1} són incompatibles per la combinació {2} + +# observations are not in chronological order: {0} is {2} s after {1} +NON_CHRONOLOGICAL_DATES_FOR_OBSERVATIONS = les observacions no es troben en ordre cronològic: {0} és {2} s després de {1} + +# Use of the ExceptionalDataContext detected. This is typically used to detect developer errors. +EXCEPTIONAL_DATA_CONTEXT = s''ha detectat una utilització de ExceptionalDataContext. Això s''utilitza normalment per detectar errors del desenvolupador + +# Observations must have different dates: {0}, {1} ({3,number,0.0##############E0} s from first observation), and {2} ({4,number,0.0##############E0} s from first observation, {5,number,0.0##############E0} s from second observation) +NON_DIFFERENT_DATES_FOR_OBSERVATIONS = les observacions han de tenir dates diferents: {0}, {1} ({3,number,0.0##############E0} s des de la primera observació), i {2} ({4,number,0.0##############E0} des de la primera observació, {5,number,0.0##############E0} des de la segona observació) + +# observations are not in the same plane +NON_COPLANAR_POINTS = les observacions no estan en el mateix pla + +# invalid parameter {0}: {1} not in range [{2}, {3}] +INVALID_PARAMETER_RANGE = invalidesa del paràmetre {0}: {1} fora del rang [{2}, {3}] + +# The parameter {0} should not be null in {1} +PARAMETER_NOT_SET = el paràmetre {0} no hauria de ser nul en {1} + +# {0} is not implemented +FUNCTION_NOT_IMPLEMENTED = {0} no està implementat + +# Impossible to execute {0} with {1} set to {2} +INVALID_TYPE_FOR_FUNCTION = impossible ejecutar {0} amb {1} establit a {2} + +# No data could be parsed from file {0} +NO_DATA_IN_FILE = cap dada ha pogut llegir-se des del fitxer {0} + +# Unexpected end of CPF file (after line {0}) +CPF_UNEXPECTED_END_OF_FILE = fi inesperada del fitxer CPF (després de la linea {0}) + +# Unexpected file format. Must be {0} but is {1} +UNEXPECTED_FORMAT_FOR_ILRS_FILE = Format de fitxer inesperat. Deu ser {0} però és {1} + +# Invalid range indicator {0} in CRD file header +INVALID_RANGE_INDICATOR_IN_CRD_FILE = Indicador de rang invàlid {0} en la capçalera del fitxer CRD + +# Unexpected end of CRD file (after line {0}) +CRD_UNEXPECTED_END_OF_FILE = fi inesperada del fitxer CRD (després de la linea {0}) + +# end of encoded message reached +END_OF_ENCODED_MESSAGE = s''ha arribat al final del missatge codificat + +# too large data type ({0} bits) +TOO_LARGE_DATA_TYPE = tipus de dades massa grans ({0} bits) + +# unknown encoded message number {0} +UNKNOWN_ENCODED_MESSAGE_NUMBER = número de missatge codificat {0} desconegut + +# unknown authentication method: {0} +UNKNOWN_AUTHENTICATION_METHOD = el mètode d''autentificació és desconegut: {0} + +# unknown carrier phase code: {0} +UNKNOWN_CARRIER_PHASE_CODE = el codi de la fase portadora {0} és desconegut + +# unknown data format: {0} +UNKNOWN_DATA_FORMAT = el format de dades {0} és desconegut + +# unknown navigation system: {0} +UNKNOWN_NAVIGATION_SYSTEM = sistema de navegació {0} desconegut + +# data stream {0} requires a NMEA fix data +STREAM_REQUIRES_NMEA_FIX = el flux de dades {0} requereix una dada fixa NMEA + +# failed authentication for mountpoint {0} +FAILED_AUTHENTICATION = fallo de l''autentificació pel punt de montatge {0} + +# error connecting to {0}: {1} +CONNECTION_ERROR = error de conexió a {0}: {1} + +# unexpected content type {0} +UNEXPECTED_CONTENT_TYPE = tipus de contingut {0} inesperat + +# cannot parse GNSS data from {0} +CANNOT_PARSE_GNSS_DATA = no es poden analitzar les dades GNSS de {0} + +# invalid GNSS data: {0} +INVALID_GNSS_DATA = dades GNSS invàides: {0} + +# GNSS parity error on word {0} +GNSS_PARITY_ERROR = error de paritat GNSS en la paraula {0} + +# unknown host {0} +UNKNOWN_HOST = anfitrió {0} desconegut + +# error parsing sourcetable line {0} from {1}: {2} +SOURCETABLE_PARSE_ERROR = error d''anàlisis de la linea {0} de la taula d''origen {1}: {2} + +# cannot parse sourcetable from {0} +CANNOT_PARSE_SOURCETABLE = no es pot analitzar la taula d''origen des de {0} + +# mount point {0} is already connected +MOUNPOINT_ALREADY_CONNECTED = el punt de montatge {0} ja està conectat + +# missing header from {0}: {1} +MISSING_HEADER = falta capçalera de {0}: {1} + +# {0} is not a valid international designator +NOT_VALID_INTERNATIONAL_DESIGNATOR = {0} no és un designador internacional vàlid + +# value for key {0} has not been initialized +UNINITIALIZED_VALUE_FOR_KEY = el valor no s''ha inicialitzat per la clau {0} + +# unknown unit {0} +UNKNOWN_UNIT = unitat {0} desconeguda + +# units {0} and {1} are not compatible +INCOMPATIBLE_UNITS = les unitats {0} i {1} no són compatibles + +# missing velocity data +MISSING_VELOCITY = falten dades de velocitat + +# attempt to generate file {0} with a formatting error +ATTEMPT_TO_GENERATE_MALFORMED_FILE = tentativa de generar el fitxer {0} amb un error de format + +# {0} failed to find root between {1} (g={2,number,0.0##############E0}) and {3} (g={4,number,0.0##############E0})\nLast iteration at {5} (g={6,number,0.0##############E0}) +FIND_ROOT = {0} ha fallat buscant una solució entre {1} (g={2,number,0.0##############E0}) i {3} (g={4,number,0.0##############E0})\nÚltima iteració en {5} (g={6,number,0.0##############E0}) + +# missing station data for epoch {0} +MISSING_STATION_DATA_FOR_EPOCH = Falten dades de l''estació per l''època {0} + +# inconsistent parameters selection between pairs {0}/{1} and {2}/{3} +INCONSISTENT_SELECTION = selecció de paràmetres inconsistents entre els pars {0}/{1} i {2}/{3} + +# no unscented transform configured +NO_UNSCENTED_TRANSFORM_CONFIGURED = cap transformació unscented configurada + +# value is not strictly positive: {0} +NOT_STRICTLY_POSITIVE = el valor {0} no és estrictament positiu + +# transform from {0} to {1} is not implemented +UNSUPPORTED_TRANSFORM = la transformació de {0} a {1} no s''ha implementat + +# orbital parameters type: {0} is different from expected orbital type : {1} +WRONG_ORBIT_PARAMETERS_TYPE = paràmetre orbital de tipus: {0} és diferent del paràmetre orbital esperat de tipus: {1} + +# {0} expects {1} elements, got {2} +WRONG_NB_COMPONENTS = {0} necessita {1} elements, en té {2} + +# cannot change covariance type if defined in a local orbital frame +CANNOT_CHANGE_COVARIANCE_TYPE_IF_DEFINED_IN_LOF = no pot camviar el tipis de covariança si es defineix en el el marc de referència de l''orbita local + +# cannot change covariance type if defined in a non pseudo-inertial reference frame +CANNOT_CHANGE_COVARIANCE_TYPE_IF_DEFINED_IN_NON_INERTIAL_FRAME = no pot camviar el tipis de covariança si es defineix en el el marc de referència no pseudo-inercial + +# primary collision object time of closest approach is different from the secondary collision object's one +DIFFERENT_TIME_OF_CLOSEST_APPROACH = el temps del major apropament del primer objecte de col·lisió és diferent del segon objecte de col·lisió + +# first date {0} does not match second date {1} +DATES_MISMATCH = la primera data {0} no coincideix amb la segona data {1} + +# first orbit mu {0} does not match second orbit mu {1} +ORBITS_MUS_MISMATCH = la mu {0} de la primera òrbita no coincideix amb la mu de la segona òrbita {1} + +# one state is defined using an orbit while the other is defined using an absolute position-velocity-acceleration +DIFFERENT_STATE_DEFINITION = un estat està definit utilizant una òrbita mentres que l''altre estat està definit utilizant una posició-velocitat-acceleració absolutes + +# state date {0} does not match its covariance date {1} +STATE_AND_COVARIANCE_DATES_MISMATCH = la data {0} de l''estat no coincideix amb la data {1} de la seva covariança + +# creating a spacecraft state interpolator requires at least one orbit interpolator or an absolute position-velocity-acceleration interpolator +NO_INTERPOLATOR_FOR_STATE_DEFINITION = crear un interpolador pel vehicle espacial requereix al menys un in interpolador d''òrbita o un interpolador absolut de posició-velocitat-acceleració + +# wrong interpolator defined for this spacecraft state type (orbit or absolute PV) +WRONG_INTERPOLATOR_DEFINED_FOR_STATE_INTERPOLATION = interpolador mal definit per aquest tipus de definició del vehicle espacial (òrbita o PV absoluts) + +# multiple interpolators are used so they may use different numbers of interpolation points +MULTIPLE_INTERPOLATOR_USED = mala interpolació definida per aquest tipus de definició del vehícule espacial (òrbita o PV) + +# header for file {0} has not been written yet +HEADER_NOT_WRITTEN = la capçalera del fitxer {0} encara no s''ha escrit + +# header for file {0} has already been written +HEADER_ALREADY_WRITTEN = la capçalera del fitxer {0} ja s''ha escrit + +# Cannot start the propagation from an infinitely far date +CANNOT_START_PROPAGATION_FROM_INFINITY = + +# invalid satellite id {0} +INVALID_SATELLITE_ID = + +# EOP interpolation degree must be of the form 4k-1, got {0} +WRONG_EOP_INTERPOLATION_DEGREE = diff --git a/src/site/markdown/index.md b/src/site/markdown/index.md index 75330c2485..505b04f790 100644 --- a/src/site/markdown/index.md +++ b/src/site/markdown/index.md @@ -348,6 +348,7 @@ * Localized in several languages + * Catalan * Danish * English * French diff --git a/src/test/java/org/orekit/errors/OrekitMessagesTest.java b/src/test/java/org/orekit/errors/OrekitMessagesTest.java index cd06de0959..9b0af1d390 100644 --- a/src/test/java/org/orekit/errors/OrekitMessagesTest.java +++ b/src/test/java/org/orekit/errors/OrekitMessagesTest.java @@ -26,7 +26,7 @@ public class OrekitMessagesTest { - private final String[] LANGUAGES_LIST = { "da", "de", "el", "en", "es", "fr", "gl", "it", "no", "ro" }; + private final String[] LANGUAGES_LIST = { "ca", "da", "de", "el", "en", "es", "fr", "gl", "it", "no", "ro" }; @Test public void testMessageNumber() { From e91ef0dc4ffe4fdec1d031eb73d83479ce2476fd Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Tue, 14 Nov 2023 10:02:17 +0100 Subject: [PATCH 009/359] Added new Catalan translations. Thanks to Elisabet Cid Borobia for the translations! --- .../org/orekit/localization/OrekitMessages_ca.utf8 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/resources/assets/org/orekit/localization/OrekitMessages_ca.utf8 b/src/main/resources/assets/org/orekit/localization/OrekitMessages_ca.utf8 index b6376c27bc..70932e2930 100644 --- a/src/main/resources/assets/org/orekit/localization/OrekitMessages_ca.utf8 +++ b/src/main/resources/assets/org/orekit/localization/OrekitMessages_ca.utf8 @@ -392,10 +392,10 @@ DSST_ECC_NO_NUMERICAL_AVERAGING_METHOD = l''òrbita té una excentricitat ({0} > SP3_UNSUPPORTED_VERSION = versió de format sp3 {0} no reconeguda # invalid header entry {0} "{1}" in file {2} (format version {3}) -SP3_INVALID_HEADER_ENTRY = +SP3_INVALID_HEADER_ENTRY = Entrada {0} "{1}" de la capçalera invàlida dins del fitxer {2} (versió del format {3}) # version "{0}" supports only up to {1} satellites, found {2} in file {3} -SP3_TOO_MANY_SATELLITES_FOR_VERSION = +SP3_TOO_MANY_SATELLITES_FOR_VERSION = La versió "{0}" accepta fins a {1} satèl·lits, però se n’’han trobat {2} dins el fitxer {3} # found {0} epochs in file {1}, expected {2} SP3_NUMBER_OF_EPOCH_MISMATCH = s''han trobat {0} èpoques en el fitxer {1} en comptes de {2} @@ -638,7 +638,7 @@ IRREGULAR_OR_INCOMPLETE_GRID = quadrícula irregular o incompleta en el fitxer { INVALID_SATELLITE_SYSTEM = el sistema de satèl·lits {0} no és vàlid # IONEX files {0} does not contain TEC data for date {1} -NO_TEC_DATA_IN_FILES_FOR_DATE = els fitxers IONEX {0} no conté dades TEC per la data {1} +NO_TEC_DATA_IN_FILES_FOR_DATE = els fitxers IONEX {0} no contenent dades TEC per la data {1} # number of maps {0} is inconsistent with header specification: {1} INCONSISTENT_NUMBER_OF_TEC_MAPS_IN_FILE = el número de mapes {0} no és coherent amb l''especificació de la capçalera {1} @@ -859,10 +859,10 @@ HEADER_NOT_WRITTEN = la capçalera del fitxer {0} encara no s''ha escrit HEADER_ALREADY_WRITTEN = la capçalera del fitxer {0} ja s''ha escrit # Cannot start the propagation from an infinitely far date -CANNOT_START_PROPAGATION_FROM_INFINITY = +CANNOT_START_PROPAGATION_FROM_INFINITY = La propagagació no pot començar a partir d’’una data infinita # invalid satellite id {0} -INVALID_SATELLITE_ID = +INVALID_SATELLITE_ID = Id {0} del satél·lit invàlid # EOP interpolation degree must be of the form 4k-1, got {0} -WRONG_EOP_INTERPOLATION_DEGREE = +WRONG_EOP_INTERPOLATION_DEGREE = El grau de l’’interpolador EOP ha de tenir la forma 4k-1, ara és {0} From 9f4e4e932ad180bf4bc9222d4fd24a340a7473c7 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Thu, 23 Nov 2023 11:39:01 +0100 Subject: [PATCH 010/359] Fixed exceptions occurring in EOP prediction. Fixes #1278 --- src/changes/changes.xml | 5 +- .../orekit/frames/SingleParameterFitter.java | 82 ++++++++++--------- .../frames/PredictedEOPHistoryTest.java | 61 +++++++++++--- 3 files changed, 98 insertions(+), 50 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 1cb39fe26a..a01416635e 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -20,7 +20,10 @@ Orekit Changes - + + + Fixed exceptions occurring in EOP prediction with ill chosen fitting parameters. + Added translation of error messages in Catalan language. diff --git a/src/main/java/org/orekit/frames/SingleParameterFitter.java b/src/main/java/org/orekit/frames/SingleParameterFitter.java index 4f0d938a37..b333c4ae41 100644 --- a/src/main/java/org/orekit/frames/SingleParameterFitter.java +++ b/src/main/java/org/orekit/frames/SingleParameterFitter.java @@ -23,7 +23,6 @@ import org.hipparchus.util.FastMath; import org.hipparchus.util.MathUtils; -import org.orekit.time.AbsoluteDate; import org.orekit.utils.Constants; import org.orekit.utils.SecularAndHarmonic; @@ -45,9 +44,6 @@ public class SingleParameterFitter implements Serializable { /** Serializable UID. */ private static final long serialVersionUID = 20230309L; - /** Duration of the fitting window at the end of the raw history (s). */ - private final double fittingDuration; - /** Time constant of the exponential decay weight. */ private final double timeConstant; @@ -61,7 +57,7 @@ public class SingleParameterFitter implements Serializable { private final double[] pulsations; /** Simple constructor. - * @param fittingDuration duration of the fitting window at the end of the raw history (s) + * @param fittingDuration ignored parameter since 12.0 * @param timeConstant time constant \(\tau\) of the exponential decay weight, point weight is \(e^{\frac{t-t_0}{\tau}}\), * i.e. points far in the past before \(t_0\) have smaller weights * @param convergence convergence on fitted parameter @@ -74,10 +70,31 @@ public class SingleParameterFitter implements Serializable { * @see #createDefaultNutationFitterShortTermPrediction() * @see #createDefaultNutationFitterLongTermPrediction() * @see SecularAndHarmonic + * @deprecated replaced by {@link #SingleParameterFitter(double, double, int, double...)} */ + @Deprecated public SingleParameterFitter(final double fittingDuration, final double timeConstant, final double convergence, final int degree, final double... pulsations) { - this.fittingDuration = fittingDuration; + this(timeConstant, convergence, degree, pulsations); + } + + /** Simple constructor. + * @param timeConstant time constant \(\tau\) of the exponential decay weight, point weight is \(e^{\frac{t-t_0}{\tau}}\), + * i.e. points far in the past before \(t_0\) have smaller weights + * @param convergence convergence on fitted parameter + * @param degree degree of the polynomial model + * @param pulsations pulsations of harmonic part (rad/s) + * @see #createDefaultDut1FitterShortTermPrediction() + * @see #createDefaultDut1FitterLongTermPrediction() + * @see #createDefaultPoleFitterShortTermPrediction() + * @see #createDefaultPoleFitterLongTermPrediction() + * @see #createDefaultNutationFitterShortTermPrediction() + * @see #createDefaultNutationFitterLongTermPrediction() + * @see SecularAndHarmonic + * @since 12.0.1 + */ + public SingleParameterFitter(final double timeConstant, final double convergence, + final int degree, final double... pulsations) { this.timeConstant = timeConstant; this.convergence = convergence; this.degree = degree; @@ -106,18 +123,11 @@ public SecularAndHarmonic fit(final EOPHistory rawHistory, final ToDoubleFunctio sh.resetFitting(last.getDate(), initialGuess); // sample history - final AbsoluteDate fitStart = last.getDate().shiftedBy(-fittingDuration); final ListIterator backwardIterator = rawEntries.listIterator(rawEntries.size()); while (backwardIterator.hasPrevious()) { final EOPEntry entry = backwardIterator.previous(); - if (entry.getDate().isAfterOrEqualTo(fitStart)) { - // the entry belongs to the fitting interval - sh.addWeightedPoint(entry.getDate(), extractor.applyAsDouble(entry), - FastMath.exp(entry.getDate().durationFrom(fitStart) / timeConstant)); - } else { - // we have processed all entries from the fitting interval - break; - } + sh.addWeightedPoint(entry.getDate(), extractor.applyAsDouble(entry), + FastMath.exp(entry.getDate().durationFrom(last.getDate()) / timeConstant)); } // perform fitting @@ -138,7 +148,6 @@ public SecularAndHarmonic fit(final EOPHistory rawHistory, final ToDoubleFunctio * These settings are intended when prediction is used for at most 5 days after raw EOP end. *

*
    - *
  • fitting duration set to one {@link Constants#JULIAN_YEAR year}
  • *
  • time constant \(\tau\) of the exponential decay set to 6 {@link Constants#JULIAN_DAY days}
  • *
  • convergence set to 10⁻¹² s
  • *
  • polynomial part set to degree 3
  • @@ -153,9 +162,9 @@ public SecularAndHarmonic fit(final EOPHistory rawHistory, final ToDoubleFunctio * @see #createDefaultDut1FitterShortTermPrediction() */ public static SingleParameterFitter createDefaultDut1FitterShortTermPrediction() { - return new SingleParameterFitter(Constants.JULIAN_YEAR, 6 * Constants.JULIAN_DAY, 1.0e-12, 3, - SUN_PULSATION, 2 * SUN_PULSATION, 3 * SUN_PULSATION, - MOON_DRACONIC_PULSATION, 2 * MOON_DRACONIC_PULSATION, 3 * MOON_DRACONIC_PULSATION); + return new SingleParameterFitter(6 * Constants.JULIAN_DAY, 1.0e-12, 3, + SUN_PULSATION, 2 * SUN_PULSATION, 3 * SUN_PULSATION, + MOON_DRACONIC_PULSATION, 2 * MOON_DRACONIC_PULSATION, 3 * MOON_DRACONIC_PULSATION); } /** Create fitter with default parameters adapted for fitting orientation parameters dUT1 and LOD @@ -169,7 +178,6 @@ public static SingleParameterFitter createDefaultDut1FitterShortTermPrediction() * These settings are intended when prediction is used for 5 days after raw EOP end or more. *

    *
      - *
    • fitting duration set to three {@link Constants#JULIAN_YEAR years}
    • *
    • time constant \(\tau\) of the exponential decay set to 60 {@link Constants#JULIAN_DAY days}
    • *
    • convergence set to 10⁻¹² s
    • *
    • polynomial part set to degree 3
    • @@ -184,9 +192,9 @@ public static SingleParameterFitter createDefaultDut1FitterShortTermPrediction() * @see #createDefaultDut1FitterShortTermPrediction() */ public static SingleParameterFitter createDefaultDut1FitterLongTermPrediction() { - return new SingleParameterFitter(3 * Constants.JULIAN_YEAR, 60 * Constants.JULIAN_DAY, 1.0e-12, 3, - SUN_PULSATION, 2 * SUN_PULSATION, 3 * SUN_PULSATION, - MOON_DRACONIC_PULSATION, 2 * MOON_DRACONIC_PULSATION, 3 * MOON_DRACONIC_PULSATION); + return new SingleParameterFitter(60 * Constants.JULIAN_DAY, 1.0e-12, 3, + SUN_PULSATION, 2 * SUN_PULSATION, 3 * SUN_PULSATION, + MOON_DRACONIC_PULSATION, 2 * MOON_DRACONIC_PULSATION, 3 * MOON_DRACONIC_PULSATION); } /** Create fitter with default parameters adapted for fitting pole parameters Xp and Yp @@ -200,7 +208,6 @@ public static SingleParameterFitter createDefaultDut1FitterLongTermPrediction() * These settings are intended when prediction is used for at most 5 days after raw EOP end. *

      *
        - *
      • fitting duration set to one {@link Constants#JULIAN_YEAR year}
      • *
      • time constant \(\tau\) of the exponential decay set to 12 {@link Constants#JULIAN_DAY days}
      • *
      • convergence set to 10⁻¹² rad
      • *
      • polynomial part set to degree 3
      • @@ -214,9 +221,9 @@ public static SingleParameterFitter createDefaultDut1FitterLongTermPrediction() * @return fitter with default configuration for pole parameters Xp and Yp */ public static SingleParameterFitter createDefaultPoleFitterShortTermPrediction() { - return new SingleParameterFitter(Constants.JULIAN_YEAR, 12 * Constants.JULIAN_DAY, 1.0e-12, 3, - SUN_PULSATION, 2 * SUN_PULSATION, 3 * SUN_PULSATION, - MOON_DRACONIC_PULSATION, 2 * MOON_DRACONIC_PULSATION, 3 * MOON_DRACONIC_PULSATION); + return new SingleParameterFitter(12 * Constants.JULIAN_DAY, 1.0e-12, 3, + SUN_PULSATION, 2 * SUN_PULSATION, 3 * SUN_PULSATION, + MOON_DRACONIC_PULSATION, 2 * MOON_DRACONIC_PULSATION, 3 * MOON_DRACONIC_PULSATION); } /** Create fitter with default parameters adapted for fitting pole parameters Xp and Yp @@ -230,7 +237,6 @@ public static SingleParameterFitter createDefaultPoleFitterShortTermPrediction() * These settings are intended when prediction is used for 5 days after raw EOP end or more. *

        *
          - *
        • fitting duration set to three {@link Constants#JULIAN_YEAR years}
        • *
        • time constant \(\tau\) of the exponential decay set to 60 {@link Constants#JULIAN_DAY days}
        • *
        • convergence set to 10⁻¹² rad
        • *
        • polynomial part set to degree 3
        • @@ -244,9 +250,9 @@ public static SingleParameterFitter createDefaultPoleFitterShortTermPrediction() * @return fitter with default configuration for pole parameters Xp and Yp */ public static SingleParameterFitter createDefaultPoleFitterLongTermPrediction() { - return new SingleParameterFitter(3 * Constants.JULIAN_YEAR, 60 * Constants.JULIAN_DAY, 1.0e-12, 3, - SUN_PULSATION, 2 * SUN_PULSATION, 3 * SUN_PULSATION, - MOON_DRACONIC_PULSATION, 2 * MOON_DRACONIC_PULSATION, 3 * MOON_DRACONIC_PULSATION); + return new SingleParameterFitter(60 * Constants.JULIAN_DAY, 1.0e-12, 3, + SUN_PULSATION, 2 * SUN_PULSATION, 3 * SUN_PULSATION, + MOON_DRACONIC_PULSATION, 2 * MOON_DRACONIC_PULSATION, 3 * MOON_DRACONIC_PULSATION); } /** Create fitter with default parameters adapted for fitting nutation parameters dx and dy @@ -260,7 +266,6 @@ public static SingleParameterFitter createDefaultPoleFitterLongTermPrediction() * These settings are intended when prediction is used for at most 5 days after raw EOP end. *

          *
            - *
          • fitting duration set to one {@link Constants#JULIAN_YEAR year}
          • *
          • time constant \(\tau\) of the exponential decay set to 12 {@link Constants#JULIAN_DAY days}
          • *
          • convergence set to 10⁻¹² s
          • *
          • polynomial part set to degree 3
          • @@ -274,9 +279,9 @@ public static SingleParameterFitter createDefaultPoleFitterLongTermPrediction() * @return fitter with default configuration for pole nutation parameters dx and dy */ public static SingleParameterFitter createDefaultNutationFitterShortTermPrediction() { - return new SingleParameterFitter(Constants.JULIAN_YEAR, 12 * Constants.JULIAN_DAY, 1.0e-12, 3, - SUN_PULSATION, 2 * SUN_PULSATION, 3 * SUN_PULSATION, - MOON_DRACONIC_PULSATION, 2 * MOON_DRACONIC_PULSATION, 3 * MOON_DRACONIC_PULSATION); + return new SingleParameterFitter(12 * Constants.JULIAN_DAY, 1.0e-12, 3, + SUN_PULSATION, 2 * SUN_PULSATION, 3 * SUN_PULSATION, + MOON_DRACONIC_PULSATION, 2 * MOON_DRACONIC_PULSATION, 3 * MOON_DRACONIC_PULSATION); } /** Create fitter with default parameters adapted for fitting nutation parameters dx and dy @@ -290,7 +295,6 @@ public static SingleParameterFitter createDefaultNutationFitterShortTermPredicti * These settings are intended when prediction is used for 5 days after raw EOP end or more. *

            *
              - *
            • fitting duration set to three {@link Constants#JULIAN_YEAR years}
            • *
            • time constant \(\tau\) of the exponential decay set to 60 {@link Constants#JULIAN_DAY days}
            • *
            • convergence set to 10⁻¹² s
            • *
            • polynomial part set to degree 3
            • @@ -304,9 +308,9 @@ public static SingleParameterFitter createDefaultNutationFitterShortTermPredicti * @return fitter with default configuration for pole nutation parameters dx and dy */ public static SingleParameterFitter createDefaultNutationFitterLongTermPrediction() { - return new SingleParameterFitter(3 * Constants.JULIAN_YEAR, 60 * Constants.JULIAN_DAY, 1.0e-12, 3, - SUN_PULSATION, 2 * SUN_PULSATION, 3 * SUN_PULSATION, - MOON_DRACONIC_PULSATION, 2 * MOON_DRACONIC_PULSATION, 3 * MOON_DRACONIC_PULSATION); + return new SingleParameterFitter(60 * Constants.JULIAN_DAY, 1.0e-12, 3, + SUN_PULSATION, 2 * SUN_PULSATION, 3 * SUN_PULSATION, + MOON_DRACONIC_PULSATION, 2 * MOON_DRACONIC_PULSATION, 3 * MOON_DRACONIC_PULSATION); } } diff --git a/src/test/java/org/orekit/frames/PredictedEOPHistoryTest.java b/src/test/java/org/orekit/frames/PredictedEOPHistoryTest.java index e29f23d9cf..cebc5940c4 100644 --- a/src/test/java/org/orekit/frames/PredictedEOPHistoryTest.java +++ b/src/test/java/org/orekit/frames/PredictedEOPHistoryTest.java @@ -110,14 +110,14 @@ public void testCommonCoverage() { final double[] predENC = predicted.getEquinoxNutationCorrection(date); final double[] rawNroNC = truncatedEOP.getNonRotatinOriginNutationCorrection(date); final double[] predNroNC = predicted.getNonRotatinOriginNutationCorrection(date); - maxErrorUT1 = FastMath.max(maxErrorUT1, truncatedEOP.getUT1MinusUTC(date) - predicted.getUT1MinusUTC(date)); - maxErrorLOD = FastMath.max(maxErrorLOD, truncatedEOP.getLOD(date) - predicted.getLOD(date)); - maxErrorXp = FastMath.max(maxErrorXp, rawPC.getXp() - predPC.getXp()); - maxErrorYp = FastMath.max(maxErrorYp, rawPC.getYp() - predPC.getYp()); - maxErrordPsi = FastMath.max(maxErrordPsi, rawENC[0] - predENC[0]); - maxErrordEps = FastMath.max(maxErrordEps, rawENC[1] - predENC[1]); - maxErrordx = FastMath.max(maxErrordx, rawNroNC[0] - predNroNC[0]); - maxErrordy = FastMath.max(maxErrordy, rawNroNC[1] - predNroNC[1]); + maxErrorUT1 = FastMath.max(maxErrorUT1, FastMath.abs(truncatedEOP.getUT1MinusUTC(date) - predicted.getUT1MinusUTC(date))); + maxErrorLOD = FastMath.max(maxErrorLOD, FastMath.abs(truncatedEOP.getLOD(date) - predicted.getLOD(date))); + maxErrorXp = FastMath.max(maxErrorXp, FastMath.abs(rawPC.getXp() - predPC.getXp())); + maxErrorYp = FastMath.max(maxErrorYp, FastMath.abs(rawPC.getYp() - predPC.getYp())); + maxErrordPsi = FastMath.max(maxErrordPsi, FastMath.abs(rawENC[0] - predENC[0])); + maxErrordEps = FastMath.max(maxErrordEps, FastMath.abs(rawENC[1] - predENC[1])); + maxErrordx = FastMath.max(maxErrordx, FastMath.abs(rawNroNC[0] - predNroNC[0])); + maxErrordy = FastMath.max(maxErrordy, FastMath.abs(rawNroNC[1] - predNroNC[1])); } Assertions.assertEquals(0.0, maxErrorUT1, 1.0e-15); Assertions.assertEquals(0.0, maxErrorLOD, 1.0e-15); @@ -129,14 +129,55 @@ public void testCommonCoverage() { Assertions.assertEquals(0.0, maxErrordy, 1.0e-15); } + @Test + @Deprecated + public void testDeprecated() { + + // truncate EOP between 2018 and 2021 + final int mjdLimit = new DateComponents(2022, 1, 1).getMJD(); + final EOPHistory truncatedEOP = new EOPHistory(trueEOP.getConventions(), + EOPHistory.DEFAULT_INTERPOLATION_DEGREE, + trueEOP.getEntries(). + stream(). + filter(e -> e.getMjd() < mjdLimit). + collect(Collectors.toList()), + trueEOP.isSimpleEop(), + trueEOP.getTimeScales()); + + EOPHistory predicted = new PredictedEOPHistory(truncatedEOP, + 30 * Constants.JULIAN_DAY, + new EOPFitter(new SingleParameterFitter(3 * Constants.JULIAN_YEAR, + Constants.JULIAN_DAY, + 1.0e-12, 3, + SingleParameterFitter.SUN_PULSATION, + 2 * SingleParameterFitter.SUN_PULSATION, + 3 * SingleParameterFitter.SUN_PULSATION, + SingleParameterFitter.MOON_DRACONIC_PULSATION, + 2 * SingleParameterFitter.MOON_DRACONIC_PULSATION, + 3 * SingleParameterFitter.MOON_DRACONIC_PULSATION), + SingleParameterFitter.createDefaultPoleFitterLongTermPrediction(), + SingleParameterFitter.createDefaultPoleFitterLongTermPrediction(), + SingleParameterFitter.createDefaultNutationFitterLongTermPrediction(), + SingleParameterFitter.createDefaultNutationFitterLongTermPrediction())); + + // check we get the same value as raw EOP (dropping the last interpolated day) + double maxErrorUT1 = 0; + for (double dt = Constants.JULIAN_DAY; dt < 10 * Constants.JULIAN_DAY; dt += 20000.0) { + final AbsoluteDate date = truncatedEOP.getEndDate().shiftedBy(dt); + maxErrorUT1 = FastMath.max(maxErrorUT1, FastMath.abs(trueEOP.getUT1MinusUTC(date) - predicted.getUT1MinusUTC(date))); + } + Assertions.assertEquals(4.563, maxErrorUT1, 0.001); + + } + @Test public void testAccuracyShortTerm() { - doTestAccuracy(true, 0.147, 0.580, 1.529, 7.842, 316.169, 6077.219, 40759.570); + doTestAccuracy(true, 0.148, 0.580, 1.528, 7.842, 316.165, 6077.182, 40759.430); } @Test public void testAccuracyLongTerm() { - doTestAccuracy(false, 1.514, 1.987, 2.291, 3.014, 7.416, 17.635, 27.392); + doTestAccuracy(false, 1.518, 1.993, 2.298, 3.013, 7.398, 17.582, 27.296); } private void doTestAccuracy(final boolean shortTerm, From 528010c3870ff1d33a10080caf228374d49e4dfb Mon Sep 17 00:00:00 2001 From: Serrof Date: Tue, 21 Nov 2023 22:45:31 +0100 Subject: [PATCH 011/359] Fixes #1275: add utility classes for position angle conversions --- src/changes/changes.xml | 3 + .../org/orekit/errors/OrekitMessages.java | 6 + .../CircularLatitudeArgumentUtility.java | 175 ++++++++++++++++ .../java/org/orekit/orbits/CircularOrbit.java | 62 ++---- .../EquinoctialLongitudeArgumentUtility.java | 175 ++++++++++++++++ .../org/orekit/orbits/EquinoctialOrbit.java | 62 ++---- .../FieldCircularLatitudeArgumentUtility.java | 189 ++++++++++++++++++ .../org/orekit/orbits/FieldCircularOrbit.java | 61 ++---- ...ldEquinoctialLongitudeArgumentUtility.java | 188 +++++++++++++++++ .../orekit/orbits/FieldEquinoctialOrbit.java | 66 ++---- .../orbits/FieldKeplerianAnomalyUtility.java | 2 +- .../orbits/KeplerianAnomalyUtility.java | 2 +- .../localization/OrekitMessages_ca.utf8 | 6 + .../localization/OrekitMessages_da.utf8 | 6 + .../localization/OrekitMessages_de.utf8 | 6 + .../localization/OrekitMessages_el.utf8 | 6 + .../localization/OrekitMessages_en.utf8 | 6 + .../localization/OrekitMessages_es.utf8 | 6 + .../localization/OrekitMessages_fr.utf8 | 6 + .../localization/OrekitMessages_gl.utf8 | 6 + .../localization/OrekitMessages_it.utf8 | 6 + .../localization/OrekitMessages_no.utf8 | 6 + .../localization/OrekitMessages_ro.utf8 | 6 + .../org/orekit/errors/OrekitMessagesTest.java | 2 +- .../CircularLatitudeArgumentUtilityTest.java | 78 ++++++++ .../org/orekit/orbits/CircularOrbitTest.java | 81 +++++--- ...uinoctialLongitudeArgumentUtilityTest.java | 78 ++++++++ .../orekit/orbits/EquinoctialOrbitTest.java | 80 +++++--- ...ldCircularLatitudeArgumentUtilityTest.java | 157 +++++++++++++++ ...uinoctialLongitudeArgumentUtilityTest.java | 157 +++++++++++++++ 30 files changed, 1447 insertions(+), 243 deletions(-) create mode 100644 src/main/java/org/orekit/orbits/CircularLatitudeArgumentUtility.java create mode 100644 src/main/java/org/orekit/orbits/EquinoctialLongitudeArgumentUtility.java create mode 100644 src/main/java/org/orekit/orbits/FieldCircularLatitudeArgumentUtility.java create mode 100644 src/main/java/org/orekit/orbits/FieldEquinoctialLongitudeArgumentUtility.java create mode 100644 src/test/java/org/orekit/orbits/CircularLatitudeArgumentUtilityTest.java create mode 100644 src/test/java/org/orekit/orbits/EquinoctialLongitudeArgumentUtilityTest.java create mode 100644 src/test/java/org/orekit/orbits/FieldCircularLatitudeArgumentUtilityTest.java create mode 100644 src/test/java/org/orekit/orbits/FieldEquinoctialLongitudeArgumentUtilityTest.java diff --git a/src/changes/changes.xml b/src/changes/changes.xml index a01416635e..0481c0d1f2 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -21,6 +21,9 @@ + + Added utility classes for position angle conversions for (Field) CircularOrbit and EquinoctialOrbit. + Fixed exceptions occurring in EOP prediction with ill chosen fitting parameters. diff --git a/src/main/java/org/orekit/errors/OrekitMessages.java b/src/main/java/org/orekit/errors/OrekitMessages.java index 289a40acc4..32f2c6d850 100644 --- a/src/main/java/org/orekit/errors/OrekitMessages.java +++ b/src/main/java/org/orekit/errors/OrekitMessages.java @@ -537,6 +537,12 @@ public enum OrekitMessages implements Localizable { /** UNABLE_TO_COMPUTE_HYPERBOLIC_ECCENTRIC_ANOMALY. */ UNABLE_TO_COMPUTE_HYPERBOLIC_ECCENTRIC_ANOMALY("unable to compute hyperbolic eccentric anomaly from the mean anomaly after {0} iterations"), + /** UNABLE_TO_COMPUTE_ECCENTRIC_LONGITUDE_ARGUMENT. */ + UNABLE_TO_COMPUTE_ECCENTRIC_LONGITUDE_ARGUMENT("unable to compute eccentric longitude argument from the mean one after {0} iterations"), + + /** UNABLE_TO_COMPUTE_ECCENTRIC_LATITUDE_ARGUMENT. */ + UNABLE_TO_COMPUTE_ECCENTRIC_LATITUDE_ARGUMENT("unable to compute eccentric latitude argument from the mean one after {0} iterations"), + /** UNABLE_TO_COMPUTE_DSST_MEAN_PARAMETERS. */ UNABLE_TO_COMPUTE_DSST_MEAN_PARAMETERS("unable to compute mean orbit from osculating orbit after {0} iterations"), diff --git a/src/main/java/org/orekit/orbits/CircularLatitudeArgumentUtility.java b/src/main/java/org/orekit/orbits/CircularLatitudeArgumentUtility.java new file mode 100644 index 0000000000..c0078c8014 --- /dev/null +++ b/src/main/java/org/orekit/orbits/CircularLatitudeArgumentUtility.java @@ -0,0 +1,175 @@ +/* Copyright 2022-2023 Romain Serra + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.orbits; + +import org.hipparchus.util.FastMath; +import org.hipparchus.util.SinCos; +import org.orekit.errors.OrekitException; +import org.orekit.errors.OrekitMessages; + +/** + * Utility methods for converting between different latitude arguments used by {@link org.orekit.orbits.CircularOrbit}. + * @author Romain Serra + * @see org.orekit.orbits.CircularOrbit + * @since 12.1 + */ +public class CircularLatitudeArgumentUtility { + + /** Tolerance for stopping criterion in iterative conversion from mean to eccentric angle. */ + private static final double TOLERANCE_CONVERGENCE = 1.0e-12; + + /** Maximum number of iterations in iterative conversion from mean to eccentric angle. */ + private static final int MAXIMUM_ITERATION = 50; + + /** Private constructor for utility class. */ + private CircularLatitudeArgumentUtility() { + // nothing here (utils class) + } + + /** + * Computes the true latitude argument from the eccentric latitude argument. + * + * @param ex e cos(ω), first component of circular eccentricity vector + * @param ey e sin(ω), second component of circular eccentricity vector + * @param alphaE = E + ω eccentric latitude argument (rad) + * @return the true latitude argument. + */ + public static double eccentricToTrue(final double ex, final double ey, final double alphaE) { + final double epsilon = eccentricAndTrueEpsilon(ex, ey); + final SinCos scAlphaE = FastMath.sinCos(alphaE); + final double num = ex * scAlphaE.sin() - ey * scAlphaE.cos(); + final double den = epsilon + 1 - ex * scAlphaE.cos() - ey * scAlphaE.sin(); + return alphaE + eccentricAndTrueAtan(num, den); + } + + /** + * Computes the eccentric latitude argument from the true latitude argument. + * + * @param ex e cos(ω), first component of circular eccentricity vector + * @param ey e sin(ω), second component of circular eccentricity vector + * @param alphaV = V + ω true latitude argument (rad) + * @return the eccentric latitude argument. + */ + public static double trueToEccentric(final double ex, final double ey, final double alphaV) { + final double epsilon = eccentricAndTrueEpsilon(ex, ey); + final SinCos scAlphaV = FastMath.sinCos(alphaV); + final double num = ey * scAlphaV.cos() - ex * scAlphaV.sin(); + final double den = epsilon + 1 + ex * scAlphaV.cos() + ey * scAlphaV.sin(); + return alphaV + eccentricAndTrueAtan(num, den); + } + + /** + * Computes an intermediate quantity for conversions between true and eccentric. + * + * @param ex e cos(ω), first component of circular eccentricity vector + * @param ey e sin(ω), second component of circular eccentricity vector + * @return intermediate variable referred to as epsilon. + */ + private static double eccentricAndTrueEpsilon(final double ex, final double ey) { + return FastMath.sqrt(1 - ex * ex - ey * ey); + } + + /** + * Computes another intermediate quantity for conversions between true and eccentric. + * + * @param num numerator for angular conversion + * @param den denominator for angular conversion + * @return arc-tangent of ratio of inputs times two. + */ + private static double eccentricAndTrueAtan(final double num, final double den) { + return 2. * FastMath.atan(num / den); + } + + /** + * Computes the eccentric latitude argument from the mean latitude argument. + * + * @param ex e cos(ω), first component of circular eccentricity vector + * @param ey e sin(ω), second component of circular eccentricity vector + * @param alphaM = M + ω mean latitude argument (rad) + * @return the eccentric latitude argument. + */ + public static double meanToEccentric(final double ex, final double ey, final double alphaM) { + // Generalization of Kepler equation to circular parameters + // with alphaE = PA + E and + // alphaM = PA + M = alphaE - ex.sin(alphaE) + ey.cos(alphaE) + double alphaE = alphaM; + double shift; + double alphaEMalphaM = 0.0; + boolean hasConverged; + int iter = 0; + do { + final SinCos scAlphaE = FastMath.sinCos(alphaE); + final double f2 = ex * scAlphaE.sin() - ey * scAlphaE.cos(); + final double f1 = 1.0 - ex * scAlphaE.cos() - ey * scAlphaE.sin(); + final double f0 = alphaEMalphaM - f2; + + final double f12 = 2.0 * f1; + shift = f0 * f12 / (f1 * f12 - f0 * f2); + + alphaEMalphaM -= shift; + alphaE = alphaM + alphaEMalphaM; + + hasConverged = FastMath.abs(shift) <= TOLERANCE_CONVERGENCE; + } while (++iter < MAXIMUM_ITERATION && !hasConverged); + + if (!hasConverged) { + throw new OrekitException(OrekitMessages.UNABLE_TO_COMPUTE_ECCENTRIC_LATITUDE_ARGUMENT, iter); + } + return alphaE; + + } + + /** + * Computes the mean latitude argument from the eccentric latitude argument. + * + * @param ex e cos(ω), first component of circular eccentricity vector + * @param ey e sin(ω), second component of circular eccentricity vector + * @param alphaE = E + ω mean latitude argument (rad) + * @return the mean latitude argument. + */ + public static double eccentricToMean(final double ex, final double ey, final double alphaE) { + final SinCos scAlphaE = FastMath.sinCos(alphaE); + return alphaE + (ey * scAlphaE.cos() - ex * scAlphaE.sin()); + } + + /** + * Computes the mean latitude argument from the eccentric latitude argument. + * + * @param ex e cos(ω), first component of circular eccentricity vector + * @param ey e sin(ω), second component of circular eccentricity vector + * @param alphaV = V + ω true latitude argument (rad) + * @return the mean latitude argument. + */ + public static double trueToMean(final double ex, final double ey, final double alphaV) { + final double alphaE = trueToEccentric(ex, ey, alphaV); + return eccentricToMean(ex, ey, alphaE); + } + + /** + * Computes the true latitude argument from the eccentric latitude argument. + * + * @param ex e cos(ω), first component of circular eccentricity vector + * @param ey e sin(ω), second component of circular eccentricity vector + * @param alphaM = M + ω mean latitude argument (rad) + * @return the true latitude argument. + */ + public static double meanToTrue(final double ex, final double ey, final double alphaM) { + final double alphaE = meanToEccentric(ex, ey, alphaM); + return eccentricToTrue(ex, ey, alphaE); + } + +} diff --git a/src/main/java/org/orekit/orbits/CircularOrbit.java b/src/main/java/org/orekit/orbits/CircularOrbit.java index 943cbbf535..51521817b5 100644 --- a/src/main/java/org/orekit/orbits/CircularOrbit.java +++ b/src/main/java/org/orekit/orbits/CircularOrbit.java @@ -195,10 +195,10 @@ public CircularOrbit(final double a, final double ex, final double ey, final UnivariateDerivative1 alphavUD; switch (type) { case MEAN : - alphavUD = FieldCircularOrbit.eccentricToTrue(FieldCircularOrbit.meanToEccentric(alphaUD, exUD, eyUD), exUD, eyUD); + alphavUD = FieldCircularLatitudeArgumentUtility.meanToTrue(exUD, eyUD, alphaUD); break; case ECCENTRIC : - alphavUD = FieldCircularOrbit.eccentricToTrue(alphaUD, exUD, eyUD); + alphavUD = FieldCircularLatitudeArgumentUtility.eccentricToTrue(exUD, eyUD, alphaUD); break; case TRUE : alphavUD = alphaUD; @@ -211,10 +211,10 @@ public CircularOrbit(final double a, final double ex, final double ey, } else { switch (type) { case MEAN : - this.alphaV = eccentricToTrue(meanToEccentric(alpha, ex, ey), ex, ey); + this.alphaV = CircularLatitudeArgumentUtility.meanToTrue(ex, ey, alpha); break; case ECCENTRIC : - this.alphaV = eccentricToTrue(alpha, ex, ey); + this.alphaV = CircularLatitudeArgumentUtility.eccentricToTrue(ex, ey, alpha); break; case TRUE : this.alphaV = alpha; @@ -337,7 +337,7 @@ public CircularOrbit(final TimeStampedPVCoordinates pvCoordinates, final Frame f // compute latitude argument final double beta = 1 / (1 + FastMath.sqrt(1 - ex * ex - ey * ey)); - alphaV = eccentricToTrue(FastMath.atan2(y2 + ey + eSE * beta * ex, x2 + ex - eSE * beta * ey), ex, ey); + alphaV = CircularLatitudeArgumentUtility.eccentricToTrue(ex, ey, FastMath.atan2(y2 + ey + eSE * beta * ex, x2 + ex - eSE * beta * ey)); partialPV = pvCoordinates; @@ -365,7 +365,7 @@ public CircularOrbit(final TimeStampedPVCoordinates pvCoordinates, final Frame f final UnivariateDerivative1 exUD = new UnivariateDerivative1(ex, exDot); final UnivariateDerivative1 eyUD = new UnivariateDerivative1(ey, eyDot); final UnivariateDerivative1 alphaMUD = new UnivariateDerivative1(getAlphaM(), alphaMDot); - final UnivariateDerivative1 alphavUD = FieldCircularOrbit.eccentricToTrue(FieldCircularOrbit.meanToEccentric(alphaMUD, exUD, eyUD), exUD, eyUD); + final UnivariateDerivative1 alphavUD = FieldCircularLatitudeArgumentUtility.meanToTrue(exUD, eyUD, alphaMUD); alphaVDot = alphavUD.getDerivative(1); } else { @@ -585,7 +585,7 @@ public double getAlphaVDot() { * @return E + ω eccentric latitude argument (rad) */ public double getAlphaE() { - return trueToEccentric(alphaV, ex, ey); + return CircularLatitudeArgumentUtility.trueToEccentric(ex, ey, alphaV); } /** Get the eccentric latitude argument derivative. @@ -599,7 +599,7 @@ public double getAlphaEDot() { final UnivariateDerivative1 alphaVUD = new UnivariateDerivative1(alphaV, alphaVDot); final UnivariateDerivative1 exUD = new UnivariateDerivative1(ex, exDot); final UnivariateDerivative1 eyUD = new UnivariateDerivative1(ey, eyDot); - final UnivariateDerivative1 alphaEUD = FieldCircularOrbit.trueToEccentric(alphaVUD, exUD, eyUD); + final UnivariateDerivative1 alphaEUD = FieldCircularLatitudeArgumentUtility.trueToEccentric(exUD, eyUD, alphaVUD); return alphaEUD.getDerivative(1); } @@ -607,7 +607,7 @@ public double getAlphaEDot() { * @return M + ω mean latitude argument (rad) */ public double getAlphaM() { - return eccentricToMean(trueToEccentric(alphaV, ex, ey), ex, ey); + return CircularLatitudeArgumentUtility.trueToMean(ex, ey, alphaV); } /** Get the mean latitude argument derivative. @@ -621,7 +621,7 @@ public double getAlphaMDot() { final UnivariateDerivative1 alphaVUD = new UnivariateDerivative1(alphaV, alphaVDot); final UnivariateDerivative1 exUD = new UnivariateDerivative1(ex, exDot); final UnivariateDerivative1 eyUD = new UnivariateDerivative1(ey, eyDot); - final UnivariateDerivative1 alphaMUD = FieldCircularOrbit.eccentricToMean(FieldCircularOrbit.trueToEccentric(alphaVUD, exUD, eyUD), exUD, eyUD); + final UnivariateDerivative1 alphaMUD = FieldCircularLatitudeArgumentUtility.trueToMean(exUD, eyUD, alphaVUD); return alphaMUD.getDerivative(1); } @@ -655,11 +655,9 @@ public double getAlphaDot(final PositionAngleType type) { * @param ey e sin(ω), second component of circular eccentricity vector * @return the true latitude argument. */ + @Deprecated public static double eccentricToTrue(final double alphaE, final double ex, final double ey) { - final double epsilon = FastMath.sqrt(1 - ex * ex - ey * ey); - final SinCos scAlphaE = FastMath.sinCos(alphaE); - return alphaE + 2 * FastMath.atan((ex * scAlphaE.sin() - ey * scAlphaE.cos()) / - (epsilon + 1 - ex * scAlphaE.cos() - ey * scAlphaE.sin())); + return CircularLatitudeArgumentUtility.eccentricToTrue(ex, ey, alphaE); } /** Computes the eccentric latitude argument from the true latitude argument. @@ -668,11 +666,9 @@ public static double eccentricToTrue(final double alphaE, final double ex, final * @param ey e sin(ω), second component of circular eccentricity vector * @return the eccentric latitude argument. */ + @Deprecated public static double trueToEccentric(final double alphaV, final double ex, final double ey) { - final double epsilon = FastMath.sqrt(1 - ex * ex - ey * ey); - final SinCos scAlphaV = FastMath.sinCos(alphaV); - return alphaV + 2 * FastMath.atan((ey * scAlphaV.cos() - ex * scAlphaV.sin()) / - (epsilon + 1 + ex * scAlphaV.cos() + ey * scAlphaV.sin())); + return CircularLatitudeArgumentUtility.trueToEccentric(ex, ey, alphaV); } /** Computes the eccentric latitude argument from the mean latitude argument. @@ -681,31 +677,9 @@ public static double trueToEccentric(final double alphaV, final double ex, final * @param ey e sin(ω), second component of circular eccentricity vector * @return the eccentric latitude argument. */ + @Deprecated public static double meanToEccentric(final double alphaM, final double ex, final double ey) { - // Generalization of Kepler equation to circular parameters - // with alphaE = PA + E and - // alphaM = PA + M = alphaE - ex.sin(alphaE) + ey.cos(alphaE) - double alphaE = alphaM; - double shift = 0.0; - double alphaEMalphaM = 0.0; - SinCos scAlphaE = FastMath.sinCos(alphaE); - int iter = 0; - do { - final double f2 = ex * scAlphaE.sin() - ey * scAlphaE.cos(); - final double f1 = 1.0 - ex * scAlphaE.cos() - ey * scAlphaE.sin(); - final double f0 = alphaEMalphaM - f2; - - final double f12 = 2.0 * f1; - shift = f0 * f12 / (f1 * f12 - f0 * f2); - - alphaEMalphaM -= shift; - alphaE = alphaM + alphaEMalphaM; - scAlphaE = FastMath.sinCos(alphaE); - - } while (++iter < 50 && FastMath.abs(shift) > 1.0e-12); - - return alphaE; - + return CircularLatitudeArgumentUtility.meanToEccentric(ex, ey, alphaM); } /** Computes the mean latitude argument from the eccentric latitude argument. @@ -714,9 +688,9 @@ public static double meanToEccentric(final double alphaM, final double ex, final * @param ey e sin(ω), second component of circular eccentricity vector * @return the mean latitude argument. */ + @Deprecated public static double eccentricToMean(final double alphaE, final double ex, final double ey) { - final SinCos scAlphaE = FastMath.sinCos(alphaE); - return alphaE + (ey * scAlphaE.cos() - ex * scAlphaE.sin()); + return CircularLatitudeArgumentUtility.eccentricToMean(ex, ey, alphaE); } /** {@inheritDoc} */ diff --git a/src/main/java/org/orekit/orbits/EquinoctialLongitudeArgumentUtility.java b/src/main/java/org/orekit/orbits/EquinoctialLongitudeArgumentUtility.java new file mode 100644 index 0000000000..f8f9ee36bb --- /dev/null +++ b/src/main/java/org/orekit/orbits/EquinoctialLongitudeArgumentUtility.java @@ -0,0 +1,175 @@ +/* Copyright 2022-2023 Romain Serra + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.orbits; + +import org.hipparchus.util.FastMath; +import org.hipparchus.util.SinCos; +import org.orekit.errors.OrekitException; +import org.orekit.errors.OrekitMessages; + +/** + * Utility methods for converting between different longitude arguments used by {@link EquinoctialOrbit}. + * @author Romain Serra + * @see EquinoctialOrbit + * @since 12.1 + */ +public class EquinoctialLongitudeArgumentUtility { + + /** Tolerance for stopping criterion in iterative conversion from mean to eccentric angle. */ + private static final double TOLERANCE_CONVERGENCE = 1.0e-12; + + /** Maximum number of iterations in iterative conversion from mean to eccentric angle. */ + private static final int MAXIMUM_ITERATION = 50; + + /** Private constructor for utility class. */ + private EquinoctialLongitudeArgumentUtility() { + // nothing here (utils class) + } + + /** + * Computes the true longitude argument from the eccentric longitude argument. + * + * @param ex e cos(ω), first component of eccentricity vector + * @param ey e sin(ω), second component of eccentricity vector + * @param lE = E + ω + Ω eccentric longitude argument (rad) + * @return the true longitude argument. + */ + public static double eccentricToTrue(final double ex, final double ey, final double lE) { + final double epsilon = eccentricAndTrueEpsilon(ex, ey); + final SinCos scLE = FastMath.sinCos(lE); + final double num = ex * scLE.sin() - ey * scLE.cos(); + final double den = epsilon + 1 - ex * scLE.cos() - ey * scLE.sin(); + return lE + eccentricAndTrueAtan(num, den); + } + + /** + * Computes the eccentric longitude argument from the true longitude argument. + * + * @param ex e cos(ω), first component of eccentricity vector + * @param ey e sin(ω), second component of eccentricity vector + * @param lV = V + ω + Ω true longitude argument (rad) + * @return the eccentric longitude argument. + */ + public static double trueToEccentric(final double ex, final double ey, final double lV) { + final double epsilon = eccentricAndTrueEpsilon(ex, ey); + final SinCos scLv = FastMath.sinCos(lV); + final double num = ey * scLv.cos() - ex * scLv.sin(); + final double den = epsilon + 1 + ex * scLv.cos() + ey * scLv.sin(); + return lV + eccentricAndTrueAtan(num, den); + } + + /** + * Computes an intermediate quantity for conversions between true and eccentric. + * + * @param ex e cos(ω), first component of eccentricity vector + * @param ey e sin(ω), second component of eccentricity vector + * @return intermediate variable referred to as epsilon. + */ + private static double eccentricAndTrueEpsilon(final double ex, final double ey) { + return FastMath.sqrt(1 - ex * ex - ey * ey); + } + + /** + * Computes another intermediate quantity for conversions between true and eccentric. + * + * @param num numerator for angular conversion + * @param den denominator for angular conversion + * @return arc-tangent of ratio of inputs times two. + */ + private static double eccentricAndTrueAtan(final double num, final double den) { + return 2. * FastMath.atan(num / den); + } + + /** + * Computes the eccentric longitude argument from the mean longitude argument. + * + * @param ex e cos(ω), first component of eccentricity vector + * @param ey e sin(ω), second component of eccentricity vector + * @param lM = M + ω + Ω mean longitude argument (rad) + * @return the eccentric longitude argument. + */ + public static double meanToEccentric(final double ex, final double ey, final double lM) { + // Generalization of Kepler equation to equinoctial parameters + // with lE = PA + RAAN + E and + // lM = PA + RAAN + M = lE - ex.sin(lE) + ey.cos(lE) + double lE = lM; + double shift; + double lEmlM = 0.0; + boolean hasConverged; + int iter = 0; + do { + final SinCos scLE = FastMath.sinCos(lE); + final double f2 = ex * scLE.sin() - ey * scLE.cos(); + final double f1 = 1.0 - ex * scLE.cos() - ey * scLE.sin(); + final double f0 = lEmlM - f2; + + final double f12 = 2.0 * f1; + shift = f0 * f12 / (f1 * f12 - f0 * f2); + + lEmlM -= shift; + lE = lM + lEmlM; + + hasConverged = FastMath.abs(shift) <= TOLERANCE_CONVERGENCE; + } while (++iter < MAXIMUM_ITERATION && !hasConverged); + + if (!hasConverged) { + throw new OrekitException(OrekitMessages.UNABLE_TO_COMPUTE_ECCENTRIC_LONGITUDE_ARGUMENT, iter); + } + return lE; + + } + + /** + * Computes the mean longitude argument from the eccentric longitude argument. + * + * @param ex e cos(ω), first component of eccentricity vector + * @param ey e sin(ω), second component of eccentricity vector + * @param lE = E + ω + Ω mean longitude argument (rad) + * @return the mean longitude argument. + */ + public static double eccentricToMean(final double ex, final double ey, final double lE) { + final SinCos scLE = FastMath.sinCos(lE); + return lE - ex * scLE.sin() + ey * scLE.cos(); + } + + /** + * Computes the mean longitude argument from the eccentric longitude argument. + * + * @param ex e cos(ω), first component of eccentricity vector + * @param ey e sin(ω), second component of eccentricity vector + * @param lV = V + ω + Ω true longitude argument (rad) + * @return the mean longitude argument. + */ + public static double trueToMean(final double ex, final double ey, final double lV) { + final double alphaE = trueToEccentric(ex, ey, lV); + return eccentricToMean(ex, ey, alphaE); + } + + /** + * Computes the true longitude argument from the eccentric longitude argument. + * + * @param ex e cos(ω), first component of eccentricity vector + * @param ey e sin(ω), second component of eccentricity vector + * @param lM = M + ω + Ω mean longitude argument (rad) + * @return the true longitude argument. + */ + public static double meanToTrue(final double ex, final double ey, final double lM) { + final double alphaE = meanToEccentric(ex, ey, lM); + return eccentricToTrue(ex, ey, alphaE); + } + +} diff --git a/src/main/java/org/orekit/orbits/EquinoctialOrbit.java b/src/main/java/org/orekit/orbits/EquinoctialOrbit.java index e69fc170bf..5dc8306562 100644 --- a/src/main/java/org/orekit/orbits/EquinoctialOrbit.java +++ b/src/main/java/org/orekit/orbits/EquinoctialOrbit.java @@ -192,10 +192,10 @@ public EquinoctialOrbit(final double a, final double ex, final double ey, final UnivariateDerivative1 lvUD; switch (type) { case MEAN : - lvUD = FieldEquinoctialOrbit.eccentricToTrue(FieldEquinoctialOrbit.meanToEccentric(lUD, exUD, eyUD), exUD, eyUD); + lvUD = FieldEquinoctialLongitudeArgumentUtility.meanToTrue(exUD, eyUD, lUD); break; case ECCENTRIC : - lvUD = FieldEquinoctialOrbit.eccentricToTrue(lUD, exUD, eyUD); + lvUD = FieldEquinoctialLongitudeArgumentUtility.eccentricToTrue(exUD, eyUD, lUD); break; case TRUE : lvUD = lUD; @@ -208,10 +208,10 @@ public EquinoctialOrbit(final double a, final double ex, final double ey, } else { switch (type) { case MEAN : - this.lv = eccentricToTrue(meanToEccentric(l, ex, ey), ex, ey); + this.lv = EquinoctialLongitudeArgumentUtility.meanToTrue(ex, ey, l); break; case ECCENTRIC : - this.lv = eccentricToTrue(l, ex, ey); + this.lv = EquinoctialLongitudeArgumentUtility.eccentricToTrue(ex, ey, l); break; case TRUE : this.lv = l; @@ -308,7 +308,7 @@ public EquinoctialOrbit(final TimeStampedPVCoordinates pvCoordinates, final UnivariateDerivative1 exUD = new UnivariateDerivative1(ex, exDot); final UnivariateDerivative1 eyUD = new UnivariateDerivative1(ey, eyDot); final UnivariateDerivative1 lMUD = new UnivariateDerivative1(getLM(), lMDot); - final UnivariateDerivative1 lvUD = FieldEquinoctialOrbit.eccentricToTrue(FieldEquinoctialOrbit.meanToEccentric(lMUD, exUD, eyUD), exUD, eyUD); + final UnivariateDerivative1 lvUD = FieldEquinoctialLongitudeArgumentUtility.meanToTrue(exUD, eyUD, lMUD); lvDot = lvUD.getDerivative(1); } else { @@ -433,7 +433,7 @@ public double getLvDot() { /** {@inheritDoc} */ public double getLE() { - return trueToEccentric(lv, ex, ey); + return EquinoctialLongitudeArgumentUtility.trueToEccentric(ex, ey, lv); } /** {@inheritDoc} */ @@ -441,13 +441,13 @@ public double getLEDot() { final UnivariateDerivative1 lVUD = new UnivariateDerivative1(lv, lvDot); final UnivariateDerivative1 exUD = new UnivariateDerivative1(ex, exDot); final UnivariateDerivative1 eyUD = new UnivariateDerivative1(ey, eyDot); - final UnivariateDerivative1 lEUD = FieldEquinoctialOrbit.trueToEccentric(lVUD, exUD, eyUD); + final UnivariateDerivative1 lEUD = FieldEquinoctialLongitudeArgumentUtility.trueToEccentric(exUD, eyUD, lVUD); return lEUD.getDerivative(1); } /** {@inheritDoc} */ public double getLM() { - return eccentricToMean(trueToEccentric(lv, ex, ey), ex, ey); + return EquinoctialLongitudeArgumentUtility.trueToMean(ex, ey, lv); } /** {@inheritDoc} */ @@ -455,7 +455,7 @@ public double getLMDot() { final UnivariateDerivative1 lVUD = new UnivariateDerivative1(lv, lvDot); final UnivariateDerivative1 exUD = new UnivariateDerivative1(ex, exDot); final UnivariateDerivative1 eyUD = new UnivariateDerivative1(ey, eyDot); - final UnivariateDerivative1 lMUD = FieldEquinoctialOrbit.eccentricToMean(FieldEquinoctialOrbit.trueToEccentric(lVUD, exUD, eyUD), exUD, eyUD); + final UnivariateDerivative1 lMUD = FieldEquinoctialLongitudeArgumentUtility.trueToMean(exUD, eyUD, lVUD); return lMUD.getDerivative(1); } @@ -485,12 +485,9 @@ public double getLDot(final PositionAngleType type) { * @param ey second component of the eccentricity vector * @return the true longitude argument */ + @Deprecated public static double eccentricToTrue(final double lE, final double ex, final double ey) { - final double epsilon = FastMath.sqrt(1 - ex * ex - ey * ey); - final SinCos scLE = FastMath.sinCos(lE); - final double num = ex * scLE.sin() - ey * scLE.cos(); - final double den = epsilon + 1 - ex * scLE.cos() - ey * scLE.sin(); - return lE + 2 * FastMath.atan(num / den); + return EquinoctialLongitudeArgumentUtility.eccentricToTrue(ex, ey, lE); } /** Computes the eccentric longitude argument from the true longitude argument. @@ -499,12 +496,9 @@ public static double eccentricToTrue(final double lE, final double ex, final dou * @param ey second component of the eccentricity vector * @return the eccentric longitude argument */ + @Deprecated public static double trueToEccentric(final double lv, final double ex, final double ey) { - final double epsilon = FastMath.sqrt(1 - ex * ex - ey * ey); - final SinCos scLv = FastMath.sinCos(lv); - final double num = ey * scLv.cos() - ex * scLv.sin(); - final double den = epsilon + 1 + ex * scLv.cos() + ey * scLv.sin(); - return lv + 2 * FastMath.atan(num / den); + return EquinoctialLongitudeArgumentUtility.trueToEccentric(ex, ey, lv); } /** Computes the eccentric longitude argument from the mean longitude argument. @@ -513,31 +507,9 @@ public static double trueToEccentric(final double lv, final double ex, final dou * @param ey second component of the eccentricity vector * @return the eccentric longitude argument */ + @Deprecated public static double meanToEccentric(final double lM, final double ex, final double ey) { - // Generalization of Kepler equation to equinoctial parameters - // with lE = PA + RAAN + E and - // lM = PA + RAAN + M = lE - ex.sin(lE) + ey.cos(lE) - double lE = lM; - double shift = 0.0; - double lEmlM = 0.0; - SinCos scLE = FastMath.sinCos(lE); - int iter = 0; - do { - final double f2 = ex * scLE.sin() - ey * scLE.cos(); - final double f1 = 1.0 - ex * scLE.cos() - ey * scLE.sin(); - final double f0 = lEmlM - f2; - - final double f12 = 2.0 * f1; - shift = f0 * f12 / (f1 * f12 - f0 * f2); - - lEmlM -= shift; - lE = lM + lEmlM; - scLE = FastMath.sinCos(lE); - - } while (++iter < 50 && FastMath.abs(shift) > 1.0e-12); - - return lE; - + return EquinoctialLongitudeArgumentUtility.meanToEccentric(ex, ey, lM); } /** Computes the mean longitude argument from the eccentric longitude argument. @@ -546,9 +518,9 @@ public static double meanToEccentric(final double lM, final double ex, final dou * @param ey second component of the eccentricity vector * @return the mean longitude argument */ + @Deprecated public static double eccentricToMean(final double lE, final double ex, final double ey) { - final SinCos scLE = FastMath.sinCos(lE); - return lE - ex * scLE.sin() + ey * scLE.cos(); + return EquinoctialLongitudeArgumentUtility.eccentricToMean(ex, ey, lE); } /** {@inheritDoc} */ diff --git a/src/main/java/org/orekit/orbits/FieldCircularLatitudeArgumentUtility.java b/src/main/java/org/orekit/orbits/FieldCircularLatitudeArgumentUtility.java new file mode 100644 index 0000000000..4fa0731c4a --- /dev/null +++ b/src/main/java/org/orekit/orbits/FieldCircularLatitudeArgumentUtility.java @@ -0,0 +1,189 @@ +/* Copyright 2022-2023 Romain Serra + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.orbits; + +import org.hipparchus.CalculusFieldElement; +import org.hipparchus.util.FastMath; +import org.hipparchus.util.FieldSinCos; +import org.orekit.errors.OrekitException; +import org.orekit.errors.OrekitMessages; + +/** + * Utility methods for converting between different latitude arguments used by {@link FieldCircularOrbit}. + * @author Romain Serra + * @see FieldCircularOrbit + * @since 12.1 + */ +public class FieldCircularLatitudeArgumentUtility { + + /** Tolerance for stopping criterion in iterative conversion from mean to eccentric angle. */ + private static final double TOLERANCE_CONVERGENCE = 1.0e-12; + + /** Maximum number of iterations in iterative conversion from mean to eccentric angle. */ + private static final int MAXIMUM_ITERATION = 50; + + /** Private constructor for utility class. */ + private FieldCircularLatitudeArgumentUtility() { + // nothing here (utils class) + } + + /** + * Computes the true latitude argument from the eccentric latitude argument. + * + * @param Type of the field elements + * @param ex e cos(ω), first component of circular eccentricity vector + * @param ey e sin(ω), second component of circular eccentricity vector + * @param alphaE = E + ω eccentric latitude argument (rad) + * @return the true latitude argument. + */ + public static > T eccentricToTrue(final T ex, final T ey, final T alphaE) { + final T epsilon = eccentricAndTrueEpsilon(ex, ey); + final FieldSinCos scAlphaE = FastMath.sinCos(alphaE); + final T cosAlphaE = scAlphaE.cos(); + final T sinAlphaE = scAlphaE.sin(); + final T num = ex.multiply(sinAlphaE).subtract(ey.multiply(cosAlphaE)); + final T den = epsilon.add(1).subtract(ex.multiply(cosAlphaE)).subtract(ey.multiply(sinAlphaE)); + return alphaE.add(eccentricAndTrueAtan(num, den)); + } + + /** + * Computes the eccentric latitude argument from the true latitude argument. + * + * @param Type of the field elements + * @param ex e cos(ω), first component of circular eccentricity vector + * @param ey e sin(ω), second component of circular eccentricity vector + * @param alphaV = v + ω true latitude argument (rad) + * @return the eccentric latitude argument. + */ + public static > T trueToEccentric(final T ex, final T ey, final T alphaV) { + final T epsilon = eccentricAndTrueEpsilon(ex, ey); + final FieldSinCos scAlphaV = FastMath.sinCos(alphaV); + final T cosAlphaV = scAlphaV.cos(); + final T sinAlphaV = scAlphaV.sin(); + final T num = ey.multiply(cosAlphaV).subtract(ex.multiply(sinAlphaV)); + final T den = epsilon.add(1).add(ex.multiply(cosAlphaV).add(ey.multiply(sinAlphaV))); + return alphaV.add(eccentricAndTrueAtan(num, den)); + } + + /** + * Computes an intermediate quantity for conversions between true and eccentric. + * + * @param Type of the field elements + * @param ex e cos(ω), first component of circular eccentricity vector + * @param ey e sin(ω), second component of circular eccentricity vector + * @return intermediate variable referred to as epsilon. + */ + private static > T eccentricAndTrueEpsilon(final T ex, final T ey) { + return (ex.multiply(ex).negate().subtract(ey.multiply(ey)).add(1.)).sqrt(); + } + + /** + * Computes another intermediate quantity for conversions between true and eccentric. + * + * @param Type of the field elements + * @param num numerator for angular conversion + * @param den denominator for angular conversion + * @return arc-tangent of ratio of inputs times two. + */ + private static > T eccentricAndTrueAtan(final T num, final T den) { + return (num.divide(den)).atan().multiply(2); + } + + /** + * Computes the eccentric latitude argument from the mean latitude argument. + * + * @param Type of the field elements + * @param ex e cos(ω), first component of circular eccentricity vector + * @param ey e sin(ω), second component of circular eccentricity vector + * @param alphaM = M + ω mean latitude argument (rad) + * @return the eccentric latitude argument. + */ + public static > T meanToEccentric(final T ex, final T ey, final T alphaM) { + // Generalization of Kepler equation to circular parameters + // with alphaE = PA + E and + // alphaM = PA + M = alphaE - ex.sin(alphaE) + ey.cos(alphaE) + + T alphaE = alphaM; + T shift; + T alphaEMalphaM = alphaM.getField().getZero(); + boolean hasConverged; + int iter = 0; + do { + final FieldSinCos scAlphaE = FastMath.sinCos(alphaE); + final T f2 = ex.multiply(scAlphaE.sin()).subtract(ey.multiply(scAlphaE.cos())); + final T f1 = ex.negate().multiply(scAlphaE.cos()).subtract(ey.multiply(scAlphaE.sin())).add(1); + final T f0 = alphaEMalphaM.subtract(f2); + + final T f12 = f1.multiply(2); + shift = f0.multiply(f12).divide(f1.multiply(f12).subtract(f0.multiply(f2))); + + alphaEMalphaM = alphaEMalphaM.subtract(shift); + alphaE = alphaM.add(alphaEMalphaM); + + hasConverged = FastMath.abs(shift.getReal()) <= TOLERANCE_CONVERGENCE; + } while (++iter < MAXIMUM_ITERATION && !hasConverged); + + if (!hasConverged) { + throw new OrekitException(OrekitMessages.UNABLE_TO_COMPUTE_ECCENTRIC_LATITUDE_ARGUMENT, iter); + } + return alphaE; + + } + + /** + * Computes the mean latitude argument from the eccentric latitude argument. + * + * @param Type of the field elements + * @param ex e cos(ω), first component of circular eccentricity vector + * @param ey e sin(ω), second component of circular eccentricity vector + * @param alphaE = E + ω eccentric latitude argument (rad) + * @return the mean latitude argument. + */ + public static > T eccentricToMean(final T ex, final T ey, final T alphaE) { + final FieldSinCos scAlphaE = FastMath.sinCos(alphaE); + return alphaE.subtract(ex.multiply(scAlphaE.sin()).subtract(ey.multiply(scAlphaE.cos()))); + } + + /** + * Computes the mean latitude argument from the eccentric latitude argument. + * + * @param Type of the field elements + * @param ex e cos(ω), first component of circular eccentricity vector + * @param ey e sin(ω), second component of circular eccentricity vector + * @param alphaV = V + ω true latitude argument (rad) + * @return the mean latitude argument. + */ + public static > T trueToMean(final T ex, final T ey, final T alphaV) { + final T alphaE = trueToEccentric(ex, ey, alphaV); + return eccentricToMean(ex, ey, alphaE); + } + + /** + * Computes the true latitude argument from the eccentric latitude argument. + * + * @param Type of the field elements + * @param ex e cos(ω), first component of circular eccentricity vector + * @param ey e sin(ω), second component of circular eccentricity vector + * @param alphaM = M + ω mean latitude argument (rad) + * @return the true latitude argument. + */ + public static > T meanToTrue(final T ex, final T ey, final T alphaM) { + final T alphaE = meanToEccentric(ex, ey, alphaM); + return eccentricToTrue(ex, ey, alphaE); + } + +} diff --git a/src/main/java/org/orekit/orbits/FieldCircularOrbit.java b/src/main/java/org/orekit/orbits/FieldCircularOrbit.java index cc81382f79..26e51fbde8 100644 --- a/src/main/java/org/orekit/orbits/FieldCircularOrbit.java +++ b/src/main/java/org/orekit/orbits/FieldCircularOrbit.java @@ -190,10 +190,10 @@ public FieldCircularOrbit(final T a, final T ex, final T ey, final FieldUnivariateDerivative1 alphavUD; switch (type) { case MEAN : - alphavUD = eccentricToTrue(meanToEccentric(alphaUD, exUD, eyUD), exUD, eyUD); + alphavUD = FieldCircularLatitudeArgumentUtility.meanToTrue(exUD, eyUD, alphaUD); break; case ECCENTRIC : - alphavUD = eccentricToTrue(alphaUD, exUD, eyUD); + alphavUD = FieldCircularLatitudeArgumentUtility.eccentricToTrue(exUD, eyUD, alphaUD); break; case TRUE : alphavUD = alphaUD; @@ -206,10 +206,10 @@ public FieldCircularOrbit(final T a, final T ex, final T ey, } else { switch (type) { case MEAN : - this.alphaV = eccentricToTrue(meanToEccentric(alpha, ex, ey), ex, ey); + this.alphaV = FieldCircularLatitudeArgumentUtility.meanToTrue(ex, ey, alpha); break; case ECCENTRIC : - this.alphaV = eccentricToTrue(alpha, ex, ey); + this.alphaV = FieldCircularLatitudeArgumentUtility.eccentricToTrue(ex, ey, alpha); break; case TRUE : this.alphaV = alpha; @@ -290,8 +290,8 @@ public FieldCircularOrbit(final TimeStampedFieldPVCoordinates pvCoordinates, // compute latitude argument final T beta = (ex.multiply(ex).add(ey.multiply(ey)).negate().add(1)).sqrt().add(1).reciprocal(); - alphaV = eccentricToTrue(y2.add(ey).add(eSE.multiply(beta).multiply(ex)).atan2(x2.add(ex).subtract(eSE.multiply(beta).multiply(ey))), - ex, ey); + alphaV = FieldCircularLatitudeArgumentUtility.eccentricToTrue(ex, ey, y2.add(ey).add(eSE.multiply(beta).multiply(ex)).atan2(x2.add(ex).subtract(eSE.multiply(beta).multiply(ey))) + ); partialPV = pvCoordinates; @@ -319,7 +319,7 @@ public FieldCircularOrbit(final TimeStampedFieldPVCoordinates pvCoordinates, final FieldUnivariateDerivative1 exUD = new FieldUnivariateDerivative1<>(ex, exDot); final FieldUnivariateDerivative1 eyUD = new FieldUnivariateDerivative1<>(ey, eyDot); final FieldUnivariateDerivative1 alphaMUD = new FieldUnivariateDerivative1<>(getAlphaM(), alphaMDot); - final FieldUnivariateDerivative1 alphavUD = eccentricToTrue(meanToEccentric(alphaMUD, exUD, eyUD), exUD, eyUD); + final FieldUnivariateDerivative1 alphavUD = FieldCircularLatitudeArgumentUtility.meanToTrue(exUD, eyUD, alphaMUD); alphaVDot = alphavUD.getDerivative(1); } else { @@ -629,7 +629,7 @@ public T getAlphaEDot() { * @return M + ω mean latitude argument (rad) */ public T getAlphaM() { - return eccentricToMean(trueToEccentric(alphaV, ex, ey), ex, ey); + return FieldCircularLatitudeArgumentUtility.trueToMean(ex, ey, alphaV); } /** Get the mean latitude argument derivative. @@ -644,7 +644,8 @@ public T getAlphaMDot() { final FieldUnivariateDerivative1 alphaVUD = new FieldUnivariateDerivative1<>(alphaV, alphaVDot); final FieldUnivariateDerivative1 exUD = new FieldUnivariateDerivative1<>(ex, exDot); final FieldUnivariateDerivative1 eyUD = new FieldUnivariateDerivative1<>(ey, eyDot); - final FieldUnivariateDerivative1 alphaMUD = eccentricToMean(trueToEccentric(alphaVUD, exUD, eyUD), exUD, eyUD); + final FieldUnivariateDerivative1 alphaMUD = FieldCircularLatitudeArgumentUtility.trueToMean(exUD, eyUD, alphaVUD + ); return alphaMUD.getDerivative(1); } @@ -676,12 +677,9 @@ public T getAlphaDot(final PositionAngleType type) { * @param Type of the field elements * @return the true latitude argument. */ + @Deprecated public static > T eccentricToTrue(final T alphaE, final T ex, final T ey) { - final T epsilon = ex.multiply(ex).add(ey.multiply(ey)).negate().add(1).sqrt(); - final FieldSinCos scAlphaE = FastMath.sinCos(alphaE); - return alphaE.add(ex.multiply(scAlphaE.sin()).subtract(ey.multiply(scAlphaE.cos())).divide( - epsilon.add(1).subtract(ex.multiply(scAlphaE.cos())).subtract( - ey.multiply(scAlphaE.sin()))).atan().multiply(2)); + return FieldCircularLatitudeArgumentUtility.eccentricToTrue(ex, ey, alphaE); } /** Computes the eccentric latitude argument from the true latitude argument. @@ -691,11 +689,9 @@ public static > T eccentricToTrue(final T alph * @param Type of the field elements * @return the eccentric latitude argument. */ + @Deprecated public static > T trueToEccentric(final T alphaV, final T ex, final T ey) { - final T epsilon = ex.multiply(ex).add(ey.multiply(ey)).negate().add(1).sqrt(); - final FieldSinCos scAlphaV = FastMath.sinCos(alphaV); - return alphaV.add(ey.multiply(scAlphaV.cos()).subtract(ex.multiply(scAlphaV.sin())).divide - (epsilon.add(1).add(ex.multiply(scAlphaV.cos()).add(ey.multiply(scAlphaV.sin())))).atan().multiply(2)); + return FieldCircularLatitudeArgumentUtility.trueToEccentric(ex, ey, alphaV); } /** Computes the eccentric latitude argument from the mean latitude argument. @@ -705,30 +701,9 @@ public static > T trueToEccentric(final T alph * @param Type of the field elements * @return the eccentric latitude argument. */ + @Deprecated public static > T meanToEccentric(final T alphaM, final T ex, final T ey) { - // Generalization of Kepler equation to circular parameters - // with alphaE = PA + E and - // alphaM = PA + M = alphaE - ex.sin(alphaE) + ey.cos(alphaE) - - T alphaE = alphaM; - T shift = alphaM.getField().getZero(); - T alphaEMalphaM = alphaM.getField().getZero(); - FieldSinCos scAlphaE = FastMath.sinCos(alphaE); - int iter = 0; - do { - final T f2 = ex.multiply(scAlphaE.sin()).subtract(ey.multiply(scAlphaE.cos())); - final T f1 = ex.negate().multiply(scAlphaE.cos()).subtract(ey.multiply(scAlphaE.sin())).add(1); - final T f0 = alphaEMalphaM.subtract(f2); - - final T f12 = f1.multiply(2); - shift = f0.multiply(f12).divide(f1.multiply(f12).subtract(f0.multiply(f2))); - - alphaEMalphaM = alphaEMalphaM.subtract(shift); - alphaE = alphaM.add(alphaEMalphaM); - scAlphaE = FastMath.sinCos(alphaE); - } while (++iter < 50 && FastMath.abs(shift.getReal()) > 1.0e-12); - return alphaE; - + return FieldCircularLatitudeArgumentUtility.meanToEccentric(ex, ey, alphaM); } /** Computes the mean latitude argument from the eccentric latitude argument. @@ -738,9 +713,9 @@ public static > T meanToEccentric(final T alph * @param Type of the field elements * @return the mean latitude argument. */ + @Deprecated public static > T eccentricToMean(final T alphaE, final T ex, final T ey) { - final FieldSinCos scAlphaE = FastMath.sinCos(alphaE); - return alphaE.subtract(ex.multiply(scAlphaE.sin()).subtract(ey.multiply(scAlphaE.cos()))); + return FieldCircularLatitudeArgumentUtility.eccentricToMean(ex, ey, alphaE); } /** {@inheritDoc} */ diff --git a/src/main/java/org/orekit/orbits/FieldEquinoctialLongitudeArgumentUtility.java b/src/main/java/org/orekit/orbits/FieldEquinoctialLongitudeArgumentUtility.java new file mode 100644 index 0000000000..11c96513c6 --- /dev/null +++ b/src/main/java/org/orekit/orbits/FieldEquinoctialLongitudeArgumentUtility.java @@ -0,0 +1,188 @@ +/* Copyright 2022-2023 Romain Serra + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.orbits; + +import org.hipparchus.CalculusFieldElement; +import org.hipparchus.util.FastMath; +import org.hipparchus.util.FieldSinCos; +import org.orekit.errors.OrekitException; +import org.orekit.errors.OrekitMessages; + +/** + * Utility methods for converting between different longitude arguments used by {@link FieldEquinoctialOrbit}. + * @author Romain Serra + * @see FieldEquinoctialOrbit + * @since 12.1 + */ +public class FieldEquinoctialLongitudeArgumentUtility { + + /** Tolerance for stopping criterion in iterative conversion from mean to eccentric angle. */ + private static final double TOLERANCE_CONVERGENCE = 1.0e-12; + + /** Maximum number of iterations in iterative conversion from mean to eccentric angle. */ + private static final int MAXIMUM_ITERATION = 50; + + /** Private constructor for utility class. */ + private FieldEquinoctialLongitudeArgumentUtility() { + // nothing here (utils class) + } + + /** + * Computes the true longitude argument from the eccentric longitude argument. + * + * @param Type of the field elements + * @param ex e cos(ω), first component of eccentricity vector + * @param ey e sin(ω), second component of eccentricity vector + * @param lE = E + ω + Ω eccentric longitude argument (rad) + * @return the true longitude argument. + */ + public static > T eccentricToTrue(final T ex, final T ey, final T lE) { + final T epsilon = eccentricAndTrueEpsilon(ex, ey); + final FieldSinCos scLE = FastMath.sinCos(lE); + final T cosLE = scLE.cos(); + final T sinLE = scLE.sin(); + final T num = ex.multiply(sinLE).subtract(ey.multiply(cosLE)); + final T den = epsilon.add(1).subtract(ex.multiply(cosLE)).subtract(ey.multiply(sinLE)); + return lE.add(eccentricAndTrueAtan(num, den)); + } + + /** + * Computes the eccentric longitude argument from the true longitude argument. + * + * @param Type of the field elements + * @param ex e cos(ω), first component of eccentricity vector + * @param ey e sin(ω), second component of eccentricity vector + * @param lV = V + ω + Ω true longitude argument (rad) + * @return the eccentric longitude argument. + */ + public static > T trueToEccentric(final T ex, final T ey, final T lV) { + final T epsilon = eccentricAndTrueEpsilon(ex, ey); + final FieldSinCos scLv = FastMath.sinCos(lV); + final T cosLv = scLv.cos(); + final T sinLv = scLv.sin(); + final T num = ey.multiply(cosLv).subtract(ex.multiply(sinLv)); + final T den = epsilon.add(1).add(ex.multiply(cosLv)).add(ey.multiply(sinLv)); + return lV.add(eccentricAndTrueAtan(num, den)); + } + + /** + * Computes an intermediate quantity for conversions between true and eccentric. + * + * @param Type of the field elements + * @param ex e cos(ω), first component of eccentricity vector + * @param ey e sin(ω), second component of eccentricity vector + * @return intermediate variable referred to as epsilon. + */ + private static > T eccentricAndTrueEpsilon(final T ex, final T ey) { + return (ex.multiply(ex).negate().subtract(ey.multiply(ey)).add(1.)).sqrt(); + } + + /** + * Computes another intermediate quantity for conversions between true and eccentric. + * + * @param Type of the field elements + * @param num numerator for angular conversion + * @param den denominator for angular conversion + * @return arc-tangent of ratio of inputs times two. + */ + private static > T eccentricAndTrueAtan(final T num, final T den) { + return (num.divide(den)).atan().multiply(2); + } + + /** + * Computes the eccentric longitude argument from the mean longitude argument. + * + * @param Type of the field elements + * @param ex e cos(ω), first component of eccentricity vector + * @param ey e sin(ω), second component of eccentricity vector + * @param lM = M + ω + Ω mean longitude argument (rad) + * @return the eccentric longitude argument. + */ + public static > T meanToEccentric(final T ex, final T ey, final T lM) { + // Generalization of Kepler equation to equinoctial parameters + // with lE = PA + RAAN + E and + // lM = PA + RAAN + M = lE - ex.sin(lE) + ey.cos(lE) + T lE = lM; + T shift; + T lEmlM = lM.getField().getZero(); + boolean hasConverged; + int iter = 0; + do { + final FieldSinCos scLE = FastMath.sinCos(lE); + final T f2 = ex.multiply(scLE.sin()).subtract(ey.multiply(scLE.cos())); + final T f1 = ex.multiply(scLE.cos()).add(ey.multiply(scLE.sin())).negate().add(1); + final T f0 = lEmlM.subtract(f2); + + final T f12 = f1.multiply(2.0); + shift = f0.multiply(f12).divide(f1.multiply(f12).subtract(f0.multiply(f2))); + + lEmlM = lEmlM.subtract(shift); + lE = lM.add(lEmlM); + + hasConverged = FastMath.abs(shift.getReal()) <= TOLERANCE_CONVERGENCE; + } while (++iter < MAXIMUM_ITERATION && !hasConverged); + + if (!hasConverged) { + throw new OrekitException(OrekitMessages.UNABLE_TO_COMPUTE_ECCENTRIC_LONGITUDE_ARGUMENT, iter); + } + return lE; + + } + + /** + * Computes the mean longitude argument from the eccentric longitude argument. + * + * @param Type of the field elements + * @param ex e cos(ω), first component of eccentricity vector + * @param ey e sin(ω), second component of eccentricity vector + * @param lE = E + ω + Ω mean longitude argument (rad) + * @return the mean longitude argument. + */ + public static > T eccentricToMean(final T ex, final T ey, final T lE) { + final FieldSinCos scLE = FastMath.sinCos(lE); + return lE.subtract(ex.multiply(scLE.sin())).add(ey.multiply(scLE.cos())); + } + + /** + * Computes the mean longitude argument from the eccentric longitude argument. + * + * @param Type of the field elements + * @param ex e cos(ω), first component of eccentricity vector + * @param ey e sin(ω), second component of eccentricity vector + * @param lV = V + ω + Ω true longitude argument (rad) + * @return the mean longitude argument. + */ + public static > T trueToMean(final T ex, final T ey, final T lV) { + final T alphaE = trueToEccentric(ex, ey, lV); + return eccentricToMean(ex, ey, alphaE); + } + + /** + * Computes the true longitude argument from the eccentric longitude argument. + * + * @param Type of the field elements + * @param ex e cos(ω), first component of eccentricity vector + * @param ey e sin(ω), second component of eccentricity vector + * @param lM = M + ω + Ω mean longitude argument (rad) + * @return the true longitude argument. + */ + public static > T meanToTrue(final T ex, final T ey, final T lM) { + final T alphaE = meanToEccentric(ex, ey, lM); + return eccentricToTrue(ex, ey, alphaE); + } + +} diff --git a/src/main/java/org/orekit/orbits/FieldEquinoctialOrbit.java b/src/main/java/org/orekit/orbits/FieldEquinoctialOrbit.java index e526fab34d..ca7f6065d8 100644 --- a/src/main/java/org/orekit/orbits/FieldEquinoctialOrbit.java +++ b/src/main/java/org/orekit/orbits/FieldEquinoctialOrbit.java @@ -192,10 +192,10 @@ public FieldEquinoctialOrbit(final T a, final T ex, final T ey, final FieldUnivariateDerivative1 lvUD; switch (type) { case MEAN : - lvUD = eccentricToTrue(meanToEccentric(lUD, exUD, eyUD), exUD, eyUD); + lvUD = FieldEquinoctialLongitudeArgumentUtility.meanToTrue(exUD, eyUD, lUD); break; case ECCENTRIC : - lvUD = eccentricToTrue(lUD, exUD, eyUD); + lvUD = FieldEquinoctialLongitudeArgumentUtility.eccentricToTrue(exUD, eyUD, lUD); break; case TRUE : lvUD = lUD; @@ -208,10 +208,10 @@ public FieldEquinoctialOrbit(final T a, final T ex, final T ey, } else { switch (type) { case MEAN : - this.lv = eccentricToTrue(meanToEccentric(l, ex, ey), ex, ey); + this.lv = FieldEquinoctialLongitudeArgumentUtility.meanToTrue(ex, ey, l); break; case ECCENTRIC : - this.lv = eccentricToTrue(l, ex, ey); + this.lv = FieldEquinoctialLongitudeArgumentUtility.eccentricToTrue(ex, ey, l); break; case TRUE : this.lv = l; @@ -308,7 +308,7 @@ public FieldEquinoctialOrbit(final TimeStampedFieldPVCoordinates pvCoordinate final FieldUnivariateDerivative1 exUD = new FieldUnivariateDerivative1<>(ex, exDot); final FieldUnivariateDerivative1 eyUD = new FieldUnivariateDerivative1<>(ey, eyDot); final FieldUnivariateDerivative1 lMUD = new FieldUnivariateDerivative1<>(getLM(), lMDot); - final FieldUnivariateDerivative1 lvUD = eccentricToTrue(meanToEccentric(lMUD, exUD, eyUD), exUD, eyUD); + final FieldUnivariateDerivative1 lvUD = FieldEquinoctialLongitudeArgumentUtility.meanToTrue(exUD, eyUD, lMUD); lvDot = lvUD.getDerivative(1); } else { @@ -478,7 +478,7 @@ public T getLvDot() { /** {@inheritDoc} */ public T getLE() { - return trueToEccentric(lv, ex, ey); + return FieldEquinoctialLongitudeArgumentUtility.trueToEccentric(ex, ey, lv); } /** {@inheritDoc} */ @@ -491,14 +491,14 @@ public T getLEDot() { final FieldUnivariateDerivative1 lVUD = new FieldUnivariateDerivative1<>(lv, lvDot); final FieldUnivariateDerivative1 exUD = new FieldUnivariateDerivative1<>(ex, exDot); final FieldUnivariateDerivative1 eyUD = new FieldUnivariateDerivative1<>(ey, eyDot); - final FieldUnivariateDerivative1 lEUD = trueToEccentric(lVUD, exUD, eyUD); + final FieldUnivariateDerivative1 lEUD = FieldEquinoctialLongitudeArgumentUtility.trueToEccentric(exUD, eyUD, lVUD); return lEUD.getDerivative(1); } /** {@inheritDoc} */ public T getLM() { - return eccentricToMean(trueToEccentric(lv, ex, ey), ex, ey); + return FieldEquinoctialLongitudeArgumentUtility.trueToMean(ex, ey, lv); } /** {@inheritDoc} */ @@ -511,7 +511,7 @@ public T getLMDot() { final FieldUnivariateDerivative1 lVUD = new FieldUnivariateDerivative1<>(lv, lvDot); final FieldUnivariateDerivative1 exUD = new FieldUnivariateDerivative1<>(ex, exDot); final FieldUnivariateDerivative1 eyUD = new FieldUnivariateDerivative1<>(ey, eyDot); - final FieldUnivariateDerivative1 lMUD = eccentricToMean(trueToEccentric(lVUD, exUD, eyUD), exUD, eyUD); + final FieldUnivariateDerivative1 lMUD = FieldEquinoctialLongitudeArgumentUtility.trueToMean(exUD, eyUD, lVUD); return lMUD.getDerivative(1); } @@ -549,14 +549,9 @@ public boolean hasDerivatives() { * @param Type of the field elements * @return the true longitude argument */ + @Deprecated public static > T eccentricToTrue(final T lE, final T ex, final T ey) { - final T epsilon = ex.multiply(ex).add(ey.multiply(ey)).negate().add(1).sqrt(); - final FieldSinCos scLE = FastMath.sinCos(lE); - final T cosLE = scLE.cos(); - final T sinLE = scLE.sin(); - final T num = ex.multiply(sinLE).subtract(ey.multiply(cosLE)); - final T den = epsilon.add(1).subtract(ex.multiply(cosLE)).subtract(ey.multiply(sinLE)); - return lE.add(num.divide(den).atan().multiply(2)); + return FieldEquinoctialLongitudeArgumentUtility.eccentricToTrue(ex, ey, lE); } /** Computes the eccentric longitude argument from the true longitude argument. @@ -566,14 +561,9 @@ public static > T eccentricToTrue(final T lE, * @param Type of the field elements * @return the eccentric longitude argument */ + @Deprecated public static > T trueToEccentric(final T lv, final T ex, final T ey) { - final T epsilon = ex.multiply(ex).add(ey.multiply(ey)).negate().add(1).sqrt(); - final FieldSinCos scLv = FastMath.sinCos(lv); - final T cosLv = scLv.cos(); - final T sinLv = scLv.sin(); - final T num = ey.multiply(cosLv).subtract(ex.multiply(sinLv)); - final T den = epsilon.add(1).add(ex.multiply(cosLv)).add(ey.multiply(sinLv)); - return lv.add(num.divide(den).atan().multiply(2)); + return FieldEquinoctialLongitudeArgumentUtility.trueToEccentric(ex, ey, lv); } /** Computes the eccentric longitude argument from the mean longitude argument. @@ -583,31 +573,9 @@ public static > T trueToEccentric(final T lv, * @param Type of the field elements * @return the eccentric longitude argument */ + @Deprecated public static > T meanToEccentric(final T lM, final T ex, final T ey) { - // Generalization of Kepler equation to equinoctial parameters - // with lE = PA + RAAN + E and - // lM = PA + RAAN + M = lE - ex.sin(lE) + ey.cos(lE) - T lE = lM; - T shift = lM.getField().getZero(); - T lEmlM = lM.getField().getZero(); - FieldSinCos scLE = FastMath.sinCos(lE); - int iter = 0; - do { - final T f2 = ex.multiply(scLE.sin()).subtract(ey.multiply(scLE.cos())); - final T f1 = ex.multiply(scLE.cos()).add(ey.multiply(scLE.sin())).negate().add(1); - final T f0 = lEmlM.subtract(f2); - - final T f12 = f1.multiply(2.0); - shift = f0.multiply(f12).divide(f1.multiply(f12).subtract(f0.multiply(f2))); - - lEmlM = lEmlM.subtract(shift); - lE = lM.add(lEmlM); - scLE = FastMath.sinCos(lE); - - } while (++iter < 50 && FastMath.abs(shift.getReal()) > 1.0e-12); - - return lE; - + return FieldEquinoctialLongitudeArgumentUtility.meanToEccentric(ex, ey, lM); } /** Computes the mean longitude argument from the eccentric longitude argument. @@ -617,9 +585,9 @@ public static > T meanToEccentric(final T lM, * @param Type of the field elements * @return the mean longitude argument */ + @Deprecated public static > T eccentricToMean(final T lE, final T ex, final T ey) { - final FieldSinCos scLE = FastMath.sinCos(lE); - return lE.subtract(ex.multiply(scLE.sin())).add(ey.multiply(scLE.cos())); + return FieldEquinoctialLongitudeArgumentUtility.eccentricToMean(ex, ey, lE); } /** {@inheritDoc} */ diff --git a/src/main/java/org/orekit/orbits/FieldKeplerianAnomalyUtility.java b/src/main/java/org/orekit/orbits/FieldKeplerianAnomalyUtility.java index 9f04bdf30b..5e2bace3dc 100644 --- a/src/main/java/org/orekit/orbits/FieldKeplerianAnomalyUtility.java +++ b/src/main/java/org/orekit/orbits/FieldKeplerianAnomalyUtility.java @@ -201,7 +201,7 @@ private static > T eMeSinE(final T e, final T // the inequality test below IS intentional and should NOT be replaced by a // check with a small tolerance for (T x0 = E.getField().getZero().add(Double.NaN); !Double.valueOf(x.getReal()) - .equals(Double.valueOf(x0.getReal()));) { + .equals(x0.getReal());) { d += 2; term = term.multiply(mE2.divide(d * (d + 1))); x0 = x; diff --git a/src/main/java/org/orekit/orbits/KeplerianAnomalyUtility.java b/src/main/java/org/orekit/orbits/KeplerianAnomalyUtility.java index 8ffa0a6d2d..935bf9cec4 100644 --- a/src/main/java/org/orekit/orbits/KeplerianAnomalyUtility.java +++ b/src/main/java/org/orekit/orbits/KeplerianAnomalyUtility.java @@ -176,7 +176,7 @@ private static double eMeSinE(final double e, final double E) { double d = 0; // the inequality test below IS intentional and should NOT be replaced by a // check with a small tolerance - for (double x0 = Double.NaN; !Double.valueOf(x).equals(Double.valueOf(x0));) { + for (double x0 = Double.NaN; !Double.valueOf(x).equals(x0);) { d += 2; term *= mE2 / (d * (d + 1)); x0 = x; diff --git a/src/main/resources/assets/org/orekit/localization/OrekitMessages_ca.utf8 b/src/main/resources/assets/org/orekit/localization/OrekitMessages_ca.utf8 index 70932e2930..83c0e49dcb 100644 --- a/src/main/resources/assets/org/orekit/localization/OrekitMessages_ca.utf8 +++ b/src/main/resources/assets/org/orekit/localization/OrekitMessages_ca.utf8 @@ -454,6 +454,12 @@ UNABLE_TO_GENERATE_NEW_DATA_AFTER = no es poden generar noves dades després de # unable to compute hyperbolic eccentric anomaly from the mean anomaly after {0} iterations UNABLE_TO_COMPUTE_HYPERBOLIC_ECCENTRIC_ANOMALY = després de {0} iteracins no s''ha aconseguit calcular l''anomalia excèntrica hiperbòlica a partir de l''anomalia mitjana +# unable to compute eccentric longitude argument from the mean one after {0} iterations +UNABLE_TO_COMPUTE_ECCENTRIC_LONGITUDE_ARGUMENT = + +# unable to compute eccentric latitude argument from the mean one after {0} iterations +UNABLE_TO_COMPUTE_ECCENTRIC_LATITUDE_ARGUMENT = + # unable to compute mean orbit from osculating orbit after {0} iterations UNABLE_TO_COMPUTE_DSST_MEAN_PARAMETERS = no es pot calcular l''òrbita mitjana a partir de l''òrbita osculating al cap de {0} iteracions diff --git a/src/main/resources/assets/org/orekit/localization/OrekitMessages_da.utf8 b/src/main/resources/assets/org/orekit/localization/OrekitMessages_da.utf8 index f4073f88c3..29c1ea34b6 100644 --- a/src/main/resources/assets/org/orekit/localization/OrekitMessages_da.utf8 +++ b/src/main/resources/assets/org/orekit/localization/OrekitMessages_da.utf8 @@ -454,6 +454,12 @@ UNABLE_TO_GENERATE_NEW_DATA_AFTER = # unable to compute hyperbolic eccentric anomaly from the mean anomaly after {0} iterations UNABLE_TO_COMPUTE_HYPERBOLIC_ECCENTRIC_ANOMALY = kan ikke beregne hyperbolsk excentrisk anomali fra hovedanomalien efter {0} iterationer +# unable to compute eccentric longitude argument from the mean one after {0} iterations +UNABLE_TO_COMPUTE_ECCENTRIC_LONGITUDE_ARGUMENT = + +# unable to compute eccentric latitude argument from the mean one after {0} iterations +UNABLE_TO_COMPUTE_ECCENTRIC_LATITUDE_ARGUMENT = + # unable to compute mean orbit from osculating orbit after {0} iterations UNABLE_TO_COMPUTE_DSST_MEAN_PARAMETERS = kan ikke beregne hovedbane ud fra oskulerende bane efter {0} iterationer diff --git a/src/main/resources/assets/org/orekit/localization/OrekitMessages_de.utf8 b/src/main/resources/assets/org/orekit/localization/OrekitMessages_de.utf8 index 5559b29dac..86919e7790 100644 --- a/src/main/resources/assets/org/orekit/localization/OrekitMessages_de.utf8 +++ b/src/main/resources/assets/org/orekit/localization/OrekitMessages_de.utf8 @@ -454,6 +454,12 @@ UNABLE_TO_GENERATE_NEW_DATA_AFTER = # unable to compute hyperbolic eccentric anomaly from the mean anomaly after {0} iterations UNABLE_TO_COMPUTE_HYPERBOLIC_ECCENTRIC_ANOMALY = die hyperbolisch-exzentrische Anomalie kann nicht aus der mittleren Anomalie berechnet werden nach {0} Iterationen +# unable to compute eccentric longitude argument from the mean one after {0} iterations +UNABLE_TO_COMPUTE_ECCENTRIC_LONGITUDE_ARGUMENT = + +# unable to compute eccentric latitude argument from the mean one after {0} iterations +UNABLE_TO_COMPUTE_ECCENTRIC_LATITUDE_ARGUMENT = + # unable to compute mean orbit from osculating orbit after {0} iterations UNABLE_TO_COMPUTE_DSST_MEAN_PARAMETERS = die Durschnittsumlaufbahn kann auch nach {0} Iterationen nicht von der oskulierenden Umlaufbahn berechnet werden diff --git a/src/main/resources/assets/org/orekit/localization/OrekitMessages_el.utf8 b/src/main/resources/assets/org/orekit/localization/OrekitMessages_el.utf8 index 5caea1b28d..ec885a0114 100644 --- a/src/main/resources/assets/org/orekit/localization/OrekitMessages_el.utf8 +++ b/src/main/resources/assets/org/orekit/localization/OrekitMessages_el.utf8 @@ -454,6 +454,12 @@ UNABLE_TO_GENERATE_NEW_DATA_AFTER = # unable to compute hyperbolic eccentric anomaly from the mean anomaly after {0} iterations UNABLE_TO_COMPUTE_HYPERBOLIC_ECCENTRIC_ANOMALY = αδύνατο να υπολογίστει υπερβολική εκκεντρική ανωμαλία από τη μέση ανωμαλία μετά από {0} επαναλήψεις +# unable to compute eccentric longitude argument from the mean one after {0} iterations +UNABLE_TO_COMPUTE_ECCENTRIC_LONGITUDE_ARGUMENT = + +# unable to compute eccentric latitude argument from the mean one after {0} iterations +UNABLE_TO_COMPUTE_ECCENTRIC_LATITUDE_ARGUMENT = + # unable to compute mean orbit from osculating orbit after {0} iterations UNABLE_TO_COMPUTE_DSST_MEAN_PARAMETERS = diff --git a/src/main/resources/assets/org/orekit/localization/OrekitMessages_en.utf8 b/src/main/resources/assets/org/orekit/localization/OrekitMessages_en.utf8 index 50760d653e..dbf76e6fe0 100644 --- a/src/main/resources/assets/org/orekit/localization/OrekitMessages_en.utf8 +++ b/src/main/resources/assets/org/orekit/localization/OrekitMessages_en.utf8 @@ -454,6 +454,12 @@ UNABLE_TO_GENERATE_NEW_DATA_AFTER = unable to generate new data after {0}, but d # unable to compute hyperbolic eccentric anomaly from the mean anomaly after {0} iterations UNABLE_TO_COMPUTE_HYPERBOLIC_ECCENTRIC_ANOMALY = unable to compute hyperbolic eccentric anomaly from the mean anomaly after {0} iterations +# unable to compute eccentric longitude argument from the mean one after {0} iterations +UNABLE_TO_COMPUTE_ECCENTRIC_LONGITUDE_ARGUMENT = unable to compute eccentric longitude argument from the mean one after {0} iterations + +# unable to compute eccentric latitude argument from the mean one after {0} iterations +UNABLE_TO_COMPUTE_ECCENTRIC_LATITUDE_ARGUMENT = unable to compute eccentric latitude argument from the mean one after {0} iterations + # unable to compute mean orbit from osculating orbit after {0} iterations UNABLE_TO_COMPUTE_DSST_MEAN_PARAMETERS = unable to compute mean orbit from osculating orbit after {0} iterations diff --git a/src/main/resources/assets/org/orekit/localization/OrekitMessages_es.utf8 b/src/main/resources/assets/org/orekit/localization/OrekitMessages_es.utf8 index 7d14d8b07a..88aecb9b04 100644 --- a/src/main/resources/assets/org/orekit/localization/OrekitMessages_es.utf8 +++ b/src/main/resources/assets/org/orekit/localization/OrekitMessages_es.utf8 @@ -454,6 +454,12 @@ UNABLE_TO_GENERATE_NEW_DATA_AFTER = no se pueden generar nuevos datos después d # unable to compute hyperbolic eccentric anomaly from the mean anomaly after {0} iterations UNABLE_TO_COMPUTE_HYPERBOLIC_ECCENTRIC_ANOMALY = después de {0} iteraciones no se ha conseguido calcular la anomalía excéntrica hiperbólica a partir de la anomalía media +# unable to compute eccentric longitude argument from the mean one after {0} iterations +UNABLE_TO_COMPUTE_ECCENTRIC_LONGITUDE_ARGUMENT = unable to compute eccentric longitude argument from the mean one after {0} iterations + +# unable to compute eccentric latitude argument from the mean one after {0} iterations +UNABLE_TO_COMPUTE_ECCENTRIC_LATITUDE_ARGUMENT = unable to compute eccentric latitude argument from the mean one after {0} iterations + # unable to compute mean orbit from osculating orbit after {0} iterations UNABLE_TO_COMPUTE_DSST_MEAN_PARAMETERS = no se puede calcular la órbita media a partir de la órbita osculatriz tras {0} iteraciones diff --git a/src/main/resources/assets/org/orekit/localization/OrekitMessages_fr.utf8 b/src/main/resources/assets/org/orekit/localization/OrekitMessages_fr.utf8 index 13e6244952..d4ec7ef13c 100644 --- a/src/main/resources/assets/org/orekit/localization/OrekitMessages_fr.utf8 +++ b/src/main/resources/assets/org/orekit/localization/OrekitMessages_fr.utf8 @@ -454,6 +454,12 @@ UNABLE_TO_GENERATE_NEW_DATA_AFTER = impossible de générer des données après # unable to compute hyperbolic eccentric anomaly from the mean anomaly after {0} iterations UNABLE_TO_COMPUTE_HYPERBOLIC_ECCENTRIC_ANOMALY = impossible de calculer l''anomalie excentrique hyperbolique à partir de l''anomalie moyenne après {0} itérations +# unable to compute eccentric longitude argument from the mean one after {0} iterations +UNABLE_TO_COMPUTE_ECCENTRIC_LONGITUDE_ARGUMENT = impossible de calculer l''argument de longitude excentrique à partir de celle moyenne {0} itérations + +# unable to compute eccentric latitude argument from the mean one after {0} iterations +UNABLE_TO_COMPUTE_ECCENTRIC_LATITUDE_ARGUMENT = impossible de calculer l''argument de latitude excentrique à partir de celle moyenne {0} itérations + # unable to compute mean orbit from osculating orbit after {0} iterations UNABLE_TO_COMPUTE_DSST_MEAN_PARAMETERS = impossible de calculer l''orbite moyenne à partir de l''orbite osculatrice après {0} itérations diff --git a/src/main/resources/assets/org/orekit/localization/OrekitMessages_gl.utf8 b/src/main/resources/assets/org/orekit/localization/OrekitMessages_gl.utf8 index d9922665fc..bc953e0c5e 100644 --- a/src/main/resources/assets/org/orekit/localization/OrekitMessages_gl.utf8 +++ b/src/main/resources/assets/org/orekit/localization/OrekitMessages_gl.utf8 @@ -454,6 +454,12 @@ UNABLE_TO_GENERATE_NEW_DATA_AFTER = # unable to compute hyperbolic eccentric anomaly from the mean anomaly after {0} iterations UNABLE_TO_COMPUTE_HYPERBOLIC_ECCENTRIC_ANOMALY = imposible de calcular la anomalía excéntrica hiperbólica a partir de la anomalía media después de {0} iteraciones +# unable to compute eccentric longitude argument from the mean one after {0} iterations +UNABLE_TO_COMPUTE_ECCENTRIC_LONGITUDE_ARGUMENT = unable to compute eccentric longitude argument from the mean one after {0} iterations + +# unable to compute eccentric latitude argument from the mean one after {0} iterations +UNABLE_TO_COMPUTE_ECCENTRIC_LATITUDE_ARGUMENT = unable to compute eccentric latitude argument from the mean one after {0} iterations + # unable to compute mean orbit from osculating orbit after {0} iterations UNABLE_TO_COMPUTE_DSST_MEAN_PARAMETERS = diff --git a/src/main/resources/assets/org/orekit/localization/OrekitMessages_it.utf8 b/src/main/resources/assets/org/orekit/localization/OrekitMessages_it.utf8 index 0041216a32..e1f794fcc9 100644 --- a/src/main/resources/assets/org/orekit/localization/OrekitMessages_it.utf8 +++ b/src/main/resources/assets/org/orekit/localization/OrekitMessages_it.utf8 @@ -454,6 +454,12 @@ UNABLE_TO_GENERATE_NEW_DATA_AFTER =impossibile generare dati dopo il {0}, dati r # unable to compute hyperbolic eccentric anomaly from the mean anomaly after {0} iterations UNABLE_TO_COMPUTE_HYPERBOLIC_ECCENTRIC_ANOMALY = impossibile calcolare l''anomalia eccentrica iperbolica a partire dall''anomalia media dopo {0} iterazioni +# unable to compute eccentric longitude argument from the mean one after {0} iterations +UNABLE_TO_COMPUTE_ECCENTRIC_LONGITUDE_ARGUMENT = unable to compute eccentric longitude argument from the mean one after {0} iterations + +# unable to compute eccentric latitude argument from the mean one after {0} iterations +UNABLE_TO_COMPUTE_ECCENTRIC_LATITUDE_ARGUMENT = unable to compute eccentric latitude argument from the mean one after {0} iterations + # unable to compute mean orbit from osculating orbit after {0} iterations UNABLE_TO_COMPUTE_DSST_MEAN_PARAMETERS = impossibile calcolare l''orbita media a partire dall''orbita osculatrice dopo {0} iterazioni diff --git a/src/main/resources/assets/org/orekit/localization/OrekitMessages_no.utf8 b/src/main/resources/assets/org/orekit/localization/OrekitMessages_no.utf8 index f5b7b6164c..bb613d78f5 100644 --- a/src/main/resources/assets/org/orekit/localization/OrekitMessages_no.utf8 +++ b/src/main/resources/assets/org/orekit/localization/OrekitMessages_no.utf8 @@ -454,6 +454,12 @@ UNABLE_TO_GENERATE_NEW_DATA_AFTER = # unable to compute hyperbolic eccentric anomaly from the mean anomaly after {0} iterations UNABLE_TO_COMPUTE_HYPERBOLIC_ECCENTRIC_ANOMALY = kan ikke beregne hyperbolsk eksentrisk anomali fra hovedanomalien etter {0} iterasjoner +# unable to compute eccentric longitude argument from the mean one after {0} iterations +UNABLE_TO_COMPUTE_ECCENTRIC_LONGITUDE_ARGUMENT = unable to compute eccentric longitude argument from the mean one after {0} iterations + +# unable to compute eccentric latitude argument from the mean one after {0} iterations +UNABLE_TO_COMPUTE_ECCENTRIC_LATITUDE_ARGUMENT = unable to compute eccentric latitude argument from the mean one after {0} iterations + # unable to compute mean orbit from osculating orbit after {0} iterations UNABLE_TO_COMPUTE_DSST_MEAN_PARAMETERS = kan ikke beregne hovedbane utfra osculærbane etter {0} gjentakelser diff --git a/src/main/resources/assets/org/orekit/localization/OrekitMessages_ro.utf8 b/src/main/resources/assets/org/orekit/localization/OrekitMessages_ro.utf8 index f0bfc97bf9..edd24fdfa5 100644 --- a/src/main/resources/assets/org/orekit/localization/OrekitMessages_ro.utf8 +++ b/src/main/resources/assets/org/orekit/localization/OrekitMessages_ro.utf8 @@ -454,6 +454,12 @@ UNABLE_TO_GENERATE_NEW_DATA_AFTER = imposibil de generat noi date înainte de {0 # unable to compute hyperbolic eccentric anomaly from the mean anomaly after {0} iterations UNABLE_TO_COMPUTE_HYPERBOLIC_ECCENTRIC_ANOMALY = imposibil de calculat anomalia excentrică hiperbolică pornind de la anomalia medie după {0} iterații +# unable to compute eccentric longitude argument from the mean one after {0} iterations +UNABLE_TO_COMPUTE_ECCENTRIC_LONGITUDE_ARGUMENT = unable to compute eccentric longitude argument from the mean one after {0} iterations + +# unable to compute eccentric latitude argument from the mean one after {0} iterations +UNABLE_TO_COMPUTE_ECCENTRIC_LATITUDE_ARGUMENT = unable to compute eccentric latitude argument from the mean one after {0} iterations + # unable to compute mean orbit from osculating orbit after {0} iterations UNABLE_TO_COMPUTE_DSST_MEAN_PARAMETERS = imposibil de calculat orbita medie din orbita osculatorie după {0} iterații diff --git a/src/test/java/org/orekit/errors/OrekitMessagesTest.java b/src/test/java/org/orekit/errors/OrekitMessagesTest.java index 9b0af1d390..b01ce55b07 100644 --- a/src/test/java/org/orekit/errors/OrekitMessagesTest.java +++ b/src/test/java/org/orekit/errors/OrekitMessagesTest.java @@ -30,7 +30,7 @@ public class OrekitMessagesTest { @Test public void testMessageNumber() { - Assertions.assertEquals(289, OrekitMessages.values().length); + Assertions.assertEquals(291, OrekitMessages.values().length); } @Test diff --git a/src/test/java/org/orekit/orbits/CircularLatitudeArgumentUtilityTest.java b/src/test/java/org/orekit/orbits/CircularLatitudeArgumentUtilityTest.java new file mode 100644 index 0000000000..c125daa8cb --- /dev/null +++ b/src/test/java/org/orekit/orbits/CircularLatitudeArgumentUtilityTest.java @@ -0,0 +1,78 @@ +/* Copyright 2022-2023 Romain Serra + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.orbits; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.orekit.errors.OrekitException; +import org.orekit.errors.OrekitMessages; + +class CircularLatitudeArgumentUtilityTest { + + private static final double EX = 0.1; + private static final double EY = 0.66; + private static final double TOLERANCE = 1e-10; + + @Test + void testMeanToTrueAndBack() { + // GIVEN + final double expectedLatitudeArgument = 3.; + // WHEN + final double intermediateLatitudeArgument = CircularLatitudeArgumentUtility.meanToTrue(EX, EY, + expectedLatitudeArgument); + final double actualLatitudeArgument = CircularLatitudeArgumentUtility.trueToMean(EX, EY, + intermediateLatitudeArgument); + // THEN + Assertions.assertEquals(expectedLatitudeArgument, actualLatitudeArgument, TOLERANCE); + } + + @Test + void testEccentricToTrueAndBack() { + // GIVEN + final double expectedLatitudeArgument = 3.; + // WHEN + final double intermediateLatitudeArgument = CircularLatitudeArgumentUtility.eccentricToTrue(EX, EY, + expectedLatitudeArgument); + final double actualLatitudeArgument = CircularLatitudeArgumentUtility.trueToEccentric(EX, EY, + intermediateLatitudeArgument); + // THEN + Assertions.assertEquals(expectedLatitudeArgument, actualLatitudeArgument, TOLERANCE); + } + + @Test + void testEccentricToMeanAndBack() { + // GIVEN + final double expectedLatitudeArgument = 3.; + // WHEN + final double intermediateLatitudeArgument = CircularLatitudeArgumentUtility.eccentricToMean(EX, EY, + expectedLatitudeArgument); + final double actualLatitudeArgument = CircularLatitudeArgumentUtility.meanToEccentric(EX, EY, + intermediateLatitudeArgument); + // THEN + Assertions.assertEquals(expectedLatitudeArgument, actualLatitudeArgument, TOLERANCE); + } + + @Test + void testMeanToEccentricException() { + // GIVEN + final double nanLatitudeArgument = Double.NaN; + // WHEN & THEN + Assertions.assertThrows(OrekitException.class, () -> CircularLatitudeArgumentUtility.meanToEccentric(EX, EY, + nanLatitudeArgument), OrekitMessages.UNABLE_TO_COMPUTE_ECCENTRIC_LATITUDE_ARGUMENT.toString()); + } + +} \ No newline at end of file diff --git a/src/test/java/org/orekit/orbits/CircularOrbitTest.java b/src/test/java/org/orekit/orbits/CircularOrbitTest.java index 57d0e2f479..1e83d286ce 100644 --- a/src/test/java/org/orekit/orbits/CircularOrbitTest.java +++ b/src/test/java/org/orekit/orbits/CircularOrbitTest.java @@ -61,7 +61,7 @@ public class CircularOrbitTest { private double mu; @Test - public void testCircularToEquinoctialEll() { + void testCircularToEquinoctialEll() { double ix = 1.200e-04; double iy = -1.16e-04; @@ -89,7 +89,7 @@ public void testCircularToEquinoctialEll() { } @Test - public void testCircularToEquinoctialCirc() { + void testCircularToEquinoctialCirc() { double ix = 1.200e-04; double iy = -1.16e-04; @@ -117,7 +117,7 @@ public void testCircularToEquinoctialCirc() { } @Test - public void testCircularToCartesian() { + void testCircularToCartesian() { double ix = 1.200e-04; double iy = -1.16e-04; @@ -153,7 +153,7 @@ public void testCircularToCartesian() { } @Test - public void testCircularToKeplerian() { + void testCircularToKeplerian() { double ix = 1.20e-4; double iy = -1.16e-4; @@ -189,7 +189,7 @@ public void testCircularToKeplerian() { } @Test - public void testHyperbolic1() { + void testHyperbolic1() { try { new CircularOrbit(42166712.0, 0.9, 0.5, 0.01, -0.02, 5.300, PositionAngleType.MEAN, FramesFactory.getEME2000(), date, mu); @@ -199,7 +199,7 @@ public void testHyperbolic1() { } @Test - public void testHyperbolic2() { + void testHyperbolic2() { Orbit orbit = new KeplerianOrbit(42166712.0, 0.9, 0.5, 0.01, -0.02, 5.300, PositionAngleType.MEAN, FramesFactory.getEME2000(), date, mu); try { @@ -210,7 +210,7 @@ public void testHyperbolic2() { } @Test - public void testAnomalyEll() { + void testAnomalyEll() { // elliptic orbit Vector3D position = new Vector3D(7.0e6, 1.0e6, 4.0e6); @@ -262,7 +262,7 @@ public void testAnomalyEll() { } @Test - public void testAnomalyCirc() { + void testAnomalyCirc() { Vector3D position = new Vector3D(7.0e6, 1.0e6, 4.0e6); Vector3D velocity = new Vector3D(-500.0, 8000.0, 1000.0); @@ -309,7 +309,7 @@ public void testAnomalyCirc() { } @Test - public void testPositionVelocityNormsEll() { + void testPositionVelocityNormsEll() { // elliptic and non equatorial (i retrograde) orbit double hx = 1.2; @@ -341,7 +341,7 @@ public void testPositionVelocityNormsEll() { } @Test - public void testNumericalIssue25() { + void testNumericalIssue25() { Vector3D position = new Vector3D(3782116.14107698, 416663.11924914, 5875541.62103057); Vector3D velocity = new Vector3D(-6349.7848910501, 288.4061811651, 4066.9366759691); CircularOrbit orbit = new CircularOrbit(new PVCoordinates(position, velocity), @@ -353,7 +353,7 @@ public void testNumericalIssue25() { } @Test - public void testPerfectlyEquatorial() { + void testPerfectlyEquatorial() { Vector3D position = new Vector3D(-7293947.695148368, 5122184.668436634, 0.0); Vector3D velocity = new Vector3D(-3890.4029433398, -5369.811285264604, 0.0); CircularOrbit orbit = new CircularOrbit(new PVCoordinates(position, velocity), @@ -366,7 +366,7 @@ public void testPerfectlyEquatorial() { } @Test - public void testPositionVelocityNormsCirc() { + void testPositionVelocityNormsCirc() { // elliptic and non equatorial (i retrograde) orbit double hx = 0.1e-8; @@ -397,7 +397,7 @@ public void testPositionVelocityNormsCirc() { } @Test - public void testGeometryEll() { + void testGeometryEll() { // elliptic and non equatorial (i retrograde) orbit double hx = 1.2; @@ -441,7 +441,7 @@ public void testGeometryEll() { } @Test - public void testGeometryCirc() { + void testGeometryCirc() { // circular and equatorial orbit double hx = 0.1e-8; @@ -486,7 +486,7 @@ public void testGeometryCirc() { } @Test - public void testSymmetryEll() { + void testSymmetryEll() { // elliptic and non equatorail orbit Vector3D position = new Vector3D(4512.9, 18260., -5127.); @@ -507,7 +507,7 @@ public void testSymmetryEll() { } @Test - public void testSymmetryCir() { + void testSymmetryCir() { // circular and equatorial orbit Vector3D position = new Vector3D(33051.2, 26184.9, -1.3E-5); Vector3D velocity = new Vector3D(-60376.2, 76208., 2.7E-4); @@ -524,7 +524,7 @@ public void testSymmetryCir() { } @Test - public void testNonInertialFrame() throws IllegalArgumentException { + void testNonInertialFrame() throws IllegalArgumentException { Assertions.assertThrows(IllegalArgumentException.class, () -> { Vector3D position = new Vector3D(33051.2, 26184.9, -1.3E-5); Vector3D velocity = new Vector3D(-60376.2, 76208., 2.7E-4); @@ -536,7 +536,7 @@ public void testNonInertialFrame() throws IllegalArgumentException { } @Test - public void testJacobianReference() { + void testJacobianReference() { AbsoluteDate dateTca = new AbsoluteDate(2000, 04, 01, 0, 0, 0.000, TimeScalesFactory.getUTC()); double mu = 3.986004415e+14; @@ -617,7 +617,7 @@ public void testJacobianReference() { } @Test - public void testJacobianFinitedifferences() { + void testJacobianFinitedifferences() { AbsoluteDate dateTca = new AbsoluteDate(2000, 04, 01, 0, 0, 0.000, TimeScalesFactory.getUTC()); double mu = 3.986004415e+14; @@ -753,7 +753,7 @@ private void fillColumn(PositionAngleType type, int i, CircularOrbit orbit, doub } @Test - public void testSerialization() + void testSerialization() throws IOException, ClassNotFoundException { Vector3D position = new Vector3D(-29536113.0, 30329259.0, -100125.0); Vector3D velocity = new Vector3D(-2194.0, -2141.0, -8.0); @@ -790,7 +790,7 @@ public void testSerialization() } @Test - public void testSerializationWithDerivatives() + void testSerializationWithDerivatives() throws IOException, ClassNotFoundException { Vector3D position = new Vector3D(-29536113.0, 30329259.0, -100125.0); Vector3D velocity = new Vector3D(-2194.0, -2141.0, -8.0); @@ -831,7 +831,7 @@ public void testSerializationWithDerivatives() } @Test - public void testSerializationNoPVWithDerivatives() + void testSerializationNoPVWithDerivatives() throws IOException, ClassNotFoundException { Vector3D position = new Vector3D(-29536113.0, 30329259.0, -100125.0); Vector3D velocity = new Vector3D(-2194.0, -2141.0, -8.0); @@ -883,7 +883,7 @@ public void testSerializationNoPVWithDerivatives() } @Test - public void testNonKeplerianDerivatives() { + void testNonKeplerianDerivatives() { final AbsoluteDate date = new AbsoluteDate("2003-05-01T00:00:20.000", TimeScalesFactory.getUTC()); final Vector3D position = new Vector3D(6896874.444705, 1956581.072644, -147476.245054); final Vector3D velocity = new Vector3D(166.816407662, -1106.783301861, -7372.745712770); @@ -963,7 +963,7 @@ public double value(double dt) { } @Test - public void testPositionAngleDerivatives() { + void testPositionAngleDerivatives() { final AbsoluteDate date = new AbsoluteDate("2003-05-01T00:00:20.000", TimeScalesFactory.getUTC()); final Vector3D position = new Vector3D(6896874.444705, 1956581.072644, -147476.245054); final Vector3D velocity = new Vector3D(166.816407662, -1106.783301861, -7372.745712770); @@ -1008,7 +1008,7 @@ public void testPositionAngleDerivatives() { } @Test - public void testEquatorialRetrograde() { + void testEquatorialRetrograde() { Vector3D position = new Vector3D(10000000.0, 0.0, 0.0); Vector3D velocity = new Vector3D(0.0, -6500.0, 1.0e-10); double r2 = position.getNormSq(); @@ -1030,7 +1030,7 @@ public void testEquatorialRetrograde() { } @Test - public void testDerivativesConversionSymmetry() { + void testDerivativesConversionSymmetry() { final AbsoluteDate date = new AbsoluteDate("2003-05-01T00:01:20.000", TimeScalesFactory.getUTC()); Vector3D position = new Vector3D(6893443.400234382, 1886406.1073757345, -589265.1150359757); Vector3D velocity = new Vector3D(-281.1261461082365, -1231.6165642450928, -7348.756363469432); @@ -1060,7 +1060,7 @@ public void testDerivativesConversionSymmetry() { } @Test - public void testToString() { + void testToString() { Vector3D position = new Vector3D(-29536113.0, 30329259.0, -100125.0); Vector3D velocity = new Vector3D(-2194.0, -2141.0, -8.0); PVCoordinates pvCoordinates = new PVCoordinates(position, velocity); @@ -1094,7 +1094,7 @@ void testRemoveRates() { } @Test - public void testCopyNonKeplerianAcceleration() { + void testCopyNonKeplerianAcceleration() { final Frame eme2000 = FramesFactory.getEME2000(); @@ -1125,7 +1125,7 @@ public void testCopyNonKeplerianAcceleration() { } @Test - public void testNormalize() { + void testNormalize() { CircularOrbit withoutDerivatives = new CircularOrbit(42166712.0, 0.005, -0.025, 1.6, 1.25, 0.4, PositionAngleType.MEAN, @@ -1175,6 +1175,29 @@ public void testNormalize() { } + @Test + void positionAngleNonRegressionOnDeprecated() { + // Can be removed when deprecated routines are removed in next major release (13.0) + // GIVEN + final double ex = 0.2; + final double ey = 0.3; + final double originalPositionAngle = 1.; + // WHEN + final double actualEccentricToMean = CircularOrbit.eccentricToMean(originalPositionAngle, ex, ey); + final double actualEccentricToTrue = CircularOrbit.eccentricToTrue(originalPositionAngle, ex, ey); + final double actualMeanToEccentric = CircularOrbit.meanToEccentric(originalPositionAngle, ex, ey); + final double actualTrueToEccentric = CircularOrbit.trueToEccentric(originalPositionAngle, ex, ey); + // THEN + Assertions.assertEquals(CircularLatitudeArgumentUtility.eccentricToMean(ex, ey, originalPositionAngle), + actualEccentricToMean); + Assertions.assertEquals(CircularLatitudeArgumentUtility.eccentricToTrue(ex, ey, originalPositionAngle), + actualEccentricToTrue); + Assertions.assertEquals(CircularLatitudeArgumentUtility.meanToEccentric(ex, ey, originalPositionAngle), + actualMeanToEccentric); + Assertions.assertEquals(CircularLatitudeArgumentUtility.trueToEccentric(ex, ey, originalPositionAngle), + actualTrueToEccentric); + } + @BeforeEach public void setUp() { diff --git a/src/test/java/org/orekit/orbits/EquinoctialLongitudeArgumentUtilityTest.java b/src/test/java/org/orekit/orbits/EquinoctialLongitudeArgumentUtilityTest.java new file mode 100644 index 0000000000..0e81f0e99a --- /dev/null +++ b/src/test/java/org/orekit/orbits/EquinoctialLongitudeArgumentUtilityTest.java @@ -0,0 +1,78 @@ +/* Copyright 2022-2023 Romain Serra + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.orbits; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.orekit.errors.OrekitException; +import org.orekit.errors.OrekitMessages; + +class EquinoctialLongitudeArgumentUtilityTest { + + private static final double EX = 0.1; + private static final double EY = 0.66; + private static final double TOLERANCE = 1e-10; + + @Test + void testMeanToTrueAndBack() { + // GIVEN + final double expectedLatitudeArgument = 3.; + // WHEN + final double intermediateLatitudeArgument = EquinoctialLongitudeArgumentUtility.meanToTrue(EX, EY, + expectedLatitudeArgument); + final double actualLatitudeArgument = EquinoctialLongitudeArgumentUtility.trueToMean(EX, EY, + intermediateLatitudeArgument); + // THEN + Assertions.assertEquals(expectedLatitudeArgument, actualLatitudeArgument, TOLERANCE); + } + + @Test + void testEccentricToTrueAndBack() { + // GIVEN + final double expectedLatitudeArgument = 3.; + // WHEN + final double intermediateLatitudeArgument = EquinoctialLongitudeArgumentUtility.eccentricToTrue(EX, EY, + expectedLatitudeArgument); + final double actualLatitudeArgument = EquinoctialLongitudeArgumentUtility.trueToEccentric(EX, EY, + intermediateLatitudeArgument); + // THEN + Assertions.assertEquals(expectedLatitudeArgument, actualLatitudeArgument, TOLERANCE); + } + + @Test + void testEccentricToMeanAndBack() { + // GIVEN + final double expectedLatitudeArgument = 3.; + // WHEN + final double intermediateLatitudeArgument = EquinoctialLongitudeArgumentUtility.eccentricToMean(EX, EY, + expectedLatitudeArgument); + final double actualLatitudeArgument = EquinoctialLongitudeArgumentUtility.meanToEccentric(EX, EY, + intermediateLatitudeArgument); + // THEN + Assertions.assertEquals(expectedLatitudeArgument, actualLatitudeArgument, TOLERANCE); + } + + @Test + void testMeanToEccentricException() { + // GIVEN + final double nanLatitudeArgument = Double.NaN; + // WHEN & THEN + Assertions.assertThrows(OrekitException.class, () -> EquinoctialLongitudeArgumentUtility.meanToEccentric(EX, EY, + nanLatitudeArgument), OrekitMessages.UNABLE_TO_COMPUTE_ECCENTRIC_LONGITUDE_ARGUMENT.toString()); + } + +} \ No newline at end of file diff --git a/src/test/java/org/orekit/orbits/EquinoctialOrbitTest.java b/src/test/java/org/orekit/orbits/EquinoctialOrbitTest.java index 6d1d105f65..7683b6dc73 100644 --- a/src/test/java/org/orekit/orbits/EquinoctialOrbitTest.java +++ b/src/test/java/org/orekit/orbits/EquinoctialOrbitTest.java @@ -59,7 +59,7 @@ public class EquinoctialOrbitTest { private double mu; @Test - public void testEquinoctialToEquinoctialEll() { + void testEquinoctialToEquinoctialEll() { double ix = 1.200e-04; double iy = -1.16e-04; @@ -93,7 +93,7 @@ public void testEquinoctialToEquinoctialEll() { } @Test - public void testEquinoctialToEquinoctialCirc() { + void testEquinoctialToEquinoctialCirc() { double ix = 1.200e-04; double iy = -1.16e-04; @@ -129,7 +129,7 @@ public void testEquinoctialToEquinoctialCirc() { } @Test - public void testEquinoctialToCartesian() { + void testEquinoctialToCartesian() { double ix = 1.200e-04; double iy = -1.16e-04; @@ -159,7 +159,7 @@ public void testEquinoctialToCartesian() { } @Test - public void testEquinoctialToKeplerian() { + void testEquinoctialToKeplerian() { double ix = 1.20e-4; double iy = -1.16e-4; @@ -191,7 +191,7 @@ public void testEquinoctialToKeplerian() { } @Test - public void testHyperbolic() { + void testHyperbolic() { Assertions.assertThrows(IllegalArgumentException.class, () -> { new EquinoctialOrbit(42166712.0, 0.9, 0.5, 0.01, -0.02, 5.300, PositionAngleType.MEAN, FramesFactory.getEME2000(), date, mu); @@ -199,7 +199,7 @@ public void testHyperbolic() { } @Test - public void testNumericalIssue25() { + void testNumericalIssue25() { Vector3D position = new Vector3D(3782116.14107698, 416663.11924914, 5875541.62103057); Vector3D velocity = new Vector3D(-6349.7848910501, 288.4061811651, 4066.9366759691); EquinoctialOrbit orbit = new EquinoctialOrbit(new PVCoordinates(position, velocity), @@ -212,7 +212,7 @@ public void testNumericalIssue25() { @Test - public void testAnomaly() { + void testAnomaly() { // elliptic orbit Vector3D position = new Vector3D(7.0e6, 1.0e6, 4.0e6); @@ -294,7 +294,7 @@ public void testAnomaly() { } @Test - public void testPositionVelocityNorms() { + void testPositionVelocityNorms() { // elliptic and non equatorial (i retrograde) orbit EquinoctialOrbit p = @@ -343,7 +343,7 @@ public void testPositionVelocityNorms() { } @Test - public void testGeometry() { + void testGeometry() { // elliptic and non equatorial (i retrograde) orbit EquinoctialOrbit p = @@ -427,7 +427,7 @@ public void testGeometry() { @Test - public void testRadiusOfCurvature() { + void testRadiusOfCurvature() { // elliptic and non equatorial (i retrograde) orbit EquinoctialOrbit p = @@ -465,7 +465,7 @@ public void testRadiusOfCurvature() { } @Test - public void testSymmetry() { + void testSymmetry() { // elliptic and non equatorial orbit Vector3D position = new Vector3D(4512.9, 18260., -5127.); @@ -495,7 +495,7 @@ public void testSymmetry() { } @Test - public void testNonInertialFrame() throws IllegalArgumentException { + void testNonInertialFrame() throws IllegalArgumentException { Assertions.assertThrows(IllegalArgumentException.class, () -> { Vector3D position = new Vector3D(4512.9, 18260., -5127.); Vector3D velocity = new Vector3D(134664.6, 90066.8, 72047.6); @@ -507,9 +507,9 @@ public void testNonInertialFrame() throws IllegalArgumentException { } @Test - public void testJacobianReference() { + void testJacobianReference() { - AbsoluteDate dateTca = new AbsoluteDate(2000, 04, 01, 0, 0, 0.000, TimeScalesFactory.getUTC()); + AbsoluteDate dateTca = new AbsoluteDate(2000, 4, 1, 0, 0, 0.000, TimeScalesFactory.getUTC()); double mu = 3.986004415e+14; EquinoctialOrbit orbEqu = new EquinoctialOrbit(7000000.0, 0.01, -0.02, 1.2, 2.1, FastMath.toRadians(40.), PositionAngleType.MEAN, @@ -613,9 +613,9 @@ public void testJacobianReference() { } @Test - public void testJacobianFinitedifferences() { + void testJacobianFinitedifferences() { - AbsoluteDate dateTca = new AbsoluteDate(2000, 04, 01, 0, 0, 0.000, TimeScalesFactory.getUTC()); + AbsoluteDate dateTca = new AbsoluteDate(2000, 4, 1, 0, 0, 0.000, TimeScalesFactory.getUTC()); double mu = 3.986004415e+14; EquinoctialOrbit orbEqu = new EquinoctialOrbit(7000000.0, 0.01, -0.02, 1.2, 2.1, FastMath.toRadians(40.), PositionAngleType.MEAN, @@ -749,7 +749,7 @@ private void fillColumn(PositionAngleType type, int i, EquinoctialOrbit orbit, d } @Test - public void testSerialization() + void testSerialization() throws IOException, ClassNotFoundException { Vector3D position = new Vector3D(-29536113.0, 30329259.0, -100125.0); Vector3D velocity = new Vector3D(-2194.0, -2141.0, -8.0); @@ -786,7 +786,7 @@ public void testSerialization() } @Test - public void testSerializationWithDerivatives() + void testSerializationWithDerivatives() throws IOException, ClassNotFoundException { Vector3D position = new Vector3D(-29536113.0, 30329259.0, -100125.0); Vector3D velocity = new Vector3D(-2194.0, -2141.0, -8.0); @@ -827,7 +827,7 @@ public void testSerializationWithDerivatives() } @Test - public void testNonKeplerianDerivatives() { + void testNonKeplerianDerivatives() { final AbsoluteDate date = new AbsoluteDate("2003-05-01T00:00:20.000", TimeScalesFactory.getUTC()); final Vector3D position = new Vector3D(6896874.444705, 1956581.072644, -147476.245054); final Vector3D velocity = new Vector3D(166.816407662, -1106.783301861, -7372.745712770); @@ -883,16 +883,13 @@ public void testNonKeplerianDerivatives() { double differentiate(TimeStampedPVCoordinates pv, Frame frame, double mu, S picker) { final DSFactory factory = new DSFactory(1, 1); FiniteDifferencesDifferentiator differentiator = new FiniteDifferencesDifferentiator(8, 0.1); - UnivariateDifferentiableFunction diff = differentiator.differentiate(new UnivariateFunction() { - public double value(double dt) { - return picker.apply(new EquinoctialOrbit(pv.shiftedBy(dt), frame, mu)); - } - }); + UnivariateDifferentiableFunction diff = differentiator.differentiate((UnivariateFunction) dt -> + picker.apply(new EquinoctialOrbit(pv.shiftedBy(dt), frame, mu))); return diff.value(factory.variable(0, 0.0)).getPartialDerivative(1); } @Test - public void testPositionAngleDerivatives() { + void testPositionAngleDerivatives() { final AbsoluteDate date = new AbsoluteDate("2003-05-01T00:00:20.000", TimeScalesFactory.getUTC()); final Vector3D position = new Vector3D(6896874.444705, 1956581.072644, -147476.245054); final Vector3D velocity = new Vector3D(166.816407662, -1106.783301861, -7372.745712770); @@ -935,7 +932,7 @@ public void testPositionAngleDerivatives() { } @Test - public void testEquatorialRetrograde() { + void testEquatorialRetrograde() { Vector3D position = new Vector3D(10000000.0, 0.0, 0.0); Vector3D velocity = new Vector3D(0.0, -6500.0, 0.0); double r2 = position.getNormSq(); @@ -960,7 +957,7 @@ public void testEquatorialRetrograde() { } @Test - public void testDerivativesConversionSymmetry() { + void testDerivativesConversionSymmetry() { final AbsoluteDate date = new AbsoluteDate("2003-05-01T00:01:20.000", TimeScalesFactory.getUTC()); Vector3D position = new Vector3D(6893443.400234382, 1886406.1073757345, -589265.1150359757); Vector3D velocity = new Vector3D(-281.1261461082365, -1231.6165642450928, -7348.756363469432); @@ -990,7 +987,7 @@ public void testDerivativesConversionSymmetry() { } @Test - public void testToString() { + void testToString() { Vector3D position = new Vector3D(-29536113.0, 30329259.0, -100125.0); Vector3D velocity = new Vector3D(-2194.0, -2141.0, -8.0); PVCoordinates pvCoordinates = new PVCoordinates(position, velocity); @@ -1023,7 +1020,7 @@ void testRemoveRates() { } @Test - public void testCopyNonKeplerianAcceleration() { + void testCopyNonKeplerianAcceleration() { final Frame eme2000 = FramesFactory.getEME2000(); @@ -1054,7 +1051,7 @@ public void testCopyNonKeplerianAcceleration() { } @Test - public void testNormalize() { + void testNormalize() { EquinoctialOrbit withoutDerivatives = new EquinoctialOrbit(42166712.0, 0.005, -0.025, 0.17, 0.34, 0.4, PositionAngleType.MEAN, @@ -1105,6 +1102,29 @@ public void testNormalize() { } + @Test + void positionAngleNonRegressionOnDeprecated() { + // Can be removed when deprecated routines are removed in next major release (13.0) + // GIVEN + final double ex = 0.2; + final double ey = 0.3; + final double originalPositionAngle = 1.; + // WHEN + final double actualEccentricToMean = EquinoctialOrbit.eccentricToMean(originalPositionAngle, ex, ey); + final double actualEccentricToTrue = EquinoctialOrbit.eccentricToTrue(originalPositionAngle, ex, ey); + final double actualMeanToEccentric = EquinoctialOrbit.meanToEccentric(originalPositionAngle, ex, ey); + final double actualTrueToEccentric = EquinoctialOrbit.trueToEccentric(originalPositionAngle, ex, ey); + // THEN + Assertions.assertEquals(EquinoctialLongitudeArgumentUtility.eccentricToMean(ex, ey, originalPositionAngle), + actualEccentricToMean); + Assertions.assertEquals(EquinoctialLongitudeArgumentUtility.eccentricToTrue(ex, ey, originalPositionAngle), + actualEccentricToTrue); + Assertions.assertEquals(EquinoctialLongitudeArgumentUtility.meanToEccentric(ex, ey, originalPositionAngle), + actualMeanToEccentric); + Assertions.assertEquals(EquinoctialLongitudeArgumentUtility.trueToEccentric(ex, ey, originalPositionAngle), + actualTrueToEccentric); + } + @BeforeEach public void setUp() { diff --git a/src/test/java/org/orekit/orbits/FieldCircularLatitudeArgumentUtilityTest.java b/src/test/java/org/orekit/orbits/FieldCircularLatitudeArgumentUtilityTest.java new file mode 100644 index 0000000000..d632cd78da --- /dev/null +++ b/src/test/java/org/orekit/orbits/FieldCircularLatitudeArgumentUtilityTest.java @@ -0,0 +1,157 @@ +/* Copyright 2022-2023 Romain Serra + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.orbits; + +import org.hipparchus.complex.Complex; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.orekit.errors.OrekitException; +import org.orekit.errors.OrekitMessages; + +class FieldCircularLatitudeArgumentUtilityTest { + + private static final Complex EX = new Complex(0.1, 0.); + private static final Complex EY = new Complex(0.66, 0.); + private static final double TOLERANCE = 1e-10; + + @Test + void testMeanToTrueAndBack() { + // GIVEN + final Complex expectedLatitudeArgument = new Complex(3., 0.); + // WHEN + final Complex intermediateLatitudeArgument = FieldCircularLatitudeArgumentUtility.meanToTrue(EX, EY, + expectedLatitudeArgument); + final Complex actualLatitudeArgument = FieldCircularLatitudeArgumentUtility.trueToMean(EX, EY, + intermediateLatitudeArgument); + // THEN + Assertions.assertEquals(expectedLatitudeArgument.getReal(), actualLatitudeArgument.getReal(), TOLERANCE); + } + + @Test + void testEccentricToTrueAndBack() { + // GIVEN + final Complex expectedLatitudeArgument = new Complex(3., 0.); + // WHEN + final Complex intermediateLatitudeArgument = FieldCircularLatitudeArgumentUtility.eccentricToTrue(EX, EY, + expectedLatitudeArgument); + final Complex actualLatitudeArgument = FieldCircularLatitudeArgumentUtility.trueToEccentric(EX, EY, + intermediateLatitudeArgument); + // THEN + Assertions.assertEquals(expectedLatitudeArgument.getReal(), actualLatitudeArgument.getReal(), TOLERANCE); + } + + @Test + void testEccentricToMeanAndBack() { + // GIVEN + final Complex expectedLatitudeArgument = new Complex(3., 0.); + // WHEN + final Complex intermediateLatitudeArgument = FieldCircularLatitudeArgumentUtility.eccentricToMean(EX, EY, + expectedLatitudeArgument); + final Complex actualLatitudeArgument = FieldCircularLatitudeArgumentUtility.meanToEccentric(EX, EY, + intermediateLatitudeArgument); + // THEN + Assertions.assertEquals(expectedLatitudeArgument.getReal(), actualLatitudeArgument.getReal(), TOLERANCE); + } + + @Test + void testMeanToTrueVersusDouble() { + // GIVEN + final Complex fieldOriginalPositionAngle = new Complex(3., 0.); + // WHEN + final double actualConvertedPositionAngle = FieldCircularLatitudeArgumentUtility.meanToTrue( + EX, EY, fieldOriginalPositionAngle).getReal(); + // THEN + final double expectedPositionAngle = CircularLatitudeArgumentUtility.meanToTrue( + EX.getReal(), EY.getReal(), fieldOriginalPositionAngle.getReal()); + Assertions.assertEquals(expectedPositionAngle, actualConvertedPositionAngle, TOLERANCE); + } + + @Test + void testMeanToEccentricVersusDouble() { + // GIVEN + final Complex fieldOriginalPositionAngle = new Complex(3., 0.); + // WHEN + final double actualConvertedPositionAngle = FieldCircularLatitudeArgumentUtility.meanToEccentric( + EX, EY, fieldOriginalPositionAngle).getReal(); + // THEN + final double expectedPositionAngle = CircularLatitudeArgumentUtility.meanToEccentric( + EX.getReal(), EY.getReal(), fieldOriginalPositionAngle.getReal()); + Assertions.assertEquals(expectedPositionAngle, actualConvertedPositionAngle, TOLERANCE); + } + + @Test + void testTrueToEccentricVersusDouble() { + // GIVEN + final Complex fieldOriginalPositionAngle = new Complex(3., 0.); + // WHEN + final double actualConvertedPositionAngle = FieldCircularLatitudeArgumentUtility.trueToEccentric( + EX, EY, fieldOriginalPositionAngle).getReal(); + // THEN + final double expectedPositionAngle = CircularLatitudeArgumentUtility.trueToEccentric( + EX.getReal(), EY.getReal(), fieldOriginalPositionAngle.getReal()); + Assertions.assertEquals(expectedPositionAngle, actualConvertedPositionAngle, TOLERANCE); + } + + @Test + void testTrueToMeanVersusDouble() { + // GIVEN + final Complex fieldOriginalPositionAngle = new Complex(3., 0.); + // WHEN + final double actualConvertedPositionAngle = FieldCircularLatitudeArgumentUtility.trueToMean( + EX, EY, fieldOriginalPositionAngle).getReal(); + // THEN + final double expectedPositionAngle = CircularLatitudeArgumentUtility.trueToMean( + EX.getReal(), EY.getReal(), fieldOriginalPositionAngle.getReal()); + Assertions.assertEquals(expectedPositionAngle, actualConvertedPositionAngle, TOLERANCE); + } + + @Test + void testEccentricToMeanVersusDouble() { + // GIVEN + final Complex fieldOriginalPositionAngle = new Complex(3., 0.); + // WHEN + final double actualConvertedPositionAngle = FieldCircularLatitudeArgumentUtility.eccentricToMean( + EX, EY, fieldOriginalPositionAngle).getReal(); + // THEN + final double expectedPositionAngle = CircularLatitudeArgumentUtility.eccentricToMean( + EX.getReal(), EY.getReal(), fieldOriginalPositionAngle.getReal()); + Assertions.assertEquals(expectedPositionAngle, actualConvertedPositionAngle, TOLERANCE); + } + + @Test + void testEccentricToTrueVersusDouble() { + // GIVEN + final Complex fieldOriginalPositionAngle = new Complex(3., 0.); + // WHEN + final double actualConvertedPositionAngle = FieldCircularLatitudeArgumentUtility.eccentricToTrue( + EX, EY, fieldOriginalPositionAngle).getReal(); + // THEN + final double expectedPositionAngle = CircularLatitudeArgumentUtility.eccentricToTrue( + EX.getReal(), EY.getReal(), fieldOriginalPositionAngle.getReal()); + Assertions.assertEquals(expectedPositionAngle, actualConvertedPositionAngle, TOLERANCE); + } + + @Test + void testMeanToEccentricException() { + // GIVEN + final Complex fieldNaNPositionAngle = Complex.NaN; + // WHEN & THEN + Assertions.assertThrows(OrekitException.class, () -> FieldCircularLatitudeArgumentUtility.meanToEccentric(EX, + EY, fieldNaNPositionAngle), OrekitMessages.UNABLE_TO_COMPUTE_ECCENTRIC_LATITUDE_ARGUMENT.toString()); + } + +} \ No newline at end of file diff --git a/src/test/java/org/orekit/orbits/FieldEquinoctialLongitudeArgumentUtilityTest.java b/src/test/java/org/orekit/orbits/FieldEquinoctialLongitudeArgumentUtilityTest.java new file mode 100644 index 0000000000..9d76f8a334 --- /dev/null +++ b/src/test/java/org/orekit/orbits/FieldEquinoctialLongitudeArgumentUtilityTest.java @@ -0,0 +1,157 @@ +/* Copyright 2022-2023 Romain Serra + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.orbits; + +import org.hipparchus.complex.Complex; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.orekit.errors.OrekitException; +import org.orekit.errors.OrekitMessages; + +class FieldEquinoctialLongitudeArgumentUtilityTest { + + private static final Complex EX = new Complex(0.1, 0.); + private static final Complex EY = new Complex(0.66, 0.); + private static final double TOLERANCE = 1e-10; + + @Test + void testMeanToTrueAndBack() { + // GIVEN + final Complex expectedLatitudeArgument = new Complex(3., 0.); + // WHEN + final Complex intermediateLatitudeArgument = FieldEquinoctialLongitudeArgumentUtility.meanToTrue( + EX, EY, expectedLatitudeArgument); + final Complex actualLatitudeArgument = FieldEquinoctialLongitudeArgumentUtility.trueToMean( + EX, EY, intermediateLatitudeArgument); + // THEN + Assertions.assertEquals(expectedLatitudeArgument.getReal(), actualLatitudeArgument.getReal(), TOLERANCE); + } + + @Test + void testEccentricToTrueAndBack() { + // GIVEN + final Complex expectedLatitudeArgument = new Complex(3., 0.); + // WHEN + final Complex intermediateLatitudeArgument = FieldEquinoctialLongitudeArgumentUtility + .eccentricToTrue(EX, EY, expectedLatitudeArgument); + final Complex actualLatitudeArgument = FieldEquinoctialLongitudeArgumentUtility + .trueToEccentric(EX, EY, intermediateLatitudeArgument); + // THEN + Assertions.assertEquals(expectedLatitudeArgument.getReal(), actualLatitudeArgument.getReal(), TOLERANCE); + } + + @Test + void testEccentricToMeanAndBack() { + // GIVEN + final Complex expectedLatitudeArgument = new Complex(3., 0.); + // WHEN + final Complex intermediateLatitudeArgument = FieldEquinoctialLongitudeArgumentUtility + .eccentricToMean(EX, EY, expectedLatitudeArgument); + final Complex actualLatitudeArgument = FieldEquinoctialLongitudeArgumentUtility + .meanToEccentric(EX, EY, intermediateLatitudeArgument); + // THEN + Assertions.assertEquals(expectedLatitudeArgument.getReal(), actualLatitudeArgument.getReal(), TOLERANCE); + } + + @Test + void testMeanToTrueVersusDouble() { + // GIVEN + final Complex fieldOriginalPositionAngle = new Complex(3., 0.); + // WHEN + final double actualConvertedPositionAngle = FieldEquinoctialLongitudeArgumentUtility.meanToTrue( + EX, EY, fieldOriginalPositionAngle).getReal(); + // THEN + final double expectedPositionAngle = CircularLatitudeArgumentUtility.meanToTrue( + EX.getReal(), EY.getReal(), fieldOriginalPositionAngle.getReal()); + Assertions.assertEquals(expectedPositionAngle, actualConvertedPositionAngle, TOLERANCE); + } + + @Test + void testMeanToEccentricVersusDouble() { + // GIVEN + final Complex fieldOriginalPositionAngle = new Complex(3., 0.); + // WHEN + final double actualConvertedPositionAngle = FieldEquinoctialLongitudeArgumentUtility.meanToEccentric( + EX, EY, fieldOriginalPositionAngle).getReal(); + // THEN + final double expectedPositionAngle = CircularLatitudeArgumentUtility.meanToEccentric( + EX.getReal(), EY.getReal(), fieldOriginalPositionAngle.getReal()); + Assertions.assertEquals(expectedPositionAngle, actualConvertedPositionAngle, TOLERANCE); + } + + @Test + void testTrueToEccentricVersusDouble() { + // GIVEN + final Complex fieldOriginalPositionAngle = new Complex(3., 0.); + // WHEN + final double actualConvertedPositionAngle = FieldEquinoctialLongitudeArgumentUtility.trueToEccentric( + EX, EY, fieldOriginalPositionAngle).getReal(); + // THEN + final double expectedPositionAngle = CircularLatitudeArgumentUtility.trueToEccentric( + EX.getReal(), EY.getReal(), fieldOriginalPositionAngle.getReal()); + Assertions.assertEquals(expectedPositionAngle, actualConvertedPositionAngle, TOLERANCE); + } + + @Test + void testTrueToMeanVersusDouble() { + // GIVEN + final Complex fieldOriginalPositionAngle = new Complex(3., 0.); + // WHEN + final double actualConvertedPositionAngle = FieldEquinoctialLongitudeArgumentUtility.trueToMean( + EX, EY, fieldOriginalPositionAngle).getReal(); + // THEN + final double expectedPositionAngle = CircularLatitudeArgumentUtility.trueToMean( + EX.getReal(), EY.getReal(), fieldOriginalPositionAngle.getReal()); + Assertions.assertEquals(expectedPositionAngle, actualConvertedPositionAngle, TOLERANCE); + } + + @Test + void testEccentricToMeanVersusDouble() { + // GIVEN + final Complex fieldOriginalPositionAngle = new Complex(3., 0.); + // WHEN + final double actualConvertedPositionAngle = FieldEquinoctialLongitudeArgumentUtility.eccentricToMean( + EX, EY, fieldOriginalPositionAngle).getReal(); + // THEN + final double expectedPositionAngle = CircularLatitudeArgumentUtility.eccentricToMean( + EX.getReal(), EY.getReal(), fieldOriginalPositionAngle.getReal()); + Assertions.assertEquals(expectedPositionAngle, actualConvertedPositionAngle, TOLERANCE); + } + + @Test + void testEccentricToTrueVersusDouble() { + // GIVEN + final Complex fieldOriginalPositionAngle = new Complex(3., 0.); + // WHEN + final double actualConvertedPositionAngle = FieldEquinoctialLongitudeArgumentUtility.eccentricToTrue( + EX, EY, fieldOriginalPositionAngle).getReal(); + // THEN + final double expectedPositionAngle = CircularLatitudeArgumentUtility.eccentricToTrue( + EX.getReal(), EY.getReal(), fieldOriginalPositionAngle.getReal()); + Assertions.assertEquals(expectedPositionAngle, actualConvertedPositionAngle, TOLERANCE); + } + + @Test + void testMeanToEccentricException() { + // GIVEN + final Complex fieldNaNPositionAngle = Complex.NaN; + // WHEN & THEN + Assertions.assertThrows(OrekitException.class, () -> FieldEquinoctialLongitudeArgumentUtility.meanToEccentric(EX, + EY, fieldNaNPositionAngle), OrekitMessages.UNABLE_TO_COMPUTE_ECCENTRIC_LONGITUDE_ARGUMENT.toString()); + } + +} \ No newline at end of file From ac69eecd66d950e0afda613d5f4ece757991349f Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Mon, 4 Dec 2023 08:51:27 +0100 Subject: [PATCH 012/359] =?UTF-8?q?Renamed=20SaastamoinenModel=20=E2=86=92?= =?UTF-8?q?=20ModifiedSaastamoinenModel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../EstimatedTroposphericModel.java | 6 +- .../ModifiedSaastamoinenModel.java | 456 ++++++++++++++++++ .../earth/troposphere/SaastamoinenModel.java | 401 +-------------- .../common/AbstractOrbitDetermination.java | 4 +- .../measurements/BistaticRangeRateTest.java | 6 +- .../measurements/BistaticRangeTest.java | 6 +- .../estimation/measurements/Range2Test.java | 6 +- .../measurements/RangeAnalyticTest.java | 6 +- .../measurements/RangeRateTest.java | 6 +- .../estimation/measurements/RangeTest.java | 6 +- .../estimation/measurements/TDOATest.java | 6 +- .../TurnAroundRangeAnalyticTest.java | 6 +- .../measurements/TurnAroundRangeTest.java | 6 +- .../modifiers/TropoModifierTest.java | 18 +- .../ModifiedSaastamoinenModelTest.java | 437 +++++++++++++++++ .../troposphere/SaastamoinenModelTest.java | 2 +- 16 files changed, 960 insertions(+), 418 deletions(-) create mode 100644 src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java create mode 100644 src/test/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModelTest.java diff --git a/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java b/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java index ece77cc7c0..90749f2e7e 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java @@ -45,7 +45,7 @@ * the {@link GlobalMappingFunctionModel Global Mapping Function}, or * the {@link NiellMappingFunctionModel Niell Mapping Function} *

              - * The tropospheric zenith delay δh is computed empirically with a {@link SaastamoinenModel} + * The tropospheric zenith delay δh is computed empirically with a {@link ModifiedSaastamoinenModel} * while the tropospheric total zenith delay δt is estimated as a {@link ParameterDriver} */ public class EstimatedTroposphericModel implements DiscreteTroposphericModel { @@ -105,7 +105,7 @@ public List getParametersDrivers() { public double pathDelay(final double elevation, final GeodeticPoint point, final double[] parameters, final AbsoluteDate date) { // Use an empirical model for tropospheric zenith hydro-static delay : Saastamoinen model - final SaastamoinenModel saastamoinen = new SaastamoinenModel(t0, p0, 0.0); + final ModifiedSaastamoinenModel saastamoinen = new ModifiedSaastamoinenModel(t0, p0, 0.0); // Zenith delays. elevation = pi/2 because we compute the delay in the zenith direction final double zhd = saastamoinen.pathDelay(0.5 * FastMath.PI, point, parameters, date); final double ztd = parameters[0]; @@ -120,7 +120,7 @@ public double pathDelay(final double elevation, final GeodeticPoint point, public > T pathDelay(final T elevation, final FieldGeodeticPoint point, final T[] parameters, final FieldAbsoluteDate date) { // Use an empirical model for tropospheric zenith hydro-static delay : Saastamoinen model - final SaastamoinenModel saastamoinen = new SaastamoinenModel(t0, p0, 0.0); + final ModifiedSaastamoinenModel saastamoinen = new ModifiedSaastamoinenModel(t0, p0, 0.0); // Zenith delays. elevation = pi/2 because we compute the delay in the zenith direction final T zhd = saastamoinen.pathDelay(elevation.getPi().multiply(0.5), point, parameters, date); final T ztd = parameters[0]; diff --git a/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java b/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java new file mode 100644 index 0000000000..ab03d5ac66 --- /dev/null +++ b/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java @@ -0,0 +1,456 @@ +/* Copyright 2011-2012 Space Applications Services + * Licensed to CS Communication & Systèmes (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import java.util.Collections; +import java.util.List; +import java.util.regex.Pattern; + +import org.hipparchus.CalculusFieldElement; +import org.hipparchus.Field; +import org.hipparchus.analysis.interpolation.BilinearInterpolatingFunction; +import org.hipparchus.analysis.interpolation.LinearInterpolator; +import org.hipparchus.analysis.polynomials.PolynomialFunction; +import org.hipparchus.analysis.polynomials.PolynomialSplineFunction; +import org.hipparchus.util.FastMath; +import org.orekit.annotation.DefaultDataContext; +import org.orekit.bodies.FieldGeodeticPoint; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.data.DataContext; +import org.orekit.data.DataProvidersManager; +import org.orekit.errors.OrekitException; +import org.orekit.errors.OrekitMessages; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; +import org.orekit.utils.InterpolationTableLoader; +import org.orekit.utils.ParameterDriver; + +/** The modified Saastamoinen model. Estimates the path delay imposed to + * electro-magnetic signals by the troposphere according to the formula: + *

              + * δ = 2.277e-3 / cos z * (P + (1255 / T + 0.05) * e - B * tan²
              + * z) + δR
              + * 
              + * with the following input data provided to the model: + *
                + *
              • z: zenith angle
              • + *
              • P: atmospheric pressure
              • + *
              • T: temperature
              • + *
              • e: partial pressure of water vapour
              • + *
              • B, δR: correction terms
              • + *
              + *

              + * The model supports custom δR correction terms to be read from a + * configuration file (saastamoinen-correction.txt) via the + * {@link DataProvidersManager}. + *

              + * @author Thomas Neidhart + * @see "Guochang Xu, GPS - Theory, Algorithms and Applications, Springer, 2007" + */ +public class ModifiedSaastamoinenModel implements DiscreteTroposphericModel { + + /** Default file name for δR correction term table. */ + public static final String DELTA_R_FILE_NAME = "^saastamoinen-correction\\.txt$"; + + /** Default lowest acceptable elevation angle [rad]. */ + public static final double DEFAULT_LOW_ELEVATION_THRESHOLD = 0.05; + + /** First pattern for δR correction term table. */ + private static final Pattern FIRST_DELTA_R_PATTERN = Pattern.compile("^\\^"); + + /** Second pattern for δR correction term table. */ + private static final Pattern SECOND_DELTA_R_PATTERN = Pattern.compile("\\$$"); + + /** X values for the B function. */ + private static final double[] X_VALUES_FOR_B = { + 0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0 + }; + + /** E values for the B function. */ + private static final double[] Y_VALUES_FOR_B = { + 1.156, 1.079, 1.006, 0.938, 0.874, 0.813, 0.757, 0.654, 0.563 + }; + + /** Coefficients for the partial pressure of water vapor polynomial. */ + private static final double[] E_COEFFICIENTS = { + -37.2465, 0.213166, -0.000256908 + }; + + /** Interpolation function for the B correction term. */ + private final PolynomialSplineFunction bFunction; + + /** Polynomial function for the e term. */ + private final PolynomialFunction eFunction; + + /** Interpolation function for the delta R correction term. */ + private final BilinearInterpolatingFunction deltaRFunction; + + /** The temperature at the station [K]. */ + private double t0; + + /** The atmospheric pressure [mbar]. */ + private double p0; + + /** The humidity [percent]. */ + private double r0; + + /** Lowest acceptable elevation angle [rad]. */ + private double lowElevationThreshold; + + /** + * Create a new Saastamoinen model for the troposphere using the given environmental + * conditions and table from the reference book. + * + * @param t0 the temperature at the station [K] + * @param p0 the atmospheric pressure at the station [mbar] + * @param r0 the humidity at the station [fraction] (50% -> 0.5) + * @see #ModifiedSaastamoinenModel(double, double, double, String, DataProvidersManager) + * @since 10.1 + */ + public ModifiedSaastamoinenModel(final double t0, final double p0, final double r0) { + this(t0, p0, r0, defaultDeltaR()); + } + + /** Create a new Saastamoinen model for the troposphere using the given + * environmental conditions. This constructor uses the {@link DataContext#getDefault() + * default data context} if {@code deltaRFileName != null}. + * + * @param t0 the temperature at the station [K] + * @param p0 the atmospheric pressure at the station [mbar] + * @param r0 the humidity at the station [fraction] (50% -> 0.5) + * @param deltaRFileName regular expression for filename containing δR + * correction term table (typically {@link #DELTA_R_FILE_NAME}), if null + * default values from the reference book are used + * @since 7.1 + * @see #ModifiedSaastamoinenModel(double, double, double, String, DataProvidersManager) + */ + @DefaultDataContext + public ModifiedSaastamoinenModel(final double t0, final double p0, final double r0, + final String deltaRFileName) { + this(t0, p0, r0, deltaRFileName, + DataContext.getDefault().getDataProvidersManager()); + } + + /** Create a new Saastamoinen model for the troposphere using the given + * environmental conditions. This constructor allows the user to specify the source of + * of the δR file. + * + * @param t0 the temperature at the station [K] + * @param p0 the atmospheric pressure at the station [mbar] + * @param r0 the humidity at the station [fraction] (50% -> 0.5) + * @param deltaRFileName regular expression for filename containing δR + * correction term table (typically {@link #DELTA_R_FILE_NAME}), if null + * default values from the reference book are used + * @param dataProvidersManager provides access to auxiliary data. + * @since 10.1 + */ + public ModifiedSaastamoinenModel(final double t0, + final double p0, + final double r0, + final String deltaRFileName, + final DataProvidersManager dataProvidersManager) { + this(t0, p0, r0, + deltaRFileName == null ? + defaultDeltaR() : + loadDeltaR(deltaRFileName, dataProvidersManager)); + } + + /** Create a new Saastamoinen model. + * + * @param t0 the temperature at the station [K] + * @param p0 the atmospheric pressure at the station [mbar] + * @param r0 the humidity at the station [fraction] (50% -> 0.5) + * @param deltaR δR correction term function + * @since 7.1 + */ + private ModifiedSaastamoinenModel(final double t0, final double p0, final double r0, + final BilinearInterpolatingFunction deltaR) { + checkParameterRangeInclusive("humidity", r0, 0.0, 1.0); + this.t0 = t0; + this.p0 = p0; + this.r0 = r0; + this.bFunction = new LinearInterpolator().interpolate(X_VALUES_FOR_B, Y_VALUES_FOR_B); + this.eFunction = new PolynomialFunction(E_COEFFICIENTS); + this.deltaRFunction = deltaR; + this.lowElevationThreshold = DEFAULT_LOW_ELEVATION_THRESHOLD; + } + + /** Create a new Saastamoinen model using a standard atmosphere model. + * + *
                + *
              • temperature: 18 degree Celsius + *
              • pressure: 1013.25 mbar + *
              • humidity: 50% + *
              + * + * @return a Saastamoinen model with standard environmental values + */ + public static ModifiedSaastamoinenModel getStandardModel() { + return new ModifiedSaastamoinenModel(273.16 + 18, 1013.25, 0.5); + } + + /** Check if the given parameter is within an acceptable range. + * The bounds are inclusive: an exception is raised when either of those conditions are met: + *
                + *
              • The parameter is strictly greater than upperBound
              • + *
              • The parameter is strictly lower than lowerBound
              • + *
              + *

              + * In either of these cases, an OrekitException is raised. + *

              + * @param parameterName name of the parameter + * @param parameter value of the parameter + * @param lowerBound lower bound of the acceptable range (inclusive) + * @param upperBound upper bound of the acceptable range (inclusive) + */ + private void checkParameterRangeInclusive(final String parameterName, final double parameter, + final double lowerBound, final double upperBound) { + if (parameter < lowerBound || parameter > upperBound) { + throw new OrekitException(OrekitMessages.INVALID_PARAMETER_RANGE, parameterName, + parameter, lowerBound, upperBound); + } + } + + /** {@inheritDoc} + *

              + * The Saastamoinen model is not defined for altitudes below 0.0. for continuity + * reasons, we use the value for h = 0 when altitude is negative. + *

              + *

              + * There are also numerical issues for elevation angles close to zero. For continuity reasons, + * elevations lower than a threshold will use the value obtained + * for the threshold itself. + *

              + * @see #getLowElevationThreshold() + * @see #setLowElevationThreshold(double) + */ + @Override + public double pathDelay(final double elevation, final GeodeticPoint point, + final double[] parameters, final AbsoluteDate date) { + + // there are no data in the model for negative altitudes and altitude bigger than 5000 m + // limit the height to a range of [0, 5000] m + final double fixedHeight = FastMath.min(FastMath.max(0, point.getAltitude()), 5000); + + // the corrected temperature using a temperature gradient of -6.5 K/km + final double T = t0 - 6.5e-3 * fixedHeight; + // the corrected pressure + final double P = p0 * FastMath.pow(1.0 - 2.26e-5 * fixedHeight, 5.225); + // the corrected humidity + final double R = r0 * FastMath.exp(-6.396e-4 * fixedHeight); + + // interpolate the b correction term + final double B = bFunction.value(fixedHeight / 1e3); + // calculate e + final double e = R * FastMath.exp(eFunction.value(T)); + + // calculate the zenith angle from the elevation + final double z = FastMath.abs(0.5 * FastMath.PI - FastMath.max(elevation, lowElevationThreshold)); + + // get correction factor + final double deltaR = getDeltaR(fixedHeight, z); + + // calculate the path delay in m + final double tan = FastMath.tan(z); + final double delta = 2.277e-3 / FastMath.cos(z) * + (P + (1255d / T + 5e-2) * e - B * tan * tan) + deltaR; + + return delta; + } + + /** {@inheritDoc} + *

              + * The Saastamoinen model is not defined for altitudes below 0.0. for continuity + * reasons, we use the value for h = 0 when altitude is negative. + *

              + *

              + * There are also numerical issues for elevation angles close to zero. For continuity reasons, + * elevations lower than a threshold will use the value obtained + * for the threshold itself. + *

              + * @see #getLowElevationThreshold() + * @see #setLowElevationThreshold(double) + */ + @Override + public > T pathDelay(final T elevation, final FieldGeodeticPoint point, + final T[] parameters, final FieldAbsoluteDate date) { + + final Field field = date.getField(); + final T zero = field.getZero(); + // there are no data in the model for negative altitudes and altitude bigger than 5000 m + // limit the height to a range of [0, 5000] m + final T fixedHeight = FastMath.min(FastMath.max(zero, point.getAltitude()), zero.add(5000)); + + // the corrected temperature using a temperature gradient of -6.5 K/km + final T T = fixedHeight.multiply(6.5e-3).negate().add(t0); + // the corrected pressure + final T P = fixedHeight.multiply(2.26e-5).negate().add(1.0).pow(5.225).multiply(p0); + // the corrected humidity + final T R = FastMath.exp(fixedHeight.multiply(-6.396e-4)).multiply(r0); + + // interpolate the b correction term + final T B = bFunction.value(fixedHeight.divide(1e3)); + // calculate e + final T e = R.multiply(FastMath.exp(eFunction.value(T))); + + // calculate the zenith angle from the elevation + final T z = FastMath.abs(FastMath.max(elevation, zero.add(lowElevationThreshold)).negate().add(zero.getPi().multiply(0.5))); + + // get correction factor + final T deltaR = getDeltaR(fixedHeight, z, field); + + // calculate the path delay in m + final T tan = FastMath.tan(z); + final T delta = FastMath.cos(z).divide(2.277e-3).reciprocal(). + multiply(P.add(T.divide(1255d).reciprocal().add(5e-2).multiply(e)).subtract(B.multiply(tan).multiply(tan))).add(deltaR); + + return delta; + } + + /** Calculates the delta R correction term using linear interpolation. + * @param height the height of the station in m + * @param zenith the zenith angle of the satellite + * @return the delta R correction term in m + */ + private double getDeltaR(final double height, final double zenith) { + // limit the height to a range of [0, 5000] m + final double h = FastMath.min(FastMath.max(0, height), 5000); + // limit the zenith angle to 90 degree + // Note: the function is symmetric for negative zenith angles + final double z = FastMath.min(Math.abs(zenith), 0.5 * FastMath.PI); + return deltaRFunction.value(h, z); + } + + /** Calculates the delta R correction term using linear interpolation. + * @param type of the elements + * @param height the height of the station in m + * @param zenith the zenith angle of the satellite + * @param field field used by default + * @return the delta R correction term in m + */ + private > T getDeltaR(final T height, final T zenith, + final Field field) { + final T zero = field.getZero(); + // limit the height to a range of [0, 5000] m + final T h = FastMath.min(FastMath.max(zero, height), zero.add(5000)); + // limit the zenith angle to 90 degree + // Note: the function is symmetric for negative zenith angles + final T z = FastMath.min(zenith.abs(), zero.getPi().multiply(0.5)); + return deltaRFunction.value(h, z); + } + + /** Load δR function. + * @param deltaRFileName regular expression for filename containing δR + * correction term table + * @param dataProvidersManager provides access to auxiliary data. + * @return δR function + */ + private static BilinearInterpolatingFunction loadDeltaR( + final String deltaRFileName, + final DataProvidersManager dataProvidersManager) { + + // read the δR interpolation function from the config file + final InterpolationTableLoader loader = new InterpolationTableLoader(); + dataProvidersManager.feed(deltaRFileName, loader); + if (!loader.stillAcceptsData()) { + final double[] elevations = loader.getOrdinateGrid(); + for (int i = 0; i < elevations.length; ++i) { + elevations[i] = FastMath.toRadians(elevations[i]); + } + return new BilinearInterpolatingFunction(loader.getAbscissaGrid(), elevations, + loader.getValuesSamples()); + } + throw new OrekitException(OrekitMessages.UNABLE_TO_FIND_FILE, + SECOND_DELTA_R_PATTERN. + matcher(FIRST_DELTA_R_PATTERN.matcher(deltaRFileName).replaceAll("")). + replaceAll("")); + } + + /** Create the default δR function. + * @return δR function + */ + private static BilinearInterpolatingFunction defaultDeltaR() { + + // the correction table in the referenced book only contains values for an angle of 60 - 80 + // degree, thus for 0 degree, the correction term is assumed to be 0, for degrees > 80 it + // is assumed to be the same value as for 80. + + // the height in m + final double[] xValForR = { + 0, 500, 1000, 1500, 2000, 3000, 4000, 5000 + }; + + // the zenith angle + final double[] yValForR = { + FastMath.toRadians( 0.00), FastMath.toRadians(60.00), FastMath.toRadians(66.00), FastMath.toRadians(70.00), + FastMath.toRadians(73.00), FastMath.toRadians(75.00), FastMath.toRadians(76.00), FastMath.toRadians(77.00), + FastMath.toRadians(78.00), FastMath.toRadians(78.50), FastMath.toRadians(79.00), FastMath.toRadians(79.50), + FastMath.toRadians(79.75), FastMath.toRadians(80.00), FastMath.toRadians(90.00) + }; + + final double[][] fval = new double[][] { + { + 0.000, 0.003, 0.006, 0.012, 0.020, 0.031, 0.039, 0.050, 0.065, 0.075, 0.087, 0.102, 0.111, 0.121, 0.121 + }, { + 0.000, 0.003, 0.006, 0.011, 0.018, 0.028, 0.035, 0.045, 0.059, 0.068, 0.079, 0.093, 0.101, 0.110, 0.110 + }, { + 0.000, 0.002, 0.005, 0.010, 0.017, 0.025, 0.032, 0.041, 0.054, 0.062, 0.072, 0.085, 0.092, 0.100, 0.100 + }, { + 0.000, 0.002, 0.005, 0.009, 0.015, 0.023, 0.029, 0.037, 0.049, 0.056, 0.065, 0.077, 0.083, 0.091, 0.091 + }, { + 0.000, 0.002, 0.004, 0.008, 0.013, 0.021, 0.026, 0.033, 0.044, 0.051, 0.059, 0.070, 0.076, 0.083, 0.083 + }, { + 0.000, 0.002, 0.003, 0.006, 0.011, 0.017, 0.021, 0.027, 0.036, 0.042, 0.049, 0.058, 0.063, 0.068, 0.068 + }, { + 0.000, 0.001, 0.003, 0.005, 0.009, 0.014, 0.017, 0.022, 0.030, 0.034, 0.040, 0.047, 0.052, 0.056, 0.056 + }, { + 0.000, 0.001, 0.002, 0.004, 0.007, 0.011, 0.014, 0.018, 0.024, 0.028, 0.033, 0.039, 0.043, 0.047, 0.047 + } + }; + + // the actual delta R is interpolated using a a bilinear interpolator + return new BilinearInterpolatingFunction(xValForR, yValForR, fval); + + } + + /** {@inheritDoc} */ + @Override + public List getParametersDrivers() { + return Collections.emptyList(); + } + + /** Get the low elevation threshold value for path delay computation. + * @return low elevation threshold, in rad. + * @see #pathDelay(double, GeodeticPoint, double[], AbsoluteDate) + * @see #pathDelay(CalculusFieldElement, FieldGeodeticPoint, CalculusFieldElement[], FieldAbsoluteDate) + * @since 10.2 + */ + public double getLowElevationThreshold() { + return lowElevationThreshold; + } + + /** Set the low elevation threshold value for path delay computation. + * @param lowElevationThreshold The new value for the threshold [rad] + * @see #pathDelay(double, GeodeticPoint, double[], AbsoluteDate) + * @see #pathDelay(CalculusFieldElement, FieldGeodeticPoint, CalculusFieldElement[], FieldAbsoluteDate) + * @since 10.2 + */ + public void setLowElevationThreshold(final double lowElevationThreshold) { + this.lowElevationThreshold = lowElevationThreshold; + } +} + diff --git a/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java b/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java index 78c9c99883..b4fb6da29e 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java @@ -1,4 +1,4 @@ -/* Copyright 2011-2012 Space Applications Services +/* Copyright 2023 Thales Alenia Space * Licensed to CS Communication & Systèmes (CS) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. @@ -16,100 +16,22 @@ */ package org.orekit.models.earth.troposphere; -import java.util.Collections; -import java.util.List; -import java.util.regex.Pattern; - -import org.hipparchus.CalculusFieldElement; -import org.hipparchus.Field; -import org.hipparchus.analysis.interpolation.BilinearInterpolatingFunction; -import org.hipparchus.analysis.interpolation.LinearInterpolator; -import org.hipparchus.analysis.polynomials.PolynomialFunction; -import org.hipparchus.analysis.polynomials.PolynomialSplineFunction; -import org.hipparchus.util.FastMath; import org.orekit.annotation.DefaultDataContext; -import org.orekit.bodies.FieldGeodeticPoint; -import org.orekit.bodies.GeodeticPoint; import org.orekit.data.DataContext; import org.orekit.data.DataProvidersManager; -import org.orekit.errors.OrekitException; -import org.orekit.errors.OrekitMessages; -import org.orekit.time.AbsoluteDate; -import org.orekit.time.FieldAbsoluteDate; -import org.orekit.utils.InterpolationTableLoader; -import org.orekit.utils.ParameterDriver; -/** The modified Saastamoinen model. Estimates the path delay imposed to - * electro-magnetic signals by the troposphere according to the formula: - *
              - * δ = 2.277e-3 / cos z * (P + (1255 / T + 0.05) * e - B * tan²
              - * z) + δR
              - * 
              - * with the following input data provided to the model: - *
                - *
              • z: zenith angle
              • - *
              • P: atmospheric pressure
              • - *
              • T: temperature
              • - *
              • e: partial pressure of water vapour
              • - *
              • B, δR: correction terms
              • - *
              - *

              - * The model supports custom δR correction terms to be read from a - * configuration file (saastamoinen-correction.txt) via the - * {@link DataProvidersManager}. - *

              - * @author Thomas Neidhart - * @see "Guochang Xu, GPS - Theory, Algorithms and Applications, Springer, 2007" +/** The modified Saastamoinen model. + * @author Luc Maisonobe + * @deprecated as of 12.1, replaced by {@link ModifiedSaastamoinenModel} */ -public class SaastamoinenModel implements DiscreteTroposphericModel { +@Deprecated +public class SaastamoinenModel extends ModifiedSaastamoinenModel { /** Default file name for δR correction term table. */ - public static final String DELTA_R_FILE_NAME = "^saastamoinen-correction\\.txt$"; + public static final String DELTA_R_FILE_NAME = ModifiedSaastamoinenModel.DELTA_R_FILE_NAME; /** Default lowest acceptable elevation angle [rad]. */ - public static final double DEFAULT_LOW_ELEVATION_THRESHOLD = 0.05; - - /** First pattern for δR correction term table. */ - private static final Pattern FIRST_DELTA_R_PATTERN = Pattern.compile("^\\^"); - - /** Second pattern for δR correction term table. */ - private static final Pattern SECOND_DELTA_R_PATTERN = Pattern.compile("\\$$"); - - /** X values for the B function. */ - private static final double[] X_VALUES_FOR_B = { - 0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0 - }; - - /** E values for the B function. */ - private static final double[] Y_VALUES_FOR_B = { - 1.156, 1.079, 1.006, 0.938, 0.874, 0.813, 0.757, 0.654, 0.563 - }; - - /** Coefficients for the partial pressure of water vapor polynomial. */ - private static final double[] E_COEFFICIENTS = { - -37.2465, 0.213166, -0.000256908 - }; - - /** Interpolation function for the B correction term. */ - private final PolynomialSplineFunction bFunction; - - /** Polynomial function for the e term. */ - private final PolynomialFunction eFunction; - - /** Interpolation function for the delta R correction term. */ - private final BilinearInterpolatingFunction deltaRFunction; - - /** The temperature at the station [K]. */ - private double t0; - - /** The atmospheric pressure [mbar]. */ - private double p0; - - /** The humidity [percent]. */ - private double r0; - - /** Lowest acceptable elevation angle [rad]. */ - private double lowElevationThreshold; + public static final double DEFAULT_LOW_ELEVATION_THRESHOLD = ModifiedSaastamoinenModel.DEFAULT_LOW_ELEVATION_THRESHOLD; /** * Create a new Saastamoinen model for the troposphere using the given environmental @@ -118,11 +40,11 @@ public class SaastamoinenModel implements DiscreteTroposphericModel { * @param t0 the temperature at the station [K] * @param p0 the atmospheric pressure at the station [mbar] * @param r0 the humidity at the station [fraction] (50% -> 0.5) - * @see #SaastamoinenModel(double, double, double, String, DataProvidersManager) + * @see #ModifiedSaastamoinenModel(double, double, double, String, DataProvidersManager) * @since 10.1 */ public SaastamoinenModel(final double t0, final double p0, final double r0) { - this(t0, p0, r0, defaultDeltaR()); + super(t0, p0, r0); } /** Create a new Saastamoinen model for the troposphere using the given @@ -136,13 +58,12 @@ public SaastamoinenModel(final double t0, final double p0, final double r0) { * correction term table (typically {@link #DELTA_R_FILE_NAME}), if null * default values from the reference book are used * @since 7.1 - * @see #SaastamoinenModel(double, double, double, String, DataProvidersManager) + * @see #ModifiedSaastamoinenModel(double, double, double, String, DataProvidersManager) */ @DefaultDataContext public SaastamoinenModel(final double t0, final double p0, final double r0, final String deltaRFileName) { - this(t0, p0, r0, deltaRFileName, - DataContext.getDefault().getDataProvidersManager()); + super(t0, p0, r0, deltaRFileName); } /** Create a new Saastamoinen model for the troposphere using the given @@ -163,294 +84,22 @@ public SaastamoinenModel(final double t0, final double r0, final String deltaRFileName, final DataProvidersManager dataProvidersManager) { - this(t0, p0, r0, - deltaRFileName == null ? - defaultDeltaR() : - loadDeltaR(deltaRFileName, dataProvidersManager)); - } - - /** Create a new Saastamoinen model. - * - * @param t0 the temperature at the station [K] - * @param p0 the atmospheric pressure at the station [mbar] - * @param r0 the humidity at the station [fraction] (50% -> 0.5) - * @param deltaR δR correction term function - * @since 7.1 - */ - private SaastamoinenModel(final double t0, final double p0, final double r0, - final BilinearInterpolatingFunction deltaR) { - checkParameterRangeInclusive("humidity", r0, 0.0, 1.0); - this.t0 = t0; - this.p0 = p0; - this.r0 = r0; - this.bFunction = new LinearInterpolator().interpolate(X_VALUES_FOR_B, Y_VALUES_FOR_B); - this.eFunction = new PolynomialFunction(E_COEFFICIENTS); - this.deltaRFunction = deltaR; - this.lowElevationThreshold = DEFAULT_LOW_ELEVATION_THRESHOLD; + super(t0, p0, r0, deltaRFileName, dataProvidersManager); } /** Create a new Saastamoinen model using a standard atmosphere model. - * - *
                - *
              • temperature: 18 degree Celsius - *
              • pressure: 1013.25 mbar - *
              • humidity: 50% - *
              - * - * @return a Saastamoinen model with standard environmental values - */ - public static SaastamoinenModel getStandardModel() { - return new SaastamoinenModel(273.16 + 18, 1013.25, 0.5); - } - - /** Check if the given parameter is within an acceptable range. - * The bounds are inclusive: an exception is raised when either of those conditions are met: - *
                - *
              • The parameter is strictly greater than upperBound
              • - *
              • The parameter is strictly lower than lowerBound
              • - *
              - *

              - * In either of these cases, an OrekitException is raised. - *

              - * @param parameterName name of the parameter - * @param parameter value of the parameter - * @param lowerBound lower bound of the acceptable range (inclusive) - * @param upperBound upper bound of the acceptable range (inclusive) - */ - private void checkParameterRangeInclusive(final String parameterName, final double parameter, - final double lowerBound, final double upperBound) { - if (parameter < lowerBound || parameter > upperBound) { - throw new OrekitException(OrekitMessages.INVALID_PARAMETER_RANGE, parameterName, - parameter, lowerBound, upperBound); - } - } - - /** {@inheritDoc} - *

              - * The Saastamoinen model is not defined for altitudes below 0.0. for continuity - * reasons, we use the value for h = 0 when altitude is negative. - *

              - *

              - * There are also numerical issues for elevation angles close to zero. For continuity reasons, - * elevations lower than a threshold will use the value obtained - * for the threshold itself. - *

              - * @see #getLowElevationThreshold() - * @see #setLowElevationThreshold(double) - */ - @Override - public double pathDelay(final double elevation, final GeodeticPoint point, - final double[] parameters, final AbsoluteDate date) { + * + *
                + *
              • temperature: 18 degree Celsius + *
              • pressure: 1013.25 mbar + *
              • humidity: 50% + *
              + * + * @return a Saastamoinen model with standard environmental values + */ + public static SaastamoinenModel getStandardModel() { + return new SaastamoinenModel(273.16 + 18, 1013.25, 0.5); + } - // there are no data in the model for negative altitudes and altitude bigger than 5000 m - // limit the height to a range of [0, 5000] m - final double fixedHeight = FastMath.min(FastMath.max(0, point.getAltitude()), 5000); - - // the corrected temperature using a temperature gradient of -6.5 K/km - final double T = t0 - 6.5e-3 * fixedHeight; - // the corrected pressure - final double P = p0 * FastMath.pow(1.0 - 2.26e-5 * fixedHeight, 5.225); - // the corrected humidity - final double R = r0 * FastMath.exp(-6.396e-4 * fixedHeight); - - // interpolate the b correction term - final double B = bFunction.value(fixedHeight / 1e3); - // calculate e - final double e = R * FastMath.exp(eFunction.value(T)); - - // calculate the zenith angle from the elevation - final double z = FastMath.abs(0.5 * FastMath.PI - FastMath.max(elevation, lowElevationThreshold)); - - // get correction factor - final double deltaR = getDeltaR(fixedHeight, z); - - // calculate the path delay in m - final double tan = FastMath.tan(z); - final double delta = 2.277e-3 / FastMath.cos(z) * - (P + (1255d / T + 5e-2) * e - B * tan * tan) + deltaR; - - return delta; - } - - /** {@inheritDoc} - *

              - * The Saastamoinen model is not defined for altitudes below 0.0. for continuity - * reasons, we use the value for h = 0 when altitude is negative. - *

              - *

              - * There are also numerical issues for elevation angles close to zero. For continuity reasons, - * elevations lower than a threshold will use the value obtained - * for the threshold itself. - *

              - * @see #getLowElevationThreshold() - * @see #setLowElevationThreshold(double) - */ - @Override - public > T pathDelay(final T elevation, final FieldGeodeticPoint point, - final T[] parameters, final FieldAbsoluteDate date) { - - final Field field = date.getField(); - final T zero = field.getZero(); - // there are no data in the model for negative altitudes and altitude bigger than 5000 m - // limit the height to a range of [0, 5000] m - final T fixedHeight = FastMath.min(FastMath.max(zero, point.getAltitude()), zero.add(5000)); - - // the corrected temperature using a temperature gradient of -6.5 K/km - final T T = fixedHeight.multiply(6.5e-3).negate().add(t0); - // the corrected pressure - final T P = fixedHeight.multiply(2.26e-5).negate().add(1.0).pow(5.225).multiply(p0); - // the corrected humidity - final T R = FastMath.exp(fixedHeight.multiply(-6.396e-4)).multiply(r0); - - // interpolate the b correction term - final T B = bFunction.value(fixedHeight.divide(1e3)); - // calculate e - final T e = R.multiply(FastMath.exp(eFunction.value(T))); - - // calculate the zenith angle from the elevation - final T z = FastMath.abs(FastMath.max(elevation, zero.add(lowElevationThreshold)).negate().add(zero.getPi().multiply(0.5))); - - // get correction factor - final T deltaR = getDeltaR(fixedHeight, z, field); - - // calculate the path delay in m - final T tan = FastMath.tan(z); - final T delta = FastMath.cos(z).divide(2.277e-3).reciprocal(). - multiply(P.add(T.divide(1255d).reciprocal().add(5e-2).multiply(e)).subtract(B.multiply(tan).multiply(tan))).add(deltaR); - - return delta; - } - - /** Calculates the delta R correction term using linear interpolation. - * @param height the height of the station in m - * @param zenith the zenith angle of the satellite - * @return the delta R correction term in m - */ - private double getDeltaR(final double height, final double zenith) { - // limit the height to a range of [0, 5000] m - final double h = FastMath.min(FastMath.max(0, height), 5000); - // limit the zenith angle to 90 degree - // Note: the function is symmetric for negative zenith angles - final double z = FastMath.min(Math.abs(zenith), 0.5 * FastMath.PI); - return deltaRFunction.value(h, z); - } - - /** Calculates the delta R correction term using linear interpolation. - * @param type of the elements - * @param height the height of the station in m - * @param zenith the zenith angle of the satellite - * @param field field used by default - * @return the delta R correction term in m - */ - private > T getDeltaR(final T height, final T zenith, - final Field field) { - final T zero = field.getZero(); - // limit the height to a range of [0, 5000] m - final T h = FastMath.min(FastMath.max(zero, height), zero.add(5000)); - // limit the zenith angle to 90 degree - // Note: the function is symmetric for negative zenith angles - final T z = FastMath.min(zenith.abs(), zero.getPi().multiply(0.5)); - return deltaRFunction.value(h, z); - } - - /** Load δR function. - * @param deltaRFileName regular expression for filename containing δR - * correction term table - * @param dataProvidersManager provides access to auxiliary data. - * @return δR function - */ - private static BilinearInterpolatingFunction loadDeltaR( - final String deltaRFileName, - final DataProvidersManager dataProvidersManager) { - - // read the δR interpolation function from the config file - final InterpolationTableLoader loader = new InterpolationTableLoader(); - dataProvidersManager.feed(deltaRFileName, loader); - if (!loader.stillAcceptsData()) { - final double[] elevations = loader.getOrdinateGrid(); - for (int i = 0; i < elevations.length; ++i) { - elevations[i] = FastMath.toRadians(elevations[i]); - } - return new BilinearInterpolatingFunction(loader.getAbscissaGrid(), elevations, - loader.getValuesSamples()); - } - throw new OrekitException(OrekitMessages.UNABLE_TO_FIND_FILE, - SECOND_DELTA_R_PATTERN. - matcher(FIRST_DELTA_R_PATTERN.matcher(deltaRFileName).replaceAll("")). - replaceAll("")); - } - - /** Create the default δR function. - * @return δR function - */ - private static BilinearInterpolatingFunction defaultDeltaR() { - - // the correction table in the referenced book only contains values for an angle of 60 - 80 - // degree, thus for 0 degree, the correction term is assumed to be 0, for degrees > 80 it - // is assumed to be the same value as for 80. - - // the height in m - final double[] xValForR = { - 0, 500, 1000, 1500, 2000, 3000, 4000, 5000 - }; - - // the zenith angle - final double[] yValForR = { - FastMath.toRadians( 0.00), FastMath.toRadians(60.00), FastMath.toRadians(66.00), FastMath.toRadians(70.00), - FastMath.toRadians(73.00), FastMath.toRadians(75.00), FastMath.toRadians(76.00), FastMath.toRadians(77.00), - FastMath.toRadians(78.00), FastMath.toRadians(78.50), FastMath.toRadians(79.00), FastMath.toRadians(79.50), - FastMath.toRadians(79.75), FastMath.toRadians(80.00), FastMath.toRadians(90.00) - }; - - final double[][] fval = new double[][] { - { - 0.000, 0.003, 0.006, 0.012, 0.020, 0.031, 0.039, 0.050, 0.065, 0.075, 0.087, 0.102, 0.111, 0.121, 0.121 - }, { - 0.000, 0.003, 0.006, 0.011, 0.018, 0.028, 0.035, 0.045, 0.059, 0.068, 0.079, 0.093, 0.101, 0.110, 0.110 - }, { - 0.000, 0.002, 0.005, 0.010, 0.017, 0.025, 0.032, 0.041, 0.054, 0.062, 0.072, 0.085, 0.092, 0.100, 0.100 - }, { - 0.000, 0.002, 0.005, 0.009, 0.015, 0.023, 0.029, 0.037, 0.049, 0.056, 0.065, 0.077, 0.083, 0.091, 0.091 - }, { - 0.000, 0.002, 0.004, 0.008, 0.013, 0.021, 0.026, 0.033, 0.044, 0.051, 0.059, 0.070, 0.076, 0.083, 0.083 - }, { - 0.000, 0.002, 0.003, 0.006, 0.011, 0.017, 0.021, 0.027, 0.036, 0.042, 0.049, 0.058, 0.063, 0.068, 0.068 - }, { - 0.000, 0.001, 0.003, 0.005, 0.009, 0.014, 0.017, 0.022, 0.030, 0.034, 0.040, 0.047, 0.052, 0.056, 0.056 - }, { - 0.000, 0.001, 0.002, 0.004, 0.007, 0.011, 0.014, 0.018, 0.024, 0.028, 0.033, 0.039, 0.043, 0.047, 0.047 - } - }; - - // the actual delta R is interpolated using a a bilinear interpolator - return new BilinearInterpolatingFunction(xValForR, yValForR, fval); - - } - - /** {@inheritDoc} */ - @Override - public List getParametersDrivers() { - return Collections.emptyList(); - } - - /** Get the low elevation threshold value for path delay computation. - * @return low elevation threshold, in rad. - * @see #pathDelay(double, GeodeticPoint, double[], AbsoluteDate) - * @see #pathDelay(CalculusFieldElement, FieldGeodeticPoint, CalculusFieldElement[], FieldAbsoluteDate) - * @since 10.2 - */ - public double getLowElevationThreshold() { - return lowElevationThreshold; - } - - /** Set the low elevation threshold value for path delay computation. - * @param lowElevationThreshold The new value for the threshold [rad] - * @see #pathDelay(double, GeodeticPoint, double[], AbsoluteDate) - * @see #pathDelay(CalculusFieldElement, FieldGeodeticPoint, CalculusFieldElement[], FieldAbsoluteDate) - * @since 10.2 - */ - public void setLowElevationThreshold(final double lowElevationThreshold) { - this.lowElevationThreshold = lowElevationThreshold; - } } diff --git a/src/test/java/org/orekit/estimation/common/AbstractOrbitDetermination.java b/src/test/java/org/orekit/estimation/common/AbstractOrbitDetermination.java index 828255b177..b84ca47992 100644 --- a/src/test/java/org/orekit/estimation/common/AbstractOrbitDetermination.java +++ b/src/test/java/org/orekit/estimation/common/AbstractOrbitDetermination.java @@ -137,7 +137,7 @@ import org.orekit.models.earth.troposphere.MappingFunction; import org.orekit.models.earth.troposphere.MendesPavlisModel; import org.orekit.models.earth.troposphere.NiellMappingFunctionModel; -import org.orekit.models.earth.troposphere.SaastamoinenModel; +import org.orekit.models.earth.troposphere.ModifiedSaastamoinenModel; import org.orekit.models.earth.troposphere.TimeSpanEstimatedTroposphericModel; import org.orekit.models.earth.weather.GlobalPressureTemperatureModel; import org.orekit.orbits.CartesianOrbit; @@ -1678,7 +1678,7 @@ private Map createStationsData(final KeyValueFileParser measurement : measurements) { @@ -324,7 +324,7 @@ public void testParameterDerivativesWithModifier() { 1.0, 3.0, 300.0); propagator.clearStepHandlers(); - final BistaticRangeRateTroposphericDelayModifier modifier = new BistaticRangeRateTroposphericDelayModifier(SaastamoinenModel.getStandardModel()); + final BistaticRangeRateTroposphericDelayModifier modifier = new BistaticRangeRateTroposphericDelayModifier(ModifiedSaastamoinenModel.getStandardModel()); double maxRelativeError = 0; for (final ObservedMeasurement measurement : measurements) { diff --git a/src/test/java/org/orekit/estimation/measurements/BistaticRangeTest.java b/src/test/java/org/orekit/estimation/measurements/BistaticRangeTest.java index 93602f795d..cc70a99746 100644 --- a/src/test/java/org/orekit/estimation/measurements/BistaticRangeTest.java +++ b/src/test/java/org/orekit/estimation/measurements/BistaticRangeTest.java @@ -26,7 +26,7 @@ import org.orekit.estimation.Context; import org.orekit.estimation.EstimationTestUtils; import org.orekit.estimation.measurements.modifiers.BistaticRangeTroposphericDelayModifier; -import org.orekit.models.earth.troposphere.SaastamoinenModel; +import org.orekit.models.earth.troposphere.ModifiedSaastamoinenModel; import org.orekit.orbits.OrbitType; import org.orekit.orbits.PositionAngleType; import org.orekit.propagation.Propagator; @@ -169,7 +169,7 @@ public void testStateDerivativesWithModifier() { 1.0, 3.0, 300.0); propagator.clearStepHandlers(); - final BistaticRangeTroposphericDelayModifier modifier = new BistaticRangeTroposphericDelayModifier(SaastamoinenModel.getStandardModel()); + final BistaticRangeTroposphericDelayModifier modifier = new BistaticRangeTroposphericDelayModifier(ModifiedSaastamoinenModel.getStandardModel()); double maxRelativeError = 0; for (final ObservedMeasurement measurement : measurements) { @@ -325,7 +325,7 @@ public void testParameterDerivativesWithModifier() { 1.0, 3.0, 300.0); propagator.clearStepHandlers(); - final BistaticRangeTroposphericDelayModifier modifier = new BistaticRangeTroposphericDelayModifier(SaastamoinenModel.getStandardModel()); + final BistaticRangeTroposphericDelayModifier modifier = new BistaticRangeTroposphericDelayModifier(ModifiedSaastamoinenModel.getStandardModel()); double maxRelativeError = 0; for (final ObservedMeasurement measurement : measurements) { diff --git a/src/test/java/org/orekit/estimation/measurements/Range2Test.java b/src/test/java/org/orekit/estimation/measurements/Range2Test.java index 64c9502ca8..6b97fb5a91 100644 --- a/src/test/java/org/orekit/estimation/measurements/Range2Test.java +++ b/src/test/java/org/orekit/estimation/measurements/Range2Test.java @@ -28,7 +28,7 @@ import org.orekit.estimation.Context; import org.orekit.estimation.EstimationTestUtils; import org.orekit.estimation.measurements.modifiers.RangeTroposphericDelayModifier; -import org.orekit.models.earth.troposphere.SaastamoinenModel; +import org.orekit.models.earth.troposphere.ModifiedSaastamoinenModel; import org.orekit.orbits.OrbitType; import org.orekit.orbits.PositionAngleType; import org.orekit.propagation.Propagator; @@ -330,7 +330,7 @@ void genericTestStateDerivatives(final boolean isModifier, final boolean printRe ) { // Add modifiers if test implies it - final RangeTroposphericDelayModifier modifier = new RangeTroposphericDelayModifier(SaastamoinenModel.getStandardModel()); + final RangeTroposphericDelayModifier modifier = new RangeTroposphericDelayModifier(ModifiedSaastamoinenModel.getStandardModel()); if (isModifier) { ((Range) measurement).addModifier(modifier); } @@ -481,7 +481,7 @@ void genericTestParameterDerivatives(final boolean isModifier, final boolean pri ) { // Add modifiers if test implies it - final RangeTroposphericDelayModifier modifier = new RangeTroposphericDelayModifier(SaastamoinenModel.getStandardModel()); + final RangeTroposphericDelayModifier modifier = new RangeTroposphericDelayModifier(ModifiedSaastamoinenModel.getStandardModel()); if (isModifier) { ((Range) measurement).addModifier(modifier); } diff --git a/src/test/java/org/orekit/estimation/measurements/RangeAnalyticTest.java b/src/test/java/org/orekit/estimation/measurements/RangeAnalyticTest.java index a03097bd43..7bb17a32be 100644 --- a/src/test/java/org/orekit/estimation/measurements/RangeAnalyticTest.java +++ b/src/test/java/org/orekit/estimation/measurements/RangeAnalyticTest.java @@ -31,7 +31,7 @@ import org.orekit.estimation.Context; import org.orekit.estimation.EstimationTestUtils; import org.orekit.estimation.measurements.modifiers.RangeTroposphericDelayModifier; -import org.orekit.models.earth.troposphere.SaastamoinenModel; +import org.orekit.models.earth.troposphere.ModifiedSaastamoinenModel; import org.orekit.orbits.OrbitType; import org.orekit.orbits.PositionAngleType; import org.orekit.propagation.Propagator; @@ -361,7 +361,7 @@ void genericTestStateDerivatives(final boolean isModifier, final boolean isFinit ) { // Add modifiers if test implies it - final RangeTroposphericDelayModifier modifier = new RangeTroposphericDelayModifier(SaastamoinenModel.getStandardModel()); + final RangeTroposphericDelayModifier modifier = new RangeTroposphericDelayModifier(ModifiedSaastamoinenModel.getStandardModel()); if (isModifier) { ((Range) measurement).addModifier(modifier); } @@ -536,7 +536,7 @@ void genericTestParameterDerivatives(final boolean isModifier, final boolean isF ) { // Add modifiers if test implies it - final RangeTroposphericDelayModifier modifier = new RangeTroposphericDelayModifier(SaastamoinenModel.getStandardModel()); + final RangeTroposphericDelayModifier modifier = new RangeTroposphericDelayModifier(ModifiedSaastamoinenModel.getStandardModel()); if (isModifier) { ((Range) measurement).addModifier(modifier); } diff --git a/src/test/java/org/orekit/estimation/measurements/RangeRateTest.java b/src/test/java/org/orekit/estimation/measurements/RangeRateTest.java index 92b5a2b083..dc5c4d480e 100644 --- a/src/test/java/org/orekit/estimation/measurements/RangeRateTest.java +++ b/src/test/java/org/orekit/estimation/measurements/RangeRateTest.java @@ -27,7 +27,7 @@ import org.orekit.estimation.measurements.modifiers.RangeRateTroposphericDelayModifier; import org.orekit.models.earth.troposphere.EstimatedTroposphericModel; import org.orekit.models.earth.troposphere.GlobalMappingFunctionModel; -import org.orekit.models.earth.troposphere.SaastamoinenModel; +import org.orekit.models.earth.troposphere.ModifiedSaastamoinenModel; import org.orekit.orbits.OrbitType; import org.orekit.orbits.PositionAngleType; import org.orekit.propagation.Propagator; @@ -463,7 +463,7 @@ public void testStateDerivativesWithModifier() { double maxRelativeError = 0; for (final ObservedMeasurement measurement : measurements) { - final RangeRateTroposphericDelayModifier modifier = new RangeRateTroposphericDelayModifier(SaastamoinenModel.getStandardModel(), true); + final RangeRateTroposphericDelayModifier modifier = new RangeRateTroposphericDelayModifier(ModifiedSaastamoinenModel.getStandardModel(), true); ((RangeRate) measurement).addModifier(modifier); // @@ -610,7 +610,7 @@ public void testParameterDerivativesWithModifier() { double maxRelativeError = 0; for (final ObservedMeasurement measurement : measurements) { - final RangeRateTroposphericDelayModifier modifier = new RangeRateTroposphericDelayModifier(SaastamoinenModel.getStandardModel(), true); + final RangeRateTroposphericDelayModifier modifier = new RangeRateTroposphericDelayModifier(ModifiedSaastamoinenModel.getStandardModel(), true); ((RangeRate) measurement).addModifier(modifier); // parameter corresponding to station position offset diff --git a/src/test/java/org/orekit/estimation/measurements/RangeTest.java b/src/test/java/org/orekit/estimation/measurements/RangeTest.java index 1c2eef63ed..c4c8fd34fd 100644 --- a/src/test/java/org/orekit/estimation/measurements/RangeTest.java +++ b/src/test/java/org/orekit/estimation/measurements/RangeTest.java @@ -33,7 +33,7 @@ import org.orekit.estimation.measurements.modifiers.RangeTroposphericDelayModifier; import org.orekit.models.earth.troposphere.EstimatedTroposphericModel; import org.orekit.models.earth.troposphere.NiellMappingFunctionModel; -import org.orekit.models.earth.troposphere.SaastamoinenModel; +import org.orekit.models.earth.troposphere.ModifiedSaastamoinenModel; import org.orekit.orbits.OrbitType; import org.orekit.orbits.PositionAngleType; import org.orekit.propagation.Propagator; @@ -350,7 +350,7 @@ void genericTestStateDerivatives(final boolean isModifier, final boolean printRe ) { // Add modifiers if test implies it - final RangeTroposphericDelayModifier modifier = new RangeTroposphericDelayModifier(SaastamoinenModel.getStandardModel()); + final RangeTroposphericDelayModifier modifier = new RangeTroposphericDelayModifier(ModifiedSaastamoinenModel.getStandardModel()); if (isModifier) { ((Range) measurement).addModifier(modifier); } @@ -501,7 +501,7 @@ void genericTestParameterDerivatives(final boolean isModifier, final boolean pri ) { // Add modifiers if test implies it - final RangeTroposphericDelayModifier modifier = new RangeTroposphericDelayModifier(SaastamoinenModel.getStandardModel()); + final RangeTroposphericDelayModifier modifier = new RangeTroposphericDelayModifier(ModifiedSaastamoinenModel.getStandardModel()); if (isModifier) { ((Range) measurement).addModifier(modifier); } diff --git a/src/test/java/org/orekit/estimation/measurements/TDOATest.java b/src/test/java/org/orekit/estimation/measurements/TDOATest.java index 12e06855e0..7d22a02194 100644 --- a/src/test/java/org/orekit/estimation/measurements/TDOATest.java +++ b/src/test/java/org/orekit/estimation/measurements/TDOATest.java @@ -26,7 +26,7 @@ import org.orekit.estimation.Context; import org.orekit.estimation.EstimationTestUtils; import org.orekit.estimation.measurements.modifiers.TDOATroposphericDelayModifier; -import org.orekit.models.earth.troposphere.SaastamoinenModel; +import org.orekit.models.earth.troposphere.ModifiedSaastamoinenModel; import org.orekit.orbits.OrbitType; import org.orekit.orbits.PositionAngleType; import org.orekit.propagation.Propagator; @@ -170,7 +170,7 @@ public void testStateDerivativesWithModifier() { // create a modifier final TDOATroposphericDelayModifier modifier = - new TDOATroposphericDelayModifier(SaastamoinenModel.getStandardModel()); + new TDOATroposphericDelayModifier(ModifiedSaastamoinenModel.getStandardModel()); double maxRelativeError = 0; for (final ObservedMeasurement measurement : measurements) { @@ -328,7 +328,7 @@ public void testParameterDerivativesWithModifier() { // create a modifier final TDOATroposphericDelayModifier modifier = - new TDOATroposphericDelayModifier(SaastamoinenModel.getStandardModel()); + new TDOATroposphericDelayModifier(ModifiedSaastamoinenModel.getStandardModel()); double maxRelativeError = 0; for (final ObservedMeasurement measurement : measurements) { diff --git a/src/test/java/org/orekit/estimation/measurements/TurnAroundRangeAnalyticTest.java b/src/test/java/org/orekit/estimation/measurements/TurnAroundRangeAnalyticTest.java index 4a2d52d6a0..80a9c81040 100644 --- a/src/test/java/org/orekit/estimation/measurements/TurnAroundRangeAnalyticTest.java +++ b/src/test/java/org/orekit/estimation/measurements/TurnAroundRangeAnalyticTest.java @@ -31,7 +31,7 @@ import org.orekit.estimation.Context; import org.orekit.estimation.EstimationTestUtils; import org.orekit.estimation.measurements.modifiers.TurnAroundRangeTroposphericDelayModifier; -import org.orekit.models.earth.troposphere.SaastamoinenModel; +import org.orekit.models.earth.troposphere.ModifiedSaastamoinenModel; import org.orekit.orbits.OrbitType; import org.orekit.orbits.PositionAngleType; import org.orekit.propagation.Propagator; @@ -366,7 +366,7 @@ void genericTestStateDerivatives(final boolean isModifier, final boolean isFinit // Add modifiers if test implies it final TurnAroundRangeTroposphericDelayModifier modifier = - new TurnAroundRangeTroposphericDelayModifier(SaastamoinenModel.getStandardModel()); + new TurnAroundRangeTroposphericDelayModifier(ModifiedSaastamoinenModel.getStandardModel()); if (isModifier) { ((TurnAroundRange) measurement).addModifier(modifier); } @@ -538,7 +538,7 @@ void genericTestParameterDerivatives(final boolean isModifier, final boolean isF for (final ObservedMeasurement measurement : measurements) { // Add modifiers if test implies it - final TurnAroundRangeTroposphericDelayModifier modifier = new TurnAroundRangeTroposphericDelayModifier(SaastamoinenModel.getStandardModel()); + final TurnAroundRangeTroposphericDelayModifier modifier = new TurnAroundRangeTroposphericDelayModifier(ModifiedSaastamoinenModel.getStandardModel()); if (isModifier) { ((TurnAroundRange) measurement).addModifier(modifier); } diff --git a/src/test/java/org/orekit/estimation/measurements/TurnAroundRangeTest.java b/src/test/java/org/orekit/estimation/measurements/TurnAroundRangeTest.java index 2b6187d55d..a9c0eed8fc 100644 --- a/src/test/java/org/orekit/estimation/measurements/TurnAroundRangeTest.java +++ b/src/test/java/org/orekit/estimation/measurements/TurnAroundRangeTest.java @@ -31,7 +31,7 @@ import org.orekit.estimation.Context; import org.orekit.estimation.EstimationTestUtils; import org.orekit.estimation.measurements.modifiers.TurnAroundRangeTroposphericDelayModifier; -import org.orekit.models.earth.troposphere.SaastamoinenModel; +import org.orekit.models.earth.troposphere.ModifiedSaastamoinenModel; import org.orekit.orbits.OrbitType; import org.orekit.orbits.PositionAngleType; import org.orekit.propagation.Propagator; @@ -309,7 +309,7 @@ void genericTestStateDerivatives(final boolean isModifier, final boolean printRe // Add modifiers if test implies it final TurnAroundRangeTroposphericDelayModifier modifier = - new TurnAroundRangeTroposphericDelayModifier(SaastamoinenModel.getStandardModel()); + new TurnAroundRangeTroposphericDelayModifier(ModifiedSaastamoinenModel.getStandardModel()); if (isModifier) { ((TurnAroundRange) measurement).addModifier(modifier); } @@ -456,7 +456,7 @@ void genericTestParameterDerivatives(final boolean isModifier, final boolean pri for (final ObservedMeasurement measurement : measurements) { // Add modifiers if test implies it - final TurnAroundRangeTroposphericDelayModifier modifier = new TurnAroundRangeTroposphericDelayModifier(SaastamoinenModel.getStandardModel()); + final TurnAroundRangeTroposphericDelayModifier modifier = new TurnAroundRangeTroposphericDelayModifier(ModifiedSaastamoinenModel.getStandardModel()); if (isModifier) { ((TurnAroundRange) measurement).addModifier(modifier); } diff --git a/src/test/java/org/orekit/estimation/measurements/modifiers/TropoModifierTest.java b/src/test/java/org/orekit/estimation/measurements/modifiers/TropoModifierTest.java index 67a5b4b684..a9610c86cf 100644 --- a/src/test/java/org/orekit/estimation/measurements/modifiers/TropoModifierTest.java +++ b/src/test/java/org/orekit/estimation/measurements/modifiers/TropoModifierTest.java @@ -52,7 +52,7 @@ import org.orekit.models.earth.EarthITU453AtmosphereRefraction; import org.orekit.models.earth.troposphere.EstimatedTroposphericModel; import org.orekit.models.earth.troposphere.NiellMappingFunctionModel; -import org.orekit.models.earth.troposphere.SaastamoinenModel; +import org.orekit.models.earth.troposphere.ModifiedSaastamoinenModel; import org.orekit.orbits.OrbitType; import org.orekit.orbits.PositionAngleType; import org.orekit.propagation.Propagator; @@ -97,7 +97,7 @@ public void testRangeTropoModifier() { 1.0, 3.0, 300.0); propagator.clearStepHandlers(); - final RangeTroposphericDelayModifier modifier = new RangeTroposphericDelayModifier(SaastamoinenModel.getStandardModel()); + final RangeTroposphericDelayModifier modifier = new RangeTroposphericDelayModifier(ModifiedSaastamoinenModel.getStandardModel()); for (final ObservedMeasurement measurement : measurements) { final AbsoluteDate date = measurement.getDate(); @@ -198,7 +198,7 @@ public void testPhaseTropoModifier() { 1.0, 3.0, 300.0); propagator.clearStepHandlers(); - final PhaseTroposphericDelayModifier modifier = new PhaseTroposphericDelayModifier(SaastamoinenModel.getStandardModel()); + final PhaseTroposphericDelayModifier modifier = new PhaseTroposphericDelayModifier(ModifiedSaastamoinenModel.getStandardModel()); for (final ObservedMeasurement measurement : measurements) { final AbsoluteDate date = measurement.getDate(); @@ -306,7 +306,7 @@ public void testTurnAroundRangeTropoModifier() { 1.0, 3.0, 300.0); propagator.clearStepHandlers(); - final TurnAroundRangeTroposphericDelayModifier modifier = new TurnAroundRangeTroposphericDelayModifier(SaastamoinenModel.getStandardModel()); + final TurnAroundRangeTroposphericDelayModifier modifier = new TurnAroundRangeTroposphericDelayModifier(ModifiedSaastamoinenModel.getStandardModel()); for (final ObservedMeasurement measurement : measurements) { final AbsoluteDate date = measurement.getDate(); @@ -357,7 +357,7 @@ public void testBistaticRangeTropoModifier() { propagator.clearStepHandlers(); final BistaticRangeTroposphericDelayModifier modifier = - new BistaticRangeTroposphericDelayModifier(SaastamoinenModel.getStandardModel()); + new BistaticRangeTroposphericDelayModifier(ModifiedSaastamoinenModel.getStandardModel()); for (final ObservedMeasurement measurement : measurements) { BistaticRange biRange = (BistaticRange) measurement; @@ -408,7 +408,7 @@ public void testBistaticRangeRateTropoModifier() { propagator.clearStepHandlers(); final BistaticRangeRateTroposphericDelayModifier modifier = - new BistaticRangeRateTroposphericDelayModifier(SaastamoinenModel.getStandardModel()); + new BistaticRangeRateTroposphericDelayModifier(ModifiedSaastamoinenModel.getStandardModel()); for (final ObservedMeasurement measurement : measurements) { BistaticRangeRate biRangeRate = (BistaticRangeRate) measurement; @@ -520,7 +520,7 @@ public void testTDOATropoModifier() { propagator.clearStepHandlers(); final TDOATroposphericDelayModifier modifier = - new TDOATroposphericDelayModifier(SaastamoinenModel.getStandardModel()); + new TDOATroposphericDelayModifier(ModifiedSaastamoinenModel.getStandardModel()); for (final ObservedMeasurement measurement : measurements) { TDOA tdoa = (TDOA) measurement; @@ -625,7 +625,7 @@ public void testRangeRateTropoModifier() { 1.0, 3.0, 300.0); propagator.clearStepHandlers(); - final RangeRateTroposphericDelayModifier modifier = new RangeRateTroposphericDelayModifier(SaastamoinenModel.getStandardModel(), false); + final RangeRateTroposphericDelayModifier modifier = new RangeRateTroposphericDelayModifier(ModifiedSaastamoinenModel.getStandardModel(), false); for (final ObservedMeasurement measurement : measurements) { final AbsoluteDate date = measurement.getDate(); @@ -722,7 +722,7 @@ public void testAngularTropoModifier() { 1.0, 3.0, 300.0); propagator.clearStepHandlers(); - final AngularTroposphericDelayModifier modifier = new AngularTroposphericDelayModifier(SaastamoinenModel.getStandardModel()); + final AngularTroposphericDelayModifier modifier = new AngularTroposphericDelayModifier(ModifiedSaastamoinenModel.getStandardModel()); for (final ObservedMeasurement measurement : measurements) { final AbsoluteDate date = measurement.getDate(); diff --git a/src/test/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModelTest.java new file mode 100644 index 0000000000..02c2008ba0 --- /dev/null +++ b/src/test/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModelTest.java @@ -0,0 +1,437 @@ +/* Copyright 2011-2012 Space Applications Services + * Licensed to CS Communication & Systèmes (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import org.hipparchus.CalculusFieldElement; +import org.hipparchus.Field; +import org.hipparchus.util.Binary64Field; +import org.hipparchus.util.FastMath; +import org.hipparchus.util.Precision; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.orekit.Utils; +import org.orekit.bodies.FieldGeodeticPoint; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.errors.OrekitException; +import org.orekit.errors.OrekitMessages; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; + + +public class ModifiedSaastamoinenModelTest { + + private static double epsilon = 1e-6; + + private double[][] expectedValues; + + private double[] elevations; + + private double[] heights; + + @Test + public void testIssue1078() { + try { + new ModifiedSaastamoinenModel(273.16 + 18, 1013.25, 50.0); + } catch (OrekitException oe) { + Assertions.assertEquals(OrekitMessages.INVALID_PARAMETER_RANGE, oe.getSpecifier()); + } + try { + new ModifiedSaastamoinenModel(273.16 + 18, 1013.25, -50.0); + } catch (OrekitException oe) { + Assertions.assertEquals(OrekitMessages.INVALID_PARAMETER_RANGE, oe.getSpecifier()); + } + } + + @Test + public void testFixedElevation() { + Utils.setDataRoot("atmosphere"); + ModifiedSaastamoinenModel model = ModifiedSaastamoinenModel.getStandardModel(); + double lastDelay = Double.MAX_VALUE; + // delay shall decline with increasing height of the station + for (double height = 0; height < 5000; height += 100) { + final double delay = model.pathDelay(FastMath.toRadians(5), new GeodeticPoint(0.0, 0.0, height), null, AbsoluteDate.J2000_EPOCH); + Assertions.assertTrue(Precision.compareTo(delay, lastDelay, epsilon) < 0); + lastDelay = delay; + } + } + + @Test + public void testFieldFixedElevation() { + doTestFieldFixedElevation(Binary64Field.getInstance()); + } + + private > void doTestFieldFixedElevation(final Field field) { + final T zero = field.getZero(); + Utils.setDataRoot("atmosphere"); + ModifiedSaastamoinenModel model = ModifiedSaastamoinenModel.getStandardModel(); + T lastDelay = zero.add(Double.MAX_VALUE); + // delay shall decline with increasing height of the station + for (double height = 0; height < 5000; height += 100) { + final T delay = model.pathDelay(zero.add(FastMath.toRadians(5)), new FieldGeodeticPoint<>(zero, zero, zero.add(height)), null, FieldAbsoluteDate.getJ2000Epoch(field)); + Assertions.assertTrue(Precision.compareTo(delay.getReal(), lastDelay.getReal(), epsilon) < 0); + lastDelay = delay; + } + } + + @Test + public void testFixedHeight() { + Utils.setDataRoot("atmosphere"); + ModifiedSaastamoinenModel model = ModifiedSaastamoinenModel.getStandardModel(); + double lastDelay = Double.MAX_VALUE; + // delay shall decline with increasing elevation angle + for (double elev = 10d; elev < 90d; elev += 8d) { + final double delay = model.pathDelay(FastMath.toRadians(elev), new GeodeticPoint(0.0, 0.0, 350.0), null, AbsoluteDate.J2000_EPOCH); + Assertions.assertTrue(Precision.compareTo(delay, lastDelay, epsilon) < 0); + lastDelay = delay; + } + } + + @Test + public void testFieldFixedHeight() { + doTestFieldFixedHeight(Binary64Field.getInstance()); + } + + private > void doTestFieldFixedHeight(final Field field) { + final T zero = field.getZero(); + Utils.setDataRoot("atmosphere"); + ModifiedSaastamoinenModel model = ModifiedSaastamoinenModel.getStandardModel(); + T lastDelay = zero.add(Double.MAX_VALUE); + // delay shall decline with increasing elevation angle + for (double elev = 10d; elev < 90d; elev += 8d) { + final T delay = model.pathDelay(zero.add(FastMath.toRadians(elev)), new FieldGeodeticPoint<>(zero, zero, zero.add(350.0)), null, FieldAbsoluteDate.getJ2000Epoch(field)); + Assertions.assertTrue(Precision.compareTo(delay.getReal(), lastDelay.getReal(), epsilon) < 0); + lastDelay = delay; + } + } + + @Test + public void NoFile() { + Utils.setDataRoot("atmosphere"); + try { + new ModifiedSaastamoinenModel(273.16 + 18, 1013.25, 0.5, "^non-existent-file$"); + Assertions.fail("an exception should have been thrown"); + } catch (OrekitException oe) { + Assertions.assertEquals(OrekitMessages.UNABLE_TO_FIND_FILE, oe.getSpecifier()); + Assertions.assertEquals("non-existent-file", oe.getParts()[0]); + } + } + + @Test + public void compareDefaultAndLoaded() { + Utils.setDataRoot("atmosphere"); + ModifiedSaastamoinenModel defaultModel = new ModifiedSaastamoinenModel(273.16 + 18, 1013.25, 0.5, null); + ModifiedSaastamoinenModel loadedModel = new ModifiedSaastamoinenModel(273.16 + 18, 1013.25, 0.5, ModifiedSaastamoinenModel.DELTA_R_FILE_NAME); + double[] heights = new double[] { + 0.0, 250.0, 500.0, 750.0, 1000.0, 1250.0, 1500.0, 1750.0, 2000.0, 2250.0, 2500.0, 2750.0, 3000.0, 3250.0, + 3500.0, 3750.0, 4000.0, 4250.0, 4500.0, 4750.0, 5000.0 + }; + double[] elevations = new double[] { + FastMath.toRadians(10.0), FastMath.toRadians(15.0), FastMath.toRadians(20.0), + FastMath.toRadians(25.0), FastMath.toRadians(30.0), FastMath.toRadians(35.0), + FastMath.toRadians(40.0), FastMath.toRadians(45.0), FastMath.toRadians(50.0), + FastMath.toRadians(55.0), FastMath.toRadians(60.0), FastMath.toRadians(65.0), + FastMath.toRadians(70.0), FastMath.toRadians(75.0), FastMath.toRadians(80.0), + FastMath.toRadians(85.0), FastMath.toRadians(90.0) + }; + for (int h = 0; h < heights.length; h++) { + for (int e = 0; e < elevations.length; e++) { + double height = heights[h]; + double elevation = elevations[e]; + double expectedValue = defaultModel.pathDelay(elevation, new GeodeticPoint(0.0, 0.0, height), null, AbsoluteDate.J2000_EPOCH); + double actualValue = loadedModel.pathDelay(elevation, new GeodeticPoint(0.0, 0.0, height), null, AbsoluteDate.J2000_EPOCH); + Assertions.assertEquals(expectedValue, actualValue, epsilon, "For height=" + height + " elevation = " + + FastMath.toDegrees(elevation) + " precision not met"); + } + } + } + + @Test + public void testNegativeHeight() { + Utils.setDataRoot("atmosphere"); + ModifiedSaastamoinenModel model = ModifiedSaastamoinenModel.getStandardModel(); + final double height = -500.0; + for (double elevation = 0; elevation < FastMath.PI; elevation += 0.1) { + Assertions.assertEquals(model.pathDelay(elevation, new GeodeticPoint(0.0, 0.0, 0.0), null, AbsoluteDate.J2000_EPOCH), + model.pathDelay(elevation, new GeodeticPoint(0.0, 0.0, height), null, AbsoluteDate.J2000_EPOCH), + 1.e-10); + } + } + + @Test + public void testFieldNegativeHeight() { + doTestFieldNegativeHeight(Binary64Field.getInstance()); + } + + private > void doTestFieldNegativeHeight(final Field field) { + final T zero = field.getZero(); + Utils.setDataRoot("atmosphere"); + ModifiedSaastamoinenModel model = ModifiedSaastamoinenModel.getStandardModel(); + final T height = zero.subtract(500.0); + for (double elevation = 0; elevation < FastMath.PI; elevation += 0.1) { + Assertions.assertEquals(model.pathDelay(zero.add(elevation), new FieldGeodeticPoint<>(zero, zero, zero), null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), + model.pathDelay(zero.add(elevation), new FieldGeodeticPoint<>(zero, zero, zero.add(height)), null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), + 1.e-10); + } + } + + @Test + public void testIssue654LowElevation() { + Utils.setDataRoot("atmosphere"); + ModifiedSaastamoinenModel model = ModifiedSaastamoinenModel.getStandardModel(); + + // Test model new setter/getter + model.setLowElevationThreshold(1e-3); + Assertions.assertEquals(1.e-3, model.getLowElevationThreshold(), 0.); + + // Reset to default value + model.setLowElevationThreshold(ModifiedSaastamoinenModel.DEFAULT_LOW_ELEVATION_THRESHOLD); + double lowElevationPathDelay = model.pathDelay(0.001, new GeodeticPoint(0.0, 0.0, 0.0), null, AbsoluteDate.J2000_EPOCH); + Assertions.assertTrue(lowElevationPathDelay > 0.); + Assertions.assertEquals(model.pathDelay(model.getLowElevationThreshold(), new GeodeticPoint(0.0, 0.0, 0.0), null, AbsoluteDate.J2000_EPOCH), + lowElevationPathDelay, 1.e-10); + } + + @Test + public void testIssue654FieldLowElevation() { doTestFieldLowElevation(Binary64Field.getInstance()); } + + private > void doTestFieldLowElevation(final Field field) { + final T zero = field.getZero(); + Utils.setDataRoot("atmosphere"); + ModifiedSaastamoinenModel model = ModifiedSaastamoinenModel.getStandardModel(); + final T elevation = zero.add(0.001); + double lowElevationPathDelay = model.pathDelay(zero.add(elevation), new FieldGeodeticPoint<>(zero, zero, zero), null, + FieldAbsoluteDate.getJ2000Epoch(field)).getReal(); + double thresholdElevationPathDelay = model.pathDelay(zero.add(model.getLowElevationThreshold()), new FieldGeodeticPoint<>(zero, zero, zero), + null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(); + Assertions.assertTrue(lowElevationPathDelay > 0.); + Assertions.assertEquals(thresholdElevationPathDelay, lowElevationPathDelay, 1.e-10); + } + + @Test + public void compareExpectedValues() { + Utils.setDataRoot("atmosphere"); + ModifiedSaastamoinenModel model = ModifiedSaastamoinenModel.getStandardModel(); + + for (int h = 0; h < heights.length; h++) { + for (int e = 0; e < elevations.length; e++) { + double height = heights[h]; + double elevation = elevations[e]; + double expectedValue = expectedValues[h][e]; + double actualValue = model.pathDelay(elevation, new GeodeticPoint(0.0, 0.0, height), null, AbsoluteDate.J2000_EPOCH); + Assertions.assertEquals(expectedValue, actualValue, epsilon, "For height=" + height + " elevation = " + + FastMath.toDegrees(elevation) + " precision not met"); + } + } + } + + @Test + public void compareFieldExpectedValues() { + doCompareFieldExpectedValues(Binary64Field.getInstance()); + } + + private > void doCompareFieldExpectedValues(final Field field) { + final T zero = field.getZero(); + Utils.setDataRoot("atmosphere"); + ModifiedSaastamoinenModel model = ModifiedSaastamoinenModel.getStandardModel(); + + for (int h = 0; h < heights.length; h++) { + for (int e = 0; e < elevations.length; e++) { + T height = zero.add(heights[h]); + T elevation = zero.add(elevations[e]); + double expectedValue = expectedValues[h][e]; + T actualValue = model.pathDelay(elevation, new FieldGeodeticPoint<>(zero, zero, zero.add(height)), null, FieldAbsoluteDate.getJ2000Epoch(field)); + Assertions.assertEquals(expectedValue, actualValue.getReal(), epsilon, "For height=" + height + " elevation = " + + FastMath.toDegrees(elevation.getReal()) + " precision not met"); + } + } + } + + @Test + public void testIssue572() { + Utils.setDataRoot("atmosphere"); + ModifiedSaastamoinenModel model = ModifiedSaastamoinenModel.getStandardModel(); + final double height = 6000.0; + for (double elevation = 0; elevation < FastMath.PI; elevation += 0.1) { + Assertions.assertEquals(model.pathDelay(elevation, new GeodeticPoint(0.0, 0.0, 5000.0), null, AbsoluteDate.J2000_EPOCH), model.pathDelay(elevation, new GeodeticPoint(0.0, 0.0, height), null, AbsoluteDate.J2000_EPOCH), 1.e-10); + } + } + + @Test + public void testFieldIssue572() { + doTestFieldIssue572(Binary64Field.getInstance()); + } + + private > void doTestFieldIssue572(final Field field) { + final T zero = field.getZero(); + Utils.setDataRoot("atmosphere"); + ModifiedSaastamoinenModel model = ModifiedSaastamoinenModel.getStandardModel(); + final T height = zero.add(6000.0); + for (double elevation = 0; elevation < FastMath.PI; elevation += 0.1) { + Assertions.assertEquals(model.pathDelay(zero.add(elevation),new FieldGeodeticPoint<>(zero, zero, zero.add(5000.0)), null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), + model.pathDelay(zero.add(elevation), new FieldGeodeticPoint<>(zero, zero, zero.add(height)), null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), + 1.e-10); + } + } + + @BeforeEach + public void setUp() throws Exception { + heights = new double[] { + 0.0, 250.0, 500.0, 750.0, 1000.0, 1250.0, 1500.0, 1750.0, 2000.0, 2250.0, 2500.0, 2750.0, 3000.0, 3250.0, + 3500.0, 3750.0, 4000.0, 4250.0, 4500.0, 4750.0, 5000.0 + }; + + elevations = new double[] { + FastMath.toRadians(10.0), FastMath.toRadians(15.0), FastMath.toRadians(20.0), + FastMath.toRadians(25.0), FastMath.toRadians(30.0), FastMath.toRadians(35.0), + FastMath.toRadians(40.0), FastMath.toRadians(45.0), FastMath.toRadians(50.0), + FastMath.toRadians(55.0), FastMath.toRadians(60.0), FastMath.toRadians(65.0), + FastMath.toRadians(70.0), FastMath.toRadians(75.0), FastMath.toRadians(80.0), + FastMath.toRadians(85.0), FastMath.toRadians(90.0) + }; + + expectedValues = new double[][] { + { + 13.517414068807756, 9.204443522241771, 7.0029750138616835, 5.681588299211439, 4.8090544808193805, + 4.196707503563898, 3.7474156937027994, 3.408088733958258, 3.1468182787091985, 2.943369134588668, + 2.784381959210485, 2.6607786449639343, 2.5662805210588195, 2.496526411065139, 2.4485331622035984, + 2.420362989334734, 2.4109238764096896 + }, + { + 13.004543691989646, 8.85635958366884, 6.7385672069739835, 5.467398852004842, 4.627733401816586, + 4.038498891518074, 3.606157486803878, 3.279627416773643, 3.0282066103153564, 2.8324244661904134, + 2.6794262487842104, 2.56047665894495, 2.4695340768552505, 2.402401959167246, 2.356209754788866, + 2.329092816778967, 2.3200003434082928 + }, + { + 12.531363728988735, 8.534904937493899, 6.494310751299656, 5.269517663702665, 4.460196658874199, + 3.892306407739391, 3.475621589928269, 3.1609130970914956, 2.9185920283074447, 2.729893581384905, + 2.582428928493012, 2.4677793389442715, 2.380122124673593, 2.3154128046624067, 2.2708848382055904, + 2.2447411392156, 2.2359689784370986 + }, + { + 12.09063673875363, 8.235209195291242, 6.266604991324561, 5.084562550097057, 4.303522687504001, + 3.755568409663704, 3.353518885593948, 3.0498713508982442, 2.8160742841783275, 2.6340206738065692, + 2.4917559301110956, 2.3811563829818176, 2.2966034070866277, 2.234194258980332, 2.191259347593356, + 2.1660645619383274, 2.1576326612520003 + }, + { + 11.67727244511714, 7.953871771343415, 6.052791636499061, 4.910850401669602, 4.156351680934609, + 3.6271143683534492, 3.2388081756428404, 2.9455492155570195, 2.7197591598098305, 2.5439482552015917, + 2.4065694710150236, 2.2997761077823076, 2.218141111456481, 2.157894809849032, 2.1164586386563973, + 2.0921576169523175, 2.0840478264673044 + }, + { + 11.286432636721148, 7.688212194124222, 5.850570088713712, 4.747059102172618, 4.017661723553029, + 3.506085459183713, 3.1307362765144857, 2.8472616350388877, 2.6290036896596245, 2.459056474904878, + 2.3262584011701235, 2.223024699820715, 2.1441094810550236, 2.085868912585518, 2.0458105091517886, + 2.022315205377469, 2.0144705937765144 + }, + { + 10.915292255872545, 7.435769456080562, 5.6583502024136285, 4.591362033342799, 3.8858133055608204, + 3.391020479976734, 3.027986150306355, 2.7538117534167346, 2.5427137172039873, 2.3783406833254412, + 2.249897295933348, 2.1500476936060946, 2.0737181577274097, 2.0173844567055803, 1.978635920228296, + 1.9559066302818124, 1.9483141307804097 + }, + { + 10.560838722447652, 7.194507733765155, 5.474676340193435, 4.442196283017724, 3.759852141271757, + 3.281095182764508, 2.9298266864995415, 2.6645376694677676, 2.4602800254909183, 2.3012323491024245, + 2.1769492208902093, 2.080332602007238, 2.0064732734566384, 1.9519612730357911, 1.9144640973301363, + 1.8924666054100323, 1.8851149566358782 + }, + { + 10.221303680396087, 6.9632552008410915, 5.298576794548074, 4.299160340784349, 3.6390721146637293, + 3.175686404496119, 2.8356974323630437, 2.5789272031073223, 2.381228081225778, 2.2272865154903485, + 2.106992477081925, 2.0134758868645615, 1.9419852149640153, 1.8892200435803028, 1.8529228069725603, + 1.8316270449308856, 1.8245063513318645 + }, + { + 9.894629211990411, 6.740704058398638, 5.129125614634508, 4.161737017461952, 3.5228709097629975, + 3.0742748111390386, 2.7451382632192436, 2.4965641131187946, 2.305174987172354, 2.156146000844558, + 2.039689834231423, 1.949155743414788, 1.8799439192071106, 1.8288593407337934, 1.7937165420599064, + 1.7730958998798743, 1.7661974033814984 + }, + { + 9.579864280378851, 6.526143322382175, 4.965721065018929, 4.029207163135991, 3.4108058435845767, + 2.9764687866827866, 2.6577964388561925, 2.417125714868741, 2.2318215659378273, 2.087530132722662, + 1.9747751921856533, 1.8871174620329965, 1.820103416896286, 1.770639660836324, 1.7366102498117952, + 1.7166407238790062, 1.709956524792288 + }, + { + 9.274887896199909, 6.318551036055798, 4.807695974007752, 3.901070574943598, 3.302472329989199, + 2.881925175414427, 2.5733712370891264, 2.3403420235759187, 2.1609208036663294, 2.021209397507298, + 1.9120324913823707, 1.8271553141955852, 1.7622658032319802, 1.7143688314998151, 1.681415677692901, + 1.662075550126913, 1.6555984999945992 + }, + { + 8.979896361522131, 6.117657835260275, 4.654740323946152, 3.777036627543426, 3.197606518234132, + 2.7904044409768964, 2.4916434285107703, 2.266010367769514, 2.0922834230246177, 1.9570053034359607, + 1.851291869170061, 1.7691062591782465, 1.706273315177691, 1.6598930167213255, 1.627981703939375, + 1.6092508503238145, 1.6029743261170657 + }, + { + 8.69399537567174, 5.922971478822413, 4.5066379960473855, 3.6569305214071046, 3.0956861718504136, + 2.701448680145781, 2.412205508374445, 2.193765237935503, 2.025580422503155, 1.8946215440529706, + 1.7922869252688411, 1.7127316699243513, 1.6519133992903239, 1.6070243276625142, 1.5761438889147779, + 1.5580245420477885, 1.5519632546752067 + }, + { + 8.416815377025097, 5.734136251055505, 4.362963429392922, 3.5404077519897172, 2.996794592537471, + 2.615133166436779, 2.3351235507871273, 2.1236617698358717, 1.9608543092876316, 1.8340865056076205, + 1.735030640851246, 1.658028018024244, 1.5991650567003197, 1.555723443805895, 1.5258438192326151, + 1.5083184020062343, 1.5024665667687351 + }, + { + 8.1478867312736, 5.550837062543208, 4.223478184395355, 3.4272753528502906, 2.9007686780115858, + 2.531315719772937, 2.2602706846943197, 2.055584632739777, 1.8979986259230126, 1.7753006325382452, + 1.679428848769866, 1.60490532174873, 1.5479415024951926, 1.5059059371968162, 1.4769986856932136, + 1.4600505675451787, 1.4544027112557927 + }, + { + 7.886816833128103, 5.372810504566989, 4.087982930125399, 3.3173720077392095, 2.807472077886753, + 2.449877480332473, 2.187540848323867, 1.9894374123646559, 1.8369243760154002, 1.718180698301642, + 1.6254028270926364, 1.5532883580952295, 1.4981701861499142, 1.457501227681867, 1.4295392613913276, + 1.4131526030534576, 1.4077035129433761 + }, + { + 7.632757849842542, 5.199465832889435, 3.956158045029617, 3.2103200618121055, 2.7169983015566497, + 2.370922636048298, 2.1170374348830436, 1.9253162741272756, 1.7777165574325338, 1.6627979450991903, + 1.5730082599508786, 1.5032159322097494, 1.4498720192717967, 1.4105115179325056, 1.3834483541077152, + 1.3675873164708097, 1.3623112195283247 + }, + { + 7.385939247167236, 5.03097891384785, 3.8280091975097514, 3.1062430912053003, 2.629039083023718, + 2.294159790631063, 2.048490000181759, 1.8629731967599608, 1.720149999888605, 1.608950046027118, + 1.5220654734302106, 1.454530760098946, 1.402911820651357, 1.364823439078982, 1.3386341212762891, + 1.3232841113878862, 1.3181762050118586 + }, + { + 7.146111766814672, 4.867182513816216, 3.7034098358166165, 3.005038679030282, 2.5435078557931674, + 2.219513482041795, 1.981831207440737, 1.8023469685072222, 1.664168201116958, 1.5565841619968868, + 1.472524488341563, 1.407185083983383, 1.3572435292187972, 1.320392181006258, 1.295052611935796, + 1.2801995392223198, 1.2752551861465835 + }, + { + 6.913054711276373, 4.707928561310275, 3.58224790888857, 2.906616143639732, 2.460327972424674, + 2.14691689491338, 1.9170014355353862, 1.7433833914442447, 1.6097211330539392, 1.5056535083847744, + 1.4243410522646305, 1.3611366183164608, 1.3128263617229614, 1.277178068079704, 1.2526649111609156, + 1.238295129863562, 1.2335098392123367 + } + }; + } + +} diff --git a/src/test/java/org/orekit/models/earth/troposphere/SaastamoinenModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/SaastamoinenModelTest.java index f3676b0b5f..e02b8b1c77 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/SaastamoinenModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/SaastamoinenModelTest.java @@ -32,7 +32,7 @@ import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; - +@Deprecated public class SaastamoinenModelTest { private static double epsilon = 1e-6; From 18728a1003b6fd3470a2a354cee1ee06172a56c7 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Tue, 5 Dec 2023 10:27:13 +0100 Subject: [PATCH 013/359] Work In Progress on tropospheric models. --- .../CanonicalSaastamoinenModel.java | 260 ++++++++++++++++++ .../earth/troposphere/GiacomoDavis.java | 92 +++++++ .../earth/troposphere/MendesPavlisModel.java | 25 +- .../ModifiedSaastamoinenModel.java | 2 +- .../WaterVaporPressureProvider.java | 45 +++ .../FieldPressureTemperatureHumidity.java | 71 +++++ .../weather/PressureTemperatureHumidity.java | 68 +++++ 7 files changed, 538 insertions(+), 25 deletions(-) create mode 100644 src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java create mode 100644 src/main/java/org/orekit/models/earth/troposphere/GiacomoDavis.java create mode 100644 src/main/java/org/orekit/models/earth/troposphere/WaterVaporPressureProvider.java create mode 100644 src/main/java/org/orekit/models/earth/weather/FieldPressureTemperatureHumidity.java create mode 100644 src/main/java/org/orekit/models/earth/weather/PressureTemperatureHumidity.java diff --git a/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java b/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java new file mode 100644 index 0000000000..4d3e204344 --- /dev/null +++ b/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java @@ -0,0 +1,260 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS Communication & Systèmes (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import java.util.Collections; +import java.util.List; +import java.util.regex.Pattern; + +import org.hipparchus.CalculusFieldElement; +import org.hipparchus.Field; +import org.hipparchus.analysis.interpolation.BilinearInterpolatingFunction; +import org.hipparchus.analysis.interpolation.LinearInterpolator; +import org.hipparchus.analysis.polynomials.PolynomialFunction; +import org.hipparchus.analysis.polynomials.PolynomialSplineFunction; +import org.hipparchus.util.FastMath; +import org.orekit.annotation.DefaultDataContext; +import org.orekit.bodies.FieldGeodeticPoint; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.data.DataContext; +import org.orekit.data.DataProvidersManager; +import org.orekit.errors.OrekitException; +import org.orekit.errors.OrekitMessages; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; +import org.orekit.utils.InterpolationTableLoader; +import org.orekit.utils.ParameterDriver; + +/** The canonical Saastamoinen model. + *

              + * Estimates the path delay imposed to + * electro-magnetic signals by the troposphere according to the formula: + * \[ + * \delta = \frac{0.002277}{\cos z (1 - 0.00266\cos 2\varphi - 0.00028 h})} + * \left[P+(\frac{1255}{T}+0.005)e - B(h) \tan^2 z\right] + * \] + * with the following input data provided to the model: + *

                + *
              • z: zenith angle
              • + *
              • P: atmospheric pressure
              • + *
              • T: temperature
              • + *
              • e: partial pressure of water vapor
              • + *
              + * @author Luc Maisonobe + * @see "J Saastamoinen, Atmospheric Correction for the Troposphere and Stratosphere in Radio + * Ranging of Satellites" + * @since 12.1 + */ +public class CanonicalSaastamoinenModel implements DiscreteTroposphericModel { + + /** Default lowest acceptable elevation angle [rad]. */ + public static final double DEFAULT_LOW_ELEVATION_THRESHOLD = 0.05; + + /** X values for the B function (table 1 in reference paper). */ + private static final double[] X_VALUES_FOR_B = { + 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0, 6.0 + }; + + /** E values for the B function (table 1 in reference paper). */ + private static final double[] Y_VALUES_FOR_B = { + 1.16, 1.13, 1.10, 1.07, 1.04, 1.01, 0.94, 0.88, 0.82, 0.76, 0.66, 0.57, 0.49 + }; + + /** Interpolation function for the B correction term. */ + private final PolynomialSplineFunction bFunction; + + /** The temperature at the station [K]. */ + private double t0; + + /** The atmospheric pressure [mbar]. */ + private double p0; + + /** The humidity [percent]. */ + private double r0; + + /** Lowest acceptable elevation angle [rad]. */ + private double lowElevationThreshold; + + /** + * Create a new Saastamoinen model for the troposphere using the given environmental + * conditions and table from the reference book. + * + * @param t0 the temperature at the station [K] + * @param p0 the atmospheric pressure at the station [mbar] + * @param r0 the humidity at the station [fraction] (50% -> 0.5) + */ + public CanonicalSaastamoinenModel(final double t0, final double p0, final double r0) { + checkParameterRangeInclusive("humidity", r0, 0.0, 1.0); + this.t0 = t0; + this.p0 = p0; + this.r0 = r0; + this.bFunction = new LinearInterpolator().interpolate(X_VALUES_FOR_B, Y_VALUES_FOR_B); + this.lowElevationThreshold = DEFAULT_LOW_ELEVATION_THRESHOLD; + } + + /** Create a new Saastamoinen model using a standard atmosphere model. + * + *
                + *
              • temperature: 18 degree Celsius + *
              • pressure: 1013.25 mbar + *
              • humidity: 50% + *
              + * + * @return a Saastamoinen model with standard environmental values + */ + public static CanonicalSaastamoinenModel getStandardModel() { + return new CanonicalSaastamoinenModel(273.16 + 18, 1013.25, 0.5); + } + + /** Check if the given parameter is within an acceptable range. + * The bounds are inclusive: an exception is raised when either of those conditions are met: + *
                + *
              • The parameter is strictly greater than upperBound
              • + *
              • The parameter is strictly lower than lowerBound
              • + *
              + *

              + * In either of these cases, an OrekitException is raised. + *

              + * @param parameterName name of the parameter + * @param parameter value of the parameter + * @param lowerBound lower bound of the acceptable range (inclusive) + * @param upperBound upper bound of the acceptable range (inclusive) + */ + private void checkParameterRangeInclusive(final String parameterName, final double parameter, + final double lowerBound, final double upperBound) { + if (parameter < lowerBound || parameter > upperBound) { + throw new OrekitException(OrekitMessages.INVALID_PARAMETER_RANGE, parameterName, + parameter, lowerBound, upperBound); + } + } + + /** {@inheritDoc} + *

              + * The Saastamoinen model is not defined for altitudes below 0.0. for continuity + * reasons, we use the value for h = 0 when altitude is negative. + *

              + *

              + * There are also numerical issues for elevation angles close to zero. For continuity reasons, + * elevations lower than a threshold will use the value obtained + * for the threshold itself. + *

              + * @see #getLowElevationThreshold() + * @see #setLowElevationThreshold(double) + */ + @Override + public double pathDelay(final double elevation, final GeodeticPoint point, + final double[] parameters, final AbsoluteDate date) { + + // there are no data in the model for negative altitudes and altitude bigger than 5000 m + // limit the height to a range of [0, 5000] m + final double fixedHeight = FastMath.min(FastMath.max(0, point.getAltitude()), 5000); + + // the corrected temperature using a temperature gradient of -6.5 K/km + final double T = t0 - 6.5e-3 * fixedHeight; + // the corrected pressure + final double P = p0 * FastMath.pow(1.0 - 2.26e-5 * fixedHeight, 5.225); + // the corrected humidity + final double R = r0 * FastMath.exp(-6.396e-4 * fixedHeight); + + // interpolate the b correction term + final double B = bFunction.value(fixedHeight / 1e3); + // calculate e + final double e = R * FastMath.exp(eFunction.value(T)); + + // calculate the zenith angle from the elevation + final double z = FastMath.abs(0.5 * FastMath.PI - FastMath.max(elevation, lowElevationThreshold)); + + // calculate the path delay in m + final double tan = FastMath.tan(z); + final double delta = 2.277e-3 / FastMath.cos(z) * + (P + (1255d / T + 5e-2) * e - B * tan * tan); + + return delta; + } + + /** {@inheritDoc} + *

              + * The Saastamoinen model is not defined for altitudes below 0.0. for continuity + * reasons, we use the value for h = 0 when altitude is negative. + *

              + *

              + * There are also numerical issues for elevation angles close to zero. For continuity reasons, + * elevations lower than a threshold will use the value obtained + * for the threshold itself. + *

              + * @see #getLowElevationThreshold() + * @see #setLowElevationThreshold(double) + */ + @Override + public > T pathDelay(final T elevation, final FieldGeodeticPoint point, + final T[] parameters, final FieldAbsoluteDate date) { + + final Field field = date.getField(); + final T zero = field.getZero(); + // there are no data in the model for negative altitudes and altitude bigger than 5000 m + // limit the height to a range of [0, 5000] m + final T fixedHeight = FastMath.min(FastMath.max(zero, point.getAltitude()), zero.add(5000)); + + // the corrected temperature using a temperature gradient of -6.5 K/km + final T T = fixedHeight.multiply(6.5e-3).negate().add(t0); + // the corrected pressure + final T P = fixedHeight.multiply(2.26e-5).negate().add(1.0).pow(5.225).multiply(p0); + // the corrected humidity + final T R = FastMath.exp(fixedHeight.multiply(-6.396e-4)).multiply(r0); + + // interpolate the b correction term + final T B = bFunction.value(fixedHeight.divide(1e3)); + // calculate e + final T e = R.multiply(FastMath.exp(eFunction.value(T))); + + // calculate the zenith angle from the elevation + final T z = FastMath.abs(FastMath.max(elevation, zero.add(lowElevationThreshold)).negate().add(zero.getPi().multiply(0.5))); + + // calculate the path delay in m + final T tan = FastMath.tan(z); + final T delta = FastMath.cos(z).divide(2.277e-3).reciprocal(). + multiply(P.add(T.divide(1255d).reciprocal().add(5e-2).multiply(e)).subtract(B.multiply(tan).multiply(tan))); + + return delta; + } + + /** {@inheritDoc} */ + @Override + public List getParametersDrivers() { + return Collections.emptyList(); + } + + /** Get the low elevation threshold value for path delay computation. + * @return low elevation threshold, in rad. + * @see #pathDelay(double, GeodeticPoint, double[], AbsoluteDate) + * @see #pathDelay(CalculusFieldElement, FieldGeodeticPoint, CalculusFieldElement[], FieldAbsoluteDate) + */ + public double getLowElevationThreshold() { + return lowElevationThreshold; + } + + /** Set the low elevation threshold value for path delay computation. + * @param lowElevationThreshold The new value for the threshold [rad] + * @see #pathDelay(double, GeodeticPoint, double[], AbsoluteDate) + * @see #pathDelay(CalculusFieldElement, FieldGeodeticPoint, CalculusFieldElement[], FieldAbsoluteDate) + */ + public void setLowElevationThreshold(final double lowElevationThreshold) { + this.lowElevationThreshold = lowElevationThreshold; + } + +} + diff --git a/src/main/java/org/orekit/models/earth/troposphere/GiacomoDavis.java b/src/main/java/org/orekit/models/earth/troposphere/GiacomoDavis.java new file mode 100644 index 0000000000..3eedf53240 --- /dev/null +++ b/src/main/java/org/orekit/models/earth/troposphere/GiacomoDavis.java @@ -0,0 +1,92 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS Communication & Systèmes (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import org.hipparchus.CalculusFieldElement; +import org.hipparchus.util.FastMath; + +/** Giacomo and Davis water vapor mode. + * + * See: Giacomo, P., Equation for the determination of the density of moist air, Metrologia, V. 18, 1982 + * + * @author Bryan Cazabonne + * @author Luc Maisonobe + * @since 12.1 + */ +public class GiacomoDavis implements WaterVaporPressureProvider { + + /** Saturation water vapor coefficient. */ + private static final double E = 0.01; + + /** Laurent series coefficient for degree +2. */ + private static final double L_P2 = 1.2378847e-5; + + /** Laurent series coefficient for degree +1. */ + private static final double L_P1 = -1.9121316e-2; + + /** Laurent series coefficient for degree 0. */ + private static final double L_0 = 33.93711047; + + /** Laurent series coefficient for degree -1. */ + private static final double L_M1 = -6343.1645; + + /** Celsius temperature offset. */ + private static final double CELSIUS = 273.15; + + /** Constant enhancement factor. */ + private static final double F_0 = 1.00062; + + /** Pressure enhancement factor. */ + private static final double F_P = 3.14e-6; + + /** Temperature enhancement factor. */ + private static final double F_T2 = 5.6e-7; + + /** {@inheritDoc} */ + @Override + public double waterVaporPressure(final double t, final double p, final double rh) { + + // saturation water vapor, equation (3) of reference paper, in mbar + // with amended 1991 values (see reference paper) + final double es = FastMath.exp(t * (t * L_P2 + L_P1) + L_0 + L_M1 / t) * E; + + // enhancement factor, equation (4) of reference paper + final double tC = t - CELSIUS; + final double fw = p * F_P + tC * tC * F_T2 + F_0; + + return rh * fw * es; + + } + + /** {@inheritDoc} */ + @Override + public > T waterVaporPressure(final T t, final T p, final T rh) { + + // saturation water vapor, equation (3) of reference paper, in mbar + // with amended 1991 values (see reference paper) + final T es = FastMath.exp(t.multiply(t.multiply(L_P2).add(L_P1)).add(L_0).add(t.reciprocal().multiply(L_M1))). + multiply(E); + + // enhancement factor, equation (4) of reference paper + final T tC = t.subtract(CELSIUS); + final T fw = p.multiply(F_P).add(tC.multiply(tC).multiply(F_T2)).add(F_0); + + return rh.multiply(fw).multiply(es); + + } + +} diff --git a/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java b/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java index 4644e256b2..6e21891b80 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java @@ -86,7 +86,7 @@ public MendesPavlisModel(final double t0, final double p0, final double rh, final double lambda) { this.P0 = p0; this.T0 = t0; - this.e0 = getWaterVapor(rh); + this.e0 = new GiacomoDavis().waterVaporPressure(t0, p0, rh); this.lambda = lambda; } @@ -378,27 +378,4 @@ private > T computeMFCoeffient(final double a0 return point.getAltitude().multiply(a3).add(FastMath.cos(point.getLatitude()).multiply(a2)).add(a0 + a1 * T); } - /** Get the water vapor. - * The water vapor model is the one of Giacomo and Davis as indicated in IERS TN 32, chap. 9. - * - * See: Giacomo, P., Equation for the dertermination of the density of moist air, Metrologia, V. 18, 1982 - * - * @param rh relative humidity, in percent (50% → 0.5). - * @return the water vapor, in mbar (1 mbar = 1 hPa). - */ - private double getWaterVapor(final double rh) { - - // saturation water vapor, equation (3) of reference paper, in mbar - // with amended 1991 values (see reference paper) - final double es = 0.01 * FastMath.exp((1.2378847 * 1e-5) * T0 * T0 - - (1.9121316 * 1e-2) * T0 + - 33.93711047 - - (6.3431645 * 1e3) * 1. / T0); - - // enhancement factor, equation (4) of reference paper - final double fw = 1.00062 + (3.14 * 1e-6) * P0 + (5.6 * 1e-7) * FastMath.pow(T0 - 273.15, 2); - - final double e = rh * fw * es; - return e; - } } diff --git a/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java b/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java index ab03d5ac66..fa626a6fe6 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java @@ -80,7 +80,7 @@ public class ModifiedSaastamoinenModel implements DiscreteTroposphericModel { 0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0 }; - /** E values for the B function. */ + /** Y values for the B function. */ private static final double[] Y_VALUES_FOR_B = { 1.156, 1.079, 1.006, 0.938, 0.874, 0.813, 0.757, 0.654, 0.563 }; diff --git a/src/main/java/org/orekit/models/earth/troposphere/WaterVaporPressureProvider.java b/src/main/java/org/orekit/models/earth/troposphere/WaterVaporPressureProvider.java new file mode 100644 index 0000000000..6d3e80471b --- /dev/null +++ b/src/main/java/org/orekit/models/earth/troposphere/WaterVaporPressureProvider.java @@ -0,0 +1,45 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS Communication & Systèmes (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import org.hipparchus.CalculusFieldElement; + +/** Interface for converting relative humidity into water vapor pressure. + * @author Luc Maisonobe + * @since 12.1 + */ +public interface WaterVaporPressureProvider { + + /** Compute water vapor pressure. + * @param t temperature (Kelvin) + * @param p pressure (hPa) + * @param rh relative humidity, in percent (50% → 0.5) + * @return water vapor pressure (hPa) + */ + double waterVaporPressure(double t, double p, double rh); + + /** Compute water vapor pressure. + * @param type of the field elements + * @param t temperature (Kelvin) + * @param p pressure (hPa) + * @param rh relative humidity, in percent (50% → 0.5) + * @return water vapor pressure (hPa) + */ + > T waterVaporPressure(T t, T p, T rh); + +} + diff --git a/src/main/java/org/orekit/models/earth/weather/FieldPressureTemperatureHumidity.java b/src/main/java/org/orekit/models/earth/weather/FieldPressureTemperatureHumidity.java new file mode 100644 index 0000000000..40003dcfcc --- /dev/null +++ b/src/main/java/org/orekit/models/earth/weather/FieldPressureTemperatureHumidity.java @@ -0,0 +1,71 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.weather; + +import org.hipparchus.CalculusFieldElement; + +/** Container for pressure, temperature, and humidity. + * @param type of the field elements + * @author Luc Maisonobe + * @since 12.1 + */ +public class FieldPressureTemperatureHumidity> { + + /** Pressure (hPa). */ + private final T pressure; + + /** Temperature (Kelvin). */ + private final T temperature; + + /** Humidity as water vapor pressure (hPa). */ + private final T waterVaporPressure; + + /** Simple constructor. + * @param pressure pressure (hPa) + * @param temperature temperature (Kelvin) + * @param humidity humidity as water vapor pressure (hPa) + */ + public FieldPressureTemperatureHumidity(final T pressure, + final T temperature, + final T waterVaporPressure) { + this.pressure = pressure; + this.temperature = temperature; + this.waterVaporPressure = waterVaporPressure; + } + + /** Get pressure. + * @return pressure hPa + */ + public T getPressure() { + return pressure; + } + + /** Get temperature. + * @return temperature (Kelvin) + */ + public T getTemperature() { + return temperature; + } + + /** Get humidity as water vapor pressure. + * @return humidity as water vapor pressure (hPa) + */ + public T getWaterVaporPressure() { + return waterVaporPressure; + } + +} diff --git a/src/main/java/org/orekit/models/earth/weather/PressureTemperatureHumidity.java b/src/main/java/org/orekit/models/earth/weather/PressureTemperatureHumidity.java new file mode 100644 index 0000000000..a5bf8541c5 --- /dev/null +++ b/src/main/java/org/orekit/models/earth/weather/PressureTemperatureHumidity.java @@ -0,0 +1,68 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.weather; + +/** Container for pressure, temperature, and humidity. + * @author Luc Maisonobe + * @since 12.1 + */ +public class PressureTemperatureHumidity { + + /** Pressure (hPa). */ + private final double pressure; + + /** Temperature (Kelvin). */ + private final double temperature; + + /** Humidity as water vapor pressure (hPa). */ + private final double waterVaporPressure; + + /** Simple constructor. + * @param pressure pressure (hPa) + * @param temperature temperature (Kelvin) + * @param humidity humidity as water vapor pressure (hPa) + */ + public PressureTemperatureHumidity(final double pressure, + final double temperature, + final double waterVaporPressure) { + this.pressure = pressure; + this.temperature = temperature; + this.waterVaporPressure = waterVaporPressure; + } + + /** Get pressure. + * @return pressure hPa + */ + public double getPressure() { + return pressure; + } + + /** Get temperature. + * @return temperature (Kelvin) + */ + public double getTemperature() { + return temperature; + } + + /** Get humidity as water vapor pressure. + * @return humidity as water vapor pressure (hPa) + */ + public double getWaterVaporPressure() { + return waterVaporPressure; + } + +} From 47a51cef832e42b9a79302d19b95d2516673fdc0 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Tue, 5 Dec 2023 10:55:34 +0100 Subject: [PATCH 014/359] Typo. --- src/changes/changes.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 1cb39fe26a..ebe14aace0 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -2189,7 +2189,7 @@ view detector, measurement generation feature, possibility to use Marshall Solar Activity Future Estimation to feed NRL MSISE 2000 atmosphere model, new tropospheric models: Mendes-Pavlis, Vienna 1, Vienna 3, estimated model, new mapping functions for tropospheric effect: Global Mapping Function, Niell Mapping Function, Global - Pression Temperature Models GPT and GPT2, possibility to estimate tropospheric zenith delay, + Pressure Temperature Models GPT and GPT2, possibility to estimate tropospheric zenith delay, clock offset that can be estimated (both for ground station and satellite clocks)."> Added a way to manage clock corrections from GPSPropagator. From 43ba0252a94bb435add87ac1b12ba41875e6f4b9 Mon Sep 17 00:00:00 2001 From: Serrof Date: Tue, 5 Dec 2023 21:03:14 +0100 Subject: [PATCH 015/359] Fixed #1276: replace use of scalar multiply on Field one --- src/changes/changes.xml | 5 +- .../orekit/attitudes/AttitudesSequence.java | 4 +- .../org/orekit/attitudes/NadirPointing.java | 8 +- .../org/orekit/bodies/PosVelChebyshev.java | 12 +-- .../EstimatedEarthFrameProvider.java | 2 +- .../HolmesFeatherstoneAttractionModel.java | 2 +- .../forces/gravity/NewtonianAttraction.java | 2 +- .../ScaledConstantThrustPropulsionModel.java | 2 +- .../radiation/KnockeRediffusedForceModel.java | 4 +- .../java/org/orekit/frames/EOPHistory.java | 10 +-- .../orekit/frames/L1TransformProvider.java | 8 +- .../orekit/frames/L2TransformProvider.java | 8 +- .../org/orekit/frames/TopocentricFrame.java | 6 +- .../java/org/orekit/frames/VEISProvider.java | 2 +- .../org/orekit/gnss/attitude/GPSBlockIIA.java | 8 +- .../org/orekit/gnss/attitude/GPSBlockIIF.java | 6 +- .../org/orekit/gnss/attitude/GPSBlockIIR.java | 4 +- .../org/orekit/gnss/attitude/Galileo.java | 2 +- .../org/orekit/gnss/attitude/Glonass.java | 14 +-- .../java/org/orekit/models/earth/Geoid.java | 6 +- .../models/earth/atmosphere/DTM2000.java | 12 +-- .../earth/atmosphere/HarrisPriester.java | 4 +- .../models/earth/atmosphere/JB2008.java | 10 +-- .../models/earth/atmosphere/NRLMSISE00.java | 88 +++++++++---------- .../ionosphere/FieldNeQuickParameters.java | 31 +++---- .../earth/ionosphere/KlobucharIonoModel.java | 4 +- .../models/earth/ionosphere/NeQuickModel.java | 6 +- .../troposphere/FixedTroposphericDelay.java | 2 +- .../GlobalMappingFunctionModel.java | 16 ++-- .../earth/troposphere/MendesPavlisModel.java | 2 +- .../NiellMappingFunctionModel.java | 4 +- .../earth/troposphere/SaastamoinenModel.java | 6 +- .../troposphere/TroposphericModelUtils.java | 2 +- .../earth/troposphere/ViennaOneModel.java | 24 ++--- .../earth/troposphere/ViennaThreeModel.java | 8 +- .../orekit/orbits/FieldCartesianOrbit.java | 4 +- .../org/orekit/orbits/FieldCircularOrbit.java | 30 +++---- .../orekit/orbits/FieldEquinoctialOrbit.java | 30 +++---- .../orbits/FieldKeplerianAnomalyUtility.java | 12 +-- .../orekit/orbits/FieldKeplerianOrbit.java | 22 ++--- .../propagation/FieldSpacecraftState.java | 24 ++--- .../FieldSpacecraftStateInterpolator.java | 2 +- .../BrouwerLyddaneGradientConverter.java | 2 +- .../EcksteinHechlerGradientConverter.java | 2 +- .../FieldBrouwerLyddanePropagator.java | 2 +- .../FieldEcksteinHechlerPropagator.java | 6 +- .../analytical/FieldKeplerianPropagator.java | 9 +- .../KeplerianGradientConverter.java | 2 +- .../gnss/GLONASSAnalyticalPropagator.java | 10 +-- .../analytical/tle/FieldDeepSDP4.java | 20 ++--- .../propagation/analytical/tle/FieldSGP4.java | 2 +- .../propagation/analytical/tle/FieldTLE.java | 10 +-- .../analytical/tle/FieldTLEPropagator.java | 10 +-- .../FixedPointTleGenerationAlgorithm.java | 2 +- .../LeastSquaresTleGenerationAlgorithm.java | 2 +- ...stractFixedStepFieldIntegratorBuilder.java | 2 +- .../events/FieldAltitudeDetector.java | 6 +- .../propagation/events/FieldDateDetector.java | 2 +- .../events/FieldElevationDetector.java | 2 +- .../propagation/events/FieldEventState.java | 4 +- .../events/FieldFunctionalDetector.java | 2 +- .../events/FieldLatitudeCrossingDetector.java | 2 +- .../FieldLongitudeCrossingDetector.java | 2 +- .../propagation/events/FieldNodeDetector.java | 2 +- .../numerical/FieldNumericalPropagator.java | 4 +- .../numerical/cr3bp/CR3BPForceModel.java | 4 +- .../dsst/FieldDSSTPropagator.java | 6 +- .../forces/AbstractGaussianContribution.java | 6 +- .../forces/DSSTSolarRadiationPressure.java | 6 +- .../dsst/forces/DSSTTesseral.java | 10 +-- .../dsst/forces/DSSTThirdBody.java | 16 ++-- .../semianalytical/dsst/forces/DSSTZonal.java | 16 ++-- .../dsst/forces/FieldDSSTTesseralContext.java | 2 +- .../dsst/utilities/CoefficientsFactory.java | 2 +- .../dsst/utilities/FieldCjSjCoefficient.java | 2 +- .../dsst/utilities/FieldLnsCoefficients.java | 2 +- .../dsst/utilities/UpperBounds.java | 8 +- .../hansen/FieldHansenThirdBodyLinear.java | 2 +- .../FieldShortTermEncounter2DDefinition.java | 4 +- .../probability/twod/Laas2015.java | 10 +-- .../probability/twod/Patera2005.java | 2 +- src/main/java/org/orekit/time/BDTScale.java | 2 +- src/main/java/org/orekit/time/GPSScale.java | 2 +- .../java/org/orekit/time/GalileoScale.java | 2 +- src/main/java/org/orekit/time/IRNSSScale.java | 2 +- src/main/java/org/orekit/time/QZSSScale.java | 2 +- src/main/java/org/orekit/time/TTScale.java | 2 +- src/main/java/org/orekit/time/UTCScale.java | 2 +- .../java/org/orekit/time/UTCTAIOffset.java | 2 +- .../orekit/utils/FieldAngularCoordinates.java | 4 +- .../java/org/orekit/utils/Fieldifier.java | 76 ++++++++-------- .../org/orekit/utils/IERSConventions.java | 4 +- .../utils/ParameterDriversProvider.java | 6 +- .../TimeStampedFieldAngularCoordinates.java | 2 +- ...AngularCoordinatesHermiteInterpolator.java | 2 +- .../attitudes/FrameAlignedProviderTest.java | 2 +- 96 files changed, 389 insertions(+), 386 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 0481c0d1f2..de1a4eb91a 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -20,7 +20,10 @@ Orekit Changes - + + + Removed uses of scalar multiply on Field one. + Added utility classes for position angle conversions for (Field) CircularOrbit and EquinoctialOrbit. diff --git a/src/main/java/org/orekit/attitudes/AttitudesSequence.java b/src/main/java/org/orekit/attitudes/AttitudesSequence.java index 3daab4b3dc..6001b285b1 100644 --- a/src/main/java/org/orekit/attitudes/AttitudesSequence.java +++ b/src/main/java/org/orekit/attitudes/AttitudesSequence.java @@ -157,13 +157,13 @@ public void init(final FieldSpacecraftState s0, /** {@inheritDoc} */ @Override public T g(final FieldSpacecraftState s) { - return field.getZero().add(sw.g(s.toSpacecraftState())); + return field.getZero().newInstance(sw.g(s.toSpacecraftState())); } /** {@inheritDoc} */ @Override public T getThreshold() { - return field.getZero().add(sw.getThreshold()); + return field.getZero().newInstance(sw.getThreshold()); } /** {@inheritDoc} */ diff --git a/src/main/java/org/orekit/attitudes/NadirPointing.java b/src/main/java/org/orekit/attitudes/NadirPointing.java index 9f28620005..56923da920 100644 --- a/src/main/java/org/orekit/attitudes/NadirPointing.java +++ b/src/main/java/org/orekit/attitudes/NadirPointing.java @@ -109,11 +109,11 @@ public > TimeStampedFieldPVCoordinates getT // sample intersection points in current date neighborhood final double h = 0.01; final List> sample = new ArrayList<>(); - sample.add(nadirRef(pvProv.getPVCoordinates(date.shiftedBy(-2 * h), frame), refToBody.staticShiftedBy(zero.add(-2 * h)))); - sample.add(nadirRef(pvProv.getPVCoordinates(date.shiftedBy(-h), frame), refToBody.staticShiftedBy(zero.add(-h)))); + sample.add(nadirRef(pvProv.getPVCoordinates(date.shiftedBy(-2 * h), frame), refToBody.staticShiftedBy(zero.newInstance(-2 * h)))); + sample.add(nadirRef(pvProv.getPVCoordinates(date.shiftedBy(-h), frame), refToBody.staticShiftedBy(zero.newInstance(-h)))); sample.add(nadirRef(pvProv.getPVCoordinates(date, frame), refToBody)); - sample.add(nadirRef(pvProv.getPVCoordinates(date.shiftedBy(+h), frame), refToBody.staticShiftedBy(zero.add(+h)))); - sample.add(nadirRef(pvProv.getPVCoordinates(date.shiftedBy(+2 * h), frame), refToBody.staticShiftedBy(zero.add(+2 * h)))); + sample.add(nadirRef(pvProv.getPVCoordinates(date.shiftedBy(+h), frame), refToBody.staticShiftedBy(zero.newInstance(+h)))); + sample.add(nadirRef(pvProv.getPVCoordinates(date.shiftedBy(+2 * h), frame), refToBody.staticShiftedBy(zero.newInstance(+2 * h)))); // create interpolator final FieldTimeInterpolator, T> interpolator = diff --git a/src/main/java/org/orekit/bodies/PosVelChebyshev.java b/src/main/java/org/orekit/bodies/PosVelChebyshev.java index 1451eeba7f..2c3b7fc120 100644 --- a/src/main/java/org/orekit/bodies/PosVelChebyshev.java +++ b/src/main/java/org/orekit/bodies/PosVelChebyshev.java @@ -169,9 +169,9 @@ > FieldVector3D getPosition(final FieldAbso // initialize Chebyshev polynomials recursion T pKm1 = one; T pK = t; - T xP = zero.add(xCoeffs[0]); - T yP = zero.add(yCoeffs[0]); - T zP = zero.add(zCoeffs[0]); + T xP = zero.newInstance(xCoeffs[0]); + T yP = zero.newInstance(yCoeffs[0]); + T zP = zero.newInstance(zCoeffs[0]); // combine polynomials by applying coefficients for (int k = 1; k < xCoeffs.length; ++k) { @@ -281,9 +281,9 @@ > FieldPVCoordinates getPositionVelocityAcc // initialize Chebyshev polynomials recursion T pKm1 = one; T pK = t; - T xP = zero.add(xCoeffs[0]); - T yP = zero.add(yCoeffs[0]); - T zP = zero.add(zCoeffs[0]); + T xP = zero.newInstance(xCoeffs[0]); + T yP = zero.newInstance(yCoeffs[0]); + T zP = zero.newInstance(zCoeffs[0]); // initialize Chebyshev polynomials derivatives recursion T qKm1 = zero; diff --git a/src/main/java/org/orekit/estimation/measurements/EstimatedEarthFrameProvider.java b/src/main/java/org/orekit/estimation/measurements/EstimatedEarthFrameProvider.java index 9222f17365..d399c22270 100644 --- a/src/main/java/org/orekit/estimation/measurements/EstimatedEarthFrameProvider.java +++ b/src/main/java/org/orekit/estimation/measurements/EstimatedEarthFrameProvider.java @@ -279,7 +279,7 @@ public > FieldTransform getTransform(final // prime meridian shift parameters final T theta = linearModel(date, primeMeridianOffsetDriver, primeMeridianDriftDriver); - final T thetaDot = zero.add(primeMeridianDriftDriver.getValue()); + final T thetaDot = zero.newInstance(primeMeridianDriftDriver.getValue()); // pole shift parameters final T xpNeg = linearModel(date, polarOffsetXDriver, polarDriftXDriver).negate(); diff --git a/src/main/java/org/orekit/forces/gravity/HolmesFeatherstoneAttractionModel.java b/src/main/java/org/orekit/forces/gravity/HolmesFeatherstoneAttractionModel.java index 21bf1c3aff..03809eb4ed 100644 --- a/src/main/java/org/orekit/forces/gravity/HolmesFeatherstoneAttractionModel.java +++ b/src/main/java/org/orekit/forces/gravity/HolmesFeatherstoneAttractionModel.java @@ -977,7 +977,7 @@ private > int computeTesseral(final int m, fin // initialize recursion from sectorial terms int n = FastMath.max(2, m); if (n == m) { - pnm0[n] = zero.add(sectorial[n]); + pnm0[n] = zero.newInstance(sectorial[n]); ++n; } diff --git a/src/main/java/org/orekit/forces/gravity/NewtonianAttraction.java b/src/main/java/org/orekit/forces/gravity/NewtonianAttraction.java index 6a891e860b..bba1b4c458 100644 --- a/src/main/java/org/orekit/forces/gravity/NewtonianAttraction.java +++ b/src/main/java/org/orekit/forces/gravity/NewtonianAttraction.java @@ -83,7 +83,7 @@ public double getMu(final AbsoluteDate date) { */ public > T getMu(final Field field, final FieldAbsoluteDate date) { final T zero = field.getZero(); - return zero.add(gmParameterDriver.getValue(date.toAbsoluteDate())); + return zero.newInstance(gmParameterDriver.getValue(date.toAbsoluteDate())); } /** {@inheritDoc} */ diff --git a/src/main/java/org/orekit/forces/maneuvers/propulsion/ScaledConstantThrustPropulsionModel.java b/src/main/java/org/orekit/forces/maneuvers/propulsion/ScaledConstantThrustPropulsionModel.java index 2f0242340e..999ae687a0 100644 --- a/src/main/java/org/orekit/forces/maneuvers/propulsion/ScaledConstantThrustPropulsionModel.java +++ b/src/main/java/org/orekit/forces/maneuvers/propulsion/ScaledConstantThrustPropulsionModel.java @@ -154,6 +154,6 @@ public > FieldVector3D getThrustVector(fina /** {@inheritDoc} */ @Override public > T getFlowRate(final T[] parameters) { - return parameters[0].getField().getZero().add(getInitialFlowRate()); + return parameters[0].getField().getZero().newInstance(getInitialFlowRate()); } } diff --git a/src/main/java/org/orekit/forces/radiation/KnockeRediffusedForceModel.java b/src/main/java/org/orekit/forces/radiation/KnockeRediffusedForceModel.java index 756cde4a7f..870495a304 100644 --- a/src/main/java/org/orekit/forces/radiation/KnockeRediffusedForceModel.java +++ b/src/main/java/org/orekit/forces/radiation/KnockeRediffusedForceModel.java @@ -293,8 +293,8 @@ public > FieldVector3D acceleration(final F // Compute current elementary crown sector area, it results of the integration of an elementary crown sector // over the angular resolution - final T sectorArea = zero.add(equatorialRadius * equatorialRadius * - 2.0 * angularResolution * FastMath.sin(0.5 * angularResolution) * FastMath.sin(eastAxisOffset)); + final T sectorArea = zero.newInstance(equatorialRadius * equatorialRadius * + 2.0 * angularResolution * FastMath.sin(0.5 * angularResolution) * FastMath.sin(eastAxisOffset)); // Add current sector contribution to total rediffused flux rediffusedFlux = rediffusedFlux.add(computeElementaryFlux(s, currentCenter, sunPosition, earth, sectorArea)); diff --git a/src/main/java/org/orekit/frames/EOPHistory.java b/src/main/java/org/orekit/frames/EOPHistory.java index cf787b1630..e93264a491 100644 --- a/src/main/java/org/orekit/frames/EOPHistory.java +++ b/src/main/java/org/orekit/frames/EOPHistory.java @@ -405,7 +405,7 @@ public void accept(final EOPEntry neighbor) { dut = neighbor.getUT1MinusUTC(); } final T[] array = MathArrays.buildArray(date.getField(), 1); - array[0] = date.getField().getZero().add(dut); + array[0] = date.getField().getZero().newInstance(dut); interpolator.addSamplePoint(date.durationFrom(neighbor.getDate()).negate(), array); } @@ -745,7 +745,7 @@ private > T interpolate(final FieldAbsoluteDat // if T was DerivativeStructure getNeighbors(aDate, interpolationDegree + 1). forEach(entry -> { - y[0] = zero.add(selector.apply(entry)); + y[0] = zero.newInstance(selector.apply(entry)); interpolator.addSamplePoint(central.durationFrom(entry.getDate()).negate(), y); }); return interpolator.value(date.durationFrom(central))[0]; // here, we introduce derivatives again (in DerivativeStructure case) @@ -842,8 +842,8 @@ private > T[] interpolate(final FieldAbsoluteD // if T was DerivativeStructure getNeighbors(aDate, interpolationDegree + 1). forEach(entry -> { - y[0] = zero.add(selector1.apply(entry)); - y[1] = zero.add(selector2.apply(entry)); + y[0] = zero.newInstance(selector1.apply(entry)); + y[1] = zero.newInstance(selector2.apply(entry)); interpolator.addSamplePoint(central.durationFrom(entry.getDate()).negate(), y); }); return interpolator.value(date.durationFrom(central)); // here, we introduce derivatives again (in DerivativeStructure case) @@ -1052,7 +1052,7 @@ public > T[] value(final FieldAbsoluteDate // if T was DerivativeStructure cache.getNeighbors(aDate).forEach(entry -> { for (int i = 0; i < y.length; ++i) { - y[i] = zero.add(entry.correction[i]); + y[i] = zero.newInstance(entry.correction[i]); } interpolator.addSamplePoint(central.durationFrom(entry.getDate()).negate(), y); }); diff --git a/src/main/java/org/orekit/frames/L1TransformProvider.java b/src/main/java/org/orekit/frames/L1TransformProvider.java index 1e6710772c..78d5f0d816 100644 --- a/src/main/java/org/orekit/frames/L1TransformProvider.java +++ b/src/main/java/org/orekit/frames/L1TransformProvider.java @@ -195,13 +195,13 @@ private Vector3D getL1(final Vector3D primaryToSecondary) { final T zero = primaryToSecondary.getX().getField().getZero(); final T[] searchInterval = UnivariateSolverUtils.bracket(l1Equation, baseR, zero, bigR.multiply(2), - bigR.multiply(0.01), zero.add(1), + bigR.multiply(0.01), zero.newInstance(1), MAX_EVALUATIONS); - final T relativeAccuracy = zero.add(RELATIVE_ACCURACY); - final T absoluteAccuracy = zero.add(ABSOLUTE_ACCURACY); - final T functionAccuracy = zero.add(FUNCTION_ACCURACY); + final T relativeAccuracy = zero.newInstance(RELATIVE_ACCURACY); + final T absoluteAccuracy = zero.newInstance(ABSOLUTE_ACCURACY); + final T functionAccuracy = zero.newInstance(FUNCTION_ACCURACY); final FieldBracketingNthOrderBrentSolver solver = new FieldBracketingNthOrderBrentSolver<>(relativeAccuracy, diff --git a/src/main/java/org/orekit/frames/L2TransformProvider.java b/src/main/java/org/orekit/frames/L2TransformProvider.java index f36b28141f..1364e0311b 100644 --- a/src/main/java/org/orekit/frames/L2TransformProvider.java +++ b/src/main/java/org/orekit/frames/L2TransformProvider.java @@ -195,13 +195,13 @@ private Vector3D getL2(final Vector3D primaryToSecondary) { final T zero = primaryToSecondary.getX().getField().getZero(); final T[] searchInterval = UnivariateSolverUtils.bracket(l2Equation, baseR, zero, bigR.multiply(2), - bigR.multiply(0.01), zero.add(1), + bigR.multiply(0.01), zero, MAX_EVALUATIONS); - final T relativeAccuracy = zero.add(RELATIVE_ACCURACY); - final T absoluteAccuracy = zero.add(ABSOLUTE_ACCURACY); - final T functionAccuracy = zero.add(FUNCTION_ACCURACY); + final T relativeAccuracy = zero.newInstance(RELATIVE_ACCURACY); + final T absoluteAccuracy = zero.newInstance(ABSOLUTE_ACCURACY); + final T functionAccuracy = zero.newInstance(FUNCTION_ACCURACY); final FieldBracketingNthOrderBrentSolver solver = new FieldBracketingNthOrderBrentSolver<>(relativeAccuracy, diff --git a/src/main/java/org/orekit/frames/TopocentricFrame.java b/src/main/java/org/orekit/frames/TopocentricFrame.java index 4722bd37e7..ccb84ae3f5 100644 --- a/src/main/java/org/orekit/frames/TopocentricFrame.java +++ b/src/main/java/org/orekit/frames/TopocentricFrame.java @@ -129,9 +129,9 @@ public Vector3D getCartesianPoint() { */ public > FieldGeodeticPoint getPoint(final Field field) { final T zero = field.getZero(); - return new FieldGeodeticPoint<>(zero.add(point.getLatitude()), - zero.add(point.getLongitude()), - zero.add(point.getAltitude())); + return new FieldGeodeticPoint<>(zero.newInstance(point.getLatitude()), + zero.newInstance(point.getLongitude()), + zero.newInstance(point.getAltitude())); } /** Get the zenith direction of topocentric frame, expressed in parent shape frame. diff --git a/src/main/java/org/orekit/frames/VEISProvider.java b/src/main/java/org/orekit/frames/VEISProvider.java index 7d192d00b5..4a98db53b6 100644 --- a/src/main/java/org/orekit/frames/VEISProvider.java +++ b/src/main/java/org/orekit/frames/VEISProvider.java @@ -108,7 +108,7 @@ public > FieldTransform getTransform(final final T vst = ttd.multiply(VST1).add(rdtt.multiply(MathUtils.TWO_PI)).add(VST0).remainder(MathUtils.TWO_PI); // compute angular rotation of Earth, in rad/s - final FieldVector3D rotationRate = new FieldVector3D<>(date.getField().getZero().add(-VSTD), + final FieldVector3D rotationRate = new FieldVector3D<>(date.getField().getZero().newInstance(-VSTD), Vector3D.PLUS_K); // set up the transform from parent GTOD diff --git a/src/main/java/org/orekit/gnss/attitude/GPSBlockIIA.java b/src/main/java/org/orekit/gnss/attitude/GPSBlockIIA.java index eb71b14e22..29676edb9a 100644 --- a/src/main/java/org/orekit/gnss/attitude/GPSBlockIIA.java +++ b/src/main/java/org/orekit/gnss/attitude/GPSBlockIIA.java @@ -159,7 +159,7 @@ protected > TimeStampedFieldAngularCoordinates // noon beta angle limit from yaw rate final T aNoon = FastMath.atan(context.getMuRate().divide(yawRate)); - final T aNight = field.getZero().add(NIGHT_TURN_LIMIT); + final T aNight = field.getZero().newInstance(NIGHT_TURN_LIMIT); final double cNoon = FastMath.cos(aNoon.getReal()); final double cNight = FastMath.cos(aNight.getReal()); @@ -183,16 +183,16 @@ protected > TimeStampedFieldAngularCoordinates if (beta.getReal() > 0 && beta.getReal() < yawBias) { // noon turn problem for small positive beta in block IIA // rotation is in the wrong direction for these spacecrafts - phiDot = field.getZero().add(FastMath.copySign(yawRate, beta.getReal())); + phiDot = field.getZero().newInstance(FastMath.copySign(yawRate, beta.getReal())); linearPhi = phiStart.add(phiDot.multiply(dtStart)); } else { // regular noon turn - phiDot = field.getZero().add(-FastMath.copySign(yawRate, beta.getReal())); + phiDot = field.getZero().newInstance(-FastMath.copySign(yawRate, beta.getReal())); linearPhi = phiStart.add(phiDot.multiply(dtStart)); } } else { // midnight turn - phiDot = field.getZero().add(yawRate); + phiDot = field.getZero().newInstance(yawRate); linearPhi = phiStart.add(phiDot.multiply(dtStart)); } diff --git a/src/main/java/org/orekit/gnss/attitude/GPSBlockIIF.java b/src/main/java/org/orekit/gnss/attitude/GPSBlockIIF.java index 15bda16b27..67a3056660 100644 --- a/src/main/java/org/orekit/gnss/attitude/GPSBlockIIF.java +++ b/src/main/java/org/orekit/gnss/attitude/GPSBlockIIF.java @@ -140,7 +140,7 @@ protected > TimeStampedFieldAngularCoordinates // noon beta angle limit from yaw rate final T aNoon = FastMath.atan(context.getMuRate().divide(yawRate)); - final T aNight = field.getZero().add(NIGHT_TURN_LIMIT); + final T aNight = field.getZero().newInstance(NIGHT_TURN_LIMIT); final double cNoon = FastMath.cos(aNoon.getReal()); final double cNight = FastMath.cos(aNight.getReal()); @@ -164,11 +164,11 @@ protected > TimeStampedFieldAngularCoordinates if (beta.getReal() > yawBias && beta.getReal() < 0) { // noon turn problem for small negative beta in block IIF // rotation is in the wrong direction for these spacecrafts - phiDot = field.getZero().add(FastMath.copySign(yawRate, beta.getReal())); + phiDot = field.getZero().newInstance(FastMath.copySign(yawRate, beta.getReal())); linearPhi = phiStart.add(phiDot.multiply(dtStart)); } else { // regular noon turn - phiDot = field.getZero().add(-FastMath.copySign(yawRate, beta.getReal())); + phiDot = field.getZero().newInstance(-FastMath.copySign(yawRate, beta.getReal())); linearPhi = phiStart.add(phiDot.multiply(dtStart)); } } else { diff --git a/src/main/java/org/orekit/gnss/attitude/GPSBlockIIR.java b/src/main/java/org/orekit/gnss/attitude/GPSBlockIIR.java index 736e2908db..9d5e49ff02 100644 --- a/src/main/java/org/orekit/gnss/attitude/GPSBlockIIR.java +++ b/src/main/java/org/orekit/gnss/attitude/GPSBlockIIR.java @@ -135,11 +135,11 @@ protected > TimeStampedFieldAngularCoordinates if (context.inSunSide()) { // noon turn - phiDot = field.getZero().add(-FastMath.copySign(yawRate, beta.getReal())); + phiDot = field.getZero().newInstance(-FastMath.copySign(yawRate, beta.getReal())); linearPhi = phiStart.add(phiDot.multiply(dtStart)); } else { // midnight turn - phiDot = field.getZero().add(FastMath.copySign(yawRate, beta.getReal())); + phiDot = field.getZero().newInstance(FastMath.copySign(yawRate, beta.getReal())); linearPhi = phiStart.add(phiDot.multiply(dtStart)); } diff --git a/src/main/java/org/orekit/gnss/attitude/Galileo.java b/src/main/java/org/orekit/gnss/attitude/Galileo.java index e5f3fd0a1b..8c7da5b94b 100644 --- a/src/main/java/org/orekit/gnss/attitude/Galileo.java +++ b/src/main/java/org/orekit/gnss/attitude/Galileo.java @@ -127,7 +127,7 @@ protected > TimeStampedFieldAngularCoordinates context.setUpTurnRegion(COS_NIGHT, COS_NOON)) { final Field field = context.getDate().getField(); - final T betaX = field.getZero().add(BETA_X); + final T betaX = field.getZero().newInstance(BETA_X); context.setHalfSpan(context.inSunSide() ? betaX : context.inOrbitPlaneAbsoluteAngle(betaX), diff --git a/src/main/java/org/orekit/gnss/attitude/Glonass.java b/src/main/java/org/orekit/gnss/attitude/Glonass.java index bcdf39dcc8..5d4c46d9e3 100644 --- a/src/main/java/org/orekit/gnss/attitude/Glonass.java +++ b/src/main/java/org/orekit/gnss/attitude/Glonass.java @@ -152,7 +152,7 @@ protected > TimeStampedFieldAngularCoordinates // noon beta angle limit from yaw rate final T realBeta = context.beta(context.getDate()); final T muRate = context.getMuRate(); - final T aNight = field.getZero().add(NIGHT_TURN_LIMIT); + final T aNight = field.getZero().newInstance(NIGHT_TURN_LIMIT); T aNoon = FastMath.atan(muRate.divide(yawRate)); if (FastMath.abs(realBeta).getReal() < aNoon.getReal()) { final CalculusFieldUnivariateFunction f = yawEnd -> { @@ -161,11 +161,11 @@ protected > TimeStampedFieldAngularCoordinates subtract(context.computePhi(realBeta, delta.negate()))). multiply(0.5)); }; - final T[] bracket = UnivariateSolverUtils.bracket(f, field.getZero().add(YAW_END_ZERO), + final T[] bracket = UnivariateSolverUtils.bracket(f, field.getZero().newInstance(YAW_END_ZERO), field.getZero(), field.getZero().getPi()); - final T yawEnd = new FieldBracketingNthOrderBrentSolver<>(field.getZero().add(1.0e-14), - field.getZero().add(1.0e-8), - field.getZero().add(1.0e-15), + final T yawEnd = new FieldBracketingNthOrderBrentSolver<>(field.getZero().newInstance(1.0e-14), + field.getZero().newInstance(1.0e-8), + field.getZero().newInstance(1.0e-15), 5). solve(50, f, bracket[0], bracket[1], AllowedSolution.ANY_SIDE); aNoon = muRate.multiply(yawEnd).divide(yawRate); @@ -192,11 +192,11 @@ protected > TimeStampedFieldAngularCoordinates final T phiEnd = context.getYawEnd(beta); if (context.inSunSide()) { // noon turn - phiDot = field.getZero().add(-FastMath.copySign(yawRate, beta.getReal())); + phiDot = field.getZero().newInstance(-FastMath.copySign(yawRate, beta.getReal())); linearPhi = phiStart.add(phiDot.multiply(dtStart)); } else { // midnight turn - phiDot = field.getZero().add(FastMath.copySign(yawRate, beta.getReal())); + phiDot = field.getZero().newInstance(FastMath.copySign(yawRate, beta.getReal())); linearPhi = phiStart.add(phiDot.multiply(dtStart)); // this turn limitation is only computed for midnight turns in Kouba model diff --git a/src/main/java/org/orekit/models/earth/Geoid.java b/src/main/java/org/orekit/models/earth/Geoid.java index bde307050a..0dacf98d11 100644 --- a/src/main/java/org/orekit/models/earth/Geoid.java +++ b/src/main/java/org/orekit/models/earth/Geoid.java @@ -520,9 +520,9 @@ public > FieldGeodeticPoint getIntersection } // solve line search problem to find the intersection final FieldBracketingNthOrderBrentSolver solver = - new FieldBracketingNthOrderBrentSolver<>(field.getZero().add(1.0e-14), - field.getZero().add(1.0e-6), - field.getZero().add(1.0e-15), + new FieldBracketingNthOrderBrentSolver<>(field.getZero().newInstance(1.0e-14), + field.getZero().newInstance(1.0e-6), + field.getZero().newInstance(1.0e-15), 5); try { final T abscissa = solver.solve(MAX_EVALUATIONS, heightFunction, lowPoint, highPoint, diff --git a/src/main/java/org/orekit/models/earth/atmosphere/DTM2000.java b/src/main/java/org/orekit/models/earth/atmosphere/DTM2000.java index 8102af1d65..4f515f57cf 100644 --- a/src/main/java/org/orekit/models/earth/atmosphere/DTM2000.java +++ b/src/main/java/org/orekit/models/earth/atmosphere/DTM2000.java @@ -1154,8 +1154,8 @@ private T gFunction(final double[] a, final T[] da, fmfb[2] = f[2] - fbar[2]; fbm150[1] = fbar[1] - 150.0; fbm150[2] = fbar[2]; - da[4] = zero.add(fmfb[1]); - da[6] = zero.add(fbm150[1]); + da[4] = zero.newInstance(fmfb[1]); + da[6] = zero.newInstance(fbm150[1]); da[4] = da[4].add(a[70] * fmfb[2]); da[6] = da[6].add(a[71] * fbm150[2]); da[70] = da[4].multiply(a[ 5]).multiply(2). @@ -1200,10 +1200,10 @@ private T gFunction(final double[] a, final T[] da, da[60] = dkp.multiply(dkp); da[61] = p20mg.multiply(da[60]); da[75] = da[60].multiply(da[60]); - da[64] = zero.add(dkpm); + da[64] = zero.newInstance(dkpm); da[65] = p20mg.multiply(dkpm); da[72] = p40mg.multiply(dkpm); - da[66] = zero.add(dkpm * dkpm); + da[66] = zero.newInstance(dkpm * dkpm); da[73] = p20mg.multiply(da[66]); da[76] = da[66].multiply(da[66]); @@ -1240,10 +1240,10 @@ private T gFunction(final double[] a, final T[] da, add(da[78].multiply(a78)). add(da[79].multiply(a[79])); // termes annuels symetriques en latitude - da[9] = zero.add(FastMath.cos(ROT * (day - a[11]))); + da[9] = zero.newInstance(FastMath.cos(ROT * (day - a[11]))); da[10] = p20.multiply(da[9]); // termes semi-annuels symetriques en latitude - da[12] = zero.add(FastMath.cos(ROT2 * (day - a[14]))); + da[12] = zero.newInstance(FastMath.cos(ROT2 * (day - a[14]))); da[13] = p20.multiply(da[12]); // termes annuels non symetriques en latitude final double coste = FastMath.cos(ROT * (day - a[18])); diff --git a/src/main/java/org/orekit/models/earth/atmosphere/HarrisPriester.java b/src/main/java/org/orekit/models/earth/atmosphere/HarrisPriester.java index f7ae30c8c6..78eaf2d834 100644 --- a/src/main/java/org/orekit/models/earth/atmosphere/HarrisPriester.java +++ b/src/main/java/org/orekit/models/earth/atmosphere/HarrisPriester.java @@ -361,13 +361,13 @@ public > T getDensity(final Vector3D sunInEart final T dH = posAlt.negate().add(tabAltRho[ia][0]).divide(tabAltRho[ia][0] - tabAltRho[ia + 1][0]); // Min exponential density interpolation - final T rhoMin = zero.add(tabAltRho[ia + 1][1] / tabAltRho[ia][1]).pow(dH).multiply(tabAltRho[ia][1]); + final T rhoMin = zero.newInstance(tabAltRho[ia + 1][1] / tabAltRho[ia][1]).pow(dH).multiply(tabAltRho[ia][1]); if (Precision.equals(cosPow.getReal(), 0.)) { return zero.add(rhoMin); } else { // Max exponential density interpolation - final T rhoMax = zero.add(tabAltRho[ia + 1][2] / tabAltRho[ia][2]).pow(dH).multiply(tabAltRho[ia][2]); + final T rhoMax = zero.newInstance(tabAltRho[ia + 1][2] / tabAltRho[ia][2]).pow(dH).multiply(tabAltRho[ia][2]); return rhoMin.add(rhoMax.subtract(rhoMin).multiply(cosPow)); } diff --git a/src/main/java/org/orekit/models/earth/atmosphere/JB2008.java b/src/main/java/org/orekit/models/earth/atmosphere/JB2008.java index 5cb45077b5..5bfd618fda 100644 --- a/src/main/java/org/orekit/models/earth/atmosphere/JB2008.java +++ b/src/main/java/org/orekit/models/earth/atmosphere/JB2008.java @@ -576,7 +576,7 @@ public > T getDensity(final T dateMJD, final T tc[3] = gsubx.divide(tc[2]); // Equation (5) - final T z1 = field.getZero().add(90.); + final T z1 = field.getZero().newInstance(90.); final T z2 = min(105.0, altKm); T al = z2.divide(z1).log(); int n = 1 + (int) FastMath.floor(al.getReal() / R1); @@ -826,7 +826,7 @@ private static > T dTc(final double f10, final final T h = satAlt.subtract(200.0).divide(50.0); dTc = poly1CDTC(fs, st, cs).multiply(h).add(poly2CDTC(fs, st, cs)); } else if (satAlt.getReal() > 240.0 && satAlt.getReal() <= 300.0) { - final T h = solarTime.getField().getZero().add(0.8); + final T h = solarTime.getField().getZero().newInstance(0.8); final T bb = poly1CDTC(fs, st, cs); final T aa = bb.multiply(h).add(poly2CDTC(fs, st, cs)); final T p2BDT = poly2BDTC(st); @@ -998,7 +998,7 @@ private static double mBar(final double z) { */ private static > T mBar(final T z) { final T dz = z.subtract(100.); - T amb = z.getField().getZero().add(CMB[6]); + T amb = z.getField().getZero().newInstance(CMB[6]); for (int i = 5; i >= 0; --i) { amb = dz.multiply(amb).add(CMB[i]); } @@ -1182,7 +1182,7 @@ private static > T dayOfYear(final T dateMJD) * @return min value */ private > T min(final double d, final T f) { - return (f.getReal() > d) ? f.getField().getZero().add(d) : f; + return (f.getReal() > d) ? f.getField().getZero().newInstance(d) : f; } /** Compute max of two values, one double and one field element. @@ -1192,7 +1192,7 @@ private > T min(final double d, final T f) { * @return max value */ private > T max(final double d, final T f) { - return (f.getReal() <= d) ? f.getField().getZero().add(d) : f; + return (f.getReal() <= d) ? f.getField().getZero().newInstance(d) : f; } /** Get the local density. diff --git a/src/main/java/org/orekit/models/earth/atmosphere/NRLMSISE00.java b/src/main/java/org/orekit/models/earth/atmosphere/NRLMSISE00.java index bd429b6479..82a37ad305 100644 --- a/src/main/java/org/orekit/models/earth/atmosphere/NRLMSISE00.java +++ b/src/main/java/org/orekit/models/earth/atmosphere/NRLMSISE00.java @@ -2825,7 +2825,7 @@ public class FieldOutput> { temperatures = MathArrays.buildArray(field, 2); // Calculates latitude variable gravity and effective radius - final T xlat = (sw[2] == 0) ? zero.add(LAT_REF) : lat; + final T xlat = (sw[2] == 0) ? zero.newInstance(LAT_REF) : lat; final T c2 = xlat.multiply(2 * DEG_TO_RAD).cos(); glat = c2.multiply(-0.0026373).add(1).multiply(G_REF); rlat = glat.multiply(2).divide(c2.multiply(2.27e-9).add(3.085462e-6)).multiply(1.e-5); @@ -2921,7 +2921,7 @@ void gts7(final T alt) { final double xmm = PDM[2][4]; /**** Exospheric temperature ****/ - T tinf = zero.add(PTM[0] * PT[0]); + T tinf = zero.newInstance(PTM[0] * PT[0]); // Tinf variations not important below ZA or ZN[0] if (alt.getReal() > ZN1[0]) { tinf = tinf.multiply(globe7(PT).multiply(sw[16]).add(1)); @@ -2929,24 +2929,24 @@ void gts7(final T alt) { setTemperature(EXOSPHERIC, tinf); // Gradient variations not important below ZN[4] - T g0 = zero.add(PTM[3] * PS[0]); + T g0 = zero.newInstance(PTM[3] * PS[0]); if (alt.getReal() > ZN1[4]) { g0 = g0.multiply(globe7(PS).multiply(sw[19]).add(1)); } // Temperature at lower boundary - T tlb = zero.add(PTM[1] * PD[3][0]); + T tlb = zero.newInstance(PTM[1] * PD[3][0]); tlb = tlb.multiply(globe7(PD[3]).multiply(sw[17]).add(1)); // Slope final T s = g0.divide(tinf.subtract(tlb)); // Lower thermosphere temp variations not significant for density above 300 km - meso_tn1[1] = zero.add(PTM[6] * PTL[0][0]); - meso_tn1[2] = zero.add(PTM[2] * PTL[1][0]); - meso_tn1[3] = zero.add(PTM[7] * PTL[2][0]); - meso_tn1[4] = zero.add(PTM[4] * PTL[3][0]); - meso_tgn1[1] = zero.add(PTM[8] * PMA[8][0]); + meso_tn1[1] = zero.newInstance(PTM[6] * PTL[0][0]); + meso_tn1[2] = zero.newInstance(PTM[2] * PTL[1][0]); + meso_tn1[3] = zero.newInstance(PTM[7] * PTL[2][0]); + meso_tn1[4] = zero.newInstance(PTM[4] * PTL[3][0]); + meso_tgn1[1] = zero.newInstance(PTM[8] * PMA[8][0]); if (alt.getReal() < 300.0) { final double r = PTM[4] * PTL[3][0]; meso_tn1[1] = meso_tn1[1].divide(glob7s(PTL[0]).multiply(sw[18] ).negate().add(1)); @@ -2958,7 +2958,7 @@ void gts7(final T alt) { } /**** Temperature at altitude ****/ - setTemperature(ALTITUDE, densu(alt, zero.add(1.0), tinf, tlb, 0, 0, PTM[5], s)); + setTemperature(ALTITUDE, densu(alt, zero.newInstance(1.0), tinf, tlb, 0, 0, PTM[5], s)); /**** N2 density ****/ /* Density variation factor at Zlb */ @@ -2999,7 +2999,7 @@ void gts7(final T alt) { /* Turbopause */ final double zh04 = PDM[0][2]; /* Mixed density at Zlb */ - final T b04 = densu(zero.add(zh04), db04, tinf, tlb, HE_MASS - xmm, alpha[0] - 1., PTM[5], s); + final T b04 = densu(zero.newInstance(zh04), db04, tinf, tlb, HE_MASS - xmm, alpha[0] - 1., PTM[5], s); /* Mixed density at Alt */ final T dm04 = densu(alt, b04, tinf, tlb, xmm, 0., PTM[5], s); final double zhm04 = zhm28; @@ -3025,7 +3025,7 @@ void gts7(final T alt) { /* Turbopause */ final double zh16 = PDM[1][2]; /* Mixed density at Zlb */ - final T b16 = densu(zero.add(zh16), db16, tinf, tlb, O_MASS - xmm, alpha[1] - 1.0, PTM[5], s); + final T b16 = densu(zero.newInstance(zh16), db16, tinf, tlb, O_MASS - xmm, alpha[1] - 1.0, PTM[5], s); /* Mixed density at Alt */ final T dm16 = densu(alt, b16, tinf, tlb, xmm, 0., PTM[5], s); final double zhm16 = zhm28; @@ -3041,7 +3041,7 @@ void gts7(final T alt) { final double zcc16 = PDM[1][6] * PDL[1][12]; final double rc16 = PDM[1][3] * PDL[1][14]; /* Net density corrected at Alt */ - setDensity(ATOMIC_OXYGEN, diffusiveDensity.multiply(ccor(alt, zero.add(rc16), hcc16, zcc16))); + setDensity(ATOMIC_OXYGEN, diffusiveDensity.multiply(ccor(alt, zero.newInstance(rc16), hcc16, zcc16))); } /**** O2 density ****/ @@ -3057,7 +3057,7 @@ void gts7(final T alt) { /* Turbopause */ final double zh32 = PDM[3][2]; /* Mixed density at Zlb */ - final T b32 = densu(zero.add(zh32), db32, tinf, tlb, O2_MASS - xmm, alpha[3] - 1., PTM[5], s); + final T b32 = densu(zero.newInstance(zh32), db32, tinf, tlb, O2_MASS - xmm, alpha[3] - 1., PTM[5], s); /* Mixed density at Alt */ final T dm32 = densu(alt, b32, tinf, tlb, xmm, 0., PTM[5], s); final double zhm32 = zhm28; @@ -3090,7 +3090,7 @@ void gts7(final T alt) { /* Turbopause */ final double zh40 = PDM[4][2]; /* Mixed density at Zlb */ - final T b40 = densu(zero.add(zh40), db40, tinf, tlb, AR_MASS - xmm, alpha[4] - 1., PTM[5], s); + final T b40 = densu(zero.newInstance(zh40), db40, tinf, tlb, AR_MASS - xmm, alpha[4] - 1., PTM[5], s); /* Mixed density at Alt */ final T dm40 = densu(alt, b40, tinf, tlb, xmm, 0., PTM[5], s); final double zhm40 = zhm28; @@ -3116,7 +3116,7 @@ void gts7(final T alt) { /* Turbopause */ final double zh01 = PDM[5][2]; /* Mixed density at Zlb */ - final T b01 = densu(zero.add(zh01), db01, tinf, tlb, H_MASS - xmm, alpha[6] - 1., PTM[5], s); + final T b01 = densu(zero.newInstance(zh01), db01, tinf, tlb, H_MASS - xmm, alpha[6] - 1., PTM[5], s); /* Mixed density at Alt */ final T dm01 = densu(alt, b01, tinf, tlb, xmm, 0., PTM[5], s); final double zhm01 = zhm28; @@ -3132,7 +3132,7 @@ void gts7(final T alt) { final double zcc01 = PDM[5][6] * PDL[1][18]; final double rc01 = PDM[5][3] * PDL[1][20]; /* Net density corrected at Alt */ - setDensity(HYDROGEN, diffusiveDensity.multiply(ccor(alt, zero.add(rc01), hcc01, zcc01))); + setDensity(HYDROGEN, diffusiveDensity.multiply(ccor(alt, zero.newInstance(rc01), hcc01, zcc01))); } /**** N density ****/ @@ -3147,7 +3147,7 @@ void gts7(final T alt) { /* Turbopause */ final double zh14 = PDM[6][2]; /* Mixed density at Zlb */ - final T b14 = densu(zero.add(zh14), db14, tinf, tlb, N_MASS - xmm, alpha[7] - 1., PTM[5], s); + final T b14 = densu(zero.newInstance(zh14), db14, tinf, tlb, N_MASS - xmm, alpha[7] - 1., PTM[5], s); /* Mixed density at Alt */ final T dm14 = densu(alt, b14, tinf, tlb, xmm, 0., PTM[5], s); final double zhm14 = zhm28; @@ -3163,14 +3163,14 @@ void gts7(final T alt) { final double zcc14 = PDM[6][6] * PDL[0][3]; final double rc14 = PDM[6][3] * PDL[0][5]; /* Net density corrected at Alt */ - setDensity(ATOMIC_NITROGEN, diffusiveDensity.multiply(ccor(alt, zero.add(rc14), hcc14, zcc14))); + setDensity(ATOMIC_NITROGEN, diffusiveDensity.multiply(ccor(alt, zero.newInstance(rc14), hcc14, zcc14))); } /**** Anomalous O density ****/ final T g16h = globe7(PD[8]).multiply(sw[21]); final T db16h = g16h.exp().multiply(PDM[7][0] * PD[8][0]); final double tho = PDM[7][9] * PDL[0][6]; - diffusiveDensity = densu(alt, db16h, zero.add(tho), zero.add(tho), O_MASS, alpha[8], PTM[5], s); + diffusiveDensity = densu(alt, db16h, zero.newInstance(tho), zero.newInstance(tho), O_MASS, alpha[8], PTM[5], s); final double zsht = PDM[7][5]; final double zmho = PDM[7][4]; final T zsho = scalh(zmho, O_MASS, tho); @@ -3219,7 +3219,7 @@ void gts7(final T alt) { void gtd7(final T alt) { // Calculates for thermosphere/mesosphere (above ZN2[0]) - final T altt = (alt.getReal() > ZN2[0]) ? alt : zero.add(ZN2[0]); + final T altt = (alt.getReal() > ZN2[0]) ? alt : zero.newInstance(ZN2[0]); gts7(altt); if (alt.getReal() >= ZN2[0]) { return; @@ -3404,10 +3404,8 @@ private T globe7(final double[] p) { // F10.7 effect final double df = f107 - f107a; final double dfa = f107a - FLUX_REF; - t[0] = zero.add(p[19] * df * (1.0 + p[59] * dfa) + - p[20] * df * df + - p[21] * dfa + - p[29] * dfa * dfa); + t[0] = zero.newInstance(p[19] * df * (1.0 + p[59] * dfa) + p[20] * df * df + + p[21] * dfa + p[29] * dfa * dfa); final double f1 = 1.0 + (p[47] * dfa + p[19] * df + p[20] * df * df) * swc[1]; final double f2 = 1.0 + (p[49] * dfa + p[19] * df + p[20] * df * df) * swc[1]; @@ -3420,7 +3418,7 @@ private T globe7(final double[] p) { add(plg[0][1].multiply(p[26])); // Symmetrical annual - t[2] = zero.add(p[18] * cd32); + t[2] = zero.newInstance(p[18] * cd32); // Symmetrical semiannual t[3] = plg[0][2].multiply(p[16]).add(p[15]).multiply(cd18); @@ -3539,7 +3537,7 @@ private T globe7(final double[] p) { } // Sum all effects (params not used: 82, 89, 99, 139-149) - T tinf = zero.add(p[30]); + T tinf = zero.newInstance(p[30]); for (int i = 0; i < 14; i++) { tinf = tinf.add(t[i].multiply(FastMath.abs(sw[i + 1]))); } @@ -3562,7 +3560,7 @@ private T glob7s(final double[] p) { final double cd39 = FastMath.cos(2.0 * DAY_TO_RAD * (doy - p[38])); // F10.7 effect - t[0] = zero.add(p[21] * (f107a - FLUX_REF)); + t[0] = zero.newInstance(p[21] * (f107a - FLUX_REF)); // Time independent t[1] = plg[0][2].multiply(p[1]). @@ -3715,7 +3713,7 @@ private T ccor2(final T alt, final double r, final double h1, final double zh, f if (e1.getReal() > 70. || e2.getReal() > 70.) { return field.getOne(); } else if (e1.getReal() < -70. && e2.getReal() < -70.) { - return zero.add(FastMath.exp(r)); + return zero.newInstance(FastMath.exp(r)); } else { final T ex1 = e1.exp(); final T ex2 = e2.exp(); @@ -3849,7 +3847,7 @@ private T[] spline(final T[] x, final T[] y, final T yp1, final T ypn) { final T[] u = MathArrays.buildArray(field, n); if (yp1.getReal() < 1e+30) { - y2[0] = zero.add(-0.5); + y2[0] = zero.newInstance(-0.5); final T dx = x[1].subtract(x[0]); final T dy = y[1].subtract(y[0]); u[0] = dx.reciprocal().multiply(3.0).multiply(dy.divide(dx).subtract(yp1)); @@ -3896,20 +3894,20 @@ private T densm(final T alt, final T d0, final double xm) { // stratosphere/mesosphere temperature int mn = ZN2.length; - T z = (alt.getReal() > ZN2[mn - 1]) ? alt : zero.add(ZN2[mn - 1]); + T z = (alt.getReal() > ZN2[mn - 1]) ? alt : zero.newInstance(ZN2[mn - 1]); double z1 = ZN2[0]; double z2 = ZN2[mn - 1]; T t1 = meso_tn2[0]; T t2 = meso_tn2[mn - 1]; T zg = zeta(z, z1); - T zgdif = zeta(zero.add(z2), z1); + T zgdif = zeta(zero.newInstance(z2), z1); /* set up spline nodes */ T[] xs = MathArrays.buildArray(field, mn); T[] ys = MathArrays.buildArray(field, mn); for (int k = 0; k < mn; k++) { - xs[k] = zeta(zero.add(ZN2[k]), z1).divide(zgdif); + xs[k] = zeta(zero.newInstance(ZN2[k]), z1).divide(zgdif); ys[k] = meso_tn2[k].reciprocal(); } final T qSM = rlat.add(z2).divide(rlat.add(z1)); @@ -3926,7 +3924,7 @@ private T densm(final T alt, final T d0, final double xm) { if (xm != 0.0) { /* calculate stratosphere / mesospehere density */ - final T glb = galt(zero.add(z1)); + final T glb = galt(zero.newInstance(z1)); final T gamm = glb.multiply(zgdif).multiply(xm / R_GAS); /* Integrate temperature profile */ @@ -3949,13 +3947,13 @@ private T densm(final T alt, final T d0, final double xm) { t1 = meso_tn3[0]; t2 = meso_tn3[mn - 1]; zg = zeta(z, z1); - zgdif = zeta(zero.add(z2), z1); + zgdif = zeta(zero.newInstance(z2), z1); /* set up spline nodes */ xs = MathArrays.buildArray(field, mn); ys = MathArrays.buildArray(field, mn); for (int k = 0; k < mn; k++) { - xs[k] = zeta(zero.add(ZN3[k]), z1).divide(zgdif); + xs[k] = zeta(zero.newInstance(ZN3[k]), z1).divide(zgdif); ys[k] = meso_tn3[k].reciprocal(); } final T qTS = rlat.add(z2) .divide(rlat.add(z1)); @@ -3972,7 +3970,7 @@ private T densm(final T alt, final T d0, final double xm) { if (xm != 0.0) { /* calculate tropospheric / stratosphere density */ - final T glb = galt(zero.add(z1)); + final T glb = galt(zero.newInstance(z1)); final T gamm = glb.multiply(zgdif).multiply(xm / R_GAS); /* Integrate temperature profile */ @@ -4001,7 +3999,7 @@ private T densu(final T alt, final T dlb, final T tinf, final T tlb, final double xm, final double alpha, final double zlb, final T s2) { /* joining altitudes of Bates and spline */ - T z = (alt.getReal() > ZN1[0]) ? alt : zero.add(ZN1[0]); + T z = (alt.getReal() > ZN1[0]) ? alt : zero.newInstance(ZN1[0]); /* geopotential altitude difference from ZLB */ final T zg2 = zeta(z, zlb); @@ -4024,7 +4022,7 @@ private T densu(final T alt, final T dlb, final T tinf, final T dta = tinf.subtract(ta).multiply(s2).multiply(p.multiply(p)); meso_tgn1[0] = dta; meso_tn1[0] = ta; - final T tzn1mn1 = zero.add(ZN1[mn - 1]); + final T tzn1mn1 = zero.newInstance(ZN1[mn - 1]); z = (alt.getReal() > ZN1[mn - 1]) ? alt : tzn1mn1; final T t1 = meso_tn1[0]; @@ -4034,7 +4032,7 @@ private T densu(final T alt, final T dlb, final T tinf, zgdif = zeta(tzn1mn1, ZN1[0]); /* set up spline nodes */ for (int k = 0; k < mn; k++) { - xs[k] = zeta(zero.add(ZN1[k]), ZN1[0]).divide(zgdif); + xs[k] = zeta(zero.newInstance(ZN1[k]), ZN1[0]).divide(zgdif); ys[k] = meso_tn1[k].reciprocal(); } /* end node derivatives */ @@ -4054,20 +4052,20 @@ private T densu(final T alt, final T dlb, final T tinf, } /* calculate density above za */ - T glb = galt(zero.add(zlb)); + T glb = galt(zero.newInstance(zlb)); T gamma = glb.divide(s2.multiply(tinf)).multiply(xm / R_GAS); T expl = tt.getReal() <= 0 ? - zero.add(50) : + zero.newInstance(50) : min(50.0, s2.negate().multiply(gamma).multiply(zg2).exp()); T densu = dlb.multiply(tlb.divide(tt).pow(gamma.add(alpha + 1))).multiply(expl); /* calculate density below za */ if (alt.getReal() < ZN1[0]) { - glb = galt(zero.add(ZN1[0])); + glb = galt(zero.newInstance(ZN1[0])); gamma = glb.multiply(zgdif).multiply(xm / R_GAS); /* integrate spline temperatures */ expl = tz.getReal() <= 0 ? - zero.add(50.0) : + zero.newInstance(50.0) : min(50.0, gamma.multiply(splini(xs, ys, y2out, x))); /* correct density at altitude */ densu = densu.multiply(meso_tn1[0].divide(tz).pow(alpha + 1).multiply(expl.negate().exp())); @@ -4083,7 +4081,7 @@ private T densu(final T alt, final T dlb, final T tinf, * @return min value */ private T min(final double d, final T f) { - return (f.getReal() > d) ? zero.add(d) : f; + return (f.getReal() > d) ? zero.newInstance(d) : f; } /** Calculate gravity at altitude. diff --git a/src/main/java/org/orekit/models/earth/ionosphere/FieldNeQuickParameters.java b/src/main/java/org/orekit/models/earth/ionosphere/FieldNeQuickParameters.java index ee94cbb057..df37f73596 100644 --- a/src/main/java/org/orekit/models/earth/ionosphere/FieldNeQuickParameters.java +++ b/src/main/java/org/orekit/models/earth/ionosphere/FieldNeQuickParameters.java @@ -124,7 +124,7 @@ class FieldNeQuickParameters > { } // E layer maximum density height in km (Eq. 78) - this.hmE = field.getZero().add(120.0); + this.hmE = field.getZero().newInstance(120.0); // E layer critical frequency in MHz final T foE = computefoE(date.getMonth(), az, xeff, latitude); // E layer maximum density in 10^11 m-3 (Eq. 36) @@ -162,8 +162,8 @@ class FieldNeQuickParameters > { this.b2Bot = nmF2.divide(a).multiply(0.385); this.b1Top = hmF2.subtract(hmF1).multiply(0.3); this.b1Bot = hmF1.subtract(hmE).multiply(0.5); - this.beTop = FastMath.max(b1Bot, zero.add(7.0)); - this.beBot = zero.add(5.0); + this.beTop = FastMath.max(b1Bot, zero.newInstance(7.0)); + this.beBot = zero.newInstance(5.0); // Layer amplitude coefficients this.amplitudes = computeLayerAmplitudes(field, nmE, nmF1, foF1); @@ -344,14 +344,14 @@ private T computeAz(final T modip, final double[] alpha) { final T zero = field.getZero(); // Particular condition (Eq. 17) if (alpha[0] == 0.0 && alpha[1] == 0.0 && alpha[2] == 0.0) { - return zero.add(63.7); + return zero.newInstance(63.7); } // Az = a0 + modip * a1 + modip^2 * a2 (Eq. 18) T az = modip.multiply(alpha[2]).add(alpha[1]).multiply(modip).add(alpha[0]); // If Az < 0 -> Az = 0 az = FastMath.max(zero, az); // If Az > 400 -> Az = 400 - az = FastMath.min(zero.add(400.0), az); + az = FastMath.min(zero.newInstance(400.0), az); return az; } @@ -392,7 +392,8 @@ private T computeEffectiveSolarAngle(final int month, final T angle = FastMath.atan2(FastMath.sqrt(cZenith.multiply(cZenith).negate().add(1.0)), cZenith); final T x = FastMath.toDegrees(angle); // Effective solar zenith angle (Eq. 28) - final T xeff = join(clipExp(x.multiply(0.2).negate().add(20.0)).multiply(0.24).negate().add(90.0), x, zero.add(12.0), x.subtract(X0)); + final T xeff = join(clipExp(x.multiply(0.2).negate().add(20.0)).multiply(0.24).negate().add(90.0), x, + zero.newInstance(12.0), x.subtract(X0)); return FastMath.toRadians(xeff); } @@ -441,7 +442,7 @@ private T computehmF2(final Field field, final T foE, final T foF2, final T m final T zero = field.getZero(); // Ratio final T fo = foF2.divide(foE); - final T ratio = join(fo, zero.add(1.75), zero.add(20.0), fo.subtract(1.75)); + final T ratio = join(fo, zero.newInstance(1.75), zero.newInstance(20.0), fo.subtract(1.75)); // deltaM parameter T deltaM = zero.subtract(0.012); @@ -624,9 +625,9 @@ private T computeMF2(final Field field, final T modip, final T[] cm3, */ private T computefoF1(final Field field, final T foE, final T foF2) { final T zero = field.getZero(); - final T temp = join(foE.multiply(1.4), zero, zero.add(1000.0), foE.subtract(2.0)); - final T temp2 = join(zero, temp, zero.add(1000.0), foE.subtract(temp)); - final T value = join(temp2, temp2.multiply(0.85), zero.add(60.0), foF2.multiply(0.85).subtract(temp2)); + final T temp = join(foE.multiply(1.4), zero, zero.newInstance(1000.0), foE.subtract(2.0)); + final T temp2 = join(zero, temp, zero.newInstance(1000.0), foE.subtract(temp)); + final T value = join(temp2, temp2.multiply(0.85), zero.newInstance(60.0), foF2.multiply(0.85).subtract(temp2)); if (value.getReal() < 1.0E-6) { return zero; } else { @@ -674,7 +675,7 @@ private T[] computeLayerAmplitudes(final Field field, final T nmE, final T nm a3a = nmE.subtract(epst(a2a, hmF1, b1Bot, hmE)).subtract(epst(a1, hmF2, b2Bot, hmE)).multiply(4.0); } amplitude[1] = a2a; - amplitude[2] = join(a3a, zero.add(0.05), zero.add(60.0), a3a.subtract(0.005)); + amplitude[2] = join(a3a, zero.newInstance(0.05), zero.newInstance(60.0), a3a.subtract(0.005)); } return amplitude; @@ -705,8 +706,8 @@ private T computeH0(final Field field, final int month, final T azr) { } // Auxiliary parameter kb (Eq. 101 and 102) - T kb = join(ka, one.multiply(2.0), one, ka.subtract(2.0)); - kb = join(one.multiply(8.0), kb, one, kb.subtract(8.0)); + T kb = join(ka, one.newInstance(2.0), one, ka.subtract(2.0)); + kb = join(one.newInstance(8.0), kb, one, kb.subtract(8.0)); // Auxiliary parameter Ha (Eq. 103) final T hA = kb.multiply(b2Bot); @@ -732,9 +733,9 @@ private T computeH0(final Field field, final int month, final T azr) { private T clipExp(final T power) { final T zero = power.getField().getZero(); if (power.getReal() > 80.0) { - return zero.add(5.5406E34); + return zero.newInstance(5.5406E34); } else if (power.getReal() < -80) { - return zero.add(1.8049E-35); + return zero.newInstance(1.8049E-35); } else { return FastMath.exp(power); } diff --git a/src/main/java/org/orekit/models/earth/ionosphere/KlobucharIonoModel.java b/src/main/java/org/orekit/models/earth/ionosphere/KlobucharIonoModel.java index 1958f92e5f..16da1e053b 100644 --- a/src/main/java/org/orekit/models/earth/ionosphere/KlobucharIonoModel.java +++ b/src/main/java/org/orekit/models/earth/ionosphere/KlobucharIonoModel.java @@ -250,7 +250,7 @@ public > T pathDelay(final FieldAbsoluteDate> T pathDelay(final FieldAbsoluteDate> T bottomElectronDensity(final Field< // Compute the exponential argument for each layer (Eq. 111 to 113) // If h < 100km we use h = 100km as recommended in the reference document - final T hTemp = FastMath.max(zero.add(100.0), h); + final T hTemp = FastMath.max(zero.newInstance(100.0), h); final T exp = clipExp(field, FastMath.abs(hTemp.subtract(parameters.getHmF2())).add(1.0).divide(10.0).reciprocal()); final T[] arguments = MathArrays.buildArray(field, 3); arguments[0] = hTemp.subtract(parameters.getHmF2()).divide(bf2); @@ -655,9 +655,9 @@ private double clipExp(final double power) { private > T clipExp(final Field field, final T power) { final T zero = field.getZero(); if (power.getReal() > 80.0) { - return zero.add(5.5406E34); + return zero.newInstance(5.5406E34); } else if (power.getReal() < -80) { - return zero.add(1.8049E-35); + return zero.newInstance(1.8049E-35); } else { return FastMath.exp(power); } diff --git a/src/main/java/org/orekit/models/earth/troposphere/FixedTroposphericDelay.java b/src/main/java/org/orekit/models/earth/troposphere/FixedTroposphericDelay.java index 12e2aee5bb..5c7a5a34e3 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/FixedTroposphericDelay.java +++ b/src/main/java/org/orekit/models/earth/troposphere/FixedTroposphericDelay.java @@ -147,7 +147,7 @@ public > T pathDelay(final T elevation, final final T zero = date.getField().getZero(); final T pi = zero.getPi(); // limit the height to 5000 m - final T h = FastMath.min(FastMath.max(zero, point.getAltitude()), zero.add(5000)); + final T h = FastMath.min(FastMath.max(zero, point.getAltitude()), zero.newInstance(5000)); // limit the elevation to 0 - π final T ele = FastMath.min(pi, FastMath.max(zero, elevation)); // mirror elevation at the right angle of π/2 diff --git a/src/main/java/org/orekit/models/earth/troposphere/GlobalMappingFunctionModel.java b/src/main/java/org/orekit/models/earth/troposphere/GlobalMappingFunctionModel.java index 1c326c24df..be4bcf3d12 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/GlobalMappingFunctionModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/GlobalMappingFunctionModel.java @@ -185,8 +185,8 @@ public > T[] mappingFactors(final T elevation, final T zero = field.getZero(); // bh and ch constants (Boehm, J et al, 2006) | HYDROSTATIC PART - final T bh = zero.add(0.0029); - final T c0h = zero.add(0.062); + final T bh = zero.newInstance(0.0029); + final T c0h = zero.newInstance(0.062); final T c10h; final T c11h; final T psi; @@ -197,12 +197,12 @@ public > T[] mappingFactors(final T elevation, // sin(latitude) > 0 -> northern hemisphere if (FastMath.sin(latitude.getReal()) > 0) { - c10h = zero.add(0.001); - c11h = zero.add(0.005); + c10h = zero.newInstance(0.001); + c11h = zero.newInstance(0.005); psi = zero; } else { - c10h = zero.add(0.002); - c11h = zero.add(0.007); + c10h = zero.newInstance(0.002); + c11h = zero.newInstance(0.007); psi = zero.getPi(); } @@ -215,8 +215,8 @@ public > T[] mappingFactors(final T elevation, final T ch = c11h.divide(2.0).multiply(FastMath.cos(coef).add(1.0)).add(c10h).multiply(FastMath.cos(latitude).negate().add(1.0)).add(c0h); // bw and cw constants (Boehm, J et al, 2006) | WET PART - final T bw = zero.add(0.00146); - final T cw = zero.add(0.04391); + final T bw = zero.newInstance(0.00146); + final T cw = zero.newInstance(0.04391); // Compute coefficients ah and aw with spherical harmonics Eq. 3 (Ref 1) diff --git a/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java b/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java index 4644e256b2..ad5d8625fa 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java @@ -201,7 +201,7 @@ public > T[] computeZenithDelay(final FieldGeo final T[] delay = MathArrays.buildArray(field, 2); // Dispertion Equation for the Hydrostatic component - final T sigma = zero.add(1 / lambda); + final T sigma = zero.newInstance(1 / lambda); final T sigma2 = sigma.multiply(sigma); final T coef1 = sigma2.add(K_COEFFICIENTS[0]); final T coef2 = sigma2.negate().add(K_COEFFICIENTS[0]); diff --git a/src/main/java/org/orekit/models/earth/troposphere/NiellMappingFunctionModel.java b/src/main/java/org/orekit/models/earth/troposphere/NiellMappingFunctionModel.java index a7392f71e1..0cbae2db97 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/NiellMappingFunctionModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/NiellMappingFunctionModel.java @@ -236,8 +236,8 @@ public > T[] mappingFactors(final T elevation, function[0] = TroposphericModelUtils.mappingFunction(ah, bh, ch, elevation); // Wet mapping factor - function[1] = TroposphericModelUtils.mappingFunction(zero.add(awFunction.value(absLatidude)), zero.add(bwFunction.value(absLatidude)), - zero.add(cwFunction.value(absLatidude)), elevation); + function[1] = TroposphericModelUtils.mappingFunction(zero.newInstance(awFunction.value(absLatidude)), zero.newInstance(bwFunction.value(absLatidude)), + zero.newInstance(cwFunction.value(absLatidude)), elevation); // Apply height correction final T correction = TroposphericModelUtils.computeHeightCorrection(elevation, point.getAltitude(), field); diff --git a/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java b/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java index 78c9c99883..ab728dca0a 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java @@ -293,7 +293,7 @@ public > T pathDelay(final T elevation, final final T zero = field.getZero(); // there are no data in the model for negative altitudes and altitude bigger than 5000 m // limit the height to a range of [0, 5000] m - final T fixedHeight = FastMath.min(FastMath.max(zero, point.getAltitude()), zero.add(5000)); + final T fixedHeight = FastMath.min(FastMath.max(zero, point.getAltitude()), zero.newInstance(5000)); // the corrected temperature using a temperature gradient of -6.5 K/km final T T = fixedHeight.multiply(6.5e-3).negate().add(t0); @@ -308,7 +308,7 @@ public > T pathDelay(final T elevation, final final T e = R.multiply(FastMath.exp(eFunction.value(T))); // calculate the zenith angle from the elevation - final T z = FastMath.abs(FastMath.max(elevation, zero.add(lowElevationThreshold)).negate().add(zero.getPi().multiply(0.5))); + final T z = FastMath.abs(FastMath.max(elevation, zero.newInstance(lowElevationThreshold)).negate().add(zero.getPi().multiply(0.5))); // get correction factor final T deltaR = getDeltaR(fixedHeight, z, field); @@ -346,7 +346,7 @@ private > T getDeltaR(final T height, final T final Field field) { final T zero = field.getZero(); // limit the height to a range of [0, 5000] m - final T h = FastMath.min(FastMath.max(zero, height), zero.add(5000)); + final T h = FastMath.min(FastMath.max(zero, height), zero.newInstance(5000)); // limit the zenith angle to 90 degree // Note: the function is symmetric for negative zenith angles final T z = FastMath.min(zenith.abs(), zero.getPi().multiply(0.5)); diff --git a/src/main/java/org/orekit/models/earth/troposphere/TroposphericModelUtils.java b/src/main/java/org/orekit/models/earth/troposphere/TroposphericModelUtils.java index 59d3aac3e0..fd8f078ca4 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/TroposphericModelUtils.java +++ b/src/main/java/org/orekit/models/earth/troposphere/TroposphericModelUtils.java @@ -116,7 +116,7 @@ public static > T computeHeightCorrection(fina final T fixedHeight = FastMath.max(zero, height); final T sinE = FastMath.sin(elevation); // Ref: Eq. 4 - final T function = TroposphericModelUtils.mappingFunction(zero.add(2.53e-5), zero.add(5.49e-3), zero.add(1.14e-3), elevation); + final T function = TroposphericModelUtils.mappingFunction(zero.newInstance(2.53e-5), zero.newInstance(5.49e-3), zero.newInstance(1.14e-3), elevation); // Ref: Eq. 6 final T dmdh = sinE.reciprocal().subtract(function); // Ref: Eq. 7 diff --git a/src/main/java/org/orekit/models/earth/troposphere/ViennaOneModel.java b/src/main/java/org/orekit/models/earth/troposphere/ViennaOneModel.java index bf2f0e4a4e..0df80dc35f 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/ViennaOneModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/ViennaOneModel.java @@ -146,8 +146,8 @@ public > T[] computeZenithDelay(final FieldGeo final Field field = date.getField(); final T zero = field.getZero(); final T[] delays = MathArrays.buildArray(field, 2); - delays[0] = zero.add(zenithDelay[0]); - delays[1] = zero.add(zenithDelay[1]); + delays[0] = zero.newInstance(zenithDelay[0]); + delays[1] = zero.newInstance(zenithDelay[1]); return delays; } @@ -217,8 +217,8 @@ public > T[] mappingFactors(final T elevation, final int dofyear = dtc.getDate().getDayOfYear(); // General constants | Hydrostatic part - final T bh = zero.add(0.0029); - final T c0h = zero.add(0.062); + final T bh = zero.newInstance(0.0029); + final T c0h = zero.newInstance(0.062); final T c10h; final T c11h; final T psi; @@ -228,12 +228,12 @@ public > T[] mappingFactors(final T elevation, // sin(latitude) > 0 -> northern hemisphere if (FastMath.sin(latitude.getReal()) > 0) { - c10h = zero.add(0.001); - c11h = zero.add(0.005); + c10h = zero.newInstance(0.001); + c11h = zero.newInstance(0.005); psi = zero; } else { - c10h = zero.add(0.002); - c11h = zero.add(0.007); + c10h = zero.newInstance(0.002); + c11h = zero.newInstance(0.007); psi = zero.getPi(); } @@ -248,12 +248,12 @@ public > T[] mappingFactors(final T elevation, final T ch = c11h.divide(2.0).multiply(FastMath.cos(coef).add(1.0)).add(c10h).multiply(FastMath.cos(latitude).negate().add(1.)).add(c0h); // General constants | Wet part - final T bw = zero.add(0.00146); - final T cw = zero.add(0.04391); + final T bw = zero.newInstance(0.00146); + final T cw = zero.newInstance(0.04391); final T[] function = MathArrays.buildArray(field, 2); - function[0] = TroposphericModelUtils.mappingFunction(zero.add(coefficientsA[0]), bh, ch, elevation); - function[1] = TroposphericModelUtils.mappingFunction(zero.add(coefficientsA[1]), bw, cw, elevation); + function[0] = TroposphericModelUtils.mappingFunction(zero.newInstance(coefficientsA[0]), bh, ch, elevation); + function[1] = TroposphericModelUtils.mappingFunction(zero.newInstance(coefficientsA[1]), bw, cw, elevation); // Apply height correction final T correction = TroposphericModelUtils.computeHeightCorrection(elevation, point.getAltitude(), field); diff --git a/src/main/java/org/orekit/models/earth/troposphere/ViennaThreeModel.java b/src/main/java/org/orekit/models/earth/troposphere/ViennaThreeModel.java index ac7a704aee..be0ed78b61 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/ViennaThreeModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/ViennaThreeModel.java @@ -262,8 +262,8 @@ public > T[] mappingFactors(final T elevation, // Compute Mapping Function Eq. 4 final T[] function = MathArrays.buildArray(field, 2); - function[0] = TroposphericModelUtils.mappingFunction(zero.add(coefficientsA[0]), bh, ch, elevation); - function[1] = TroposphericModelUtils.mappingFunction(zero.add(coefficientsA[1]), bw, cw, elevation); + function[0] = TroposphericModelUtils.mappingFunction(zero.newInstance(coefficientsA[0]), bh, ch, elevation); + function[1] = TroposphericModelUtils.mappingFunction(zero.newInstance(coefficientsA[1]), bw, cw, elevation); return function; } @@ -324,8 +324,8 @@ public > T[] computeZenithDelay(final FieldGeo final Field field = date.getField(); final T zero = field.getZero(); final T[] delays = MathArrays.buildArray(field, 2); - delays[0] = zero.add(zenithDelay[0]); - delays[1] = zero.add(zenithDelay[1]); + delays[0] = zero.newInstance(zenithDelay[0]); + delays[1] = zero.newInstance(zenithDelay[1]); return delays; } diff --git a/src/main/java/org/orekit/orbits/FieldCartesianOrbit.java b/src/main/java/org/orekit/orbits/FieldCartesianOrbit.java index f83ce34f1f..13541b5c6d 100644 --- a/src/main/java/org/orekit/orbits/FieldCartesianOrbit.java +++ b/src/main/java/org/orekit/orbits/FieldCartesianOrbit.java @@ -147,7 +147,7 @@ public FieldCartesianOrbit(final FieldOrbit op) { */ public FieldCartesianOrbit(final Field field, final CartesianOrbit op) { super(new TimeStampedFieldPVCoordinates<>(field, op.getPVCoordinates()), op.getFrame(), - field.getZero().add(op.getMu())); + field.getZero().newInstance(op.getMu())); hasNonKeplerianAcceleration = op.hasDerivatives(); if (op.isElliptical()) { equinoctial = new FieldEquinoctialOrbit<>(field, new EquinoctialOrbit(op)); @@ -428,7 +428,7 @@ protected TimeStampedFieldPVCoordinates initPVCoordinates() { /** {@inheritDoc} */ public FieldCartesianOrbit shiftedBy(final double dt) { - return shiftedBy(getZero().add(dt)); + return shiftedBy(getZero().newInstance(dt)); } /** {@inheritDoc} */ diff --git a/src/main/java/org/orekit/orbits/FieldCircularOrbit.java b/src/main/java/org/orekit/orbits/FieldCircularOrbit.java index 26e51fbde8..676987e9cd 100644 --- a/src/main/java/org/orekit/orbits/FieldCircularOrbit.java +++ b/src/main/java/org/orekit/orbits/FieldCircularOrbit.java @@ -411,22 +411,22 @@ public FieldCircularOrbit(final FieldOrbit op) { * @since 12.0 */ public FieldCircularOrbit(final Field field, final CircularOrbit op) { - super(op.getFrame(), new FieldAbsoluteDate<>(field, op.getDate()), field.getZero().add(op.getMu())); + super(op.getFrame(), new FieldAbsoluteDate<>(field, op.getDate()), field.getZero().newInstance(op.getMu())); - a = getZero().add(op.getA()); - i = getZero().add(op.getI()); - raan = getZero().add(op.getRightAscensionOfAscendingNode()); - ex = getZero().add(op.getCircularEx()); - ey = getZero().add(op.getCircularEy()); - alphaV = getZero().add(op.getAlphaV()); + a = getZero().newInstance(op.getA()); + i = getZero().newInstance(op.getI()); + raan = getZero().newInstance(op.getRightAscensionOfAscendingNode()); + ex = getZero().newInstance(op.getCircularEx()); + ey = getZero().newInstance(op.getCircularEy()); + alphaV = getZero().newInstance(op.getAlphaV()); if (op.hasDerivatives()) { - aDot = getZero().add(op.getADot()); - iDot = getZero().add(op.getIDot()); - raanDot = getZero().add(op.getRightAscensionOfAscendingNodeDot()); - exDot = getZero().add(op.getCircularExDot()); - eyDot = getZero().add(op.getCircularEyDot()); - alphaVDot = getZero().add(op.getAlphaVDot()); + aDot = getZero().newInstance(op.getADot()); + iDot = getZero().newInstance(op.getIDot()); + raanDot = getZero().newInstance(op.getRightAscensionOfAscendingNodeDot()); + exDot = getZero().newInstance(op.getCircularExDot()); + eyDot = getZero().newInstance(op.getCircularEyDot()); + alphaVDot = getZero().newInstance(op.getAlphaVDot()); } else { aDot = null; exDot = null; @@ -955,7 +955,7 @@ protected TimeStampedFieldPVCoordinates initPVCoordinates() { /** {@inheritDoc} */ public FieldCircularOrbit shiftedBy(final double dt) { - return shiftedBy(getZero().add(dt)); + return shiftedBy(getZero().newInstance(dt)); } /** {@inheritDoc} */ @@ -1108,7 +1108,7 @@ protected T[][] computeJacobianMeanWrtCartesian() { final FieldVector3D dc1P = new FieldVector3D<>(aOr2.multiply(eSinE.multiply(eSinE).multiply(2).add(1).subtract(eCosE)).divide(r2), position, aOr2.multiply(-2).multiply(eSinE).multiply(oOsqrtMuA), velocity); final FieldVector3D dc1V = new FieldVector3D<>(aOr2.multiply(-2).multiply(eSinE).multiply(oOsqrtMuA), position, - getZero().add(2).divide(mu), velocity); + getZero().newInstance(2).divide(mu), velocity); final FieldVector3D dc2P = new FieldVector3D<>(aOr2.multiply(eSinE).multiply(eSinE.multiply(eSinE).subtract(e2.negate().add(1))).divide(r2.multiply(epsilon)), position, aOr2.multiply(e2.negate().add(1).subtract(eSinE.multiply(eSinE))).multiply(oOsqrtMuA).divide(epsilon), velocity); final FieldVector3D dc2V = new FieldVector3D<>(aOr2.multiply(e2.negate().add(1).subtract(eSinE.multiply(eSinE))).multiply(oOsqrtMuA).divide(epsilon), position, diff --git a/src/main/java/org/orekit/orbits/FieldEquinoctialOrbit.java b/src/main/java/org/orekit/orbits/FieldEquinoctialOrbit.java index ca7f6065d8..8abb1674c2 100644 --- a/src/main/java/org/orekit/orbits/FieldEquinoctialOrbit.java +++ b/src/main/java/org/orekit/orbits/FieldEquinoctialOrbit.java @@ -374,22 +374,22 @@ public FieldEquinoctialOrbit(final FieldOrbit op) { * @since 12.0 */ public FieldEquinoctialOrbit(final Field field, final EquinoctialOrbit op) { - super(op.getFrame(), new FieldAbsoluteDate<>(field, op.getDate()), field.getZero().add(op.getMu())); + super(op.getFrame(), new FieldAbsoluteDate<>(field, op.getDate()), field.getZero().newInstance(op.getMu())); - a = getZero().add(op.getA()); - ex = getZero().add(op.getEquinoctialEx()); - ey = getZero().add(op.getEquinoctialEy()); - hx = getZero().add(op.getHx()); - hy = getZero().add(op.getHy()); - lv = getZero().add(op.getLv()); + a = getZero().newInstance(op.getA()); + ex = getZero().newInstance(op.getEquinoctialEx()); + ey = getZero().newInstance(op.getEquinoctialEy()); + hx = getZero().newInstance(op.getHx()); + hy = getZero().newInstance(op.getHy()); + lv = getZero().newInstance(op.getLv()); if (op.hasDerivatives()) { - aDot = getZero().add(op.getADot()); - exDot = getZero().add(op.getEquinoctialExDot()); - eyDot = getZero().add(op.getEquinoctialEyDot()); - hxDot = getZero().add(op.getHxDot()); - hyDot = getZero().add(op.getHyDot()); - lvDot = getZero().add(op.getLvDot()); + aDot = getZero().newInstance(op.getADot()); + exDot = getZero().newInstance(op.getEquinoctialExDot()); + eyDot = getZero().newInstance(op.getEquinoctialEyDot()); + hxDot = getZero().newInstance(op.getHxDot()); + hyDot = getZero().newInstance(op.getHyDot()); + lvDot = getZero().newInstance(op.getLvDot()); } else { aDot = null; exDot = null; @@ -781,7 +781,7 @@ protected TimeStampedFieldPVCoordinates initPVCoordinates() { /** {@inheritDoc} */ public FieldEquinoctialOrbit shiftedBy(final double dt) { - return shiftedBy(getZero().add(dt)); + return shiftedBy(getZero().newInstance(dt)); } /** {@inheritDoc} */ @@ -905,7 +905,7 @@ protected T[][] computeJacobianMeanWrtCartesian() { // dLambdaM final T l = ratio.negate().divide(sqrtMuA); fillHalfRow(getOne().negate().divide(sqrtMuA), velocity, d2, w, l.multiply(ex), drDotSdEx, l.multiply(ey), drDotSdEy, jacobian[5], 0); - fillHalfRow(getZero().add(-2).divide(sqrtMuA), position, ex.multiply(beta), vectorEyRDot, ey.negate().multiply(beta), vectorExRDot, d3, w, jacobian[5], 3); + fillHalfRow(getZero().newInstance(-2).divide(sqrtMuA), position, ex.multiply(beta), vectorEyRDot, ey.negate().multiply(beta), vectorExRDot, d3, w, jacobian[5], 3); return jacobian; diff --git a/src/main/java/org/orekit/orbits/FieldKeplerianAnomalyUtility.java b/src/main/java/org/orekit/orbits/FieldKeplerianAnomalyUtility.java index 5e2bace3dc..96366adbcb 100644 --- a/src/main/java/org/orekit/orbits/FieldKeplerianAnomalyUtility.java +++ b/src/main/java/org/orekit/orbits/FieldKeplerianAnomalyUtility.java @@ -290,11 +290,11 @@ public static > T hyperbolicMeanToEccentric(fi final Field field = e.getField(); final T zero = field.getZero(); final T one = field.getOne(); - final T two = zero.add(2.0); - final T three = zero.add(3.0); - final T half = zero.add(0.5); - final T onePointFive = zero.add(1.5); - final T fourThirds = zero.add(4.0).divide(zero.add(3.0)); + final T two = zero.newInstance(2.0); + final T three = zero.newInstance(3.0); + final T half = zero.newInstance(0.5); + final T onePointFive = zero.newInstance(1.5); + final T fourThirds = zero.newInstance(4.0).divide(3.0); // Solve L = S - g * asinh(S) for S = sinh(H). final T L = M.divide(e); @@ -324,7 +324,7 @@ public static > T hyperbolicMeanToEccentric(fi T f; T fd; - if (s0.divide(zero.add(6.0)).add(g1).getReal() >= 0.5) { + if (s0.divide(6.0).add(g1).getReal() >= 0.5) { f = S.subtract(g.multiply(S.asinh())).subtract(L); fd = one.subtract(g.divide(s2)); } else { diff --git a/src/main/java/org/orekit/orbits/FieldKeplerianOrbit.java b/src/main/java/org/orekit/orbits/FieldKeplerianOrbit.java index 1945680ced..a8fe85f177 100644 --- a/src/main/java/org/orekit/orbits/FieldKeplerianOrbit.java +++ b/src/main/java/org/orekit/orbits/FieldKeplerianOrbit.java @@ -428,16 +428,16 @@ public FieldKeplerianOrbit(final FieldOrbit op) { * @since 12.0 */ public FieldKeplerianOrbit(final Field field, final KeplerianOrbit op) { - this(field.getZero().add(op.getA()), field.getZero().add(op.getE()), field.getZero().add(op.getI()), - field.getZero().add(op.getPerigeeArgument()), field.getZero().add(op.getRightAscensionOfAscendingNode()), - field.getZero().add(op.getTrueAnomaly()), - (op.hasDerivatives()) ? field.getZero().add(op.getADot()) : null, - (op.hasDerivatives()) ? field.getZero().add(op.getEDot()) : null, - (op.hasDerivatives()) ? field.getZero().add(op.getIDot()) : null, - (op.hasDerivatives()) ? field.getZero().add(op.getPerigeeArgumentDot()) : null, - (op.hasDerivatives()) ? field.getZero().add(op.getRightAscensionOfAscendingNodeDot()) : null, - (op.hasDerivatives()) ? field.getZero().add(op.getTrueAnomalyDot()) : null, PositionAngleType.TRUE, - op.getFrame(), new FieldAbsoluteDate<>(field, op.getDate()), field.getZero().add(op.getMu())); + this(field.getZero().newInstance(op.getA()), field.getZero().newInstance(op.getE()), field.getZero().newInstance(op.getI()), + field.getZero().newInstance(op.getPerigeeArgument()), field.getZero().newInstance(op.getRightAscensionOfAscendingNode()), + field.getZero().newInstance(op.getTrueAnomaly()), + (op.hasDerivatives()) ? field.getZero().newInstance(op.getADot()) : null, + (op.hasDerivatives()) ? field.getZero().newInstance(op.getEDot()) : null, + (op.hasDerivatives()) ? field.getZero().newInstance(op.getIDot()) : null, + (op.hasDerivatives()) ? field.getZero().newInstance(op.getPerigeeArgumentDot()) : null, + (op.hasDerivatives()) ? field.getZero().newInstance(op.getRightAscensionOfAscendingNodeDot()) : null, + (op.hasDerivatives()) ? field.getZero().newInstance(op.getTrueAnomalyDot()) : null, PositionAngleType.TRUE, + op.getFrame(), new FieldAbsoluteDate<>(field, op.getDate()), field.getZero().newInstance(op.getMu())); } /** Constructor from Field and Orbit. @@ -926,7 +926,7 @@ protected TimeStampedFieldPVCoordinates initPVCoordinates() { /** {@inheritDoc} */ public FieldKeplerianOrbit shiftedBy(final double dt) { - return shiftedBy(getZero().add(dt)); + return shiftedBy(getZero().newInstance(dt)); } /** {@inheritDoc} */ diff --git a/src/main/java/org/orekit/propagation/FieldSpacecraftState.java b/src/main/java/org/orekit/propagation/FieldSpacecraftState.java index 7f237778ba..4a61628533 100644 --- a/src/main/java/org/orekit/propagation/FieldSpacecraftState.java +++ b/src/main/java/org/orekit/propagation/FieldSpacecraftState.java @@ -113,7 +113,7 @@ public class FieldSpacecraftState > public FieldSpacecraftState(final FieldOrbit orbit) { this(orbit, SpacecraftState.getDefaultAttitudeProvider(orbit.getFrame()) .getAttitude(orbit, orbit.getDate(), orbit.getFrame()), - orbit.getA().getField().getZero().add(DEFAULT_MASS), (FieldArrayDictionary) null); + orbit.getA().getField().getZero().newInstance(DEFAULT_MASS), (FieldArrayDictionary) null); } /** Build a spacecraft state from orbit and attitude. @@ -125,7 +125,7 @@ public FieldSpacecraftState(final FieldOrbit orbit) { */ public FieldSpacecraftState(final FieldOrbit orbit, final FieldAttitude attitude) throws IllegalArgumentException { - this(orbit, attitude, orbit.getA().getField().getZero().add(DEFAULT_MASS), (FieldArrayDictionary) null); + this(orbit, attitude, orbit.getA().getField().getZero().newInstance(DEFAULT_MASS), (FieldArrayDictionary) null); } /** Create a new instance from orbit and mass. @@ -160,7 +160,7 @@ public FieldSpacecraftState(final FieldOrbit orbit, final FieldAttitude at public FieldSpacecraftState(final FieldOrbit orbit, final FieldArrayDictionary additional) { this(orbit, SpacecraftState.getDefaultAttitudeProvider(orbit.getFrame()) .getAttitude(orbit, orbit.getDate(), orbit.getFrame()), - orbit.getA().getField().getZero().add(DEFAULT_MASS), additional); + orbit.getA().getField().getZero().newInstance(DEFAULT_MASS), additional); } /** Build a spacecraft state from orbit attitude and additional states. @@ -174,7 +174,7 @@ public FieldSpacecraftState(final FieldOrbit orbit, final FieldArrayDictionar */ public FieldSpacecraftState(final FieldOrbit orbit, final FieldAttitude attitude, final FieldArrayDictionary additional) throws IllegalArgumentException { - this(orbit, attitude, orbit.getA().getField().getZero().add(DEFAULT_MASS), additional); + this(orbit, attitude, orbit.getA().getField().getZero().newInstance(DEFAULT_MASS), additional); } /** Create a new instance from orbit, mass and additional states. @@ -250,7 +250,7 @@ public FieldSpacecraftState(final Field field, final SpacecraftState state) { state.getOrbit().getType().mapOrbitToArray(state.getOrbit(), positionAngleType, stateD, stateDotD); final T[] stateF = MathArrays.buildArray(field, 6); for (int i = 0; i < stateD.length; ++i) { - stateF[i] = field.getZero().add(stateD[i]); + stateF[i] = field.getZero().newInstance(stateD[i]); } final T[] stateDotF; if (stateDotD == null) { @@ -258,14 +258,14 @@ public FieldSpacecraftState(final Field field, final SpacecraftState state) { } else { stateDotF = MathArrays.buildArray(field, 6); for (int i = 0; i < stateDotD.length; ++i) { - stateDotF[i] = field.getZero().add(stateDotD[i]); + stateDotF[i] = field.getZero().newInstance(stateDotD[i]); } } final FieldAbsoluteDate dateF = new FieldAbsoluteDate<>(field, state.getDate()); this.orbit = state.getOrbit().getType().mapArrayToOrbit(stateF, stateDotF, positionAngleType, dateF, - field.getZero().add(state.getMu()), state.getFrame()); + field.getZero().newInstance(state.getMu()), state.getFrame()); this.absPva = null; } else { @@ -280,7 +280,7 @@ public FieldSpacecraftState(final Field field, final SpacecraftState state) { } this.attitude = new FieldAttitude<>(field, state.getAttitude()); - this.mass = field.getZero().add(state.getMass()); + this.mass = field.getZero().newInstance(state.getMass()); final DoubleArrayDictionary additionalD = state.getAdditionalStatesValues(); if (additionalD.size() == 0) { @@ -311,7 +311,7 @@ public FieldSpacecraftState(final FieldAbsolutePVCoordinates absPva) { this(absPva, SpacecraftState.getDefaultAttitudeProvider(absPva.getFrame()). getAttitude(absPva, absPva.getDate(), absPva.getFrame()), - absPva.getDate().getField().getZero().add(DEFAULT_MASS), (FieldArrayDictionary) null); + absPva.getDate().getField().getZero().newInstance(DEFAULT_MASS), (FieldArrayDictionary) null); } /** Build a spacecraft state from orbit and attitude. @@ -323,7 +323,7 @@ public FieldSpacecraftState(final FieldAbsolutePVCoordinates absPva) { */ public FieldSpacecraftState(final FieldAbsolutePVCoordinates absPva, final FieldAttitude attitude) throws IllegalArgumentException { - this(absPva, attitude, absPva.getDate().getField().getZero().add(DEFAULT_MASS), (FieldArrayDictionary) null); + this(absPva, attitude, absPva.getDate().getField().getZero().newInstance(DEFAULT_MASS), (FieldArrayDictionary) null); } /** Create a new instance from orbit and mass. @@ -358,7 +358,7 @@ public FieldSpacecraftState(final FieldAbsolutePVCoordinates absPva, final Fi public FieldSpacecraftState(final FieldAbsolutePVCoordinates absPva, final FieldArrayDictionary additional) { this(absPva, SpacecraftState.getDefaultAttitudeProvider(absPva.getFrame()) .getAttitude(absPva, absPva.getDate(), absPva.getFrame()), - absPva.getDate().getField().getZero().add(DEFAULT_MASS), additional); + absPva.getDate().getField().getZero().newInstance(DEFAULT_MASS), additional); } /** Build a spacecraft state from orbit and attitude. @@ -373,7 +373,7 @@ public FieldSpacecraftState(final FieldAbsolutePVCoordinates absPva, final Fi public FieldSpacecraftState(final FieldAbsolutePVCoordinates absPva, final FieldAttitude attitude, final FieldArrayDictionary additional) throws IllegalArgumentException { - this(absPva, attitude, absPva.getDate().getField().getZero().add(DEFAULT_MASS), additional); + this(absPva, attitude, absPva.getDate().getField().getZero().newInstance(DEFAULT_MASS), additional); } /** Create a new instance from orbit and mass. diff --git a/src/main/java/org/orekit/propagation/FieldSpacecraftStateInterpolator.java b/src/main/java/org/orekit/propagation/FieldSpacecraftStateInterpolator.java index 874f85bb0f..ab33c6855c 100644 --- a/src/main/java/org/orekit/propagation/FieldSpacecraftStateInterpolator.java +++ b/src/main/java/org/orekit/propagation/FieldSpacecraftStateInterpolator.java @@ -405,7 +405,7 @@ protected FieldSpacecraftState interpolate(final InterpolationData interpola interpolatedMass = massInterpolator.interpolate(interpolationDate, masses).getValue(); } else { - interpolatedMass = one.multiply(SpacecraftState.DEFAULT_MASS); + interpolatedMass = one.newInstance(SpacecraftState.DEFAULT_MASS); } // Interpolate additional states and derivatives diff --git a/src/main/java/org/orekit/propagation/analytical/BrouwerLyddaneGradientConverter.java b/src/main/java/org/orekit/propagation/analytical/BrouwerLyddaneGradientConverter.java index e36c18d061..eb6e04c408 100644 --- a/src/main/java/org/orekit/propagation/analytical/BrouwerLyddaneGradientConverter.java +++ b/src/main/java/org/orekit/propagation/analytical/BrouwerLyddaneGradientConverter.java @@ -60,7 +60,7 @@ public FieldBrouwerLyddanePropagator getPropagator(final FieldSpacecra final AttitudeProvider provider = propagator.getAttitudeProvider(); // Central attraction coefficient - final Gradient mu = zero.add(propagator.getMu()); + final Gradient mu = zero.newInstance(propagator.getMu()); // Return the "Field" propagator return new FieldBrouwerLyddanePropagator<>(state.getOrbit(), provider, radius, mu, diff --git a/src/main/java/org/orekit/propagation/analytical/EcksteinHechlerGradientConverter.java b/src/main/java/org/orekit/propagation/analytical/EcksteinHechlerGradientConverter.java index 891ed4f077..e00d57a0a1 100644 --- a/src/main/java/org/orekit/propagation/analytical/EcksteinHechlerGradientConverter.java +++ b/src/main/java/org/orekit/propagation/analytical/EcksteinHechlerGradientConverter.java @@ -61,7 +61,7 @@ public FieldEcksteinHechlerPropagator getPropagator(final FieldSpacecr final AttitudeProvider provider = propagator.getAttitudeProvider(); // Central attraction coefficient - final Gradient mu = zero.add(propagator.getMu()); + final Gradient mu = zero.newInstance(propagator.getMu()); // Return the "Field" propagator return new FieldEcksteinHechlerPropagator<>(state.getOrbit(), provider, radius, mu, diff --git a/src/main/java/org/orekit/propagation/analytical/FieldBrouwerLyddanePropagator.java b/src/main/java/org/orekit/propagation/analytical/FieldBrouwerLyddanePropagator.java index a3d5c6838a..8a25b76bd4 100644 --- a/src/main/java/org/orekit/propagation/analytical/FieldBrouwerLyddanePropagator.java +++ b/src/main/java/org/orekit/propagation/analytical/FieldBrouwerLyddanePropagator.java @@ -992,7 +992,7 @@ private static class FieldBLModel> { subtract(epp2.multiply(5.0).add(2.0).multiply(40.0).multiply(cosI4.divide(C5c2))). subtract(epp2.multiply(400.0).multiply(cosI6).divide(C5c2).divide(C5c2)); final T qyp42 = one.divide(5.0).multiply(qyp22. - add(one.multiply(4.0).multiply(epp2. + add(one.newInstance(4.0).multiply(epp2. add(2.0). subtract(cosI2.multiply(epp2.multiply(3.0).add(2.0)))))); final T qyp52bis = cosI1.multiply(sinI1).multiply(epp).multiply(epp2.multiply(3.0).add(4.0)). diff --git a/src/main/java/org/orekit/propagation/analytical/FieldEcksteinHechlerPropagator.java b/src/main/java/org/orekit/propagation/analytical/FieldEcksteinHechlerPropagator.java index 674d4394f9..dc4a32d50a 100644 --- a/src/main/java/org/orekit/propagation/analytical/FieldEcksteinHechlerPropagator.java +++ b/src/main/java/org/orekit/propagation/analytical/FieldEcksteinHechlerPropagator.java @@ -791,7 +791,7 @@ private static class FieldEHModel> { final T zero = mass.getField().getZero(); final T one = mass.getField().getOne(); // preliminary processing - T q = zero.add(referenceRadius).divide(mean.getA()); + T q = zero.newInstance(referenceRadius).divide(mean.getA()); T ql = q.multiply(q); final T g2 = ql.multiply(ck0[2]); ql = ql.multiply(q); @@ -833,7 +833,7 @@ private static class FieldEHModel> { g6.multiply(13.125).multiply(one.subtract(sinI2.multiply(8.0)).add(sinI4.multiply(129.0 / 8.0)).subtract(sinI6.multiply(297.0 / 32.0)) )); - q = zero.add(3.0).divide(rdpom.multiply(32.0)); + q = zero.newInstance(3.0).divide(rdpom.multiply(32.0)); eps1 = q.multiply(g4).multiply(sinI2).multiply(sinI2.multiply(-35.0).add(30.0)).subtract( q.multiply(175.0).multiply(g6).multiply(sinI2).multiply(sinI2.multiply(-3.0).add(sinI4.multiply(2.0625)).add(1.0))); q = sinI1.multiply(3.0).divide(rdpom.multiply(8.0)); @@ -856,7 +856,7 @@ private static class FieldEHModel> { final T qC = g6.multiply(105.0 / 16.0).multiply(sinI2); final T qD = g3.multiply(-0.75).multiply(sinI1); final T qE = g5.multiply(3.75).multiply(sinI1); - kh = zero.add(0.375).divide(rdpom); + kh = zero.newInstance(0.375).divide(rdpom); kl = kh.divide(sinI1); ax1 = qq.multiply(sinI2.multiply(-3.5).add(2.0)); diff --git a/src/main/java/org/orekit/propagation/analytical/FieldKeplerianPropagator.java b/src/main/java/org/orekit/propagation/analytical/FieldKeplerianPropagator.java index 4a60015bc4..ada282cad5 100644 --- a/src/main/java/org/orekit/propagation/analytical/FieldKeplerianPropagator.java +++ b/src/main/java/org/orekit/propagation/analytical/FieldKeplerianPropagator.java @@ -56,7 +56,7 @@ public class FieldKeplerianPropagator> extends */ public FieldKeplerianPropagator(final FieldOrbit initialFieldOrbit) { this(initialFieldOrbit, FrameAlignedProvider.of(initialFieldOrbit.getFrame()), - initialFieldOrbit.getMu(), initialFieldOrbit.getA().getField().getZero().add(DEFAULT_MASS)); + initialFieldOrbit.getMu(), initialFieldOrbit.getA().getField().getZero().newInstance(DEFAULT_MASS)); } /** Build a propagator from orbit and central attraction coefficient μ. @@ -68,7 +68,7 @@ public FieldKeplerianPropagator(final FieldOrbit initialFieldOrbit) { */ public FieldKeplerianPropagator(final FieldOrbit initialFieldOrbit, final T mu) { this(initialFieldOrbit, FrameAlignedProvider.of(initialFieldOrbit.getFrame()), - mu, initialFieldOrbit.getA().getField().getZero().add(DEFAULT_MASS)); + mu, initialFieldOrbit.getA().getField().getZero().newInstance(DEFAULT_MASS)); } /** Build a propagator from orbit and attitude provider. @@ -80,7 +80,8 @@ public FieldKeplerianPropagator(final FieldOrbit initialFieldOrbit, final T m */ public FieldKeplerianPropagator(final FieldOrbit initialFieldOrbit, final AttitudeProvider attitudeProv) { - this(initialFieldOrbit, attitudeProv, initialFieldOrbit.getMu(), initialFieldOrbit.getA().getField().getZero().add(DEFAULT_MASS)); + this(initialFieldOrbit, attitudeProv, initialFieldOrbit.getMu(), + initialFieldOrbit.getA().getField().getZero().newInstance(DEFAULT_MASS)); } /** Build a propagator from orbit, attitude provider and central attraction @@ -93,7 +94,7 @@ public FieldKeplerianPropagator(final FieldOrbit initialFieldOrbit, public FieldKeplerianPropagator(final FieldOrbit initialFieldOrbit, final AttitudeProvider attitudeProv, final T mu) { - this(initialFieldOrbit, attitudeProv, mu, initialFieldOrbit.getA().getField().getZero().add(DEFAULT_MASS)); + this(initialFieldOrbit, attitudeProv, mu, initialFieldOrbit.getA().getField().getZero().newInstance(DEFAULT_MASS)); } /** Build propagator from orbit, attitude provider, central attraction diff --git a/src/main/java/org/orekit/propagation/analytical/KeplerianGradientConverter.java b/src/main/java/org/orekit/propagation/analytical/KeplerianGradientConverter.java index 143c28392e..2f3cd318dd 100644 --- a/src/main/java/org/orekit/propagation/analytical/KeplerianGradientConverter.java +++ b/src/main/java/org/orekit/propagation/analytical/KeplerianGradientConverter.java @@ -59,7 +59,7 @@ public FieldKeplerianPropagator getPropagator(final FieldSpacecraftSta final AttitudeProvider provider = propagator.getAttitudeProvider(); // Central attraction coefficient - final Gradient mu = zero.add(propagator.getInitialState().getMu()); + final Gradient mu = zero.newInstance(propagator.getInitialState().getMu()); // Return the "Field" propagator return new FieldKeplerianPropagator<>(state.getOrbit(), provider, mu); diff --git a/src/main/java/org/orekit/propagation/analytical/gnss/GLONASSAnalyticalPropagator.java b/src/main/java/org/orekit/propagation/analytical/gnss/GLONASSAnalyticalPropagator.java index 52ef9b6416..09d03e7a5f 100644 --- a/src/main/java/org/orekit/propagation/analytical/gnss/GLONASSAnalyticalPropagator.java +++ b/src/main/java/org/orekit/propagation/analytical/gnss/GLONASSAnalyticalPropagator.java @@ -169,10 +169,10 @@ public PVCoordinates propagateInEcef(final AbsoluteDate date) { final UnivariateDerivative2 w = FastMath.floor(dTpr.divide(GLONASS_MEAN_DRACONIAN_PERIOD + glonassOrbit.getDeltaT())); // Current inclination - final UnivariateDerivative2 i = zero.add(GLONASS_MEAN_INCLINATION / 180 * GNSSConstants.GLONASS_PI + glonassOrbit.getDeltaI()); + final UnivariateDerivative2 i = zero.newInstance(GLONASS_MEAN_INCLINATION / 180 * GNSSConstants.GLONASS_PI + glonassOrbit.getDeltaI()); // Eccentricity - final UnivariateDerivative2 e = zero.add(glonassOrbit.getE()); + final UnivariateDerivative2 e = zero.newInstance(glonassOrbit.getE()); // Mean draconique period in orbite w+1 and mean motion final UnivariateDerivative2 tDR = w.multiply(2.0).add(1.0).multiply(glonassOrbit.getDeltaTDot()). @@ -227,9 +227,9 @@ public PVCoordinates propagateInEcef(final AbsoluteDate date) { paCorr = zero; } else { if (lCorr.getValue() == eCorr.getValue()) { - paCorr = zero.add(0.5 * GNSSConstants.GLONASS_PI); + paCorr = zero.newInstance(0.5 * GNSSConstants.GLONASS_PI); } else if (lCorr.getValue() == -eCorr.getValue()) { - paCorr = zero.add(-0.5 * GNSSConstants.GLONASS_PI); + paCorr = zero.newInstance(-0.5 * GNSSConstants.GLONASS_PI); } else { paCorr = FastMath.atan2(hCorr, lCorr); } @@ -428,7 +428,7 @@ private UnivariateDerivative2 computeSma(final UnivariateDerivative2 tDR, final UnivariateDerivative2 sin2I = sinI.multiply(sinI); final UnivariateDerivative2 ome2 = e.multiply(e).negate().add(1.0); final UnivariateDerivative2 ome2Pow3o2 = FastMath.sqrt(ome2).multiply(ome2); - final UnivariateDerivative2 pa = zero.add(glonassOrbit.getPa()); + final UnivariateDerivative2 pa = zero.newInstance(glonassOrbit.getPa()); final UnivariateDerivative2 cosPA = FastMath.cos(pa); final UnivariateDerivative2 opecosPA = e.multiply(cosPA).add(1.0); final UnivariateDerivative2 opecosPAPow2 = opecosPA.multiply(opecosPA); diff --git a/src/main/java/org/orekit/propagation/analytical/tle/FieldDeepSDP4.java b/src/main/java/org/orekit/propagation/analytical/tle/FieldDeepSDP4.java index 3faa765d39..5a7f24b418 100644 --- a/src/main/java/org/orekit/propagation/analytical/tle/FieldDeepSDP4.java +++ b/src/main/java/org/orekit/propagation/analytical/tle/FieldDeepSDP4.java @@ -222,12 +222,12 @@ protected void luniSolarTermsComputation() { zmos = MathUtils.normalizeAngle(6.2565837 + 0.017201977 * daysSince1900, pi.getReal()); // Do solar terms - savtsn = zero.add(1e20); + savtsn = zero.newInstance(1e20); - T zcosi = zero.add(0.91744867); - T zsini = zero.add(0.39785416); - T zsing = zero.add(-0.98088458); - T zcosg = zero.add(0.1945905); + T zcosi = zero.newInstance(0.91744867); + T zsini = zero.newInstance(0.39785416); + T zsing = zero.newInstance(-0.98088458); + T zcosg = zero.newInstance(0.1945905); T se = zero; T sgh = zero; @@ -328,10 +328,10 @@ protected void luniSolarTermsComputation() { sh3 = xh3; sl4 = xl4; sgh4 = xgh4; - zcosg = zero.add(zcosgl); - zsing = zero.add(zsingl); - zcosi = zero.add(zcosil); - zsini = zero.add(zsinil); + zcosg = zero.newInstance(zcosgl); + zsing = zero.newInstance(zsingl); + zcosi = zero.newInstance(zcosil); + zsini = zero.newInstance(zsinil); zcosh = cosq.multiply(zcoshl).add(sinq.multiply(zsinhl)); zsinh = sinq.multiply(zcoshl).subtract(cosq.multiply(zsinhl)); zn = TLEConstants.ZNL; @@ -520,7 +520,7 @@ protected void deepSecularEffects(final T t) { final T xldot = xni.add(xfact); - T xlpow = t.getField().getZero().add(1.); + T xlpow = t.getField().getOne(); xli = xli.add(xldot.multiply(delt)); xni = xni.add(derivs[0].multiply(delt)); double delt_factor = delt; diff --git a/src/main/java/org/orekit/propagation/analytical/tle/FieldSGP4.java b/src/main/java/org/orekit/propagation/analytical/tle/FieldSGP4.java index ab24f562b7..0fdad946fd 100644 --- a/src/main/java/org/orekit/propagation/analytical/tle/FieldSGP4.java +++ b/src/main/java/org/orekit/propagation/analytical/tle/FieldSGP4.java @@ -168,7 +168,7 @@ protected void sxpPropagate(final T tSince, final T[] parameters) { // A highly arbitrary lower limit on e, of 1e-6: if (e.getReal() < 1e-6) { - e = e.getField().getZero().add(1e-6); + e = e.getField().getZero().newInstance(1e-6); } xl = xmp.add(omega).add(xnode).add(xn0dp.multiply(templ)); diff --git a/src/main/java/org/orekit/propagation/analytical/tle/FieldTLE.java b/src/main/java/org/orekit/propagation/analytical/tle/FieldTLE.java index 876d08b660..676dd8911a 100644 --- a/src/main/java/org/orekit/propagation/analytical/tle/FieldTLE.java +++ b/src/main/java/org/orekit/propagation/analytical/tle/FieldTLE.java @@ -239,11 +239,11 @@ public FieldTLE(final Field field, final String line1, final String line2, fi line1.substring(45, 50) + 'e' + line1.substring(50, 52)).replace(' ', '0'))).divide(5.3747712e13); - eccentricity = zero.add(Double.parseDouble("." + line2.substring(26, 33).replace(' ', '0'))); - inclination = zero.add(FastMath.toRadians(ParseUtils.parseDouble(line2, 8, 8))); - pa = zero.add(FastMath.toRadians(ParseUtils.parseDouble(line2, 34, 8))); - raan = zero.add(FastMath.toRadians(Double.parseDouble(line2.substring(17, 25).replace(' ', '0')))); - meanAnomaly = zero.add(FastMath.toRadians(ParseUtils.parseDouble(line2, 43, 8))); + eccentricity = zero.newInstance(Double.parseDouble("." + line2.substring(26, 33).replace(' ', '0'))); + inclination = zero.newInstance(FastMath.toRadians(ParseUtils.parseDouble(line2, 8, 8))); + pa = zero.newInstance(FastMath.toRadians(ParseUtils.parseDouble(line2, 34, 8))); + raan = zero.newInstance(FastMath.toRadians(Double.parseDouble(line2.substring(17, 25).replace(' ', '0')))); + meanAnomaly = zero.newInstance(FastMath.toRadians(ParseUtils.parseDouble(line2, 43, 8))); revolutionNumberAtEpoch = ParseUtils.parseInteger(line2, 63, 5); final double bStarValue = Double.parseDouble((line1.substring(53, 54) + '.' + diff --git a/src/main/java/org/orekit/propagation/analytical/tle/FieldTLEPropagator.java b/src/main/java/org/orekit/propagation/analytical/tle/FieldTLEPropagator.java index 4dc6f28e68..02e7ef3b23 100644 --- a/src/main/java/org/orekit/propagation/analytical/tle/FieldTLEPropagator.java +++ b/src/main/java/org/orekit/propagation/analytical/tle/FieldTLEPropagator.java @@ -253,7 +253,7 @@ public static > FieldTLEPropagator selectEx return selectExtrapolator( tle, FrameAlignedProvider.of(teme), - tle.getE().getField().getZero().add(DEFAULT_MASS), + tle.getE().getField().getZero().newInstance(DEFAULT_MASS), teme, parameters); } @@ -361,8 +361,8 @@ private void initializeCommons(final T[] parameters) { a0dp = a0.divide(delta0.negate().add(1.0)); // Values of s and qms2t : - s4 = zero.add(TLEConstants.S); // unmodified value for s - T q0ms24 = zero.add(TLEConstants.QOMS2T); // unmodified value for q0ms2T + s4 = zero.newInstance(TLEConstants.S); // unmodified value for s + T q0ms24 = zero.newInstance(TLEConstants.QOMS2T); // unmodified value for q0ms2T perige = a0dp.multiply(tle.getE().negate().add(1.0)).subtract(TLEConstants.NORMALIZED_EQUATORIAL_RADIUS).multiply( TLEConstants.EARTH_RADIUS); // perige @@ -370,7 +370,7 @@ private void initializeCommons(final T[] parameters) { // For perigee below 156 km, the values of s and qoms2t are changed : if (perige.getReal() < 156.0) { if (perige.getReal() <= 98.0) { - s4 = zero.add(20.0); + s4 = zero.newInstance(20.0); } else { s4 = perige.subtract(78.0); } @@ -606,7 +606,7 @@ protected T getMass(final FieldAbsoluteDate date) { /** {@inheritDoc} */ public FieldOrbit propagateOrbit(final FieldAbsoluteDate date, final T[] parameters) { - return new FieldCartesianOrbit<>(getPVCoordinates(date, parameters), teme, date, date.getField().getZero().add(TLEConstants.MU)); + return new FieldCartesianOrbit<>(getPVCoordinates(date, parameters), teme, date, date.getField().getZero().newInstance(TLEConstants.MU)); } /** Get the underlying TLE. diff --git a/src/main/java/org/orekit/propagation/analytical/tle/generation/FixedPointTleGenerationAlgorithm.java b/src/main/java/org/orekit/propagation/analytical/tle/generation/FixedPointTleGenerationAlgorithm.java index 9e88ca2ed5..572b7f8703 100644 --- a/src/main/java/org/orekit/propagation/analytical/tle/generation/FixedPointTleGenerationAlgorithm.java +++ b/src/main/java/org/orekit/propagation/analytical/tle/generation/FixedPointTleGenerationAlgorithm.java @@ -231,7 +231,7 @@ public > FieldTLE generate(final FieldSpace T lv = equinoctialOrbit.getLv(); // rough initialization of the TLE - final T bStar = state.getA().getField().getZero().add(templateTLE.getBStar()); + final T bStar = state.getA().getField().getZero().newInstance(templateTLE.getBStar()); final FieldKeplerianOrbit keplerianOrbit = (FieldKeplerianOrbit) OrbitType.KEPLERIAN.convertType(equinoctialOrbit); FieldTLE current = TleGenerationUtil.newTLE(keplerianOrbit, templateTLE, bStar, utc); diff --git a/src/main/java/org/orekit/propagation/analytical/tle/generation/LeastSquaresTleGenerationAlgorithm.java b/src/main/java/org/orekit/propagation/analytical/tle/generation/LeastSquaresTleGenerationAlgorithm.java index b671adc3d3..195534ec5d 100644 --- a/src/main/java/org/orekit/propagation/analytical/tle/generation/LeastSquaresTleGenerationAlgorithm.java +++ b/src/main/java/org/orekit/propagation/analytical/tle/generation/LeastSquaresTleGenerationAlgorithm.java @@ -290,7 +290,7 @@ private FieldVector meanStateToPV(final FieldVector state) { final FieldVector3D position = new FieldVector3D<>(state.getSubVector(0, 3).toArray()); final FieldVector3D velocity = new FieldVector3D<>(state.getSubVector(3, 3).toArray()); final FieldPVCoordinates pvCoordinates = new FieldPVCoordinates<>(position, velocity); - final FieldKeplerianOrbit orbit = new FieldKeplerianOrbit<>(pvCoordinates, teme, epoch, field.getZero().add(TLEPropagator.getMU())); + final FieldKeplerianOrbit orbit = new FieldKeplerianOrbit<>(pvCoordinates, teme, epoch, field.getZero().newInstance(TLEPropagator.getMU())); // Convert to TLE final FieldTLE tle = TleGenerationUtil.newTLE(orbit, templateTLE, bStar[0], utc); diff --git a/src/main/java/org/orekit/propagation/conversion/AbstractFixedStepFieldIntegratorBuilder.java b/src/main/java/org/orekit/propagation/conversion/AbstractFixedStepFieldIntegratorBuilder.java index c53f1d3b68..dde29dc1fe 100644 --- a/src/main/java/org/orekit/propagation/conversion/AbstractFixedStepFieldIntegratorBuilder.java +++ b/src/main/java/org/orekit/propagation/conversion/AbstractFixedStepFieldIntegratorBuilder.java @@ -83,6 +83,6 @@ protected void checkStep(final double stepToCheck) { * @return "fielded" step size (s) */ protected T getFieldStep(final Field field) { - return fieldStep != null ? fieldStep : field.getOne().multiply(step); + return fieldStep != null ? fieldStep : field.getZero().newInstance(step); } } diff --git a/src/main/java/org/orekit/propagation/events/FieldAltitudeDetector.java b/src/main/java/org/orekit/propagation/events/FieldAltitudeDetector.java index 1d30234c09..70b76348d7 100644 --- a/src/main/java/org/orekit/propagation/events/FieldAltitudeDetector.java +++ b/src/main/java/org/orekit/propagation/events/FieldAltitudeDetector.java @@ -53,8 +53,8 @@ public class FieldAltitudeDetector> extends Fi * @param bodyShape body shape with respect to which altitude should be evaluated */ public FieldAltitudeDetector(final T altitude, final BodyShape bodyShape) { - this(altitude.getField().getZero().add(DEFAULT_MAXCHECK), - altitude.getField().getZero().add(DEFAULT_THRESHOLD), + this(altitude.getField().getZero().newInstance(DEFAULT_MAXCHECK), + altitude.getField().getZero().newInstance(DEFAULT_THRESHOLD), altitude, bodyShape); } @@ -71,7 +71,7 @@ public FieldAltitudeDetector(final T altitude, final BodyShape bodyShape) { public FieldAltitudeDetector(final T maxCheck, final T altitude, final BodyShape bodyShape) { - this(maxCheck, altitude.getField().getZero().add(DEFAULT_THRESHOLD), altitude, bodyShape); + this(maxCheck, altitude.getField().getZero().newInstance(DEFAULT_THRESHOLD), altitude, bodyShape); } /** Build a new altitude detector. diff --git a/src/main/java/org/orekit/propagation/events/FieldDateDetector.java b/src/main/java/org/orekit/propagation/events/FieldDateDetector.java index ac06c057d0..821155bb7a 100644 --- a/src/main/java/org/orekit/propagation/events/FieldDateDetector.java +++ b/src/main/java/org/orekit/propagation/events/FieldDateDetector.java @@ -158,7 +158,7 @@ public List> getDates() { public T g(final FieldSpacecraftState s) { gDate = s.getDate(); if (currentIndex < 0) { - return s.getA().getField().getZero().add(-1); + return s.getA().getField().getZero().newInstance(-1); } else { final FieldEventDate event = getClosest(gDate); return event.isgIncrease() ? gDate.durationFrom(event.getDate()) : event.getDate().durationFrom(gDate); diff --git a/src/main/java/org/orekit/propagation/events/FieldElevationDetector.java b/src/main/java/org/orekit/propagation/events/FieldElevationDetector.java index b9d3e4ca7d..06a9d7b3a4 100644 --- a/src/main/java/org/orekit/propagation/events/FieldElevationDetector.java +++ b/src/main/java/org/orekit/propagation/events/FieldElevationDetector.java @@ -70,7 +70,7 @@ public class FieldElevationDetector> extends F */ public FieldElevationDetector(final Field field, final TopocentricFrame topo) { this(s -> DEFAULT_MAXCHECK, - field.getZero().add(DEFAULT_THRESHOLD), DEFAULT_MAX_ITER, + field.getZero().newInstance(DEFAULT_THRESHOLD), DEFAULT_MAX_ITER, new FieldStopOnDecreasing<>(), 0.0, null, null, topo); } diff --git a/src/main/java/org/orekit/propagation/events/FieldEventState.java b/src/main/java/org/orekit/propagation/events/FieldEventState.java index a36189b69b..2386db1fcc 100644 --- a/src/main/java/org/orekit/propagation/events/FieldEventState.java +++ b/src/main/java/org/orekit/propagation/events/FieldEventState.java @@ -399,9 +399,9 @@ private boolean findRoot(final FieldOrekitStepInterpolator interpolator, final Interval interval = solver.solveInterval(maxIterationCount, f, tbDouble, 0); beforeRootT = date.apply(interval.getRightAbscissa()); - beforeRootG = zero.add(interval.getRightValue()); + beforeRootG = zero.newInstance(interval.getRightValue()); afterRootT = date.apply(interval.getLeftAbscissa()); - afterRootG = zero.add(interval.getLeftValue()); + afterRootG = zero.newInstance(interval.getLeftValue()); // CHECKSTYLE: stop IllegalCatch check } catch (RuntimeException e) { // CHECKSTYLE: resume IllegalCatch check diff --git a/src/main/java/org/orekit/propagation/events/FieldFunctionalDetector.java b/src/main/java/org/orekit/propagation/events/FieldFunctionalDetector.java index d72651c2c0..666cf04122 100644 --- a/src/main/java/org/orekit/propagation/events/FieldFunctionalDetector.java +++ b/src/main/java/org/orekit/propagation/events/FieldFunctionalDetector.java @@ -56,7 +56,7 @@ public class FieldFunctionalDetector> */ public FieldFunctionalDetector(final Field field) { this(s -> DEFAULT_MAXCHECK, - field.getZero().add(DEFAULT_THRESHOLD), + field.getZero().newInstance(DEFAULT_THRESHOLD), DEFAULT_MAX_ITER, new FieldContinueOnEvent<>(), value -> field.getOne()); } diff --git a/src/main/java/org/orekit/propagation/events/FieldLatitudeCrossingDetector.java b/src/main/java/org/orekit/propagation/events/FieldLatitudeCrossingDetector.java index afc334971f..441993e8cd 100644 --- a/src/main/java/org/orekit/propagation/events/FieldLatitudeCrossingDetector.java +++ b/src/main/java/org/orekit/propagation/events/FieldLatitudeCrossingDetector.java @@ -53,7 +53,7 @@ public FieldLatitudeCrossingDetector(final Field field, final OneAxisEllipsoid body, final double latitude) { this(s -> DEFAULT_MAXCHECK, - field.getZero().add(DEFAULT_THRESHOLD), DEFAULT_MAX_ITER, new FieldStopOnIncreasing<>(), + field.getZero().newInstance(DEFAULT_THRESHOLD), DEFAULT_MAX_ITER, new FieldStopOnIncreasing<>(), body, latitude); } diff --git a/src/main/java/org/orekit/propagation/events/FieldLongitudeCrossingDetector.java b/src/main/java/org/orekit/propagation/events/FieldLongitudeCrossingDetector.java index bcf25f9169..f443ecd3a9 100644 --- a/src/main/java/org/orekit/propagation/events/FieldLongitudeCrossingDetector.java +++ b/src/main/java/org/orekit/propagation/events/FieldLongitudeCrossingDetector.java @@ -65,7 +65,7 @@ public class FieldLongitudeCrossingDetector > */ public FieldLongitudeCrossingDetector(final Field field, final OneAxisEllipsoid body, final double longitude) { this(s -> DEFAULT_MAXCHECK, - field.getZero().add(DEFAULT_THRESHOLD), DEFAULT_MAX_ITER, new FieldStopOnIncreasing<>(), body, longitude); + field.getZero().newInstance(DEFAULT_THRESHOLD), DEFAULT_MAX_ITER, new FieldStopOnIncreasing<>(), body, longitude); } /** diff --git a/src/main/java/org/orekit/propagation/events/FieldNodeDetector.java b/src/main/java/org/orekit/propagation/events/FieldNodeDetector.java index a35daceca1..0c4c8a65fa 100644 --- a/src/main/java/org/orekit/propagation/events/FieldNodeDetector.java +++ b/src/main/java/org/orekit/propagation/events/FieldNodeDetector.java @@ -74,7 +74,7 @@ public FieldNodeDetector(final FieldOrbit orbit, final Frame frame) { * {@link org.orekit.frames.FramesFactory#getITRF(org.orekit.utils.IERSConventions, boolean) ITRF}) */ public FieldNodeDetector(final T threshold, final FieldOrbit orbit, final Frame frame) { - this(s -> orbit.getA().getField().getZero().add(2 * estimateNodesTimeSeparation(orbit.toOrbit()) / 3).getReal(), threshold, + this(s -> orbit.getA().getField().getZero().newInstance(2 * estimateNodesTimeSeparation(orbit.toOrbit()) / 3).getReal(), threshold, DEFAULT_MAX_ITER, new FieldStopOnIncreasing<>(), frame); } diff --git a/src/main/java/org/orekit/propagation/numerical/FieldNumericalPropagator.java b/src/main/java/org/orekit/propagation/numerical/FieldNumericalPropagator.java index 66208e8dd3..ad25bf99a5 100644 --- a/src/main/java/org/orekit/propagation/numerical/FieldNumericalPropagator.java +++ b/src/main/java/org/orekit/propagation/numerical/FieldNumericalPropagator.java @@ -268,13 +268,13 @@ public void addForceModel(final ForceModel model) { @Override public void valueChanged(final double previousValue, final ParameterDriver driver, final AbsoluteDate date) { // mu PDriver should have only 1 span - superSetMu(field.getZero().add(driver.getValue(date))); + superSetMu(field.getZero().newInstance(driver.getValue(date))); } /** {@inheritDoc} */ @Override public void valueSpanMapChanged(final TimeSpanMap previousValue, final ParameterDriver driver) { // mu PDriver should have only 1 span - superSetMu(field.getZero().add(driver.getValue())); + superSetMu(field.getZero().newInstance(driver.getValue())); } }); } catch (OrekitException oe) { diff --git a/src/main/java/org/orekit/propagation/numerical/cr3bp/CR3BPForceModel.java b/src/main/java/org/orekit/propagation/numerical/cr3bp/CR3BPForceModel.java index 33b57198af..b41a2d0d9f 100644 --- a/src/main/java/org/orekit/propagation/numerical/cr3bp/CR3BPForceModel.java +++ b/src/main/java/org/orekit/propagation/numerical/cr3bp/CR3BPForceModel.java @@ -143,7 +143,7 @@ public DerivativeStructure getPotential(final SpacecraftState s) { // Get CR3BP System mass ratio // By construction, mudriver has 1 value for the all time period that is why // the getValue can be called with any date argument or null argument - final DerivativeStructure mu = zero.add(muParameterDriver.getValue(s.getDate())); + final DerivativeStructure mu = zero.newInstance(muParameterDriver.getValue(s.getDate())); // Normalized distances between primaries and barycenter in CR3BP final DerivativeStructure d1 = mu; @@ -186,7 +186,7 @@ public > FieldDerivativeStructure getPotent // Get CR3BP System mass ratio // By construction, mudriver has 1 value for the all time period that is why // the getValue can be called with any date argument or null argument - final FieldDerivativeStructure mu = zero.add(muParameterDriver.getValue(s.getDate().toAbsoluteDate())); + final FieldDerivativeStructure mu = zero.newInstance(muParameterDriver.getValue(s.getDate().toAbsoluteDate())); // Normalized distances between primaries and barycenter in CR3BP final FieldDerivativeStructure d1 = mu; diff --git a/src/main/java/org/orekit/propagation/semianalytical/dsst/FieldDSSTPropagator.java b/src/main/java/org/orekit/propagation/semianalytical/dsst/FieldDSSTPropagator.java index 67c5d0d68c..f5c91d1311 100644 --- a/src/main/java/org/orekit/propagation/semianalytical/dsst/FieldDSSTPropagator.java +++ b/src/main/java/org/orekit/propagation/semianalytical/dsst/FieldDSSTPropagator.java @@ -419,13 +419,13 @@ public void addForceModel(final DSSTForceModel force) { @Override public void valueChanged(final double previousValue, final ParameterDriver driver, final AbsoluteDate date) { // mu PDriver should have only 1 span - superSetMu(field.getZero().add(driver.getValue())); + superSetMu(field.getZero().newInstance(driver.getValue())); } /** {@inheritDoc} */ @Override public void valueSpanMapChanged(final TimeSpanMap previousValue, final ParameterDriver driver) { // mu PDriver should have only 1 span - superSetMu(field.getZero().add(driver.getValue())); + superSetMu(field.getZero().newInstance(driver.getValue())); } }); } catch (OrekitException oe) { @@ -721,7 +721,7 @@ private static > FieldOrbit computeMeanOrbi FieldEquinoctialOrbit meanOrbit = (FieldEquinoctialOrbit) OrbitType.EQUINOCTIAL.convertType(osculating.getOrbit()); // threshold for each parameter - final T epsilonT = zero.add(epsilon); + final T epsilonT = zero.newInstance(epsilon); final T thresholdA = epsilonT.multiply(FastMath.abs(meanOrbit.getA()).add(1.)); final T thresholdE = epsilonT.multiply(meanOrbit.getE().add(1.)); final T thresholdI = epsilonT.multiply(meanOrbit.getI().add(1.)); diff --git a/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/AbstractGaussianContribution.java b/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/AbstractGaussianContribution.java index 1f5aaff5d9..e90c2a0d0d 100644 --- a/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/AbstractGaussianContribution.java +++ b/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/AbstractGaussianContribution.java @@ -615,7 +615,7 @@ private > T[][] computeRhoSigmaCoefficients(fi final T b = auxiliaryElements.getB().add(1.).reciprocal(); // (-b)j - T mbtj = zero.add(1.); + T mbtj = zero.newInstance(1.); for (int j = 1; j <= 3 * JMAX; j++) { @@ -1417,8 +1417,8 @@ public > T[] integrate(final CalculusFieldUniv final T[] adaptedWeights = MathArrays.buildArray(field, numberOfPoints); for (int i = 0; i < numberOfPoints; i++) { - adaptedPoints[i] = zero.add(nodePoints[i]); - adaptedWeights[i] = zero.add(nodeWeights[i]); + adaptedPoints[i] = zero.newInstance(nodePoints[i]); + adaptedWeights[i] = zero.newInstance(nodeWeights[i]); } transform(adaptedPoints, adaptedWeights, lowerBound, upperBound); diff --git a/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/DSSTSolarRadiationPressure.java b/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/DSSTSolarRadiationPressure.java index 7a575af301..81512a6685 100644 --- a/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/DSSTSolarRadiationPressure.java +++ b/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/DSSTSolarRadiationPressure.java @@ -498,7 +498,7 @@ private > int realQuarticRoots(final T[] a, fi // Solve resolvant cubic final T[] z3 = MathArrays.buildArray(field, 3); final T[] i = MathArrays.buildArray(field, 4); - i[0] = zero.add(1.0); + i[0] = zero.newInstance(1.0); i[1] = c.negate(); i[2] = b.multiply(d).subtract(e.multiply(4.0)); i[3] = e.multiply(c.multiply(4.).subtract(b.multiply(b))).subtract(d.multiply(d)); @@ -521,13 +521,13 @@ private > int realQuarticRoots(final T[] a, fi // Solve quadratic factors of quartic equation final T[] y1 = MathArrays.buildArray(field, 2); final T[] n = MathArrays.buildArray(field, 3); - n[0] = zero.add(1.0); + n[0] = zero.newInstance(1.0); n[1] = bh.subtract(pp); n[2] = zh.subtract(qq); final int n1 = realQuadraticRoots(n, y1); final T[] y2 = MathArrays.buildArray(field, 2); final T[] nn = MathArrays.buildArray(field, 3); - nn[0] = zero.add(1.0); + nn[0] = zero.newInstance(1.0); nn[1] = bh.add(pp); nn[2] = zh.add(qq); final int n2 = realQuadraticRoots(nn, y2); diff --git a/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/DSSTTesseral.java b/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/DSSTTesseral.java index 51da268b84..16b7520003 100644 --- a/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/DSSTTesseral.java +++ b/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/DSSTTesseral.java @@ -1017,7 +1017,7 @@ private > T[][] computeNSum(final FieldAbsolut if ((n - s) % 2 == 0) { // Vmns coefficient - final T vMNS = zero.add(CoefficientsFactory.getVmns(m, n, s)); + final T vMNS = zero.newInstance(CoefficientsFactory.getVmns(m, n, s)); // Inclination function Gamma and derivative final T gaMNS = gammaMNS.getValue(m, n, s); @@ -1046,8 +1046,8 @@ private > T[][] computeNSum(final FieldAbsolut JacobiPolynomials.getValue(l, v, w, FieldGradient.variable(1, 0, auxiliaryElements.getGamma())); // Geopotential coefficients - final T cnm = zero.add(harmonics.getUnnormalizedCnm(n, m)); - final T snm = zero.add(harmonics.getUnnormalizedSnm(n, m)); + final T cnm = zero.newInstance(harmonics.getUnnormalizedCnm(n, m)); + final T snm = zero.newInstance(harmonics.getUnnormalizedSnm(n, m)); // Common factors from expansion of equations 3.3-4 final T cf_0 = roaPow[n].multiply(Im).multiply(vMNS); @@ -1439,7 +1439,7 @@ private class FieldFourierCjSjCoefficients > { this.cCoef = MathArrays.buildArray(field, rows, columns, 6); this.sCoef = MathArrays.buildArray(field, rows, columns, 6); this.roaPow = MathArrays.buildArray(field, maxDegree + 1); - roaPow[0] = zero.add(1.); + roaPow[0] = zero.newInstance(1.); } /** @@ -2562,7 +2562,7 @@ private class FieldUAnddU > { // R / a up to power degree final T[] roaPow = MathArrays.buildArray(field, maxDegree + 1); - roaPow[0] = zero.add(1.); + roaPow[0] = zero.newInstance(1.); for (int i = 1; i <= maxDegree; i++) { roaPow[i] = roaPow[i - 1].multiply(context.getRoa()); } diff --git a/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/DSSTThirdBody.java b/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/DSSTThirdBody.java index b214b1137d..1c9f102b44 100644 --- a/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/DSSTThirdBody.java +++ b/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/DSSTThirdBody.java @@ -1667,8 +1667,8 @@ private class FieldWnsjEtomjmsCoefficient > { opc2tn = MathArrays.buildArray(field, staticContext.getMaxAR3Pow() + staticContext.getMaxFreqF() + 2); final T omc2 = c2.negate().add(1.); final T opc2 = c2.add(1.); - omc2tn[0] = zero.add(1.); - opc2tn[0] = zero.add(1.); + omc2tn[0] = zero.newInstance(1.); + opc2tn[0] = zero.newInstance(1.); for (int i = 1; i <= staticContext.getMaxAR3Pow() + staticContext.getMaxFreqF() + 1; i++) { omc2tn[i] = omc2tn[i - 1].multiply(omc2); opc2tn[i] = opc2tn[i - 1].multiply(opc2); @@ -1676,7 +1676,7 @@ private class FieldWnsjEtomjmsCoefficient > { //Compute the powers of b btjms = MathArrays.buildArray(field, staticContext.getMaxAR3Pow() + staticContext.getMaxFreqF() + 1); - btjms[0] = zero.add(1.); + btjms[0] = zero.newInstance(1.); for (int i = 1; i <= staticContext.getMaxAR3Pow() + staticContext.getMaxFreqF(); i++) { btjms[i] = btjms[i - 1].multiply(context.getb()); } @@ -1715,15 +1715,15 @@ public T[] computeWjnsEmjmsAndDeriv(final int j, final int s, final int n, final T factCoef; if (absS > absJ) { //factCoef = (fact[n + s] / fact[n + j]) * (fact[n - s] / fact[n - j]); - factCoef = zero.add((CombinatoricsUtils.factorialDouble(n + s) / CombinatoricsUtils.factorialDouble(n + j)) * (CombinatoricsUtils.factorialDouble(n - s) / CombinatoricsUtils.factorialDouble(n - j))); + factCoef = zero.newInstance((CombinatoricsUtils.factorialDouble(n + s) / CombinatoricsUtils.factorialDouble(n + j)) * (CombinatoricsUtils.factorialDouble(n - s) / CombinatoricsUtils.factorialDouble(n - j))); l = n - absS; } else { - factCoef = zero.add(1.); + factCoef = zero.newInstance(1.); l = n - absJ; } // (-1)|j-s| - final T sign = absJmS % 2 != 0 ? zero.add(-1.) : zero.add(1.); + final T sign = absJmS % 2 != 0 ? zero.newInstance(-1.) : zero.newInstance(1.); //(1 - c²)n-|s| / (1 + c²)n final T coef1 = omc2tn[l].divide(opc2tn[n]); //-b|j-s| @@ -1960,7 +1960,7 @@ private void generateCoefficients(final FieldDSSTThirdBodyDynamicContext cont // compute the coefficients only if (n - s) % 2 == 0 if ( (n - s) % 2 == 0 ) { // Kronecker symbol (2 - delta(0,s)) - final T delta0s = (s == 0) ? zero.add(1.) : zero.add(2.); + final T delta0s = (s == 0) ? zero.newInstance(1.) : zero.newInstance(2.); final double vns = Vns.get(new NSKey(n, s)); final T coef0 = aoR3Pow[n].multiply(vns).multiply(context.getMuoR3()).multiply(delta0s); final T coef1 = coef0.multiply(qns[n][s]); @@ -3782,7 +3782,7 @@ private class FieldUAnddU > { } // Kronecker symbol (2 - delta(0,s)) - final T delta0s = zero.add((s == 0) ? 1. : 2.); + final T delta0s = zero.newInstance((s == 0) ? 1. : 2.); for (int n = FastMath.max(2, s); n <= staticContext.getMaxAR3Pow(); n++) { // (n - s) must be even diff --git a/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/DSSTZonal.java b/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/DSSTZonal.java index be3b2c1f2d..c727c9c270 100644 --- a/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/DSSTZonal.java +++ b/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/DSSTZonal.java @@ -432,14 +432,14 @@ private > void computeMeanElementsTruncations( final T ax2or = auxiliaryElements.getSma().multiply(2.).divide(provider.getAe()); T xmuran = parameters[0].divide(auxiliaryElements.getSma()); // Set a lower bound for eccentricity - final T eo2 = FastMath.max(zero.add(0.0025), auxiliaryElements.getEcc().divide(2.)); + final T eo2 = FastMath.max(zero.newInstance(0.0025), auxiliaryElements.getEcc().divide(2.)); final T x2o2 = context.getXX().divide(2.); final T[] eccPwr = MathArrays.buildArray(field, maxDegree + 1); final T[] chiPwr = MathArrays.buildArray(field, maxDegree + 1); final T[] hafPwr = MathArrays.buildArray(field, maxDegree + 1); - eccPwr[0] = zero.add(1.); + eccPwr[0] = zero.newInstance(1.); chiPwr[0] = context.getX(); - hafPwr[0] = zero.add(1.); + hafPwr[0] = zero.newInstance(1.); for (int i = 1; i <= maxDegree; i++) { eccPwr[i] = eccPwr[i - 1].multiply(eo2); chiPwr[i] = chiPwr[i - 1].multiply(x2o2); @@ -457,8 +457,8 @@ private > void computeMeanElementsTruncations( // Loop over m do { // Compute magnitude of current spherical harmonic coefficient. - final T cnm = zero.add(harmonics.getUnnormalizedCnm(maxDeg, m)); - final T snm = zero.add(harmonics.getUnnormalizedSnm(maxDeg, m)); + final T cnm = zero.newInstance(harmonics.getUnnormalizedCnm(maxDeg, m)); + final T snm = zero.newInstance(harmonics.getUnnormalizedSnm(maxDeg, m)); final T csnm = FastMath.hypot(cnm, snm); if (csnm.getReal() == 0.) { break; @@ -1393,7 +1393,7 @@ private > T[][] computeRhoSigmaCoefficients(fi final T b = auxiliaryElements.getB().add(1.).reciprocal(); // (-b)j - T mbtj = zero.add(1.); + T mbtj = zero.newInstance(1.); final T[][] rhoSigma = MathArrays.buildArray(field, slot.cij.length, 2); for (int j = 1; j < rhoSigma.length; j++) { @@ -3711,7 +3711,7 @@ private class FieldUAnddU > { final T[][] Qns = CoefficientsFactory.computeQns(auxiliaryElements.getGamma(), maxDegree, maxEccPowMeanElements); final T[] roaPow = MathArrays.buildArray(field, maxDegree + 1); - roaPow[0] = zero.add(1.); + roaPow[0] = zero.newInstance(1.); for (int i = 1; i <= maxDegree; i++) { roaPow[i] = roaPow[i - 1].multiply(context.getRoa()); } @@ -3748,7 +3748,7 @@ private class FieldUAnddU > { } // Kronecker symbol (2 - delta(0,s)) - final T d0s = zero.add((s == 0) ? 1 : 2); + final T d0s = zero.newInstance((s == 0) ? 1 : 2); for (int n = s + 2; n <= maxDegree; n++) { // (n - s) must be even diff --git a/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/FieldDSSTTesseralContext.java b/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/FieldDSSTTesseralContext.java index 477fe6d384..3f039faac3 100644 --- a/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/FieldDSSTTesseralContext.java +++ b/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/FieldDSSTTesseralContext.java @@ -133,7 +133,7 @@ public class FieldDSSTTesseralContext> extends // Keplerian period final T a = auxiliaryElements.getSma(); - period = (a.getReal() < 0) ? zero.add(Double.POSITIVE_INFINITY) : a.multiply(a.getPi().multiply(2.0)).multiply(a.divide(mu).sqrt()); + period = (a.getReal() < 0) ? zero.newInstance(Double.POSITIVE_INFINITY) : a.multiply(a.getPi().multiply(2.0)).multiply(a.divide(mu).sqrt()); A = FastMath.sqrt(mu.multiply(auxiliaryElements.getSma())); diff --git a/src/main/java/org/orekit/propagation/semianalytical/dsst/utilities/CoefficientsFactory.java b/src/main/java/org/orekit/propagation/semianalytical/dsst/utilities/CoefficientsFactory.java index 47b2ab74a9..3e26f6dad3 100644 --- a/src/main/java/org/orekit/propagation/semianalytical/dsst/utilities/CoefficientsFactory.java +++ b/src/main/java/org/orekit/propagation/semianalytical/dsst/utilities/CoefficientsFactory.java @@ -190,7 +190,7 @@ public static > T[][] computeGsHs(final T k, f final T kaphb = k.multiply(alpha).add(h.multiply(beta)); // Initialization final T[][] GsHs = MathArrays.buildArray(field, 2, order + 1); - GsHs[0][0] = zero.add(1.); + GsHs[0][0] = zero.newInstance(1.); GsHs[1][0] = zero; for (int s = 1; s <= order; s++) { diff --git a/src/main/java/org/orekit/propagation/semianalytical/dsst/utilities/FieldCjSjCoefficient.java b/src/main/java/org/orekit/propagation/semianalytical/dsst/utilities/FieldCjSjCoefficient.java index fa51c58df4..056777a8fb 100644 --- a/src/main/java/org/orekit/propagation/semianalytical/dsst/utilities/FieldCjSjCoefficient.java +++ b/src/main/java/org/orekit/propagation/semianalytical/dsst/utilities/FieldCjSjCoefficient.java @@ -60,7 +60,7 @@ public FieldCjSjCoefficient(final T k, final T h, final Field field) { zero = field.getZero(); kih = new FieldComplex<>(k, h); cjsj = new ArrayList>(); - cjsj.add(new FieldComplex<>(zero.add(1.), zero)); + cjsj.add(new FieldComplex<>(zero.newInstance(1.), zero)); cjsj.add(kih); jLast = 1; } diff --git a/src/main/java/org/orekit/propagation/semianalytical/dsst/utilities/FieldLnsCoefficients.java b/src/main/java/org/orekit/propagation/semianalytical/dsst/utilities/FieldLnsCoefficients.java index 1bc3730044..9446558c21 100644 --- a/src/main/java/org/orekit/propagation/semianalytical/dsst/utilities/FieldLnsCoefficients.java +++ b/src/main/java/org/orekit/propagation/semianalytical/dsst/utilities/FieldLnsCoefficients.java @@ -58,7 +58,7 @@ public FieldLnsCoefficients(final int nMax, final int sMax, this.dlns = MathArrays.buildArray(field, rows, columns); final T[] roaPow = MathArrays.buildArray(field, rows); - roaPow[0] = zero.add(1.); + roaPow[0] = zero.newInstance(1.); for (int i = 1; i <= nMax; i++) { roaPow[i] = roa.multiply(roaPow[i - 1]); } diff --git a/src/main/java/org/orekit/propagation/semianalytical/dsst/utilities/UpperBounds.java b/src/main/java/org/orekit/propagation/semianalytical/dsst/utilities/UpperBounds.java index 06649e40ab..d8432c424c 100644 --- a/src/main/java/org/orekit/propagation/semianalytical/dsst/utilities/UpperBounds.java +++ b/src/main/java/org/orekit/propagation/semianalytical/dsst/utilities/UpperBounds.java @@ -174,7 +174,7 @@ public static > T getRnml(final T gamma, final int mei = m * eps * irf; final T sinisq = gamma.multiply(gamma).negate().add(1.); // Set a lower bound for inclination - final T sininc = FastMath.max(zero.add(0.03), FastMath.sqrt(sinisq)); + final T sininc = FastMath.max(zero.newInstance(0.03), FastMath.sqrt(sinisq)); final T onepig = gamma.multiply(irf).add(1.); final T sinincPowLmMEI = FastMath.pow(sininc, l - mei); final T onepigPowLmMEI = FastMath.pow(onepig, mei); @@ -186,7 +186,7 @@ public static > T getRnml(final T gamma, if (n > l) { final int lp1 = l + 1; - T dpnml = zero.add(lp1 * eps); + T dpnml = zero.newInstance(lp1 * eps); T pnml = gamma.multiply(dpnml).subtract(m); // If index > 1 @@ -195,9 +195,9 @@ public static > T getRnml(final T gamma, final int ml = m * l; final int mm = m * m; - T pn1ml = zero.add(1.); + T pn1ml = zero.newInstance(1.); T dpn1ml = zero; - T pn2ml = zero.add(1.); + T pn2ml = zero.newInstance(1.); T dpn2ml = zero; for (int in = l + 2; in <= n; in++) { final int nm1 = in - 1; diff --git a/src/main/java/org/orekit/propagation/semianalytical/dsst/utilities/hansen/FieldHansenThirdBodyLinear.java b/src/main/java/org/orekit/propagation/semianalytical/dsst/utilities/hansen/FieldHansenThirdBodyLinear.java index f24aeafcaf..932ccbc0b0 100644 --- a/src/main/java/org/orekit/propagation/semianalytical/dsst/utilities/hansen/FieldHansenThirdBodyLinear.java +++ b/src/main/java/org/orekit/propagation/semianalytical/dsst/utilities/hansen/FieldHansenThirdBodyLinear.java @@ -285,7 +285,7 @@ private void generatePolynomials() { public void computeInitValues(final T chitm1, final T chitm2, final T chitm3) { final Field field = chitm2.getField(); final T zero = field.getZero(); - this.hansenRoot[0][0] = zero.add(twosp1dfosp1f); + this.hansenRoot[0][0] = zero.newInstance(twosp1dfosp1f); this.hansenRoot[0][1] = (chitm2.negate().add(this.twosp3)).multiply(this.twosp1dfosp2f); this.hansenDerivRoot[0][0] = zero; this.hansenDerivRoot[0][1] = chitm3.multiply(two2sp1dfosp2f); diff --git a/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/FieldShortTermEncounter2DDefinition.java b/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/FieldShortTermEncounter2DDefinition.java index 49e2f2e221..b104ad255e 100644 --- a/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/FieldShortTermEncounter2DDefinition.java +++ b/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/FieldShortTermEncounter2DDefinition.java @@ -455,7 +455,7 @@ public FieldVector2D computeOtherPositionInRotatedCollisionPlane(final double public T computeCoppolaEncounterDuration() { // Default value for γ = 1e-16 - final T DEFAULT_ALPHA_C = instanceField.getOne().multiply(5.864); + final T DEFAULT_ALPHA_C = instanceField.getZero().newInstance(5.864); final FieldMatrix combinedPositionalCovarianceMatrix = computeCombinedCovarianceInEncounterFrame() .getMatrix().getSubMatrix(0, 2, 0, 2); @@ -670,7 +670,7 @@ private FieldMatrix computeEncounterPlaneRotationMatrix(final double zeroThre else { // Rotation in order to have sigmaXSquared < sigmaYSquared if (sigmaXSquared.subtract(sigmaYSquared).getReal() > 0) { - theta = tca.getField().getOne().multiply(MathUtils.SEMI_PI); + theta = tca.getField().getZero().newInstance(MathUtils.SEMI_PI); } // Else, there is no need for a rotation else { diff --git a/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/Laas2015.java b/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/Laas2015.java index 0db7a451ec..9eea23169e 100644 --- a/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/Laas2015.java +++ b/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/Laas2015.java @@ -349,11 +349,11 @@ public final > FieldProbabilityOfCollision final T auxiliaryTerm4 = pPhiY.multiply(recurrentTerm0).multiply(2.); final T auxiliaryTerm5 = p.multiply(phiY.multiply(2.).add(1.)); - T kPlus2 = one.multiply(2.); - T kPlus3 = one.multiply(3.); - T kPlus4 = one.multiply(4.); - T kPlus5 = one.multiply(5.); - T halfY = one.multiply(2.5); + T kPlus2 = one.newInstance(2.); + T kPlus3 = one.newInstance(3.); + T kPlus4 = one.newInstance(4.); + T kPlus5 = one.newInstance(5.); + T halfY = one.newInstance(2.5); // Initialize recurrence T c0 = alpha0.multiply(radiusSquared); diff --git a/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/Patera2005.java b/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/Patera2005.java index 8f48342390..c4c36bc99d 100644 --- a/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/Patera2005.java +++ b/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/Patera2005.java @@ -122,7 +122,7 @@ public > FieldProbabilityOfCollision comput final Field field = xm.getField(); final T zero = field.getZero(); final T one = field.getOne(); - final T twoPiField = one.multiply(MathUtils.TWO_PI); + final T twoPiField = one.newInstance(MathUtils.TWO_PI); final T value; final double missDistance = xm.multiply(xm).add(ym.multiply(ym)).sqrt().getReal(); diff --git a/src/main/java/org/orekit/time/BDTScale.java b/src/main/java/org/orekit/time/BDTScale.java index a2ea177105..c8744e406f 100644 --- a/src/main/java/org/orekit/time/BDTScale.java +++ b/src/main/java/org/orekit/time/BDTScale.java @@ -47,7 +47,7 @@ public double offsetFromTAI(final AbsoluteDate date) { /** {@inheritDoc} */ @Override public > T offsetFromTAI(final FieldAbsoluteDate date) { - return date.getField().getZero().add(OFFSET); + return date.getField().getZero().newInstance(OFFSET); } /** {@inheritDoc} */ diff --git a/src/main/java/org/orekit/time/GPSScale.java b/src/main/java/org/orekit/time/GPSScale.java index 1832bfa42b..de335c9e83 100644 --- a/src/main/java/org/orekit/time/GPSScale.java +++ b/src/main/java/org/orekit/time/GPSScale.java @@ -47,7 +47,7 @@ public double offsetFromTAI(final AbsoluteDate date) { /** {@inheritDoc} */ @Override public > T offsetFromTAI(final FieldAbsoluteDate date) { - return date.getField().getZero().add(OFFSET); + return date.getField().getZero().newInstance(OFFSET); } /** {@inheritDoc} */ diff --git a/src/main/java/org/orekit/time/GalileoScale.java b/src/main/java/org/orekit/time/GalileoScale.java index de32a8c9e5..6d8cd2bd4e 100644 --- a/src/main/java/org/orekit/time/GalileoScale.java +++ b/src/main/java/org/orekit/time/GalileoScale.java @@ -54,7 +54,7 @@ public double offsetFromTAI(final AbsoluteDate date) { /** {@inheritDoc} */ @Override public > T offsetFromTAI(final FieldAbsoluteDate date) { - return date.getField().getZero().add(OFFSET); + return date.getField().getZero().newInstance(OFFSET); } /** {@inheritDoc} */ diff --git a/src/main/java/org/orekit/time/IRNSSScale.java b/src/main/java/org/orekit/time/IRNSSScale.java index 403ed8ceb8..0bfa429bf9 100644 --- a/src/main/java/org/orekit/time/IRNSSScale.java +++ b/src/main/java/org/orekit/time/IRNSSScale.java @@ -48,7 +48,7 @@ public double offsetFromTAI(final AbsoluteDate date) { /** {@inheritDoc} */ @Override public > T offsetFromTAI(final FieldAbsoluteDate date) { - return date.getField().getZero().add(OFFSET); + return date.getField().getZero().newInstance(OFFSET); } /** {@inheritDoc} */ diff --git a/src/main/java/org/orekit/time/QZSSScale.java b/src/main/java/org/orekit/time/QZSSScale.java index 65e2f49b90..b2d47c4c19 100644 --- a/src/main/java/org/orekit/time/QZSSScale.java +++ b/src/main/java/org/orekit/time/QZSSScale.java @@ -51,7 +51,7 @@ public double offsetFromTAI(final AbsoluteDate date) { /** {@inheritDoc} */ @Override public > T offsetFromTAI(final FieldAbsoluteDate date) { - return date.getField().getZero().add(OFFSET); + return date.getField().getZero().newInstance(OFFSET); } /** {@inheritDoc} */ diff --git a/src/main/java/org/orekit/time/TTScale.java b/src/main/java/org/orekit/time/TTScale.java index d62b689be4..b3030c81a7 100644 --- a/src/main/java/org/orekit/time/TTScale.java +++ b/src/main/java/org/orekit/time/TTScale.java @@ -49,7 +49,7 @@ public double offsetFromTAI(final AbsoluteDate date) { /** {@inheritDoc} */ @Override public > T offsetFromTAI(final FieldAbsoluteDate date) { - return date.getField().getZero().add(OFFSET); + return date.getField().getZero().newInstance(OFFSET); } /** {@inheritDoc} */ diff --git a/src/main/java/org/orekit/time/UTCScale.java b/src/main/java/org/orekit/time/UTCScale.java index 456d81508a..8b5424493b 100644 --- a/src/main/java/org/orekit/time/UTCScale.java +++ b/src/main/java/org/orekit/time/UTCScale.java @@ -301,7 +301,7 @@ public double getLeap(final AbsoluteDate date) { /** {@inheritDoc} */ @Override public > T getLeap(final FieldAbsoluteDate date) { - return date.getField().getZero().add(getLeap(date.toAbsoluteDate())); + return date.getField().getZero().newInstance(getLeap(date.toAbsoluteDate())); } /** Find the index of the offset valid at some date. diff --git a/src/main/java/org/orekit/time/UTCTAIOffset.java b/src/main/java/org/orekit/time/UTCTAIOffset.java index 073bdd5400..061cbb1d0d 100644 --- a/src/main/java/org/orekit/time/UTCTAIOffset.java +++ b/src/main/java/org/orekit/time/UTCTAIOffset.java @@ -150,7 +150,7 @@ public > T getOffset(final FieldAbsoluteDate estimateRate(final FieldRotation start, final FieldRotation end, final double dt) { - return estimateRate(start, end, start.getQ0().getField().getZero().add(dt)); + return estimateRate(start, end, start.getQ0().getField().getZero().newInstance(dt)); } /** Estimate rotation rate between two orientations. @@ -632,7 +632,7 @@ public FieldRotation rotationShiftedBy(final T dt) { */ @Override public FieldAngularCoordinates shiftedBy(final double dt) { - return shiftedBy(rotation.getQ0().getField().getZero().add(dt)); + return shiftedBy(rotation.getQ0().getField().getZero().newInstance(dt)); } /** Get a time-shifted state. diff --git a/src/main/java/org/orekit/utils/Fieldifier.java b/src/main/java/org/orekit/utils/Fieldifier.java index b6c5d0f12c..4515aba3c6 100644 --- a/src/main/java/org/orekit/utils/Fieldifier.java +++ b/src/main/java/org/orekit/utils/Fieldifier.java @@ -65,7 +65,7 @@ public static > FieldOrbit fieldify(final F final T one = field.getOne(); final FieldAbsoluteDate fieldDate = new FieldAbsoluteDate<>(field, orbit.getDate()); - final T fieldMu = one.multiply(orbit.getMu()); + final T fieldMu = one.newInstance(orbit.getMu()); final Frame frame = orbit.getFrame(); switch (orbit.getType()) { @@ -73,20 +73,20 @@ public static > FieldOrbit fieldify(final F final CircularOrbit circOrbit = (CircularOrbit) OrbitType.CIRCULAR.convertType(orbit); // Get orbital elements - final T a = one.multiply(circOrbit.getA()); - final T ex = one.multiply(circOrbit.getCircularEx()); - final T ey = one.multiply(circOrbit.getCircularEy()); - final T i = one.multiply(circOrbit.getI()); - final T raan = one.multiply(circOrbit.getRightAscensionOfAscendingNode()); - final T alphaM = one.multiply(circOrbit.getAlphaM()); + final T a = one.newInstance(circOrbit.getA()); + final T ex = one.newInstance(circOrbit.getCircularEx()); + final T ey = one.newInstance(circOrbit.getCircularEy()); + final T i = one.newInstance(circOrbit.getI()); + final T raan = one.newInstance(circOrbit.getRightAscensionOfAscendingNode()); + final T alphaM = one.newInstance(circOrbit.getAlphaM()); // Get derivatives - final T aDot = one.multiply(circOrbit.getADot()); - final T exDot = one.multiply(circOrbit.getCircularExDot()); - final T eyDot = one.multiply(circOrbit.getCircularEyDot()); - final T iDot = one.multiply(circOrbit.getIDot()); - final T raanDot = one.multiply(circOrbit.getRightAscensionOfAscendingNodeDot()); - final T alphaMDot = one.multiply(circOrbit.getAlphaMDot()); + final T aDot = one.newInstance(circOrbit.getADot()); + final T exDot = one.newInstance(circOrbit.getCircularExDot()); + final T eyDot = one.newInstance(circOrbit.getCircularEyDot()); + final T iDot = one.newInstance(circOrbit.getIDot()); + final T raanDot = one.newInstance(circOrbit.getRightAscensionOfAscendingNodeDot()); + final T alphaMDot = one.newInstance(circOrbit.getAlphaMDot()); return new FieldCircularOrbit<>(a, ex, ey, i, raan, alphaM, aDot, exDot, eyDot, iDot, raanDot, alphaMDot, PositionAngleType.MEAN, frame, fieldDate, fieldMu); @@ -102,20 +102,20 @@ public static > FieldOrbit fieldify(final F final KeplerianOrbit kepOrbit = (KeplerianOrbit) OrbitType.KEPLERIAN.convertType(orbit); // Get orbital elements - final T a = one.multiply(kepOrbit.getA()); - final T e = one.multiply(kepOrbit.getE()); - final T i = one.multiply(kepOrbit.getI()); - final T raan = one.multiply(kepOrbit.getRightAscensionOfAscendingNode()); - final T pa = one.multiply(kepOrbit.getPerigeeArgument()); - final T meanAnomaly = one.multiply(kepOrbit.getMeanAnomaly()); + final T a = one.newInstance(kepOrbit.getA()); + final T e = one.newInstance(kepOrbit.getE()); + final T i = one.newInstance(kepOrbit.getI()); + final T raan = one.newInstance(kepOrbit.getRightAscensionOfAscendingNode()); + final T pa = one.newInstance(kepOrbit.getPerigeeArgument()); + final T meanAnomaly = one.newInstance(kepOrbit.getMeanAnomaly()); // Get derivatives - final T aDot = one.multiply(kepOrbit.getADot()); - final T eDot = one.multiply(kepOrbit.getEDot()); - final T iDot = one.multiply(kepOrbit.getIDot()); - final T raanDot = one.multiply(kepOrbit.getRightAscensionOfAscendingNodeDot()); - final T paDot = one.multiply(kepOrbit.getPerigeeArgumentDot()); - final T meanAnomalyDot = one.multiply(kepOrbit.getMeanAnomalyDot()); + final T aDot = one.newInstance(kepOrbit.getADot()); + final T eDot = one.newInstance(kepOrbit.getEDot()); + final T iDot = one.newInstance(kepOrbit.getIDot()); + final T raanDot = one.newInstance(kepOrbit.getRightAscensionOfAscendingNodeDot()); + final T paDot = one.newInstance(kepOrbit.getPerigeeArgumentDot()); + final T meanAnomalyDot = one.newInstance(kepOrbit.getMeanAnomalyDot()); return new FieldKeplerianOrbit<>(a, e, i, pa, raan, meanAnomaly, aDot, eDot, iDot, paDot, raanDot, meanAnomalyDot, PositionAngleType.MEAN, frame, fieldDate, fieldMu); @@ -124,20 +124,20 @@ public static > FieldOrbit fieldify(final F final EquinoctialOrbit equiOrbit = (EquinoctialOrbit) OrbitType.EQUINOCTIAL.convertType(orbit); // Get orbital elements - final T a = one.multiply(equiOrbit.getA()); - final T ex = one.multiply(equiOrbit.getEquinoctialEx()); - final T ey = one.multiply(equiOrbit.getEquinoctialEy()); - final T hx = one.multiply(equiOrbit.getHx()); - final T hy = one.multiply(equiOrbit.getHy()); - final T lm = one.multiply(equiOrbit.getLM()); + final T a = one.newInstance(equiOrbit.getA()); + final T ex = one.newInstance(equiOrbit.getEquinoctialEx()); + final T ey = one.newInstance(equiOrbit.getEquinoctialEy()); + final T hx = one.newInstance(equiOrbit.getHx()); + final T hy = one.newInstance(equiOrbit.getHy()); + final T lm = one.newInstance(equiOrbit.getLM()); // Get derivatives - final T aDot = one.multiply(equiOrbit.getADot()); - final T exDot = one.multiply(equiOrbit.getEquinoctialExDot()); - final T eyDot = one.multiply(equiOrbit.getEquinoctialEyDot()); - final T hxDot = one.multiply(equiOrbit.getHxDot()); - final T hyDot = one.multiply(equiOrbit.getHyDot()); - final T lmDot = one.multiply(equiOrbit.getLMDot()); + final T aDot = one.newInstance(equiOrbit.getADot()); + final T exDot = one.newInstance(equiOrbit.getEquinoctialExDot()); + final T eyDot = one.newInstance(equiOrbit.getEquinoctialEyDot()); + final T hxDot = one.newInstance(equiOrbit.getHxDot()); + final T hyDot = one.newInstance(equiOrbit.getHyDot()); + final T lmDot = one.newInstance(equiOrbit.getLMDot()); return new FieldEquinoctialOrbit<>(a, ex, ey, hx, hy, lm, aDot, exDot, eyDot, hxDot, hyDot, lmDot, PositionAngleType.MEAN, frame, fieldDate, fieldMu); @@ -168,7 +168,7 @@ public static > FieldMatrix fieldify(final for (int i = 0; i < rowDim; i++) { for (int j = 0; j < columnDim; j++) { - fieldMatrix.setEntry(i, j, field.getOne().multiply(matrix.getEntry(i, j))); + fieldMatrix.setEntry(i, j, field.getOne().newInstance(matrix.getEntry(i, j))); } } diff --git a/src/main/java/org/orekit/utils/IERSConventions.java b/src/main/java/org/orekit/utils/IERSConventions.java index 45346ce05c..06fc728f47 100644 --- a/src/main/java/org/orekit/utils/IERSConventions.java +++ b/src/main/java/org/orekit/utils/IERSConventions.java @@ -1387,8 +1387,8 @@ public > T[] value(final FieldAbsoluteDate // for example removing derivatives // if T was DerivativeStructure annualCache.getNeighbors(aDate).forEach(neighbor -> { - y[0] = zero.add(neighbor.getX()); - y[1] = zero.add(neighbor.getY()); + y[0] = zero.newInstance(neighbor.getX()); + y[1] = zero.newInstance(neighbor.getY()); interpolator.addSamplePoint(central.durationFrom(neighbor.getDate()).negate(), y); }); final T[] interpolated = interpolator.value(date.durationFrom(central)); // here, we introduce derivatives again (in DerivativeStructure case) diff --git a/src/main/java/org/orekit/utils/ParameterDriversProvider.java b/src/main/java/org/orekit/utils/ParameterDriversProvider.java index 3f0168ed24..b87c7ab24f 100644 --- a/src/main/java/org/orekit/utils/ParameterDriversProvider.java +++ b/src/main/java/org/orekit/utils/ParameterDriversProvider.java @@ -120,7 +120,7 @@ default > T[] getParametersAllValues(final Fie int paramIndex = 0; for (int i = 0; i < drivers.size(); ++i) { for (Span span = drivers.get(i).getValueSpanMap().getFirstSpan(); span != null; span = span.next()) { - parameters[paramIndex++] = field.getZero().add(span.getData()); + parameters[paramIndex++] = field.getZero().newInstance(span.getData()); } } return parameters; @@ -139,7 +139,7 @@ default > T[] getParameters(final Field fie final List drivers = getParametersDrivers(); final T[] parameters = MathArrays.buildArray(field, drivers.size()); for (int i = 0; i < drivers.size(); ++i) { - parameters[i] = field.getZero().add(drivers.get(i).getValue()); + parameters[i] = field.getZero().newInstance(drivers.get(i).getValue()); } return parameters; } @@ -156,7 +156,7 @@ default > T[] getParameters(final Field fie final List drivers = getParametersDrivers(); final T[] parameters = MathArrays.buildArray(field, drivers.size()); for (int i = 0; i < drivers.size(); ++i) { - parameters[i] = field.getZero().add(drivers.get(i).getValue(date.toAbsoluteDate())); + parameters[i] = field.getZero().newInstance(drivers.get(i).getValue(date.toAbsoluteDate())); } return parameters; } diff --git a/src/main/java/org/orekit/utils/TimeStampedFieldAngularCoordinates.java b/src/main/java/org/orekit/utils/TimeStampedFieldAngularCoordinates.java index 99c2f466e6..8dc8802f8f 100644 --- a/src/main/java/org/orekit/utils/TimeStampedFieldAngularCoordinates.java +++ b/src/main/java/org/orekit/utils/TimeStampedFieldAngularCoordinates.java @@ -191,7 +191,7 @@ public FieldAbsoluteDate getDate() { * @return a new state, shifted with respect to the instance (which is immutable) */ public TimeStampedFieldAngularCoordinates shiftedBy(final double dt) { - return shiftedBy(getDate().getField().getZero().add(dt)); + return shiftedBy(getDate().getField().getZero().newInstance(dt)); } /** Get a time-shifted state. diff --git a/src/main/java/org/orekit/utils/TimeStampedFieldAngularCoordinatesHermiteInterpolator.java b/src/main/java/org/orekit/utils/TimeStampedFieldAngularCoordinatesHermiteInterpolator.java index 5f726f077d..c33ec3ca3b 100644 --- a/src/main/java/org/orekit/utils/TimeStampedFieldAngularCoordinatesHermiteInterpolator.java +++ b/src/main/java/org/orekit/utils/TimeStampedFieldAngularCoordinatesHermiteInterpolator.java @@ -246,7 +246,7 @@ protected TimeStampedFieldAngularCoordinates interpolate(final Interpolation // we need to offset all rotations to avoid the singularity offset = offset.addOffset( new FieldAngularCoordinates<>(new FieldRotation<>(FieldVector3D.getPlusI(field), - one.multiply(epsilon), + one.newInstance(epsilon), RotationConvention.VECTOR_OPERATOR), FieldVector3D.getZero(field), FieldVector3D.getZero(field))); } else { diff --git a/src/test/java/org/orekit/attitudes/FrameAlignedProviderTest.java b/src/test/java/org/orekit/attitudes/FrameAlignedProviderTest.java index 0624919625..aa41e441df 100644 --- a/src/test/java/org/orekit/attitudes/FrameAlignedProviderTest.java +++ b/src/test/java/org/orekit/attitudes/FrameAlignedProviderTest.java @@ -211,7 +211,7 @@ public void testGetAttitudeField() { new FieldPVCoordinates<>(one, this.orbit0.getPVCoordinates()), eci, date, - one.multiply(orbit0.getMu())); + one.newInstance(orbit0.getMu())); // action + verify FieldAttitude actual = law.getAttitude(orbit, date, eci); From 3658232037863c32ca993f12f5cbf28edbcac83b Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Wed, 6 Dec 2023 18:06:28 +0100 Subject: [PATCH 016/359] Added field versions of unit conversions from and to SI units. Fixes #1285 --- src/changes/changes.xml | 3 +++ .../java/org/orekit/utils/units/Unit.java | 20 +++++++++++++++++++ .../java/org/orekit/utils/units/UnitTest.java | 5 +++++ 3 files changed, 28 insertions(+) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index de1a4eb91a..b4dd059bfc 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -21,6 +21,9 @@ + + Added field versions of unit conversions from and to SI units. + Removed uses of scalar multiply on Field one. diff --git a/src/main/java/org/orekit/utils/units/Unit.java b/src/main/java/org/orekit/utils/units/Unit.java index 77f827cf88..d1a3c6abd0 100644 --- a/src/main/java/org/orekit/utils/units/Unit.java +++ b/src/main/java/org/orekit/utils/units/Unit.java @@ -19,6 +19,7 @@ import java.io.Serializable; import java.util.List; +import org.hipparchus.CalculusFieldElement; import org.hipparchus.fraction.Fraction; import org.hipparchus.util.FastMath; import org.hipparchus.util.Precision; @@ -417,6 +418,16 @@ public double toSI(final Double value) { return value == null ? Double.NaN : value.doubleValue() * scale; } + /** Convert a value to SI units. + * @param type of the field elements + * @param value value instance unit + * @return value in SI units + * @since 12.1 + */ + public > T toSI(final T value) { + return value.multiply(scale); + } + /** Convert a value from SI units. * @param value value SI unit * @return value in instance units @@ -433,6 +444,15 @@ public double fromSI(final Double value) { return value == null ? Double.NaN : value.doubleValue() / scale; } + /** Convert a value from SI units. + * @param type of the field elements + * @param value value SI unit + * @return value in instance units + */ + public > T fromSI(final T value) { + return value.divide(scale); + } + /** Parse a unit. *

              * The grammar for unit specification allows chains units multiplication and diff --git a/src/test/java/org/orekit/utils/units/UnitTest.java b/src/test/java/org/orekit/utils/units/UnitTest.java index 1010602a24..9eb037cad1 100644 --- a/src/test/java/org/orekit/utils/units/UnitTest.java +++ b/src/test/java/org/orekit/utils/units/UnitTest.java @@ -20,6 +20,7 @@ import java.util.Collections; import org.hipparchus.fraction.Fraction; +import org.hipparchus.util.Binary64; import org.hipparchus.util.FastMath; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -41,11 +42,15 @@ public void testTime() { Assertions.assertEquals( 3600.0, Unit.HOUR.toSI(1.0), 1.0e-10); Assertions.assertEquals( 86400.0, Unit.DAY.toSI(1.0), 1.0e-10); Assertions.assertEquals(31557600.0, Unit.YEAR.toSI(1.0), 1.0e-10); + Assertions.assertEquals(31557600.0, Unit.YEAR.toSI(Double.valueOf(1.0)), 1.0e-10); + Assertions.assertEquals(31557600.0, Unit.YEAR.toSI(new Binary64(1.0)).getReal(), 1.0e-10); Assertions.assertEquals(1.0, Unit.SECOND.fromSI( 1.0), 1.0e-10); Assertions.assertEquals(1.0, Unit.MINUTE.fromSI( 60.0), 1.0e-10); Assertions.assertEquals(1.0, Unit.HOUR.fromSI( 3600.0), 1.0e-10); Assertions.assertEquals(1.0, Unit.DAY.fromSI( 86400.0), 1.0e-10); Assertions.assertEquals(1.0, Unit.YEAR.fromSI(31557600.0), 1.0e-10); + Assertions.assertEquals(1.0, Unit.YEAR.fromSI(Double.valueOf(31557600.0)), 1.0e-10); + Assertions.assertEquals(1.0, Unit.YEAR.fromSI(new Binary64(31557600.0)).getReal(), 1.0e-10); Assertions.assertEquals(365.25, Unit.DAY.fromSI(Unit.YEAR.toSI(1.0)), 1.0e-10); } From 37ac9addb6f0790dd26ff941f05aec92c85d3b4b Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Thu, 7 Dec 2023 16:30:03 +0100 Subject: [PATCH 017/359] Added water package. --- .../CanonicalSaastamoinenModel.java | 119 +++++++----------- ...ntPressureTemperatureHumidityProvider.java | 58 +++++++++ .../FieldPressureTemperatureHumidity.java | 12 +- .../weather/PressureTemperatureHumidity.java | 12 +- .../PressureTemperatureHumidityProvider.java | 47 +++++++ .../earth/weather/water/NbsNrcSteamTable.java | 84 +++++++++++++ .../water/WaterVaporPressureProvider.java | 45 +++++++ .../earth/weather/water/package-info.java | 20 +++ 8 files changed, 310 insertions(+), 87 deletions(-) create mode 100644 src/main/java/org/orekit/models/earth/weather/ConstantPressureTemperatureHumidityProvider.java create mode 100644 src/main/java/org/orekit/models/earth/weather/PressureTemperatureHumidityProvider.java create mode 100644 src/main/java/org/orekit/models/earth/weather/water/NbsNrcSteamTable.java create mode 100644 src/main/java/org/orekit/models/earth/weather/water/WaterVaporPressureProvider.java create mode 100644 src/main/java/org/orekit/models/earth/weather/water/package-info.java diff --git a/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java b/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java index 4d3e204344..a133a4f97f 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java @@ -18,26 +18,23 @@ import java.util.Collections; import java.util.List; -import java.util.regex.Pattern; import org.hipparchus.CalculusFieldElement; import org.hipparchus.Field; -import org.hipparchus.analysis.interpolation.BilinearInterpolatingFunction; import org.hipparchus.analysis.interpolation.LinearInterpolator; -import org.hipparchus.analysis.polynomials.PolynomialFunction; import org.hipparchus.analysis.polynomials.PolynomialSplineFunction; import org.hipparchus.util.FastMath; -import org.orekit.annotation.DefaultDataContext; import org.orekit.bodies.FieldGeodeticPoint; import org.orekit.bodies.GeodeticPoint; -import org.orekit.data.DataContext; -import org.orekit.data.DataProvidersManager; -import org.orekit.errors.OrekitException; -import org.orekit.errors.OrekitMessages; +import org.orekit.models.earth.weather.ConstantPressureTemperatureHumidityProvider; +import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; +import org.orekit.models.earth.weather.PressureTemperatureHumidity; +import org.orekit.models.earth.weather.PressureTemperatureHumidityProvider; +import org.orekit.models.earth.weather.water.NbsNrcSteamTable; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; -import org.orekit.utils.InterpolationTableLoader; import org.orekit.utils.ParameterDriver; +import org.orekit.utils.units.Unit; /** The canonical Saastamoinen model. *

              @@ -66,7 +63,7 @@ public class CanonicalSaastamoinenModel implements DiscreteTroposphericModel { /** X values for the B function (table 1 in reference paper). */ private static final double[] X_VALUES_FOR_B = { - 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0, 6.0 + 0.0, 200.0, 400.0, 600.0, 8000.0, 1000.0, 1500.0, 2000.0, 2500.0, 3000.0, 4000.0, 5000.0, 6000.0 }; /** E values for the B function (table 1 in reference paper). */ @@ -77,14 +74,8 @@ public class CanonicalSaastamoinenModel implements DiscreteTroposphericModel { /** Interpolation function for the B correction term. */ private final PolynomialSplineFunction bFunction; - /** The temperature at the station [K]. */ - private double t0; - - /** The atmospheric pressure [mbar]. */ - private double p0; - - /** The humidity [percent]. */ - private double r0; + /** Provider for pressure, temperature and humidity. */ + private final PressureTemperatureHumidityProvider pthProvider; /** Lowest acceptable elevation angle [rad]. */ private double lowElevationThreshold; @@ -93,16 +84,11 @@ public class CanonicalSaastamoinenModel implements DiscreteTroposphericModel { * Create a new Saastamoinen model for the troposphere using the given environmental * conditions and table from the reference book. * - * @param t0 the temperature at the station [K] - * @param p0 the atmospheric pressure at the station [mbar] - * @param r0 the humidity at the station [fraction] (50% -> 0.5) + * @param pthProvider provider for pressure, temperature and humidity */ - public CanonicalSaastamoinenModel(final double t0, final double p0, final double r0) { - checkParameterRangeInclusive("humidity", r0, 0.0, 1.0); - this.t0 = t0; - this.p0 = p0; - this.r0 = r0; - this.bFunction = new LinearInterpolator().interpolate(X_VALUES_FOR_B, Y_VALUES_FOR_B); + public CanonicalSaastamoinenModel(final PressureTemperatureHumidityProvider pthProvider) { + this.pthProvider = pthProvider; + this.bFunction = new LinearInterpolator().interpolate(X_VALUES_FOR_B, Y_VALUES_FOR_B); this.lowElevationThreshold = DEFAULT_LOW_ELEVATION_THRESHOLD; } @@ -117,29 +103,17 @@ public CanonicalSaastamoinenModel(final double t0, final double p0, final double * @return a Saastamoinen model with standard environmental values */ public static CanonicalSaastamoinenModel getStandardModel() { - return new CanonicalSaastamoinenModel(273.16 + 18, 1013.25, 0.5); - } - /** Check if the given parameter is within an acceptable range. - * The bounds are inclusive: an exception is raised when either of those conditions are met: - *

                - *
              • The parameter is strictly greater than upperBound
              • - *
              • The parameter is strictly lower than lowerBound
              • - *
              - *

              - * In either of these cases, an OrekitException is raised. - *

              - * @param parameterName name of the parameter - * @param parameter value of the parameter - * @param lowerBound lower bound of the acceptable range (inclusive) - * @param upperBound upper bound of the acceptable range (inclusive) - */ - private void checkParameterRangeInclusive(final String parameterName, final double parameter, - final double lowerBound, final double upperBound) { - if (parameter < lowerBound || parameter > upperBound) { - throw new OrekitException(OrekitMessages.INVALID_PARAMETER_RANGE, parameterName, - parameter, lowerBound, upperBound); - } + // build standard meteorological data + final double pressure = Unit.parse("hPa").toSI(1013.25); + final double temperature = 273.15 + 18; + final double waterVaporPressure = new NbsNrcSteamTable().waterVaporPressure(temperature, pressure, 0.5); + final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(pressure, + temperature, + waterVaporPressure); + + return new CanonicalSaastamoinenModel(new ConstantPressureTemperatureHumidityProvider(pth)); + } /** {@inheritDoc} @@ -159,21 +133,15 @@ private void checkParameterRangeInclusive(final String parameterName, final doub public double pathDelay(final double elevation, final GeodeticPoint point, final double[] parameters, final AbsoluteDate date) { - // there are no data in the model for negative altitudes and altitude bigger than 5000 m - // limit the height to a range of [0, 5000] m - final double fixedHeight = FastMath.min(FastMath.max(0, point.getAltitude()), 5000); + final PressureTemperatureHumidity pth = pthProvider.getWeatherParamerers(point, date); - // the corrected temperature using a temperature gradient of -6.5 K/km - final double T = t0 - 6.5e-3 * fixedHeight; - // the corrected pressure - final double P = p0 * FastMath.pow(1.0 - 2.26e-5 * fixedHeight, 5.225); - // the corrected humidity - final double R = r0 * FastMath.exp(-6.396e-4 * fixedHeight); + // there are no data in the model for negative altitudes and altitude bigger than 6000 m + // limit the height to a range of [0, 5000] m + final double fixedHeight = FastMath.min(FastMath.max(point.getAltitude(), X_VALUES_FOR_B[0]), + X_VALUES_FOR_B[X_VALUES_FOR_B.length - 1]); // interpolate the b correction term - final double B = bFunction.value(fixedHeight / 1e3); - // calculate e - final double e = R * FastMath.exp(eFunction.value(T)); + final double B = bFunction.value(fixedHeight); // calculate the zenith angle from the elevation final double z = FastMath.abs(0.5 * FastMath.PI - FastMath.max(elevation, lowElevationThreshold)); @@ -181,7 +149,8 @@ public double pathDelay(final double elevation, final GeodeticPoint point, // calculate the path delay in m final double tan = FastMath.tan(z); final double delta = 2.277e-3 / FastMath.cos(z) * - (P + (1255d / T + 5e-2) * e - B * tan * tan); + (pth.getPressure() + + (1255.0 / pth.getTemperature() + 0.05) * pth.getWaterVaporPressure() - B * tan * tan); return delta; } @@ -205,31 +174,31 @@ public > T pathDelay(final T elevation, final final Field field = date.getField(); final T zero = field.getZero(); + + final FieldPressureTemperatureHumidity pth = pthProvider.getWeatherParamerers(point, date); + // there are no data in the model for negative altitudes and altitude bigger than 5000 m // limit the height to a range of [0, 5000] m - final T fixedHeight = FastMath.min(FastMath.max(zero, point.getAltitude()), zero.add(5000)); - - // the corrected temperature using a temperature gradient of -6.5 K/km - final T T = fixedHeight.multiply(6.5e-3).negate().add(t0); - // the corrected pressure - final T P = fixedHeight.multiply(2.26e-5).negate().add(1.0).pow(5.225).multiply(p0); - // the corrected humidity - final T R = FastMath.exp(fixedHeight.multiply(-6.396e-4)).multiply(r0); + final T fixedHeight = FastMath.min(FastMath.max(point.getAltitude(), X_VALUES_FOR_B[0]), + X_VALUES_FOR_B[X_VALUES_FOR_B.length - 1]); // interpolate the b correction term - final T B = bFunction.value(fixedHeight.divide(1e3)); - // calculate e - final T e = R.multiply(FastMath.exp(eFunction.value(T))); + final T B = bFunction.value(fixedHeight); // calculate the zenith angle from the elevation - final T z = FastMath.abs(FastMath.max(elevation, zero.add(lowElevationThreshold)).negate().add(zero.getPi().multiply(0.5))); + final T z = FastMath.abs(zero.getPi().multiply(0.5). + subtract(FastMath.max(elevation, lowElevationThreshold))); // calculate the path delay in m final T tan = FastMath.tan(z); final T delta = FastMath.cos(z).divide(2.277e-3).reciprocal(). - multiply(P.add(T.divide(1255d).reciprocal().add(5e-2).multiply(e)).subtract(B.multiply(tan).multiply(tan))); + multiply(pth.getPressure(). + add(pth.getTemperature().reciprocal().multiply(1255.0).add(0.05). + multiply(pth.getWaterVaporPressure())). + subtract(B.multiply(tan).multiply(tan))); return delta; + } /** {@inheritDoc} */ diff --git a/src/main/java/org/orekit/models/earth/weather/ConstantPressureTemperatureHumidityProvider.java b/src/main/java/org/orekit/models/earth/weather/ConstantPressureTemperatureHumidityProvider.java new file mode 100644 index 0000000000..f6d0acb422 --- /dev/null +++ b/src/main/java/org/orekit/models/earth/weather/ConstantPressureTemperatureHumidityProvider.java @@ -0,0 +1,58 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS Communication & Systèmes (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.weather; + +import org.hipparchus.CalculusFieldElement; +import org.orekit.bodies.FieldGeodeticPoint; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; + +/** Provider for constant weather parameters. + * @author Luc Maisonobe + * @since 12.1 + */ +public class ConstantPressureTemperatureHumidityProvider implements PressureTemperatureHumidityProvider { + + /** Constant parameters. */ + private final PressureTemperatureHumidity pth; + + /** Simple constructor. + * @param pth constant parameters + */ + public ConstantPressureTemperatureHumidityProvider(final PressureTemperatureHumidity pth) { + this.pth = pth; + } + + /** {@inheritDoc} */ + @Override + public PressureTemperatureHumidity getWeatherParamerers(final GeodeticPoint location, + final AbsoluteDate date) { + return pth; + } + + /** {@inheritDoc} */ + @Override + public > FieldPressureTemperatureHumidity getWeatherParamerers(final FieldGeodeticPoint location, + final FieldAbsoluteDate date) { + final T zero = date.getField().getZero(); + return new FieldPressureTemperatureHumidity<>(zero.newInstance(pth.getPressure()), + zero.newInstance(pth.getTemperature()), + zero.newInstance(pth.getWaterVaporPressure())); + } + +} diff --git a/src/main/java/org/orekit/models/earth/weather/FieldPressureTemperatureHumidity.java b/src/main/java/org/orekit/models/earth/weather/FieldPressureTemperatureHumidity.java index 40003dcfcc..9349a725d5 100644 --- a/src/main/java/org/orekit/models/earth/weather/FieldPressureTemperatureHumidity.java +++ b/src/main/java/org/orekit/models/earth/weather/FieldPressureTemperatureHumidity.java @@ -25,19 +25,19 @@ */ public class FieldPressureTemperatureHumidity> { - /** Pressure (hPa). */ + /** Pressure (Pa). */ private final T pressure; /** Temperature (Kelvin). */ private final T temperature; - /** Humidity as water vapor pressure (hPa). */ + /** Humidity as water vapor pressure (Pa). */ private final T waterVaporPressure; /** Simple constructor. - * @param pressure pressure (hPa) + * @param pressure pressure (Pa) * @param temperature temperature (Kelvin) - * @param humidity humidity as water vapor pressure (hPa) + * @param waterVaporPressure humidity as water vapor pressure (Pa) */ public FieldPressureTemperatureHumidity(final T pressure, final T temperature, @@ -48,7 +48,7 @@ public FieldPressureTemperatureHumidity(final T pressure, } /** Get pressure. - * @return pressure hPa + * @return pressure (Pa) */ public T getPressure() { return pressure; @@ -62,7 +62,7 @@ public T getTemperature() { } /** Get humidity as water vapor pressure. - * @return humidity as water vapor pressure (hPa) + * @return humidity as water vapor pressure (Pa) */ public T getWaterVaporPressure() { return waterVaporPressure; diff --git a/src/main/java/org/orekit/models/earth/weather/PressureTemperatureHumidity.java b/src/main/java/org/orekit/models/earth/weather/PressureTemperatureHumidity.java index a5bf8541c5..d355d6d90f 100644 --- a/src/main/java/org/orekit/models/earth/weather/PressureTemperatureHumidity.java +++ b/src/main/java/org/orekit/models/earth/weather/PressureTemperatureHumidity.java @@ -22,19 +22,19 @@ */ public class PressureTemperatureHumidity { - /** Pressure (hPa). */ + /** Pressure (Pa). */ private final double pressure; /** Temperature (Kelvin). */ private final double temperature; - /** Humidity as water vapor pressure (hPa). */ + /** Humidity as water vapor pressure (Pa). */ private final double waterVaporPressure; /** Simple constructor. - * @param pressure pressure (hPa) + * @param pressure pressure (Pa) * @param temperature temperature (Kelvin) - * @param humidity humidity as water vapor pressure (hPa) + * @param waterVaporPressure humidity as water vapor pressure (Pa) */ public PressureTemperatureHumidity(final double pressure, final double temperature, @@ -45,7 +45,7 @@ public PressureTemperatureHumidity(final double pressure, } /** Get pressure. - * @return pressure hPa + * @return pressure (Pa) */ public double getPressure() { return pressure; @@ -59,7 +59,7 @@ public double getTemperature() { } /** Get humidity as water vapor pressure. - * @return humidity as water vapor pressure (hPa) + * @return humidity as water vapor pressure (Pa) */ public double getWaterVaporPressure() { return waterVaporPressure; diff --git a/src/main/java/org/orekit/models/earth/weather/PressureTemperatureHumidityProvider.java b/src/main/java/org/orekit/models/earth/weather/PressureTemperatureHumidityProvider.java new file mode 100644 index 0000000000..7bcc440ec4 --- /dev/null +++ b/src/main/java/org/orekit/models/earth/weather/PressureTemperatureHumidityProvider.java @@ -0,0 +1,47 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS Communication & Systèmes (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.weather; + +import org.hipparchus.CalculusFieldElement; +import org.orekit.bodies.FieldGeodeticPoint; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; + +/** Interface for providing weather parameters. + * @author Luc Maisonobe + * @since 12.1 + */ +public interface PressureTemperatureHumidityProvider { + + /** Provide weather parameters. + * @param location location at which parameters are requested + * @param date date at which parameters are requested + * @return weather parameters + */ + PressureTemperatureHumidity getWeatherParamerers(GeodeticPoint location, AbsoluteDate date); + + /** Provide weather parameters. + * @param type of the field elements + * @param location location at which parameters are requested + * @param date date at which parameters are requested + * @return weather parameters + */ + > FieldPressureTemperatureHumidity getWeatherParamerers(FieldGeodeticPoint location, + FieldAbsoluteDate date); + +} diff --git a/src/main/java/org/orekit/models/earth/weather/water/NbsNrcSteamTable.java b/src/main/java/org/orekit/models/earth/weather/water/NbsNrcSteamTable.java new file mode 100644 index 0000000000..08e9bc6b64 --- /dev/null +++ b/src/main/java/org/orekit/models/earth/weather/water/NbsNrcSteamTable.java @@ -0,0 +1,84 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS Communication & Systèmes (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.weather.water; + +import org.hipparchus.CalculusFieldElement; +import org.hipparchus.analysis.interpolation.SplineInterpolator; +import org.hipparchus.analysis.polynomials.PolynomialSplineFunction; +import org.hipparchus.util.FastMath; + +/** Steam table from US National Bureau of Standards (NBS) and National Research Council (NRC) of Canada. + *

              + * The table is an extract from table 1 in Thermopedia, + * using only the pressure column and truncated to 99°C (the original table goes up to 373.976°C). According to + * the access page, this data is available for free. + *

              + * @see Thermopedia Steam Tables + * + * @author Luc Maisonobe + * @since 12.1 + */ +public class NbsNrcSteamTable implements WaterVaporPressureProvider { + + /** Celsius temperature offset. */ + private static final double CELSIUS = 273.15; + + /** Minimum temperature of the model. */ + private static final double MIN_T = CELSIUS + 0.01; + + /** Saturation pressure model. */ + private static final PolynomialSplineFunction MODEL; + + static { + + // saturation pressure in SI units (Pa) + final double[] pressure = { + 00611.73, 657.16, 706.05, 758.13, 813.59, 872.60, 935.37, 1002.09, 1072.97, 1148.25, + 01228.10, 1312.90, 1402.70, 1497.90, 1598.80, 1705.60, 1818.50, 1938.00, 2064.40, 2197.90, + 02338.80, 2487.70, 2644.70, 2810.40, 2985.00, 3169.10, 3362.90, 3567.00, 3781.80, 4007.80, + 04245.50, 4495.30, 4757.80, 5033.50, 5322.90, 5626.70, 5945.40, 6279.50, 6629.80, 6996.90, + 07381.40, 7784.00, 8205.40, 8646.40, 9107.60, 9589.80, 10093.80, 10620.50, 11170.60, 11744.90, + 12344.00, 12970.00, 13623.00, 14303.00, 15012.00, 15752.00, 16522.00, 17324.00, 18159.00, 19028.00, + 19932.00, 20873.00, 21851.00, 22868.00, 23925.00, 25022.00, 26163.00, 27347.00, 28576.00, 29852.00, + 31176.00, 32549.00, 33972.00, 35448.00, 36978.00, 38563.00, 40205.00, 41905.00, 43665.00, 45487.00, + 47373.00, 49324.00, 51342.00, 53428.00, 55585.00, 57815.00, 60119.00, 62499.00, 64958.00, 67496.00, + 70117.00, 72823.00, 75614.00, 78495.00, 81465.00, 84529.00, 87688.00, 90945.00, 94301.00, 97759.00 + }; + + // the table first entry is at 0.01°C, not 0.00°C, but remaining entries are 1°C, 2°C, … 99°C + final double[] temperature = new double[pressure.length]; + for (int i = 0; i < temperature.length; ++i) { + temperature[i] = (i == 0) ? MIN_T : (CELSIUS + i); + } + + MODEL = new SplineInterpolator().interpolate(temperature, pressure); + + } + + /** {@inheritDoc} */ + @Override + public double waterVaporPressure(final double t, final double p, final double rh) { + return MODEL.value(FastMath.max(t, MIN_T)) * rh; + } + + /** {@inheritDoc} */ + @Override + public > T waterVaporPressure(final T t, final T p, final T rh) { + return MODEL.value(FastMath.max(t, MIN_T)).multiply(rh); + } + +} diff --git a/src/main/java/org/orekit/models/earth/weather/water/WaterVaporPressureProvider.java b/src/main/java/org/orekit/models/earth/weather/water/WaterVaporPressureProvider.java new file mode 100644 index 0000000000..0a6196afc3 --- /dev/null +++ b/src/main/java/org/orekit/models/earth/weather/water/WaterVaporPressureProvider.java @@ -0,0 +1,45 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS Communication & Systèmes (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.weather.water; + +import org.hipparchus.CalculusFieldElement; + +/** Interface for converting relative humidity into water vapor pressure. + * @author Luc Maisonobe + * @since 12.1 + */ +public interface WaterVaporPressureProvider { + + /** Compute water vapor pressure. + * @param t temperature (Kelvin) + * @param p pressure (Pa) + * @param rh relative humidity, in percent (50% → 0.5) + * @return water vapor pressure (Pa) + */ + double waterVaporPressure(double t, double p, double rh); + + /** Compute water vapor pressure. + * @param type of the field elements + * @param t temperature (Kelvin) + * @param p pressure (Pa) + * @param rh relative humidity, in percent (50% → 0.5) + * @return water vapor pressure (Pa) + */ + > T waterVaporPressure(T t, T p, T rh); + +} + diff --git a/src/main/java/org/orekit/models/earth/weather/water/package-info.java b/src/main/java/org/orekit/models/earth/weather/water/package-info.java new file mode 100644 index 0000000000..c759917dfd --- /dev/null +++ b/src/main/java/org/orekit/models/earth/weather/water/package-info.java @@ -0,0 +1,20 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** This package provides models that convert between relative humidity and partial water pressure. + * @author Luc Maisonobe + */ +package org.orekit.models.earth.weather.water; From ff725f8ca6867a07cffa15d9fe57547a680aaa67 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Thu, 7 Dec 2023 19:07:56 +0100 Subject: [PATCH 018/359] Added hectoPascal unit. --- .../java/org/orekit/utils/units/Unit.java | 5 ++ .../java/org/orekit/utils/units/UnitTest.java | 59 ++++++++++--------- .../utils/units/UnitsConverterTest.java | 11 ++-- 3 files changed, 42 insertions(+), 33 deletions(-) diff --git a/src/main/java/org/orekit/utils/units/Unit.java b/src/main/java/org/orekit/utils/units/Unit.java index d1a3c6abd0..cb8bf25442 100644 --- a/src/main/java/org/orekit/utils/units/Unit.java +++ b/src/main/java/org/orekit/utils/units/Unit.java @@ -107,6 +107,11 @@ public class Unit implements Serializable { /** Pascal unit. */ public static final Unit PASCAL = NEWTON.divide("Pa", METRE.power(null, Fraction.TWO)); + /** HectoPascal unit. + * @since 12.1 + */ + public static final Unit HECTO_PASCAL = PASCAL.scale("hPa", 100.0); + /** Bar unit. */ public static final Unit BAR = PASCAL.scale("bar", 100000.0); diff --git a/src/test/java/org/orekit/utils/units/UnitTest.java b/src/test/java/org/orekit/utils/units/UnitTest.java index 9eb037cad1..8e8b1bcd68 100644 --- a/src/test/java/org/orekit/utils/units/UnitTest.java +++ b/src/test/java/org/orekit/utils/units/UnitTest.java @@ -78,36 +78,37 @@ public void testEquals() { @Test public void testReference() { - checkReference(Unit.NONE, "n/a", 1.0, 0, 0, 0, 0, 0); - checkReference(Unit.ONE, "1", 1.0, 0, 0, 0, 0, 0); - checkReference(Unit.PERCENT, "%", 0.01, 0, 0, 0, 0, 0); - checkReference(Unit.SECOND, "s", 1.0, 0, 0, 1, 0, 0); - checkReference(Unit.MINUTE, "min", 60.0, 0, 0, 1, 0, 0); - checkReference(Unit.HOUR, "h", 3600.0, 0, 0, 1, 0, 0); - checkReference(Unit.DAY, "d", 86400.0, 0, 0, 1, 0, 0); - checkReference(Unit.YEAR, "a", 31557600.0, 0, 0, 1, 0, 0); - checkReference(Unit.HERTZ, "Hz", 1.0, 0, 0, -1, 0, 0); - checkReference(Unit.METRE, "m", 1.0, 0, 1, 0, 0, 0); - checkReference(Unit.KILOMETRE, "km", 1000.0, 0, 1, 0, 0, 0); - checkReference(Unit.KILOGRAM, "kg", 1.0, 1, 0, 0, 0, 0); - checkReference(Unit.GRAM, "g", 0.001, 1, 0, 0, 0, 0); - checkReference(Unit.AMPERE, "A", 1.0, 0, 0, 0, 1, 0); - checkReference(Unit.RADIAN, "rad", 1.0, 0, 0, 0, 0, 1); - checkReference(Unit.DEGREE, "°", FastMath.PI / 180.0, 0, 0, 0, 0, 1); - checkReference(Unit.ARC_MINUTE, "′", FastMath.PI / 10800.0, 0, 0, 0, 0, 1); - checkReference(Unit.ARC_SECOND, "″", FastMath.PI / 648000.0, 0, 0, 0, 0, 1); - checkReference(Unit.REVOLUTION, "rev", 2.0 * FastMath.PI, 0, 0, 0, 0, 1); - checkReference(Unit.NEWTON, "N", 1.0, 1, 1, -2, 0, 0); - checkReference(Unit.PASCAL, "Pa", 1.0, 1, -1, -2, 0, 0); - checkReference(Unit.BAR, "bar", 100000.0, 1, -1, -2, 0, 0); - checkReference(Unit.JOULE, "J", 1.0, 1, 2, -2, 0, 0); - checkReference(Unit.WATT, "W", 1.0, 1, 2, -3, 0, 0); - checkReference(Unit.COULOMB, "C", 1.0, 0, 0, 1, 1, 0); - checkReference(Unit.VOLT, "V", 1.0, 1, 2, -3, -1, 0); - checkReference(Unit.OHM, "Ω", 1.0, 1, 2, -3, -2, 0); - checkReference(Unit.TESLA, "T", 1.0, 1, 0, -2, -1, 0); + checkReference(Unit.NONE, "n/a", 1.0, 0, 0, 0, 0, 0); + checkReference(Unit.ONE, "1", 1.0, 0, 0, 0, 0, 0); + checkReference(Unit.PERCENT, "%", 0.01, 0, 0, 0, 0, 0); + checkReference(Unit.SECOND, "s", 1.0, 0, 0, 1, 0, 0); + checkReference(Unit.MINUTE, "min", 60.0, 0, 0, 1, 0, 0); + checkReference(Unit.HOUR, "h", 3600.0, 0, 0, 1, 0, 0); + checkReference(Unit.DAY, "d", 86400.0, 0, 0, 1, 0, 0); + checkReference(Unit.YEAR, "a", 31557600.0, 0, 0, 1, 0, 0); + checkReference(Unit.HERTZ, "Hz", 1.0, 0, 0, -1, 0, 0); + checkReference(Unit.METRE, "m", 1.0, 0, 1, 0, 0, 0); + checkReference(Unit.KILOMETRE, "km", 1000.0, 0, 1, 0, 0, 0); + checkReference(Unit.KILOGRAM, "kg", 1.0, 1, 0, 0, 0, 0); + checkReference(Unit.GRAM, "g", 0.001, 1, 0, 0, 0, 0); + checkReference(Unit.AMPERE, "A", 1.0, 0, 0, 0, 1, 0); + checkReference(Unit.RADIAN, "rad", 1.0, 0, 0, 0, 0, 1); + checkReference(Unit.DEGREE, "°", FastMath.PI / 180.0, 0, 0, 0, 0, 1); + checkReference(Unit.ARC_MINUTE, "′", FastMath.PI / 10800.0, 0, 0, 0, 0, 1); + checkReference(Unit.ARC_SECOND, "″", FastMath.PI / 648000.0, 0, 0, 0, 0, 1); + checkReference(Unit.REVOLUTION, "rev", 2.0 * FastMath.PI, 0, 0, 0, 0, 1); + checkReference(Unit.NEWTON, "N", 1.0, 1, 1, -2, 0, 0); + checkReference(Unit.PASCAL, "Pa", 1.0, 1, -1, -2, 0, 0); + checkReference(Unit.HECTO_PASCAL, "hPa", 100.0, 1, -1, -2, 0, 0); + checkReference(Unit.BAR, "bar", 100000.0, 1, -1, -2, 0, 0); + checkReference(Unit.JOULE, "J", 1.0, 1, 2, -2, 0, 0); + checkReference(Unit.WATT, "W", 1.0, 1, 2, -3, 0, 0); + checkReference(Unit.COULOMB, "C", 1.0, 0, 0, 1, 1, 0); + checkReference(Unit.VOLT, "V", 1.0, 1, 2, -3, -1, 0); + checkReference(Unit.OHM, "Ω", 1.0, 1, 2, -3, -2, 0); + checkReference(Unit.TESLA, "T", 1.0, 1, 0, -2, -1, 0); checkReference(Unit.SOLAR_FLUX_UNIT, "SFU", 1.0e-22, 1, 0, -2, 0, 0); - checkReference(Unit.TOTAL_ELECTRON_CONTENT_UNIT, "TECU", 1.0e16, 0, -2, 0, 0, 0); + checkReference(Unit.TOTAL_ELECTRON_CONTENT_UNIT, "TECU", 1.0e16, 0, -2, 0, 0, 0); } diff --git a/src/test/java/org/orekit/utils/units/UnitsConverterTest.java b/src/test/java/org/orekit/utils/units/UnitsConverterTest.java index fdbc24e075..20fae6499c 100644 --- a/src/test/java/org/orekit/utils/units/UnitsConverterTest.java +++ b/src/test/java/org/orekit/utils/units/UnitsConverterTest.java @@ -48,10 +48,13 @@ public void testRotationRate() { @Test public void testPressure() { final double atm = 1013.25; - final Unit mbar = Unit.parse("mbar"); - final Unit hPa = Unit.parse("hPa"); - final UnitsConverter mbar2hPa = new UnitsConverter(mbar, hPa); - Assertions.assertEquals(atm, mbar2hPa.convert(atm), 1.0e-12); + final Unit mbar = Unit.parse("mbar"); + final Unit hPa1 = Unit.parse("hPa"); + final Unit hPa2 = Unit.HECTO_PASCAL; + final UnitsConverter mbar2hPa1 = new UnitsConverter(mbar, hPa1); + Assertions.assertEquals(atm, mbar2hPa1.convert(atm), 1.0e-12); + final UnitsConverter mbar2hPa2 = new UnitsConverter(mbar, hPa2); + Assertions.assertEquals(atm, mbar2hPa2.convert(atm), 1.0e-12); } @Test From 249bef0c5de5219d6abdc0c93851745b0e926de6 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Thu, 7 Dec 2023 19:08:46 +0100 Subject: [PATCH 019/359] Separated CIPM-2007 water vapor model in dedicated class. --- .../earth/troposphere/MariniMurrayModel.java | 85 +++++++++---------- .../earth/troposphere/MendesPavlisModel.java | 54 +++++++----- .../WaterVaporPressureProvider.java | 45 ---------- .../water/CIPM2007.java} | 45 +++++----- .../water/WaterVaporPressureProvider.java | 10 +-- 5 files changed, 105 insertions(+), 134 deletions(-) delete mode 100644 src/main/java/org/orekit/models/earth/troposphere/WaterVaporPressureProvider.java rename src/main/java/org/orekit/models/earth/{troposphere/GiacomoDavis.java => weather/water/CIPM2007.java} (59%) diff --git a/src/main/java/org/orekit/models/earth/troposphere/MariniMurrayModel.java b/src/main/java/org/orekit/models/earth/troposphere/MariniMurrayModel.java index b24a2b8d3d..dc743acfaa 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/MariniMurrayModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/MariniMurrayModel.java @@ -23,9 +23,12 @@ import org.hipparchus.util.FastMath; import org.orekit.bodies.FieldGeodeticPoint; import org.orekit.bodies.GeodeticPoint; +import org.orekit.models.earth.weather.PressureTemperatureHumidity; +import org.orekit.models.earth.weather.water.CIPM2007; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; import org.orekit.utils.ParameterDriver; +import org.orekit.utils.units.Unit; /** The Marini-Murray tropospheric delay model for laser ranging. * @@ -36,14 +39,8 @@ */ public class MariniMurrayModel implements DiscreteTroposphericModel { - /** The temperature at the station, K. */ - private double T0; - - /** The atmospheric pressure, mbar. */ - private double P0; - - /** water vapor pressure at the laser site, mbar. */ - private double e0; + /** Pressure, temperature and humidity. */ + private PressureTemperatureHumidity pth; /** Laser wavelength, micrometers. */ private double lambda; @@ -56,10 +53,19 @@ public class MariniMurrayModel implements DiscreteTroposphericModel { * @param lambda laser wavelength (c/f), nm */ public MariniMurrayModel(final double t0, final double p0, final double rh, final double lambda) { - this.T0 = t0; - this.P0 = p0; - this.e0 = getWaterVapor(rh); - this.lambda = lambda * 1e-3; + this(new PressureTemperatureHumidity(Unit.HECTO_PASCAL.toSI(p0), + t0, + new CIPM2007().waterVaporPressure(Unit.HECTO_PASCAL.toSI(p0), t0, rh)), + lambda); + } + + /** Create a new Marini-Murray model for the troposphere. + * @param pth atmospheric pressure, temperature and humidity at the station + * @param lambda laser wavelength, nm + * */ + public MariniMurrayModel(final PressureTemperatureHumidity pth, final double lambda) { + this.pth = pth; + this.lambda = lambda * 1.0e-3; } /** Create a new Marini-Murray model using a standard atmosphere model. @@ -75,16 +81,27 @@ public MariniMurrayModel(final double t0, final double p0, final double rh, fina * @return a Marini-Murray model with standard environmental values */ public static MariniMurrayModel getStandardModel(final double lambda) { - return new MariniMurrayModel(273.15 + 20, 1013.25, 0.5, lambda); + final double p = Unit.HECTO_PASCAL.toSI(1013.25); + final double t = 273.15 + 20; + final double rh = 0.5; + return new MariniMurrayModel(new PressureTemperatureHumidity(p, t, + new CIPM2007().waterVaporPressure(p, t, rh)), + lambda); } /** {@inheritDoc} */ @Override public double pathDelay(final double elevation, final GeodeticPoint point, final double[] parameters, final AbsoluteDate date) { - final double A = 0.002357 * P0 + 0.000141 * e0; - final double K = 1.163 - 0.00968 * FastMath.cos(2 * point.getLatitude()) - 0.00104 * T0 + 0.00001435 * P0; - final double B = (1.084 * 1e-8) * P0 * T0 * K + (4.734 * 1e-8) * P0 * (P0 / T0) * (2 * K) / (3 * K - 1); + + final double p = pth.getPressure(); + final double t = pth.getTemperature(); + final double e = pth.getWaterVaporPressure(); + + // beware since version 12.1 pressures are in Pa and not in hPa, hence the scaling has changed + final double A = 0.00002357 * p + 0.00000141 * e; + final double K = 1.163 - 0.00968 * FastMath.cos(2 * point.getLatitude()) - 0.00104 * t + 0.0000001435 * p; + final double B = 1.084e-10 * p * t * K + 4.734e-12 * p * (p / t) * (2 * K) / (3 * K - 1); final double flambda = getLaserFrequencyParameter(); final double fsite = getSiteFunctionValue(point); @@ -98,9 +115,15 @@ public double pathDelay(final double elevation, final GeodeticPoint point, @Override public > T pathDelay(final T elevation, final FieldGeodeticPoint point, final T[] parameters, final FieldAbsoluteDate date) { - final double A = 0.002357 * P0 + 0.000141 * e0; - final T K = FastMath.cos(point.getLatitude().multiply(2.)).multiply(0.00968).negate().add(1.163).subtract(0.00104 * T0).add(0.00001435 * P0); - final T B = K.multiply((1.084 * 1e-8) * P0 * T0).add(K.multiply(2.).multiply((4.734 * 1e-8) * P0 * (P0 / T0)).divide(K.multiply(3.).subtract(1.))); + + final double p = pth.getPressure(); + final double t = pth.getTemperature(); + final double e = pth.getWaterVaporPressure(); + + // beware since version 12.1 pressures are in Pa and not in hPa, hence the scaling has changed + final double A = 0.00002357 * p + 0.00000141 * e; + final T K = FastMath.cos(point.getLatitude().multiply(2.)).multiply(0.00968).negate().add(1.163).subtract(0.00104 * t).add(0.0000001435 * p); + final T B = K.multiply(1.084e-10 * p * t).add(K.multiply(2.).multiply(4.734e-12 * p * (p / t)).divide(K.multiply(3.).subtract(1.))); final double flambda = getLaserFrequencyParameter(); final T fsite = getSiteFunctionValue(point); @@ -145,28 +168,4 @@ private > T getSiteFunctionValue(final FieldGe return FastMath.cos(point.getLatitude().multiply(2)).multiply(0.0026).add(point.getAltitude().multiply(0.001).multiply(0.00031)).negate().add(1.); } - /** Get the water vapor. - * The water vapor model is the one of Giacomo and Davis as indicated in IERS TN 32, chap. 9. - * - * See: Giacomo, P., Equation for the dertermination of the density of moist air, Metrologia, V. 18, 1982 - * - * @param rh relative humidity, in percent (50% -> 0.5). - * @return the water vapor, in mbar (1 mbar = 100 Pa). - */ - private double getWaterVapor(final double rh) { - - // saturation water vapor, equation (3) of reference paper, in mbar - // with amended 1991 values (see reference paper) - final double es = 0.01 * FastMath.exp((1.2378847 * 1e-5) * T0 * T0 - - (1.9121316 * 1e-2) * T0 + - 33.93711047 - - (6.3431645 * 1e3) * 1. / T0); - - // enhancement factor, equation (4) of reference paper - final double fw = 1.00062 + (3.14 * 1e-6) * P0 + (5.6 * 1e-7) * FastMath.pow(T0 - 273.15, 2); - - final double e = rh * fw * es; - return e; - } - } diff --git a/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java b/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java index 14cdf21ab7..aeea86f03f 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java @@ -25,9 +25,12 @@ import org.hipparchus.util.MathArrays; import org.orekit.bodies.FieldGeodeticPoint; import org.orekit.bodies.GeodeticPoint; +import org.orekit.models.earth.weather.PressureTemperatureHumidity; +import org.orekit.models.earth.weather.water.CIPM2007; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; import org.orekit.utils.ParameterDriver; +import org.orekit.utils.units.Unit; /** The Mendes - Pavlis tropospheric delay model for optical techniques. * It is valid for a wide range of wavelengths from 0.355µm to 1.064µm (Mendes and Pavlis, 2003) @@ -65,17 +68,11 @@ public class MendesPavlisModel implements DiscreteTroposphericModel, MappingFunc /** Laser wavelength [µm]. */ private double lambda; - /** The atmospheric pressure [hPa]. */ - private double P0; - - /** The temperature at the station [K]. */ - private double T0; - - /** Water vapor pressure at the laser site [hPa]. */ - private double e0; + /** Pressure, temperature and humidity. */ + private PressureTemperatureHumidity pth; /** Create a new Mendes-Pavlis model for the troposphere. - * This initialisation will compute the water vapor pressure + * This initialization will compute the water vapor pressure * thanks to the values of the pressure, the temperature and the humidity * @param t0 the temperature at the station, K * @param p0 the atmospheric pressure at the station, hPa @@ -84,9 +81,18 @@ public class MendesPavlisModel implements DiscreteTroposphericModel, MappingFunc * */ public MendesPavlisModel(final double t0, final double p0, final double rh, final double lambda) { - this.P0 = p0; - this.T0 = t0; - this.e0 = new GiacomoDavis().waterVaporPressure(t0, p0, rh); + this(new PressureTemperatureHumidity(Unit.HECTO_PASCAL.toSI(p0), + t0, + new CIPM2007().waterVaporPressure(Unit.HECTO_PASCAL.toSI(p0), t0, rh)), + lambda); + } + + /** Create a new Mendes-Pavlis model for the troposphere. + * @param pth atmospheric pressure, temperature and humidity at the station + * @param lambda laser wavelength, µm + * */ + public MendesPavlisModel(final PressureTemperatureHumidity pth, final double lambda) { + this.pth = pth; this.lambda = lambda; } @@ -103,7 +109,12 @@ public MendesPavlisModel(final double t0, final double p0, * @return a Mendes-Pavlis model with standard environmental values */ public static MendesPavlisModel getStandardModel(final double lambda) { - return new MendesPavlisModel(273.15 + 18, 1013.25, 0.5, lambda); + final double p = Unit.HECTO_PASCAL.toSI(1013.25); + final double t = 273.15 + 18; + final double rh = 0.5; + return new MendesPavlisModel(new PressureTemperatureHumidity(p, t, + new CIPM2007().waterVaporPressure(p, t, rh)), + lambda); } /** {@inheritDoc} */ @@ -161,7 +172,8 @@ public double[] computeZenithDelay(final GeodeticPoint point, final double[] par final double fLambdaH = 0.01 * (K_COEFFICIENTS[1] * frac1 + K_COEFFICIENTS[3] * frac2) * C02; // Zenith delay for the hydrostatic component - delay[0] = 0.002416579 * (fLambdaH / fsite) * P0; + // beware since version 12.1 pressure is in Pa and not in hPa, hence the scaling has changed + delay[0] = 0.00002416579 * (fLambdaH / fsite) * pth.getPressure(); // Dispertion Equation for the Non-Hydrostatic component final double sigma4 = sigma2 * sigma2; @@ -173,7 +185,8 @@ public double[] computeZenithDelay(final GeodeticPoint point, final double[] par final double fLambdaNH = 0.003101 * (W_COEFFICIENTS[0] + w1s2 + w2s4 + w3s6); // Zenith delay for the non-hydrostatic component - delay[1] = 0.0001 * (5.316 * fLambdaNH - 3.759 * fLambdaH) * (e0 / fsite); + // beware since version 12.1 e0 is in Pa and not in hPa, hence the scaling has changed + delay[1] = 0.000001 * (5.316 * fLambdaNH - 3.759 * fLambdaH) * (pth.getWaterVaporPressure() / fsite); return delay; } @@ -214,7 +227,8 @@ public > T[] computeZenithDelay(final FieldGeo final T fLambdaH = frac1.multiply(K_COEFFICIENTS[1]).add(frac2.multiply(K_COEFFICIENTS[3])).multiply(0.01 * C02); // Zenith delay for the hydrostatic component - delay[0] = fLambdaH.divide(fsite).multiply(P0).multiply(0.002416579); + // beware since version 12.1 pressure is in Pa and not in hPa, hence the scaling has changed + delay[0] = fLambdaH.divide(fsite).multiply(pth.getPressure()).multiply(0.00002416579); // Dispertion Equation for the Non-Hydrostatic component final T sigma4 = sigma2.multiply(sigma2); @@ -226,7 +240,9 @@ public > T[] computeZenithDelay(final FieldGeo final T fLambdaNH = w1s2.add(w2s4).add(w3s6).add(W_COEFFICIENTS[0]).multiply(0.003101); // Zenith delay for the non-hydrostatic component - delay[1] = fLambdaNH.multiply(5.316).subtract(fLambdaH.multiply(3.759)).multiply(fsite.divide(e0).reciprocal()).multiply(0.0001); + // beware since version 12.1 e0 is in Pa and not in hPa, hence the scaling has changed + delay[1] = fLambdaNH.multiply(5.316).subtract(fLambdaH.multiply(3.759)). + multiply(fsite.divide(pth.getWaterVaporPressure()).reciprocal()).multiply(0.000001); return delay; } @@ -249,7 +265,7 @@ public double[] mappingFactors(final double elevation, final GeodeticPoint point final AbsoluteDate date) { final double sinE = FastMath.sin(elevation); - final double T2degree = T0 - 273.15; + final double T2degree = pth.getTemperature() - 273.15; // Mapping function coefficients final double a1 = computeMFCoeffient(A_COEFFICIENTS[0][0], A_COEFFICIENTS[0][1], @@ -295,7 +311,7 @@ public > T[] mappingFactors(final T elevation, final T sinE = FastMath.sin(elevation); - final double T2degree = T0 - 273.15; + final double T2degree = pth.getTemperature() - 273.15; // Mapping function coefficients final T a1 = computeMFCoeffient(A_COEFFICIENTS[0][0], A_COEFFICIENTS[0][1], diff --git a/src/main/java/org/orekit/models/earth/troposphere/WaterVaporPressureProvider.java b/src/main/java/org/orekit/models/earth/troposphere/WaterVaporPressureProvider.java deleted file mode 100644 index 6d3e80471b..0000000000 --- a/src/main/java/org/orekit/models/earth/troposphere/WaterVaporPressureProvider.java +++ /dev/null @@ -1,45 +0,0 @@ -/* Copyright 2023 Thales Alenia Space - * Licensed to CS Communication & Systèmes (CS) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * CS licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.orekit.models.earth.troposphere; - -import org.hipparchus.CalculusFieldElement; - -/** Interface for converting relative humidity into water vapor pressure. - * @author Luc Maisonobe - * @since 12.1 - */ -public interface WaterVaporPressureProvider { - - /** Compute water vapor pressure. - * @param t temperature (Kelvin) - * @param p pressure (hPa) - * @param rh relative humidity, in percent (50% → 0.5) - * @return water vapor pressure (hPa) - */ - double waterVaporPressure(double t, double p, double rh); - - /** Compute water vapor pressure. - * @param type of the field elements - * @param t temperature (Kelvin) - * @param p pressure (hPa) - * @param rh relative humidity, in percent (50% → 0.5) - * @return water vapor pressure (hPa) - */ - > T waterVaporPressure(T t, T p, T rh); - -} - diff --git a/src/main/java/org/orekit/models/earth/troposphere/GiacomoDavis.java b/src/main/java/org/orekit/models/earth/weather/water/CIPM2007.java similarity index 59% rename from src/main/java/org/orekit/models/earth/troposphere/GiacomoDavis.java rename to src/main/java/org/orekit/models/earth/weather/water/CIPM2007.java index 3eedf53240..16d42181fc 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/GiacomoDavis.java +++ b/src/main/java/org/orekit/models/earth/weather/water/CIPM2007.java @@ -14,20 +14,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.orekit.models.earth.troposphere; +package org.orekit.models.earth.weather.water; import org.hipparchus.CalculusFieldElement; import org.hipparchus.util.FastMath; - -/** Giacomo and Davis water vapor mode. - * - * See: Giacomo, P., Equation for the determination of the density of moist air, Metrologia, V. 18, 1982 +import org.orekit.utils.units.Unit; + +/** Official model CIPM-2007 (identical to CIPM-1981/91) from Comité International des Poids et Mesures. + *

              + * This water vapor model is the one from Giacomo and Davis as indicated in IERS TN 32, chap. 9. + *

              + * @see Revised + * formula for the density of moist air (CIPM-2007), Metrologia 45 (2008) 149–155 * - * @author Bryan Cazabonne * @author Luc Maisonobe * @since 12.1 */ -public class GiacomoDavis implements WaterVaporPressureProvider { +public class CIPM2007 implements WaterVaporPressureProvider { /** Saturation water vapor coefficient. */ private static final double E = 0.01; @@ -58,34 +61,32 @@ public class GiacomoDavis implements WaterVaporPressureProvider { /** {@inheritDoc} */ @Override - public double waterVaporPressure(final double t, final double p, final double rh) { + public double waterVaporPressure(final double p, final double t, final double rh) { - // saturation water vapor, equation (3) of reference paper, in mbar - // with amended 1991 values (see reference paper) - final double es = FastMath.exp(t * (t * L_P2 + L_P1) + L_0 + L_M1 / t) * E; + // saturation water vapor, equation A1.1 + final double psv = FastMath.exp(t * (t * L_P2 + L_P1) + L_0 + L_M1 / t) * E; - // enhancement factor, equation (4) of reference paper + // enhancement factor, equation A1.2 final double tC = t - CELSIUS; - final double fw = p * F_P + tC * tC * F_T2 + F_0; + final double fw = Unit.HECTO_PASCAL.fromSI(p) * F_P + tC * tC * F_T2 + F_0; - return rh * fw * es; + return Unit.HECTO_PASCAL.toSI(rh * fw * psv); } /** {@inheritDoc} */ @Override - public > T waterVaporPressure(final T t, final T p, final T rh) { + public > T waterVaporPressure(final T p, final T t, final T rh) { - // saturation water vapor, equation (3) of reference paper, in mbar - // with amended 1991 values (see reference paper) - final T es = FastMath.exp(t.multiply(t.multiply(L_P2).add(L_P1)).add(L_0).add(t.reciprocal().multiply(L_M1))). - multiply(E); + // saturation water vapor, equation A1.1 + final T psv = FastMath.exp(t.multiply(t.multiply(L_P2).add(L_P1)).add(L_0).add(t.reciprocal().multiply(L_M1))). + multiply(E); - // enhancement factor, equation (4) of reference paper + // enhancement factor, equation A1.2 final T tC = t.subtract(CELSIUS); - final T fw = p.multiply(F_P).add(tC.multiply(tC).multiply(F_T2)).add(F_0); + final T fw = Unit.HECTO_PASCAL.fromSI(p).multiply(F_P).add(tC.multiply(tC).multiply(F_T2)).add(F_0); - return rh.multiply(fw).multiply(es); + return Unit.HECTO_PASCAL.toSI(rh.multiply(fw).multiply(psv)); } diff --git a/src/main/java/org/orekit/models/earth/weather/water/WaterVaporPressureProvider.java b/src/main/java/org/orekit/models/earth/weather/water/WaterVaporPressureProvider.java index 0a6196afc3..b13ca25b05 100644 --- a/src/main/java/org/orekit/models/earth/weather/water/WaterVaporPressureProvider.java +++ b/src/main/java/org/orekit/models/earth/weather/water/WaterVaporPressureProvider.java @@ -25,21 +25,21 @@ public interface WaterVaporPressureProvider { /** Compute water vapor pressure. - * @param t temperature (Kelvin) * @param p pressure (Pa) + * @param t temperature (Kelvin) * @param rh relative humidity, in percent (50% → 0.5) * @return water vapor pressure (Pa) */ - double waterVaporPressure(double t, double p, double rh); + double waterVaporPressure(double p, double t, double rh); /** Compute water vapor pressure. - * @param type of the field elements - * @param t temperature (Kelvin) * @param p pressure (Pa) + * @param t temperature (Kelvin) * @param rh relative humidity, in percent (50% → 0.5) + * @param type of the field elements * @return water vapor pressure (Pa) */ - > T waterVaporPressure(T t, T p, T rh); + > T waterVaporPressure(T p, T t, T rh); } From b82a0ce22a94d0078f9f46bc002c956955a53bcb Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Fri, 8 Dec 2023 15:01:42 +0100 Subject: [PATCH 020/359] Set up specific units constants for tropospheric models. --- .../models/earth/troposphere/TropoUnit.java | 41 +++++++++++++++++++ .../models/earth/weather/water/CIPM2007.java | 10 ++--- .../java/org/orekit/utils/units/Unit.java | 5 --- .../java/org/orekit/utils/units/UnitTest.java | 1 - .../utils/units/UnitsConverterTest.java | 9 ++-- 5 files changed, 49 insertions(+), 17 deletions(-) create mode 100644 src/main/java/org/orekit/models/earth/troposphere/TropoUnit.java diff --git a/src/main/java/org/orekit/models/earth/troposphere/TropoUnit.java b/src/main/java/org/orekit/models/earth/troposphere/TropoUnit.java new file mode 100644 index 0000000000..36b713d9bf --- /dev/null +++ b/src/main/java/org/orekit/models/earth/troposphere/TropoUnit.java @@ -0,0 +1,41 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS Communication & Systèmes (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import org.orekit.utils.units.Unit; + +/** Units used in tropospheric models. + * @author Luc Maisonobe + * @since 12.1 + */ +public class TropoUnit { + + /** Nanometers unit. */ + public static final Unit NANO_M = Unit.parse("nm"); + + /** Micrometers unit. */ + public static final Unit MICRO_M = Unit.parse("µm"); + + /** HectoPascal unit. */ + public static final Unit HECTO_PASCAL = Unit.parse("hPa"); + + /** Private constructor for a constants class. */ + private TropoUnit() { + // nothing to do + } + +} diff --git a/src/main/java/org/orekit/models/earth/weather/water/CIPM2007.java b/src/main/java/org/orekit/models/earth/weather/water/CIPM2007.java index 16d42181fc..769119388a 100644 --- a/src/main/java/org/orekit/models/earth/weather/water/CIPM2007.java +++ b/src/main/java/org/orekit/models/earth/weather/water/CIPM2007.java @@ -18,7 +18,7 @@ import org.hipparchus.CalculusFieldElement; import org.hipparchus.util.FastMath; -import org.orekit.utils.units.Unit; +import org.orekit.models.earth.troposphere.TropoUnit; /** Official model CIPM-2007 (identical to CIPM-1981/91) from Comité International des Poids et Mesures. *

              @@ -68,9 +68,9 @@ public double waterVaporPressure(final double p, final double t, final double rh // enhancement factor, equation A1.2 final double tC = t - CELSIUS; - final double fw = Unit.HECTO_PASCAL.fromSI(p) * F_P + tC * tC * F_T2 + F_0; + final double fw = TropoUnit.HECTO_PASCAL.fromSI(p) * F_P + tC * tC * F_T2 + F_0; - return Unit.HECTO_PASCAL.toSI(rh * fw * psv); + return TropoUnit.HECTO_PASCAL.toSI(rh * fw * psv); } @@ -84,9 +84,9 @@ public > T waterVaporPressure(final T p, final // enhancement factor, equation A1.2 final T tC = t.subtract(CELSIUS); - final T fw = Unit.HECTO_PASCAL.fromSI(p).multiply(F_P).add(tC.multiply(tC).multiply(F_T2)).add(F_0); + final T fw = TropoUnit.HECTO_PASCAL.fromSI(p).multiply(F_P).add(tC.multiply(tC).multiply(F_T2)).add(F_0); - return Unit.HECTO_PASCAL.toSI(rh.multiply(fw).multiply(psv)); + return TropoUnit.HECTO_PASCAL.toSI(rh.multiply(fw).multiply(psv)); } diff --git a/src/main/java/org/orekit/utils/units/Unit.java b/src/main/java/org/orekit/utils/units/Unit.java index cb8bf25442..d1a3c6abd0 100644 --- a/src/main/java/org/orekit/utils/units/Unit.java +++ b/src/main/java/org/orekit/utils/units/Unit.java @@ -107,11 +107,6 @@ public class Unit implements Serializable { /** Pascal unit. */ public static final Unit PASCAL = NEWTON.divide("Pa", METRE.power(null, Fraction.TWO)); - /** HectoPascal unit. - * @since 12.1 - */ - public static final Unit HECTO_PASCAL = PASCAL.scale("hPa", 100.0); - /** Bar unit. */ public static final Unit BAR = PASCAL.scale("bar", 100000.0); diff --git a/src/test/java/org/orekit/utils/units/UnitTest.java b/src/test/java/org/orekit/utils/units/UnitTest.java index 8e8b1bcd68..e226828227 100644 --- a/src/test/java/org/orekit/utils/units/UnitTest.java +++ b/src/test/java/org/orekit/utils/units/UnitTest.java @@ -99,7 +99,6 @@ public void testReference() { checkReference(Unit.REVOLUTION, "rev", 2.0 * FastMath.PI, 0, 0, 0, 0, 1); checkReference(Unit.NEWTON, "N", 1.0, 1, 1, -2, 0, 0); checkReference(Unit.PASCAL, "Pa", 1.0, 1, -1, -2, 0, 0); - checkReference(Unit.HECTO_PASCAL, "hPa", 100.0, 1, -1, -2, 0, 0); checkReference(Unit.BAR, "bar", 100000.0, 1, -1, -2, 0, 0); checkReference(Unit.JOULE, "J", 1.0, 1, 2, -2, 0, 0); checkReference(Unit.WATT, "W", 1.0, 1, 2, -3, 0, 0); diff --git a/src/test/java/org/orekit/utils/units/UnitsConverterTest.java b/src/test/java/org/orekit/utils/units/UnitsConverterTest.java index 20fae6499c..83be61b10f 100644 --- a/src/test/java/org/orekit/utils/units/UnitsConverterTest.java +++ b/src/test/java/org/orekit/utils/units/UnitsConverterTest.java @@ -49,12 +49,9 @@ public void testRotationRate() { public void testPressure() { final double atm = 1013.25; final Unit mbar = Unit.parse("mbar"); - final Unit hPa1 = Unit.parse("hPa"); - final Unit hPa2 = Unit.HECTO_PASCAL; - final UnitsConverter mbar2hPa1 = new UnitsConverter(mbar, hPa1); - Assertions.assertEquals(atm, mbar2hPa1.convert(atm), 1.0e-12); - final UnitsConverter mbar2hPa2 = new UnitsConverter(mbar, hPa2); - Assertions.assertEquals(atm, mbar2hPa2.convert(atm), 1.0e-12); + final Unit hPa = Unit.parse("hPa"); + final UnitsConverter mbar2hPa = new UnitsConverter(mbar, hPa); + Assertions.assertEquals(atm, mbar2hPa.convert(atm), 1.0e-12); } @Test From 8115bc745d7faac4910e5471a4512ee984ccbad1 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Fri, 8 Dec 2023 15:02:09 +0100 Subject: [PATCH 021/359] Use explicit units for optical tropospheric models. --- .../earth/troposphere/MariniMurrayModel.java | 107 +++++--- .../earth/troposphere/MendesPavlisModel.java | 235 ++++++++++-------- .../FieldMendesPavlisModelTest.java | 33 ++- .../troposphere/MariniMurrayModelTest.java | 46 +++- .../troposphere/MendesPavlisModelTest.java | 91 ++++++- 5 files changed, 353 insertions(+), 159 deletions(-) diff --git a/src/main/java/org/orekit/models/earth/troposphere/MariniMurrayModel.java b/src/main/java/org/orekit/models/earth/troposphere/MariniMurrayModel.java index dc743acfaa..6f1df5c600 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/MariniMurrayModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/MariniMurrayModel.java @@ -23,12 +23,16 @@ import org.hipparchus.util.FastMath; import org.orekit.bodies.FieldGeodeticPoint; import org.orekit.bodies.GeodeticPoint; +import org.orekit.models.earth.weather.ConstantPressureTemperatureHumidityProvider; +import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; import org.orekit.models.earth.weather.PressureTemperatureHumidity; +import org.orekit.models.earth.weather.PressureTemperatureHumidityProvider; import org.orekit.models.earth.weather.water.CIPM2007; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; import org.orekit.utils.ParameterDriver; import org.orekit.utils.units.Unit; +import org.orekit.utils.units.UnitsConverter; /** The Marini-Murray tropospheric delay model for laser ranging. * @@ -39,11 +43,11 @@ */ public class MariniMurrayModel implements DiscreteTroposphericModel { - /** Pressure, temperature and humidity. */ - private PressureTemperatureHumidity pth; + /** Provider for pressure, temperature and humidity. */ + private PressureTemperatureHumidityProvider pthProvider; - /** Laser wavelength, micrometers. */ - private double lambda; + /** Laser frequency parameter. */ + private double fLambda; /** Create a new Marini-Murray model for the troposphere using the given * environmental conditions. @@ -51,21 +55,39 @@ public class MariniMurrayModel implements DiscreteTroposphericModel { * @param p0 the atmospheric pressure at the station, mbar * @param rh the humidity at the station, percent (50% -> 0.5) * @param lambda laser wavelength (c/f), nm + * @deprecated as of 12.1, replaced by {@link #MariniMurrayModel(PressureTemperatureHumidityProvider, double, Unit)} */ + @Deprecated public MariniMurrayModel(final double t0, final double p0, final double rh, final double lambda) { - this(new PressureTemperatureHumidity(Unit.HECTO_PASCAL.toSI(p0), - t0, - new CIPM2007().waterVaporPressure(Unit.HECTO_PASCAL.toSI(p0), t0, rh)), - lambda); + this(new ConstantPressureTemperatureHumidityProvider(new PressureTemperatureHumidity(TropoUnit.HECTO_PASCAL.toSI(p0), + t0, + new CIPM2007(). + waterVaporPressure(TropoUnit.HECTO_PASCAL.toSI(p0), + t0, + rh))), + lambda, TropoUnit.NANO_M); } /** Create a new Marini-Murray model for the troposphere. - * @param pth atmospheric pressure, temperature and humidity at the station - * @param lambda laser wavelength, nm + *

              + * BEWARE: this constructor uses + *

              + * @param pthProvider provider for atmospheric pressure, temperature and humidity at the station + * @param lambda laser wavelength + * @param lambdaUnits units in which {@code lambda} is given + * @see TropoUnit + * @since 12.1 * */ - public MariniMurrayModel(final PressureTemperatureHumidity pth, final double lambda) { - this.pth = pth; - this.lambda = lambda * 1.0e-3; + public MariniMurrayModel(final PressureTemperatureHumidityProvider pthProvider, + final double lambda, final Unit lambdaUnits) { + + this.pthProvider = pthProvider; + + // compute laser frequency parameter + final double lambdaMicrometer = new UnitsConverter(lambdaUnits, TropoUnit.MICRO_M).convert(lambda); + final double l2 = lambdaMicrometer * lambdaMicrometer; + fLambda = 0.9650 + (0.0164 + 0.000228 / l2) / l2; + } /** Create a new Marini-Murray model using a standard atmosphere model. @@ -79,14 +101,35 @@ public MariniMurrayModel(final PressureTemperatureHumidity pth, final double lam * @param lambda laser wavelength (c/f), nm * * @return a Marini-Murray model with standard environmental values + * @deprecated since 12.1, replaced by {@link #getStandardModel(double, Unit)} */ + @Deprecated public static MariniMurrayModel getStandardModel(final double lambda) { - final double p = Unit.HECTO_PASCAL.toSI(1013.25); + return getStandardModel(lambda, TropoUnit.NANO_M); + } + + /** Create a new Marini-Murray model using a standard atmosphere model. + * + *
                + *
              • temperature: 20 degree Celsius
              • + *
              • pressure: 1013.25 mbar
              • + *
              • humidity: 50%
              • + *
              + * + * @param lambda laser wavelength (c/f) + * @param lambdaUnits units in which {@code lambda} is given + * @return a Marini-Murray model with standard environmental values + * @see TropoUnit + * @since 12.1 + */ + public static MariniMurrayModel getStandardModel(final double lambda, final Unit lambdaUnits) { + final double p = TropoUnit.HECTO_PASCAL.toSI(1013.25); final double t = 273.15 + 20; final double rh = 0.5; - return new MariniMurrayModel(new PressureTemperatureHumidity(p, t, - new CIPM2007().waterVaporPressure(p, t, rh)), - lambda); + final PressureTemperatureHumidity pth = + new PressureTemperatureHumidity(p, t, new CIPM2007().waterVaporPressure(p, t, rh)); + return new MariniMurrayModel(new ConstantPressureTemperatureHumidityProvider(pth), + lambda, TropoUnit.NANO_M); } /** {@inheritDoc} */ @@ -94,6 +137,7 @@ public static MariniMurrayModel getStandardModel(final double lambda) { public double pathDelay(final double elevation, final GeodeticPoint point, final double[] parameters, final AbsoluteDate date) { + final PressureTemperatureHumidity pth = pthProvider.getWeatherParamerers(point, date); final double p = pth.getPressure(); final double t = pth.getTemperature(); final double e = pth.getWaterVaporPressure(); @@ -114,16 +158,21 @@ public double pathDelay(final double elevation, final GeodeticPoint point, /** {@inheritDoc} */ @Override public > T pathDelay(final T elevation, final FieldGeodeticPoint point, - final T[] parameters, final FieldAbsoluteDate date) { + final T[] parameters, final FieldAbsoluteDate date) { - final double p = pth.getPressure(); - final double t = pth.getTemperature(); - final double e = pth.getWaterVaporPressure(); + final FieldPressureTemperatureHumidity pth = pthProvider.getWeatherParamerers(point, date); + final T p = pth.getPressure(); + final T t = pth.getTemperature(); + final T e = pth.getWaterVaporPressure(); // beware since version 12.1 pressures are in Pa and not in hPa, hence the scaling has changed - final double A = 0.00002357 * p + 0.00000141 * e; - final T K = FastMath.cos(point.getLatitude().multiply(2.)).multiply(0.00968).negate().add(1.163).subtract(0.00104 * t).add(0.0000001435 * p); - final T B = K.multiply(1.084e-10 * p * t).add(K.multiply(2.).multiply(4.734e-12 * p * (p / t)).divide(K.multiply(3.).subtract(1.))); + final T A = p.multiply(0.00002357).add(e.multiply(0.00000141)); + final T K = FastMath.cos(point.getLatitude().multiply(2.)).multiply(0.00968).negate(). + add(1.163). + subtract(t.multiply(0.00104)). + add(p.multiply(0.0000001435)); + final T B = K.multiply(t.multiply(p).multiply(1.084e-10 )). + add(K.multiply(2.).multiply(p.multiply(p).divide(t).multiply(4.734e-12)).divide(K.multiply(3.).subtract(1.))); final double flambda = getLaserFrequencyParameter(); final T fsite = getSiteFunctionValue(point); @@ -146,23 +195,23 @@ public List getParametersDrivers() { * @return the laser frequency parameter f(lambda). */ private double getLaserFrequencyParameter() { - return 0.9650 + 0.0164 * FastMath.pow(lambda, -2) + 0.000228 * FastMath.pow(lambda, -4); + return fLambda; } - /** Get the laser frequency parameter f(lambda). + /** Get the site parameter. * * @param point station location - * @return the laser frequency parameter f(lambda). + * @return the site parameter. */ private double getSiteFunctionValue(final GeodeticPoint point) { return 1. - 0.0026 * FastMath.cos(2 * point.getLatitude()) - 0.00031 * 0.001 * point.getAltitude(); } - /** Get the laser frequency parameter f(lambda). + /** Get the site parameter. * * @param type of the elements * @param point station location - * @return the laser frequency parameter f(lambda). + * @return the site parameter. */ private > T getSiteFunctionValue(final FieldGeodeticPoint point) { return FastMath.cos(point.getLatitude().multiply(2)).multiply(0.0026).add(point.getAltitude().multiply(0.001).multiply(0.00031)).negate().add(1.); diff --git a/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java b/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java index aeea86f03f..174f45a06f 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java @@ -19,13 +19,16 @@ import java.util.Collections; import java.util.List; -import org.hipparchus.Field; import org.hipparchus.CalculusFieldElement; +import org.hipparchus.Field; import org.hipparchus.util.FastMath; import org.hipparchus.util.MathArrays; import org.orekit.bodies.FieldGeodeticPoint; import org.orekit.bodies.GeodeticPoint; +import org.orekit.models.earth.weather.ConstantPressureTemperatureHumidityProvider; +import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; import org.orekit.models.earth.weather.PressureTemperatureHumidity; +import org.orekit.models.earth.weather.PressureTemperatureHumidityProvider; import org.orekit.models.earth.weather.water.CIPM2007; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; @@ -65,11 +68,14 @@ public class MendesPavlisModel implements DiscreteTroposphericModel, MappingFunc /** Carbon dioxyde content (IAG recommendations). */ private static final double C02 = 0.99995995; - /** Laser wavelength [µm]. */ - private double lambda; + /** Dispersion equation for the hydrostatic component. */ + private double fLambdaH; + + /** Dispersion equation for the non-hydrostatic component. */ + private double fLambdaNH; - /** Pressure, temperature and humidity. */ - private PressureTemperatureHumidity pth; + /** Provider for pressure, temperature and humidity. */ + private PressureTemperatureHumidityProvider pthProvider; /** Create a new Mendes-Pavlis model for the troposphere. * This initialization will compute the water vapor pressure @@ -78,43 +84,93 @@ public class MendesPavlisModel implements DiscreteTroposphericModel, MappingFunc * @param p0 the atmospheric pressure at the station, hPa * @param rh the humidity at the station, percent (50% → 0.5) * @param lambda laser wavelength, µm - * */ + * @deprecated as of 12.1, replaced by {@link #MendesPavlisModel(PressureTemperatureHumidity, double, Unit)} + */ + @Deprecated public MendesPavlisModel(final double t0, final double p0, final double rh, final double lambda) { - this(new PressureTemperatureHumidity(Unit.HECTO_PASCAL.toSI(p0), - t0, - new CIPM2007().waterVaporPressure(Unit.HECTO_PASCAL.toSI(p0), t0, rh)), - lambda); + this(new ConstantPressureTemperatureHumidityProvider(new PressureTemperatureHumidity(TropoUnit.HECTO_PASCAL.toSI(p0), + t0, + new CIPM2007(). + waterVaporPressure(TropoUnit.HECTO_PASCAL.toSI(p0), + t0, + rh))), + lambda, TropoUnit.MICRO_M); } /** Create a new Mendes-Pavlis model for the troposphere. - * @param pth atmospheric pressure, temperature and humidity at the station - * @param lambda laser wavelength, µm + * @param pthProvider provider for atmospheric pressure, temperature and humidity at the station + * @param lambda laser wavelength + * @param lambdaUnits units in which {@code lambda} is given + * @see TropoUnit + * @since 12.1 * */ - public MendesPavlisModel(final PressureTemperatureHumidity pth, final double lambda) { - this.pth = pth; - this.lambda = lambda; + public MendesPavlisModel(final PressureTemperatureHumidityProvider pthProvider, + final double lambda, final Unit lambdaUnits) { + this.pthProvider = pthProvider; + + // Dispersion equation for the hydrostatic component + final double sigma = 1 / lambda; + final double sigma2 = sigma * sigma; + final double coef1 = K_COEFFICIENTS[0] + sigma2; + final double coef2 = K_COEFFICIENTS[0] - sigma2; + final double coef3 = K_COEFFICIENTS[2] + sigma2; + final double coef4 = K_COEFFICIENTS[2] - sigma2; + final double frac1 = coef1 / (coef2 * coef2); + final double frac2 = coef3 / (coef4 * coef4); + fLambdaH = 0.01 * (K_COEFFICIENTS[1] * frac1 + K_COEFFICIENTS[3] * frac2) * C02; + + // Dispersion equation for the non-hydrostatic component + final double sigma4 = sigma2 * sigma2; + final double sigma6 = sigma4 * sigma2; + final double w1s2 = 3 * W_COEFFICIENTS[1] * sigma2; + final double w2s4 = 5 * W_COEFFICIENTS[2] * sigma4; + final double w3s6 = 7 * W_COEFFICIENTS[3] * sigma6; + + fLambdaNH = 0.003101 * (W_COEFFICIENTS[0] + w1s2 + w2s4 + w3s6); + } /** Create a new Mendes-Pavlis model using a standard atmosphere model. * *
                - *
              • temperature: 18 degree Celsius - *
              • pressure: 1013.25 hPa - *
              • humidity: 50% + *
              • temperature: 18 degree Celsius
              • + *
              • pressure: 1013.25 hPa
              • + *
              • humidity: 50%
              • *
              * * @param lambda laser wavelength, µm * * @return a Mendes-Pavlis model with standard environmental values + * @deprecated as of 12.1, replaced by {@link #getStandardModel(double, Unit)} */ + @Deprecated public static MendesPavlisModel getStandardModel(final double lambda) { - final double p = Unit.HECTO_PASCAL.toSI(1013.25); + return getStandardModel(lambda, TropoUnit.MICRO_M); + } + + /** Create a new Mendes-Pavlis model using a standard atmosphere model. + * + *
                + *
              • temperature: 18 degree Celsius
              • + *
              • pressure: 1013.25 hPa
              • + *
              • humidity: 50%
              • + *
              + * + * @param lambda laser wavelength, µm + * @param lambdaUnits units in which {@code lambda} is given + * @return a Mendes-Pavlis model with standard environmental values + * @see TropoUnit + * @since 12.1 + */ + public static MendesPavlisModel getStandardModel(final double lambda, final Unit lambdaUnits) { + final double p = TropoUnit.HECTO_PASCAL.toSI(1013.25); final double t = 273.15 + 18; final double rh = 0.5; - return new MendesPavlisModel(new PressureTemperatureHumidity(p, t, - new CIPM2007().waterVaporPressure(p, t, rh)), - lambda); + final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(p, t, + new CIPM2007().waterVaporPressure(p, t, rh)); + return new MendesPavlisModel(new ConstantPressureTemperatureHumidityProvider(pth), + lambda, lambdaUnits); } /** {@inheritDoc} */ @@ -153,36 +209,16 @@ public > T pathDelay(final T elevation, final * @return a two components array containing the zenith hydrostatic and wet delays. */ public double[] computeZenithDelay(final GeodeticPoint point, final double[] parameters, final AbsoluteDate date) { + + final PressureTemperatureHumidity pth = pthProvider.getWeatherParamerers(point, date); final double fsite = getSiteFunctionValue(point); // Array for zenith delay final double[] delay = new double[2]; - // Dispertion Equation for the Hydrostatic component - final double sigma = 1 / lambda; - final double sigma2 = sigma * sigma; - final double coef1 = K_COEFFICIENTS[0] + sigma2; - final double coef2 = K_COEFFICIENTS[0] - sigma2; - final double coef3 = K_COEFFICIENTS[2] + sigma2; - final double coef4 = K_COEFFICIENTS[2] - sigma2; - - final double frac1 = coef1 / (coef2 * coef2); - final double frac2 = coef3 / (coef4 * coef4); - - final double fLambdaH = 0.01 * (K_COEFFICIENTS[1] * frac1 + K_COEFFICIENTS[3] * frac2) * C02; - // Zenith delay for the hydrostatic component // beware since version 12.1 pressure is in Pa and not in hPa, hence the scaling has changed - delay[0] = 0.00002416579 * (fLambdaH / fsite) * pth.getPressure(); - - // Dispertion Equation for the Non-Hydrostatic component - final double sigma4 = sigma2 * sigma2; - final double sigma6 = sigma4 * sigma2; - final double w1s2 = 3 * W_COEFFICIENTS[1] * sigma2; - final double w2s4 = 5 * W_COEFFICIENTS[2] * sigma4; - final double w3s6 = 7 * W_COEFFICIENTS[3] * sigma6; - - final double fLambdaNH = 0.003101 * (W_COEFFICIENTS[0] + w1s2 + w2s4 + w3s6); + delay[0] = pth.getPressure() * 0.00002416579 * (fLambdaH / fsite); // Zenith delay for the non-hydrostatic component // beware since version 12.1 e0 is in Pa and not in hPa, hence the scaling has changed @@ -205,46 +241,25 @@ public double[] computeZenithDelay(final GeodeticPoint point, final double[] par */ public > T[] computeZenithDelay(final FieldGeodeticPoint point, final T[] parameters, final FieldAbsoluteDate date) { - final Field field = date.getField(); - final T zero = field.getZero(); + + final FieldPressureTemperatureHumidity pth = pthProvider.getWeatherParamerers(point, date); final T fsite = getSiteFunctionValue(point); // Array for zenith delay - final T[] delay = MathArrays.buildArray(field, 2); - - // Dispertion Equation for the Hydrostatic component - final T sigma = zero.newInstance(1 / lambda); - final T sigma2 = sigma.multiply(sigma); - final T coef1 = sigma2.add(K_COEFFICIENTS[0]); - final T coef2 = sigma2.negate().add(K_COEFFICIENTS[0]); - final T coef3 = sigma2.add(K_COEFFICIENTS[2]); - final T coef4 = sigma2.negate().add(K_COEFFICIENTS[2]); - - final T frac1 = coef1.divide(coef2.multiply(coef2)); - final T frac2 = coef3.divide(coef4.multiply(coef4)); - - final T fLambdaH = frac1.multiply(K_COEFFICIENTS[1]).add(frac2.multiply(K_COEFFICIENTS[3])).multiply(0.01 * C02); + final T[] delay = MathArrays.buildArray(date.getField(), 2); // Zenith delay for the hydrostatic component // beware since version 12.1 pressure is in Pa and not in hPa, hence the scaling has changed - delay[0] = fLambdaH.divide(fsite).multiply(pth.getPressure()).multiply(0.00002416579); - - // Dispertion Equation for the Non-Hydrostatic component - final T sigma4 = sigma2.multiply(sigma2); - final T sigma6 = sigma4.multiply(sigma2); - final T w1s2 = sigma2.multiply(3 * W_COEFFICIENTS[1]); - final T w2s4 = sigma4.multiply(5 * W_COEFFICIENTS[2]); - final T w3s6 = sigma6.multiply(7 * W_COEFFICIENTS[3]); - - final T fLambdaNH = w1s2.add(w2s4).add(w3s6).add(W_COEFFICIENTS[0]).multiply(0.003101); + delay[0] = pth.getPressure().multiply(0.00002416579).multiply(fLambdaH).divide(fsite); // Zenith delay for the non-hydrostatic component // beware since version 12.1 e0 is in Pa and not in hPa, hence the scaling has changed - delay[1] = fLambdaNH.multiply(5.316).subtract(fLambdaH.multiply(3.759)). - multiply(fsite.divide(pth.getWaterVaporPressure()).reciprocal()).multiply(0.000001); + delay[1] = pth.getWaterVaporPressure().divide(fsite). + multiply(0.000001 * (5.316 * fLambdaNH - 3.759 * fLambdaH)); return delay; + } /** With the Mendes Pavlis tropospheric model, the mapping @@ -265,6 +280,7 @@ public double[] mappingFactors(final double elevation, final GeodeticPoint point final AbsoluteDate date) { final double sinE = FastMath.sin(elevation); + final PressureTemperatureHumidity pth = pthProvider.getWeatherParamerers(point, date); final double T2degree = pth.getTemperature() - 273.15; // Mapping function coefficients @@ -311,7 +327,8 @@ public > T[] mappingFactors(final T elevation, final T sinE = FastMath.sin(elevation); - final double T2degree = pth.getTemperature() - 273.15; + final FieldPressureTemperatureHumidity pth = pthProvider.getWeatherParamerers(point, date); + final T T2degree = pth.getTemperature().subtract(273.15); // Mapping function coefficients final T a1 = computeMFCoeffient(A_COEFFICIENTS[0][0], A_COEFFICIENTS[0][1], @@ -344,54 +361,54 @@ public List getParametersDrivers() { return Collections.emptyList(); } - /** Get the laser frequency parameter f(lambda). - * - * @param point station location - * @return the laser frequency parameter f(lambda). - */ + /** Get the site parameter. + * + * @param point station location + * @return the site parameter. + */ private double getSiteFunctionValue(final GeodeticPoint point) { return 1. - 0.00266 * FastMath.cos(2. * point.getLatitude()) - 0.00000028 * point.getAltitude(); } - /** Get the laser frequency parameter f(lambda). - * - * @param type of the elements - * @param point station location - * @return the laser frequency parameter f(lambda). - */ + /** Get the site parameter. + * + * @param type of the elements + * @param point station location + * @return the site parameter. + */ private > T getSiteFunctionValue(final FieldGeodeticPoint point) { return FastMath.cos(point.getLatitude().multiply(2.)).multiply(0.00266).add(point.getAltitude().multiply(0.00000028)).negate().add(1.); } /** Compute the coefficients of the Mapping Function. - * - * @param T the temperature at the station site, °C - * @param a0 first coefficient - * @param a1 second coefficient - * @param a2 third coefficient - * @param a3 fourth coefficient - * @param point station location - * @return the value of the coefficient - */ + * + * @param t the temperature at the station site, °C + * @param a0 first coefficient + * @param a1 second coefficient + * @param a2 third coefficient + * @param a3 fourth coefficient + * @param point station location + * @return the value of the coefficient + */ private double computeMFCoeffient(final double a0, final double a1, final double a2, final double a3, - final double T, final GeodeticPoint point) { - return a0 + a1 * T + a2 * FastMath.cos(point.getLatitude()) + a3 * point.getAltitude(); + final double t, final GeodeticPoint point) { + return a0 + a1 * t + a2 * FastMath.cos(point.getLatitude()) + a3 * point.getAltitude(); } - /** Compute the coefficients of the Mapping Function. - * - * @param type of the elements - * @param T the temperature at the station site, °C - * @param a0 first coefficient - * @param a1 second coefficient - * @param a2 third coefficient - * @param a3 fourth coefficient - * @param point station location - * @return the value of the coefficient - */ + /** Compute the coefficients of the Mapping Function. + * + * @param type of the elements + * @param t the temperature at the station site, °C + * @param a0 first coefficient + * @param a1 second coefficient + * @param a2 third coefficient + * @param a3 fourth coefficient + * @param point station location + * @return the value of the coefficient + */ private > T computeMFCoeffient(final double a0, final double a1, final double a2, final double a3, - final double T, final FieldGeodeticPoint point) { - return point.getAltitude().multiply(a3).add(FastMath.cos(point.getLatitude()).multiply(a2)).add(a0 + a1 * T); + final T t, final FieldGeodeticPoint point) { + return point.getAltitude().multiply(a3).add(FastMath.cos(point.getLatitude()).multiply(a2)).add(t.multiply(a1).add(a0)); } } diff --git a/src/test/java/org/orekit/models/earth/troposphere/FieldMendesPavlisModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/FieldMendesPavlisModelTest.java index dcec1a47df..d268e8caef 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/FieldMendesPavlisModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/FieldMendesPavlisModelTest.java @@ -39,6 +39,9 @@ import org.orekit.frames.Frame; import org.orekit.frames.FramesFactory; import org.orekit.frames.TopocentricFrame; +import org.orekit.models.earth.weather.ConstantPressureTemperatureHumidityProvider; +import org.orekit.models.earth.weather.PressureTemperatureHumidity; +import org.orekit.models.earth.weather.water.CIPM2007; import org.orekit.orbits.FieldKeplerianOrbit; import org.orekit.orbits.FieldOrbit; import org.orekit.orbits.Orbit; @@ -90,9 +93,15 @@ private > void doTestZenithDelay(final Field point = new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), zero.add(height)); @@ -107,8 +116,8 @@ private > void doTestZenithDelay(final Field date = new FieldAbsoluteDate<>(field, 2009, 8, 12, TimeScalesFactory.getUTC()); - final MendesPavlisModel model = new MendesPavlisModel(temperature, pressure, - humidity, lambda); + final MendesPavlisModel model = new MendesPavlisModel(new ConstantPressureTemperatureHumidityProvider(pth), + lambda, TropoUnit.MICRO_M); final T[] computedDelay = model.computeZenithDelay(point, model.getParameters(field), date); @@ -144,9 +153,15 @@ private > void doTestMappingFactors(final Fiel final double latitude = FastMath.toRadians(30.67166667); final double longitude = FastMath.toRadians(-104.0250); final double height = 2075; - final double pressure = 798.4188; + final double pressure = TropoUnit.HECTO_PASCAL.toSI(798.4188); final double temperature = 300.15; final double humidity = 0.4; + final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(pressure, + temperature, + new CIPM2007(). + waterVaporPressure(pressure, + temperature, + humidity)); final double lambda = 0.532; final FieldGeodeticPoint point = new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), zero.add(height)); @@ -155,8 +170,8 @@ private > void doTestMappingFactors(final Fiel final double expectedMapping = 3.80024367; // Test for the second constructor - final MendesPavlisModel model = new MendesPavlisModel(temperature, pressure, - humidity, lambda); + final MendesPavlisModel model = new MendesPavlisModel(new ConstantPressureTemperatureHumidityProvider(pth), + lambda, TropoUnit.MICRO_M); final T[] computedMapping = model.mappingFactors(zero.add(elevation), point, date); @@ -175,7 +190,7 @@ private > void doTestDelay(final Field fiel final double height = 100d; final FieldAbsoluteDate date = new FieldAbsoluteDate<>(field); final FieldGeodeticPoint point = new FieldGeodeticPoint<>(zero.add(FastMath.toRadians(45.0)), zero.add(FastMath.toRadians(45.0)), zero.add(height)); - MendesPavlisModel model = MendesPavlisModel.getStandardModel(0.6943); + MendesPavlisModel model = MendesPavlisModel.getStandardModel(0.6943, TropoUnit.MICRO_M); final T path = model.pathDelay(zero.add(FastMath.toRadians(elevation)), point, model.getParameters(field), date); Assertions.assertTrue(Precision.compareTo(path.getReal(), 20d, epsilon) < 0); Assertions.assertTrue(Precision.compareTo(path.getReal(), 0d, epsilon) > 0); @@ -190,7 +205,7 @@ private > void doTestFixedHeight(final Field date = new FieldAbsoluteDate<>(field); final FieldGeodeticPoint point = new FieldGeodeticPoint<>(zero.add(FastMath.toRadians(45.0)), zero.add(FastMath.toRadians(45.0)), zero.add(350.0)); - MendesPavlisModel model = MendesPavlisModel.getStandardModel(0.6943); + MendesPavlisModel model = MendesPavlisModel.getStandardModel(0.6943, TropoUnit.MICRO_M); T lastDelay = zero.add(Double.MAX_VALUE); // delay shall decline with increasing elevation angle for (double elev = 10d; elev < 90d; elev += 8d) { @@ -219,7 +234,7 @@ public void testDelayStateDerivatives() { final GroundStation station = new GroundStation(baseFrame); // Tropospheric model - final MendesPavlisModel model = MendesPavlisModel.getStandardModel(0.65); + final MendesPavlisModel model = MendesPavlisModel.getStandardModel(0.65, TropoUnit.MICRO_M); // Derivative Structure final DSFactory factory = new DSFactory(6, 1); diff --git a/src/test/java/org/orekit/models/earth/troposphere/MariniMurrayModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/MariniMurrayModelTest.java index 07cd3151c3..b8fc187c66 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/MariniMurrayModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/MariniMurrayModelTest.java @@ -35,8 +35,6 @@ public class MariniMurrayModelTest { private static double epsilon = 1e-6; - private DiscreteTroposphericModel model; - private double latitude; private double longitude; @@ -48,8 +46,6 @@ public static void setUpGlobal() { @BeforeEach public void setUp() throws Exception { - // ruby laser with wavelength 694.3 nm - model = MariniMurrayModel.getStandardModel(694.3); latitude = FastMath.toRadians(45.0); longitude = FastMath.toRadians(45.0); } @@ -59,6 +55,36 @@ public void testDelay() { final double elevation = 10d; final double height = 100d; + // ruby laser with wavelength 694.3 nm + DiscreteTroposphericModel model = MariniMurrayModel.getStandardModel(694.3, TropoUnit.NANO_M); + final double path = model.pathDelay(FastMath.toRadians(elevation), new GeodeticPoint(latitude, longitude, height), null, AbsoluteDate.J2000_EPOCH); + + Assertions.assertTrue(Precision.compareTo(path, 20d, epsilon) < 0); + Assertions.assertTrue(Precision.compareTo(path, 0d, epsilon) > 0); + } + + @Deprecated + @Test + public void testDeprecatedConstructor1() { + final double elevation = 10d; + final double height = 100d; + + // ruby laser with wavelength 694.3 nm + DiscreteTroposphericModel model = MariniMurrayModel.getStandardModel(694.3); + final double path = model.pathDelay(FastMath.toRadians(elevation), new GeodeticPoint(latitude, longitude, height), null, AbsoluteDate.J2000_EPOCH); + + Assertions.assertTrue(Precision.compareTo(path, 20d, epsilon) < 0); + Assertions.assertTrue(Precision.compareTo(path, 0d, epsilon) > 0); + } + + @Deprecated + @Test + public void testDeprecatedConstructor2() { + final double elevation = 10d; + final double height = 100d; + + // ruby laser with wavelength 694.3 nm + DiscreteTroposphericModel model = new MariniMurrayModel(273.15 + 20, 1013.25, 0.5, 694.3); final double path = model.pathDelay(FastMath.toRadians(elevation), new GeodeticPoint(latitude, longitude, height), null, AbsoluteDate.J2000_EPOCH); Assertions.assertTrue(Precision.compareTo(path, 20d, epsilon) < 0); @@ -75,6 +101,8 @@ private > void doTestFieldDelay(final Field final T elevation = zero.add(FastMath.toRadians(10d)); final T height = zero.add(100d); + // ruby laser with wavelength 694.3 nm + DiscreteTroposphericModel model = MariniMurrayModel.getStandardModel(694.3, TropoUnit.NANO_M); final T path = model.pathDelay(elevation, new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), height), null, FieldAbsoluteDate.getJ2000Epoch(field)); Assertions.assertTrue(Precision.compareTo(path.getReal(), 20d, epsilon) < 0); @@ -83,6 +111,8 @@ private > void doTestFieldDelay(final Field @Test public void testFixedHeight() { + // ruby laser with wavelength 694.3 nm + DiscreteTroposphericModel model = MariniMurrayModel.getStandardModel(694.3, TropoUnit.NANO_M); double lastDelay = Double.MAX_VALUE; // delay shall decline with increasing elevation angle for (double elev = 10d; elev < 90d; elev += 8d) { @@ -98,6 +128,8 @@ public void testFieldFixedHeight() { } private > void doTestFieldFixedHeight(final Field field) { + // ruby laser with wavelength 694.3 nm + DiscreteTroposphericModel model = MariniMurrayModel.getStandardModel(694.3, TropoUnit.NANO_M); final T zero = field.getZero(); T lastDelay = zero.add(Double.MAX_VALUE); // delay shall decline with increasing elevation angle @@ -111,6 +143,9 @@ private > void doTestFieldFixedHeight(final Fi @Test public void compareExpectedValues() { + // ruby laser with wavelength 694.3 nm + DiscreteTroposphericModel model = MariniMurrayModel.getStandardModel(694.3, TropoUnit.NANO_M); + double height = 0; double elevation = 10; double expectedValue = 13.26069; @@ -126,6 +161,9 @@ public void compareFieldExpectedValue() { private > void doCompareFieldExpectedValues(final Field field) { + // ruby laser with wavelength 694.3 nm + DiscreteTroposphericModel model = MariniMurrayModel.getStandardModel(694.3, TropoUnit.NANO_M); + T zero = field.getZero(); T height = zero; T elevation = zero.add(FastMath.toRadians(10)); diff --git a/src/test/java/org/orekit/models/earth/troposphere/MendesPavlisModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/MendesPavlisModelTest.java index d6d2de8f54..8174b02431 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/MendesPavlisModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/MendesPavlisModelTest.java @@ -25,6 +25,9 @@ import org.orekit.Utils; import org.orekit.bodies.GeodeticPoint; import org.orekit.errors.OrekitException; +import org.orekit.models.earth.weather.ConstantPressureTemperatureHumidityProvider; +import org.orekit.models.earth.weather.PressureTemperatureHumidity; +import org.orekit.models.earth.weather.water.CIPM2007; import org.orekit.time.AbsoluteDate; import org.orekit.time.TimeScalesFactory; @@ -63,9 +66,15 @@ public void testZenithDelay() { final double latitude = FastMath.toRadians(30.67166667); final double longitude = FastMath.toRadians(-104.0250); final double height = 2010.344; - final double pressure = 798.4188; + final double pressure = TropoUnit.HECTO_PASCAL.toSI(798.4188); final double temperature = 300.15; final double humidity = 0.4; + final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(pressure, + temperature, + new CIPM2007(). + waterVaporPressure(pressure, + temperature, + humidity)); final double lambda = 0.532; final GeodeticPoint point = new GeodeticPoint(latitude, longitude, height); @@ -80,8 +89,8 @@ public void testZenithDelay() { final AbsoluteDate date = new AbsoluteDate(2009, 8, 12, TimeScalesFactory.getUTC()); - final MendesPavlisModel model = new MendesPavlisModel(temperature, pressure, - humidity, lambda); + final MendesPavlisModel model = new MendesPavlisModel(new ConstantPressureTemperatureHumidityProvider(pth), + lambda, TropoUnit.MICRO_M); final double[] computedDelay = model.computeZenithDelay(point, model.getParameters(), date); @@ -112,9 +121,15 @@ public void testMappingFactors() { final double latitude = FastMath.toRadians(30.67166667); final double longitude = FastMath.toRadians(-104.0250); final double height = 2075; - final double pressure = 798.4188; + final double pressure = TropoUnit.HECTO_PASCAL.toSI(798.4188); final double temperature = 300.15; final double humidity = 0.4; + final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(pressure, + temperature, + new CIPM2007(). + waterVaporPressure(pressure, + temperature, + humidity)); final double lambda = 0.532; final GeodeticPoint point = new GeodeticPoint(latitude, longitude, height); @@ -123,8 +138,8 @@ public void testMappingFactors() { final double expectedMapping = 3.80024367; // Test for the second constructor - final MendesPavlisModel model = new MendesPavlisModel(temperature, pressure, - humidity, lambda); + final MendesPavlisModel model = new MendesPavlisModel(new ConstantPressureTemperatureHumidityProvider(pth), + lambda, TropoUnit.MICRO_M); final double[] computedMapping = model.mappingFactors(elevation, point, date); @@ -138,7 +153,7 @@ public void testDelay() { final double height = 100d; final AbsoluteDate date = new AbsoluteDate(); final GeodeticPoint point = new GeodeticPoint(FastMath.toRadians(45.0), FastMath.toRadians(45.0), height); - MendesPavlisModel model = MendesPavlisModel.getStandardModel( 0.6943); + MendesPavlisModel model = MendesPavlisModel.getStandardModel( 0.6943, TropoUnit.MICRO_M); final double path = model.pathDelay(FastMath.toRadians(elevation), point, model.getParameters(), date); Assertions.assertTrue(Precision.compareTo(path, 20d, epsilon) < 0); Assertions.assertTrue(Precision.compareTo(path, 0d, epsilon) > 0); @@ -148,7 +163,7 @@ public void testDelay() { public void testFixedHeight() { final AbsoluteDate date = new AbsoluteDate(); final GeodeticPoint point = new GeodeticPoint(FastMath.toRadians(45.0), FastMath.toRadians(45.0), 350.0); - MendesPavlisModel model = MendesPavlisModel.getStandardModel(0.6943); + MendesPavlisModel model = MendesPavlisModel.getStandardModel(0.6943, TropoUnit.MICRO_M); double lastDelay = Double.MAX_VALUE; // delay shall decline with increasing elevation angle for (double elev = 10d; elev < 90d; elev += 8d) { @@ -158,4 +173,64 @@ public void testFixedHeight() { } } + @Deprecated + @Test + public void testDeprecatedConstructor1() { + + // Site: McDonald Observatory + // latitude: 30.67166667 ° + // longitude: -104.0250 ° + // height: 2010.344 m + // + // Meteo: pressure: 798.4188 hPa + // water vapor presure: 14.322 hPa + // temperature: 300.15 K + // humidity: 40 % + // + // Ref: Petit, G. and Luzum, B. (eds.), IERS Conventions (2010), + // IERS Technical Note No. 36, BKG (2010) + + final double latitude = FastMath.toRadians(30.67166667); + final double longitude = FastMath.toRadians(-104.0250); + final double height = 2010.344; + final double pressure = 798.4188; + final double temperature = 300.15; + final double humidity = 0.4; + final double lambda = 0.532; + final GeodeticPoint point = new GeodeticPoint(latitude, longitude, height); + + // Expected zenith hydrostatic delay: 1.932992 m (Ref) + final double expectedHydroDelay = 1.932992; + // Expected zenith wet delay: 0.223375*10-2 m (Ref) + final double expectedWetDelay = 0.223375e-2; + // Expected total zenith delay: 1.935226 m (Ref) + final double expectedDelay = 1.935226; + + final double precision = 4.0e-6; + + final AbsoluteDate date = new AbsoluteDate(2009, 8, 12, TimeScalesFactory.getUTC()); + + final MendesPavlisModel model = new MendesPavlisModel(temperature, pressure, humidity, lambda); + + final double[] computedDelay = model.computeZenithDelay(point, model.getParameters(), date); + + Assertions.assertEquals(expectedHydroDelay, computedDelay[0], precision); + Assertions.assertEquals(expectedWetDelay, computedDelay[1], precision); + Assertions.assertEquals(expectedDelay, computedDelay[0] + computedDelay[1], precision); + + } + + @Deprecated + @Test + public void testDeprecatedConstructor2() { + final double elevation = 10d; + final double height = 100d; + final AbsoluteDate date = new AbsoluteDate(); + final GeodeticPoint point = new GeodeticPoint(FastMath.toRadians(45.0), FastMath.toRadians(45.0), height); + MendesPavlisModel model = MendesPavlisModel.getStandardModel( 0.6943); + final double path = model.pathDelay(FastMath.toRadians(elevation), point, model.getParameters(), date); + Assertions.assertTrue(Precision.compareTo(path, 20d, epsilon) < 0); + Assertions.assertTrue(Precision.compareTo(path, 0d, epsilon) > 0); + } + } From ac40fa0c83ec0e516aefa437a6d4553b9a347245 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Fri, 8 Dec 2023 17:09:13 +0100 Subject: [PATCH 022/359] Store relative humidity in addition to water vapor pressure. --- .../models/earth/troposphere/MariniMurrayModel.java | 3 ++- .../models/earth/troposphere/MendesPavlisModel.java | 3 ++- ...ConstantPressureTemperatureHumidityProvider.java | 3 ++- .../weather/FieldPressureTemperatureHumidity.java | 13 +++++++++++++ .../earth/weather/PressureTemperatureHumidity.java | 13 +++++++++++++ .../troposphere/FieldMendesPavlisModelTest.java | 2 ++ .../earth/troposphere/MendesPavlisModelTest.java | 2 ++ 7 files changed, 36 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/orekit/models/earth/troposphere/MariniMurrayModel.java b/src/main/java/org/orekit/models/earth/troposphere/MariniMurrayModel.java index 6f1df5c600..bc92e099fc 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/MariniMurrayModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/MariniMurrayModel.java @@ -61,6 +61,7 @@ public class MariniMurrayModel implements DiscreteTroposphericModel { public MariniMurrayModel(final double t0, final double p0, final double rh, final double lambda) { this(new ConstantPressureTemperatureHumidityProvider(new PressureTemperatureHumidity(TropoUnit.HECTO_PASCAL.toSI(p0), t0, + rh, new CIPM2007(). waterVaporPressure(TropoUnit.HECTO_PASCAL.toSI(p0), t0, @@ -127,7 +128,7 @@ public static MariniMurrayModel getStandardModel(final double lambda, final Unit final double t = 273.15 + 20; final double rh = 0.5; final PressureTemperatureHumidity pth = - new PressureTemperatureHumidity(p, t, new CIPM2007().waterVaporPressure(p, t, rh)); + new PressureTemperatureHumidity(p, t, rh, new CIPM2007().waterVaporPressure(p, t, rh)); return new MariniMurrayModel(new ConstantPressureTemperatureHumidityProvider(pth), lambda, TropoUnit.NANO_M); } diff --git a/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java b/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java index 174f45a06f..f1be3f5cdd 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java @@ -91,6 +91,7 @@ public MendesPavlisModel(final double t0, final double p0, final double rh, final double lambda) { this(new ConstantPressureTemperatureHumidityProvider(new PressureTemperatureHumidity(TropoUnit.HECTO_PASCAL.toSI(p0), t0, + rh, new CIPM2007(). waterVaporPressure(TropoUnit.HECTO_PASCAL.toSI(p0), t0, @@ -167,7 +168,7 @@ public static MendesPavlisModel getStandardModel(final double lambda, final Unit final double p = TropoUnit.HECTO_PASCAL.toSI(1013.25); final double t = 273.15 + 18; final double rh = 0.5; - final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(p, t, + final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(p, t, rh, new CIPM2007().waterVaporPressure(p, t, rh)); return new MendesPavlisModel(new ConstantPressureTemperatureHumidityProvider(pth), lambda, lambdaUnits); diff --git a/src/main/java/org/orekit/models/earth/weather/ConstantPressureTemperatureHumidityProvider.java b/src/main/java/org/orekit/models/earth/weather/ConstantPressureTemperatureHumidityProvider.java index f6d0acb422..b20d25430b 100644 --- a/src/main/java/org/orekit/models/earth/weather/ConstantPressureTemperatureHumidityProvider.java +++ b/src/main/java/org/orekit/models/earth/weather/ConstantPressureTemperatureHumidityProvider.java @@ -47,11 +47,12 @@ public PressureTemperatureHumidity getWeatherParamerers(final GeodeticPoint loca /** {@inheritDoc} */ @Override - public > FieldPressureTemperatureHumidity getWeatherParamerers(final FieldGeodeticPoint location, + public > FieldPressureTemperatureHumidity getWeatherParamerers(final FieldGeodeticPoint location, final FieldAbsoluteDate date) { final T zero = date.getField().getZero(); return new FieldPressureTemperatureHumidity<>(zero.newInstance(pth.getPressure()), zero.newInstance(pth.getTemperature()), + zero.newInstance(pth.getRelativeHumidity()), zero.newInstance(pth.getWaterVaporPressure())); } diff --git a/src/main/java/org/orekit/models/earth/weather/FieldPressureTemperatureHumidity.java b/src/main/java/org/orekit/models/earth/weather/FieldPressureTemperatureHumidity.java index 9349a725d5..ba2c2c15cc 100644 --- a/src/main/java/org/orekit/models/earth/weather/FieldPressureTemperatureHumidity.java +++ b/src/main/java/org/orekit/models/earth/weather/FieldPressureTemperatureHumidity.java @@ -31,19 +31,25 @@ public class FieldPressureTemperatureHumidity> /** Temperature (Kelvin). */ private final T temperature; + /** Humidity as relative humididy (50% → 0.5). */ + private final T relativeHumidity; + /** Humidity as water vapor pressure (Pa). */ private final T waterVaporPressure; /** Simple constructor. * @param pressure pressure (Pa) * @param temperature temperature (Kelvin) + * @param relativeHumidity humidity as relative humididy (50% → 0.5) * @param waterVaporPressure humidity as water vapor pressure (Pa) */ public FieldPressureTemperatureHumidity(final T pressure, final T temperature, + final T relativeHumidity, final T waterVaporPressure) { this.pressure = pressure; this.temperature = temperature; + this.relativeHumidity = relativeHumidity; this.waterVaporPressure = waterVaporPressure; } @@ -61,6 +67,13 @@ public T getTemperature() { return temperature; } + /** Get humidity as relative humididy (50% → 0.5). + * @return humidity as relative humididy (50% → 0.5) + */ + public T getRelativeHumidity() { + return relativeHumidity; + } + /** Get humidity as water vapor pressure. * @return humidity as water vapor pressure (Pa) */ diff --git a/src/main/java/org/orekit/models/earth/weather/PressureTemperatureHumidity.java b/src/main/java/org/orekit/models/earth/weather/PressureTemperatureHumidity.java index d355d6d90f..97979cba82 100644 --- a/src/main/java/org/orekit/models/earth/weather/PressureTemperatureHumidity.java +++ b/src/main/java/org/orekit/models/earth/weather/PressureTemperatureHumidity.java @@ -28,19 +28,25 @@ public class PressureTemperatureHumidity { /** Temperature (Kelvin). */ private final double temperature; + /** Humidity as relative humididy (50% → 0.5). */ + private final double relativeHumidity; + /** Humidity as water vapor pressure (Pa). */ private final double waterVaporPressure; /** Simple constructor. * @param pressure pressure (Pa) * @param temperature temperature (Kelvin) + * @param relativeHumidity humidity as relative humididy (50% → 0.5) * @param waterVaporPressure humidity as water vapor pressure (Pa) */ public PressureTemperatureHumidity(final double pressure, final double temperature, + final double relativeHumidity, final double waterVaporPressure) { this.pressure = pressure; this.temperature = temperature; + this.relativeHumidity = relativeHumidity; this.waterVaporPressure = waterVaporPressure; } @@ -58,6 +64,13 @@ public double getTemperature() { return temperature; } + /** Get humidity as relative humididy (50% → 0.5). + * @return humidity as relative humididy (50% → 0.5) + */ + public double getRelativeHumidity() { + return relativeHumidity; + } + /** Get humidity as water vapor pressure. * @return humidity as water vapor pressure (Pa) */ diff --git a/src/test/java/org/orekit/models/earth/troposphere/FieldMendesPavlisModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/FieldMendesPavlisModelTest.java index d268e8caef..73079aed54 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/FieldMendesPavlisModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/FieldMendesPavlisModelTest.java @@ -98,6 +98,7 @@ private > void doTestZenithDelay(final Field> void doTestMappingFactors(final Fiel final double humidity = 0.4; final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(pressure, temperature, + humidity, new CIPM2007(). waterVaporPressure(pressure, temperature, diff --git a/src/test/java/org/orekit/models/earth/troposphere/MendesPavlisModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/MendesPavlisModelTest.java index 8174b02431..7f8e80feca 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/MendesPavlisModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/MendesPavlisModelTest.java @@ -71,6 +71,7 @@ public void testZenithDelay() { final double humidity = 0.4; final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(pressure, temperature, + humidity, new CIPM2007(). waterVaporPressure(pressure, temperature, @@ -126,6 +127,7 @@ public void testMappingFactors() { final double humidity = 0.4; final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(pressure, temperature, + humidity, new CIPM2007(). waterVaporPressure(pressure, temperature, From 8073b88b04a452c91876035318dba5aca29517fc Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Fri, 8 Dec 2023 17:09:46 +0100 Subject: [PATCH 023/359] Use PressionTemperatureHumidityProvider in Saastamoinen. --- .../EstimatedTroposphericModel.java | 41 +++-- .../ModifiedSaastamoinenModel.java | 172 ++++++++---------- .../earth/troposphere/SaastamoinenModel.java | 15 +- .../models/earth/weather/water/Wang1988.java | 54 ++++++ .../ModifiedSaastamoinenModelTest.java | 41 +++-- 5 files changed, 188 insertions(+), 135 deletions(-) create mode 100644 src/main/java/org/orekit/models/earth/weather/water/Wang1988.java diff --git a/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java b/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java index 90749f2e7e..cab54dab80 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java @@ -23,6 +23,8 @@ import org.hipparchus.util.FastMath; import org.orekit.bodies.FieldGeodeticPoint; import org.orekit.bodies.GeodeticPoint; +import org.orekit.models.earth.weather.ConstantPressureTemperatureHumidityProvider; +import org.orekit.models.earth.weather.PressureTemperatureHumidity; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; import org.orekit.utils.ParameterDriver; @@ -45,8 +47,10 @@ * the {@link GlobalMappingFunctionModel Global Mapping Function}, or * the {@link NiellMappingFunctionModel Niell Mapping Function} *

              - * The tropospheric zenith delay δh is computed empirically with a {@link ModifiedSaastamoinenModel} - * while the tropospheric total zenith delay δt is estimated as a {@link ParameterDriver} + * The tropospheric zenith delay δh is computed empirically with a + * {@link DiscreteTroposphericModel tropospheric model} + * while the tropospheric total zenith delay δt is estimated as a {@link ParameterDriver}, + * hence the wet part is the difference between the two. */ public class EstimatedTroposphericModel implements DiscreteTroposphericModel { @@ -59,13 +63,13 @@ public class EstimatedTroposphericModel implements DiscreteTroposphericModel { /** Driver for the tropospheric zenith total delay.*/ private final ParameterDriver totalZenithDelay; - /** The temperature at the station [K]. */ - private double t0; - - /** The atmospheric pressure [mbar]. */ - private double p0; + /** Model for hydrostatic component. */ + private final DiscreteTroposphericModel hydrostatic; /** Build a new instance using the given environmental conditions. + *

              + * This constructor uses a {@link ModifiedSaastamoinenModel} for the hydrostatic contribution. + *

              * @param t0 the temperature at the station [K] * @param p0 the atmospheric pressure at the station [mbar] * @param model mapping function model (NMF or GMF). @@ -73,12 +77,23 @@ public class EstimatedTroposphericModel implements DiscreteTroposphericModel { */ public EstimatedTroposphericModel(final double t0, final double p0, final MappingFunction model, final double totalDelay) { + this(new ModifiedSaastamoinenModel(new ConstantPressureTemperatureHumidityProvider(new PressureTemperatureHumidity(p0, t0, 0.0, 0.0))), + model, totalDelay); + } + + /** Build a new instance using the given environmental conditions. + * @param hydrostatic model for hydrostatic component + * @param model mapping function model (NMF or GMF). + * @param totalDelay initial value for the tropospheric zenith total delay [m] + * @since 12.1 + */ + public EstimatedTroposphericModel(final DiscreteTroposphericModel hydrostatic, + final MappingFunction model, final double totalDelay) { totalZenithDelay = new ParameterDriver(EstimatedTroposphericModel.TOTAL_ZENITH_DELAY, totalDelay, FastMath.scalb(1.0, 0), 0.0, Double.POSITIVE_INFINITY); - this.t0 = t0; - this.p0 = p0; + this.hydrostatic = hydrostatic; this.model = model; } @@ -104,10 +119,8 @@ public List getParametersDrivers() { @Override public double pathDelay(final double elevation, final GeodeticPoint point, final double[] parameters, final AbsoluteDate date) { - // Use an empirical model for tropospheric zenith hydro-static delay : Saastamoinen model - final ModifiedSaastamoinenModel saastamoinen = new ModifiedSaastamoinenModel(t0, p0, 0.0); // Zenith delays. elevation = pi/2 because we compute the delay in the zenith direction - final double zhd = saastamoinen.pathDelay(0.5 * FastMath.PI, point, parameters, date); + final double zhd = hydrostatic.pathDelay(0.5 * FastMath.PI, point, parameters, date); final double ztd = parameters[0]; // Mapping functions final double[] mf = model.mappingFactors(elevation, point, date); @@ -119,10 +132,8 @@ public double pathDelay(final double elevation, final GeodeticPoint point, @Override public > T pathDelay(final T elevation, final FieldGeodeticPoint point, final T[] parameters, final FieldAbsoluteDate date) { - // Use an empirical model for tropospheric zenith hydro-static delay : Saastamoinen model - final ModifiedSaastamoinenModel saastamoinen = new ModifiedSaastamoinenModel(t0, p0, 0.0); // Zenith delays. elevation = pi/2 because we compute the delay in the zenith direction - final T zhd = saastamoinen.pathDelay(elevation.getPi().multiply(0.5), point, parameters, date); + final T zhd = hydrostatic.pathDelay(elevation.getPi().multiply(0.5), point, parameters, date); final T ztd = parameters[0]; // Mapping functions final T[] mf = model.mappingFactors(elevation, point, date); diff --git a/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java b/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java index fa626a6fe6..9f89aa5d94 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java @@ -24,7 +24,6 @@ import org.hipparchus.Field; import org.hipparchus.analysis.interpolation.BilinearInterpolatingFunction; import org.hipparchus.analysis.interpolation.LinearInterpolator; -import org.hipparchus.analysis.polynomials.PolynomialFunction; import org.hipparchus.analysis.polynomials.PolynomialSplineFunction; import org.hipparchus.util.FastMath; import org.orekit.annotation.DefaultDataContext; @@ -34,6 +33,11 @@ import org.orekit.data.DataProvidersManager; import org.orekit.errors.OrekitException; import org.orekit.errors.OrekitMessages; +import org.orekit.models.earth.weather.ConstantPressureTemperatureHumidityProvider; +import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; +import org.orekit.models.earth.weather.PressureTemperatureHumidity; +import org.orekit.models.earth.weather.PressureTemperatureHumidityProvider; +import org.orekit.models.earth.weather.water.Wang1988; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; import org.orekit.utils.InterpolationTableLoader; @@ -42,8 +46,7 @@ /** The modified Saastamoinen model. Estimates the path delay imposed to * electro-magnetic signals by the troposphere according to the formula: *
              - * δ = 2.277e-3 / cos z * (P + (1255 / T + 0.05) * e - B * tan²
              - * z) + δR
              + * δ = 2.277e-3 / cos z * (P + (1255 / T + 0.05) * e - B * tan² z) + δR
                * 
              * with the following input data provided to the model: *
                @@ -60,6 +63,7 @@ *

                * @author Thomas Neidhart * @see "Guochang Xu, GPS - Theory, Algorithms and Applications, Springer, 2007" + * @since 12.1 */ public class ModifiedSaastamoinenModel implements DiscreteTroposphericModel { @@ -69,6 +73,9 @@ public class ModifiedSaastamoinenModel implements DiscreteTroposphericModel { /** Default lowest acceptable elevation angle [rad]. */ public static final double DEFAULT_LOW_ELEVATION_THRESHOLD = 0.05; + /** Provider for water pressure. */ + public static final Wang1988 WATER = new Wang1988(); + /** First pattern for δR correction term table. */ private static final Pattern FIRST_DELTA_R_PATTERN = Pattern.compile("^\\^"); @@ -80,33 +87,23 @@ public class ModifiedSaastamoinenModel implements DiscreteTroposphericModel { 0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0 }; - /** Y values for the B function. */ + /** Y values for the B function. + *

                + * The values have been scaled up by a factor 100.0 due to conversion from hPa to Pa. + *

                + */ private static final double[] Y_VALUES_FOR_B = { - 1.156, 1.079, 1.006, 0.938, 0.874, 0.813, 0.757, 0.654, 0.563 - }; - - /** Coefficients for the partial pressure of water vapor polynomial. */ - private static final double[] E_COEFFICIENTS = { - -37.2465, 0.213166, -0.000256908 + 115.6, 107.9, 100.6, 93.8, 87.4, 81.3, 75.7, 65.4, 56.3 }; /** Interpolation function for the B correction term. */ - private final PolynomialSplineFunction bFunction; - - /** Polynomial function for the e term. */ - private final PolynomialFunction eFunction; + private static final PolynomialSplineFunction B_FUNCTION = new LinearInterpolator().interpolate(X_VALUES_FOR_B, Y_VALUES_FOR_B); /** Interpolation function for the delta R correction term. */ private final BilinearInterpolatingFunction deltaRFunction; - /** The temperature at the station [K]. */ - private double t0; - - /** The atmospheric pressure [mbar]. */ - private double p0; - - /** The humidity [percent]. */ - private double r0; + /** Provider for pressure, temperature and humidity. */ + private PressureTemperatureHumidityProvider pthProvider; /** Lowest acceptable elevation angle [rad]. */ private double lowElevationThreshold; @@ -115,55 +112,44 @@ public class ModifiedSaastamoinenModel implements DiscreteTroposphericModel { * Create a new Saastamoinen model for the troposphere using the given environmental * conditions and table from the reference book. * - * @param t0 the temperature at the station [K] - * @param p0 the atmospheric pressure at the station [mbar] - * @param r0 the humidity at the station [fraction] (50% -> 0.5) - * @see #ModifiedSaastamoinenModel(double, double, double, String, DataProvidersManager) - * @since 10.1 + * @param pthProvider provider for atmospheric pressure, temperature and humidity at the station + * @see #ModifiedSaastamoinenModel(PressureTemperatureHumidityProvider, String, DataProvidersManager) */ - public ModifiedSaastamoinenModel(final double t0, final double p0, final double r0) { - this(t0, p0, r0, defaultDeltaR()); + public ModifiedSaastamoinenModel(final PressureTemperatureHumidityProvider pthProvider) { + this(pthProvider, defaultDeltaR()); } /** Create a new Saastamoinen model for the troposphere using the given * environmental conditions. This constructor uses the {@link DataContext#getDefault() * default data context} if {@code deltaRFileName != null}. * - * @param t0 the temperature at the station [K] - * @param p0 the atmospheric pressure at the station [mbar] - * @param r0 the humidity at the station [fraction] (50% -> 0.5) + * @param pthProvider provider for atmospheric pressure, temperature and humidity at the station * @param deltaRFileName regular expression for filename containing δR * correction term table (typically {@link #DELTA_R_FILE_NAME}), if null * default values from the reference book are used - * @since 7.1 - * @see #ModifiedSaastamoinenModel(double, double, double, String, DataProvidersManager) + * @see #ModifiedSaastamoinenModel(PressureTemperatureHumidityProvider, String, DataProvidersManager) */ @DefaultDataContext - public ModifiedSaastamoinenModel(final double t0, final double p0, final double r0, - final String deltaRFileName) { - this(t0, p0, r0, deltaRFileName, - DataContext.getDefault().getDataProvidersManager()); + public ModifiedSaastamoinenModel(final PressureTemperatureHumidityProvider pthProvider, + final String deltaRFileName) { + this(pthProvider, deltaRFileName, + DataContext.getDefault().getDataProvidersManager()); } /** Create a new Saastamoinen model for the troposphere using the given * environmental conditions. This constructor allows the user to specify the source of * of the δR file. * - * @param t0 the temperature at the station [K] - * @param p0 the atmospheric pressure at the station [mbar] - * @param r0 the humidity at the station [fraction] (50% -> 0.5) + * @param pthProvider provider for atmospheric pressure, temperature and humidity at the station * @param deltaRFileName regular expression for filename containing δR * correction term table (typically {@link #DELTA_R_FILE_NAME}), if null * default values from the reference book are used * @param dataProvidersManager provides access to auxiliary data. - * @since 10.1 */ - public ModifiedSaastamoinenModel(final double t0, - final double p0, - final double r0, - final String deltaRFileName, - final DataProvidersManager dataProvidersManager) { - this(t0, p0, r0, + public ModifiedSaastamoinenModel(final PressureTemperatureHumidityProvider pthProvider, + final String deltaRFileName, + final DataProvidersManager dataProvidersManager) { + this(pthProvider, deltaRFileName == null ? defaultDeltaR() : loadDeltaR(deltaRFileName, dataProvidersManager)); @@ -171,58 +157,38 @@ public ModifiedSaastamoinenModel(final double t0, /** Create a new Saastamoinen model. * - * @param t0 the temperature at the station [K] - * @param p0 the atmospheric pressure at the station [mbar] - * @param r0 the humidity at the station [fraction] (50% -> 0.5) + * @param pthProvider provider for atmospheric pressure, temperature and humidity at the station * @param deltaR δR correction term function - * @since 7.1 */ - private ModifiedSaastamoinenModel(final double t0, final double p0, final double r0, - final BilinearInterpolatingFunction deltaR) { - checkParameterRangeInclusive("humidity", r0, 0.0, 1.0); - this.t0 = t0; - this.p0 = p0; - this.r0 = r0; - this.bFunction = new LinearInterpolator().interpolate(X_VALUES_FOR_B, Y_VALUES_FOR_B); - this.eFunction = new PolynomialFunction(E_COEFFICIENTS); - this.deltaRFunction = deltaR; + private ModifiedSaastamoinenModel(final PressureTemperatureHumidityProvider pthProvider, + final BilinearInterpolatingFunction deltaR) { + this.pthProvider = pthProvider; + this.deltaRFunction = deltaR; this.lowElevationThreshold = DEFAULT_LOW_ELEVATION_THRESHOLD; } /** Create a new Saastamoinen model using a standard atmosphere model. * *
                  - *
                • temperature: 18 degree Celsius - *
                • pressure: 1013.25 mbar - *
                • humidity: 50% + *
                • temperature: 18 degree Celsius
                • + *
                • pressure: 1013.25 mbar
                • + *
                • humidity: 50%
                • + *
                • @link {@link Wang1988 Wang 1988} model to compute water vapor pressure
                • *
                * * @return a Saastamoinen model with standard environmental values */ public static ModifiedSaastamoinenModel getStandardModel() { - return new ModifiedSaastamoinenModel(273.16 + 18, 1013.25, 0.5); - } - - /** Check if the given parameter is within an acceptable range. - * The bounds are inclusive: an exception is raised when either of those conditions are met: - *
                  - *
                • The parameter is strictly greater than upperBound
                • - *
                • The parameter is strictly lower than lowerBound
                • - *
                - *

                - * In either of these cases, an OrekitException is raised. - *

                - * @param parameterName name of the parameter - * @param parameter value of the parameter - * @param lowerBound lower bound of the acceptable range (inclusive) - * @param upperBound upper bound of the acceptable range (inclusive) - */ - private void checkParameterRangeInclusive(final String parameterName, final double parameter, - final double lowerBound, final double upperBound) { - if (parameter < lowerBound || parameter > upperBound) { - throw new OrekitException(OrekitMessages.INVALID_PARAMETER_RANGE, parameterName, - parameter, lowerBound, upperBound); - } + final double pressure = TropoUnit.HECTO_PASCAL.toSI(1013.25); + final double temperature = 273.16 + 18; + final double humidity = 0.5; + final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(pressure, + temperature, + humidity, + WATER.waterVaporPressure(pressure, + temperature, + humidity)); + return new ModifiedSaastamoinenModel(new ConstantPressureTemperatureHumidityProvider(pth)); } /** {@inheritDoc} @@ -242,21 +208,23 @@ private void checkParameterRangeInclusive(final String parameterName, final doub public double pathDelay(final double elevation, final GeodeticPoint point, final double[] parameters, final AbsoluteDate date) { + final PressureTemperatureHumidity pth = pthProvider.getWeatherParamerers(point, date); + // there are no data in the model for negative altitudes and altitude bigger than 5000 m // limit the height to a range of [0, 5000] m final double fixedHeight = FastMath.min(FastMath.max(0, point.getAltitude()), 5000); // the corrected temperature using a temperature gradient of -6.5 K/km - final double T = t0 - 6.5e-3 * fixedHeight; + final double T = pth.getTemperature() - 6.5e-3 * fixedHeight; // the corrected pressure - final double P = p0 * FastMath.pow(1.0 - 2.26e-5 * fixedHeight, 5.225); + final double P = pth.getPressure() * FastMath.pow(1.0 - 2.26e-5 * fixedHeight, 5.225); // the corrected humidity - final double R = r0 * FastMath.exp(-6.396e-4 * fixedHeight); + final double R = pth.getRelativeHumidity() * FastMath.exp(-6.396e-4 * fixedHeight); // interpolate the b correction term - final double B = bFunction.value(fixedHeight / 1e3); + final double B = B_FUNCTION.value(fixedHeight / 1e3); // calculate e - final double e = R * FastMath.exp(eFunction.value(T)); + final double e = WATER.waterVaporPressure(P, T, R); // calculate the zenith angle from the elevation final double z = FastMath.abs(0.5 * FastMath.PI - FastMath.max(elevation, lowElevationThreshold)); @@ -265,8 +233,9 @@ public double pathDelay(final double elevation, final GeodeticPoint point, final double deltaR = getDeltaR(fixedHeight, z); // calculate the path delay in m + // beware since version 12.1 pressures are in Pa and not in hPa, hence the scaling has changed final double tan = FastMath.tan(z); - final double delta = 2.277e-3 / FastMath.cos(z) * + final double delta = 2.277e-5 / FastMath.cos(z) * (P + (1255d / T + 5e-2) * e - B * tan * tan) + deltaR; return delta; @@ -287,7 +256,9 @@ public double pathDelay(final double elevation, final GeodeticPoint point, */ @Override public > T pathDelay(final T elevation, final FieldGeodeticPoint point, - final T[] parameters, final FieldAbsoluteDate date) { + final T[] parameters, final FieldAbsoluteDate date) { + + final FieldPressureTemperatureHumidity pth = pthProvider.getWeatherParamerers(point, date); final Field field = date.getField(); final T zero = field.getZero(); @@ -296,16 +267,16 @@ public > T pathDelay(final T elevation, final final T fixedHeight = FastMath.min(FastMath.max(zero, point.getAltitude()), zero.add(5000)); // the corrected temperature using a temperature gradient of -6.5 K/km - final T T = fixedHeight.multiply(6.5e-3).negate().add(t0); + final T T = pth.getTemperature().subtract(fixedHeight.multiply(6.5e-3)); // the corrected pressure - final T P = fixedHeight.multiply(2.26e-5).negate().add(1.0).pow(5.225).multiply(p0); + final T P = pth.getPressure().multiply(fixedHeight.multiply(2.26e-5).negate().add(1.0).pow(5.225)); // the corrected humidity - final T R = FastMath.exp(fixedHeight.multiply(-6.396e-4)).multiply(r0); + final T R = pth.getRelativeHumidity().multiply(FastMath.exp(fixedHeight.multiply(-6.396e-4))); // interpolate the b correction term - final T B = bFunction.value(fixedHeight.divide(1e3)); + final T B = B_FUNCTION.value(fixedHeight.divide(1e3)); // calculate e - final T e = R.multiply(FastMath.exp(eFunction.value(T))); + final T e = WATER.waterVaporPressure(P, T, R); // calculate the zenith angle from the elevation final T z = FastMath.abs(FastMath.max(elevation, zero.add(lowElevationThreshold)).negate().add(zero.getPi().multiply(0.5))); @@ -314,8 +285,9 @@ public > T pathDelay(final T elevation, final final T deltaR = getDeltaR(fixedHeight, z, field); // calculate the path delay in m + // beware since version 12.1 pressures are in Pa and not in hPa, hence the scaling has changed final T tan = FastMath.tan(z); - final T delta = FastMath.cos(z).divide(2.277e-3).reciprocal(). + final T delta = FastMath.cos(z).divide(2.277e-5).reciprocal(). multiply(P.add(T.divide(1255d).reciprocal().add(5e-2).multiply(e)).subtract(B.multiply(tan).multiply(tan))).add(deltaR); return delta; diff --git a/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java b/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java index 5a2e5ee299..3d46fa27ee 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java @@ -19,6 +19,9 @@ import org.orekit.annotation.DefaultDataContext; import org.orekit.data.DataContext; import org.orekit.data.DataProvidersManager; +import org.orekit.models.earth.weather.ConstantPressureTemperatureHumidityProvider; +import org.orekit.models.earth.weather.PressureTemperatureHumidity; +import org.orekit.models.earth.weather.water.Wang1988; /** The modified Saastamoinen model. * @author Luc Maisonobe @@ -44,7 +47,7 @@ public class SaastamoinenModel extends ModifiedSaastamoinenModel { * @since 10.1 */ public SaastamoinenModel(final double t0, final double p0, final double r0) { - super(t0, p0, r0); + this(t0, p0, r0, DELTA_R_FILE_NAME); } /** Create a new Saastamoinen model for the troposphere using the given @@ -63,7 +66,7 @@ public SaastamoinenModel(final double t0, final double p0, final double r0) { @DefaultDataContext public SaastamoinenModel(final double t0, final double p0, final double r0, final String deltaRFileName) { - super(t0, p0, r0, deltaRFileName); + this(t0, p0, r0, deltaRFileName, DataContext.getDefault().getDataProvidersManager()); } /** Create a new Saastamoinen model for the troposphere using the given @@ -84,7 +87,13 @@ public SaastamoinenModel(final double t0, final double r0, final String deltaRFileName, final DataProvidersManager dataProvidersManager) { - super(t0, p0, r0, deltaRFileName, dataProvidersManager); + super(new ConstantPressureTemperatureHumidityProvider(new PressureTemperatureHumidity(TropoUnit.HECTO_PASCAL.toSI(p0), + t0, + r0, + new Wang1988().waterVaporPressure(TropoUnit.HECTO_PASCAL.toSI(p0), + t0, + r0))), + deltaRFileName, dataProvidersManager); } /** Create a new Saastamoinen model using a standard atmosphere model. diff --git a/src/main/java/org/orekit/models/earth/weather/water/Wang1988.java b/src/main/java/org/orekit/models/earth/weather/water/Wang1988.java new file mode 100644 index 0000000000..8e9b54d04c --- /dev/null +++ b/src/main/java/org/orekit/models/earth/weather/water/Wang1988.java @@ -0,0 +1,54 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS Communication & Systèmes (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.weather.water; + +import org.hipparchus.CalculusFieldElement; +import org.hipparchus.analysis.polynomials.PolynomialFunction; +import org.hipparchus.util.FastMath; + +/** Conversion polynomial from "The Principle of the GPS Precise Positioning System", Wang et al, 1988. + *

                + * This corresponds to equation 5.96 in Guochang Xu, GPS - Theory, Algorithms and Applications, Springer, 2007. + *

                + * @author Luc Maisonobe + * @since 12.1 + */ +public class Wang1988 implements WaterVaporPressureProvider { + + /** Coefficients for the partial pressure of water vapor polynomial. */ + private static final double[] E_COEFFICIENTS = { + -37.2465, 0.213166, -0.000256908 + }; + + /** Conversion polynomial. */ + private static final PolynomialFunction E_POLYNOMIAL = new PolynomialFunction(E_COEFFICIENTS); + + /** {@inheritDoc} */ + @Override + public double waterVaporPressure(final double p, final double t, final double rh) { + // the 100.0 factor is due to conversion from hPa to Pa + return rh * 100.0 * FastMath.exp(E_POLYNOMIAL.value(t)); + } + + /** {@inheritDoc} */ + @Override + public > T waterVaporPressure(final T p, final T t, final T rh) { + // the 100.0 factor is due to conversion from hPa to Pa + return rh.multiply(100.0).multiply(FastMath.exp(E_POLYNOMIAL.value(t))); + } + +} diff --git a/src/test/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModelTest.java index 02c2008ba0..68863ee19a 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModelTest.java @@ -29,6 +29,9 @@ import org.orekit.bodies.GeodeticPoint; import org.orekit.errors.OrekitException; import org.orekit.errors.OrekitMessages; +import org.orekit.models.earth.weather.ConstantPressureTemperatureHumidityProvider; +import org.orekit.models.earth.weather.PressureTemperatureHumidity; +import org.orekit.models.earth.weather.PressureTemperatureHumidityProvider; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; @@ -43,20 +46,6 @@ public class ModifiedSaastamoinenModelTest { private double[] heights; - @Test - public void testIssue1078() { - try { - new ModifiedSaastamoinenModel(273.16 + 18, 1013.25, 50.0); - } catch (OrekitException oe) { - Assertions.assertEquals(OrekitMessages.INVALID_PARAMETER_RANGE, oe.getSpecifier()); - } - try { - new ModifiedSaastamoinenModel(273.16 + 18, 1013.25, -50.0); - } catch (OrekitException oe) { - Assertions.assertEquals(OrekitMessages.INVALID_PARAMETER_RANGE, oe.getSpecifier()); - } - } - @Test public void testFixedElevation() { Utils.setDataRoot("atmosphere"); @@ -123,7 +112,16 @@ private > void doTestFieldFixedHeight(final Fi public void NoFile() { Utils.setDataRoot("atmosphere"); try { - new ModifiedSaastamoinenModel(273.16 + 18, 1013.25, 0.5, "^non-existent-file$"); + final double temperature = 273.15 + 18; + final double pressure = TropoUnit.HECTO_PASCAL.toSI(1013.25); + final double humidity = 0.5; + final double waterPressure = ModifiedSaastamoinenModel.WATER.waterVaporPressure(pressure, + temperature, + humidity); + final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(pressure, temperature, humidity, + waterPressure); + final PressureTemperatureHumidityProvider pthProvider = new ConstantPressureTemperatureHumidityProvider(pth); + new ModifiedSaastamoinenModel(pthProvider, "^non-existent-file$"); Assertions.fail("an exception should have been thrown"); } catch (OrekitException oe) { Assertions.assertEquals(OrekitMessages.UNABLE_TO_FIND_FILE, oe.getSpecifier()); @@ -134,8 +132,17 @@ public void NoFile() { @Test public void compareDefaultAndLoaded() { Utils.setDataRoot("atmosphere"); - ModifiedSaastamoinenModel defaultModel = new ModifiedSaastamoinenModel(273.16 + 18, 1013.25, 0.5, null); - ModifiedSaastamoinenModel loadedModel = new ModifiedSaastamoinenModel(273.16 + 18, 1013.25, 0.5, ModifiedSaastamoinenModel.DELTA_R_FILE_NAME); + final double temperature = 273.15 + 18; + final double pressure = TropoUnit.HECTO_PASCAL.toSI(1013.25); + final double humidity = 0.5; + final double waterPressure = ModifiedSaastamoinenModel.WATER.waterVaporPressure(pressure, + temperature, + humidity); + final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(pressure, temperature, humidity, + waterPressure); + final PressureTemperatureHumidityProvider pthProvider = new ConstantPressureTemperatureHumidityProvider(pth); + ModifiedSaastamoinenModel defaultModel = new ModifiedSaastamoinenModel(pthProvider, null); + ModifiedSaastamoinenModel loadedModel = new ModifiedSaastamoinenModel(pthProvider, ModifiedSaastamoinenModel.DELTA_R_FILE_NAME); double[] heights = new double[] { 0.0, 250.0, 500.0, 750.0, 1000.0, 1250.0, 1500.0, 1750.0, 2000.0, 2250.0, 2500.0, 2750.0, 3000.0, 3250.0, 3500.0, 3750.0, 4000.0, 4250.0, 4500.0, 4750.0, 5000.0 From fd0088d6e0c3630dd4d6e6ca1f438afc78fbc81a Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Fri, 8 Dec 2023 18:07:44 +0100 Subject: [PATCH 024/359] Fixed wavelength units conversion error. --- .../earth/troposphere/MendesPavlisModel.java | 4 +++- .../common/AbstractOrbitDetermination.java | 24 ++++++++++++++----- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java b/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java index f1be3f5cdd..a6b923c398 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java @@ -34,6 +34,7 @@ import org.orekit.time.FieldAbsoluteDate; import org.orekit.utils.ParameterDriver; import org.orekit.utils.units.Unit; +import org.orekit.utils.units.UnitsConverter; /** The Mendes - Pavlis tropospheric delay model for optical techniques. * It is valid for a wide range of wavelengths from 0.355µm to 1.064µm (Mendes and Pavlis, 2003) @@ -111,7 +112,8 @@ public MendesPavlisModel(final PressureTemperatureHumidityProvider pthProvider, this.pthProvider = pthProvider; // Dispersion equation for the hydrostatic component - final double sigma = 1 / lambda; + final double lambdaMicrometer = new UnitsConverter(lambdaUnits, TropoUnit.MICRO_M).convert(lambda); + final double sigma = 1.0 / lambdaMicrometer; final double sigma2 = sigma * sigma; final double coef1 = K_COEFFICIENTS[0] + sigma2; final double coef2 = K_COEFFICIENTS[0] - sigma2; diff --git a/src/test/java/org/orekit/estimation/common/AbstractOrbitDetermination.java b/src/test/java/org/orekit/estimation/common/AbstractOrbitDetermination.java index b84ca47992..2b9b209b52 100644 --- a/src/test/java/org/orekit/estimation/common/AbstractOrbitDetermination.java +++ b/src/test/java/org/orekit/estimation/common/AbstractOrbitDetermination.java @@ -73,8 +73,8 @@ import org.orekit.estimation.measurements.modifiers.AngularRadioRefractionModifier; import org.orekit.estimation.measurements.modifiers.Bias; import org.orekit.estimation.measurements.modifiers.DynamicOutlierFilter; -import org.orekit.estimation.measurements.modifiers.PhaseCentersRangeModifier; import org.orekit.estimation.measurements.modifiers.OutlierFilter; +import org.orekit.estimation.measurements.modifiers.PhaseCentersRangeModifier; import org.orekit.estimation.measurements.modifiers.RangeIonosphericDelayModifier; import org.orekit.estimation.measurements.modifiers.RangeRateIonosphericDelayModifier; import org.orekit.estimation.measurements.modifiers.RangeTroposphericDelayModifier; @@ -97,12 +97,12 @@ import org.orekit.files.ilrs.CRD.RangeMeasurement; import org.orekit.files.ilrs.CRDHeader; import org.orekit.files.ilrs.CRDHeader.RangeType; +import org.orekit.files.ilrs.CRDParser; import org.orekit.files.rinex.HatanakaCompressFilter; import org.orekit.files.rinex.observation.ObservationData; import org.orekit.files.rinex.observation.ObservationDataSet; import org.orekit.files.rinex.observation.RinexObservation; import org.orekit.files.rinex.observation.RinexObservationParser; -import org.orekit.files.ilrs.CRDParser; import org.orekit.files.sinex.SinexLoader; import org.orekit.files.sinex.Station; import org.orekit.forces.drag.DragSensitive; @@ -136,10 +136,13 @@ import org.orekit.models.earth.troposphere.GlobalMappingFunctionModel; import org.orekit.models.earth.troposphere.MappingFunction; import org.orekit.models.earth.troposphere.MendesPavlisModel; -import org.orekit.models.earth.troposphere.NiellMappingFunctionModel; import org.orekit.models.earth.troposphere.ModifiedSaastamoinenModel; +import org.orekit.models.earth.troposphere.NiellMappingFunctionModel; import org.orekit.models.earth.troposphere.TimeSpanEstimatedTroposphericModel; +import org.orekit.models.earth.weather.ConstantPressureTemperatureHumidityProvider; import org.orekit.models.earth.weather.GlobalPressureTemperatureModel; +import org.orekit.models.earth.weather.PressureTemperatureHumidity; +import org.orekit.models.earth.weather.water.CIPM2007; import org.orekit.orbits.CartesianOrbit; import org.orekit.orbits.CircularOrbit; import org.orekit.orbits.EquinoctialOrbit; @@ -166,6 +169,7 @@ import org.orekit.utils.ParameterDriversList; import org.orekit.utils.ParameterDriversList.DelegatingDriver; import org.orekit.utils.TimeSpanMap.Span; +import org.orekit.utils.units.Unit; /** Base class for Orekit orbit determination tutorials. * @param type of the propagator builder @@ -2312,10 +2316,18 @@ private List> readCrd(final DataSource source, // Tropospheric model final DiscreteTroposphericModel model; if (meteoData != null) { - model = new MendesPavlisModel(meteoData.getTemperature(), meteoData.getPressure() * 1000.0, - 0.01 * meteoData.getHumidity(), wavelength * 1.0e6); + final PressureTemperatureHumidity pth = + new PressureTemperatureHumidity(Unit.BAR.toSI(meteoData.getPressure()), + meteoData.getTemperature(), + 0.01 * meteoData.getHumidity(), + new CIPM2007(). + waterVaporPressure(Unit.BAR.toSI(meteoData.getPressure()), + meteoData.getTemperature(), + 0.01 * meteoData.getHumidity())); + model = new MendesPavlisModel(new ConstantPressureTemperatureHumidityProvider(pth), + wavelength, Unit.METRE); } else { - model = MendesPavlisModel.getStandardModel(wavelength * 1.0e6); + model = MendesPavlisModel.getStandardModel(wavelength, Unit.METRE); } measurement.addModifier(new RangeTroposphericDelayModifier(model)); From be4e5d09a9cef308ab0469433400cfeb96f508c1 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Fri, 8 Dec 2023 18:08:14 +0100 Subject: [PATCH 025/359] Fixed missing pressure conversion. --- .../models/earth/troposphere/EstimatedTroposphericModel.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java b/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java index cab54dab80..75e54a9011 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java @@ -77,7 +77,10 @@ public class EstimatedTroposphericModel implements DiscreteTroposphericModel { */ public EstimatedTroposphericModel(final double t0, final double p0, final MappingFunction model, final double totalDelay) { - this(new ModifiedSaastamoinenModel(new ConstantPressureTemperatureHumidityProvider(new PressureTemperatureHumidity(p0, t0, 0.0, 0.0))), + this(new ModifiedSaastamoinenModel(new ConstantPressureTemperatureHumidityProvider(new PressureTemperatureHumidity(TropoUnit.HECTO_PASCAL.toSI(p0), + t0, + 0.0, + 0.0))), model, totalDelay); } From 3077b826a3c8db0b79cbb1b3213d5a725591fd06 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Fri, 8 Dec 2023 18:09:29 +0100 Subject: [PATCH 026/359] Fixed temperature conversion error. --- .../ModifiedSaastamoinenModel.java | 2 +- .../ModifiedSaastamoinenModelTest.java | 28 +++++++++++++++++-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java b/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java index 9f89aa5d94..0c56014290 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java @@ -180,7 +180,7 @@ private ModifiedSaastamoinenModel(final PressureTemperatureHumidityProvider pthP */ public static ModifiedSaastamoinenModel getStandardModel() { final double pressure = TropoUnit.HECTO_PASCAL.toSI(1013.25); - final double temperature = 273.16 + 18; + final double temperature = 273.15 + 18; final double humidity = 0.5; final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(pressure, temperature, diff --git a/src/test/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModelTest.java index 68863ee19a..06417ed067 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModelTest.java @@ -232,7 +232,19 @@ private > void doTestFieldLowElevation(final F @Test public void compareExpectedValues() { Utils.setDataRoot("atmosphere"); - ModifiedSaastamoinenModel model = ModifiedSaastamoinenModel.getStandardModel(); + final double pressure = TropoUnit.HECTO_PASCAL.toSI(1013.25); + // it seems the reference values for the test have been computed using a wrong conversion + // between Celsius and Kelvin (273.16 offset instead of 273.15) + // so for the sake of the test, we use a temperature of 18.01°C and not the standard atmosphere at 18.00°C + final double temperature = 273.15 + 18.01; + final double humidity = 0.5; + final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(pressure, + temperature, + humidity, + ModifiedSaastamoinenModel.WATER.waterVaporPressure(pressure, + temperature, + humidity)); + ModifiedSaastamoinenModel model = new ModifiedSaastamoinenModel(new ConstantPressureTemperatureHumidityProvider(pth)); for (int h = 0; h < heights.length; h++) { for (int e = 0; e < elevations.length; e++) { @@ -254,7 +266,19 @@ public void compareFieldExpectedValues() { private > void doCompareFieldExpectedValues(final Field field) { final T zero = field.getZero(); Utils.setDataRoot("atmosphere"); - ModifiedSaastamoinenModel model = ModifiedSaastamoinenModel.getStandardModel(); + final double pressure = TropoUnit.HECTO_PASCAL.toSI(1013.25); + // it seems the reference values for the test have been computed using a wrong conversion + // between Celsius and Kelvin (273.16 offset instead of 273.15) + // so for the sake of the test, we use a temperature of 18.01°C and not the standard atmosphere at 18.00°C + final double temperature = 273.15 + 18.01; + final double humidity = 0.5; + final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(pressure, + temperature, + humidity, + ModifiedSaastamoinenModel.WATER.waterVaporPressure(pressure, + temperature, + humidity)); + ModifiedSaastamoinenModel model = new ModifiedSaastamoinenModel(new ConstantPressureTemperatureHumidityProvider(pth)); for (int h = 0; h < heights.length; h++) { for (int e = 0; e < elevations.length; e++) { From c76a79b3c4d38a895b3ec69d5a2268e1b162160b Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Fri, 8 Dec 2023 18:10:07 +0100 Subject: [PATCH 027/359] Updated tests after small numerical changes. --- .../org/orekit/estimation/measurements/BistaticRangeTest.java | 2 +- src/test/java/org/orekit/estimation/measurements/RangeTest.java | 2 +- .../estimation/measurements/modifiers/TropoModifierTest.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/java/org/orekit/estimation/measurements/BistaticRangeTest.java b/src/test/java/org/orekit/estimation/measurements/BistaticRangeTest.java index cc70a99746..6d3d8b3406 100644 --- a/src/test/java/org/orekit/estimation/measurements/BistaticRangeTest.java +++ b/src/test/java/org/orekit/estimation/measurements/BistaticRangeTest.java @@ -204,7 +204,7 @@ public double[] value(final SpacecraftState state) { } } - Assertions.assertEquals(0, maxRelativeError, 2.5e-5); + Assertions.assertEquals(0, maxRelativeError, 2.7e-5); } diff --git a/src/test/java/org/orekit/estimation/measurements/RangeTest.java b/src/test/java/org/orekit/estimation/measurements/RangeTest.java index c4c8fd34fd..2d8fd0f75a 100644 --- a/src/test/java/org/orekit/estimation/measurements/RangeTest.java +++ b/src/test/java/org/orekit/estimation/measurements/RangeTest.java @@ -100,7 +100,7 @@ public void testStateDerivativesWithModifier() { } // Run test boolean isModifier = true; - double refErrorsPMedian = 7.5e-10; + double refErrorsPMedian = 7.6e-10; double refErrorsPMean = 3.2e-09; double refErrorsPMax = 9.2e-08; double refErrorsVMedian = 2.1e-04; diff --git a/src/test/java/org/orekit/estimation/measurements/modifiers/TropoModifierTest.java b/src/test/java/org/orekit/estimation/measurements/modifiers/TropoModifierTest.java index a9610c86cf..552f3ee1a0 100644 --- a/src/test/java/org/orekit/estimation/measurements/modifiers/TropoModifierTest.java +++ b/src/test/java/org/orekit/estimation/measurements/modifiers/TropoModifierTest.java @@ -596,7 +596,7 @@ public void testTDOAEstimatedTropoModifier() { final double epsilon = 5.e-11; Assertions.assertTrue(Precision.compareTo(diffSec, 4.90e-9, epsilon) < 0); - Assertions.assertTrue(Precision.compareTo(diffSec, -2.20e-9, epsilon) > 0); + Assertions.assertTrue(Precision.compareTo(diffSec, -2.21e-9, epsilon) > 0); } } From e0b60df095c31ff002409ce3de228b35d04e69a1 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Fri, 8 Dec 2023 21:31:58 +0100 Subject: [PATCH 028/359] Added canonical Saastamoinen model. --- .../CanonicalSaastamoinenModel.java | 52 ++++--- .../EstimatedTroposphericModel.java | 3 +- .../ModifiedSaastamoinenModel.java | 96 +++++++------ .../earth/troposphere/SaastamoinenModel.java | 3 +- ...ntPressureTemperatureHumidityProvider.java | 134 ++++++++++++++++++ .../earth/weather/water/NbsNrcSteamTable.java | 6 +- .../CanonicalSaastamoinenModelTest.java | 58 ++++++++ .../ModifiedSaastamoinenModelTest.java | 14 +- 8 files changed, 292 insertions(+), 74 deletions(-) create mode 100644 src/main/java/org/orekit/models/earth/weather/HeightDependentPressureTemperatureHumidityProvider.java create mode 100644 src/test/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModelTest.java diff --git a/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java b/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java index a133a4f97f..4d895ab2ff 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java @@ -28,9 +28,11 @@ import org.orekit.bodies.GeodeticPoint; import org.orekit.models.earth.weather.ConstantPressureTemperatureHumidityProvider; import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; +import org.orekit.models.earth.weather.HeightDependentPressureTemperatureHumidityProvider; import org.orekit.models.earth.weather.PressureTemperatureHumidity; import org.orekit.models.earth.weather.PressureTemperatureHumidityProvider; import org.orekit.models.earth.weather.water.NbsNrcSteamTable; +import org.orekit.models.earth.weather.water.WaterVaporPressureProvider; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; import org.orekit.utils.ParameterDriver; @@ -63,20 +65,28 @@ public class CanonicalSaastamoinenModel implements DiscreteTroposphericModel { /** X values for the B function (table 1 in reference paper). */ private static final double[] X_VALUES_FOR_B = { - 0.0, 200.0, 400.0, 600.0, 8000.0, 1000.0, 1500.0, 2000.0, 2500.0, 3000.0, 4000.0, 5000.0, 6000.0 + 0.0, 200.0, 400.0, 600.0, 800.0, 1000.0, 1500.0, 2000.0, 2500.0, 3000.0, 4000.0, 5000.0, 6000.0 }; - /** E values for the B function (table 1 in reference paper). */ + /** Y values for the B function (table 1 in reference paper). + *

                + * The values have been scaled up by a factor 100.0 due to conversion from hPa to Pa. + *

                + */ private static final double[] Y_VALUES_FOR_B = { - 1.16, 1.13, 1.10, 1.07, 1.04, 1.01, 0.94, 0.88, 0.82, 0.76, 0.66, 0.57, 0.49 + 116.0, 113.0, 110.0, 107.0, 104.0, 101.0, 94.0, 88.0, 82.0, 76.0, 66.0, 57.0, 49.0 }; /** Interpolation function for the B correction term. */ - private final PolynomialSplineFunction bFunction; + private static final PolynomialSplineFunction B_FUNCTION; /** Provider for pressure, temperature and humidity. */ private final PressureTemperatureHumidityProvider pthProvider; + static { + B_FUNCTION = new LinearInterpolator().interpolate(X_VALUES_FOR_B, Y_VALUES_FOR_B); + } + /** Lowest acceptable elevation angle [rad]. */ private double lowElevationThreshold; @@ -85,10 +95,10 @@ public class CanonicalSaastamoinenModel implements DiscreteTroposphericModel { * conditions and table from the reference book. * * @param pthProvider provider for pressure, temperature and humidity + * @see HeightDependentPressureTemperatureHumidityProvider */ public CanonicalSaastamoinenModel(final PressureTemperatureHumidityProvider pthProvider) { this.pthProvider = pthProvider; - this.bFunction = new LinearInterpolator().interpolate(X_VALUES_FOR_B, Y_VALUES_FOR_B); this.lowElevationThreshold = DEFAULT_LOW_ELEVATION_THRESHOLD; } @@ -105,14 +115,22 @@ public CanonicalSaastamoinenModel(final PressureTemperatureHumidityProvider pthP public static CanonicalSaastamoinenModel getStandardModel() { // build standard meteorological data - final double pressure = Unit.parse("hPa").toSI(1013.25); - final double temperature = 273.15 + 18; - final double waterVaporPressure = new NbsNrcSteamTable().waterVaporPressure(temperature, pressure, 0.5); - final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(pressure, - temperature, - waterVaporPressure); - - return new CanonicalSaastamoinenModel(new ConstantPressureTemperatureHumidityProvider(pth)); + final double pressure = Unit.parse("hPa").toSI(1013.25); + final double temperature = 273.15 + 18; + final double relativeHumidity = 0.5; + final WaterVaporPressureProvider waterPressureProvider = new NbsNrcSteamTable(); + final double waterVaporPressure = waterPressureProvider.waterVaporPressure(pressure, + temperature, + relativeHumidity); + final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(pressure, + temperature, + relativeHumidity, + waterVaporPressure); + final PressureTemperatureHumidityProvider pth0Provider = + new ConstantPressureTemperatureHumidityProvider(pth); + final PressureTemperatureHumidityProvider pthProvider = + new HeightDependentPressureTemperatureHumidityProvider(0.0, 5000.0, 0.0, pth0Provider, waterPressureProvider); + return new CanonicalSaastamoinenModel(pthProvider); } @@ -141,14 +159,14 @@ public double pathDelay(final double elevation, final GeodeticPoint point, X_VALUES_FOR_B[X_VALUES_FOR_B.length - 1]); // interpolate the b correction term - final double B = bFunction.value(fixedHeight); + final double B = B_FUNCTION.value(fixedHeight); // calculate the zenith angle from the elevation final double z = FastMath.abs(0.5 * FastMath.PI - FastMath.max(elevation, lowElevationThreshold)); // calculate the path delay in m final double tan = FastMath.tan(z); - final double delta = 2.277e-3 / FastMath.cos(z) * + final double delta = 2.277e-5 / FastMath.cos(z) * (pth.getPressure() + (1255.0 / pth.getTemperature() + 0.05) * pth.getWaterVaporPressure() - B * tan * tan); @@ -183,7 +201,7 @@ public > T pathDelay(final T elevation, final X_VALUES_FOR_B[X_VALUES_FOR_B.length - 1]); // interpolate the b correction term - final T B = bFunction.value(fixedHeight); + final T B = B_FUNCTION.value(fixedHeight); // calculate the zenith angle from the elevation final T z = FastMath.abs(zero.getPi().multiply(0.5). @@ -191,7 +209,7 @@ public > T pathDelay(final T elevation, final // calculate the path delay in m final T tan = FastMath.tan(z); - final T delta = FastMath.cos(z).divide(2.277e-3).reciprocal(). + final T delta = FastMath.cos(z).divide(2.277e-5).reciprocal(). multiply(pth.getPressure(). add(pth.getTemperature().reciprocal().multiply(1255.0).add(0.05). multiply(pth.getWaterVaporPressure())). diff --git a/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java b/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java index 75e54a9011..e8acd76a7c 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java @@ -77,7 +77,8 @@ public class EstimatedTroposphericModel implements DiscreteTroposphericModel { */ public EstimatedTroposphericModel(final double t0, final double p0, final MappingFunction model, final double totalDelay) { - this(new ModifiedSaastamoinenModel(new ConstantPressureTemperatureHumidityProvider(new PressureTemperatureHumidity(TropoUnit.HECTO_PASCAL.toSI(p0), + this(new ModifiedSaastamoinenModel(0.0, + new ConstantPressureTemperatureHumidityProvider(new PressureTemperatureHumidity(TropoUnit.HECTO_PASCAL.toSI(p0), t0, 0.0, 0.0))), diff --git a/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java b/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java index 0c56014290..b625f2003b 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java @@ -35,6 +35,7 @@ import org.orekit.errors.OrekitMessages; import org.orekit.models.earth.weather.ConstantPressureTemperatureHumidityProvider; import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; +import org.orekit.models.earth.weather.HeightDependentPressureTemperatureHumidityProvider; import org.orekit.models.earth.weather.PressureTemperatureHumidity; import org.orekit.models.earth.weather.PressureTemperatureHumidityProvider; import org.orekit.models.earth.weather.water.Wang1988; @@ -84,7 +85,7 @@ public class ModifiedSaastamoinenModel implements DiscreteTroposphericModel { /** X values for the B function. */ private static final double[] X_VALUES_FOR_B = { - 0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0 + 0.0, 500.0, 1000.0, 1500.0, 2000.0, 2500.0, 3000.0, 4000.0, 5000.0 }; /** Y values for the B function. @@ -102,8 +103,8 @@ public class ModifiedSaastamoinenModel implements DiscreteTroposphericModel { /** Interpolation function for the delta R correction term. */ private final BilinearInterpolatingFunction deltaRFunction; - /** Provider for pressure, temperature and humidity. */ - private PressureTemperatureHumidityProvider pthProvider; + /** Height dependent provider for pressure, temperature and humidity. */ + private HeightDependentPressureTemperatureHumidityProvider pthProvider; /** Lowest acceptable elevation angle [rad]. */ private double lowElevationThreshold; @@ -112,27 +113,31 @@ public class ModifiedSaastamoinenModel implements DiscreteTroposphericModel { * Create a new Saastamoinen model for the troposphere using the given environmental * conditions and table from the reference book. * - * @param pthProvider provider for atmospheric pressure, temperature and humidity at the station - * @see #ModifiedSaastamoinenModel(PressureTemperatureHumidityProvider, String, DataProvidersManager) + * @param h0 reference altitude + * @param pth0Provider provider for atmospheric pressure, temperature and humidity at reference altitude + * @see #ModifiedSaastamoinenModel(double, PressureTemperatureHumidityProvider, String, DataProvidersManager) */ - public ModifiedSaastamoinenModel(final PressureTemperatureHumidityProvider pthProvider) { - this(pthProvider, defaultDeltaR()); + @DefaultDataContext + public ModifiedSaastamoinenModel(final double h0, final PressureTemperatureHumidityProvider pth0Provider) { + this(h0, pth0Provider, defaultDeltaR()); } /** Create a new Saastamoinen model for the troposphere using the given * environmental conditions. This constructor uses the {@link DataContext#getDefault() * default data context} if {@code deltaRFileName != null}. * - * @param pthProvider provider for atmospheric pressure, temperature and humidity at the station + * @param h0 reference altitude + * @param pth0Provider provider for atmospheric pressure, temperature and humidity at reference altitude * @param deltaRFileName regular expression for filename containing δR * correction term table (typically {@link #DELTA_R_FILE_NAME}), if null * default values from the reference book are used - * @see #ModifiedSaastamoinenModel(PressureTemperatureHumidityProvider, String, DataProvidersManager) + * @see #ModifiedSaastamoinenModel(double, PressureTemperatureHumidityProvider, String, DataProvidersManager) */ @DefaultDataContext - public ModifiedSaastamoinenModel(final PressureTemperatureHumidityProvider pthProvider, + public ModifiedSaastamoinenModel(final double h0, + final PressureTemperatureHumidityProvider pth0Provider, final String deltaRFileName) { - this(pthProvider, deltaRFileName, + this(h0, pth0Provider, deltaRFileName, DataContext.getDefault().getDataProvidersManager()); } @@ -140,16 +145,18 @@ public ModifiedSaastamoinenModel(final PressureTemperatureHumidityProvider pthPr * environmental conditions. This constructor allows the user to specify the source of * of the δR file. * - * @param pthProvider provider for atmospheric pressure, temperature and humidity at the station + * @param h0 reference altitude + * @param pth0Provider provider for atmospheric pressure, temperature and humidity at reference altitude * @param deltaRFileName regular expression for filename containing δR * correction term table (typically {@link #DELTA_R_FILE_NAME}), if null * default values from the reference book are used * @param dataProvidersManager provides access to auxiliary data. */ - public ModifiedSaastamoinenModel(final PressureTemperatureHumidityProvider pthProvider, + public ModifiedSaastamoinenModel(final double h0, + final PressureTemperatureHumidityProvider pth0Provider, final String deltaRFileName, final DataProvidersManager dataProvidersManager) { - this(pthProvider, + this(h0, pth0Provider, deltaRFileName == null ? defaultDeltaR() : loadDeltaR(deltaRFileName, dataProvidersManager)); @@ -157,12 +164,18 @@ public ModifiedSaastamoinenModel(final PressureTemperatureHumidityProvider pthPr /** Create a new Saastamoinen model. * - * @param pthProvider provider for atmospheric pressure, temperature and humidity at the station + * @param h0 reference altitude + * @param pth0Provider provider for atmospheric pressure, temperature and humidity at reference altitude * @param deltaR δR correction term function */ - private ModifiedSaastamoinenModel(final PressureTemperatureHumidityProvider pthProvider, + private ModifiedSaastamoinenModel(final double h0, + final PressureTemperatureHumidityProvider pth0Provider, final BilinearInterpolatingFunction deltaR) { - this.pthProvider = pthProvider; + final double hMin = X_VALUES_FOR_B[0]; + final double hMax = X_VALUES_FOR_B[X_VALUES_FOR_B.length - 1]; + this.pthProvider = new HeightDependentPressureTemperatureHumidityProvider(hMin, hMax, + hMin, pth0Provider, + WATER); this.deltaRFunction = deltaR; this.lowElevationThreshold = DEFAULT_LOW_ELEVATION_THRESHOLD; } @@ -178,6 +191,7 @@ private ModifiedSaastamoinenModel(final PressureTemperatureHumidityProvider pthP * * @return a Saastamoinen model with standard environmental values */ + @DefaultDataContext public static ModifiedSaastamoinenModel getStandardModel() { final double pressure = TropoUnit.HECTO_PASCAL.toSI(1013.25); final double temperature = 273.15 + 18; @@ -188,7 +202,8 @@ public static ModifiedSaastamoinenModel getStandardModel() { WATER.waterVaporPressure(pressure, temperature, humidity)); - return new ModifiedSaastamoinenModel(new ConstantPressureTemperatureHumidityProvider(pth)); + final PressureTemperatureHumidityProvider pth0Provider = new ConstantPressureTemperatureHumidityProvider(pth); + return new ModifiedSaastamoinenModel(X_VALUES_FOR_B[0], pth0Provider); } /** {@inheritDoc} @@ -210,21 +225,12 @@ public double pathDelay(final double elevation, final GeodeticPoint point, final PressureTemperatureHumidity pth = pthProvider.getWeatherParamerers(point, date); - // there are no data in the model for negative altitudes and altitude bigger than 5000 m - // limit the height to a range of [0, 5000] m - final double fixedHeight = FastMath.min(FastMath.max(0, point.getAltitude()), 5000); - - // the corrected temperature using a temperature gradient of -6.5 K/km - final double T = pth.getTemperature() - 6.5e-3 * fixedHeight; - // the corrected pressure - final double P = pth.getPressure() * FastMath.pow(1.0 - 2.26e-5 * fixedHeight, 5.225); - // the corrected humidity - final double R = pth.getRelativeHumidity() * FastMath.exp(-6.396e-4 * fixedHeight); + // limit the height to model range + final double fixedHeight = FastMath.min(FastMath.max(point.getAltitude(), pthProvider.getHMin()), + pthProvider.getHMax()) - pthProvider.getH0(); // interpolate the b correction term - final double B = B_FUNCTION.value(fixedHeight / 1e3); - // calculate e - final double e = WATER.waterVaporPressure(P, T, R); + final double B = B_FUNCTION.value(fixedHeight); // calculate the zenith angle from the elevation final double z = FastMath.abs(0.5 * FastMath.PI - FastMath.max(elevation, lowElevationThreshold)); @@ -236,7 +242,9 @@ public double pathDelay(final double elevation, final GeodeticPoint point, // beware since version 12.1 pressures are in Pa and not in hPa, hence the scaling has changed final double tan = FastMath.tan(z); final double delta = 2.277e-5 / FastMath.cos(z) * - (P + (1255d / T + 5e-2) * e - B * tan * tan) + deltaR; + (pth.getPressure() + + (1255d / pth.getTemperature() + 5e-2) * pth.getWaterVaporPressure() - + B * tan * tan) + deltaR; return delta; } @@ -262,24 +270,16 @@ public > T pathDelay(final T elevation, final final Field field = date.getField(); final T zero = field.getZero(); - // there are no data in the model for negative altitudes and altitude bigger than 5000 m - // limit the height to a range of [0, 5000] m - final T fixedHeight = FastMath.min(FastMath.max(zero, point.getAltitude()), zero.add(5000)); - - // the corrected temperature using a temperature gradient of -6.5 K/km - final T T = pth.getTemperature().subtract(fixedHeight.multiply(6.5e-3)); - // the corrected pressure - final T P = pth.getPressure().multiply(fixedHeight.multiply(2.26e-5).negate().add(1.0).pow(5.225)); - // the corrected humidity - final T R = pth.getRelativeHumidity().multiply(FastMath.exp(fixedHeight.multiply(-6.396e-4))); + // limit the height to model range + final T fixedHeight = FastMath.min(FastMath.max(point.getAltitude(), pthProvider.getHMin()), + pthProvider.getHMax()).subtract(pthProvider.getH0()); // interpolate the b correction term - final T B = B_FUNCTION.value(fixedHeight.divide(1e3)); - // calculate e - final T e = WATER.waterVaporPressure(P, T, R); + final T B = B_FUNCTION.value(fixedHeight); // calculate the zenith angle from the elevation - final T z = FastMath.abs(FastMath.max(elevation, zero.add(lowElevationThreshold)).negate().add(zero.getPi().multiply(0.5))); + final T z = FastMath.abs(FastMath.max(elevation, zero.add(lowElevationThreshold)).negate(). + add(zero.getPi().multiply(0.5))); // get correction factor final T deltaR = getDeltaR(fixedHeight, z, field); @@ -288,7 +288,9 @@ public > T pathDelay(final T elevation, final // beware since version 12.1 pressures are in Pa and not in hPa, hence the scaling has changed final T tan = FastMath.tan(z); final T delta = FastMath.cos(z).divide(2.277e-5).reciprocal(). - multiply(P.add(T.divide(1255d).reciprocal().add(5e-2).multiply(e)).subtract(B.multiply(tan).multiply(tan))).add(deltaR); + multiply(pth.getPressure(). + add(pth.getTemperature().divide(1255d).reciprocal().add(5e-2).multiply(pth.getWaterVaporPressure())). + subtract(B.multiply(tan).multiply(tan))).add(deltaR); return delta; } diff --git a/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java b/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java index 3d46fa27ee..65f3bcc23b 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java @@ -87,7 +87,8 @@ public SaastamoinenModel(final double t0, final double r0, final String deltaRFileName, final DataProvidersManager dataProvidersManager) { - super(new ConstantPressureTemperatureHumidityProvider(new PressureTemperatureHumidity(TropoUnit.HECTO_PASCAL.toSI(p0), + super(0.0, + new ConstantPressureTemperatureHumidityProvider(new PressureTemperatureHumidity(TropoUnit.HECTO_PASCAL.toSI(p0), t0, r0, new Wang1988().waterVaporPressure(TropoUnit.HECTO_PASCAL.toSI(p0), diff --git a/src/main/java/org/orekit/models/earth/weather/HeightDependentPressureTemperatureHumidityProvider.java b/src/main/java/org/orekit/models/earth/weather/HeightDependentPressureTemperatureHumidityProvider.java new file mode 100644 index 0000000000..4471940a9e --- /dev/null +++ b/src/main/java/org/orekit/models/earth/weather/HeightDependentPressureTemperatureHumidityProvider.java @@ -0,0 +1,134 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS Communication & Systèmes (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.weather; + +import org.hipparchus.CalculusFieldElement; +import org.hipparchus.util.FastMath; +import org.orekit.bodies.FieldGeodeticPoint; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.models.earth.weather.water.WaterVaporPressureProvider; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; + +/** Provider for weather parameters that change with height. + *

                + * Height variations correspond to equations 5.98, 5.99 and 5.100 from + * Guochang Xu, GPS - Theory, Algorithms and Applications, Springer, 2007 + *

                + * @author Luc Maisonobe + * @since 12.1 + */ +public class HeightDependentPressureTemperatureHumidityProvider implements PressureTemperatureHumidityProvider { + + /** Minimum altitude (m). */ + private final double hMin; + + /** Maximum altitude (m). */ + private final double hMax; + + /** Reference altitude (m). */ + private final double h0; + + /** PTH provider at reference height. */ + private final PressureTemperatureHumidityProvider pth0Provider; + + /** Water pressure provider for water vapor pressure. */ + private final WaterVaporPressureProvider provider; + + /** Simple constructor. + *

                + * Points outside of altitude range will be silently clipped back to range. + *

                + * @param hMin minimum altitude + * @param hMax maximum altitude + * @param h0 reference altitude + * @param pth0Provider PTH provider at reference height + * @param provider provider for water vapor pressure + */ + public HeightDependentPressureTemperatureHumidityProvider(final double hMin, final double hMax, + final double h0, + final PressureTemperatureHumidityProvider pth0Provider, + final WaterVaporPressureProvider provider) { + this.hMin = hMin; + this.hMax = hMax; + this.h0 = h0; + this.pth0Provider = pth0Provider; + this.provider = provider; + } + + /** Get minimum altitude. + * @return minimum altitude + */ + public double getHMin() { + return hMin; + } + + /** Get maximum altitude. + * @return maximum altitude + */ + public double getHMax() { + return hMax; + } + + /** Get reference altitude. + * @return reference altitude + */ + public double getH0() { + return h0; + } + + /** {@inheritDoc} */ + @Override + public PressureTemperatureHumidity getWeatherParamerers(final GeodeticPoint location, + final AbsoluteDate date) { + + // retrieve parameters at reference altitude + final PressureTemperatureHumidity pth0 = pth0Provider.getWeatherParamerers(new GeodeticPoint(location.getLatitude(), + location.getLongitude(), + h0), + date); + + // compute changes due to altitude change + final double dh = FastMath.min(FastMath.max(location.getAltitude(), hMin), hMax) - h0; + final double p = pth0.getPressure() * FastMath.pow(1.0 - 2.26e-5 * dh, 5.225); + final double t = pth0.getTemperature() - 6.5e-3 * dh; + final double rh = pth0.getRelativeHumidity() * FastMath.exp(-6.396e-4 * dh); + + return new PressureTemperatureHumidity(p, t, rh, provider.waterVaporPressure(p, t, rh)); + + } + + /** {@inheritDoc} */ + @Override + public > FieldPressureTemperatureHumidity getWeatherParamerers(final FieldGeodeticPoint location, + final FieldAbsoluteDate date) { + // retrieve parameters at reference altitude + final FieldPressureTemperatureHumidity pth0 = + pth0Provider.getWeatherParamerers(new FieldGeodeticPoint<>(location.getLatitude(), + location.getLongitude(), + location.getAltitude().newInstance(h0)), + date); + + // compute changes due to altitude change + final T dh = FastMath.min(FastMath.max(location.getAltitude(), hMin), hMax).subtract(h0); + final T t = pth0.getTemperature().subtract(dh.multiply(6.5e-3)); + final T p = pth0.getPressure().multiply(dh.multiply(2.26e-5).negate().add(1.0).pow(5.225)); + final T rh = pth0.getRelativeHumidity().multiply(FastMath.exp(dh.multiply(-6.396e-4))); + return new FieldPressureTemperatureHumidity<>(p, t, rh, provider.waterVaporPressure(p, t, rh)); + } + +} diff --git a/src/main/java/org/orekit/models/earth/weather/water/NbsNrcSteamTable.java b/src/main/java/org/orekit/models/earth/weather/water/NbsNrcSteamTable.java index 08e9bc6b64..ef1ab955c1 100644 --- a/src/main/java/org/orekit/models/earth/weather/water/NbsNrcSteamTable.java +++ b/src/main/java/org/orekit/models/earth/weather/water/NbsNrcSteamTable.java @@ -37,7 +37,7 @@ public class NbsNrcSteamTable implements WaterVaporPressureProvider { /** Celsius temperature offset. */ private static final double CELSIUS = 273.15; - /** Minimum temperature of the model. */ + /** Minimum temperature of the model, at the triple point of water, i.e. 273.16K (which is 0.01°C). */ private static final double MIN_T = CELSIUS + 0.01; /** Saturation pressure model. */ @@ -71,13 +71,13 @@ public class NbsNrcSteamTable implements WaterVaporPressureProvider { /** {@inheritDoc} */ @Override - public double waterVaporPressure(final double t, final double p, final double rh) { + public double waterVaporPressure(final double p, final double t, final double rh) { return MODEL.value(FastMath.max(t, MIN_T)) * rh; } /** {@inheritDoc} */ @Override - public > T waterVaporPressure(final T t, final T p, final T rh) { + public > T waterVaporPressure(final T p, final T t, final T rh) { return MODEL.value(FastMath.max(t, MIN_T)).multiply(rh); } diff --git a/src/test/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModelTest.java new file mode 100644 index 0000000000..dd582bfb83 --- /dev/null +++ b/src/test/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModelTest.java @@ -0,0 +1,58 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS Communication & Systèmes (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import org.hipparchus.util.FastMath; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.orekit.Utils; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.time.AbsoluteDate; + + +public class CanonicalSaastamoinenModelTest { + + @Test + public void testComparisonToModifiedModelLowElevation() { + doTestComparisonToModifiedModel(FastMath.toRadians(5), 0.06, 0.15); + } + + @Test + public void testComparisonToModifiedModelHighElevation() { + doTestComparisonToModifiedModel(FastMath.toRadians(60), -0.001, 0.003); + } + + private void doTestComparisonToModifiedModel(final double elevation, + final double minDifference, final double maxDifference) { + final CanonicalSaastamoinenModel canonical = CanonicalSaastamoinenModel.getStandardModel(); + final ModifiedSaastamoinenModel modified = ModifiedSaastamoinenModel.getStandardModel(); + for (double height = 0; height < 5000; height += 100) { + final GeodeticPoint location = new GeodeticPoint(0.0, 0.0, height); + final double canonicalDelay = canonical.pathDelay(elevation, location, null, AbsoluteDate.J2000_EPOCH); + final double modifiedDelay = modified.pathDelay(elevation, location, null, AbsoluteDate.J2000_EPOCH); + Assertions.assertTrue(modifiedDelay - canonicalDelay > minDifference); + Assertions.assertTrue(modifiedDelay - canonicalDelay < maxDifference); + } + } + + @BeforeEach + public void setUp() { + Utils.setDataRoot("atmosphere"); + } + +} diff --git a/src/test/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModelTest.java index 06417ed067..91f24deabf 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModelTest.java @@ -121,7 +121,7 @@ public void NoFile() { final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(pressure, temperature, humidity, waterPressure); final PressureTemperatureHumidityProvider pthProvider = new ConstantPressureTemperatureHumidityProvider(pth); - new ModifiedSaastamoinenModel(pthProvider, "^non-existent-file$"); + new ModifiedSaastamoinenModel(0.0, pthProvider, "^non-existent-file$"); Assertions.fail("an exception should have been thrown"); } catch (OrekitException oe) { Assertions.assertEquals(OrekitMessages.UNABLE_TO_FIND_FILE, oe.getSpecifier()); @@ -141,8 +141,8 @@ public void compareDefaultAndLoaded() { final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(pressure, temperature, humidity, waterPressure); final PressureTemperatureHumidityProvider pthProvider = new ConstantPressureTemperatureHumidityProvider(pth); - ModifiedSaastamoinenModel defaultModel = new ModifiedSaastamoinenModel(pthProvider, null); - ModifiedSaastamoinenModel loadedModel = new ModifiedSaastamoinenModel(pthProvider, ModifiedSaastamoinenModel.DELTA_R_FILE_NAME); + ModifiedSaastamoinenModel defaultModel = new ModifiedSaastamoinenModel(0.0, pthProvider, null); + ModifiedSaastamoinenModel loadedModel = new ModifiedSaastamoinenModel(0.0, pthProvider, ModifiedSaastamoinenModel.DELTA_R_FILE_NAME); double[] heights = new double[] { 0.0, 250.0, 500.0, 750.0, 1000.0, 1250.0, 1500.0, 1750.0, 2000.0, 2250.0, 2500.0, 2750.0, 3000.0, 3250.0, 3500.0, 3750.0, 4000.0, 4250.0, 4500.0, 4750.0, 5000.0 @@ -235,6 +235,8 @@ public void compareExpectedValues() { final double pressure = TropoUnit.HECTO_PASCAL.toSI(1013.25); // it seems the reference values for the test have been computed using a wrong conversion // between Celsius and Kelvin (273.16 offset instead of 273.15) + // which is probably due to a similar error in equation 5.97 of + // Guochang Xu, GPS - Theory, Algorithms and Applications, Springer, 2007 // so for the sake of the test, we use a temperature of 18.01°C and not the standard atmosphere at 18.00°C final double temperature = 273.15 + 18.01; final double humidity = 0.5; @@ -244,7 +246,8 @@ public void compareExpectedValues() { ModifiedSaastamoinenModel.WATER.waterVaporPressure(pressure, temperature, humidity)); - ModifiedSaastamoinenModel model = new ModifiedSaastamoinenModel(new ConstantPressureTemperatureHumidityProvider(pth)); + final PressureTemperatureHumidityProvider pth0Provider = new ConstantPressureTemperatureHumidityProvider(pth); + ModifiedSaastamoinenModel model = new ModifiedSaastamoinenModel(0.0, pth0Provider); for (int h = 0; h < heights.length; h++) { for (int e = 0; e < elevations.length; e++) { @@ -278,7 +281,8 @@ private > void doCompareFieldExpectedValues(fi ModifiedSaastamoinenModel.WATER.waterVaporPressure(pressure, temperature, humidity)); - ModifiedSaastamoinenModel model = new ModifiedSaastamoinenModel(new ConstantPressureTemperatureHumidityProvider(pth)); + final PressureTemperatureHumidityProvider pth0Provider = new ConstantPressureTemperatureHumidityProvider(pth); + ModifiedSaastamoinenModel model = new ModifiedSaastamoinenModel(0.0, pth0Provider); for (int h = 0; h < heights.length; h++) { for (int e = 0; e < elevations.length; e++) { From 3f373301459a087d258fd32b17cb594aa9b81522 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Sat, 9 Dec 2023 10:28:44 +0100 Subject: [PATCH 029/359] Fixed parsing of SP3 files with partly missing standard deviations. Fixes #1286 --- src/changes/changes.xml | 3 + .../java/org/orekit/files/sp3/SP3Parser.java | 10 +- .../org/orekit/files/sp3/SP3ParserTest.java | 23 + .../sp3/missing-standard-deviation.sp3 | 716 ++++++++++++++++++ 4 files changed, 750 insertions(+), 2 deletions(-) create mode 100644 src/test/resources/sp3/missing-standard-deviation.sp3 diff --git a/src/changes/changes.xml b/src/changes/changes.xml index b4dd059bfc..ff90f8a4bd 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -21,6 +21,9 @@ + + Fixed parsing of SP3 files with partly missing standard deviations. + Added field versions of unit conversions from and to SI units. diff --git a/src/main/java/org/orekit/files/sp3/SP3Parser.java b/src/main/java/org/orekit/files/sp3/SP3Parser.java index b5ef3106af..7b16d6cd4e 100644 --- a/src/main/java/org/orekit/files/sp3/SP3Parser.java +++ b/src/main/java/org/orekit/files/sp3/SP3Parser.java @@ -705,7 +705,10 @@ public void parse(final String line, final ParseInfo pi) { if (pi.latestPosition.getNorm() > 0) { - if (line.length() < 69 || line.substring(61, 69).trim().length() == 0) { + if (line.length() < 69 || + line.substring(61, 63).trim().length() == 0 || + line.substring(64, 66).trim().length() == 0 || + line.substring(67, 69).trim().length() == 0) { pi.latestPositionAccuracy = null; } else { pi.latestPositionAccuracy = new Vector3D(SP3Utils.siAccuracy(SP3Utils.POSITION_ACCURACY_UNIT, @@ -795,7 +798,10 @@ public void parse(final String line, final ParseInfo pi) { Double.parseDouble(line.substring(46, 60).trim())); final Vector3D velocityAccuracy; - if (line.length() < 69 || line.substring(61, 69).trim().length() == 0) { + if (line.length() < 69 || + line.substring(61, 63).trim().length() == 0 || + line.substring(64, 66).trim().length() == 0 || + line.substring(67, 69).trim().length() == 0) { velocityAccuracy = null; } else { velocityAccuracy = new Vector3D(SP3Utils.siAccuracy(SP3Utils.VELOCITY_ACCURACY_UNIT, diff --git a/src/test/java/org/orekit/files/sp3/SP3ParserTest.java b/src/test/java/org/orekit/files/sp3/SP3ParserTest.java index 0adac6f16b..7c085f4f7f 100644 --- a/src/test/java/org/orekit/files/sp3/SP3ParserTest.java +++ b/src/test/java/org/orekit/files/sp3/SP3ParserTest.java @@ -445,6 +445,29 @@ public void testMissingEOF() throws IOException { } + @Test + public void testMissingStandardDeviation() throws IOException { + final String ex = "/sp3/missing-standard-deviation.sp3"; + final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex)); + final Frame frame = FramesFactory.getITRF(IERSConventions.IERS_2003, true); + final SP3Parser parser = new SP3Parser(Constants.EIGEN5C_EARTH_MU, 3, s -> frame); + final SP3 sp3 = parser.parse(source); + Assertions.assertEquals(32, sp3.getSatelliteCount()); + List coordinates06 = sp3.getEphemeris("G06").getSegments().get(0).getCoordinates(); + Assertions.assertEquals(21, coordinates06.size()); + for (int i = 0; i < 21; ++i) { + final Vector3D positionAccuracy = coordinates06.get(i).getPositionAccuracy(); + if (i == 7 || i == 8) { + // some standard deviations are missing + Assertions.assertNull(positionAccuracy); + } else { + // other are present + Assertions.assertTrue(positionAccuracy.getNorm() < 0.0122); + Assertions.assertTrue(positionAccuracy.getNorm() > 0.0045); + } + } + } + @Test public void testWrongLineIdentifier() throws IOException { try { diff --git a/src/test/resources/sp3/missing-standard-deviation.sp3 b/src/test/resources/sp3/missing-standard-deviation.sp3 new file mode 100644 index 0000000000..6b84861d94 --- /dev/null +++ b/src/test/resources/sp3/missing-standard-deviation.sp3 @@ -0,0 +1,716 @@ +#cP2023 7 31 6 0 0.00000000 21 ORBIT IGS20 HLM IGS +## 2273 108000.00000000 900.00000000 60156 0.2500000000000 ++ 32 G01G02G03G04G05G06G07G08G09G10G11G12G13G14G15G16G17 ++ G18G19G20G21G22G23G24G25G26G27G28G29G30G31G32 0 0 ++ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +++ 3 3 4 4 4 4 3 4 3 3 4 3 4 4 4 4 4 +++ 3 4 4 3 5 4 4 3 4 4 4 3 4 4 3 0 0 +++ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +++ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +++ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +%c G cc GPS ccc cccc cccc cccc cccc ccccc ccccc ccccc ccccc +%c cc cc ccc ccc cccc cccc cccc cccc ccccc ccccc ccccc ccccc +%f 1.2500000 1.025000000 0.00000000000 0.000000000000000 +%f 0.0000000 0.000000000 0.00000000000 0.000000000000000 +%i 0 0 0 0 0 0 0 0 0 +%i 0 0 0 0 0 0 0 0 0 +/* ULTRA ORBIT COMBINATION 22732_06 (60157.250) FROM: +/* cou emu esu gfu gru siu usu whu +/* REFERENCED TO emu CLOCK AND TO WEIGHTED MEAN POLE: +/* PCV:IGS20 OL/AL:FES2014b NONE Y ORB:CMB CLK:CMB +* 2023 7 31 6 0 0.00000000 +PG01 5370.288362 -17056.193267 -19861.821809 170.525951 7 8 6 174 +PG02 11570.045645 -18654.831442 -14332.375724 -570.582464 8 7 6 191 +PG03 -5811.034233 -18526.685666 -18317.775661 -209.240648 8 8 7 207 +PG04 105.872552 -26291.706278 3291.884762 111.406385 8 8 6 189 +PG05 -10472.800237 11092.759180 21569.214671 -136.961268 7 10 7 145 +PG06 -23955.422039 3822.948996 -10867.196745 572.274910 9 10 4 195 +PG07 -11909.194315 -11202.721584 21471.128553 109.508363 7 7 2 170 +PG08 6454.865410 -24178.020905 8208.339835 -134.879348 6 6 7 164 +PG09 -7520.090994 -22535.627956 11751.136758 -98.800607 6 7 6 147 +PG10 23729.360028 10447.006705 -6316.918246 -47.339270 5 9 10 200 +PG11 -23078.423429 12689.210137 3244.474640 -299.453708 5 4 10 192 +PG12 791.916183 17919.996530 -19886.713693 -407.196548 3 9 9 196 +PG13 -13080.649438 18495.656562 13504.334480 554.084890 8 9 7 172 +PG14 -23003.131672 -12967.534750 -3567.132243 139.229011 5 7 5 165 +PG15 -3005.625247 25184.609723 6965.686157 63.104130 10 6 9 134 +PG16 15308.894161 -6127.917085 20610.262231 -474.307345 7 7 7 199 +PG17 -13466.789221 -7893.871620 -21039.955648 721.973303 9 8 3 201 +PG18 13872.657412 9018.779519 20813.230668 -365.385261 10 9 8 172 +PG19 -15205.249804 267.421842 -21963.421108 351.185728 9 9 8 176 +PG20 -19278.603907 5232.073707 17445.163209 419.785129 3 7 7 162 +PG21 13466.407600 -18412.834665 -12280.873428 151.454431 7 8 7 204 +PG22 15235.085815 -4664.943536 -20770.818424 520.410972 10 8 9 154 +PG23 19926.228929 16765.912157 5661.362068 49.364254 6 9 10 148 +PG24 -8422.509892 19375.800626 -16206.450350 -274.976195 7 8 7 188 +PG25 14209.462478 19261.961766 -12105.072452 459.372399 6 7 7 200 +PG26 22752.431472 990.398871 13828.587380 234.697729 5 9 7 184 +PG27 12613.385498 -15427.689098 17098.904918 -13.347228 5 5 9 194 +PG28 23268.420338 -2792.965423 -12518.957556 79.828153 7 5 4 180 +PG29 4632.279154 23474.850878 11369.786901 -606.779095 8 9 8 197 +PG30 -20042.047222 -4209.965155 17172.777323 -500.226433 6 5 6 164 +PG31 24793.005843 -9895.376449 -2451.741287 -221.017679 3 4 9 197 +PG32 14854.437972 3996.973179 -21487.639874 -531.672466 8 9 4 193 +* 2023 7 31 6 15 0.00000000 +PG01 7298.914310 -17955.017620 -18341.951007 170.524499 7 8 7 177 +PG02 13014.113086 -19352.207057 -12054.105008 -570.578489 8 7 6 194 +PG03 -3932.857990 -17487.120427 -19781.751559 -209.225280 8 8 7 204 +PG04 373.756752 -26489.134007 434.039671 111.416403 7 9 5 189 +PG05 -12620.142485 9866.537110 21022.576190 -136.962941 7 9 7 152 +PG06 -22800.523956 3047.008514 -13301.757481 572.270901 9 10 4 198 +PG07 -9827.433007 -12354.447529 21855.423505 109.498381 7 6 3 174 +PG08 6725.694572 -23071.045815 10788.915902 -134.881520 7 5 7 172 +PG09 -7280.711146 -23749.867365 9259.207607 -98.791970 5 8 6 152 +PG10 24131.465714 10896.051078 -3515.369223 -47.340870 6 8 10 200 +PG11 -23371.452100 12558.591660 386.670489 -299.468845 5 4 10 190 +PG12 -1112.916444 16668.002867 -20939.953006 -407.200492 4 9 9 198 +PG13 -12989.796950 16784.780231 15647.741818 554.089439 8 8 7 177 +PG14 -23060.003103 -13336.480047 -760.858314 139.239644 5 7 5 166 +PG15 -3457.691400 24217.932694 9556.349948 63.107179 10 8 9 133 +PG16 17153.502793 -4671.998181 19567.263798 -474.303111 7 6 7 200 +PG17 -13180.528013 -10324.316519 -20158.999626 721.973456 8 8 2 201 +PG18 11752.953386 10182.528553 21552.905099 -365.397687 10 8 8 165 +PG19 -14906.146714 -2186.798066 -22090.692266 351.190783 8 8 8 177 +PG20 -20969.194582 4352.274242 15621.999039 419.782905 3 7 8 161 +PG21 14763.087890 -18927.865838 -9787.344018 151.454146 7 8 7 205 +PG22 15026.388102 -2166.434644 -21328.406772 520.415455 10 9 9 161 +PG23 19137.619870 16537.031215 8384.114703 49.368286 6 8 10 146 +PG24 -9978.328678 20117.097825 -14217.884351 -274.986875 6 8 7 190 +PG25 12852.171179 18688.113735 -14347.219486 459.374458 7 7 7 201 +PG26 23940.265003 1884.667242 11598.470968 234.696558 5 8 7 188 +PG27 12733.020607 -13316.993087 18721.767742 -13.353535 5 5 9 194 +PG28 22029.582830 -1829.539456 -14744.079040 79.825977 6 5 4 185 +PG29 4321.467662 24611.491113 8802.345156 -606.779939 7 9 8 200 +PG30 -18331.311857 -5313.834286 18696.574361 -500.223789 6 5 6 159 +PG31 24533.576552 -9494.587724 -5225.063138 -221.018067 4 3 8 200 +PG32 14776.554285 6460.482479 -20957.329584 -531.679016 8 9 5 193 +* 2023 7 31 6 30 0.00000000 +PG01 9015.971554 -18865.648723 -16510.866381 170.523034 7 8 7 175 +PG02 14196.193252 -19960.124850 -9560.984261 -570.574893 8 7 6 188 +PG03 -1870.673410 -16484.996840 -20910.426052 -209.209998 9 8 6 206 +PG04 631.268188 -26375.216822 -2431.333507 111.426408 6 9 5 186 +PG05 -14752.401846 8791.536544 20108.864520 -136.963650 7 8 7 161 +PG06 -21466.707122 2068.181674 -15507.701035 572.266887 9 9 3 194 +PG07 -7785.407453 -13626.818032 21880.115661 109.488516 7 4 4 169 +PG08 7069.782660 -21696.253058 13179.176338 -134.883670 7 5 7 162 +PG09 -7087.625755 -24683.145639 6607.012487 -98.783344 3 8 6 148 +PG10 24276.073411 11171.416662 -654.299992 -47.341126 6 8 9 201 +PG11 -23387.655797 12285.281897 -2477.806233 -299.483962 6 4 10 191 +PG12 -3165.013285 15467.837046 -21641.926342 -407.204824 5 10 9 200 +PG13 -12966.172269 14843.064555 17515.978243 554.093474 8 7 7 187 +PG14 -22860.598157 -13544.648512 2058.379822 139.250265 6 7 5 160 +PG15 -4007.242744 22989.716943 11976.898436 63.110439 10 9 8 118 +PG16 18951.971202 -3393.961297 18182.851282 -474.298945 6 6 7 199 +PG17 -13026.680052 -12642.936824 -18916.909439 721.974422 8 9 3 196 +PG18 9644.340758 11492.893372 21922.433345 -365.410066 9 6 8 169 +PG19 -14742.272171 -4643.959920 -21845.414390 351.195188 8 6 9 174 +PG20 -22492.060468 3626.978393 13528.428759 419.781504 3 7 7 163 +PG21 15789.690740 -19326.271186 -7112.659581 151.453754 7 8 7 202 +PG22 14943.675063 380.879624 -21502.829609 520.420349 9 10 9 149 +PG23 18068.802694 16219.148029 10963.954965 49.372296 7 8 10 146 +PG24 -11312.570094 20788.964880 -11985.166571 -274.997593 6 7 7 186 +PG25 11257.585225 18076.534148 -16350.024567 459.376487 6 7 7 202 +PG26 24930.138829 2611.856162 9171.140617 234.695403 4 8 7 185 +PG27 12968.396893 -11049.729547 20011.613220 -13.359890 6 4 8 195 +PG28 20645.932267 -670.140407 -16715.783054 79.823833 6 6 5 177 +PG29 4084.859161 25462.664452 6082.256458 -606.780761 6 9 8 200 +PG30 -16544.951534 -6580.450980 19904.276586 -500.221104 6 5 5 168 +PG31 24032.809657 -8925.769496 -7911.050724 -221.018697 4 4 8 197 +PG32 14822.684553 8841.124237 -20061.650465 -531.685598 7 8 5 196 +* 2023 7 31 6 45 0.00000000 +PG01 10500.162819 -19745.772137 -14398.288442 170.521512 6 8 8 171 +PG02 15115.917565 -20437.548760 -6898.231992 -570.571042 7 7 6 188 +PG03 342.197190 -15554.966794 -21684.614940 -209.194737 9 8 5 204 +PG04 915.801893 -25952.498824 -5254.551832 111.436391 6 10 6 181 +PG05 -16821.384017 7877.008825 18844.566969 -136.965279 6 7 7 167 +PG06 -19998.007007 878.440128 -17446.844948 572.262902 8 9 4 196 +PG07 -5821.767985 -14995.732572 21543.443892 109.478727 7 4 4 164 +PG08 7515.884152 -20083.945661 15337.213908 -134.885802 7 5 7 154 +PG09 -6905.479708 -25319.847306 3840.535320 -98.774704 2 8 6 144 +PG10 24141.627893 11305.337106 2217.837236 -47.343036 7 7 9 200 +PG11 -23147.616792 11837.774068 -5299.507852 -299.499046 6 5 9 193 +PG12 -5329.820844 14351.640327 -21980.941196 -407.208822 5 11 9 201 +PG13 -13038.011495 12707.006114 19076.160045 554.097913 7 6 7 187 +PG14 -22388.522023 -13624.195234 4842.549221 139.260952 6 7 5 161 +PG15 -4679.023056 21529.455507 14183.449471 63.113862 9 9 8 126 +PG16 20658.364846 -2301.846382 16482.760811 -474.294632 6 6 7 196 +PG17 -12989.849630 -14802.062223 -17336.425484 721.975084 7 9 3 195 +PG18 7591.633883 12928.305778 21914.955667 -365.422458 9 6 8 170 +PG19 -14713.483919 -7055.563894 -21232.603451 351.199853 7 5 9 173 +PG20 -23807.518316 3040.892249 11200.367736 419.779499 4 8 7 166 +PG21 16550.463470 -19568.259568 -4306.714848 151.452971 8 7 7 201 +PG22 14991.357842 2925.303368 -21291.327639 520.425094 9 10 10 143 +PG23 16724.219418 15852.715189 13356.809108 49.376240 7 8 9 152 +PG24 -12418.713634 21351.185450 -9545.494205 -275.008292 5 7 7 191 +PG25 9443.240901 17465.202073 -18080.394538 459.378479 6 7 7 201 +PG26 25689.828683 3190.965758 6588.264137 234.694212 3 7 7 185 +PG27 13334.209286 -8673.029849 20946.098927 -13.366207 6 4 7 193 +PG28 19161.242961 686.423493 -18400.242336 79.821612 6 6 5 178 +PG29 3886.830288 26009.966140 3256.720686 -606.781571 5 9 8 201 +PG30 -14725.966310 -8000.796162 20775.040411 -500.218461 6 5 5 168 +PG31 23320.912208 -8166.413458 -10464.935997 -221.019478 5 6 8 198 +PG32 14978.858578 11092.547898 -18816.991979 -531.692170 6 7 6 196 +* 2023 7 31 7 0 0.00000000 +PG01 11738.565029 -20551.000111 -12039.011811 170.520016 6 7 8 174 +PG02 15781.980140 -20746.015740 -4113.708855 -570.567592 8 6 7 188 +PG03 2666.333592 -14725.923804 -22091.043650 -209.179495 9 9 5 203 +PG04 1263.480393 -25232.450958 -7986.667642 111.446417 4 9 6 181 +PG05 -18779.241604 7123.759297 17252.296135 -136.966645 6 7 7 166 +PG06 -18440.732531 -521.543234 -19085.522796 572.258947 8 8 5 195 +PG07 -3970.802291 -16430.774234 20849.380838 109.468813 6 5 5 157 +PG08 8087.041855 -18271.088292 17225.412455 -134.887576 7 5 7 157 +PG09 -6697.298970 -25653.028748 1007.676183 -98.766101 3 7 7 146 +PG10 23714.462866 11334.098286 5052.622826 -47.344147 8 7 9 199 +PG11 -22679.050673 11190.009960 -8029.721931 -299.514192 6 6 9 187 +PG12 -7567.527573 13345.502192 -21951.234079 -407.212875 6 11 9 202 +PG13 -13227.177595 10419.072096 20300.941463 554.102316 7 5 7 195 +PG14 -21635.232016 -13610.517323 7544.220499 139.271615 7 7 6 155 +PG15 -5491.787991 19873.082979 16135.797221 63.116971 9 9 7 138 +PG16 22227.805233 -1395.090992 14497.970270 -474.290331 6 6 7 194 +PG17 -13047.261984 -16758.996666 -15446.476665 721.975209 7 9 3 196 +PG18 5635.704018 14459.881733 21530.079556 -365.434806 9 7 8 174 +PG19 -14811.547827 -9374.381148 -20263.283549 351.204648 6 5 10 174 +PG20 -24881.022261 2572.063953 8677.924892 419.777581 4 9 8 165 +PG21 17058.879003 -19617.908187 -1421.613317 151.452028 8 6 7 201 +PG22 15165.477255 5415.277805 -20698.347559 520.430072 9 10 10 118 +PG23 15117.092782 15477.609767 15521.713788 49.380265 7 9 9 154 +PG24 -13298.192233 21764.518817 -6940.088517 -275.019000 5 7 7 188 +PG25 7434.039873 16889.122487 -19509.686786 459.380432 6 7 7 200 +PG26 26192.870955 3646.773409 3893.902310 234.692994 2 5 7 187 +PG27 13837.160360 -6236.851052 21509.460005 -13.372503 6 3 6 196 +PG28 17620.181914 2232.996393 -19768.571294 79.819398 6 7 6 176 +PG29 3689.424766 26243.862575 374.746295 -606.782298 5 8 9 203 +PG30 -12916.089143 -9558.241543 21293.581664 -500.215817 6 5 5 171 +PG31 22433.023368 -7200.580843 -12844.159459 -221.020168 5 7 7 199 +PG32 15223.901001 13172.620181 -17245.788156 -531.698741 6 7 6 198 +* 2023 7 31 7 15 0.00000000 +PG01 12727.016890 -21236.600692 -9472.416440 170.518475 6 5 8 172 +PG02 16211.502490 -20851.234433 -1256.953788 -570.563886 8 5 7 187 +PG03 5057.513117 -14019.932095 -22122.571613 -209.164184 9 9 4 201 +PG04 1707.538943 -24235.043332 -10580.336902 111.456420 3 9 6 180 +PG05 -20580.208356 6524.296774 15360.341626 -136.967581 6 8 7 171 +PG06 -16841.722564 -2122.207400 -20395.183249 572.255030 8 6 5 196 +PG07 -2261.300215 -17896.180955 19807.678999 109.459090 6 6 6 154 +PG08 8799.509155 -16299.930425 18811.126504 -134.890344 7 4 6 154 +PG09 -6426.120517 -25684.598840 -1842.593509 -98.757552 3 8 7 147 +PG10 22989.363257 11296.486301 7802.435663 -47.345054 8 7 8 198 +PG11 -22015.651169 10322.578871 -10621.320617 -299.529353 6 6 9 191 +PG12 -9834.367813 12468.553189 -21553.064569 -407.216931 7 11 9 204 +PG13 -13548.185635 8026.187390 21169.019239 554.106653 7 4 7 197 +PG14 -20600.476174 -13540.740182 10117.352182 139.282265 7 6 6 159 +PG15 -6457.298678 18061.641383 17798.265239 63.120150 9 9 7 145 +PG16 23618.110535 -664.825660 12264.051240 -474.286143 5 6 8 193 +PG17 -13169.827186 -18477.542747 -13281.557769 721.976065 6 9 3 192 +PG18 3812.052830 16052.403350 20773.922217 -365.447143 8 7 8 177 +PG19 -15020.518038 -11556.024725 -18954.267546 351.209119 5 6 10 172 +PG20 -25684.455579 2192.919648 6004.710161 419.775588 5 9 7 164 +PG21 17336.789428 -19444.763237 1489.512034 151.451536 8 5 7 199 +PG22 15453.903458 7801.266233 -19735.405299 520.434581 8 9 10 119 +PG23 13269.096163 15131.497446 17421.506347 49.384251 7 9 9 156 +PG24 -13960.227828 21992.321238 -4213.544917 -275.029726 4 7 7 187 +PG25 5261.503021 16378.987764 -20614.127315 459.382433 6 7 7 199 +PG26 26419.527155 4008.673869 1133.777686 234.691772 2 4 6 187 +PG27 14475.633935 -3792.148378 21692.754842 -13.378793 6 4 5 194 +PG28 16066.640515 3954.159392 -20797.315517 79.817162 5 7 7 175 +PG29 3454.034060 26164.005920 -2513.720725 -606.783256 5 7 8 203 +PG30 -11154.318747 -11228.994949 21450.457415 -500.213125 6 5 5 172 +PG31 21407.873228 -6019.673417 -15009.011002 -221.020678 5 8 7 199 +PG32 15530.359501 15044.854685 -15376.061758 -531.705302 6 7 6 198 +* 2023 7 31 7 30 0.00000000 +PG01 13470.177359 -21759.283162 -6741.878411 170.516963 5 4 8 162 +PG02 16429.074858 -20724.497870 1621.776511 -570.560316 8 5 7 183 +PG03 7468.190085 -13451.421902 -21778.324281 -209.148935 9 9 4 201 +PG04 2276.826846 -22987.996646 -12990.657185 111.466497 2 8 7 192 +PG05 -22182.250943 6063.318570 13202.122204 -136.968873 6 8 7 165 +PG06 -15246.588829 -3905.263460 -21352.904857 572.251085 8 3 5 197 +PG07 -715.603981 -19352.034714 18433.843544 109.449078 5 7 7 160 +PG08 9661.961495 -14216.434953 20067.251611 -134.891509 7 4 6 150 +PG09 -6056.621637 -25425.166562 -4661.089484 -98.749012 4 10 7 146 +PG10 21969.824184 11232.159428 10421.195535 -47.346926 8 7 8 199 +PG11 -21195.714585 9223.662513 -13029.581814 -299.544495 7 6 9 189 +PG12 -12084.076578 11732.321868 -20792.727089 -407.220994 7 11 9 203 +PG13 -14007.539231 5578.050376 21665.513855 554.110942 7 4 7 198 +PG14 -19292.428965 -13452.146007 12518.053100 139.292895 7 6 6 164 +PG15 -7579.609696 16139.729200 19140.471385 63.123240 8 8 6 135 +PG16 24791.316512 -94.489826 9820.464765 -474.281723 6 7 8 194 +PG17 -13323.470667 -19929.249605 -10880.994490 721.976041 6 7 4 174 +PG18 2149.594827 17665.562267 19659.040422 -365.459592 8 7 8 175 +PG19 -15317.407785 -13560.411079 -17327.861037 351.213551 5 6 10 171 +PG20 -26197.186827 1871.530024 3227.070540 419.774263 6 8 7 165 +PG21 17413.229841 -19025.183096 4373.665390 151.451208 8 5 8 197 +PG22 15836.892402 10037.541750 -18420.791360 520.439505 7 9 10 119 +PG23 11209.708779 14848.287504 19023.457587 49.388254 7 9 9 159 +PG24 -14421.358261 22002.107702 -1413.089096 -275.040456 3 7 7 182 +PG25 2962.790839 15960.007430 -21375.165203 459.384456 6 7 7 199 +PG26 26357.504922 4309.356870 -1645.468655 234.690562 3 4 6 183 +PG27 15239.725826 -1389.027820 21493.962439 -13.385013 5 5 6 192 +PG28 14542.109909 5826.636968 -21468.848387 79.814963 5 8 7 173 +PG29 3143.103676 25779.200482 -5358.681761 -606.783916 6 6 8 200 +PG30 -9475.557215 -12982.824349 21242.262245 -500.210483 6 5 5 175 +PG31 20286.325654 -4622.940920 -16923.231659 -221.021576 5 9 7 198 +PG32 15865.684029 16679.613412 -13240.874990 -531.711758 6 8 7 198 +* 2023 7 31 7 45 0.00000000 +PG01 13981.244044 -22078.971379 -3894.083635 170.515400 5 4 8 162 +PG02 16465.524891 -20343.856954 4472.441375 -570.556718 8 5 7 186 +PG03 9849.106608 -13026.681273 -21063.730021 -209.133663 9 9 3 200 +PG04 2994.485132 -21525.742926 -15175.959221 111.476582 4 8 7 193 +PG05 -23548.573776 5718.507419 10815.551918 -136.970375 6 9 8 159 +PG06 -13698.013307 -5844.198436 -21941.816232 572.247160 8 4 197 +PG07 651.118677 -20755.634601 16749.024099 109.439219 4 8 7 159 +PG08 10675.027531 -12068.579126 20972.675414 -134.892859 8 4 5 154 +PG09 -5556.683974 -24893.563427 -7399.270809 -98.740373 5 8 7 145 +PG10 20667.999953 11180.003106 12865.074124 -47.348671 8 7 7 198 +PG11 -20260.598088 7889.688165 -15212.967314 -299.559606 6 6 8 187 +PG12 -14269.445439 11140.379024 -19682.479246 -407.225186 7 11 8 202 +PG13 -14603.405155 3125.347399 21782.220047 554.115160 8 4 7 195 +PG14 -17727.518409 -13380.603678 14705.311651 139.303578 7 5 6 168 +PG15 -8854.688384 14153.800402 20137.979756 63.126733 8 7 6 135 +PG16 25715.023112 339.265379 7209.818577 -474.277471 6 7 8 194 +PG17 -13470.667862 -21094.334949 -8288.119433 721.977312 6 6 5 175 +PG18 669.696983 19255.418496 18204.246486 -365.472038 7 8 8 174 +PG19 -15673.124687 -15353.062924 -15411.494855 351.218115 4 6 9 175 +PG20 -26406.846681 1573.057244 393.268733 419.772286 6 8 7 164 +PG21 17322.941134 -18343.367565 7179.102643 151.451223 9 6 8 198 +PG22 16287.969687 12083.801032 -16779.130987 520.443954 6 8 10 134 +PG23 8975.278369 14656.737598 20299.836703 49.392259 7 9 9 159 +PG24 -14704.666411 21766.987413 1412.250710 -275.051201 2 7 7 182 +PG25 579.523203 15650.945987 -21779.760843 459.386495 6 7 7 199 +PG26 26002.412258 4583.372334 -4397.022544 234.689382 3 4 6 184 +PG27 16111.625425 925.043359 20917.934446 -13.391311 5 6 7 190 +PG28 13084.162040 7820.010170 -21771.668557 79.812762 5 7 7 176 +PG29 2721.796523 25107.023426 -8110.967221 -606.784645 7 6 8 200 +PG30 -7909.403091 -14784.037441 20671.733581 -500.207803 6 4 4 170 +PG31 19109.855351 -3017.706898 -18554.571096 -221.021735 6 9 7 197 +PG32 16193.606723 18055.036874 -10877.700680 -531.718312 7 8 7 196 +* 2023 7 31 8 0 0.00000000 +PG01 14281.333717 -22160.493610 -978.251245 170.513851 5 4 7 166 +PG02 16356.473492 -19695.014401 7246.103404 -570.553105 9 6 7 188 +PG03 12150.976992 -12743.664332 -19990.459894 -209.118384 8 8 3 201 +PG04 3876.853590 -19888.137218 -17098.537023 111.486642 6 7 7 195 +PG05 -24648.919401 5461.604364 8242.335158 -136.971645 6 8 8 154 +PG06 -12234.166632 -7905.105755 -22151.412721 572.243195 7 3 197 +PG07 1831.346321 -22063.011805 14779.817660 109.429504 3 8 8 160 +PG08 11831.155953 -9904.598884 21512.603131 -134.894782 8 3 4 159 +PG09 -4898.830815 -24116.061283 -10010.078264 -98.731615 7 3 8 130 +PG10 19104.346872 11176.526655 15093.167572 -47.349713 9 7 7 197 +PG11 -19253.072464 6325.663926 -17133.843860 -299.574745 6 5 8 189 +PG12 -16343.925984 10688.283203 -18240.385696 -407.229323 7 11 8 203 +PG13 -15325.638027 717.939695 21517.722900 554.119765 8 4 6 193 +PG14 -15929.950095 -13359.059273 16641.681069 139.314242 7 4 6 171 +PG15 -10270.386489 12150.388970 20772.818375 63.129960 8 7 6 132 +PG16 26363.521161 665.430472 4477.102011 -474.273285 7 7 8 195 +PG17 -13572.112556 -21962.248300 -5549.384242 721.977576 5 7 6 178 +PG18 -614.485668 20776.019724 16434.311185 -365.484447 7 7 7 170 +PG19 -16053.636109 -16906.209754 -13237.291154 351.222781 3 6 9 176 +PG20 -26309.792811 1261.324127 -2447.379794 419.770358 6 7 7 152 +PG21 17104.691972 -17392.036161 9856.360363 151.451411 9 7 8 201 +PG22 16775.097562 13906.537593 -14840.816461 520.448933 5 7 10 132 +PG23 6607.824537 14579.262199 21228.398648 49.396313 7 9 8 156 +PG24 -14838.735933 21266.908489 4212.541019 -275.061888 1 7 7 180 +PG25 -1843.562457 15463.402237 -21820.605104 459.388534 6 8 8 200 +PG26 25357.931164 4865.636316 -7074.635230 234.688172 3 5 6 188 +PG27 17066.326264 3106.895190 19976.209143 -13.397580 5 6 7 191 +PG28 11725.094125 9897.709795 -21700.593678 79.810552 5 7 7 178 +PG29 2159.546897 24173.116231 -10723.098139 -606.785769 7 7 8 202 +PG30 -6479.145872 -16592.684083 19747.761316 -500.205153 6 4 4 165 +PG31 17919.011519 -1219.303786 -19875.295485 -221.022712 5 9 6 198 +PG32 16475.665257 19157.671167 -8327.728692 -531.724801 8 9 8 193 +* 2023 7 31 8 15 0.00000000 +PG01 14398.541308 -21975.117364 1954.722756 170.512290 5 3 7 156 +PG02 16140.743303 -18771.912580 9895.753361 -570.549418 9 7 7 188 +PG03 14326.184857 -12592.124852 -18576.269199 -209.103149 8 8 4 201 +PG04 4932.650648 -18118.971723 -18725.303127 111.496666 7 6 7 197 +PG05 -25460.616253 5259.711310 5527.206200 -136.973217 6 8 8 145 +PG06 -10887.309695 -10047.812333 -21977.762404 572.239267 8 2 3 195 +PG07 2825.395359 -23230.537139 12557.975236 109.419802 3 8 8 163 +PG08 13114.819322 -7771.248382 21678.755055 -134.897327 8 4 3 158 +PG09 -4061.481600 -23125.317728 -12448.740199 -98.722941 8 2 7 144 +PG10 17306.973666 11254.358413 17068.124208 -47.351846 9 6 6 198 +PG11 -18215.634069 4545.182426 -18759.134356 -299.589909 6 5 8 169 +PG12 -18263.225086 10363.831595 -16490.076757 -407.233442 6 10 8 205 +PG13 -16156.151787 -1596.903166 20877.379556 554.123943 8 3 6 192 +PG14 -13930.944629 -13416.144310 18293.910313 139.324883 7 4 6 177 +PG15 -11806.767795 10174.338854 21033.846200 63.133264 8 6 6 118 +PG16 26718.663710 917.297089 1668.913023 -474.268976 7 8 8 195 +PG17 -13588.444534 -22531.859855 -2713.433450 721.977955 5 8 7 177 +PG18 -1698.350960 22181.118860 14379.556749 -365.496846 6 7 7 169 +PG19 -16421.323026 -18199.649206 -10841.567930 351.227539 1 8 168 +PG20 -25911.242765 900.441854 -5245.394169 419.768649 6 6 7 159 +PG21 16799.485724 -16172.738659 12359.173252 151.450744 9 8 8 200 +PG22 17262.068829 15480.121128 -12641.332164 520.453742 3 7 10 145 +PG23 4153.625821 14630.991317 21792.785014 49.400320 6 8 8 156 +PG24 -14856.371482 20489.652863 6937.891470 -275.072632 2 8 7 177 +PG25 -4260.070295 15401.356193 -21496.266188 459.390578 6 8 8 201 +PG26 24435.706489 5189.931987 -9633.346546 234.686973 3 6 5 188 +PG27 18072.629938 5119.117560 18686.698293 -13.403876 6 5 8 189 +PG28 10490.787989 12018.252166 -21256.847395 79.808393 5 7 7 175 +PG29 1431.443452 23010.176387 -13150.111749 -606.786517 8 8 8 201 +PG30 -5201.001485 -18365.940006 18485.297855 -500.202506 6 4 4 165 +PG31 16751.921181 749.282821 -20862.640227 -221.023063 5 9 7 198 +PG32 16672.808117 19982.772993 -5635.122599 -531.731344 8 9 8 193 +* 2023 7 31 8 30 0.00000000 +PG01 14366.708272 -21501.861010 4853.187067 170.510729 6 3 7 161 +PG02 15858.687471 -17577.002406 12377.061140 -570.545831 9 8 7 193 +PG03 16330.430867 -12554.072358 -16844.740696 -209.087866 7 8 5 198 +PG04 6162.458444 -16264.351491 -20028.357338 111.506699 8 6 6 200 +PG05 -25969.336462 5076.768690 2717.129153 -136.974609 5 8 8 143 +PG06 -9682.633889 -12227.260288 -21423.596174 572.235330 8 3 2 200 +PG07 3641.314678 -24216.565209 10120.006098 109.409989 4 8 8 167 +PG08 14503.042042 -5712.143997 21469.437059 -134.899070 8 5 3 167 +PG09 -3029.975246 -21959.091623 -14673.532173 -98.714287 8 1 7 162 +PG10 15310.722744 11440.892247 18756.721489 -47.353158 9 6 6 196 +PG11 -17188.842015 2570.092427 -20060.887821 -299.605026 5 5 8 175 +PG12 -19986.835504 10147.610202 -14460.421454 -407.237502 5 9 7 196 +PG13 -17069.619770 -3776.152277 19873.170069 554.128024 7 2 5 193 +PG14 -11767.715558 -13574.954796 19633.510697 139.335540 7 4 6 177 +PG15 -13436.777570 8267.119261 20916.958831 63.136695 8 6 6 136 +PG16 26770.457158 1130.978235 -1167.310292 -474.264667 8 7 9 198 +PG17 -13481.962143 -22811.276768 169.835160 721.978532 6 10 8 182 +PG18 -2585.852136 23425.922918 12075.345412 -365.509227 6 7 7 165 +PG19 -16736.474916 -19221.340219 -8264.286782 351.232063 7 170 +PG20 -25225.068463 456.429644 -7952.021776 419.766879 6 4 7 150 +PG21 16448.738069 -14695.800277 14645.262463 151.449892 9 8 8 205 +PG22 17710.062902 16787.544816 -10220.495216 520.458211 3 7 10 147 +PG23 1661.642057 14819.117244 21982.830491 49.404288 6 8 7 157 +PG24 -14793.133689 19431.531393 9539.432026 -275.083367 4 8 7 178 +PG25 -6623.474001 15461.001597 -20811.260620 459.392688 6 7 8 173 +PG26 23254.955372 5587.459518 -12030.184906 234.685780 3 7 5 190 +PG27 19094.396303 6931.272309 17073.260546 -13.410135 6 5 8 189 +PG28 9399.827383 14136.670893 -20448.038317 79.806253 5 6 7 182 +PG29 519.386841 21656.690453 -15350.336202 -606.787277 8 8 8 203 +PG30 -4083.620213 -20059.622598 16905.165904 -500.199863 6 4 4 153 +PG31 15642.884596 2858.051447 -21499.201546 -221.023708 4 8 7 200 +PG32 16747.018537 20534.286384 -2846.241523 -531.737862 9 9 8 188 +* 2023 7 31 8 45 0.00000000 +PG01 14223.945301 -20728.520703 7665.703462 170.509201 6 3 6 168 +PG02 15550.505504 -16121.193446 14649.045051 -570.542055 9 8 7 193 +PG03 18124.269854 -12604.536157 -14824.930607 -209.072584 6 7 5 198 +PG04 7558.532917 -14370.995875 -20985.459358 111.516820 8 6 6 199 +PG05 -26169.538438 4875.148059 -139.525993 -136.976242 5 7 8 157 +PG06 -8637.386268 -14395.090751 -20498.278793 572.231415 8 3 2 200 +PG07 4294.476868 -24983.054159 7506.675545 109.400126 4 8 8 158 +PG08 15966.226544 -3766.256720 20889.488235 -134.901452 7 6 4 164 +PG09 -1797.323429 -20658.779822 -16646.478109 -98.705551 8 2 7 148 +PG10 13156.014247 11757.133312 20130.386430 -47.354502 8 4 5 194 +PG11 -16209.745492 429.850735 -21016.758330 -299.620087 4 6 8 195 +PG12 -21479.446351 10013.826761 -12185.115441 -407.241603 5 7 7 201 +PG13 -18034.471583 -5782.485929 18523.424142 554.133111 7 3 5 198 +PG14 -9482.224438 -13852.048118 20637.248999 139.346182 7 5 6 175 +PG15 -15127.222687 6465.300639 20425.128557 63.139924 8 4 5 147 +PG16 26517.358049 1343.846382 -3984.043295 -474.260462 8 7 8 195 +PG17 -13218.248919 -22817.304794 3050.200673 721.978891 6 9 7 182 +PG18 -3289.160575 24468.804168 9561.471456 -365.521657 5 7 6 166 +PG19 -16958.873680 -19967.707500 -5548.448820 351.236557 3 5 7 170 +PG20 -24273.260006 -101.240097 -10520.119750 419.764712 6 7 138 +PG21 16092.505925 -12979.920994 16676.985247 151.449707 9 8 7 205 +PG22 18079.294426 17820.818793 -7621.635342 520.463162 3 7 11 109 +PG23 -818.169671 15142.556457 21794.768054 49.408307 5 8 7 159 +PG24 -14685.749746 18097.741363 11970.293758 -275.094076 5 8 7 185 +PG25 -8888.662057 15630.873206 -19776.044479 459.394588 6 7 8 201 +PG26 21841.811850 6085.486632 -14224.836718 234.684595 3 7 5 194 +PG27 20091.984144 8520.812861 15165.177047 -13.416375 7 4 8 192 +PG28 8462.906581 16206.090549 -19288.031281 79.804047 4 5 7 183 +PG29 -587.022858 20155.459470 -17286.101046 -606.787890 9 9 8 207 +PG30 -3127.889018 -21629.783355 15033.762823 -500.197153 6 4 4 158 +PG31 14621.112976 5070.885063 -21773.260602 -221.024205 4 8 7 203 +PG32 16662.894651 20824.497455 -8.841579 -531.744356 9 9 8 191 +* 2023 7 31 9 0 0.00000000 +PG01 14010.967228 -19652.361442 10342.040110 170.507672 7 2 6 159 +PG02 15254.609609 -14423.497236 16674.655327 -570.538496 9 7 6 190 +PG03 19674.479149 -12712.611134 -12550.919920 -209.057302 4 6 5 199 +PG04 9104.945766 -12484.532364 -21580.397845 111.526851 8 5 6 200 +PG05 -26064.581603 4617.296169 -2993.816123 -136.977852 4 6 7 138 +PG06 -7760.314842 -16501.368804 -19217.660123 572.227438 8 4 2 198 +PG07 4806.871102 -25497.096687 4762.395054 109.389985 4 8 8 155 +PG08 17469.240375 -1966.608964 19950.112406 -134.903631 7 7 5 158 +PG09 -364.665643 -19267.832346 -18333.982059 -98.696967 9 4 7 161 +PG10 10887.492544 12216.784361 21165.653945 -47.355762 8 2 4 195 +PG11 -15310.462289 -1839.420685 -21610.384960 -299.635183 5 7 8 189 +PG12 -22712.180821 9931.399657 -9702.185259 -407.245975 5 6 7 204 +PG13 -19014.143065 -7585.517682 16852.433222 554.137401 6 5 5 198 +PG14 -7119.758162 -14256.697097 21287.558535 139.356715 7 5 6 173 +PG15 -16840.016290 4799.257837 19568.280852 63.143155 7 3 5 140 +PG16 25966.271774 1592.946919 -6734.405121 -474.256143 9 6 8 196 +PG17 -12767.650125 -22574.587557 5878.019309 721.979257 6 9 7 186 +PG18 -3828.001027 25272.905249 6881.467008 -365.534062 5 6 6 167 +PG19 -17049.411226 -20443.645867 -2739.443791 351.241189 5 7 6 170 +PG20 -23085.080249 -798.234700 -12905.006003 419.762962 7 7 145 +PG21 15767.839532 -11051.462472 18421.843903 151.449128 10 7 7 202 +PG22 18330.683758 18581.004334 -4890.737287 520.467895 4 7 11 116 +PG23 -3236.582486 15591.942148 21231.327435 49.412327 5 8 6 161 +PG24 -14570.468402 16502.363494 14186.565978 -275.104796 6 8 7 178 +PG25 -11013.447068 15892.268618 -18406.920919 459.396577 5 7 8 201 +PG26 20228.429956 6706.148054 -16180.278168 234.683399 3 7 5 193 +PG27 21023.820746 9873.682975 12996.545933 -13.422665 7 6 8 190 +PG28 7682.552388 18179.382732 -17796.712952 79.801822 4 4 7 181 +PG29 -1889.902788 18551.975316 -18924.371755 -606.788880 9 9 8 204 +PG30 -2327.039433 -23034.317218 12902.662188 -500.194527 6 4 4 165 +PG31 13709.655042 7346.686927 -21679.033396 -221.024941 4 7 6 201 +PG32 16389.126481 20873.385329 2828.729476 -531.750845 9 8 8 193 +* 2023 7 31 9 15 0.00000000 +PG01 13769.308659 -18280.434584 12834.165153 170.506124 8 3 5 157 +PG02 15006.099450 -12510.386060 18421.270626 -570.534820 9 6 6 189 +PG03 20955.205203 -12842.748132 -10061.275115 -209.042027 3 5 6 200 +PG04 10778.051872 -10647.849085 -21803.250670 111.536927 8 5 7 198 +PG05 -25666.513336 4267.366552 -5797.052277 -136.979107 5 6 8 152 +PG06 -7051.456498 -18496.382452 -17603.808145 572.223529 8 4 2 197 +PG07 5206.115375 -25732.297223 1934.507444 109.380268 4 7 8 159 +PG08 18972.717572 -339.221999 18668.602262 -134.905487 5 8 6 156 +PG09 1258.590526 -17830.107238 -19707.381260 -98.688414 9 5 7 159 +PG10 8552.521452 12825.606251 21844.557525 -47.357037 8 4 195 +PG11 -14516.963444 -4196.136114 -21831.666616 -299.650300 5 7 8 192 +PG12 -23663.613199 9865.266158 -7053.411771 -407.250009 6 5 8 202 +PG13 -19968.526034 -9162.740911 14889.959675 554.142192 6 5 5 200 +PG14 -4727.380567 -14790.431266 21572.860516 139.367382 7 5 6 174 +PG15 -18533.628733 3292.154699 18363.015446 63.146537 7 4 5 137 +PG16 25132.259258 1913.443106 -9372.859055 -474.252348 9 5 8 196 +PG17 -12106.544207 -22114.467573 8605.077697 721.979980 5 9 6 186 +PG18 -4228.685206 25807.573567 4081.834141 -365.546479 6 6 5 161 +PG19 -16971.683879 -20662.222879 115.641956 351.245971 7 8 6 163 +PG20 -21695.944521 -1654.149995 -15065.262249 419.761152 7 4 7 147 +PG21 15507.318021 -8943.466654 19852.858182 151.448510 10 5 7 200 +PG22 18427.480762 19077.898784 -2075.567765 520.472543 5 8 11 116 +PG23 -5546.805232 16149.950268 20301.722917 49.416294 5 7 5 153 +PG24 -14481.432594 14667.992506 16148.201902 -275.115507 6 8 7 176 +PG25 -12959.985722 16219.954584 -16725.860153 459.398577 4 6 8 203 +PG26 18451.876521 7465.437081 -17863.362471 234.682219 4 7 5 193 +PG27 21848.036000 10984.580119 10605.612717 -13.428915 8 6 9 190 +PG28 7053.169782 20010.841768 -15999.655396 79.799601 5 4 7 177 +PG29 -3382.829647 16892.711737 -20237.298480 -606.789667 9 10 8 204 +PG30 -1667.060593 -24234.526774 10548.115360 -500.191912 5 5 4 167 +PG31 12924.553721 9640.715827 -21216.839457 -221.025377 5 6 6 200 +PG32 15899.815521 20707.698090 5618.331746 -531.757364 9 8 7 194 +* 2023 7 31 9 30 0.00000000 +PG01 13539.496602 -16629.500417 15097.214040 170.504617 8 3 4 156 +PG02 14835.396294 -10414.897998 19861.108675 -570.531209 9 5 6 187 +PG03 21948.842862 -12956.241789 -7398.424233 -209.026770 4 4 6 200 +PG04 12547.263047 -8899.569363 -21650.533305 111.547008 8 5 7 197 +PG05 -24995.540397 3792.776373 -8501.608300 -136.980244 6 6 7 161 +PG06 -6502.276386 -20332.445134 -15684.627822 572.219558 8 4 2 195 +PG07 5524.218979 -25669.932304 -927.525776 109.370823 4 6 8 153 +PG08 20434.520655 1097.650934 17067.966441 -134.906607 4 8 7 149 +PG09 3054.948321 -16388.228034 -20743.412777 -98.679820 9 6 6 161 +PG10 6199.579837 13581.077485 22154.946593 -47.357825 8 2 4 195 +PG11 -13848.110671 -6594.659754 -21676.927583 -299.665447 6 7 8 191 +PG12 -24320.523814 9777.864246 -4283.677314 -407.254103 7 5 8 203 +PG13 -20855.557487 -10500.157316 12670.656418 554.146260 6 5 5 202 +PG14 -2352.315514 -15446.884970 21487.789029 139.378046 7 6 6 174 +PG15 -20164.677906 1959.249401 16832.185444 63.149728 6 5 4 140 +PG16 24037.966782 2337.145735 -11855.877799 -474.248000 9 3 8 193 +PG17 -11218.364937 -21473.622017 11185.385503 721.980689 4 8 5 183 +PG18 -4522.882123 26049.566741 1211.217770 -365.558918 6 6 4 167 +PG19 -16693.506537 -20644.087914 2968.752421 351.250433 8 8 5 160 +PG20 -20146.071165 -2681.544379 -16963.472752 419.758900 8 5 7 162 +PG21 15337.815894 -6694.457229 20948.810073 151.448405 10 3 7 199 +PG22 18336.778604 19329.395102 775.193220 520.477351 5 8 11 129 +PG23 -7706.100642 16791.949049 19021.528301 49.420272 5 7 5 159 +PG24 -14449.143638 12625.013017 17819.845700 -275.126214 6 8 7 175 +PG25 -14696.057269 16583.137658 -14760.228570 459.400625 4 5 8 201 +PG26 16552.851990 8372.426250 -19245.355769 234.681023 5 7 6 190 +PG27 22524.096654 11856.882577 8034.053183 -13.435200 8 7 9 191 +PG28 6561.409059 21657.816408 -13927.682924 79.797330 6 4 8 173 +PG29 -5050.916491 15223.396404 -21202.671046 -606.790258 9 10 8 201 +PG30 -1127.404828 -25196.579460 8010.458265 -500.189338 5 5 3 171 +PG31 12274.267486 11906.076699 -20393.182288 -221.026049 7 6 6 199 +PG32 15175.589556 20359.791890 8312.815296 -531.763877 9 8 6 197 +* 2023 7 31 9 45 0.00000000 +PG01 13359.260413 -14725.552466 17090.403478 170.503152 8 3 3 146 +PG02 14767.079532 -8175.525872 20971.553866 -570.527867 10 4 6 190 +PG03 22646.611000 -13012.860189 -4607.956157 -209.011478 5 4 5 197 +PG04 14376.097157 -7272.706313 -21125.234446 111.557067 7 4 8 200 +PG05 -24079.208507 3165.630402 -11061.698973 -136.981911 7 7 7 149 +PG06 -6096.153370 -21965.630725 -13493.372367 572.215543 7 4 2 198 +PG07 5796.139170 -25299.836716 -3773.022715 109.361263 4 4 7 157 +PG08 21811.305034 2333.982717 15176.470786 -134.907589 6 8 8 157 +PG09 4999.312372 -14982.005997 -21424.587637 -98.671241 9 6 6 163 +PG10 3876.613155 14472.367992 22090.724856 -47.359367 7 3 5 195 +PG11 -13314.983174 -8986.877398 -21148.971555 -299.680520 6 8 8 193 +PG12 -24678.358953 9630.734418 -1440.243114 -407.258345 8 6 8 202 +PG13 -21632.883653 -11592.570302 10233.411547 554.150687 7 4 5 201 +PG14 -40.321734 -16211.960484 21033.314142 139.388704 7 6 6 179 +PG15 -21689.587444 807.543428 15004.352292 63.152946 7 6 5 138 +PG16 22712.802207 2891.176563 -14142.569627 -474.243585 9 4 8 197 +PG17 -10094.341840 -20692.532416 13575.897243 721.981198 4 7 4 187 +PG18 -4746.174670 25983.979890 -1680.464490 -365.571312 7 5 4 161 +PG19 -16188.291193 -20416.605920 5771.616659 351.255001 8 8 4 176 +PG20 -18478.957853 -3885.257269 -18566.884287 419.757439 8 6 7 152 +PG21 15279.534560 -4347.079008 21694.373112 151.447721 10 5 7 201 +PG22 18030.861658 19360.551694 3612.799505 520.482026 6 8 11 141 +PG23 -9677.253420 17486.949200 17412.438800 49.424257 6 6 3 155 +PG24 -14499.087310 10410.550267 19171.556131 -275.136922 7 8 7 174 +PG25 -16196.151553 16946.669067 -12542.424603 459.402663 3 4 8 206 +PG26 14574.283488 9428.746689 -20302.414826 234.679726 6 8 6 190 +PG27 23014.378851 12502.252154 5326.224446 -13.441475 9 7 9 189 +PG28 6186.840009 23082.235385 -11616.349064 79.795091 6 4 7 173 +PG29 -6871.219805 13587.330239 -21804.274189 -606.791240 8 10 8 200 +PG30 -681.961163 -25892.798576 5333.431190 -500.186661 3 5 3 163 +PG31 11759.382584 14095.315752 -19220.734811 -221.026862 8 6 5 196 +PG32 14204.473615 19866.278966 10866.774501 -531.770381 10 8 5 194 +* 2023 7 31 10 0 0.00000000 +PG01 13261.859273 -12602.959202 18777.865535 170.501680 9 4 2 140 +PG02 14818.959996 -5834.932795 21735.405597 -570.524217 10 5 7 190 +PG03 23048.799179 -12972.554066 -1737.852981 -208.996115 6 4 5 197 +PG04 16223.461230 -5793.547879 -20236.739957 111.567132 6 3 9 201 +PG05 -22951.323888 2363.959901 -13434.116994 -136.983384 7 7 7 143 +PG06 -5809.192096 -23357.372442 -11068.055759 572.211549 6 5 3 199 +PG07 6058.188041 -24620.966999 -6551.047672 109.351007 5 3 7 166 +PG08 23060.125400 3368.110836 13027.105554 -134.910424 8 9 8 164 +PG09 7059.771690 -13646.986273 -21739.467909 -98.662665 9 6 6 168 +PG10 1629.398883 15480.631936 21652.003944 -47.361227 7 4 5 196 +PG11 -12920.519058 -11323.865821 -20257.023892 -299.695541 7 8 8 195 +PG12 -24741.372891 9386.181496 1428.034280 -407.262583 9 6 8 198 +PG13 -22259.532893 -12443.537793 7620.633044 554.154977 8 2 4 197 +PG14 2165.879237 -17064.302495 20216.758999 139.399366 7 6 5 181 +PG15 -23066.240584 -164.219721 12913.137388 63.156061 7 7 6 128 +PG16 21191.888042 3596.809283 -16195.262245 -474.239421 9 5 7 199 +PG17 -8733.938683 -19813.850649 15737.156410 721.982063 6 6 3 188 +PG18 -4936.460972 25604.856782 -4542.918127 -365.583782 8 4 4 155 +PG19 -15436.237942 -20012.743889 8476.522958 351.259386 8 8 4 172 +PG20 -16739.745480 -5262.039003 -19847.974894 419.755515 8 6 6 148 +PG21 15345.320198 -1946.631408 22080.140170 151.447286 11 6 8 201 +PG22 17488.340835 19202.417494 6389.250164 520.486865 7 8 11 146 +PG23 -11429.830532 18198.819728 15501.921782 49.428215 7 6 2 155 +PG24 -14650.584768 8067.141304 20179.405472 -275.147621 7 8 7 168 +PG25 -17442.322590 17272.443991 -10109.420337 459.404714 3 5 8 201 +PG26 12559.839084 10628.347318 -21015.999617 234.678530 6 8 7 191 +PG27 23285.621758 12939.935817 2528.398552 -13.447743 10 7 10 188 +PG28 5902.906904 24251.968570 -9105.332065 79.792861 7 4 7 175 +PG29 -8813.460111 12023.817739 -22032.138903 -606.791935 8 10 8 199 +PG30 -300.260512 -26302.734242 2563.422057 -500.184030 3 5 2 162 +PG31 11372.632708 16162.063626 -17718.223728 -221.027398 9 6 5 190 +PG32 12982.487251 19266.536182 13237.265379 -531.776895 10 8 4 192 +* 2023 7 31 10 15 0.00000000 +PG01 13274.602969 -10303.257474 20129.377495 170.500229 9 4 3 144 +PG02 15001.415669 -3438.540555 22141.051630 -570.520747 10 5 7 195 +PG03 23164.672419 -12797.178893 1162.332587 -208.980718 7 4 4 197 +PG04 18045.118462 -4480.813377 -19000.648115 111.577262 5 2 9 203 +PG05 -21650.659198 1372.731868 -15578.919527 -136.984525 8 7 7 131 +PG06 -5611.328905 -24475.862335 -8450.777623 572.207543 5 5 2 203 +PG07 6346.355784 -23641.606435 -9211.423573 109.341321 6 3 7 174 +PG08 24140.023810 4206.557412 10656.990448 -134.912287 9 9 9 171 +PG09 9198.645237 -12413.171971 -21682.843674 -98.654080 9 6 6 171 +PG10 -500.015566 16579.613502 20845.166825 -47.362599 6 5 5 195 +PG11 -12659.484264 -13557.596090 -19016.563699 -299.710627 7 7 8 196 +PG12 -24522.440748 9008.932182 4271.536408 -407.266956 9 6 9 197 +PG13 -22697.532653 -13064.992421 4877.488761 554.158864 9 1 2 186 +PG14 4228.062050 -17976.068235 19051.708294 139.410050 6 6 5 185 +PG15 -24255.560437 -965.216188 10596.492967 63.159383 7 7 6 140 +PG16 19514.827928 4468.525694 -17980.041622 -474.234981 9 7 7 202 +PG17 -7144.981734 -18880.724342 17633.857920 721.982819 7 6 1 193 +PG18 -5132.265631 24915.459822 -7326.375058 -365.596186 8 4 3 150 +PG19 -14425.291532 -19469.747149 11037.103048 351.264064 8 8 3 178 +PG20 -14973.535414 -6800.506226 -20784.921447 419.753490 9 6 6 139 +PG21 15540.277402 460.448900 22102.564174 151.446634 11 7 8 206 +PG22 16695.039949 18890.664065 9058.054004 520.491542 8 8 11 148 +PG23 -12941.183515 18887.723374 13322.760550 49.432221 7 5 152 +PG24 -14915.920124 5641.186099 20825.937221 -275.158288 7 8 7 175 +PG25 -18424.770591 17520.946582 -7502.209762 459.406777 4 5 9 200 +PG26 10552.415538 11957.545882 -21373.213841 234.677337 7 8 7 196 +PG27 23310.211537 13195.799460 -312.008595 -13.454030 10 7 10 189 +PG28 5678.127182 25141.971554 -6437.758759 79.790586 7 3 7 182 +PG29 -10841.027611 10566.767102 -21882.687524 -606.792752 8 10 8 203 +PG30 51.134067 -26413.968259 -251.353689 -500.181449 2 5 2 144 +PG31 11099.231822 18062.666188 -15910.207871 -221.028095 10 7 5 194 +PG32 11513.948375 18601.129625 15384.477727 -531.783412 10 8 4 186 +* 2023 7 31 10 30 0.00000000 +PG01 13417.633136 -7873.649090 21120.966336 170.498785 9 5 2 142 +PG02 15317.006578 -1033.039149 22182.570661 -570.516986 10 5 8 192 +PG03 23012.034461 -12452.161378 4042.340947 -208.965389 7 4 4 198 +PG04 19795.282361 -3345.111767 -17438.480840 111.587308 2 4 10 203 +PG05 -20219.493229 184.592982 -17460.056268 -136.986393 8 8 7 135 +PG06 -5467.686816 -25297.196008 -5686.973482 572.203427 5 6 3 201 +PG07 6694.623902 -22379.191249 -11705.763478 109.331642 7 3 7 168 +PG08 25013.541450 4863.543378 8106.729111 -134.914617 10 9 9 164 +PG09 11373.750624 -11303.973222 -21255.808258 -98.645521 8 5 7 171 +PG10 -2474.745033 17736.548467 19682.835844 -47.363648 5 5 5 196 +PG11 -12518.769197 -15642.605801 -17449.049211 -299.725722 7 7 8 196 +PG12 -24042.543501 8467.722118 7040.752612 -407.271013 9 6 9 198 +PG13 -22913.409374 -13476.549471 2051.116558 554.163236 10 2 1 196 +PG14 6113.787047 -18913.965954 17557.807305 139.420664 6 6 6 182 +PG15 -25222.953659 -1611.888488 8095.915335 63.162500 8 7 6 122 +PG16 17724.328184 5513.317853 -19467.243227 -474.230765 8 7 7 201 +PG17 -5343.480786 -17935.143087 19235.327347 721.983225 9 6 190 +PG18 -5371.029725 23928.187919 -9982.486162 -365.608615 8 3 4 160 +PG19 -13151.823655 -18827.651211 13409.115507 351.268743 9 7 3 173 +PG20 -13223.727176 -8481.423380 -21361.958563 419.751744 9 6 5 145 +PG21 15861.677576 2828.103929 21763.825736 151.446470 11 7 8 202 +PG22 15644.607451 18464.080779 11574.938908 520.496242 9 8 10 149 +PG23 -14197.152304 19511.716193 10912.497673 49.436237 7 5 142 +PG24 -15299.782655 3181.248369 21100.471526 -275.168980 7 8 7 173 +PG25 -19142.124095 17652.884398 -4765.166960 459.408843 5 6 9 202 +PG26 8592.653535 13395.373870 -21367.066405 234.676160 7 8 7 192 +PG27 23067.252720 13301.135102 -3147.201851 -13.460332 11 8 10 189 +PG28 5477.487259 25735.169607 -3659.467915 79.788373 8 4 7 177 +PG29 -12912.233922 9243.511936 -21358.771936 -606.793479 7 9 8 202 +PG30 407.107435 -26222.617026 -3061.721063 -500.178820 3 5 1 156 +PG31 10917.514034 19757.740688 -13826.747303 -221.028441 10 7 5 188 +PG32 9811.474198 17910.212922 17272.354832 -531.789924 10 7 4 190 +* 2023 7 31 10 45 0.00000000 +PG01 13703.019713 -5365.266483 21735.371173 170.497372 9 5 3 156 +PG02 15760.377001 1335.133420 21859.767871 -570.513421 10 6 8 198 +PG03 22616.463646 -11908.042827 6852.094858 -208.949970 7 4 3 195 +PG04 21428.276869 -2388.720116 -15577.297156 111.597376 4 5 10 207 +PG05 -18702.038830 -1199.677541 -19045.932130 -136.987480 8 8 7 140 +PG06 -5340.124674 -25806.217554 -2824.605054 572.199364 5 6 3 205 +PG07 7133.345592 -20859.755634 -13988.491101 109.321854 8 4 7 179 +PG08 25648.100138 5360.219886 5419.724285 -134.915976 10 8 10 176 +PG09 13539.848529 -10335.419629 -20465.731416 -98.636882 8 4 7 177 +PG10 -4264.314647 18913.333370 18183.740923 -47.365015 5 5 5 193 +PG11 -12478.000591 -17537.576694 -15581.541649 -299.740882 7 6 9 199 +PG12 -23329.939826 7736.746945 9687.170309 -407.274972 9 6 8 194 +PG13 -22879.516195 -13704.534228 -810.181183 554.167464 10 2 1 189 +PG14 7797.469729 -19840.523513 15760.452553 139.431441 5 6 6 187 +PG15 -25939.563284 -2127.014482 5455.622888 63.165851 8 7 7 140 +PG16 15864.720088 6730.259573 -20631.892926 -474.226320 9 8 7 204 +PG17 -3353.156247 -17016.363382 20515.917277 721.983871 9 6 197 +PG18 -5687.449224 22664.145804 -12465.185000 -365.621046 8 3 5 158 +PG19 -11621.009773 -18127.682113 15551.216214 351.273397 8 7 3 184 +PG20 -11530.441882 -10278.297676 -21569.624056 419.750073 9 5 5 142 +PG21 16299.152034 5112.120629 21071.640406 151.445917 11 7 8 207 +PG22 14338.838705 17962.991125 13898.500379 520.500972 9 7 10 155 +PG23 -15192.441592 20028.448544 8312.786766 49.440282 7 5 1 149 +PG24 -15799.045877 736.282298 20999.253184 -275.179647 7 8 8 179 +PG25 -19601.404415 17630.849910 -1945.320323 459.410938 5 6 9 199 +PG26 6717.534536 14914.207232 -20996.647079 234.675016 7 8 8 192 +PG27 22543.392703 13291.289062 -5929.755558 -13.466619 11 8 10 188 +PG28 5263.981137 26023.046851 -818.225423 79.786159 8 4 7 185 +PG29 -14981.762041 8073.897567 -20469.605788 -606.794168 6 9 8 204 +PG30 802.404642 -25733.508730 -5818.443766 -500.176226 5 5 136 +PG31 10799.862070 21213.595393 -11502.962188 -221.028917 10 7 5 198 +PG32 7895.680289 17231.957056 18869.154309 -531.796424 10 6 5 183 +* 2023 7 31 11 0 0.00000000 +PG01 14134.212056 -2831.284288 21962.352141 170.495905 8 5 3 151 +PG02 16318.444782 3621.292280 21178.146495 -570.509969 10 5 8 195 +PG03 22010.249048 -11141.835679 9542.597206 -208.934624 6 4 3 196 +PG04 22900.199195 -1605.688391 -13449.216473 111.607422 7 6 10 204 +PG05 -17142.816665 -2771.021482 -20309.898671 -136.988495 9 8 7 139 +PG06 -5188.917748 -25997.031847 86.693499 572.195270 6 6 3 202 +PG07 7687.769957 -19117.012430 -16017.818445 109.312136 9 4 7 170 +PG08 26017.205458 5723.649278 2641.464266 -134.917185 11 8 10 170 +PG09 15650.209070 -9515.664699 -19326.131477 -98.628327 7 4 8 167 +PG10 -5845.674573 20067.923432 16372.484520 -47.366647 4 5 4 197 +PG11 -12510.444009 -19206.757785 -13446.234407 -299.755980 7 6 9 197 +PG12 -22419.052720 6796.915450 12164.168028 -407.279036 9 6 8 197 +PG13 -22575.140897 -13780.769889 -3657.745374 554.172306 10 3 2 191 +PG14 9261.187591 -20715.539296 13690.377297 139.442081 4 6 6 185 +PG15 -26383.287056 -2538.545482 2721.719786 63.168862 8 7 7 121 +PG16 13980.431498 8110.362712 -21454.094356 -474.222268 9 8 7 203 +PG17 -1204.694730 -16159.465147 21455.322445 721.984671 9 6 192 +PG18 -6111.929243 21152.382701 -14731.505570 -365.633495 7 3 6 154 +PG19 -9846.879578 -17410.604013 17425.702417 351.277772 8 6 4 179 +PG20 -9929.092554 -12158.262486 -21404.888649 419.747799 8 5 5 132 +PG21 16835.152338 7271.503917 20039.016505 151.445406 11 6 8 204 +PG22 12787.704342 17427.648104 15990.785870 520.505722 10 7 9 150 +PG23 -15930.653714 20396.899941 5568.663894 49.444238 8 4 2 135 +PG24 -16402.889044 -1646.136609 20525.443008 -275.190335 7 8 8 176 +PG25 -19817.666621 17420.943033 908.447965 459.412955 6 7 9 200 +PG26 4959.111663 16480.664294 -20267.209903 234.673777 7 8 8 195 +PG27 21733.374455 13204.163063 -8613.338448 -13.472948 11 8 10 192 +PG28 5000.231815 26005.917693 2037.095431 79.783855 8 4 7 179 +PG29 -17002.259622 7069.664728 -19230.593108 -606.794882 6 9 8 203 +PG30 1270.041201 -24960.024628 -8473.133448 -500.173630 6 5 150 +PG31 10713.893522 22403.453760 -8978.483200 -221.029681 11 7 5 190 +PG32 5794.588956 16601.067973 20147.944328 -531.802961 9 5 5 189 +EOF From 228907744e051b6f51546c91d114e12942b11f1e Mon Sep 17 00:00:00 2001 From: Serrof Date: Wed, 15 Nov 2023 21:22:54 +0100 Subject: [PATCH 030/359] Fixed #1260: start using square for Field --- pom.xml | 2 +- src/changes/changes.xml | 3 +++ .../java/org/orekit/attitudes/TorqueFree.java | 10 ++++----- .../java/org/orekit/bodies/FieldEllipse.java | 10 ++++----- .../org/orekit/bodies/OneAxisEllipsoid.java | 16 +++++++------- .../HolmesFeatherstoneAttractionModel.java | 12 +++++----- .../gravity/LenseThirringRelativity.java | 2 +- .../radiation/KnockeRediffusedForceModel.java | 2 +- .../geometry/fov/EllipticalFieldOfView.java | 2 +- .../models/earth/atmosphere/DTM2000.java | 4 ++-- .../models/earth/atmosphere/JB2008.java | 4 ++-- .../models/earth/atmosphere/NRLMSISE00.java | 16 +++++++------- .../ionosphere/FieldNeQuickParameters.java | 2 +- .../orekit/orbits/FieldCartesianOrbit.java | 4 ++-- .../FieldCircularLatitudeArgumentUtility.java | 2 +- .../org/orekit/orbits/FieldCircularOrbit.java | 20 ++++++++--------- ...ldEquinoctialLongitudeArgumentUtility.java | 2 +- .../orekit/orbits/FieldEquinoctialOrbit.java | 18 +++++++-------- .../orbits/FieldKeplerianAnomalyUtility.java | 4 ++-- .../orekit/orbits/FieldKeplerianOrbit.java | 12 +++++----- .../analytical/BrouwerLyddanePropagator.java | 4 ++-- .../analytical/EcksteinHechlerPropagator.java | 4 ++-- .../FieldBrouwerLyddanePropagator.java | 22 +++++++++---------- .../FieldEcksteinHechlerPropagator.java | 4 ++-- .../gnss/GLONASSAnalyticalPropagator.java | 4 ++-- .../analytical/tle/FieldDeepSDP4.java | 8 +++---- .../propagation/analytical/tle/FieldSDP4.java | 2 +- .../propagation/analytical/tle/FieldSGP4.java | 6 ++--- .../analytical/tle/FieldTLEPropagator.java | 14 ++++++------ .../numerical/cr3bp/CR3BPForceModel.java | 16 +++++++------- .../forces/AbstractGaussianContribution.java | 2 +- .../forces/DSSTSolarRadiationPressure.java | 8 +++---- .../dsst/forces/DSSTThirdBody.java | 2 +- .../FieldDSSTJ2SquaredClosedFormContext.java | 2 +- .../FieldDSSTThirdBodyDynamicContext.java | 2 +- .../dsst/forces/FieldDSSTZonalContext.java | 2 +- .../dsst/utilities/UpperBounds.java | 2 +- .../probability/twod/Alfano2005.java | 10 ++++----- .../probability/twod/Alfriend1999.java | 2 +- .../FieldShortTermEncounter2DDefinition.java | 2 +- .../probability/twod/Laas2015.java | 18 +++++++-------- .../probability/twod/Patera2005.java | 8 +++---- .../orekit/utils/FieldAngularCoordinates.java | 10 ++++----- .../utils/FieldLegendrePolynomials.java | 2 +- .../org/orekit/utils/FieldPVCoordinates.java | 2 +- .../org/orekit/utils/IERSConventions.java | 2 +- .../forces/gravity/ReferenceFieldModel.java | 4 ++-- .../probability/twod/Alfriend1999Test.java | 4 ++-- .../probability/twod/Patera2005Test.java | 2 +- .../orekit/time/FieldAbsoluteDateTest.java | 12 +++++----- 50 files changed, 166 insertions(+), 163 deletions(-) diff --git a/pom.xml b/pom.xml index 6ba9982894..3d13e40bc7 100644 --- a/pom.xml +++ b/pom.xml @@ -54,7 +54,7 @@ 3.1.1 <script type="text/x-mathjax-config">MathJax.Hub.Config({ TeX: { extensions: ["autoload.js"]}});</script> <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS_CHTML"></script> - 3.0 + 3.1-SNAPSHOT 5.10.0 2.2 1.8 diff --git a/src/changes/changes.xml b/src/changes/changes.xml index ff90f8a4bd..10659c11c0 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -21,6 +21,9 @@ + + Started using new square method for Field. + Fixed parsing of SP3 files with partly missing standard deviations. diff --git a/src/main/java/org/orekit/attitudes/TorqueFree.java b/src/main/java/org/orekit/attitudes/TorqueFree.java index ec85154cf4..b8de44354d 100644 --- a/src/main/java/org/orekit/attitudes/TorqueFree.java +++ b/src/main/java/org/orekit/attitudes/TorqueFree.java @@ -516,11 +516,11 @@ private class FieldModel > { final T o1 = FieldVector3D.dotProduct(omega0, n1); final T o2 = FieldVector3D.dotProduct(omega0, n2); final T o3 = FieldVector3D.dotProduct(omega0, n3); - final T o12 = o1.multiply(o1); - final T o22 = o2.multiply(o2); - final T o32 = o3.multiply(o3); + final T o12 = o1.square(); + final T o22 = o2.square(); + final T o32 = o3.square(); final T twoE = fI1.multiply(o12).add(fI2.multiply(o22)).add(fI3.multiply(o32)); - final T m2 = fI1.multiply(fI1).multiply(o12).add(fI2.multiply(fI2).multiply(o22)).add(fI3.multiply(fI3).multiply(o32)); + final T m2 = fI1.square().multiply(o12).add(fI2.square().multiply(o22)).add(fI3.square().multiply(o32)); final T separatrixInertia = (twoE.isZero()) ? zero : m2.divide(twoE); final boolean clockwise; if (separatrixInertia.subtract(tmpInertia.getInertiaAxis2().getI()).getReal() < 0) { @@ -651,7 +651,7 @@ public int getDimension() { public T[] computeDerivatives(final T t, final T[] y) { final T sn = jacobi.valuesN(t.subtract(dtRef).multiply(tScale)).sn(); final T[] yDot = MathArrays.buildArray(dtRef.getField(), 1); - yDot[0] = b.divide(c.add(d.multiply(sn).multiply(sn))); + yDot[0] = b.divide(c.add(d.multiply(sn.square()))); return yDot; } diff --git a/src/main/java/org/orekit/bodies/FieldEllipse.java b/src/main/java/org/orekit/bodies/FieldEllipse.java index a98733945f..ed8213592e 100644 --- a/src/main/java/org/orekit/bodies/FieldEllipse.java +++ b/src/main/java/org/orekit/bodies/FieldEllipse.java @@ -99,13 +99,13 @@ public FieldEllipse(final FieldVector3D center, final FieldVector3D u, this.a = a; this.b = b; this.frame = frame; - this.a2 = a.multiply(a); + this.a2 = a.square(); this.g = b.divide(a); this.g2 = g.multiply(g); this.e2 = g2.negate().add(1); - this.b2 = b.multiply(b); - this.evoluteFactorX = a2.subtract(b2).divide(a2.multiply(a2)); - this.evoluteFactorY = b2.subtract(a2).divide(b2.multiply(b2)); + this.b2 = b.square(); + this.evoluteFactorX = a2.subtract(b2).divide(a2.square()); + this.evoluteFactorY = b2.subtract(a2).divide(b2.square()); } /** Get the center of the 2D ellipse. @@ -273,7 +273,7 @@ public TimeStampedFieldPVCoordinates projectToEllipse(final TimeStampedFieldP // tangent to the ellipse final T fx = a2.negate().multiply(e2D.getY()); final T fy = b2.multiply(e2D.getX()); - final T f2 = fx.multiply(fx).add(fy.multiply(fy)); + final T f2 = fx.square().add(fy.square()); final T f = FastMath.sqrt(f2); final FieldVector2Dtangent = new FieldVector2D<>(fx.divide(f), fy.divide(f)); diff --git a/src/main/java/org/orekit/bodies/OneAxisEllipsoid.java b/src/main/java/org/orekit/bodies/OneAxisEllipsoid.java index 1b3f87808f..852664bdda 100644 --- a/src/main/java/org/orekit/bodies/OneAxisEllipsoid.java +++ b/src/main/java/org/orekit/bodies/OneAxisEllipsoid.java @@ -280,21 +280,21 @@ public > FieldVector3D getCartesianIntersec final T x = point.getX(); final T y = point.getY(); final T z = point.getZ(); - final T z2 = z.multiply(z); - final T r2 = x.multiply(x).add(y.multiply(y)); + final T z2 = z.square(); + final T r2 = x.square().add(y.square()); final FieldVector3D direction = lineInBodyFrame.getDirection(); final T dx = direction.getX(); final T dy = direction.getY(); final T dz = direction.getZ(); - final T cz2 = dx.multiply(dx).add(dy.multiply(dy)); + final T cz2 = dx.square().add(dy.square()); // abscissa of the intersection as a root of a 2nd degree polynomial : // a k^2 - 2 b k + c = 0 final T a = cz2.multiply(e2).subtract(1.0).negate(); final T b = x.multiply(dx).add(y.multiply(dy)).multiply(g2).add(z.multiply(dz)).negate(); final T c = r2.subtract(ae2).multiply(g2).add(z2); - final T b2 = b.multiply(b); + final T b2 = b.square(); final T ac = a.multiply(c); if (b2.getReal() < ac.getReal()) { return null; @@ -683,8 +683,8 @@ public > FieldGeodeticPoint transform(final sn = sn.scalb(-exp); cn = cn.scalb(-exp); - sn2 = sn.multiply(sn); - cn2 = cn.multiply(cn); + sn2 = sn.square(); + cn2 = cn.square(); an2 = cn2.add(sn2); an = an2.sqrt(); @@ -727,7 +727,7 @@ public FieldGeodeticPoint transform(final PVCoordinates poi final Transform toBody = frame.getTransformTo(bodyFrame, date); final PVCoordinates pointInBodyFrame = toBody.transformPVCoordinates(point); final FieldVector3D p = pointInBodyFrame.toDerivativeStructureVector(2); - final DerivativeStructure pr2 = p.getX().multiply(p.getX()).add(p.getY().multiply(p.getY())); + final DerivativeStructure pr2 = p.getX().square().add(p.getY().square()); final DerivativeStructure pr = pr2.sqrt(); final DerivativeStructure pz = p.getZ(); @@ -735,7 +735,7 @@ public FieldGeodeticPoint transform(final PVCoordinates poi final TimeStampedPVCoordinates groundPoint = projectToGround(new TimeStampedPVCoordinates(date, pointInBodyFrame), bodyFrame); final FieldVector3D gp = groundPoint.toDerivativeStructureVector(2); - final DerivativeStructure gpr2 = gp.getX().multiply(gp.getX()).add(gp.getY().multiply(gp.getY())); + final DerivativeStructure gpr2 = gp.getX().square().add(gp.getY().square()); final DerivativeStructure gpr = gpr2.sqrt(); final DerivativeStructure gpz = gp.getZ(); diff --git a/src/main/java/org/orekit/forces/gravity/HolmesFeatherstoneAttractionModel.java b/src/main/java/org/orekit/forces/gravity/HolmesFeatherstoneAttractionModel.java index 03809eb4ed..1895f2f39c 100644 --- a/src/main/java/org/orekit/forces/gravity/HolmesFeatherstoneAttractionModel.java +++ b/src/main/java/org/orekit/forces/gravity/HolmesFeatherstoneAttractionModel.java @@ -416,11 +416,11 @@ public > T[] gradient(final FieldAbsoluteDate< final T x = position.getX(); final T y = position.getY(); final T z = position.getZ(); - final T x2 = x.multiply(x); - final T y2 = y.multiply(y); + final T x2 = x.square(); + final T y2 = y.square(); final T rho2 = x2.add(y2); final T rho = rho2.sqrt(); - final T z2 = z.multiply(z); + final T z2 = z.square(); final T r2 = rho2.add(z2); final T r = r2.sqrt(); final T t = z.divide(r); // cos(theta), where theta is the polar angle @@ -506,9 +506,9 @@ public > T[] gradient(final FieldAbsoluteDate< final T xPos = position.getX(); final T yPos = position.getY(); final T zPos = position.getZ(); - final T rho2Pos = x.multiply(x).add(y.multiply(y)); + final T rho2Pos = x.square().add(y.square()); final T rhoPos = rho2.sqrt(); - final T r2Pos = rho2.add(z.multiply(z)); + final T r2Pos = rho2.add(z.square()); final T rPos = r2Pos.sqrt(); final T[][] jacobianPos = MathArrays.buildArray(zero.getField(), 3, 3); @@ -972,7 +972,7 @@ private > int computeTesseral(final int m, fin final T[] pnm0Plus2, final T[] pnm0Plus1, final T[] pnm1Plus1, final T[] pnm0, final T[] pnm1, final T[] pnm2) { - final T u2 = u.multiply(u); + final T u2 = u.square(); final T zero = u.getField().getZero(); // initialize recursion from sectorial terms int n = FastMath.max(2, m); diff --git a/src/main/java/org/orekit/forces/gravity/LenseThirringRelativity.java b/src/main/java/org/orekit/forces/gravity/LenseThirringRelativity.java index 72e6d5dc5e..cf3e379045 100644 --- a/src/main/java/org/orekit/forces/gravity/LenseThirringRelativity.java +++ b/src/main/java/org/orekit/forces/gravity/LenseThirringRelativity.java @@ -133,7 +133,7 @@ public > FieldVector3D acceleration(final F // Radius final T r = p.getNorm(); - final T r2 = r.multiply(r); + final T r2 = r.square(); // Earth’s angular momentum per unit mass final FieldStaticTransform t = bodyFrame.getStaticTransformTo(s.getFrame(), s.getDate()); diff --git a/src/main/java/org/orekit/forces/radiation/KnockeRediffusedForceModel.java b/src/main/java/org/orekit/forces/radiation/KnockeRediffusedForceModel.java index 870495a304..5f2634ec01 100644 --- a/src/main/java/org/orekit/forces/radiation/KnockeRediffusedForceModel.java +++ b/src/main/java/org/orekit/forces/radiation/KnockeRediffusedForceModel.java @@ -604,7 +604,7 @@ private > FieldVector3D computeElementaryFl // Compute attenuated projected elemetary area vector final FieldVector3D projectedAreaVector = r.scalarMultiply(elementArea.multiply(FastMath.cos(alpha)).divide( - rNorm.multiply(rNorm).multiply(rNorm).multiply(zero.getPi()))); + rNorm.square().multiply(rNorm).multiply(zero.getPi()))); // Compute elementary radiation flux from current elementary area return projectedAreaVector.scalarMultiply(albedoAndIR.divide(Constants.SPEED_OF_LIGHT)); diff --git a/src/main/java/org/orekit/geometry/fov/EllipticalFieldOfView.java b/src/main/java/org/orekit/geometry/fov/EllipticalFieldOfView.java index f9f15066dd..359cfddd7f 100644 --- a/src/main/java/org/orekit/geometry/fov/EllipticalFieldOfView.java +++ b/src/main/java/org/orekit/geometry/fov/EllipticalFieldOfView.java @@ -400,7 +400,7 @@ private > FieldVector3D directionAt(final T final T cos2 = FastMath.cos(d2); final T a1 = cos1.subtract(cos2.multiply(dotF1F2)).multiply(d); final T a2 = cos2.subtract(cos1.multiply(dotF1F2)).multiply(d); - final T ac = FastMath.sqrt(a1.multiply(a1.add(a2.multiply(2 * dotF1F2))).add(a2.multiply(a2)).negate().add(1).multiply(d)); + final T ac = FastMath.sqrt(a1.multiply(a1.add(a2.multiply(2 * dotF1F2))).add(a2.square()).negate().add(1).multiply(d)); return new FieldVector3D<>(a1, focus1, a2, focus2, FastMath.copySign(ac, sign), crossF1F2); } diff --git a/src/main/java/org/orekit/models/earth/atmosphere/DTM2000.java b/src/main/java/org/orekit/models/earth/atmosphere/DTM2000.java index 4f515f57cf..428785c129 100644 --- a/src/main/java/org/orekit/models/earth/atmosphere/DTM2000.java +++ b/src/main/java/org/orekit/models/earth/atmosphere/DTM2000.java @@ -973,8 +973,8 @@ private static class FieldComputation> { // compute Legendre polynomials wrt geographic pole final T c = scLat.sin(); - final T c2 = c.multiply(c); - final T c4 = c2.multiply(c2); + final T c2 = c.square(); + final T c4 = c2.square(); final T s = scLat.cos(); final T s2 = s.multiply(s); p10 = c; diff --git a/src/main/java/org/orekit/models/earth/atmosphere/JB2008.java b/src/main/java/org/orekit/models/earth/atmosphere/JB2008.java index 5bfd618fda..32b6bf2bd3 100644 --- a/src/main/java/org/orekit/models/earth/atmosphere/JB2008.java +++ b/src/main/java/org/orekit/models/earth/atmosphere/JB2008.java @@ -544,9 +544,9 @@ public > T getDensity(final T dateMJD, final T // Equation (17) final T cos = eta.cos(); - final T cosEta = cos.multiply(cos).multiply(cos.sqrt()); + final T cosEta = cos.square().multiply(cos.sqrt()); final T sin = theta.sin(); - final T sinTeta = sin.multiply(sin).multiply(sin.sqrt()); + final T sinTeta = sin.square().multiply(sin.sqrt()); final T cosTau = tau.multiply(0.5).cos().abs(); final T df = sinTeta.add(cosEta.subtract(sinTeta).multiply(cosTau).multiply(cosTau).multiply(cosTau)); final T tsubl = df.multiply(0.31).add(1).multiply(tsubc); diff --git a/src/main/java/org/orekit/models/earth/atmosphere/NRLMSISE00.java b/src/main/java/org/orekit/models/earth/atmosphere/NRLMSISE00.java index 82a37ad305..c08722e1ea 100644 --- a/src/main/java/org/orekit/models/earth/atmosphere/NRLMSISE00.java +++ b/src/main/java/org/orekit/models/earth/atmosphere/NRLMSISE00.java @@ -3656,10 +3656,10 @@ private T sg0(final T ex, final double p24, final double p25) { final double g04 = g0(ap[4], p24, p25); final double g05 = g0(ap[5], p24, p25); final double g06 = g0(ap[6], p24, p25); - final T ex2 = ex.multiply(ex); + final T ex2 = ex.square(); final T ex3 = ex.multiply(ex2); - final T ex4 = ex2.multiply(ex2); - final T ex8 = ex4.multiply(ex4); + final T ex4 = ex2.square(); + final T ex8 = ex4.square(); final T ex12 = ex4.multiply(ex8); final T g234 = ex.multiply(g02).add(ex2.multiply(g03)).add(ex3.multiply(g04)); final T g56 = ex4.multiply(g05).add(ex12.multiply(g06)); @@ -3730,7 +3730,7 @@ private T ccor2(final T alt, final double r, final double h1, final double zh, f private T scalh(final double alt, final double xm, final double temp) { // Gravity at altitude final T denom = rlat.reciprocal().multiply(alt).add(1); - final T galt = glat.divide(denom.multiply(denom)); + final T galt = glat.divide(denom.square()); return galt.reciprocal().multiply(R_GAS * temp / xm); } @@ -3788,11 +3788,11 @@ private T splini(final T[] xa, final T[] ya, final T[] y2a, final T x) { final T h = xa[khi].subtract(xa[klo]); final T a = xa[khi].subtract(xx).divide(h); final T b = xx.subtract(xa[klo]).divide(h); - final T a2 = a.multiply(a); - final T b2 = b.multiply(b); + final T a2 = a.square(); + final T b2 = b.square(); final T z = - a2.divide(2).subtract(a2.multiply(a2).add(1).divide(4)).multiply(y2a[klo]). + a2.divide(2).subtract(a2.square().add(1).divide(4)).multiply(y2a[klo]). add(b2.multiply(b2).divide(4).subtract(b2.divide(2)).multiply(y2a[khi])); yi = yi.add( a2.negate().add(1).multiply(ya[klo]).divide(2). add(b2.multiply(ya[khi]).divide(2)). @@ -3828,7 +3828,7 @@ private T splint(final T[] xa, final T[] ya, final T[] y2a, final T x) { final T a = xa[khi].subtract(x).divide(h); final T b = x.subtract(xa[klo]).divide(h); return a.multiply(ya[klo]).add(b.multiply(ya[khi])). - add(( a.multiply(a).multiply(a).subtract(a).multiply(y2a[klo]). + add(( a.square().multiply(a).subtract(a).multiply(y2a[klo]). add(b.multiply(b).multiply(b).subtract(b).multiply(y2a[khi])) ).multiply(h).multiply(h).divide(6)); } diff --git a/src/main/java/org/orekit/models/earth/ionosphere/FieldNeQuickParameters.java b/src/main/java/org/orekit/models/earth/ionosphere/FieldNeQuickParameters.java index df37f73596..58ac1ab799 100644 --- a/src/main/java/org/orekit/models/earth/ionosphere/FieldNeQuickParameters.java +++ b/src/main/java/org/orekit/models/earth/ionosphere/FieldNeQuickParameters.java @@ -451,7 +451,7 @@ private T computehmF2(final Field field, final T foE, final T foF2, final T m } // hmF2 Eq. 80 - final T mF2Sq = mF2.multiply(mF2); + final T mF2Sq = mF2.square(); final T temp = FastMath.sqrt(mF2Sq.multiply(0.0196).add(1.0).divide(mF2Sq.multiply(1.2967).subtract(1.0))); final T height = mF2.multiply(1490.0).multiply(temp).divide(mF2.add(deltaM)).subtract(176.0); return height; diff --git a/src/main/java/org/orekit/orbits/FieldCartesianOrbit.java b/src/main/java/org/orekit/orbits/FieldCartesianOrbit.java index 13541b5c6d..6d7dedf0f3 100644 --- a/src/main/java/org/orekit/orbits/FieldCartesianOrbit.java +++ b/src/main/java/org/orekit/orbits/FieldCartesianOrbit.java @@ -495,7 +495,7 @@ private FieldPVCoordinates shiftPVElliptic(final T dt) { // add the quadratic motion due to the non-Keplerian acceleration to the Keplerian motion final FieldVector3D fixedP = new FieldVector3D<>(getOne(), shiftedP, - dt.multiply(dt).multiply(0.5), nonKeplerianAcceleration); + dt.square().multiply(0.5), nonKeplerianAcceleration); final T fixedR2 = fixedP.getNormSq(); final T fixedR = fixedR2.sqrt(); final FieldVector3D fixedV = new FieldVector3D<>(getOne(), shiftedV, @@ -568,7 +568,7 @@ private FieldPVCoordinates shiftPVHyperbolic(final T dt) { // add the quadratic motion due to the non-Keplerian acceleration to the Keplerian motion final FieldVector3D fixedP = new FieldVector3D<>(getOne(), shiftedP, - dt.multiply(dt).multiply(0.5), nonKeplerianAcceleration); + dt.square().multiply(0.5), nonKeplerianAcceleration); final T fixedR2 = fixedP.getNormSq(); final T fixedR = fixedR2.sqrt(); final FieldVector3D fixedV = new FieldVector3D<>(getOne(), shiftedV, diff --git a/src/main/java/org/orekit/orbits/FieldCircularLatitudeArgumentUtility.java b/src/main/java/org/orekit/orbits/FieldCircularLatitudeArgumentUtility.java index 4fa0731c4a..28fe0c8d86 100644 --- a/src/main/java/org/orekit/orbits/FieldCircularLatitudeArgumentUtility.java +++ b/src/main/java/org/orekit/orbits/FieldCircularLatitudeArgumentUtility.java @@ -88,7 +88,7 @@ public static > T trueToEccentric(final T ex, * @return intermediate variable referred to as epsilon. */ private static > T eccentricAndTrueEpsilon(final T ex, final T ey) { - return (ex.multiply(ex).negate().subtract(ey.multiply(ey)).add(1.)).sqrt(); + return (ex.square().negate().subtract(ey.square()).add(1.)).sqrt(); } /** diff --git a/src/main/java/org/orekit/orbits/FieldCircularOrbit.java b/src/main/java/org/orekit/orbits/FieldCircularOrbit.java index 676987e9cd..0e7555a96b 100644 --- a/src/main/java/org/orekit/orbits/FieldCircularOrbit.java +++ b/src/main/java/org/orekit/orbits/FieldCircularOrbit.java @@ -284,7 +284,7 @@ public FieldCircularOrbit(final TimeStampedFieldPVCoordinates pvCoordinates, final T f = eCE.subtract(e2); final T g = eSE.multiply(e2.negate().add(1).sqrt()); final T aOnR = a.divide(r); - final T a2OnR2 = aOnR.multiply(aOnR); + final T a2OnR2 = aOnR.square(); ex = a2OnR2.multiply(f.multiply(x2).add(g.multiply(y2))); ey = a2OnR2.multiply(f.multiply(y2).subtract(g.multiply(x2))); @@ -366,7 +366,7 @@ public FieldCircularOrbit(final FieldOrbit op) { i = op.getI(); final T hx = op.getHx(); final T hy = op.getHy(); - final T h2 = hx.multiply(hx).add(hy.multiply(hy)); + final T h2 = hx.square().add(hy.square()); final T h = h2.sqrt(); raan = hy.atan2(hx); final FieldSinCos scRaan = FastMath.sinCos(raan); @@ -825,8 +825,8 @@ private void computePVWithoutA() { // eccentricity-related intermediate parameters final T exey = equEx.multiply(equEy); - final T ex2 = equEx.multiply(equEx); - final T ey2 = equEy.multiply(equEy); + final T ex2 = equEx.square(); + final T ey2 = equEy.square(); final T e2 = ex2.add(ey2); final T eta = e2.negate().add(1).sqrt().add(1); final T beta = eta.reciprocal(); @@ -914,8 +914,8 @@ protected FieldVector3D initPosition() { // eccentricity-related intermediate parameters final T exey = equEx.multiply(equEy); - final T ex2 = equEx.multiply(equEx); - final T ey2 = equEy.multiply(equEy); + final T ex2 = equEx.square(); + final T ey2 = equEy.square(); final T e2 = ex2.add(ey2); final T eta = e2.negate().add(1).sqrt().add(1); final T beta = eta.reciprocal(); @@ -975,7 +975,7 @@ PositionAngleType.MEAN, getFrame(), // add quadratic effect of non-Keplerian acceleration to Keplerian-only shift keplerianShifted.computePVWithoutA(); final FieldVector3D fixedP = new FieldVector3D<>(getOne(), keplerianShifted.partialPV.getPosition(), - dt.multiply(dt).multiply(0.5), nonKeplerianAcceleration); + dt.square().multiply(0.5), nonKeplerianAcceleration); final T fixedR2 = fixedP.getNormSq(); final T fixedR = fixedR2.sqrt(); final FieldVector3D fixedV = new FieldVector3D<>(getOne(), keplerianShifted.partialPV.getVelocity(), @@ -1022,10 +1022,10 @@ protected T[][] computeJacobianMeanWrtCartesian() { final T rOa = r.divide(a); final T aOr = a.divide(r); final T aOr2 = a.divide(r2); - final T a2 = a.multiply(a); + final T a2 = a.square(); - final T ex2 = ex.multiply(ex); - final T ey2 = ey.multiply(ey); + final T ex2 = ex.square(); + final T ey2 = ey.square(); final T e2 = ex2.add(ey2); final T epsilon = e2.negate().add(1.0).sqrt(); final T beta = epsilon.add(1).reciprocal(); diff --git a/src/main/java/org/orekit/orbits/FieldEquinoctialLongitudeArgumentUtility.java b/src/main/java/org/orekit/orbits/FieldEquinoctialLongitudeArgumentUtility.java index 11c96513c6..d0e2bbddcf 100644 --- a/src/main/java/org/orekit/orbits/FieldEquinoctialLongitudeArgumentUtility.java +++ b/src/main/java/org/orekit/orbits/FieldEquinoctialLongitudeArgumentUtility.java @@ -88,7 +88,7 @@ public static > T trueToEccentric(final T ex, * @return intermediate variable referred to as epsilon. */ private static > T eccentricAndTrueEpsilon(final T ex, final T ey) { - return (ex.multiply(ex).negate().subtract(ey.multiply(ey)).add(1.)).sqrt(); + return (ex.square().negate().subtract(ey.square()).add(1.)).sqrt(); } /** diff --git a/src/main/java/org/orekit/orbits/FieldEquinoctialOrbit.java b/src/main/java/org/orekit/orbits/FieldEquinoctialOrbit.java index 8abb1674c2..ee1792cc44 100644 --- a/src/main/java/org/orekit/orbits/FieldEquinoctialOrbit.java +++ b/src/main/java/org/orekit/orbits/FieldEquinoctialOrbit.java @@ -618,7 +618,7 @@ public T getIDot() { return null; } - final T h2 = hx.multiply(hx).add(hy.multiply(hy)); + final T h2 = hx.square().add(hy.square()); final T h = h2.sqrt(); return hx.multiply(hxDot).add(hy.multiply(hyDot)).multiply(2).divide(h.multiply(h2.add(1))); @@ -637,7 +637,7 @@ private void computePVWithoutA() { final T lE = getLE(); // inclination-related intermediate parameters - final T hx2 = hx.multiply(hx); + final T hx2 = hx.square(); final T hy2 = hy.multiply(hy); final T factH = getOne().divide(hx2.add(1.0).add(hy2)); @@ -651,9 +651,9 @@ private void computePVWithoutA() { final T vz = hx.multiply(factH).multiply(2); // eccentricity-related intermediate parameters - final T ex2 = ex.multiply(ex); + final T ex2 = ex.square(); final T exey = ex.multiply(ey); - final T ey2 = ey.multiply(ey); + final T ey2 = ey.square(); final T e2 = ex2.add(ey2); final T eta = getOne().subtract(e2).sqrt().add(1); final T beta = getOne().divide(eta); @@ -725,8 +725,8 @@ protected FieldVector3D initPosition() { final T lE = getLE(); // inclination-related intermediate parameters - final T hx2 = hx.multiply(hx); - final T hy2 = hy.multiply(hy); + final T hx2 = hx.square(); + final T hy2 = hy.square(); final T factH = getOne().divide(hx2.add(1.0).add(hy2)); // reference axes defining the orbital plane @@ -801,7 +801,7 @@ PositionAngleType.MEAN, getFrame(), // add quadratic effect of non-Keplerian acceleration to Keplerian-only shift keplerianShifted.computePVWithoutA(); final FieldVector3D fixedP = new FieldVector3D<>(getOne(), keplerianShifted.partialPV.getPosition(), - dt.multiply(dt).multiply(0.5), nonKeplerianAcceleration); + dt.square().multiply(0.5), nonKeplerianAcceleration); final T fixedR2 = fixedP.getNormSq(); final T fixedR = fixedR2.sqrt(); final FieldVector3D fixedV = new FieldVector3D<>(getOne(), keplerianShifted.partialPV.getVelocity(), @@ -837,7 +837,7 @@ protected T[][] computeJacobianMeanWrtCartesian() { final T mu = getMu(); final T sqrtMuA = a.multiply(mu).sqrt(); - final T a2 = a.multiply(a); + final T a2 = a.square(); final T e2 = ex.multiply(ex).add(ey.multiply(ey)); final T oMe2 = getOne().subtract(e2); @@ -997,7 +997,7 @@ public void addKeplerContribution(final PositionAngleType type, final T gm, pDot[5] = pDot[5].add(n); break; case ECCENTRIC : - oMe2 = getOne().subtract(ex.multiply(ex)).subtract(ey.multiply(ey)); + oMe2 = getOne().subtract(ex.square()).subtract(ey.square()); ksi = ex.multiply(sc.cos()).add(1).add(ey.multiply(sc.sin())); pDot[5] = pDot[5].add(n.multiply(ksi).divide(oMe2)); break; diff --git a/src/main/java/org/orekit/orbits/FieldKeplerianAnomalyUtility.java b/src/main/java/org/orekit/orbits/FieldKeplerianAnomalyUtility.java index 96366adbcb..e26df76d76 100644 --- a/src/main/java/org/orekit/orbits/FieldKeplerianAnomalyUtility.java +++ b/src/main/java/org/orekit/orbits/FieldKeplerianAnomalyUtility.java @@ -195,7 +195,7 @@ public static > T ellipticMeanToEccentric(fina */ private static > T eMeSinE(final T e, final T E) { T x = (e.negate().add(1)).multiply(E.sin()); - final T mE2 = E.negate().multiply(E); + final T mE2 = E.square().negate(); T term = E; double d = 0; // the inequality test below IS intentional and should NOT be replaced by a @@ -331,7 +331,7 @@ public static > T hyperbolicMeanToEccentric(fi // Accurate computation of S - (1 - g1) * asinh(S) // when (g1, S) is close to (0, 0). final T t = S.divide(one.add(one.add(S.multiply(S)).sqrt())); - final T tsq = t.multiply(t); + final T tsq = t.square(); T x = S.multiply(g1.add(g.multiply(tsq))); T term = two.multiply(g).multiply(t); T twoI1 = one; diff --git a/src/main/java/org/orekit/orbits/FieldKeplerianOrbit.java b/src/main/java/org/orekit/orbits/FieldKeplerianOrbit.java index a8fe85f177..315cf2d42e 100644 --- a/src/main/java/org/orekit/orbits/FieldKeplerianOrbit.java +++ b/src/main/java/org/orekit/orbits/FieldKeplerianOrbit.java @@ -945,7 +945,7 @@ public FieldKeplerianOrbit shiftedBy(final T dt) { // add quadratic effect of non-Keplerian acceleration to Keplerian-only shift keplerianShifted.computePVWithoutA(); final FieldVector3D fixedP = new FieldVector3D<>(getOne(), keplerianShifted.partialPV.getPosition(), - dt.multiply(dt).multiply(0.5), nonKeplerianAcceleration); + dt.square().multiply(0.5), nonKeplerianAcceleration); final T fixedR2 = fixedP.getNormSq(); final T fixedR = fixedR2.sqrt(); final FieldVector3D fixedV = new FieldVector3D<>(getOne(), keplerianShifted.partialPV.getVelocity(), @@ -1010,7 +1010,7 @@ private T[][] computeJacobianMeanWrtCartesianElliptical() { final T mu = getMu(); final T sqrtMuA = FastMath.sqrt(a.multiply(mu)); final T sqrtAoMu = FastMath.sqrt(a.divide(mu)); - final T a2 = a.multiply(a); + final T a2 = a.square(); final T twoA = a.multiply(2); final T rOnA = r.divide(a); @@ -1149,7 +1149,7 @@ private T[][] computeJacobianMeanWrtCartesianHyperbolic() { final T mu = getMu(); final T absA = a.negate(); final T sqrtMuA = absA.multiply(mu).sqrt(); - final T a2 = a.multiply(a); + final T a2 = a.square(); final T rOa = r.divide(absA); final FieldSinCos scI = FastMath.sinCos(i); @@ -1227,7 +1227,7 @@ private T[][] computeJacobianMeanWrtCartesianHyperbolic() { // dM final T s2a = pv.divide(absA.multiply(2)); - final T oObux = m.multiply(m).add(absA.multiply(mu)).sqrt().reciprocal(); + final T oObux = m.square().add(absA.multiply(mu)).sqrt().reciprocal(); final T scasbu = pv.multiply(oObux); final FieldVector3D dauP = new FieldVector3D<>(sqrtMuA.reciprocal(), velocity, s2a.negate().divide(sqrtMuA), vectorAR); final FieldVector3D dauV = new FieldVector3D<>(sqrtMuA.reciprocal(), position, s2a.negate().divide(sqrtMuA), vectorARDot); @@ -1411,12 +1411,12 @@ public void addKeplerContribution(final PositionAngleType type, final T gm, pDot[5] = pDot[5].add(n); break; case ECCENTRIC : - oMe2 = e.multiply(e).negate().add(1).abs(); + oMe2 = e.square().negate().add(1).abs(); ksi = e.multiply(v.cos()).add(1); pDot[5] = pDot[5].add( n.multiply(ksi).divide(oMe2)); break; case TRUE : - oMe2 = e.multiply(e).negate().add(1).abs(); + oMe2 = e.square().negate().add(1).abs(); ksi = e.multiply(v.cos()).add(1); pDot[5] = pDot[5].add(n.multiply(ksi).multiply(ksi).divide(oMe2.multiply(oMe2.sqrt()))); break; diff --git a/src/main/java/org/orekit/propagation/analytical/BrouwerLyddanePropagator.java b/src/main/java/org/orekit/propagation/analytical/BrouwerLyddanePropagator.java index 5075f72f70..a2b26a0c51 100644 --- a/src/main/java/org/orekit/propagation/analytical/BrouwerLyddanePropagator.java +++ b/src/main/java/org/orekit/propagation/analytical/BrouwerLyddanePropagator.java @@ -1315,10 +1315,10 @@ public KeplerianOrbit propagateParameters(final AbsoluteDate date) { // Long periodical terms final UnivariateDerivative2 cg1 = gpp.cos(); final UnivariateDerivative2 sg1 = gpp.sin(); - final UnivariateDerivative2 c2g = cg1.multiply(cg1).subtract(sg1.multiply(sg1)); + final UnivariateDerivative2 c2g = cg1.square().subtract(sg1.square()); final UnivariateDerivative2 s2g = cg1.multiply(sg1).add(sg1.multiply(cg1)); final UnivariateDerivative2 c3g = c2g.multiply(cg1).subtract(s2g.multiply(sg1)); - final UnivariateDerivative2 sg2 = sg1.multiply(sg1); + final UnivariateDerivative2 sg2 = sg1.square(); final UnivariateDerivative2 sg3 = sg1.multiply(sg2); diff --git a/src/main/java/org/orekit/propagation/analytical/EcksteinHechlerPropagator.java b/src/main/java/org/orekit/propagation/analytical/EcksteinHechlerPropagator.java index b8783e3ba1..4b0f3bb044 100644 --- a/src/main/java/org/orekit/propagation/analytical/EcksteinHechlerPropagator.java +++ b/src/main/java/org/orekit/propagation/analytical/EcksteinHechlerPropagator.java @@ -1114,8 +1114,8 @@ private TimeStampedPVCoordinates toCartesian(final AbsoluteDate date, final Univ final UnivariateDerivative2 alphaE = meanToEccentric(parameters[5], parameters[1], parameters[2]); final UnivariateDerivative2 cosAE = alphaE.cos(); final UnivariateDerivative2 sinAE = alphaE.sin(); - final UnivariateDerivative2 ex2 = parameters[1].multiply(parameters[1]); - final UnivariateDerivative2 ey2 = parameters[2].multiply(parameters[2]); + final UnivariateDerivative2 ex2 = parameters[1].square(); + final UnivariateDerivative2 ey2 = parameters[2].square(); final UnivariateDerivative2 exy = parameters[1].multiply(parameters[2]); final UnivariateDerivative2 q = ex2.add(ey2).subtract(1).negate().sqrt(); final UnivariateDerivative2 beta = q.add(1).reciprocal(); diff --git a/src/main/java/org/orekit/propagation/analytical/FieldBrouwerLyddanePropagator.java b/src/main/java/org/orekit/propagation/analytical/FieldBrouwerLyddanePropagator.java index 8a25b76bd4..ec4f235de7 100644 --- a/src/main/java/org/orekit/propagation/analytical/FieldBrouwerLyddanePropagator.java +++ b/src/main/java/org/orekit/propagation/analytical/FieldBrouwerLyddanePropagator.java @@ -919,11 +919,11 @@ private static class FieldBLModel> { final T y2 = ql.multiply(-0.5 * ck0[2]); n = ((mean.getE().multiply(mean.getE()).negate()).add(1.0)).sqrt(); - final T n2 = n.multiply(n); + final T n2 = n.square(); final T n3 = n2.multiply(n); - final T n4 = n2.multiply(n2); + final T n4 = n2.square(); final T n6 = n4.multiply(n2); - final T n8 = n4.multiply(n4); + final T n8 = n4.square(); final T n10 = n8.multiply(n2); final T yp2 = y2.divide(n4); @@ -939,17 +939,17 @@ private static class FieldBLModel> { final T sinI1 = sc.sin(); final T sinI2 = sinI1.multiply(sinI1); final T cosI1 = sc.cos(); - final T cosI2 = cosI1.multiply(cosI1); + final T cosI2 = cosI1.square(); final T cosI3 = cosI2.multiply(cosI1); - final T cosI4 = cosI2.multiply(cosI2); + final T cosI4 = cosI2.square(); final T cosI6 = cosI4.multiply(cosI2); final T C5c2 = T2(cosI1).reciprocal(); final T C3c2 = cosI2.multiply(3.0).subtract(1.0); final T epp = mean.getE(); - final T epp2 = epp.multiply(epp); + final T epp2 = epp.square(); final T epp3 = epp2.multiply(epp); - final T epp4 = epp2.multiply(epp2); + final T epp4 = epp2.square(); if (epp.getReal() >= 1) { // Only for elliptical (e < 1) orbits @@ -1101,7 +1101,7 @@ private static class FieldBLModel> { */ private FieldUnivariateDerivative2 eMeSinE(final FieldUnivariateDerivative2 E) { FieldUnivariateDerivative2 x = E.sin().multiply(mean.getE().negate().add(1.0)); - final FieldUnivariateDerivative2 mE2 = E.negate().multiply(E); + final FieldUnivariateDerivative2 mE2 = E.square().negate(); FieldUnivariateDerivative2 term = E; FieldUnivariateDerivative2 d = E.getField().getZero(); // the inequality test below IS intentional and should NOT be replaced by a check with a small tolerance @@ -1206,8 +1206,8 @@ private FieldUnivariateDerivative2 getEccentricAnomaly(final FieldUnivariateD private T T2(final T cosInc) { // X = (1.0 - 5.0 * cos²(inc)) - final T x = cosInc.multiply(cosInc).multiply(-5.0).add(1.0); - final T x2 = x.multiply(x); + final T x = cosInc.square().multiply(-5.0).add(1.0); + final T x2 = x.square(); // Eq. 2.48 T sum = x.getField().getZero(); @@ -1280,7 +1280,7 @@ public FieldKeplerianOrbit propagateParameters(final FieldAbsoluteDate dat final FieldUnivariateDerivative2 c2g = cg1.multiply(cg1).subtract(sg1.multiply(sg1)); final FieldUnivariateDerivative2 s2g = cg1.multiply(sg1).add(sg1.multiply(cg1)); final FieldUnivariateDerivative2 c3g = c2g.multiply(cg1).subtract(s2g.multiply(sg1)); - final FieldUnivariateDerivative2 sg2 = sg1.multiply(sg1); + final FieldUnivariateDerivative2 sg2 = sg1.square(); final FieldUnivariateDerivative2 sg3 = sg1.multiply(sg2); diff --git a/src/main/java/org/orekit/propagation/analytical/FieldEcksteinHechlerPropagator.java b/src/main/java/org/orekit/propagation/analytical/FieldEcksteinHechlerPropagator.java index dc4a32d50a..6e643642d9 100644 --- a/src/main/java/org/orekit/propagation/analytical/FieldEcksteinHechlerPropagator.java +++ b/src/main/java/org/orekit/propagation/analytical/FieldEcksteinHechlerPropagator.java @@ -1058,8 +1058,8 @@ private TimeStampedFieldPVCoordinates toCartesian(final FieldAbsoluteDate final FieldUnivariateDerivative2 alphaE = meanToEccentric(parameters[5], parameters[1], parameters[2]); final FieldUnivariateDerivative2 cosAE = alphaE.cos(); final FieldUnivariateDerivative2 sinAE = alphaE.sin(); - final FieldUnivariateDerivative2 ex2 = parameters[1].multiply(parameters[1]); - final FieldUnivariateDerivative2 ey2 = parameters[2].multiply(parameters[2]); + final FieldUnivariateDerivative2 ex2 = parameters[1].square(); + final FieldUnivariateDerivative2 ey2 = parameters[2].square(); final FieldUnivariateDerivative2 exy = parameters[1].multiply(parameters[2]); final FieldUnivariateDerivative2 q = ex2.add(ey2).subtract(1).negate().sqrt(); final FieldUnivariateDerivative2 beta = q.add(1).reciprocal(); diff --git a/src/main/java/org/orekit/propagation/analytical/gnss/GLONASSAnalyticalPropagator.java b/src/main/java/org/orekit/propagation/analytical/gnss/GLONASSAnalyticalPropagator.java index 09d03e7a5f..d864c00229 100644 --- a/src/main/java/org/orekit/propagation/analytical/gnss/GLONASSAnalyticalPropagator.java +++ b/src/main/java/org/orekit/propagation/analytical/gnss/GLONASSAnalyticalPropagator.java @@ -203,7 +203,7 @@ public PVCoordinates propagateInEcef(final AbsoluteDate date) { // Current mean longitude final UnivariateDerivative2 correction = dTpr. subtract(w.multiply(GLONASS_MEAN_DRACONIAN_PERIOD + glonassOrbit.getDeltaT())). - subtract(w.multiply(w).multiply(glonassOrbit.getDeltaTDot())); + subtract(w.square().multiply(glonassOrbit.getDeltaTDot())); final UnivariateDerivative2 m = m1.add(n.multiply(correction)); // Take into consideration the periodic perturbations @@ -374,7 +374,7 @@ private UnivariateDerivative2 eMeSinE(final UnivariateDerivative2 E, final Univa * @return the true anomaly (rad) */ private UnivariateDerivative2 getTrueAnomaly(final UnivariateDerivative2 ek, final UnivariateDerivative2 ecc) { - final UnivariateDerivative2 svk = ek.sin().multiply(FastMath.sqrt( ecc.multiply(ecc).negate().add(1.0))); + final UnivariateDerivative2 svk = ek.sin().multiply(FastMath.sqrt( ecc.square().negate().add(1.0))); final UnivariateDerivative2 cvk = ek.cos().subtract(ecc); return svk.atan2(cvk); } diff --git a/src/main/java/org/orekit/propagation/analytical/tle/FieldDeepSDP4.java b/src/main/java/org/orekit/propagation/analytical/tle/FieldDeepSDP4.java index 5a7f24b418..9376aa4a6f 100644 --- a/src/main/java/org/orekit/propagation/analytical/tle/FieldDeepSDP4.java +++ b/src/main/java/org/orekit/propagation/analytical/tle/FieldDeepSDP4.java @@ -258,9 +258,9 @@ protected void luniSolarTermsComputation() { final T x6 = a6.multiply(sing); final T x7 = a5.multiply(cosg); final T x8 = a6.multiply(cosg); - final T z31 = x1.multiply(x1).multiply(12).subtract(x3.multiply(x3).multiply(3)); + final T z31 = x1.square().multiply(12).subtract(x3.square().multiply(3)); final T z32 = x1.multiply(x2).multiply(24).subtract(x3.multiply(x4).multiply(6)); - final T z33 = x2.multiply(x2).multiply(12).subtract(x4.multiply(x4).multiply(3)); + final T z33 = x2.square().multiply(12).subtract(x4.square().multiply(3)); final T z11 = a1.multiply(-6).multiply(a5).add(e0sq.multiply(x1.multiply(x7).multiply(-24).add(x3.multiply(x5).multiply(-6)))); final T z12 = a1.multiply(a6).add(a3.multiply(a5)).multiply(-6).add( e0sq.multiply(x2.multiply(x7).add(x1.multiply(x8)).multiply(-24).add( @@ -280,9 +280,9 @@ protected void luniSolarTermsComputation() { final T s5 = x1.multiply(x3).add(x2.multiply(x4)); final T s6 = x2.multiply(x3).add(x1.multiply(x4)); final T s7 = x2.multiply(x4).subtract(x1.multiply(x3)); - T z1 = a1.multiply(a1).add(a2.multiply(a2)).multiply(3).add(z31.multiply(e0sq)); + T z1 = a1.square().add(a2.square()).multiply(3).add(z31.multiply(e0sq)); T z2 = a1.multiply(a3).add(a2.multiply(a4)).multiply(6).add(z32.multiply(e0sq)); - T z3 = a3.multiply(a3).add(a4.multiply(a4)).multiply(3).add(z33.multiply(e0sq)); + T z3 = a3.square().add(a4.square()).multiply(3).add(z33.multiply(e0sq)); z1 = z1.add(z1).add(beta02.multiply(z31)); z2 = z2.add(z2).add(beta02.multiply(z32)); diff --git a/src/main/java/org/orekit/propagation/analytical/tle/FieldSDP4.java b/src/main/java/org/orekit/propagation/analytical/tle/FieldSDP4.java index 994972d64c..d387123f6b 100644 --- a/src/main/java/org/orekit/propagation/analytical/tle/FieldSDP4.java +++ b/src/main/java/org/orekit/propagation/analytical/tle/FieldSDP4.java @@ -94,7 +94,7 @@ protected void sxpPropagate(final T tSince, final T[] parameters) { final T bStar = parameters[0]; omgadf = tle.getPerigeeArgument().add(omgdot.multiply(tSince)); final T xnoddf = tle.getRaan().add(xnodot.multiply(tSince)); - final T tSinceSq = tSince.multiply(tSince); + final T tSinceSq = tSince.square(); xnode = xnoddf.add(xnodcf.multiply(tSinceSq)); xn = xn0dp; diff --git a/src/main/java/org/orekit/propagation/analytical/tle/FieldSGP4.java b/src/main/java/org/orekit/propagation/analytical/tle/FieldSGP4.java index 0fdad946fd..672fa3d9d9 100644 --- a/src/main/java/org/orekit/propagation/analytical/tle/FieldSGP4.java +++ b/src/main/java/org/orekit/propagation/analytical/tle/FieldSGP4.java @@ -104,7 +104,7 @@ protected void sxpInitialize(final T[] parameters) { lessThan220 = perige.getReal() < 220; if (!lessThan220) { final FieldSinCos scM0 = FastMath.sinCos(tle.getMeanAnomaly()); - final T c1sq = c1.multiply(c1); + final T c1sq = c1.square(); delM0 = eta.multiply(scM0.cos()).add(1.0); delM0 = delM0.multiply(delM0).multiply(delM0); d2 = a0dp.multiply(tsi).multiply(c1sq).multiply(4.0); @@ -143,7 +143,7 @@ protected void sxpPropagate(final T tSince, final T[] parameters) { final T xn0ddf = tle.getRaan().add(xnodot.multiply(tSince)); omega = omgadf; T xmp = xmdf; - final T tsq = tSince.multiply(tSince); + final T tsq = tSince.square(); xnode = xn0ddf.add(xnodcf.multiply(tsq)); T tempa = c1.multiply(tSince).negate().add(1.0); T tempe = bStar.multiply(c4).multiply(tSince); @@ -152,7 +152,7 @@ protected void sxpPropagate(final T tSince, final T[] parameters) { if (!lessThan220) { final T delomg = omgcof.multiply(tSince); T delm = eta.multiply(FastMath.cos(xmdf)).add(1.0); - delm = xmcof.multiply(delm.multiply(delm).multiply(delm).subtract(delM0)); + delm = xmcof.multiply(delm.square().multiply(delm).subtract(delM0)); final T temp = delomg.add(delm); xmp = xmdf.add(temp); omega = omgadf.subtract(temp); diff --git a/src/main/java/org/orekit/propagation/analytical/tle/FieldTLEPropagator.java b/src/main/java/org/orekit/propagation/analytical/tle/FieldTLEPropagator.java index 02e7ef3b23..9080c8a04b 100644 --- a/src/main/java/org/orekit/propagation/analytical/tle/FieldTLEPropagator.java +++ b/src/main/java/org/orekit/propagation/analytical/tle/FieldTLEPropagator.java @@ -347,7 +347,7 @@ private void initializeCommons(final T[] parameters) { cosi0 = FastMath.cos(tle.getI()); theta2 = cosi0.multiply(cosi0); final T x3thm1 = theta2.multiply(3.0).subtract(1.0); - e0sq = tle.getE().multiply(tle.getE()); + e0sq = tle.getE().square(); beta02 = e0sq.negate().add(1.0); beta0 = FastMath.sqrt(beta02); final T tval = x3thm1.multiply(1.5 * TLEConstants.CK2).divide(beta0.multiply(beta02)); @@ -376,20 +376,20 @@ private void initializeCommons(final T[] parameters) { } final T temp_val = s4.negate().add(120.0).multiply(TLEConstants.NORMALIZED_EQUATORIAL_RADIUS / TLEConstants.EARTH_RADIUS); final T temp_val_squared = temp_val.multiply(temp_val); - q0ms24 = temp_val_squared.multiply(temp_val_squared); + q0ms24 = temp_val_squared.square(); s4 = s4.divide(TLEConstants.EARTH_RADIUS).add(TLEConstants.NORMALIZED_EQUATORIAL_RADIUS); // new value for q0ms2T and s } final T pinv = a0dp.multiply(beta02).reciprocal(); - final T pinvsq = pinv.multiply(pinv); + final T pinvsq = pinv.square(); tsi = a0dp.subtract(s4).reciprocal(); eta = a0dp.multiply(tle.getE()).multiply(tsi); - etasq = eta.multiply(eta); + etasq = eta.square(); eeta = tle.getE().multiply(eta); final T psisq = etasq.negate().add(1.0).abs(); // abs because pow 3.5 needs positive value final T tsi_squared = tsi.multiply(tsi); - coef = q0ms24.multiply(tsi_squared.multiply(tsi_squared)); + coef = q0ms24.multiply(tsi_squared.square()); coef1 = coef.divide(psisq.pow(3.5)); // C2 and C1 coefficients computation : @@ -452,7 +452,7 @@ private FieldPVCoordinates computePVCoordinates() { final T aynl = temp.multiply(aycof); final T xlt = xl.add(xll); final T ayn = e.multiply(FastMath.sin(omega)).add(aynl); - final T elsq = axn.multiply(axn).add(ayn.multiply(ayn)); + final T elsq = axn.square().add(ayn.square()); final T capu = MathUtils.normalizeAngle(xlt.subtract(xnode), zero.getPi()); T epw = capu; T ecosE = zero; @@ -461,7 +461,7 @@ private FieldPVCoordinates computePVCoordinates() { T cosEPW = zero; // Dundee changes: items dependent on cosio get recomputed: - final T cosi0Sq = cosi0.multiply(cosi0); + final T cosi0Sq = cosi0.square(); final T x3thm1 = cosi0Sq.multiply(3.0).subtract(1.0); final T x1mth2 = cosi0Sq.negate().add(1.0); final T x7thm1 = cosi0Sq.multiply(7.0).subtract(1.0); diff --git a/src/main/java/org/orekit/propagation/numerical/cr3bp/CR3BPForceModel.java b/src/main/java/org/orekit/propagation/numerical/cr3bp/CR3BPForceModel.java index b41a2d0d9f..1b81c0def9 100644 --- a/src/main/java/org/orekit/propagation/numerical/cr3bp/CR3BPForceModel.java +++ b/src/main/java/org/orekit/propagation/numerical/cr3bp/CR3BPForceModel.java @@ -151,17 +151,17 @@ public DerivativeStructure getPotential(final SpacecraftState s) { // Norm of the Spacecraft position relative to the primary body final DerivativeStructure r1 = - FastMath.sqrt((fpx.add(d1)).multiply(fpx.add(d1)).add(fpy.multiply(fpy)) - .add(fpz.multiply(fpz))); + FastMath.sqrt((fpx.add(d1)).multiply(fpx.add(d1)).add(fpy.square()) + .add(fpz.square())); // Norm of the Spacecraft position relative to the secondary body final DerivativeStructure r2 = FastMath.sqrt((fpx.subtract(d2)).multiply(fpx.subtract(d2)) - .add(fpy.multiply(fpy)).add(fpz.multiply(fpz))); + .add(fpy.square()).add(fpz.square())); // Potential of the Spacecraft return (mu.negate().add(1.0).divide(r1)).add(mu.divide(r2)) - .add(fpx.multiply(fpx).add(fpy.multiply(fpy)).multiply(0.5)).add(d1.multiply(d2).multiply(0.5)); + .add(fpx.square().add(fpy.square()).multiply(0.5)).add(d1.multiply(d2).multiply(0.5)); } /** @@ -194,17 +194,17 @@ public > FieldDerivativeStructure getPotent // Norm of the Spacecraft position relative to the primary body final FieldDerivativeStructure r1 = - FastMath.sqrt((fpx.add(d1)).multiply(fpx.add(d1)).add(fpy.multiply(fpy)) - .add(fpz.multiply(fpz))); + FastMath.sqrt((fpx.add(d1)).multiply(fpx.add(d1)).add(fpy.square()) + .add(fpz.square())); // Norm of the Spacecraft position relative to the secondary body final FieldDerivativeStructure r2 = FastMath.sqrt((fpx.subtract(d2)).multiply(fpx.subtract(d2)) - .add(fpy.multiply(fpy)).add(fpz.multiply(fpz))); + .add(fpy.square()).add(fpz.square())); // Potential of the Spacecraft return (mu.negate().add(1.0).divide(r1)).add(mu.divide(r2)) - .add(fpx.multiply(fpx).add(fpy.multiply(fpy)).multiply(0.5)).add(d1.multiply(d2).multiply(0.5)); + .add(fpx.square().add(fpy.square()).multiply(0.5)).add(d1.multiply(d2).multiply(0.5)); } /** {@inheritDoc} */ diff --git a/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/AbstractGaussianContribution.java b/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/AbstractGaussianContribution.java index e90c2a0d0d..9a4e05f8d6 100644 --- a/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/AbstractGaussianContribution.java +++ b/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/AbstractGaussianContribution.java @@ -2254,7 +2254,7 @@ public T[] value(final FieldOrbit meanOrbit) { // Compute the center (l - λ) final T center = L.subtract(meanOrbit.getLM()); // Compute (l - λ)² - final T center2 = center.multiply(center); + final T center2 = center.square(); // Initialize short periodic variations final T[] shortPeriodicVariation = slot.cij[0].value(meanOrbit.getDate()); diff --git a/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/DSSTSolarRadiationPressure.java b/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/DSSTSolarRadiationPressure.java index 81512a6685..c286e92e5e 100644 --- a/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/DSSTSolarRadiationPressure.java +++ b/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/DSSTSolarRadiationPressure.java @@ -315,8 +315,8 @@ protected > T[] getLLimits(final FieldSpacecra final T h2 = auxiliaryElements.getH().multiply(auxiliaryElements.getH()); final T k2 = auxiliaryElements.getK().multiply(auxiliaryElements.getK()); final T m = (auxiliaryElements.getSma().multiply(auxiliaryElements.getB())).divide(ae).reciprocal(); - final T m2 = m.multiply(m); - final T m4 = m2.multiply(m2); + final T m2 = m.square(); + final T m4 = m2.square(); final T bb = alpha.multiply(beta).add(m2.multiply(auxiliaryElements.getH()).multiply(auxiliaryElements.getK())); final T b2 = bb.multiply(bb); final T cc = alpha.multiply(alpha).subtract(bet2).add(m2.multiply(k2.subtract(h2))); @@ -658,7 +658,7 @@ private > int realCubicRoots(final T[] a, fina final T b = a[1].divide(a[0].multiply(3.)).negate(); final T c = a[2].divide(a[0]); final T d = a[3].divide(a[0]); - final T b2 = b.multiply(b); + final T b2 = b.square(); final T p = b2.subtract(c.divide(3.)); final T q = b.multiply(b2.subtract(c.multiply(0.5))).subtract(d.multiply(0.5)); @@ -789,7 +789,7 @@ private > int realQuadraticRoots(final T[] a, final T c = a[2].divide(a[0]); // Compute discriminant - final T d = b.multiply(b).subtract(c); + final T d = b.square().subtract(c); if (d.getReal() < 0.) { // No real roots diff --git a/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/DSSTThirdBody.java b/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/DSSTThirdBody.java index 1c9f102b44..df1f0811e5 100644 --- a/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/DSSTThirdBody.java +++ b/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/DSSTThirdBody.java @@ -1642,7 +1642,7 @@ private class FieldWnsjEtomjmsCoefficient > { //initialise fields c = auxiliaryElements.getEcc().multiply(context.getb()); - final T c2 = c.multiply(c); + final T c2 = c.square(); //b² * χ final T b2Chi = context.getb().multiply(context.getb()).multiply(context.getX()); diff --git a/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/FieldDSSTJ2SquaredClosedFormContext.java b/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/FieldDSSTJ2SquaredClosedFormContext.java index 18c2f8685d..c7493fc290 100644 --- a/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/FieldDSSTJ2SquaredClosedFormContext.java +++ b/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/FieldDSSTJ2SquaredClosedFormContext.java @@ -73,7 +73,7 @@ public FieldDSSTJ2SquaredClosedFormContext(final FieldAuxiliaryElements auxil this.eta = FastMath.sqrt(auxiliaryElements.getEcc().multiply(auxiliaryElements.getEcc()).negate().add(1.0)); final T a2 = auxiliaryElements.getSma().multiply(auxiliaryElements.getSma()); - this.a4 = a2.multiply(a2); + this.a4 = a2.square(); } /** diff --git a/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/FieldDSSTThirdBodyDynamicContext.java b/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/FieldDSSTThirdBodyDynamicContext.java index 2673748c0e..3b1a2db156 100644 --- a/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/FieldDSSTThirdBodyDynamicContext.java +++ b/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/FieldDSSTThirdBodyDynamicContext.java @@ -136,7 +136,7 @@ public FieldDSSTThirdBodyDynamicContext(final FieldAuxiliaryElements aux, // Χ X = aux.getB().reciprocal(); - XX = X.multiply(X); + XX = X.square(); XXX = X.multiply(XX); // -2 * a / A m2aoA = aux.getSma().multiply(-2.).divide(A); diff --git a/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/FieldDSSTZonalContext.java b/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/FieldDSSTZonalContext.java index 1075048e1c..c73840307e 100644 --- a/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/FieldDSSTZonalContext.java +++ b/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/FieldDSSTZonalContext.java @@ -109,7 +109,7 @@ public class FieldDSSTZonalContext> extends Fi // Χ = 1 / B X = auxiliaryElements.getB().reciprocal(); - XX = X.multiply(X); + XX = X.square(); XXX = X.multiply(XX); // 1 / AB diff --git a/src/main/java/org/orekit/propagation/semianalytical/dsst/utilities/UpperBounds.java b/src/main/java/org/orekit/propagation/semianalytical/dsst/utilities/UpperBounds.java index d8432c424c..0166c3a8d0 100644 --- a/src/main/java/org/orekit/propagation/semianalytical/dsst/utilities/UpperBounds.java +++ b/src/main/java/org/orekit/propagation/semianalytical/dsst/utilities/UpperBounds.java @@ -172,7 +172,7 @@ public static > T getRnml(final T gamma, final T zero = gamma.getField().getZero(); // Initialization final int mei = m * eps * irf; - final T sinisq = gamma.multiply(gamma).negate().add(1.); + final T sinisq = gamma.square().negate().add(1.); // Set a lower bound for inclination final T sininc = FastMath.max(zero.newInstance(0.03), FastMath.sqrt(sinisq)); final T onepig = gamma.multiply(irf).add(1.); diff --git a/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/Alfano2005.java b/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/Alfano2005.java index 8940c5c4a3..ee55f0c61c 100644 --- a/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/Alfano2005.java +++ b/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/Alfano2005.java @@ -120,7 +120,7 @@ public > FieldProbabilityOfCollision comput final T rootTwoSigmaY = sigmaY.multiply(FastMath.sqrt(2)); - final T otherTerm = xm.multiply(xm).divide(sigmaX.multiply(sigmaX).multiply(-2.)).exp() + final T otherTerm = xm.square().divide(sigmaX.multiply(sigmaX).multiply(-2.)).exp() .multiply(Erf.erf(radius.subtract(ym).divide(rootTwoSigmaY)) .subtract(Erf.erf(radius.add(ym).negate().divide(rootTwoSigmaY)))); @@ -248,16 +248,16 @@ private double getRecurrentPart(final double x, final double xm, final double ym */ private > T getRecurrentPart(final T x, final T xm, final T ym, final T sigmaX, final T sigmaY, final T radius) { - final T minusTwoSigmaXSquared = sigmaX.multiply(sigmaX).multiply(-2.); - final T radiusSquaredMinusXSquaredSQRT = radius.multiply(radius).subtract(x.multiply(x)).sqrt(); + final T minusTwoSigmaXSquared = sigmaX.square().multiply(-2.); + final T radiusSquaredMinusXSquaredSQRT = radius.square().subtract(x.square()).sqrt(); final T rootTwoSigmaY = sigmaY.multiply(FastMath.sqrt(2)); final T xMinusXm = x.subtract(xm); final T xPlusXm = x.add(xm); return Erf.erf(radiusSquaredMinusXSquaredSQRT.subtract(ym).divide(rootTwoSigmaY)).subtract( Erf.erf(radiusSquaredMinusXSquaredSQRT.add(ym).negate().divide(rootTwoSigmaY))) - .multiply(xMinusXm.multiply(xMinusXm).divide(minusTwoSigmaXSquared).exp() - .add(xPlusXm.multiply(xPlusXm).divide(minusTwoSigmaXSquared).exp())); + .multiply(xMinusXm.square().divide(minusTwoSigmaXSquared).exp() + .add(xPlusXm.square().divide(minusTwoSigmaXSquared).exp())); } /** {@inheritDoc} */ diff --git a/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/Alfriend1999.java b/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/Alfriend1999.java index a11ce6bbd3..1c259fb287 100644 --- a/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/Alfriend1999.java +++ b/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/Alfriend1999.java @@ -72,7 +72,7 @@ public ShortTermEncounter2DPOCMethodType getType() { @Override > T computeValue(final T radius, final T squaredMahalanobisDistance, final T covarianceMatrixDeterminant) { - return squaredMahalanobisDistance.multiply(-0.5).exp().multiply(radius).multiply(radius) + return squaredMahalanobisDistance.multiply(-0.5).exp().multiply(radius.square()) .divide(covarianceMatrixDeterminant.sqrt().multiply(2.)); } diff --git a/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/FieldShortTermEncounter2DDefinition.java b/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/FieldShortTermEncounter2DDefinition.java index b104ad255e..9ff9fe383f 100644 --- a/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/FieldShortTermEncounter2DDefinition.java +++ b/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/FieldShortTermEncounter2DDefinition.java @@ -334,7 +334,7 @@ public FieldMatrix computeProjectedAndDiagonalizedCombinedPositionalCovarianc final T crossTerm = covarianceMatrixToDiagonalize.getEntry(0, 1); final T recurrentTerm = sigmaXSquared.subtract(sigmaYSquared).multiply(0.5).pow(2) - .add(crossTerm.multiply(crossTerm)).sqrt(); + .add(crossTerm.square()).sqrt(); final T eigenValueX = sigmaXSquared.add(sigmaYSquared).multiply(0.5).subtract(recurrentTerm); final T eigenValueY = sigmaXSquared.add(sigmaYSquared).multiply(0.5).add(recurrentTerm); diff --git a/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/Laas2015.java b/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/Laas2015.java index 9eea23169e..b0618b5180 100644 --- a/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/Laas2015.java +++ b/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/Laas2015.java @@ -280,16 +280,16 @@ public final > FieldProbabilityOfCollision final T zero = field.getZero(); final T one = field.getOne(); - final T xmSquared = xm.multiply(xm); - final T ymSquared = ym.multiply(ym); - final T sigmaXSquared = sigmaX.multiply(sigmaX); - final T sigmaYSquared = sigmaY.multiply(sigmaY); + final T xmSquared = xm.square(); + final T ymSquared = ym.square(); + final T sigmaXSquared = sigmaX.square(); + final T sigmaYSquared = sigmaY.square(); final T twoSigmaXY = sigmaX.multiply(sigmaY).multiply(2); - final T radiusSquared = radius.multiply(radius); - final T radiusFourth = radiusSquared.multiply(radiusSquared); + final T radiusSquared = radius.square(); + final T radiusFourth = radiusSquared.square(); final T radiusSixth = radiusFourth.multiply(radiusSquared); - final T p = sigmaX.multiply(sigmaX).reciprocal().multiply(0.5); + final T p = sigmaX.square().reciprocal().multiply(0.5); final T pTimesRadiusSquared = p.multiply(radiusSquared); final T phiY = sigmaXSquared.divide(sigmaYSquared).negate().add(1.); final T omegaX = xm.divide(sigmaXSquared.multiply(2.)).pow(2.); @@ -298,10 +298,10 @@ public final > FieldProbabilityOfCollision final T bigOmega = phiY.multiply(0.5).add(omegaX.add(omegaY).divide(p)); final T minusP = p.negate(); - final T pSquared = p.multiply(p); + final T pSquared = p.square(); final T pCubed = p.multiply(pSquared); final T pPhiY = p.multiply(phiY); - final T phiYSquared = phiY.multiply(phiY); + final T phiYSquared = phiY.square(); final T pRadiusSquaredBigOmega = p.multiply(radiusSquared).multiply(bigOmega); final T bigOmegaPlusOne = bigOmega.add(1.); final T pSqTimesHalfPhiYSqPlusOne = pSquared.multiply(phiYSquared.multiply(0.5).add(1.)); diff --git a/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/Patera2005.java b/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/Patera2005.java index c4c36bc99d..4a82d64b01 100644 --- a/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/Patera2005.java +++ b/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/Patera2005.java @@ -125,7 +125,7 @@ public > FieldProbabilityOfCollision comput final T twoPiField = one.newInstance(MathUtils.TWO_PI); final T value; - final double missDistance = xm.multiply(xm).add(ym.multiply(ym)).sqrt().getReal(); + final double missDistance = xm.square().add(ym.square()).sqrt().getReal(); final double radiusReal = radius.getReal(); // Reference outside the hardbody area, first part of eq(11) is equal to 0 @@ -399,10 +399,10 @@ public T value(final T xm, final T ym, final T scaleFactor, final T sigma, final T yPrime = getYPrime(sinTheta); final T rSquared = getRSquared(xPrime, yPrime); - return rSquared.divide(sigma).divide(sigma).multiply(-0.5).exp() + return rSquared.divide(sigma.square()).multiply(-0.5).exp() .multiply(radius.multiply(scaleFactor).multiply(xm.multiply(cosTheta) .add(ym.multiply(sinTheta))) - .add(scaleFactor.multiply(radius).multiply(radius))).divide(rSquared); + .add(scaleFactor.multiply(radius.square()))).divide(rSquared); } } @@ -443,7 +443,7 @@ public T value(final T xm, final T ym, final T scaleFactor, final T sigma, final T xPrime = scaleFactor.multiply(xm).add(scaleFactor.multiply(radius).multiply(cosTheta)); final T yPrime = ym.add(radius.multiply(sinTheta)); - final T rSquared = xPrime.multiply(xPrime).add(yPrime.multiply(yPrime)); + final T rSquared = xPrime.square().add(yPrime.square()); final T sigmaSquared = sigma.multiply(sigma); final T oneOverTwoSigmaSq = sigmaSquared.multiply(2.).reciprocal(); final T rSqOverTwoSigmaSq = rSquared.multiply(oneOverTwoSigmaSq); diff --git a/src/main/java/org/orekit/utils/FieldAngularCoordinates.java b/src/main/java/org/orekit/utils/FieldAngularCoordinates.java index 1c25721f6a..dcc4eac89f 100644 --- a/src/main/java/org/orekit/utils/FieldAngularCoordinates.java +++ b/src/main/java/org/orekit/utils/FieldAngularCoordinates.java @@ -608,7 +608,7 @@ public FieldRotation rotationShiftedBy(final T dt) { // frame seem to rotate in the opposite direction final FieldRotation quadraticContribution = new FieldRotation<>(rotationAcceleration, - acc.multiply(dt).multiply(dt).multiply(0.5), + acc.multiply(dt.square()).multiply(0.5), RotationConvention.FRAME_TRANSFORM); // the quadratic contribution is a small rotation: @@ -688,7 +688,7 @@ public FieldAngularCoordinates shiftedBy(final T dt) { // frame seem to rotate in the opposite direction final FieldAngularCoordinates quadraticContribution = new FieldAngularCoordinates<>(new FieldRotation<>(rotationAcceleration, - acc.multiply(dt.multiply(0.5).multiply(dt)), + acc.multiply(dt.square().multiply(0.5)), RotationConvention.FRAME_TRANSFORM), new FieldVector3D<>(dt, rotationAcceleration), rotationAcceleration); @@ -998,7 +998,7 @@ private T linearCombination(final T a1, final T b1, final T a2, final T b2, fina public static > FieldAngularCoordinates createFromModifiedRodrigues(final T[][] r) { // rotation - final T rSquared = r[0][0].multiply(r[0][0]).add(r[0][1].multiply(r[0][1])).add(r[0][2].multiply(r[0][2])); + final T rSquared = r[0][0].square().add(r[0][1].square()).add(r[0][2].square()); final T oPQ0 = rSquared.add(1).reciprocal().multiply(2); final T q0 = oPQ0.subtract(1); final T q1 = oPQ0.multiply(r[0][0]); @@ -1016,9 +1016,9 @@ public static > FieldAngularCoordinates cr final T oZ = q0.linearCombination(q3.negate(), q0Dot, q2, q1Dot, q1.negate(), q2Dot, q0, q3Dot).multiply(2); // rotation acceleration - final T q0DotDot = q0.subtract(1).negate().divide(oPQ0).multiply(q0Dot).multiply(q0Dot). + final T q0DotDot = q0.subtract(1).negate().divide(oPQ0).multiply(q0Dot.square()). subtract(oPQ02.multiply(q0.linearCombination(r[0][0], r[2][0], r[0][1], r[2][1], r[0][2], r[2][2]))). - subtract(q1Dot.multiply(q1Dot).add(q2Dot.multiply(q2Dot)).add(q3Dot.multiply(q3Dot))); + subtract(q1Dot.square().add(q2Dot.square()).add(q3Dot.square())); final T q1DotDot = q0.linearCombination(oPQ0, r[2][0], r[1][0].add(r[1][0]), q0Dot, r[0][0], q0DotDot); final T q2DotDot = q0.linearCombination(oPQ0, r[2][1], r[1][1].add(r[1][1]), q0Dot, r[0][1], q0DotDot); final T q3DotDot = q0.linearCombination(oPQ0, r[2][2], r[1][2].add(r[1][2]), q0Dot, r[0][2], q0DotDot); diff --git a/src/main/java/org/orekit/utils/FieldLegendrePolynomials.java b/src/main/java/org/orekit/utils/FieldLegendrePolynomials.java index 14aa877080..e1f605f22c 100644 --- a/src/main/java/org/orekit/utils/FieldLegendrePolynomials.java +++ b/src/main/java/org/orekit/utils/FieldLegendrePolynomials.java @@ -51,7 +51,7 @@ public FieldLegendrePolynomials(final int degree, final int order, // Initialize array this.pCoef = MathArrays.buildArray(field, degree + 1, order + 1); - final T t2 = t.multiply(t); + final T t2 = t.square(); for (int n = 0; n <= degree; n++) { diff --git a/src/main/java/org/orekit/utils/FieldPVCoordinates.java b/src/main/java/org/orekit/utils/FieldPVCoordinates.java index 224ce72ce6..20c6ab486d 100644 --- a/src/main/java/org/orekit/utils/FieldPVCoordinates.java +++ b/src/main/java/org/orekit/utils/FieldPVCoordinates.java @@ -668,7 +668,7 @@ public FieldPVCoordinates shiftedBy(final T dt) { */ public FieldVector3D positionShiftedBy(final T dt) { final T one = dt.getField().getOne(); - return new FieldVector3D<>(one, position, dt, velocity, dt.multiply(dt).multiply(0.5), acceleration); + return new FieldVector3D<>(one, position, dt, velocity, dt.square().multiply(0.5), acceleration); } /** Gets the position. diff --git a/src/main/java/org/orekit/utils/IERSConventions.java b/src/main/java/org/orekit/utils/IERSConventions.java index 06fc728f47..6de5315094 100644 --- a/src/main/java/org/orekit/utils/IERSConventions.java +++ b/src/main/java/org/orekit/utils/IERSConventions.java @@ -258,7 +258,7 @@ public > T[] value(final FieldAbsoluteDate final T f = elements.getF(); final T d = elements.getD(); final T t = elements.getTC(); - final T t2 = t.multiply(t); + final T t2 = t.square(); final FieldSinCos scOmega = FastMath.sinCos(omega); final FieldSinCos sc2omega = FieldSinCos.sum(scOmega, scOmega); diff --git a/src/test/java/org/orekit/forces/gravity/ReferenceFieldModel.java b/src/test/java/org/orekit/forces/gravity/ReferenceFieldModel.java index fa5ef0e5df..63a788e0f2 100644 --- a/src/test/java/org/orekit/forces/gravity/ReferenceFieldModel.java +++ b/src/test/java/org/orekit/forces/gravity/ReferenceFieldModel.java @@ -106,9 +106,9 @@ public Dfp nonCentralPart(final AbsoluteDate date, final Vector3D position) Dfp y = dfpField.newDfp(position.getY()); Dfp z = dfpField.newDfp(position.getZ()); - Dfp rho2 = x.multiply(x).add(y.multiply(y)); + Dfp rho2 = x.square().add(y.square()); Dfp rho = rho2.sqrt(); - Dfp r2 = rho2.add(z.multiply(z)); + Dfp r2 = rho2.add(z.square()); Dfp r = r2.sqrt(); Dfp aOr = dfpField.newDfp(provider.getAe()).divide(r); Dfp lambda = position.getX() > 0 ? diff --git a/src/test/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/Alfriend1999Test.java b/src/test/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/Alfriend1999Test.java index d2655b5769..7020f17208 100644 --- a/src/test/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/Alfriend1999Test.java +++ b/src/test/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/Alfriend1999Test.java @@ -247,8 +247,8 @@ void testReturnAcceptableStatisticsAboutMaximumProbabilityOfCollisionWithArmelli armellinDataRowList); // THEN - Assertions.assertTrue(statistics.getMean() <= 8.844620688058309E-10); - Assertions.assertTrue(statistics.getStandardDeviation() <= 3.606826996118531E-9); + Assertions.assertTrue(statistics.getMean() <= 8.8446207E-10); + Assertions.assertTrue(statistics.getStandardDeviation() <= 3.6068271E-9); } /** diff --git a/src/test/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/Patera2005Test.java b/src/test/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/Patera2005Test.java index 6c2124bc64..a0e597b2fe 100644 --- a/src/test/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/Patera2005Test.java +++ b/src/test/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/Patera2005Test.java @@ -899,7 +899,7 @@ void testComputeProbabilityFromACdmField() { 1e-15); // THEN - Assertions.assertEquals(0.0034965176443840836, result.getValue().getReal(), 1e-19); + Assertions.assertEquals(0.0034965176443840836, result.getValue().getReal(), 2e-18); } diff --git a/src/test/java/org/orekit/time/FieldAbsoluteDateTest.java b/src/test/java/org/orekit/time/FieldAbsoluteDateTest.java index 26b1b54ed3..5b8b6a4305 100644 --- a/src/test/java/org/orekit/time/FieldAbsoluteDateTest.java +++ b/src/test/java/org/orekit/time/FieldAbsoluteDateTest.java @@ -397,7 +397,11 @@ public void testHasZeroField() { Assertions.assertFalse(gdConstantDate.shiftedBy(gdDt0).hasZeroField()); Assertions.assertFalse(gdConstantDate.shiftedBy(gdDt1).hasZeroField()); Assertions.assertFalse(gdConstantDate.shiftedBy(gdDt0).shiftedBy(gdDt1).hasZeroField()); - + + // SparseGradient + final FieldAbsoluteDate sgdDate = new FieldAbsoluteDate<>(SparseGradient.createConstant(10.).getField()); + Assertions.assertTrue(sgdDate.hasZeroField()); + // Complex // ------- @@ -431,11 +435,7 @@ public void testHasZeroField() { // FieldTuple final FieldAbsoluteDate> ftpDate = new FieldAbsoluteDate<>(new FieldTuple<>(dsDt0, dsDt1).getField()); Assertions.assertFalse(ftpDate.hasZeroField()); - - // SparseGradient - final FieldAbsoluteDate sgdDate = new FieldAbsoluteDate<>(SparseGradient.createConstant(10.).getField()); - Assertions.assertFalse(sgdDate.hasZeroField()); - + // Tuple final FieldAbsoluteDate tpDate = new FieldAbsoluteDate<>(new Tuple(0., 1., 2.).getField()); Assertions.assertFalse(tpDate.hasZeroField()); From 8506fd8f08ece1e1e85140f53e3598a836a6db54 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Mon, 11 Dec 2023 17:09:14 +0100 Subject: [PATCH 031/359] Removed relative humidity. --- .../CanonicalSaastamoinenModel.java | 4 +- .../EstimatedTroposphericModel.java | 1 - .../earth/troposphere/MariniMurrayModel.java | 5 +- .../earth/troposphere/MendesPavlisModel.java | 9 +-- .../ModifiedSaastamoinenModel.java | 1 - .../earth/troposphere/SaastamoinenModel.java | 14 ++--- ...ntPressureTemperatureHumidityProvider.java | 1 - .../weather/FieldPressureTemperature.java | 57 +++++++++++++++++++ .../FieldPressureTemperatureHumidity.java | 38 +------------ ...ntPressureTemperatureHumidityProvider.java | 13 +++-- .../earth/weather/PressureTemperature.java | 54 ++++++++++++++++++ .../weather/PressureTemperatureHumidity.java | 38 +------------ .../models/earth/weather/WeatherModel.java | 2 + .../models/earth/weather/water/Wang1988.java | 7 +-- .../water/WaterVaporPressureProvider.java | 4 +- .../common/AbstractOrbitDetermination.java | 1 - .../FieldMendesPavlisModelTest.java | 2 - .../troposphere/MendesPavlisModelTest.java | 2 - .../ModifiedSaastamoinenModelTest.java | 8 +-- 19 files changed, 146 insertions(+), 115 deletions(-) create mode 100644 src/main/java/org/orekit/models/earth/weather/FieldPressureTemperature.java create mode 100644 src/main/java/org/orekit/models/earth/weather/PressureTemperature.java diff --git a/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java b/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java index 4d895ab2ff..0d8f15215f 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java @@ -36,7 +36,6 @@ import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; import org.orekit.utils.ParameterDriver; -import org.orekit.utils.units.Unit; /** The canonical Saastamoinen model. *

                @@ -115,7 +114,7 @@ public CanonicalSaastamoinenModel(final PressureTemperatureHumidityProvider pthP public static CanonicalSaastamoinenModel getStandardModel() { // build standard meteorological data - final double pressure = Unit.parse("hPa").toSI(1013.25); + final double pressure = TropoUnit.HECTO_PASCAL.toSI(1013.25); final double temperature = 273.15 + 18; final double relativeHumidity = 0.5; final WaterVaporPressureProvider waterPressureProvider = new NbsNrcSteamTable(); @@ -124,7 +123,6 @@ public static CanonicalSaastamoinenModel getStandardModel() { relativeHumidity); final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(pressure, temperature, - relativeHumidity, waterVaporPressure); final PressureTemperatureHumidityProvider pth0Provider = new ConstantPressureTemperatureHumidityProvider(pth); diff --git a/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java b/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java index e8acd76a7c..d9566e4c7d 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java @@ -80,7 +80,6 @@ public EstimatedTroposphericModel(final double t0, final double p0, this(new ModifiedSaastamoinenModel(0.0, new ConstantPressureTemperatureHumidityProvider(new PressureTemperatureHumidity(TropoUnit.HECTO_PASCAL.toSI(p0), t0, - 0.0, 0.0))), model, totalDelay); } diff --git a/src/main/java/org/orekit/models/earth/troposphere/MariniMurrayModel.java b/src/main/java/org/orekit/models/earth/troposphere/MariniMurrayModel.java index bc92e099fc..f7e9ee9c25 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/MariniMurrayModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/MariniMurrayModel.java @@ -53,7 +53,7 @@ public class MariniMurrayModel implements DiscreteTroposphericModel { * environmental conditions. * @param t0 the temperature at the station, K * @param p0 the atmospheric pressure at the station, mbar - * @param rh the humidity at the station, percent (50% -> 0.5) + * @param rh the humidity at the station, as a ratio (50% → 0.5) * @param lambda laser wavelength (c/f), nm * @deprecated as of 12.1, replaced by {@link #MariniMurrayModel(PressureTemperatureHumidityProvider, double, Unit)} */ @@ -61,7 +61,6 @@ public class MariniMurrayModel implements DiscreteTroposphericModel { public MariniMurrayModel(final double t0, final double p0, final double rh, final double lambda) { this(new ConstantPressureTemperatureHumidityProvider(new PressureTemperatureHumidity(TropoUnit.HECTO_PASCAL.toSI(p0), t0, - rh, new CIPM2007(). waterVaporPressure(TropoUnit.HECTO_PASCAL.toSI(p0), t0, @@ -128,7 +127,7 @@ public static MariniMurrayModel getStandardModel(final double lambda, final Unit final double t = 273.15 + 20; final double rh = 0.5; final PressureTemperatureHumidity pth = - new PressureTemperatureHumidity(p, t, rh, new CIPM2007().waterVaporPressure(p, t, rh)); + new PressureTemperatureHumidity(p, t, new CIPM2007().waterVaporPressure(p, t, rh)); return new MariniMurrayModel(new ConstantPressureTemperatureHumidityProvider(pth), lambda, TropoUnit.NANO_M); } diff --git a/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java b/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java index a6b923c398..94d34d9cbd 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java @@ -83,7 +83,7 @@ public class MendesPavlisModel implements DiscreteTroposphericModel, MappingFunc * thanks to the values of the pressure, the temperature and the humidity * @param t0 the temperature at the station, K * @param p0 the atmospheric pressure at the station, hPa - * @param rh the humidity at the station, percent (50% → 0.5) + * @param rh the humidity at the station, as a ratio (50% → 0.5) * @param lambda laser wavelength, µm * @deprecated as of 12.1, replaced by {@link #MendesPavlisModel(PressureTemperatureHumidity, double, Unit)} */ @@ -92,11 +92,9 @@ public MendesPavlisModel(final double t0, final double p0, final double rh, final double lambda) { this(new ConstantPressureTemperatureHumidityProvider(new PressureTemperatureHumidity(TropoUnit.HECTO_PASCAL.toSI(p0), t0, - rh, new CIPM2007(). waterVaporPressure(TropoUnit.HECTO_PASCAL.toSI(p0), - t0, - rh))), + t0, rh))), lambda, TropoUnit.MICRO_M); } @@ -170,8 +168,7 @@ public static MendesPavlisModel getStandardModel(final double lambda, final Unit final double p = TropoUnit.HECTO_PASCAL.toSI(1013.25); final double t = 273.15 + 18; final double rh = 0.5; - final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(p, t, rh, - new CIPM2007().waterVaporPressure(p, t, rh)); + final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(p, t, new CIPM2007().waterVaporPressure(p, t, rh)); return new MendesPavlisModel(new ConstantPressureTemperatureHumidityProvider(pth), lambda, lambdaUnits); } diff --git a/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java b/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java index b625f2003b..eb11943481 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java @@ -198,7 +198,6 @@ public static ModifiedSaastamoinenModel getStandardModel() { final double humidity = 0.5; final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(pressure, temperature, - humidity, WATER.waterVaporPressure(pressure, temperature, humidity)); diff --git a/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java b/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java index 65f3bcc23b..d6c2a705fa 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java @@ -42,7 +42,7 @@ public class SaastamoinenModel extends ModifiedSaastamoinenModel { * * @param t0 the temperature at the station [K] * @param p0 the atmospheric pressure at the station [mbar] - * @param r0 the humidity at the station [fraction] (50% -> 0.5) + * @param r0 the humidity at the station [fraction] (50% → 0.5) * @see #ModifiedSaastamoinenModel(double, double, double, String, DataProvidersManager) * @since 10.1 */ @@ -56,7 +56,7 @@ public SaastamoinenModel(final double t0, final double p0, final double r0) { * * @param t0 the temperature at the station [K] * @param p0 the atmospheric pressure at the station [mbar] - * @param r0 the humidity at the station [fraction] (50% -> 0.5) + * @param r0 the humidity at the station [fraction] (50% → 0.5) * @param deltaRFileName regular expression for filename containing δR * correction term table (typically {@link #DELTA_R_FILE_NAME}), if null * default values from the reference book are used @@ -75,7 +75,7 @@ public SaastamoinenModel(final double t0, final double p0, final double r0, * * @param t0 the temperature at the station [K] * @param p0 the atmospheric pressure at the station [mbar] - * @param r0 the humidity at the station [fraction] (50% -> 0.5) + * @param r0 the humidity at the station [fraction] (50% → 0.5) * @param deltaRFileName regular expression for filename containing δR * correction term table (typically {@link #DELTA_R_FILE_NAME}), if null * default values from the reference book are used @@ -90,10 +90,10 @@ public SaastamoinenModel(final double t0, super(0.0, new ConstantPressureTemperatureHumidityProvider(new PressureTemperatureHumidity(TropoUnit.HECTO_PASCAL.toSI(p0), t0, - r0, - new Wang1988().waterVaporPressure(TropoUnit.HECTO_PASCAL.toSI(p0), - t0, - r0))), + new Wang1988(). + waterVaporPressure(TropoUnit.HECTO_PASCAL.toSI(p0), + t0, + r0))), deltaRFileName, dataProvidersManager); } diff --git a/src/main/java/org/orekit/models/earth/weather/ConstantPressureTemperatureHumidityProvider.java b/src/main/java/org/orekit/models/earth/weather/ConstantPressureTemperatureHumidityProvider.java index b20d25430b..025701875a 100644 --- a/src/main/java/org/orekit/models/earth/weather/ConstantPressureTemperatureHumidityProvider.java +++ b/src/main/java/org/orekit/models/earth/weather/ConstantPressureTemperatureHumidityProvider.java @@ -52,7 +52,6 @@ public > FieldPressureTemperatureHumidity g final T zero = date.getField().getZero(); return new FieldPressureTemperatureHumidity<>(zero.newInstance(pth.getPressure()), zero.newInstance(pth.getTemperature()), - zero.newInstance(pth.getRelativeHumidity()), zero.newInstance(pth.getWaterVaporPressure())); } diff --git a/src/main/java/org/orekit/models/earth/weather/FieldPressureTemperature.java b/src/main/java/org/orekit/models/earth/weather/FieldPressureTemperature.java new file mode 100644 index 0000000000..cd836c8dca --- /dev/null +++ b/src/main/java/org/orekit/models/earth/weather/FieldPressureTemperature.java @@ -0,0 +1,57 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.weather; + +import org.hipparchus.CalculusFieldElement; + +/** Container for pressure and temperature. + * @param type of the field elements + * @author Luc Maisonobe + * @since 12.1 + */ +public class FieldPressureTemperature> { + + /** Pressure (Pa). */ + private final T pressure; + + /** Temperature (Kelvin). */ + private final T temperature; + + /** Simple constructor. + * @param pressure pressure (Pa) + * @param temperature temperature (Kelvin) + */ + public FieldPressureTemperature(final T pressure, final T temperature) { + this.pressure = pressure; + this.temperature = temperature; + } + + /** Get pressure. + * @return pressure (Pa) + */ + public T getPressure() { + return pressure; + } + + /** Get temperature. + * @return temperature (Kelvin) + */ + public T getTemperature() { + return temperature; + } + +} diff --git a/src/main/java/org/orekit/models/earth/weather/FieldPressureTemperatureHumidity.java b/src/main/java/org/orekit/models/earth/weather/FieldPressureTemperatureHumidity.java index ba2c2c15cc..2c5e4db534 100644 --- a/src/main/java/org/orekit/models/earth/weather/FieldPressureTemperatureHumidity.java +++ b/src/main/java/org/orekit/models/earth/weather/FieldPressureTemperatureHumidity.java @@ -23,16 +23,7 @@ * @author Luc Maisonobe * @since 12.1 */ -public class FieldPressureTemperatureHumidity> { - - /** Pressure (Pa). */ - private final T pressure; - - /** Temperature (Kelvin). */ - private final T temperature; - - /** Humidity as relative humididy (50% → 0.5). */ - private final T relativeHumidity; +public class FieldPressureTemperatureHumidity> extends FieldPressureTemperature { /** Humidity as water vapor pressure (Pa). */ private final T waterVaporPressure; @@ -40,40 +31,15 @@ public class FieldPressureTemperatureHumidity> /** Simple constructor. * @param pressure pressure (Pa) * @param temperature temperature (Kelvin) - * @param relativeHumidity humidity as relative humididy (50% → 0.5) * @param waterVaporPressure humidity as water vapor pressure (Pa) */ public FieldPressureTemperatureHumidity(final T pressure, final T temperature, - final T relativeHumidity, final T waterVaporPressure) { - this.pressure = pressure; - this.temperature = temperature; - this.relativeHumidity = relativeHumidity; + super(pressure, temperature); this.waterVaporPressure = waterVaporPressure; } - /** Get pressure. - * @return pressure (Pa) - */ - public T getPressure() { - return pressure; - } - - /** Get temperature. - * @return temperature (Kelvin) - */ - public T getTemperature() { - return temperature; - } - - /** Get humidity as relative humididy (50% → 0.5). - * @return humidity as relative humididy (50% → 0.5) - */ - public T getRelativeHumidity() { - return relativeHumidity; - } - /** Get humidity as water vapor pressure. * @return humidity as water vapor pressure (Pa) */ diff --git a/src/main/java/org/orekit/models/earth/weather/HeightDependentPressureTemperatureHumidityProvider.java b/src/main/java/org/orekit/models/earth/weather/HeightDependentPressureTemperatureHumidityProvider.java index 4471940a9e..6ca69d5092 100644 --- a/src/main/java/org/orekit/models/earth/weather/HeightDependentPressureTemperatureHumidityProvider.java +++ b/src/main/java/org/orekit/models/earth/weather/HeightDependentPressureTemperatureHumidityProvider.java @@ -101,14 +101,16 @@ public PressureTemperatureHumidity getWeatherParamerers(final GeodeticPoint loca location.getLongitude(), h0), date); + final double saturationPressure0 = provider.waterVaporPressure(pth0.getPressure(), pth0.getTemperature(), 1.0); + final double rh0 = pth0.getWaterVaporPressure() / saturationPressure0; // compute changes due to altitude change final double dh = FastMath.min(FastMath.max(location.getAltitude(), hMin), hMax) - h0; final double p = pth0.getPressure() * FastMath.pow(1.0 - 2.26e-5 * dh, 5.225); final double t = pth0.getTemperature() - 6.5e-3 * dh; - final double rh = pth0.getRelativeHumidity() * FastMath.exp(-6.396e-4 * dh); + final double rh = rh0 * FastMath.exp(-6.396e-4 * dh); - return new PressureTemperatureHumidity(p, t, rh, provider.waterVaporPressure(p, t, rh)); + return new PressureTemperatureHumidity(p, t, provider.waterVaporPressure(p, t, rh)); } @@ -122,13 +124,16 @@ public > FieldPressureTemperatureHumidity g location.getLongitude(), location.getAltitude().newInstance(h0)), date); + final T one = date.getField().getOne(); + final T saturationPressure0 = provider.waterVaporPressure(pth0.getPressure(), pth0.getTemperature(), one); + final T rh0 = pth0.getWaterVaporPressure().divide(saturationPressure0); // compute changes due to altitude change final T dh = FastMath.min(FastMath.max(location.getAltitude(), hMin), hMax).subtract(h0); final T t = pth0.getTemperature().subtract(dh.multiply(6.5e-3)); final T p = pth0.getPressure().multiply(dh.multiply(2.26e-5).negate().add(1.0).pow(5.225)); - final T rh = pth0.getRelativeHumidity().multiply(FastMath.exp(dh.multiply(-6.396e-4))); - return new FieldPressureTemperatureHumidity<>(p, t, rh, provider.waterVaporPressure(p, t, rh)); + final T rh = rh0.multiply(FastMath.exp(dh.multiply(-6.396e-4))); + return new FieldPressureTemperatureHumidity<>(p, t, provider.waterVaporPressure(p, t, rh)); } } diff --git a/src/main/java/org/orekit/models/earth/weather/PressureTemperature.java b/src/main/java/org/orekit/models/earth/weather/PressureTemperature.java new file mode 100644 index 0000000000..98cfd9dfef --- /dev/null +++ b/src/main/java/org/orekit/models/earth/weather/PressureTemperature.java @@ -0,0 +1,54 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.weather; + +/** Container for pressure and temperature + * @author Luc Maisonobe + * @since 12.1 + */ +public class PressureTemperature { + + /** Pressure (Pa). */ + private final double pressure; + + /** Temperature (Kelvin). */ + private final double temperature; + + /** Simple constructor. + * @param pressure pressure (Pa) + * @param temperature temperature (Kelvin) + */ + public PressureTemperature(final double pressure, final double temperature) { + this.pressure = pressure; + this.temperature = temperature; + } + + /** Get pressure. + * @return pressure (Pa) + */ + public double getPressure() { + return pressure; + } + + /** Get temperature. + * @return temperature (Kelvin) + */ + public double getTemperature() { + return temperature; + } + +} diff --git a/src/main/java/org/orekit/models/earth/weather/PressureTemperatureHumidity.java b/src/main/java/org/orekit/models/earth/weather/PressureTemperatureHumidity.java index 97979cba82..cc1007257a 100644 --- a/src/main/java/org/orekit/models/earth/weather/PressureTemperatureHumidity.java +++ b/src/main/java/org/orekit/models/earth/weather/PressureTemperatureHumidity.java @@ -20,16 +20,7 @@ * @author Luc Maisonobe * @since 12.1 */ -public class PressureTemperatureHumidity { - - /** Pressure (Pa). */ - private final double pressure; - - /** Temperature (Kelvin). */ - private final double temperature; - - /** Humidity as relative humididy (50% → 0.5). */ - private final double relativeHumidity; +public class PressureTemperatureHumidity extends PressureTemperature { /** Humidity as water vapor pressure (Pa). */ private final double waterVaporPressure; @@ -37,40 +28,15 @@ public class PressureTemperatureHumidity { /** Simple constructor. * @param pressure pressure (Pa) * @param temperature temperature (Kelvin) - * @param relativeHumidity humidity as relative humididy (50% → 0.5) * @param waterVaporPressure humidity as water vapor pressure (Pa) */ public PressureTemperatureHumidity(final double pressure, final double temperature, - final double relativeHumidity, final double waterVaporPressure) { - this.pressure = pressure; - this.temperature = temperature; - this.relativeHumidity = relativeHumidity; + super(pressure, temperature); this.waterVaporPressure = waterVaporPressure; } - /** Get pressure. - * @return pressure (Pa) - */ - public double getPressure() { - return pressure; - } - - /** Get temperature. - * @return temperature (Kelvin) - */ - public double getTemperature() { - return temperature; - } - - /** Get humidity as relative humididy (50% → 0.5). - * @return humidity as relative humididy (50% → 0.5) - */ - public double getRelativeHumidity() { - return relativeHumidity; - } - /** Get humidity as water vapor pressure. * @return humidity as water vapor pressure (Pa) */ diff --git a/src/main/java/org/orekit/models/earth/weather/WeatherModel.java b/src/main/java/org/orekit/models/earth/weather/WeatherModel.java index 73613fa1d0..a07e30676c 100644 --- a/src/main/java/org/orekit/models/earth/weather/WeatherModel.java +++ b/src/main/java/org/orekit/models/earth/weather/WeatherModel.java @@ -22,7 +22,9 @@ * compute the different weather parameters (pressure, temperature, ...). * @author Bryan Cazabonne * @since 9.3 + * @deprecated as of 12.1, replaced by {@link PressureTemperatureHumidityProvider} */ +@Deprecated public interface WeatherModel { /** Calculates the weather parameters of the model. diff --git a/src/main/java/org/orekit/models/earth/weather/water/Wang1988.java b/src/main/java/org/orekit/models/earth/weather/water/Wang1988.java index 8e9b54d04c..0a6d9e5915 100644 --- a/src/main/java/org/orekit/models/earth/weather/water/Wang1988.java +++ b/src/main/java/org/orekit/models/earth/weather/water/Wang1988.java @@ -19,6 +19,7 @@ import org.hipparchus.CalculusFieldElement; import org.hipparchus.analysis.polynomials.PolynomialFunction; import org.hipparchus.util.FastMath; +import org.orekit.models.earth.troposphere.TropoUnit; /** Conversion polynomial from "The Principle of the GPS Precise Positioning System", Wang et al, 1988. *

                @@ -40,15 +41,13 @@ public class Wang1988 implements WaterVaporPressureProvider { /** {@inheritDoc} */ @Override public double waterVaporPressure(final double p, final double t, final double rh) { - // the 100.0 factor is due to conversion from hPa to Pa - return rh * 100.0 * FastMath.exp(E_POLYNOMIAL.value(t)); + return TropoUnit.HECTO_PASCAL.toSI(rh * FastMath.exp(E_POLYNOMIAL.value(t))); } /** {@inheritDoc} */ @Override public > T waterVaporPressure(final T p, final T t, final T rh) { - // the 100.0 factor is due to conversion from hPa to Pa - return rh.multiply(100.0).multiply(FastMath.exp(E_POLYNOMIAL.value(t))); + return TropoUnit.HECTO_PASCAL.toSI(rh.multiply(FastMath.exp(E_POLYNOMIAL.value(t)))); } } diff --git a/src/main/java/org/orekit/models/earth/weather/water/WaterVaporPressureProvider.java b/src/main/java/org/orekit/models/earth/weather/water/WaterVaporPressureProvider.java index b13ca25b05..1dd0fe8cb8 100644 --- a/src/main/java/org/orekit/models/earth/weather/water/WaterVaporPressureProvider.java +++ b/src/main/java/org/orekit/models/earth/weather/water/WaterVaporPressureProvider.java @@ -27,7 +27,7 @@ public interface WaterVaporPressureProvider { /** Compute water vapor pressure. * @param p pressure (Pa) * @param t temperature (Kelvin) - * @param rh relative humidity, in percent (50% → 0.5) + * @param rh relative humidity, as a ratio (50% → 0.5) * @return water vapor pressure (Pa) */ double waterVaporPressure(double p, double t, double rh); @@ -35,7 +35,7 @@ public interface WaterVaporPressureProvider { /** Compute water vapor pressure. * @param p pressure (Pa) * @param t temperature (Kelvin) - * @param rh relative humidity, in percent (50% → 0.5) + * @param rh relative humidity, as a ratio (50% → 0.5) * @param type of the field elements * @return water vapor pressure (Pa) */ diff --git a/src/test/java/org/orekit/estimation/common/AbstractOrbitDetermination.java b/src/test/java/org/orekit/estimation/common/AbstractOrbitDetermination.java index 2b9b209b52..25c23c6bd0 100644 --- a/src/test/java/org/orekit/estimation/common/AbstractOrbitDetermination.java +++ b/src/test/java/org/orekit/estimation/common/AbstractOrbitDetermination.java @@ -2319,7 +2319,6 @@ private List> readCrd(final DataSource source, final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(Unit.BAR.toSI(meteoData.getPressure()), meteoData.getTemperature(), - 0.01 * meteoData.getHumidity(), new CIPM2007(). waterVaporPressure(Unit.BAR.toSI(meteoData.getPressure()), meteoData.getTemperature(), diff --git a/src/test/java/org/orekit/models/earth/troposphere/FieldMendesPavlisModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/FieldMendesPavlisModelTest.java index 73079aed54..d268e8caef 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/FieldMendesPavlisModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/FieldMendesPavlisModelTest.java @@ -98,7 +98,6 @@ private > void doTestZenithDelay(final Field> void doTestMappingFactors(final Fiel final double humidity = 0.4; final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(pressure, temperature, - humidity, new CIPM2007(). waterVaporPressure(pressure, temperature, diff --git a/src/test/java/org/orekit/models/earth/troposphere/MendesPavlisModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/MendesPavlisModelTest.java index 7f8e80feca..8174b02431 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/MendesPavlisModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/MendesPavlisModelTest.java @@ -71,7 +71,6 @@ public void testZenithDelay() { final double humidity = 0.4; final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(pressure, temperature, - humidity, new CIPM2007(). waterVaporPressure(pressure, temperature, @@ -127,7 +126,6 @@ public void testMappingFactors() { final double humidity = 0.4; final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(pressure, temperature, - humidity, new CIPM2007(). waterVaporPressure(pressure, temperature, diff --git a/src/test/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModelTest.java index 91f24deabf..d62d923306 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModelTest.java @@ -118,8 +118,7 @@ public void NoFile() { final double waterPressure = ModifiedSaastamoinenModel.WATER.waterVaporPressure(pressure, temperature, humidity); - final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(pressure, temperature, humidity, - waterPressure); + final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(pressure, temperature, waterPressure); final PressureTemperatureHumidityProvider pthProvider = new ConstantPressureTemperatureHumidityProvider(pth); new ModifiedSaastamoinenModel(0.0, pthProvider, "^non-existent-file$"); Assertions.fail("an exception should have been thrown"); @@ -138,8 +137,7 @@ public void compareDefaultAndLoaded() { final double waterPressure = ModifiedSaastamoinenModel.WATER.waterVaporPressure(pressure, temperature, humidity); - final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(pressure, temperature, humidity, - waterPressure); + final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(pressure, temperature, waterPressure); final PressureTemperatureHumidityProvider pthProvider = new ConstantPressureTemperatureHumidityProvider(pth); ModifiedSaastamoinenModel defaultModel = new ModifiedSaastamoinenModel(0.0, pthProvider, null); ModifiedSaastamoinenModel loadedModel = new ModifiedSaastamoinenModel(0.0, pthProvider, ModifiedSaastamoinenModel.DELTA_R_FILE_NAME); @@ -242,7 +240,6 @@ public void compareExpectedValues() { final double humidity = 0.5; final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(pressure, temperature, - humidity, ModifiedSaastamoinenModel.WATER.waterVaporPressure(pressure, temperature, humidity)); @@ -277,7 +274,6 @@ private > void doCompareFieldExpectedValues(fi final double humidity = 0.5; final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(pressure, temperature, - humidity, ModifiedSaastamoinenModel.WATER.waterVaporPressure(pressure, temperature, humidity)); From 3f603fe493cabbf2baf84c475aa766e31a94e698 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Mon, 11 Dec 2023 17:11:05 +0100 Subject: [PATCH 032/359] Redesigned GPT2 to implement PressureTemperatureHumidityProvider. --- .../weather/GlobalPressureTemperature2.java | 594 ++++++++++++++++++ .../GlobalPressureTemperature2Model.java | 416 +----------- .../GlobalPressureTemperature2ModelTest.java | 1 + .../GlobalPressureTemperature2Test.java | 186 ++++++ 4 files changed, 798 insertions(+), 399 deletions(-) create mode 100644 src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2.java create mode 100644 src/test/java/org/orekit/models/earth/weather/GlobalPressureTemperature2Test.java diff --git a/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2.java b/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2.java new file mode 100644 index 0000000000..6b06f1a06e --- /dev/null +++ b/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2.java @@ -0,0 +1,594 @@ +/* Copyright 2002-2023 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.weather; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.List; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.function.ToDoubleFunction; +import java.util.regex.Pattern; + +import org.hipparchus.CalculusFieldElement; +import org.hipparchus.analysis.interpolation.BilinearInterpolatingFunction; +import org.hipparchus.util.FastMath; +import org.hipparchus.util.MathUtils; +import org.hipparchus.util.SinCos; +import org.orekit.annotation.DefaultDataContext; +import org.orekit.bodies.FieldGeodeticPoint; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.data.DataContext; +import org.orekit.data.DataLoader; +import org.orekit.data.DataProvidersManager; +import org.orekit.errors.OrekitException; +import org.orekit.errors.OrekitMessages; +import org.orekit.models.earth.Geoid; +import org.orekit.models.earth.troposphere.TropoUnit; +import org.orekit.models.earth.troposphere.ViennaOneModel; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; +import org.orekit.time.TimeScale; +import org.orekit.utils.Constants; + +/** The Global Pressure and Temperature 2 (GPT2) model. + * This model is an empirical model that provides the temperature, the pressure and the water vapor pressure + * of a site depending its latitude and longitude. This model also provides the ah + * and aw coefficients used for the {@link ViennaOneModel Vienna 1} model. + *

                + * The requisite coefficients for the computation of the weather parameters are provided by the + * Department of Geodesy and Geoinformation of the Vienna University. They are based on an + * external grid file like "gpt2_1.grd" (1° x 1°) or "gpt2_5.grd" (5° x 5°) available at: + * link + *

                + *

                + * A bilinear interpolation is performed in order to obtained the correct values of the weather parameters. + *

                + *

                + * The format is always the same, with and example shown below for the pressure and the temperature. + *

                + * Example: + *

                + *
                + * %  lat    lon   p:a0    A1   B1   A2   B2  T:a0    A1   B1   A2   B2
                + *   87.5    2.5 101421    21  409 -217 -122 259.2 -13.2 -6.1  2.6  0.3
                + *   87.5    7.5 101416    21  411 -213 -120 259.3 -13.1 -6.1  2.6  0.3
                + *   87.5   12.5 101411    22  413 -209 -118 259.3 -13.1 -6.1  2.6  0.3
                + *   87.5   17.5 101407    23  415 -205 -116 259.4 -13.0 -6.1  2.6  0.3
                + *   ...
                + * 
                + * + * @see "K. Lagler, M. Schindelegger, J. Böhm, H. Krasna, T. Nilsson (2013), + * GPT2: empirical slant delay model for radio space geodetic techniques. Geophys + * Res Lett 40(6):1069–1073. doi:10.1002/grl.50288" + * + * @author Bryan Cazabonne + * @author Luc Maisonobe + * @since 12.1 + */ +public class GlobalPressureTemperature2 implements PressureTemperatureHumidityProvider { + + /** Default supported files name pattern. */ + public static final String DEFAULT_SUPPORTED_NAMES = "gpt2_\\d+.grd"; + + /** Pattern for delimiting regular expressions. */ + private static final Pattern SEPARATOR = Pattern.compile("\\s+"); + + /** Standard gravity constant [m/s²]. */ + private static final double G = Constants.G0_STANDARD_GRAVITY; + + /** Ideal gas constant for dry air [J/kg/K]. */ + private static final double R = 287.0; + + /** Conversion factor from degrees to mill arcseconds. */ + private static final int DEG_TO_MAS = 3600000; + + /** Loaded grid. */ + private final Grid grid; + + /** Geoid used to compute the undulations. */ + private final Geoid geoid; + + /** UTC time scale. */ + private final TimeScale utc; + + /** + * Constructor with supported names given by user. This constructor uses the {@link + * DataContext#getDefault() default data context}. + * + * @param supportedNames supported names + * @param geoid level surface of the gravity potential of a body + * @see #GlobalPressureTemperature2(String, Geoid, DataProvidersManager, TimeScale) + */ + @DefaultDataContext + public GlobalPressureTemperature2(final String supportedNames, final Geoid geoid) { + this(supportedNames, geoid, + DataContext.getDefault().getDataProvidersManager(), + DataContext.getDefault().getTimeScales().getUTC()); + } + + /** + * Constructor with supported names and source of GPT2 auxiliary data given by user. + * + * @param supportedNames supported names + * @param geoid level surface of the gravity potential of a body + * @param dataProvidersManager provides access to auxiliary data. + * @param utc UTC time scale. + */ + public GlobalPressureTemperature2(final String supportedNames, + final Geoid geoid, + final DataProvidersManager dataProvidersManager, + final TimeScale utc) { + this.geoid = geoid; + this.utc = utc; + + // load the grid data + final Parser parser = new Parser(); + dataProvidersManager.feed(supportedNames, parser); + this.grid = parser.grid; + + } + + /** + * Constructor with default supported names. This constructor uses the {@link + * DataContext#getDefault() default data context}. + * + * @param geoid level surface of the gravity potential of a body + * @see #GlobalPressureTemperature2String, Geoid, DataProvidersManager, TimeScale) + */ + @DefaultDataContext + public GlobalPressureTemperature2(final Geoid geoid) { + this(DEFAULT_SUPPORTED_NAMES, geoid); + } + + /** Get coefficients array for VMF mapping function. + *
                  + *
                • double[0] = ah + *
                • double[1] = aw + *
                + * @param location location at which parameters are requested + * @param date date at which parameters are requested + * @return the coefficients array for VMF mapping function + */ + public double[] getA(final GeodeticPoint location, final AbsoluteDate date) { + + final Neighbors neighbors = new Neighbors(location.getLatitude(), location.getLongitude(), grid); + final int dayOfYear = date.getComponents(utc).getDate().getDayOfYear(); + + // ah and aw coefficients + return new double[] { + neighbors.interpolate(e -> evaluate(dayOfYear, e.ah)) * 0.001, + neighbors.interpolate(e -> evaluate(dayOfYear, e.aw)) * 0.001 + }; + + } + + /** {@inheritDoc} */ + @Override + public PressureTemperatureHumidity getWeatherParamerers(final GeodeticPoint location, final AbsoluteDate date) { + + final Neighbors neighbors = new Neighbors(location.getLatitude(), location.getLongitude(), grid); + final int dayOfYear = date.getComponents(utc).getDate().getDayOfYear(); + + // Corrected height (can be negative) + final double undu = geoid.getUndulation(neighbors.latitude, neighbors.longitude, date); + final double correctedheight = location.getAltitude() - undu - neighbors.interpolate(e -> e.hS); + + // Temperature gradient [K/m] + final double dTdH = neighbors.interpolate(e -> evaluate(dayOfYear, e.dT)) * 0.001; + + // Specific humidity + final double qv = neighbors.interpolate(e -> evaluate(dayOfYear, e.qv0)) * 0.001; + + // For the computation of the temperature and the pressure, we use + // the standard ICAO atmosphere formulas. + + // Temperature [K] + final double t0 = neighbors.interpolate(e -> evaluate(dayOfYear, e.temperature0)); + final double temperature = t0 + dTdH * correctedheight; + + // Pressure [hPa] + final double p0 = neighbors.interpolate(e -> evaluate(dayOfYear, e.pressure0)); + final double exponent = G / (dTdH * R); + final double pressure = p0 * FastMath.pow(1 - (dTdH / t0) * correctedheight, exponent) * 0.01; + + // Water vapor pressure [hPa] + final double e0 = qv * pressure / (0.622 + 0.378 * qv); + + return new PressureTemperatureHumidity(TropoUnit.HECTO_PASCAL.toSI(pressure), + temperature, + TropoUnit.HECTO_PASCAL.toSI(e0)); + + } + + /** {@inheritDoc} */ + @Override + public > FieldPressureTemperatureHumidity getWeatherParamerers(final FieldGeodeticPoint location, + final FieldAbsoluteDate date) { + + final Neighbors neighbors = new Neighbors(location.getLatitude().getReal(), + location.getLongitude().getReal(), + grid); + final int dayOfYear = date.getComponents(utc).getDate().getDayOfYear(); + + // Corrected height (can be negative) + final double undu = geoid.getUndulation(neighbors.latitude, neighbors.longitude, date.toAbsoluteDate()); + final T correctedheight = location.getAltitude().subtract(undu).subtract(neighbors.interpolate(e -> e.hS)); + + // Temperature gradient [K/m] + final double dTdH = neighbors.interpolate(e -> evaluate(dayOfYear, e.dT)) * 0.001; + + // Specific humidity + final double qv = neighbors.interpolate(e -> evaluate(dayOfYear, e.qv0)) * 0.001; + + // For the computation of the temperature and the pressure, we use + // the standard ICAO atmosphere formulas. + + // Temperature [K] + final double t0 = neighbors.interpolate(e -> evaluate(dayOfYear, e.temperature0)); + final T temperature = correctedheight.multiply(dTdH).add(t0); + + // Pressure [hPa] + final double p0 = neighbors.interpolate(e -> evaluate(dayOfYear, e.pressure0)); + final double exponent = G / (dTdH * R); + final T pressure = FastMath.pow(correctedheight.multiply(-dTdH / t0).add(1), exponent).multiply(p0 * 0.01); + + // Water vapor pressure [hPa] + final T e0 = pressure.multiply(qv / (0.622 + 0.378 * qv)); + + return new FieldPressureTemperatureHumidity<>(TropoUnit.HECTO_PASCAL.toSI(pressure), + temperature, + TropoUnit.HECTO_PASCAL.toSI(e0)); + + } + + /** Evaluate a model for some day. + * @param dayOfYear day to evaluate + * @param model model array + * @return model value at specified day + */ + private double evaluate(final int dayOfYear, final double[] model) { + + final double coef = (dayOfYear / 365.25) * 2 * FastMath.PI; + final SinCos sc1 = FastMath.sinCos(coef); + final SinCos sc2 = FastMath.sinCos(2.0 * coef); + + return model[0] + + model[1] * sc1.cos() + model[2] * sc1.sin() + + model[3] * sc2.cos() + model[4] * sc2.sin(); + + } + + /** Container for neighboring grid entries. */ + private static class Neighbors { + + /** Latitude of point of interest. */ + private final double latitude; + + /** Longitude of point of interest. */ + private final double longitude; + + /** South-West grid entry. */ + private final GridEntry southWest; + + /** South-East grid entry. */ + private final GridEntry southEast; + + /** North-West grid entry. */ + private final GridEntry northWest; + + /** North-East grid entry. */ + private final GridEntry northEast; + + /** Simple constructor. + * @param latitude latitude of point of interest + * @param longitude longitude of point of interest + * @param grid global grid + */ + Neighbors(final double latitude, final double longitude, final Grid grid) { + this.latitude = latitude; + this.longitude = MathUtils.normalizeAngle(longitude, + grid.entries[0][0].longitude + FastMath.PI); + + final int southIndex = grid.getSouthIndex(this.latitude); + final int westIndex = grid.getWestIndex(this.longitude); + this.southWest = grid.entries[southIndex ][westIndex ]; + this.southEast = grid.entries[southIndex ][westIndex + 1]; + this.northWest = grid.entries[southIndex + 1][westIndex ]; + this.northEast = grid.entries[southIndex + 1][westIndex + 1]; + + } + + /** Interpolate a grid function. + * @param gridGetter getter for the grid function + * @return interpolated function" + */ + private double interpolate(final ToDoubleFunction gridGetter) { + + // cell surrounding the point + final double[] xVal = new double[] { + southWest.longitude, southEast.longitude + }; + final double[] yVal = new double[] { + southWest.latitude, northWest.latitude + }; + + // evaluate grid points at specified day + final double[][] fval = new double[][] { + { + gridGetter.applyAsDouble(southWest), + gridGetter.applyAsDouble(northWest) + }, { + gridGetter.applyAsDouble(southEast), + gridGetter.applyAsDouble(northEast) + } + }; + + // perform interpolation in the grid + return new BilinearInterpolatingFunction(xVal, yVal, fval).value(longitude, latitude); + + } + + } + + /** Parser for GPT2 grid files. */ + private static class Parser implements DataLoader { + + /** Grid entries. */ + private Grid grid; + + @Override + public boolean stillAcceptsData() { + return grid == null; + } + + @Override + public void loadData(final InputStream input, final String name) + throws IOException, ParseException { + + final SortedSet latSample = new TreeSet<>(); + final SortedSet lonSample = new TreeSet<>(); + final List entries = new ArrayList<>(); + + // Open stream and parse data + int lineNumber = 0; + String line = null; + try (InputStreamReader isr = new InputStreamReader(input, StandardCharsets.UTF_8); + BufferedReader br = new BufferedReader(isr)) { + + for (line = br.readLine(); line != null; line = br.readLine()) { + ++lineNumber; + line = line.trim(); + + // read grid data + if (line.length() > 0 && !line.startsWith("%")) { + final GridEntry entry = new GridEntry(SEPARATOR.split(line)); + latSample.add(entry.latKey); + lonSample.add(entry.lonKey); + entries.add(entry); + } + + } + } catch (NumberFormatException nfe) { + throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE, + lineNumber, name, line); + } + + // organize entries in a grid that wraps arouns Earth in longitude + grid = new Grid(latSample, lonSample, entries, name); + + } + + } + + /** Container for complete grid. */ + private static class Grid { + + /** Latitude sample. */ + private final SortedSet latitudeSample; + + /** Longitude sample. */ + private final SortedSet longitudeSample; + + /** Grid entries. */ + private final GridEntry[][] entries; + + /** Simple constructor. + * @param latitudeSample latitude sample + * @param longitudeSample longitude sample + * @param loadedEntries loaded entries, organized as a simple list + * @param name file name + */ + Grid(final SortedSet latitudeSample, final SortedSet longitudeSample, + final List loadedEntries, final String name) { + + final int nA = latitudeSample.size(); + final int nO = longitudeSample.size() + 1; // we add one here for wrapping the grid + this.entries = new GridEntry[nA][nO]; + this.latitudeSample = latitudeSample; + this.longitudeSample = longitudeSample; + + // organize entries in the regular grid + for (final GridEntry entry : loadedEntries) { + final int latitudeIndex = latitudeSample.headSet(entry.latKey + 1).size() - 1; + final int longitudeIndex = longitudeSample.headSet(entry.lonKey + 1).size() - 1; + entries[latitudeIndex][longitudeIndex] = entry; + } + + // finalize the grid + for (final GridEntry[] row : entries) { + + // check for missing entries + for (int longitudeIndex = 0; longitudeIndex < nO - 1; ++longitudeIndex) { + if (row[longitudeIndex] == null) { + throw new OrekitException(OrekitMessages.IRREGULAR_OR_INCOMPLETE_GRID, name); + } + } + + // wrap the grid around the Earth in longitude + row[nO - 1] = new GridEntry(row[0].latitude, row[0].latKey, + row[0].longitude + 2 * FastMath.PI, + row[0].lonKey + DEG_TO_MAS * 360, + row[0].hS, row[0].pressure0, row[0].temperature0, + row[0].qv0, row[0].dT, row[0].ah, row[0].aw); + + } + + } + + /** Get index of South entries in the grid. + * @param latitude latitude to locate (radians) + * @return index of South entries in the grid + */ + public int getSouthIndex(final double latitude) { + + final int latKey = (int) FastMath.rint(FastMath.toDegrees(latitude) * DEG_TO_MAS); + final int index = latitudeSample.headSet(latKey + 1).size() - 1; + + // make sure we have at least one point remaining on North by clipping to size - 2 + return FastMath.min(index, latitudeSample.size() - 2); + + } + + /** Get index of West entries in the grid. + * @param longitude longitude to locate (radians) + * @return index of West entries in the grid + */ + public int getWestIndex(final double longitude) { + + final int lonKey = (int) FastMath.rint(FastMath.toDegrees(longitude) * DEG_TO_MAS); + final int index = longitudeSample.headSet(lonKey + 1).size() - 1; + + // we don't do clipping in longitude because we have added a row to wrap around the Earth + return index; + + } + + } + + /** Container for grid entries. */ + private static class GridEntry { + + /** Latitude (radian). */ + private final double latitude; + + /** Latitude key (mas). */ + private final int latKey; + + /** Longitude (radian). */ + private final double longitude; + + /** Longitude key (mas). */ + private final int lonKey; + + /** Height correction. */ + private final double hS; + + /** Pressure model. */ + private final double[] pressure0; + + /** Temperature model. */ + private final double[] temperature0; + + /** Specific humidity model. */ + private final double[] qv0; + + /** Temperature gradient model. */ + private final double[] dT; + + /** ah coefficient model. */ + private final double[] ah; + + /** aw coefficient model. */ + private final double[] aw; + + /** Build an entry from a parsed line. + * @param fields line fields + */ + GridEntry(final String[] fields) { + + final double latDegree = Double.parseDouble(fields[0]); + final double lonDegree = Double.parseDouble(fields[1]); + latitude = FastMath.toRadians(latDegree); + longitude = FastMath.toRadians(lonDegree); + latKey = (int) FastMath.rint(latDegree * DEG_TO_MAS); + lonKey = (int) FastMath.rint(lonDegree * DEG_TO_MAS); + + hS = Double.parseDouble(fields[23]); + + pressure0 = createModel(fields, 2); + temperature0 = createModel(fields, 7); + qv0 = createModel(fields, 12); + dT = createModel(fields, 17); + ah = createModel(fields, 24); + aw = createModel(fields, 29); + + } + + /** Build an entry from its components. + * @param latitude latitude (radian) + * @param latKey latitude key (mas) + * @param longitude longitude (radian) + * @param lonKey longitude key (mas) + * @param hS height correction + * @param pressure0 pressure model + * @param temperature0 temperature model + * @param qv0 specific humidity model + * @param dT temperature gradient model + * @param ah ah coefficient model + * @param aw aw coefficient model + */ + GridEntry(final double latitude, final int latKey, final double longitude, final int lonKey, + final double hS, final double[] pressure0, final double[] temperature0, + final double[] qv0, final double[] dT, final double[] ah, final double[] aw) { + + this.latitude = latitude; + this.latKey = latKey; + this.longitude = longitude; + this.lonKey = lonKey; + this.hS = hS; + this.pressure0 = pressure0.clone(); + this.temperature0 = temperature0.clone(); + this.qv0 = qv0.clone(); + this.dT = dT.clone(); + this.ah = ah.clone(); + this.aw = aw.clone(); + } + + /** Create a time model array. + * @param fields line fields + * @param first index of the first component of the model + * @return time model array + */ + private double[] createModel(final String[] fields, final int first) { + return new double[] { + Double.parseDouble(fields[first ]), + Double.parseDouble(fields[first + 1]), + Double.parseDouble(fields[first + 2]), + Double.parseDouble(fields[first + 3]), + Double.parseDouble(fields[first + 4]) + }; + } + + } + +} diff --git a/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2Model.java b/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2Model.java index b64d485a31..20e9ad8349 100644 --- a/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2Model.java +++ b/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2Model.java @@ -16,35 +16,15 @@ */ package org.orekit.models.earth.weather; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; -import java.text.ParseException; -import java.util.ArrayList; -import java.util.List; -import java.util.SortedSet; -import java.util.TreeSet; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.ToDoubleFunction; -import java.util.regex.Pattern; - -import org.hipparchus.analysis.interpolation.BilinearInterpolatingFunction; -import org.hipparchus.util.FastMath; -import org.hipparchus.util.MathUtils; -import org.hipparchus.util.SinCos; import org.orekit.annotation.DefaultDataContext; +import org.orekit.bodies.GeodeticPoint; import org.orekit.data.DataContext; -import org.orekit.data.DataLoader; import org.orekit.data.DataProvidersManager; -import org.orekit.errors.OrekitException; -import org.orekit.errors.OrekitMessages; import org.orekit.models.earth.Geoid; +import org.orekit.models.earth.troposphere.TropoUnit; import org.orekit.models.earth.troposphere.ViennaOneModel; import org.orekit.time.AbsoluteDate; import org.orekit.time.TimeScale; -import org.orekit.utils.Constants; /** The Global Pressure and Temperature 2 (GPT2) model. * This model is an empirical model that provides the temperature, the pressure and the water vapor pressure @@ -78,39 +58,13 @@ * Res Lett 40(6):1069–1073. doi:10.1002/grl.50288" * * @author Bryan Cazabonne - * + * as of 12.1, replaced by {@link GlobalPressureTemperature2} */ -public class GlobalPressureTemperature2Model implements WeatherModel { +@Deprecated +public class GlobalPressureTemperature2Model extends GlobalPressureTemperature2 implements WeatherModel { /** Default supported files name pattern. */ - public static final String DEFAULT_SUPPORTED_NAMES = "gpt2_\\d+.grd"; - - /** Pattern for delimiting regular expressions. */ - private static final Pattern SEPARATOR = Pattern.compile("\\s+"); - - /** Standard gravity constant [m/s²]. */ - private static final double G = Constants.G0_STANDARD_GRAVITY; - - /** Ideal gas constant for dry air [J/kg/K]. */ - private static final double R = 287.0; - - /** Conversion factor from degrees to mill arcseconds. */ - private static final int DEG_TO_MAS = 3600000; - - /** Shared lazily loaded grid. */ - private static final AtomicReference SHARED_GRID = new AtomicReference<>(null); - - /** South-West grid entry. */ - private final GridEntry southWest; - - /** South-East grid entry. */ - private final GridEntry southEast; - - /** North-West grid entry. */ - private final GridEntry northWest; - - /** North-East grid entry. */ - private final GridEntry northEast; + public static final String DEFAULT_SUPPORTED_NAMES = GlobalPressureTemperature2.DEFAULT_SUPPORTED_NAMES; /** The hydrostatic and wet a coefficients loaded. */ private double[] coefficientsA; @@ -130,12 +84,6 @@ public class GlobalPressureTemperature2Model implements WeatherModel { /** water vapour pressure, in hPa. */ private double e0; - /** Geoid used to compute the undulations. */ - private final Geoid geoid; - - /** UTC time scale. */ - private final TimeScale utc; - /** * Constructor with supported names given by user. This constructor uses the {@link * DataContext#getDefault() default data context}. @@ -151,8 +99,8 @@ public class GlobalPressureTemperature2Model implements WeatherModel { public GlobalPressureTemperature2Model(final String supportedNames, final double latitude, final double longitude, final Geoid geoid) { this(supportedNames, latitude, longitude, geoid, - DataContext.getDefault().getDataProvidersManager(), - DataContext.getDefault().getTimeScales().getUTC()); + DataContext.getDefault().getDataProvidersManager(), + DataContext.getDefault().getTimeScales().getUTC()); } /** @@ -172,33 +120,13 @@ public GlobalPressureTemperature2Model(final String supportedNames, final Geoid geoid, final DataProvidersManager dataProvidersManager, final TimeScale utc) { + super(supportedNames, geoid, dataProvidersManager, utc); this.coefficientsA = null; this.temperature = Double.NaN; this.pressure = Double.NaN; this.e0 = Double.NaN; - this.geoid = geoid; this.latitude = latitude; - this.utc = utc; - - // get the lazily loaded shared grid - Grid grid = SHARED_GRID.get(); - if (grid == null) { - // this is the first instance we create, we need to load the grid data - final Parser parser = new Parser(); - dataProvidersManager.feed(supportedNames, parser); - SHARED_GRID.compareAndSet(null, parser.grid); - grid = parser.grid; - } - - // Normalize longitude according to the grid - this.longitude = MathUtils.normalizeAngle(longitude, grid.entries[0][0].longitude + FastMath.PI); - - final int southIndex = grid.getSouthIndex(this.latitude); - final int westIndex = grid.getWestIndex(this.longitude); - this.southWest = grid.entries[southIndex ][westIndex ]; - this.southEast = grid.entries[southIndex ][westIndex + 1]; - this.northWest = grid.entries[southIndex + 1][westIndex ]; - this.northEast = grid.entries[southIndex + 1][westIndex + 1]; + this.longitude = longitude; } @@ -252,326 +180,16 @@ public double getWaterVaporPressure() { @Override public void weatherParameters(final double stationHeight, final AbsoluteDate currentDate) { - final int dayOfYear = currentDate.getComponents(utc).getDate().getDayOfYear(); + final GeodeticPoint location = new GeodeticPoint(latitude, longitude, stationHeight); // ah and aw coefficients - coefficientsA = new double[] { - interpolate(e -> evaluate(dayOfYear, e.ah)) * 0.001, - interpolate(e -> evaluate(dayOfYear, e.aw)) * 0.001 - }; - - // Corrected height (can be negative) - final double undu = geoid.getUndulation(latitude, longitude, currentDate); - final double correctedheight = stationHeight - undu - interpolate(e -> e.hS); - - // Temperature gradient [K/m] - final double dTdH = interpolate(e -> evaluate(dayOfYear, e.dT)) * 0.001; - - // Specific humidity - final double qv = interpolate(e -> evaluate(dayOfYear, e.qv0)) * 0.001; - - // For the computation of the temperature and the pressure, we use - // the standard ICAO atmosphere formulas. - - // Temperature [K] - final double t0 = interpolate(e -> evaluate(dayOfYear, e.temperature0)); - this.temperature = t0 + dTdH * correctedheight; - - // Pressure [hPa] - final double p0 = interpolate(e -> evaluate(dayOfYear, e.pressure0)); - final double exponent = G / (dTdH * R); - this.pressure = p0 * FastMath.pow(1 - (dTdH / t0) * correctedheight, exponent) * 0.01; - - // Water vapor pressure [hPa] - this.e0 = qv * pressure / (0.622 + 0.378 * qv); - - } - - /** Interpolate a grid function. - * @param gridGetter getter for the grid function - * @return interpolated function" - */ - private double interpolate(final ToDoubleFunction gridGetter) { - - // cell surrounding the point - final double[] xVal = new double[] { - southWest.longitude, southEast.longitude - }; - final double[] yVal = new double[] { - southWest.latitude, northWest.latitude - }; - - // evaluate grid points at specified day - final double[][] fval = new double[][] { - { - gridGetter.applyAsDouble(southWest), - gridGetter.applyAsDouble(northWest) - }, { - gridGetter.applyAsDouble(southEast), - gridGetter.applyAsDouble(northEast) - } - }; - - // perform interpolation in the grid - return new BilinearInterpolatingFunction(xVal, yVal, fval).value(longitude, latitude); - - } - - /** Evaluate a model for some day. - * @param dayOfYear day to evaluate - * @param model model array - * @return model value at specified day - */ - private double evaluate(final int dayOfYear, final double[] model) { - - final double coef = (dayOfYear / 365.25) * 2 * FastMath.PI; - final SinCos sc1 = FastMath.sinCos(coef); - final SinCos sc2 = FastMath.sinCos(2.0 * coef); - - return model[0] + - model[1] * sc1.cos() + model[2] * sc1.sin() + - model[3] * sc2.cos() + model[4] * sc2.sin(); - - } - - /** Parser for GPT2 grid files. */ - private static class Parser implements DataLoader { - - /** Grid entries. */ - private Grid grid; - - @Override - public boolean stillAcceptsData() { - return grid == null; - } - - @Override - public void loadData(final InputStream input, final String name) - throws IOException, ParseException { - - final SortedSet latSample = new TreeSet<>(); - final SortedSet lonSample = new TreeSet<>(); - final List entries = new ArrayList<>(); - - // Open stream and parse data - int lineNumber = 0; - String line = null; - try (InputStreamReader isr = new InputStreamReader(input, StandardCharsets.UTF_8); - BufferedReader br = new BufferedReader(isr)) { - - for (line = br.readLine(); line != null; line = br.readLine()) { - ++lineNumber; - line = line.trim(); - - // read grid data - if (line.length() > 0 && !line.startsWith("%")) { - final GridEntry entry = new GridEntry(SEPARATOR.split(line)); - latSample.add(entry.latKey); - lonSample.add(entry.lonKey); - entries.add(entry); - } - - } - } catch (NumberFormatException nfe) { - throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE, - lineNumber, name, line); - } - - // organize entries in a grid that wraps arouns Earth in longitude - grid = new Grid(latSample, lonSample, entries, name); - - } - - } - - /** Container for complete grid. */ - private static class Grid { - - /** Latitude sample. */ - private final SortedSet latitudeSample; - - /** Longitude sample. */ - private final SortedSet longitudeSample; - - /** Grid entries. */ - private final GridEntry[][] entries; - - /** Simple constructor. - * @param latitudeSample latitude sample - * @param longitudeSample longitude sample - * @param loadedEntries loaded entries, organized as a simple list - * @param name file name - */ - Grid(final SortedSet latitudeSample, final SortedSet longitudeSample, - final List loadedEntries, final String name) { - - final int nA = latitudeSample.size(); - final int nO = longitudeSample.size() + 1; // we add one here for wrapping the grid - this.entries = new GridEntry[nA][nO]; - this.latitudeSample = latitudeSample; - this.longitudeSample = longitudeSample; - - // organize entries in the regular grid - for (final GridEntry entry : loadedEntries) { - final int latitudeIndex = latitudeSample.headSet(entry.latKey + 1).size() - 1; - final int longitudeIndex = longitudeSample.headSet(entry.lonKey + 1).size() - 1; - entries[latitudeIndex][longitudeIndex] = entry; - } - - // finalize the grid - for (final GridEntry[] row : entries) { - - // check for missing entries - for (int longitudeIndex = 0; longitudeIndex < nO - 1; ++longitudeIndex) { - if (row[longitudeIndex] == null) { - throw new OrekitException(OrekitMessages.IRREGULAR_OR_INCOMPLETE_GRID, name); - } - } - - // wrap the grid around the Earth in longitude - row[nO - 1] = new GridEntry(row[0].latitude, row[0].latKey, - row[0].longitude + 2 * FastMath.PI, - row[0].lonKey + DEG_TO_MAS * 360, - row[0].hS, row[0].pressure0, row[0].temperature0, - row[0].qv0, row[0].dT, row[0].ah, row[0].aw); - - } - - } - - /** Get index of South entries in the grid. - * @param latitude latitude to locate (radians) - * @return index of South entries in the grid - */ - public int getSouthIndex(final double latitude) { - - final int latKey = (int) FastMath.rint(FastMath.toDegrees(latitude) * DEG_TO_MAS); - final int index = latitudeSample.headSet(latKey + 1).size() - 1; - - // make sure we have at least one point remaining on North by clipping to size - 2 - return FastMath.min(index, latitudeSample.size() - 2); - - } - - /** Get index of West entries in the grid. - * @param longitude longitude to locate (radians) - * @return index of West entries in the grid - */ - public int getWestIndex(final double longitude) { - - final int lonKey = (int) FastMath.rint(FastMath.toDegrees(longitude) * DEG_TO_MAS); - final int index = longitudeSample.headSet(lonKey + 1).size() - 1; - - // we don't do clipping in longitude because we have added a row to wrap around the Earth - return index; - - } - - } - - /** Container for grid entries. */ - private static class GridEntry { - - /** Latitude (radian). */ - private final double latitude; - - /** Latitude key (mas). */ - private final int latKey; - - /** Longitude (radian). */ - private final double longitude; - - /** Longitude key (mas). */ - private final int lonKey; - - /** Height correction. */ - private final double hS; - - /** Pressure model. */ - private final double[] pressure0; - - /** Temperature model. */ - private final double[] temperature0; - - /** Specific humidity model. */ - private final double[] qv0; - - /** Temperature gradient model. */ - private final double[] dT; - - /** ah coefficient model. */ - private final double[] ah; - - /** aw coefficient model. */ - private final double[] aw; - - /** Build an entry from a parsed line. - * @param fields line fields - */ - GridEntry(final String[] fields) { - - final double latDegree = Double.parseDouble(fields[0]); - final double lonDegree = Double.parseDouble(fields[1]); - latitude = FastMath.toRadians(latDegree); - longitude = FastMath.toRadians(lonDegree); - latKey = (int) FastMath.rint(latDegree * DEG_TO_MAS); - lonKey = (int) FastMath.rint(lonDegree * DEG_TO_MAS); - - hS = Double.parseDouble(fields[23]); - - pressure0 = createModel(fields, 2); - temperature0 = createModel(fields, 7); - qv0 = createModel(fields, 12); - dT = createModel(fields, 17); - ah = createModel(fields, 24); - aw = createModel(fields, 29); - - } - - /** Build an entry from its components. - * @param latitude latitude (radian) - * @param latKey latitude key (mas) - * @param longitude longitude (radian) - * @param lonKey longitude key (mas) - * @param hS height correction - * @param pressure0 pressure model - * @param temperature0 temperature model - * @param qv0 specific humidity model - * @param dT temperature gradient model - * @param ah ah coefficient model - * @param aw aw coefficient model - */ - GridEntry(final double latitude, final int latKey, final double longitude, final int lonKey, - final double hS, final double[] pressure0, final double[] temperature0, - final double[] qv0, final double[] dT, final double[] ah, final double[] aw) { - - this.latitude = latitude; - this.latKey = latKey; - this.longitude = longitude; - this.lonKey = lonKey; - this.hS = hS; - this.pressure0 = pressure0.clone(); - this.temperature0 = temperature0.clone(); - this.qv0 = qv0.clone(); - this.dT = dT.clone(); - this.ah = ah.clone(); - this.aw = aw.clone(); - } + coefficientsA = getA(location, currentDate); - /** Create a time model array. - * @param fields line fields - * @param first index of the first component of the model - * @return time model array - */ - private double[] createModel(final String[] fields, final int first) { - return new double[] { - Double.parseDouble(fields[first ]), - Double.parseDouble(fields[first + 1]), - Double.parseDouble(fields[first + 2]), - Double.parseDouble(fields[first + 3]), - Double.parseDouble(fields[first + 4]) - }; - } + // Pressure, temperature, humidity + final PressureTemperatureHumidity pth = getWeatherParamerers(location, currentDate); + this.temperature = pth.getTemperature(); + this.pressure = TropoUnit.HECTO_PASCAL.fromSI(pth.getPressure()); + this.e0 = TropoUnit.HECTO_PASCAL.fromSI(pth.getWaterVaporPressure()); } diff --git a/src/test/java/org/orekit/models/earth/weather/GlobalPressureTemperature2ModelTest.java b/src/test/java/org/orekit/models/earth/weather/GlobalPressureTemperature2ModelTest.java index f68224c51a..a09ed3a0ab 100644 --- a/src/test/java/org/orekit/models/earth/weather/GlobalPressureTemperature2ModelTest.java +++ b/src/test/java/org/orekit/models/earth/weather/GlobalPressureTemperature2ModelTest.java @@ -31,6 +31,7 @@ import org.orekit.time.TimeScalesFactory; import org.orekit.utils.IERSConventions; +@Deprecated public class GlobalPressureTemperature2ModelTest { private static double epsilon = 1.0e-12; diff --git a/src/test/java/org/orekit/models/earth/weather/GlobalPressureTemperature2Test.java b/src/test/java/org/orekit/models/earth/weather/GlobalPressureTemperature2Test.java new file mode 100644 index 0000000000..1e0f1b1c7f --- /dev/null +++ b/src/test/java/org/orekit/models/earth/weather/GlobalPressureTemperature2Test.java @@ -0,0 +1,186 @@ +/* Copyright 2002-2023 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.weather; + +import org.hipparchus.util.FastMath; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.orekit.Utils; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.errors.OrekitException; +import org.orekit.errors.OrekitMessages; +import org.orekit.forces.gravity.potential.GRGSFormatReader; +import org.orekit.forces.gravity.potential.GravityFieldFactory; +import org.orekit.frames.FramesFactory; +import org.orekit.models.earth.Geoid; +import org.orekit.models.earth.ReferenceEllipsoid; +import org.orekit.models.earth.troposphere.TropoUnit; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.TimeScalesFactory; +import org.orekit.utils.IERSConventions; + +public class GlobalPressureTemperature2Test { + + private static double epsilon = 1.0e-12; + + @Test + public void testWeatherParameters() { + + Utils.setDataRoot("regular-data:potential:gpt2-grid"); + GravityFieldFactory.addPotentialCoefficientsReader(new GRGSFormatReader("grim4s4_gr", true)); + + // Site Vienna: latitude: 48.20°N + // longitude: 16.37°E + // height: 156 m + // + // Date: 2 August 2012 + // + // Expected outputs are given by the Department of Geodesy and Geoinformation of the Vienna University. + // Expected parameters : temperature -> 22.12 °C + // pressure -> 1002.56 hPa + // e -> 15.63 hPa + // ah -> 0.0012647 + // aw -> 0.0005726 + // + // We test the fiability of our implementation by comparing our output values with + // the ones obtained by the Vienna University. + + final double latitude = FastMath.toRadians(48.20); + final double longitude = FastMath.toRadians(16.37); + final double height = 156.0; + final AbsoluteDate date = AbsoluteDate.createMJDDate(56141, 0.0, TimeScalesFactory.getUTC()); + final Geoid geoid = new Geoid(GravityFieldFactory.getNormalizedProvider(12, 12), + ReferenceEllipsoid.getWgs84(FramesFactory.getITRF(IERSConventions.IERS_2010, true))); + final GlobalPressureTemperature2 model = + new GlobalPressureTemperature2("gpt2_5_extract.grd", geoid); + + final GeodeticPoint location = new GeodeticPoint(latitude, longitude, height); + final double a[] = model.getA(location, date); + final PressureTemperatureHumidity pth = model.getWeatherParamerers(location, date); + + Assertions.assertEquals(0.0012647, a[0], 1.1e-7); + Assertions.assertEquals(0.0005726, a[1], 8.6e-8); + Assertions.assertEquals(273.15 + 22.12, pth.getTemperature(), 2.3e-1); + Assertions.assertEquals(1002.56, TropoUnit.HECTO_PASCAL.fromSI(pth.getPressure()), 5.1e-1); + Assertions.assertEquals(15.63, TropoUnit.HECTO_PASCAL.fromSI(pth.getWaterVaporPressure()), 5.0e-2); + + } + + @Test + public void testEquality() { + + Utils.setDataRoot("regular-data:potential:gpt2-grid"); + GravityFieldFactory.addPotentialCoefficientsReader(new GRGSFormatReader("grim4s4_gr", true)); + + // Commons parameters + final Geoid geoid = new Geoid(GravityFieldFactory.getNormalizedProvider(12, 12), + ReferenceEllipsoid.getWgs84(FramesFactory.getITRF(IERSConventions.IERS_2010, true))); + + final AbsoluteDate date = AbsoluteDate.createMJDDate(56141, 0.0, TimeScalesFactory.getUTC()); + final double latitude = FastMath.toRadians(45.0); + final double height = 0.0; + + GlobalPressureTemperature2 model = new GlobalPressureTemperature2(geoid); + + // Test longitude = 181° and longitude = -179° + GeodeticPoint location1 = new GeodeticPoint(latitude, FastMath.toRadians(181.0), height); + double[] a1 = model.getA(location1, date); + PressureTemperatureHumidity pth1 = model.getWeatherParamerers(location1, date); + GeodeticPoint location2 = new GeodeticPoint(latitude, FastMath.toRadians(-179.0), height); + double[] a2 = model.getA(location2, date); + PressureTemperatureHumidity pth2 = model.getWeatherParamerers(location2, date); + + Assertions.assertEquals(pth1.getTemperature(), pth2.getTemperature(), epsilon); + Assertions.assertEquals(pth1.getPressure(), pth2.getPressure(), epsilon); + Assertions.assertEquals(pth1.getWaterVaporPressure(), pth2.getWaterVaporPressure(), epsilon); + Assertions.assertEquals(a1[0], a2[0], epsilon); + Assertions.assertEquals(a1[1], a2[1], epsilon); + + // Test longitude = 180° and longitude = -180° + location1 = new GeodeticPoint(latitude, FastMath.toRadians(180.0), height); + a1 = model.getA(location1, date); + pth1 = model.getWeatherParamerers(location1, date); + location2 = new GeodeticPoint(latitude, FastMath.toRadians(-180.0), height); + a2 = model.getA(location2, date); + pth2 = model.getWeatherParamerers(location2, date); + + Assertions.assertEquals(pth1.getTemperature(), pth2.getTemperature(), epsilon); + Assertions.assertEquals(pth1.getPressure(), pth2.getPressure(), epsilon); + Assertions.assertEquals(pth1.getWaterVaporPressure(), pth2.getWaterVaporPressure(), epsilon); + Assertions.assertEquals(a1[0], a2[0], epsilon); + Assertions.assertEquals(a1[1], a2[1], epsilon); + + // Test longitude = 0° and longitude = 360° + location1 = new GeodeticPoint(latitude, FastMath.toRadians(0.0), height); + a1 = model.getA(location1, date); + pth1 = model.getWeatherParamerers(location1, date); + location2 = new GeodeticPoint(latitude, FastMath.toRadians(360.0), height); + a2 = model.getA(location2, date); + pth2 = model.getWeatherParamerers(location2, date); + + Assertions.assertEquals(pth1.getTemperature(), pth2.getTemperature(), epsilon); + Assertions.assertEquals(pth1.getPressure(), pth2.getPressure(), epsilon); + Assertions.assertEquals(pth1.getWaterVaporPressure(), pth2.getWaterVaporPressure(), epsilon); + Assertions.assertEquals(a1[0], a2[0], epsilon); + Assertions.assertEquals(a1[1], a2[1], epsilon); + + } + + @Test + public void testCorruptedFileBadData() { + + Utils.setDataRoot("regular-data:potential:gpt2-grid"); + GravityFieldFactory.addPotentialCoefficientsReader(new GRGSFormatReader("grim4s4_gr", true)); + + // Date is not used here + final Geoid geoid = new Geoid(GravityFieldFactory.getNormalizedProvider(12, 12), + ReferenceEllipsoid.getWgs84(FramesFactory.getITRF(IERSConventions.IERS_2010, true))); + + final String fileName = "corrupted-bad-data-gpt2_5.grd"; + try { + new GlobalPressureTemperature2(fileName, geoid); + Assertions.fail("An exception should have been thrown"); + } catch (OrekitException oe) { + Assertions.assertEquals(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE, oe.getSpecifier()); + Assertions.assertEquals(6, ((Integer) oe.getParts()[0]).intValue()); + Assertions.assertTrue(((String) oe.getParts()[1]).endsWith(fileName)); + } + + } + + @Test + public void testCorruptedIrregularGrid() { + + Utils.setDataRoot("regular-data:potential:gpt2-grid"); + GravityFieldFactory.addPotentialCoefficientsReader(new GRGSFormatReader("grim4s4_gr", true)); + + // Date is not used here + final Geoid geoid = new Geoid(GravityFieldFactory.getNormalizedProvider(12, 12), + ReferenceEllipsoid.getWgs84(FramesFactory.getITRF(IERSConventions.IERS_2010, true))); + + final String fileName = "corrupted-irregular-grid-gpt2_5.grd"; + try { + new GlobalPressureTemperature2(fileName, geoid); + Assertions.fail("An exception should have been thrown"); + } catch (OrekitException oe) { + Assertions.assertEquals(OrekitMessages.IRREGULAR_OR_INCOMPLETE_GRID, oe.getSpecifier()); + Assertions.assertTrue(((String) oe.getParts()[0]).endsWith(fileName)); + } + + } + +} From e0957e1ec679089d82245e768cff512c862a94cb Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Mon, 11 Dec 2023 17:47:57 +0100 Subject: [PATCH 033/359] Redesigned GPT. --- .../weather/GlobalPressureTemperature.java | 696 ++++++++++++++++++ .../GlobalPressureTemperatureModel.java | 634 +--------------- .../GlobalPressureTemperatureModelTest.java | 1 + .../GlobalPressureTemperatureTest.java | 148 ++++ 4 files changed, 863 insertions(+), 616 deletions(-) create mode 100644 src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature.java create mode 100644 src/test/java/org/orekit/models/earth/weather/GlobalPressureTemperatureTest.java diff --git a/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature.java b/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature.java new file mode 100644 index 0000000000..7ebda1f977 --- /dev/null +++ b/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature.java @@ -0,0 +1,696 @@ +/* Copyright 2002-2023 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.weather; + +import org.hipparchus.util.FastMath; +import org.hipparchus.util.SinCos; +import org.orekit.annotation.DefaultDataContext; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.data.DataContext; +import org.orekit.models.earth.Geoid; +import org.orekit.models.earth.troposphere.TropoUnit; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.DateTimeComponents; +import org.orekit.time.TimeScale; +import org.orekit.utils.LegendrePolynomials; + +/** The Global Pressure and Temperature model. + * This model is an empirical model that provides the temperature and the pressure depending + * the latitude and the longitude of the station. + *

                + * The Global Pressure and Temperature model is based on spherical harmonics up + * to degree and order of 9. The residual values ​​of this model can reach 20 hPa + * for pressure and 10 ° C for temperature. They are significant for higher latitudes and + * small near the equator (Böhm, 2007) + *

                + * + * @see "J. Böhm, R. Heinkelmann, and H. Schuh (2007), + * Short Note: A global model of pressure and temperature for geodetic applications. J Geod, + * doi:10.1007/s00190-007-0135-3." + * + * @author Bryan Cazabonne + * @author Luc Maisonobe + * @since 12.1 + */ +public class GlobalPressureTemperature { + + /** Temperature gradient (°C/m). */ + private static final double TEMPERATURE_GRADIENT = -6.5e-3; + + /** Spherical harmonics degree. */ + private static final int DEGREE = 9; + + /** Spherical harmonics order. */ + private static final int ORDER = 9; + + /** Geoid used to compute the undulations. */ + private final Geoid geoid; + + /** UTC time scale. */ + private final TimeScale utc; + + /** Build a new instance. + * + *

                This method uses the {@link DataContext#getDefault() default data context}. + * + * @param geoid level surface of the gravity potential of a body + * @see #GlobalPressureTemperatureModel(Geoid, DataContext) + */ + @DefaultDataContext + public GlobalPressureTemperature(final Geoid geoid) { + this(geoid, DataContext.getDefault().getTimeScales().getUTC()); + } + + /** Build a new instance. + * @param geoid level surface of the gravity potential of a body + * @param utc UTC time scale. + */ + public GlobalPressureTemperature(final Geoid geoid, final TimeScale utc) { + this.geoid = geoid; + this.utc = utc; + } + + /** Provide weather parameters. + * @param location location at which parameters are requested + * @param date date at which parameters are requested + * @return weather parameters + */ + public PressureTemperature getWeatherParameters(final GeodeticPoint location, final AbsoluteDate date) { + + // Day of year computation + final DateTimeComponents dtc = date.getComponents(utc); + final int dofyear = dtc.getDate().getDayOfYear(); + + // Reference day: 28 January 1980 (Niell, 1996) + final int t0 = 28; + final double coef = ((dofyear + 1 - t0) / 365.25) * 2 * FastMath.PI; + final double cosCoef = FastMath.cos(coef); + + // Compute Legendre Polynomials Pnm(sin(phi)) + final LegendrePolynomials p = new LegendrePolynomials(DEGREE, ORDER, + FastMath.sin(location.getLatitude())); + + // Corrected height + final double correctedheight = FastMath.max(0.0, + location.getAltitude() - geoid.getUndulation(location.getLatitude(), + location.getLongitude(), + date)); + + // Eq. 4 (Ref) + double meanT0 = 0.0; + double amplitudeT0 = 0.0; + double meanP0 = 0.0; + double amplitudeP0 = 0.0; + final ABCoefficients abCoef = new ABCoefficients(); + int j = 0; + for (int n = 0; n <= DEGREE; n++) { + for (int m = 0; m <= n; m++) { + final SinCos sc = FastMath.sinCos(m * location.getLongitude()); + final double pCosmLambda = p.getPnm(n, m) * sc.cos(); + final double pSinmLambda = p.getPnm(n, m) * sc.sin(); + + meanT0 = meanT0 + + (abCoef.getAnmTemperatureMean(j) * pCosmLambda + abCoef.getBnmTemperatureMean(j) * pSinmLambda); + amplitudeT0 = amplitudeT0 + + (abCoef.getAnmTemperatureAmpl(j) * pCosmLambda + abCoef.getBnmTemperatureAmpl(j) * pSinmLambda); + meanP0 = meanP0 + + (abCoef.getAnmPressureMean(j) * pCosmLambda + abCoef.getBnmPressureMean(j) * pSinmLambda); + amplitudeP0 = amplitudeP0 + + (abCoef.getAnmPressureAmpl(j) * pCosmLambda + abCoef.getBnmPressureAmpl(j) * pSinmLambda); + + j = j + 1; + } + } + + // Eq. 3 (Ref) + final double temp0 = meanT0 + amplitudeT0 * cosCoef; + final double pres0 = meanP0 + amplitudeP0 * cosCoef; + + // Compute pressure and temperature Eq. 1 and 2 (Ref) + final double degrees = temp0 + TEMPERATURE_GRADIENT * correctedheight; + final double temperature = degrees + 273.15; + final double pressure = pres0 * FastMath.pow(1.0 - correctedheight * 0.0000226, 5.225); + + return new PressureTemperature(TropoUnit.HECTO_PASCAL.toSI(pressure), temperature); + + } + + private static class ABCoefficients { + + /** Mean Anm coefficients for the pressure. */ + private static final double[] A_PRESSURE_MEAN = { + 1.0108e+03, + 8.4886e+00, + 1.4799e+00, + -1.3897e+01, + 3.7516e-03, + -1.4936e-01, + 1.2232e+01, + -7.6615e-01, + -6.7699e-02, + 8.1002e-03, + -1.5874e+01, + 3.6614e-01, + -6.7807e-02, + -3.6309e-03, + 5.9966e-04, + 4.8163e+00, + -3.7363e-01, + -7.2071e-02, + 1.9998e-03, + -6.2385e-04, + -3.7916e-04, + 4.7609e+00, + -3.9534e-01, + 8.6667e-03, + 1.1569e-02, + 1.1441e-03, + -1.4193e-04, + -8.5723e-05, + 6.5008e-01, + -5.0889e-01, + -1.5754e-02, + -2.8305e-03, + 5.7458e-04, + 3.2577e-05, + -9.6052e-06, + -2.7974e-06, + 1.3530e+00, + -2.7271e-01, + -3.0276e-04, + 3.6286e-03, + -2.0398e-04, + 1.5846e-05, + -7.7787e-06, + 1.1210e-06, + 9.9020e-08, + 5.5046e-01, + -2.7312e-01, + 3.2532e-03, + -2.4277e-03, + 1.1596e-04, + 2.6421e-07, + -1.3263e-06, + 2.7322e-07, + 1.4058e-07, + 4.9414e-09 + }; + + /** Mean Bnm coefficients for the pressure. */ + private static final double[] B_PRESSURE_MEAN = { + 0.0000e+00, + 0.0000e+00, + -1.2878e+00, + 0.0000e+00, + 7.0444e-01, + 3.3222e-01, + 0.0000e+00, + -2.9636e-01, + 7.2248e-03, + 7.9655e-03, + 0.0000e+00, + 1.0854e+00, + 1.1145e-02, + -3.6513e-02, + 3.1527e-03, + 0.0000e+00, + -4.8434e-01, + 5.2023e-02, + -1.3091e-02, + 1.8515e-03, + 1.5422e-04, + 0.0000e+00, + 6.8298e-01, + 2.5261e-03, + -9.9703e-04, + -1.0829e-03, + +1.7688e-04, + -3.1418e-05, + +0.0000e+00, + -3.7018e-01, + 4.3234e-02, + 7.2559e-03, + 3.1516e-04, + 2.0024e-05, + -8.0581e-06, + -2.3653e-06, + 0.0000e+00, + 1.0298e-01, + -1.5086e-02, + 5.6186e-03, + 3.2613e-05, + 4.0567e-05, + -1.3925e-06, + -3.6219e-07, + -2.0176e-08, + 0.0000e+00, + -1.8364e-01, + 1.8508e-02, + 7.5016e-04, + -9.6139e-05, + -3.1995e-06, + 1.3868e-07, + -1.9486e-07, + 3.0165e-10, + -6.4376e-10 + }; + + /** Amplitude Anm coefficients for the pressure. */ + private static final double[] A_PRESSURE_AMPLITUDE = { + -1.0444e-01, + 1.6618e-01, + -6.3974e-02, + 1.0922e+00, + 5.7472e-01, + -3.0277e-01, + -3.5087e+00, + 7.1264e-03, + -1.4030e-01, + 3.7050e-02, + 4.0208e-01, + -3.0431e-01, + -1.3292e-01, + 4.6746e-03, + -1.5902e-04, + 2.8624e+00, + -3.9315e-01, + -6.4371e-02, + 1.6444e-02, + -2.3403e-03, + 4.2127e-05, + 1.9945e+00, + -6.0907e-01, + -3.5386e-02, + -1.0910e-03, + -1.2799e-04, + 4.0970e-05, + 2.2131e-05, + -5.3292e-01, + -2.9765e-01, + -3.2877e-02, + 1.7691e-03, + 5.9692e-05, + 3.1725e-05, + 2.0741e-05, + -3.7622e-07, + 2.6372e+00, + -3.1165e-01, + 1.6439e-02, + 2.1633e-04, + 1.7485e-04, + 2.1587e-05, + 6.1064e-06, + -1.3755e-08, + -7.8748e-08, + -5.9152e-01, + -1.7676e-01, + 8.1807e-03, + 1.0445e-03, + 2.3432e-04, + 9.3421e-06, + 2.8104e-06, + -1.5788e-07, + -3.0648e-08, + 2.6421e-10 + }; + + /** Amplitude Bnm coefficients for the pressure. */ + private static final double[] B_PRESSURE_AMPLITUDE = { + 0.0000e+00, + 0.0000e+00, + 9.3340e-01, + 0.0000e+00, + 8.2346e-01, + 2.2082e-01, + 0.0000e+00, + 9.6177e-01, + -1.5650e-02, + 1.2708e-03, + 0.0000e+00, + -3.9913e-01, + 2.8020e-02, + 2.8334e-02, + 8.5980e-04, + 0.0000e+00, + 3.0545e-01, + -2.1691e-02, + 6.4067e-04, + -3.6528e-05, + -1.1166e-04, + 0.0000e+00, + -7.6974e-02, + -1.8986e-02, + +5.6896e-03, + -2.4159e-04, + -2.3033e-04, + -9.6783e-06, + 0.0000e+00, + -1.0218e-01, + -1.3916e-02, + -4.1025e-03, + -5.1340e-05, + -7.0114e-05, + -3.3152e-07, + 1.6901e-06, + 0.0000e+00, + -1.2422e-02, + +2.5072e-03, + +1.1205e-03, + -1.3034e-04, + -2.3971e-05, + -2.6622e-06, + 5.7852e-07, + 4.5847e-08, + 0.0000e+00, + 4.4777e-02, + -3.0421e-03, + 2.6062e-05, + -7.2421e-05, + 1.9119e-06, + 3.9236e-07, + 2.2390e-07, + 2.9765e-09, + -4.6452e-09 + }; + + /** Mean Anm coefficients for the temperature. */ + private static final double[] A_TEMPERATURE_MEAN = { + 1.6257e+01, + 2.1224e+00, + 9.2569e-01, + -2.5974e+01, + 1.4510e+00, + 9.2468e-02, + -5.3192e-01, + 2.1094e-01, + -6.9210e-02, + -3.4060e-02, + -4.6569e+00, + 2.6385e-01, + -3.6093e-02, + 1.0198e-02, + -1.8783e-03, + 7.4983e-01, + 1.1741e-01, + 3.9940e-02, + 5.1348e-03, + 5.9111e-03, + 8.6133e-06, + 6.3057e-01, + 1.5203e-01, + 3.9702e-02, + 4.6334e-03, + 2.4406e-04, + 1.5189e-04, + 1.9581e-07, + 5.4414e-01, + 3.5722e-01, + 5.2763e-02, + 4.1147e-03, + -2.7239e-04, + -5.9957e-05, + 1.6394e-06, + -7.3045e-07, + -2.9394e+00, + 5.5579e-02, + 1.8852e-02, + 3.4272e-03, + -2.3193e-05, + -2.9349e-05, + 3.6397e-07, + 2.0490e-06, + -6.4719e-08, + -5.2225e-01, + 2.0799e-01, + 1.3477e-03, + 3.1613e-04, + -2.2285e-04, + -1.8137e-05, + -1.5177e-07, + 6.1343e-07, + 7.8566e-08, + 1.0749e-09 + }; + + /** Mean Bnm coefficients for the temperature. */ + private static final double[] B_TEMPERATURE_MEAN = { + 0.0000e+00, + 0.0000e+00, + 1.0210e+00, + 0.0000e+00, + 6.0194e-01, + 1.2292e-01, + 0.0000e+00, + -4.2184e-01, + 1.8230e-01, + 4.2329e-02, + 0.0000e+00, + 9.3312e-02, + 9.5346e-02, + -1.9724e-03, + 5.8776e-03, + 0.0000e+00, + -2.0940e-01, + 3.4199e-02, + -5.7672e-03, + -2.1590e-03, + 5.6815e-04, + 0.0000e+00, + 2.2858e-01, + 1.2283e-02, + -9.3679e-03, + -1.4233e-03, + -1.5962e-04, + 4.0160e-05, + 0.0000e+00, + 3.6353e-02, + -9.4263e-04, + -3.6762e-03, + 5.8608e-05, + -2.6391e-05, + 3.2095e-06, + -1.1605e-06, + 0.0000e+00, + 1.6306e-01, + 1.3293e-02, + -1.1395e-03, + 5.1097e-05, + 3.3977e-05, + 7.6449e-06, + -1.7602e-07, + -7.6558e-08, + 0.0000e+00, + -4.5415e-02, + -1.8027e-02, + 3.6561e-04, + -1.1274e-04, + 1.3047e-05, + 2.0001e-06, + -1.5152e-07, + -2.7807e-08, + 7.7491e-09 + }; + + /** Amplitude Anm coefficients for the temperature. */ + private static final double[] A_TEMPERATURE_AMPLITUDE = { + -1.8654e+00, + -9.0041e+00, + -1.2974e-01, + -3.6053e+00, + 2.0284e-02, + 2.1872e-01, + -1.3015e+00, + 4.0355e-01, + 2.2216e-01, + -4.0605e-03, + 1.9623e+00, + 4.2887e-01, + 2.1437e-01, + -1.0061e-02, + -1.1368e-03, + -6.9235e-02, + 5.6758e-01, + 1.1917e-01, + -7.0765e-03, + 3.0017e-04, + 3.0601e-04, + 1.6559e+00, + 2.0722e-01, + 6.0013e-02, + 1.7023e-04, + -9.2424e-04, + 1.1269e-05, + -6.9911e-06, + -2.0886e+00, + -6.7879e-02, + -8.5922e-04, + -1.6087e-03, + -4.5549e-05, + 3.3178e-05, + -6.1715e-06, + -1.4446e-06, + -3.7210e-01, + 1.5775e-01, + -1.7827e-03, + -4.4396e-04, + 2.2844e-04, + -1.1215e-05, + -2.1120e-06, + -9.6421e-07, + -1.4170e-08, + 7.8720e-01, + -4.4238e-02, + -1.5120e-03, + -9.4119e-04, + 4.0645e-06, + -4.9253e-06, + -1.8656e-06, + -4.0736e-07, + -4.9594e-08, + 1.6134e-09 + }; + + /** Amplitude Bnm coefficients for the temperature. */ + private static final double[] B_TEMPERATURE_AMPLITUDE = { + 0.0000e+00, + 0.0000e+00, + -8.9895e-01, + 0.0000e+00, + -1.0790e+00, + -1.2699e-01, + 0.0000e+00, + -5.9033e-01, + 3.4865e-02, + -3.2614e-02, + 0.0000e+00, + -2.4310e-02, + 1.5607e-02, + -2.9833e-02, + -5.9048e-03, + 0.0000e+00, + 2.8383e-01, + 4.0509e-02, + -1.8834e-02, + -1.2654e-03, + -1.3794e-04, + 0.0000e+00, + 1.3306e-01, + 3.4960e-02, + -3.6799e-03, + -3.5626e-04, + 1.4814e-04, + 3.7932e-06, + 0.0000e+00, + 2.0801e-01, + 6.5640e-03, + -3.4893e-03, + -2.7395e-04, + 7.4296e-05, + -7.9927e-06, + -1.0277e-06, + 0.0000e+00, + 3.6515e-02, + -7.4319e-03, + -6.2873e-04, + 8.2461e-05, + 3.1095e-05, + -5.3860e-07, + -1.2055e-07, + -1.1517e-07, + 0.0000e+00, + 3.1404e-02, + 1.5580e-02, + -1.1428e-03, + 3.3529e-05, + 1.0387e-05, + -1.9378e-06, + -2.7327e-07, + 7.5833e-09, + -9.2323e-09 + }; + + /** Build a new instance. */ + ABCoefficients() { + + } + + /** Get the value of the mean Anm pressure coefficient for the given index. + * @param index index + * @return the mean Anm pressure coefficient for the given index + */ + public double getAnmPressureMean(final int index) { + return A_PRESSURE_MEAN[index]; + } + + /** Get the value of the mean Bnm pressure coefficient for the given index. + * @param index index + * @return the mean Bnm pressure coefficient for the given index + */ + public double getBnmPressureMean(final int index) { + return B_PRESSURE_MEAN[index]; + } + + /** Get the value of the amplitude Anm pressure coefficient for the given index. + * @param index index + * @return the amplitude Anm pressure coefficient for the given index. + */ + public double getAnmPressureAmpl(final int index) { + return A_PRESSURE_AMPLITUDE[index]; + } + + /** Get the value of the amplitude Bnm pressure coefficient for the given index. + * @param index index + * @return the amplitude Bnm pressure coefficient for the given index + */ + public double getBnmPressureAmpl(final int index) { + return B_PRESSURE_AMPLITUDE[index]; + } + + /** Get the value of the mean Anm temperature coefficient for the given index. + * @param index index + * @return the mean Anm temperature coefficient for the given index + */ + public double getAnmTemperatureMean(final int index) { + return A_TEMPERATURE_MEAN[index]; + } + + /** Get the value of the mean Bnm temperature coefficient for the given index. + * @param index index + * @return the mean Bnm temperature coefficient for the given index + */ + public double getBnmTemperatureMean(final int index) { + return B_TEMPERATURE_MEAN[index]; + } + + /** Get the value of the amplitude Anm temperature coefficient for the given index. + * @param index index + * @return the amplitude Anm temperature coefficient for the given index. + */ + public double getAnmTemperatureAmpl(final int index) { + return A_TEMPERATURE_AMPLITUDE[index]; + } + + /** Get the value of the amplitude Bnm temperature coefficient for the given index. + * @param index index + * @return the amplitude Bnm temperature coefficient for the given index + */ + public double getBnmTemperatureAmpl(final int index) { + return B_TEMPERATURE_AMPLITUDE[index]; + } + } + +} diff --git a/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperatureModel.java b/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperatureModel.java index f2bbcbb35d..6469065491 100644 --- a/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperatureModel.java +++ b/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperatureModel.java @@ -16,16 +16,14 @@ */ package org.orekit.models.earth.weather; -import org.hipparchus.util.FastMath; -import org.hipparchus.util.SinCos; import org.orekit.annotation.DefaultDataContext; +import org.orekit.bodies.GeodeticPoint; import org.orekit.data.DataContext; import org.orekit.frames.Frame; import org.orekit.models.earth.Geoid; import org.orekit.models.earth.ReferenceEllipsoid; +import org.orekit.models.earth.troposphere.TropoUnit; import org.orekit.time.AbsoluteDate; -import org.orekit.time.DateTimeComponents; -import org.orekit.utils.LegendrePolynomials; /** The Global Pressure and Temperature model. * This model is an empirical model that provides the temperature and the pressure depending @@ -42,12 +40,16 @@ * doi:10.1007/s00190-007-0135-3." * * @author Bryan Cazabonne - * + * @deprecated as of 12.1, replaced by {@link GlobalPressureTemperature} */ -public class GlobalPressureTemperatureModel implements WeatherModel { +@Deprecated +public class GlobalPressureTemperatureModel extends GlobalPressureTemperature implements WeatherModel { + + /** Spherical harmonics degree. */ + private static final int DEGREE = 9; - /** Temperature gradient (°C/m). */ - private static final double TEMPERATURE_GRADIENT = -6.5e-3; + /** Spherical harmonics order. */ + private static final int ORDER = 9; /** Geodetic latitude, in radians. */ private final double latitude; @@ -61,12 +63,6 @@ public class GlobalPressureTemperatureModel implements WeatherModel { /** Pressure site, in hPa. */ private double pressure; - /** Body frame related to body shape. */ - private final Frame bodyFrame; - - /** Data context for time and gravity. */ - private final DataContext dataContext; - /** Build a new instance. *

                * At the initialization the values of the pressure and the temperature are set to NaN. @@ -103,12 +99,13 @@ public GlobalPressureTemperatureModel(final double latitude, final double longitude, final Frame bodyFrame, final DataContext dataContext) { - this.bodyFrame = bodyFrame; + super(new Geoid(dataContext.getGravityFields().getNormalizedProvider(DEGREE, ORDER), + ReferenceEllipsoid.getWgs84(bodyFrame)), + dataContext.getTimeScales().getUTC()); this.latitude = latitude; this.longitude = longitude; this.temperature = Double.NaN; this.pressure = Double.NaN; - this.dataContext = dataContext; } /** Get the atmospheric temperature of the station depending its position. @@ -126,610 +123,15 @@ public double getPressure() { } @Override - @DefaultDataContext public void weatherParameters(final double height, final AbsoluteDate date) { - // Day of year computation - final DateTimeComponents dtc = - date.getComponents(dataContext.getTimeScales().getUTC()); - final int dofyear = dtc.getDate().getDayOfYear(); - - // Reference day: 28 January 1980 (Niell, 1996) - final int t0 = 28; - final double coef = ((dofyear + 1 - t0) / 365.25) * 2 * FastMath.PI; - final double cosCoef = FastMath.cos(coef); - - // Compute Legendre Polynomials Pnm(sin(phi)) - final int degree = 9; - final int order = 9; - final LegendrePolynomials p = new LegendrePolynomials(degree, order, FastMath.sin(latitude)); - - // Geoid for height computation - final Geoid geoid = new Geoid( - dataContext.getGravityFields().getNormalizedProvider(degree, order), - ReferenceEllipsoid.getWgs84(bodyFrame)); - - // Corrected height - final double correctedheight = FastMath.max(0.0, height - geoid.getUndulation(latitude, longitude, date)); - - // Eq. 4 (Ref) - double meanT0 = 0.0; - double amplitudeT0 = 0.0; - double meanP0 = 0.0; - double amplitudeP0 = 0.0; - final ABCoefficients abCoef = new ABCoefficients(); - int j = 0; - for (int n = 0; n <= 9; n++) { - for (int m = 0; m <= n; m++) { - final SinCos sc = FastMath.sinCos(m * longitude); - final double pCosmLambda = p.getPnm(n, m) * sc.cos(); - final double pSinmLambda = p.getPnm(n, m) * sc.sin(); - - meanT0 = meanT0 + - (abCoef.getAnmTemperatureMean(j) * pCosmLambda + abCoef.getBnmTemperatureMean(j) * pSinmLambda); - amplitudeT0 = amplitudeT0 + - (abCoef.getAnmTemperatureAmpl(j) * pCosmLambda + abCoef.getBnmTemperatureAmpl(j) * pSinmLambda); - meanP0 = meanP0 + - (abCoef.getAnmPressureMean(j) * pCosmLambda + abCoef.getBnmPressureMean(j) * pSinmLambda); - amplitudeP0 = amplitudeP0 + - (abCoef.getAnmPressureAmpl(j) * pCosmLambda + abCoef.getBnmPressureAmpl(j) * pSinmLambda); - - j = j + 1; - } - } - - // Eq. 3 (Ref) - final double temp0 = meanT0 + amplitudeT0 * cosCoef; - final double pres0 = meanP0 + amplitudeP0 * cosCoef; - - // Compute pressure and temperature Eq. 1 and 2 (Ref) - final double degrees = temp0 + TEMPERATURE_GRADIENT * correctedheight; - this.temperature = degrees + 273.15; - this.pressure = pres0 * FastMath.pow(1.0 - correctedheight * 0.0000226, 5.225); - } - - private static class ABCoefficients { - - /** Mean Anm coefficients for the pressure. */ - private static final double[] A_PRESSURE_MEAN = { - 1.0108e+03, - 8.4886e+00, - 1.4799e+00, - -1.3897e+01, - 3.7516e-03, - -1.4936e-01, - 1.2232e+01, - -7.6615e-01, - -6.7699e-02, - 8.1002e-03, - -1.5874e+01, - 3.6614e-01, - -6.7807e-02, - -3.6309e-03, - 5.9966e-04, - 4.8163e+00, - -3.7363e-01, - -7.2071e-02, - 1.9998e-03, - -6.2385e-04, - -3.7916e-04, - 4.7609e+00, - -3.9534e-01, - 8.6667e-03, - 1.1569e-02, - 1.1441e-03, - -1.4193e-04, - -8.5723e-05, - 6.5008e-01, - -5.0889e-01, - -1.5754e-02, - -2.8305e-03, - 5.7458e-04, - 3.2577e-05, - -9.6052e-06, - -2.7974e-06, - 1.3530e+00, - -2.7271e-01, - -3.0276e-04, - 3.6286e-03, - -2.0398e-04, - 1.5846e-05, - -7.7787e-06, - 1.1210e-06, - 9.9020e-08, - 5.5046e-01, - -2.7312e-01, - 3.2532e-03, - -2.4277e-03, - 1.1596e-04, - 2.6421e-07, - -1.3263e-06, - 2.7322e-07, - 1.4058e-07, - 4.9414e-09 - }; - - /** Mean Bnm coefficients for the pressure. */ - private static final double[] B_PRESSURE_MEAN = { - 0.0000e+00, - 0.0000e+00, - -1.2878e+00, - 0.0000e+00, - 7.0444e-01, - 3.3222e-01, - 0.0000e+00, - -2.9636e-01, - 7.2248e-03, - 7.9655e-03, - 0.0000e+00, - 1.0854e+00, - 1.1145e-02, - -3.6513e-02, - 3.1527e-03, - 0.0000e+00, - -4.8434e-01, - 5.2023e-02, - -1.3091e-02, - 1.8515e-03, - 1.5422e-04, - 0.0000e+00, - 6.8298e-01, - 2.5261e-03, - -9.9703e-04, - -1.0829e-03, - +1.7688e-04, - -3.1418e-05, - +0.0000e+00, - -3.7018e-01, - 4.3234e-02, - 7.2559e-03, - 3.1516e-04, - 2.0024e-05, - -8.0581e-06, - -2.3653e-06, - 0.0000e+00, - 1.0298e-01, - -1.5086e-02, - 5.6186e-03, - 3.2613e-05, - 4.0567e-05, - -1.3925e-06, - -3.6219e-07, - -2.0176e-08, - 0.0000e+00, - -1.8364e-01, - 1.8508e-02, - 7.5016e-04, - -9.6139e-05, - -3.1995e-06, - 1.3868e-07, - -1.9486e-07, - 3.0165e-10, - -6.4376e-10 - }; - - /** Amplitude Anm coefficients for the pressure. */ - private static final double[] A_PRESSURE_AMPLITUDE = { - -1.0444e-01, - 1.6618e-01, - -6.3974e-02, - 1.0922e+00, - 5.7472e-01, - -3.0277e-01, - -3.5087e+00, - 7.1264e-03, - -1.4030e-01, - 3.7050e-02, - 4.0208e-01, - -3.0431e-01, - -1.3292e-01, - 4.6746e-03, - -1.5902e-04, - 2.8624e+00, - -3.9315e-01, - -6.4371e-02, - 1.6444e-02, - -2.3403e-03, - 4.2127e-05, - 1.9945e+00, - -6.0907e-01, - -3.5386e-02, - -1.0910e-03, - -1.2799e-04, - 4.0970e-05, - 2.2131e-05, - -5.3292e-01, - -2.9765e-01, - -3.2877e-02, - 1.7691e-03, - 5.9692e-05, - 3.1725e-05, - 2.0741e-05, - -3.7622e-07, - 2.6372e+00, - -3.1165e-01, - 1.6439e-02, - 2.1633e-04, - 1.7485e-04, - 2.1587e-05, - 6.1064e-06, - -1.3755e-08, - -7.8748e-08, - -5.9152e-01, - -1.7676e-01, - 8.1807e-03, - 1.0445e-03, - 2.3432e-04, - 9.3421e-06, - 2.8104e-06, - -1.5788e-07, - -3.0648e-08, - 2.6421e-10 - }; - - /** Amplitude Bnm coefficients for the pressure. */ - private static final double[] B_PRESSURE_AMPLITUDE = { - 0.0000e+00, - 0.0000e+00, - 9.3340e-01, - 0.0000e+00, - 8.2346e-01, - 2.2082e-01, - 0.0000e+00, - 9.6177e-01, - -1.5650e-02, - 1.2708e-03, - 0.0000e+00, - -3.9913e-01, - 2.8020e-02, - 2.8334e-02, - 8.5980e-04, - 0.0000e+00, - 3.0545e-01, - -2.1691e-02, - 6.4067e-04, - -3.6528e-05, - -1.1166e-04, - 0.0000e+00, - -7.6974e-02, - -1.8986e-02, - +5.6896e-03, - -2.4159e-04, - -2.3033e-04, - -9.6783e-06, - 0.0000e+00, - -1.0218e-01, - -1.3916e-02, - -4.1025e-03, - -5.1340e-05, - -7.0114e-05, - -3.3152e-07, - 1.6901e-06, - 0.0000e+00, - -1.2422e-02, - +2.5072e-03, - +1.1205e-03, - -1.3034e-04, - -2.3971e-05, - -2.6622e-06, - 5.7852e-07, - 4.5847e-08, - 0.0000e+00, - 4.4777e-02, - -3.0421e-03, - 2.6062e-05, - -7.2421e-05, - 1.9119e-06, - 3.9236e-07, - 2.2390e-07, - 2.9765e-09, - -4.6452e-09 - }; - - /** Mean Anm coefficients for the temperature. */ - private static final double[] A_TEMPERATURE_MEAN = { - 1.6257e+01, - 2.1224e+00, - 9.2569e-01, - -2.5974e+01, - 1.4510e+00, - 9.2468e-02, - -5.3192e-01, - 2.1094e-01, - -6.9210e-02, - -3.4060e-02, - -4.6569e+00, - 2.6385e-01, - -3.6093e-02, - 1.0198e-02, - -1.8783e-03, - 7.4983e-01, - 1.1741e-01, - 3.9940e-02, - 5.1348e-03, - 5.9111e-03, - 8.6133e-06, - 6.3057e-01, - 1.5203e-01, - 3.9702e-02, - 4.6334e-03, - 2.4406e-04, - 1.5189e-04, - 1.9581e-07, - 5.4414e-01, - 3.5722e-01, - 5.2763e-02, - 4.1147e-03, - -2.7239e-04, - -5.9957e-05, - 1.6394e-06, - -7.3045e-07, - -2.9394e+00, - 5.5579e-02, - 1.8852e-02, - 3.4272e-03, - -2.3193e-05, - -2.9349e-05, - 3.6397e-07, - 2.0490e-06, - -6.4719e-08, - -5.2225e-01, - 2.0799e-01, - 1.3477e-03, - 3.1613e-04, - -2.2285e-04, - -1.8137e-05, - -1.5177e-07, - 6.1343e-07, - 7.8566e-08, - 1.0749e-09 - }; - - /** Mean Bnm coefficients for the temperature. */ - private static final double[] B_TEMPERATURE_MEAN = { - 0.0000e+00, - 0.0000e+00, - 1.0210e+00, - 0.0000e+00, - 6.0194e-01, - 1.2292e-01, - 0.0000e+00, - -4.2184e-01, - 1.8230e-01, - 4.2329e-02, - 0.0000e+00, - 9.3312e-02, - 9.5346e-02, - -1.9724e-03, - 5.8776e-03, - 0.0000e+00, - -2.0940e-01, - 3.4199e-02, - -5.7672e-03, - -2.1590e-03, - 5.6815e-04, - 0.0000e+00, - 2.2858e-01, - 1.2283e-02, - -9.3679e-03, - -1.4233e-03, - -1.5962e-04, - 4.0160e-05, - 0.0000e+00, - 3.6353e-02, - -9.4263e-04, - -3.6762e-03, - 5.8608e-05, - -2.6391e-05, - 3.2095e-06, - -1.1605e-06, - 0.0000e+00, - 1.6306e-01, - 1.3293e-02, - -1.1395e-03, - 5.1097e-05, - 3.3977e-05, - 7.6449e-06, - -1.7602e-07, - -7.6558e-08, - 0.0000e+00, - -4.5415e-02, - -1.8027e-02, - 3.6561e-04, - -1.1274e-04, - 1.3047e-05, - 2.0001e-06, - -1.5152e-07, - -2.7807e-08, - 7.7491e-09 - }; - - /** Amplitude Anm coefficients for the temperature. */ - private static final double[] A_TEMPERATURE_AMPLITUDE = { - -1.8654e+00, - -9.0041e+00, - -1.2974e-01, - -3.6053e+00, - 2.0284e-02, - 2.1872e-01, - -1.3015e+00, - 4.0355e-01, - 2.2216e-01, - -4.0605e-03, - 1.9623e+00, - 4.2887e-01, - 2.1437e-01, - -1.0061e-02, - -1.1368e-03, - -6.9235e-02, - 5.6758e-01, - 1.1917e-01, - -7.0765e-03, - 3.0017e-04, - 3.0601e-04, - 1.6559e+00, - 2.0722e-01, - 6.0013e-02, - 1.7023e-04, - -9.2424e-04, - 1.1269e-05, - -6.9911e-06, - -2.0886e+00, - -6.7879e-02, - -8.5922e-04, - -1.6087e-03, - -4.5549e-05, - 3.3178e-05, - -6.1715e-06, - -1.4446e-06, - -3.7210e-01, - 1.5775e-01, - -1.7827e-03, - -4.4396e-04, - 2.2844e-04, - -1.1215e-05, - -2.1120e-06, - -9.6421e-07, - -1.4170e-08, - 7.8720e-01, - -4.4238e-02, - -1.5120e-03, - -9.4119e-04, - 4.0645e-06, - -4.9253e-06, - -1.8656e-06, - -4.0736e-07, - -4.9594e-08, - 1.6134e-09 - }; - - /** Amplitude Bnm coefficients for the temperature. */ - private static final double[] B_TEMPERATURE_AMPLITUDE = { - 0.0000e+00, - 0.0000e+00, - -8.9895e-01, - 0.0000e+00, - -1.0790e+00, - -1.2699e-01, - 0.0000e+00, - -5.9033e-01, - 3.4865e-02, - -3.2614e-02, - 0.0000e+00, - -2.4310e-02, - 1.5607e-02, - -2.9833e-02, - -5.9048e-03, - 0.0000e+00, - 2.8383e-01, - 4.0509e-02, - -1.8834e-02, - -1.2654e-03, - -1.3794e-04, - 0.0000e+00, - 1.3306e-01, - 3.4960e-02, - -3.6799e-03, - -3.5626e-04, - 1.4814e-04, - 3.7932e-06, - 0.0000e+00, - 2.0801e-01, - 6.5640e-03, - -3.4893e-03, - -2.7395e-04, - 7.4296e-05, - -7.9927e-06, - -1.0277e-06, - 0.0000e+00, - 3.6515e-02, - -7.4319e-03, - -6.2873e-04, - 8.2461e-05, - 3.1095e-05, - -5.3860e-07, - -1.2055e-07, - -1.1517e-07, - 0.0000e+00, - 3.1404e-02, - 1.5580e-02, - -1.1428e-03, - 3.3529e-05, - 1.0387e-05, - -1.9378e-06, - -2.7327e-07, - 7.5833e-09, - -9.2323e-09 - }; - - /** Build a new instance. */ - ABCoefficients() { - - } - - /** Get the value of the mean Anm pressure coefficient for the given index. - * @param index index - * @return the mean Anm pressure coefficient for the given index - */ - public double getAnmPressureMean(final int index) { - return A_PRESSURE_MEAN[index]; - } - - /** Get the value of the mean Bnm pressure coefficient for the given index. - * @param index index - * @return the mean Bnm pressure coefficient for the given index - */ - public double getBnmPressureMean(final int index) { - return B_PRESSURE_MEAN[index]; - } - - /** Get the value of the amplitude Anm pressure coefficient for the given index. - * @param index index - * @return the amplitude Anm pressure coefficient for the given index. - */ - public double getAnmPressureAmpl(final int index) { - return A_PRESSURE_AMPLITUDE[index]; - } - - /** Get the value of the amplitude Bnm pressure coefficient for the given index. - * @param index index - * @return the amplitude Bnm pressure coefficient for the given index - */ - public double getBnmPressureAmpl(final int index) { - return B_PRESSURE_AMPLITUDE[index]; - } - - /** Get the value of the mean Anm temperature coefficient for the given index. - * @param index index - * @return the mean Anm temperature coefficient for the given index - */ - public double getAnmTemperatureMean(final int index) { - return A_TEMPERATURE_MEAN[index]; - } - - /** Get the value of the mean Bnm temperature coefficient for the given index. - * @param index index - * @return the mean Bnm temperature coefficient for the given index - */ - public double getBnmTemperatureMean(final int index) { - return B_TEMPERATURE_MEAN[index]; - } + final GeodeticPoint location = new GeodeticPoint(latitude, longitude, height); - /** Get the value of the amplitude Anm temperature coefficient for the given index. - * @param index index - * @return the amplitude Anm temperature coefficient for the given index. - */ - public double getAnmTemperatureAmpl(final int index) { - return A_TEMPERATURE_AMPLITUDE[index]; - } + // Pressure and temperature + final PressureTemperature pt = getWeatherParameters(location, date); + this.temperature = pt.getTemperature(); + this.pressure = TropoUnit.HECTO_PASCAL.fromSI(pt.getPressure()); - /** Get the value of the amplitude Bnm temperature coefficient for the given index. - * @param index index - * @return the amplitude Bnm temperature coefficient for the given index - */ - public double getBnmTemperatureAmpl(final int index) { - return B_TEMPERATURE_AMPLITUDE[index]; - } } } diff --git a/src/test/java/org/orekit/models/earth/weather/GlobalPressureTemperatureModelTest.java b/src/test/java/org/orekit/models/earth/weather/GlobalPressureTemperatureModelTest.java index bc8b8f4bb8..c2df2ccced 100644 --- a/src/test/java/org/orekit/models/earth/weather/GlobalPressureTemperatureModelTest.java +++ b/src/test/java/org/orekit/models/earth/weather/GlobalPressureTemperatureModelTest.java @@ -29,6 +29,7 @@ import org.orekit.time.TimeScalesFactory; import org.orekit.utils.IERSConventions; +@Deprecated public class GlobalPressureTemperatureModelTest { @BeforeEach diff --git a/src/test/java/org/orekit/models/earth/weather/GlobalPressureTemperatureTest.java b/src/test/java/org/orekit/models/earth/weather/GlobalPressureTemperatureTest.java new file mode 100644 index 0000000000..8544822d45 --- /dev/null +++ b/src/test/java/org/orekit/models/earth/weather/GlobalPressureTemperatureTest.java @@ -0,0 +1,148 @@ +/* Copyright 2002-2023 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.weather; + +import org.hipparchus.util.FastMath; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.orekit.Utils; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.data.DataContext; +import org.orekit.errors.OrekitException; +import org.orekit.forces.gravity.potential.GRGSFormatReader; +import org.orekit.forces.gravity.potential.GravityFieldFactory; +import org.orekit.frames.FramesFactory; +import org.orekit.models.earth.Geoid; +import org.orekit.models.earth.ReferenceEllipsoid; +import org.orekit.models.earth.troposphere.TropoUnit; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.TimeScalesFactory; +import org.orekit.utils.IERSConventions; + +public class GlobalPressureTemperatureTest { + + @BeforeEach + public void setUp() throws OrekitException { + Utils.setDataRoot("regular-data:potential"); + GravityFieldFactory.addPotentialCoefficientsReader(new GRGSFormatReader("grim4s4_gr", true)); + } + + @Test + public void testParameterComputation() { + + // Site Toulouse, Cité de l'Espace (France): latitude: 43.59°N + // longitude: 1.49°E + // height: 140 m + // + // Date: 09 January 2019 at 0h UT + // + // Expected outputs are obtained by performing the Matlab script gpt.m provided by TU WIEN: + // http://vmf.geo.tuwien.ac.at/codes/ + // + // Expected parameters : temperature -> 7.3311 °C + // pressure -> 1010.2749 hPa + // + // The real weather conditions are obtained with www.infoclimat.fr + // + // Real weather conditions: temperature -> 7.3 °C + // pressure -> 1027.5 hPa + + final AbsoluteDate date = new AbsoluteDate(2019, 1, 8, 0, 0, 0.0, TimeScalesFactory.getUTC()); + final GeodeticPoint location = new GeodeticPoint(FastMath.toRadians(43.59), + FastMath.toRadians(1.49), + 140.0); + + // Given by the model + final double expectedTemperature = 7.3311; + final double expectedPressure = 1010.2749; + + final DataContext dataContext = DataContext.getDefault(); + final Geoid geoid = new Geoid(dataContext.getGravityFields().getNormalizedProvider(9, 9), + ReferenceEllipsoid.getWgs84(FramesFactory.getITRF(IERSConventions.IERS_2010, true))); + final GlobalPressureTemperature model = new GlobalPressureTemperature(geoid, + dataContext.getTimeScales().getUTC()); + PressureTemperature pt = model.getWeatherParameters(location, date); + + final double computedTemperature = pt.getTemperature() - 273.15; + final double computedPressure = TropoUnit.HECTO_PASCAL.fromSI(pt.getPressure()); + + Assertions.assertEquals(expectedPressure, computedPressure, 0.1); + Assertions.assertEquals(expectedTemperature, computedTemperature, 0.1); + + // Real weather conditions + final double realTemperature = 7.3; + final double realPressure = 1027.5; + + // We test the model accuracy (10°C and 20 hPa) + Assertions.assertEquals(realTemperature, computedTemperature, 10); + Assertions.assertEquals(realPressure, computedPressure, 20); + } + + @Test + public void testHighAltitude() { + + // Site Pic du Midi de Bigorre (France): latitude: 42.94°N + // longitude: 0.14°E + // height: 2877 m + // + // Date: 09 January 2019 at 0h UT + // + // Expected outputs are obtained by performing the Matlab script gpt.m provided by TU WIEN: + // http://vmf.geo.tuwien.ac.at/codes/ + // + // Expected parameters : temperature -> -9.88 °C + // pressure -> 723.33 hPa + // + // The real weather conditions are obtained by the Laboratoire d'Aérologie de l'Observatoire Midi Pyrénées + // + // Real weather conditions: temperature -> -8.3 °C + // pressure -> 717.9 hPa + + final AbsoluteDate date = new AbsoluteDate(2019, 1, 8, 0, 0, 0.0, TimeScalesFactory.getUTC()); + final GeodeticPoint location = new GeodeticPoint(FastMath.toRadians(42.94), + FastMath.toRadians(0.14), + 2877); + + // Given by the model + final double expectedTemperature = -9.88; + final double expectedPressure = 723.33; + + final DataContext dataContext = DataContext.getDefault(); + final Geoid geoid = new Geoid(dataContext.getGravityFields().getNormalizedProvider(9, 9), + ReferenceEllipsoid.getWgs84(FramesFactory.getITRF(IERSConventions.IERS_2010, true))); + final GlobalPressureTemperature model = new GlobalPressureTemperature(geoid, + dataContext.getTimeScales().getUTC()); + PressureTemperature pt = model.getWeatherParameters(location, date); + + + final double computedTemperature = pt.getTemperature() - 273.15; + final double computedPressure = TropoUnit.HECTO_PASCAL.fromSI(pt.getPressure()); + + Assertions.assertEquals(expectedPressure, computedPressure, 0.1); + Assertions.assertEquals(expectedTemperature, computedTemperature, 0.1); + + // Real weather conditions + final double realTemperature = -8.3; + final double realPressure = 717.9; + + // We test the model accuracy (10°C and 20 hPa) + Assertions.assertEquals(realTemperature, computedTemperature, 10); + Assertions.assertEquals(realPressure, computedPressure, 20); + } + +} From 93f57da9598e0facc7ca435fff55b9de8f6638a0 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Tue, 12 Dec 2023 09:18:40 +0100 Subject: [PATCH 034/359] Typo. --- .../org/orekit/models/earth/weather/PressureTemperature.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/orekit/models/earth/weather/PressureTemperature.java b/src/main/java/org/orekit/models/earth/weather/PressureTemperature.java index 98cfd9dfef..2a8ca8aa8c 100644 --- a/src/main/java/org/orekit/models/earth/weather/PressureTemperature.java +++ b/src/main/java/org/orekit/models/earth/weather/PressureTemperature.java @@ -16,7 +16,7 @@ */ package org.orekit.models.earth.weather; -/** Container for pressure and temperature +/** Container for pressure and temperature. * @author Luc Maisonobe * @since 12.1 */ From 67fce7c7b805da554e66e0698094bd6c87ada1fe Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Tue, 12 Dec 2023 10:10:04 +0100 Subject: [PATCH 035/359] Removed forward/backward pressure conversions. --- .../models/earth/weather/water/CIPM2007.java | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/orekit/models/earth/weather/water/CIPM2007.java b/src/main/java/org/orekit/models/earth/weather/water/CIPM2007.java index 769119388a..f214e48086 100644 --- a/src/main/java/org/orekit/models/earth/weather/water/CIPM2007.java +++ b/src/main/java/org/orekit/models/earth/weather/water/CIPM2007.java @@ -32,9 +32,6 @@ */ public class CIPM2007 implements WaterVaporPressureProvider { - /** Saturation water vapor coefficient. */ - private static final double E = 0.01; - /** Laurent series coefficient for degree +2. */ private static final double L_P2 = 1.2378847e-5; @@ -63,14 +60,14 @@ public class CIPM2007 implements WaterVaporPressureProvider { @Override public double waterVaporPressure(final double p, final double t, final double rh) { - // saturation water vapor, equation A1.1 - final double psv = FastMath.exp(t * (t * L_P2 + L_P1) + L_0 + L_M1 / t) * E; + // saturation water vapor, equation A1.1 (now in Pa, not hPa) + final double psv = FastMath.exp(t * (t * L_P2 + L_P1) + L_0 + L_M1 / t); // enhancement factor, equation A1.2 final double tC = t - CELSIUS; final double fw = TropoUnit.HECTO_PASCAL.fromSI(p) * F_P + tC * tC * F_T2 + F_0; - return TropoUnit.HECTO_PASCAL.toSI(rh * fw * psv); + return rh * fw * psv; } @@ -78,15 +75,14 @@ public double waterVaporPressure(final double p, final double t, final double rh @Override public > T waterVaporPressure(final T p, final T t, final T rh) { - // saturation water vapor, equation A1.1 - final T psv = FastMath.exp(t.multiply(t.multiply(L_P2).add(L_P1)).add(L_0).add(t.reciprocal().multiply(L_M1))). - multiply(E); + // saturation water vapor, equation A1.1 (now in Pa, not hPa) + final T psv = FastMath.exp(t.multiply(t.multiply(L_P2).add(L_P1)).add(L_0).add(t.reciprocal().multiply(L_M1))); // enhancement factor, equation A1.2 final T tC = t.subtract(CELSIUS); final T fw = TropoUnit.HECTO_PASCAL.fromSI(p).multiply(F_P).add(tC.multiply(tC).multiply(F_T2)).add(F_0); - return TropoUnit.HECTO_PASCAL.toSI(rh.multiply(fw).multiply(psv)); + return rh.multiply(fw).multiply(psv); } From 436ef36eadc08a289bf4e5267b03febdd867fd67 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Tue, 12 Dec 2023 10:11:21 +0100 Subject: [PATCH 036/359] Added reverse computation of relative humidity. --- ...ntPressureTemperatureHumidityProvider.java | 7 ++--- .../water/WaterVaporPressureProvider.java | 28 +++++++++++++++++-- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/orekit/models/earth/weather/HeightDependentPressureTemperatureHumidityProvider.java b/src/main/java/org/orekit/models/earth/weather/HeightDependentPressureTemperatureHumidityProvider.java index 6ca69d5092..a04c6c2deb 100644 --- a/src/main/java/org/orekit/models/earth/weather/HeightDependentPressureTemperatureHumidityProvider.java +++ b/src/main/java/org/orekit/models/earth/weather/HeightDependentPressureTemperatureHumidityProvider.java @@ -101,8 +101,7 @@ public PressureTemperatureHumidity getWeatherParamerers(final GeodeticPoint loca location.getLongitude(), h0), date); - final double saturationPressure0 = provider.waterVaporPressure(pth0.getPressure(), pth0.getTemperature(), 1.0); - final double rh0 = pth0.getWaterVaporPressure() / saturationPressure0; + final double rh0 = provider.relativeHumidity(pth0.getPressure(), pth0.getTemperature(), pth0.getWaterVaporPressure()); // compute changes due to altitude change final double dh = FastMath.min(FastMath.max(location.getAltitude(), hMin), hMax) - h0; @@ -124,9 +123,7 @@ public > FieldPressureTemperatureHumidity g location.getLongitude(), location.getAltitude().newInstance(h0)), date); - final T one = date.getField().getOne(); - final T saturationPressure0 = provider.waterVaporPressure(pth0.getPressure(), pth0.getTemperature(), one); - final T rh0 = pth0.getWaterVaporPressure().divide(saturationPressure0); + final T rh0 = provider.relativeHumidity(pth0.getPressure(), pth0.getTemperature(), pth0.getWaterVaporPressure()); // compute changes due to altitude change final T dh = FastMath.min(FastMath.max(location.getAltitude(), hMin), hMax).subtract(h0); diff --git a/src/main/java/org/orekit/models/earth/weather/water/WaterVaporPressureProvider.java b/src/main/java/org/orekit/models/earth/weather/water/WaterVaporPressureProvider.java index 1dd0fe8cb8..e1b4a658a7 100644 --- a/src/main/java/org/orekit/models/earth/weather/water/WaterVaporPressureProvider.java +++ b/src/main/java/org/orekit/models/earth/weather/water/WaterVaporPressureProvider.java @@ -18,7 +18,7 @@ import org.hipparchus.CalculusFieldElement; -/** Interface for converting relative humidity into water vapor pressure. +/** Interface for converting between relative humidity and water vapor pressure. * @author Luc Maisonobe * @since 12.1 */ @@ -32,14 +32,36 @@ public interface WaterVaporPressureProvider { */ double waterVaporPressure(double p, double t, double rh); + /** Compute relative humidity. + * @param p pressure (Pa) + * @param t temperature (Kelvin) + * @param e water vapor pressure (Pa) + * @return relative humidity, as a ratio (50% → 0.5) + */ + default double relativeHumidity(final double p, final double t, final double e) { + final double saturationPressure = waterVaporPressure(p, t, 1.0); + return e / saturationPressure; + } + /** Compute water vapor pressure. + * @param type of the field elements * @param p pressure (Pa) * @param t temperature (Kelvin) * @param rh relative humidity, as a ratio (50% → 0.5) - * @param type of the field elements * @return water vapor pressure (Pa) */ > T waterVaporPressure(T p, T t, T rh); -} + /** Compute relative humidity. + * @param type of the field elements + * @param p pressure (Pa) + * @param t temperature (Kelvin) + * @param e water vapor pressure (Pa) + * @return relative humidity, as a ratio (50% → 0.5) + */ + default > T relativeHumidity(final T p, T t, T e) { + final T saturationPressure = waterVaporPressure(p, t, p.getField().getOne()); + return e.divide(saturationPressure); + } +} From c46b9ffbb2e9b77730e8e012ec6c5a45068e8b41 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Tue, 12 Dec 2023 10:11:29 +0100 Subject: [PATCH 037/359] Added tests. --- ...bstractWaterVaporPressureProviderTest.java | 53 +++++++++++++++++++ .../earth/weather/water/CIPM2007Test.java | 32 +++++++++++ .../weather/water/NbsNrcSteamTableTest.java | 32 +++++++++++ .../earth/weather/water/Wang1988Test.java | 32 +++++++++++ 4 files changed, 149 insertions(+) create mode 100644 src/test/java/org/orekit/models/earth/weather/water/AbstractWaterVaporPressureProviderTest.java create mode 100644 src/test/java/org/orekit/models/earth/weather/water/CIPM2007Test.java create mode 100644 src/test/java/org/orekit/models/earth/weather/water/NbsNrcSteamTableTest.java create mode 100644 src/test/java/org/orekit/models/earth/weather/water/Wang1988Test.java diff --git a/src/test/java/org/orekit/models/earth/weather/water/AbstractWaterVaporPressureProviderTest.java b/src/test/java/org/orekit/models/earth/weather/water/AbstractWaterVaporPressureProviderTest.java new file mode 100644 index 0000000000..8262ab0cd0 --- /dev/null +++ b/src/test/java/org/orekit/models/earth/weather/water/AbstractWaterVaporPressureProviderTest.java @@ -0,0 +1,53 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.weather.water; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.orekit.models.earth.troposphere.TropoUnit; + +public abstract class AbstractWaterVaporPressureProviderTest { + + protected abstract WaterVaporPressureProvider buildProvider(); + + @Test + public abstract void testReferenceWaterVaporPressure(); + + protected void doTestReferenceWaterVaporPressure(final double tolerance) { + // the reference value is from NBS/NRC steam table + final WaterVaporPressureProvider provider = buildProvider(); + Assertions.assertEquals(TropoUnit.HECTO_PASCAL.toSI(10.55154), + provider.waterVaporPressure(TropoUnit.HECTO_PASCAL.toSI(1013.25), 273.5 + 18, 0.5), + tolerance); + } + + @Test + public void testRelativeHumidity() { + final WaterVaporPressureProvider provider = buildProvider(); + for (double pPa = 700; pPa < 1100; pPa += 0.5) { + final double p = TropoUnit.HECTO_PASCAL.toSI(pPa); + for (double tC = 0.01; tC < 99; tC += 0.25) { + final double t = 273.15 + tC; + for (double rH = 0.0; rH < 1.0; rH += 0.02) { + final double e = provider.waterVaporPressure(p, t, rH); + Assertions.assertEquals(rH, provider.relativeHumidity(p, t, e), 1.0e-10); + } + } + } + } + +} diff --git a/src/test/java/org/orekit/models/earth/weather/water/CIPM2007Test.java b/src/test/java/org/orekit/models/earth/weather/water/CIPM2007Test.java new file mode 100644 index 0000000000..e6c47b3f35 --- /dev/null +++ b/src/test/java/org/orekit/models/earth/weather/water/CIPM2007Test.java @@ -0,0 +1,32 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.weather.water; + +import org.junit.jupiter.api.Test; + +public class CIPM2007Test extends AbstractWaterVaporPressureProviderTest { + + protected WaterVaporPressureProvider buildProvider() { + return new CIPM2007(); + } + + @Test + public void testReferenceWaterVaporPressure() { + doTestReferenceWaterVaporPressure(5.0); + } + +} diff --git a/src/test/java/org/orekit/models/earth/weather/water/NbsNrcSteamTableTest.java b/src/test/java/org/orekit/models/earth/weather/water/NbsNrcSteamTableTest.java new file mode 100644 index 0000000000..9106e1c0af --- /dev/null +++ b/src/test/java/org/orekit/models/earth/weather/water/NbsNrcSteamTableTest.java @@ -0,0 +1,32 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.weather.water; + +import org.junit.jupiter.api.Test; + +public class NbsNrcSteamTableTest extends AbstractWaterVaporPressureProviderTest { + + protected WaterVaporPressureProvider buildProvider() { + return new NbsNrcSteamTable(); + } + + @Test + public void testReferenceWaterVaporPressure() { + doTestReferenceWaterVaporPressure(1.0e-3); + } + +} diff --git a/src/test/java/org/orekit/models/earth/weather/water/Wang1988Test.java b/src/test/java/org/orekit/models/earth/weather/water/Wang1988Test.java new file mode 100644 index 0000000000..6e59bb6ade --- /dev/null +++ b/src/test/java/org/orekit/models/earth/weather/water/Wang1988Test.java @@ -0,0 +1,32 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.weather.water; + +import org.junit.jupiter.api.Test; + +public class Wang1988Test extends AbstractWaterVaporPressureProviderTest { + + protected WaterVaporPressureProvider buildProvider() { + return new Wang1988(); + } + + @Test + public void testReferenceWaterVaporPressure() { + doTestReferenceWaterVaporPressure(13.0); + } + +} From dcd88d5c7897fdd3355fdef92f5326c5537d3dfd Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Tue, 12 Dec 2023 11:11:09 +0100 Subject: [PATCH 038/359] Added field tests. --- ...bstractWaterVaporPressureProviderTest.java | 36 +++++++++++++++++++ .../earth/weather/water/CIPM2007Test.java | 6 ++++ .../weather/water/NbsNrcSteamTableTest.java | 6 ++++ .../earth/weather/water/Wang1988Test.java | 6 ++++ 4 files changed, 54 insertions(+) diff --git a/src/test/java/org/orekit/models/earth/weather/water/AbstractWaterVaporPressureProviderTest.java b/src/test/java/org/orekit/models/earth/weather/water/AbstractWaterVaporPressureProviderTest.java index 8262ab0cd0..6ffd92e043 100644 --- a/src/test/java/org/orekit/models/earth/weather/water/AbstractWaterVaporPressureProviderTest.java +++ b/src/test/java/org/orekit/models/earth/weather/water/AbstractWaterVaporPressureProviderTest.java @@ -16,6 +16,9 @@ */ package org.orekit.models.earth.weather.water; +import org.hipparchus.CalculusFieldElement; +import org.hipparchus.Field; +import org.hipparchus.util.Binary64Field; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.orekit.models.earth.troposphere.TropoUnit; @@ -35,6 +38,20 @@ protected void doTestReferenceWaterVaporPressure(final double tolerance) { tolerance); } + @Test + public abstract void testReferenceWaterVaporPressureField(); + + protected > void doTestReferenceWaterVaporPressureField(final Field field, + final double tolerance) { + // the reference value is from NBS/NRC steam table + final WaterVaporPressureProvider provider = buildProvider(); + Assertions.assertEquals(TropoUnit.HECTO_PASCAL.toSI(10.55154), + provider.waterVaporPressure(TropoUnit.HECTO_PASCAL.toSI(field.getZero().newInstance(1013.25)), + field.getZero().newInstance(273.5 + 18), + field.getZero().newInstance(0.5)).getReal(), + tolerance); + } + @Test public void testRelativeHumidity() { final WaterVaporPressureProvider provider = buildProvider(); @@ -50,4 +67,23 @@ public void testRelativeHumidity() { } } + @Test + public void testRelativeHumidityField() { + doTestRelativeHumidityField(Binary64Field.getInstance()); + } + + private > void doTestRelativeHumidityField(final Field field) { + final WaterVaporPressureProvider provider = buildProvider(); + for (double pPa = 700; pPa < 1100; pPa += 0.5) { + final T p = TropoUnit.HECTO_PASCAL.toSI(field.getZero().newInstance(pPa)); + for (double tC = 0.01; tC < 99; tC += 0.25) { + final T t = field.getZero().newInstance(273.15 + tC); + for (double rH = 0.0; rH < 1.0; rH += 0.02) { + final T e = provider.waterVaporPressure(p, t, field.getZero().newInstance(rH)); + Assertions.assertEquals(rH, provider.relativeHumidity(p, t, e).getReal(), 1.0e-10); + } + } + } + } + } diff --git a/src/test/java/org/orekit/models/earth/weather/water/CIPM2007Test.java b/src/test/java/org/orekit/models/earth/weather/water/CIPM2007Test.java index e6c47b3f35..b6c229e4c4 100644 --- a/src/test/java/org/orekit/models/earth/weather/water/CIPM2007Test.java +++ b/src/test/java/org/orekit/models/earth/weather/water/CIPM2007Test.java @@ -16,6 +16,7 @@ */ package org.orekit.models.earth.weather.water; +import org.hipparchus.util.Binary64Field; import org.junit.jupiter.api.Test; public class CIPM2007Test extends AbstractWaterVaporPressureProviderTest { @@ -29,4 +30,9 @@ public void testReferenceWaterVaporPressure() { doTestReferenceWaterVaporPressure(5.0); } + @Test + public void testReferenceWaterVaporPressureField() { + doTestReferenceWaterVaporPressureField(Binary64Field.getInstance(), 5.0); + } + } diff --git a/src/test/java/org/orekit/models/earth/weather/water/NbsNrcSteamTableTest.java b/src/test/java/org/orekit/models/earth/weather/water/NbsNrcSteamTableTest.java index 9106e1c0af..9225bad51b 100644 --- a/src/test/java/org/orekit/models/earth/weather/water/NbsNrcSteamTableTest.java +++ b/src/test/java/org/orekit/models/earth/weather/water/NbsNrcSteamTableTest.java @@ -16,6 +16,7 @@ */ package org.orekit.models.earth.weather.water; +import org.hipparchus.util.Binary64Field; import org.junit.jupiter.api.Test; public class NbsNrcSteamTableTest extends AbstractWaterVaporPressureProviderTest { @@ -29,4 +30,9 @@ public void testReferenceWaterVaporPressure() { doTestReferenceWaterVaporPressure(1.0e-3); } + @Test + public void testReferenceWaterVaporPressureField() { + doTestReferenceWaterVaporPressureField(Binary64Field.getInstance(), 1.0e-3); + } + } diff --git a/src/test/java/org/orekit/models/earth/weather/water/Wang1988Test.java b/src/test/java/org/orekit/models/earth/weather/water/Wang1988Test.java index 6e59bb6ade..b7d7621cd8 100644 --- a/src/test/java/org/orekit/models/earth/weather/water/Wang1988Test.java +++ b/src/test/java/org/orekit/models/earth/weather/water/Wang1988Test.java @@ -16,6 +16,7 @@ */ package org.orekit.models.earth.weather.water; +import org.hipparchus.util.Binary64Field; import org.junit.jupiter.api.Test; public class Wang1988Test extends AbstractWaterVaporPressureProviderTest { @@ -29,4 +30,9 @@ public void testReferenceWaterVaporPressure() { doTestReferenceWaterVaporPressure(13.0); } + @Test + public void testReferenceWaterVaporPressureField() { + doTestReferenceWaterVaporPressureField(Binary64Field.getInstance(), 13.0); + } + } From f7e665fa39a49e67e3b060713c3085fcb0582df5 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Tue, 12 Dec 2023 11:17:03 +0100 Subject: [PATCH 039/359] Added Chao mapping function. --- .../troposphere/ChaoMappingFunction.java | 78 +++++ .../AbstractFieldMappingFunctionTest.java | 301 ++++++++++++++++++ .../AbstractMappingFunctionTest.java | 84 +++++ .../troposphere/ChaoMappingFunctionTest.java | 32 ++ .../FieldChaoMappingFunctionTest.java | 38 +++ .../FieldNiellMappingFunctionModelTest.java | 283 +--------------- .../NiellMappingFunctionModelTest.java | 73 +---- 7 files changed, 543 insertions(+), 346 deletions(-) create mode 100644 src/main/java/org/orekit/models/earth/troposphere/ChaoMappingFunction.java create mode 100644 src/test/java/org/orekit/models/earth/troposphere/AbstractFieldMappingFunctionTest.java create mode 100644 src/test/java/org/orekit/models/earth/troposphere/AbstractMappingFunctionTest.java create mode 100644 src/test/java/org/orekit/models/earth/troposphere/ChaoMappingFunctionTest.java create mode 100644 src/test/java/org/orekit/models/earth/troposphere/FieldChaoMappingFunctionTest.java diff --git a/src/main/java/org/orekit/models/earth/troposphere/ChaoMappingFunction.java b/src/main/java/org/orekit/models/earth/troposphere/ChaoMappingFunction.java new file mode 100644 index 0000000000..829f78e392 --- /dev/null +++ b/src/main/java/org/orekit/models/earth/troposphere/ChaoMappingFunction.java @@ -0,0 +1,78 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import org.hipparchus.CalculusFieldElement; +import org.hipparchus.util.FastMath; +import org.hipparchus.util.MathArrays; +import org.orekit.bodies.FieldGeodeticPoint; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; + +/** Chao mapping function for radio wavelengths. + * + * @see "C. C. Chao, A model for tropospheric calibration from delay surface and radiosonde ballon measurements, 1972" + * + * @author Luc Maisonobe + * @since 12.1 + */ +public class ChaoMappingFunction implements MappingFunction { + + /** First coefficient for hydrostatic (dry) component. */ + private static final double AD = 0.00143; + + /** Second coefficient for hydrostatic (dry) component. */ + private static final double BD = 0.0445; + + /** First coefficient for wet component. */ + private static final double AW = 0.00035; + + /** Second coefficient for wet component. */ + private static final double BW = 0.017; + + /** Builds a new instance. + */ + public ChaoMappingFunction() { + // nothing to do + } + + /** {@inheritDoc} */ + @Override + public double[] mappingFactors(final double elevation, final GeodeticPoint point, + final AbsoluteDate date) { + final double sinE = FastMath.sin(elevation); + final double tanE = FastMath.tan(elevation); + return new double[] { + 1 / (sinE + AD / (tanE + BD)), + 1 / (sinE + AW / (tanE + BW)) + }; + } + + /** {@inheritDoc} */ + @Override + public > T[] mappingFactors(final T elevation, final FieldGeodeticPoint point, + final FieldAbsoluteDate date) { + final T sinE = FastMath.sin(elevation); + final T tanE = FastMath.tan(elevation); + final T[] mapping = MathArrays.buildArray(date.getField(), 2); + mapping[0] = sinE.add(tanE.add(BD).reciprocal().multiply(AD)).reciprocal(); + mapping[1] = sinE.add(tanE.add(BW).reciprocal().multiply(AW)).reciprocal(); + return mapping; + } + +} diff --git a/src/test/java/org/orekit/models/earth/troposphere/AbstractFieldMappingFunctionTest.java b/src/test/java/org/orekit/models/earth/troposphere/AbstractFieldMappingFunctionTest.java new file mode 100644 index 0000000000..350868a31c --- /dev/null +++ b/src/test/java/org/orekit/models/earth/troposphere/AbstractFieldMappingFunctionTest.java @@ -0,0 +1,301 @@ +/* Copyright 2002-2023 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import org.hipparchus.CalculusFieldElement; +import org.hipparchus.Field; +import org.hipparchus.analysis.differentiation.DSFactory; +import org.hipparchus.analysis.differentiation.DerivativeStructure; +import org.hipparchus.geometry.euclidean.threed.FieldVector3D; +import org.hipparchus.geometry.euclidean.threed.Vector3D; +import org.hipparchus.util.Binary64Field; +import org.hipparchus.util.FastMath; +import org.hipparchus.util.MathArrays; +import org.hipparchus.util.Precision; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.orekit.Utils; +import org.orekit.attitudes.Attitude; +import org.orekit.bodies.FieldGeodeticPoint; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.bodies.OneAxisEllipsoid; +import org.orekit.estimation.measurements.GroundStation; +import org.orekit.frames.Frame; +import org.orekit.frames.FramesFactory; +import org.orekit.frames.TopocentricFrame; +import org.orekit.orbits.FieldKeplerianOrbit; +import org.orekit.orbits.FieldOrbit; +import org.orekit.orbits.Orbit; +import org.orekit.orbits.OrbitType; +import org.orekit.orbits.PositionAngleType; +import org.orekit.propagation.FieldSpacecraftState; +import org.orekit.propagation.SpacecraftState; +import org.orekit.propagation.numerical.NumericalPropagator; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; +import org.orekit.time.TimeScalesFactory; +import org.orekit.utils.Constants; +import org.orekit.utils.IERSConventions; + +public abstract class AbstractFieldMappingFunctionTest { + + protected abstract MappingFunction buildMappingFunction(); + + @Test + public abstract void testMappingFactors(); + + protected > void doTestMappingFactors(final Field field, + final double expectedHydro, + final double expectedWet) { + + final T zero = field.getZero(); + + // Site (Le Mans, France): latitude: 48.0° + // longitude: 0.20° + // height: 68 m + // + // Date: 1st January 1994 at 0h UT + // + // Ref: Mercier F., Perosanz F., Mesures GNSS, Résolution des ambiguités. + + final FieldAbsoluteDate date = new FieldAbsoluteDate<>(field, 1994, 1, 1, TimeScalesFactory.getUTC()); + + final double latitude = FastMath.toRadians(48.0); + final double longitude = FastMath.toRadians(0.20); + final double height = 68.0; + + final FieldGeodeticPoint point = new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), zero.add(height)); + + final double elevation = FastMath.toRadians(5.0); + + final MappingFunction model = buildMappingFunction(); + + final T[] computedMapping = model.mappingFactors(zero.add(elevation), point, date); + + Assertions.assertEquals(expectedHydro, computedMapping[0].getReal(), 1.0e-2); + Assertions.assertEquals(expectedWet, computedMapping[1].getReal(), 1.0e-2); + } + + @Test + public void testFixedHeight() { + doTestFixedHeight(Binary64Field.getInstance()); + } + + private > void doTestFixedHeight(final Field field) { + final T zero = field.getZero(); + final FieldAbsoluteDate date = new FieldAbsoluteDate<>(field); + final FieldGeodeticPoint point = new FieldGeodeticPoint<>(zero.add(FastMath.toRadians(45.0)), zero.add(FastMath.toRadians(45.0)), zero.add(350.0)); + final MappingFunction model = buildMappingFunction(); + T[] lastFactors = MathArrays.buildArray(field, 2); + lastFactors[0] = zero.add(Double.MAX_VALUE); + lastFactors[1] = zero.add(Double.MAX_VALUE); + // mapping functions shall decline with increasing elevation angle + for (double elev = 10d; elev < 90d; elev += 8d) { + final T[] factors = model.mappingFactors(zero.add(FastMath.toRadians(elev)), point, + date); + Assertions.assertTrue(Precision.compareTo(factors[0].getReal(), lastFactors[0].getReal(), 1.0e-6) < 0); + Assertions.assertTrue(Precision.compareTo(factors[1].getReal(), lastFactors[1].getReal(), 1.0e-6) < 0); + lastFactors[0] = factors[0]; + lastFactors[1] = factors[1]; + } + } + + @Test + public abstract void testMFStateDerivatives(); + + protected void doTestMFStateDerivatives(final double epsMFH, final double epsMFW) { + + // Geodetic point + final double latitude = FastMath.toRadians(45.0); + final double longitude = FastMath.toRadians(45.0); + final double height = 0.0; + final GeodeticPoint point = new GeodeticPoint(latitude, longitude, height); + // Body: earth + final OneAxisEllipsoid earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS, + Constants.WGS84_EARTH_FLATTENING, + FramesFactory.getITRF(IERSConventions.IERS_2010, true)); + // Topocentric frame + final TopocentricFrame baseFrame = new TopocentricFrame(earth, point, "topo"); + + // Station + final GroundStation station = new GroundStation(baseFrame); + + // Mapping Function model + final MappingFunction model = buildMappingFunction(); + + // Derivative Structure + final DSFactory factory = new DSFactory(6, 1); + final DerivativeStructure a0 = factory.variable(0, 24464560.0); + final DerivativeStructure e0 = factory.variable(1, 0.05); + final DerivativeStructure i0 = factory.variable(2, 0.122138); + final DerivativeStructure pa0 = factory.variable(3, 3.10686); + final DerivativeStructure raan0 = factory.variable(4, 1.00681); + final DerivativeStructure anomaly0 = factory.variable(5, 0.048363); + final Field field = a0.getField(); + final DerivativeStructure zero = field.getZero(); + + // Field Date + final FieldAbsoluteDate dsDate = new FieldAbsoluteDate<>(field); + // Field Orbit + final Frame frame = FramesFactory.getEME2000(); + final FieldOrbit dsOrbit = new FieldKeplerianOrbit<>(a0, e0, i0, pa0, raan0, anomaly0, + PositionAngleType.MEAN, frame, + dsDate, zero.add(3.9860047e14)); + // Field State + final FieldSpacecraftState dsState = new FieldSpacecraftState<>(dsOrbit); + + // Initial satellite elevation + final FieldVector3D position = dsState.getPosition(); + final DerivativeStructure dsElevation = baseFrame.getTrackingCoordinates(position, frame, dsDate).getElevation(); + + // Compute mapping factors with state derivatives + final FieldGeodeticPoint dsPoint = new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), zero.add(height)); + final DerivativeStructure[] factors = model.mappingFactors(dsElevation, dsPoint, dsDate); + + final double[] compMFH = factors[0].getAllDerivatives(); + final double[] compMFW = factors[1].getAllDerivatives(); + + // Field -> non-field + final Orbit orbit = dsOrbit.toOrbit(); + final SpacecraftState state = dsState.toSpacecraftState(); + + // Finite differences for reference values + final double[][] refMF = new double[2][6]; + final OrbitType orbitType = OrbitType.KEPLERIAN; + final PositionAngleType angleType = PositionAngleType.MEAN; + double dP = 0.001; + double[] steps = NumericalPropagator.tolerances(1000000 * dP, orbit, orbitType)[0]; + for (int i = 0; i < 6; i++) { + SpacecraftState stateM4 = shiftState(state, orbitType, angleType, -4 * steps[i], i); + final Vector3D positionM4 = stateM4.getPosition(); + final double elevationM4 = station.getBaseFrame(). + getTrackingCoordinates(positionM4, stateM4.getFrame(), stateM4.getDate()). + getElevation(); + double[] delayM4 = model.mappingFactors(elevationM4, point, stateM4.getDate()); + + SpacecraftState stateM3 = shiftState(state, orbitType, angleType, -3 * steps[i], i); + final Vector3D positionM3 = stateM3.getPosition(); + final double elevationM3 = station.getBaseFrame(). + getTrackingCoordinates(positionM3, stateM3.getFrame(), stateM3.getDate()). + getElevation(); + double[] delayM3 = model.mappingFactors(elevationM3, point, stateM3.getDate()); + + SpacecraftState stateM2 = shiftState(state, orbitType, angleType, -2 * steps[i], i); + final Vector3D positionM2 = stateM2.getPosition(); + final double elevationM2 = station.getBaseFrame(). + getTrackingCoordinates(positionM2, stateM2.getFrame(), stateM2.getDate()). + getElevation(); + double[] delayM2 = model.mappingFactors(elevationM2, point, stateM2.getDate()); + + SpacecraftState stateM1 = shiftState(state, orbitType, angleType, -1 * steps[i], i); + final Vector3D positionM1 = stateM1.getPosition(); + final double elevationM1 = station.getBaseFrame(). + getTrackingCoordinates(positionM1, stateM1.getFrame(), stateM1.getDate()). + getElevation(); + double[] delayM1 = model.mappingFactors(elevationM1, point, stateM1.getDate()); + + SpacecraftState stateP1 = shiftState(state, orbitType, angleType, 1 * steps[i], i); + final Vector3D positionP1 = stateP1.getPosition(); + final double elevationP1 = station.getBaseFrame(). + getTrackingCoordinates(positionP1, stateP1.getFrame(), stateP1.getDate()). + getElevation(); + double[] delayP1 = model.mappingFactors(elevationP1, point, stateP1.getDate()); + + SpacecraftState stateP2 = shiftState(state, orbitType, angleType, 2 * steps[i], i); + final Vector3D positionP2 = stateP2.getPosition(); + final double elevationP2 = station.getBaseFrame(). + getTrackingCoordinates(positionP2, stateP2.getFrame(), stateP2.getDate()). + getElevation(); + double[] delayP2 = model.mappingFactors(elevationP2, point, stateP2.getDate()); + + SpacecraftState stateP3 = shiftState(state, orbitType, angleType, 3 * steps[i], i); + final Vector3D positionP3 = stateP3.getPosition(); + final double elevationP3 = station.getBaseFrame(). + getTrackingCoordinates(positionP3, stateP3.getFrame(), stateP3.getDate()). + getElevation(); + double[] delayP3 = model.mappingFactors(elevationP3, point, stateP3.getDate()); + + SpacecraftState stateP4 = shiftState(state, orbitType, angleType, 4 * steps[i], i); + final Vector3D positionP4 = stateP4.getPosition(); + final double elevationP4 = station.getBaseFrame(). + getTrackingCoordinates(positionP4, stateP4.getFrame(), stateP4.getDate()). + getElevation(); + double[] delayP4 = model.mappingFactors(elevationP4, point, stateP4.getDate()); + + fillJacobianColumn(refMF, i, orbitType, angleType, steps[i], + delayM4, delayM3, delayM2, delayM1, + delayP1, delayP2, delayP3, delayP4); + } + + // Tolerances + for (int i = 0; i < 6; i++) { + Assertions.assertEquals(0., FastMath.abs(compMFH[i + 1] - refMF[0][i]), epsMFH); + Assertions.assertEquals(0., FastMath.abs(compMFW[i + 1] - refMF[1][i]), epsMFW); + } + } + + private void fillJacobianColumn(double[][] jacobian, int column, + OrbitType orbitType, PositionAngleType angleType, double h, + double[] sM4h, double[] sM3h, + double[] sM2h, double[] sM1h, + double[] sP1h, double[] sP2h, + double[] sP3h, double[] sP4h) { + for (int i = 0; i < jacobian.length; ++i) { + jacobian[i][column] = ( -3 * (sP4h[i] - sM4h[i]) + + 32 * (sP3h[i] - sM3h[i]) - + 168 * (sP2h[i] - sM2h[i]) + + 672 * (sP1h[i] - sM1h[i])) / (840 * h); + } + } + + private SpacecraftState shiftState(SpacecraftState state, OrbitType orbitType, PositionAngleType angleType, + double delta, int column) { + + double[][] array = stateToArray(state, orbitType, angleType, true); + array[0][column] += delta; + + return arrayToState(array, orbitType, angleType, state.getFrame(), state.getDate(), + state.getMu(), state.getAttitude()); + + } + + private double[][] stateToArray(SpacecraftState state, OrbitType orbitType, PositionAngleType angleType, + boolean withMass) { + double[][] array = new double[2][withMass ? 7 : 6]; + orbitType.mapOrbitToArray(state.getOrbit(), angleType, array[0], array[1]); + if (withMass) { + array[0][6] = state.getMass(); + } + return array; + } + + private SpacecraftState arrayToState(double[][] array, OrbitType orbitType, PositionAngleType angleType, + Frame frame, AbsoluteDate date, double mu, + Attitude attitude) { + Orbit orbit = orbitType.mapArrayToOrbit(array[0], array[1], angleType, date, mu, frame); + return (array.length > 6) ? + new SpacecraftState(orbit, attitude) : + new SpacecraftState(orbit, attitude, array[0][6]); + } + + @BeforeEach + public void setUp() { + Utils.setDataRoot("regular-data"); + } + +} diff --git a/src/test/java/org/orekit/models/earth/troposphere/AbstractMappingFunctionTest.java b/src/test/java/org/orekit/models/earth/troposphere/AbstractMappingFunctionTest.java new file mode 100644 index 0000000000..b8268b25c1 --- /dev/null +++ b/src/test/java/org/orekit/models/earth/troposphere/AbstractMappingFunctionTest.java @@ -0,0 +1,84 @@ +/* Copyright 2002-2023 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import org.hipparchus.util.FastMath; +import org.hipparchus.util.Precision; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.orekit.Utils; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.TimeScalesFactory; + +public abstract class AbstractMappingFunctionTest { + + protected abstract MappingFunction buildMappingFunction(); + + @Test + public abstract void testMappingFactors(); + + protected void doTestMappingFactors(final double expectedHydro, + final double expectedWet) { + + // Site (Le Mans, France): latitude: 48.0° + // longitude: 0.20° + // height: 68 m + + final AbsoluteDate date = new AbsoluteDate(1994, 1, 1, TimeScalesFactory.getUTC()); + + final double latitude = FastMath.toRadians(48.0); + final double longitude = FastMath.toRadians(0.20); + final double height = 68.0; + final GeodeticPoint point = new GeodeticPoint(latitude, longitude, height); + + final double elevation = FastMath.toRadians(5.0); + + final MappingFunction model = buildMappingFunction(); + + final double[] computedMapping = model.mappingFactors(elevation, point, date); + Assertions.assertEquals(expectedHydro, computedMapping[0], 1.0e-2); + Assertions.assertEquals(expectedWet, computedMapping[1], 1.0e-2); + + } + + @Test + public void doTestFixedHeight() { + final AbsoluteDate date = new AbsoluteDate(); + final GeodeticPoint point = new GeodeticPoint(FastMath.toRadians(45.0), FastMath.toRadians(45.0), 350.0); + MappingFunction model = buildMappingFunction(); + double[] lastFactors = new double[] { + Double.MAX_VALUE, + Double.MAX_VALUE + }; + // mapping functions shall decline with increasing elevation angle + for (double elev = 10d; elev < 90d; elev += 8d) { + final double[] factors = model.mappingFactors(FastMath.toRadians(elev), point, date); + Assertions.assertTrue(Precision.compareTo(factors[0], lastFactors[0], 1.0e-6) < 0); + Assertions.assertTrue(Precision.compareTo(factors[1], lastFactors[1], 1.0e-6) < 0); + lastFactors[0] = factors[0]; + lastFactors[1] = factors[1]; + } + } + + @BeforeEach + public void setUp() { + Utils.setDataRoot("regular-data"); + } + +} diff --git a/src/test/java/org/orekit/models/earth/troposphere/ChaoMappingFunctionTest.java b/src/test/java/org/orekit/models/earth/troposphere/ChaoMappingFunctionTest.java new file mode 100644 index 0000000000..75d612cd42 --- /dev/null +++ b/src/test/java/org/orekit/models/earth/troposphere/ChaoMappingFunctionTest.java @@ -0,0 +1,32 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import org.junit.jupiter.api.Test; + +public class ChaoMappingFunctionTest extends AbstractMappingFunctionTest { + + protected MappingFunction buildMappingFunction() { + return new ChaoMappingFunction(); + } + + @Test + public void testMappingFactors() { + doTestMappingFactors(10.21, 11.05); + } + +} diff --git a/src/test/java/org/orekit/models/earth/troposphere/FieldChaoMappingFunctionTest.java b/src/test/java/org/orekit/models/earth/troposphere/FieldChaoMappingFunctionTest.java new file mode 100644 index 0000000000..3af2bbd6f8 --- /dev/null +++ b/src/test/java/org/orekit/models/earth/troposphere/FieldChaoMappingFunctionTest.java @@ -0,0 +1,38 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import org.hipparchus.util.Binary64Field; +import org.junit.jupiter.api.Test; + +public class FieldChaoMappingFunctionTest extends AbstractFieldMappingFunctionTest { + + protected MappingFunction buildMappingFunction() { + return new ChaoMappingFunction(); + } + + @Test + public void testMappingFactors() { + doTestMappingFactors(Binary64Field.getInstance(), 10.21, 11.05); + } + + @Test + public void testMFStateDerivatives() { + doTestMFStateDerivatives(2.2e-11, 9.2e-12); + } + +} diff --git a/src/test/java/org/orekit/models/earth/troposphere/FieldNiellMappingFunctionModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/FieldNiellMappingFunctionModelTest.java index 339b3111e6..f8e412830a 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/FieldNiellMappingFunctionModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/FieldNiellMappingFunctionModelTest.java @@ -16,296 +16,23 @@ */ package org.orekit.models.earth.troposphere; -import org.hipparchus.CalculusFieldElement; -import org.hipparchus.Field; -import org.hipparchus.analysis.differentiation.DSFactory; -import org.hipparchus.analysis.differentiation.DerivativeStructure; -import org.hipparchus.geometry.euclidean.threed.FieldVector3D; -import org.hipparchus.geometry.euclidean.threed.Vector3D; import org.hipparchus.util.Binary64Field; -import org.hipparchus.util.FastMath; -import org.hipparchus.util.MathArrays; -import org.hipparchus.util.Precision; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.orekit.Utils; -import org.orekit.attitudes.Attitude; -import org.orekit.bodies.FieldGeodeticPoint; -import org.orekit.bodies.GeodeticPoint; -import org.orekit.bodies.OneAxisEllipsoid; -import org.orekit.errors.OrekitException; -import org.orekit.estimation.measurements.GroundStation; -import org.orekit.frames.Frame; -import org.orekit.frames.FramesFactory; -import org.orekit.frames.TopocentricFrame; -import org.orekit.orbits.FieldKeplerianOrbit; -import org.orekit.orbits.FieldOrbit; -import org.orekit.orbits.Orbit; -import org.orekit.orbits.OrbitType; -import org.orekit.orbits.PositionAngleType; -import org.orekit.propagation.FieldSpacecraftState; -import org.orekit.propagation.SpacecraftState; -import org.orekit.propagation.numerical.NumericalPropagator; -import org.orekit.time.AbsoluteDate; -import org.orekit.time.FieldAbsoluteDate; -import org.orekit.time.TimeScalesFactory; -import org.orekit.utils.Constants; -import org.orekit.utils.IERSConventions; -public class FieldNiellMappingFunctionModelTest { +public class FieldNiellMappingFunctionModelTest extends AbstractFieldMappingFunctionTest { - @BeforeAll - public static void setUpGlobal() { - Utils.setDataRoot("atmosphere"); - } - - @BeforeEach - public void setUp() throws OrekitException { - Utils.setDataRoot("regular-data:potential/shm-format"); + protected MappingFunction buildMappingFunction() { + return new NiellMappingFunctionModel(); } @Test public void testMappingFactors() { - doTestMappingFactors(Binary64Field.getInstance()); - } - - private > void doTestMappingFactors(final Field field) { - - final T zero = field.getZero(); - - // Site (Le Mans, France): latitude: 48.0° - // longitude: 0.20° - // height: 68 m - // - // Date: 1st January 1994 at 0h UT - // - // Ref: Mercier F., Perosanz F., Mesures GNSS, Résolution des ambiguités. - // - // Expected mapping factors : hydrostatic -> 10.16 (Ref) - // wet -> 10.75 (Ref) - - final FieldAbsoluteDate date = new FieldAbsoluteDate<>(field, 1994, 1, 1, TimeScalesFactory.getUTC()); - - final double latitude = FastMath.toRadians(48.0); - final double longitude = FastMath.toRadians(0.20); - final double height = 68.0; - - final FieldGeodeticPoint point = new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), zero.add(height)); - - final double elevation = FastMath.toRadians(5.0); - final double expectedHydro = 10.16; - final double expectedWet = 10.75; - - final MappingFunction model = new NiellMappingFunctionModel(); - - final T[] computedMapping = model.mappingFactors(zero.add(elevation), point, date); - - Assertions.assertEquals(expectedHydro, computedMapping[0].getReal(), 1.0e-2); - Assertions.assertEquals(expectedWet, computedMapping[1].getReal(), 1.0e-2); - } - - @Test - public void testFixedHeight() { - doTestFixedHeight(Binary64Field.getInstance()); - } - - private > void doTestFixedHeight(final Field field) { - final T zero = field.getZero(); - final FieldAbsoluteDate date = new FieldAbsoluteDate<>(field); - final FieldGeodeticPoint point = new FieldGeodeticPoint<>(zero.add(FastMath.toRadians(45.0)), zero.add(FastMath.toRadians(45.0)), zero.add(350.0)); - MappingFunction model = new NiellMappingFunctionModel(); - T[] lastFactors = MathArrays.buildArray(field, 2); - lastFactors[0] = zero.add(Double.MAX_VALUE); - lastFactors[1] = zero.add(Double.MAX_VALUE); - // mapping functions shall decline with increasing elevation angle - for (double elev = 10d; elev < 90d; elev += 8d) { - final T[] factors = model.mappingFactors(zero.add(FastMath.toRadians(elev)), point, - date); - Assertions.assertTrue(Precision.compareTo(factors[0].getReal(), lastFactors[0].getReal(), 1.0e-6) < 0); - Assertions.assertTrue(Precision.compareTo(factors[1].getReal(), lastFactors[1].getReal(), 1.0e-6) < 0); - lastFactors[0] = factors[0]; - lastFactors[1] = factors[1]; - } + doTestMappingFactors(Binary64Field.getInstance(), 10.16, 10.75); } @Test public void testMFStateDerivatives() { - - // Geodetic point - final double latitude = FastMath.toRadians(45.0); - final double longitude = FastMath.toRadians(45.0); - final double height = 0.0; - final GeodeticPoint point = new GeodeticPoint(latitude, longitude, height); - // Body: earth - final OneAxisEllipsoid earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS, - Constants.WGS84_EARTH_FLATTENING, - FramesFactory.getITRF(IERSConventions.IERS_2010, true)); - // Topocentric frame - final TopocentricFrame baseFrame = new TopocentricFrame(earth, point, "topo"); - - // Station - final GroundStation station = new GroundStation(baseFrame); - - // Mapping Function model - final MappingFunction model = new NiellMappingFunctionModel(); - - // Derivative Structure - final DSFactory factory = new DSFactory(6, 1); - final DerivativeStructure a0 = factory.variable(0, 24464560.0); - final DerivativeStructure e0 = factory.variable(1, 0.05); - final DerivativeStructure i0 = factory.variable(2, 0.122138); - final DerivativeStructure pa0 = factory.variable(3, 3.10686); - final DerivativeStructure raan0 = factory.variable(4, 1.00681); - final DerivativeStructure anomaly0 = factory.variable(5, 0.048363); - final Field field = a0.getField(); - final DerivativeStructure zero = field.getZero(); - - // Field Date - final FieldAbsoluteDate dsDate = new FieldAbsoluteDate<>(field); - // Field Orbit - final Frame frame = FramesFactory.getEME2000(); - final FieldOrbit dsOrbit = new FieldKeplerianOrbit<>(a0, e0, i0, pa0, raan0, anomaly0, - PositionAngleType.MEAN, frame, - dsDate, zero.add(3.9860047e14)); - // Field State - final FieldSpacecraftState dsState = new FieldSpacecraftState<>(dsOrbit); - - // Initial satellite elevation - final FieldVector3D position = dsState.getPosition(); - final DerivativeStructure dsElevation = baseFrame.getTrackingCoordinates(position, frame, dsDate).getElevation(); - - // Compute mapping factors with state derivatives - final FieldGeodeticPoint dsPoint = new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), zero.add(height)); - final DerivativeStructure[] factors = model.mappingFactors(dsElevation, dsPoint, dsDate); - - final double[] compMFH = factors[0].getAllDerivatives(); - final double[] compMFW = factors[1].getAllDerivatives(); - - // Field -> non-field - final Orbit orbit = dsOrbit.toOrbit(); - final SpacecraftState state = dsState.toSpacecraftState(); - - // Finite differences for reference values - final double[][] refMF = new double[2][6]; - final OrbitType orbitType = OrbitType.KEPLERIAN; - final PositionAngleType angleType = PositionAngleType.MEAN; - double dP = 0.001; - double[] steps = NumericalPropagator.tolerances(1000000 * dP, orbit, orbitType)[0]; - for (int i = 0; i < 6; i++) { - SpacecraftState stateM4 = shiftState(state, orbitType, angleType, -4 * steps[i], i); - final Vector3D positionM4 = stateM4.getPosition(); - final double elevationM4 = station.getBaseFrame(). - getTrackingCoordinates(positionM4, stateM4.getFrame(), stateM4.getDate()). - getElevation(); - double[] delayM4 = model.mappingFactors(elevationM4, point, stateM4.getDate()); - - SpacecraftState stateM3 = shiftState(state, orbitType, angleType, -3 * steps[i], i); - final Vector3D positionM3 = stateM3.getPosition(); - final double elevationM3 = station.getBaseFrame(). - getTrackingCoordinates(positionM3, stateM3.getFrame(), stateM3.getDate()). - getElevation(); - double[] delayM3 = model.mappingFactors(elevationM3, point, stateM3.getDate()); - - SpacecraftState stateM2 = shiftState(state, orbitType, angleType, -2 * steps[i], i); - final Vector3D positionM2 = stateM2.getPosition(); - final double elevationM2 = station.getBaseFrame(). - getTrackingCoordinates(positionM2, stateM2.getFrame(), stateM2.getDate()). - getElevation(); - double[] delayM2 = model.mappingFactors(elevationM2, point, stateM2.getDate()); - - SpacecraftState stateM1 = shiftState(state, orbitType, angleType, -1 * steps[i], i); - final Vector3D positionM1 = stateM1.getPosition(); - final double elevationM1 = station.getBaseFrame(). - getTrackingCoordinates(positionM1, stateM1.getFrame(), stateM1.getDate()). - getElevation(); - double[] delayM1 = model.mappingFactors(elevationM1, point, stateM1.getDate()); - - SpacecraftState stateP1 = shiftState(state, orbitType, angleType, 1 * steps[i], i); - final Vector3D positionP1 = stateP1.getPosition(); - final double elevationP1 = station.getBaseFrame(). - getTrackingCoordinates(positionP1, stateP1.getFrame(), stateP1.getDate()). - getElevation(); - double[] delayP1 = model.mappingFactors(elevationP1, point, stateP1.getDate()); - - SpacecraftState stateP2 = shiftState(state, orbitType, angleType, 2 * steps[i], i); - final Vector3D positionP2 = stateP2.getPosition(); - final double elevationP2 = station.getBaseFrame(). - getTrackingCoordinates(positionP2, stateP2.getFrame(), stateP2.getDate()). - getElevation(); - double[] delayP2 = model.mappingFactors(elevationP2, point, stateP2.getDate()); - - SpacecraftState stateP3 = shiftState(state, orbitType, angleType, 3 * steps[i], i); - final Vector3D positionP3 = stateP3.getPosition(); - final double elevationP3 = station.getBaseFrame(). - getTrackingCoordinates(positionP3, stateP3.getFrame(), stateP3.getDate()). - getElevation(); - double[] delayP3 = model.mappingFactors(elevationP3, point, stateP3.getDate()); - - SpacecraftState stateP4 = shiftState(state, orbitType, angleType, 4 * steps[i], i); - final Vector3D positionP4 = stateP4.getPosition(); - final double elevationP4 = station.getBaseFrame(). - getTrackingCoordinates(positionP4, stateP4.getFrame(), stateP4.getDate()). - getElevation(); - double[] delayP4 = model.mappingFactors(elevationP4, point, stateP4.getDate()); - - fillJacobianColumn(refMF, i, orbitType, angleType, steps[i], - delayM4, delayM3, delayM2, delayM1, - delayP1, delayP2, delayP3, delayP4); - } - - // Tolerances - final double epsMFH = 6.506e-12; - final double epsMFW = 1.557e-11; - for (int i = 0; i < 6; i++) { - Assertions.assertEquals(0., FastMath.abs(compMFH[i + 1] - refMF[0][i]), epsMFH); - Assertions.assertEquals(0., FastMath.abs(compMFW[i + 1] - refMF[1][i]), epsMFW); - } - } - - private void fillJacobianColumn(double[][] jacobian, int column, - OrbitType orbitType, PositionAngleType angleType, double h, - double[] sM4h, double[] sM3h, - double[] sM2h, double[] sM1h, - double[] sP1h, double[] sP2h, - double[] sP3h, double[] sP4h) { - for (int i = 0; i < jacobian.length; ++i) { - jacobian[i][column] = ( -3 * (sP4h[i] - sM4h[i]) + - 32 * (sP3h[i] - sM3h[i]) - - 168 * (sP2h[i] - sM2h[i]) + - 672 * (sP1h[i] - sM1h[i])) / (840 * h); - } - } - - private SpacecraftState shiftState(SpacecraftState state, OrbitType orbitType, PositionAngleType angleType, - double delta, int column) { - - double[][] array = stateToArray(state, orbitType, angleType, true); - array[0][column] += delta; - - return arrayToState(array, orbitType, angleType, state.getFrame(), state.getDate(), - state.getMu(), state.getAttitude()); - - } - - private double[][] stateToArray(SpacecraftState state, OrbitType orbitType, PositionAngleType angleType, - boolean withMass) { - double[][] array = new double[2][withMass ? 7 : 6]; - orbitType.mapOrbitToArray(state.getOrbit(), angleType, array[0], array[1]); - if (withMass) { - array[0][6] = state.getMass(); - } - return array; - } - - private SpacecraftState arrayToState(double[][] array, OrbitType orbitType, PositionAngleType angleType, - Frame frame, AbsoluteDate date, double mu, - Attitude attitude) { - Orbit orbit = orbitType.mapArrayToOrbit(array[0], array[1], angleType, date, mu, frame); - return (array.length > 6) ? - new SpacecraftState(orbit, attitude) : - new SpacecraftState(orbit, attitude, array[0][6]); + doTestMFStateDerivatives(6.506e-12, 1.557e-11); } } diff --git a/src/test/java/org/orekit/models/earth/troposphere/NiellMappingFunctionModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/NiellMappingFunctionModelTest.java index 5240f6a5f0..5e06dd965a 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/NiellMappingFunctionModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/NiellMappingFunctionModelTest.java @@ -1,4 +1,4 @@ -/* Copyright 2002-2023 CS GROUP +/* Copyright 2023 Thales Alenia Space * Licensed to CS GROUP (CS) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. @@ -16,80 +16,17 @@ */ package org.orekit.models.earth.troposphere; -import org.hipparchus.util.FastMath; -import org.hipparchus.util.Precision; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.orekit.Utils; -import org.orekit.bodies.GeodeticPoint; -import org.orekit.errors.OrekitException; -import org.orekit.time.AbsoluteDate; -import org.orekit.time.TimeScalesFactory; -public class NiellMappingFunctionModelTest { +public class NiellMappingFunctionModelTest extends AbstractMappingFunctionTest { - @BeforeAll - public static void setUpGlobal() { - Utils.setDataRoot("atmosphere"); - } - - @BeforeEach - public void setUp() throws OrekitException { - Utils.setDataRoot("regular-data:potential/shm-format"); + protected MappingFunction buildMappingFunction() { + return new NiellMappingFunctionModel(); } @Test public void testMappingFactors() { - - // Site (Le Mans, France): latitude: 48.0° - // longitude: 0.20° - // height: 68 m - // - // Date: 1st January 1994 at 0h UT - // - // Ref: Mercier F., Perosanz F., Mesures GNSS, Résolution des ambiguités. - // - // Expected mapping factors : hydrostatic -> 10.16 (Ref) - // wet -> 10.75 (Ref) - - final AbsoluteDate date = new AbsoluteDate(1994, 1, 1, TimeScalesFactory.getUTC()); - - final double latitude = FastMath.toRadians(48.0); - final double longitude = FastMath.toRadians(0.20); - final double height = 68.0; - final GeodeticPoint point = new GeodeticPoint(latitude, longitude, height); - - final double elevation = FastMath.toRadians(5.0); - final double expectedHydro = 10.16; - final double expectedWet = 10.75; - - final MappingFunction model = new NiellMappingFunctionModel(); - - final double[] computedMapping = model.mappingFactors(elevation, point, date); - - Assertions.assertEquals(expectedHydro, computedMapping[0], 1.0e-2); - Assertions.assertEquals(expectedWet, computedMapping[1], 1.0e-2); - } - - @Test - public void testFixedHeight() { - final AbsoluteDate date = new AbsoluteDate(); - final GeodeticPoint point = new GeodeticPoint(FastMath.toRadians(45.0), FastMath.toRadians(45.0), 350.0); - MappingFunction model = new NiellMappingFunctionModel(); - double[] lastFactors = new double[] { - Double.MAX_VALUE, - Double.MAX_VALUE - }; - // mapping functions shall decline with increasing elevation angle - for (double elev = 10d; elev < 90d; elev += 8d) { - final double[] factors = model.mappingFactors(FastMath.toRadians(elev), point, date); - Assertions.assertTrue(Precision.compareTo(factors[0], lastFactors[0], 1.0e-6) < 0); - Assertions.assertTrue(Precision.compareTo(factors[1], lastFactors[1], 1.0e-6) < 0); - lastFactors[0] = factors[0]; - lastFactors[1] = factors[1]; - } + doTestMappingFactors(10.16, 10.75); } } From 66f68c4f75454d3d9283a0f866e491dff5cecfa9 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Tue, 12 Dec 2023 11:54:57 +0100 Subject: [PATCH 040/359] Added revised Chao mapping function. --- .../AbstractChaoMappingFunction.java | 85 +++++++++++++++++++ .../troposphere/ChaoMappingFunction.java | 36 +------- .../RevisedChaoMappingFunction.java | 46 ++++++++++ .../FieldRevisedChaoMappingFunctionTest.java | 38 +++++++++ .../RevisedChaoMappingFunctionTest.java | 32 +++++++ 5 files changed, 203 insertions(+), 34 deletions(-) create mode 100644 src/main/java/org/orekit/models/earth/troposphere/AbstractChaoMappingFunction.java create mode 100644 src/main/java/org/orekit/models/earth/troposphere/RevisedChaoMappingFunction.java create mode 100644 src/test/java/org/orekit/models/earth/troposphere/FieldRevisedChaoMappingFunctionTest.java create mode 100644 src/test/java/org/orekit/models/earth/troposphere/RevisedChaoMappingFunctionTest.java diff --git a/src/main/java/org/orekit/models/earth/troposphere/AbstractChaoMappingFunction.java b/src/main/java/org/orekit/models/earth/troposphere/AbstractChaoMappingFunction.java new file mode 100644 index 0000000000..c841f96244 --- /dev/null +++ b/src/main/java/org/orekit/models/earth/troposphere/AbstractChaoMappingFunction.java @@ -0,0 +1,85 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import org.hipparchus.CalculusFieldElement; +import org.hipparchus.util.FastMath; +import org.hipparchus.util.MathArrays; +import org.orekit.bodies.FieldGeodeticPoint; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; + +/** Chao mapping function for radio wavelengths. + * + * @see "C. C. Chao, A model for tropospheric calibration from delay surface and radiosonde ballon measurements, 1972" + * + * @author Luc Maisonobe + * @since 12.1 + */ +public class AbstractChaoMappingFunction implements MappingFunction { + + /** First coefficient for hydrostatic (dry) component. */ + private final double ad; + + /** Second coefficient for hydrostatic (dry) component. */ + private final double bd; + + /** First coefficient for wet component. */ + private final double aw; + + /** Second coefficient for wet component. */ + private final double bw; + + /** Builds a new instance. + * @param ad first coefficient for hydrostatic (dry) component + * @param bd second coefficient for hydrostatic (dry) component + * @param aw first coefficient for wet component + * @param bw second coefficient for wet component + */ + protected AbstractChaoMappingFunction(final double ad, final double bd, final double aw, final double bw) { + this.ad = ad; + this.bd = bd; + this.aw = aw; + this.bw = bw; + } + + /** {@inheritDoc} */ + @Override + public double[] mappingFactors(final double elevation, final GeodeticPoint point, + final AbsoluteDate date) { + final double sinE = FastMath.sin(elevation); + final double tanE = FastMath.tan(elevation); + return new double[] { + 1 / (sinE + ad / (tanE + bd)), + 1 / (sinE + aw / (tanE + bw)) + }; + } + + /** {@inheritDoc} */ + @Override + public > T[] mappingFactors(final T elevation, final FieldGeodeticPoint point, + final FieldAbsoluteDate date) { + final T sinE = FastMath.sin(elevation); + final T tanE = FastMath.tan(elevation); + final T[] mapping = MathArrays.buildArray(date.getField(), 2); + mapping[0] = sinE.add(tanE.add(bd).reciprocal().multiply(ad)).reciprocal(); + mapping[1] = sinE.add(tanE.add(bw).reciprocal().multiply(aw)).reciprocal(); + return mapping; + } + +} diff --git a/src/main/java/org/orekit/models/earth/troposphere/ChaoMappingFunction.java b/src/main/java/org/orekit/models/earth/troposphere/ChaoMappingFunction.java index 829f78e392..c2b552162d 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/ChaoMappingFunction.java +++ b/src/main/java/org/orekit/models/earth/troposphere/ChaoMappingFunction.java @@ -16,14 +16,6 @@ */ package org.orekit.models.earth.troposphere; -import org.hipparchus.CalculusFieldElement; -import org.hipparchus.util.FastMath; -import org.hipparchus.util.MathArrays; -import org.orekit.bodies.FieldGeodeticPoint; -import org.orekit.bodies.GeodeticPoint; -import org.orekit.time.AbsoluteDate; -import org.orekit.time.FieldAbsoluteDate; - /** Chao mapping function for radio wavelengths. * * @see "C. C. Chao, A model for tropospheric calibration from delay surface and radiosonde ballon measurements, 1972" @@ -31,7 +23,7 @@ * @author Luc Maisonobe * @since 12.1 */ -public class ChaoMappingFunction implements MappingFunction { +public class ChaoMappingFunction extends AbstractChaoMappingFunction { /** First coefficient for hydrostatic (dry) component. */ private static final double AD = 0.00143; @@ -48,31 +40,7 @@ public class ChaoMappingFunction implements MappingFunction { /** Builds a new instance. */ public ChaoMappingFunction() { - // nothing to do - } - - /** {@inheritDoc} */ - @Override - public double[] mappingFactors(final double elevation, final GeodeticPoint point, - final AbsoluteDate date) { - final double sinE = FastMath.sin(elevation); - final double tanE = FastMath.tan(elevation); - return new double[] { - 1 / (sinE + AD / (tanE + BD)), - 1 / (sinE + AW / (tanE + BW)) - }; - } - - /** {@inheritDoc} */ - @Override - public > T[] mappingFactors(final T elevation, final FieldGeodeticPoint point, - final FieldAbsoluteDate date) { - final T sinE = FastMath.sin(elevation); - final T tanE = FastMath.tan(elevation); - final T[] mapping = MathArrays.buildArray(date.getField(), 2); - mapping[0] = sinE.add(tanE.add(BD).reciprocal().multiply(AD)).reciprocal(); - mapping[1] = sinE.add(tanE.add(BW).reciprocal().multiply(AW)).reciprocal(); - return mapping; + super(AD, BD, AW, BW); } } diff --git a/src/main/java/org/orekit/models/earth/troposphere/RevisedChaoMappingFunction.java b/src/main/java/org/orekit/models/earth/troposphere/RevisedChaoMappingFunction.java new file mode 100644 index 0000000000..a1d51ac60a --- /dev/null +++ b/src/main/java/org/orekit/models/earth/troposphere/RevisedChaoMappingFunction.java @@ -0,0 +1,46 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +/** Chao mapping function for radio wavelengths. + * + * @see "J. A. Estefan, O. J. Sovers, A Comparative Survey of Current and Proposed Tropospheric + * Refraction-Delay Models for DSN Radio Metric Data Calibration", 1994 + * @author Luc Maisonobe + * @since 12.1 + */ +public class RevisedChaoMappingFunction extends AbstractChaoMappingFunction { + + /** First coefficient for hydrostatic (dry) component. */ + private static final double AD = 0.00147; + + /** Second coefficient for hydrostatic (dry) component. */ + private static final double BD = 0.0400; + + /** First coefficient for wet component. */ + private static final double AW = 0.00035; + + /** Second coefficient for wet component. */ + private static final double BW = 0.017; + + /** Builds a new instance. + */ + public RevisedChaoMappingFunction() { + super(AD, BD, AW, BW); + } + +} diff --git a/src/test/java/org/orekit/models/earth/troposphere/FieldRevisedChaoMappingFunctionTest.java b/src/test/java/org/orekit/models/earth/troposphere/FieldRevisedChaoMappingFunctionTest.java new file mode 100644 index 0000000000..4177128fc4 --- /dev/null +++ b/src/test/java/org/orekit/models/earth/troposphere/FieldRevisedChaoMappingFunctionTest.java @@ -0,0 +1,38 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import org.hipparchus.util.Binary64Field; +import org.junit.jupiter.api.Test; + +public class FieldRevisedChaoMappingFunctionTest extends AbstractFieldMappingFunctionTest { + + protected MappingFunction buildMappingFunction() { + return new RevisedChaoMappingFunction(); + } + + @Test + public void testMappingFactors() { + doTestMappingFactors(Binary64Field.getInstance(), 10.13, 11.05); + } + + @Test + public void testMFStateDerivatives() { + doTestMFStateDerivatives(3.2e-11, 9.2e-12); + } + +} diff --git a/src/test/java/org/orekit/models/earth/troposphere/RevisedChaoMappingFunctionTest.java b/src/test/java/org/orekit/models/earth/troposphere/RevisedChaoMappingFunctionTest.java new file mode 100644 index 0000000000..01ed1a1eb8 --- /dev/null +++ b/src/test/java/org/orekit/models/earth/troposphere/RevisedChaoMappingFunctionTest.java @@ -0,0 +1,32 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import org.junit.jupiter.api.Test; + +public class RevisedChaoMappingFunctionTest extends AbstractMappingFunctionTest { + + protected MappingFunction buildMappingFunction() { + return new RevisedChaoMappingFunction(); + } + + @Test + public void testMappingFactors() { + doTestMappingFactors(10.13, 11.05); + } + +} From 8be8898fe7570941d008a23e588b1675e878a50b Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Tue, 12 Dec 2023 15:43:58 +0100 Subject: [PATCH 041/359] Removed TropoUnit. --- .../CanonicalSaastamoinenModel.java | 2 +- .../EstimatedTroposphericModel.java | 2 +- .../earth/troposphere/MariniMurrayModel.java | 14 +++---- .../earth/troposphere/MendesPavlisModel.java | 12 +++--- .../ModifiedSaastamoinenModel.java | 2 +- .../earth/troposphere/SaastamoinenModel.java | 4 +- .../models/earth/troposphere/TropoUnit.java | 41 ------------------- .../troposphere/TroposphericModelUtils.java | 16 ++++++++ .../weather/GlobalPressureTemperature.java | 4 +- .../weather/GlobalPressureTemperature2.java | 10 ++--- .../GlobalPressureTemperature2Model.java | 6 +-- .../GlobalPressureTemperatureModel.java | 4 +- .../models/earth/weather/water/CIPM2007.java | 6 +-- .../models/earth/weather/water/Wang1988.java | 6 +-- .../FieldMendesPavlisModelTest.java | 14 +++---- .../troposphere/MariniMurrayModelTest.java | 12 +++--- .../troposphere/MendesPavlisModelTest.java | 12 +++--- .../ModifiedSaastamoinenModelTest.java | 8 ++-- .../GlobalPressureTemperature2Test.java | 6 +-- .../GlobalPressureTemperatureTest.java | 6 +-- ...bstractWaterVaporPressureProviderTest.java | 14 +++---- 21 files changed, 88 insertions(+), 113 deletions(-) delete mode 100644 src/main/java/org/orekit/models/earth/troposphere/TropoUnit.java diff --git a/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java b/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java index 0d8f15215f..812e0e915e 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java @@ -114,7 +114,7 @@ public CanonicalSaastamoinenModel(final PressureTemperatureHumidityProvider pthP public static CanonicalSaastamoinenModel getStandardModel() { // build standard meteorological data - final double pressure = TropoUnit.HECTO_PASCAL.toSI(1013.25); + final double pressure = TroposphericModelUtils.HECTO_PASCAL.toSI(1013.25); final double temperature = 273.15 + 18; final double relativeHumidity = 0.5; final WaterVaporPressureProvider waterPressureProvider = new NbsNrcSteamTable(); diff --git a/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java b/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java index d9566e4c7d..fb23fa1568 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java @@ -78,7 +78,7 @@ public class EstimatedTroposphericModel implements DiscreteTroposphericModel { public EstimatedTroposphericModel(final double t0, final double p0, final MappingFunction model, final double totalDelay) { this(new ModifiedSaastamoinenModel(0.0, - new ConstantPressureTemperatureHumidityProvider(new PressureTemperatureHumidity(TropoUnit.HECTO_PASCAL.toSI(p0), + new ConstantPressureTemperatureHumidityProvider(new PressureTemperatureHumidity(TroposphericModelUtils.HECTO_PASCAL.toSI(p0), t0, 0.0))), model, totalDelay); diff --git a/src/main/java/org/orekit/models/earth/troposphere/MariniMurrayModel.java b/src/main/java/org/orekit/models/earth/troposphere/MariniMurrayModel.java index f7e9ee9c25..5e75296beb 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/MariniMurrayModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/MariniMurrayModel.java @@ -59,13 +59,13 @@ public class MariniMurrayModel implements DiscreteTroposphericModel { */ @Deprecated public MariniMurrayModel(final double t0, final double p0, final double rh, final double lambda) { - this(new ConstantPressureTemperatureHumidityProvider(new PressureTemperatureHumidity(TropoUnit.HECTO_PASCAL.toSI(p0), + this(new ConstantPressureTemperatureHumidityProvider(new PressureTemperatureHumidity(TroposphericModelUtils.HECTO_PASCAL.toSI(p0), t0, new CIPM2007(). - waterVaporPressure(TropoUnit.HECTO_PASCAL.toSI(p0), + waterVaporPressure(TroposphericModelUtils.HECTO_PASCAL.toSI(p0), t0, rh))), - lambda, TropoUnit.NANO_M); + lambda, TroposphericModelUtils.NANO_M); } /** Create a new Marini-Murray model for the troposphere. @@ -84,7 +84,7 @@ public MariniMurrayModel(final PressureTemperatureHumidityProvider pthProvider, this.pthProvider = pthProvider; // compute laser frequency parameter - final double lambdaMicrometer = new UnitsConverter(lambdaUnits, TropoUnit.MICRO_M).convert(lambda); + final double lambdaMicrometer = new UnitsConverter(lambdaUnits, TroposphericModelUtils.MICRO_M).convert(lambda); final double l2 = lambdaMicrometer * lambdaMicrometer; fLambda = 0.9650 + (0.0164 + 0.000228 / l2) / l2; @@ -105,7 +105,7 @@ public MariniMurrayModel(final PressureTemperatureHumidityProvider pthProvider, */ @Deprecated public static MariniMurrayModel getStandardModel(final double lambda) { - return getStandardModel(lambda, TropoUnit.NANO_M); + return getStandardModel(lambda, TroposphericModelUtils.NANO_M); } /** Create a new Marini-Murray model using a standard atmosphere model. @@ -123,13 +123,13 @@ public static MariniMurrayModel getStandardModel(final double lambda) { * @since 12.1 */ public static MariniMurrayModel getStandardModel(final double lambda, final Unit lambdaUnits) { - final double p = TropoUnit.HECTO_PASCAL.toSI(1013.25); + final double p = TroposphericModelUtils.HECTO_PASCAL.toSI(1013.25); final double t = 273.15 + 20; final double rh = 0.5; final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(p, t, new CIPM2007().waterVaporPressure(p, t, rh)); return new MariniMurrayModel(new ConstantPressureTemperatureHumidityProvider(pth), - lambda, TropoUnit.NANO_M); + lambda, TroposphericModelUtils.NANO_M); } /** {@inheritDoc} */ diff --git a/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java b/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java index 94d34d9cbd..74b768f013 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java @@ -90,12 +90,12 @@ public class MendesPavlisModel implements DiscreteTroposphericModel, MappingFunc @Deprecated public MendesPavlisModel(final double t0, final double p0, final double rh, final double lambda) { - this(new ConstantPressureTemperatureHumidityProvider(new PressureTemperatureHumidity(TropoUnit.HECTO_PASCAL.toSI(p0), + this(new ConstantPressureTemperatureHumidityProvider(new PressureTemperatureHumidity(TroposphericModelUtils.HECTO_PASCAL.toSI(p0), t0, new CIPM2007(). - waterVaporPressure(TropoUnit.HECTO_PASCAL.toSI(p0), + waterVaporPressure(TroposphericModelUtils.HECTO_PASCAL.toSI(p0), t0, rh))), - lambda, TropoUnit.MICRO_M); + lambda, TroposphericModelUtils.MICRO_M); } /** Create a new Mendes-Pavlis model for the troposphere. @@ -110,7 +110,7 @@ public MendesPavlisModel(final PressureTemperatureHumidityProvider pthProvider, this.pthProvider = pthProvider; // Dispersion equation for the hydrostatic component - final double lambdaMicrometer = new UnitsConverter(lambdaUnits, TropoUnit.MICRO_M).convert(lambda); + final double lambdaMicrometer = new UnitsConverter(lambdaUnits, TroposphericModelUtils.MICRO_M).convert(lambda); final double sigma = 1.0 / lambdaMicrometer; final double sigma2 = sigma * sigma; final double coef1 = K_COEFFICIENTS[0] + sigma2; @@ -147,7 +147,7 @@ public MendesPavlisModel(final PressureTemperatureHumidityProvider pthProvider, */ @Deprecated public static MendesPavlisModel getStandardModel(final double lambda) { - return getStandardModel(lambda, TropoUnit.MICRO_M); + return getStandardModel(lambda, TroposphericModelUtils.MICRO_M); } /** Create a new Mendes-Pavlis model using a standard atmosphere model. @@ -165,7 +165,7 @@ public static MendesPavlisModel getStandardModel(final double lambda) { * @since 12.1 */ public static MendesPavlisModel getStandardModel(final double lambda, final Unit lambdaUnits) { - final double p = TropoUnit.HECTO_PASCAL.toSI(1013.25); + final double p = TroposphericModelUtils.HECTO_PASCAL.toSI(1013.25); final double t = 273.15 + 18; final double rh = 0.5; final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(p, t, new CIPM2007().waterVaporPressure(p, t, rh)); diff --git a/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java b/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java index eb11943481..44e59e4198 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java @@ -193,7 +193,7 @@ private ModifiedSaastamoinenModel(final double h0, */ @DefaultDataContext public static ModifiedSaastamoinenModel getStandardModel() { - final double pressure = TropoUnit.HECTO_PASCAL.toSI(1013.25); + final double pressure = TroposphericModelUtils.HECTO_PASCAL.toSI(1013.25); final double temperature = 273.15 + 18; final double humidity = 0.5; final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(pressure, diff --git a/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java b/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java index d6c2a705fa..37964131ce 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java @@ -88,10 +88,10 @@ public SaastamoinenModel(final double t0, final String deltaRFileName, final DataProvidersManager dataProvidersManager) { super(0.0, - new ConstantPressureTemperatureHumidityProvider(new PressureTemperatureHumidity(TropoUnit.HECTO_PASCAL.toSI(p0), + new ConstantPressureTemperatureHumidityProvider(new PressureTemperatureHumidity(TroposphericModelUtils.HECTO_PASCAL.toSI(p0), t0, new Wang1988(). - waterVaporPressure(TropoUnit.HECTO_PASCAL.toSI(p0), + waterVaporPressure(TroposphericModelUtils.HECTO_PASCAL.toSI(p0), t0, r0))), deltaRFileName, dataProvidersManager); diff --git a/src/main/java/org/orekit/models/earth/troposphere/TropoUnit.java b/src/main/java/org/orekit/models/earth/troposphere/TropoUnit.java deleted file mode 100644 index 36b713d9bf..0000000000 --- a/src/main/java/org/orekit/models/earth/troposphere/TropoUnit.java +++ /dev/null @@ -1,41 +0,0 @@ -/* Copyright 2023 Thales Alenia Space - * Licensed to CS Communication & Systèmes (CS) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * CS licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.orekit.models.earth.troposphere; - -import org.orekit.utils.units.Unit; - -/** Units used in tropospheric models. - * @author Luc Maisonobe - * @since 12.1 - */ -public class TropoUnit { - - /** Nanometers unit. */ - public static final Unit NANO_M = Unit.parse("nm"); - - /** Micrometers unit. */ - public static final Unit MICRO_M = Unit.parse("µm"); - - /** HectoPascal unit. */ - public static final Unit HECTO_PASCAL = Unit.parse("hPa"); - - /** Private constructor for a constants class. */ - private TropoUnit() { - // nothing to do - } - -} diff --git a/src/main/java/org/orekit/models/earth/troposphere/TroposphericModelUtils.java b/src/main/java/org/orekit/models/earth/troposphere/TroposphericModelUtils.java index fd8f078ca4..c56b4a89ad 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/TroposphericModelUtils.java +++ b/src/main/java/org/orekit/models/earth/troposphere/TroposphericModelUtils.java @@ -19,6 +19,7 @@ import org.hipparchus.Field; import org.hipparchus.CalculusFieldElement; import org.hipparchus.util.FastMath; +import org.orekit.utils.units.Unit; /** * Utility class for tropospheric models. @@ -27,6 +28,21 @@ */ public class TroposphericModelUtils { + /** Nanometers unit. + * @since 12.1 + */ + public static final Unit NANO_M = Unit.parse("nm"); + + /** Micrometers unit. + * @since 12.1 + */ + public static final Unit MICRO_M = Unit.parse("µm"); + + /** HectoPascal unit. + * @since 12.1 + */ + public static final Unit HECTO_PASCAL = Unit.parse("hPa"); + /** * Private constructor as class is a utility. */ diff --git a/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature.java b/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature.java index 7ebda1f977..28efdc03b3 100644 --- a/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature.java +++ b/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature.java @@ -22,7 +22,7 @@ import org.orekit.bodies.GeodeticPoint; import org.orekit.data.DataContext; import org.orekit.models.earth.Geoid; -import org.orekit.models.earth.troposphere.TropoUnit; +import org.orekit.models.earth.troposphere.TroposphericModelUtils; import org.orekit.time.AbsoluteDate; import org.orekit.time.DateTimeComponents; import org.orekit.time.TimeScale; @@ -145,7 +145,7 @@ public PressureTemperature getWeatherParameters(final GeodeticPoint location, fi final double temperature = degrees + 273.15; final double pressure = pres0 * FastMath.pow(1.0 - correctedheight * 0.0000226, 5.225); - return new PressureTemperature(TropoUnit.HECTO_PASCAL.toSI(pressure), temperature); + return new PressureTemperature(TroposphericModelUtils.HECTO_PASCAL.toSI(pressure), temperature); } diff --git a/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2.java b/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2.java index 6b06f1a06e..56b3a14d62 100644 --- a/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2.java +++ b/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2.java @@ -43,7 +43,7 @@ import org.orekit.errors.OrekitException; import org.orekit.errors.OrekitMessages; import org.orekit.models.earth.Geoid; -import org.orekit.models.earth.troposphere.TropoUnit; +import org.orekit.models.earth.troposphere.TroposphericModelUtils; import org.orekit.models.earth.troposphere.ViennaOneModel; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; @@ -214,9 +214,9 @@ public PressureTemperatureHumidity getWeatherParamerers(final GeodeticPoint loca // Water vapor pressure [hPa] final double e0 = qv * pressure / (0.622 + 0.378 * qv); - return new PressureTemperatureHumidity(TropoUnit.HECTO_PASCAL.toSI(pressure), + return new PressureTemperatureHumidity(TroposphericModelUtils.HECTO_PASCAL.toSI(pressure), temperature, - TropoUnit.HECTO_PASCAL.toSI(e0)); + TroposphericModelUtils.HECTO_PASCAL.toSI(e0)); } @@ -255,9 +255,9 @@ public > FieldPressureTemperatureHumidity g // Water vapor pressure [hPa] final T e0 = pressure.multiply(qv / (0.622 + 0.378 * qv)); - return new FieldPressureTemperatureHumidity<>(TropoUnit.HECTO_PASCAL.toSI(pressure), + return new FieldPressureTemperatureHumidity<>(TroposphericModelUtils.HECTO_PASCAL.toSI(pressure), temperature, - TropoUnit.HECTO_PASCAL.toSI(e0)); + TroposphericModelUtils.HECTO_PASCAL.toSI(e0)); } diff --git a/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2Model.java b/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2Model.java index 20e9ad8349..04a9f7bf6c 100644 --- a/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2Model.java +++ b/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2Model.java @@ -21,7 +21,7 @@ import org.orekit.data.DataContext; import org.orekit.data.DataProvidersManager; import org.orekit.models.earth.Geoid; -import org.orekit.models.earth.troposphere.TropoUnit; +import org.orekit.models.earth.troposphere.TroposphericModelUtils; import org.orekit.models.earth.troposphere.ViennaOneModel; import org.orekit.time.AbsoluteDate; import org.orekit.time.TimeScale; @@ -188,8 +188,8 @@ public void weatherParameters(final double stationHeight, final AbsoluteDate cur // Pressure, temperature, humidity final PressureTemperatureHumidity pth = getWeatherParamerers(location, currentDate); this.temperature = pth.getTemperature(); - this.pressure = TropoUnit.HECTO_PASCAL.fromSI(pth.getPressure()); - this.e0 = TropoUnit.HECTO_PASCAL.fromSI(pth.getWaterVaporPressure()); + this.pressure = TroposphericModelUtils.HECTO_PASCAL.fromSI(pth.getPressure()); + this.e0 = TroposphericModelUtils.HECTO_PASCAL.fromSI(pth.getWaterVaporPressure()); } diff --git a/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperatureModel.java b/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperatureModel.java index 6469065491..a1960e493d 100644 --- a/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperatureModel.java +++ b/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperatureModel.java @@ -22,7 +22,7 @@ import org.orekit.frames.Frame; import org.orekit.models.earth.Geoid; import org.orekit.models.earth.ReferenceEllipsoid; -import org.orekit.models.earth.troposphere.TropoUnit; +import org.orekit.models.earth.troposphere.TroposphericModelUtils; import org.orekit.time.AbsoluteDate; /** The Global Pressure and Temperature model. @@ -130,7 +130,7 @@ public void weatherParameters(final double height, final AbsoluteDate date) { // Pressure and temperature final PressureTemperature pt = getWeatherParameters(location, date); this.temperature = pt.getTemperature(); - this.pressure = TropoUnit.HECTO_PASCAL.fromSI(pt.getPressure()); + this.pressure = TroposphericModelUtils.HECTO_PASCAL.fromSI(pt.getPressure()); } diff --git a/src/main/java/org/orekit/models/earth/weather/water/CIPM2007.java b/src/main/java/org/orekit/models/earth/weather/water/CIPM2007.java index f214e48086..026046e468 100644 --- a/src/main/java/org/orekit/models/earth/weather/water/CIPM2007.java +++ b/src/main/java/org/orekit/models/earth/weather/water/CIPM2007.java @@ -18,7 +18,7 @@ import org.hipparchus.CalculusFieldElement; import org.hipparchus.util.FastMath; -import org.orekit.models.earth.troposphere.TropoUnit; +import org.orekit.models.earth.troposphere.TroposphericModelUtils; /** Official model CIPM-2007 (identical to CIPM-1981/91) from Comité International des Poids et Mesures. *

                @@ -65,7 +65,7 @@ public double waterVaporPressure(final double p, final double t, final double rh // enhancement factor, equation A1.2 final double tC = t - CELSIUS; - final double fw = TropoUnit.HECTO_PASCAL.fromSI(p) * F_P + tC * tC * F_T2 + F_0; + final double fw = TroposphericModelUtils.HECTO_PASCAL.fromSI(p) * F_P + tC * tC * F_T2 + F_0; return rh * fw * psv; @@ -80,7 +80,7 @@ public > T waterVaporPressure(final T p, final // enhancement factor, equation A1.2 final T tC = t.subtract(CELSIUS); - final T fw = TropoUnit.HECTO_PASCAL.fromSI(p).multiply(F_P).add(tC.multiply(tC).multiply(F_T2)).add(F_0); + final T fw = TroposphericModelUtils.HECTO_PASCAL.fromSI(p).multiply(F_P).add(tC.multiply(tC).multiply(F_T2)).add(F_0); return rh.multiply(fw).multiply(psv); diff --git a/src/main/java/org/orekit/models/earth/weather/water/Wang1988.java b/src/main/java/org/orekit/models/earth/weather/water/Wang1988.java index 0a6d9e5915..ac34c4b19e 100644 --- a/src/main/java/org/orekit/models/earth/weather/water/Wang1988.java +++ b/src/main/java/org/orekit/models/earth/weather/water/Wang1988.java @@ -19,7 +19,7 @@ import org.hipparchus.CalculusFieldElement; import org.hipparchus.analysis.polynomials.PolynomialFunction; import org.hipparchus.util.FastMath; -import org.orekit.models.earth.troposphere.TropoUnit; +import org.orekit.models.earth.troposphere.TroposphericModelUtils; /** Conversion polynomial from "The Principle of the GPS Precise Positioning System", Wang et al, 1988. *

                @@ -41,13 +41,13 @@ public class Wang1988 implements WaterVaporPressureProvider { /** {@inheritDoc} */ @Override public double waterVaporPressure(final double p, final double t, final double rh) { - return TropoUnit.HECTO_PASCAL.toSI(rh * FastMath.exp(E_POLYNOMIAL.value(t))); + return TroposphericModelUtils.HECTO_PASCAL.toSI(rh * FastMath.exp(E_POLYNOMIAL.value(t))); } /** {@inheritDoc} */ @Override public > T waterVaporPressure(final T p, final T t, final T rh) { - return TropoUnit.HECTO_PASCAL.toSI(rh.multiply(FastMath.exp(E_POLYNOMIAL.value(t)))); + return TroposphericModelUtils.HECTO_PASCAL.toSI(rh.multiply(FastMath.exp(E_POLYNOMIAL.value(t)))); } } diff --git a/src/test/java/org/orekit/models/earth/troposphere/FieldMendesPavlisModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/FieldMendesPavlisModelTest.java index d268e8caef..41f61d100e 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/FieldMendesPavlisModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/FieldMendesPavlisModelTest.java @@ -93,7 +93,7 @@ private > void doTestZenithDelay(final Field> void doTestZenithDelay(final Field date = new FieldAbsoluteDate<>(field, 2009, 8, 12, TimeScalesFactory.getUTC()); final MendesPavlisModel model = new MendesPavlisModel(new ConstantPressureTemperatureHumidityProvider(pth), - lambda, TropoUnit.MICRO_M); + lambda, TroposphericModelUtils.MICRO_M); final T[] computedDelay = model.computeZenithDelay(point, model.getParameters(field), date); @@ -153,7 +153,7 @@ private > void doTestMappingFactors(final Fiel final double latitude = FastMath.toRadians(30.67166667); final double longitude = FastMath.toRadians(-104.0250); final double height = 2075; - final double pressure = TropoUnit.HECTO_PASCAL.toSI(798.4188); + final double pressure = TroposphericModelUtils.HECTO_PASCAL.toSI(798.4188); final double temperature = 300.15; final double humidity = 0.4; final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(pressure, @@ -171,7 +171,7 @@ private > void doTestMappingFactors(final Fiel // Test for the second constructor final MendesPavlisModel model = new MendesPavlisModel(new ConstantPressureTemperatureHumidityProvider(pth), - lambda, TropoUnit.MICRO_M); + lambda, TroposphericModelUtils.MICRO_M); final T[] computedMapping = model.mappingFactors(zero.add(elevation), point, date); @@ -190,7 +190,7 @@ private > void doTestDelay(final Field fiel final double height = 100d; final FieldAbsoluteDate date = new FieldAbsoluteDate<>(field); final FieldGeodeticPoint point = new FieldGeodeticPoint<>(zero.add(FastMath.toRadians(45.0)), zero.add(FastMath.toRadians(45.0)), zero.add(height)); - MendesPavlisModel model = MendesPavlisModel.getStandardModel(0.6943, TropoUnit.MICRO_M); + MendesPavlisModel model = MendesPavlisModel.getStandardModel(0.6943, TroposphericModelUtils.MICRO_M); final T path = model.pathDelay(zero.add(FastMath.toRadians(elevation)), point, model.getParameters(field), date); Assertions.assertTrue(Precision.compareTo(path.getReal(), 20d, epsilon) < 0); Assertions.assertTrue(Precision.compareTo(path.getReal(), 0d, epsilon) > 0); @@ -205,7 +205,7 @@ private > void doTestFixedHeight(final Field date = new FieldAbsoluteDate<>(field); final FieldGeodeticPoint point = new FieldGeodeticPoint<>(zero.add(FastMath.toRadians(45.0)), zero.add(FastMath.toRadians(45.0)), zero.add(350.0)); - MendesPavlisModel model = MendesPavlisModel.getStandardModel(0.6943, TropoUnit.MICRO_M); + MendesPavlisModel model = MendesPavlisModel.getStandardModel(0.6943, TroposphericModelUtils.MICRO_M); T lastDelay = zero.add(Double.MAX_VALUE); // delay shall decline with increasing elevation angle for (double elev = 10d; elev < 90d; elev += 8d) { @@ -234,7 +234,7 @@ public void testDelayStateDerivatives() { final GroundStation station = new GroundStation(baseFrame); // Tropospheric model - final MendesPavlisModel model = MendesPavlisModel.getStandardModel(0.65, TropoUnit.MICRO_M); + final MendesPavlisModel model = MendesPavlisModel.getStandardModel(0.65, TroposphericModelUtils.MICRO_M); // Derivative Structure final DSFactory factory = new DSFactory(6, 1); diff --git a/src/test/java/org/orekit/models/earth/troposphere/MariniMurrayModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/MariniMurrayModelTest.java index b8fc187c66..687cc14efd 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/MariniMurrayModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/MariniMurrayModelTest.java @@ -56,7 +56,7 @@ public void testDelay() { final double height = 100d; // ruby laser with wavelength 694.3 nm - DiscreteTroposphericModel model = MariniMurrayModel.getStandardModel(694.3, TropoUnit.NANO_M); + DiscreteTroposphericModel model = MariniMurrayModel.getStandardModel(694.3, TroposphericModelUtils.NANO_M); final double path = model.pathDelay(FastMath.toRadians(elevation), new GeodeticPoint(latitude, longitude, height), null, AbsoluteDate.J2000_EPOCH); Assertions.assertTrue(Precision.compareTo(path, 20d, epsilon) < 0); @@ -102,7 +102,7 @@ private > void doTestFieldDelay(final Field final T height = zero.add(100d); // ruby laser with wavelength 694.3 nm - DiscreteTroposphericModel model = MariniMurrayModel.getStandardModel(694.3, TropoUnit.NANO_M); + DiscreteTroposphericModel model = MariniMurrayModel.getStandardModel(694.3, TroposphericModelUtils.NANO_M); final T path = model.pathDelay(elevation, new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), height), null, FieldAbsoluteDate.getJ2000Epoch(field)); Assertions.assertTrue(Precision.compareTo(path.getReal(), 20d, epsilon) < 0); @@ -112,7 +112,7 @@ private > void doTestFieldDelay(final Field @Test public void testFixedHeight() { // ruby laser with wavelength 694.3 nm - DiscreteTroposphericModel model = MariniMurrayModel.getStandardModel(694.3, TropoUnit.NANO_M); + DiscreteTroposphericModel model = MariniMurrayModel.getStandardModel(694.3, TroposphericModelUtils.NANO_M); double lastDelay = Double.MAX_VALUE; // delay shall decline with increasing elevation angle for (double elev = 10d; elev < 90d; elev += 8d) { @@ -129,7 +129,7 @@ public void testFieldFixedHeight() { private > void doTestFieldFixedHeight(final Field field) { // ruby laser with wavelength 694.3 nm - DiscreteTroposphericModel model = MariniMurrayModel.getStandardModel(694.3, TropoUnit.NANO_M); + DiscreteTroposphericModel model = MariniMurrayModel.getStandardModel(694.3, TroposphericModelUtils.NANO_M); final T zero = field.getZero(); T lastDelay = zero.add(Double.MAX_VALUE); // delay shall decline with increasing elevation angle @@ -144,7 +144,7 @@ private > void doTestFieldFixedHeight(final Fi public void compareExpectedValues() { // ruby laser with wavelength 694.3 nm - DiscreteTroposphericModel model = MariniMurrayModel.getStandardModel(694.3, TropoUnit.NANO_M); + DiscreteTroposphericModel model = MariniMurrayModel.getStandardModel(694.3, TroposphericModelUtils.NANO_M); double height = 0; double elevation = 10; @@ -162,7 +162,7 @@ public void compareFieldExpectedValue() { private > void doCompareFieldExpectedValues(final Field field) { // ruby laser with wavelength 694.3 nm - DiscreteTroposphericModel model = MariniMurrayModel.getStandardModel(694.3, TropoUnit.NANO_M); + DiscreteTroposphericModel model = MariniMurrayModel.getStandardModel(694.3, TroposphericModelUtils.NANO_M); T zero = field.getZero(); T height = zero; diff --git a/src/test/java/org/orekit/models/earth/troposphere/MendesPavlisModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/MendesPavlisModelTest.java index 8174b02431..60141c9d14 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/MendesPavlisModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/MendesPavlisModelTest.java @@ -66,7 +66,7 @@ public void testZenithDelay() { final double latitude = FastMath.toRadians(30.67166667); final double longitude = FastMath.toRadians(-104.0250); final double height = 2010.344; - final double pressure = TropoUnit.HECTO_PASCAL.toSI(798.4188); + final double pressure = TroposphericModelUtils.HECTO_PASCAL.toSI(798.4188); final double temperature = 300.15; final double humidity = 0.4; final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(pressure, @@ -90,7 +90,7 @@ public void testZenithDelay() { final AbsoluteDate date = new AbsoluteDate(2009, 8, 12, TimeScalesFactory.getUTC()); final MendesPavlisModel model = new MendesPavlisModel(new ConstantPressureTemperatureHumidityProvider(pth), - lambda, TropoUnit.MICRO_M); + lambda, TroposphericModelUtils.MICRO_M); final double[] computedDelay = model.computeZenithDelay(point, model.getParameters(), date); @@ -121,7 +121,7 @@ public void testMappingFactors() { final double latitude = FastMath.toRadians(30.67166667); final double longitude = FastMath.toRadians(-104.0250); final double height = 2075; - final double pressure = TropoUnit.HECTO_PASCAL.toSI(798.4188); + final double pressure = TroposphericModelUtils.HECTO_PASCAL.toSI(798.4188); final double temperature = 300.15; final double humidity = 0.4; final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(pressure, @@ -139,7 +139,7 @@ public void testMappingFactors() { // Test for the second constructor final MendesPavlisModel model = new MendesPavlisModel(new ConstantPressureTemperatureHumidityProvider(pth), - lambda, TropoUnit.MICRO_M); + lambda, TroposphericModelUtils.MICRO_M); final double[] computedMapping = model.mappingFactors(elevation, point, date); @@ -153,7 +153,7 @@ public void testDelay() { final double height = 100d; final AbsoluteDate date = new AbsoluteDate(); final GeodeticPoint point = new GeodeticPoint(FastMath.toRadians(45.0), FastMath.toRadians(45.0), height); - MendesPavlisModel model = MendesPavlisModel.getStandardModel( 0.6943, TropoUnit.MICRO_M); + MendesPavlisModel model = MendesPavlisModel.getStandardModel( 0.6943, TroposphericModelUtils.MICRO_M); final double path = model.pathDelay(FastMath.toRadians(elevation), point, model.getParameters(), date); Assertions.assertTrue(Precision.compareTo(path, 20d, epsilon) < 0); Assertions.assertTrue(Precision.compareTo(path, 0d, epsilon) > 0); @@ -163,7 +163,7 @@ public void testDelay() { public void testFixedHeight() { final AbsoluteDate date = new AbsoluteDate(); final GeodeticPoint point = new GeodeticPoint(FastMath.toRadians(45.0), FastMath.toRadians(45.0), 350.0); - MendesPavlisModel model = MendesPavlisModel.getStandardModel(0.6943, TropoUnit.MICRO_M); + MendesPavlisModel model = MendesPavlisModel.getStandardModel(0.6943, TroposphericModelUtils.MICRO_M); double lastDelay = Double.MAX_VALUE; // delay shall decline with increasing elevation angle for (double elev = 10d; elev < 90d; elev += 8d) { diff --git a/src/test/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModelTest.java index d62d923306..85367790ec 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModelTest.java @@ -113,7 +113,7 @@ public void NoFile() { Utils.setDataRoot("atmosphere"); try { final double temperature = 273.15 + 18; - final double pressure = TropoUnit.HECTO_PASCAL.toSI(1013.25); + final double pressure = TroposphericModelUtils.HECTO_PASCAL.toSI(1013.25); final double humidity = 0.5; final double waterPressure = ModifiedSaastamoinenModel.WATER.waterVaporPressure(pressure, temperature, @@ -132,7 +132,7 @@ public void NoFile() { public void compareDefaultAndLoaded() { Utils.setDataRoot("atmosphere"); final double temperature = 273.15 + 18; - final double pressure = TropoUnit.HECTO_PASCAL.toSI(1013.25); + final double pressure = TroposphericModelUtils.HECTO_PASCAL.toSI(1013.25); final double humidity = 0.5; final double waterPressure = ModifiedSaastamoinenModel.WATER.waterVaporPressure(pressure, temperature, @@ -230,7 +230,7 @@ private > void doTestFieldLowElevation(final F @Test public void compareExpectedValues() { Utils.setDataRoot("atmosphere"); - final double pressure = TropoUnit.HECTO_PASCAL.toSI(1013.25); + final double pressure = TroposphericModelUtils.HECTO_PASCAL.toSI(1013.25); // it seems the reference values for the test have been computed using a wrong conversion // between Celsius and Kelvin (273.16 offset instead of 273.15) // which is probably due to a similar error in equation 5.97 of @@ -266,7 +266,7 @@ public void compareFieldExpectedValues() { private > void doCompareFieldExpectedValues(final Field field) { final T zero = field.getZero(); Utils.setDataRoot("atmosphere"); - final double pressure = TropoUnit.HECTO_PASCAL.toSI(1013.25); + final double pressure = TroposphericModelUtils.HECTO_PASCAL.toSI(1013.25); // it seems the reference values for the test have been computed using a wrong conversion // between Celsius and Kelvin (273.16 offset instead of 273.15) // so for the sake of the test, we use a temperature of 18.01°C and not the standard atmosphere at 18.00°C diff --git a/src/test/java/org/orekit/models/earth/weather/GlobalPressureTemperature2Test.java b/src/test/java/org/orekit/models/earth/weather/GlobalPressureTemperature2Test.java index 1e0f1b1c7f..81dad43be9 100644 --- a/src/test/java/org/orekit/models/earth/weather/GlobalPressureTemperature2Test.java +++ b/src/test/java/org/orekit/models/earth/weather/GlobalPressureTemperature2Test.java @@ -28,7 +28,7 @@ import org.orekit.frames.FramesFactory; import org.orekit.models.earth.Geoid; import org.orekit.models.earth.ReferenceEllipsoid; -import org.orekit.models.earth.troposphere.TropoUnit; +import org.orekit.models.earth.troposphere.TroposphericModelUtils; import org.orekit.time.AbsoluteDate; import org.orekit.time.TimeScalesFactory; import org.orekit.utils.IERSConventions; @@ -75,8 +75,8 @@ public void testWeatherParameters() { Assertions.assertEquals(0.0012647, a[0], 1.1e-7); Assertions.assertEquals(0.0005726, a[1], 8.6e-8); Assertions.assertEquals(273.15 + 22.12, pth.getTemperature(), 2.3e-1); - Assertions.assertEquals(1002.56, TropoUnit.HECTO_PASCAL.fromSI(pth.getPressure()), 5.1e-1); - Assertions.assertEquals(15.63, TropoUnit.HECTO_PASCAL.fromSI(pth.getWaterVaporPressure()), 5.0e-2); + Assertions.assertEquals(1002.56, TroposphericModelUtils.HECTO_PASCAL.fromSI(pth.getPressure()), 5.1e-1); + Assertions.assertEquals(15.63, TroposphericModelUtils.HECTO_PASCAL.fromSI(pth.getWaterVaporPressure()), 5.0e-2); } diff --git a/src/test/java/org/orekit/models/earth/weather/GlobalPressureTemperatureTest.java b/src/test/java/org/orekit/models/earth/weather/GlobalPressureTemperatureTest.java index 8544822d45..3df2babc7a 100644 --- a/src/test/java/org/orekit/models/earth/weather/GlobalPressureTemperatureTest.java +++ b/src/test/java/org/orekit/models/earth/weather/GlobalPressureTemperatureTest.java @@ -29,7 +29,7 @@ import org.orekit.frames.FramesFactory; import org.orekit.models.earth.Geoid; import org.orekit.models.earth.ReferenceEllipsoid; -import org.orekit.models.earth.troposphere.TropoUnit; +import org.orekit.models.earth.troposphere.TroposphericModelUtils; import org.orekit.time.AbsoluteDate; import org.orekit.time.TimeScalesFactory; import org.orekit.utils.IERSConventions; @@ -79,7 +79,7 @@ public void testParameterComputation() { PressureTemperature pt = model.getWeatherParameters(location, date); final double computedTemperature = pt.getTemperature() - 273.15; - final double computedPressure = TropoUnit.HECTO_PASCAL.fromSI(pt.getPressure()); + final double computedPressure = TroposphericModelUtils.HECTO_PASCAL.fromSI(pt.getPressure()); Assertions.assertEquals(expectedPressure, computedPressure, 0.1); Assertions.assertEquals(expectedTemperature, computedTemperature, 0.1); @@ -131,7 +131,7 @@ public void testHighAltitude() { final double computedTemperature = pt.getTemperature() - 273.15; - final double computedPressure = TropoUnit.HECTO_PASCAL.fromSI(pt.getPressure()); + final double computedPressure = TroposphericModelUtils.HECTO_PASCAL.fromSI(pt.getPressure()); Assertions.assertEquals(expectedPressure, computedPressure, 0.1); Assertions.assertEquals(expectedTemperature, computedTemperature, 0.1); diff --git a/src/test/java/org/orekit/models/earth/weather/water/AbstractWaterVaporPressureProviderTest.java b/src/test/java/org/orekit/models/earth/weather/water/AbstractWaterVaporPressureProviderTest.java index 6ffd92e043..a305e7d64c 100644 --- a/src/test/java/org/orekit/models/earth/weather/water/AbstractWaterVaporPressureProviderTest.java +++ b/src/test/java/org/orekit/models/earth/weather/water/AbstractWaterVaporPressureProviderTest.java @@ -21,7 +21,7 @@ import org.hipparchus.util.Binary64Field; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import org.orekit.models.earth.troposphere.TropoUnit; +import org.orekit.models.earth.troposphere.TroposphericModelUtils; public abstract class AbstractWaterVaporPressureProviderTest { @@ -33,8 +33,8 @@ public abstract class AbstractWaterVaporPressureProviderTest { protected void doTestReferenceWaterVaporPressure(final double tolerance) { // the reference value is from NBS/NRC steam table final WaterVaporPressureProvider provider = buildProvider(); - Assertions.assertEquals(TropoUnit.HECTO_PASCAL.toSI(10.55154), - provider.waterVaporPressure(TropoUnit.HECTO_PASCAL.toSI(1013.25), 273.5 + 18, 0.5), + Assertions.assertEquals(TroposphericModelUtils.HECTO_PASCAL.toSI(10.55154), + provider.waterVaporPressure(TroposphericModelUtils.HECTO_PASCAL.toSI(1013.25), 273.5 + 18, 0.5), tolerance); } @@ -45,8 +45,8 @@ protected > void doTestReferenceWaterVaporPres final double tolerance) { // the reference value is from NBS/NRC steam table final WaterVaporPressureProvider provider = buildProvider(); - Assertions.assertEquals(TropoUnit.HECTO_PASCAL.toSI(10.55154), - provider.waterVaporPressure(TropoUnit.HECTO_PASCAL.toSI(field.getZero().newInstance(1013.25)), + Assertions.assertEquals(TroposphericModelUtils.HECTO_PASCAL.toSI(10.55154), + provider.waterVaporPressure(TroposphericModelUtils.HECTO_PASCAL.toSI(field.getZero().newInstance(1013.25)), field.getZero().newInstance(273.5 + 18), field.getZero().newInstance(0.5)).getReal(), tolerance); @@ -56,7 +56,7 @@ protected > void doTestReferenceWaterVaporPres public void testRelativeHumidity() { final WaterVaporPressureProvider provider = buildProvider(); for (double pPa = 700; pPa < 1100; pPa += 0.5) { - final double p = TropoUnit.HECTO_PASCAL.toSI(pPa); + final double p = TroposphericModelUtils.HECTO_PASCAL.toSI(pPa); for (double tC = 0.01; tC < 99; tC += 0.25) { final double t = 273.15 + tC; for (double rH = 0.0; rH < 1.0; rH += 0.02) { @@ -75,7 +75,7 @@ public void testRelativeHumidityField() { private > void doTestRelativeHumidityField(final Field field) { final WaterVaporPressureProvider provider = buildProvider(); for (double pPa = 700; pPa < 1100; pPa += 0.5) { - final T p = TropoUnit.HECTO_PASCAL.toSI(field.getZero().newInstance(pPa)); + final T p = TroposphericModelUtils.HECTO_PASCAL.toSI(field.getZero().newInstance(pPa)); for (double tC = 0.01; tC < 99; tC += 0.25) { final T t = field.getZero().newInstance(273.15 + tC); for (double rH = 0.0; rH < 1.0; rH += 0.02) { From 01e2a76b0eff3ddfffdc66ef79c5358b909ca32b Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Wed, 13 Dec 2023 21:10:02 +0100 Subject: [PATCH 042/359] Pass pressure/temperature/humidity throughout troposphere computation. --- .../measurements/GroundStation.java | 118 +++- .../AngularTroposphericDelayModifier.java | 22 +- ...aseRangeRateTroposphericDelayModifier.java | 39 +- .../BaseRangeTroposphericDelayModifier.java | 27 +- ...ticRangeRateTroposphericDelayModifier.java | 18 +- ...istaticRangeTroposphericDelayModifier.java | 15 +- .../PhaseTroposphericDelayModifier.java | 27 +- .../RangeRateTroposphericDelayModifier.java | 22 +- .../RangeTroposphericDelayModifier.java | 15 +- .../TDOATroposphericDelayModifier.java | 25 +- ...nAroundRangeTroposphericDelayModifier.java | 27 +- .../org/orekit/frames/TopocentricFrame.java | 4 +- .../CanonicalSaastamoinenModel.java | 20 +- .../DiscreteTroposphericModel.java | 3 + .../earth/troposphere/EstimatedModel.java | 154 ++++++ .../EstimatedTroposphericModel.java | 67 +-- .../troposphere/FixedTroposphericDelay.java | 27 +- .../earth/troposphere/MariniMurrayModel.java | 35 +- .../earth/troposphere/MendesPavlisModel.java | 32 +- .../ModifiedSaastamoinenModel.java | 78 +-- .../earth/troposphere/SaastamoinenModel.java | 36 +- .../troposphere/TimeSpanEstimatedModel.java | 273 ++++++++++ .../TimeSpanEstimatedTroposphericModel.java | 2 + .../earth/troposphere/TroposphericModel.java | 66 +++ .../troposphere/TroposphericModelAdapter.java | 78 +++ .../troposphere/TroposphericModelUtils.java | 22 + .../earth/troposphere/ViennaOneModel.java | 27 +- .../earth/troposphere/ViennaThreeModel.java | 25 +- ...ntPressureTemperatureHumidityProvider.java | 5 +- .../weather/FieldPressureTemperature.java | 29 +- .../FieldPressureTemperatureHumidity.java | 16 +- .../weather/GlobalPressureTemperature.java | 4 +- .../weather/GlobalPressureTemperature2.java | 6 +- ...tPressureTemperatureHumidityConverter.java | 86 +++ ...ntPressureTemperatureHumidityProvider.java | 136 ----- .../earth/weather/PressureTemperature.java | 19 +- .../weather/PressureTemperatureHumidity.java | 6 +- src/test/java/org/orekit/Utils.java | 4 +- .../estimation/BrouwerLyddaneContext.java | 2 + .../java/org/orekit/estimation/Context.java | 2 + .../org/orekit/estimation/DSSTContext.java | 2 + .../estimation/EcksteinHechlerContext.java | 2 + .../orekit/estimation/EphemerisContext.java | 2 + .../orekit/estimation/KeplerianContext.java | 2 + .../org/orekit/estimation/TLEContext.java | 2 + .../common/AbstractOrbitDetermination.java | 80 +-- .../estimation/iod/AbstractIodTest.java | 9 +- .../orekit/estimation/iod/IodLaplaceTest.java | 4 +- .../DSSTOrbitDeterminationTest.java | 6 +- .../NumericalOrbitDeterminationTest.java | 24 +- .../TLEOrbitDeterminationTest.java | 2 +- .../measurements/AngularRaDecTest.java | 4 +- .../ComparableMeasurementTest.java | 4 +- .../measurements/GroundStationTest.java | 14 +- .../measurements/RangeRateTest.java | 5 +- .../estimation/measurements/RangeTest.java | 13 +- .../estimation/measurements/TDOATest.java | 2 +- .../TurnAroundRangeAnalyticTest.java | 5 +- .../measurements/TurnAroundRangeTest.java | 12 +- .../filtering/ElevationFilteringTest.java | 4 +- .../gnss/InterSatellitesWindUpTest.java | 10 +- .../measurements/gnss/PhaseTest.java | 12 +- .../modifiers/AberrationModifierTest.java | 4 +- .../RelativisticClockPhaseModifierTest.java | 4 +- .../RelativisticClockRangeModifierTest.java | 4 +- ...elativisticClockRangeRateModifierTest.java | 4 +- .../modifiers/TropoModifierTest.java | 51 +- ...KalmanNumericalOrbitDeterminationTest.java | 8 +- .../TLEKalmanOrbitDeterminationTest.java | 2 +- .../earth/atmosphere/AtmosphereTest.java | 2 + .../EstimatedIonosphericModelTest.java | 4 +- .../AbstractFieldMappingFunctionTest.java | 3 +- .../CanonicalSaastamoinenModelTest.java | 10 +- .../earth/troposphere/EstimatedModelTest.java | 453 ++++++++++++++++ .../EstimatedTroposphericModelTest.java | 4 +- .../FieldGlobalMappingFunctionModelTest.java | 3 +- .../FieldMendesPavlisModelTest.java | 46 +- .../troposphere/FieldViennaOneModelTest.java | 42 +- .../FieldViennaThreeModelTest.java | 36 +- .../FixedTroposphericModelTest.java | 73 ++- .../troposphere/MariniMurrayModelTest.java | 44 +- .../troposphere/MendesPavlisModelTest.java | 14 +- .../ModifiedSaastamoinenModelTest.java | 111 ++-- .../troposphere/SaastamoinenModelTest.java | 8 +- .../TimeSpanEstimatedModelTest.java | 502 ++++++++++++++++++ ...imeSpanEstimatedTroposphericModelTest.java | 1 + .../earth/troposphere/ViennaOneModelTest.java | 8 +- .../troposphere/ViennaThreeModelTest.java | 8 +- .../org/orekit/orbits/FieldOrbitTest.java | 1 - .../propagation/FieldSpacecraftStateTest.java | 1 - 90 files changed, 2730 insertions(+), 560 deletions(-) create mode 100644 src/main/java/org/orekit/models/earth/troposphere/EstimatedModel.java create mode 100644 src/main/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModel.java create mode 100644 src/main/java/org/orekit/models/earth/troposphere/TroposphericModel.java create mode 100644 src/main/java/org/orekit/models/earth/troposphere/TroposphericModelAdapter.java create mode 100644 src/main/java/org/orekit/models/earth/weather/HeightDependentPressureTemperatureHumidityConverter.java delete mode 100644 src/main/java/org/orekit/models/earth/weather/HeightDependentPressureTemperatureHumidityProvider.java create mode 100644 src/test/java/org/orekit/models/earth/troposphere/EstimatedModelTest.java create mode 100644 src/test/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModelTest.java diff --git a/src/main/java/org/orekit/estimation/measurements/GroundStation.java b/src/main/java/org/orekit/estimation/measurements/GroundStation.java index 5e2e359695..014de0434e 100644 --- a/src/main/java/org/orekit/estimation/measurements/GroundStation.java +++ b/src/main/java/org/orekit/estimation/measurements/GroundStation.java @@ -18,6 +18,7 @@ import java.util.Map; +import org.hipparchus.CalculusFieldElement; import org.hipparchus.Field; import org.hipparchus.analysis.differentiation.Gradient; import org.hipparchus.geometry.euclidean.threed.FieldRotation; @@ -41,6 +42,10 @@ import org.orekit.frames.TopocentricFrame; import org.orekit.frames.Transform; import org.orekit.models.earth.displacement.StationDisplacement; +import org.orekit.models.earth.troposphere.TroposphericModelUtils; +import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; +import org.orekit.models.earth.weather.PressureTemperatureHumidity; +import org.orekit.models.earth.weather.PressureTemperatureHumidityProvider; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; import org.orekit.time.UT1Scale; @@ -114,6 +119,11 @@ public class GroundStation { /** Provider for Earth frame whose EOP parameters can be estimated. */ private final EstimatedEarthFrameProvider estimatedEarthFrameProvider; + /** Provider for weather parameters. + * @since 12.1 + */ + private final PressureTemperatureHumidityProvider pthProvider; + /** Earth frame whose EOP parameters can be estimated. */ private final Frame estimatedEarthFrame; @@ -142,6 +152,10 @@ public class GroundStation { private final ParameterDriver zenithOffsetDriver; /** Build a ground station ignoring {@link StationDisplacement station displacements}. + *

                + * Calls {@link #GroundStation(TopocentricFrame, PressureTemperatureHumidityProvider)} + * with {@link TroposphericModelUtils#STANDARD_ATMOSPHERE_PROVIDER} as the provider. + *

                *

                * The initial values for the pole and prime meridian parametric linear models * ({@link #getPrimeMeridianOffsetDriver()}, {@link #getPrimeMeridianDriftDriver()}, @@ -159,7 +173,31 @@ public class GroundStation { * @see #GroundStation(TopocentricFrame, EOPHistory, StationDisplacement...) */ public GroundStation(final TopocentricFrame baseFrame) { - this(baseFrame, FramesFactory.findEOP(baseFrame), new StationDisplacement[0]); + this(baseFrame, TroposphericModelUtils.STANDARD_ATMOSPHERE_PROVIDER, + FramesFactory.findEOP(baseFrame), new StationDisplacement[0]); + } + + /** Build a ground station ignoring {@link StationDisplacement station displacements}. + *

                + * The initial values for the pole and prime meridian parametric linear models + * ({@link #getPrimeMeridianOffsetDriver()}, {@link #getPrimeMeridianDriftDriver()}, + * {@link #getPolarOffsetXDriver()}, {@link #getPolarDriftXDriver()}, + * {@link #getPolarOffsetXDriver()}, {@link #getPolarDriftXDriver()}) are set to 0. + * The initial values for the station offset model ({@link #getClockOffsetDriver()}, + * {@link #getEastOffsetDriver()}, {@link #getNorthOffsetDriver()}, + * {@link #getZenithOffsetDriver()}) are set to 0. + * This implies that as long as these values are not changed, the offset frame is + * the same as the {@link #getBaseFrame() base frame}. As soon as some of these models + * are changed, the offset frame moves away from the {@link #getBaseFrame() base frame}. + *

                + * @param baseFrame base frame associated with the station, without *any* parametric + * model (no station offset, no polar motion, no meridian shift) + * @param pthProvider provider for weather parameters + * @see #GroundStation(TopocentricFrame, EOPHistory, StationDisplacement...) + * @since 12.1 + */ + public GroundStation(final TopocentricFrame baseFrame, final PressureTemperatureHumidityProvider pthProvider) { + this(baseFrame, pthProvider, FramesFactory.findEOP(baseFrame), new StationDisplacement[0]); } /** Simple constructor. @@ -181,11 +219,43 @@ public GroundStation(final TopocentricFrame baseFrame) { * @param displacements ground station displacement model (tides, ocean loading, * atmospheric loading, thermal effects...) * @since 9.1 + * @deprecated as of 12.1, replaced by {@link #GroundStation(TopocentricFrame, + * PressureTemperatureHumidityProvider, EOPHistory, StationDisplacement...)} */ + @Deprecated public GroundStation(final TopocentricFrame baseFrame, final EOPHistory eopHistory, final StationDisplacement... displacements) { + this(baseFrame, TroposphericModelUtils.STANDARD_ATMOSPHERE_PROVIDER, eopHistory, displacements); + } + + /** Simple constructor. + *

                + * The initial values for the pole and prime meridian parametric linear models + * ({@link #getPrimeMeridianOffsetDriver()}, {@link #getPrimeMeridianDriftDriver()}, + * {@link #getPolarOffsetXDriver()}, {@link #getPolarDriftXDriver()}, + * {@link #getPolarOffsetXDriver()}, {@link #getPolarDriftXDriver()}) are set to 0. + * The initial values for the station offset model ({@link #getClockOffsetDriver()}, + * {@link #getEastOffsetDriver()}, {@link #getNorthOffsetDriver()}, + * {@link #getZenithOffsetDriver()}, {@link #getClockOffsetDriver()}) are set to 0. + * This implies that as long as these values are not changed, the offset frame is + * the same as the {@link #getBaseFrame() base frame}. As soon as some of these models + * are changed, the offset frame moves away from the {@link #getBaseFrame() base frame}. + *

                + * @param baseFrame base frame associated with the station, without *any* parametric + * model (no station offset, no polar motion, no meridian shift) + * @param pthProvider provider for weather parameters + * @param eopHistory EOP history associated with Earth frames + * @param displacements ground station displacement model (tides, ocean loading, + * atmospheric loading, thermal effects...) + * @since 12.1 + */ + public GroundStation(final TopocentricFrame baseFrame, + final PressureTemperatureHumidityProvider pthProvider, + final EOPHistory eopHistory, + final StationDisplacement... displacements) { - this.baseFrame = baseFrame; + this.baseFrame = baseFrame; + this.pthProvider = pthProvider; if (eopHistory == null) { throw new OrekitException(OrekitMessages.NO_EARTH_ORIENTATION_PARAMETERS); @@ -229,6 +299,25 @@ public GroundStation(final TopocentricFrame baseFrame, final EOPHistory eopHisto } + /** Get the weather parameters. + * @param date date at which weather parameters are requested + * @return weather parameters + * @since 12.1 + */ + public PressureTemperatureHumidity getPressureTemperatureHumidity(final AbsoluteDate date) { + return pthProvider.getWeatherParamerers(getOffsetGeodeticPoint(date), date); + } + + /** Get the weather parameters. + * @param type of the field elements + * @param date date at which weather parameters are requested + * @return weather parameters + * @since 12.1 + */ + public > FieldPressureTemperatureHumidity getPressureTemperatureHumidity(final FieldAbsoluteDate date) { + return pthProvider.getWeatherParamerers(getOffsetGeodeticPoint(date), date); + } + /** Get the displacement models. * @return displacement models (empty if no model has been set up) * @since 9.1 @@ -425,6 +514,31 @@ public GeodeticPoint getOffsetGeodeticPoint(final AbsoluteDate date) { } + /** Get the geodetic point at the center of the offset frame. + * @param type of the field elements + * @param date current date (may be null if displacements are ignored) + * @return geodetic point at the center of the offset frame + * @since 12.1 + */ + public > FieldGeodeticPoint getOffsetGeodeticPoint(final FieldAbsoluteDate date) { + + // take station offset into account + final double x = eastOffsetDriver.getValue(); + final double y = northOffsetDriver.getValue(); + final double z = zenithOffsetDriver.getValue(); + final BodyShape baseShape = baseFrame.getParentShape(); + final FieldStaticTransform baseToBody = + baseFrame.getStaticTransformTo(baseShape.getBodyFrame(), date); + FieldVector3D origin = baseToBody.transformPosition(new Vector3D(x, y, z)); + + if (date != null) { + origin = origin.add(computeDisplacement(date.toAbsoluteDate(), origin.toVector3D())); + } + + return baseShape.transform(origin, baseShape.getBodyFrame(), null); + + } + /** Get the transform between offset frame and inertial frame. *

                * The offset frame takes the current position offset, diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/AngularTroposphericDelayModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/AngularTroposphericDelayModifier.java index 28dda835ad..30294c291b 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/AngularTroposphericDelayModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/AngularTroposphericDelayModifier.java @@ -25,7 +25,7 @@ import org.orekit.estimation.measurements.EstimationModifier; import org.orekit.estimation.measurements.GroundStation; import org.orekit.frames.Frame; -import org.orekit.models.earth.troposphere.DiscreteTroposphericModel; +import org.orekit.models.earth.troposphere.TroposphericModel; import org.orekit.propagation.SpacecraftState; import org.orekit.time.AbsoluteDate; import org.orekit.utils.Constants; @@ -47,13 +47,24 @@ public class AngularTroposphericDelayModifier implements EstimationModifier { /** Tropospheric delay model. */ - private final DiscreteTroposphericModel tropoModel; + private final TroposphericModel tropoModel; /** Constructor. * * @param model Tropospheric delay model appropriate for the current angular measurement method. + * @deprecated as of 12.1, replaced by {@link #AngularTroposphericDelayModifier(TroposphericModel)} */ - public AngularTroposphericDelayModifier(final DiscreteTroposphericModel model) { + @Deprecated + public AngularTroposphericDelayModifier(final org.orekit.models.earth.troposphere.DiscreteTroposphericModel model) { + this(new org.orekit.models.earth.troposphere.TroposphericModelAdapter(model)); + } + + /** Constructor. + * + * @param model Tropospheric delay model appropriate for the current angular measurement method. + * @since 12.1 + */ + public AngularTroposphericDelayModifier(final TroposphericModel model) { tropoModel = model; } @@ -75,7 +86,10 @@ private double angularErrorTroposphericModel(final GroundStation station, // only consider measures above the horizon if (elevation > 0.0) { // delay in meters - final double delay = tropoModel.pathDelay(elevation, station.getBaseFrame().getPoint(), tropoModel.getParameters(state.getDate()), state.getDate()); + final double delay = tropoModel.pathDelay(elevation, + station.getOffsetGeodeticPoint(state.getDate()), + station.getPressureTemperatureHumidity(state.getDate()), + tropoModel.getParameters(state.getDate()), state.getDate()); // one-way measurement. return delay; diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/BaseRangeRateTroposphericDelayModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/BaseRangeRateTroposphericDelayModifier.java index a2bd297af3..14c0355f59 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/BaseRangeRateTroposphericDelayModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/BaseRangeRateTroposphericDelayModifier.java @@ -23,7 +23,7 @@ import org.hipparchus.geometry.euclidean.threed.FieldVector3D; import org.hipparchus.geometry.euclidean.threed.Vector3D; import org.orekit.estimation.measurements.GroundStation; -import org.orekit.models.earth.troposphere.DiscreteTroposphericModel; +import org.orekit.models.earth.troposphere.TroposphericModel; import org.orekit.propagation.FieldSpacecraftState; import org.orekit.propagation.SpacecraftState; import org.orekit.utils.ParameterDriver; @@ -42,20 +42,31 @@ public abstract class BaseRangeRateTroposphericDelayModifier { /** Tropospheric delay model. */ - private final DiscreteTroposphericModel tropoModel; + private final TroposphericModel tropoModel; /** Constructor. * * @param model Tropospheric delay model appropriate for the current range-rate measurement method. + * @deprecated as of 12.1, replaced by {@link #BaseRangeRateTroposphericDelayModifier(TroposphericModel)} */ - protected BaseRangeRateTroposphericDelayModifier(final DiscreteTroposphericModel model) { + @Deprecated + protected BaseRangeRateTroposphericDelayModifier(final org.orekit.models.earth.troposphere.DiscreteTroposphericModel model) { + this(new org.orekit.models.earth.troposphere.TroposphericModelAdapter(model)); + } + + /** Constructor. + * + * @param model Tropospheric delay model appropriate for the current range-rate measurement method. + * @since 12.1 + */ + protected BaseRangeRateTroposphericDelayModifier(final TroposphericModel model) { tropoModel = model; } /** Get the tropospheric delay model. * @return tropospheric delay model */ - protected DiscreteTroposphericModel getTropoModel() { + protected TroposphericModel getTropoModel() { return tropoModel; } @@ -82,7 +93,10 @@ public double rangeRateErrorTroposphericModel(final GroundStation station, // only consider measures above the horizon if (elevation1 > 0) { // tropospheric delay in meters - final double d1 = tropoModel.pathDelay(elevation1, station.getBaseFrame().getPoint(), tropoModel.getParameters(state.getDate()), state.getDate()); + final double d1 = tropoModel.pathDelay(elevation1, + station.getOffsetGeodeticPoint(state.getDate()), + station.getPressureTemperatureHumidity(state.getDate()), + tropoModel.getParameters(state.getDate()), state.getDate()); // propagate spacecraft state forward by dt final SpacecraftState state2 = state.shiftedBy(dt); @@ -96,7 +110,10 @@ public double rangeRateErrorTroposphericModel(final GroundStation station, getElevation(); // tropospheric delay dt after - final double d2 = tropoModel.pathDelay(elevation2, station.getBaseFrame().getPoint(), tropoModel.getParameters(state2.getDate()), state2.getDate()); + final double d2 = tropoModel.pathDelay(elevation2, + station.getOffsetGeodeticPoint(state.getDate()), + station.getPressureTemperatureHumidity(state.getDate()), + tropoModel.getParameters(state2.getDate()), state2.getDate()); return (d2 - d1) / dt; } @@ -133,7 +150,10 @@ public > T rangeRateErrorTroposphericModel(fin // only consider measures above the horizon if (elevation1.getReal() > 0) { // tropospheric delay in meters - final T d1 = tropoModel.pathDelay(elevation1, station.getBaseFrame().getPoint(field), parameters, state.getDate()); + final T d1 = tropoModel.pathDelay(elevation1, + station.getOffsetGeodeticPoint(state.getDate()), + station.getPressureTemperatureHumidity(state.getDate()), + parameters, state.getDate()); // propagate spacecraft state forward by dt final FieldSpacecraftState state2 = state.shiftedBy(dt); @@ -148,7 +168,10 @@ public > T rangeRateErrorTroposphericModel(fin // tropospheric delay dt after - final T d2 = tropoModel.pathDelay(elevation2, station.getBaseFrame().getPoint(field), parameters, state2.getDate()); + final T d2 = tropoModel.pathDelay(elevation2, + station.getOffsetGeodeticPoint(state.getDate()), + station.getPressureTemperatureHumidity(state.getDate()), + parameters, state2.getDate()); return d2.subtract(d1).divide(dt); } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/BaseRangeTroposphericDelayModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/BaseRangeTroposphericDelayModifier.java index 17b30bbf72..2fbc62e614 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/BaseRangeTroposphericDelayModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/BaseRangeTroposphericDelayModifier.java @@ -23,7 +23,7 @@ import org.hipparchus.geometry.euclidean.threed.FieldVector3D; import org.hipparchus.geometry.euclidean.threed.Vector3D; import org.orekit.estimation.measurements.GroundStation; -import org.orekit.models.earth.troposphere.DiscreteTroposphericModel; +import org.orekit.models.earth.troposphere.TroposphericModel; import org.orekit.propagation.FieldSpacecraftState; import org.orekit.propagation.SpacecraftState; import org.orekit.utils.ParameterDriver; @@ -41,20 +41,31 @@ public abstract class BaseRangeTroposphericDelayModifier { /** Tropospheric delay model. */ - private final DiscreteTroposphericModel tropoModel; + private final TroposphericModel tropoModel; + + /** Constructor. + * + * @param model Tropospheric delay model appropriate for the current range measurement method. + * @deprecated as of 12.1, replaced by {@link #BaseRangeTroposphericDelayModifier(TroposphericModel)} + */ + @Deprecated + protected BaseRangeTroposphericDelayModifier(final org.orekit.models.earth.troposphere.DiscreteTroposphericModel model) { + this(new org.orekit.models.earth.troposphere.TroposphericModelAdapter(model)); + } /** Constructor. * * @param model Tropospheric delay model appropriate for the current range measurement method. + * @since 12.1 */ - protected BaseRangeTroposphericDelayModifier(final DiscreteTroposphericModel model) { + protected BaseRangeTroposphericDelayModifier(final TroposphericModel model) { tropoModel = model; } /** Get the tropospheric delay model. * @return tropospheric delay model */ - protected DiscreteTroposphericModel getTropoModel() { + protected TroposphericModel getTropoModel() { return tropoModel; } @@ -75,7 +86,9 @@ public double rangeErrorTroposphericModel(final GroundStation station, // only consider measures above the horizon if (elevation > 0) { // tropospheric delay in meters - final double delay = tropoModel.pathDelay(elevation, station.getBaseFrame().getPoint(), + final double delay = tropoModel.pathDelay(elevation, + station.getOffsetGeodeticPoint(state.getDate()), + station.getPressureTemperatureHumidity(state.getDate()), tropoModel.getParameters(), state.getDate()); return delay; @@ -108,7 +121,9 @@ public > T rangeErrorTroposphericModel(final G // only consider measures above the horizon if (elevation .getReal() > 0) { // tropospheric delay in meters - final T delay = tropoModel.pathDelay(elevation, station.getBaseFrame().getPoint(field), + final T delay = tropoModel.pathDelay(elevation, + station.getOffsetGeodeticPoint(state.getDate()), + station.getPressureTemperatureHumidity(state.getDate()), parameters, state.getDate()); return delay; diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/BistaticRangeRateTroposphericDelayModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/BistaticRangeRateTroposphericDelayModifier.java index 8c499de798..a9672e44a7 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/BistaticRangeRateTroposphericDelayModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/BistaticRangeRateTroposphericDelayModifier.java @@ -22,7 +22,7 @@ import org.orekit.estimation.measurements.EstimatedMeasurementBase; import org.orekit.estimation.measurements.EstimationModifier; import org.orekit.estimation.measurements.GroundStation; -import org.orekit.models.earth.troposphere.DiscreteTroposphericModel; +import org.orekit.models.earth.troposphere.TroposphericModel; import org.orekit.propagation.SpacecraftState; /** Class modifying theoretical bistatic range-rate measurements with tropospheric delay. @@ -35,13 +35,25 @@ * @author Pascal Parraud * @since 11.2 */ -public class BistaticRangeRateTroposphericDelayModifier extends BaseRangeRateTroposphericDelayModifier implements EstimationModifier { +public class BistaticRangeRateTroposphericDelayModifier + extends BaseRangeRateTroposphericDelayModifier implements EstimationModifier { /** Constructor. * * @param model Tropospheric delay model appropriate for the current range-rate measurement method. + * @deprecated as of 12.1, replaced by {@link #BistaticRangeRateTroposphericDelayModifier(TroposphericModel)} */ - public BistaticRangeRateTroposphericDelayModifier(final DiscreteTroposphericModel model) { + @Deprecated + public BistaticRangeRateTroposphericDelayModifier(final org.orekit.models.earth.troposphere.DiscreteTroposphericModel model) { + this(new org.orekit.models.earth.troposphere.TroposphericModelAdapter(model)); + } + + /** Constructor. + * + * @param model Tropospheric delay model appropriate for the current range-rate measurement method. + * @since 12.1 + */ + public BistaticRangeRateTroposphericDelayModifier(final TroposphericModel model) { super(model); } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/BistaticRangeTroposphericDelayModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/BistaticRangeTroposphericDelayModifier.java index 868fee4237..f20892b724 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/BistaticRangeTroposphericDelayModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/BistaticRangeTroposphericDelayModifier.java @@ -22,7 +22,7 @@ import org.orekit.estimation.measurements.EstimatedMeasurementBase; import org.orekit.estimation.measurements.EstimationModifier; import org.orekit.estimation.measurements.GroundStation; -import org.orekit.models.earth.troposphere.DiscreteTroposphericModel; +import org.orekit.models.earth.troposphere.TroposphericModel; import org.orekit.propagation.SpacecraftState; /** Class modifying theoretical bistatic range measurement with tropospheric delay. @@ -42,8 +42,19 @@ public class BistaticRangeTroposphericDelayModifier extends BaseRangeTropospheri /** Constructor. * * @param model Tropospheric delay model appropriate for the current range measurement method. + * @deprecated as of 12.1 replaced by {@link #BistaticRangeTroposphericDelayModifier(TroposphericModel)} */ - public BistaticRangeTroposphericDelayModifier(final DiscreteTroposphericModel model) { + @Deprecated + public BistaticRangeTroposphericDelayModifier(final org.orekit.models.earth.troposphere.DiscreteTroposphericModel model) { + this(new org.orekit.models.earth.troposphere.TroposphericModelAdapter(model)); + } + + /** Constructor. + * + * @param model Tropospheric delay model appropriate for the current range measurement method. + * @since 12.1 + */ + public BistaticRangeTroposphericDelayModifier(final TroposphericModel model) { super(model); } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseTroposphericDelayModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseTroposphericDelayModifier.java index 5a0d9c9a5a..b4111d9de6 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseTroposphericDelayModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseTroposphericDelayModifier.java @@ -28,7 +28,7 @@ import org.orekit.estimation.measurements.EstimationModifier; import org.orekit.estimation.measurements.GroundStation; import org.orekit.estimation.measurements.gnss.Phase; -import org.orekit.models.earth.troposphere.DiscreteTroposphericModel; +import org.orekit.models.earth.troposphere.TroposphericModel; import org.orekit.propagation.FieldSpacecraftState; import org.orekit.propagation.SpacecraftState; import org.orekit.utils.Differentiation; @@ -47,13 +47,24 @@ public class PhaseTroposphericDelayModifier implements EstimationModifier { /** Tropospheric delay model. */ - private final DiscreteTroposphericModel tropoModel; + private final TroposphericModel tropoModel; /** Constructor. * * @param model Tropospheric delay model appropriate for the current range measurement method. + * @deprecated as of 12.1, replaced by {@link #PhaseTroposphericDelayModifier(TroposphericModel)} */ - public PhaseTroposphericDelayModifier(final DiscreteTroposphericModel model) { + @Deprecated + public PhaseTroposphericDelayModifier(final org.orekit.models.earth.troposphere.DiscreteTroposphericModel model) { + this(new org.orekit.models.earth.troposphere.TroposphericModelAdapter(model)); + } + + /** Constructor. + * + * @param model Tropospheric delay model appropriate for the current range measurement method. + * @since 12.1 + */ + public PhaseTroposphericDelayModifier(final TroposphericModel model) { tropoModel = model; } @@ -73,7 +84,10 @@ private double phaseErrorTroposphericModel(final GroundStation station, final Sp // only consider measures above the horizon if (elevation > 0) { // delay in meters - final double delay = tropoModel.pathDelay(elevation, station.getBaseFrame().getPoint(), tropoModel.getParameters(state.getDate()), state.getDate()); + final double delay = tropoModel.pathDelay(elevation, + station.getOffsetGeodeticPoint(state.getDate()), + station.getPressureTemperatureHumidity(state.getDate()), + tropoModel.getParameters(state.getDate()), state.getDate()); return delay / wavelength; } @@ -106,7 +120,10 @@ private > T phaseErrorTroposphericModel(final // only consider measures above the horizon if (elevation.getReal() > 0) { // delay in meters - final T delay = tropoModel.pathDelay(elevation, station.getBaseFrame().getPoint(field), parameters, state.getDate()); + final T delay = tropoModel.pathDelay(elevation, + station.getOffsetGeodeticPoint(state.getDate()), + station.getPressureTemperatureHumidity(state.getDate()), + parameters, state.getDate()); return delay.divide(wavelength); } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/RangeRateTroposphericDelayModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/RangeRateTroposphericDelayModifier.java index 39bc3ffeed..62691bc062 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/RangeRateTroposphericDelayModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/RangeRateTroposphericDelayModifier.java @@ -23,7 +23,7 @@ import org.orekit.estimation.measurements.EstimationModifier; import org.orekit.estimation.measurements.GroundStation; import org.orekit.estimation.measurements.RangeRate; -import org.orekit.models.earth.troposphere.DiscreteTroposphericModel; +import org.orekit.models.earth.troposphere.TroposphericModel; import org.orekit.propagation.FieldSpacecraftState; import org.orekit.propagation.SpacecraftState; @@ -43,12 +43,30 @@ public class RangeRateTroposphericDelayModifier extends BaseRangeRateTropospheri /** Two-way measurement factor. */ private final double fTwoWay; + /** Constructor. + * + * @param model Tropospheric delay model appropriate for the current range-rate measurement method. + * @param tw Flag indicating whether the measurement is two-way. + * @deprecated as of 12.1, replaced byb {@link #RangeRateTroposphericDelayModifier(TroposphericModel, boolean)} + */ + @Deprecated + public RangeRateTroposphericDelayModifier(final org.orekit.models.earth.troposphere.DiscreteTroposphericModel model, + final boolean tw) { + super(model); + if (tw) { + fTwoWay = 2.; + } else { + fTwoWay = 1.; + } + } + /** Constructor. * * @param model Tropospheric delay model appropriate for the current range-rate measurement method. * @param tw Flag indicating whether the measurement is two-way. + * @since 12.1 */ - public RangeRateTroposphericDelayModifier(final DiscreteTroposphericModel model, final boolean tw) { + public RangeRateTroposphericDelayModifier(final TroposphericModel model, final boolean tw) { super(model); if (tw) { fTwoWay = 2.; diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/RangeTroposphericDelayModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/RangeTroposphericDelayModifier.java index 55ac510e2e..3f1316d1df 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/RangeTroposphericDelayModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/RangeTroposphericDelayModifier.java @@ -22,7 +22,7 @@ import org.orekit.estimation.measurements.EstimationModifier; import org.orekit.estimation.measurements.GroundStation; import org.orekit.estimation.measurements.Range; -import org.orekit.models.earth.troposphere.DiscreteTroposphericModel; +import org.orekit.models.earth.troposphere.TroposphericModel; import org.orekit.propagation.SpacecraftState; /** Class modifying theoretical range measurement with tropospheric delay. @@ -41,8 +41,19 @@ public class RangeTroposphericDelayModifier extends BaseRangeTroposphericDelayMo /** Constructor. * * @param model Tropospheric delay model appropriate for the current range measurement method. + * @deprecated as of 12.1, replaced by {@link #RangeTroposphericDelayModifier(TroposphericModel)} */ - public RangeTroposphericDelayModifier(final DiscreteTroposphericModel model) { + @Deprecated + public RangeTroposphericDelayModifier(final org.orekit.models.earth.troposphere.DiscreteTroposphericModel model) { + this(new org.orekit.models.earth.troposphere.TroposphericModelAdapter(model)); + } + + /** Constructor. + * + * @param model Tropospheric delay model appropriate for the current range measurement method. + * @since 12.1 + */ + public RangeTroposphericDelayModifier(final TroposphericModel model) { super(model); } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/TDOATroposphericDelayModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/TDOATroposphericDelayModifier.java index 87efd5b07c..f2a231200e 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/TDOATroposphericDelayModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/TDOATroposphericDelayModifier.java @@ -28,7 +28,7 @@ import org.orekit.estimation.measurements.EstimationModifier; import org.orekit.estimation.measurements.GroundStation; import org.orekit.estimation.measurements.TDOA; -import org.orekit.models.earth.troposphere.DiscreteTroposphericModel; +import org.orekit.models.earth.troposphere.TroposphericModel; import org.orekit.propagation.FieldSpacecraftState; import org.orekit.propagation.SpacecraftState; import org.orekit.utils.Constants; @@ -47,13 +47,24 @@ public class TDOATroposphericDelayModifier implements EstimationModifier { /** Tropospheric delay model. */ - private final DiscreteTroposphericModel tropoModel; + private final TroposphericModel tropoModel; /** Constructor. * * @param model tropospheric model appropriate for the current TDOA measurement method. + * @deprecated as of 12.1, replaced by {@link #TDOATroposphericDelayModifier(TroposphericModel)} */ - public TDOATroposphericDelayModifier(final DiscreteTroposphericModel model) { + @Deprecated + public TDOATroposphericDelayModifier(final org.orekit.models.earth.troposphere.DiscreteTroposphericModel model) { + this(new org.orekit.models.earth.troposphere.TroposphericModelAdapter(model)); + } + + /** Constructor. + * + * @param model tropospheric model appropriate for the current TDOA measurement method. + * @since 12.1 + */ + public TDOATroposphericDelayModifier(final TroposphericModel model) { tropoModel = model; } @@ -73,7 +84,9 @@ private double timeErrorTroposphericModel(final GroundStation station, final Spa // only consider measurements above the horizon if (elevation > 0) { // Delay in meters - final double delay = tropoModel.pathDelay(elevation, station.getBaseFrame().getPoint(), + final double delay = tropoModel.pathDelay(elevation, + station.getOffsetGeodeticPoint(state.getDate()), + station.getPressureTemperatureHumidity(state.getDate()), tropoModel.getParameters(state.getDate()), state.getDate()); // return delay in seconds return delay / Constants.SPEED_OF_LIGHT; @@ -105,7 +118,9 @@ private > T timeErrorTroposphericModel(final G // only consider measurements above the horizon if (elevation.getReal() > 0) { // delay in meters - final T delay = tropoModel.pathDelay(elevation, station.getBaseFrame().getPoint(field), + final T delay = tropoModel.pathDelay(elevation, + station.getOffsetGeodeticPoint(state.getDate()), + station.getPressureTemperatureHumidity(state.getDate()), parameters, state.getDate()); // return delay in seconds return delay.divide(Constants.SPEED_OF_LIGHT); diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/TurnAroundRangeTroposphericDelayModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/TurnAroundRangeTroposphericDelayModifier.java index 6e0706513e..a71db8851f 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/TurnAroundRangeTroposphericDelayModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/TurnAroundRangeTroposphericDelayModifier.java @@ -30,7 +30,7 @@ import org.orekit.estimation.measurements.EstimationModifier; import org.orekit.estimation.measurements.GroundStation; import org.orekit.estimation.measurements.TurnAroundRange; -import org.orekit.models.earth.troposphere.DiscreteTroposphericModel; +import org.orekit.models.earth.troposphere.TroposphericModel; import org.orekit.propagation.FieldSpacecraftState; import org.orekit.propagation.SpacecraftState; import org.orekit.time.AbsoluteDate; @@ -52,13 +52,24 @@ public class TurnAroundRangeTroposphericDelayModifier implements EstimationModifier { /** Tropospheric delay model. */ - private final DiscreteTroposphericModel tropoModel; + private final TroposphericModel tropoModel; /** Constructor. * * @param model Tropospheric delay model appropriate for the current TurnAroundRange measurement method. + * @deprecated as of 12.1, replaced by {@link #TurnAroundRangeTroposphericDelayModifier(TroposphericModel)} */ - public TurnAroundRangeTroposphericDelayModifier(final DiscreteTroposphericModel model) { + @Deprecated + public TurnAroundRangeTroposphericDelayModifier(final org.orekit.models.earth.troposphere.DiscreteTroposphericModel model) { + this(new org.orekit.models.earth.troposphere.TroposphericModelAdapter(model)); + } + + /** Constructor. + * + * @param model Tropospheric delay model appropriate for the current TurnAroundRange measurement method. + * @since 12.1 + */ + public TurnAroundRangeTroposphericDelayModifier(final TroposphericModel model) { tropoModel = model; } @@ -79,7 +90,10 @@ private double rangeErrorTroposphericModel(final GroundStation station, final Sp // only consider measures above the horizon if (elevation > 0) { // Delay in meters - final double delay = tropoModel.pathDelay(elevation, station.getBaseFrame().getPoint(), tropoModel.getParameters(state.getDate()), state.getDate()); + final double delay = tropoModel.pathDelay(elevation, + station.getOffsetGeodeticPoint(state.getDate()), + station.getPressureTemperatureHumidity(state.getDate()), + tropoModel.getParameters(state.getDate()), state.getDate()); return delay; } @@ -110,7 +124,10 @@ private > T rangeErrorTroposphericModel(final // only consider measures above the horizon if (dsElevation.getReal() > 0) { // Delay in meters - final T delay = tropoModel.pathDelay(dsElevation, station.getBaseFrame().getPoint(field), parameters, state.getDate()); + final T delay = tropoModel.pathDelay(dsElevation, + station.getOffsetGeodeticPoint(state.getDate()), + station.getPressureTemperatureHumidity(state.getDate()), + parameters, state.getDate()); return delay; } diff --git a/src/main/java/org/orekit/frames/TopocentricFrame.java b/src/main/java/org/orekit/frames/TopocentricFrame.java index ccb84ae3f5..190ae05ed8 100644 --- a/src/main/java/org/orekit/frames/TopocentricFrame.java +++ b/src/main/java/org/orekit/frames/TopocentricFrame.java @@ -130,8 +130,8 @@ public Vector3D getCartesianPoint() { public > FieldGeodeticPoint getPoint(final Field field) { final T zero = field.getZero(); return new FieldGeodeticPoint<>(zero.newInstance(point.getLatitude()), - zero.newInstance(point.getLongitude()), - zero.newInstance(point.getAltitude())); + zero.newInstance(point.getLongitude()), + zero.newInstance(point.getAltitude())); } /** Get the zenith direction of topocentric frame, expressed in parent shape frame. diff --git a/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java b/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java index 812e0e915e..eb94a6f40b 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java @@ -28,7 +28,7 @@ import org.orekit.bodies.GeodeticPoint; import org.orekit.models.earth.weather.ConstantPressureTemperatureHumidityProvider; import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; -import org.orekit.models.earth.weather.HeightDependentPressureTemperatureHumidityProvider; +import org.orekit.models.earth.weather.HeightDependentPressureTemperatureHumidityConverter; import org.orekit.models.earth.weather.PressureTemperatureHumidity; import org.orekit.models.earth.weather.PressureTemperatureHumidityProvider; import org.orekit.models.earth.weather.water.NbsNrcSteamTable; @@ -57,7 +57,7 @@ * Ranging of Satellites" * @since 12.1 */ -public class CanonicalSaastamoinenModel implements DiscreteTroposphericModel { +public class CanonicalSaastamoinenModel implements TroposphericModel { /** Default lowest acceptable elevation angle [rad]. */ public static final double DEFAULT_LOW_ELEVATION_THRESHOLD = 0.05; @@ -94,7 +94,7 @@ public class CanonicalSaastamoinenModel implements DiscreteTroposphericModel { * conditions and table from the reference book. * * @param pthProvider provider for pressure, temperature and humidity - * @see HeightDependentPressureTemperatureHumidityProvider + * @see HeightDependentPressureTemperatureHumidityConverter */ public CanonicalSaastamoinenModel(final PressureTemperatureHumidityProvider pthProvider) { this.pthProvider = pthProvider; @@ -114,6 +114,7 @@ public CanonicalSaastamoinenModel(final PressureTemperatureHumidityProvider pthP public static CanonicalSaastamoinenModel getStandardModel() { // build standard meteorological data + final double altitude = 0.0; final double pressure = TroposphericModelUtils.HECTO_PASCAL.toSI(1013.25); final double temperature = 273.15 + 18; final double relativeHumidity = 0.5; @@ -121,14 +122,11 @@ public static CanonicalSaastamoinenModel getStandardModel() { final double waterVaporPressure = waterPressureProvider.waterVaporPressure(pressure, temperature, relativeHumidity); - final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(pressure, + final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(altitude, + pressure, temperature, waterVaporPressure); - final PressureTemperatureHumidityProvider pth0Provider = - new ConstantPressureTemperatureHumidityProvider(pth); - final PressureTemperatureHumidityProvider pthProvider = - new HeightDependentPressureTemperatureHumidityProvider(0.0, 5000.0, 0.0, pth0Provider, waterPressureProvider); - return new CanonicalSaastamoinenModel(pthProvider); + return new CanonicalSaastamoinenModel(new ConstantPressureTemperatureHumidityProvider(pth)); } @@ -147,6 +145,7 @@ public static CanonicalSaastamoinenModel getStandardModel() { */ @Override public double pathDelay(final double elevation, final GeodeticPoint point, + final PressureTemperatureHumidity weather, final double[] parameters, final AbsoluteDate date) { final PressureTemperatureHumidity pth = pthProvider.getWeatherParamerers(point, date); @@ -186,7 +185,8 @@ public double pathDelay(final double elevation, final GeodeticPoint point, */ @Override public > T pathDelay(final T elevation, final FieldGeodeticPoint point, - final T[] parameters, final FieldAbsoluteDate date) { + final FieldPressureTemperatureHumidity weather, + final T[] parameters, final FieldAbsoluteDate date) { final Field field = date.getField(); final T zero = field.getZero(); diff --git a/src/main/java/org/orekit/models/earth/troposphere/DiscreteTroposphericModel.java b/src/main/java/org/orekit/models/earth/troposphere/DiscreteTroposphericModel.java index b79fed704f..56bb760fe5 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/DiscreteTroposphericModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/DiscreteTroposphericModel.java @@ -37,7 +37,9 @@ *

              • δnh = non-hydrostatic (or wet) delay
              • *
              * @author Bryan Cazabonne + * @deprecated as of 12.1, replaced by {@link TroposphericModel} */ +@Deprecated public interface DiscreteTroposphericModel extends ParameterDriversProvider { /** Calculates the tropospheric path delay for the signal path from a ground @@ -63,4 +65,5 @@ public interface DiscreteTroposphericModel extends ParameterDriversProvider { */ > T pathDelay(T elevation, FieldGeodeticPoint point, T[] parameters, FieldAbsoluteDate date); + } diff --git a/src/main/java/org/orekit/models/earth/troposphere/EstimatedModel.java b/src/main/java/org/orekit/models/earth/troposphere/EstimatedModel.java new file mode 100644 index 0000000000..123f21c1dc --- /dev/null +++ b/src/main/java/org/orekit/models/earth/troposphere/EstimatedModel.java @@ -0,0 +1,154 @@ +/* Copyright 2002-2023 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import java.util.Collections; +import java.util.List; + +import org.hipparchus.CalculusFieldElement; +import org.hipparchus.util.FastMath; +import org.orekit.bodies.FieldGeodeticPoint; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.models.earth.weather.ConstantPressureTemperatureHumidityProvider; +import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; +import org.orekit.models.earth.weather.PressureTemperatureHumidity; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; +import org.orekit.utils.ParameterDriver; + +/** An estimated tropospheric model. The tropospheric delay is computed according to the formula: + *

              + * δ = δh * mh + (δt - δh) * mw + *

              + * With: + *

                + *
              • δh: Tropospheric zenith hydro-static delay.
              • + *
              • δt: Tropospheric total zenith delay.
              • + *
              • mh: Hydro-static mapping function.
              • + *
              • mw: Wet mapping function.
              • + *
              + *

              + * The mapping functions mh(e) and mw(e) are + * computed thanks to a {@link #model} initialized by the user. + * The user has the possibility to use several mapping function models for the computations: + * the {@link GlobalMappingFunctionModel Global Mapping Function}, or + * the {@link NiellMappingFunctionModel Niell Mapping Function} + *

              + * The tropospheric zenith delay δh is computed empirically with a + * {@link DiscreteTroposphericModel tropospheric model} + * while the tropospheric total zenith delay δt is estimated as a {@link ParameterDriver}, + * hence the wet part is the difference between the two. + * @since 12.1 + */ +public class EstimatedModel implements TroposphericModel { + + /** Name of the parameter of this model: the total zenith delay. */ + public static final String TOTAL_ZENITH_DELAY = "total zenith delay"; + + /** Mapping Function model. */ + private final MappingFunction model; + + /** Driver for the tropospheric zenith total delay.*/ + private final ParameterDriver totalZenithDelay; + + /** Model for hydrostatic component. */ + private final TroposphericModel hydrostatic; + + /** Build a new instance using the given environmental conditions. + *

              + * This constructor uses a {@link ModifiedSaastamoinenModel} for the hydrostatic contribution. + *

              + * @param h0 altitude of the station [m] + * @param t0 the temperature at the station [K] + * @param p0 the atmospheric pressure at the station [mbar] + * @param model mapping function model (NMF or GMF). + * @param totalDelay initial value for the tropospheric zenith total delay [m] + */ + public EstimatedModel(final double h0, final double t0, final double p0, + final MappingFunction model, final double totalDelay) { + this(new ModifiedSaastamoinenModel(new ConstantPressureTemperatureHumidityProvider(new PressureTemperatureHumidity(h0, + TroposphericModelUtils.HECTO_PASCAL.toSI(p0), + t0, + 0.0))), + model, totalDelay); + } + + /** Build a new instance using the given environmental conditions. + * @param hydrostatic model for hydrostatic component + * @param model mapping function model (NMF or GMF). + * @param totalDelay initial value for the tropospheric zenith total delay [m] + * @since 12.1 + */ + public EstimatedModel(final TroposphericModel hydrostatic, + final MappingFunction model, + final double totalDelay) { + + totalZenithDelay = new ParameterDriver(EstimatedModel.TOTAL_ZENITH_DELAY, + totalDelay, FastMath.scalb(1.0, 0), 0.0, Double.POSITIVE_INFINITY); + + this.hydrostatic = hydrostatic; + this.model = model; + } + + /** Build a new instance using a standard atmosphere model. + *
                + *
              • altitude: 0m + *
              • temperature: 18 degree Celsius + *
              • pressure: 1013.25 mbar + *
              + * @param model mapping function model (NMF or GMF). + * @param totalDelay initial value for the tropospheric zenith total delay [m] + */ + public EstimatedModel(final MappingFunction model, final double totalDelay) { + this(0.0, 273.15 + 18.0, 1013.25, model, totalDelay); + } + + /** {@inheritDoc} */ + @Override + public List getParametersDrivers() { + return Collections.singletonList(totalZenithDelay); + } + + /** {@inheritDoc} */ + @Override + public double pathDelay(final double elevation, final GeodeticPoint point, + final PressureTemperatureHumidity weather, + final double[] parameters, final AbsoluteDate date) { + // Zenith delays. elevation = pi/2 because we compute the delay in the zenith direction + final double zhd = hydrostatic.pathDelay(0.5 * FastMath.PI, point, weather, parameters, date); + final double ztd = parameters[0]; + // Mapping functions + final double[] mf = model.mappingFactors(elevation, point, date); + // Total delay + return mf[0] * zhd + mf[1] * (ztd - zhd); + } + + /** {@inheritDoc} */ + @Override + public > T pathDelay(final T elevation, final FieldGeodeticPoint point, + final FieldPressureTemperatureHumidity weather, + final T[] parameters, final FieldAbsoluteDate date) { + // Zenith delays. elevation = pi/2 because we compute the delay in the zenith direction + final T zhd = hydrostatic.pathDelay(elevation.getPi().multiply(0.5), point, weather, parameters, date); + final T ztd = parameters[0]; + // Mapping functions + final T[] mf = model.mappingFactors(elevation, point, date); + // Total delay + return mf[0].multiply(zhd).add(mf[1].multiply(ztd.subtract(zhd))); + } + +} diff --git a/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java b/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java index fb23fa1568..fe531253b1 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java @@ -16,15 +16,10 @@ */ package org.orekit.models.earth.troposphere; -import java.util.Collections; -import java.util.List; - import org.hipparchus.CalculusFieldElement; -import org.hipparchus.util.FastMath; import org.orekit.bodies.FieldGeodeticPoint; import org.orekit.bodies.GeodeticPoint; -import org.orekit.models.earth.weather.ConstantPressureTemperatureHumidityProvider; -import org.orekit.models.earth.weather.PressureTemperatureHumidity; +import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; import org.orekit.utils.ParameterDriver; @@ -52,20 +47,12 @@ * while the tropospheric total zenith delay δt is estimated as a {@link ParameterDriver}, * hence the wet part is the difference between the two. */ -public class EstimatedTroposphericModel implements DiscreteTroposphericModel { +@SuppressWarnings("deprecation") +public class EstimatedTroposphericModel extends EstimatedModel implements DiscreteTroposphericModel { /** Name of the parameter of this model: the total zenith delay. */ public static final String TOTAL_ZENITH_DELAY = "total zenith delay"; - /** Mapping Function model. */ - private final MappingFunction model; - - /** Driver for the tropospheric zenith total delay.*/ - private final ParameterDriver totalZenithDelay; - - /** Model for hydrostatic component. */ - private final DiscreteTroposphericModel hydrostatic; - /** Build a new instance using the given environmental conditions. *

              * This constructor uses a {@link ModifiedSaastamoinenModel} for the hydrostatic contribution. @@ -77,11 +64,7 @@ public class EstimatedTroposphericModel implements DiscreteTroposphericModel { */ public EstimatedTroposphericModel(final double t0, final double p0, final MappingFunction model, final double totalDelay) { - this(new ModifiedSaastamoinenModel(0.0, - new ConstantPressureTemperatureHumidityProvider(new PressureTemperatureHumidity(TroposphericModelUtils.HECTO_PASCAL.toSI(p0), - t0, - 0.0))), - model, totalDelay); + super(0.0, t0, p0, model, totalDelay); } /** Build a new instance using the given environmental conditions. @@ -91,13 +74,9 @@ public EstimatedTroposphericModel(final double t0, final double p0, * @since 12.1 */ public EstimatedTroposphericModel(final DiscreteTroposphericModel hydrostatic, - final MappingFunction model, final double totalDelay) { - - totalZenithDelay = new ParameterDriver(EstimatedTroposphericModel.TOTAL_ZENITH_DELAY, - totalDelay, FastMath.scalb(1.0, 0), 0.0, Double.POSITIVE_INFINITY); - - this.hydrostatic = hydrostatic; - this.model = model; + final MappingFunction model, + final double totalDelay) { + super(new TroposphericModelAdapter(hydrostatic), model, totalDelay); } /** Build a new instance using a standard atmosphere model. @@ -114,34 +93,22 @@ public EstimatedTroposphericModel(final MappingFunction model, final double tota /** {@inheritDoc} */ @Override - public List getParametersDrivers() { - return Collections.singletonList(totalZenithDelay); - } - - /** {@inheritDoc} */ - @Override + @Deprecated public double pathDelay(final double elevation, final GeodeticPoint point, final double[] parameters, final AbsoluteDate date) { - // Zenith delays. elevation = pi/2 because we compute the delay in the zenith direction - final double zhd = hydrostatic.pathDelay(0.5 * FastMath.PI, point, parameters, date); - final double ztd = parameters[0]; - // Mapping functions - final double[] mf = model.mappingFactors(elevation, point, date); - // Total delay - return mf[0] * zhd + mf[1] * (ztd - zhd); + return pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, parameters, date); } /** {@inheritDoc} */ @Override - public > T pathDelay(final T elevation, final FieldGeodeticPoint point, - final T[] parameters, final FieldAbsoluteDate date) { - // Zenith delays. elevation = pi/2 because we compute the delay in the zenith direction - final T zhd = hydrostatic.pathDelay(elevation.getPi().multiply(0.5), point, parameters, date); - final T ztd = parameters[0]; - // Mapping functions - final T[] mf = model.mappingFactors(elevation, point, date); - // Total delay - return mf[0].multiply(zhd).add(mf[1].multiply(ztd.subtract(zhd))); + @Deprecated + public > T pathDelay(final T elevation, + final FieldGeodeticPoint point, + final T[] parameters, + final FieldAbsoluteDate date) { + return pathDelay(elevation, point, + new FieldPressureTemperatureHumidity<>(date.getField(), TroposphericModelUtils.STANDARD_ATMOSPHERE), + parameters, date); } } diff --git a/src/main/java/org/orekit/models/earth/troposphere/FixedTroposphericDelay.java b/src/main/java/org/orekit/models/earth/troposphere/FixedTroposphericDelay.java index 5c7a5a34e3..dac4c95168 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/FixedTroposphericDelay.java +++ b/src/main/java/org/orekit/models/earth/troposphere/FixedTroposphericDelay.java @@ -30,6 +30,8 @@ import org.orekit.data.DataProvidersManager; import org.orekit.errors.OrekitException; import org.orekit.errors.OrekitMessages; +import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; +import org.orekit.models.earth.weather.PressureTemperatureHumidity; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; import org.orekit.utils.InterpolationTableLoader; @@ -40,7 +42,8 @@ * the {@link DataProvidersManager}. * @author Thomas Neidhart */ -public class FixedTroposphericDelay implements DiscreteTroposphericModel { +@SuppressWarnings("deprecation") +public class FixedTroposphericDelay implements DiscreteTroposphericModel, TroposphericModel { /** Singleton object for the default model. */ private static FixedTroposphericDelay defaultModel; @@ -128,8 +131,17 @@ public static FixedTroposphericDelay getDefaultModel() { /** {@inheritDoc} */ @Override + @Deprecated public double pathDelay(final double elevation, final GeodeticPoint point, final double[] parameters, final AbsoluteDate date) { + return pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, parameters, date); + } + + /** {@inheritDoc} */ + @Override + public double pathDelay(final double elevation, final GeodeticPoint point, + final PressureTemperatureHumidity weather, + final double[] parameters, final AbsoluteDate date) { // limit the height to 5000 m final double h = FastMath.min(FastMath.max(0, point.getAltitude()), 5000); // limit the elevation to 0 - π @@ -140,10 +152,21 @@ public double pathDelay(final double elevation, final GeodeticPoint point, return delayFunction.value(h, e); } + /** {@inheritDoc} */ + @Override + @Deprecated + public > T pathDelay(final T elevation, final FieldGeodeticPoint point, + final T[] parameters, final FieldAbsoluteDate date) { + return pathDelay(elevation, point, + new FieldPressureTemperatureHumidity<>(date.getField(), TroposphericModelUtils.STANDARD_ATMOSPHERE), + parameters, date); + } + /** {@inheritDoc} */ @Override public > T pathDelay(final T elevation, final FieldGeodeticPoint point, - final T[] parameters, final FieldAbsoluteDate date) { + final FieldPressureTemperatureHumidity weather, + final T[] parameters, final FieldAbsoluteDate date) { final T zero = date.getField().getZero(); final T pi = zero.getPi(); // limit the height to 5000 m diff --git a/src/main/java/org/orekit/models/earth/troposphere/MariniMurrayModel.java b/src/main/java/org/orekit/models/earth/troposphere/MariniMurrayModel.java index 5e75296beb..a7c62fc7c3 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/MariniMurrayModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/MariniMurrayModel.java @@ -41,7 +41,8 @@ * * @author Joris Olympio */ -public class MariniMurrayModel implements DiscreteTroposphericModel { +@SuppressWarnings("deprecation") +public class MariniMurrayModel implements DiscreteTroposphericModel, TroposphericModel { /** Provider for pressure, temperature and humidity. */ private PressureTemperatureHumidityProvider pthProvider; @@ -59,7 +60,8 @@ public class MariniMurrayModel implements DiscreteTroposphericModel { */ @Deprecated public MariniMurrayModel(final double t0, final double p0, final double rh, final double lambda) { - this(new ConstantPressureTemperatureHumidityProvider(new PressureTemperatureHumidity(TroposphericModelUtils.HECTO_PASCAL.toSI(p0), + this(new ConstantPressureTemperatureHumidityProvider(new PressureTemperatureHumidity(0, + TroposphericModelUtils.HECTO_PASCAL.toSI(p0), t0, new CIPM2007(). waterVaporPressure(TroposphericModelUtils.HECTO_PASCAL.toSI(p0), @@ -111,6 +113,7 @@ public static MariniMurrayModel getStandardModel(final double lambda) { /** Create a new Marini-Murray model using a standard atmosphere model. * *

                + *
              • altitude: 0m
              • *
              • temperature: 20 degree Celsius
              • *
              • pressure: 1013.25 mbar
              • *
              • humidity: 50%
              • @@ -123,18 +126,28 @@ public static MariniMurrayModel getStandardModel(final double lambda) { * @since 12.1 */ public static MariniMurrayModel getStandardModel(final double lambda, final Unit lambdaUnits) { + final double h = 0.0; final double p = TroposphericModelUtils.HECTO_PASCAL.toSI(1013.25); final double t = 273.15 + 20; final double rh = 0.5; final PressureTemperatureHumidity pth = - new PressureTemperatureHumidity(p, t, new CIPM2007().waterVaporPressure(p, t, rh)); + new PressureTemperatureHumidity(h, p, t, new CIPM2007().waterVaporPressure(p, t, rh)); return new MariniMurrayModel(new ConstantPressureTemperatureHumidityProvider(pth), lambda, TroposphericModelUtils.NANO_M); } + /** {@inheritDoc} */ + @Override + @Deprecated + public double pathDelay(final double elevation, final GeodeticPoint point, + final double[] parameters, final AbsoluteDate date) { + return pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, parameters, date); + } + /** {@inheritDoc} */ @Override public double pathDelay(final double elevation, final GeodeticPoint point, + final PressureTemperatureHumidity weather, final double[] parameters, final AbsoluteDate date) { final PressureTemperatureHumidity pth = pthProvider.getWeatherParamerers(point, date); @@ -157,7 +170,21 @@ public double pathDelay(final double elevation, final GeodeticPoint point, /** {@inheritDoc} */ @Override - public > T pathDelay(final T elevation, final FieldGeodeticPoint point, + @Deprecated + public > T pathDelay(final T elevation, + final FieldGeodeticPoint point, + final T[] parameters, + final FieldAbsoluteDate date) { + return pathDelay(elevation, point, + new FieldPressureTemperatureHumidity<>(date.getField(), TroposphericModelUtils.STANDARD_ATMOSPHERE), + parameters, date); + } + + /** {@inheritDoc} */ + @Override + public > T pathDelay(final T elevation, + final FieldGeodeticPoint point, + final FieldPressureTemperatureHumidity weather, final T[] parameters, final FieldAbsoluteDate date) { final FieldPressureTemperatureHumidity pth = pthProvider.getWeatherParamerers(point, date); diff --git a/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java b/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java index 74b768f013..44126d8989 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java @@ -47,7 +47,8 @@ * * @author Bryan Cazabonne */ -public class MendesPavlisModel implements DiscreteTroposphericModel, MappingFunction { +@SuppressWarnings("deprecation") +public class MendesPavlisModel implements DiscreteTroposphericModel, TroposphericModel, MappingFunction { /** Coefficients for the dispertion equation for the hydrostatic component [µm-2]. */ private static final double[] K_COEFFICIENTS = { @@ -90,7 +91,8 @@ public class MendesPavlisModel implements DiscreteTroposphericModel, MappingFunc @Deprecated public MendesPavlisModel(final double t0, final double p0, final double rh, final double lambda) { - this(new ConstantPressureTemperatureHumidityProvider(new PressureTemperatureHumidity(TroposphericModelUtils.HECTO_PASCAL.toSI(p0), + this(new ConstantPressureTemperatureHumidityProvider(new PressureTemperatureHumidity(0, + TroposphericModelUtils.HECTO_PASCAL.toSI(p0), t0, new CIPM2007(). waterVaporPressure(TroposphericModelUtils.HECTO_PASCAL.toSI(p0), @@ -153,6 +155,7 @@ public static MendesPavlisModel getStandardModel(final double lambda) { /** Create a new Mendes-Pavlis model using a standard atmosphere model. * *
                  + *
                • altitude: 0m
                • *
                • temperature: 18 degree Celsius
                • *
                • pressure: 1013.25 hPa
                • *
                • humidity: 50%
                • @@ -165,17 +168,27 @@ public static MendesPavlisModel getStandardModel(final double lambda) { * @since 12.1 */ public static MendesPavlisModel getStandardModel(final double lambda, final Unit lambdaUnits) { + final double h = 0; final double p = TroposphericModelUtils.HECTO_PASCAL.toSI(1013.25); final double t = 273.15 + 18; final double rh = 0.5; - final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(p, t, new CIPM2007().waterVaporPressure(p, t, rh)); + final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(h, p, t, new CIPM2007().waterVaporPressure(p, t, rh)); return new MendesPavlisModel(new ConstantPressureTemperatureHumidityProvider(pth), lambda, lambdaUnits); } + /** {@inheritDoc} */ + @Override + @Deprecated + public double pathDelay(final double elevation, final GeodeticPoint point, + final double[] parameters, final AbsoluteDate date) { + return pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, parameters, date); + } + /** {@inheritDoc} */ @Override public double pathDelay(final double elevation, final GeodeticPoint point, + final PressureTemperatureHumidity weather, final double[] parameters, final AbsoluteDate date) { // Zenith delay final double[] zenithDelay = computeZenithDelay(point, parameters, date); @@ -185,10 +198,21 @@ public double pathDelay(final double elevation, final GeodeticPoint point, return zenithDelay[0] * mappingFunction[0] + zenithDelay[1] * mappingFunction[1]; } + /** {@inheritDoc} */ + @Override + @Deprecated + public > T pathDelay(final T elevation, final FieldGeodeticPoint point, + final T[] parameters, final FieldAbsoluteDate date) { + return pathDelay(elevation, point, + new FieldPressureTemperatureHumidity<>(date.getField(), TroposphericModelUtils.STANDARD_ATMOSPHERE), + parameters, date); + } + /** {@inheritDoc} */ @Override public > T pathDelay(final T elevation, final FieldGeodeticPoint point, - final T[] parameters, final FieldAbsoluteDate date) { + final FieldPressureTemperatureHumidity weather, + final T[] parameters, final FieldAbsoluteDate date) { // Zenith delay final T[] delays = computeZenithDelay(point, parameters, date); // Mapping function diff --git a/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java b/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java index 44e59e4198..1734eb9436 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java @@ -35,7 +35,7 @@ import org.orekit.errors.OrekitMessages; import org.orekit.models.earth.weather.ConstantPressureTemperatureHumidityProvider; import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; -import org.orekit.models.earth.weather.HeightDependentPressureTemperatureHumidityProvider; +import org.orekit.models.earth.weather.HeightDependentPressureTemperatureHumidityConverter; import org.orekit.models.earth.weather.PressureTemperatureHumidity; import org.orekit.models.earth.weather.PressureTemperatureHumidityProvider; import org.orekit.models.earth.weather.water.Wang1988; @@ -66,7 +66,7 @@ * @see "Guochang Xu, GPS - Theory, Algorithms and Applications, Springer, 2007" * @since 12.1 */ -public class ModifiedSaastamoinenModel implements DiscreteTroposphericModel { +public class ModifiedSaastamoinenModel implements TroposphericModel { /** Default file name for δR correction term table. */ public static final String DELTA_R_FILE_NAME = "^saastamoinen-correction\\.txt$"; @@ -103,8 +103,11 @@ public class ModifiedSaastamoinenModel implements DiscreteTroposphericModel { /** Interpolation function for the delta R correction term. */ private final BilinearInterpolatingFunction deltaRFunction; - /** Height dependent provider for pressure, temperature and humidity. */ - private HeightDependentPressureTemperatureHumidityProvider pthProvider; + /** Provider for atmospheric pressure, temperature and humidity at reference altitude. */ + private final PressureTemperatureHumidityProvider pth0Provider; + + /** Height dependent converter for pressure, temperature and humidity. */ + private HeightDependentPressureTemperatureHumidityConverter converter; /** Lowest acceptable elevation angle [rad]. */ private double lowElevationThreshold; @@ -113,31 +116,28 @@ public class ModifiedSaastamoinenModel implements DiscreteTroposphericModel { * Create a new Saastamoinen model for the troposphere using the given environmental * conditions and table from the reference book. * - * @param h0 reference altitude * @param pth0Provider provider for atmospheric pressure, temperature and humidity at reference altitude - * @see #ModifiedSaastamoinenModel(double, PressureTemperatureHumidityProvider, String, DataProvidersManager) + * @see #ModifiedSaastamoinenModel(PressureTemperatureHumidityProvider, String, DataProvidersManager) */ @DefaultDataContext - public ModifiedSaastamoinenModel(final double h0, final PressureTemperatureHumidityProvider pth0Provider) { - this(h0, pth0Provider, defaultDeltaR()); + public ModifiedSaastamoinenModel(final PressureTemperatureHumidityProvider pth0Provider) { + this(pth0Provider, defaultDeltaR()); } /** Create a new Saastamoinen model for the troposphere using the given * environmental conditions. This constructor uses the {@link DataContext#getDefault() * default data context} if {@code deltaRFileName != null}. * - * @param h0 reference altitude * @param pth0Provider provider for atmospheric pressure, temperature and humidity at reference altitude * @param deltaRFileName regular expression for filename containing δR * correction term table (typically {@link #DELTA_R_FILE_NAME}), if null * default values from the reference book are used - * @see #ModifiedSaastamoinenModel(double, PressureTemperatureHumidityProvider, String, DataProvidersManager) + * @see #ModifiedSaastamoinenModel(PressureTemperatureHumidityProvider, String, DataProvidersManager) */ @DefaultDataContext - public ModifiedSaastamoinenModel(final double h0, - final PressureTemperatureHumidityProvider pth0Provider, + public ModifiedSaastamoinenModel(final PressureTemperatureHumidityProvider pth0Provider, final String deltaRFileName) { - this(h0, pth0Provider, deltaRFileName, + this(pth0Provider, deltaRFileName, DataContext.getDefault().getDataProvidersManager()); } @@ -145,18 +145,16 @@ public ModifiedSaastamoinenModel(final double h0, * environmental conditions. This constructor allows the user to specify the source of * of the δR file. * - * @param h0 reference altitude * @param pth0Provider provider for atmospheric pressure, temperature and humidity at reference altitude * @param deltaRFileName regular expression for filename containing δR * correction term table (typically {@link #DELTA_R_FILE_NAME}), if null * default values from the reference book are used * @param dataProvidersManager provides access to auxiliary data. */ - public ModifiedSaastamoinenModel(final double h0, - final PressureTemperatureHumidityProvider pth0Provider, + public ModifiedSaastamoinenModel(final PressureTemperatureHumidityProvider pth0Provider, final String deltaRFileName, final DataProvidersManager dataProvidersManager) { - this(h0, pth0Provider, + this(pth0Provider, deltaRFileName == null ? defaultDeltaR() : loadDeltaR(deltaRFileName, dataProvidersManager)); @@ -164,18 +162,13 @@ public ModifiedSaastamoinenModel(final double h0, /** Create a new Saastamoinen model. * - * @param h0 reference altitude * @param pth0Provider provider for atmospheric pressure, temperature and humidity at reference altitude * @param deltaR δR correction term function */ - private ModifiedSaastamoinenModel(final double h0, - final PressureTemperatureHumidityProvider pth0Provider, + private ModifiedSaastamoinenModel(final PressureTemperatureHumidityProvider pth0Provider, final BilinearInterpolatingFunction deltaR) { - final double hMin = X_VALUES_FOR_B[0]; - final double hMax = X_VALUES_FOR_B[X_VALUES_FOR_B.length - 1]; - this.pthProvider = new HeightDependentPressureTemperatureHumidityProvider(hMin, hMax, - hMin, pth0Provider, - WATER); + this.pth0Provider = pth0Provider; + this.converter = new HeightDependentPressureTemperatureHumidityConverter(WATER); this.deltaRFunction = deltaR; this.lowElevationThreshold = DEFAULT_LOW_ELEVATION_THRESHOLD; } @@ -183,6 +176,7 @@ private ModifiedSaastamoinenModel(final double h0, /** Create a new Saastamoinen model using a standard atmosphere model. * *
                    + *
                  • altitude: 0m
                  • *
                  • temperature: 18 degree Celsius
                  • *
                  • pressure: 1013.25 mbar
                  • *
                  • humidity: 50%
                  • @@ -193,16 +187,25 @@ private ModifiedSaastamoinenModel(final double h0, */ @DefaultDataContext public static ModifiedSaastamoinenModel getStandardModel() { + final double altitude = 0; final double pressure = TroposphericModelUtils.HECTO_PASCAL.toSI(1013.25); final double temperature = 273.15 + 18; final double humidity = 0.5; - final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(pressure, + final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(altitude, + pressure, temperature, WATER.waterVaporPressure(pressure, temperature, humidity)); final PressureTemperatureHumidityProvider pth0Provider = new ConstantPressureTemperatureHumidityProvider(pth); - return new ModifiedSaastamoinenModel(X_VALUES_FOR_B[0], pth0Provider); + return new ModifiedSaastamoinenModel(pth0Provider); + } + + /** Get provider for atmospheric pressure, temperature and humidity at reference altitude. + * @return provider for atmospheric pressure, temperature and humidity at reference altitude + */ + public PressureTemperatureHumidityProvider getPth0Provider() { + return pth0Provider; } /** {@inheritDoc} @@ -220,13 +223,14 @@ public static ModifiedSaastamoinenModel getStandardModel() { */ @Override public double pathDelay(final double elevation, final GeodeticPoint point, + final PressureTemperatureHumidity weather, final double[] parameters, final AbsoluteDate date) { - final PressureTemperatureHumidity pth = pthProvider.getWeatherParamerers(point, date); - // limit the height to model range - final double fixedHeight = FastMath.min(FastMath.max(point.getAltitude(), pthProvider.getHMin()), - pthProvider.getHMax()) - pthProvider.getH0(); + final double fixedHeight = FastMath.min(FastMath.max(point.getAltitude(), X_VALUES_FOR_B[0]), + X_VALUES_FOR_B[X_VALUES_FOR_B.length - 1]); + + final PressureTemperatureHumidity pth = converter.convert(weather, fixedHeight); // interpolate the b correction term final double B = B_FUNCTION.value(fixedHeight); @@ -263,21 +267,23 @@ public double pathDelay(final double elevation, final GeodeticPoint point, */ @Override public > T pathDelay(final T elevation, final FieldGeodeticPoint point, + final FieldPressureTemperatureHumidity weather, final T[] parameters, final FieldAbsoluteDate date) { - final FieldPressureTemperatureHumidity pth = pthProvider.getWeatherParamerers(point, date); + // limit the height to model range + final T fixedHeight = FastMath.min(FastMath.max(point.getAltitude(), X_VALUES_FOR_B[0]), + X_VALUES_FOR_B[X_VALUES_FOR_B.length - 1]); + + final FieldPressureTemperatureHumidity pth = converter.convert(weather, fixedHeight); final Field field = date.getField(); final T zero = field.getZero(); - // limit the height to model range - final T fixedHeight = FastMath.min(FastMath.max(point.getAltitude(), pthProvider.getHMin()), - pthProvider.getHMax()).subtract(pthProvider.getH0()); // interpolate the b correction term final T B = B_FUNCTION.value(fixedHeight); // calculate the zenith angle from the elevation - final T z = FastMath.abs(FastMath.max(elevation, zero.add(lowElevationThreshold)).negate(). + final T z = FastMath.abs(FastMath.max(elevation, zero.newInstance(lowElevationThreshold)).negate(). add(zero.getPi().multiply(0.5))); // get correction factor diff --git a/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java b/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java index 37964131ce..dad6181044 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java @@ -16,19 +16,24 @@ */ package org.orekit.models.earth.troposphere; +import org.hipparchus.CalculusFieldElement; import org.orekit.annotation.DefaultDataContext; +import org.orekit.bodies.FieldGeodeticPoint; +import org.orekit.bodies.GeodeticPoint; import org.orekit.data.DataContext; import org.orekit.data.DataProvidersManager; import org.orekit.models.earth.weather.ConstantPressureTemperatureHumidityProvider; import org.orekit.models.earth.weather.PressureTemperatureHumidity; import org.orekit.models.earth.weather.water.Wang1988; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; /** The modified Saastamoinen model. * @author Luc Maisonobe * @deprecated as of 12.1, replaced by {@link ModifiedSaastamoinenModel} */ @Deprecated -public class SaastamoinenModel extends ModifiedSaastamoinenModel { +public class SaastamoinenModel extends ModifiedSaastamoinenModel implements DiscreteTroposphericModel { /** Default file name for δR correction term table. */ public static final String DELTA_R_FILE_NAME = ModifiedSaastamoinenModel.DELTA_R_FILE_NAME; @@ -43,7 +48,7 @@ public class SaastamoinenModel extends ModifiedSaastamoinenModel { * @param t0 the temperature at the station [K] * @param p0 the atmospheric pressure at the station [mbar] * @param r0 the humidity at the station [fraction] (50% → 0.5) - * @see #ModifiedSaastamoinenModel(double, double, double, String, DataProvidersManager) + * @see #SaastamoinenModel(double, double, double, String, DataProvidersManager) * @since 10.1 */ public SaastamoinenModel(final double t0, final double p0, final double r0) { @@ -61,7 +66,7 @@ public SaastamoinenModel(final double t0, final double p0, final double r0) { * correction term table (typically {@link #DELTA_R_FILE_NAME}), if null * default values from the reference book are used * @since 7.1 - * @see #ModifiedSaastamoinenModel(double, double, double, String, DataProvidersManager) + * @see #SaastamoinenModel(double, double, double, String, DataProvidersManager) */ @DefaultDataContext public SaastamoinenModel(final double t0, final double p0, final double r0, @@ -87,8 +92,8 @@ public SaastamoinenModel(final double t0, final double r0, final String deltaRFileName, final DataProvidersManager dataProvidersManager) { - super(0.0, - new ConstantPressureTemperatureHumidityProvider(new PressureTemperatureHumidity(TroposphericModelUtils.HECTO_PASCAL.toSI(p0), + super(new ConstantPressureTemperatureHumidityProvider(new PressureTemperatureHumidity(0.0, + TroposphericModelUtils.HECTO_PASCAL.toSI(p0), t0, new Wang1988(). waterVaporPressure(TroposphericModelUtils.HECTO_PASCAL.toSI(p0), @@ -100,6 +105,7 @@ public SaastamoinenModel(final double t0, /** Create a new Saastamoinen model using a standard atmosphere model. * *
                      + *
                    • altitude: 0m
                    • *
                    • temperature: 18 degree Celsius *
                    • pressure: 1013.25 mbar *
                    • humidity: 50% @@ -111,4 +117,24 @@ public static SaastamoinenModel getStandardModel() { return new SaastamoinenModel(273.16 + 18, 1013.25, 0.5); } + /** {@inheritDoc} */ + @Override + @Deprecated + public double pathDelay(final double elevation, final GeodeticPoint point, + final double[] parameters, final AbsoluteDate date) { + return pathDelay(elevation, point, getPth0Provider().getWeatherParamerers(point, date), parameters, date); + } + + /** {@inheritDoc} */ + @Override + @Deprecated + public > T pathDelay(final T elevation, + final FieldGeodeticPoint point, + final T[] parameters, + final FieldAbsoluteDate date) { + return pathDelay(elevation, point, + getPth0Provider().getWeatherParamerers(point, date), + parameters, date); + } + } diff --git a/src/main/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModel.java b/src/main/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModel.java new file mode 100644 index 0000000000..c473d7f8c3 --- /dev/null +++ b/src/main/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModel.java @@ -0,0 +1,273 @@ +/* Copyright 2002-2023 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import java.util.ArrayList; +import java.util.List; + +import org.hipparchus.CalculusFieldElement; +import org.hipparchus.util.MathArrays; +import org.orekit.annotation.DefaultDataContext; +import org.orekit.bodies.FieldGeodeticPoint; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; +import org.orekit.models.earth.weather.PressureTemperatureHumidity; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; +import org.orekit.time.TimeScale; +import org.orekit.time.TimeScalesFactory; +import org.orekit.utils.ParameterDriver; +import org.orekit.utils.TimeSpanMap; +import org.orekit.utils.TimeSpanMap.Span; + +/** + * Time span estimated tropospheric model. + *

                      + * This class is closely related to {@link org.orekit.models.earth.troposphere EstimatedTroposphericModel} class.
                      + * The difference is that it has a {@link TimeSpanMap} of {@link EstimatedTroposphericModel} objects as attribute.
                      + * The idea behind this model is to allow the user to design a tropospheric model that can see its physical parameters + * (total zenith delay) change with time, at dates chosen by the user.
                      + *

                      + * @author Bryan Cazabonne + * @since 10.2 + */ +public class TimeSpanEstimatedModel implements TroposphericModel { + + /** Prefix for dates before in the tropospheric parameter drivers' name. */ + public static final String DATE_BEFORE = " - Before "; + + /** Prefix for dates after in the tropospheric parameter drivers' name. */ + public static final String DATE_AFTER = " - After "; + + /** Time scale for transition dates. */ + private final TimeScale timeScale; + + /** It contains all the models use for the whole period of measurements. */ + private final TimeSpanMap troposphericModelMap; + + /** + * Constructor with default UTC time scale. + * @param model the initial model which going to be used for all the models initialization. + */ + @DefaultDataContext + public TimeSpanEstimatedModel(final EstimatedModel model) { + this(model, TimeScalesFactory.getUTC()); + } + + /** + * Constructor with default UTC time scale. + * @param model the initial model which going to be used for all the models initialization. + * @param timeScale timeScale Time scale used for the default names of the tropospheric parameter drivers + */ + public TimeSpanEstimatedModel(final EstimatedModel model, final TimeScale timeScale) { + this.troposphericModelMap = new TimeSpanMap<>(model); + this.timeScale = timeScale; + } + + /** {@inheritDoc} + *

                      + * All the parameter drivers of all Estimated models are returned in an array. + * Models are ordered chronologically. + *

                      + */ + @Override + public List getParametersDrivers() { + + // Get all transitions from the TimeSpanMap + final List listTroposphericParameterDrivers = new ArrayList<>(); + + // Loop on the spans + for (Span span = getFirstSpan(); span != null; span = span.next()) { + // Add all the parameter drivers of each span + for (ParameterDriver tropoDriver : span.getData().getParametersDrivers()) { + // Add the driver only if the name does not exist already + if (!findByName(listTroposphericParameterDrivers, tropoDriver.getName())) { + listTroposphericParameterDrivers.add(tropoDriver); + } + } + } + + // Return an array of parameter drivers with no duplicated name + return listTroposphericParameterDrivers; + + } + + /** Add an EstimatedTroposphericModel entry valid before a limit date.
                      + * Using addTroposphericValidBefore(entry, t) will make entry + * valid in ]-∞, t[ (note the open bracket). + * @param model EstimatedTroposphericModel entry + * @param latestValidityDate date before which the entry is valid + * (must be different from all dates already used for transitions) + */ + public void addTroposphericModelValidBefore(final EstimatedModel model, final AbsoluteDate latestValidityDate) { + troposphericModelMap.addValidBefore(changeTroposphericParameterDriversNames(model, + latestValidityDate, + DATE_BEFORE), + latestValidityDate, false); + } + + /** Add a EstimatedTroposphericModel entry valid after a limit date.
                      + * Using addTroposphericModelValidAfter(entry, t) will make entry + * valid in [t, +∞[ (note the closed bracket). + * @param model EstimatedTroposphericModel entry + * @param earliestValidityDate date after which the entry is valid + * (must be different from all dates already used for transitions) + */ + public void addTroposphericModelValidAfter(final EstimatedModel model, final AbsoluteDate earliestValidityDate) { + troposphericModelMap.addValidAfter(changeTroposphericParameterDriversNames(model, + earliestValidityDate, + DATE_AFTER), + earliestValidityDate, false); + } + + /** Get the {@link EstimatedTroposphericModel} model valid at a date. + * @param date the date of validity + * @return the EstimatedTroposphericModel model valid at date + */ + public EstimatedModel getTroposphericModel(final AbsoluteDate date) { + return troposphericModelMap.get(date); + } + + /** Get the first {@link Span time span} of the tropospheric model time span map. + * @return the first {@link Span time span} of the tropospheric model time span map + * @since 11.1 + */ + public Span getFirstSpan() { + return troposphericModelMap.getFirstSpan(); + } + + /** Extract the proper parameter drivers' values from the array in input of the + * {@link #pathDelay(double, GeodeticPoint, double[], AbsoluteDate) pathDelay} method. + * Parameters are filtered given an input date. + * @param parameters the input parameters array + * @param date the date + * @return the parameters given the date + */ + public double[] extractParameters(final double[] parameters, final AbsoluteDate date) { + + // Get the tropospheric parameter drivers of the date + final List troposphericParameterDriver = getTroposphericModel(date).getParametersDrivers(); + + // Find out the indexes of the parameters in the whole array of parameters + final List allTroposphericParameters = getParametersDrivers(); + final double[] outParameters = new double[troposphericParameterDriver.size()]; + int index = 0; + for (int i = 0; i < allTroposphericParameters.size(); i++) { + final String driverName = allTroposphericParameters.get(i).getName(); + for (ParameterDriver tropoDriver : troposphericParameterDriver) { + if (tropoDriver.getName().equals(driverName)) { + outParameters[index++] = parameters[i]; + } + } + } + return outParameters; + } + + /** Extract the proper parameter drivers' values from the array in input of the + * {@link #pathDelay(double, GeodeticPoint, double[], AbsoluteDate) pathDelay} method. + * Parameters are filtered given an input date. + * @param parameters the input parameters array + * @param date the date + * @param extends CalculusFieldElements + * @return the parameters given the date + */ + public > T[] extractParameters(final T[] parameters, + final FieldAbsoluteDate date) { + + // Get the tropospheric parameter drivers of the date + final List troposphericParameterDriver = getTroposphericModel(date.toAbsoluteDate()).getParametersDrivers(); + + // Find out the indexes of the parameters in the whole array of parameters + final List allTroposphericParameters = getParametersDrivers(); + final T[] outParameters = MathArrays.buildArray(date.getField(), troposphericParameterDriver.size()); + int index = 0; + for (int i = 0; i < allTroposphericParameters.size(); i++) { + final String driverName = allTroposphericParameters.get(i).getName(); + for (ParameterDriver tropoDriver : troposphericParameterDriver) { + if (tropoDriver.getName().equals(driverName)) { + outParameters[index++] = parameters[i]; + } + } + } + return outParameters; + } + + /** {@inheritDoc} */ + @Override + public double pathDelay(final double elevation, final GeodeticPoint point, + final PressureTemperatureHumidity weather, + final double[] parameters, final AbsoluteDate date) { + // Extract the proper parameters valid at date from the input array + final double[] extractedParameters = extractParameters(parameters, date); + // Compute and return the path delay + return getTroposphericModel(date).pathDelay(elevation, point, weather, + extractedParameters, date); + } + + /** {@inheritDoc} */ + @Override + public > T pathDelay(final T elevation, final FieldGeodeticPoint point, + final FieldPressureTemperatureHumidity weather, + final T[] parameters, final FieldAbsoluteDate date) { + // Extract the proper parameters valid at date from the input array + final T[] extractedParameters = extractParameters(parameters, date); + // Compute and return the path delay + return getTroposphericModel(date.toAbsoluteDate()).pathDelay(elevation, point, weather, + extractedParameters, date); + } + + /** Find if a parameter driver with a given name already exists in a list of parameter drivers. + * @param driversList the list of parameter drivers + * @param name the parameter driver's name to filter with + * @return true if the name was found, false otherwise + */ + private boolean findByName(final List driversList, final String name) { + for (final ParameterDriver driver : driversList) { + if (driver.getName().equals(name)) { + return true; + } + } + return false; + } + + /** Change the parameter drivers names of a {@link EstimatedTroposphericModel} model, if needed. + *

                      + * This is done to avoid that several parameter drivers have the same name.
                      + * It is done only if the user hasn't modify the EstimatedTroposphericModel parameter drivers default names. + *

                      + * @param troposphericModel the EstimatedTroposphericModel model + * @param date the date used in the parameter driver's name + * @param datePrefix the date prefix used in the parameter driver's name + * @return the EstimatedTroposphericModel with its drivers' names changed + */ + private EstimatedModel changeTroposphericParameterDriversNames(final EstimatedModel troposphericModel, + final AbsoluteDate date, + final String datePrefix) { + // Loop on the parameter drivers of the EstimatedTroposphericModel model + for (ParameterDriver driver: troposphericModel.getParametersDrivers()) { + final String driverName = driver.getName(); + + // If the name is the default name for EstimatedTroposphericModel parameter drivers + // Modify the name to add the prefix and the date + if (driverName.equals(EstimatedTroposphericModel.TOTAL_ZENITH_DELAY)) { + driver.setName(driverName + datePrefix + date.toString(timeScale)); + } + } + return troposphericModel; + } + +} diff --git a/src/main/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedTroposphericModel.java b/src/main/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedTroposphericModel.java index e2abe4a1d3..927f546f0e 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedTroposphericModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedTroposphericModel.java @@ -42,7 +42,9 @@ *

                      * @author Bryan Cazabonne * @since 10.2 + * @deprecated as of 12.1, replaced by {@link TimeSpanEstimatedModel} */ +@Deprecated public class TimeSpanEstimatedTroposphericModel implements DiscreteTroposphericModel { /** Prefix for dates before in the tropospheric parameter drivers' name. */ diff --git a/src/main/java/org/orekit/models/earth/troposphere/TroposphericModel.java b/src/main/java/org/orekit/models/earth/troposphere/TroposphericModel.java new file mode 100644 index 0000000000..f42008dd7f --- /dev/null +++ b/src/main/java/org/orekit/models/earth/troposphere/TroposphericModel.java @@ -0,0 +1,66 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import org.hipparchus.CalculusFieldElement; +import org.orekit.bodies.FieldGeodeticPoint; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; +import org.orekit.models.earth.weather.PressureTemperatureHumidity; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; +import org.orekit.utils.ParameterDriversProvider; + +/** Defines a tropospheric model, used to calculate the path delay imposed to + * electro-magnetic signals between an orbital satellite and a ground station. + * @author Luc Maisonobe + * @since 12.1 + */ +public interface TroposphericModel extends ParameterDriversProvider { + + /** Calculates the tropospheric path delay for the signal path from a ground + * station to a satellite. + * + * @param elevation the elevation of the satellite, in radians + * @param point station location + * @param weather weather parameters + * (could be set to {@link TroposphericModelUtils#STANDARD_ATMOSPHERE_PROVIDER} + * for constant default values) + * @param parameters tropospheric model parameters + * @param date current date + * @return the path delay due to the troposphere in m + */ + double pathDelay(double elevation, GeodeticPoint point, PressureTemperatureHumidity weather, + double[] parameters, AbsoluteDate date); + + /** Calculates the tropospheric path delay for the signal path from a ground + * station to a satellite. + * + * @param type of the elements + * @param elevation the elevation of the satellite, in radians + * @param point station location + * @param weather weather parameters + * (could be set to {@link TroposphericModelUtils#STANDARD_ATMOSPHERE_PROVIDER} + * for constant default values) + * @param parameters tropospheric model parameters at current date + * @param date current date + * @return the path delay due to the troposphere in m + */ + > T pathDelay(T elevation, FieldGeodeticPoint point, + FieldPressureTemperatureHumidity weather, + T[] parameters, FieldAbsoluteDate date); +} diff --git a/src/main/java/org/orekit/models/earth/troposphere/TroposphericModelAdapter.java b/src/main/java/org/orekit/models/earth/troposphere/TroposphericModelAdapter.java new file mode 100644 index 0000000000..5397e64088 --- /dev/null +++ b/src/main/java/org/orekit/models/earth/troposphere/TroposphericModelAdapter.java @@ -0,0 +1,78 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import java.util.List; + +import org.hipparchus.CalculusFieldElement; +import org.orekit.bodies.FieldGeodeticPoint; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; +import org.orekit.models.earth.weather.PressureTemperatureHumidity; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; +import org.orekit.utils.ParameterDriver; + +/** Adapter between {@link DiscreteTroposphericModel} and {@link TroposphericModel}. + *

                      + * This class is a temporary adapter, it will be removed when + * {@link DiscreteTroposphericModel} is removed. + *

                      + * @author Luc Maisonobe + * @since 12.1 + * @deprecated temporary adapter to be removed when {@link DiscreteTroposphericModel} is removed + */ +@Deprecated +public class TroposphericModelAdapter implements TroposphericModel { + + /** Underlying model. */ + private final DiscreteTroposphericModel model; + + /** Simple constructor. + * @param model underlying model + */ + public TroposphericModelAdapter(final DiscreteTroposphericModel model) { + this.model = model; + } + + /** {@inheritDoc} */ + @Override + public double pathDelay(final double elevation, + final GeodeticPoint point, + final PressureTemperatureHumidity weather, + final double[] parameters, + final AbsoluteDate date) { + return model.pathDelay(elevation, point, parameters, date); + } + + /** {@inheritDoc} */ + @Override + public > T pathDelay(final T elevation, + final FieldGeodeticPoint point, + final FieldPressureTemperatureHumidity weather, + final T[] parameters, + final FieldAbsoluteDate date) { + return model.pathDelay(elevation, point, parameters, date); + } + + /** {@inheritDoc} */ + @Override + public List getParametersDrivers() { + return model.getParametersDrivers(); + } + +} diff --git a/src/main/java/org/orekit/models/earth/troposphere/TroposphericModelUtils.java b/src/main/java/org/orekit/models/earth/troposphere/TroposphericModelUtils.java index c56b4a89ad..2e6b2efce3 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/TroposphericModelUtils.java +++ b/src/main/java/org/orekit/models/earth/troposphere/TroposphericModelUtils.java @@ -19,6 +19,9 @@ import org.hipparchus.Field; import org.hipparchus.CalculusFieldElement; import org.hipparchus.util.FastMath; +import org.orekit.models.earth.weather.ConstantPressureTemperatureHumidityProvider; +import org.orekit.models.earth.weather.PressureTemperatureHumidity; +import org.orekit.models.earth.weather.PressureTemperatureHumidityProvider; import org.orekit.utils.units.Unit; /** @@ -43,6 +46,25 @@ public class TroposphericModelUtils { */ public static final Unit HECTO_PASCAL = Unit.parse("hPa"); + /** Standard atmosphere. + *

                        + *
                      • altitude: 0m
                      • + *
                      • temperature: 20 degree Celsius
                      • + *
                      • pressure: 1013.25 mbar
                      • + *
                      • humidity: 50%
                      • + *
                      + * @see #STANDARD_ATMOSPHERE_PROVIDER + * @since 12.1 + */ + public static final PressureTemperatureHumidity STANDARD_ATMOSPHERE = + new PressureTemperatureHumidity(0.0, HECTO_PASCAL.toSI(1013.25), 273.15 + 20, 0.5); + + /** Provider for {@link #STANDARD_ATMOSPHERE standard atmosphere}. + * @since 12.1 + */ + public static final PressureTemperatureHumidityProvider STANDARD_ATMOSPHERE_PROVIDER = + new ConstantPressureTemperatureHumidityProvider(STANDARD_ATMOSPHERE); + /** * Private constructor as class is a utility. */ diff --git a/src/main/java/org/orekit/models/earth/troposphere/ViennaOneModel.java b/src/main/java/org/orekit/models/earth/troposphere/ViennaOneModel.java index 0df80dc35f..e94d0aa5a3 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/ViennaOneModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/ViennaOneModel.java @@ -19,14 +19,16 @@ import java.util.Collections; import java.util.List; -import org.hipparchus.Field; import org.hipparchus.CalculusFieldElement; +import org.hipparchus.Field; import org.hipparchus.util.FastMath; import org.hipparchus.util.MathArrays; import org.orekit.annotation.DefaultDataContext; import org.orekit.bodies.FieldGeodeticPoint; import org.orekit.bodies.GeodeticPoint; import org.orekit.data.DataContext; +import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; +import org.orekit.models.earth.weather.PressureTemperatureHumidity; import org.orekit.time.AbsoluteDate; import org.orekit.time.DateTimeComponents; import org.orekit.time.FieldAbsoluteDate; @@ -48,7 +50,8 @@ * * @author Bryan Cazabonne */ -public class ViennaOneModel implements DiscreteTroposphericModel, MappingFunction { +@SuppressWarnings("deprecation") +public class ViennaOneModel implements DiscreteTroposphericModel, TroposphericModel, MappingFunction { /** The a coefficient for the computation of the wet and hydrostatic mapping functions.*/ private final double[] coefficientsA; @@ -92,8 +95,17 @@ public ViennaOneModel(final double[] coefficientA, /** {@inheritDoc} */ @Override + @Deprecated public double pathDelay(final double elevation, final GeodeticPoint point, final double[] parameters, final AbsoluteDate date) { + return pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, parameters, date); + } + + /** {@inheritDoc} */ + @Override + public double pathDelay(final double elevation, final GeodeticPoint point, + final PressureTemperatureHumidity weather, + final double[] parameters, final AbsoluteDate date) { // zenith delay final double[] delays = computeZenithDelay(point, parameters, date); // mapping function @@ -104,8 +116,19 @@ public double pathDelay(final double elevation, final GeodeticPoint point, /** {@inheritDoc} */ @Override + @Deprecated public > T pathDelay(final T elevation, final FieldGeodeticPoint point, final T[] parameters, final FieldAbsoluteDate date) { + return pathDelay(elevation, point, + new FieldPressureTemperatureHumidity<>(date.getField(), TroposphericModelUtils.STANDARD_ATMOSPHERE), + parameters, date); + } + + /** {@inheritDoc} */ + @Override + public > T pathDelay(final T elevation, final FieldGeodeticPoint point, + final FieldPressureTemperatureHumidity weather, + final T[] parameters, final FieldAbsoluteDate date) { // zenith delay final T[] delays = computeZenithDelay(point, parameters, date); // mapping function diff --git a/src/main/java/org/orekit/models/earth/troposphere/ViennaThreeModel.java b/src/main/java/org/orekit/models/earth/troposphere/ViennaThreeModel.java index be0ed78b61..1498deb727 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/ViennaThreeModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/ViennaThreeModel.java @@ -29,6 +29,8 @@ import org.orekit.bodies.FieldGeodeticPoint; import org.orekit.bodies.GeodeticPoint; import org.orekit.data.DataContext; +import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; +import org.orekit.models.earth.weather.PressureTemperatureHumidity; import org.orekit.time.AbsoluteDate; import org.orekit.time.DateTimeComponents; import org.orekit.time.FieldAbsoluteDate; @@ -56,7 +58,8 @@ * * @author Bryan Cazabonne */ -public class ViennaThreeModel implements DiscreteTroposphericModel, MappingFunction { +@SuppressWarnings("deprecation") +public class ViennaThreeModel implements DiscreteTroposphericModel, TroposphericModel, MappingFunction { /** The a coefficient for the computation of the wet and hydrostatic mapping functions.*/ private final double[] coefficientsA; @@ -270,8 +273,17 @@ public > T[] mappingFactors(final T elevation, /** {@inheritDoc} */ @Override + @Deprecated public double pathDelay(final double elevation, final GeodeticPoint point, final double[] parameters, final AbsoluteDate date) { + return pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, parameters, date); + } + + /** {@inheritDoc} */ + @Override + public double pathDelay(final double elevation, final GeodeticPoint point, + final PressureTemperatureHumidity weather, + final double[] parameters, final AbsoluteDate date) { // zenith delay final double[] delays = computeZenithDelay(point, parameters, date); // mapping function @@ -282,8 +294,19 @@ public double pathDelay(final double elevation, final GeodeticPoint point, /** {@inheritDoc} */ @Override + @Deprecated public > T pathDelay(final T elevation, final FieldGeodeticPoint point, final T[] parameters, final FieldAbsoluteDate date) { + return pathDelay(elevation, point, + new FieldPressureTemperatureHumidity<>(date.getField(), TroposphericModelUtils.STANDARD_ATMOSPHERE), + parameters, date); + } + + /** {@inheritDoc} */ + @Override + public > T pathDelay(final T elevation, final FieldGeodeticPoint point, + final FieldPressureTemperatureHumidity weather, + final T[] parameters, final FieldAbsoluteDate date) { // zenith delay final T[] delays = computeZenithDelay(point, parameters, date); // mapping function diff --git a/src/main/java/org/orekit/models/earth/weather/ConstantPressureTemperatureHumidityProvider.java b/src/main/java/org/orekit/models/earth/weather/ConstantPressureTemperatureHumidityProvider.java index 025701875a..f3d7f8bfd1 100644 --- a/src/main/java/org/orekit/models/earth/weather/ConstantPressureTemperatureHumidityProvider.java +++ b/src/main/java/org/orekit/models/earth/weather/ConstantPressureTemperatureHumidityProvider.java @@ -49,10 +49,7 @@ public PressureTemperatureHumidity getWeatherParamerers(final GeodeticPoint loca @Override public > FieldPressureTemperatureHumidity getWeatherParamerers(final FieldGeodeticPoint location, final FieldAbsoluteDate date) { - final T zero = date.getField().getZero(); - return new FieldPressureTemperatureHumidity<>(zero.newInstance(pth.getPressure()), - zero.newInstance(pth.getTemperature()), - zero.newInstance(pth.getWaterVaporPressure())); + return new FieldPressureTemperatureHumidity<>(date.getField(), pth); } } diff --git a/src/main/java/org/orekit/models/earth/weather/FieldPressureTemperature.java b/src/main/java/org/orekit/models/earth/weather/FieldPressureTemperature.java index cd836c8dca..e53c105cee 100644 --- a/src/main/java/org/orekit/models/earth/weather/FieldPressureTemperature.java +++ b/src/main/java/org/orekit/models/earth/weather/FieldPressureTemperature.java @@ -17,6 +17,7 @@ package org.orekit.models.earth.weather; import org.hipparchus.CalculusFieldElement; +import org.hipparchus.Field; /** Container for pressure and temperature. * @param type of the field elements @@ -25,6 +26,9 @@ */ public class FieldPressureTemperature> { + /** Altitude at which weather parameters have been computed. */ + private final T altitude; + /** Pressure (Pa). */ private final T pressure; @@ -32,12 +36,31 @@ public class FieldPressureTemperature> { private final T temperature; /** Simple constructor. + * @param altitude altitude at which weather parameters have been computed (m) * @param pressure pressure (Pa) * @param temperature temperature (Kelvin) */ - public FieldPressureTemperature(final T pressure, final T temperature) { - this.pressure = pressure; - this.temperature = temperature; + public FieldPressureTemperature(final T altitude, final T pressure, final T temperature) { + this.altitude = altitude; + this.pressure = pressure; + this.temperature = temperature; + } + + /** Simple constructor. + * @param field field to which elements belong + * @param weather regular weather parameters + */ + public FieldPressureTemperature(final Field field, final PressureTemperatureHumidity weather) { + this.altitude = field.getZero().newInstance(weather.getAltitude()); + this.pressure = field.getZero().newInstance(weather.getPressure()); + this.temperature = field.getZero().newInstance(weather.getTemperature()); + } + + /** Get altitude at which weather parameters have been computed. + * @return altitude at which weather parameters have been computed (m) + */ + public T getAltitude() { + return altitude; } /** Get pressure. diff --git a/src/main/java/org/orekit/models/earth/weather/FieldPressureTemperatureHumidity.java b/src/main/java/org/orekit/models/earth/weather/FieldPressureTemperatureHumidity.java index 2c5e4db534..b9b4492451 100644 --- a/src/main/java/org/orekit/models/earth/weather/FieldPressureTemperatureHumidity.java +++ b/src/main/java/org/orekit/models/earth/weather/FieldPressureTemperatureHumidity.java @@ -17,6 +17,7 @@ package org.orekit.models.earth.weather; import org.hipparchus.CalculusFieldElement; +import org.hipparchus.Field; /** Container for pressure, temperature, and humidity. * @param type of the field elements @@ -29,17 +30,28 @@ public class FieldPressureTemperatureHumidity> private final T waterVaporPressure; /** Simple constructor. + * @param altitude altitude at which weather parameters have been computed (m) * @param pressure pressure (Pa) * @param temperature temperature (Kelvin) * @param waterVaporPressure humidity as water vapor pressure (Pa) */ - public FieldPressureTemperatureHumidity(final T pressure, + public FieldPressureTemperatureHumidity(final T altitude, + final T pressure, final T temperature, final T waterVaporPressure) { - super(pressure, temperature); + super(altitude, pressure, temperature); this.waterVaporPressure = waterVaporPressure; } + /** Simple constructor. + * @param field field to which elements belong + * @param weather regular weather parameters + */ + public FieldPressureTemperatureHumidity(final Field field, final PressureTemperatureHumidity weather) { + super(field, weather); + this.waterVaporPressure = field.getZero().newInstance(weather.getWaterVaporPressure()); + } + /** Get humidity as water vapor pressure. * @return humidity as water vapor pressure (Pa) */ diff --git a/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature.java b/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature.java index 28efdc03b3..18264f8aa5 100644 --- a/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature.java +++ b/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature.java @@ -145,7 +145,9 @@ public PressureTemperature getWeatherParameters(final GeodeticPoint location, fi final double temperature = degrees + 273.15; final double pressure = pres0 * FastMath.pow(1.0 - correctedheight * 0.0000226, 5.225); - return new PressureTemperature(TroposphericModelUtils.HECTO_PASCAL.toSI(pressure), temperature); + return new PressureTemperature(location.getAltitude(), + TroposphericModelUtils.HECTO_PASCAL.toSI(pressure), + temperature); } diff --git a/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2.java b/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2.java index 56b3a14d62..4c1011cb39 100644 --- a/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2.java +++ b/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2.java @@ -214,7 +214,8 @@ public PressureTemperatureHumidity getWeatherParamerers(final GeodeticPoint loca // Water vapor pressure [hPa] final double e0 = qv * pressure / (0.622 + 0.378 * qv); - return new PressureTemperatureHumidity(TroposphericModelUtils.HECTO_PASCAL.toSI(pressure), + return new PressureTemperatureHumidity(location.getAltitude(), + TroposphericModelUtils.HECTO_PASCAL.toSI(pressure), temperature, TroposphericModelUtils.HECTO_PASCAL.toSI(e0)); @@ -255,7 +256,8 @@ public > FieldPressureTemperatureHumidity g // Water vapor pressure [hPa] final T e0 = pressure.multiply(qv / (0.622 + 0.378 * qv)); - return new FieldPressureTemperatureHumidity<>(TroposphericModelUtils.HECTO_PASCAL.toSI(pressure), + return new FieldPressureTemperatureHumidity<>(location.getAltitude(), + TroposphericModelUtils.HECTO_PASCAL.toSI(pressure), temperature, TroposphericModelUtils.HECTO_PASCAL.toSI(e0)); diff --git a/src/main/java/org/orekit/models/earth/weather/HeightDependentPressureTemperatureHumidityConverter.java b/src/main/java/org/orekit/models/earth/weather/HeightDependentPressureTemperatureHumidityConverter.java new file mode 100644 index 0000000000..b8723fdfea --- /dev/null +++ b/src/main/java/org/orekit/models/earth/weather/HeightDependentPressureTemperatureHumidityConverter.java @@ -0,0 +1,86 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS Communication & Systèmes (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.weather; + +import org.hipparchus.CalculusFieldElement; +import org.hipparchus.util.FastMath; +import org.orekit.models.earth.weather.water.WaterVaporPressureProvider; + +/** Conoverter for weather parameters that change with height. + *

                      + * Height variations correspond to equations 5.98, 5.99 and 5.100 from + * Guochang Xu, GPS - Theory, Algorithms and Applications, Springer, 2007 + *

                      + * @author Luc Maisonobe + * @since 12.1 + */ +public class HeightDependentPressureTemperatureHumidityConverter { + + /** Water pressure provider for water vapor pressure. */ + private final WaterVaporPressureProvider provider; + + /** Simple constructor. + *

                      + * Points outside of altitude range will be silently clipped back to range. + *

                      + * @param provider provider for water vapor pressure + */ + public HeightDependentPressureTemperatureHumidityConverter(final WaterVaporPressureProvider provider) { + this.provider = provider; + } + + /** Convert weather parameters. + * @param pth0 weather at reference altitude + * @param h altitude at which weather is requested + * @return converted weather + */ + public PressureTemperatureHumidity convert(final PressureTemperatureHumidity pth0, + final double h) { + + // retrieve parameters at reference altitude + final double rh0 = provider.relativeHumidity(pth0.getPressure(), pth0.getTemperature(), pth0.getWaterVaporPressure()); + + // compute changes due to altitude change + final double dh = h - pth0.getAltitude(); + final double p = pth0.getPressure() * FastMath.pow(1.0 - 2.26e-5 * dh, 5.225); + final double t = pth0.getTemperature() - 6.5e-3 * dh; + final double rh = rh0 * FastMath.exp(-6.396e-4 * dh); + + return new PressureTemperatureHumidity(h, p, t, provider.waterVaporPressure(p, t, rh)); + + } + + /** Convert weather parameters. + * @param type of the elements + * @param pth0 weather at reference altitude + * @param h altitude at which weather is requested + * @return converted weather + */ + public > FieldPressureTemperatureHumidity convert(final FieldPressureTemperatureHumidity pth0, + final T h) { + // retrieve parameters at reference altitude + final T rh0 = provider.relativeHumidity(pth0.getPressure(), pth0.getTemperature(), pth0.getWaterVaporPressure()); + + // compute changes due to altitude change + final T dh = h.subtract(pth0.getAltitude()); + final T t = pth0.getTemperature().subtract(dh.multiply(6.5e-3)); + final T p = pth0.getPressure().multiply(dh.multiply(2.26e-5).negate().add(1.0).pow(5.225)); + final T rh = rh0.multiply(FastMath.exp(dh.multiply(-6.396e-4))); + return new FieldPressureTemperatureHumidity<>(h, p, t, provider.waterVaporPressure(p, t, rh)); + } + +} diff --git a/src/main/java/org/orekit/models/earth/weather/HeightDependentPressureTemperatureHumidityProvider.java b/src/main/java/org/orekit/models/earth/weather/HeightDependentPressureTemperatureHumidityProvider.java deleted file mode 100644 index a04c6c2deb..0000000000 --- a/src/main/java/org/orekit/models/earth/weather/HeightDependentPressureTemperatureHumidityProvider.java +++ /dev/null @@ -1,136 +0,0 @@ -/* Copyright 2023 Thales Alenia Space - * Licensed to CS Communication & Systèmes (CS) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * CS licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.orekit.models.earth.weather; - -import org.hipparchus.CalculusFieldElement; -import org.hipparchus.util.FastMath; -import org.orekit.bodies.FieldGeodeticPoint; -import org.orekit.bodies.GeodeticPoint; -import org.orekit.models.earth.weather.water.WaterVaporPressureProvider; -import org.orekit.time.AbsoluteDate; -import org.orekit.time.FieldAbsoluteDate; - -/** Provider for weather parameters that change with height. - *

                      - * Height variations correspond to equations 5.98, 5.99 and 5.100 from - * Guochang Xu, GPS - Theory, Algorithms and Applications, Springer, 2007 - *

                      - * @author Luc Maisonobe - * @since 12.1 - */ -public class HeightDependentPressureTemperatureHumidityProvider implements PressureTemperatureHumidityProvider { - - /** Minimum altitude (m). */ - private final double hMin; - - /** Maximum altitude (m). */ - private final double hMax; - - /** Reference altitude (m). */ - private final double h0; - - /** PTH provider at reference height. */ - private final PressureTemperatureHumidityProvider pth0Provider; - - /** Water pressure provider for water vapor pressure. */ - private final WaterVaporPressureProvider provider; - - /** Simple constructor. - *

                      - * Points outside of altitude range will be silently clipped back to range. - *

                      - * @param hMin minimum altitude - * @param hMax maximum altitude - * @param h0 reference altitude - * @param pth0Provider PTH provider at reference height - * @param provider provider for water vapor pressure - */ - public HeightDependentPressureTemperatureHumidityProvider(final double hMin, final double hMax, - final double h0, - final PressureTemperatureHumidityProvider pth0Provider, - final WaterVaporPressureProvider provider) { - this.hMin = hMin; - this.hMax = hMax; - this.h0 = h0; - this.pth0Provider = pth0Provider; - this.provider = provider; - } - - /** Get minimum altitude. - * @return minimum altitude - */ - public double getHMin() { - return hMin; - } - - /** Get maximum altitude. - * @return maximum altitude - */ - public double getHMax() { - return hMax; - } - - /** Get reference altitude. - * @return reference altitude - */ - public double getH0() { - return h0; - } - - /** {@inheritDoc} */ - @Override - public PressureTemperatureHumidity getWeatherParamerers(final GeodeticPoint location, - final AbsoluteDate date) { - - // retrieve parameters at reference altitude - final PressureTemperatureHumidity pth0 = pth0Provider.getWeatherParamerers(new GeodeticPoint(location.getLatitude(), - location.getLongitude(), - h0), - date); - final double rh0 = provider.relativeHumidity(pth0.getPressure(), pth0.getTemperature(), pth0.getWaterVaporPressure()); - - // compute changes due to altitude change - final double dh = FastMath.min(FastMath.max(location.getAltitude(), hMin), hMax) - h0; - final double p = pth0.getPressure() * FastMath.pow(1.0 - 2.26e-5 * dh, 5.225); - final double t = pth0.getTemperature() - 6.5e-3 * dh; - final double rh = rh0 * FastMath.exp(-6.396e-4 * dh); - - return new PressureTemperatureHumidity(p, t, provider.waterVaporPressure(p, t, rh)); - - } - - /** {@inheritDoc} */ - @Override - public > FieldPressureTemperatureHumidity getWeatherParamerers(final FieldGeodeticPoint location, - final FieldAbsoluteDate date) { - // retrieve parameters at reference altitude - final FieldPressureTemperatureHumidity pth0 = - pth0Provider.getWeatherParamerers(new FieldGeodeticPoint<>(location.getLatitude(), - location.getLongitude(), - location.getAltitude().newInstance(h0)), - date); - final T rh0 = provider.relativeHumidity(pth0.getPressure(), pth0.getTemperature(), pth0.getWaterVaporPressure()); - - // compute changes due to altitude change - final T dh = FastMath.min(FastMath.max(location.getAltitude(), hMin), hMax).subtract(h0); - final T t = pth0.getTemperature().subtract(dh.multiply(6.5e-3)); - final T p = pth0.getPressure().multiply(dh.multiply(2.26e-5).negate().add(1.0).pow(5.225)); - final T rh = rh0.multiply(FastMath.exp(dh.multiply(-6.396e-4))); - return new FieldPressureTemperatureHumidity<>(p, t, provider.waterVaporPressure(p, t, rh)); - } - -} diff --git a/src/main/java/org/orekit/models/earth/weather/PressureTemperature.java b/src/main/java/org/orekit/models/earth/weather/PressureTemperature.java index 2a8ca8aa8c..ee8b1e2566 100644 --- a/src/main/java/org/orekit/models/earth/weather/PressureTemperature.java +++ b/src/main/java/org/orekit/models/earth/weather/PressureTemperature.java @@ -22,6 +22,9 @@ */ public class PressureTemperature { + /** Altitude at which weather parameters have been computed. */ + private final double altitude; + /** Pressure (Pa). */ private final double pressure; @@ -29,12 +32,22 @@ public class PressureTemperature { private final double temperature; /** Simple constructor. + * @param altitude altitude at which weather parameters have been computed (m) * @param pressure pressure (Pa) * @param temperature temperature (Kelvin) */ - public PressureTemperature(final double pressure, final double temperature) { - this.pressure = pressure; - this.temperature = temperature; + public PressureTemperature(final double altitude, + final double pressure, final double temperature) { + this.altitude = altitude; + this.pressure = pressure; + this.temperature = temperature; + } + + /** Get altitude at which weather parameters have been computed. + * @return altitude at which weather parameters have been computed (m) + */ + public double getAltitude() { + return altitude; } /** Get pressure. diff --git a/src/main/java/org/orekit/models/earth/weather/PressureTemperatureHumidity.java b/src/main/java/org/orekit/models/earth/weather/PressureTemperatureHumidity.java index cc1007257a..cbb94fb78f 100644 --- a/src/main/java/org/orekit/models/earth/weather/PressureTemperatureHumidity.java +++ b/src/main/java/org/orekit/models/earth/weather/PressureTemperatureHumidity.java @@ -26,14 +26,16 @@ public class PressureTemperatureHumidity extends PressureTemperature { private final double waterVaporPressure; /** Simple constructor. + * @param altitude altitude at which weather parameters have been computed (m) * @param pressure pressure (Pa) * @param temperature temperature (Kelvin) * @param waterVaporPressure humidity as water vapor pressure (Pa) */ - public PressureTemperatureHumidity(final double pressure, + public PressureTemperatureHumidity(final double altitude, + final double pressure, final double temperature, final double waterVaporPressure) { - super(pressure, temperature); + super(altitude, pressure, temperature); this.waterVaporPressure = waterVaporPressure; } diff --git a/src/test/java/org/orekit/Utils.java b/src/test/java/org/orekit/Utils.java index ecbb816520..0fa9b94e38 100644 --- a/src/test/java/org/orekit/Utils.java +++ b/src/test/java/org/orekit/Utils.java @@ -28,7 +28,6 @@ import org.orekit.frames.EopHistoryLoader; import org.orekit.frames.FramesFactory; import org.orekit.frames.ITRFVersion; -import org.orekit.models.earth.weather.GlobalPressureTemperature2Model; import org.orekit.orbits.FieldCartesianOrbit; import org.orekit.orbits.FieldCircularOrbit; import org.orekit.orbits.FieldEquinoctialOrbit; @@ -70,6 +69,7 @@ public class Utils { public static final double ae = 6378136.460; public static final double mu = 3.986004415e+14; + @SuppressWarnings("deprecation") public static void clearFactories() { DataContext.setDefault(new LazyLoadedDataContext()); clearFactoryMaps(CelestialBodyFactory.class); @@ -88,7 +88,7 @@ public static void clearFactories() { clearFactoryMaps(c); } } - clearAtomicReference(GlobalPressureTemperature2Model.class); + clearAtomicReference(org.orekit.models.earth.weather.GlobalPressureTemperature2Model.class); FramesFactory.clearEOPHistoryLoaders(); FramesFactory.setEOPContinuityThreshold(5 * Constants.JULIAN_DAY); TimeScalesFactory.clearUTCTAIOffsetsLoaders(); diff --git a/src/test/java/org/orekit/estimation/BrouwerLyddaneContext.java b/src/test/java/org/orekit/estimation/BrouwerLyddaneContext.java index 628e1f16bc..199314015f 100644 --- a/src/test/java/org/orekit/estimation/BrouwerLyddaneContext.java +++ b/src/test/java/org/orekit/estimation/BrouwerLyddaneContext.java @@ -9,6 +9,7 @@ import org.orekit.forces.gravity.potential.UnnormalizedSphericalHarmonicsProvider; import org.orekit.frames.TopocentricFrame; import org.orekit.models.earth.displacement.StationDisplacement; +import org.orekit.models.earth.troposphere.TroposphericModelUtils; import org.orekit.orbits.CartesianOrbit; import org.orekit.orbits.Orbit; import org.orekit.orbits.PositionAngleType; @@ -72,6 +73,7 @@ GroundStation createStation(double latitudeInDegrees, double longitudeInDegrees, FastMath.toRadians(longitudeInDegrees), altitude); return new GroundStation(new TopocentricFrame(earth, gp, name), + TroposphericModelUtils.STANDARD_ATMOSPHERE_PROVIDER, ut1.getEOPHistory(), displacements); } diff --git a/src/test/java/org/orekit/estimation/Context.java b/src/test/java/org/orekit/estimation/Context.java index 94d93cc63c..9f4903ce8a 100644 --- a/src/test/java/org/orekit/estimation/Context.java +++ b/src/test/java/org/orekit/estimation/Context.java @@ -28,6 +28,7 @@ import org.orekit.forces.radiation.RadiationSensitive; import org.orekit.frames.TopocentricFrame; import org.orekit.models.earth.displacement.StationDisplacement; +import org.orekit.models.earth.troposphere.TroposphericModelUtils; import org.orekit.orbits.CartesianOrbit; import org.orekit.orbits.Orbit; import org.orekit.orbits.OrbitType; @@ -110,6 +111,7 @@ GroundStation createStation(double latitudeInDegrees, double longitudeInDegrees, FastMath.toRadians(longitudeInDegrees), altitude); return new GroundStation(new TopocentricFrame(earth, gp, name), + TroposphericModelUtils.STANDARD_ATMOSPHERE_PROVIDER, ut1.getEOPHistory(), displacements); } diff --git a/src/test/java/org/orekit/estimation/DSSTContext.java b/src/test/java/org/orekit/estimation/DSSTContext.java index 539445d5b8..ce5cbf6818 100644 --- a/src/test/java/org/orekit/estimation/DSSTContext.java +++ b/src/test/java/org/orekit/estimation/DSSTContext.java @@ -27,6 +27,7 @@ import org.orekit.forces.radiation.RadiationSensitive; import org.orekit.frames.TopocentricFrame; import org.orekit.models.earth.displacement.StationDisplacement; +import org.orekit.models.earth.troposphere.TroposphericModelUtils; import org.orekit.orbits.EquinoctialOrbit; import org.orekit.propagation.PropagationType; import org.orekit.propagation.conversion.DSSTPropagatorBuilder; @@ -107,6 +108,7 @@ GroundStation createStation(double latitudeInDegrees, double longitudeInDegrees, FastMath.toRadians(longitudeInDegrees), altitude); return new GroundStation(new TopocentricFrame(earth, gp, name), + TroposphericModelUtils.STANDARD_ATMOSPHERE_PROVIDER, ut1.getEOPHistory(), displacements); } diff --git a/src/test/java/org/orekit/estimation/EcksteinHechlerContext.java b/src/test/java/org/orekit/estimation/EcksteinHechlerContext.java index 14a946a889..42882ab11f 100644 --- a/src/test/java/org/orekit/estimation/EcksteinHechlerContext.java +++ b/src/test/java/org/orekit/estimation/EcksteinHechlerContext.java @@ -25,6 +25,7 @@ import org.orekit.forces.gravity.potential.UnnormalizedSphericalHarmonicsProvider; import org.orekit.frames.TopocentricFrame; import org.orekit.models.earth.displacement.StationDisplacement; +import org.orekit.models.earth.troposphere.TroposphericModelUtils; import org.orekit.orbits.CartesianOrbit; import org.orekit.orbits.Orbit; import org.orekit.orbits.PositionAngleType; @@ -87,6 +88,7 @@ GroundStation createStation(double latitudeInDegrees, double longitudeInDegrees, FastMath.toRadians(longitudeInDegrees), altitude); return new GroundStation(new TopocentricFrame(earth, gp, name), + TroposphericModelUtils.STANDARD_ATMOSPHERE_PROVIDER, ut1.getEOPHistory(), displacements); } diff --git a/src/test/java/org/orekit/estimation/EphemerisContext.java b/src/test/java/org/orekit/estimation/EphemerisContext.java index 11cbff4529..c5555dd7ab 100644 --- a/src/test/java/org/orekit/estimation/EphemerisContext.java +++ b/src/test/java/org/orekit/estimation/EphemerisContext.java @@ -31,6 +31,7 @@ import org.orekit.frames.TopocentricFrame; import org.orekit.models.earth.displacement.StationDisplacement; import org.orekit.models.earth.displacement.TidalDisplacement; +import org.orekit.models.earth.troposphere.TroposphericModelUtils; import org.orekit.orbits.Orbit; import org.orekit.time.TimeScale; import org.orekit.time.TimeScalesFactory; @@ -76,6 +77,7 @@ GroundStation createStation(double latitudeInDegrees, double longitudeInDegrees, FastMath.toRadians(longitudeInDegrees), altitude); return new GroundStation(new TopocentricFrame(earth, gp, name), + TroposphericModelUtils.STANDARD_ATMOSPHERE_PROVIDER, ut1.getEOPHistory(), displacements); } diff --git a/src/test/java/org/orekit/estimation/KeplerianContext.java b/src/test/java/org/orekit/estimation/KeplerianContext.java index 7a3d88049f..b334388e1f 100644 --- a/src/test/java/org/orekit/estimation/KeplerianContext.java +++ b/src/test/java/org/orekit/estimation/KeplerianContext.java @@ -8,6 +8,7 @@ import org.orekit.estimation.measurements.GroundStation; import org.orekit.frames.TopocentricFrame; import org.orekit.models.earth.displacement.StationDisplacement; +import org.orekit.models.earth.troposphere.TroposphericModelUtils; import org.orekit.orbits.CartesianOrbit; import org.orekit.orbits.Orbit; import org.orekit.orbits.PositionAngleType; @@ -64,6 +65,7 @@ GroundStation createStation(double latitudeInDegrees, double longitudeInDegrees, FastMath.toRadians(longitudeInDegrees), altitude); return new GroundStation(new TopocentricFrame(earth, gp, name), + TroposphericModelUtils.STANDARD_ATMOSPHERE_PROVIDER, ut1.getEOPHistory(), displacements); } diff --git a/src/test/java/org/orekit/estimation/TLEContext.java b/src/test/java/org/orekit/estimation/TLEContext.java index 6342cbb698..fd9f7cb222 100644 --- a/src/test/java/org/orekit/estimation/TLEContext.java +++ b/src/test/java/org/orekit/estimation/TLEContext.java @@ -24,6 +24,7 @@ import org.orekit.forces.gravity.potential.NormalizedSphericalHarmonicsProvider; import org.orekit.frames.TopocentricFrame; import org.orekit.models.earth.displacement.StationDisplacement; +import org.orekit.models.earth.troposphere.TroposphericModelUtils; import org.orekit.orbits.PositionAngleType; import org.orekit.propagation.analytical.tle.TLE; import org.orekit.propagation.analytical.tle.generation.FixedPointTleGenerationAlgorithm; @@ -67,6 +68,7 @@ GroundStation createStation(double latitudeInDegrees, double longitudeInDegrees, FastMath.toRadians(longitudeInDegrees), altitude); return new GroundStation(new TopocentricFrame(earth, gp, name), + TroposphericModelUtils.STANDARD_ATMOSPHERE_PROVIDER, ut1.getEOPHistory(), displacements); } diff --git a/src/test/java/org/orekit/estimation/common/AbstractOrbitDetermination.java b/src/test/java/org/orekit/estimation/common/AbstractOrbitDetermination.java index 25c23c6bd0..d514767728 100644 --- a/src/test/java/org/orekit/estimation/common/AbstractOrbitDetermination.java +++ b/src/test/java/org/orekit/estimation/common/AbstractOrbitDetermination.java @@ -107,6 +107,7 @@ import org.orekit.files.sinex.Station; import org.orekit.forces.drag.DragSensitive; import org.orekit.forces.drag.IsotropicDrag; +import org.orekit.forces.gravity.potential.GravityFieldFactory; import org.orekit.forces.radiation.IsotropicRadiationSingleCoefficient; import org.orekit.forces.radiation.RadiationSensitive; import org.orekit.frames.EOPHistory; @@ -118,6 +119,8 @@ import org.orekit.gnss.antenna.FrequencyPattern; import org.orekit.models.AtmosphericRefractionModel; import org.orekit.models.earth.EarthITU453AtmosphereRefraction; +import org.orekit.models.earth.Geoid; +import org.orekit.models.earth.ReferenceEllipsoid; import org.orekit.models.earth.atmosphere.Atmosphere; import org.orekit.models.earth.atmosphere.DTM2000; import org.orekit.models.earth.atmosphere.data.MarshallSolarActivityFutureEstimation; @@ -131,17 +134,20 @@ import org.orekit.models.earth.ionosphere.KlobucharIonoCoefficientsLoader; import org.orekit.models.earth.ionosphere.KlobucharIonoModel; import org.orekit.models.earth.ionosphere.SingleLayerModelMappingFunction; -import org.orekit.models.earth.troposphere.DiscreteTroposphericModel; -import org.orekit.models.earth.troposphere.EstimatedTroposphericModel; +import org.orekit.models.earth.troposphere.EstimatedModel; import org.orekit.models.earth.troposphere.GlobalMappingFunctionModel; import org.orekit.models.earth.troposphere.MappingFunction; import org.orekit.models.earth.troposphere.MendesPavlisModel; import org.orekit.models.earth.troposphere.ModifiedSaastamoinenModel; import org.orekit.models.earth.troposphere.NiellMappingFunctionModel; -import org.orekit.models.earth.troposphere.TimeSpanEstimatedTroposphericModel; +import org.orekit.models.earth.troposphere.TimeSpanEstimatedModel; +import org.orekit.models.earth.troposphere.TroposphericModel; +import org.orekit.models.earth.troposphere.TroposphericModelUtils; import org.orekit.models.earth.weather.ConstantPressureTemperatureHumidityProvider; -import org.orekit.models.earth.weather.GlobalPressureTemperatureModel; +import org.orekit.models.earth.weather.GlobalPressureTemperature; +import org.orekit.models.earth.weather.PressureTemperature; import org.orekit.models.earth.weather.PressureTemperatureHumidity; +import org.orekit.models.earth.weather.PressureTemperatureHumidityProvider; import org.orekit.models.earth.weather.water.CIPM2007; import org.orekit.orbits.CartesianOrbit; import org.orekit.orbits.CircularOrbit; @@ -1394,7 +1400,7 @@ private Map createStationsData(final KeyValueFileParser stations = new HashMap(); - final boolean useTimeSpanTroposphericModel = parser.getBoolean(ParameterKey.USE_TIME_SPAN_TROPOSPHERIC_MODEL); + final boolean useTimeSpanModel = parser.getBoolean(ParameterKey.USE_TIME_SPAN_TROPOSPHERIC_MODEL); final String[] stationNames = parser.getStringArray(ParameterKey.GROUND_STATION_NAME); final double[] stationLatitudes = parser.getAngleArray(ParameterKey.GROUND_STATION_LATITUDE); final double[] stationLongitudes = parser.getAngleArray(ParameterKey.GROUND_STATION_LONGITUDE); @@ -1424,7 +1430,7 @@ private Map createStationsData(final KeyValueFileParser createStationsData(final KeyValueFileParser createStationsData(final KeyValueFileParser createStationsData(final KeyValueFileParser createStationsData(final KeyValueFileParser createStationsData(final KeyValueFileParser createStationsData(final KeyValueFileParser createStationsData(final KeyValueFileParser> readCrd(final DataSource source, } // Tropospheric model - final DiscreteTroposphericModel model; + final TroposphericModel model; if (meteoData != null) { final PressureTemperatureHumidity pth = - new PressureTemperatureHumidity(Unit.BAR.toSI(meteoData.getPressure()), + new PressureTemperatureHumidity(stationData.getStation().getBaseFrame().getPoint().getAltitude(), + Unit.BAR.toSI(meteoData.getPressure()), meteoData.getTemperature(), new CIPM2007(). waterVaporPressure(Unit.BAR.toSI(meteoData.getPressure()), diff --git a/src/test/java/org/orekit/estimation/iod/AbstractIodTest.java b/src/test/java/org/orekit/estimation/iod/AbstractIodTest.java index 1b9cfbfb68..3b60e65ce7 100644 --- a/src/test/java/org/orekit/estimation/iod/AbstractIodTest.java +++ b/src/test/java/org/orekit/estimation/iod/AbstractIodTest.java @@ -31,6 +31,7 @@ import org.orekit.frames.Frame; import org.orekit.frames.FramesFactory; import org.orekit.frames.TopocentricFrame; +import org.orekit.models.earth.troposphere.TroposphericModelUtils; import org.orekit.orbits.Orbit; import org.orekit.propagation.Propagator; import org.orekit.propagation.SpacecraftState; @@ -79,9 +80,11 @@ public void setUp() { // The ground station is set to Austin, Texas, U.S.A final OneAxisEllipsoid body = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS, Constants.WGS84_EARTH_FLATTENING, itrf); - this.observer = new GroundStation( - new TopocentricFrame(body, new GeodeticPoint(FastMath.toRadians(40), FastMath.toRadians(-110), - 2000.0), "")); + this.observer = new GroundStation(new TopocentricFrame(body, + new GeodeticPoint(FastMath.toRadians(40), + FastMath.toRadians(-110), + 2000.0), ""), + TroposphericModelUtils.STANDARD_ATMOSPHERE_PROVIDER); this.observer.getPrimeMeridianOffsetDriver().setReferenceDate(AbsoluteDate.J2000_EPOCH); this.observer.getPolarOffsetXDriver().setReferenceDate(AbsoluteDate.J2000_EPOCH); this.observer.getPolarOffsetYDriver().setReferenceDate(AbsoluteDate.J2000_EPOCH); diff --git a/src/test/java/org/orekit/estimation/iod/IodLaplaceTest.java b/src/test/java/org/orekit/estimation/iod/IodLaplaceTest.java index 4ff2354c9c..fd2d2ab754 100644 --- a/src/test/java/org/orekit/estimation/iod/IodLaplaceTest.java +++ b/src/test/java/org/orekit/estimation/iod/IodLaplaceTest.java @@ -29,6 +29,7 @@ import org.orekit.estimation.measurements.GroundStation; import org.orekit.estimation.measurements.ObservableSatellite; import org.orekit.frames.TopocentricFrame; +import org.orekit.models.earth.troposphere.TroposphericModelUtils; import org.orekit.orbits.KeplerianOrbit; import org.orekit.orbits.Orbit; import org.orekit.orbits.PositionAngleType; @@ -54,7 +55,8 @@ public void observerOverride() { final OneAxisEllipsoid body = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS, Constants.WGS84_EARTH_FLATTENING, itrf); this.observer = new GroundStation( - new TopocentricFrame(body, new GeodeticPoint(0.528253, -1.705768, 0.0), "Austin")); + new TopocentricFrame(body, new GeodeticPoint(0.528253, -1.705768, 0.0), "Austin"), + TroposphericModelUtils.STANDARD_ATMOSPHERE_PROVIDER); this.observer.getPrimeMeridianOffsetDriver().setReferenceDate(AbsoluteDate.J2000_EPOCH); this.observer.getPolarOffsetXDriver().setReferenceDate(AbsoluteDate.J2000_EPOCH); this.observer.getPolarOffsetYDriver().setReferenceDate(AbsoluteDate.J2000_EPOCH); diff --git a/src/test/java/org/orekit/estimation/leastsquares/DSSTOrbitDeterminationTest.java b/src/test/java/org/orekit/estimation/leastsquares/DSSTOrbitDeterminationTest.java index e248edfa56..7cd0c39fe2 100644 --- a/src/test/java/org/orekit/estimation/leastsquares/DSSTOrbitDeterminationTest.java +++ b/src/test/java/org/orekit/estimation/leastsquares/DSSTOrbitDeterminationTest.java @@ -309,8 +309,8 @@ public void testGNSS() //test //definition of the accuracy for the test - final double distanceAccuracy = 6.95; - final double velocityAccuracy = 2.46e-3; + final double distanceAccuracy = 6.97; + final double velocityAccuracy = 2.47e-3; //test on the convergence final int numberOfIte = 3; @@ -329,7 +329,7 @@ public void testGNSS() //test on statistic for the range residuals final long nbRange = 4009; - final double[] RefStatRange = { -3.497, 2.594, 0.0, 0.837 }; + final double[] RefStatRange = { -3.499, 2.608, 0.0, 0.837 }; Assertions.assertEquals(nbRange, odGNSS.getRangeStat().getN()); Assertions.assertEquals(RefStatRange[0], odGNSS.getRangeStat().getMin(), 1.0e-3); Assertions.assertEquals(RefStatRange[1], odGNSS.getRangeStat().getMax(), 1.0e-3); diff --git a/src/test/java/org/orekit/estimation/leastsquares/NumericalOrbitDeterminationTest.java b/src/test/java/org/orekit/estimation/leastsquares/NumericalOrbitDeterminationTest.java index dc09962867..2d02d83cd4 100644 --- a/src/test/java/org/orekit/estimation/leastsquares/NumericalOrbitDeterminationTest.java +++ b/src/test/java/org/orekit/estimation/leastsquares/NumericalOrbitDeterminationTest.java @@ -273,8 +273,8 @@ public void testGNSS() //test //definition of the accuracy for the test - final double distanceAccuracy = 1.06; - final double velocityAccuracy = 2.26e-3; + final double distanceAccuracy = 1.05; + final double velocityAccuracy = 2.27e-3; //test on the convergence final int numberOfIte = 2; @@ -294,7 +294,7 @@ public void testGNSS() //test on statistic for the range residuals final long nbRangeInit = 8981; final long nbRangeExcluded = 305; - final double[] RefStatRange = { -3.847, 8.307, 0.0, 0.873 }; + final double[] RefStatRange = { -3.853, 8.307, 0.0, 0.873 }; Assertions.assertEquals(nbRangeInit - nbRangeExcluded, odGNSS.getRangeStat().getN()); Assertions.assertEquals(RefStatRange[0], odGNSS.getRangeStat().getMin(), 1.0e-3); Assertions.assertEquals(RefStatRange[1], odGNSS.getRangeStat().getMax(), 1.0e-3); @@ -332,8 +332,8 @@ public void testW3B() //test on the estimated position and velocity final Vector3D estimatedPos = odsatW3.getEstimatedPV().getPosition(); final Vector3D estimatedVel = odsatW3.getEstimatedPV().getVelocity(); - final Vector3D refPos = new Vector3D(-40541446.255, -9905357.41, 206777.413); - final Vector3D refVel = new Vector3D(759.0685, -1476.5156, 54.793); + final Vector3D refPos = new Vector3D(-40541446.380, -9905353.045, 206780.170); + final Vector3D refVel = new Vector3D(759.0684, -1476.5159, 54.7928); Assertions.assertEquals(0.0, Vector3D.distance(refPos, estimatedPos), distanceAccuracy); Assertions.assertEquals(0.0, Vector3D.distance(refVel, estimatedVel), velocityAccuracy); @@ -346,12 +346,12 @@ public void testW3B() propagatorParameters.getDrivers().get(3).getValue(), propagatorParameters.getDrivers().get(5).getValue()); //Assertions.assertEquals(7.215e-6, leakAcceleration.getNorm(), 1.0e-8); - Assertions.assertEquals(8.002e-6, leakAcceleration0.getNorm(), 1.0e-8); + Assertions.assertEquals(7.977e-6, leakAcceleration0.getNorm(), 1.0e-8); final Vector3D leakAcceleration1 = new Vector3D(propagatorParameters.getDrivers().get(2).getValue(), propagatorParameters.getDrivers().get(4).getValue(), propagatorParameters.getDrivers().get(6).getValue()); - Assertions.assertEquals(3.058e-10, leakAcceleration1.getNorm(), 1.0e-12); + Assertions.assertEquals(3.046e-10, leakAcceleration1.getNorm(), 1.0e-12); //test on measurements parameters final List list = new ArrayList(); @@ -360,35 +360,35 @@ public void testW3B() //station CastleRock final double[] CastleAzElBias = { 0.062701342, -0.003613508 }; - final double CastleRangeBias = 11274.4677; + final double CastleRangeBias = 11274.8335; Assertions.assertEquals(CastleAzElBias[0], FastMath.toDegrees(list.get(0).getValue()), angleAccuracy); Assertions.assertEquals(CastleAzElBias[1], FastMath.toDegrees(list.get(1).getValue()), angleAccuracy); Assertions.assertEquals(CastleRangeBias, list.get(2).getValue(), distanceAccuracy); //station Fucino final double[] FucAzElBias = { -0.053526137, 0.075483886 }; - final double FucRangeBias = 13467.8256; + final double FucRangeBias = 13467.7253; Assertions.assertEquals(FucAzElBias[0], FastMath.toDegrees(list.get(3).getValue()), angleAccuracy); Assertions.assertEquals(FucAzElBias[1], FastMath.toDegrees(list.get(4).getValue()), angleAccuracy); Assertions.assertEquals(FucRangeBias, list.get(5).getValue(), distanceAccuracy); //station Kumsan final double[] KumAzElBias = { -0.023574208, -0.054520756 }; - final double KumRangeBias = 13512.57594; + final double KumRangeBias = 13513.3007; Assertions.assertEquals(KumAzElBias[0], FastMath.toDegrees(list.get(6).getValue()), angleAccuracy); Assertions.assertEquals(KumAzElBias[1], FastMath.toDegrees(list.get(7).getValue()), angleAccuracy); Assertions.assertEquals(KumRangeBias, list.get(8).getValue(), distanceAccuracy); //station Pretoria final double[] PreAzElBias = { 0.030201539, 0.009747877 }; - final double PreRangeBias = 13594.11889; + final double PreRangeBias = 13593.6300; Assertions.assertEquals(PreAzElBias[0], FastMath.toDegrees(list.get( 9).getValue()), angleAccuracy); Assertions.assertEquals(PreAzElBias[1], FastMath.toDegrees(list.get(10).getValue()), angleAccuracy); Assertions.assertEquals(PreRangeBias, list.get(11).getValue(), distanceAccuracy); //station Uralla final double[] UraAzElBias = { 0.167814449, -0.12305252 }; - final double UraRangeBias = 13450.26738; + final double UraRangeBias = 13450.5792; Assertions.assertEquals(UraAzElBias[0], FastMath.toDegrees(list.get(12).getValue()), angleAccuracy); Assertions.assertEquals(UraAzElBias[1], FastMath.toDegrees(list.get(13).getValue()), angleAccuracy); Assertions.assertEquals(UraRangeBias, list.get(14).getValue(), distanceAccuracy); diff --git a/src/test/java/org/orekit/estimation/leastsquares/TLEOrbitDeterminationTest.java b/src/test/java/org/orekit/estimation/leastsquares/TLEOrbitDeterminationTest.java index ea1fe668c2..6099f17c3f 100644 --- a/src/test/java/org/orekit/estimation/leastsquares/TLEOrbitDeterminationTest.java +++ b/src/test/java/org/orekit/estimation/leastsquares/TLEOrbitDeterminationTest.java @@ -222,7 +222,7 @@ public void testGNSS() //test on statistic for the range residuals final long nbRange = 8211; - final double[] RefStatRange = { -14.448, 18.736, 0.132, 6.323 }; + final double[] RefStatRange = { -14.448, 18.706, 0.132, 6.322 }; Assertions.assertEquals(nbRange, odGNSS.getRangeStat().getN()); Assertions.assertEquals(RefStatRange[0], odGNSS.getRangeStat().getMin(), 1.0e-3); Assertions.assertEquals(RefStatRange[1], odGNSS.getRangeStat().getMax(), 1.0e-3); diff --git a/src/test/java/org/orekit/estimation/measurements/AngularRaDecTest.java b/src/test/java/org/orekit/estimation/measurements/AngularRaDecTest.java index 8bb8966694..143a3bd1e4 100644 --- a/src/test/java/org/orekit/estimation/measurements/AngularRaDecTest.java +++ b/src/test/java/org/orekit/estimation/measurements/AngularRaDecTest.java @@ -32,6 +32,7 @@ import org.orekit.estimation.EstimationTestUtils; import org.orekit.estimation.measurements.generation.AngularRaDecBuilder; import org.orekit.frames.*; +import org.orekit.models.earth.troposphere.TroposphericModelUtils; import org.orekit.orbits.CartesianOrbit; import org.orekit.orbits.OrbitType; import org.orekit.orbits.PositionAngleType; @@ -315,7 +316,8 @@ public void testIssue1026() { final GeodeticPoint point = new GeodeticPoint(0., 0., 100.); final TopocentricFrame baseFrame = new TopocentricFrame(earth, point, "name"); - final GroundStation station = new GroundStation(baseFrame); + final GroundStation station = new GroundStation(baseFrame, + TroposphericModelUtils.STANDARD_ATMOSPHERE_PROVIDER); final Frame[] frames = {FramesFactory.getEME2000(), FramesFactory.getGCRF(), FramesFactory.getICRF(), FramesFactory.getTOD(false)}; final double[][] raDec = new double[frames.length][]; diff --git a/src/test/java/org/orekit/estimation/measurements/ComparableMeasurementTest.java b/src/test/java/org/orekit/estimation/measurements/ComparableMeasurementTest.java index 1fe5fc289b..e521f0d4bc 100644 --- a/src/test/java/org/orekit/estimation/measurements/ComparableMeasurementTest.java +++ b/src/test/java/org/orekit/estimation/measurements/ComparableMeasurementTest.java @@ -25,6 +25,7 @@ import org.orekit.bodies.OneAxisEllipsoid; import org.orekit.frames.FramesFactory; import org.orekit.frames.TopocentricFrame; +import org.orekit.models.earth.troposphere.TroposphericModelUtils; import org.orekit.time.AbsoluteDate; import org.orekit.utils.Constants; import org.orekit.utils.IERSConventions; @@ -46,7 +47,8 @@ public void testDefaultCompareToIssue538() { OneAxisEllipsoid earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS, Constants.WGS84_EARTH_FLATTENING, FramesFactory.getITRF(IERSConventions.IERS_2010, false)); TopocentricFrame stationFrame = new TopocentricFrame(earth, new GeodeticPoint(FastMath.toRadians(45.0), FastMath.toRadians(0.0), 0.0), "station"); - GroundStation station = new GroundStation(stationFrame); + GroundStation station = new GroundStation(stationFrame, + TroposphericModelUtils.STANDARD_ATMOSPHERE_PROVIDER); AbsoluteDate date = AbsoluteDate.J2000_EPOCH; // Create a Range and Azel at same date, diff --git a/src/test/java/org/orekit/estimation/measurements/GroundStationTest.java b/src/test/java/org/orekit/estimation/measurements/GroundStationTest.java index fda5cf7a46..d76f10a2f1 100644 --- a/src/test/java/org/orekit/estimation/measurements/GroundStationTest.java +++ b/src/test/java/org/orekit/estimation/measurements/GroundStationTest.java @@ -46,6 +46,7 @@ import org.orekit.frames.StaticTransform; import org.orekit.frames.TopocentricFrame; import org.orekit.frames.Transform; +import org.orekit.models.earth.troposphere.TroposphericModelUtils; import org.orekit.orbits.OrbitType; import org.orekit.orbits.PositionAngleType; import org.orekit.propagation.Propagator; @@ -94,6 +95,7 @@ public void testEstimateClockOffset() throws IOException, ClassNotFoundException final String changedSuffix = "-changed"; final GroundStation changed = new GroundStation(new TopocentricFrame(parent, base.getPoint(), base.getName() + changedSuffix), + TroposphericModelUtils.STANDARD_ATMOSPHERE_PROVIDER, context.ut1.getEOPHistory(), context.stations.get(0).getDisplacements()); @@ -174,6 +176,7 @@ public void testEstimateStationPosition() throws IOException, ClassNotFoundExcep parent.getBodyFrame(), null), base.getName() + movedSuffix), + TroposphericModelUtils.STANDARD_ATMOSPHERE_PROVIDER, context.ut1.getEOPHistory(), context.stations.get(0).getDisplacements()); @@ -212,7 +215,7 @@ public void testEstimateStationPosition() throws IOException, ClassNotFoundExcep Assertions.assertEquals(deltaTopo.getY(), moved.getNorthOffsetDriver().getValue(), 6.2e-7); Assertions.assertEquals(deltaTopo.getZ(), moved.getZenithOffsetDriver().getValue(), 2.6e-7); - GeodeticPoint result = moved.getOffsetGeodeticPoint(null); + GeodeticPoint result = moved.getOffsetGeodeticPoint((AbsoluteDate) null); GeodeticPoint reference = context.stations.get(0).getBaseFrame().getPoint(); Assertions.assertEquals(reference.getLatitude(), result.getLatitude(), 3.3e-14); @@ -1277,7 +1280,8 @@ public void testNoReferenceDateGradient() { FramesFactory.getITRF(IERSConventions.IERS_2010, true)); final GroundStation station = new GroundStation(new TopocentricFrame(earth, new GeodeticPoint(0.1, 0.2, 100), - "dummy")); + "dummy"), + TroposphericModelUtils.STANDARD_ATMOSPHERE_PROVIDER); try { station.getOffsetToInertial(eme2000, date, false); Assertions.fail("an exception should have been thrown"); @@ -1324,7 +1328,8 @@ private void doTestCartesianDerivatives(double latitude, double longitude, doubl FramesFactory.getITRF(IERSConventions.IERS_2010, true)); final GroundStation station = new GroundStation(new TopocentricFrame(earth, new GeodeticPoint(latitude, longitude, altitude), - "dummy")); + "dummy"), + TroposphericModelUtils.STANDARD_ATMOSPHERE_PROVIDER); final GradientField gradientField = GradientField.getField(parameterPattern.length); ParameterDriver[] selectedDrivers = new ParameterDriver[parameterPattern.length]; UnivariateDifferentiableVectorFunction[] dFCartesian = new UnivariateDifferentiableVectorFunction[parameterPattern.length]; @@ -1433,7 +1438,8 @@ private void doTestAngularDerivatives(double latitude, double longitude, double FramesFactory.getITRF(IERSConventions.IERS_2010, true)); final GroundStation station = new GroundStation(new TopocentricFrame(earth, new GeodeticPoint(latitude, longitude, altitude), - "dummy")); + "dummy"), + TroposphericModelUtils.STANDARD_ATMOSPHERE_PROVIDER); ParameterDriver[] selectedDrivers = new ParameterDriver[parameterPattern.length]; UnivariateDifferentiableVectorFunction[] dFAngular = new UnivariateDifferentiableVectorFunction[parameterPattern.length]; final ParameterDriver[] allDrivers = selectAllDrivers(station); diff --git a/src/test/java/org/orekit/estimation/measurements/RangeRateTest.java b/src/test/java/org/orekit/estimation/measurements/RangeRateTest.java index dc5c4d480e..5a8eb4cb0d 100644 --- a/src/test/java/org/orekit/estimation/measurements/RangeRateTest.java +++ b/src/test/java/org/orekit/estimation/measurements/RangeRateTest.java @@ -25,6 +25,7 @@ import org.orekit.estimation.Context; import org.orekit.estimation.EstimationTestUtils; import org.orekit.estimation.measurements.modifiers.RangeRateTroposphericDelayModifier; +import org.orekit.models.earth.troposphere.EstimatedModel; import org.orekit.models.earth.troposphere.EstimatedTroposphericModel; import org.orekit.models.earth.troposphere.GlobalMappingFunctionModel; import org.orekit.models.earth.troposphere.ModifiedSaastamoinenModel; @@ -532,7 +533,7 @@ public void testStateDerivativesWithEstimatedModifier() { // Add modifiers if test implies it final GlobalMappingFunctionModel mappingFunction = new GlobalMappingFunctionModel(); - final EstimatedTroposphericModel tropoModel = new EstimatedTroposphericModel(mappingFunction, 5.0); + final EstimatedModel tropoModel = new EstimatedTroposphericModel(mappingFunction, 5.0); final RangeRateTroposphericDelayModifier modifier = new RangeRateTroposphericDelayModifier(tropoModel, true); ((RangeRate) measurement).addModifier(modifier); @@ -689,7 +690,7 @@ public void testParameterDerivativesWithEstimatedModifier() { // Add modifiers if test implies it final GlobalMappingFunctionModel mappingFunction = new GlobalMappingFunctionModel(); - final EstimatedTroposphericModel tropoModel = new EstimatedTroposphericModel(mappingFunction, 10.0); + final EstimatedModel tropoModel = new EstimatedTroposphericModel(mappingFunction, 10.0); final List parameters = tropoModel.getParametersDrivers(); for (ParameterDriver driver : parameters) { diff --git a/src/test/java/org/orekit/estimation/measurements/RangeTest.java b/src/test/java/org/orekit/estimation/measurements/RangeTest.java index 2d8fd0f75a..59687efbbc 100644 --- a/src/test/java/org/orekit/estimation/measurements/RangeTest.java +++ b/src/test/java/org/orekit/estimation/measurements/RangeTest.java @@ -31,9 +31,10 @@ import org.orekit.estimation.Context; import org.orekit.estimation.EstimationTestUtils; import org.orekit.estimation.measurements.modifiers.RangeTroposphericDelayModifier; +import org.orekit.models.earth.troposphere.EstimatedModel; import org.orekit.models.earth.troposphere.EstimatedTroposphericModel; -import org.orekit.models.earth.troposphere.NiellMappingFunctionModel; import org.orekit.models.earth.troposphere.ModifiedSaastamoinenModel; +import org.orekit.models.earth.troposphere.NiellMappingFunctionModel; import org.orekit.orbits.OrbitType; import org.orekit.orbits.PositionAngleType; import org.orekit.propagation.Propagator; @@ -100,9 +101,9 @@ public void testStateDerivativesWithModifier() { } // Run test boolean isModifier = true; - double refErrorsPMedian = 7.6e-10; - double refErrorsPMean = 3.2e-09; - double refErrorsPMax = 9.2e-08; + double refErrorsPMedian = 6.6e-10; + double refErrorsPMean = 3.1e-09; + double refErrorsPMax = 9.3e-08; double refErrorsVMedian = 2.1e-04; double refErrorsVMean = 1.3e-03; double refErrorsVMax = 5.2e-02; @@ -174,7 +175,7 @@ public void testParameterDerivativesWithEstimatedModifier() { boolean isModifier = true; double refErrorsMedian = 1.2e-9; double refErrorsMean = 1.9e-9; - double refErrorsMax = 6.6e-9; + double refErrorsMax = 6.9e-9; this.genericTestEstimatedParameterDerivatives(isModifier, printResults, refErrorsMedian, refErrorsMean, refErrorsMax); @@ -642,7 +643,7 @@ void genericTestEstimatedParameterDerivatives(final boolean isModifier, final bo // Add modifiers if test implies it final NiellMappingFunctionModel mappingFunction = new NiellMappingFunctionModel(); - final EstimatedTroposphericModel tropoModel = new EstimatedTroposphericModel(mappingFunction, 5.0); + final EstimatedModel tropoModel = new EstimatedModel(mappingFunction, 5.0); final List parameters = tropoModel.getParametersDrivers(); for (ParameterDriver driver : parameters) { diff --git a/src/test/java/org/orekit/estimation/measurements/TDOATest.java b/src/test/java/org/orekit/estimation/measurements/TDOATest.java index 7d22a02194..077c406f66 100644 --- a/src/test/java/org/orekit/estimation/measurements/TDOATest.java +++ b/src/test/java/org/orekit/estimation/measurements/TDOATest.java @@ -378,7 +378,7 @@ public double value(final ParameterDriver parameterDriver, AbsoluteDate date) { } } - Assertions.assertEquals(0, maxRelativeError, 9.0e-7); + Assertions.assertEquals(0, maxRelativeError, 2.5e-6); } diff --git a/src/test/java/org/orekit/estimation/measurements/TurnAroundRangeAnalyticTest.java b/src/test/java/org/orekit/estimation/measurements/TurnAroundRangeAnalyticTest.java index 80a9c81040..cc98b23d7b 100644 --- a/src/test/java/org/orekit/estimation/measurements/TurnAroundRangeAnalyticTest.java +++ b/src/test/java/org/orekit/estimation/measurements/TurnAroundRangeAnalyticTest.java @@ -213,7 +213,7 @@ public void testParameterDerivativesWithModifierFiniteDifferences() { boolean isModifier = true; boolean isFiniteDifferences = true; genericTestParameterDerivatives(isModifier, isFiniteDifferences, printResults, - 3.0e-06, 5.9e-06, 1.3e-04, 2.9e-6, 5.0e-6, 3.9e-5); + 2.8e-06, 5.9e-06, 1.2e-04, 4.3e-6, 1.7e-5, 1.5e-4); } @@ -221,8 +221,7 @@ public void testParameterDerivativesWithModifierFiniteDifferences() { * Generic test function for values of the TAR * @param printResults Print the results ? */ - void genericTestValues(final boolean printResults) - { + void genericTestValues(final boolean printResults) { Context context = EstimationTestUtils.eccentricContext("regular-data:potential:tides"); //Context context = EstimationTestUtils.geoStationnaryContext(); diff --git a/src/test/java/org/orekit/estimation/measurements/TurnAroundRangeTest.java b/src/test/java/org/orekit/estimation/measurements/TurnAroundRangeTest.java index a9c0eed8fc..b63b942e28 100644 --- a/src/test/java/org/orekit/estimation/measurements/TurnAroundRangeTest.java +++ b/src/test/java/org/orekit/estimation/measurements/TurnAroundRangeTest.java @@ -154,12 +154,12 @@ public void testParameterDerivativesWithModifier() { } // Run test boolean isModifier = true; - double refErrorQMMedian = 2.6e-6; - double refErrorQMMean = 2.5e-6; - double refErrorQMMax = 5.6e-6; - double refErrorQSMedian = 3.7e-7; - double refErrorQSMean = 3.6e-7; - double refErrorQSMax = 7.7e-7; + double refErrorQMMedian = 1.3e-8; + double refErrorQMMean = 8.9e-8; + double refErrorQMMax = 5.1e-6; + double refErrorQSMedian = 3.4e-7; + double refErrorQSMean = 1.3e-5; + double refErrorQSMax = 1.5e-4; this.genericTestParameterDerivatives(isModifier, printResults, refErrorQMMedian, refErrorQMMean, refErrorQMMax, refErrorQSMedian, refErrorQSMean, refErrorQSMax); diff --git a/src/test/java/org/orekit/estimation/measurements/filtering/ElevationFilteringTest.java b/src/test/java/org/orekit/estimation/measurements/filtering/ElevationFilteringTest.java index e0d2c16ad3..aa0b2a9e81 100644 --- a/src/test/java/org/orekit/estimation/measurements/filtering/ElevationFilteringTest.java +++ b/src/test/java/org/orekit/estimation/measurements/filtering/ElevationFilteringTest.java @@ -46,6 +46,7 @@ import org.orekit.frames.Frame; import org.orekit.frames.FramesFactory; import org.orekit.frames.TopocentricFrame; +import org.orekit.models.earth.troposphere.TroposphericModelUtils; import org.orekit.orbits.CartesianOrbit; import org.orekit.orbits.Orbit; import org.orekit.orbits.OrbitType; @@ -133,7 +134,8 @@ public void testElevationFilter() { final OneAxisEllipsoid body = new OneAxisEllipsoid(equatorialRadius, flattening, bodyFrame); final GeodeticPoint position = new GeodeticPoint(29.868112727, -89.673232869, -14.853146); final TopocentricFrame topo = new TopocentricFrame(body, position, "SBCH"); - final GroundStation station = new GroundStation(topo); + final GroundStation station = new GroundStation(topo, + TroposphericModelUtils.STANDARD_ATMOSPHERE_PROVIDER); final double noise = 0.1; Generator generatorThreshold = getGenerator(orbit, station, topo, noise, threshold); final GatheringSubscriber gathererThreshold = new GatheringSubscriber(); diff --git a/src/test/java/org/orekit/estimation/measurements/gnss/InterSatellitesWindUpTest.java b/src/test/java/org/orekit/estimation/measurements/gnss/InterSatellitesWindUpTest.java index 3012fe7458..ca527dc2f8 100644 --- a/src/test/java/org/orekit/estimation/measurements/gnss/InterSatellitesWindUpTest.java +++ b/src/test/java/org/orekit/estimation/measurements/gnss/InterSatellitesWindUpTest.java @@ -45,6 +45,7 @@ import org.orekit.gnss.SatelliteSystem; import org.orekit.gnss.attitude.GPSBlockIIA; import org.orekit.gnss.attitude.GPSBlockIIR; +import org.orekit.models.earth.troposphere.TroposphericModelUtils; import org.orekit.orbits.CartesianOrbit; import org.orekit.orbits.Orbit; import org.orekit.propagation.Propagator; @@ -80,7 +81,8 @@ public void testYawSteering() { new GeodeticPoint(FastMath.toRadians(55.0 + ( 1.0 + 10.0 / 60.0) / 60.0), FastMath.toRadians(82.0 + (55.0 + 22.0 / 60.0) / 60.0), 160.0), - "Новосибирск")), + "Новосибирск"), + TroposphericModelUtils.STANDARD_ATMOSPHERE_PROVIDER), -0.082134, 0.060814); } @@ -106,7 +108,8 @@ public void testMidnightTurn() { new GeodeticPoint(FastMath.toRadians( -(25.0 + 4.0 / 60.0)), FastMath.toRadians(-(130.0 + 6.0 / 60.0)), 0.0), - "Adamstown")), + "Adamstown"), + TroposphericModelUtils.STANDARD_ATMOSPHERE_PROVIDER), -0.961925, 0.360695); } @@ -128,7 +131,8 @@ public void testNoonTurn() { new GeodeticPoint(FastMath.toRadians( 19.0 + (49.0 + 20.0 / 60.0) / 60.0), FastMath.toRadians(-(155.0 + (28.0 + 30.0 / 60.0) / 60.0)), 4205.0), - "Mauna Kea")), + "Mauna Kea"), + TroposphericModelUtils.STANDARD_ATMOSPHERE_PROVIDER), 0.349123, 0.972542); } diff --git a/src/test/java/org/orekit/estimation/measurements/gnss/PhaseTest.java b/src/test/java/org/orekit/estimation/measurements/gnss/PhaseTest.java index d108594858..c9578a1778 100644 --- a/src/test/java/org/orekit/estimation/measurements/gnss/PhaseTest.java +++ b/src/test/java/org/orekit/estimation/measurements/gnss/PhaseTest.java @@ -44,8 +44,10 @@ import org.orekit.gnss.Frequency; import org.orekit.models.earth.ionosphere.IonosphericModel; import org.orekit.models.earth.ionosphere.KlobucharIonoModel; +import org.orekit.models.earth.troposphere.EstimatedModel; import org.orekit.models.earth.troposphere.EstimatedTroposphericModel; import org.orekit.models.earth.troposphere.NiellMappingFunctionModel; +import org.orekit.models.earth.troposphere.TroposphericModelUtils; import org.orekit.orbits.OrbitType; import org.orekit.orbits.PositionAngleType; import org.orekit.propagation.Propagator; @@ -624,10 +626,10 @@ public void testStateDerivativesWithTroposphericModifier() { String stationName = ((Phase) measurement).getStation().getBaseFrame().getName(); // Add modifier - final NiellMappingFunctionModel mappingFunction = new NiellMappingFunctionModel(); - final EstimatedTroposphericModel tropoModel = new EstimatedTroposphericModel(mappingFunction, 5.0); - final PhaseTroposphericDelayModifier modifier = new PhaseTroposphericDelayModifier(tropoModel); - final List parameters = modifier.getParametersDrivers(); + final NiellMappingFunctionModel mappingFunction = new NiellMappingFunctionModel(); + final EstimatedModel tropoModel = new EstimatedTroposphericModel(mappingFunction, 5.0); + final PhaseTroposphericDelayModifier modifier = new PhaseTroposphericDelayModifier(tropoModel); + final List parameters = modifier.getParametersDrivers(); parameters.get(0).setName(stationName + "/" + EstimatedTroposphericModel.TOTAL_ZENITH_DELAY); parameters.get(0).setSelected(true); ((Phase) measurement).addModifier(modifier); @@ -914,7 +916,7 @@ public void testIssue734() { final TopocentricFrame topo = new TopocentricFrame(body, new GeodeticPoint(FastMath.toRadians(51.8), FastMath.toRadians(102.2), 811.2), "BADG"); - final GroundStation station = new GroundStation(topo); + final GroundStation station = new GroundStation(topo, TroposphericModelUtils.STANDARD_ATMOSPHERE_PROVIDER); // Create a phase measurement final Phase phase = new Phase(station, AbsoluteDate.J2000_EPOCH, 119866527.060, Frequency.G01.getWavelength(), 0.02, 1.0, new ObservableSatellite(0)); diff --git a/src/test/java/org/orekit/estimation/measurements/modifiers/AberrationModifierTest.java b/src/test/java/org/orekit/estimation/measurements/modifiers/AberrationModifierTest.java index 8755eb54dd..e660a92ecf 100644 --- a/src/test/java/org/orekit/estimation/measurements/modifiers/AberrationModifierTest.java +++ b/src/test/java/org/orekit/estimation/measurements/modifiers/AberrationModifierTest.java @@ -35,6 +35,7 @@ import org.orekit.frames.FramesFactory; import org.orekit.frames.TopocentricFrame; import org.orekit.models.earth.ReferenceEllipsoid; +import org.orekit.models.earth.troposphere.TroposphericModelUtils; import org.orekit.orbits.CartesianOrbit; import org.orekit.propagation.SpacecraftState; import org.orekit.time.AbsoluteDate; @@ -66,7 +67,8 @@ static void setup() { 51.8); TopocentricFrame stationFrame = new TopocentricFrame(ReferenceEllipsoid.getWgs84(fixedFrame), stationLocation, "station"); - groundStation = new GroundStation(stationFrame); + groundStation = new GroundStation(stationFrame, + TroposphericModelUtils.STANDARD_ATMOSPHERE_PROVIDER); } @Test diff --git a/src/test/java/org/orekit/estimation/measurements/modifiers/RelativisticClockPhaseModifierTest.java b/src/test/java/org/orekit/estimation/measurements/modifiers/RelativisticClockPhaseModifierTest.java index 6282f5bf0e..812e17289b 100644 --- a/src/test/java/org/orekit/estimation/measurements/modifiers/RelativisticClockPhaseModifierTest.java +++ b/src/test/java/org/orekit/estimation/measurements/modifiers/RelativisticClockPhaseModifierTest.java @@ -31,6 +31,7 @@ import org.orekit.frames.FramesFactory; import org.orekit.frames.TopocentricFrame; import org.orekit.gnss.Frequency; +import org.orekit.models.earth.troposphere.TroposphericModelUtils; import org.orekit.orbits.CartesianOrbit; import org.orekit.propagation.SpacecraftState; import org.orekit.propagation.analytical.tle.TLE; @@ -53,7 +54,8 @@ public void testRelativisticClockCorrection() { FramesFactory.getITRF(IERSConventions.IERS_2010, true)); final GeodeticPoint point = new GeodeticPoint(FastMath.toRadians(42.0), FastMath.toRadians(1.0), 100.0); final TopocentricFrame topo = new TopocentricFrame(earth, point, ""); - final GroundStation station = new GroundStation(topo); + final GroundStation station = new GroundStation(topo, + TroposphericModelUtils.STANDARD_ATMOSPHERE_PROVIDER); // Satellite (GPS orbit from TLE) final TLE tle = new TLE("1 28474U 04045A 20252.59334296 -.00000043 00000-0 00000-0 0 9998", diff --git a/src/test/java/org/orekit/estimation/measurements/modifiers/RelativisticClockRangeModifierTest.java b/src/test/java/org/orekit/estimation/measurements/modifiers/RelativisticClockRangeModifierTest.java index a1cbb54d5f..95c9f43ae2 100644 --- a/src/test/java/org/orekit/estimation/measurements/modifiers/RelativisticClockRangeModifierTest.java +++ b/src/test/java/org/orekit/estimation/measurements/modifiers/RelativisticClockRangeModifierTest.java @@ -30,6 +30,7 @@ import org.orekit.estimation.measurements.Range; import org.orekit.frames.FramesFactory; import org.orekit.frames.TopocentricFrame; +import org.orekit.models.earth.troposphere.TroposphericModelUtils; import org.orekit.orbits.CartesianOrbit; import org.orekit.propagation.SpacecraftState; import org.orekit.propagation.analytical.tle.TLE; @@ -52,7 +53,8 @@ public void testRelativisticClockCorrection() { FramesFactory.getITRF(IERSConventions.IERS_2010, true)); final GeodeticPoint point = new GeodeticPoint(FastMath.toRadians(42.0), FastMath.toRadians(1.0), 100.0); final TopocentricFrame topo = new TopocentricFrame(earth, point, ""); - final GroundStation station = new GroundStation(topo); + final GroundStation station = new GroundStation(topo, + TroposphericModelUtils.STANDARD_ATMOSPHERE_PROVIDER); // Satellite (GPS orbit from TLE) final TLE tle = new TLE("1 28474U 04045A 20252.59334296 -.00000043 00000-0 00000-0 0 9998", diff --git a/src/test/java/org/orekit/estimation/measurements/modifiers/RelativisticClockRangeRateModifierTest.java b/src/test/java/org/orekit/estimation/measurements/modifiers/RelativisticClockRangeRateModifierTest.java index 40cb1819a9..a7aa1e1ad3 100644 --- a/src/test/java/org/orekit/estimation/measurements/modifiers/RelativisticClockRangeRateModifierTest.java +++ b/src/test/java/org/orekit/estimation/measurements/modifiers/RelativisticClockRangeRateModifierTest.java @@ -30,6 +30,7 @@ import org.orekit.estimation.measurements.RangeRate; import org.orekit.frames.FramesFactory; import org.orekit.frames.TopocentricFrame; +import org.orekit.models.earth.troposphere.TroposphericModelUtils; import org.orekit.orbits.CartesianOrbit; import org.orekit.propagation.SpacecraftState; import org.orekit.propagation.analytical.tle.TLE; @@ -52,7 +53,8 @@ public void testRelativisticClockCorrection() { FramesFactory.getITRF(IERSConventions.IERS_2010, true)); final GeodeticPoint point = new GeodeticPoint(FastMath.toRadians(42.0), FastMath.toRadians(1.0), 100.0); final TopocentricFrame topo = new TopocentricFrame(earth, point, ""); - final GroundStation station = new GroundStation(topo); + final GroundStation station = new GroundStation(topo, + TroposphericModelUtils.STANDARD_ATMOSPHERE_PROVIDER); // Satellite (GPS orbit from TLE) final TLE tle = new TLE("1 28474U 04045A 20252.59334296 -.00000043 00000-0 00000-0 0 9998", diff --git a/src/test/java/org/orekit/estimation/measurements/modifiers/TropoModifierTest.java b/src/test/java/org/orekit/estimation/measurements/modifiers/TropoModifierTest.java index 552f3ee1a0..dd86a6d20e 100644 --- a/src/test/java/org/orekit/estimation/measurements/modifiers/TropoModifierTest.java +++ b/src/test/java/org/orekit/estimation/measurements/modifiers/TropoModifierTest.java @@ -50,9 +50,10 @@ import org.orekit.frames.TopocentricFrame; import org.orekit.gnss.Frequency; import org.orekit.models.earth.EarthITU453AtmosphereRefraction; +import org.orekit.models.earth.troposphere.EstimatedModel; import org.orekit.models.earth.troposphere.EstimatedTroposphericModel; -import org.orekit.models.earth.troposphere.NiellMappingFunctionModel; import org.orekit.models.earth.troposphere.ModifiedSaastamoinenModel; +import org.orekit.models.earth.troposphere.NiellMappingFunctionModel; import org.orekit.orbits.OrbitType; import org.orekit.orbits.PositionAngleType; import org.orekit.propagation.Propagator; @@ -146,11 +147,11 @@ public void testRangeEstimatedTropoModifier() { EstimatedMeasurementBase evalNoMod = range.estimateWithoutDerivatives(0, 0, new SpacecraftState[] { refState }); // add modifier - final GroundStation stationParameter = ((Range) measurement).getStation(); - final TopocentricFrame baseFrame = stationParameter.getBaseFrame(); - final NiellMappingFunctionModel mappingFunction = new NiellMappingFunctionModel(); - final EstimatedTroposphericModel tropoModel = new EstimatedTroposphericModel(mappingFunction, 5.0); - final RangeTroposphericDelayModifier modifier = new RangeTroposphericDelayModifier(tropoModel); + final GroundStation stationParameter = ((Range) measurement).getStation(); + final TopocentricFrame baseFrame = stationParameter.getBaseFrame(); + final NiellMappingFunctionModel mappingFunction = new NiellMappingFunctionModel(); + final EstimatedModel tropoModel = new EstimatedTroposphericModel(mappingFunction, 5.0); + final RangeTroposphericDelayModifier modifier = new RangeTroposphericDelayModifier(tropoModel); final ParameterDriver parameterDriver = modifier.getParametersDrivers().get(0); parameterDriver.setSelected(true); @@ -256,11 +257,11 @@ public void testPhaseEstimatedTropoModifier() { // add modifier - final GroundStation stationParameter = phase.getStation(); - final TopocentricFrame baseFrame = stationParameter.getBaseFrame(); - final NiellMappingFunctionModel mappingFunction = new NiellMappingFunctionModel(); - final EstimatedTroposphericModel tropoModel = new EstimatedTroposphericModel(mappingFunction, 5.0); - final PhaseTroposphericDelayModifier modifier = new PhaseTroposphericDelayModifier(tropoModel); + final GroundStation stationParameter = phase.getStation(); + final TopocentricFrame baseFrame = stationParameter.getBaseFrame(); + final NiellMappingFunctionModel mappingFunction = new NiellMappingFunctionModel(); + final EstimatedModel tropoModel = new EstimatedTroposphericModel(mappingFunction, 5.0); + final PhaseTroposphericDelayModifier modifier = new PhaseTroposphericDelayModifier(tropoModel); final ParameterDriver parameterDriver = modifier.getParametersDrivers().get(0); parameterDriver.setSelected(true); @@ -469,7 +470,7 @@ public void testBistaticRangeRateEstimatedTropoModifier() { // add modifier final NiellMappingFunctionModel mappingFunc = new NiellMappingFunctionModel(); - final EstimatedTroposphericModel tropoModel = new EstimatedTroposphericModel(mappingFunc, 5.0); + final EstimatedModel tropoModel = new EstimatedTroposphericModel(mappingFunc, 5.0); final BistaticRangeRateTroposphericDelayModifier modifier = new BistaticRangeRateTroposphericDelayModifier(tropoModel); @@ -578,9 +579,9 @@ public void testTDOAEstimatedTropoModifier() { EstimatedMeasurementBase evalNoMod = tdoa.estimateWithoutDerivatives(0, 0, new SpacecraftState[] { refState }); // add modifier - final NiellMappingFunctionModel mappingFunct = new NiellMappingFunctionModel(); - final EstimatedTroposphericModel tropoModel = new EstimatedTroposphericModel(mappingFunct, 5.0); - final TDOATroposphericDelayModifier modifier = new TDOATroposphericDelayModifier(tropoModel); + final NiellMappingFunctionModel mappingFunct = new NiellMappingFunctionModel(); + final EstimatedModel tropoModel = new EstimatedTroposphericModel(mappingFunct, 5.0); + final TDOATroposphericDelayModifier modifier = new TDOATroposphericDelayModifier(tropoModel); final TopocentricFrame baseFrame = tdoa.getPrimeStation().getBaseFrame(); final ParameterDriver parameterDriver = modifier.getParametersDrivers().get(0); @@ -676,11 +677,11 @@ public void testRangeRateEstimatedTropoModifier() { EstimatedMeasurementBase evalNoMod = rangeRate.estimateWithoutDerivatives(0, 0, new SpacecraftState[] { refState }); // add modifier - final GroundStation stationParameter = ((RangeRate) measurement).getStation(); - final TopocentricFrame baseFrame = stationParameter.getBaseFrame(); - final NiellMappingFunctionModel mappingFunction = new NiellMappingFunctionModel(); - final EstimatedTroposphericModel tropoModel = new EstimatedTroposphericModel(mappingFunction, 5.0); - final RangeRateTroposphericDelayModifier modifier = new RangeRateTroposphericDelayModifier(tropoModel, false); + final GroundStation stationParameter = ((RangeRate) measurement).getStation(); + final TopocentricFrame baseFrame = stationParameter.getBaseFrame(); + final NiellMappingFunctionModel mappingFunction = new NiellMappingFunctionModel(); + final EstimatedModel tropoModel = new EstimatedTroposphericModel(mappingFunction, 5.0); + final RangeRateTroposphericDelayModifier modifier = new RangeRateTroposphericDelayModifier(tropoModel, false); final ParameterDriver parameterDriver = modifier.getParametersDrivers().get(0); parameterDriver.setSelected(true); @@ -778,11 +779,11 @@ public void testAngularEstimatedTropoModifier() { EstimatedMeasurementBase evalNoMod = angular.estimateWithoutDerivatives(0, 0, new SpacecraftState[] { refState }); // add modifier - final GroundStation stationParameter = ((AngularAzEl) measurement).getStation(); - final TopocentricFrame baseFrame = stationParameter.getBaseFrame(); - final NiellMappingFunctionModel mappingFunction = new NiellMappingFunctionModel(); - final EstimatedTroposphericModel tropoModel = new EstimatedTroposphericModel(mappingFunction, 5.0); - final AngularTroposphericDelayModifier modifier = new AngularTroposphericDelayModifier(tropoModel); + final GroundStation stationParameter = ((AngularAzEl) measurement).getStation(); + final TopocentricFrame baseFrame = stationParameter.getBaseFrame(); + final NiellMappingFunctionModel mappingFunction = new NiellMappingFunctionModel(); + final EstimatedModel tropoModel = new EstimatedTroposphericModel(mappingFunction, 5.0); + final AngularTroposphericDelayModifier modifier = new AngularTroposphericDelayModifier(tropoModel); final ParameterDriver parameterDriver = modifier.getParametersDrivers().get(0); parameterDriver.setSelected(true); diff --git a/src/test/java/org/orekit/estimation/sequential/KalmanNumericalOrbitDeterminationTest.java b/src/test/java/org/orekit/estimation/sequential/KalmanNumericalOrbitDeterminationTest.java index 640ec816c6..607b29345b 100644 --- a/src/test/java/org/orekit/estimation/sequential/KalmanNumericalOrbitDeterminationTest.java +++ b/src/test/java/org/orekit/estimation/sequential/KalmanNumericalOrbitDeterminationTest.java @@ -439,7 +439,7 @@ public void testW3B() throws URISyntaxException, IOException { // final double[] CastleAzElBias = { 0.062701342, -0.003613508 }; // final double CastleRangeBias = 11274.4677; final double[] CastleAzElBias = { 0.062635, -0.003672}; - final double CastleRangeBias = 11289.3678; + final double CastleRangeBias = 11289.544; Assertions.assertEquals(CastleAzElBias[0], FastMath.toDegrees(list.get(0).getValue()), angleAccuracy); Assertions.assertEquals(CastleAzElBias[1], FastMath.toDegrees(list.get(1).getValue()), angleAccuracy); Assertions.assertEquals(CastleRangeBias, list.get(2).getValue(), distanceAccuracy); @@ -459,7 +459,7 @@ public void testW3B() throws URISyntaxException, IOException { // final double[] KumAzElBias = { -0.023574208, -0.054520756 }; // final double KumRangeBias = 13512.57594; final double[] KumAzElBias = { -0.022805, -0.055057 }; - final double KumRangeBias = 13502.7459; + final double KumRangeBias = 13503.273; Assertions.assertEquals(KumAzElBias[0], FastMath.toDegrees(list.get(6).getValue()), angleAccuracy); Assertions.assertEquals(KumAzElBias[1], FastMath.toDegrees(list.get(7).getValue()), angleAccuracy); Assertions.assertEquals(KumRangeBias, list.get(8).getValue(), distanceAccuracy); @@ -469,7 +469,7 @@ public void testW3B() throws URISyntaxException, IOException { // final double[] PreAzElBias = { 0.030201539, 0.009747877 }; // final double PreRangeBias = 13594.11889; final double[] PreAzElBias = { 0.030353, 0.009658 }; - final double PreRangeBias = 13609.2516; + final double PreRangeBias = 13609.012; Assertions.assertEquals(PreAzElBias[0], FastMath.toDegrees(list.get( 9).getValue()), angleAccuracy); Assertions.assertEquals(PreAzElBias[1], FastMath.toDegrees(list.get(10).getValue()), angleAccuracy); Assertions.assertEquals(PreRangeBias, list.get(11).getValue(), distanceAccuracy); @@ -479,7 +479,7 @@ public void testW3B() throws URISyntaxException, IOException { // final double[] UraAzElBias = { 0.167814449, -0.12305252 }; // final double UraRangeBias = 13450.26738; final double[] UraAzElBias = { 0.167519, -0.122842 }; - final double UraRangeBias = 13441.7019; + final double UraRangeBias = 13441.978; Assertions.assertEquals(UraAzElBias[0], FastMath.toDegrees(list.get(12).getValue()), angleAccuracy); Assertions.assertEquals(UraAzElBias[1], FastMath.toDegrees(list.get(13).getValue()), angleAccuracy); Assertions.assertEquals(UraRangeBias, list.get(14).getValue(), distanceAccuracy); diff --git a/src/test/java/org/orekit/estimation/sequential/TLEKalmanOrbitDeterminationTest.java b/src/test/java/org/orekit/estimation/sequential/TLEKalmanOrbitDeterminationTest.java index 57ee93e9f2..19c0bf8708 100644 --- a/src/test/java/org/orekit/estimation/sequential/TLEKalmanOrbitDeterminationTest.java +++ b/src/test/java/org/orekit/estimation/sequential/TLEKalmanOrbitDeterminationTest.java @@ -361,7 +361,7 @@ public void testGNSS() throws URISyntaxException, IOException { // Definition of the accuracy for the test // Initial TLE error at last measurement date is 1053.6m - final double distanceAccuracy = 67.33; + final double distanceAccuracy = 67.48; // Tests diff --git a/src/test/java/org/orekit/models/earth/atmosphere/AtmosphereTest.java b/src/test/java/org/orekit/models/earth/atmosphere/AtmosphereTest.java index c7318dff69..65c228eb39 100644 --- a/src/test/java/org/orekit/models/earth/atmosphere/AtmosphereTest.java +++ b/src/test/java/org/orekit/models/earth/atmosphere/AtmosphereTest.java @@ -78,6 +78,8 @@ void testGetVelocityNonConstantFieldAbsoluteDate() { private static class TestAtmosphere implements Atmosphere { + private static final long serialVersionUID = 1L; + @Override public Frame getFrame() { return FramesFactory.getITRF(IERSConventions.IERS_2003, false); diff --git a/src/test/java/org/orekit/models/earth/ionosphere/EstimatedIonosphericModelTest.java b/src/test/java/org/orekit/models/earth/ionosphere/EstimatedIonosphericModelTest.java index 9c455ddb5e..f5e55c1fb5 100644 --- a/src/test/java/org/orekit/models/earth/ionosphere/EstimatedIonosphericModelTest.java +++ b/src/test/java/org/orekit/models/earth/ionosphere/EstimatedIonosphericModelTest.java @@ -37,6 +37,7 @@ import org.orekit.frames.FramesFactory; import org.orekit.frames.TopocentricFrame; import org.orekit.gnss.Frequency; +import org.orekit.models.earth.troposphere.TroposphericModelUtils; import org.orekit.orbits.FieldKeplerianOrbit; import org.orekit.orbits.FieldOrbit; import org.orekit.orbits.KeplerianOrbit; @@ -239,7 +240,8 @@ public void testDelayStateDerivatives() { final TopocentricFrame baseFrame = new TopocentricFrame(earth, point, "topo"); // Station - final GroundStation station = new GroundStation(baseFrame); + final GroundStation station = new GroundStation(baseFrame, + TroposphericModelUtils.STANDARD_ATMOSPHERE_PROVIDER); // Ionospheric model final IonosphericMappingFunction mapping = new SingleLayerModelMappingFunction(); diff --git a/src/test/java/org/orekit/models/earth/troposphere/AbstractFieldMappingFunctionTest.java b/src/test/java/org/orekit/models/earth/troposphere/AbstractFieldMappingFunctionTest.java index 350868a31c..bbe87d86b1 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/AbstractFieldMappingFunctionTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/AbstractFieldMappingFunctionTest.java @@ -133,7 +133,8 @@ protected void doTestMFStateDerivatives(final double epsMFH, final double epsMFW final TopocentricFrame baseFrame = new TopocentricFrame(earth, point, "topo"); // Station - final GroundStation station = new GroundStation(baseFrame); + final GroundStation station = new GroundStation(baseFrame, + TroposphericModelUtils.STANDARD_ATMOSPHERE_PROVIDER); // Mapping Function model final MappingFunction model = buildMappingFunction(); diff --git a/src/test/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModelTest.java index dd582bfb83..db678213b8 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModelTest.java @@ -29,12 +29,12 @@ public class CanonicalSaastamoinenModelTest { @Test public void testComparisonToModifiedModelLowElevation() { - doTestComparisonToModifiedModel(FastMath.toRadians(5), 0.06, 0.15); + doTestComparisonToModifiedModel(FastMath.toRadians(5), -13.24, -1.04); } @Test public void testComparisonToModifiedModelHighElevation() { - doTestComparisonToModifiedModel(FastMath.toRadians(60), -0.001, 0.003); + doTestComparisonToModifiedModel(FastMath.toRadians(60), -1.35, -0.11); } private void doTestComparisonToModifiedModel(final double elevation, @@ -43,8 +43,10 @@ private void doTestComparisonToModifiedModel(final double elevation, final ModifiedSaastamoinenModel modified = ModifiedSaastamoinenModel.getStandardModel(); for (double height = 0; height < 5000; height += 100) { final GeodeticPoint location = new GeodeticPoint(0.0, 0.0, height); - final double canonicalDelay = canonical.pathDelay(elevation, location, null, AbsoluteDate.J2000_EPOCH); - final double modifiedDelay = modified.pathDelay(elevation, location, null, AbsoluteDate.J2000_EPOCH); + final double canonicalDelay = canonical.pathDelay(elevation, location, TroposphericModelUtils.STANDARD_ATMOSPHERE, + null, AbsoluteDate.J2000_EPOCH); + final double modifiedDelay = modified.pathDelay(elevation, location, TroposphericModelUtils.STANDARD_ATMOSPHERE, + null, AbsoluteDate.J2000_EPOCH); Assertions.assertTrue(modifiedDelay - canonicalDelay > minDifference); Assertions.assertTrue(modifiedDelay - canonicalDelay < maxDifference); } diff --git a/src/test/java/org/orekit/models/earth/troposphere/EstimatedModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/EstimatedModelTest.java new file mode 100644 index 0000000000..0495b98ea7 --- /dev/null +++ b/src/test/java/org/orekit/models/earth/troposphere/EstimatedModelTest.java @@ -0,0 +1,453 @@ +/* Copyright 2002-2023 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import org.hipparchus.Field; +import org.hipparchus.analysis.differentiation.DSFactory; +import org.hipparchus.analysis.differentiation.DerivativeStructure; +import org.hipparchus.geometry.euclidean.threed.FieldVector3D; +import org.hipparchus.geometry.euclidean.threed.Vector3D; +import org.hipparchus.util.FastMath; +import org.hipparchus.util.Precision; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.orekit.Utils; +import org.orekit.attitudes.Attitude; +import org.orekit.bodies.FieldGeodeticPoint; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.bodies.OneAxisEllipsoid; +import org.orekit.errors.OrekitException; +import org.orekit.estimation.measurements.GroundStation; +import org.orekit.frames.Frame; +import org.orekit.frames.FramesFactory; +import org.orekit.frames.TopocentricFrame; +import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; +import org.orekit.orbits.FieldKeplerianOrbit; +import org.orekit.orbits.FieldOrbit; +import org.orekit.orbits.Orbit; +import org.orekit.orbits.OrbitType; +import org.orekit.orbits.PositionAngleType; +import org.orekit.propagation.FieldSpacecraftState; +import org.orekit.propagation.SpacecraftState; +import org.orekit.propagation.numerical.NumericalPropagator; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; +import org.orekit.time.TimeScalesFactory; +import org.orekit.utils.Constants; +import org.orekit.utils.IERSConventions; +import org.orekit.utils.ParameterDriver; +import org.orekit.utils.ParameterDriversList; + +import java.util.List; + +public class EstimatedModelTest { + + @BeforeAll + public static void setUpGlobal() { + Utils.setDataRoot("atmosphere"); + } + + @BeforeEach + public void setUp() throws OrekitException { + Utils.setDataRoot("regular-data:potential/shm-format"); + } + + @Test + public void testFixedHeight() { + final AbsoluteDate date = new AbsoluteDate(); + GeodeticPoint point = new GeodeticPoint(FastMath.toRadians(45.0), FastMath.toRadians(45.0), 350.0); + MappingFunction mapping = new NiellMappingFunctionModel(); + TroposphericModel model = new EstimatedTroposphericModel(mapping, 2.0); + double lastDelay = Double.MAX_VALUE; + // delay shall decline with increasing elevation angle + for (double elev = 10d; elev < 90d; elev += 8d) { + final double delay = model.pathDelay(FastMath.toRadians(elev), point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), date); + Assertions.assertTrue(Precision.compareTo(delay, lastDelay, 1.0e-6) < 0); + lastDelay = delay; + } + } + + @Test + public void testDelay() { + final double elevation = 10d; + final double height = 100d; + final AbsoluteDate date = new AbsoluteDate(); + GeodeticPoint point = new GeodeticPoint(FastMath.toRadians(45.0), FastMath.toRadians(45.0), height); + MappingFunction mapping = new NiellMappingFunctionModel(); + TroposphericModel model = new EstimatedTroposphericModel(mapping, 2.0); + final double path = model.pathDelay(FastMath.toRadians(elevation), point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), date); + Assertions.assertTrue(Precision.compareTo(path, 20d, 1.0e-6) < 0); + Assertions.assertTrue(Precision.compareTo(path, 0d, 1.0e-6) > 0); + } + + @Test + public void testStateDerivativesGMF() { + final double latitude = FastMath.toRadians(45.0); + final double longitude = FastMath.toRadians(45.0); + GeodeticPoint point = new GeodeticPoint(latitude, longitude, 0.0); + final MappingFunction gmf = new GlobalMappingFunctionModel(); + doTestDelayStateDerivatives(gmf, point, 4.7e-9); + } + + @Test + public void testStateDerivativesNMF() { + final double latitude = FastMath.toRadians(45.0); + final double longitude = FastMath.toRadians(45.0); + GeodeticPoint point = new GeodeticPoint(latitude, longitude, 0.0); + final MappingFunction nmf = new NiellMappingFunctionModel(); + doTestDelayStateDerivatives(nmf, point, 4.4e-9); + } + + private void doTestDelayStateDerivatives(final MappingFunction func, final GeodeticPoint point, final double tolerance) { + + // Body: earth + final OneAxisEllipsoid earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS, + Constants.WGS84_EARTH_FLATTENING, + FramesFactory.getITRF(IERSConventions.IERS_2010, true)); + // Topocentric frame + final TopocentricFrame baseFrame = new TopocentricFrame(earth, point, "topo"); + + // Station + final GroundStation station = new GroundStation(baseFrame, + TroposphericModelUtils.STANDARD_ATMOSPHERE_PROVIDER); + + // Tropospheric model + final TroposphericModel model = new EstimatedTroposphericModel(func, 2.0); + + // Derivative Structure + final DSFactory factory = new DSFactory(6, 1); + final DerivativeStructure a0 = factory.variable(0, 24464560.0); + final DerivativeStructure e0 = factory.variable(1, 0.05); + final DerivativeStructure i0 = factory.variable(2, 0.122138); + final DerivativeStructure pa0 = factory.variable(3, 3.10686); + final DerivativeStructure raan0 = factory.variable(4, 1.00681); + final DerivativeStructure anomaly0 = factory.variable(5, 0.048363); + final Field field = a0.getField(); + final DerivativeStructure zero = field.getZero(); + + // Field Date + final FieldAbsoluteDate dsDate = new FieldAbsoluteDate<>(field); + // Field Orbit + final Frame frame = FramesFactory.getEME2000(); + final FieldOrbit dsOrbit = new FieldKeplerianOrbit<>(a0, e0, i0, pa0, raan0, anomaly0, + PositionAngleType.MEAN, frame, + dsDate, zero.add(3.9860047e14)); + // Field State + final FieldSpacecraftState dsState = new FieldSpacecraftState<>(dsOrbit); + + // Initial satellite elevation + final FieldVector3D position = dsState.getPosition(); + final DerivativeStructure dsElevation = baseFrame.getTrackingCoordinates(position, frame, dsDate).getElevation(); + + // Set drivers reference date + for (final ParameterDriver driver : model.getParametersDrivers()) { + driver.setReferenceDate(dsDate.toAbsoluteDate()); + } + + // Compute Delay with state derivatives + final FieldGeodeticPoint dsPoint = new FieldGeodeticPoint<>(zero.add(point.getLatitude()), zero.add(point.getLongitude()), zero.add(point.getAltitude())); + final DerivativeStructure delay = model.pathDelay(dsElevation, dsPoint, + new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + model.getParameters(field), dsDate); + + final double[] compDeriv = delay.getAllDerivatives(); + + // Field -> non-field + final Orbit orbit = dsOrbit.toOrbit(); + final SpacecraftState state = dsState.toSpacecraftState(); + + // Finite differences for reference values + final double[][] refDeriv = new double[1][6]; + final OrbitType orbitType = OrbitType.KEPLERIAN; + final PositionAngleType angleType = PositionAngleType.MEAN; + double dP = 0.001; + double[] steps = NumericalPropagator.tolerances(1000000 * dP, orbit, orbitType)[0]; + for (int i = 0; i < 6; i++) { + SpacecraftState stateM4 = shiftState(state, orbitType, angleType, -4 * steps[i], i); + final Vector3D positionM4 = stateM4.getPosition(); + final double elevationM4 = station.getBaseFrame(). + getTrackingCoordinates(positionM4, stateM4.getFrame(), stateM4.getDate()). + getElevation(); + double delayM4 = model.pathDelay(elevationM4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateM4.getDate()); + + SpacecraftState stateM3 = shiftState(state, orbitType, angleType, -3 * steps[i], i); + final Vector3D positionM3 = stateM3.getPosition(); + final double elevationM3 = station.getBaseFrame(). + getTrackingCoordinates(positionM3, stateM3.getFrame(), stateM3.getDate()). + getElevation(); + double delayM3 = model.pathDelay(elevationM3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateM3.getDate()); + + SpacecraftState stateM2 = shiftState(state, orbitType, angleType, -2 * steps[i], i); + final Vector3D positionM2 = stateM2.getPosition(); + final double elevationM2 = station.getBaseFrame(). + getTrackingCoordinates(positionM2, stateM2.getFrame(), stateM2.getDate()). + getElevation(); + double delayM2 = model.pathDelay(elevationM2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateM2.getDate()); + + SpacecraftState stateM1 = shiftState(state, orbitType, angleType, -1 * steps[i], i); + final Vector3D positionM1 = stateM1.getPosition(); + final double elevationM1 = station.getBaseFrame(). + getTrackingCoordinates(positionM1, stateM1.getFrame(), stateM1.getDate()). + getElevation(); + double delayM1 = model.pathDelay(elevationM1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateM1.getDate()); + + SpacecraftState stateP1 = shiftState(state, orbitType, angleType, 1 * steps[i], i); + final Vector3D positionP1 = stateP1.getPosition(); + final double elevationP1 = station.getBaseFrame(). + getTrackingCoordinates(positionP1, stateP1.getFrame(), stateP1.getDate()). + getElevation(); + double delayP1 = model.pathDelay(elevationP1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateP1.getDate()); + + SpacecraftState stateP2 = shiftState(state, orbitType, angleType, 2 * steps[i], i); + final Vector3D positionP2 = stateP2.getPosition(); + final double elevationP2 = station.getBaseFrame(). + getTrackingCoordinates(positionP2, stateP2.getFrame(), stateP2.getDate()). + getElevation(); + double delayP2 = model.pathDelay(elevationP2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateP2.getDate()); + + SpacecraftState stateP3 = shiftState(state, orbitType, angleType, 3 * steps[i], i); + final Vector3D positionP3 = stateP3.getPosition(); + final double elevationP3 = station.getBaseFrame(). + getTrackingCoordinates(positionP3, stateP3.getFrame(), stateP3.getDate()). + getElevation(); + double delayP3 = model.pathDelay(elevationP3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateP3.getDate()); + + SpacecraftState stateP4 = shiftState(state, orbitType, angleType, 4 * steps[i], i); + final Vector3D positionP4 = stateP4.getPosition(); + final double elevationP4 = station.getBaseFrame(). + getTrackingCoordinates(positionP4, stateP4.getFrame(), stateP4.getDate()). + getElevation(); + double delayP4 = model.pathDelay(elevationP4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateP4.getDate()); + + fillJacobianColumn(refDeriv, i, orbitType, angleType, steps[i], + delayM4, delayM3, delayM2, delayM1, + delayP1, delayP2, delayP3, delayP4); + } + + for (int i = 0; i < 6; i++) { + Assertions.assertEquals(compDeriv[i + 1], refDeriv[0][i], tolerance); + } + } + + @Test + public void testDelayParameterDerivative() { + doTestParametersDerivatives(EstimatedTroposphericModel.TOTAL_ZENITH_DELAY, 5.0e-15); + } + + private void doTestParametersDerivatives(String parameterName, double tolerance) { + + // Geodetic point + final double latitude = FastMath.toRadians(45.0); + final double longitude = FastMath.toRadians(45.0); + final double height = 0.0; + final GeodeticPoint point = new GeodeticPoint(latitude, longitude, height); + // Body: earth + final OneAxisEllipsoid earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS, + Constants.WGS84_EARTH_FLATTENING, + FramesFactory.getITRF(IERSConventions.IERS_2010, true)); + // Topocentric frame + final TopocentricFrame baseFrame = new TopocentricFrame(earth, point, "topo"); + + // Tropospheric model + final MappingFunction gmf = new GlobalMappingFunctionModel(); + final TroposphericModel model = new EstimatedTroposphericModel(gmf, 5.0); + + // Set Parameter Driver + for (final ParameterDriver driver : model.getParametersDrivers()) { + driver.setValue(driver.getReferenceValue()); + driver.setSelected(driver.getName().equals(parameterName)); + } + + // Count the required number of parameters + int nbParams = 0; + for (final ParameterDriver driver : model.getParametersDrivers()) { + if (driver.isSelected()) { + ++nbParams; + } + } + + // Derivative Structure + final DSFactory factory = new DSFactory(6 + nbParams, 1); + final DerivativeStructure a0 = factory.variable(0, 24464560.0); + final DerivativeStructure e0 = factory.variable(1, 0.05); + final DerivativeStructure i0 = factory.variable(2, 0.122138); + final DerivativeStructure pa0 = factory.variable(3, 3.10686); + final DerivativeStructure raan0 = factory.variable(4, 1.00681); + final DerivativeStructure anomaly0 = factory.variable(5, 0.048363); + final Field field = a0.getField(); + final DerivativeStructure zero = field.getZero(); + + // Field Date + final FieldAbsoluteDate dsDate = new FieldAbsoluteDate<>(field, 2018, 11, 19, 18, 0, 0.0, + TimeScalesFactory.getUTC()); + + // Set drivers reference date + for (final ParameterDriver driver : model.getParametersDrivers()) { + driver.setReferenceDate(dsDate.toAbsoluteDate()); + } + + // Field Orbit + final Frame frame = FramesFactory.getEME2000(); + final FieldOrbit dsOrbit = new FieldKeplerianOrbit<>(a0, e0, i0, pa0, raan0, anomaly0, + PositionAngleType.MEAN, frame, + dsDate, zero.add(3.9860047e14)); + + // Field State + final FieldSpacecraftState dsState = new FieldSpacecraftState<>(dsOrbit); + + // Initial satellite elevation + final FieldVector3D position = dsState.getPosition(); + final DerivativeStructure dsElevation = baseFrame.getTrackingCoordinates(position, frame, dsState.getDate()).getElevation(); + + // Add parameter as a variable + final List drivers = model.getParametersDrivers(); + final DerivativeStructure[] parameters = new DerivativeStructure[drivers.size()]; + int index = 6; + for (int i = 0; i < drivers.size(); ++i) { + parameters[i] = drivers.get(i).isSelected() ? + factory.variable(index++, drivers.get(i).getValue()) : + factory.constant(drivers.get(i).getValue()); + } + + // Compute delay state derivatives + final FieldGeodeticPoint dsPoint = new FieldGeodeticPoint<>(zero.add(point.getLatitude()), zero.add(point.getLongitude()), zero.add(point.getAltitude())); + final DerivativeStructure delay = model.pathDelay(dsElevation, dsPoint, + new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + parameters, dsState.getDate()); + + final double[] compDeriv = delay.getAllDerivatives(); + + // Field -> non-field + final SpacecraftState state = dsState.toSpacecraftState(); + final double elevation = dsElevation.getReal(); + + // Finite differences for reference values + final double[][] refDeriv = new double[1][1]; + ParameterDriversList bound = new ParameterDriversList(); + for (final ParameterDriver driver : model.getParametersDrivers()) { + if (driver.getName().equals(parameterName)) { + driver.setSelected(true); + bound.add(driver); + } else { + driver.setSelected(false); + } + } + ParameterDriver selected = bound.getDrivers().get(0); + double p0 = selected.getReferenceValue(); + double h = selected.getScale(); + + final OrbitType orbitType = OrbitType.KEPLERIAN; + final PositionAngleType angleType = PositionAngleType.MEAN; + + selected.setValue(p0 - 4 * h); + double delayM4 = model.pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), state.getDate()); + + selected.setValue(p0 - 3 * h); + double delayM3 = model.pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), state.getDate()); + + selected.setValue(p0 - 2 * h); + double delayM2 = model.pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), state.getDate()); + + selected.setValue(p0 - 1 * h); + double delayM1 = model.pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), state.getDate()); + + selected.setValue(p0 + 1 * h); + double delayP1 = model.pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), state.getDate()); + + selected.setValue(p0 + 2 * h); + double delayP2 = model.pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), state.getDate()); + + selected.setValue(p0 + 3 * h); + double delayP3 = model.pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), state.getDate()); + + selected.setValue(p0 + 4 * h); + double delayP4 = model.pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), state.getDate()); + + fillJacobianColumn(refDeriv, 0, orbitType, angleType, h, + delayM4, delayM3, delayM2, delayM1, + delayP1, delayP2, delayP3, delayP4); + + Assertions.assertEquals(compDeriv[7], refDeriv[0][0], tolerance); + + } + + private SpacecraftState shiftState(SpacecraftState state, OrbitType orbitType, PositionAngleType angleType, + double delta, int column) { + + double[][] array = stateToArray(state, orbitType, angleType, true); + array[0][column] += delta; + + return arrayToState(array, orbitType, angleType, state.getFrame(), state.getDate(), + state.getMu(), state.getAttitude()); + + } + + private double[][] stateToArray(SpacecraftState state, OrbitType orbitType, PositionAngleType angleType, + boolean withMass) { + double[][] array = new double[2][withMass ? 7 : 6]; + orbitType.mapOrbitToArray(state.getOrbit(), angleType, array[0], array[1]); + if (withMass) { + array[0][6] = state.getMass(); + } + return array; + } + + private SpacecraftState arrayToState(double[][] array, OrbitType orbitType, PositionAngleType angleType, + Frame frame, AbsoluteDate date, double mu, + Attitude attitude) { + Orbit orbit = orbitType.mapArrayToOrbit(array[0], array[1], angleType, date, mu, frame); + return (array.length > 6) ? + new SpacecraftState(orbit, attitude) : + new SpacecraftState(orbit, attitude, array[0][6]); + } + + private void fillJacobianColumn(double[][] jacobian, int column, + OrbitType orbitType, PositionAngleType angleType, double h, + double sM4h, double sM3h, + double sM2h, double sM1h, + double sP1h, double sP2h, + double sP3h, double sP4h) { + + jacobian[0][column] = ( -3 * (sP4h - sM4h) + + 32 * (sP3h - sM3h) - + 168 * (sP2h - sM2h) + + 672 * (sP1h - sM1h)) / (840 * h); + } + +} diff --git a/src/test/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModelTest.java index 212ebe1172..760fd2014f 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModelTest.java @@ -55,6 +55,7 @@ import java.util.List; +@Deprecated public class EstimatedTroposphericModelTest { @BeforeAll @@ -123,7 +124,8 @@ private void doTestDelayStateDerivatives(final MappingFunction func, final Geode final TopocentricFrame baseFrame = new TopocentricFrame(earth, point, "topo"); // Station - final GroundStation station = new GroundStation(baseFrame); + final GroundStation station = new GroundStation(baseFrame, + TroposphericModelUtils.STANDARD_ATMOSPHERE_PROVIDER); // Tropospheric model final DiscreteTroposphericModel model = new EstimatedTroposphericModel(func, 2.0); diff --git a/src/test/java/org/orekit/models/earth/troposphere/FieldGlobalMappingFunctionModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/FieldGlobalMappingFunctionModelTest.java index 047709dd5f..98bfd220ef 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/FieldGlobalMappingFunctionModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/FieldGlobalMappingFunctionModelTest.java @@ -144,7 +144,8 @@ public void testMFStateDerivatives() { final TopocentricFrame baseFrame = new TopocentricFrame(earth, point, "topo"); // Station - final GroundStation station = new GroundStation(baseFrame); + final GroundStation station = new GroundStation(baseFrame, + TroposphericModelUtils.STANDARD_ATMOSPHERE_PROVIDER); // Mapping Function model final MappingFunction model = new GlobalMappingFunctionModel(); diff --git a/src/test/java/org/orekit/models/earth/troposphere/FieldMendesPavlisModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/FieldMendesPavlisModelTest.java index 41f61d100e..df25157354 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/FieldMendesPavlisModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/FieldMendesPavlisModelTest.java @@ -40,6 +40,7 @@ import org.orekit.frames.FramesFactory; import org.orekit.frames.TopocentricFrame; import org.orekit.models.earth.weather.ConstantPressureTemperatureHumidityProvider; +import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; import org.orekit.models.earth.weather.PressureTemperatureHumidity; import org.orekit.models.earth.weather.water.CIPM2007; import org.orekit.orbits.FieldKeplerianOrbit; @@ -96,7 +97,8 @@ private > void doTestZenithDelay(final Field> void doTestMappingFactors(final Fiel final double pressure = TroposphericModelUtils.HECTO_PASCAL.toSI(798.4188); final double temperature = 300.15; final double humidity = 0.4; - final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(pressure, + final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(height, + pressure, temperature, new CIPM2007(). waterVaporPressure(pressure, @@ -191,7 +194,9 @@ private > void doTestDelay(final Field fiel final FieldAbsoluteDate date = new FieldAbsoluteDate<>(field); final FieldGeodeticPoint point = new FieldGeodeticPoint<>(zero.add(FastMath.toRadians(45.0)), zero.add(FastMath.toRadians(45.0)), zero.add(height)); MendesPavlisModel model = MendesPavlisModel.getStandardModel(0.6943, TroposphericModelUtils.MICRO_M); - final T path = model.pathDelay(zero.add(FastMath.toRadians(elevation)), point, model.getParameters(field), date); + final T path = model.pathDelay(zero.add(FastMath.toRadians(elevation)), point, + new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + model.getParameters(field), date); Assertions.assertTrue(Precision.compareTo(path.getReal(), 20d, epsilon) < 0); Assertions.assertTrue(Precision.compareTo(path.getReal(), 0d, epsilon) > 0); } @@ -209,7 +214,9 @@ private > void doTestFixedHeight(final Field(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + model.getParameters(field), date); Assertions.assertTrue(Precision.compareTo(delay.getReal(), lastDelay.getReal(), epsilon) < 0); lastDelay = delay; } @@ -231,7 +238,8 @@ public void testDelayStateDerivatives() { final TopocentricFrame baseFrame = new TopocentricFrame(earth, point, "topo"); // Station - final GroundStation station = new GroundStation(baseFrame); + final GroundStation station = new GroundStation(baseFrame, + TroposphericModelUtils.STANDARD_ATMOSPHERE_PROVIDER); // Tropospheric model final MendesPavlisModel model = MendesPavlisModel.getStandardModel(0.65, TroposphericModelUtils.MICRO_M); @@ -263,7 +271,9 @@ public void testDelayStateDerivatives() { // Compute Delay with state derivatives final FieldGeodeticPoint dsPoint = new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), zero.add(height)); - final DerivativeStructure delay = model.pathDelay(dsElevation, dsPoint, model.getParameters(field, dsDate), dsDate); + final DerivativeStructure delay = model.pathDelay(dsElevation, dsPoint, + new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + model.getParameters(field, dsDate), dsDate); final double[] compDeriv = delay.getAllDerivatives(); @@ -283,56 +293,64 @@ public void testDelayStateDerivatives() { final double elevationM4 = station.getBaseFrame(). getTrackingCoordinates(positionM4, stateM4.getFrame(), stateM4.getDate()). getElevation(); - double delayM4 = model.pathDelay(elevationM4, point, model.getParameters(), stateM4.getDate()); + double delayM4 = model.pathDelay(elevationM4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateM4.getDate()); SpacecraftState stateM3 = shiftState(state, orbitType, angleType, -3 * steps[i], i); final Vector3D positionM3 = stateM3.getPosition(); final double elevationM3 = station.getBaseFrame(). getTrackingCoordinates(positionM3, stateM3.getFrame(), stateM3.getDate()). getElevation(); - double delayM3 = model.pathDelay(elevationM3, point, model.getParameters(), stateM3.getDate()); + double delayM3 = model.pathDelay(elevationM3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateM3.getDate()); SpacecraftState stateM2 = shiftState(state, orbitType, angleType, -2 * steps[i], i); final Vector3D positionM2 = stateM2.getPosition(); final double elevationM2 = station.getBaseFrame(). getTrackingCoordinates(positionM2, stateM2.getFrame(), stateM2.getDate()). getElevation(); - double delayM2 = model.pathDelay(elevationM2, point, model.getParameters(), stateM2.getDate()); + double delayM2 = model.pathDelay(elevationM2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateM2.getDate()); SpacecraftState stateM1 = shiftState(state, orbitType, angleType, -1 * steps[i], i); final Vector3D positionM1 = stateM1.getPosition(); final double elevationM1 = station.getBaseFrame(). getTrackingCoordinates(positionM1, stateM1.getFrame(), stateM1.getDate()). getElevation(); - double delayM1 = model.pathDelay(elevationM1, point, model.getParameters(), stateM1.getDate()); + double delayM1 = model.pathDelay(elevationM1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateM1.getDate()); SpacecraftState stateP1 = shiftState(state, orbitType, angleType, 1 * steps[i], i); final Vector3D positionP1 = stateP1.getPosition(); final double elevationP1 = station.getBaseFrame(). getTrackingCoordinates(positionP1, stateP1.getFrame(), stateP1.getDate()). getElevation(); - double delayP1 = model.pathDelay(elevationP1, point, model.getParameters(), stateP1.getDate()); + double delayP1 = model.pathDelay(elevationP1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateP1.getDate()); SpacecraftState stateP2 = shiftState(state, orbitType, angleType, 2 * steps[i], i); final Vector3D positionP2 = stateP2.getPosition(); final double elevationP2 = station.getBaseFrame(). getTrackingCoordinates(positionP2, stateP2.getFrame(), stateP2.getDate()). getElevation(); - double delayP2 = model.pathDelay(elevationP2, point, model.getParameters(), stateP2.getDate()); + double delayP2 = model.pathDelay(elevationP2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateP2.getDate()); SpacecraftState stateP3 = shiftState(state, orbitType, angleType, 3 * steps[i], i); final Vector3D positionP3 = stateP3.getPosition(); final double elevationP3 = station.getBaseFrame(). getTrackingCoordinates(positionP3, stateP3.getFrame(), stateP3.getDate()). getElevation(); - double delayP3 = model.pathDelay(elevationP3, point, model.getParameters(), stateP3.getDate()); + double delayP3 = model.pathDelay(elevationP3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateP3.getDate()); SpacecraftState stateP4 = shiftState(state, orbitType, angleType, 4 * steps[i], i); final Vector3D positionP4 = stateP4.getPosition(); final double elevationP4 = station.getBaseFrame(). getTrackingCoordinates(positionP4, stateP4.getFrame(), stateP4.getDate()). getElevation(); - double delayP4 = model.pathDelay(elevationP4, point, model.getParameters(), stateP4.getDate()); + double delayP4 = model.pathDelay(elevationP4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateP4.getDate()); fillJacobianColumn(refDeriv, i, orbitType, angleType, steps[i], delayM4, delayM3, delayM2, delayM1, diff --git a/src/test/java/org/orekit/models/earth/troposphere/FieldViennaOneModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/FieldViennaOneModelTest.java index d7f83c42b5..1bebb36715 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/FieldViennaOneModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/FieldViennaOneModelTest.java @@ -39,6 +39,7 @@ import org.orekit.frames.Frame; import org.orekit.frames.FramesFactory; import org.orekit.frames.TopocentricFrame; +import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; import org.orekit.orbits.FieldKeplerianOrbit; import org.orekit.orbits.FieldOrbit; import org.orekit.orbits.Orbit; @@ -133,7 +134,9 @@ private > void doTestDelay(final Field fiel final double[] z = {2.0966, 0.2140}; final FieldGeodeticPoint point = new FieldGeodeticPoint<>(zero.add(FastMath.toRadians(45.0)), zero.add(FastMath.toRadians(45.0)), zero.add(height)); ViennaOneModel model = new ViennaOneModel(a, z); - final T path = model.pathDelay(zero.add(FastMath.toRadians(elevation)), point, model.getParameters(field), date); + final T path = model.pathDelay(zero.add(FastMath.toRadians(elevation)), point, + new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + model.getParameters(field), date); Assertions.assertTrue(Precision.compareTo(path.getReal(), 20d, epsilon) < 0); Assertions.assertTrue(Precision.compareTo(path.getReal(), 0d, epsilon) > 0); } @@ -153,7 +156,9 @@ private > void doTestFixedHeight(final Field(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + model.getParameters(field), date); Assertions.assertTrue(Precision.compareTo(delay.getReal(), lastDelay.getReal(), epsilon) < 0); lastDelay = delay; } @@ -175,12 +180,13 @@ public void testDelayStateDerivatives() { final TopocentricFrame baseFrame = new TopocentricFrame(earth, point, "topo"); // Station - final GroundStation station = new GroundStation(baseFrame); + final GroundStation station = new GroundStation(baseFrame, + TroposphericModelUtils.STANDARD_ATMOSPHERE_PROVIDER); // Tropospheric model final double[] a = { 0.00127683, 0.00060955 }; final double[] z = {2.0966, 0.2140}; - final DiscreteTroposphericModel model = new ViennaOneModel(a, z); + final TroposphericModel model = new ViennaOneModel(a, z); // Derivative Structure final DSFactory factory = new DSFactory(6, 1); @@ -210,7 +216,9 @@ public void testDelayStateDerivatives() { // Compute delay state derivatives final FieldGeodeticPoint dsPoint = new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), zero.add(height)); - final DerivativeStructure delay = model.pathDelay(dsElevation, dsPoint, model.getParameters(field), dsDate); + final DerivativeStructure delay = model.pathDelay(dsElevation, dsPoint, + new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + model.getParameters(field), dsDate); final double[] compDelay = delay.getAllDerivatives(); @@ -230,56 +238,64 @@ public void testDelayStateDerivatives() { final double elevationM4 = station.getBaseFrame(). getTrackingCoordinates(positionM4, stateM4.getFrame(), stateM4.getDate()). getElevation(); - double delayM4 = model.pathDelay(elevationM4, point, model.getParameters(), stateM4.getDate()); + double delayM4 = model.pathDelay(elevationM4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateM4.getDate()); SpacecraftState stateM3 = shiftState(state, orbitType, angleType, -3 * steps[i], i); final Vector3D positionM3 = stateM3.getPosition(); final double elevationM3 = station.getBaseFrame(). getTrackingCoordinates(positionM3, stateM3.getFrame(), stateM3.getDate()). getElevation(); - double delayM3 = model.pathDelay(elevationM3, point, model.getParameters(), stateM3.getDate()); + double delayM3 = model.pathDelay(elevationM3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateM3.getDate()); SpacecraftState stateM2 = shiftState(state, orbitType, angleType, -2 * steps[i], i); final Vector3D positionM2 = stateM2.getPosition(); final double elevationM2 = station.getBaseFrame(). getTrackingCoordinates(positionM2, stateM2.getFrame(), stateM2.getDate()). getElevation(); - double delayM2 = model.pathDelay(elevationM2, point, model.getParameters(), stateM2.getDate()); + double delayM2 = model.pathDelay(elevationM2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateM2.getDate()); SpacecraftState stateM1 = shiftState(state, orbitType, angleType, -1 * steps[i], i); final Vector3D positionM1 = stateM1.getPosition(); final double elevationM1 = station.getBaseFrame(). getTrackingCoordinates(positionM1, stateM1.getFrame(), stateM1.getDate()). getElevation(); - double delayM1 = model.pathDelay(elevationM1, point, model.getParameters(), stateM1.getDate()); + double delayM1 = model.pathDelay(elevationM1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateM1.getDate()); SpacecraftState stateP1 = shiftState(state, orbitType, angleType, 1 * steps[i], i); final Vector3D positionP1 = stateP1.getPosition(); final double elevationP1 = station.getBaseFrame(). getTrackingCoordinates(positionP1, stateP1.getFrame(), stateP1.getDate()). getElevation(); - double delayP1 = model.pathDelay(elevationP1, point, model.getParameters(), stateP1.getDate()); + double delayP1 = model.pathDelay(elevationP1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateP1.getDate()); SpacecraftState stateP2 = shiftState(state, orbitType, angleType, 2 * steps[i], i); final Vector3D positionP2 = stateP2.getPosition(); final double elevationP2 = station.getBaseFrame(). getTrackingCoordinates(positionP2, stateP2.getFrame(), stateP2.getDate()). getElevation(); - double delayP2 = model.pathDelay(elevationP2, point, model.getParameters(), stateP2.getDate()); + double delayP2 = model.pathDelay(elevationP2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateP2.getDate()); SpacecraftState stateP3 = shiftState(state, orbitType, angleType, 3 * steps[i], i); final Vector3D positionP3 = stateP3.getPosition(); final double elevationP3 = station.getBaseFrame(). getTrackingCoordinates(positionP3, stateP3.getFrame(), stateP3.getDate()). getElevation(); - double delayP3 = model.pathDelay(elevationP3, point, model.getParameters(), stateP3.getDate()); + double delayP3 = model.pathDelay(elevationP3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateP3.getDate()); SpacecraftState stateP4 = shiftState(state, orbitType, angleType, 4 * steps[i], i); final Vector3D positionP4 = stateP4.getPosition(); final double elevationP4 = station.getBaseFrame(). getTrackingCoordinates(positionP4, stateP4.getFrame(), stateP4.getDate()). getElevation(); - double delayP4 = model.pathDelay(elevationP4, point, model.getParameters(), stateP4.getDate()); + double delayP4 = model.pathDelay(elevationP4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateP4.getDate()); fillJacobianColumn(refDeriv, i, orbitType, angleType, steps[i], delayM4, delayM3, delayM2, delayM1, diff --git a/src/test/java/org/orekit/models/earth/troposphere/FieldViennaThreeModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/FieldViennaThreeModelTest.java index be1c8523f9..c7f28a5f86 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/FieldViennaThreeModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/FieldViennaThreeModelTest.java @@ -39,6 +39,7 @@ import org.orekit.frames.Frame; import org.orekit.frames.FramesFactory; import org.orekit.frames.TopocentricFrame; +import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; import org.orekit.orbits.FieldKeplerianOrbit; import org.orekit.orbits.FieldOrbit; import org.orekit.orbits.Orbit; @@ -241,6 +242,7 @@ private > void doTestDelay(final Field fiel final FieldGeodeticPoint point = new FieldGeodeticPoint<>(zero.add(FastMath.toRadians(37.5)), zero.add(FastMath.toRadians(277.5)), zero.add(height)); ViennaThreeModel model = new ViennaThreeModel(a, z); final T path = model.pathDelay(zero.add(FastMath.toRadians(elevation)), point, + new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), model.getParameters(field), date); Assertions.assertTrue(Precision.compareTo(path.getReal(), 20d, epsilon) < 0); Assertions.assertTrue(Precision.compareTo(path.getReal(), 0d, epsilon) > 0); @@ -262,6 +264,7 @@ private > void doTestFixedHeight(final Field(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), model.getParameters(field), date); Assertions.assertTrue(Precision.compareTo(delay.getReal(), lastDelay.getReal(), epsilon) < 0); lastDelay = delay; @@ -284,12 +287,13 @@ public void testDelayStateDerivatives() { final TopocentricFrame baseFrame = new TopocentricFrame(earth, point, "topo"); // Station - final GroundStation station = new GroundStation(baseFrame); + final GroundStation station = new GroundStation(baseFrame, + TroposphericModelUtils.STANDARD_ATMOSPHERE_PROVIDER); // Tropospheric model final double[] a = { 0.00127683, 0.00060955 }; final double[] z = {2.0966, 0.2140}; - final DiscreteTroposphericModel model = new ViennaThreeModel(a, z); + final TroposphericModel model = new ViennaThreeModel(a, z); // Derivative Structure final DSFactory factory = new DSFactory(6, 1); @@ -319,7 +323,9 @@ public void testDelayStateDerivatives() { // Compute delay state derivatives final FieldGeodeticPoint dsPoint = new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), zero.add(height)); - final DerivativeStructure delay = model.pathDelay(dsElevation, dsPoint, model.getParameters(field), dsDate); + final DerivativeStructure delay = model.pathDelay(dsElevation, dsPoint, + new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + model.getParameters(field), dsDate); final double[] compDelay = delay.getAllDerivatives(); @@ -339,56 +345,64 @@ public void testDelayStateDerivatives() { final double elevationM4 = station.getBaseFrame(). getTrackingCoordinates(positionM4, stateM4.getFrame(), stateM4.getDate()). getElevation(); - double delayM4 = model.pathDelay(elevationM4, point, model.getParameters(), stateM4.getDate()); + double delayM4 = model.pathDelay(elevationM4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateM4.getDate()); SpacecraftState stateM3 = shiftState(state, orbitType, angleType, -3 * steps[i], i); final Vector3D positionM3 = stateM3.getPosition(); final double elevationM3 = station.getBaseFrame(). getTrackingCoordinates(positionM3, stateM3.getFrame(), stateM3.getDate()). getElevation(); - double delayM3 = model.pathDelay(elevationM3, point, model.getParameters(), stateM3.getDate()); + double delayM3 = model.pathDelay(elevationM3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateM3.getDate()); SpacecraftState stateM2 = shiftState(state, orbitType, angleType, -2 * steps[i], i); final Vector3D positionM2 = stateM2.getPosition(); final double elevationM2 = station.getBaseFrame(). getTrackingCoordinates(positionM2, stateM2.getFrame(), stateM2.getDate()). getElevation(); - double delayM2 = model.pathDelay(elevationM2, point, model.getParameters(), stateM2.getDate()); + double delayM2 = model.pathDelay(elevationM2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateM2.getDate()); SpacecraftState stateM1 = shiftState(state, orbitType, angleType, -1 * steps[i], i); final Vector3D positionM1 = stateM1.getPosition(); final double elevationM1 = station.getBaseFrame(). getTrackingCoordinates(positionM1, stateM1.getFrame(), stateM1.getDate()). getElevation(); - double delayM1 = model.pathDelay(elevationM1, point, model.getParameters(), stateM1.getDate()); + double delayM1 = model.pathDelay(elevationM1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateM1.getDate()); SpacecraftState stateP1 = shiftState(state, orbitType, angleType, 1 * steps[i], i); final Vector3D positionP1 = stateP1.getPosition(); final double elevationP1 = station.getBaseFrame(). getTrackingCoordinates(positionP1, stateP1.getFrame(), stateP1.getDate()). getElevation(); - double delayP1 = model.pathDelay(elevationP1, point, model.getParameters(), stateP1.getDate()); + double delayP1 = model.pathDelay(elevationP1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateP1.getDate()); SpacecraftState stateP2 = shiftState(state, orbitType, angleType, 2 * steps[i], i); final Vector3D positionP2 = stateP2.getPosition(); final double elevationP2 = station.getBaseFrame(). getTrackingCoordinates(positionP2, stateP2.getFrame(), stateP2.getDate()). getElevation(); - double delayP2 = model.pathDelay(elevationP2, point, model.getParameters(), stateP2.getDate()); + double delayP2 = model.pathDelay(elevationP2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateP2.getDate()); SpacecraftState stateP3 = shiftState(state, orbitType, angleType, 3 * steps[i], i); final Vector3D positionP3 = stateP3.getPosition(); final double elevationP3 = station.getBaseFrame(). getTrackingCoordinates(positionP3, stateP3.getFrame(), stateP3.getDate()). getElevation(); - double delayP3 = model.pathDelay(elevationP3, point, model.getParameters(), stateP3.getDate()); + double delayP3 = model.pathDelay(elevationP3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateP3.getDate()); SpacecraftState stateP4 = shiftState(state, orbitType, angleType, 4 * steps[i], i); final Vector3D positionP4 = stateP4.getPosition(); final double elevationP4 = station.getBaseFrame(). getTrackingCoordinates(positionP4, stateP4.getFrame(), stateP4.getDate()). getElevation(); - double delayP4 = model.pathDelay(elevationP4, point, model.getParameters(), stateP4.getDate()); + double delayP4 = model.pathDelay(elevationP4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateP4.getDate()); fillJacobianColumn(refDeriv, i, orbitType, angleType, steps[i], delayM4, delayM3, delayM2, delayM1, diff --git a/src/test/java/org/orekit/models/earth/troposphere/FixedTroposphericModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/FixedTroposphericModelTest.java index 356a897209..7c1cbc7817 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/FixedTroposphericModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/FixedTroposphericModelTest.java @@ -28,6 +28,7 @@ import org.orekit.Utils; import org.orekit.bodies.FieldGeodeticPoint; import org.orekit.bodies.GeodeticPoint; +import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; @@ -35,25 +36,39 @@ public class FixedTroposphericModelTest { private static double epsilon = 1e-6; - private DiscreteTroposphericModel model; + private TroposphericModel model; @Test public void testModel() { // check with (artificial) test values from tropospheric-delay.txt - Assertions.assertEquals(2.5d, model.pathDelay(FastMath.toRadians(90d), new GeodeticPoint(0., 0., 0.), null, AbsoluteDate.J2000_EPOCH), epsilon); - Assertions.assertEquals(20.8d, model.pathDelay(FastMath.toRadians(0d), new GeodeticPoint(0., 0., 0.), null, AbsoluteDate.J2000_EPOCH), epsilon); - - Assertions.assertEquals(12.1d, model.pathDelay(FastMath.toRadians(0d), new GeodeticPoint(0., 0., 5000.), null, AbsoluteDate.J2000_EPOCH), epsilon); - Assertions.assertEquals(2.5d, model.pathDelay(FastMath.toRadians(90d), new GeodeticPoint(0., 0., 5000.), null, AbsoluteDate.J2000_EPOCH), epsilon); + Assertions.assertEquals(2.5d, model.pathDelay(FastMath.toRadians(90d), new GeodeticPoint(0., 0., 0.), + TroposphericModelUtils.STANDARD_ATMOSPHERE, + null, AbsoluteDate.J2000_EPOCH), epsilon); + Assertions.assertEquals(20.8d, model.pathDelay(FastMath.toRadians(0d), new GeodeticPoint(0., 0., 0.), + TroposphericModelUtils.STANDARD_ATMOSPHERE, + null, AbsoluteDate.J2000_EPOCH), epsilon); + + Assertions.assertEquals(12.1d, model.pathDelay(FastMath.toRadians(0d), new GeodeticPoint(0., 0., 5000.), + TroposphericModelUtils.STANDARD_ATMOSPHERE, + null, AbsoluteDate.J2000_EPOCH), epsilon); + Assertions.assertEquals(2.5d, model.pathDelay(FastMath.toRadians(90d), new GeodeticPoint(0., 0., 5000.), + TroposphericModelUtils.STANDARD_ATMOSPHERE, + null, AbsoluteDate.J2000_EPOCH), epsilon); // interpolation between two elevation angles in the table - final double delay = model.pathDelay(FastMath.toRadians(35d), new GeodeticPoint(0., 0., 1200.), null, AbsoluteDate.J2000_EPOCH); + final double delay = model.pathDelay(FastMath.toRadians(35d), new GeodeticPoint(0., 0., 1200.), + TroposphericModelUtils.STANDARD_ATMOSPHERE, + null, AbsoluteDate.J2000_EPOCH); Assertions.assertTrue(Precision.compareTo(delay, 6.4d, epsilon) < 0); Assertions.assertTrue(Precision.compareTo(delay, 3.2d, epsilon) > 0); // sanity checks - Assertions.assertEquals(12.1d, model.pathDelay(FastMath.toRadians(-20d), new GeodeticPoint(0., 0., 5000.), null, AbsoluteDate.J2000_EPOCH), epsilon); - Assertions.assertEquals(2.5d, model.pathDelay(FastMath.toRadians(90d), new GeodeticPoint(0., 0., 100000.), null, AbsoluteDate.J2000_EPOCH), epsilon); + Assertions.assertEquals(12.1d, model.pathDelay(FastMath.toRadians(-20d), new GeodeticPoint(0., 0., 5000.), + TroposphericModelUtils.STANDARD_ATMOSPHERE, + null, AbsoluteDate.J2000_EPOCH), epsilon); + Assertions.assertEquals(2.5d, model.pathDelay(FastMath.toRadians(90d), new GeodeticPoint(0., 0., 100000.), + TroposphericModelUtils.STANDARD_ATMOSPHERE, + null, AbsoluteDate.J2000_EPOCH), epsilon); } @Test @@ -64,27 +79,43 @@ public void testFieldModel() { private > void doTestFieldModel(final Field field) { final T zero = field.getZero(); // check with (artificial) test values from tropospheric-delay.txt - Assertions.assertEquals(2.5d, model.pathDelay(zero.add(FastMath.toRadians(90d)), new FieldGeodeticPoint(zero, zero, zero), null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), epsilon); - Assertions.assertEquals(20.8d, model.pathDelay(zero.add(FastMath.toRadians(0d)), new FieldGeodeticPoint(zero, zero, zero), null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), epsilon); - - Assertions.assertEquals(12.1d, model.pathDelay(zero.add(FastMath.toRadians(0d)), new FieldGeodeticPoint(zero, zero, zero.add(5000.0)), null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), epsilon); - Assertions.assertEquals(2.5d, model.pathDelay(zero.add(FastMath.toRadians(90d)), new FieldGeodeticPoint(zero, zero, zero.add(5000.0)), null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), epsilon); + Assertions.assertEquals(2.5d, model.pathDelay(zero.add(FastMath.toRadians(90d)), new FieldGeodeticPoint(zero, zero, zero), + new FieldPressureTemperatureHumidity(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), epsilon); + Assertions.assertEquals(20.8d, model.pathDelay(zero.add(FastMath.toRadians(0d)), new FieldGeodeticPoint(zero, zero, zero), + new FieldPressureTemperatureHumidity(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), epsilon); + + Assertions.assertEquals(12.1d, model.pathDelay(zero.add(FastMath.toRadians(0d)), new FieldGeodeticPoint(zero, zero, zero.add(5000.0)), + new FieldPressureTemperatureHumidity(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), epsilon); + Assertions.assertEquals(2.5d, model.pathDelay(zero.add(FastMath.toRadians(90d)), new FieldGeodeticPoint(zero, zero, zero.add(5000.0)), + new FieldPressureTemperatureHumidity(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), epsilon); // interpolation between two elevation angles in the table - final double delay = model.pathDelay(zero.add(FastMath.toRadians(35d)), new FieldGeodeticPoint(zero, zero, zero.add(1200.0)), null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(); + final double delay = model.pathDelay(zero.add(FastMath.toRadians(35d)), new FieldGeodeticPoint(zero, zero, zero.add(1200.0)), + new FieldPressureTemperatureHumidity(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(); Assertions.assertTrue(Precision.compareTo(delay, 6.4d, epsilon) < 0); Assertions.assertTrue(Precision.compareTo(delay, 3.2d, epsilon) > 0); // sanity checks - Assertions.assertEquals(12.1d, model.pathDelay(zero.add(FastMath.toRadians(-20d)), new FieldGeodeticPoint(zero, zero, zero.add(5000.0)), null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), epsilon); - Assertions.assertEquals(2.5d, model.pathDelay(zero.add(FastMath.toRadians(90d)), new FieldGeodeticPoint(zero, zero, zero.add(100000.0)), null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), epsilon); + Assertions.assertEquals(12.1d, model.pathDelay(zero.add(FastMath.toRadians(-20d)), new FieldGeodeticPoint(zero, zero, zero.add(5000.0)), + new FieldPressureTemperatureHumidity(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), epsilon); + Assertions.assertEquals(2.5d, model.pathDelay(zero.add(FastMath.toRadians(90d)), new FieldGeodeticPoint(zero, zero, zero.add(100000.0)), + new FieldPressureTemperatureHumidity(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), epsilon); } @Test public void testSymmetry() { for (int elevation = 0; elevation < 90; elevation += 10) { - final double delay1 = model.pathDelay(FastMath.toRadians(elevation), new GeodeticPoint(0., 0., 100.), null, AbsoluteDate.J2000_EPOCH); - final double delay2 = model.pathDelay(FastMath.toRadians(180 - elevation), new GeodeticPoint(0., 0., 100.), null, AbsoluteDate.J2000_EPOCH); + final double delay1 = model.pathDelay(FastMath.toRadians(elevation), new GeodeticPoint(0., 0., 100.), + TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH); + final double delay2 = model.pathDelay(FastMath.toRadians(180 - elevation), new GeodeticPoint(0., 0., 100.), + TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH); Assertions.assertEquals(delay1, delay2, epsilon); } @@ -100,11 +131,13 @@ private > void doTestFieldSymmetry(final Field for (int elevation = 0; elevation < 90; elevation += 10) { final T delay1 = model.pathDelay(zero.add(FastMath.toRadians(elevation)), new FieldGeodeticPoint(zero, zero, zero.add(100.)), + new FieldPressureTemperatureHumidity(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), null, FieldAbsoluteDate.getJ2000Epoch(field)); final T delay2 = model.pathDelay(zero.add(FastMath.toRadians(180 - elevation)), new FieldGeodeticPoint(zero, zero, zero.add(100.)), - null, + new FieldPressureTemperatureHumidity(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + null, FieldAbsoluteDate.getJ2000Epoch(field)); Assertions.assertEquals(delay1.getReal(), delay2.getReal(), epsilon); diff --git a/src/test/java/org/orekit/models/earth/troposphere/MariniMurrayModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/MariniMurrayModelTest.java index 687cc14efd..982cdbe74c 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/MariniMurrayModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/MariniMurrayModelTest.java @@ -28,6 +28,7 @@ import org.orekit.Utils; import org.orekit.bodies.FieldGeodeticPoint; import org.orekit.bodies.GeodeticPoint; +import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; @@ -56,8 +57,9 @@ public void testDelay() { final double height = 100d; // ruby laser with wavelength 694.3 nm - DiscreteTroposphericModel model = MariniMurrayModel.getStandardModel(694.3, TroposphericModelUtils.NANO_M); - final double path = model.pathDelay(FastMath.toRadians(elevation), new GeodeticPoint(latitude, longitude, height), null, AbsoluteDate.J2000_EPOCH); + TroposphericModel model = MariniMurrayModel.getStandardModel(694.3, TroposphericModelUtils.NANO_M); + final double path = model.pathDelay(FastMath.toRadians(elevation), new GeodeticPoint(latitude, longitude, height), + TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH); Assertions.assertTrue(Precision.compareTo(path, 20d, epsilon) < 0); Assertions.assertTrue(Precision.compareTo(path, 0d, epsilon) > 0); @@ -70,8 +72,9 @@ public void testDeprecatedConstructor1() { final double height = 100d; // ruby laser with wavelength 694.3 nm - DiscreteTroposphericModel model = MariniMurrayModel.getStandardModel(694.3); - final double path = model.pathDelay(FastMath.toRadians(elevation), new GeodeticPoint(latitude, longitude, height), null, AbsoluteDate.J2000_EPOCH); + TroposphericModel model = MariniMurrayModel.getStandardModel(694.3); + final double path = model.pathDelay(FastMath.toRadians(elevation), new GeodeticPoint(latitude, longitude, height), + TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH); Assertions.assertTrue(Precision.compareTo(path, 20d, epsilon) < 0); Assertions.assertTrue(Precision.compareTo(path, 0d, epsilon) > 0); @@ -84,8 +87,9 @@ public void testDeprecatedConstructor2() { final double height = 100d; // ruby laser with wavelength 694.3 nm - DiscreteTroposphericModel model = new MariniMurrayModel(273.15 + 20, 1013.25, 0.5, 694.3); - final double path = model.pathDelay(FastMath.toRadians(elevation), new GeodeticPoint(latitude, longitude, height), null, AbsoluteDate.J2000_EPOCH); + TroposphericModel model = new MariniMurrayModel(273.15 + 20, 1013.25, 0.5, 694.3); + final double path = model.pathDelay(FastMath.toRadians(elevation), new GeodeticPoint(latitude, longitude, height), + TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH); Assertions.assertTrue(Precision.compareTo(path, 20d, epsilon) < 0); Assertions.assertTrue(Precision.compareTo(path, 0d, epsilon) > 0); @@ -102,8 +106,10 @@ private > void doTestFieldDelay(final Field final T height = zero.add(100d); // ruby laser with wavelength 694.3 nm - DiscreteTroposphericModel model = MariniMurrayModel.getStandardModel(694.3, TroposphericModelUtils.NANO_M); - final T path = model.pathDelay(elevation, new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), height), null, FieldAbsoluteDate.getJ2000Epoch(field)); + TroposphericModel model = MariniMurrayModel.getStandardModel(694.3, TroposphericModelUtils.NANO_M); + final T path = model.pathDelay(elevation, new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), height), + new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + null, FieldAbsoluteDate.getJ2000Epoch(field)); Assertions.assertTrue(Precision.compareTo(path.getReal(), 20d, epsilon) < 0); Assertions.assertTrue(Precision.compareTo(path.getReal(), 0d, epsilon) > 0); @@ -112,11 +118,12 @@ private > void doTestFieldDelay(final Field @Test public void testFixedHeight() { // ruby laser with wavelength 694.3 nm - DiscreteTroposphericModel model = MariniMurrayModel.getStandardModel(694.3, TroposphericModelUtils.NANO_M); + TroposphericModel model = MariniMurrayModel.getStandardModel(694.3, TroposphericModelUtils.NANO_M); double lastDelay = Double.MAX_VALUE; // delay shall decline with increasing elevation angle for (double elev = 10d; elev < 90d; elev += 8d) { - final double delay = model.pathDelay(FastMath.toRadians(elev), new GeodeticPoint(latitude, longitude, 350.0), null, AbsoluteDate.J2000_EPOCH); + final double delay = model.pathDelay(FastMath.toRadians(elev), new GeodeticPoint(latitude, longitude, 350.0), + TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH); Assertions.assertTrue(Precision.compareTo(delay, lastDelay, epsilon) < 0); lastDelay = delay; } @@ -129,12 +136,14 @@ public void testFieldFixedHeight() { private > void doTestFieldFixedHeight(final Field field) { // ruby laser with wavelength 694.3 nm - DiscreteTroposphericModel model = MariniMurrayModel.getStandardModel(694.3, TroposphericModelUtils.NANO_M); + TroposphericModel model = MariniMurrayModel.getStandardModel(694.3, TroposphericModelUtils.NANO_M); final T zero = field.getZero(); T lastDelay = zero.add(Double.MAX_VALUE); // delay shall decline with increasing elevation angle for (double elev = 10d; elev < 90d; elev += 8d) { - final T delay = model.pathDelay(zero.add(FastMath.toRadians(elev)), new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), zero.add(350.0)), null, FieldAbsoluteDate.getJ2000Epoch(field)); + final T delay = model.pathDelay(zero.add(FastMath.toRadians(elev)), new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), zero.add(350.0)), + new FieldPressureTemperatureHumidity(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + null, FieldAbsoluteDate.getJ2000Epoch(field)); Assertions.assertTrue(Precision.compareTo(delay.getReal(), lastDelay.getReal(), epsilon) < 0); lastDelay = delay; } @@ -144,12 +153,13 @@ private > void doTestFieldFixedHeight(final Fi public void compareExpectedValues() { // ruby laser with wavelength 694.3 nm - DiscreteTroposphericModel model = MariniMurrayModel.getStandardModel(694.3, TroposphericModelUtils.NANO_M); + TroposphericModel model = MariniMurrayModel.getStandardModel(694.3, TroposphericModelUtils.NANO_M); double height = 0; double elevation = 10; double expectedValue = 13.26069; - double actualValue = model.pathDelay(FastMath.toRadians(elevation), new GeodeticPoint(latitude, longitude, height), null, AbsoluteDate.J2000_EPOCH); + double actualValue = model.pathDelay(FastMath.toRadians(elevation), new GeodeticPoint(latitude, longitude, height), + TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH); Assertions.assertEquals(expectedValue, actualValue, 1.0e-5); } @@ -162,13 +172,15 @@ public void compareFieldExpectedValue() { private > void doCompareFieldExpectedValues(final Field field) { // ruby laser with wavelength 694.3 nm - DiscreteTroposphericModel model = MariniMurrayModel.getStandardModel(694.3, TroposphericModelUtils.NANO_M); + TroposphericModel model = MariniMurrayModel.getStandardModel(694.3, TroposphericModelUtils.NANO_M); T zero = field.getZero(); T height = zero; T elevation = zero.add(FastMath.toRadians(10)); double expectedValue = 13.26069; - T actualValue = model.pathDelay(elevation, new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), height), null, FieldAbsoluteDate.getJ2000Epoch(field)); + T actualValue = model.pathDelay(elevation, new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), height), + new FieldPressureTemperatureHumidity(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + null, FieldAbsoluteDate.getJ2000Epoch(field)); Assertions.assertEquals(expectedValue, actualValue.getReal(), 1.0e-5); } diff --git a/src/test/java/org/orekit/models/earth/troposphere/MendesPavlisModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/MendesPavlisModelTest.java index 60141c9d14..cc0342673d 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/MendesPavlisModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/MendesPavlisModelTest.java @@ -69,7 +69,8 @@ public void testZenithDelay() { final double pressure = TroposphericModelUtils.HECTO_PASCAL.toSI(798.4188); final double temperature = 300.15; final double humidity = 0.4; - final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(pressure, + final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(height, + pressure, temperature, new CIPM2007(). waterVaporPressure(pressure, @@ -124,7 +125,8 @@ public void testMappingFactors() { final double pressure = TroposphericModelUtils.HECTO_PASCAL.toSI(798.4188); final double temperature = 300.15; final double humidity = 0.4; - final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(pressure, + final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(height, + pressure, temperature, new CIPM2007(). waterVaporPressure(pressure, @@ -154,7 +156,9 @@ public void testDelay() { final AbsoluteDate date = new AbsoluteDate(); final GeodeticPoint point = new GeodeticPoint(FastMath.toRadians(45.0), FastMath.toRadians(45.0), height); MendesPavlisModel model = MendesPavlisModel.getStandardModel( 0.6943, TroposphericModelUtils.MICRO_M); - final double path = model.pathDelay(FastMath.toRadians(elevation), point, model.getParameters(), date); + final double path = model.pathDelay(FastMath.toRadians(elevation), point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), date); Assertions.assertTrue(Precision.compareTo(path, 20d, epsilon) < 0); Assertions.assertTrue(Precision.compareTo(path, 0d, epsilon) > 0); } @@ -167,7 +171,9 @@ public void testFixedHeight() { double lastDelay = Double.MAX_VALUE; // delay shall decline with increasing elevation angle for (double elev = 10d; elev < 90d; elev += 8d) { - final double delay = model.pathDelay(FastMath.toRadians(elev), point, model.getParameters(), date); + final double delay = model.pathDelay(FastMath.toRadians(elev), point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), date); Assertions.assertTrue(Precision.compareTo(delay, lastDelay, epsilon) < 0); lastDelay = delay; } diff --git a/src/test/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModelTest.java index 85367790ec..708786990c 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModelTest.java @@ -30,6 +30,7 @@ import org.orekit.errors.OrekitException; import org.orekit.errors.OrekitMessages; import org.orekit.models.earth.weather.ConstantPressureTemperatureHumidityProvider; +import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; import org.orekit.models.earth.weather.PressureTemperatureHumidity; import org.orekit.models.earth.weather.PressureTemperatureHumidityProvider; import org.orekit.time.AbsoluteDate; @@ -53,7 +54,9 @@ public void testFixedElevation() { double lastDelay = Double.MAX_VALUE; // delay shall decline with increasing height of the station for (double height = 0; height < 5000; height += 100) { - final double delay = model.pathDelay(FastMath.toRadians(5), new GeodeticPoint(0.0, 0.0, height), null, AbsoluteDate.J2000_EPOCH); + final double delay = model.pathDelay(FastMath.toRadians(5), new GeodeticPoint(0.0, 0.0, height), + TroposphericModelUtils.STANDARD_ATMOSPHERE, + null, AbsoluteDate.J2000_EPOCH); Assertions.assertTrue(Precision.compareTo(delay, lastDelay, epsilon) < 0); lastDelay = delay; } @@ -71,7 +74,9 @@ private > void doTestFieldFixedElevation(final T lastDelay = zero.add(Double.MAX_VALUE); // delay shall decline with increasing height of the station for (double height = 0; height < 5000; height += 100) { - final T delay = model.pathDelay(zero.add(FastMath.toRadians(5)), new FieldGeodeticPoint<>(zero, zero, zero.add(height)), null, FieldAbsoluteDate.getJ2000Epoch(field)); + final T delay = model.pathDelay(zero.add(FastMath.toRadians(5)), new FieldGeodeticPoint<>(zero, zero, zero.add(height)), + new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + null, FieldAbsoluteDate.getJ2000Epoch(field)); Assertions.assertTrue(Precision.compareTo(delay.getReal(), lastDelay.getReal(), epsilon) < 0); lastDelay = delay; } @@ -84,7 +89,9 @@ public void testFixedHeight() { double lastDelay = Double.MAX_VALUE; // delay shall decline with increasing elevation angle for (double elev = 10d; elev < 90d; elev += 8d) { - final double delay = model.pathDelay(FastMath.toRadians(elev), new GeodeticPoint(0.0, 0.0, 350.0), null, AbsoluteDate.J2000_EPOCH); + final double delay = model.pathDelay(FastMath.toRadians(elev), new GeodeticPoint(0.0, 0.0, 350.0), + TroposphericModelUtils.STANDARD_ATMOSPHERE, + null, AbsoluteDate.J2000_EPOCH); Assertions.assertTrue(Precision.compareTo(delay, lastDelay, epsilon) < 0); lastDelay = delay; } @@ -102,7 +109,9 @@ private > void doTestFieldFixedHeight(final Fi T lastDelay = zero.add(Double.MAX_VALUE); // delay shall decline with increasing elevation angle for (double elev = 10d; elev < 90d; elev += 8d) { - final T delay = model.pathDelay(zero.add(FastMath.toRadians(elev)), new FieldGeodeticPoint<>(zero, zero, zero.add(350.0)), null, FieldAbsoluteDate.getJ2000Epoch(field)); + final T delay = model.pathDelay(zero.add(FastMath.toRadians(elev)), new FieldGeodeticPoint<>(zero, zero, zero.add(350.0)), + new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + null, FieldAbsoluteDate.getJ2000Epoch(field)); Assertions.assertTrue(Precision.compareTo(delay.getReal(), lastDelay.getReal(), epsilon) < 0); lastDelay = delay; } @@ -112,15 +121,16 @@ private > void doTestFieldFixedHeight(final Fi public void NoFile() { Utils.setDataRoot("atmosphere"); try { + final double altitude = 0.0; final double temperature = 273.15 + 18; final double pressure = TroposphericModelUtils.HECTO_PASCAL.toSI(1013.25); final double humidity = 0.5; final double waterPressure = ModifiedSaastamoinenModel.WATER.waterVaporPressure(pressure, temperature, humidity); - final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(pressure, temperature, waterPressure); + final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(altitude, pressure, temperature, waterPressure); final PressureTemperatureHumidityProvider pthProvider = new ConstantPressureTemperatureHumidityProvider(pth); - new ModifiedSaastamoinenModel(0.0, pthProvider, "^non-existent-file$"); + new ModifiedSaastamoinenModel(pthProvider, "^non-existent-file$"); Assertions.fail("an exception should have been thrown"); } catch (OrekitException oe) { Assertions.assertEquals(OrekitMessages.UNABLE_TO_FIND_FILE, oe.getSpecifier()); @@ -131,16 +141,17 @@ public void NoFile() { @Test public void compareDefaultAndLoaded() { Utils.setDataRoot("atmosphere"); + final double altitude = 0.0; final double temperature = 273.15 + 18; final double pressure = TroposphericModelUtils.HECTO_PASCAL.toSI(1013.25); final double humidity = 0.5; final double waterPressure = ModifiedSaastamoinenModel.WATER.waterVaporPressure(pressure, temperature, humidity); - final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(pressure, temperature, waterPressure); + final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(altitude, pressure, temperature, waterPressure); final PressureTemperatureHumidityProvider pthProvider = new ConstantPressureTemperatureHumidityProvider(pth); - ModifiedSaastamoinenModel defaultModel = new ModifiedSaastamoinenModel(0.0, pthProvider, null); - ModifiedSaastamoinenModel loadedModel = new ModifiedSaastamoinenModel(0.0, pthProvider, ModifiedSaastamoinenModel.DELTA_R_FILE_NAME); + ModifiedSaastamoinenModel defaultModel = new ModifiedSaastamoinenModel(pthProvider, null); + ModifiedSaastamoinenModel loadedModel = new ModifiedSaastamoinenModel(pthProvider, ModifiedSaastamoinenModel.DELTA_R_FILE_NAME); double[] heights = new double[] { 0.0, 250.0, 500.0, 750.0, 1000.0, 1250.0, 1500.0, 1750.0, 2000.0, 2250.0, 2500.0, 2750.0, 3000.0, 3250.0, 3500.0, 3750.0, 4000.0, 4250.0, 4500.0, 4750.0, 5000.0 @@ -157,8 +168,12 @@ public void compareDefaultAndLoaded() { for (int e = 0; e < elevations.length; e++) { double height = heights[h]; double elevation = elevations[e]; - double expectedValue = defaultModel.pathDelay(elevation, new GeodeticPoint(0.0, 0.0, height), null, AbsoluteDate.J2000_EPOCH); - double actualValue = loadedModel.pathDelay(elevation, new GeodeticPoint(0.0, 0.0, height), null, AbsoluteDate.J2000_EPOCH); + double expectedValue = defaultModel.pathDelay(elevation, new GeodeticPoint(0.0, 0.0, height), + TroposphericModelUtils.STANDARD_ATMOSPHERE, + null, AbsoluteDate.J2000_EPOCH); + double actualValue = loadedModel.pathDelay(elevation, new GeodeticPoint(0.0, 0.0, height), + TroposphericModelUtils.STANDARD_ATMOSPHERE, + null, AbsoluteDate.J2000_EPOCH); Assertions.assertEquals(expectedValue, actualValue, epsilon, "For height=" + height + " elevation = " + FastMath.toDegrees(elevation) + " precision not met"); } @@ -171,8 +186,12 @@ public void testNegativeHeight() { ModifiedSaastamoinenModel model = ModifiedSaastamoinenModel.getStandardModel(); final double height = -500.0; for (double elevation = 0; elevation < FastMath.PI; elevation += 0.1) { - Assertions.assertEquals(model.pathDelay(elevation, new GeodeticPoint(0.0, 0.0, 0.0), null, AbsoluteDate.J2000_EPOCH), - model.pathDelay(elevation, new GeodeticPoint(0.0, 0.0, height), null, AbsoluteDate.J2000_EPOCH), + Assertions.assertEquals(model.pathDelay(elevation, new GeodeticPoint(0.0, 0.0, 0.0), + TroposphericModelUtils.STANDARD_ATMOSPHERE, + null, AbsoluteDate.J2000_EPOCH), + model.pathDelay(elevation, new GeodeticPoint(0.0, 0.0, height), + TroposphericModelUtils.STANDARD_ATMOSPHERE, + null, AbsoluteDate.J2000_EPOCH), 1.e-10); } } @@ -188,8 +207,12 @@ private > void doTestFieldNegativeHeight(final ModifiedSaastamoinenModel model = ModifiedSaastamoinenModel.getStandardModel(); final T height = zero.subtract(500.0); for (double elevation = 0; elevation < FastMath.PI; elevation += 0.1) { - Assertions.assertEquals(model.pathDelay(zero.add(elevation), new FieldGeodeticPoint<>(zero, zero, zero), null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), - model.pathDelay(zero.add(elevation), new FieldGeodeticPoint<>(zero, zero, zero.add(height)), null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), + Assertions.assertEquals(model.pathDelay(zero.add(elevation), new FieldGeodeticPoint<>(zero, zero, zero), + new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), + model.pathDelay(zero.add(elevation), new FieldGeodeticPoint<>(zero, zero, zero.add(height)), + new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), 1.e-10); } } @@ -205,9 +228,13 @@ public void testIssue654LowElevation() { // Reset to default value model.setLowElevationThreshold(ModifiedSaastamoinenModel.DEFAULT_LOW_ELEVATION_THRESHOLD); - double lowElevationPathDelay = model.pathDelay(0.001, new GeodeticPoint(0.0, 0.0, 0.0), null, AbsoluteDate.J2000_EPOCH); + double lowElevationPathDelay = model.pathDelay(0.001, new GeodeticPoint(0.0, 0.0, 0.0), + TroposphericModelUtils.STANDARD_ATMOSPHERE, + null, AbsoluteDate.J2000_EPOCH); Assertions.assertTrue(lowElevationPathDelay > 0.); - Assertions.assertEquals(model.pathDelay(model.getLowElevationThreshold(), new GeodeticPoint(0.0, 0.0, 0.0), null, AbsoluteDate.J2000_EPOCH), + Assertions.assertEquals(model.pathDelay(model.getLowElevationThreshold(), new GeodeticPoint(0.0, 0.0, 0.0), + TroposphericModelUtils.STANDARD_ATMOSPHERE, + null, AbsoluteDate.J2000_EPOCH), lowElevationPathDelay, 1.e-10); } @@ -219,10 +246,12 @@ private > void doTestFieldLowElevation(final F Utils.setDataRoot("atmosphere"); ModifiedSaastamoinenModel model = ModifiedSaastamoinenModel.getStandardModel(); final T elevation = zero.add(0.001); - double lowElevationPathDelay = model.pathDelay(zero.add(elevation), new FieldGeodeticPoint<>(zero, zero, zero), null, - FieldAbsoluteDate.getJ2000Epoch(field)).getReal(); + double lowElevationPathDelay = model.pathDelay(zero.add(elevation), new FieldGeodeticPoint<>(zero, zero, zero), + new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(); double thresholdElevationPathDelay = model.pathDelay(zero.add(model.getLowElevationThreshold()), new FieldGeodeticPoint<>(zero, zero, zero), - null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(); + new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(); Assertions.assertTrue(lowElevationPathDelay > 0.); Assertions.assertEquals(thresholdElevationPathDelay, lowElevationPathDelay, 1.e-10); } @@ -236,22 +265,28 @@ public void compareExpectedValues() { // which is probably due to a similar error in equation 5.97 of // Guochang Xu, GPS - Theory, Algorithms and Applications, Springer, 2007 // so for the sake of the test, we use a temperature of 18.01°C and not the standard atmosphere at 18.00°C + final double altitude = 0.0; final double temperature = 273.15 + 18.01; final double humidity = 0.5; - final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(pressure, + final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(altitude, + pressure, temperature, ModifiedSaastamoinenModel.WATER.waterVaporPressure(pressure, temperature, humidity)); final PressureTemperatureHumidityProvider pth0Provider = new ConstantPressureTemperatureHumidityProvider(pth); - ModifiedSaastamoinenModel model = new ModifiedSaastamoinenModel(0.0, pth0Provider); + ModifiedSaastamoinenModel model = new ModifiedSaastamoinenModel(pth0Provider); for (int h = 0; h < heights.length; h++) { for (int e = 0; e < elevations.length; e++) { double height = heights[h]; double elevation = elevations[e]; double expectedValue = expectedValues[h][e]; - double actualValue = model.pathDelay(elevation, new GeodeticPoint(0.0, 0.0, height), null, AbsoluteDate.J2000_EPOCH); + final GeodeticPoint location = new GeodeticPoint(0.0, 0.0, height); + final AbsoluteDate date = AbsoluteDate.J2000_EPOCH; + double actualValue = model.pathDelay(elevation, location, + pth0Provider.getWeatherParamerers(location, date), + null, date); Assertions.assertEquals(expectedValue, actualValue, epsilon, "For height=" + height + " elevation = " + FastMath.toDegrees(elevation) + " precision not met"); } @@ -270,22 +305,28 @@ private > void doCompareFieldExpectedValues(fi // it seems the reference values for the test have been computed using a wrong conversion // between Celsius and Kelvin (273.16 offset instead of 273.15) // so for the sake of the test, we use a temperature of 18.01°C and not the standard atmosphere at 18.00°C + final double altitude = 0.0; final double temperature = 273.15 + 18.01; final double humidity = 0.5; - final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(pressure, + final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(altitude, + pressure, temperature, ModifiedSaastamoinenModel.WATER.waterVaporPressure(pressure, temperature, humidity)); final PressureTemperatureHumidityProvider pth0Provider = new ConstantPressureTemperatureHumidityProvider(pth); - ModifiedSaastamoinenModel model = new ModifiedSaastamoinenModel(0.0, pth0Provider); + ModifiedSaastamoinenModel model = new ModifiedSaastamoinenModel(pth0Provider); for (int h = 0; h < heights.length; h++) { for (int e = 0; e < elevations.length; e++) { T height = zero.add(heights[h]); T elevation = zero.add(elevations[e]); double expectedValue = expectedValues[h][e]; - T actualValue = model.pathDelay(elevation, new FieldGeodeticPoint<>(zero, zero, zero.add(height)), null, FieldAbsoluteDate.getJ2000Epoch(field)); + FieldGeodeticPoint location = new FieldGeodeticPoint<>(zero, zero, zero.add(height)); + FieldAbsoluteDate date = FieldAbsoluteDate.getJ2000Epoch(field); + T actualValue = model.pathDelay(elevation, location, + pth0Provider.getWeatherParamerers(location, date), + null, date); Assertions.assertEquals(expectedValue, actualValue.getReal(), epsilon, "For height=" + height + " elevation = " + FastMath.toDegrees(elevation.getReal()) + " precision not met"); } @@ -298,7 +339,13 @@ public void testIssue572() { ModifiedSaastamoinenModel model = ModifiedSaastamoinenModel.getStandardModel(); final double height = 6000.0; for (double elevation = 0; elevation < FastMath.PI; elevation += 0.1) { - Assertions.assertEquals(model.pathDelay(elevation, new GeodeticPoint(0.0, 0.0, 5000.0), null, AbsoluteDate.J2000_EPOCH), model.pathDelay(elevation, new GeodeticPoint(0.0, 0.0, height), null, AbsoluteDate.J2000_EPOCH), 1.e-10); + Assertions.assertEquals(model.pathDelay(elevation, new GeodeticPoint(0.0, 0.0, 5000.0), + TroposphericModelUtils.STANDARD_ATMOSPHERE, + null, AbsoluteDate.J2000_EPOCH), + model.pathDelay(elevation, new GeodeticPoint(0.0, 0.0, height), + TroposphericModelUtils.STANDARD_ATMOSPHERE, + null, AbsoluteDate.J2000_EPOCH), + 1.e-10); } } @@ -313,9 +360,13 @@ private > void doTestFieldIssue572(final Field ModifiedSaastamoinenModel model = ModifiedSaastamoinenModel.getStandardModel(); final T height = zero.add(6000.0); for (double elevation = 0; elevation < FastMath.PI; elevation += 0.1) { - Assertions.assertEquals(model.pathDelay(zero.add(elevation),new FieldGeodeticPoint<>(zero, zero, zero.add(5000.0)), null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), - model.pathDelay(zero.add(elevation), new FieldGeodeticPoint<>(zero, zero, zero.add(height)), null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), - 1.e-10); + Assertions.assertEquals(model.pathDelay(zero.add(elevation),new FieldGeodeticPoint<>(zero, zero, zero.add(5000.0)), + new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), + model.pathDelay(zero.add(elevation), new FieldGeodeticPoint<>(zero, zero, zero.add(height)), + new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), + 1.e-10); } } diff --git a/src/test/java/org/orekit/models/earth/troposphere/SaastamoinenModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/SaastamoinenModelTest.java index e02b8b1c77..11ddc7f7b0 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/SaastamoinenModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/SaastamoinenModelTest.java @@ -232,7 +232,9 @@ public void compareExpectedValues() { double height = heights[h]; double elevation = elevations[e]; double expectedValue = expectedValues[h][e]; - double actualValue = model.pathDelay(elevation, new GeodeticPoint(0.0, 0.0, height), null, AbsoluteDate.J2000_EPOCH); + final GeodeticPoint location = new GeodeticPoint(0.0, 0.0, height); + final AbsoluteDate date = AbsoluteDate.J2000_EPOCH; + double actualValue = model.pathDelay(elevation, location, null, date); Assertions.assertEquals(expectedValue, actualValue, epsilon, "For height=" + height + " elevation = " + FastMath.toDegrees(elevation) + " precision not met"); } @@ -254,7 +256,9 @@ private > void doCompareFieldExpectedValues(fi T height = zero.add(heights[h]); T elevation = zero.add(elevations[e]); double expectedValue = expectedValues[h][e]; - T actualValue = model.pathDelay(elevation, new FieldGeodeticPoint<>(zero, zero, zero.add(height)), null, FieldAbsoluteDate.getJ2000Epoch(field)); + FieldGeodeticPoint location = new FieldGeodeticPoint<>(zero, zero, zero.add(height)); + FieldAbsoluteDate date = FieldAbsoluteDate.getJ2000Epoch(field); + T actualValue = model.pathDelay(elevation, location, null, date); Assertions.assertEquals(expectedValue, actualValue.getReal(), epsilon, "For height=" + height + " elevation = " + FastMath.toDegrees(elevation.getReal()) + " precision not met"); } diff --git a/src/test/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModelTest.java new file mode 100644 index 0000000000..6fc2f4e15e --- /dev/null +++ b/src/test/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModelTest.java @@ -0,0 +1,502 @@ +/* Copyright 2002-2023 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import java.util.List; + +import org.hipparchus.CalculusFieldElement; +import org.hipparchus.Field; +import org.hipparchus.analysis.differentiation.DSFactory; +import org.hipparchus.analysis.differentiation.DerivativeStructure; +import org.hipparchus.geometry.euclidean.threed.FieldVector3D; +import org.hipparchus.geometry.euclidean.threed.Vector3D; +import org.hipparchus.util.Binary64Field; +import org.hipparchus.util.FastMath; +import org.hipparchus.util.Precision; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.orekit.Utils; +import org.orekit.attitudes.Attitude; +import org.orekit.bodies.FieldGeodeticPoint; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.bodies.OneAxisEllipsoid; +import org.orekit.errors.OrekitException; +import org.orekit.estimation.measurements.GroundStation; +import org.orekit.frames.Frame; +import org.orekit.frames.FramesFactory; +import org.orekit.frames.TopocentricFrame; +import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; +import org.orekit.orbits.FieldKeplerianOrbit; +import org.orekit.orbits.FieldOrbit; +import org.orekit.orbits.Orbit; +import org.orekit.orbits.OrbitType; +import org.orekit.orbits.PositionAngleType; +import org.orekit.propagation.FieldSpacecraftState; +import org.orekit.propagation.SpacecraftState; +import org.orekit.propagation.numerical.NumericalPropagator; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; +import org.orekit.time.TimeScalesFactory; +import org.orekit.utils.Constants; +import org.orekit.utils.IERSConventions; +import org.orekit.utils.ParameterDriver; +import org.orekit.utils.ParameterDriversList; + +public class TimeSpanEstimatedModelTest { + + @BeforeAll + public static void setUpGlobal() { + Utils.setDataRoot("atmosphere"); + } + + @BeforeEach + public void setUp() throws OrekitException { + Utils.setDataRoot("regular-data:potential/shm-format"); + } + + @Test + public void testFixedHeight() { + final AbsoluteDate date = new AbsoluteDate(); + GeodeticPoint point = new GeodeticPoint(FastMath.toRadians(45.0), FastMath.toRadians(45.0), 350.0); + MappingFunction mapping = new NiellMappingFunctionModel(); + EstimatedTroposphericModel model = new EstimatedTroposphericModel(mapping, 2.0); + TroposphericModel timeSpanModel = new TimeSpanEstimatedModel(model); + double lastDelay = Double.MAX_VALUE; + // delay shall decline with increasing elevation angle + for (double elev = 10d; elev < 90d; elev += 8d) { + final double delay = timeSpanModel.pathDelay(FastMath.toRadians(elev), point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + timeSpanModel.getParameters(), date); + Assertions.assertTrue(Precision.compareTo(delay, lastDelay, 1.0e-6) < 0); + lastDelay = delay; + } + } + + @Test + public void testDelay() { + final double elevation = 10d; + final double height = 100d; + final AbsoluteDate date = new AbsoluteDate(); + GeodeticPoint point = new GeodeticPoint(FastMath.toRadians(45.0), FastMath.toRadians(45.0), height); + MappingFunction mapping = new NiellMappingFunctionModel(); + EstimatedTroposphericModel model = new EstimatedTroposphericModel(mapping, 2.0); + TroposphericModel timeSpanModel = new TimeSpanEstimatedModel(model); + final double path = timeSpanModel.pathDelay(FastMath.toRadians(elevation), point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + timeSpanModel.getParameters(), date); + Assertions.assertTrue(Precision.compareTo(path, 20d, 1.0e-6) < 0); + Assertions.assertTrue(Precision.compareTo(path, 0d, 1.0e-6) > 0); + } + + @Test + public void testStateDerivativesGMF() { + final double latitude = FastMath.toRadians(45.0); + final double longitude = FastMath.toRadians(45.0); + GeodeticPoint point = new GeodeticPoint(latitude, longitude, 0.0); + final MappingFunction gmf = new GlobalMappingFunctionModel(); + doTestDelayStateDerivatives(gmf, point, 4.7e-9); + } + + @Test + public void testStateDerivativesNMF() { + final double latitude = FastMath.toRadians(45.0); + final double longitude = FastMath.toRadians(45.0); + GeodeticPoint point = new GeodeticPoint(latitude, longitude, 0.0); + final MappingFunction nmf = new NiellMappingFunctionModel(); + doTestDelayStateDerivatives(nmf, point, 4.4e-9); + } + + private void doTestDelayStateDerivatives(final MappingFunction func, final GeodeticPoint point, final double tolerance) { + + // Body: earth + final OneAxisEllipsoid earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS, + Constants.WGS84_EARTH_FLATTENING, + FramesFactory.getITRF(IERSConventions.IERS_2010, true)); + // Topocentric frame + final TopocentricFrame baseFrame = new TopocentricFrame(earth, point, "topo"); + + // Station + final GroundStation station = new GroundStation(baseFrame); + + // Tropospheric model + EstimatedTroposphericModel model = new EstimatedTroposphericModel(func, 2.0); + TroposphericModel timeSpanModel = new TimeSpanEstimatedModel(model); + + // Derivative Structure + final DSFactory factory = new DSFactory(6, 1); + final DerivativeStructure a0 = factory.variable(0, 24464560.0); + final DerivativeStructure e0 = factory.variable(1, 0.05); + final DerivativeStructure i0 = factory.variable(2, 0.122138); + final DerivativeStructure pa0 = factory.variable(3, 3.10686); + final DerivativeStructure raan0 = factory.variable(4, 1.00681); + final DerivativeStructure anomaly0 = factory.variable(5, 0.048363); + final Field field = a0.getField(); + final DerivativeStructure zero = field.getZero(); + + // Field Date + final FieldAbsoluteDate dsDate = new FieldAbsoluteDate<>(field); + // Field Orbit + final Frame frame = FramesFactory.getEME2000(); + final FieldOrbit dsOrbit = new FieldKeplerianOrbit<>(a0, e0, i0, pa0, raan0, anomaly0, + PositionAngleType.MEAN, frame, + dsDate, zero.add(3.9860047e14)); + // Field State + final FieldSpacecraftState dsState = new FieldSpacecraftState<>(dsOrbit); + + // Initial satellite elevation + final FieldVector3D position = dsState.getPosition(); + final DerivativeStructure dsElevation = baseFrame.getTrackingCoordinates(position, frame, dsDate).getElevation(); + + // Set drivers reference date + for (final ParameterDriver driver : timeSpanModel.getParametersDrivers()) { + driver.setReferenceDate(dsDate.toAbsoluteDate()); + } + + // Compute Delay with state derivatives + final FieldGeodeticPoint dsPoint = new FieldGeodeticPoint<>(zero.add(point.getLatitude()), zero.add(point.getLongitude()), zero.add(point.getAltitude())); + final DerivativeStructure delay = timeSpanModel.pathDelay(dsElevation, dsPoint, + new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + timeSpanModel.getParameters(field), dsDate); + + final double[] compDeriv = delay.getAllDerivatives(); + + // Field -> non-field + final Orbit orbit = dsOrbit.toOrbit(); + final SpacecraftState state = dsState.toSpacecraftState(); + + // Finite differences for reference values + final double[][] refDeriv = new double[1][6]; + final OrbitType orbitType = OrbitType.KEPLERIAN; + final PositionAngleType angleType = PositionAngleType.MEAN; + double dP = 0.001; + double[] steps = NumericalPropagator.tolerances(1000000 * dP, orbit, orbitType)[0]; + for (int i = 0; i < 6; i++) { + SpacecraftState stateM4 = shiftState(state, orbitType, angleType, -4 * steps[i], i); + final Vector3D positionM4 = stateM4.getPosition(); + final double elevationM4 = station.getBaseFrame(). + getTrackingCoordinates(positionM4, stateM4.getFrame(), stateM4.getDate()). + getElevation(); + double delayM4 = timeSpanModel.pathDelay(elevationM4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + timeSpanModel.getParameters(), stateM4.getDate()); + + SpacecraftState stateM3 = shiftState(state, orbitType, angleType, -3 * steps[i], i); + final Vector3D positionM3 = stateM3.getPosition(); + final double elevationM3 = station.getBaseFrame(). + getTrackingCoordinates(positionM3, stateM3.getFrame(), stateM3.getDate()). + getElevation(); + double delayM3 = timeSpanModel.pathDelay(elevationM3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + timeSpanModel.getParameters(), stateM3.getDate()); + + SpacecraftState stateM2 = shiftState(state, orbitType, angleType, -2 * steps[i], i); + final Vector3D positionM2 = stateM2.getPosition(); + final double elevationM2 = station.getBaseFrame(). + getTrackingCoordinates(positionM2, stateM2.getFrame(), stateM2.getDate()). + getElevation(); + double delayM2 = timeSpanModel.pathDelay(elevationM2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + timeSpanModel.getParameters(), stateM2.getDate()); + + SpacecraftState stateM1 = shiftState(state, orbitType, angleType, -1 * steps[i], i); + final Vector3D positionM1 = stateM1.getPosition(); + final double elevationM1 = station.getBaseFrame(). + getTrackingCoordinates(positionM1, stateM1.getFrame(), stateM1.getDate()). + getElevation(); + double delayM1 = timeSpanModel.pathDelay(elevationM1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + timeSpanModel.getParameters(), stateM1.getDate()); + + SpacecraftState stateP1 = shiftState(state, orbitType, angleType, 1 * steps[i], i); + final Vector3D positionP1 = stateP1.getPosition(); + final double elevationP1 = station.getBaseFrame(). + getTrackingCoordinates(positionP1, stateP1.getFrame(), stateP1.getDate()). + getElevation(); + double delayP1 = timeSpanModel.pathDelay(elevationP1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + timeSpanModel.getParameters(), stateP1.getDate()); + + SpacecraftState stateP2 = shiftState(state, orbitType, angleType, 2 * steps[i], i); + final Vector3D positionP2 = stateP2.getPosition(); + final double elevationP2 = station.getBaseFrame(). + getTrackingCoordinates(positionP2, stateP2.getFrame(), stateP2.getDate()). + getElevation(); + double delayP2 = timeSpanModel.pathDelay(elevationP2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + timeSpanModel.getParameters(), stateP2.getDate()); + + SpacecraftState stateP3 = shiftState(state, orbitType, angleType, 3 * steps[i], i); + final Vector3D positionP3 = stateP3.getPosition(); + final double elevationP3 = station.getBaseFrame(). + getTrackingCoordinates(positionP3, stateP3.getFrame(), stateP3.getDate()). + getElevation(); + double delayP3 = timeSpanModel.pathDelay(elevationP3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + timeSpanModel.getParameters(), stateP3.getDate()); + + SpacecraftState stateP4 = shiftState(state, orbitType, angleType, 4 * steps[i], i); + final Vector3D positionP4 = stateP4.getPosition(); + final double elevationP4 = station.getBaseFrame(). + getTrackingCoordinates(positionP4, stateP4.getFrame(), stateP4.getDate()). + getElevation(); + double delayP4 = timeSpanModel.pathDelay(elevationP4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + timeSpanModel.getParameters(), stateP4.getDate()); + + fillJacobianColumn(refDeriv, i, orbitType, angleType, steps[i], + delayM4, delayM3, delayM2, delayM1, + delayP1, delayP2, delayP3, delayP4); + } + + for (int i = 0; i < 6; i++) { + Assertions.assertEquals(compDeriv[i + 1], refDeriv[0][i], tolerance); + } + } + + @Test + public void testDelayParameterDerivative() { + doTestParametersDerivatives(EstimatedTroposphericModel.TOTAL_ZENITH_DELAY, 5.0e-15); + } + + private void doTestParametersDerivatives(String parameterName, double tolerance) { + + // Geodetic point + final double latitude = FastMath.toRadians(45.0); + final double longitude = FastMath.toRadians(45.0); + final double height = 0.0; + final GeodeticPoint point = new GeodeticPoint(latitude, longitude, height); + // Body: earth + final OneAxisEllipsoid earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS, + Constants.WGS84_EARTH_FLATTENING, + FramesFactory.getITRF(IERSConventions.IERS_2010, true)); + // Topocentric frame + final TopocentricFrame baseFrame = new TopocentricFrame(earth, point, "topo"); + + // Tropospheric model + final MappingFunction gmf = new GlobalMappingFunctionModel(); + final TroposphericModel model = new EstimatedTroposphericModel(gmf, 5.0); + + // Set Parameter Driver + for (final ParameterDriver driver : model.getParametersDrivers()) { + driver.setValue(driver.getReferenceValue()); + driver.setSelected(driver.getName().equals(parameterName)); + } + + // Count the required number of parameters + int nbParams = 0; + for (final ParameterDriver driver : model.getParametersDrivers()) { + if (driver.isSelected()) { + ++nbParams; + } + } + + // Derivative Structure + final DSFactory factory = new DSFactory(6 + nbParams, 1); + final DerivativeStructure a0 = factory.variable(0, 24464560.0); + final DerivativeStructure e0 = factory.variable(1, 0.05); + final DerivativeStructure i0 = factory.variable(2, 0.122138); + final DerivativeStructure pa0 = factory.variable(3, 3.10686); + final DerivativeStructure raan0 = factory.variable(4, 1.00681); + final DerivativeStructure anomaly0 = factory.variable(5, 0.048363); + final Field field = a0.getField(); + final DerivativeStructure zero = field.getZero(); + + // Field Date + final FieldAbsoluteDate dsDate = new FieldAbsoluteDate<>(field, 2018, 11, 19, 18, 0, 0.0, + TimeScalesFactory.getUTC()); + + // Set drivers reference date + for (final ParameterDriver driver : model.getParametersDrivers()) { + driver.setReferenceDate(dsDate.toAbsoluteDate()); + } + + // Field Orbit + final Frame frame = FramesFactory.getEME2000(); + final FieldOrbit dsOrbit = new FieldKeplerianOrbit<>(a0, e0, i0, pa0, raan0, anomaly0, + PositionAngleType.MEAN, frame, + dsDate, zero.add(3.9860047e14)); + + // Field State + final FieldSpacecraftState dsState = new FieldSpacecraftState<>(dsOrbit); + + // Initial satellite elevation + final FieldVector3D position = dsState.getPosition(); + final DerivativeStructure dsElevation = baseFrame.getTrackingCoordinates(position, frame, dsState.getDate()).getElevation(); + + // Add parameter as a variable + final List drivers = model.getParametersDrivers(); + final DerivativeStructure[] parameters = new DerivativeStructure[drivers.size()]; + int index = 6; + for (int i = 0; i < drivers.size(); ++i) { + parameters[i] = drivers.get(i).isSelected() ? + factory.variable(index++, drivers.get(i).getValue()) : + factory.constant(drivers.get(i).getValue()); + } + + // Compute delay state derivatives + final FieldGeodeticPoint dsPoint = new FieldGeodeticPoint<>(zero.add(point.getLatitude()), zero.add(point.getLongitude()), zero.add(point.getAltitude())); + final DerivativeStructure delay = model.pathDelay(dsElevation, dsPoint, + new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + parameters, dsState.getDate()); + + final double[] compDeriv = delay.getAllDerivatives(); + + // Field -> non-field + final SpacecraftState state = dsState.toSpacecraftState(); + final double elevation = dsElevation.getReal(); + + // Finite differences for reference values + final double[][] refDeriv = new double[1][1]; + ParameterDriversList bound = new ParameterDriversList(); + for (final ParameterDriver driver : model.getParametersDrivers()) { + if (driver.getName().equals(parameterName)) { + driver.setSelected(true); + bound.add(driver); + } else { + driver.setSelected(false); + } + } + ParameterDriver selected = bound.getDrivers().get(0); + double p0 = selected.getReferenceValue(); + double h = selected.getScale(); + + final OrbitType orbitType = OrbitType.KEPLERIAN; + final PositionAngleType angleType = PositionAngleType.MEAN; + + selected.setValue(p0 - 4 * h); + double delayM4 = model.pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), state.getDate()); + + selected.setValue(p0 - 3 * h); + double delayM3 = model.pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), state.getDate()); + + selected.setValue(p0 - 2 * h); + double delayM2 = model.pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), state.getDate()); + + selected.setValue(p0 - 1 * h); + double delayM1 = model.pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), state.getDate()); + + selected.setValue(p0 + 1 * h); + double delayP1 = model.pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), state.getDate()); + + selected.setValue(p0 + 2 * h); + double delayP2 = model.pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), state.getDate()); + + selected.setValue(p0 + 3 * h); + double delayP3 = model.pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), state.getDate()); + + selected.setValue(p0 + 4 * h); + double delayP4 = model.pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), state.getDate()); + + fillJacobianColumn(refDeriv, 0, orbitType, angleType, h, + delayM4, delayM3, delayM2, delayM1, + delayP1, delayP2, delayP3, delayP4); + + Assertions.assertEquals(compDeriv[7], refDeriv[0][0], tolerance); + + } + + @Test + public void testComparisonWithEstimatedModel() { + final AbsoluteDate date = new AbsoluteDate(); + MappingFunction mapping = new NiellMappingFunctionModel(); + EstimatedTroposphericModel estimatedModel = new EstimatedTroposphericModel(mapping, 2.0); + TroposphericModel timeSpanModel = new TimeSpanEstimatedModel(estimatedModel); + final double elevation = 45.0; + final double height = 100.0; + final double[] estimatedParameters = estimatedModel.getParameters(); + final double[] timeSpanParameters = estimatedModel.getParameters(); + GeodeticPoint point = new GeodeticPoint(FastMath.toRadians(45.0), FastMath.toRadians(45.0), height); + + Assertions.assertEquals(estimatedModel.pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + estimatedParameters, date), + timeSpanModel.pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + timeSpanParameters, date), + Double.MIN_VALUE); + } + + @Test + public void testFieldComparisonWithEstimatedModel() { + doTestFieldComparisonWithEstimatedModel(Binary64Field.getInstance()); + } + + private > void doTestFieldComparisonWithEstimatedModel(final Field field) { + final T zero = field.getZero(); + final FieldAbsoluteDate date = new FieldAbsoluteDate<>(field); + MappingFunction mapping = new NiellMappingFunctionModel(); + EstimatedTroposphericModel estimatedModel = new EstimatedTroposphericModel(mapping, 2.0); + TroposphericModel timeSpanModel = new TimeSpanEstimatedModel(estimatedModel); + final T elevation = zero.add(45.0); + final T height = zero.add(100.0); + final T[] estimatedParameters = estimatedModel.getParameters(field); + final T[] timeSpanParameters = estimatedModel.getParameters(field); + final FieldGeodeticPoint dsPoint = new FieldGeodeticPoint<>(zero.add(FastMath.toRadians(45.0)), zero.add(FastMath.toRadians(45.0)), height); + + Assertions.assertEquals(estimatedModel.pathDelay(elevation, dsPoint, + new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + estimatedParameters, date).getReal(), + timeSpanModel.pathDelay(elevation, dsPoint, + new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + timeSpanParameters, date).getReal(), + Double.MIN_VALUE); + } + + private SpacecraftState shiftState(SpacecraftState state, OrbitType orbitType, PositionAngleType angleType, + double delta, int column) { + + double[][] array = stateToArray(state, orbitType, angleType, true); + array[0][column] += delta; + + return arrayToState(array, orbitType, angleType, state.getFrame(), state.getDate(), + state.getMu(), state.getAttitude()); + + } + + private double[][] stateToArray(SpacecraftState state, OrbitType orbitType, PositionAngleType angleType, + boolean withMass) { + double[][] array = new double[2][withMass ? 7 : 6]; + orbitType.mapOrbitToArray(state.getOrbit(), angleType, array[0], array[1]); + if (withMass) { + array[0][6] = state.getMass(); + } + return array; + } + + private SpacecraftState arrayToState(double[][] array, OrbitType orbitType, PositionAngleType angleType, + Frame frame, AbsoluteDate date, double mu, + Attitude attitude) { + Orbit orbit = orbitType.mapArrayToOrbit(array[0], array[1], angleType, date, mu, frame); + return (array.length > 6) ? + new SpacecraftState(orbit, attitude) : + new SpacecraftState(orbit, attitude, array[0][6]); + } + + private void fillJacobianColumn(double[][] jacobian, int column, + OrbitType orbitType, PositionAngleType angleType, double h, + double sM4h, double sM3h, + double sM2h, double sM1h, + double sP1h, double sP2h, + double sP3h, double sP4h) { + + jacobian[0][column] = ( -3 * (sP4h - sM4h) + + 32 * (sP3h - sM3h) - + 168 * (sP2h - sM2h) + + 672 * (sP1h - sM1h)) / (840 * h); + } + +} diff --git a/src/test/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedTroposphericModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedTroposphericModelTest.java index a39192dc68..915d008d69 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedTroposphericModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedTroposphericModelTest.java @@ -57,6 +57,7 @@ import java.util.List; +@Deprecated public class TimeSpanEstimatedTroposphericModelTest { @BeforeAll diff --git a/src/test/java/org/orekit/models/earth/troposphere/ViennaOneModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/ViennaOneModelTest.java index 01a31aa8d8..d9e5cd50a0 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/ViennaOneModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/ViennaOneModelTest.java @@ -99,7 +99,9 @@ public void testDelay() { final double[] z = {2.0966, 0.2140}; final GeodeticPoint point = new GeodeticPoint(FastMath.toRadians(45.0), FastMath.toRadians(45.0), height); ViennaOneModel model = new ViennaOneModel(a, z); - final double path = model.pathDelay(FastMath.toRadians(elevation), point, model.getParameters(date), date); + final double path = model.pathDelay(FastMath.toRadians(elevation), point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(date), date); Assertions.assertTrue(Precision.compareTo(path, 20d, epsilon) < 0); Assertions.assertTrue(Precision.compareTo(path, 0d, epsilon) > 0); } @@ -114,7 +116,9 @@ public void testFixedHeight() { double lastDelay = Double.MAX_VALUE; // delay shall decline with increasing elevation angle for (double elev = 10d; elev < 90d; elev += 8d) { - final double delay = model.pathDelay(FastMath.toRadians(elev), point, model.getParameters(date), date); + final double delay = model.pathDelay(FastMath.toRadians(elev), point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(date), date); Assertions.assertTrue(Precision.compareTo(delay, lastDelay, epsilon) < 0); lastDelay = delay; } diff --git a/src/test/java/org/orekit/models/earth/troposphere/ViennaThreeModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/ViennaThreeModelTest.java index 1d0dc66362..d16004a876 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/ViennaThreeModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/ViennaThreeModelTest.java @@ -186,7 +186,9 @@ public void testDelay() { final double[] z = {2.1993, 0.0690}; final GeodeticPoint point = new GeodeticPoint(FastMath.toRadians(37.5), FastMath.toRadians(277.5), height); ViennaThreeModel model = new ViennaThreeModel(a, z); - final double path = model.pathDelay(FastMath.toRadians(elevation), point, model.getParameters(date), date); + final double path = model.pathDelay(FastMath.toRadians(elevation), point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(date), date); Assertions.assertTrue(Precision.compareTo(path, 20d, epsilon) < 0); Assertions.assertTrue(Precision.compareTo(path, 0d, epsilon) > 0); } @@ -201,7 +203,9 @@ public void testFixedHeight() { double lastDelay = Double.MAX_VALUE; // delay shall decline with increasing elevation angle for (double elev = 10d; elev < 90d; elev += 8d) { - final double delay = model.pathDelay(FastMath.toRadians(elev), point, model.getParameters(date), date); + final double delay = model.pathDelay(FastMath.toRadians(elev), point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(date), date); Assertions.assertTrue(Precision.compareTo(delay, lastDelay, epsilon) < 0); lastDelay = delay; } diff --git a/src/test/java/org/orekit/orbits/FieldOrbitTest.java b/src/test/java/org/orekit/orbits/FieldOrbitTest.java index 6829513622..743dd6a34a 100644 --- a/src/test/java/org/orekit/orbits/FieldOrbitTest.java +++ b/src/test/java/org/orekit/orbits/FieldOrbitTest.java @@ -24,7 +24,6 @@ import org.mockito.Mockito; import org.orekit.frames.Frame; import org.orekit.time.FieldAbsoluteDate; -import org.orekit.time.FieldTimeStamped; import org.orekit.utils.TimeStampedFieldPVCoordinates; diff --git a/src/test/java/org/orekit/propagation/FieldSpacecraftStateTest.java b/src/test/java/org/orekit/propagation/FieldSpacecraftStateTest.java index 9fa0664b39..df1219f8b1 100644 --- a/src/test/java/org/orekit/propagation/FieldSpacecraftStateTest.java +++ b/src/test/java/org/orekit/propagation/FieldSpacecraftStateTest.java @@ -46,7 +46,6 @@ import org.orekit.errors.OrekitMessages; import org.orekit.frames.FieldStaticTransform; import org.orekit.frames.FramesFactory; -import org.orekit.frames.StaticTransform; import org.orekit.frames.Transform; import org.orekit.orbits.*; import org.orekit.propagation.analytical.FieldEcksteinHechlerPropagator; From 16947d52fc0e8a5b4ed1c400d62aa45b66e0e7d9 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Thu, 14 Dec 2023 16:05:56 +0100 Subject: [PATCH 043/359] Streamlined deprecations. --- .../earth/troposphere/EstimatedModel.java | 6 ++--- .../EstimatedTroposphericModel.java | 3 ++- .../troposphere/TimeSpanEstimatedModel.java | 4 +-- .../measurements/RangeRateTest.java | 5 ++-- .../estimation/measurements/RangeTest.java | 3 +-- .../measurements/gnss/PhaseTest.java | 5 ++-- .../modifiers/TropoModifierTest.java | 25 +++++++++---------- .../earth/troposphere/EstimatedModelTest.java | 10 ++++---- .../TimeSpanEstimatedModelTest.java | 14 +++++------ 9 files changed, 36 insertions(+), 39 deletions(-) diff --git a/src/main/java/org/orekit/models/earth/troposphere/EstimatedModel.java b/src/main/java/org/orekit/models/earth/troposphere/EstimatedModel.java index 123f21c1dc..ea29252d47 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/EstimatedModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/EstimatedModel.java @@ -75,7 +75,7 @@ public class EstimatedModel implements TroposphericModel { * @param h0 altitude of the station [m] * @param t0 the temperature at the station [K] * @param p0 the atmospheric pressure at the station [mbar] - * @param model mapping function model (NMF or GMF). + * @param model mapping function model. * @param totalDelay initial value for the tropospheric zenith total delay [m] */ public EstimatedModel(final double h0, final double t0, final double p0, @@ -89,7 +89,7 @@ public EstimatedModel(final double h0, final double t0, final double p0, /** Build a new instance using the given environmental conditions. * @param hydrostatic model for hydrostatic component - * @param model mapping function model (NMF or GMF). + * @param model mapping function model. * @param totalDelay initial value for the tropospheric zenith total delay [m] * @since 12.1 */ @@ -110,7 +110,7 @@ public EstimatedModel(final TroposphericModel hydrostatic, *
                    • temperature: 18 degree Celsius *
                    • pressure: 1013.25 mbar *
                    - * @param model mapping function model (NMF or GMF). + * @param model mapping function model. * @param totalDelay initial value for the tropospheric zenith total delay [m] */ public EstimatedModel(final MappingFunction model, final double totalDelay) { diff --git a/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java b/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java index fe531253b1..6cc114770a 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java @@ -46,8 +46,9 @@ * {@link DiscreteTroposphericModel tropospheric model} * while the tropospheric total zenith delay δt is estimated as a {@link ParameterDriver}, * hence the wet part is the difference between the two. + * @deprecated as of 12.1, replaced by {@link EstimatedModel} */ -@SuppressWarnings("deprecation") +@Deprecated public class EstimatedTroposphericModel extends EstimatedModel implements DiscreteTroposphericModel { /** Name of the parameter of this model: the total zenith delay. */ diff --git a/src/main/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModel.java b/src/main/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModel.java index c473d7f8c3..b9e6bae042 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModel.java @@ -37,8 +37,8 @@ /** * Time span estimated tropospheric model. *

                    - * This class is closely related to {@link org.orekit.models.earth.troposphere EstimatedTroposphericModel} class.
                    - * The difference is that it has a {@link TimeSpanMap} of {@link EstimatedTroposphericModel} objects as attribute.
                    + * This class is closely related to {@link org.orekit.models.earth.troposphere EstimatedModel} class.
                    + * The difference is that it has a {@link TimeSpanMap} of {@link EstimatedModel} objects as attribute.
                    * The idea behind this model is to allow the user to design a tropospheric model that can see its physical parameters * (total zenith delay) change with time, at dates chosen by the user.
                    *

                    diff --git a/src/test/java/org/orekit/estimation/measurements/RangeRateTest.java b/src/test/java/org/orekit/estimation/measurements/RangeRateTest.java index 5a8eb4cb0d..a30c3b7ef7 100644 --- a/src/test/java/org/orekit/estimation/measurements/RangeRateTest.java +++ b/src/test/java/org/orekit/estimation/measurements/RangeRateTest.java @@ -26,7 +26,6 @@ import org.orekit.estimation.EstimationTestUtils; import org.orekit.estimation.measurements.modifiers.RangeRateTroposphericDelayModifier; import org.orekit.models.earth.troposphere.EstimatedModel; -import org.orekit.models.earth.troposphere.EstimatedTroposphericModel; import org.orekit.models.earth.troposphere.GlobalMappingFunctionModel; import org.orekit.models.earth.troposphere.ModifiedSaastamoinenModel; import org.orekit.orbits.OrbitType; @@ -533,7 +532,7 @@ public void testStateDerivativesWithEstimatedModifier() { // Add modifiers if test implies it final GlobalMappingFunctionModel mappingFunction = new GlobalMappingFunctionModel(); - final EstimatedModel tropoModel = new EstimatedTroposphericModel(mappingFunction, 5.0); + final EstimatedModel tropoModel = new EstimatedModel(mappingFunction, 5.0); final RangeRateTroposphericDelayModifier modifier = new RangeRateTroposphericDelayModifier(tropoModel, true); ((RangeRate) measurement).addModifier(modifier); @@ -690,7 +689,7 @@ public void testParameterDerivativesWithEstimatedModifier() { // Add modifiers if test implies it final GlobalMappingFunctionModel mappingFunction = new GlobalMappingFunctionModel(); - final EstimatedModel tropoModel = new EstimatedTroposphericModel(mappingFunction, 10.0); + final EstimatedModel tropoModel = new EstimatedModel(mappingFunction, 10.0); final List parameters = tropoModel.getParametersDrivers(); for (ParameterDriver driver : parameters) { diff --git a/src/test/java/org/orekit/estimation/measurements/RangeTest.java b/src/test/java/org/orekit/estimation/measurements/RangeTest.java index 59687efbbc..5353e17c68 100644 --- a/src/test/java/org/orekit/estimation/measurements/RangeTest.java +++ b/src/test/java/org/orekit/estimation/measurements/RangeTest.java @@ -32,7 +32,6 @@ import org.orekit.estimation.EstimationTestUtils; import org.orekit.estimation.measurements.modifiers.RangeTroposphericDelayModifier; import org.orekit.models.earth.troposphere.EstimatedModel; -import org.orekit.models.earth.troposphere.EstimatedTroposphericModel; import org.orekit.models.earth.troposphere.ModifiedSaastamoinenModel; import org.orekit.models.earth.troposphere.NiellMappingFunctionModel; import org.orekit.orbits.OrbitType; @@ -650,7 +649,7 @@ void genericTestEstimatedParameterDerivatives(final boolean isModifier, final bo driver.setSelected(true); } - parameters.get(0).setName(stationName + "/" + EstimatedTroposphericModel.TOTAL_ZENITH_DELAY); + parameters.get(0).setName(stationName + "/" + EstimatedModel.TOTAL_ZENITH_DELAY); final RangeTroposphericDelayModifier modifier = new RangeTroposphericDelayModifier(tropoModel); if (isModifier) { ((Range) measurement).addModifier(modifier); diff --git a/src/test/java/org/orekit/estimation/measurements/gnss/PhaseTest.java b/src/test/java/org/orekit/estimation/measurements/gnss/PhaseTest.java index c9578a1778..4f84a98514 100644 --- a/src/test/java/org/orekit/estimation/measurements/gnss/PhaseTest.java +++ b/src/test/java/org/orekit/estimation/measurements/gnss/PhaseTest.java @@ -45,7 +45,6 @@ import org.orekit.models.earth.ionosphere.IonosphericModel; import org.orekit.models.earth.ionosphere.KlobucharIonoModel; import org.orekit.models.earth.troposphere.EstimatedModel; -import org.orekit.models.earth.troposphere.EstimatedTroposphericModel; import org.orekit.models.earth.troposphere.NiellMappingFunctionModel; import org.orekit.models.earth.troposphere.TroposphericModelUtils; import org.orekit.orbits.OrbitType; @@ -627,10 +626,10 @@ public void testStateDerivativesWithTroposphericModifier() { // Add modifier final NiellMappingFunctionModel mappingFunction = new NiellMappingFunctionModel(); - final EstimatedModel tropoModel = new EstimatedTroposphericModel(mappingFunction, 5.0); + final EstimatedModel tropoModel = new EstimatedModel(mappingFunction, 5.0); final PhaseTroposphericDelayModifier modifier = new PhaseTroposphericDelayModifier(tropoModel); final List parameters = modifier.getParametersDrivers(); - parameters.get(0).setName(stationName + "/" + EstimatedTroposphericModel.TOTAL_ZENITH_DELAY); + parameters.get(0).setName(stationName + "/" + EstimatedModel.TOTAL_ZENITH_DELAY); parameters.get(0).setSelected(true); ((Phase) measurement).addModifier(modifier); diff --git a/src/test/java/org/orekit/estimation/measurements/modifiers/TropoModifierTest.java b/src/test/java/org/orekit/estimation/measurements/modifiers/TropoModifierTest.java index dd86a6d20e..9d5e539273 100644 --- a/src/test/java/org/orekit/estimation/measurements/modifiers/TropoModifierTest.java +++ b/src/test/java/org/orekit/estimation/measurements/modifiers/TropoModifierTest.java @@ -51,7 +51,6 @@ import org.orekit.gnss.Frequency; import org.orekit.models.earth.EarthITU453AtmosphereRefraction; import org.orekit.models.earth.troposphere.EstimatedModel; -import org.orekit.models.earth.troposphere.EstimatedTroposphericModel; import org.orekit.models.earth.troposphere.ModifiedSaastamoinenModel; import org.orekit.models.earth.troposphere.NiellMappingFunctionModel; import org.orekit.orbits.OrbitType; @@ -150,12 +149,12 @@ public void testRangeEstimatedTropoModifier() { final GroundStation stationParameter = ((Range) measurement).getStation(); final TopocentricFrame baseFrame = stationParameter.getBaseFrame(); final NiellMappingFunctionModel mappingFunction = new NiellMappingFunctionModel(); - final EstimatedModel tropoModel = new EstimatedTroposphericModel(mappingFunction, 5.0); + final EstimatedModel tropoModel = new EstimatedModel(mappingFunction, 5.0); final RangeTroposphericDelayModifier modifier = new RangeTroposphericDelayModifier(tropoModel); final ParameterDriver parameterDriver = modifier.getParametersDrivers().get(0); parameterDriver.setSelected(true); - parameterDriver.setName(baseFrame.getName() + EstimatedTroposphericModel.TOTAL_ZENITH_DELAY); + parameterDriver.setName(baseFrame.getName() + EstimatedModel.TOTAL_ZENITH_DELAY); range.addModifier(modifier); EstimatedMeasurementBase eval = range.estimateWithoutDerivatives(0, 0, new SpacecraftState[] { refState }); @@ -260,12 +259,12 @@ public void testPhaseEstimatedTropoModifier() { final GroundStation stationParameter = phase.getStation(); final TopocentricFrame baseFrame = stationParameter.getBaseFrame(); final NiellMappingFunctionModel mappingFunction = new NiellMappingFunctionModel(); - final EstimatedModel tropoModel = new EstimatedTroposphericModel(mappingFunction, 5.0); + final EstimatedModel tropoModel = new EstimatedModel(mappingFunction, 5.0); final PhaseTroposphericDelayModifier modifier = new PhaseTroposphericDelayModifier(tropoModel); final ParameterDriver parameterDriver = modifier.getParametersDrivers().get(0); parameterDriver.setSelected(true); - parameterDriver.setName(baseFrame.getName() + EstimatedTroposphericModel.TOTAL_ZENITH_DELAY); + parameterDriver.setName(baseFrame.getName() + EstimatedModel.TOTAL_ZENITH_DELAY); phase.addModifier(modifier); EstimatedMeasurementBase eval = phase.estimateWithoutDerivatives(0, 0, new SpacecraftState[] { refState }); @@ -470,14 +469,14 @@ public void testBistaticRangeRateEstimatedTropoModifier() { // add modifier final NiellMappingFunctionModel mappingFunc = new NiellMappingFunctionModel(); - final EstimatedModel tropoModel = new EstimatedTroposphericModel(mappingFunc, 5.0); + final EstimatedModel tropoModel = new EstimatedModel(mappingFunc, 5.0); final BistaticRangeRateTroposphericDelayModifier modifier = new BistaticRangeRateTroposphericDelayModifier(tropoModel); final TopocentricFrame baseFrame = biRangeRate.getReceiverStation().getBaseFrame(); final ParameterDriver parameterDriver = modifier.getParametersDrivers().get(0); parameterDriver.setSelected(true); - parameterDriver.setName(baseFrame.getName() + EstimatedTroposphericModel.TOTAL_ZENITH_DELAY); + parameterDriver.setName(baseFrame.getName() + EstimatedModel.TOTAL_ZENITH_DELAY); biRangeRate.addModifier(modifier); @@ -580,13 +579,13 @@ public void testTDOAEstimatedTropoModifier() { // add modifier final NiellMappingFunctionModel mappingFunct = new NiellMappingFunctionModel(); - final EstimatedModel tropoModel = new EstimatedTroposphericModel(mappingFunct, 5.0); + final EstimatedModel tropoModel = new EstimatedModel(mappingFunct, 5.0); final TDOATroposphericDelayModifier modifier = new TDOATroposphericDelayModifier(tropoModel); final TopocentricFrame baseFrame = tdoa.getPrimeStation().getBaseFrame(); final ParameterDriver parameterDriver = modifier.getParametersDrivers().get(0); parameterDriver.setSelected(true); - parameterDriver.setName(baseFrame.getName() + EstimatedTroposphericModel.TOTAL_ZENITH_DELAY); + parameterDriver.setName(baseFrame.getName() + EstimatedModel.TOTAL_ZENITH_DELAY); tdoa.addModifier(modifier); @@ -680,12 +679,12 @@ public void testRangeRateEstimatedTropoModifier() { final GroundStation stationParameter = ((RangeRate) measurement).getStation(); final TopocentricFrame baseFrame = stationParameter.getBaseFrame(); final NiellMappingFunctionModel mappingFunction = new NiellMappingFunctionModel(); - final EstimatedModel tropoModel = new EstimatedTroposphericModel(mappingFunction, 5.0); + final EstimatedModel tropoModel = new EstimatedModel(mappingFunction, 5.0); final RangeRateTroposphericDelayModifier modifier = new RangeRateTroposphericDelayModifier(tropoModel, false); final ParameterDriver parameterDriver = modifier.getParametersDrivers().get(0); parameterDriver.setSelected(true); - parameterDriver.setName(baseFrame.getName() + EstimatedTroposphericModel.TOTAL_ZENITH_DELAY); + parameterDriver.setName(baseFrame.getName() + EstimatedModel.TOTAL_ZENITH_DELAY); rangeRate.addModifier(modifier); // @@ -782,12 +781,12 @@ public void testAngularEstimatedTropoModifier() { final GroundStation stationParameter = ((AngularAzEl) measurement).getStation(); final TopocentricFrame baseFrame = stationParameter.getBaseFrame(); final NiellMappingFunctionModel mappingFunction = new NiellMappingFunctionModel(); - final EstimatedModel tropoModel = new EstimatedTroposphericModel(mappingFunction, 5.0); + final EstimatedModel tropoModel = new EstimatedModel(mappingFunction, 5.0); final AngularTroposphericDelayModifier modifier = new AngularTroposphericDelayModifier(tropoModel); final ParameterDriver parameterDriver = modifier.getParametersDrivers().get(0); parameterDriver.setSelected(true); - parameterDriver.setName(baseFrame.getName() + EstimatedTroposphericModel.TOTAL_ZENITH_DELAY); + parameterDriver.setName(baseFrame.getName() + EstimatedModel.TOTAL_ZENITH_DELAY); angular.addModifier(modifier); // EstimatedMeasurementBase eval = angular.estimateWithoutDerivatives(0, 0, diff --git a/src/test/java/org/orekit/models/earth/troposphere/EstimatedModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/EstimatedModelTest.java index 0495b98ea7..e19a2981fa 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/EstimatedModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/EstimatedModelTest.java @@ -73,7 +73,7 @@ public void testFixedHeight() { final AbsoluteDate date = new AbsoluteDate(); GeodeticPoint point = new GeodeticPoint(FastMath.toRadians(45.0), FastMath.toRadians(45.0), 350.0); MappingFunction mapping = new NiellMappingFunctionModel(); - TroposphericModel model = new EstimatedTroposphericModel(mapping, 2.0); + TroposphericModel model = new EstimatedModel(mapping, 2.0); double lastDelay = Double.MAX_VALUE; // delay shall decline with increasing elevation angle for (double elev = 10d; elev < 90d; elev += 8d) { @@ -92,7 +92,7 @@ public void testDelay() { final AbsoluteDate date = new AbsoluteDate(); GeodeticPoint point = new GeodeticPoint(FastMath.toRadians(45.0), FastMath.toRadians(45.0), height); MappingFunction mapping = new NiellMappingFunctionModel(); - TroposphericModel model = new EstimatedTroposphericModel(mapping, 2.0); + TroposphericModel model = new EstimatedModel(mapping, 2.0); final double path = model.pathDelay(FastMath.toRadians(elevation), point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), date); @@ -132,7 +132,7 @@ private void doTestDelayStateDerivatives(final MappingFunction func, final Geode TroposphericModelUtils.STANDARD_ATMOSPHERE_PROVIDER); // Tropospheric model - final TroposphericModel model = new EstimatedTroposphericModel(func, 2.0); + final TroposphericModel model = new EstimatedModel(func, 2.0); // Derivative Structure final DSFactory factory = new DSFactory(6, 1); @@ -259,7 +259,7 @@ private void doTestDelayStateDerivatives(final MappingFunction func, final Geode @Test public void testDelayParameterDerivative() { - doTestParametersDerivatives(EstimatedTroposphericModel.TOTAL_ZENITH_DELAY, 5.0e-15); + doTestParametersDerivatives(EstimatedModel.TOTAL_ZENITH_DELAY, 5.0e-15); } private void doTestParametersDerivatives(String parameterName, double tolerance) { @@ -278,7 +278,7 @@ private void doTestParametersDerivatives(String parameterName, double tolerance) // Tropospheric model final MappingFunction gmf = new GlobalMappingFunctionModel(); - final TroposphericModel model = new EstimatedTroposphericModel(gmf, 5.0); + final TroposphericModel model = new EstimatedModel(gmf, 5.0); // Set Parameter Driver for (final ParameterDriver driver : model.getParametersDrivers()) { diff --git a/src/test/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModelTest.java index 6fc2f4e15e..be15711f5a 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModelTest.java @@ -75,7 +75,7 @@ public void testFixedHeight() { final AbsoluteDate date = new AbsoluteDate(); GeodeticPoint point = new GeodeticPoint(FastMath.toRadians(45.0), FastMath.toRadians(45.0), 350.0); MappingFunction mapping = new NiellMappingFunctionModel(); - EstimatedTroposphericModel model = new EstimatedTroposphericModel(mapping, 2.0); + EstimatedModel model = new EstimatedModel(mapping, 2.0); TroposphericModel timeSpanModel = new TimeSpanEstimatedModel(model); double lastDelay = Double.MAX_VALUE; // delay shall decline with increasing elevation angle @@ -95,7 +95,7 @@ public void testDelay() { final AbsoluteDate date = new AbsoluteDate(); GeodeticPoint point = new GeodeticPoint(FastMath.toRadians(45.0), FastMath.toRadians(45.0), height); MappingFunction mapping = new NiellMappingFunctionModel(); - EstimatedTroposphericModel model = new EstimatedTroposphericModel(mapping, 2.0); + EstimatedModel model = new EstimatedModel(mapping, 2.0); TroposphericModel timeSpanModel = new TimeSpanEstimatedModel(model); final double path = timeSpanModel.pathDelay(FastMath.toRadians(elevation), point, TroposphericModelUtils.STANDARD_ATMOSPHERE, @@ -135,7 +135,7 @@ private void doTestDelayStateDerivatives(final MappingFunction func, final Geode final GroundStation station = new GroundStation(baseFrame); // Tropospheric model - EstimatedTroposphericModel model = new EstimatedTroposphericModel(func, 2.0); + EstimatedModel model = new EstimatedModel(func, 2.0); TroposphericModel timeSpanModel = new TimeSpanEstimatedModel(model); // Derivative Structure @@ -263,7 +263,7 @@ private void doTestDelayStateDerivatives(final MappingFunction func, final Geode @Test public void testDelayParameterDerivative() { - doTestParametersDerivatives(EstimatedTroposphericModel.TOTAL_ZENITH_DELAY, 5.0e-15); + doTestParametersDerivatives(EstimatedModel.TOTAL_ZENITH_DELAY, 5.0e-15); } private void doTestParametersDerivatives(String parameterName, double tolerance) { @@ -282,7 +282,7 @@ private void doTestParametersDerivatives(String parameterName, double tolerance) // Tropospheric model final MappingFunction gmf = new GlobalMappingFunctionModel(); - final TroposphericModel model = new EstimatedTroposphericModel(gmf, 5.0); + final TroposphericModel model = new EstimatedModel(gmf, 5.0); // Set Parameter Driver for (final ParameterDriver driver : model.getParametersDrivers()) { @@ -415,7 +415,7 @@ private void doTestParametersDerivatives(String parameterName, double tolerance) public void testComparisonWithEstimatedModel() { final AbsoluteDate date = new AbsoluteDate(); MappingFunction mapping = new NiellMappingFunctionModel(); - EstimatedTroposphericModel estimatedModel = new EstimatedTroposphericModel(mapping, 2.0); + EstimatedModel estimatedModel = new EstimatedModel(mapping, 2.0); TroposphericModel timeSpanModel = new TimeSpanEstimatedModel(estimatedModel); final double elevation = 45.0; final double height = 100.0; @@ -439,7 +439,7 @@ private > void doTestFieldComparisonWithEstima final T zero = field.getZero(); final FieldAbsoluteDate date = new FieldAbsoluteDate<>(field); MappingFunction mapping = new NiellMappingFunctionModel(); - EstimatedTroposphericModel estimatedModel = new EstimatedTroposphericModel(mapping, 2.0); + EstimatedModel estimatedModel = new EstimatedModel(mapping, 2.0); TroposphericModel timeSpanModel = new TimeSpanEstimatedModel(estimatedModel); final T elevation = zero.add(45.0); final T height = zero.add(100.0); From 925c3e35fc5e910d89e053b23de8a3e4a74b70f4 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Thu, 14 Dec 2023 17:07:59 +0100 Subject: [PATCH 044/359] Pass pressure/temperature/humidity to mapping functions. --- .../AbstractChaoMappingFunction.java | 9 +- .../earth/troposphere/EstimatedModel.java | 12 +-- .../EstimatedTroposphericModel.java | 6 +- .../GlobalMappingFunctionModel.java | 33 ++++++- .../earth/troposphere/MappingFunction.java | 2 + .../earth/troposphere/MendesPavlisModel.java | 58 ++++++++++++- .../NiellMappingFunctionModel.java | 29 ++++++- .../troposphere/TimeSpanEstimatedModel.java | 2 +- .../TroposphereMappingFunction.java | 65 ++++++++++++++ .../TroposphereMappingFunctionAdapter.java | 86 +++++++++++++++++++ .../earth/troposphere/TroposphericModel.java | 2 - .../earth/troposphere/ViennaOneModel.java | 33 ++++++- .../earth/troposphere/ViennaThreeModel.java | 29 ++++++- .../common/AbstractOrbitDetermination.java | 4 +- .../AbstractFieldMappingFunctionTest.java | 57 ++++++++---- .../AbstractMappingFunctionTest.java | 14 +-- .../troposphere/ChaoMappingFunctionTest.java | 2 +- .../earth/troposphere/EstimatedModelTest.java | 12 +-- .../FieldChaoMappingFunctionTest.java | 2 +- .../FieldGlobalMappingFunctionModelTest.java | 55 +++++++++--- .../FieldMendesPavlisModelTest.java | 5 +- .../FieldNiellMappingFunctionModelTest.java | 2 +- .../FieldRevisedChaoMappingFunctionTest.java | 2 +- .../troposphere/FieldViennaOneModelTest.java | 5 +- .../FieldViennaThreeModelTest.java | 6 ++ .../GlobalMappingFunctionModelTest.java | 12 ++- .../troposphere/MendesPavlisModelTest.java | 4 +- .../NiellMappingFunctionModelTest.java | 2 +- .../RevisedChaoMappingFunctionTest.java | 2 +- .../TimeSpanEstimatedModelTest.java | 16 ++-- .../earth/troposphere/ViennaOneModelTest.java | 4 +- .../troposphere/ViennaThreeModelTest.java | 12 ++- 32 files changed, 490 insertions(+), 94 deletions(-) create mode 100644 src/main/java/org/orekit/models/earth/troposphere/TroposphereMappingFunction.java create mode 100644 src/main/java/org/orekit/models/earth/troposphere/TroposphereMappingFunctionAdapter.java diff --git a/src/main/java/org/orekit/models/earth/troposphere/AbstractChaoMappingFunction.java b/src/main/java/org/orekit/models/earth/troposphere/AbstractChaoMappingFunction.java index c841f96244..40cfcb4376 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/AbstractChaoMappingFunction.java +++ b/src/main/java/org/orekit/models/earth/troposphere/AbstractChaoMappingFunction.java @@ -21,6 +21,8 @@ import org.hipparchus.util.MathArrays; import org.orekit.bodies.FieldGeodeticPoint; import org.orekit.bodies.GeodeticPoint; +import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; +import org.orekit.models.earth.weather.PressureTemperatureHumidity; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; @@ -31,7 +33,7 @@ * @author Luc Maisonobe * @since 12.1 */ -public class AbstractChaoMappingFunction implements MappingFunction { +public class AbstractChaoMappingFunction implements TroposphereMappingFunction { /** First coefficient for hydrostatic (dry) component. */ private final double ad; @@ -61,6 +63,7 @@ protected AbstractChaoMappingFunction(final double ad, final double bd, final do /** {@inheritDoc} */ @Override public double[] mappingFactors(final double elevation, final GeodeticPoint point, + final PressureTemperatureHumidity weather, final AbsoluteDate date) { final double sinE = FastMath.sin(elevation); final double tanE = FastMath.tan(elevation); @@ -72,7 +75,9 @@ public double[] mappingFactors(final double elevation, final GeodeticPoint point /** {@inheritDoc} */ @Override - public > T[] mappingFactors(final T elevation, final FieldGeodeticPoint point, + public > T[] mappingFactors(final T elevation, + final FieldGeodeticPoint point, + final FieldPressureTemperatureHumidity weather, final FieldAbsoluteDate date) { final T sinE = FastMath.sin(elevation); final T tanE = FastMath.tan(elevation); diff --git a/src/main/java/org/orekit/models/earth/troposphere/EstimatedModel.java b/src/main/java/org/orekit/models/earth/troposphere/EstimatedModel.java index ea29252d47..b160ccdb72 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/EstimatedModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/EstimatedModel.java @@ -60,7 +60,7 @@ public class EstimatedModel implements TroposphericModel { public static final String TOTAL_ZENITH_DELAY = "total zenith delay"; /** Mapping Function model. */ - private final MappingFunction model; + private final TroposphereMappingFunction model; /** Driver for the tropospheric zenith total delay.*/ private final ParameterDriver totalZenithDelay; @@ -79,7 +79,7 @@ public class EstimatedModel implements TroposphericModel { * @param totalDelay initial value for the tropospheric zenith total delay [m] */ public EstimatedModel(final double h0, final double t0, final double p0, - final MappingFunction model, final double totalDelay) { + final TroposphereMappingFunction model, final double totalDelay) { this(new ModifiedSaastamoinenModel(new ConstantPressureTemperatureHumidityProvider(new PressureTemperatureHumidity(h0, TroposphericModelUtils.HECTO_PASCAL.toSI(p0), t0, @@ -94,7 +94,7 @@ public EstimatedModel(final double h0, final double t0, final double p0, * @since 12.1 */ public EstimatedModel(final TroposphericModel hydrostatic, - final MappingFunction model, + final TroposphereMappingFunction model, final double totalDelay) { totalZenithDelay = new ParameterDriver(EstimatedModel.TOTAL_ZENITH_DELAY, @@ -113,7 +113,7 @@ public EstimatedModel(final TroposphericModel hydrostatic, * @param model mapping function model. * @param totalDelay initial value for the tropospheric zenith total delay [m] */ - public EstimatedModel(final MappingFunction model, final double totalDelay) { + public EstimatedModel(final TroposphereMappingFunction model, final double totalDelay) { this(0.0, 273.15 + 18.0, 1013.25, model, totalDelay); } @@ -132,7 +132,7 @@ public double pathDelay(final double elevation, final GeodeticPoint point, final double zhd = hydrostatic.pathDelay(0.5 * FastMath.PI, point, weather, parameters, date); final double ztd = parameters[0]; // Mapping functions - final double[] mf = model.mappingFactors(elevation, point, date); + final double[] mf = model.mappingFactors(elevation, point, weather, date); // Total delay return mf[0] * zhd + mf[1] * (ztd - zhd); } @@ -146,7 +146,7 @@ public > T pathDelay(final T elevation, final final T zhd = hydrostatic.pathDelay(elevation.getPi().multiply(0.5), point, weather, parameters, date); final T ztd = parameters[0]; // Mapping functions - final T[] mf = model.mappingFactors(elevation, point, date); + final T[] mf = model.mappingFactors(elevation, point, weather, date); // Total delay return mf[0].multiply(zhd).add(mf[1].multiply(ztd.subtract(zhd))); } diff --git a/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java b/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java index 6cc114770a..d3e1667765 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java @@ -65,7 +65,7 @@ public class EstimatedTroposphericModel extends EstimatedModel implements Discre */ public EstimatedTroposphericModel(final double t0, final double p0, final MappingFunction model, final double totalDelay) { - super(0.0, t0, p0, model, totalDelay); + super(0.0, t0, p0, new TroposphereMappingFunctionAdapter(model), totalDelay); } /** Build a new instance using the given environmental conditions. @@ -77,7 +77,9 @@ public EstimatedTroposphericModel(final double t0, final double p0, public EstimatedTroposphericModel(final DiscreteTroposphericModel hydrostatic, final MappingFunction model, final double totalDelay) { - super(new TroposphericModelAdapter(hydrostatic), model, totalDelay); + super(new TroposphericModelAdapter(hydrostatic), + new TroposphereMappingFunctionAdapter(model), + totalDelay); } /** Build a new instance using a standard atmosphere model. diff --git a/src/main/java/org/orekit/models/earth/troposphere/GlobalMappingFunctionModel.java b/src/main/java/org/orekit/models/earth/troposphere/GlobalMappingFunctionModel.java index be4bcf3d12..b7202a00b8 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/GlobalMappingFunctionModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/GlobalMappingFunctionModel.java @@ -16,8 +16,8 @@ */ package org.orekit.models.earth.troposphere; -import org.hipparchus.Field; import org.hipparchus.CalculusFieldElement; +import org.hipparchus.Field; import org.hipparchus.util.FastMath; import org.hipparchus.util.FieldSinCos; import org.hipparchus.util.MathArrays; @@ -26,6 +26,8 @@ import org.orekit.bodies.FieldGeodeticPoint; import org.orekit.bodies.GeodeticPoint; import org.orekit.data.DataContext; +import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; +import org.orekit.models.earth.weather.PressureTemperatureHumidity; import org.orekit.time.AbsoluteDate; import org.orekit.time.DateTimeComponents; import org.orekit.time.FieldAbsoluteDate; @@ -54,7 +56,8 @@ * @author Bryan Cazabonne * */ -public class GlobalMappingFunctionModel implements MappingFunction { +@SuppressWarnings("deprecation") +public class GlobalMappingFunctionModel implements MappingFunction, TroposphereMappingFunction { /** Multiplication factor for mapping function coefficients. */ private static final double FACTOR = 1.0e-5; @@ -81,9 +84,20 @@ public GlobalMappingFunctionModel(final TimeScale utc) { this.utc = utc; } + /** {@inheritDoc} */ + @Override + @Deprecated + public double[] mappingFactors(final double elevation, final GeodeticPoint point, + final AbsoluteDate date) { + return mappingFactors(elevation, point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + date); + } + /** {@inheritDoc} */ @Override public double[] mappingFactors(final double elevation, final GeodeticPoint point, + final PressureTemperatureHumidity weather, final AbsoluteDate date) { // Day of year computation final DateTimeComponents dtc = date.getComponents(utc); @@ -175,8 +189,21 @@ public double[] mappingFactors(final double elevation, final GeodeticPoint point /** {@inheritDoc} */ @Override + @Deprecated public > T[] mappingFactors(final T elevation, final FieldGeodeticPoint point, - final FieldAbsoluteDate date) { + final FieldAbsoluteDate date) { + return mappingFactors(elevation, point, + new FieldPressureTemperatureHumidity<>(date.getField(), + TroposphericModelUtils.STANDARD_ATMOSPHERE), + date); + } + + /** {@inheritDoc} */ + @Override + public > T[] mappingFactors(final T elevation, + final FieldGeodeticPoint point, + final FieldPressureTemperatureHumidity weather, + final FieldAbsoluteDate date) { // Day of year computation final DateTimeComponents dtc = date.getComponents(utc); final int dofyear = dtc.getDate().getDayOfYear(); diff --git a/src/main/java/org/orekit/models/earth/troposphere/MappingFunction.java b/src/main/java/org/orekit/models/earth/troposphere/MappingFunction.java index 1465393f06..7f13987aeb 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/MappingFunction.java +++ b/src/main/java/org/orekit/models/earth/troposphere/MappingFunction.java @@ -24,7 +24,9 @@ /** Interface for mapping functions used in the tropospheric delay computation. * @author Bryan Cazabonne + * @deprecated as of 12.1, replaced by {@link TroposphereMappingFunction} */ +@Deprecated public interface MappingFunction { /** This method allows the computation of the hydrostatic and diff --git a/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java b/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java index 44126d8989..9321438658 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java @@ -48,7 +48,8 @@ * @author Bryan Cazabonne */ @SuppressWarnings("deprecation") -public class MendesPavlisModel implements DiscreteTroposphericModel, TroposphericModel, MappingFunction { +public class MendesPavlisModel + implements DiscreteTroposphericModel, TroposphericModel, MappingFunction, TroposphereMappingFunction { /** Coefficients for the dispertion equation for the hydrostatic component [µm-2]. */ private static final double[] K_COEFFICIENTS = { @@ -263,8 +264,9 @@ public double[] computeZenithDelay(final GeodeticPoint point, final double[] par * @param date current date * @return a two components array containing the zenith hydrostatic and wet delays. */ - public > T[] computeZenithDelay(final FieldGeodeticPoint point, final T[] parameters, - final FieldAbsoluteDate date) { + public > T[] computeZenithDelay(final FieldGeodeticPoint point, + final T[] parameters, + final FieldAbsoluteDate date) { final FieldPressureTemperatureHumidity pth = pthProvider.getWeatherParamerers(point, date); @@ -286,6 +288,28 @@ public > T[] computeZenithDelay(final FieldGeo } + /** With the Mendes Pavlis tropospheric model, the mapping + * function is not split into hydrostatic and wet component. + *

                    + * Therefore, the two components of the resulting array are equals. + *

                      + *
                    • double[0] = m(e) → total mapping function + *
                    • double[1] = m(e) → total mapping function + *
                    + *

                    + * The total delay will thus be computed as:
                    + * δ = Dhz * m(e) + Dwz * m(e)
                    + * δ = (Dhz + Dwz) * m(e) = δz * m(e) + */ + @Override + @Deprecated + public double[] mappingFactors(final double elevation, final GeodeticPoint point, + final AbsoluteDate date) { + return mappingFactors(elevation, point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + date); + } + /** With the Mendes Pavlis tropospheric model, the mapping * function is not split into hydrostatic and wet component. *

                    @@ -301,6 +325,7 @@ public > T[] computeZenithDelay(final FieldGeo */ @Override public double[] mappingFactors(final double elevation, final GeodeticPoint point, + final PressureTemperatureHumidity weather, final AbsoluteDate date) { final double sinE = FastMath.sin(elevation); @@ -345,8 +370,33 @@ public double[] mappingFactors(final double elevation, final GeodeticPoint point * δ = (Dhz + Dwz) * m(e) = δz * m(e) */ @Override + @Deprecated public > T[] mappingFactors(final T elevation, final FieldGeodeticPoint point, - final FieldAbsoluteDate date) { + final FieldAbsoluteDate date) { + return mappingFactors(elevation, point, + new FieldPressureTemperatureHumidity<>(date.getField(), + TroposphericModelUtils.STANDARD_ATMOSPHERE), + date); + } + + /** With the Mendes Pavlis tropospheric model, the mapping + * function is not split into hydrostatic and wet component. + *

                    + * Therefore, the two components of the resulting array are equals. + *

                      + *
                    • double[0] = m(e) → total mapping function + *
                    • double[1] = m(e) → total mapping function + *
                    + *

                    + * The total delay will thus be computed as:
                    + * δ = Dhz * m(e) + Dwz * m(e)
                    + * δ = (Dhz + Dwz) * m(e) = δz * m(e) + */ + @Override + public > T[] mappingFactors(final T elevation, + final FieldGeodeticPoint point, + final FieldPressureTemperatureHumidity weather, + final FieldAbsoluteDate date) { final Field field = date.getField(); final T sinE = FastMath.sin(elevation); diff --git a/src/main/java/org/orekit/models/earth/troposphere/NiellMappingFunctionModel.java b/src/main/java/org/orekit/models/earth/troposphere/NiellMappingFunctionModel.java index 0cbae2db97..5f6f244651 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/NiellMappingFunctionModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/NiellMappingFunctionModel.java @@ -26,6 +26,8 @@ import org.orekit.bodies.FieldGeodeticPoint; import org.orekit.bodies.GeodeticPoint; import org.orekit.data.DataContext; +import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; +import org.orekit.models.earth.weather.PressureTemperatureHumidity; import org.orekit.time.AbsoluteDate; import org.orekit.time.DateTimeComponents; import org.orekit.time.FieldAbsoluteDate; @@ -45,7 +47,8 @@ * @author Bryan Cazabonne * */ -public class NiellMappingFunctionModel implements MappingFunction { +@SuppressWarnings("deprecation") +public class NiellMappingFunctionModel implements MappingFunction, TroposphereMappingFunction { /** Values for the ah average function. */ private static final double[] VALUES_FOR_AH_AVERAGE = { @@ -160,8 +163,19 @@ public NiellMappingFunctionModel(final TimeScale utc) { /** {@inheritDoc} */ @Override + @Deprecated public double[] mappingFactors(final double elevation, final GeodeticPoint point, final AbsoluteDate date) { + return mappingFactors(elevation, point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + date); + } + + /** {@inheritDoc} */ + @Override + public double[] mappingFactors(final double elevation, final GeodeticPoint point, + final PressureTemperatureHumidity weather, + final AbsoluteDate date) { // Day of year computation final DateTimeComponents dtc = date.getComponents(utc); final int dofyear = dtc.getDate().getDayOfYear(); @@ -202,8 +216,21 @@ public double[] mappingFactors(final double elevation, final GeodeticPoint point /** {@inheritDoc} */ @Override + @Deprecated public > T[] mappingFactors(final T elevation, final FieldGeodeticPoint point, final FieldAbsoluteDate date) { + return mappingFactors(elevation, point, + new FieldPressureTemperatureHumidity<>(date.getField(), + TroposphericModelUtils.STANDARD_ATMOSPHERE), + date); + } + + /** {@inheritDoc} */ + @Override + public > T[] mappingFactors(final T elevation, + final FieldGeodeticPoint point, + final FieldPressureTemperatureHumidity weather, + final FieldAbsoluteDate date) { final Field field = date.getField(); final T zero = field.getZero(); diff --git a/src/main/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModel.java b/src/main/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModel.java index b9e6bae042..9c121582dd 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModel.java @@ -263,7 +263,7 @@ private EstimatedModel changeTroposphericParameterDriversNames(final EstimatedMo // If the name is the default name for EstimatedTroposphericModel parameter drivers // Modify the name to add the prefix and the date - if (driverName.equals(EstimatedTroposphericModel.TOTAL_ZENITH_DELAY)) { + if (driverName.equals(EstimatedModel.TOTAL_ZENITH_DELAY)) { driver.setName(driverName + datePrefix + date.toString(timeScale)); } } diff --git a/src/main/java/org/orekit/models/earth/troposphere/TroposphereMappingFunction.java b/src/main/java/org/orekit/models/earth/troposphere/TroposphereMappingFunction.java new file mode 100644 index 0000000000..2465dd24db --- /dev/null +++ b/src/main/java/org/orekit/models/earth/troposphere/TroposphereMappingFunction.java @@ -0,0 +1,65 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import org.hipparchus.CalculusFieldElement; +import org.orekit.bodies.FieldGeodeticPoint; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; +import org.orekit.models.earth.weather.PressureTemperatureHumidity; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; + +/** Interface for mapping functions used in the tropospheric delay computation. + * @author Bryan Cazabonne + * @author Luc Maisonobe + */ +public interface TroposphereMappingFunction { + + /** This method allows the computation of the hydrostatic and + * wet mapping functions. The resulting element is an array having the following form: + *

                      + *
                    • double[0] = mh(e) → hydrostatic mapping function + *
                    • double[1] = mw(e) → wet mapping function + *
                    + * @param elevation the elevation of the satellite, in radians + * @param point station location + * @param weather weather parameters + * @param date current date + * @return a two components array containing the hydrostatic and wet mapping functions. + */ + double[] mappingFactors(double elevation, GeodeticPoint point, + PressureTemperatureHumidity weather, AbsoluteDate date); + + /** This method allows the computation of the hydrostatic and + * wet mapping functions. The resulting element is an array having the following form: + *
                      + *
                    • T[0] = mh(e) → hydrostatic mapping function + *
                    • T[1] = mw(e) → wet mapping function + *
                    + * @param elevation the elevation of the satellite, in radians + * @param point station location + * @param weather weather parameters + * @param date current date + * @param type of the elements + * @return a two components array containing the hydrostatic and wet mapping functions. + */ + > T[] mappingFactors(T elevation, FieldGeodeticPoint point, + FieldPressureTemperatureHumidity weather, + FieldAbsoluteDate date); + +} diff --git a/src/main/java/org/orekit/models/earth/troposphere/TroposphereMappingFunctionAdapter.java b/src/main/java/org/orekit/models/earth/troposphere/TroposphereMappingFunctionAdapter.java new file mode 100644 index 0000000000..c43d65bc4f --- /dev/null +++ b/src/main/java/org/orekit/models/earth/troposphere/TroposphereMappingFunctionAdapter.java @@ -0,0 +1,86 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import org.hipparchus.CalculusFieldElement; +import org.orekit.bodies.FieldGeodeticPoint; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; +import org.orekit.models.earth.weather.PressureTemperatureHumidity; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; + +/** Adapter between {@link MappingFunction} and {@link TroposphereMappingFunction}. + *

                    + * This class is a temporary adapter, it will be removed when + * {@link MappingFunction} is removed. + *

                    + * @author Luc Maisonobe + * @since 12.1 + * @deprecated temporary adapter to be removed when {@link MappingFunction} is removed + */ +@Deprecated +public class TroposphereMappingFunctionAdapter implements TroposphereMappingFunction { + + /** Underlying model. */ + private final MappingFunction model; + + /** Simple constructor. + * @param model underlying model + */ + public TroposphereMappingFunctionAdapter(final MappingFunction model) { + this.model = model; + } + + /** This method allows the computation of the hydrostatic and + * wet mapping functions. The resulting element is an array having the following form: + *

                      + *
                    • double[0] = mh(e) → hydrostatic mapping function + *
                    • double[1] = mw(e) → wet mapping function + *
                    + * @param elevation the elevation of the satellite, in radians + * @param point station location + * @param weather weather parameters + * @param date current date + * @return a two components array containing the hydrostatic and wet mapping functions. + */ + public double[] mappingFactors(final double elevation, final GeodeticPoint point, + final PressureTemperatureHumidity weather, final AbsoluteDate date) { + return model.mappingFactors(elevation, point, date); + } + + /** This method allows the computation of the hydrostatic and + * wet mapping functions. The resulting element is an array having the following form: + *
                      + *
                    • T[0] = mh(e) → hydrostatic mapping function + *
                    • T[1] = mw(e) → wet mapping function + *
                    + * @param elevation the elevation of the satellite, in radians + * @param point station location + * @param weather weather parameters + * @param date current date + * @param type of the elements + * @return a two components array containing the hydrostatic and wet mapping functions. + */ + public > T[] mappingFactors(final T elevation, + final FieldGeodeticPoint point, + final FieldPressureTemperatureHumidity weather, + final FieldAbsoluteDate date) { + return model.mappingFactors(elevation, point, date); + } + +} diff --git a/src/main/java/org/orekit/models/earth/troposphere/TroposphericModel.java b/src/main/java/org/orekit/models/earth/troposphere/TroposphericModel.java index f42008dd7f..bf709392ab 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/TroposphericModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/TroposphericModel.java @@ -38,7 +38,6 @@ public interface TroposphericModel extends ParameterDriversProvider { * @param elevation the elevation of the satellite, in radians * @param point station location * @param weather weather parameters - * (could be set to {@link TroposphericModelUtils#STANDARD_ATMOSPHERE_PROVIDER} * for constant default values) * @param parameters tropospheric model parameters * @param date current date @@ -54,7 +53,6 @@ public interface TroposphericModel extends ParameterDriversProvider { * @param elevation the elevation of the satellite, in radians * @param point station location * @param weather weather parameters - * (could be set to {@link TroposphericModelUtils#STANDARD_ATMOSPHERE_PROVIDER} * for constant default values) * @param parameters tropospheric model parameters at current date * @param date current date diff --git a/src/main/java/org/orekit/models/earth/troposphere/ViennaOneModel.java b/src/main/java/org/orekit/models/earth/troposphere/ViennaOneModel.java index e94d0aa5a3..1bef2809d9 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/ViennaOneModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/ViennaOneModel.java @@ -51,7 +51,8 @@ * @author Bryan Cazabonne */ @SuppressWarnings("deprecation") -public class ViennaOneModel implements DiscreteTroposphericModel, TroposphericModel, MappingFunction { +public class ViennaOneModel + implements DiscreteTroposphericModel, TroposphericModel, MappingFunction, TroposphereMappingFunction { /** The a coefficient for the computation of the wet and hydrostatic mapping functions.*/ private final double[] coefficientsA; @@ -118,7 +119,7 @@ public double pathDelay(final double elevation, final GeodeticPoint point, @Override @Deprecated public > T pathDelay(final T elevation, final FieldGeodeticPoint point, - final T[] parameters, final FieldAbsoluteDate date) { + final T[] parameters, final FieldAbsoluteDate date) { return pathDelay(elevation, point, new FieldPressureTemperatureHumidity<>(date.getField(), TroposphericModelUtils.STANDARD_ATMOSPHERE), parameters, date); @@ -165,7 +166,7 @@ public double[] computeZenithDelay(final GeodeticPoint point, final double[] par * @return a two components array containing the zenith hydrostatic and wet delays. */ public > T[] computeZenithDelay(final FieldGeodeticPoint point, final T[] parameters, - final FieldAbsoluteDate date) { + final FieldAbsoluteDate date) { final Field field = date.getField(); final T zero = field.getZero(); final T[] delays = MathArrays.buildArray(field, 2); @@ -174,9 +175,20 @@ public > T[] computeZenithDelay(final FieldGeo return delays; } + /** {@inheritDoc} */ + @Override + @Deprecated + public double[] mappingFactors(final double elevation, final GeodeticPoint point, + final AbsoluteDate date) { + return mappingFactors(elevation, point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + date); + } + /** {@inheritDoc} */ @Override public double[] mappingFactors(final double elevation, final GeodeticPoint point, + final PressureTemperatureHumidity weather, final AbsoluteDate date) { // Day of year computation final DateTimeComponents dtc = date.getComponents(utc); @@ -230,8 +242,21 @@ public double[] mappingFactors(final double elevation, final GeodeticPoint point /** {@inheritDoc} */ @Override + @Deprecated public > T[] mappingFactors(final T elevation, final FieldGeodeticPoint point, - final FieldAbsoluteDate date) { + final FieldAbsoluteDate date) { + return mappingFactors(elevation, point, + new FieldPressureTemperatureHumidity<>(date.getField(), + TroposphericModelUtils.STANDARD_ATMOSPHERE), + date); + } + + /** {@inheritDoc} */ + @Override + public > T[] mappingFactors(final T elevation, + final FieldGeodeticPoint point, + final FieldPressureTemperatureHumidity weather, + final FieldAbsoluteDate date) { final Field field = date.getField(); final T zero = field.getZero(); diff --git a/src/main/java/org/orekit/models/earth/troposphere/ViennaThreeModel.java b/src/main/java/org/orekit/models/earth/troposphere/ViennaThreeModel.java index 1498deb727..f7e98df2fa 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/ViennaThreeModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/ViennaThreeModel.java @@ -59,7 +59,8 @@ * @author Bryan Cazabonne */ @SuppressWarnings("deprecation") -public class ViennaThreeModel implements DiscreteTroposphericModel, TroposphericModel, MappingFunction { +public class ViennaThreeModel + implements DiscreteTroposphericModel, TroposphericModel, MappingFunction, TroposphereMappingFunction { /** The a coefficient for the computation of the wet and hydrostatic mapping functions.*/ private final double[] coefficientsA; @@ -98,9 +99,20 @@ public ViennaThreeModel(final double[] coefficientA, this.utc = utc; } + /** {@inheritDoc} */ + @Override + @Deprecated + public double[] mappingFactors(final double elevation, final GeodeticPoint point, + final AbsoluteDate date) { + return mappingFactors(elevation, point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + date); + } + /** {@inheritDoc} */ @Override public double[] mappingFactors(final double elevation, final GeodeticPoint point, + final PressureTemperatureHumidity weather, final AbsoluteDate date) { // Day of year computation final DateTimeComponents dtc = date.getComponents(utc); @@ -185,8 +197,21 @@ public double[] mappingFactors(final double elevation, final GeodeticPoint point /** {@inheritDoc} */ @Override + @Deprecated public > T[] mappingFactors(final T elevation, final FieldGeodeticPoint point, - final FieldAbsoluteDate date) { + final FieldAbsoluteDate date) { + return mappingFactors(elevation, point, + new FieldPressureTemperatureHumidity<>(date.getField(), + TroposphericModelUtils.STANDARD_ATMOSPHERE), + date); + } + + /** {@inheritDoc} */ + @Override + public > T[] mappingFactors(final T elevation, + final FieldGeodeticPoint point, + final FieldPressureTemperatureHumidity weather, + final FieldAbsoluteDate date) { final Field field = date.getField(); final T zero = field.getZero(); diff --git a/src/test/java/org/orekit/estimation/common/AbstractOrbitDetermination.java b/src/test/java/org/orekit/estimation/common/AbstractOrbitDetermination.java index d514767728..5c106d4adb 100644 --- a/src/test/java/org/orekit/estimation/common/AbstractOrbitDetermination.java +++ b/src/test/java/org/orekit/estimation/common/AbstractOrbitDetermination.java @@ -136,7 +136,7 @@ import org.orekit.models.earth.ionosphere.SingleLayerModelMappingFunction; import org.orekit.models.earth.troposphere.EstimatedModel; import org.orekit.models.earth.troposphere.GlobalMappingFunctionModel; -import org.orekit.models.earth.troposphere.MappingFunction; +import org.orekit.models.earth.troposphere.TroposphereMappingFunction; import org.orekit.models.earth.troposphere.MendesPavlisModel; import org.orekit.models.earth.troposphere.ModifiedSaastamoinenModel; import org.orekit.models.earth.troposphere.NiellMappingFunctionModel; @@ -1602,7 +1602,7 @@ private Map createStationsData(final KeyValueFileParser> void doTestMappingFactors(final Fi final double elevation = FastMath.toRadians(5.0); - final MappingFunction model = buildMappingFunction(); + final TroposphereMappingFunction model = buildMappingFunction(); - final T[] computedMapping = model.mappingFactors(zero.add(elevation), point, date); + final T[] computedMapping = model.mappingFactors(zero.add(elevation), point, + new FieldPressureTemperatureHumidity<>(field, + TroposphericModelUtils.STANDARD_ATMOSPHERE), + date); Assertions.assertEquals(expectedHydro, computedMapping[0].getReal(), 1.0e-2); Assertions.assertEquals(expectedWet, computedMapping[1].getReal(), 1.0e-2); @@ -100,13 +104,16 @@ private > void doTestFixedHeight(final Field date = new FieldAbsoluteDate<>(field); final FieldGeodeticPoint point = new FieldGeodeticPoint<>(zero.add(FastMath.toRadians(45.0)), zero.add(FastMath.toRadians(45.0)), zero.add(350.0)); - final MappingFunction model = buildMappingFunction(); + final TroposphereMappingFunction model = buildMappingFunction(); T[] lastFactors = MathArrays.buildArray(field, 2); lastFactors[0] = zero.add(Double.MAX_VALUE); lastFactors[1] = zero.add(Double.MAX_VALUE); // mapping functions shall decline with increasing elevation angle for (double elev = 10d; elev < 90d; elev += 8d) { - final T[] factors = model.mappingFactors(zero.add(FastMath.toRadians(elev)), point, + final T[] factors = model.mappingFactors(zero.add(FastMath.toRadians(elev)), + point, + new FieldPressureTemperatureHumidity<>(field, + TroposphericModelUtils.STANDARD_ATMOSPHERE), date); Assertions.assertTrue(Precision.compareTo(factors[0].getReal(), lastFactors[0].getReal(), 1.0e-6) < 0); Assertions.assertTrue(Precision.compareTo(factors[1].getReal(), lastFactors[1].getReal(), 1.0e-6) < 0); @@ -137,7 +144,7 @@ protected void doTestMFStateDerivatives(final double epsMFH, final double epsMFW TroposphericModelUtils.STANDARD_ATMOSPHERE_PROVIDER); // Mapping Function model - final MappingFunction model = buildMappingFunction(); + final TroposphereMappingFunction model = buildMappingFunction(); // Derivative Structure final DSFactory factory = new DSFactory(6, 1); @@ -150,6 +157,10 @@ protected void doTestMFStateDerivatives(final double epsMFH, final double epsMFW final Field field = a0.getField(); final DerivativeStructure zero = field.getZero(); + final FieldPressureTemperatureHumidity weather = + new FieldPressureTemperatureHumidity<>(field, + TroposphericModelUtils.STANDARD_ATMOSPHERE); + // Field Date final FieldAbsoluteDate dsDate = new FieldAbsoluteDate<>(field); // Field Orbit @@ -166,7 +177,7 @@ protected void doTestMFStateDerivatives(final double epsMFH, final double epsMFW // Compute mapping factors with state derivatives final FieldGeodeticPoint dsPoint = new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), zero.add(height)); - final DerivativeStructure[] factors = model.mappingFactors(dsElevation, dsPoint, dsDate); + final DerivativeStructure[] factors = model.mappingFactors(dsElevation, dsPoint, weather, dsDate); final double[] compMFH = factors[0].getAllDerivatives(); final double[] compMFW = factors[1].getAllDerivatives(); @@ -187,56 +198,72 @@ protected void doTestMFStateDerivatives(final double epsMFH, final double epsMFW final double elevationM4 = station.getBaseFrame(). getTrackingCoordinates(positionM4, stateM4.getFrame(), stateM4.getDate()). getElevation(); - double[] delayM4 = model.mappingFactors(elevationM4, point, stateM4.getDate()); + double[] delayM4 = model.mappingFactors(elevationM4, point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + stateM4.getDate()); SpacecraftState stateM3 = shiftState(state, orbitType, angleType, -3 * steps[i], i); final Vector3D positionM3 = stateM3.getPosition(); final double elevationM3 = station.getBaseFrame(). getTrackingCoordinates(positionM3, stateM3.getFrame(), stateM3.getDate()). getElevation(); - double[] delayM3 = model.mappingFactors(elevationM3, point, stateM3.getDate()); + double[] delayM3 = model.mappingFactors(elevationM3, point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + stateM3.getDate()); SpacecraftState stateM2 = shiftState(state, orbitType, angleType, -2 * steps[i], i); final Vector3D positionM2 = stateM2.getPosition(); final double elevationM2 = station.getBaseFrame(). getTrackingCoordinates(positionM2, stateM2.getFrame(), stateM2.getDate()). getElevation(); - double[] delayM2 = model.mappingFactors(elevationM2, point, stateM2.getDate()); + double[] delayM2 = model.mappingFactors(elevationM2, point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + stateM2.getDate()); SpacecraftState stateM1 = shiftState(state, orbitType, angleType, -1 * steps[i], i); final Vector3D positionM1 = stateM1.getPosition(); final double elevationM1 = station.getBaseFrame(). getTrackingCoordinates(positionM1, stateM1.getFrame(), stateM1.getDate()). getElevation(); - double[] delayM1 = model.mappingFactors(elevationM1, point, stateM1.getDate()); + double[] delayM1 = model.mappingFactors(elevationM1, point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + stateM1.getDate()); SpacecraftState stateP1 = shiftState(state, orbitType, angleType, 1 * steps[i], i); final Vector3D positionP1 = stateP1.getPosition(); final double elevationP1 = station.getBaseFrame(). getTrackingCoordinates(positionP1, stateP1.getFrame(), stateP1.getDate()). getElevation(); - double[] delayP1 = model.mappingFactors(elevationP1, point, stateP1.getDate()); + double[] delayP1 = model.mappingFactors(elevationP1, point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + stateP1.getDate()); SpacecraftState stateP2 = shiftState(state, orbitType, angleType, 2 * steps[i], i); final Vector3D positionP2 = stateP2.getPosition(); final double elevationP2 = station.getBaseFrame(). getTrackingCoordinates(positionP2, stateP2.getFrame(), stateP2.getDate()). getElevation(); - double[] delayP2 = model.mappingFactors(elevationP2, point, stateP2.getDate()); + double[] delayP2 = model.mappingFactors(elevationP2, point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + stateP2.getDate()); SpacecraftState stateP3 = shiftState(state, orbitType, angleType, 3 * steps[i], i); final Vector3D positionP3 = stateP3.getPosition(); final double elevationP3 = station.getBaseFrame(). getTrackingCoordinates(positionP3, stateP3.getFrame(), stateP3.getDate()). getElevation(); - double[] delayP3 = model.mappingFactors(elevationP3, point, stateP3.getDate()); + double[] delayP3 = model.mappingFactors(elevationP3, point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + stateP3.getDate()); SpacecraftState stateP4 = shiftState(state, orbitType, angleType, 4 * steps[i], i); final Vector3D positionP4 = stateP4.getPosition(); final double elevationP4 = station.getBaseFrame(). getTrackingCoordinates(positionP4, stateP4.getFrame(), stateP4.getDate()). getElevation(); - double[] delayP4 = model.mappingFactors(elevationP4, point, stateP4.getDate()); + double[] delayP4 = model.mappingFactors(elevationP4, point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + stateP4.getDate()); fillJacobianColumn(refMF, i, orbitType, angleType, steps[i], delayM4, delayM3, delayM2, delayM1, diff --git a/src/test/java/org/orekit/models/earth/troposphere/AbstractMappingFunctionTest.java b/src/test/java/org/orekit/models/earth/troposphere/AbstractMappingFunctionTest.java index b8268b25c1..e265b2577c 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/AbstractMappingFunctionTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/AbstractMappingFunctionTest.java @@ -28,7 +28,7 @@ public abstract class AbstractMappingFunctionTest { - protected abstract MappingFunction buildMappingFunction(); + protected abstract TroposphereMappingFunction buildMappingFunction(); @Test public abstract void testMappingFactors(); @@ -49,9 +49,11 @@ protected void doTestMappingFactors(final double expectedHydro, final double elevation = FastMath.toRadians(5.0); - final MappingFunction model = buildMappingFunction(); + final TroposphereMappingFunction model = buildMappingFunction(); - final double[] computedMapping = model.mappingFactors(elevation, point, date); + final double[] computedMapping = model.mappingFactors(elevation, point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + date); Assertions.assertEquals(expectedHydro, computedMapping[0], 1.0e-2); Assertions.assertEquals(expectedWet, computedMapping[1], 1.0e-2); @@ -61,14 +63,16 @@ protected void doTestMappingFactors(final double expectedHydro, public void doTestFixedHeight() { final AbsoluteDate date = new AbsoluteDate(); final GeodeticPoint point = new GeodeticPoint(FastMath.toRadians(45.0), FastMath.toRadians(45.0), 350.0); - MappingFunction model = buildMappingFunction(); + TroposphereMappingFunction model = buildMappingFunction(); double[] lastFactors = new double[] { Double.MAX_VALUE, Double.MAX_VALUE }; // mapping functions shall decline with increasing elevation angle for (double elev = 10d; elev < 90d; elev += 8d) { - final double[] factors = model.mappingFactors(FastMath.toRadians(elev), point, date); + final double[] factors = model.mappingFactors(FastMath.toRadians(elev), point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + date); Assertions.assertTrue(Precision.compareTo(factors[0], lastFactors[0], 1.0e-6) < 0); Assertions.assertTrue(Precision.compareTo(factors[1], lastFactors[1], 1.0e-6) < 0); lastFactors[0] = factors[0]; diff --git a/src/test/java/org/orekit/models/earth/troposphere/ChaoMappingFunctionTest.java b/src/test/java/org/orekit/models/earth/troposphere/ChaoMappingFunctionTest.java index 75d612cd42..5a81093d07 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/ChaoMappingFunctionTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/ChaoMappingFunctionTest.java @@ -20,7 +20,7 @@ public class ChaoMappingFunctionTest extends AbstractMappingFunctionTest { - protected MappingFunction buildMappingFunction() { + protected TroposphereMappingFunction buildMappingFunction() { return new ChaoMappingFunction(); } diff --git a/src/test/java/org/orekit/models/earth/troposphere/EstimatedModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/EstimatedModelTest.java index e19a2981fa..82d576e065 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/EstimatedModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/EstimatedModelTest.java @@ -72,7 +72,7 @@ public void setUp() throws OrekitException { public void testFixedHeight() { final AbsoluteDate date = new AbsoluteDate(); GeodeticPoint point = new GeodeticPoint(FastMath.toRadians(45.0), FastMath.toRadians(45.0), 350.0); - MappingFunction mapping = new NiellMappingFunctionModel(); + TroposphereMappingFunction mapping = new NiellMappingFunctionModel(); TroposphericModel model = new EstimatedModel(mapping, 2.0); double lastDelay = Double.MAX_VALUE; // delay shall decline with increasing elevation angle @@ -91,7 +91,7 @@ public void testDelay() { final double height = 100d; final AbsoluteDate date = new AbsoluteDate(); GeodeticPoint point = new GeodeticPoint(FastMath.toRadians(45.0), FastMath.toRadians(45.0), height); - MappingFunction mapping = new NiellMappingFunctionModel(); + TroposphereMappingFunction mapping = new NiellMappingFunctionModel(); TroposphericModel model = new EstimatedModel(mapping, 2.0); final double path = model.pathDelay(FastMath.toRadians(elevation), point, TroposphericModelUtils.STANDARD_ATMOSPHERE, @@ -105,7 +105,7 @@ public void testStateDerivativesGMF() { final double latitude = FastMath.toRadians(45.0); final double longitude = FastMath.toRadians(45.0); GeodeticPoint point = new GeodeticPoint(latitude, longitude, 0.0); - final MappingFunction gmf = new GlobalMappingFunctionModel(); + final TroposphereMappingFunction gmf = new GlobalMappingFunctionModel(); doTestDelayStateDerivatives(gmf, point, 4.7e-9); } @@ -114,11 +114,11 @@ public void testStateDerivativesNMF() { final double latitude = FastMath.toRadians(45.0); final double longitude = FastMath.toRadians(45.0); GeodeticPoint point = new GeodeticPoint(latitude, longitude, 0.0); - final MappingFunction nmf = new NiellMappingFunctionModel(); + final TroposphereMappingFunction nmf = new NiellMappingFunctionModel(); doTestDelayStateDerivatives(nmf, point, 4.4e-9); } - private void doTestDelayStateDerivatives(final MappingFunction func, final GeodeticPoint point, final double tolerance) { + private void doTestDelayStateDerivatives(final TroposphereMappingFunction func, final GeodeticPoint point, final double tolerance) { // Body: earth final OneAxisEllipsoid earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS, @@ -277,7 +277,7 @@ private void doTestParametersDerivatives(String parameterName, double tolerance) final TopocentricFrame baseFrame = new TopocentricFrame(earth, point, "topo"); // Tropospheric model - final MappingFunction gmf = new GlobalMappingFunctionModel(); + final TroposphereMappingFunction gmf = new GlobalMappingFunctionModel(); final TroposphericModel model = new EstimatedModel(gmf, 5.0); // Set Parameter Driver diff --git a/src/test/java/org/orekit/models/earth/troposphere/FieldChaoMappingFunctionTest.java b/src/test/java/org/orekit/models/earth/troposphere/FieldChaoMappingFunctionTest.java index 3af2bbd6f8..66b4450587 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/FieldChaoMappingFunctionTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/FieldChaoMappingFunctionTest.java @@ -21,7 +21,7 @@ public class FieldChaoMappingFunctionTest extends AbstractFieldMappingFunctionTest { - protected MappingFunction buildMappingFunction() { + protected TroposphereMappingFunction buildMappingFunction() { return new ChaoMappingFunction(); } diff --git a/src/test/java/org/orekit/models/earth/troposphere/FieldGlobalMappingFunctionModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/FieldGlobalMappingFunctionModelTest.java index 98bfd220ef..6aa21e000d 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/FieldGlobalMappingFunctionModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/FieldGlobalMappingFunctionModelTest.java @@ -40,6 +40,7 @@ import org.orekit.frames.Frame; import org.orekit.frames.FramesFactory; import org.orekit.frames.TopocentricFrame; +import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; import org.orekit.orbits.FieldKeplerianOrbit; import org.orekit.orbits.FieldOrbit; import org.orekit.orbits.Orbit; @@ -96,9 +97,12 @@ private > void doTestMappingFactors(final Fiel final double expectedHydro = 3.425246; final double expectedWet = 3.449589; - final MappingFunction model = new GlobalMappingFunctionModel(); + final TroposphereMappingFunction model = new GlobalMappingFunctionModel(); + final FieldPressureTemperatureHumidity weather = + new FieldPressureTemperatureHumidity<>(field, + TroposphericModelUtils.STANDARD_ATMOSPHERE); - final T[] computedMapping = model.mappingFactors(zero.add(elevation), point, date); + final T[] computedMapping = model.mappingFactors(zero.add(elevation), point, weather, date); Assertions.assertEquals(expectedHydro, computedMapping[0].getReal(), 1.0e-6); Assertions.assertEquals(expectedWet, computedMapping[1].getReal(), 1.0e-6); @@ -112,7 +116,10 @@ public void testFixedHeight() { private > void doTestFixedHeight(final Field field) { final T zero = field.getZero(); final FieldAbsoluteDate date = new FieldAbsoluteDate<>(field); - MappingFunction model = new GlobalMappingFunctionModel(); + TroposphereMappingFunction model = new GlobalMappingFunctionModel(); + final FieldPressureTemperatureHumidity weather = + new FieldPressureTemperatureHumidity<>(field, + TroposphericModelUtils.STANDARD_ATMOSPHERE); FieldGeodeticPoint point = new FieldGeodeticPoint(zero.add(FastMath.toRadians(45.0)), zero.add(FastMath.toRadians(45.0)), zero.add(350.0)); final T[] lastFactors = MathArrays.buildArray(field, 2); lastFactors[0] = zero.add(Double.MAX_VALUE); @@ -120,7 +127,7 @@ private > void doTestFixedHeight(final Field field = a0.getField(); final DerivativeStructure zero = field.getZero(); + final FieldPressureTemperatureHumidity weather = + new FieldPressureTemperatureHumidity<>(field, + TroposphericModelUtils.STANDARD_ATMOSPHERE); + // Field Date final FieldAbsoluteDate dsDate = new FieldAbsoluteDate<>(field); // Field Orbit @@ -177,7 +188,7 @@ public void testMFStateDerivatives() { // Compute mapping factors state derivatives final FieldGeodeticPoint dsPoint = new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), zero.add(height)); - final DerivativeStructure[] factors = model.mappingFactors(dsElevation, dsPoint, dsDate); + final DerivativeStructure[] factors = model.mappingFactors(dsElevation, dsPoint, weather, dsDate); final double[] compMFH = factors[0].getAllDerivatives(); final double[] compMFW = factors[1].getAllDerivatives(); @@ -198,56 +209,72 @@ public void testMFStateDerivatives() { final double elevationM4 = station.getBaseFrame(). getTrackingCoordinates(positionM4, stateM4.getFrame(), stateM4.getDate()). getElevation(); - double[] delayM4 = model.mappingFactors(elevationM4, point, stateM4.getDate()); + double[] delayM4 = model.mappingFactors(elevationM4, point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + stateM4.getDate()); SpacecraftState stateM3 = shiftState(state, orbitType, angleType, -3 * steps[i], i); final Vector3D positionM3 = stateM3.getPosition(); final double elevationM3 = station.getBaseFrame(). getTrackingCoordinates(positionM3, stateM3.getFrame(), stateM3.getDate()). getElevation(); - double[] delayM3 = model.mappingFactors(elevationM3, point, stateM3.getDate()); + double[] delayM3 = model.mappingFactors(elevationM3, point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + stateM3.getDate()); SpacecraftState stateM2 = shiftState(state, orbitType, angleType, -2 * steps[i], i); final Vector3D positionM2 = stateM2.getPosition(); final double elevationM2 = station.getBaseFrame(). getTrackingCoordinates(positionM2, stateM2.getFrame(), stateM2.getDate()). getElevation(); - double[] delayM2 = model.mappingFactors(elevationM2, point, stateM2.getDate()); + double[] delayM2 = model.mappingFactors(elevationM2, point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + stateM2.getDate()); SpacecraftState stateM1 = shiftState(state, orbitType, angleType, -1 * steps[i], i); final Vector3D positionM1 = stateM1.getPosition(); final double elevationM1 = station.getBaseFrame(). getTrackingCoordinates(positionM1, stateM1.getFrame(), stateM1.getDate()). getElevation(); - double[] delayM1 = model.mappingFactors(elevationM1, point, stateM1.getDate()); + double[] delayM1 = model.mappingFactors(elevationM1, point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + stateM1.getDate()); SpacecraftState stateP1 = shiftState(state, orbitType, angleType, 1 * steps[i], i); final Vector3D positionP1 = stateP1.getPosition(); final double elevationP1 = station.getBaseFrame(). getTrackingCoordinates(positionP1, stateP1.getFrame(), stateP1.getDate()). getElevation(); - double[] delayP1 = model.mappingFactors(elevationP1, point, stateP1.getDate()); + double[] delayP1 = model.mappingFactors(elevationP1, point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + stateP1.getDate()); SpacecraftState stateP2 = shiftState(state, orbitType, angleType, 2 * steps[i], i); final Vector3D positionP2 = stateP2.getPosition(); final double elevationP2 = station.getBaseFrame(). getTrackingCoordinates(positionP2, stateP2.getFrame(), stateP2.getDate()). getElevation(); - double[] delayP2 = model.mappingFactors(elevationP2, point, stateP2.getDate()); + double[] delayP2 = model.mappingFactors(elevationP2, point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + stateP2.getDate()); SpacecraftState stateP3 = shiftState(state, orbitType, angleType, 3 * steps[i], i); final Vector3D positionP3 = stateP3.getPosition(); final double elevationP3 = station.getBaseFrame(). getTrackingCoordinates(positionP3, stateP3.getFrame(), stateP3.getDate()). getElevation(); - double[] delayP3 = model.mappingFactors(elevationP3, point, stateP3.getDate()); + double[] delayP3 = model.mappingFactors(elevationP3, point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + stateP3.getDate()); SpacecraftState stateP4 = shiftState(state, orbitType, angleType, 4 * steps[i], i); final Vector3D positionP4 = stateP4.getPosition(); final double elevationP4 = station.getBaseFrame(). getTrackingCoordinates(positionP4, stateP4.getFrame(), stateP4.getDate()). getElevation(); - double[] delayP4 = model.mappingFactors(elevationP4, point, stateP4.getDate()); + double[] delayP4 = model.mappingFactors(elevationP4, point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + stateP4.getDate()); fillJacobianColumn(refMF, i, orbitType, angleType, steps[i], delayM4, delayM3, delayM2, delayM1, diff --git a/src/test/java/org/orekit/models/earth/troposphere/FieldMendesPavlisModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/FieldMendesPavlisModelTest.java index df25157354..15b5f1f333 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/FieldMendesPavlisModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/FieldMendesPavlisModelTest.java @@ -176,7 +176,10 @@ private > void doTestMappingFactors(final Fiel final MendesPavlisModel model = new MendesPavlisModel(new ConstantPressureTemperatureHumidityProvider(pth), lambda, TroposphericModelUtils.MICRO_M); - final T[] computedMapping = model.mappingFactors(zero.add(elevation), point, date); + final T[] computedMapping = model.mappingFactors(zero.add(elevation), point, + new FieldPressureTemperatureHumidity<>(field, + TroposphericModelUtils.STANDARD_ATMOSPHERE), + date); Assertions.assertEquals(expectedMapping, computedMapping[0].getReal(), 5.0e-8); Assertions.assertEquals(expectedMapping, computedMapping[1].getReal(), 5.0e-8); diff --git a/src/test/java/org/orekit/models/earth/troposphere/FieldNiellMappingFunctionModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/FieldNiellMappingFunctionModelTest.java index f8e412830a..9ea66f611b 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/FieldNiellMappingFunctionModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/FieldNiellMappingFunctionModelTest.java @@ -21,7 +21,7 @@ public class FieldNiellMappingFunctionModelTest extends AbstractFieldMappingFunctionTest { - protected MappingFunction buildMappingFunction() { + protected TroposphereMappingFunction buildMappingFunction() { return new NiellMappingFunctionModel(); } diff --git a/src/test/java/org/orekit/models/earth/troposphere/FieldRevisedChaoMappingFunctionTest.java b/src/test/java/org/orekit/models/earth/troposphere/FieldRevisedChaoMappingFunctionTest.java index 4177128fc4..d80d8ae3e9 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/FieldRevisedChaoMappingFunctionTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/FieldRevisedChaoMappingFunctionTest.java @@ -21,7 +21,7 @@ public class FieldRevisedChaoMappingFunctionTest extends AbstractFieldMappingFunctionTest { - protected MappingFunction buildMappingFunction() { + protected TroposphereMappingFunction buildMappingFunction() { return new RevisedChaoMappingFunction(); } diff --git a/src/test/java/org/orekit/models/earth/troposphere/FieldViennaOneModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/FieldViennaOneModelTest.java index 1bebb36715..a928fe214d 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/FieldViennaOneModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/FieldViennaOneModelTest.java @@ -114,7 +114,10 @@ private > void doTestMappingFactors(final Fiel final FieldGeodeticPoint point = new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), zero.add(height)); final ViennaOneModel model = new ViennaOneModel(a, z); - final T[] computedMapping = model.mappingFactors(zero.add(elevation), point, date); + final T[] computedMapping = model.mappingFactors(zero.add(elevation), point, + new FieldPressureTemperatureHumidity<>(field, + TroposphericModelUtils.STANDARD_ATMOSPHERE), + date); Assertions.assertEquals(expectedHydro, computedMapping[0].getReal(), 4.1e-6); Assertions.assertEquals(expectedWet, computedMapping[1].getReal(), 1.0e-6); diff --git a/src/test/java/org/orekit/models/earth/troposphere/FieldViennaThreeModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/FieldViennaThreeModelTest.java index c7f28a5f86..8cdd6d5cce 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/FieldViennaThreeModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/FieldViennaThreeModelTest.java @@ -115,6 +115,8 @@ private > void doTestMappingFactors(final Fiel final ViennaThreeModel model = new ViennaThreeModel(a, z); final T[] computedMapping = model.mappingFactors(zero.add(elevation), point, + new FieldPressureTemperatureHumidity<>(field, + TroposphericModelUtils.STANDARD_ATMOSPHERE), date); Assertions.assertEquals(expectedHydro, computedMapping[0].getReal(), epsilon); @@ -168,6 +170,8 @@ private > void doTestLowElevation(final Field< final ViennaThreeModel model = new ViennaThreeModel(a, z); final T[] computedMapping = model.mappingFactors(zero.add(elevation), point, + new FieldPressureTemperatureHumidity<>(field, + TroposphericModelUtils.STANDARD_ATMOSPHERE), date); Assertions.assertEquals(expectedHydro, computedMapping[0].getReal(), epsilon); @@ -221,6 +225,8 @@ private > void doTestHightElevation(final Fiel final ViennaThreeModel model = new ViennaThreeModel(a, z); final T[] computedMapping = model.mappingFactors(zero.add(elevation), point, + new FieldPressureTemperatureHumidity<>(field, + TroposphericModelUtils.STANDARD_ATMOSPHERE), date); Assertions.assertEquals(expectedHydro, computedMapping[0].getReal(), epsilon); diff --git a/src/test/java/org/orekit/models/earth/troposphere/GlobalMappingFunctionModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/GlobalMappingFunctionModelTest.java index 52cea6b19b..83d3e7e1f5 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/GlobalMappingFunctionModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/GlobalMappingFunctionModelTest.java @@ -66,9 +66,11 @@ public void testMappingFactors() { final double expectedHydro = 3.425246; final double expectedWet = 3.449589; - final MappingFunction model = new GlobalMappingFunctionModel(); + final TroposphereMappingFunction model = new GlobalMappingFunctionModel(); - final double[] computedMapping = model.mappingFactors(elevation, point, date); + final double[] computedMapping = model.mappingFactors(elevation, point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + date); Assertions.assertEquals(expectedHydro, computedMapping[0], 1.0e-6); Assertions.assertEquals(expectedWet, computedMapping[1], 1.0e-6); @@ -77,7 +79,7 @@ public void testMappingFactors() { @Test public void testFixedHeight() { final AbsoluteDate date = new AbsoluteDate(); - MappingFunction model = new GlobalMappingFunctionModel(); + TroposphereMappingFunction model = new GlobalMappingFunctionModel(); double[] lastFactors = new double[] { Double.MAX_VALUE, Double.MAX_VALUE @@ -85,7 +87,9 @@ public void testFixedHeight() { GeodeticPoint point = new GeodeticPoint(FastMath.toRadians(45.0), FastMath.toRadians(45.0), 350.0); // mapping functions shall decline with increasing elevation angle for (double elev = 10d; elev < 90d; elev += 8d) { - final double[] factors = model.mappingFactors(FastMath.toRadians(elev), point, date); + final double[] factors = model.mappingFactors(FastMath.toRadians(elev), point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + date); Assertions.assertTrue(Precision.compareTo(factors[0], lastFactors[0], 1.0e-6) < 0); Assertions.assertTrue(Precision.compareTo(factors[1], lastFactors[1], 1.0e-6) < 0); lastFactors[0] = factors[0]; diff --git a/src/test/java/org/orekit/models/earth/troposphere/MendesPavlisModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/MendesPavlisModelTest.java index cc0342673d..fc80fed82b 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/MendesPavlisModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/MendesPavlisModelTest.java @@ -143,7 +143,9 @@ public void testMappingFactors() { final MendesPavlisModel model = new MendesPavlisModel(new ConstantPressureTemperatureHumidityProvider(pth), lambda, TroposphericModelUtils.MICRO_M); - final double[] computedMapping = model.mappingFactors(elevation, point, date); + final double[] computedMapping = model.mappingFactors(elevation, point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + date); Assertions.assertEquals(expectedMapping, computedMapping[0], 5.0e-8); Assertions.assertEquals(expectedMapping, computedMapping[1], 5.0e-8); diff --git a/src/test/java/org/orekit/models/earth/troposphere/NiellMappingFunctionModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/NiellMappingFunctionModelTest.java index 5e06dd965a..8ab2f5cf8b 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/NiellMappingFunctionModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/NiellMappingFunctionModelTest.java @@ -20,7 +20,7 @@ public class NiellMappingFunctionModelTest extends AbstractMappingFunctionTest { - protected MappingFunction buildMappingFunction() { + protected TroposphereMappingFunction buildMappingFunction() { return new NiellMappingFunctionModel(); } diff --git a/src/test/java/org/orekit/models/earth/troposphere/RevisedChaoMappingFunctionTest.java b/src/test/java/org/orekit/models/earth/troposphere/RevisedChaoMappingFunctionTest.java index 01ed1a1eb8..2322e7325c 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/RevisedChaoMappingFunctionTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/RevisedChaoMappingFunctionTest.java @@ -20,7 +20,7 @@ public class RevisedChaoMappingFunctionTest extends AbstractMappingFunctionTest { - protected MappingFunction buildMappingFunction() { + protected TroposphereMappingFunction buildMappingFunction() { return new RevisedChaoMappingFunction(); } diff --git a/src/test/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModelTest.java index be15711f5a..0122147cbd 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModelTest.java @@ -74,7 +74,7 @@ public void setUp() throws OrekitException { public void testFixedHeight() { final AbsoluteDate date = new AbsoluteDate(); GeodeticPoint point = new GeodeticPoint(FastMath.toRadians(45.0), FastMath.toRadians(45.0), 350.0); - MappingFunction mapping = new NiellMappingFunctionModel(); + TroposphereMappingFunction mapping = new NiellMappingFunctionModel(); EstimatedModel model = new EstimatedModel(mapping, 2.0); TroposphericModel timeSpanModel = new TimeSpanEstimatedModel(model); double lastDelay = Double.MAX_VALUE; @@ -94,7 +94,7 @@ public void testDelay() { final double height = 100d; final AbsoluteDate date = new AbsoluteDate(); GeodeticPoint point = new GeodeticPoint(FastMath.toRadians(45.0), FastMath.toRadians(45.0), height); - MappingFunction mapping = new NiellMappingFunctionModel(); + TroposphereMappingFunction mapping = new NiellMappingFunctionModel(); EstimatedModel model = new EstimatedModel(mapping, 2.0); TroposphericModel timeSpanModel = new TimeSpanEstimatedModel(model); final double path = timeSpanModel.pathDelay(FastMath.toRadians(elevation), point, @@ -109,7 +109,7 @@ public void testStateDerivativesGMF() { final double latitude = FastMath.toRadians(45.0); final double longitude = FastMath.toRadians(45.0); GeodeticPoint point = new GeodeticPoint(latitude, longitude, 0.0); - final MappingFunction gmf = new GlobalMappingFunctionModel(); + final TroposphereMappingFunction gmf = new GlobalMappingFunctionModel(); doTestDelayStateDerivatives(gmf, point, 4.7e-9); } @@ -118,11 +118,11 @@ public void testStateDerivativesNMF() { final double latitude = FastMath.toRadians(45.0); final double longitude = FastMath.toRadians(45.0); GeodeticPoint point = new GeodeticPoint(latitude, longitude, 0.0); - final MappingFunction nmf = new NiellMappingFunctionModel(); + final TroposphereMappingFunction nmf = new NiellMappingFunctionModel(); doTestDelayStateDerivatives(nmf, point, 4.4e-9); } - private void doTestDelayStateDerivatives(final MappingFunction func, final GeodeticPoint point, final double tolerance) { + private void doTestDelayStateDerivatives(final TroposphereMappingFunction func, final GeodeticPoint point, final double tolerance) { // Body: earth final OneAxisEllipsoid earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS, @@ -281,7 +281,7 @@ private void doTestParametersDerivatives(String parameterName, double tolerance) final TopocentricFrame baseFrame = new TopocentricFrame(earth, point, "topo"); // Tropospheric model - final MappingFunction gmf = new GlobalMappingFunctionModel(); + final TroposphereMappingFunction gmf = new GlobalMappingFunctionModel(); final TroposphericModel model = new EstimatedModel(gmf, 5.0); // Set Parameter Driver @@ -414,7 +414,7 @@ private void doTestParametersDerivatives(String parameterName, double tolerance) @Test public void testComparisonWithEstimatedModel() { final AbsoluteDate date = new AbsoluteDate(); - MappingFunction mapping = new NiellMappingFunctionModel(); + TroposphereMappingFunction mapping = new NiellMappingFunctionModel(); EstimatedModel estimatedModel = new EstimatedModel(mapping, 2.0); TroposphericModel timeSpanModel = new TimeSpanEstimatedModel(estimatedModel); final double elevation = 45.0; @@ -438,7 +438,7 @@ public void testFieldComparisonWithEstimatedModel() { private > void doTestFieldComparisonWithEstimatedModel(final Field field) { final T zero = field.getZero(); final FieldAbsoluteDate date = new FieldAbsoluteDate<>(field); - MappingFunction mapping = new NiellMappingFunctionModel(); + TroposphereMappingFunction mapping = new NiellMappingFunctionModel(); EstimatedModel estimatedModel = new EstimatedModel(mapping, 2.0); TroposphericModel timeSpanModel = new TimeSpanEstimatedModel(estimatedModel); final T elevation = zero.add(45.0); diff --git a/src/test/java/org/orekit/models/earth/troposphere/ViennaOneModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/ViennaOneModelTest.java index d9e5cd50a0..ccf56a84d2 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/ViennaOneModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/ViennaOneModelTest.java @@ -84,7 +84,9 @@ public void testMappingFactors() { final ViennaOneModel model = new ViennaOneModel(a, z); - final double[] computedMapping = model.mappingFactors(elevation, point, date); + final double[] computedMapping = model.mappingFactors(elevation, point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + date); Assertions.assertEquals(expectedHydro, computedMapping[0], 4.1e-6); Assertions.assertEquals(expectedWet, computedMapping[1], 1.0e-6); diff --git a/src/test/java/org/orekit/models/earth/troposphere/ViennaThreeModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/ViennaThreeModelTest.java index d16004a876..8300b33b71 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/ViennaThreeModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/ViennaThreeModelTest.java @@ -81,7 +81,9 @@ public void testMappingFactors() { final ViennaThreeModel model = new ViennaThreeModel(a, z); - final double[] computedMapping = model.mappingFactors(elevation, point, date); + final double[] computedMapping = model.mappingFactors(elevation, point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + date); Assertions.assertEquals(expectedHydro, computedMapping[0], epsilon); Assertions.assertEquals(expectedWet, computedMapping[1], epsilon); @@ -126,7 +128,9 @@ public void testLowElevation() { final ViennaThreeModel model = new ViennaThreeModel(a, z); - final double[] computedMapping = model.mappingFactors(elevation, point, date); + final double[] computedMapping = model.mappingFactors(elevation, point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + date); Assertions.assertEquals(expectedHydro, computedMapping[0], epsilon); Assertions.assertEquals(expectedWet, computedMapping[1], epsilon); @@ -171,7 +175,9 @@ public void testHightElevation() { final ViennaThreeModel model = new ViennaThreeModel(a, z); - final double[] computedMapping = model.mappingFactors(elevation, point, date); + final double[] computedMapping = model.mappingFactors(elevation, point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + date); Assertions.assertEquals(expectedHydro, computedMapping[0], epsilon); Assertions.assertEquals(expectedWet, computedMapping[1], epsilon); From 1ec8dacc8cb4fb88b7f5e6063ff86e69317726ee Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Thu, 14 Dec 2023 17:14:16 +0100 Subject: [PATCH 045/359] Typo. --- .../HeightDependentPressureTemperatureHumidityConverter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/orekit/models/earth/weather/HeightDependentPressureTemperatureHumidityConverter.java b/src/main/java/org/orekit/models/earth/weather/HeightDependentPressureTemperatureHumidityConverter.java index b8723fdfea..4d4b7aa6ea 100644 --- a/src/main/java/org/orekit/models/earth/weather/HeightDependentPressureTemperatureHumidityConverter.java +++ b/src/main/java/org/orekit/models/earth/weather/HeightDependentPressureTemperatureHumidityConverter.java @@ -20,7 +20,7 @@ import org.hipparchus.util.FastMath; import org.orekit.models.earth.weather.water.WaterVaporPressureProvider; -/** Conoverter for weather parameters that change with height. +/** Converter for weather parameters that change with height. *

                    * Height variations correspond to equations 5.98, 5.99 and 5.100 from * Guochang Xu, GPS - Theory, Algorithms and Applications, Springer, 2007 From cafb8a39ef103d350c2ac58969fca349cf8ae2dc Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Fri, 15 Dec 2023 15:36:20 +0100 Subject: [PATCH 046/359] Added ModifiedHopfieldModel for tropospheric delay. --- .../troposphere/ModifiedHopfieldModel.java | 238 ++++++++++++ .../ModifiedHopfieldModelTest.java | 353 ++++++++++++++++++ 2 files changed, 591 insertions(+) create mode 100644 src/main/java/org/orekit/models/earth/troposphere/ModifiedHopfieldModel.java create mode 100644 src/test/java/org/orekit/models/earth/troposphere/ModifiedHopfieldModelTest.java diff --git a/src/main/java/org/orekit/models/earth/troposphere/ModifiedHopfieldModel.java b/src/main/java/org/orekit/models/earth/troposphere/ModifiedHopfieldModel.java new file mode 100644 index 0000000000..d6921b8467 --- /dev/null +++ b/src/main/java/org/orekit/models/earth/troposphere/ModifiedHopfieldModel.java @@ -0,0 +1,238 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS Communication & Systèmes (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import java.util.Collections; +import java.util.List; + +import org.hipparchus.CalculusFieldElement; +import org.hipparchus.util.FastMath; +import org.hipparchus.util.FieldSinCos; +import org.hipparchus.util.MathUtils; +import org.hipparchus.util.SinCos; +import org.orekit.bodies.FieldGeodeticPoint; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; +import org.orekit.models.earth.weather.PressureTemperatureHumidity; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; +import org.orekit.utils.ParameterDriver; + +/** The modified Hopfield model. + *

                    + * This model from Hopfield 1969, 1970, 1972 is described in equations + * 5.105, 5.106, 5.107 and 5.108 in Guochang Xu, GPS - Theory, Algorithms + * and Applications, Springer, 2007. + *

                    + * @author Luc Maisonobe + * @see "Guochang Xu, GPS - Theory, Algorithms and Applications, Springer, 2007" + * @since 12.1 + */ +public class ModifiedHopfieldModel implements TroposphericModel { + + /** Constant for dry altitude effect. */ + private static final double HD0 = 40136.0; + + /** Slope for dry altitude effect. */ + private static final double HD1 = 148.72; + + /** Temperature reference. */ + private static final double T0 = 273.16; + + /** Constant for wet altitude effect. */ + private static final double HW0 = 11000.0; + + /** Dry delay factor. */ + private static final double ND = 77.64e-6; + + /** Wet delay factor, degree 1. */ + private static final double NW1 = -12.96e-6; + + /** Wet delay factor, degree 2. */ + private static final double NW2 = 0.371800; + + /** BAse radius. */ + private static final double RE = 6378137.0; + + /** Create a new Hopfield model. + */ + public ModifiedHopfieldModel() { + // nothing to do + } + + /** {@inheritDoc} */ + @Override + public double pathDelay(final double elevation, final GeodeticPoint point, + final PressureTemperatureHumidity weather, + final double[] parameters, final AbsoluteDate date) { + + // zenith angle + final double zenithAngle = MathUtils.SEMI_PI - elevation; + + // dry component + final double hd = HD0 + HD1 * (weather.getTemperature() - T0); + final double nd = ND * TroposphericModelUtils.HECTO_PASCAL.fromSI(weather.getPressure()) / + weather.getTemperature(); + final double deltaD = delay(zenithAngle, hd, nd); + + // wet component + final double hw = HW0; + final double nw = (NW1 + NW2 / weather.getTemperature()) / weather.getTemperature(); + final double deltaW = delay(zenithAngle, hw, nw); + + return deltaD + deltaW; + + } + + /** {@inheritDoc} + *

                    + * The Saastamoinen model is not defined for altitudes below 0.0. for continuity + * reasons, we use the value for h = 0 when altitude is negative. + *

                    + *

                    + * There are also numerical issues for elevation angles close to zero. For continuity reasons, + * elevations lower than a threshold will use the value obtained + * for the threshold itself. + *

                    + * @see #getLowElevationThreshold() + * @see #setLowElevationThreshold(double) + */ + @Override + public > T pathDelay(final T elevation, final FieldGeodeticPoint point, + final FieldPressureTemperatureHumidity weather, + final T[] parameters, final FieldAbsoluteDate date) { + + // zenith angle + final T zenithAngle = elevation.negate().add(MathUtils.SEMI_PI); + + // dry component + final T hd = weather.getTemperature().subtract(T0).multiply(HD1).add(HD0); + final T nd = TroposphericModelUtils.HECTO_PASCAL.fromSI(weather.getPressure()). + multiply(ND). + divide(weather.getTemperature()); + final T deltaD = delay(zenithAngle, hd, nd); + + // wet component + final T hw = elevation.getField().getZero().newInstance(HW0); + final T nw = weather.getTemperature().reciprocal().multiply(NW2).add(NW1).divide(weather.getTemperature()); + final T deltaW = delay(zenithAngle, hw, nw); + + return deltaD.add(deltaW); + + } + + /** {@inheritDoc} */ + @Override + public List getParametersDrivers() { + return Collections.emptyList(); + } + + /** Compute the 9 terms sum delay. + * @param zenithAngle zenith angle + * @param hi altitude effect + * @param ni delay factor + * @return 9 terms sum delay + */ + private double delay(final double zenithAngle, final double hi, final double ni) { + + // equation 5.107 + final SinCos scZ = FastMath.sinCos(zenithAngle); + final double rePhi = RE + hi; + final double reS = RE * scZ.sin(); + final double reC = RE * scZ.cos(); + final double ri = FastMath.sqrt(rePhi * rePhi - reS * reS) - reC; + + final double ai = -scZ.cos() / hi; + final double bi = -scZ.sin() * scZ.sin() / (2 * hi * RE); + final double ai2 = ai * ai; + final double bi2 = bi * bi; + + final double f1i = 1; + final double f2i = 4 * ai; + final double f3i = 6 * ai2 + 4 * bi; + final double f4i = 4 * ai * (ai2 + 3 * bi); + final double f5i = ai2 * ai2 + 12 * ai2 * bi + 6 * bi2; + final double f6i = 4 * ai * bi * (ai2 + 3 * bi); + final double f7i = bi2 * (6 * ai2 + 4 * bi); + final double f8i = 4 * ai * bi * bi2; + final double f9i = bi2 * bi2; + + return ni * (ri * (f1i + + ri * (f2i / 2 + + ri * (f3i / 3 + + ri * (f4i / 4 + + ri * (f5i / 5 + + ri * (f6i / 6 + + ri * (f7i / 7 + + ri * (f8i / 8 + + ri * f9i / 9))))))))); + + } + + /** Compute the 9 terms sum delay. + * @param type of the elements + * @param zenithAngle zenith angle + * @param hi altitude effect + * @param ni delay factor + * @return 9 terms sum delay + */ + private > T delay(final T zenithAngle, final T hi, final T ni) { + + // equation 5.107 + final FieldSinCos scZ = FastMath.sinCos(zenithAngle); + final T rePhi = hi.add(RE); + final T reS = scZ.sin().multiply(RE); + final T reC = scZ.cos().multiply(RE); + final T ri = FastMath.sqrt(rePhi.multiply(rePhi).subtract(reS.multiply(reS))).subtract(reC); + + final T ai = scZ.cos().negate().divide(hi); + final T bi = scZ.sin().multiply(scZ.sin()).negate().divide(hi.add(hi).multiply(RE)); + final T ai2 = ai.multiply(ai); + final T bi2 = bi.multiply(bi); + + final T f1i = ai.getField().getOne(); + final T f2i = ai.multiply(4); + final T f3i = ai2.multiply(6).add(bi.multiply(4)); + final T f4i = ai.multiply(4).multiply(ai2.add(bi.multiply(3))); + final T f5i = ai2.multiply(ai2).add(ai2.multiply(12).multiply(bi)).add(bi2.multiply(6)); + final T f6i = ai.multiply(4).multiply(bi).multiply(ai2.add(bi.multiply(3))); + final T f7i = bi2.multiply(ai2.multiply(6).add(bi.multiply(4))); + final T f8i = ai.multiply(4).multiply(bi).multiply(bi2); + final T f9i = bi2.multiply(bi2); + + return ni. + multiply(ri. + multiply(f1i. + add(ri. + multiply(f2i.divide(2). + add(ri. + multiply(f3i.divide(3). + add(ri. + multiply(f4i.divide(4). + add(ri. + multiply(f5i.divide(5). + add(ri. + multiply(f6i.divide(6). + add(ri. + multiply(f7i.divide(7). + add(ri. + multiply(f8i.divide(8). + add(ri.multiply(f9i.divide(9))))))))))))))))))); + + } + +} diff --git a/src/test/java/org/orekit/models/earth/troposphere/ModifiedHopfieldModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/ModifiedHopfieldModelTest.java new file mode 100644 index 0000000000..3b3cc18faf --- /dev/null +++ b/src/test/java/org/orekit/models/earth/troposphere/ModifiedHopfieldModelTest.java @@ -0,0 +1,353 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS Communication & Systèmes (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import org.hipparchus.CalculusFieldElement; +import org.hipparchus.Field; +import org.hipparchus.util.Binary64Field; +import org.hipparchus.util.FastMath; +import org.hipparchus.util.Precision; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.orekit.Utils; +import org.orekit.bodies.FieldGeodeticPoint; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; +import org.orekit.models.earth.weather.HeightDependentPressureTemperatureHumidityConverter; +import org.orekit.models.earth.weather.water.CIPM2007; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; + + +public class ModifiedHopfieldModelTest { + + private static double epsilon = 1e-6; + + private double[][] expectedValues; + + private double[] elevations; + + private double[] heights; + + @Test + public void testFixedElevation() { + Utils.setDataRoot("atmosphere"); + ModifiedHopfieldModel model = new ModifiedHopfieldModel(); + HeightDependentPressureTemperatureHumidityConverter converter = + new HeightDependentPressureTemperatureHumidityConverter(new CIPM2007()); + double lastDelay = Double.MAX_VALUE; + // delay shall decline with increasing height of the station + for (double height = 0; height < 5000; height += 100) { + final double delay = model.pathDelay(FastMath.toRadians(5), new GeodeticPoint(0.0, 0.0, height), + converter.convert(TroposphericModelUtils.STANDARD_ATMOSPHERE, height), + null, AbsoluteDate.J2000_EPOCH); + Assertions.assertTrue(Precision.compareTo(delay, lastDelay, epsilon) < 0); + lastDelay = delay; + } + } + + @Test + public void testFieldFixedElevation() { + doTestFieldFixedElevation(Binary64Field.getInstance()); + } + + private > void doTestFieldFixedElevation(final Field field) { + final T zero = field.getZero(); + Utils.setDataRoot("atmosphere"); + ModifiedHopfieldModel model = new ModifiedHopfieldModel(); + HeightDependentPressureTemperatureHumidityConverter converter = + new HeightDependentPressureTemperatureHumidityConverter(new CIPM2007()); + T lastDelay = zero.newInstance(Double.MAX_VALUE); + // delay shall decline with increasing height of the station + for (double height = 0; height < 5000; height += 100) { + final T delay = model.pathDelay(zero.newInstance(FastMath.toRadians(5)), new FieldGeodeticPoint<>(zero, zero, zero.newInstance(height)), + converter.convert(new FieldPressureTemperatureHumidity<>(field, + TroposphericModelUtils.STANDARD_ATMOSPHERE), + zero.newInstance(height)), + null, FieldAbsoluteDate.getJ2000Epoch(field)); + Assertions.assertTrue(Precision.compareTo(delay.getReal(), lastDelay.getReal(), epsilon) < 0); + lastDelay = delay; + } + } + + @Test + public void testFixedHeight() { + Utils.setDataRoot("atmosphere"); + ModifiedHopfieldModel model = new ModifiedHopfieldModel(); + double lastDelay = Double.MAX_VALUE; + // delay shall decline with increasing elevation angle + for (double elev = 10d; elev < 90d; elev += 8d) { + final double delay = model.pathDelay(FastMath.toRadians(elev), new GeodeticPoint(0.0, 0.0, 350.0), + TroposphericModelUtils.STANDARD_ATMOSPHERE, + null, AbsoluteDate.J2000_EPOCH); + Assertions.assertTrue(Precision.compareTo(delay, lastDelay, epsilon) < 0); + lastDelay = delay; + } + } + + @Test + public void testFieldFixedHeight() { + doTestFieldFixedHeight(Binary64Field.getInstance()); + } + + private > void doTestFieldFixedHeight(final Field field) { + final T zero = field.getZero(); + Utils.setDataRoot("atmosphere"); + ModifiedHopfieldModel model = new ModifiedHopfieldModel(); + T lastDelay = zero.newInstance(Double.MAX_VALUE); + // delay shall decline with increasing elevation angle + for (double elev = 10d; elev < 90d; elev += 8d) { + final T delay = model.pathDelay(zero.newInstance(FastMath.toRadians(elev)), new FieldGeodeticPoint<>(zero, zero, zero.newInstance(350.0)), + new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + null, FieldAbsoluteDate.getJ2000Epoch(field)); + Assertions.assertTrue(Precision.compareTo(delay.getReal(), lastDelay.getReal(), epsilon) < 0); + lastDelay = delay; + } + } + + @Test + public void testFieldVsNative() { + doTestFieldVsNative(Binary64Field.getInstance()); + } + + private > void doTestFieldVsNative(final Field field) { + final T zero = field.getZero(); + Utils.setDataRoot("atmosphere"); + ModifiedHopfieldModel model = new ModifiedHopfieldModel(); + HeightDependentPressureTemperatureHumidityConverter converter = + new HeightDependentPressureTemperatureHumidityConverter(new CIPM2007()); + for (int h = 0; h < 5000.0; h += 100) { + for (int e = 0; e < 90; e += 1.0) { + final double delayN = model.pathDelay(FastMath.toRadians(e), new GeodeticPoint(0, 0, h), + converter.convert(TroposphericModelUtils.STANDARD_ATMOSPHERE, h), + null, AbsoluteDate.J2000_EPOCH); + final T delayT = model.pathDelay(zero.newInstance(FastMath.toRadians(e)), new FieldGeodeticPoint<>(zero, zero, zero.newInstance(h)), + converter.convert(new FieldPressureTemperatureHumidity<>(field, + TroposphericModelUtils.STANDARD_ATMOSPHERE), + zero.newInstance(h)), + null, FieldAbsoluteDate.getJ2000Epoch(field)); + Assertions.assertEquals(delayN, delayT.getReal(), epsilon); + } + } + } + + @Test + public void testNegativeHeight() { + Utils.setDataRoot("atmosphere"); + ModifiedHopfieldModel model = new ModifiedHopfieldModel(); + final double height = -500.0; + for (double elevation = 0; elevation < FastMath.PI; elevation += 0.1) { + Assertions.assertEquals(model.pathDelay(elevation, new GeodeticPoint(0.0, 0.0, 0.0), + TroposphericModelUtils.STANDARD_ATMOSPHERE, + null, AbsoluteDate.J2000_EPOCH), + model.pathDelay(elevation, new GeodeticPoint(0.0, 0.0, height), + TroposphericModelUtils.STANDARD_ATMOSPHERE, + null, AbsoluteDate.J2000_EPOCH), + 1.e-10); + } + } + + @Test + public void testFieldNegativeHeight() { + doTestFieldNegativeHeight(Binary64Field.getInstance()); + } + + private > void doTestFieldNegativeHeight(final Field field) { + final T zero = field.getZero(); + Utils.setDataRoot("atmosphere"); + ModifiedHopfieldModel model = new ModifiedHopfieldModel(); + final T height = zero.subtract(500.0); + for (double elevation = 0; elevation < FastMath.PI; elevation += 0.1) { + Assertions.assertEquals(model.pathDelay(zero.newInstance(elevation), new FieldGeodeticPoint<>(zero, zero, zero), + new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), + model.pathDelay(zero.newInstance(elevation), new FieldGeodeticPoint<>(zero, zero, height), + new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), + 1.e-10); + } + } + + @Test + public void compareExpectedValues() { + Utils.setDataRoot("atmosphere"); + // the reference values have been computed by our own implementation, + // but checked against the plot in Guochang Xu, GPS - Theory, Algorithms and Applications, Springer, 2007 + // by making a screenshot of figure 5.4 and using it as the background of a gnuplot plot, + // twicking the scales and offset to ensure the elevation scales at 0° and 90° line up + // as well as the delay scale at 0m and 40m + ModifiedHopfieldModel model = new ModifiedHopfieldModel(); + HeightDependentPressureTemperatureHumidityConverter converter = + new HeightDependentPressureTemperatureHumidityConverter(new CIPM2007()); + + for (int h = 0; h < heights.length; h++) { + for (int e = 0; e < elevations.length; e++) { + double height = heights[h]; + double elevation = elevations[e]; + double expectedValue = expectedValues[h][e]; + final GeodeticPoint location = new GeodeticPoint(0.0, 0.0, height); + final AbsoluteDate date = AbsoluteDate.J2000_EPOCH; + double actualValue = model.pathDelay(elevation, location, + converter.convert(TroposphericModelUtils.STANDARD_ATMOSPHERE, height), + null, date); + Assertions.assertEquals(expectedValue, actualValue, epsilon, "For height=" + height + " elevation = " + + FastMath.toDegrees(elevation) + " precision not met"); + } + } + } + + @Test + public void compareFieldExpectedValues() { + doCompareFieldExpectedValues(Binary64Field.getInstance()); + } + + private > void doCompareFieldExpectedValues(final Field field) { + final T zero = field.getZero(); + Utils.setDataRoot("atmosphere"); + // the reference values have been computed by our own implementation, + // but checked against the plot in Guochang Xu, GPS - Theory, Algorithms and Applications, Springer, 2007 + // by making a screenshot of figure 5.4 and using it as the background of a gnuplot plot, + // twicking the scales and offset to ensure the elevation scales at 0° and 90° line up + // as well as the delay scale at 0m and 40m + ModifiedHopfieldModel model = new ModifiedHopfieldModel(); + HeightDependentPressureTemperatureHumidityConverter converter = + new HeightDependentPressureTemperatureHumidityConverter(new CIPM2007()); + + for (int h = 0; h < heights.length; h++) { + for (int e = 0; e < elevations.length; e++) { + T height = zero.newInstance(heights[h]); + T elevation = zero.newInstance(elevations[e]); + double expectedValue = expectedValues[h][e]; + FieldGeodeticPoint location = new FieldGeodeticPoint<>(zero, zero, height); + FieldAbsoluteDate date = FieldAbsoluteDate.getJ2000Epoch(field); + T actualValue = model.pathDelay(elevation, location, + converter.convert(new FieldPressureTemperatureHumidity<>(field, + TroposphericModelUtils.STANDARD_ATMOSPHERE), + height), + null, date); + Assertions.assertEquals(expectedValue, actualValue.getReal(), epsilon, "For height=" + height + " elevation = " + + FastMath.toDegrees(elevation.getReal()) + " precision not met"); + } + } + } + + @BeforeEach + public void setUp() throws Exception { + heights = new double[] { + 0.0, 250.0, 500.0, 750.0, 1000.0, 1250.0, 1500.0, 1750.0, 2000.0, 2250.0, 2500.0, 2750.0, 3000.0, 3250.0, + 3500.0, 3750.0, 4000.0, 4250.0, 4500.0, 4750.0, 5000.0 + }; + + elevations = new double[] { + FastMath.toRadians(10.0), FastMath.toRadians(15.0), FastMath.toRadians(20.0), + FastMath.toRadians(25.0), FastMath.toRadians(30.0), FastMath.toRadians(35.0), + FastMath.toRadians(40.0), FastMath.toRadians(45.0), FastMath.toRadians(50.0), + FastMath.toRadians(55.0), FastMath.toRadians(60.0), FastMath.toRadians(65.0), + FastMath.toRadians(70.0), FastMath.toRadians(75.0), FastMath.toRadians(80.0), + FastMath.toRadians(85.0), FastMath.toRadians(90.0) + }; + + expectedValues = new double[][] { + { 12.934879975754736, 8.84084160477251, 6.736022203196621, 5.46898001730666, 4.630745784092203, + 4.041035315294115, 3.608411951861711, 3.2817269682153354, 3.030241489495224, 2.8344622441649374, + 2.6815195803527967, 2.56266799580085, 2.4718587456496492, 2.4048902896027595, 2.358888630010781, + 2.3319868666687267, 2.3231329225099335 }, + { 12.561159287653568, 8.5845772339206, 6.540524901381437, 5.310160285259242, 4.496223800666109, + 3.9236205924564462, 3.503553629933834, 3.1863534038999624, 2.942171043169153, 2.7520781316145233, + 2.6035781540118803, 2.488179277049209, 2.4000082578504416, 2.334985490083572, 2.29032039704188, + 2.2642002736876043, 2.255603586487864 }, + { 12.196271109246876, 8.334396708338184, 6.349676953558442, 5.1551208397950665, 4.364905266082483, + 3.8090027338029726, 3.401193538602676, 3.0932523859733427, 2.8561993139217607, 2.671657358487666, + 2.5274942798666755, 2.415465885996259, 2.3298702638610886, 2.2667468414729446, 2.223386478825016, + 2.1980293767510024, 2.189683818548383 }, + { 11.840056851277243, 8.090190002026562, 6.1633940364070305, 5.003793024325134, 4.236731955221294, + 3.697130880280773, 3.301286235350814, 3.0023825684445966, 2.7722881127132357, 2.593164195299694, + 2.4532341509182074, 2.344495510225485, 2.2614135935595785, 2.2001440162361927, 2.158057126701398, + 2.1334447657599136, 2.1253443200250293 }, + { 11.492359892250795, 7.85184847179859, 5.981592891895236, 4.856109051837414, 4.111646381469352, + 3.5879548184769834, 3.203786854867139, 2.9137031306992824, 2.6903997358985885, 2.516563366789527, + 2.3807643900137903, 2.275236248208002, 2.1946074732175376, 2.135147072538955, 2.09430297036501, + 2.0704174046704082, 2.062556164891846 }, + { 11.153025565763668, 7.619264848064081, 5.804191320080653, 4.7120019989793684, 3.9895917916751586, + 3.4814249761974767, 3.1086511050880046, 2.8271737738921936, 2.6104969618924763, 2.4418200487968793, + 2.310052046890637, 2.2076566064757457, 2.1294215227726028, 2.0717264515927147, 2.0320950152583372, + 2.0089186289188268, 2.0012907971982328 }, + { 10.821901147844857, 7.392333225629629, 5.631108171923848, 4.57140580015122, 3.870512161113126, + 3.377492418053854, 3.0158352632458802, 2.74275471734699, 2.5325430478403774, 2.3688998651454702, + 2.2410645952252195, 2.1417254968001207, 2.0658257531059148, 2.0098529750053538, 1.9714046399731924, + 1.9489201428519454, 1.9415200285087917 }, + { 10.498835844315545, 7.1709490545137635, 5.462263342114509, 4.434255241609992, 3.7543521884571724, + 3.2761088410589285, 2.925296171925621, 2.6604066949628806, 2.456501726296164, 2.2977688845324415, + 2.173769929688361, 2.0774122333761604, 2.0037905633251, 1.9494978421369638, 1.9122035936566382, + 1.8903940171622173, 1.8832160353482224 }, + { 10.183680778166208, 6.955009130777359, 5.297577761910658, 4.30048595558501, 3.641057290764192, + 3.1772265702307525, 2.8369912351285764, 2.5800909516284145, 2.3823372019064784, 2.2283936174238486, + 2.108136363006301, 2.0146865300124164, 1.9432867380526482, 1.8906326274610628, 1.8544639934221097, + 1.8333126863281592, 1.8263513566513527 }, + { 9.8762889769513, 6.744411587369776, 5.136973391991192, 4.17003441440436, 3.5305735984673015, + 3.080798554205539, 2.750878414344576, 2.501769239642544, 2.3100141481017182, 2.1607410129566422, + 2.0441326230277275, 1.9535184973264808, 1.8842854447198623, 1.8332292779310844, 1.798158321765943, + 1.7776489460600666, 1.770898891218422 }, + { 9.576515360202594, 6.539055884991308, 4.980373215321884, 4.042837924633299, 3.42284795037922, + 2.9867783608594287, 2.666916224632045, 2.425403815143106, 2.2394977037939823, 2.0947784558469777, + 1.9817278497969246, 1.89387863994656, 1.8267582308665125, 1.777260110352495, 1.743259423989196, + 1.7233759507509971, 1.7168318951757036 }, + { 9.284216726861493, 6.338842802972065, 4.8277012300356, 3.9188346212243026, 3.317827888706016, + 2.8951201729394875, 2.585063730706338, 2.350957434542875, 2.1707534700819777, 2.0304737633052126, + 1.9208915926332406, 1.835737853718858, 1.7706770214462317, 1.7226978087605191, 1.6897405056251327, + 1.6704672109333, 1.664123979441577 }, + { 8.999251742730987, 6.143674430167964, 4.6788824423264685, 3.797963461679377, 3.2154616540713117, + 2.8057787837040173, 2.505280543036565, 2.278393350973342, 2.103747506963166, 1.9677951819575752, + 1.861593807216871, 1.7790674229211891, 1.7160141161378446, 1.6695154218036077, 1.6375751298722576, + 1.6188965907406763, 1.6127491071981621 }, + { 8.721480927948047, 5.95345415587411, 4.533842859358816, 3.680164220224668, 3.115698180551306, + 2.7187095925724325, 2.4275268139509656, 2.2076753107363376, 2.0384463300531492, 1.9067113847747645, + 1.8038048526812085, 1.723839017482765, 1.6627421866627106, 1.6176863601327756, 1.586737215033144, + 1.568638305375983, 1.5626815913686267 }, + { 8.450766644477026, 5.768086660756171, 4.392509482191019, 3.5653774819978135, 3.0184870907207904, + 2.6338686007848495, 2.3517632337511234, 2.1387675497637897, 1.9748169073126105, 1.8471914680074653, + 1.7474954887117944, 1.6700246902104292, 1.6108342741082338, 1.5671843937969427, 1.5372010319591705, + 1.5196669185848175, 1.513896092100304 }, + { 8.18697308362473, 5.587477907800089, 4.25481029871462, 3.4535446372483163, 2.923778690710489, + 2.5512124070717315, 2.277951026835166, 2.0716347900856587, 1.9128266557818219, 1.789204948129171, + 1.6926368726521528, 1.6175968740213034, 1.5602637862576487, 1.5179836496443941, 1.4889412015012302, + 1.4719573401350756, 1.4663676142537276 }, + { 7.929966253578143, 5.411535133280728, 4.120674276609269, 3.344607875551149, 2.8315239652758417, + 2.470698203333716, 2.206051947830202, 2.006242236306332, 1.8524434383230521, 1.732721758786236, + 1.6392005566165015, 1.5665283791822082, 1.511004494926278, 1.470058608730549, 1.4419326919666187, + 1.4254848233025974, 1.4200715048977355 }, + { 7.6796139669652295, 5.240166837750182, 3.9900313563137013, 3.2385101800340683, 2.7416745728777223, + 2.3922837703318565, 2.136028277734145, 1.94255557208964, 1.7936355603709304, 1.677712247755512, + 1.587158484609674, 1.51679239055582, 1.4630305333043425, 1.4233841037320645, 1.3961508165822356, + 1.3802249623630023, 1.374983450810773 }, + { 7.435785828440213, 5.073282777045855, 3.862812444013299, 3.135195321618908, 2.6541828407752037, + 2.315927473388706, 2.0678428200672396, 1.8805409566527334, 1.7363717666909935, 1.6241471739096365, + 1.536482989654237, 1.4683624648538693, 1.416316393306523, 1.3779353163675905, 1.3515712309641663, + 1.3361536900899693, 1.3310794759885491 }, + { 7.198353222293529, 4.910793953319438, 3.7389494046447243, 3.034607853277241, 2.5690017601307655, + 2.2415882581002715, 2.0014588970334697, 1.820165021268985, 1.6806212381467098, 1.5719977041902182, + 1.4871467909251757, 1.4212125278974417, 1.3708369229284505, 1.3336877748252136, 1.3081699305939638, + 1.2932472752599524, 1.2883359391581959 }, + { 6.967189300087932, 4.75261260608708, 3.618375054918015, 2.936693104300784, 2.486084981128291, + 2.1692256460593353, 1.9368403456921452, 1.7613948657802356, 1.6263535884750422, 1.5212354105891261, + 1.4391229908922085, 1.3753168718846802, 1.3265673236102633, 1.2906173511967862, 1.2659232483016118, + 1.2514823201637046, 1.246729531299119 }, + }; + } + +} From 5d91cfd333119ce98a5ea52575012c866755eae5 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Fri, 15 Dec 2023 15:36:40 +0100 Subject: [PATCH 047/359] Announced many changes in tropospheric models. --- src/changes/changes.xml | 48 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 8b235fec82..92fd9b46ad 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -21,6 +21,54 @@ + + Added ChaoMappingFunction for tropospheric mapping function. + + + Added ModifiedHopfieldModel for tropospheric delay. + + + Added CanonicalSaastamoinenModel for tropospheric delay. + + + Replaced SaastamoinenModel by ModifiedSaastamoinenModel for tropospheric delay. + + + Added NBS/NRC steam table model for water vapor pressure. + + + Added Wang1988 model for water vapor pressure. + + + Added CIPM2007 model for water vapor pressure. + + + Added WaterVaporPressureProvider interface. + + + Added HeightDependentPressureTemperatureHumidityConverter for converting weather parameters. + + + Replaced WeatherModel by {Field}PressureTemperatureHumidityProvider. + + + Added {Field}PressureTemperature and {Field}PressureTemperatureHumidity containers. + + + Replaced GlobalPressureTemperature2Model by GlobalPressureTemperature2. + + + Replaced GlobalPressureTemperatureModel by GlobalPressureTemperature. + + + Replaced MappingFunction by TroposphereMappingFunction. + + + Replaced EstimatedTroposphericModel by EstimatedModel. + + + Replaced DiscreteTroposphericModel by TroposphericModel. + Fixed parsing of SP3 files with partly missing standard deviations. From 1dc102447ea1e24c96fa4a32f191c26c40d54aed Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Tue, 19 Dec 2023 14:51:06 +0100 Subject: [PATCH 048/359] Fixed compilation warnings. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Several warnings appear only when compiling with JDK 8 and don't appear with JDK 17 or later with Java 8 compatibility. In fact, with JDK 17, the @SuppressWarnings required for JDK 8 trigger themselves warnings as they are now unnecessary… --- .../models/earth/atmosphere/AtmosphereTest.java | 2 ++ .../org/orekit/orbits/CircularOrbitTest.java | 1 + .../org/orekit/orbits/EquinoctialOrbitTest.java | 1 + .../java/org/orekit/orbits/FieldOrbitTest.java | 1 - .../propagation/FieldSpacecraftStateTest.java | 17 ++++++++++++++--- .../FieldStepHandlerMultiplexerTest.java | 6 ++++++ 6 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/test/java/org/orekit/models/earth/atmosphere/AtmosphereTest.java b/src/test/java/org/orekit/models/earth/atmosphere/AtmosphereTest.java index c7318dff69..65c228eb39 100644 --- a/src/test/java/org/orekit/models/earth/atmosphere/AtmosphereTest.java +++ b/src/test/java/org/orekit/models/earth/atmosphere/AtmosphereTest.java @@ -78,6 +78,8 @@ void testGetVelocityNonConstantFieldAbsoluteDate() { private static class TestAtmosphere implements Atmosphere { + private static final long serialVersionUID = 1L; + @Override public Frame getFrame() { return FramesFactory.getITRF(IERSConventions.IERS_2003, false); diff --git a/src/test/java/org/orekit/orbits/CircularOrbitTest.java b/src/test/java/org/orekit/orbits/CircularOrbitTest.java index 1e83d286ce..4399101c7e 100644 --- a/src/test/java/org/orekit/orbits/CircularOrbitTest.java +++ b/src/test/java/org/orekit/orbits/CircularOrbitTest.java @@ -1176,6 +1176,7 @@ void testNormalize() { } @Test + @Deprecated void positionAngleNonRegressionOnDeprecated() { // Can be removed when deprecated routines are removed in next major release (13.0) // GIVEN diff --git a/src/test/java/org/orekit/orbits/EquinoctialOrbitTest.java b/src/test/java/org/orekit/orbits/EquinoctialOrbitTest.java index 7683b6dc73..cf6eb35495 100644 --- a/src/test/java/org/orekit/orbits/EquinoctialOrbitTest.java +++ b/src/test/java/org/orekit/orbits/EquinoctialOrbitTest.java @@ -1103,6 +1103,7 @@ void testNormalize() { } @Test + @Deprecated void positionAngleNonRegressionOnDeprecated() { // Can be removed when deprecated routines are removed in next major release (13.0) // GIVEN diff --git a/src/test/java/org/orekit/orbits/FieldOrbitTest.java b/src/test/java/org/orekit/orbits/FieldOrbitTest.java index 6829513622..743dd6a34a 100644 --- a/src/test/java/org/orekit/orbits/FieldOrbitTest.java +++ b/src/test/java/org/orekit/orbits/FieldOrbitTest.java @@ -24,7 +24,6 @@ import org.mockito.Mockito; import org.orekit.frames.Frame; import org.orekit.time.FieldAbsoluteDate; -import org.orekit.time.FieldTimeStamped; import org.orekit.utils.TimeStampedFieldPVCoordinates; diff --git a/src/test/java/org/orekit/propagation/FieldSpacecraftStateTest.java b/src/test/java/org/orekit/propagation/FieldSpacecraftStateTest.java index 9fa0664b39..940b68b373 100644 --- a/src/test/java/org/orekit/propagation/FieldSpacecraftStateTest.java +++ b/src/test/java/org/orekit/propagation/FieldSpacecraftStateTest.java @@ -46,9 +46,13 @@ import org.orekit.errors.OrekitMessages; import org.orekit.frames.FieldStaticTransform; import org.orekit.frames.FramesFactory; -import org.orekit.frames.StaticTransform; import org.orekit.frames.Transform; -import org.orekit.orbits.*; +import org.orekit.orbits.FieldCartesianOrbit; +import org.orekit.orbits.FieldKeplerianOrbit; +import org.orekit.orbits.FieldOrbit; +import org.orekit.orbits.KeplerianOrbit; +import org.orekit.orbits.Orbit; +import org.orekit.orbits.PositionAngleType; import org.orekit.propagation.analytical.FieldEcksteinHechlerPropagator; import org.orekit.propagation.analytical.FieldKeplerianPropagator; import org.orekit.propagation.events.FieldDateDetector; @@ -60,7 +64,14 @@ import org.orekit.time.FieldAbsoluteDate; import org.orekit.time.TimeComponents; import org.orekit.time.TimeScalesFactory; -import org.orekit.utils.*; +import org.orekit.utils.Constants; +import org.orekit.utils.FieldAbsolutePVCoordinates; +import org.orekit.utils.FieldArrayDictionary; +import org.orekit.utils.FieldPVCoordinates; +import org.orekit.utils.IERSConventions; +import org.orekit.utils.PVCoordinates; +import org.orekit.utils.TimeStampedAngularCoordinates; +import org.orekit.utils.TimeStampedFieldAngularCoordinates; public class FieldSpacecraftStateTest { diff --git a/src/test/java/org/orekit/propagation/sampling/FieldStepHandlerMultiplexerTest.java b/src/test/java/org/orekit/propagation/sampling/FieldStepHandlerMultiplexerTest.java index 9d67bf8c74..41cd0de8b3 100644 --- a/src/test/java/org/orekit/propagation/sampling/FieldStepHandlerMultiplexerTest.java +++ b/src/test/java/org/orekit/propagation/sampling/FieldStepHandlerMultiplexerTest.java @@ -238,12 +238,14 @@ public void testOnTheFlyChanges() { double add60 = 3.0; double rem60 = 78.0; FieldFixedCounter counter60 = new FieldFixedCounter(); + @SuppressWarnings("unchecked") FieldDateDetector d1 = new FieldDateDetector<>(field, initDate.shiftedBy(add60)). withHandler((s, d, i) -> { multiplexer.add(zero.newInstance(60.0), counter60); return Action.CONTINUE; }); propagator.addEventDetector(d1); + @SuppressWarnings("unchecked") FieldDateDetector d2 = new FieldDateDetector<>(field, initDate.shiftedBy(rem60)). withHandler((s, d, i) -> { multiplexer.remove(counter60); @@ -254,12 +256,14 @@ public void testOnTheFlyChanges() { double addVar = 5.0; double remVar = 7.0; FieldVariableCounter counterVar = new FieldVariableCounter(); + @SuppressWarnings("unchecked") FieldDateDetector d3 = new FieldDateDetector<>(field, initDate.shiftedBy(addVar)). withHandler((s, d, i) -> { multiplexer.add(counterVar); return Action.CONTINUE; }); propagator.addEventDetector(d3); + @SuppressWarnings("unchecked") FieldDateDetector d4 = new FieldDateDetector<>(field, initDate.shiftedBy(remVar)). withHandler((s, d, i) -> { multiplexer.remove(counterVar); @@ -270,12 +274,14 @@ public void testOnTheFlyChanges() { double add10 = 6.0; double rem10 = 82.0; FieldFixedCounter counter10 = new FieldFixedCounter(); + @SuppressWarnings("unchecked") FieldDateDetector d5 = new FieldDateDetector<>(field, initDate.shiftedBy(add10)). withHandler((s, d, i) -> { multiplexer.add(zero.newInstance(10.0), counter10); return Action.CONTINUE; }); propagator.addEventDetector(d5); + @SuppressWarnings("unchecked") FieldDateDetector d6 = new FieldDateDetector<>(field, initDate.shiftedBy(rem10)). withHandler((s, d, i) -> { multiplexer.clear(); From cb40bc8071dae3b52de3186113d7f4124ca91fcd Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Tue, 19 Dec 2023 16:25:29 +0100 Subject: [PATCH 049/359] Notify use of default context. --- .../org/orekit/models/earth/troposphere/EstimatedModel.java | 2 ++ .../org/orekit/models/earth/troposphere/SaastamoinenModel.java | 1 + 2 files changed, 3 insertions(+) diff --git a/src/main/java/org/orekit/models/earth/troposphere/EstimatedModel.java b/src/main/java/org/orekit/models/earth/troposphere/EstimatedModel.java index b160ccdb72..2a223bcb28 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/EstimatedModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/EstimatedModel.java @@ -21,6 +21,7 @@ import org.hipparchus.CalculusFieldElement; import org.hipparchus.util.FastMath; +import org.orekit.annotation.DefaultDataContext; import org.orekit.bodies.FieldGeodeticPoint; import org.orekit.bodies.GeodeticPoint; import org.orekit.models.earth.weather.ConstantPressureTemperatureHumidityProvider; @@ -78,6 +79,7 @@ public class EstimatedModel implements TroposphericModel { * @param model mapping function model. * @param totalDelay initial value for the tropospheric zenith total delay [m] */ + @DefaultDataContext public EstimatedModel(final double h0, final double t0, final double p0, final TroposphereMappingFunction model, final double totalDelay) { this(new ModifiedSaastamoinenModel(new ConstantPressureTemperatureHumidityProvider(new PressureTemperatureHumidity(h0, diff --git a/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java b/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java index dad6181044..fb5d85c860 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java @@ -51,6 +51,7 @@ public class SaastamoinenModel extends ModifiedSaastamoinenModel implements Disc * @see #SaastamoinenModel(double, double, double, String, DataProvidersManager) * @since 10.1 */ + @DefaultDataContext public SaastamoinenModel(final double t0, final double p0, final double r0) { this(t0, p0, r0, DELTA_R_FILE_NAME); } From a4f911a3349ce4cf740f29e31bfb4f6862517f44 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Tue, 19 Dec 2023 16:29:16 +0100 Subject: [PATCH 050/359] Notify use of default context. --- .../org/orekit/models/earth/troposphere/EstimatedModel.java | 1 + .../models/earth/troposphere/EstimatedTroposphericModel.java | 3 +++ .../org/orekit/models/earth/troposphere/SaastamoinenModel.java | 1 + 3 files changed, 5 insertions(+) diff --git a/src/main/java/org/orekit/models/earth/troposphere/EstimatedModel.java b/src/main/java/org/orekit/models/earth/troposphere/EstimatedModel.java index 2a223bcb28..f8d29db8c6 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/EstimatedModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/EstimatedModel.java @@ -115,6 +115,7 @@ public EstimatedModel(final TroposphericModel hydrostatic, * @param model mapping function model. * @param totalDelay initial value for the tropospheric zenith total delay [m] */ + @DefaultDataContext public EstimatedModel(final TroposphereMappingFunction model, final double totalDelay) { this(0.0, 273.15 + 18.0, 1013.25, model, totalDelay); } diff --git a/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java b/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java index d3e1667765..f292851e87 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java @@ -17,6 +17,7 @@ package org.orekit.models.earth.troposphere; import org.hipparchus.CalculusFieldElement; +import org.orekit.annotation.DefaultDataContext; import org.orekit.bodies.FieldGeodeticPoint; import org.orekit.bodies.GeodeticPoint; import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; @@ -63,6 +64,7 @@ public class EstimatedTroposphericModel extends EstimatedModel implements Discre * @param model mapping function model (NMF or GMF). * @param totalDelay initial value for the tropospheric zenith total delay [m] */ + @DefaultDataContext public EstimatedTroposphericModel(final double t0, final double p0, final MappingFunction model, final double totalDelay) { super(0.0, t0, p0, new TroposphereMappingFunctionAdapter(model), totalDelay); @@ -90,6 +92,7 @@ public EstimatedTroposphericModel(final DiscreteTroposphericModel hydrostatic, * @param model mapping function model (NMF or GMF). * @param totalDelay initial value for the tropospheric zenith total delay [m] */ + @DefaultDataContext public EstimatedTroposphericModel(final MappingFunction model, final double totalDelay) { this(273.15 + 18.0, 1013.25, model, totalDelay); } diff --git a/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java b/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java index fb5d85c860..de63ae98ba 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java @@ -114,6 +114,7 @@ public SaastamoinenModel(final double t0, * * @return a Saastamoinen model with standard environmental values */ + @DefaultDataContext public static SaastamoinenModel getStandardModel() { return new SaastamoinenModel(273.16 + 18, 1013.25, 0.5); } From c5dcb585e71108d40445e87869e04c02005e283a Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Tue, 19 Dec 2023 20:47:55 +0100 Subject: [PATCH 051/359] Consider azimuth in tropospheric effects. This will be needed when GPT3 is implemented. --- .../AngularTroposphericDelayModifier.java | 11 +- ...aseRangeRateTroposphericDelayModifier.java | 38 +++--- .../BaseRangeTroposphericDelayModifier.java | 20 ++-- .../PhaseTroposphericDelayModifier.java | 24 ++-- .../TDOATroposphericDelayModifier.java | 24 ++-- ...nAroundRangeTroposphericDelayModifier.java | 22 ++-- .../AbstractChaoMappingFunction.java | 14 ++- .../CanonicalSaastamoinenModel.java | 12 +- .../earth/troposphere/EstimatedModel.java | 22 +++- .../EstimatedTroposphericModel.java | 8 +- .../troposphere/FixedTroposphericDelay.java | 17 ++- .../GlobalMappingFunctionModel.java | 31 +++-- .../earth/troposphere/MariniMurrayModel.java | 16 ++- .../earth/troposphere/MendesPavlisModel.java | 34 +++--- .../troposphere/ModifiedHopfieldModel.java | 14 ++- .../ModifiedSaastamoinenModel.java | 14 ++- .../NiellMappingFunctionModel.java | 33 ++++-- .../earth/troposphere/SaastamoinenModel.java | 8 +- .../troposphere/TimeSpanEstimatedModel.java | 11 +- .../TroposphereMappingFunction.java | 11 +- .../TroposphereMappingFunctionAdapter.java | 14 ++- .../earth/troposphere/TroposphericModel.java | 11 +- .../troposphere/TroposphericModelAdapter.java | 10 +- .../earth/troposphere/ViennaOneModel.java | 47 +++++--- .../earth/troposphere/ViennaThreeModel.java | 41 ++++--- .../AbstractFieldMappingFunctionTest.java | 73 ++++++------ .../AbstractMappingFunctionTest.java | 8 +- .../CanonicalSaastamoinenModelTest.java | 8 +- .../earth/troposphere/EstimatedModelTest.java | 94 +++++++-------- .../FieldGlobalMappingFunctionModelTest.java | 75 ++++++------ .../FieldMendesPavlisModelTest.java | 79 +++++++------ .../troposphere/FieldViennaOneModelTest.java | 80 +++++++------ .../FieldViennaThreeModelTest.java | 80 ++++++------- .../FixedTroposphericModelTest.java | 54 ++++++--- .../GlobalMappingFunctionModelTest.java | 8 +- .../troposphere/MariniMurrayModelTest.java | 32 ++++-- .../troposphere/MendesPavlisModelTest.java | 11 +- .../ModifiedHopfieldModelTest.java | 48 ++++++-- .../ModifiedSaastamoinenModelTest.java | 76 ++++++++---- .../TimeSpanEstimatedModelTest.java | 108 +++++++++--------- .../earth/troposphere/ViennaOneModelTest.java | 11 +- .../troposphere/ViennaThreeModelTest.java | 19 +-- 42 files changed, 799 insertions(+), 572 deletions(-) diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/AngularTroposphericDelayModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/AngularTroposphericDelayModifier.java index 30294c291b..86e8669fd9 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/AngularTroposphericDelayModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/AngularTroposphericDelayModifier.java @@ -78,15 +78,14 @@ private double angularErrorTroposphericModel(final GroundStation station, // final Vector3D position = state.getPosition(); - // elevation - final double elevation = - station.getBaseFrame().getTrackingCoordinates(position, state.getFrame(), state.getDate()). - getElevation(); + // tracking + final TrackingCoordinates trackingCoordinates = + station.getBaseFrame().getTrackingCoordinates(position, state.getFrame(), state.getDate()); // only consider measures above the horizon - if (elevation > 0.0) { + if (trackingCoordinates.getElevation() > 0.0) { // delay in meters - final double delay = tropoModel.pathDelay(elevation, + final double delay = tropoModel.pathDelay(trackingCoordinates, station.getOffsetGeodeticPoint(state.getDate()), station.getPressureTemperatureHumidity(state.getDate()), tropoModel.getParameters(state.getDate()), state.getDate()); diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/BaseRangeRateTroposphericDelayModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/BaseRangeRateTroposphericDelayModifier.java index 14c0355f59..8ad52494c8 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/BaseRangeRateTroposphericDelayModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/BaseRangeRateTroposphericDelayModifier.java @@ -26,7 +26,9 @@ import org.orekit.models.earth.troposphere.TroposphericModel; import org.orekit.propagation.FieldSpacecraftState; import org.orekit.propagation.SpacecraftState; +import org.orekit.utils.FieldTrackingCoordinates; import org.orekit.utils.ParameterDriver; +import org.orekit.utils.TrackingCoordinates; /** Baselass modifying theoretical range-rate measurements with tropospheric delay. * The effect of tropospheric correction on the range-rate is directly computed @@ -85,15 +87,14 @@ public double rangeRateErrorTroposphericModel(final GroundStation station, // spacecraft position and elevation as seen from the ground station final Vector3D position = state.getPosition(); - // elevation - final double elevation1 = - station.getBaseFrame().getTrackingCoordinates(position, state.getFrame(), state.getDate()). - getElevation(); + // tracking + final TrackingCoordinates trackingCoordinates1 = + station.getBaseFrame().getTrackingCoordinates(position, state.getFrame(), state.getDate()); // only consider measures above the horizon - if (elevation1 > 0) { + if (trackingCoordinates1.getElevation() > 0) { // tropospheric delay in meters - final double d1 = tropoModel.pathDelay(elevation1, + final double d1 = tropoModel.pathDelay(trackingCoordinates1, station.getOffsetGeodeticPoint(state.getDate()), station.getPressureTemperatureHumidity(state.getDate()), tropoModel.getParameters(state.getDate()), state.getDate()); @@ -104,13 +105,12 @@ public double rangeRateErrorTroposphericModel(final GroundStation station, // spacecraft position and elevation as seen from the ground station final Vector3D position2 = state2.getPosition(); - // elevation - final double elevation2 = - station.getBaseFrame().getTrackingCoordinates(position2, state2.getFrame(), state2.getDate()). - getElevation(); + // tracking + final TrackingCoordinates trackingCoordinates2 = + station.getBaseFrame().getTrackingCoordinates(position2, state2.getFrame(), state2.getDate()); // tropospheric delay dt after - final double d2 = tropoModel.pathDelay(elevation2, + final double d2 = tropoModel.pathDelay(trackingCoordinates2, station.getOffsetGeodeticPoint(state.getDate()), station.getPressureTemperatureHumidity(state.getDate()), tropoModel.getParameters(state2.getDate()), state2.getDate()); @@ -143,14 +143,13 @@ public > T rangeRateErrorTroposphericModel(fin // spacecraft position and elevation as seen from the ground station final FieldVector3D position = state.getPosition(); - final T elevation1 = - station.getBaseFrame().getTrackingCoordinates(position, state.getFrame(), state.getDate()). - getElevation(); + final FieldTrackingCoordinates trackingCoordinates1 = + station.getBaseFrame().getTrackingCoordinates(position, state.getFrame(), state.getDate()); // only consider measures above the horizon - if (elevation1.getReal() > 0) { + if (trackingCoordinates1.getElevation().getReal() > 0) { // tropospheric delay in meters - final T d1 = tropoModel.pathDelay(elevation1, + final T d1 = tropoModel.pathDelay(trackingCoordinates1, station.getOffsetGeodeticPoint(state.getDate()), station.getPressureTemperatureHumidity(state.getDate()), parameters, state.getDate()); @@ -162,13 +161,12 @@ public > T rangeRateErrorTroposphericModel(fin final FieldVector3D position2 = state2.getPosition(); // elevation - final T elevation2 = - station.getBaseFrame().getTrackingCoordinates(position2, state2.getFrame(), state2.getDate()). - getElevation(); + final FieldTrackingCoordinates trackingCoordinates2 = + station.getBaseFrame().getTrackingCoordinates(position2, state2.getFrame(), state2.getDate()); // tropospheric delay dt after - final T d2 = tropoModel.pathDelay(elevation2, + final T d2 = tropoModel.pathDelay(trackingCoordinates2, station.getOffsetGeodeticPoint(state.getDate()), station.getPressureTemperatureHumidity(state.getDate()), parameters, state2.getDate()); diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/BaseRangeTroposphericDelayModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/BaseRangeTroposphericDelayModifier.java index 2fbc62e614..085cbced4f 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/BaseRangeTroposphericDelayModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/BaseRangeTroposphericDelayModifier.java @@ -26,7 +26,9 @@ import org.orekit.models.earth.troposphere.TroposphericModel; import org.orekit.propagation.FieldSpacecraftState; import org.orekit.propagation.SpacecraftState; +import org.orekit.utils.FieldTrackingCoordinates; import org.orekit.utils.ParameterDriver; +import org.orekit.utils.TrackingCoordinates; /** Base class modifying theoretical range measurements with tropospheric delay. * The effect of tropospheric correction on the range is directly computed @@ -79,14 +81,13 @@ public double rangeErrorTroposphericModel(final GroundStation station, // spacecraft position and elevation as seen from the ground station final Vector3D position = state.getPosition(); - final double elevation = - station.getBaseFrame().getTrackingCoordinates(position, state.getFrame(), state.getDate()). - getElevation(); + final TrackingCoordinates trackingCoordinates = + station.getBaseFrame().getTrackingCoordinates(position, state.getFrame(), state.getDate()); // only consider measures above the horizon - if (elevation > 0) { + if (trackingCoordinates.getElevation() > 0) { // tropospheric delay in meters - final double delay = tropoModel.pathDelay(elevation, + final double delay = tropoModel.pathDelay(trackingCoordinates, station.getOffsetGeodeticPoint(state.getDate()), station.getPressureTemperatureHumidity(state.getDate()), tropoModel.getParameters(), state.getDate()); @@ -114,14 +115,13 @@ public > T rangeErrorTroposphericModel(final G // spacecraft position and elevation as seen from the ground station final FieldVector3D position = state.getPosition(); - final T elevation = - station.getBaseFrame().getTrackingCoordinates(position, state.getFrame(), state.getDate()). - getElevation(); + final FieldTrackingCoordinates trackingCoordinates = + station.getBaseFrame().getTrackingCoordinates(position, state.getFrame(), state.getDate()); // only consider measures above the horizon - if (elevation .getReal() > 0) { + if (trackingCoordinates.getElevation() .getReal() > 0) { // tropospheric delay in meters - final T delay = tropoModel.pathDelay(elevation, + final T delay = tropoModel.pathDelay(trackingCoordinates, station.getOffsetGeodeticPoint(state.getDate()), station.getPressureTemperatureHumidity(state.getDate()), parameters, state.getDate()); diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseTroposphericDelayModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseTroposphericDelayModifier.java index b4111d9de6..df264a8dc1 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseTroposphericDelayModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseTroposphericDelayModifier.java @@ -32,9 +32,11 @@ import org.orekit.propagation.FieldSpacecraftState; import org.orekit.propagation.SpacecraftState; import org.orekit.utils.Differentiation; +import org.orekit.utils.FieldTrackingCoordinates; import org.orekit.utils.ParameterDriver; import org.orekit.utils.ParameterFunction; import org.orekit.utils.TimeSpanMap.Span; +import org.orekit.utils.TrackingCoordinates; /** * Class modifying theoretical phase measurement with tropospheric delay. @@ -76,15 +78,14 @@ public PhaseTroposphericDelayModifier(final TroposphericModel model) { */ private double phaseErrorTroposphericModel(final GroundStation station, final SpacecraftState state, final double wavelength) { - // elevation - final double elevation = - station.getBaseFrame().getTrackingCoordinates(state.getPosition(), state.getFrame(), state.getDate()). - getElevation(); + // tracking + final TrackingCoordinates trackingCoordinates = + station.getBaseFrame().getTrackingCoordinates(state.getPosition(), state.getFrame(), state.getDate()); // only consider measures above the horizon - if (elevation > 0) { + if (trackingCoordinates.getElevation() > 0) { // delay in meters - final double delay = tropoModel.pathDelay(elevation, + final double delay = tropoModel.pathDelay(trackingCoordinates, station.getOffsetGeodeticPoint(state.getDate()), station.getPressureTemperatureHumidity(state.getDate()), tropoModel.getParameters(state.getDate()), state.getDate()); @@ -111,16 +112,15 @@ private > T phaseErrorTroposphericModel(final final Field field = state.getDate().getField(); final T zero = field.getZero(); - // satellite elevation - final T elevation = - station.getBaseFrame().getTrackingCoordinates(state.getPosition(), state.getFrame(), state.getDate()). - getElevation(); + // tracking + final FieldTrackingCoordinates trackingCoordinates = + station.getBaseFrame().getTrackingCoordinates(state.getPosition(), state.getFrame(), state.getDate()); // only consider measures above the horizon - if (elevation.getReal() > 0) { + if (trackingCoordinates.getElevation().getReal() > 0) { // delay in meters - final T delay = tropoModel.pathDelay(elevation, + final T delay = tropoModel.pathDelay(trackingCoordinates, station.getOffsetGeodeticPoint(state.getDate()), station.getPressureTemperatureHumidity(state.getDate()), parameters, state.getDate()); diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/TDOATroposphericDelayModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/TDOATroposphericDelayModifier.java index f2a231200e..ee3d770a9d 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/TDOATroposphericDelayModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/TDOATroposphericDelayModifier.java @@ -32,7 +32,9 @@ import org.orekit.propagation.FieldSpacecraftState; import org.orekit.propagation.SpacecraftState; import org.orekit.utils.Constants; +import org.orekit.utils.FieldTrackingCoordinates; import org.orekit.utils.ParameterDriver; +import org.orekit.utils.TrackingCoordinates; /** Class modifying theoretical TDOA measurements with tropospheric delay. *

                    @@ -76,15 +78,14 @@ public TDOATroposphericDelayModifier(final TroposphericModel model) { private double timeErrorTroposphericModel(final GroundStation station, final SpacecraftState state) { final Vector3D position = state.getPosition(); - // elevation - final double elevation = - station.getBaseFrame().getTrackingCoordinates(position, state.getFrame(), state.getDate()). - getElevation(); + // tracking + final TrackingCoordinates trackingCoordinates = + station.getBaseFrame().getTrackingCoordinates(position, state.getFrame(), state.getDate()); // only consider measurements above the horizon - if (elevation > 0) { + if (trackingCoordinates.getElevation() > 0) { // Delay in meters - final double delay = tropoModel.pathDelay(elevation, + final double delay = tropoModel.pathDelay(trackingCoordinates, station.getOffsetGeodeticPoint(state.getDate()), station.getPressureTemperatureHumidity(state.getDate()), tropoModel.getParameters(state.getDate()), state.getDate()); @@ -109,16 +110,15 @@ private > T timeErrorTroposphericModel(final G final Field field = state.getDate().getField(); final T zero = field.getZero(); - // elevation + // tracking final FieldVector3D pos = state.getPosition(); - final T elevation = - station.getBaseFrame().getTrackingCoordinates(pos, state.getFrame(), state.getDate()). - getElevation(); + final FieldTrackingCoordinates trackingCoordinates = + station.getBaseFrame().getTrackingCoordinates(pos, state.getFrame(), state.getDate()); // only consider measurements above the horizon - if (elevation.getReal() > 0) { + if (trackingCoordinates.getElevation().getReal() > 0) { // delay in meters - final T delay = tropoModel.pathDelay(elevation, + final T delay = tropoModel.pathDelay(trackingCoordinates, station.getOffsetGeodeticPoint(state.getDate()), station.getPressureTemperatureHumidity(state.getDate()), parameters, state.getDate()); diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/TurnAroundRangeTroposphericDelayModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/TurnAroundRangeTroposphericDelayModifier.java index a71db8851f..0f185f8e72 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/TurnAroundRangeTroposphericDelayModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/TurnAroundRangeTroposphericDelayModifier.java @@ -35,9 +35,11 @@ import org.orekit.propagation.SpacecraftState; import org.orekit.time.AbsoluteDate; import org.orekit.utils.Differentiation; +import org.orekit.utils.FieldTrackingCoordinates; import org.orekit.utils.ParameterDriver; import org.orekit.utils.ParameterFunction; import org.orekit.utils.TimeSpanMap.Span; +import org.orekit.utils.TrackingCoordinates; /** Class modifying theoretical turn-around TurnAroundRange measurement with tropospheric delay. * The effect of tropospheric correction on the TurnAroundRange is directly computed @@ -82,15 +84,14 @@ private double rangeErrorTroposphericModel(final GroundStation station, final Sp // final Vector3D position = state.getPosition(); - // elevation - final double elevation = - station.getBaseFrame().getTrackingCoordinates(position, state.getFrame(), state.getDate()). - getElevation(); + // tracking + final TrackingCoordinates trackingCoordinates = + station.getBaseFrame().getTrackingCoordinates(position, state.getFrame(), state.getDate()); // only consider measures above the horizon - if (elevation > 0) { + if (trackingCoordinates.getElevation() > 0) { // Delay in meters - final double delay = tropoModel.pathDelay(elevation, + final double delay = tropoModel.pathDelay(trackingCoordinates, station.getOffsetGeodeticPoint(state.getDate()), station.getPressureTemperatureHumidity(state.getDate()), tropoModel.getParameters(state.getDate()), state.getDate()); @@ -117,14 +118,13 @@ private > T rangeErrorTroposphericModel(final // final FieldVector3D position = state.getPosition(); - final T dsElevation = - station.getBaseFrame().getTrackingCoordinates(position, state.getFrame(), state.getDate()). - getElevation(); + final FieldTrackingCoordinates trackingCoordinates = + station.getBaseFrame().getTrackingCoordinates(position, state.getFrame(), state.getDate()); // only consider measures above the horizon - if (dsElevation.getReal() > 0) { + if (trackingCoordinates.getElevation().getReal() > 0) { // Delay in meters - final T delay = tropoModel.pathDelay(dsElevation, + final T delay = tropoModel.pathDelay(trackingCoordinates, station.getOffsetGeodeticPoint(state.getDate()), station.getPressureTemperatureHumidity(state.getDate()), parameters, state.getDate()); diff --git a/src/main/java/org/orekit/models/earth/troposphere/AbstractChaoMappingFunction.java b/src/main/java/org/orekit/models/earth/troposphere/AbstractChaoMappingFunction.java index 40cfcb4376..a7eb0f7140 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/AbstractChaoMappingFunction.java +++ b/src/main/java/org/orekit/models/earth/troposphere/AbstractChaoMappingFunction.java @@ -25,6 +25,8 @@ import org.orekit.models.earth.weather.PressureTemperatureHumidity; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; +import org.orekit.utils.FieldTrackingCoordinates; +import org.orekit.utils.TrackingCoordinates; /** Chao mapping function for radio wavelengths. * @@ -62,11 +64,11 @@ protected AbstractChaoMappingFunction(final double ad, final double bd, final do /** {@inheritDoc} */ @Override - public double[] mappingFactors(final double elevation, final GeodeticPoint point, + public double[] mappingFactors(final TrackingCoordinates trackingCoordinates, final GeodeticPoint point, final PressureTemperatureHumidity weather, final AbsoluteDate date) { - final double sinE = FastMath.sin(elevation); - final double tanE = FastMath.tan(elevation); + final double sinE = FastMath.sin(trackingCoordinates.getElevation()); + final double tanE = FastMath.tan(trackingCoordinates.getElevation()); return new double[] { 1 / (sinE + ad / (tanE + bd)), 1 / (sinE + aw / (tanE + bw)) @@ -75,12 +77,12 @@ public double[] mappingFactors(final double elevation, final GeodeticPoint point /** {@inheritDoc} */ @Override - public > T[] mappingFactors(final T elevation, + public > T[] mappingFactors(final FieldTrackingCoordinates trackingCoordinates, final FieldGeodeticPoint point, final FieldPressureTemperatureHumidity weather, final FieldAbsoluteDate date) { - final T sinE = FastMath.sin(elevation); - final T tanE = FastMath.tan(elevation); + final T sinE = FastMath.sin(trackingCoordinates.getElevation()); + final T tanE = FastMath.tan(trackingCoordinates.getElevation()); final T[] mapping = MathArrays.buildArray(date.getField(), 2); mapping[0] = sinE.add(tanE.add(bd).reciprocal().multiply(ad)).reciprocal(); mapping[1] = sinE.add(tanE.add(bw).reciprocal().multiply(aw)).reciprocal(); diff --git a/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java b/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java index eb94a6f40b..ebb63353db 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java @@ -35,7 +35,9 @@ import org.orekit.models.earth.weather.water.WaterVaporPressureProvider; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; +import org.orekit.utils.FieldTrackingCoordinates; import org.orekit.utils.ParameterDriver; +import org.orekit.utils.TrackingCoordinates; /** The canonical Saastamoinen model. *

                    @@ -144,7 +146,7 @@ public static CanonicalSaastamoinenModel getStandardModel() { * @see #setLowElevationThreshold(double) */ @Override - public double pathDelay(final double elevation, final GeodeticPoint point, + public double pathDelay(final TrackingCoordinates trackingCoordinates, final GeodeticPoint point, final PressureTemperatureHumidity weather, final double[] parameters, final AbsoluteDate date) { @@ -159,7 +161,8 @@ public double pathDelay(final double elevation, final GeodeticPoint point, final double B = B_FUNCTION.value(fixedHeight); // calculate the zenith angle from the elevation - final double z = FastMath.abs(0.5 * FastMath.PI - FastMath.max(elevation, lowElevationThreshold)); + final double z = FastMath.abs(0.5 * FastMath.PI - FastMath.max(trackingCoordinates.getElevation(), + lowElevationThreshold)); // calculate the path delay in m final double tan = FastMath.tan(z); @@ -184,7 +187,8 @@ public double pathDelay(final double elevation, final GeodeticPoint point, * @see #setLowElevationThreshold(double) */ @Override - public > T pathDelay(final T elevation, final FieldGeodeticPoint point, + public > T pathDelay(final FieldTrackingCoordinates trackingCoordinates, + final FieldGeodeticPoint point, final FieldPressureTemperatureHumidity weather, final T[] parameters, final FieldAbsoluteDate date) { @@ -203,7 +207,7 @@ public > T pathDelay(final T elevation, final // calculate the zenith angle from the elevation final T z = FastMath.abs(zero.getPi().multiply(0.5). - subtract(FastMath.max(elevation, lowElevationThreshold))); + subtract(FastMath.max(trackingCoordinates.getElevation(), lowElevationThreshold))); // calculate the path delay in m final T tan = FastMath.tan(z); diff --git a/src/main/java/org/orekit/models/earth/troposphere/EstimatedModel.java b/src/main/java/org/orekit/models/earth/troposphere/EstimatedModel.java index f8d29db8c6..78507c33b6 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/EstimatedModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/EstimatedModel.java @@ -29,7 +29,9 @@ import org.orekit.models.earth.weather.PressureTemperatureHumidity; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; +import org.orekit.utils.FieldTrackingCoordinates; import org.orekit.utils.ParameterDriver; +import org.orekit.utils.TrackingCoordinates; /** An estimated tropospheric model. The tropospheric delay is computed according to the formula: *

                    @@ -128,28 +130,36 @@ public List getParametersDrivers() { /** {@inheritDoc} */ @Override - public double pathDelay(final double elevation, final GeodeticPoint point, + public double pathDelay(final TrackingCoordinates trackingCoordinates, + final GeodeticPoint point, final PressureTemperatureHumidity weather, final double[] parameters, final AbsoluteDate date) { // Zenith delays. elevation = pi/2 because we compute the delay in the zenith direction - final double zhd = hydrostatic.pathDelay(0.5 * FastMath.PI, point, weather, parameters, date); + final double zhd = hydrostatic.pathDelay(new TrackingCoordinates(trackingCoordinates.getAzimuth(), + 0.5 * FastMath.PI, + trackingCoordinates.getRange()), + point, weather, parameters, date); final double ztd = parameters[0]; // Mapping functions - final double[] mf = model.mappingFactors(elevation, point, weather, date); + final double[] mf = model.mappingFactors(trackingCoordinates, point, weather, date); // Total delay return mf[0] * zhd + mf[1] * (ztd - zhd); } /** {@inheritDoc} */ @Override - public > T pathDelay(final T elevation, final FieldGeodeticPoint point, + public > T pathDelay(final FieldTrackingCoordinates trackingCoordinates, + final FieldGeodeticPoint point, final FieldPressureTemperatureHumidity weather, final T[] parameters, final FieldAbsoluteDate date) { // Zenith delays. elevation = pi/2 because we compute the delay in the zenith direction - final T zhd = hydrostatic.pathDelay(elevation.getPi().multiply(0.5), point, weather, parameters, date); + final T zhd = hydrostatic.pathDelay(new FieldTrackingCoordinates<>(trackingCoordinates.getAzimuth(), + trackingCoordinates.getElevation().getPi().multiply(0.5), + trackingCoordinates.getRange()), + point, weather, parameters, date); final T ztd = parameters[0]; // Mapping functions - final T[] mf = model.mappingFactors(elevation, point, weather, date); + final T[] mf = model.mappingFactors(trackingCoordinates, point, weather, date); // Total delay return mf[0].multiply(zhd).add(mf[1].multiply(ztd.subtract(zhd))); } diff --git a/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java b/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java index f292851e87..409264bcba 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java @@ -23,7 +23,9 @@ import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; +import org.orekit.utils.FieldTrackingCoordinates; import org.orekit.utils.ParameterDriver; +import org.orekit.utils.TrackingCoordinates; /** An estimated tropospheric model. The tropospheric delay is computed according to the formula: *

                    @@ -102,7 +104,8 @@ public EstimatedTroposphericModel(final MappingFunction model, final double tota @Deprecated public double pathDelay(final double elevation, final GeodeticPoint point, final double[] parameters, final AbsoluteDate date) { - return pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, parameters, date); + return pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, parameters, date); } /** {@inheritDoc} */ @@ -112,7 +115,8 @@ public > T pathDelay(final T elevation, final FieldGeodeticPoint point, final T[] parameters, final FieldAbsoluteDate date) { - return pathDelay(elevation, point, + return pathDelay(new FieldTrackingCoordinates<>(date.getField().getZero(), elevation, date.getField().getZero()), + point, new FieldPressureTemperatureHumidity<>(date.getField(), TroposphericModelUtils.STANDARD_ATMOSPHERE), parameters, date); } diff --git a/src/main/java/org/orekit/models/earth/troposphere/FixedTroposphericDelay.java b/src/main/java/org/orekit/models/earth/troposphere/FixedTroposphericDelay.java index dac4c95168..103e547aa8 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/FixedTroposphericDelay.java +++ b/src/main/java/org/orekit/models/earth/troposphere/FixedTroposphericDelay.java @@ -34,8 +34,10 @@ import org.orekit.models.earth.weather.PressureTemperatureHumidity; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; +import org.orekit.utils.FieldTrackingCoordinates; import org.orekit.utils.InterpolationTableLoader; import org.orekit.utils.ParameterDriver; +import org.orekit.utils.TrackingCoordinates; /** A static tropospheric model that interpolates the actual tropospheric delay * based on values read from a configuration file (tropospheric-delay.txt) via @@ -134,18 +136,19 @@ public static FixedTroposphericDelay getDefaultModel() { @Deprecated public double pathDelay(final double elevation, final GeodeticPoint point, final double[] parameters, final AbsoluteDate date) { - return pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, parameters, date); + return pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, parameters, date); } /** {@inheritDoc} */ @Override - public double pathDelay(final double elevation, final GeodeticPoint point, + public double pathDelay(final TrackingCoordinates trackingCoordinates, final GeodeticPoint point, final PressureTemperatureHumidity weather, final double[] parameters, final AbsoluteDate date) { // limit the height to 5000 m final double h = FastMath.min(FastMath.max(0, point.getAltitude()), 5000); // limit the elevation to 0 - π - final double ele = FastMath.min(FastMath.PI, FastMath.max(0d, elevation)); + final double ele = FastMath.min(FastMath.PI, FastMath.max(0d, trackingCoordinates.getElevation())); // mirror elevation at the right angle of π/2 final double e = ele > 0.5 * FastMath.PI ? FastMath.PI - ele : ele; @@ -157,14 +160,16 @@ public double pathDelay(final double elevation, final GeodeticPoint point, @Deprecated public > T pathDelay(final T elevation, final FieldGeodeticPoint point, final T[] parameters, final FieldAbsoluteDate date) { - return pathDelay(elevation, point, + return pathDelay(new FieldTrackingCoordinates<>(date.getField().getZero(), elevation, date.getField().getZero()), + point, new FieldPressureTemperatureHumidity<>(date.getField(), TroposphericModelUtils.STANDARD_ATMOSPHERE), parameters, date); } /** {@inheritDoc} */ @Override - public > T pathDelay(final T elevation, final FieldGeodeticPoint point, + public > T pathDelay(final FieldTrackingCoordinates trackingCoordinates, + final FieldGeodeticPoint point, final FieldPressureTemperatureHumidity weather, final T[] parameters, final FieldAbsoluteDate date) { final T zero = date.getField().getZero(); @@ -172,7 +177,7 @@ public > T pathDelay(final T elevation, final // limit the height to 5000 m final T h = FastMath.min(FastMath.max(zero, point.getAltitude()), zero.newInstance(5000)); // limit the elevation to 0 - π - final T ele = FastMath.min(pi, FastMath.max(zero, elevation)); + final T ele = FastMath.min(pi, FastMath.max(zero, trackingCoordinates.getElevation())); // mirror elevation at the right angle of π/2 final T e = ele.getReal() > pi.multiply(0.5).getReal() ? ele.negate().add(pi) : ele; diff --git a/src/main/java/org/orekit/models/earth/troposphere/GlobalMappingFunctionModel.java b/src/main/java/org/orekit/models/earth/troposphere/GlobalMappingFunctionModel.java index b7202a00b8..95c72d6dbd 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/GlobalMappingFunctionModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/GlobalMappingFunctionModel.java @@ -33,7 +33,9 @@ import org.orekit.time.FieldAbsoluteDate; import org.orekit.time.TimeScale; import org.orekit.utils.FieldLegendrePolynomials; +import org.orekit.utils.FieldTrackingCoordinates; import org.orekit.utils.LegendrePolynomials; +import org.orekit.utils.TrackingCoordinates; /** The Global Mapping Function model for radio techniques. * This model is an empirical mapping function. It only needs the @@ -89,14 +91,15 @@ public GlobalMappingFunctionModel(final TimeScale utc) { @Deprecated public double[] mappingFactors(final double elevation, final GeodeticPoint point, final AbsoluteDate date) { - return mappingFactors(elevation, point, + return mappingFactors(new TrackingCoordinates(0.0, elevation, 0.0), point, TroposphericModelUtils.STANDARD_ATMOSPHERE, date); } /** {@inheritDoc} */ @Override - public double[] mappingFactors(final double elevation, final GeodeticPoint point, + public double[] mappingFactors(final TrackingCoordinates trackingCoordinates, + final GeodeticPoint point, final PressureTemperatureHumidity weather, final AbsoluteDate date) { // Day of year computation @@ -177,11 +180,14 @@ public double[] mappingFactors(final double elevation, final GeodeticPoint point final double aw = a0Wet + amplWet * FastMath.cos(coef - psi); final double[] function = new double[2]; - function[0] = TroposphericModelUtils.mappingFunction(ah, bh, ch, elevation); - function[1] = TroposphericModelUtils.mappingFunction(aw, bw, cw, elevation); + function[0] = TroposphericModelUtils.mappingFunction(ah, bh, ch, + trackingCoordinates.getElevation()); + function[1] = TroposphericModelUtils.mappingFunction(aw, bw, cw, + trackingCoordinates.getElevation()); // Apply height correction - final double correction = TroposphericModelUtils.computeHeightCorrection(elevation, point.getAltitude()); + final double correction = TroposphericModelUtils.computeHeightCorrection(trackingCoordinates.getElevation(), + point.getAltitude()); function[0] = function[0] + correction; return function; @@ -192,7 +198,8 @@ public double[] mappingFactors(final double elevation, final GeodeticPoint point @Deprecated public > T[] mappingFactors(final T elevation, final FieldGeodeticPoint point, final FieldAbsoluteDate date) { - return mappingFactors(elevation, point, + return mappingFactors(new FieldTrackingCoordinates<>(date.getField().getZero(), elevation, date.getField().getZero()), + point, new FieldPressureTemperatureHumidity<>(date.getField(), TroposphericModelUtils.STANDARD_ATMOSPHERE), date); @@ -200,7 +207,7 @@ public > T[] mappingFactors(final T elevation, /** {@inheritDoc} */ @Override - public > T[] mappingFactors(final T elevation, + public > T[] mappingFactors(final FieldTrackingCoordinates trackingCoordinates, final FieldGeodeticPoint point, final FieldPressureTemperatureHumidity weather, final FieldAbsoluteDate date) { @@ -289,11 +296,15 @@ public > T[] mappingFactors(final T elevation, final T aw = a0Wet.add(amplWet.multiply(FastMath.cos(coef.subtract(psi)))); final T[] function = MathArrays.buildArray(field, 2); - function[0] = TroposphericModelUtils.mappingFunction(ah, bh, ch, elevation); - function[1] = TroposphericModelUtils.mappingFunction(aw, bw, cw, elevation); + function[0] = TroposphericModelUtils.mappingFunction(ah, bh, ch, + trackingCoordinates.getElevation()); + function[1] = TroposphericModelUtils.mappingFunction(aw, bw, cw, + trackingCoordinates.getElevation()); // Apply height correction - final T correction = TroposphericModelUtils.computeHeightCorrection(elevation, point.getAltitude(), field); + final T correction = TroposphericModelUtils.computeHeightCorrection(trackingCoordinates.getElevation(), + point.getAltitude(), + field); function[0] = function[0].add(correction); return function; diff --git a/src/main/java/org/orekit/models/earth/troposphere/MariniMurrayModel.java b/src/main/java/org/orekit/models/earth/troposphere/MariniMurrayModel.java index a7c62fc7c3..756c8cb3c2 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/MariniMurrayModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/MariniMurrayModel.java @@ -30,7 +30,9 @@ import org.orekit.models.earth.weather.water.CIPM2007; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; +import org.orekit.utils.FieldTrackingCoordinates; import org.orekit.utils.ParameterDriver; +import org.orekit.utils.TrackingCoordinates; import org.orekit.utils.units.Unit; import org.orekit.utils.units.UnitsConverter; @@ -141,12 +143,13 @@ public static MariniMurrayModel getStandardModel(final double lambda, final Unit @Deprecated public double pathDelay(final double elevation, final GeodeticPoint point, final double[] parameters, final AbsoluteDate date) { - return pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, parameters, date); + return pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, parameters, date); } /** {@inheritDoc} */ @Override - public double pathDelay(final double elevation, final GeodeticPoint point, + public double pathDelay(final TrackingCoordinates trackingCoordinates, final GeodeticPoint point, final PressureTemperatureHumidity weather, final double[] parameters, final AbsoluteDate date) { @@ -163,7 +166,7 @@ public double pathDelay(final double elevation, final GeodeticPoint point, final double fsite = getSiteFunctionValue(point); - final double sinE = FastMath.sin(elevation); + final double sinE = FastMath.sin(trackingCoordinates.getElevation()); final double dR = (flambda / fsite) * (A + B) / (sinE + B / ((A + B) * (sinE + 0.01)) ); return dR; } @@ -175,14 +178,15 @@ public > T pathDelay(final T elevation, final FieldGeodeticPoint point, final T[] parameters, final FieldAbsoluteDate date) { - return pathDelay(elevation, point, + return pathDelay(new FieldTrackingCoordinates<>(date.getField().getZero(), elevation, date.getField().getZero()), + point, new FieldPressureTemperatureHumidity<>(date.getField(), TroposphericModelUtils.STANDARD_ATMOSPHERE), parameters, date); } /** {@inheritDoc} */ @Override - public > T pathDelay(final T elevation, + public > T pathDelay(final FieldTrackingCoordinates trackingCoordinates, final FieldGeodeticPoint point, final FieldPressureTemperatureHumidity weather, final T[] parameters, final FieldAbsoluteDate date) { @@ -204,7 +208,7 @@ public > T pathDelay(final T elevation, final T fsite = getSiteFunctionValue(point); - final T sinE = FastMath.sin(elevation); + final T sinE = FastMath.sin(trackingCoordinates.getElevation()); final T dR = fsite.divide(flambda).reciprocal().multiply(B.add(A)).divide(sinE.add(sinE.add(0.01).multiply(B.add(A)).divide(B).reciprocal())); return dR; } diff --git a/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java b/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java index 9321438658..c59eac7fd5 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java @@ -32,7 +32,9 @@ import org.orekit.models.earth.weather.water.CIPM2007; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; +import org.orekit.utils.FieldTrackingCoordinates; import org.orekit.utils.ParameterDriver; +import org.orekit.utils.TrackingCoordinates; import org.orekit.utils.units.Unit; import org.orekit.utils.units.UnitsConverter; @@ -183,18 +185,19 @@ public static MendesPavlisModel getStandardModel(final double lambda, final Unit @Deprecated public double pathDelay(final double elevation, final GeodeticPoint point, final double[] parameters, final AbsoluteDate date) { - return pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, parameters, date); + return pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, parameters, date); } /** {@inheritDoc} */ @Override - public double pathDelay(final double elevation, final GeodeticPoint point, + public double pathDelay(final TrackingCoordinates trackingCoordinates, final GeodeticPoint point, final PressureTemperatureHumidity weather, final double[] parameters, final AbsoluteDate date) { // Zenith delay final double[] zenithDelay = computeZenithDelay(point, parameters, date); // Mapping function - final double[] mappingFunction = mappingFactors(elevation, point, date); + final double[] mappingFunction = mappingFactors(trackingCoordinates, point, weather, date); // Tropospheric path delay return zenithDelay[0] * mappingFunction[0] + zenithDelay[1] * mappingFunction[1]; } @@ -204,20 +207,22 @@ public double pathDelay(final double elevation, final GeodeticPoint point, @Deprecated public > T pathDelay(final T elevation, final FieldGeodeticPoint point, final T[] parameters, final FieldAbsoluteDate date) { - return pathDelay(elevation, point, + return pathDelay(new FieldTrackingCoordinates<>(date.getField().getZero(), elevation, date.getField().getZero()), + point, new FieldPressureTemperatureHumidity<>(date.getField(), TroposphericModelUtils.STANDARD_ATMOSPHERE), parameters, date); } /** {@inheritDoc} */ @Override - public > T pathDelay(final T elevation, final FieldGeodeticPoint point, + public > T pathDelay(final FieldTrackingCoordinates trackingCoordinates, + final FieldGeodeticPoint point, final FieldPressureTemperatureHumidity weather, final T[] parameters, final FieldAbsoluteDate date) { // Zenith delay final T[] delays = computeZenithDelay(point, parameters, date); // Mapping function - final T[] mappingFunction = mappingFactors(elevation, point, date); + final T[] mappingFunction = mappingFactors(trackingCoordinates, point, weather, date); // Tropospheric path delay return delays[0].multiply(mappingFunction[0]).add(delays[1].multiply(mappingFunction[1])); } @@ -305,7 +310,7 @@ public > T[] computeZenithDelay(final FieldGeo @Deprecated public double[] mappingFactors(final double elevation, final GeodeticPoint point, final AbsoluteDate date) { - return mappingFactors(elevation, point, + return mappingFactors(new TrackingCoordinates(0.0, elevation, 0.0), point, TroposphericModelUtils.STANDARD_ATMOSPHERE, date); } @@ -324,10 +329,11 @@ public double[] mappingFactors(final double elevation, final GeodeticPoint point * δ = (Dhz + Dwz) * m(e) = δz * m(e) */ @Override - public double[] mappingFactors(final double elevation, final GeodeticPoint point, + public double[] mappingFactors(final TrackingCoordinates trackingCoordinates, + final GeodeticPoint point, final PressureTemperatureHumidity weather, final AbsoluteDate date) { - final double sinE = FastMath.sin(elevation); + final double sinE = FastMath.sin(trackingCoordinates.getElevation()); final PressureTemperatureHumidity pth = pthProvider.getWeatherParamerers(point, date); final double T2degree = pth.getTemperature() - 273.15; @@ -371,9 +377,11 @@ public double[] mappingFactors(final double elevation, final GeodeticPoint point */ @Override @Deprecated - public > T[] mappingFactors(final T elevation, final FieldGeodeticPoint point, + public > T[] mappingFactors(final T elevation, + final FieldGeodeticPoint point, final FieldAbsoluteDate date) { - return mappingFactors(elevation, point, + return mappingFactors(new FieldTrackingCoordinates<>(date.getField().getZero(), elevation, date.getField().getZero()), + point, new FieldPressureTemperatureHumidity<>(date.getField(), TroposphericModelUtils.STANDARD_ATMOSPHERE), date); @@ -393,13 +401,13 @@ public > T[] mappingFactors(final T elevation, * δ = (Dhz + Dwz) * m(e) = δz * m(e) */ @Override - public > T[] mappingFactors(final T elevation, + public > T[] mappingFactors(final FieldTrackingCoordinates trackingCoordinates, final FieldGeodeticPoint point, final FieldPressureTemperatureHumidity weather, final FieldAbsoluteDate date) { final Field field = date.getField(); - final T sinE = FastMath.sin(elevation); + final T sinE = FastMath.sin(trackingCoordinates.getElevation()); final FieldPressureTemperatureHumidity pth = pthProvider.getWeatherParamerers(point, date); final T T2degree = pth.getTemperature().subtract(273.15); diff --git a/src/main/java/org/orekit/models/earth/troposphere/ModifiedHopfieldModel.java b/src/main/java/org/orekit/models/earth/troposphere/ModifiedHopfieldModel.java index d6921b8467..2b274f69f1 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/ModifiedHopfieldModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/ModifiedHopfieldModel.java @@ -30,7 +30,9 @@ import org.orekit.models.earth.weather.PressureTemperatureHumidity; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; +import org.orekit.utils.FieldTrackingCoordinates; import org.orekit.utils.ParameterDriver; +import org.orekit.utils.TrackingCoordinates; /** The modified Hopfield model. *

                    @@ -76,12 +78,13 @@ public ModifiedHopfieldModel() { /** {@inheritDoc} */ @Override - public double pathDelay(final double elevation, final GeodeticPoint point, + public double pathDelay(final TrackingCoordinates trackingCoordinates, + final GeodeticPoint point, final PressureTemperatureHumidity weather, final double[] parameters, final AbsoluteDate date) { // zenith angle - final double zenithAngle = MathUtils.SEMI_PI - elevation; + final double zenithAngle = MathUtils.SEMI_PI - trackingCoordinates.getElevation(); // dry component final double hd = HD0 + HD1 * (weather.getTemperature() - T0); @@ -112,12 +115,13 @@ public double pathDelay(final double elevation, final GeodeticPoint point, * @see #setLowElevationThreshold(double) */ @Override - public > T pathDelay(final T elevation, final FieldGeodeticPoint point, + public > T pathDelay(final FieldTrackingCoordinates trackingCoordinates, + final FieldGeodeticPoint point, final FieldPressureTemperatureHumidity weather, final T[] parameters, final FieldAbsoluteDate date) { // zenith angle - final T zenithAngle = elevation.negate().add(MathUtils.SEMI_PI); + final T zenithAngle = trackingCoordinates.getElevation().negate().add(MathUtils.SEMI_PI); // dry component final T hd = weather.getTemperature().subtract(T0).multiply(HD1).add(HD0); @@ -127,7 +131,7 @@ public > T pathDelay(final T elevation, final final T deltaD = delay(zenithAngle, hd, nd); // wet component - final T hw = elevation.getField().getZero().newInstance(HW0); + final T hw = date.getField().getZero().newInstance(HW0); final T nw = weather.getTemperature().reciprocal().multiply(NW2).add(NW1).divide(weather.getTemperature()); final T deltaW = delay(zenithAngle, hw, nw); diff --git a/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java b/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java index 1734eb9436..c74d736b91 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java @@ -41,8 +41,10 @@ import org.orekit.models.earth.weather.water.Wang1988; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; +import org.orekit.utils.FieldTrackingCoordinates; import org.orekit.utils.InterpolationTableLoader; import org.orekit.utils.ParameterDriver; +import org.orekit.utils.TrackingCoordinates; /** The modified Saastamoinen model. Estimates the path delay imposed to * electro-magnetic signals by the troposphere according to the formula: @@ -222,7 +224,8 @@ public PressureTemperatureHumidityProvider getPth0Provider() { * @see #setLowElevationThreshold(double) */ @Override - public double pathDelay(final double elevation, final GeodeticPoint point, + public double pathDelay(final TrackingCoordinates trackingCoordinates, + final GeodeticPoint point, final PressureTemperatureHumidity weather, final double[] parameters, final AbsoluteDate date) { @@ -236,7 +239,8 @@ public double pathDelay(final double elevation, final GeodeticPoint point, final double B = B_FUNCTION.value(fixedHeight); // calculate the zenith angle from the elevation - final double z = FastMath.abs(0.5 * FastMath.PI - FastMath.max(elevation, lowElevationThreshold)); + final double z = FastMath.abs(0.5 * FastMath.PI - + FastMath.max(trackingCoordinates.getElevation(), lowElevationThreshold)); // get correction factor final double deltaR = getDeltaR(fixedHeight, z); @@ -266,7 +270,8 @@ public double pathDelay(final double elevation, final GeodeticPoint point, * @see #setLowElevationThreshold(double) */ @Override - public > T pathDelay(final T elevation, final FieldGeodeticPoint point, + public > T pathDelay(final FieldTrackingCoordinates trackingCoordinates, + final FieldGeodeticPoint point, final FieldPressureTemperatureHumidity weather, final T[] parameters, final FieldAbsoluteDate date) { @@ -283,7 +288,8 @@ public > T pathDelay(final T elevation, final final T B = B_FUNCTION.value(fixedHeight); // calculate the zenith angle from the elevation - final T z = FastMath.abs(FastMath.max(elevation, zero.newInstance(lowElevationThreshold)).negate(). + final T z = FastMath.abs(FastMath.max(trackingCoordinates.getElevation(), + zero.newInstance(lowElevationThreshold)).negate(). add(zero.getPi().multiply(0.5))); // get correction factor diff --git a/src/main/java/org/orekit/models/earth/troposphere/NiellMappingFunctionModel.java b/src/main/java/org/orekit/models/earth/troposphere/NiellMappingFunctionModel.java index 5f6f244651..5180fdb5fc 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/NiellMappingFunctionModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/NiellMappingFunctionModel.java @@ -32,6 +32,8 @@ import org.orekit.time.DateTimeComponents; import org.orekit.time.FieldAbsoluteDate; import org.orekit.time.TimeScale; +import org.orekit.utils.FieldTrackingCoordinates; +import org.orekit.utils.TrackingCoordinates; /** The Niell Mapping Function model for radio wavelengths. * This model is an empirical mapping function. It only needs the @@ -166,14 +168,15 @@ public NiellMappingFunctionModel(final TimeScale utc) { @Deprecated public double[] mappingFactors(final double elevation, final GeodeticPoint point, final AbsoluteDate date) { - return mappingFactors(elevation, point, + return mappingFactors(new TrackingCoordinates(0.0, elevation, 0.0), + point, TroposphericModelUtils.STANDARD_ATMOSPHERE, date); } /** {@inheritDoc} */ @Override - public double[] mappingFactors(final double elevation, final GeodeticPoint point, + public double[] mappingFactors(final TrackingCoordinates trackingCoordinates, final GeodeticPoint point, final PressureTemperatureHumidity weather, final AbsoluteDate date) { // Day of year computation @@ -202,13 +205,17 @@ public double[] mappingFactors(final double elevation, final GeodeticPoint point final double[] function = new double[2]; // Hydrostatic mapping factor - function[0] = TroposphericModelUtils.mappingFunction(ah, bh, ch, elevation); + function[0] = TroposphericModelUtils.mappingFunction(ah, bh, ch, trackingCoordinates.getElevation()); // Wet mapping factor - function[1] = TroposphericModelUtils.mappingFunction(awFunction.value(absLatidude), bwFunction.value(absLatidude), cwFunction.value(absLatidude), elevation); + function[1] = TroposphericModelUtils.mappingFunction(awFunction.value(absLatidude), + bwFunction.value(absLatidude), + cwFunction.value(absLatidude), + trackingCoordinates.getElevation()); // Apply height correction - final double correction = TroposphericModelUtils.computeHeightCorrection(elevation, point.getAltitude()); + final double correction = TroposphericModelUtils.computeHeightCorrection(trackingCoordinates.getElevation(), + point.getAltitude()); function[0] = function[0] + correction; return function; @@ -218,8 +225,9 @@ public double[] mappingFactors(final double elevation, final GeodeticPoint point @Override @Deprecated public > T[] mappingFactors(final T elevation, final FieldGeodeticPoint point, - final FieldAbsoluteDate date) { - return mappingFactors(elevation, point, + final FieldAbsoluteDate date) { + return mappingFactors(new FieldTrackingCoordinates<>(date.getField().getZero(), elevation, date.getField().getZero()), + point, new FieldPressureTemperatureHumidity<>(date.getField(), TroposphericModelUtils.STANDARD_ATMOSPHERE), date); @@ -227,7 +235,7 @@ public > T[] mappingFactors(final T elevation, /** {@inheritDoc} */ @Override - public > T[] mappingFactors(final T elevation, + public > T[] mappingFactors(final FieldTrackingCoordinates trackingCoordinates, final FieldGeodeticPoint point, final FieldPressureTemperatureHumidity weather, final FieldAbsoluteDate date) { @@ -260,14 +268,17 @@ public > T[] mappingFactors(final T elevation, final T[] function = MathArrays.buildArray(field, 2); // Hydrostatic mapping factor - function[0] = TroposphericModelUtils.mappingFunction(ah, bh, ch, elevation); + function[0] = TroposphericModelUtils.mappingFunction(ah, bh, ch, + trackingCoordinates.getElevation()); // Wet mapping factor function[1] = TroposphericModelUtils.mappingFunction(zero.newInstance(awFunction.value(absLatidude)), zero.newInstance(bwFunction.value(absLatidude)), - zero.newInstance(cwFunction.value(absLatidude)), elevation); + zero.newInstance(cwFunction.value(absLatidude)), trackingCoordinates.getElevation()); // Apply height correction - final T correction = TroposphericModelUtils.computeHeightCorrection(elevation, point.getAltitude(), field); + final T correction = TroposphericModelUtils.computeHeightCorrection(trackingCoordinates.getElevation(), + point.getAltitude(), + field); function[0] = function[0].add(correction); return function; diff --git a/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java b/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java index de63ae98ba..a8b71d9eda 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java @@ -27,6 +27,8 @@ import org.orekit.models.earth.weather.water.Wang1988; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; +import org.orekit.utils.FieldTrackingCoordinates; +import org.orekit.utils.TrackingCoordinates; /** The modified Saastamoinen model. * @author Luc Maisonobe @@ -124,7 +126,8 @@ public static SaastamoinenModel getStandardModel() { @Deprecated public double pathDelay(final double elevation, final GeodeticPoint point, final double[] parameters, final AbsoluteDate date) { - return pathDelay(elevation, point, getPth0Provider().getWeatherParamerers(point, date), parameters, date); + return pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), point, + getPth0Provider().getWeatherParamerers(point, date), parameters, date); } /** {@inheritDoc} */ @@ -134,7 +137,8 @@ public > T pathDelay(final T elevation, final FieldGeodeticPoint point, final T[] parameters, final FieldAbsoluteDate date) { - return pathDelay(elevation, point, + return pathDelay(new FieldTrackingCoordinates<>(date.getField().getZero(), elevation, date.getField().getZero()), + point, getPth0Provider().getWeatherParamerers(point, date), parameters, date); } diff --git a/src/main/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModel.java b/src/main/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModel.java index 9c121582dd..21173a508e 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModel.java @@ -30,9 +30,11 @@ import org.orekit.time.FieldAbsoluteDate; import org.orekit.time.TimeScale; import org.orekit.time.TimeScalesFactory; +import org.orekit.utils.FieldTrackingCoordinates; import org.orekit.utils.ParameterDriver; import org.orekit.utils.TimeSpanMap; import org.orekit.utils.TimeSpanMap.Span; +import org.orekit.utils.TrackingCoordinates; /** * Time span estimated tropospheric model. @@ -208,25 +210,26 @@ public > T[] extractParameters(final T[] param /** {@inheritDoc} */ @Override - public double pathDelay(final double elevation, final GeodeticPoint point, + public double pathDelay(final TrackingCoordinates trackingCoordinates, final GeodeticPoint point, final PressureTemperatureHumidity weather, final double[] parameters, final AbsoluteDate date) { // Extract the proper parameters valid at date from the input array final double[] extractedParameters = extractParameters(parameters, date); // Compute and return the path delay - return getTroposphericModel(date).pathDelay(elevation, point, weather, + return getTroposphericModel(date).pathDelay(trackingCoordinates, point, weather, extractedParameters, date); } /** {@inheritDoc} */ @Override - public > T pathDelay(final T elevation, final FieldGeodeticPoint point, + public > T pathDelay(final FieldTrackingCoordinates trackingCoordinates, + final FieldGeodeticPoint point, final FieldPressureTemperatureHumidity weather, final T[] parameters, final FieldAbsoluteDate date) { // Extract the proper parameters valid at date from the input array final T[] extractedParameters = extractParameters(parameters, date); // Compute and return the path delay - return getTroposphericModel(date.toAbsoluteDate()).pathDelay(elevation, point, weather, + return getTroposphericModel(date.toAbsoluteDate()).pathDelay(trackingCoordinates, point, weather, extractedParameters, date); } diff --git a/src/main/java/org/orekit/models/earth/troposphere/TroposphereMappingFunction.java b/src/main/java/org/orekit/models/earth/troposphere/TroposphereMappingFunction.java index 2465dd24db..ecff34fe56 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/TroposphereMappingFunction.java +++ b/src/main/java/org/orekit/models/earth/troposphere/TroposphereMappingFunction.java @@ -23,6 +23,8 @@ import org.orekit.models.earth.weather.PressureTemperatureHumidity; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; +import org.orekit.utils.FieldTrackingCoordinates; +import org.orekit.utils.TrackingCoordinates; /** Interface for mapping functions used in the tropospheric delay computation. * @author Bryan Cazabonne @@ -36,13 +38,13 @@ public interface TroposphereMappingFunction { *

                  • double[0] = mh(e) → hydrostatic mapping function *
                  • double[1] = mw(e) → wet mapping function *
                  - * @param elevation the elevation of the satellite, in radians + * @param trackingCoordinates tracking coordinates of the satellite * @param point station location * @param weather weather parameters * @param date current date * @return a two components array containing the hydrostatic and wet mapping functions. */ - double[] mappingFactors(double elevation, GeodeticPoint point, + double[] mappingFactors(TrackingCoordinates trackingCoordinates, GeodeticPoint point, PressureTemperatureHumidity weather, AbsoluteDate date); /** This method allows the computation of the hydrostatic and @@ -51,14 +53,15 @@ public interface TroposphereMappingFunction { *
                • T[0] = mh(e) → hydrostatic mapping function *
                • T[1] = mw(e) → wet mapping function *
                - * @param elevation the elevation of the satellite, in radians + * @param trackingCoordinates tracking coordinates of the satellite * @param point station location * @param weather weather parameters * @param date current date * @param type of the elements * @return a two components array containing the hydrostatic and wet mapping functions. */ - > T[] mappingFactors(T elevation, FieldGeodeticPoint point, + > T[] mappingFactors(FieldTrackingCoordinates trackingCoordinates, + FieldGeodeticPoint point, FieldPressureTemperatureHumidity weather, FieldAbsoluteDate date); diff --git a/src/main/java/org/orekit/models/earth/troposphere/TroposphereMappingFunctionAdapter.java b/src/main/java/org/orekit/models/earth/troposphere/TroposphereMappingFunctionAdapter.java index c43d65bc4f..7168c1a299 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/TroposphereMappingFunctionAdapter.java +++ b/src/main/java/org/orekit/models/earth/troposphere/TroposphereMappingFunctionAdapter.java @@ -23,6 +23,8 @@ import org.orekit.models.earth.weather.PressureTemperatureHumidity; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; +import org.orekit.utils.FieldTrackingCoordinates; +import org.orekit.utils.TrackingCoordinates; /** Adapter between {@link MappingFunction} and {@link TroposphereMappingFunction}. *

                @@ -52,15 +54,15 @@ public TroposphereMappingFunctionAdapter(final MappingFunction model) { *

              • double[0] = mh(e) → hydrostatic mapping function *
              • double[1] = mw(e) → wet mapping function *
              - * @param elevation the elevation of the satellite, in radians + * @param trackingCoordinates tracking coordinates of the satellite * @param point station location * @param weather weather parameters * @param date current date * @return a two components array containing the hydrostatic and wet mapping functions. */ - public double[] mappingFactors(final double elevation, final GeodeticPoint point, + public double[] mappingFactors(final TrackingCoordinates trackingCoordinates, final GeodeticPoint point, final PressureTemperatureHumidity weather, final AbsoluteDate date) { - return model.mappingFactors(elevation, point, date); + return model.mappingFactors(trackingCoordinates.getElevation(), point, date); } /** This method allows the computation of the hydrostatic and @@ -69,18 +71,18 @@ public double[] mappingFactors(final double elevation, final GeodeticPoint point *
            • T[0] = mh(e) → hydrostatic mapping function *
            • T[1] = mw(e) → wet mapping function *
            - * @param elevation the elevation of the satellite, in radians + * @param trackingCoordinates tracking coordinates of the satellite * @param point station location * @param weather weather parameters * @param date current date * @param type of the elements * @return a two components array containing the hydrostatic and wet mapping functions. */ - public > T[] mappingFactors(final T elevation, + public > T[] mappingFactors(final FieldTrackingCoordinates trackingCoordinates, final FieldGeodeticPoint point, final FieldPressureTemperatureHumidity weather, final FieldAbsoluteDate date) { - return model.mappingFactors(elevation, point, date); + return model.mappingFactors(trackingCoordinates.getElevation(), point, date); } } diff --git a/src/main/java/org/orekit/models/earth/troposphere/TroposphericModel.java b/src/main/java/org/orekit/models/earth/troposphere/TroposphericModel.java index bf709392ab..82947f4eee 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/TroposphericModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/TroposphericModel.java @@ -23,7 +23,9 @@ import org.orekit.models.earth.weather.PressureTemperatureHumidity; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; +import org.orekit.utils.FieldTrackingCoordinates; import org.orekit.utils.ParameterDriversProvider; +import org.orekit.utils.TrackingCoordinates; /** Defines a tropospheric model, used to calculate the path delay imposed to * electro-magnetic signals between an orbital satellite and a ground station. @@ -35,7 +37,7 @@ public interface TroposphericModel extends ParameterDriversProvider { /** Calculates the tropospheric path delay for the signal path from a ground * station to a satellite. * - * @param elevation the elevation of the satellite, in radians + * @param trackingCoordinates tracking coordinates of the satellite * @param point station location * @param weather weather parameters * for constant default values) @@ -43,14 +45,14 @@ public interface TroposphericModel extends ParameterDriversProvider { * @param date current date * @return the path delay due to the troposphere in m */ - double pathDelay(double elevation, GeodeticPoint point, PressureTemperatureHumidity weather, + double pathDelay(TrackingCoordinates trackingCoordinates, GeodeticPoint point, PressureTemperatureHumidity weather, double[] parameters, AbsoluteDate date); /** Calculates the tropospheric path delay for the signal path from a ground * station to a satellite. * * @param type of the elements - * @param elevation the elevation of the satellite, in radians + * @param trackingCoordinates tracking coordinates of the satellite * @param point station location * @param weather weather parameters * for constant default values) @@ -58,7 +60,8 @@ public interface TroposphericModel extends ParameterDriversProvider { * @param date current date * @return the path delay due to the troposphere in m */ - > T pathDelay(T elevation, FieldGeodeticPoint point, + > T pathDelay(FieldTrackingCoordinates trackingCoordinates, + FieldGeodeticPoint point, FieldPressureTemperatureHumidity weather, T[] parameters, FieldAbsoluteDate date); } diff --git a/src/main/java/org/orekit/models/earth/troposphere/TroposphericModelAdapter.java b/src/main/java/org/orekit/models/earth/troposphere/TroposphericModelAdapter.java index 5397e64088..fea0a69e13 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/TroposphericModelAdapter.java +++ b/src/main/java/org/orekit/models/earth/troposphere/TroposphericModelAdapter.java @@ -25,7 +25,9 @@ import org.orekit.models.earth.weather.PressureTemperatureHumidity; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; +import org.orekit.utils.FieldTrackingCoordinates; import org.orekit.utils.ParameterDriver; +import org.orekit.utils.TrackingCoordinates; /** Adapter between {@link DiscreteTroposphericModel} and {@link TroposphericModel}. *

            @@ -51,22 +53,22 @@ public TroposphericModelAdapter(final DiscreteTroposphericModel model) { /** {@inheritDoc} */ @Override - public double pathDelay(final double elevation, + public double pathDelay(final TrackingCoordinates trackingCoordinates, final GeodeticPoint point, final PressureTemperatureHumidity weather, final double[] parameters, final AbsoluteDate date) { - return model.pathDelay(elevation, point, parameters, date); + return model.pathDelay(trackingCoordinates.getElevation(), point, parameters, date); } /** {@inheritDoc} */ @Override - public > T pathDelay(final T elevation, + public > T pathDelay(final FieldTrackingCoordinates trackingCoordinates, final FieldGeodeticPoint point, final FieldPressureTemperatureHumidity weather, final T[] parameters, final FieldAbsoluteDate date) { - return model.pathDelay(elevation, point, parameters, date); + return model.pathDelay(trackingCoordinates.getElevation(), point, parameters, date); } /** {@inheritDoc} */ diff --git a/src/main/java/org/orekit/models/earth/troposphere/ViennaOneModel.java b/src/main/java/org/orekit/models/earth/troposphere/ViennaOneModel.java index 1bef2809d9..6ec49ddf03 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/ViennaOneModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/ViennaOneModel.java @@ -33,7 +33,9 @@ import org.orekit.time.DateTimeComponents; import org.orekit.time.FieldAbsoluteDate; import org.orekit.time.TimeScale; +import org.orekit.utils.FieldTrackingCoordinates; import org.orekit.utils.ParameterDriver; +import org.orekit.utils.TrackingCoordinates; /** The Vienna1 tropospheric delay model for radio techniques. * The Vienna model data are given with a time interval of 6 hours @@ -99,18 +101,19 @@ public ViennaOneModel(final double[] coefficientA, @Deprecated public double pathDelay(final double elevation, final GeodeticPoint point, final double[] parameters, final AbsoluteDate date) { - return pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, parameters, date); + return pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), + point, TroposphericModelUtils.STANDARD_ATMOSPHERE, parameters, date); } /** {@inheritDoc} */ @Override - public double pathDelay(final double elevation, final GeodeticPoint point, + public double pathDelay(final TrackingCoordinates trackingCoordinates, final GeodeticPoint point, final PressureTemperatureHumidity weather, final double[] parameters, final AbsoluteDate date) { // zenith delay final double[] delays = computeZenithDelay(point, parameters, date); // mapping function - final double[] mappingFunction = mappingFactors(elevation, point, date); + final double[] mappingFunction = mappingFactors(trackingCoordinates, point, weather, date); // Tropospheric path delay return delays[0] * mappingFunction[0] + delays[1] * mappingFunction[1]; } @@ -120,20 +123,22 @@ public double pathDelay(final double elevation, final GeodeticPoint point, @Deprecated public > T pathDelay(final T elevation, final FieldGeodeticPoint point, final T[] parameters, final FieldAbsoluteDate date) { - return pathDelay(elevation, point, + return pathDelay(new FieldTrackingCoordinates<>(date.getField().getZero(), elevation, date.getField().getZero()), + point, new FieldPressureTemperatureHumidity<>(date.getField(), TroposphericModelUtils.STANDARD_ATMOSPHERE), parameters, date); } /** {@inheritDoc} */ @Override - public > T pathDelay(final T elevation, final FieldGeodeticPoint point, + public > T pathDelay(final FieldTrackingCoordinates trackingCoordinates, + final FieldGeodeticPoint point, final FieldPressureTemperatureHumidity weather, final T[] parameters, final FieldAbsoluteDate date) { // zenith delay final T[] delays = computeZenithDelay(point, parameters, date); // mapping function - final T[] mappingFunction = mappingFactors(elevation, point, date); + final T[] mappingFunction = mappingFactors(trackingCoordinates, point, weather, date); // Tropospheric path delay return delays[0].multiply(mappingFunction[0]).add(delays[1].multiply(mappingFunction[1])); } @@ -180,14 +185,16 @@ public > T[] computeZenithDelay(final FieldGeo @Deprecated public double[] mappingFactors(final double elevation, final GeodeticPoint point, final AbsoluteDate date) { - return mappingFactors(elevation, point, + return mappingFactors(new TrackingCoordinates(0.0, elevation, 0.0), + point, TroposphericModelUtils.STANDARD_ATMOSPHERE, date); } /** {@inheritDoc} */ @Override - public double[] mappingFactors(final double elevation, final GeodeticPoint point, + public double[] mappingFactors(final TrackingCoordinates trackingCoordinates, + final GeodeticPoint point, final PressureTemperatureHumidity weather, final AbsoluteDate date) { // Day of year computation @@ -230,11 +237,14 @@ public double[] mappingFactors(final double elevation, final GeodeticPoint point final double cw = 0.04391; final double[] function = new double[2]; - function[0] = TroposphericModelUtils.mappingFunction(coefficientsA[0], bh, ch, elevation); - function[1] = TroposphericModelUtils.mappingFunction(coefficientsA[1], bw, cw, elevation); + function[0] = TroposphericModelUtils.mappingFunction(coefficientsA[0], bh, ch, + trackingCoordinates.getElevation()); + function[1] = TroposphericModelUtils.mappingFunction(coefficientsA[1], bw, cw, + trackingCoordinates.getElevation()); // Apply height correction - final double correction = TroposphericModelUtils.computeHeightCorrection(elevation, point.getAltitude()); + final double correction = TroposphericModelUtils.computeHeightCorrection(trackingCoordinates.getElevation(), + point.getAltitude()); function[0] = function[0] + correction; return function; @@ -245,7 +255,8 @@ public double[] mappingFactors(final double elevation, final GeodeticPoint point @Deprecated public > T[] mappingFactors(final T elevation, final FieldGeodeticPoint point, final FieldAbsoluteDate date) { - return mappingFactors(elevation, point, + return mappingFactors(new FieldTrackingCoordinates<>(date.getField().getZero(), elevation, date.getField().getZero()), + point, new FieldPressureTemperatureHumidity<>(date.getField(), TroposphericModelUtils.STANDARD_ATMOSPHERE), date); @@ -253,7 +264,7 @@ public > T[] mappingFactors(final T elevation, /** {@inheritDoc} */ @Override - public > T[] mappingFactors(final T elevation, + public > T[] mappingFactors(final FieldTrackingCoordinates trackingCoordinates, final FieldGeodeticPoint point, final FieldPressureTemperatureHumidity weather, final FieldAbsoluteDate date) { @@ -300,11 +311,15 @@ public > T[] mappingFactors(final T elevation, final T cw = zero.newInstance(0.04391); final T[] function = MathArrays.buildArray(field, 2); - function[0] = TroposphericModelUtils.mappingFunction(zero.newInstance(coefficientsA[0]), bh, ch, elevation); - function[1] = TroposphericModelUtils.mappingFunction(zero.newInstance(coefficientsA[1]), bw, cw, elevation); + function[0] = TroposphericModelUtils.mappingFunction(zero.newInstance(coefficientsA[0]), bh, ch, + trackingCoordinates.getElevation()); + function[1] = TroposphericModelUtils.mappingFunction(zero.newInstance(coefficientsA[1]), bw, cw, + trackingCoordinates.getElevation()); // Apply height correction - final T correction = TroposphericModelUtils.computeHeightCorrection(elevation, point.getAltitude(), field); + final T correction = TroposphericModelUtils.computeHeightCorrection(trackingCoordinates.getElevation(), + point.getAltitude(), + field); function[0] = function[0].add(correction); return function; diff --git a/src/main/java/org/orekit/models/earth/troposphere/ViennaThreeModel.java b/src/main/java/org/orekit/models/earth/troposphere/ViennaThreeModel.java index f7e98df2fa..030abc1aa7 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/ViennaThreeModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/ViennaThreeModel.java @@ -36,8 +36,10 @@ import org.orekit.time.FieldAbsoluteDate; import org.orekit.time.TimeScale; import org.orekit.utils.FieldLegendrePolynomials; +import org.orekit.utils.FieldTrackingCoordinates; import org.orekit.utils.LegendrePolynomials; import org.orekit.utils.ParameterDriver; +import org.orekit.utils.TrackingCoordinates; /** The Vienna3 tropospheric delay model for radio techniques. * The Vienna model data are given with a time interval of 6 hours. @@ -104,14 +106,15 @@ public ViennaThreeModel(final double[] coefficientA, @Deprecated public double[] mappingFactors(final double elevation, final GeodeticPoint point, final AbsoluteDate date) { - return mappingFactors(elevation, point, + return mappingFactors(new TrackingCoordinates(0.0, elevation, 0.0), point, TroposphericModelUtils.STANDARD_ATMOSPHERE, date); } /** {@inheritDoc} */ @Override - public double[] mappingFactors(final double elevation, final GeodeticPoint point, + public double[] mappingFactors(final TrackingCoordinates trackingCoordinates, + final GeodeticPoint point, final PressureTemperatureHumidity weather, final AbsoluteDate date) { // Day of year computation @@ -189,8 +192,10 @@ public double[] mappingFactors(final double elevation, final GeodeticPoint point // Compute Mapping Function Eq. 4 final double[] function = new double[2]; - function[0] = TroposphericModelUtils.mappingFunction(coefficientsA[0], bh, ch, elevation); - function[1] = TroposphericModelUtils.mappingFunction(coefficientsA[1], bw, cw, elevation); + function[0] = TroposphericModelUtils.mappingFunction(coefficientsA[0], bh, ch, + trackingCoordinates.getElevation()); + function[1] = TroposphericModelUtils.mappingFunction(coefficientsA[1], bw, cw, + trackingCoordinates.getElevation()); return function; } @@ -200,7 +205,8 @@ public double[] mappingFactors(final double elevation, final GeodeticPoint point @Deprecated public > T[] mappingFactors(final T elevation, final FieldGeodeticPoint point, final FieldAbsoluteDate date) { - return mappingFactors(elevation, point, + return mappingFactors(new FieldTrackingCoordinates<>(date.getField().getZero(), elevation, date.getField().getZero()), + point, new FieldPressureTemperatureHumidity<>(date.getField(), TroposphericModelUtils.STANDARD_ATMOSPHERE), date); @@ -208,7 +214,7 @@ public > T[] mappingFactors(final T elevation, /** {@inheritDoc} */ @Override - public > T[] mappingFactors(final T elevation, + public > T[] mappingFactors(final FieldTrackingCoordinates trackingCoordinates, final FieldGeodeticPoint point, final FieldPressureTemperatureHumidity weather, final FieldAbsoluteDate date) { @@ -290,8 +296,10 @@ public > T[] mappingFactors(final T elevation, // Compute Mapping Function Eq. 4 final T[] function = MathArrays.buildArray(field, 2); - function[0] = TroposphericModelUtils.mappingFunction(zero.newInstance(coefficientsA[0]), bh, ch, elevation); - function[1] = TroposphericModelUtils.mappingFunction(zero.newInstance(coefficientsA[1]), bw, cw, elevation); + function[0] = TroposphericModelUtils.mappingFunction(zero.newInstance(coefficientsA[0]), bh, ch, + trackingCoordinates.getElevation()); + function[1] = TroposphericModelUtils.mappingFunction(zero.newInstance(coefficientsA[1]), bw, cw, + trackingCoordinates.getElevation()); return function; } @@ -301,18 +309,19 @@ public > T[] mappingFactors(final T elevation, @Deprecated public double pathDelay(final double elevation, final GeodeticPoint point, final double[] parameters, final AbsoluteDate date) { - return pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, parameters, date); + return pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, parameters, date); } /** {@inheritDoc} */ @Override - public double pathDelay(final double elevation, final GeodeticPoint point, + public double pathDelay(final TrackingCoordinates trackingCoordinates, final GeodeticPoint point, final PressureTemperatureHumidity weather, final double[] parameters, final AbsoluteDate date) { // zenith delay final double[] delays = computeZenithDelay(point, parameters, date); // mapping function - final double[] mappingFunction = mappingFactors(elevation, point, date); + final double[] mappingFunction = mappingFactors(trackingCoordinates, point, weather, date); // Tropospheric path delay return delays[0] * mappingFunction[0] + delays[1] * mappingFunction[1]; } @@ -321,21 +330,23 @@ public double pathDelay(final double elevation, final GeodeticPoint point, @Override @Deprecated public > T pathDelay(final T elevation, final FieldGeodeticPoint point, - final T[] parameters, final FieldAbsoluteDate date) { - return pathDelay(elevation, point, + final T[] parameters, final FieldAbsoluteDate date) { + return pathDelay(new FieldTrackingCoordinates<>(date.getField().getZero(), elevation, date.getField().getZero()), + point, new FieldPressureTemperatureHumidity<>(date.getField(), TroposphericModelUtils.STANDARD_ATMOSPHERE), parameters, date); } /** {@inheritDoc} */ @Override - public > T pathDelay(final T elevation, final FieldGeodeticPoint point, + public > T pathDelay(final FieldTrackingCoordinates trackingCoordinates, + final FieldGeodeticPoint point, final FieldPressureTemperatureHumidity weather, final T[] parameters, final FieldAbsoluteDate date) { // zenith delay final T[] delays = computeZenithDelay(point, parameters, date); // mapping function - final T[] mappingFunction = mappingFactors(elevation, point, date); + final T[] mappingFunction = mappingFactors(trackingCoordinates.getElevation(), point, date); // Tropospheric path delay return delays[0].multiply(mappingFunction[0]).add(delays[1].multiply(mappingFunction[1])); } diff --git a/src/test/java/org/orekit/models/earth/troposphere/AbstractFieldMappingFunctionTest.java b/src/test/java/org/orekit/models/earth/troposphere/AbstractFieldMappingFunctionTest.java index 00c5366d9e..f6bc881656 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/AbstractFieldMappingFunctionTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/AbstractFieldMappingFunctionTest.java @@ -51,7 +51,9 @@ import org.orekit.time.FieldAbsoluteDate; import org.orekit.time.TimeScalesFactory; import org.orekit.utils.Constants; +import org.orekit.utils.FieldTrackingCoordinates; import org.orekit.utils.IERSConventions; +import org.orekit.utils.TrackingCoordinates; public abstract class AbstractFieldMappingFunctionTest { @@ -82,11 +84,13 @@ protected > void doTestMappingFactors(final Fi final FieldGeodeticPoint point = new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), zero.add(height)); - final double elevation = FastMath.toRadians(5.0); + final FieldTrackingCoordinates trackingCoordinates = new FieldTrackingCoordinates<>(zero, + FastMath.toRadians(zero.newInstance(5.0)), + zero); final TroposphereMappingFunction model = buildMappingFunction(); - final T[] computedMapping = model.mappingFactors(zero.add(elevation), point, + final T[] computedMapping = model.mappingFactors(trackingCoordinates, point, new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), date); @@ -110,7 +114,9 @@ private > void doTestFixedHeight(final Field(zero, + FastMath.toRadians(zero.newInstance(elev)), + zero), point, new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), @@ -173,11 +179,12 @@ protected void doTestMFStateDerivatives(final double epsMFH, final double epsMFW // Initial satellite elevation final FieldVector3D position = dsState.getPosition(); - final DerivativeStructure dsElevation = baseFrame.getTrackingCoordinates(position, frame, dsDate).getElevation(); + final FieldTrackingCoordinates dsTrackingCoordinates = + baseFrame.getTrackingCoordinates(position, frame, dsDate); // Compute mapping factors with state derivatives final FieldGeodeticPoint dsPoint = new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), zero.add(height)); - final DerivativeStructure[] factors = model.mappingFactors(dsElevation, dsPoint, weather, dsDate); + final DerivativeStructure[] factors = model.mappingFactors(dsTrackingCoordinates, dsPoint, weather, dsDate); final double[] compMFH = factors[0].getAllDerivatives(); final double[] compMFW = factors[1].getAllDerivatives(); @@ -195,73 +202,65 @@ protected void doTestMFStateDerivatives(final double epsMFH, final double epsMFW for (int i = 0; i < 6; i++) { SpacecraftState stateM4 = shiftState(state, orbitType, angleType, -4 * steps[i], i); final Vector3D positionM4 = stateM4.getPosition(); - final double elevationM4 = station.getBaseFrame(). - getTrackingCoordinates(positionM4, stateM4.getFrame(), stateM4.getDate()). - getElevation(); - double[] delayM4 = model.mappingFactors(elevationM4, point, + final TrackingCoordinates trackingCoordinatesM4 = station.getBaseFrame(). + getTrackingCoordinates(positionM4, stateM4.getFrame(), stateM4.getDate()); + double[] delayM4 = model.mappingFactors(trackingCoordinatesM4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, stateM4.getDate()); SpacecraftState stateM3 = shiftState(state, orbitType, angleType, -3 * steps[i], i); final Vector3D positionM3 = stateM3.getPosition(); - final double elevationM3 = station.getBaseFrame(). - getTrackingCoordinates(positionM3, stateM3.getFrame(), stateM3.getDate()). - getElevation(); - double[] delayM3 = model.mappingFactors(elevationM3, point, + final TrackingCoordinates trackingCoordinatesM3 = station.getBaseFrame(). + getTrackingCoordinates(positionM3, stateM3.getFrame(), stateM3.getDate()); + double[] delayM3 = model.mappingFactors(trackingCoordinatesM3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, stateM3.getDate()); SpacecraftState stateM2 = shiftState(state, orbitType, angleType, -2 * steps[i], i); final Vector3D positionM2 = stateM2.getPosition(); - final double elevationM2 = station.getBaseFrame(). - getTrackingCoordinates(positionM2, stateM2.getFrame(), stateM2.getDate()). - getElevation(); - double[] delayM2 = model.mappingFactors(elevationM2, point, + final TrackingCoordinates trackingCoordinatesM2 = station.getBaseFrame(). + getTrackingCoordinates(positionM2, stateM2.getFrame(), stateM2.getDate()); + double[] delayM2 = model.mappingFactors(trackingCoordinatesM2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, stateM2.getDate()); SpacecraftState stateM1 = shiftState(state, orbitType, angleType, -1 * steps[i], i); final Vector3D positionM1 = stateM1.getPosition(); - final double elevationM1 = station.getBaseFrame(). - getTrackingCoordinates(positionM1, stateM1.getFrame(), stateM1.getDate()). - getElevation(); - double[] delayM1 = model.mappingFactors(elevationM1, point, + final TrackingCoordinates trackingCoordinatesM1 = station.getBaseFrame(). + getTrackingCoordinates(positionM1, stateM1.getFrame(), stateM1.getDate()); + double[] delayM1 = model.mappingFactors(trackingCoordinatesM1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, stateM1.getDate()); SpacecraftState stateP1 = shiftState(state, orbitType, angleType, 1 * steps[i], i); final Vector3D positionP1 = stateP1.getPosition(); - final double elevationP1 = station.getBaseFrame(). - getTrackingCoordinates(positionP1, stateP1.getFrame(), stateP1.getDate()). - getElevation(); - double[] delayP1 = model.mappingFactors(elevationP1, point, + final TrackingCoordinates trackingCoordinatesP1 = station.getBaseFrame(). + getTrackingCoordinates(positionP1, stateP1.getFrame(), stateP1.getDate()); + double[] delayP1 = model.mappingFactors(trackingCoordinatesP1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, stateP1.getDate()); SpacecraftState stateP2 = shiftState(state, orbitType, angleType, 2 * steps[i], i); final Vector3D positionP2 = stateP2.getPosition(); - final double elevationP2 = station.getBaseFrame(). - getTrackingCoordinates(positionP2, stateP2.getFrame(), stateP2.getDate()). - getElevation(); - double[] delayP2 = model.mappingFactors(elevationP2, point, + final TrackingCoordinates trackingCoordinatesP2 = station.getBaseFrame(). + getTrackingCoordinates(positionP2, stateP2.getFrame(), stateP2.getDate()); + double[] delayP2 = model.mappingFactors(trackingCoordinatesP2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, stateP2.getDate()); SpacecraftState stateP3 = shiftState(state, orbitType, angleType, 3 * steps[i], i); final Vector3D positionP3 = stateP3.getPosition(); - final double elevationP3 = station.getBaseFrame(). - getTrackingCoordinates(positionP3, stateP3.getFrame(), stateP3.getDate()). - getElevation(); - double[] delayP3 = model.mappingFactors(elevationP3, point, + final TrackingCoordinates trackingCoordinatesP3 = station.getBaseFrame(). + getTrackingCoordinates(positionP3, stateP3.getFrame(), stateP3.getDate()); + double[] delayP3 = model.mappingFactors(trackingCoordinatesP3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, stateP3.getDate()); SpacecraftState stateP4 = shiftState(state, orbitType, angleType, 4 * steps[i], i); final Vector3D positionP4 = stateP4.getPosition(); - final double elevationP4 = station.getBaseFrame(). - getTrackingCoordinates(positionP4, stateP4.getFrame(), stateP4.getDate()). - getElevation(); - double[] delayP4 = model.mappingFactors(elevationP4, point, + final TrackingCoordinates trackingCoordinatesP4 = station.getBaseFrame(). + getTrackingCoordinates(positionP4, stateP4.getFrame(), stateP4.getDate()); + double[] delayP4 = model.mappingFactors(trackingCoordinatesP4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, stateP4.getDate()); diff --git a/src/test/java/org/orekit/models/earth/troposphere/AbstractMappingFunctionTest.java b/src/test/java/org/orekit/models/earth/troposphere/AbstractMappingFunctionTest.java index e265b2577c..a0749d366d 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/AbstractMappingFunctionTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/AbstractMappingFunctionTest.java @@ -25,6 +25,7 @@ import org.orekit.bodies.GeodeticPoint; import org.orekit.time.AbsoluteDate; import org.orekit.time.TimeScalesFactory; +import org.orekit.utils.TrackingCoordinates; public abstract class AbstractMappingFunctionTest { @@ -47,11 +48,11 @@ protected void doTestMappingFactors(final double expectedHydro, final double height = 68.0; final GeodeticPoint point = new GeodeticPoint(latitude, longitude, height); - final double elevation = FastMath.toRadians(5.0); + final TrackingCoordinates trackingCoordinates = new TrackingCoordinates(0.0, FastMath.toRadians(5.0), 0.0); final TroposphereMappingFunction model = buildMappingFunction(); - final double[] computedMapping = model.mappingFactors(elevation, point, + final double[] computedMapping = model.mappingFactors(trackingCoordinates, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, date); Assertions.assertEquals(expectedHydro, computedMapping[0], 1.0e-2); @@ -70,7 +71,8 @@ public void doTestFixedHeight() { }; // mapping functions shall decline with increasing elevation angle for (double elev = 10d; elev < 90d; elev += 8d) { - final double[] factors = model.mappingFactors(FastMath.toRadians(elev), point, + final double[] factors = model.mappingFactors(new TrackingCoordinates(0.0, FastMath.toRadians(elev), 0.0), + point, TroposphericModelUtils.STANDARD_ATMOSPHERE, date); Assertions.assertTrue(Precision.compareTo(factors[0], lastFactors[0], 1.0e-6) < 0); diff --git a/src/test/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModelTest.java index db678213b8..4e0ae6fd01 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModelTest.java @@ -23,6 +23,7 @@ import org.orekit.Utils; import org.orekit.bodies.GeodeticPoint; import org.orekit.time.AbsoluteDate; +import org.orekit.utils.TrackingCoordinates; public class CanonicalSaastamoinenModelTest { @@ -39,13 +40,16 @@ public void testComparisonToModifiedModelHighElevation() { private void doTestComparisonToModifiedModel(final double elevation, final double minDifference, final double maxDifference) { + final TrackingCoordinates trackingCoordinates = new TrackingCoordinates(0.0, elevation, 0.0); final CanonicalSaastamoinenModel canonical = CanonicalSaastamoinenModel.getStandardModel(); final ModifiedSaastamoinenModel modified = ModifiedSaastamoinenModel.getStandardModel(); for (double height = 0; height < 5000; height += 100) { final GeodeticPoint location = new GeodeticPoint(0.0, 0.0, height); - final double canonicalDelay = canonical.pathDelay(elevation, location, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final double canonicalDelay = canonical.pathDelay(trackingCoordinates, location, + TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH); - final double modifiedDelay = modified.pathDelay(elevation, location, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final double modifiedDelay = modified.pathDelay(trackingCoordinates, location, + TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH); Assertions.assertTrue(modifiedDelay - canonicalDelay > minDifference); Assertions.assertTrue(modifiedDelay - canonicalDelay < maxDifference); diff --git a/src/test/java/org/orekit/models/earth/troposphere/EstimatedModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/EstimatedModelTest.java index 82d576e065..8ec472b01d 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/EstimatedModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/EstimatedModelTest.java @@ -50,9 +50,11 @@ import org.orekit.time.FieldAbsoluteDate; import org.orekit.time.TimeScalesFactory; import org.orekit.utils.Constants; +import org.orekit.utils.FieldTrackingCoordinates; import org.orekit.utils.IERSConventions; import org.orekit.utils.ParameterDriver; import org.orekit.utils.ParameterDriversList; +import org.orekit.utils.TrackingCoordinates; import java.util.List; @@ -77,7 +79,8 @@ public void testFixedHeight() { double lastDelay = Double.MAX_VALUE; // delay shall decline with increasing elevation angle for (double elev = 10d; elev < 90d; elev += 8d) { - final double delay = model.pathDelay(FastMath.toRadians(elev), point, + final double delay = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elev), 0.0), + point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), date); Assertions.assertTrue(Precision.compareTo(delay, lastDelay, 1.0e-6) < 0); @@ -93,7 +96,8 @@ public void testDelay() { GeodeticPoint point = new GeodeticPoint(FastMath.toRadians(45.0), FastMath.toRadians(45.0), height); TroposphereMappingFunction mapping = new NiellMappingFunctionModel(); TroposphericModel model = new EstimatedModel(mapping, 2.0); - final double path = model.pathDelay(FastMath.toRadians(elevation), point, + final double path = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elevation), 0.0), + point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), date); Assertions.assertTrue(Precision.compareTo(path, 20d, 1.0e-6) < 0); @@ -157,7 +161,8 @@ private void doTestDelayStateDerivatives(final TroposphereMappingFunction func, // Initial satellite elevation final FieldVector3D position = dsState.getPosition(); - final DerivativeStructure dsElevation = baseFrame.getTrackingCoordinates(position, frame, dsDate).getElevation(); + final FieldTrackingCoordinates dsTrackingCoordinates = + baseFrame.getTrackingCoordinates(position, frame, dsDate); // Set drivers reference date for (final ParameterDriver driver : model.getParametersDrivers()) { @@ -166,7 +171,7 @@ private void doTestDelayStateDerivatives(final TroposphereMappingFunction func, // Compute Delay with state derivatives final FieldGeodeticPoint dsPoint = new FieldGeodeticPoint<>(zero.add(point.getLatitude()), zero.add(point.getLongitude()), zero.add(point.getAltitude())); - final DerivativeStructure delay = model.pathDelay(dsElevation, dsPoint, + final DerivativeStructure delay = model.pathDelay(dsTrackingCoordinates, dsPoint, new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), model.getParameters(field), dsDate); @@ -185,66 +190,58 @@ private void doTestDelayStateDerivatives(final TroposphereMappingFunction func, for (int i = 0; i < 6; i++) { SpacecraftState stateM4 = shiftState(state, orbitType, angleType, -4 * steps[i], i); final Vector3D positionM4 = stateM4.getPosition(); - final double elevationM4 = station.getBaseFrame(). - getTrackingCoordinates(positionM4, stateM4.getFrame(), stateM4.getDate()). - getElevation(); - double delayM4 = model.pathDelay(elevationM4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final TrackingCoordinates trackingCoordinatesM4 = station.getBaseFrame(). + getTrackingCoordinates(positionM4, stateM4.getFrame(), stateM4.getDate()); + double delayM4 = model.pathDelay(trackingCoordinatesM4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), stateM4.getDate()); SpacecraftState stateM3 = shiftState(state, orbitType, angleType, -3 * steps[i], i); final Vector3D positionM3 = stateM3.getPosition(); - final double elevationM3 = station.getBaseFrame(). - getTrackingCoordinates(positionM3, stateM3.getFrame(), stateM3.getDate()). - getElevation(); - double delayM3 = model.pathDelay(elevationM3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final TrackingCoordinates trackingCoordinatesM3 = station.getBaseFrame(). + getTrackingCoordinates(positionM3, stateM3.getFrame(), stateM3.getDate()); + double delayM3 = model.pathDelay(trackingCoordinatesM3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), stateM3.getDate()); SpacecraftState stateM2 = shiftState(state, orbitType, angleType, -2 * steps[i], i); final Vector3D positionM2 = stateM2.getPosition(); - final double elevationM2 = station.getBaseFrame(). - getTrackingCoordinates(positionM2, stateM2.getFrame(), stateM2.getDate()). - getElevation(); - double delayM2 = model.pathDelay(elevationM2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final TrackingCoordinates trackingCoordinatesM2 = station.getBaseFrame(). + getTrackingCoordinates(positionM2, stateM2.getFrame(), stateM2.getDate()); + double delayM2 = model.pathDelay(trackingCoordinatesM2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), stateM2.getDate()); SpacecraftState stateM1 = shiftState(state, orbitType, angleType, -1 * steps[i], i); final Vector3D positionM1 = stateM1.getPosition(); - final double elevationM1 = station.getBaseFrame(). - getTrackingCoordinates(positionM1, stateM1.getFrame(), stateM1.getDate()). - getElevation(); - double delayM1 = model.pathDelay(elevationM1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final TrackingCoordinates trackingCoordinatesM1 = station.getBaseFrame(). + getTrackingCoordinates(positionM1, stateM1.getFrame(), stateM1.getDate()); + double delayM1 = model.pathDelay(trackingCoordinatesM1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), stateM1.getDate()); SpacecraftState stateP1 = shiftState(state, orbitType, angleType, 1 * steps[i], i); final Vector3D positionP1 = stateP1.getPosition(); - final double elevationP1 = station.getBaseFrame(). - getTrackingCoordinates(positionP1, stateP1.getFrame(), stateP1.getDate()). - getElevation(); - double delayP1 = model.pathDelay(elevationP1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final TrackingCoordinates trackingCoordinatesP1 = station.getBaseFrame(). + getTrackingCoordinates(positionP1, stateP1.getFrame(), stateP1.getDate()); + double delayP1 = model.pathDelay(trackingCoordinatesP1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), stateP1.getDate()); SpacecraftState stateP2 = shiftState(state, orbitType, angleType, 2 * steps[i], i); final Vector3D positionP2 = stateP2.getPosition(); - final double elevationP2 = station.getBaseFrame(). - getTrackingCoordinates(positionP2, stateP2.getFrame(), stateP2.getDate()). - getElevation(); - double delayP2 = model.pathDelay(elevationP2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final TrackingCoordinates trackingCoordinatesP2 = station.getBaseFrame(). + getTrackingCoordinates(positionP2, stateP2.getFrame(), stateP2.getDate()); + double delayP2 = model.pathDelay(trackingCoordinatesP2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), stateP2.getDate()); SpacecraftState stateP3 = shiftState(state, orbitType, angleType, 3 * steps[i], i); final Vector3D positionP3 = stateP3.getPosition(); - final double elevationP3 = station.getBaseFrame(). - getTrackingCoordinates(positionP3, stateP3.getFrame(), stateP3.getDate()). - getElevation(); - double delayP3 = model.pathDelay(elevationP3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final TrackingCoordinates trackingCoordinatesP3 = station.getBaseFrame(). + getTrackingCoordinates(positionP3, stateP3.getFrame(), stateP3.getDate()); + double delayP3 = model.pathDelay(trackingCoordinatesP3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), stateP3.getDate()); SpacecraftState stateP4 = shiftState(state, orbitType, angleType, 4 * steps[i], i); final Vector3D positionP4 = stateP4.getPosition(); - final double elevationP4 = station.getBaseFrame(). - getTrackingCoordinates(positionP4, stateP4.getFrame(), stateP4.getDate()). - getElevation(); - double delayP4 = model.pathDelay(elevationP4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final TrackingCoordinates trackingCoordinatesP4 = station.getBaseFrame(). + getTrackingCoordinates(positionP4, stateP4.getFrame(), stateP4.getDate()); + double delayP4 = model.pathDelay(trackingCoordinatesP4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), stateP4.getDate()); fillJacobianColumn(refDeriv, i, orbitType, angleType, steps[i], @@ -325,7 +322,8 @@ private void doTestParametersDerivatives(String parameterName, double tolerance) // Initial satellite elevation final FieldVector3D position = dsState.getPosition(); - final DerivativeStructure dsElevation = baseFrame.getTrackingCoordinates(position, frame, dsState.getDate()).getElevation(); + final FieldTrackingCoordinates dsTrackingCoordinates = + baseFrame.getTrackingCoordinates(position, frame, dsState.getDate()); // Add parameter as a variable final List drivers = model.getParametersDrivers(); @@ -339,7 +337,7 @@ private void doTestParametersDerivatives(String parameterName, double tolerance) // Compute delay state derivatives final FieldGeodeticPoint dsPoint = new FieldGeodeticPoint<>(zero.add(point.getLatitude()), zero.add(point.getLongitude()), zero.add(point.getAltitude())); - final DerivativeStructure delay = model.pathDelay(dsElevation, dsPoint, + final DerivativeStructure delay = model.pathDelay(dsTrackingCoordinates, dsPoint, new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), parameters, dsState.getDate()); @@ -347,7 +345,9 @@ private void doTestParametersDerivatives(String parameterName, double tolerance) // Field -> non-field final SpacecraftState state = dsState.toSpacecraftState(); - final double elevation = dsElevation.getReal(); + final TrackingCoordinates trackingCoordinates = new TrackingCoordinates(dsTrackingCoordinates.getAzimuth().getReal(), + dsTrackingCoordinates.getElevation().getReal(), + dsTrackingCoordinates.getRange().getReal()); // Finite differences for reference values final double[][] refDeriv = new double[1][1]; @@ -368,35 +368,35 @@ private void doTestParametersDerivatives(String parameterName, double tolerance) final PositionAngleType angleType = PositionAngleType.MEAN; selected.setValue(p0 - 4 * h); - double delayM4 = model.pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + double delayM4 = model.pathDelay(trackingCoordinates, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), state.getDate()); selected.setValue(p0 - 3 * h); - double delayM3 = model.pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + double delayM3 = model.pathDelay(trackingCoordinates, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), state.getDate()); selected.setValue(p0 - 2 * h); - double delayM2 = model.pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + double delayM2 = model.pathDelay(trackingCoordinates, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), state.getDate()); selected.setValue(p0 - 1 * h); - double delayM1 = model.pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + double delayM1 = model.pathDelay(trackingCoordinates, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), state.getDate()); selected.setValue(p0 + 1 * h); - double delayP1 = model.pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + double delayP1 = model.pathDelay(trackingCoordinates, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), state.getDate()); selected.setValue(p0 + 2 * h); - double delayP2 = model.pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + double delayP2 = model.pathDelay(trackingCoordinates, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), state.getDate()); selected.setValue(p0 + 3 * h); - double delayP3 = model.pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + double delayP3 = model.pathDelay(trackingCoordinates, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), state.getDate()); selected.setValue(p0 + 4 * h); - double delayP4 = model.pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + double delayP4 = model.pathDelay(trackingCoordinates, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), state.getDate()); fillJacobianColumn(refDeriv, 0, orbitType, angleType, h, diff --git a/src/test/java/org/orekit/models/earth/troposphere/FieldGlobalMappingFunctionModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/FieldGlobalMappingFunctionModelTest.java index 6aa21e000d..0f2bcf4825 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/FieldGlobalMappingFunctionModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/FieldGlobalMappingFunctionModelTest.java @@ -53,7 +53,9 @@ import org.orekit.time.FieldAbsoluteDate; import org.orekit.time.TimeScalesFactory; import org.orekit.utils.Constants; +import org.orekit.utils.FieldTrackingCoordinates; import org.orekit.utils.IERSConventions; +import org.orekit.utils.TrackingCoordinates; public class FieldGlobalMappingFunctionModelTest { @@ -93,7 +95,10 @@ private > void doTestMappingFactors(final Fiel final double height = 844.715; final FieldGeodeticPoint point = new FieldGeodeticPoint(zero.add(latitude), zero.add(longitude), zero.add(height)); - final double elevation = 0.5 * FastMath.PI - 1.278564131; + final FieldTrackingCoordinates trackingCoordinates = + new FieldTrackingCoordinates<>(zero, + zero.newInstance(0.5 * FastMath.PI - 1.278564131), + zero); final double expectedHydro = 3.425246; final double expectedWet = 3.449589; @@ -102,7 +107,7 @@ private > void doTestMappingFactors(final Fiel new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE); - final T[] computedMapping = model.mappingFactors(zero.add(elevation), point, weather, date); + final T[] computedMapping = model.mappingFactors(trackingCoordinates, point, weather, date); Assertions.assertEquals(expectedHydro, computedMapping[0].getReal(), 1.0e-6); Assertions.assertEquals(expectedWet, computedMapping[1].getReal(), 1.0e-6); @@ -127,7 +132,10 @@ private > void doTestFixedHeight(final Field(zero, + zero.newInstance(FastMath.toRadians(elev)), + zero), + point, weather, date); Assertions.assertTrue(Precision.compareTo(factors[0].getReal(), lastFactors[0].getReal(), 1.0e-6) < 0); Assertions.assertTrue(Precision.compareTo(factors[1].getReal(), lastFactors[1].getReal(), 1.0e-6) < 0); lastFactors[0] = factors[0]; @@ -184,11 +192,12 @@ public void testMFStateDerivatives() { // Initial satellite elevation final FieldVector3D position = dsState.getPosition(); - final DerivativeStructure dsElevation = baseFrame.getTrackingCoordinates(position, frame, dsDate).getElevation(); + final FieldTrackingCoordinates dsTrackingCoordinates = + baseFrame.getTrackingCoordinates(position, frame, dsDate); // Compute mapping factors state derivatives final FieldGeodeticPoint dsPoint = new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), zero.add(height)); - final DerivativeStructure[] factors = model.mappingFactors(dsElevation, dsPoint, weather, dsDate); + final DerivativeStructure[] factors = model.mappingFactors(dsTrackingCoordinates, dsPoint, weather, dsDate); final double[] compMFH = factors[0].getAllDerivatives(); final double[] compMFW = factors[1].getAllDerivatives(); @@ -206,73 +215,65 @@ public void testMFStateDerivatives() { for (int i = 0; i < 6; i++) { SpacecraftState stateM4 = shiftState(state, orbitType, angleType, -4 * steps[i], i); final Vector3D positionM4 = stateM4.getPosition(); - final double elevationM4 = station.getBaseFrame(). - getTrackingCoordinates(positionM4, stateM4.getFrame(), stateM4.getDate()). - getElevation(); - double[] delayM4 = model.mappingFactors(elevationM4, point, + final TrackingCoordinates trackingCoordinatesM4 = station.getBaseFrame(). + getTrackingCoordinates(positionM4, stateM4.getFrame(), stateM4.getDate()); + double[] delayM4 = model.mappingFactors(trackingCoordinatesM4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, stateM4.getDate()); SpacecraftState stateM3 = shiftState(state, orbitType, angleType, -3 * steps[i], i); final Vector3D positionM3 = stateM3.getPosition(); - final double elevationM3 = station.getBaseFrame(). - getTrackingCoordinates(positionM3, stateM3.getFrame(), stateM3.getDate()). - getElevation(); - double[] delayM3 = model.mappingFactors(elevationM3, point, + final TrackingCoordinates trackingCoordinatesM3 = station.getBaseFrame(). + getTrackingCoordinates(positionM3, stateM3.getFrame(), stateM3.getDate()); + double[] delayM3 = model.mappingFactors(trackingCoordinatesM3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, stateM3.getDate()); SpacecraftState stateM2 = shiftState(state, orbitType, angleType, -2 * steps[i], i); final Vector3D positionM2 = stateM2.getPosition(); - final double elevationM2 = station.getBaseFrame(). - getTrackingCoordinates(positionM2, stateM2.getFrame(), stateM2.getDate()). - getElevation(); - double[] delayM2 = model.mappingFactors(elevationM2, point, + final TrackingCoordinates trackingCoordinatesM2 = station.getBaseFrame(). + getTrackingCoordinates(positionM2, stateM2.getFrame(), stateM2.getDate()); + double[] delayM2 = model.mappingFactors(trackingCoordinatesM2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, stateM2.getDate()); SpacecraftState stateM1 = shiftState(state, orbitType, angleType, -1 * steps[i], i); final Vector3D positionM1 = stateM1.getPosition(); - final double elevationM1 = station.getBaseFrame(). - getTrackingCoordinates(positionM1, stateM1.getFrame(), stateM1.getDate()). - getElevation(); - double[] delayM1 = model.mappingFactors(elevationM1, point, + final TrackingCoordinates trackingCoordinatesM1 = station.getBaseFrame(). + getTrackingCoordinates(positionM1, stateM1.getFrame(), stateM1.getDate()); + double[] delayM1 = model.mappingFactors(trackingCoordinatesM1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, stateM1.getDate()); SpacecraftState stateP1 = shiftState(state, orbitType, angleType, 1 * steps[i], i); final Vector3D positionP1 = stateP1.getPosition(); - final double elevationP1 = station.getBaseFrame(). - getTrackingCoordinates(positionP1, stateP1.getFrame(), stateP1.getDate()). - getElevation(); - double[] delayP1 = model.mappingFactors(elevationP1, point, + final TrackingCoordinates trackingCoordinatesP1 = station.getBaseFrame(). + getTrackingCoordinates(positionP1, stateP1.getFrame(), stateP1.getDate()); + double[] delayP1 = model.mappingFactors(trackingCoordinatesP1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, stateP1.getDate()); SpacecraftState stateP2 = shiftState(state, orbitType, angleType, 2 * steps[i], i); final Vector3D positionP2 = stateP2.getPosition(); - final double elevationP2 = station.getBaseFrame(). - getTrackingCoordinates(positionP2, stateP2.getFrame(), stateP2.getDate()). - getElevation(); - double[] delayP2 = model.mappingFactors(elevationP2, point, + final TrackingCoordinates trackingCoordinatesP2 = station.getBaseFrame(). + getTrackingCoordinates(positionP2, stateP2.getFrame(), stateP2.getDate()); + double[] delayP2 = model.mappingFactors(trackingCoordinatesP2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, stateP2.getDate()); SpacecraftState stateP3 = shiftState(state, orbitType, angleType, 3 * steps[i], i); final Vector3D positionP3 = stateP3.getPosition(); - final double elevationP3 = station.getBaseFrame(). - getTrackingCoordinates(positionP3, stateP3.getFrame(), stateP3.getDate()). - getElevation(); - double[] delayP3 = model.mappingFactors(elevationP3, point, + final TrackingCoordinates trackingCoordinatesP3 = station.getBaseFrame(). + getTrackingCoordinates(positionP3, stateP3.getFrame(), stateP3.getDate()); + double[] delayP3 = model.mappingFactors(trackingCoordinatesP3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, stateP3.getDate()); SpacecraftState stateP4 = shiftState(state, orbitType, angleType, 4 * steps[i], i); final Vector3D positionP4 = stateP4.getPosition(); - final double elevationP4 = station.getBaseFrame(). - getTrackingCoordinates(positionP4, stateP4.getFrame(), stateP4.getDate()). - getElevation(); - double[] delayP4 = model.mappingFactors(elevationP4, point, + final TrackingCoordinates trackingCoordinatesP4 = station.getBaseFrame(). + getTrackingCoordinates(positionP4, stateP4.getFrame(), stateP4.getDate()); + double[] delayP4 = model.mappingFactors(trackingCoordinatesP4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, stateP4.getDate()); diff --git a/src/test/java/org/orekit/models/earth/troposphere/FieldMendesPavlisModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/FieldMendesPavlisModelTest.java index 15b5f1f333..9c99233ebf 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/FieldMendesPavlisModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/FieldMendesPavlisModelTest.java @@ -55,7 +55,9 @@ import org.orekit.time.FieldAbsoluteDate; import org.orekit.time.TimeScalesFactory; import org.orekit.utils.Constants; +import org.orekit.utils.FieldTrackingCoordinates; import org.orekit.utils.IERSConventions; +import org.orekit.utils.TrackingCoordinates; public class FieldMendesPavlisModelTest { @@ -168,7 +170,9 @@ private > void doTestMappingFactors(final Fiel final double lambda = 0.532; final FieldGeodeticPoint point = new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), zero.add(height)); - final double elevation = FastMath.toRadians(15.0); + final FieldTrackingCoordinates trackingCoordinates = new FieldTrackingCoordinates<>(zero, + zero.newInstance(FastMath.toRadians(15.0)), + zero); // Expected mapping factor: 3.80024367 (Ref) final double expectedMapping = 3.80024367; @@ -176,7 +180,7 @@ private > void doTestMappingFactors(final Fiel final MendesPavlisModel model = new MendesPavlisModel(new ConstantPressureTemperatureHumidityProvider(pth), lambda, TroposphericModelUtils.MICRO_M); - final T[] computedMapping = model.mappingFactors(zero.add(elevation), point, + final T[] computedMapping = model.mappingFactors(trackingCoordinates, point, new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), date); @@ -197,7 +201,10 @@ private > void doTestDelay(final Field fiel final FieldAbsoluteDate date = new FieldAbsoluteDate<>(field); final FieldGeodeticPoint point = new FieldGeodeticPoint<>(zero.add(FastMath.toRadians(45.0)), zero.add(FastMath.toRadians(45.0)), zero.add(height)); MendesPavlisModel model = MendesPavlisModel.getStandardModel(0.6943, TroposphericModelUtils.MICRO_M); - final T path = model.pathDelay(zero.add(FastMath.toRadians(elevation)), point, + final T path = model.pathDelay(new FieldTrackingCoordinates<>(zero, + zero.newInstance(FastMath.toRadians(elevation)), + zero), + point, new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), model.getParameters(field), date); Assertions.assertTrue(Precision.compareTo(path.getReal(), 20d, epsilon) < 0); @@ -217,7 +224,10 @@ private > void doTestFixedHeight(final Field(zero, + zero.newInstance(FastMath.toRadians(elev)), + zero), + point, new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), model.getParameters(field), date); Assertions.assertTrue(Precision.compareTo(delay.getReal(), lastDelay.getReal(), epsilon) < 0); @@ -270,11 +280,12 @@ public void testDelayStateDerivatives() { // Initial satellite elevation final FieldVector3D position = dsState.getPosition(); - final DerivativeStructure dsElevation = baseFrame.getTrackingCoordinates(position, frame, dsDate).getElevation(); + final FieldTrackingCoordinates dsTrackingCoordinates = + baseFrame.getTrackingCoordinates(position, frame, dsDate); // Compute Delay with state derivatives final FieldGeodeticPoint dsPoint = new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), zero.add(height)); - final DerivativeStructure delay = model.pathDelay(dsElevation, dsPoint, + final DerivativeStructure delay = model.pathDelay(dsTrackingCoordinates, dsPoint, new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), model.getParameters(field, dsDate), dsDate); @@ -293,66 +304,58 @@ public void testDelayStateDerivatives() { for (int i = 0; i < 6; i++) { SpacecraftState stateM4 = shiftState(state, orbitType, angleType, -4 * steps[i], i); final Vector3D positionM4 = stateM4.getPosition(); - final double elevationM4 = station.getBaseFrame(). - getTrackingCoordinates(positionM4, stateM4.getFrame(), stateM4.getDate()). - getElevation(); - double delayM4 = model.pathDelay(elevationM4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final TrackingCoordinates trackingCoordinatesM4 = station.getBaseFrame(). + getTrackingCoordinates(positionM4, stateM4.getFrame(), stateM4.getDate()); + double delayM4 = model.pathDelay(trackingCoordinatesM4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), stateM4.getDate()); SpacecraftState stateM3 = shiftState(state, orbitType, angleType, -3 * steps[i], i); final Vector3D positionM3 = stateM3.getPosition(); - final double elevationM3 = station.getBaseFrame(). - getTrackingCoordinates(positionM3, stateM3.getFrame(), stateM3.getDate()). - getElevation(); - double delayM3 = model.pathDelay(elevationM3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final TrackingCoordinates trackingCoordinatesM3 = station.getBaseFrame(). + getTrackingCoordinates(positionM3, stateM3.getFrame(), stateM3.getDate()); + double delayM3 = model.pathDelay(trackingCoordinatesM3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), stateM3.getDate()); SpacecraftState stateM2 = shiftState(state, orbitType, angleType, -2 * steps[i], i); final Vector3D positionM2 = stateM2.getPosition(); - final double elevationM2 = station.getBaseFrame(). - getTrackingCoordinates(positionM2, stateM2.getFrame(), stateM2.getDate()). - getElevation(); - double delayM2 = model.pathDelay(elevationM2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final TrackingCoordinates trackingCoordinatesM2 = station.getBaseFrame(). + getTrackingCoordinates(positionM2, stateM2.getFrame(), stateM2.getDate()); + double delayM2 = model.pathDelay(trackingCoordinatesM2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), stateM2.getDate()); SpacecraftState stateM1 = shiftState(state, orbitType, angleType, -1 * steps[i], i); final Vector3D positionM1 = stateM1.getPosition(); - final double elevationM1 = station.getBaseFrame(). - getTrackingCoordinates(positionM1, stateM1.getFrame(), stateM1.getDate()). - getElevation(); - double delayM1 = model.pathDelay(elevationM1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final TrackingCoordinates trackingCoordinatesM1 = station.getBaseFrame(). + getTrackingCoordinates(positionM1, stateM1.getFrame(), stateM1.getDate()); + double delayM1 = model.pathDelay(trackingCoordinatesM1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), stateM1.getDate()); SpacecraftState stateP1 = shiftState(state, orbitType, angleType, 1 * steps[i], i); final Vector3D positionP1 = stateP1.getPosition(); - final double elevationP1 = station.getBaseFrame(). - getTrackingCoordinates(positionP1, stateP1.getFrame(), stateP1.getDate()). - getElevation(); - double delayP1 = model.pathDelay(elevationP1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final TrackingCoordinates trackingCoordinatesP1 = station.getBaseFrame(). + getTrackingCoordinates(positionP1, stateP1.getFrame(), stateP1.getDate()); + double delayP1 = model.pathDelay(trackingCoordinatesP1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), stateP1.getDate()); SpacecraftState stateP2 = shiftState(state, orbitType, angleType, 2 * steps[i], i); final Vector3D positionP2 = stateP2.getPosition(); - final double elevationP2 = station.getBaseFrame(). - getTrackingCoordinates(positionP2, stateP2.getFrame(), stateP2.getDate()). - getElevation(); - double delayP2 = model.pathDelay(elevationP2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final TrackingCoordinates trackingCoordinatesP2 = station.getBaseFrame(). + getTrackingCoordinates(positionP2, stateP2.getFrame(), stateP2.getDate()); + double delayP2 = model.pathDelay(trackingCoordinatesP2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), stateP2.getDate()); SpacecraftState stateP3 = shiftState(state, orbitType, angleType, 3 * steps[i], i); final Vector3D positionP3 = stateP3.getPosition(); - final double elevationP3 = station.getBaseFrame(). - getTrackingCoordinates(positionP3, stateP3.getFrame(), stateP3.getDate()). - getElevation(); - double delayP3 = model.pathDelay(elevationP3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final TrackingCoordinates trackingCoordinatesP3 = station.getBaseFrame(). + getTrackingCoordinates(positionP3, stateP3.getFrame(), stateP3.getDate()); + double delayP3 = model.pathDelay(trackingCoordinatesP3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), stateP3.getDate()); SpacecraftState stateP4 = shiftState(state, orbitType, angleType, 4 * steps[i], i); final Vector3D positionP4 = stateP4.getPosition(); - final double elevationP4 = station.getBaseFrame(). - getTrackingCoordinates(positionP4, stateP4.getFrame(), stateP4.getDate()). - getElevation(); - double delayP4 = model.pathDelay(elevationP4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final TrackingCoordinates trackingCoordinatesP4 = station.getBaseFrame(). + getTrackingCoordinates(positionP4, stateP4.getFrame(), stateP4.getDate()); + double delayP4 = model.pathDelay(trackingCoordinatesP4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), stateP4.getDate()); fillJacobianColumn(refDeriv, i, orbitType, angleType, steps[i], diff --git a/src/test/java/org/orekit/models/earth/troposphere/FieldViennaOneModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/FieldViennaOneModelTest.java index a928fe214d..aa15214191 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/FieldViennaOneModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/FieldViennaOneModelTest.java @@ -52,7 +52,9 @@ import org.orekit.time.FieldAbsoluteDate; import org.orekit.time.TimeScalesFactory; import org.orekit.utils.Constants; +import org.orekit.utils.FieldTrackingCoordinates; import org.orekit.utils.IERSConventions; +import org.orekit.utils.TrackingCoordinates; public class FieldViennaOneModelTest { @@ -104,7 +106,10 @@ private > void doTestMappingFactors(final Fiel final double longitude = FastMath.toRadians(280.0); final double height = 824.17; - final double elevation = 0.5 * FastMath.PI - 1.278564131; + final FieldTrackingCoordinates trackingCoordinates = + new FieldTrackingCoordinates<>(zero, + zero.newInstance(0.5 * FastMath.PI - 1.278564131), + zero); final double expectedHydro = 3.425088; final double expectedWet = 3.448300; @@ -114,7 +119,7 @@ private > void doTestMappingFactors(final Fiel final FieldGeodeticPoint point = new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), zero.add(height)); final ViennaOneModel model = new ViennaOneModel(a, z); - final T[] computedMapping = model.mappingFactors(zero.add(elevation), point, + final T[] computedMapping = model.mappingFactors(trackingCoordinates, point, new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), date); @@ -137,7 +142,10 @@ private > void doTestDelay(final Field fiel final double[] z = {2.0966, 0.2140}; final FieldGeodeticPoint point = new FieldGeodeticPoint<>(zero.add(FastMath.toRadians(45.0)), zero.add(FastMath.toRadians(45.0)), zero.add(height)); ViennaOneModel model = new ViennaOneModel(a, z); - final T path = model.pathDelay(zero.add(FastMath.toRadians(elevation)), point, + final T path = model.pathDelay(new FieldTrackingCoordinates<>(zero, + zero.newInstance(FastMath.toRadians(elevation)), + zero), + point, new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), model.getParameters(field), date); Assertions.assertTrue(Precision.compareTo(path.getReal(), 20d, epsilon) < 0); @@ -159,7 +167,10 @@ private > void doTestFixedHeight(final Field(zero, + zero.newInstance(FastMath.toRadians(elev)), + zero), + point, new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), model.getParameters(field), date); Assertions.assertTrue(Precision.compareTo(delay.getReal(), lastDelay.getReal(), epsilon) < 0); @@ -215,11 +226,12 @@ public void testDelayStateDerivatives() { // Initial satellite elevation final FieldVector3D position = dsState.getPosition(); - final DerivativeStructure dsElevation = baseFrame.getTrackingCoordinates(position, frame, dsDate).getElevation(); + final FieldTrackingCoordinates dsTrackingCoordinates = + baseFrame.getTrackingCoordinates(position, frame, dsDate); // Compute delay state derivatives final FieldGeodeticPoint dsPoint = new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), zero.add(height)); - final DerivativeStructure delay = model.pathDelay(dsElevation, dsPoint, + final DerivativeStructure delay = model.pathDelay(dsTrackingCoordinates, dsPoint, new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), model.getParameters(field), dsDate); @@ -238,66 +250,58 @@ public void testDelayStateDerivatives() { for (int i = 0; i < 6; i++) { SpacecraftState stateM4 = shiftState(state, orbitType, angleType, -4 * steps[i], i); final Vector3D positionM4 = stateM4.getPosition(); - final double elevationM4 = station.getBaseFrame(). - getTrackingCoordinates(positionM4, stateM4.getFrame(), stateM4.getDate()). - getElevation(); - double delayM4 = model.pathDelay(elevationM4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final TrackingCoordinates trackingCoordinatesM4 = station.getBaseFrame(). + getTrackingCoordinates(positionM4, stateM4.getFrame(), stateM4.getDate()); + double delayM4 = model.pathDelay(trackingCoordinatesM4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), stateM4.getDate()); SpacecraftState stateM3 = shiftState(state, orbitType, angleType, -3 * steps[i], i); final Vector3D positionM3 = stateM3.getPosition(); - final double elevationM3 = station.getBaseFrame(). - getTrackingCoordinates(positionM3, stateM3.getFrame(), stateM3.getDate()). - getElevation(); - double delayM3 = model.pathDelay(elevationM3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final TrackingCoordinates trackingCoordinatesM3 = station.getBaseFrame(). + getTrackingCoordinates(positionM3, stateM3.getFrame(), stateM3.getDate()); + double delayM3 = model.pathDelay(trackingCoordinatesM3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), stateM3.getDate()); SpacecraftState stateM2 = shiftState(state, orbitType, angleType, -2 * steps[i], i); final Vector3D positionM2 = stateM2.getPosition(); - final double elevationM2 = station.getBaseFrame(). - getTrackingCoordinates(positionM2, stateM2.getFrame(), stateM2.getDate()). - getElevation(); - double delayM2 = model.pathDelay(elevationM2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final TrackingCoordinates trackingCoordinatesM2 = station.getBaseFrame(). + getTrackingCoordinates(positionM2, stateM2.getFrame(), stateM2.getDate()); + double delayM2 = model.pathDelay(trackingCoordinatesM2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), stateM2.getDate()); SpacecraftState stateM1 = shiftState(state, orbitType, angleType, -1 * steps[i], i); final Vector3D positionM1 = stateM1.getPosition(); - final double elevationM1 = station.getBaseFrame(). - getTrackingCoordinates(positionM1, stateM1.getFrame(), stateM1.getDate()). - getElevation(); - double delayM1 = model.pathDelay(elevationM1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final TrackingCoordinates trackingCoordinatesM1 = station.getBaseFrame(). + getTrackingCoordinates(positionM1, stateM1.getFrame(), stateM1.getDate()); + double delayM1 = model.pathDelay(trackingCoordinatesM1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), stateM1.getDate()); SpacecraftState stateP1 = shiftState(state, orbitType, angleType, 1 * steps[i], i); final Vector3D positionP1 = stateP1.getPosition(); - final double elevationP1 = station.getBaseFrame(). - getTrackingCoordinates(positionP1, stateP1.getFrame(), stateP1.getDate()). - getElevation(); - double delayP1 = model.pathDelay(elevationP1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final TrackingCoordinates trackingCoordinatesP1 = station.getBaseFrame(). + getTrackingCoordinates(positionP1, stateP1.getFrame(), stateP1.getDate()); + double delayP1 = model.pathDelay(trackingCoordinatesP1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), stateP1.getDate()); SpacecraftState stateP2 = shiftState(state, orbitType, angleType, 2 * steps[i], i); final Vector3D positionP2 = stateP2.getPosition(); - final double elevationP2 = station.getBaseFrame(). - getTrackingCoordinates(positionP2, stateP2.getFrame(), stateP2.getDate()). - getElevation(); - double delayP2 = model.pathDelay(elevationP2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final TrackingCoordinates trackingCoordinatesP2 = station.getBaseFrame(). + getTrackingCoordinates(positionP2, stateP2.getFrame(), stateP2.getDate()); + double delayP2 = model.pathDelay(trackingCoordinatesP2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), stateP2.getDate()); SpacecraftState stateP3 = shiftState(state, orbitType, angleType, 3 * steps[i], i); final Vector3D positionP3 = stateP3.getPosition(); - final double elevationP3 = station.getBaseFrame(). - getTrackingCoordinates(positionP3, stateP3.getFrame(), stateP3.getDate()). - getElevation(); - double delayP3 = model.pathDelay(elevationP3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final TrackingCoordinates trackingCoordinatesP3 = station.getBaseFrame(). + getTrackingCoordinates(positionP3, stateP3.getFrame(), stateP3.getDate()); + double delayP3 = model.pathDelay(trackingCoordinatesP3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), stateP3.getDate()); SpacecraftState stateP4 = shiftState(state, orbitType, angleType, 4 * steps[i], i); final Vector3D positionP4 = stateP4.getPosition(); - final double elevationP4 = station.getBaseFrame(). - getTrackingCoordinates(positionP4, stateP4.getFrame(), stateP4.getDate()). - getElevation(); - double delayP4 = model.pathDelay(elevationP4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final TrackingCoordinates trackingCoordinatesP4 = station.getBaseFrame(). + getTrackingCoordinates(positionP4, stateP4.getFrame(), stateP4.getDate()); + double delayP4 = model.pathDelay(trackingCoordinatesP4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), stateP4.getDate()); fillJacobianColumn(refDeriv, i, orbitType, angleType, steps[i], diff --git a/src/test/java/org/orekit/models/earth/troposphere/FieldViennaThreeModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/FieldViennaThreeModelTest.java index 8cdd6d5cce..5ddd0bf6a5 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/FieldViennaThreeModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/FieldViennaThreeModelTest.java @@ -52,7 +52,9 @@ import org.orekit.time.FieldAbsoluteDate; import org.orekit.time.TimeScalesFactory; import org.orekit.utils.Constants; +import org.orekit.utils.FieldTrackingCoordinates; import org.orekit.utils.IERSConventions; +import org.orekit.utils.TrackingCoordinates; public class FieldViennaThreeModelTest { @@ -103,7 +105,8 @@ private > void doTestMappingFactors(final Fiel final double longitude = FastMath.toRadians(277.5); final double height = 824.0; - final double elevation = FastMath.toRadians(38.0); + final FieldTrackingCoordinates trackingCoordinates = + new FieldTrackingCoordinates(zero, zero.newInstance(FastMath.toRadians(38.0)), zero); final double expectedHydro = 1.621024; final double expectedWet = 1.623023; @@ -114,7 +117,7 @@ private > void doTestMappingFactors(final Fiel final ViennaThreeModel model = new ViennaThreeModel(a, z); - final T[] computedMapping = model.mappingFactors(zero.add(elevation), point, + final T[] computedMapping = model.mappingFactors(trackingCoordinates, point, new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), date); @@ -169,7 +172,8 @@ private > void doTestLowElevation(final Field< final ViennaThreeModel model = new ViennaThreeModel(a, z); - final T[] computedMapping = model.mappingFactors(zero.add(elevation), point, + final T[] computedMapping = model.mappingFactors(new FieldTrackingCoordinates(zero, zero.newInstance(elevation), zero), + point, new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), date); @@ -224,7 +228,8 @@ private > void doTestHightElevation(final Fiel final ViennaThreeModel model = new ViennaThreeModel(a, z); - final T[] computedMapping = model.mappingFactors(zero.add(elevation), point, + final T[] computedMapping = model.mappingFactors(new FieldTrackingCoordinates(zero, zero.newInstance(elevation), zero), + point, new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), date); @@ -247,7 +252,8 @@ private > void doTestDelay(final Field fiel final double[] z = {2.1993, 0.0690}; final FieldGeodeticPoint point = new FieldGeodeticPoint<>(zero.add(FastMath.toRadians(37.5)), zero.add(FastMath.toRadians(277.5)), zero.add(height)); ViennaThreeModel model = new ViennaThreeModel(a, z); - final T path = model.pathDelay(zero.add(FastMath.toRadians(elevation)), point, + final T path = model.pathDelay(new FieldTrackingCoordinates(zero, zero.newInstance(FastMath.toRadians(elevation)), zero), + point, new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), model.getParameters(field), date); Assertions.assertTrue(Precision.compareTo(path.getReal(), 20d, epsilon) < 0); @@ -269,7 +275,8 @@ private > void doTestFixedHeight(final Field(zero, zero.newInstance(FastMath.toRadians(elev)), zero), + point, new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), model.getParameters(field), date); Assertions.assertTrue(Precision.compareTo(delay.getReal(), lastDelay.getReal(), epsilon) < 0); @@ -325,11 +332,12 @@ public void testDelayStateDerivatives() { // Initial satellite elevation final FieldVector3D position = dsState.getPosition(); - final DerivativeStructure dsElevation = baseFrame.getTrackingCoordinates(position, frame, dsDate).getElevation(); + final FieldTrackingCoordinates dsTrackingCoordinates = + baseFrame.getTrackingCoordinates(position, frame, dsDate); // Compute delay state derivatives final FieldGeodeticPoint dsPoint = new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), zero.add(height)); - final DerivativeStructure delay = model.pathDelay(dsElevation, dsPoint, + final DerivativeStructure delay = model.pathDelay(dsTrackingCoordinates, dsPoint, new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), model.getParameters(field), dsDate); @@ -348,66 +356,58 @@ public void testDelayStateDerivatives() { for (int i = 0; i < 6; i++) { SpacecraftState stateM4 = shiftState(state, orbitType, angleType, -4 * steps[i], i); final Vector3D positionM4 = stateM4.getPosition(); - final double elevationM4 = station.getBaseFrame(). - getTrackingCoordinates(positionM4, stateM4.getFrame(), stateM4.getDate()). - getElevation(); - double delayM4 = model.pathDelay(elevationM4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final TrackingCoordinates trackingCoordinatesM4 = station.getBaseFrame(). + getTrackingCoordinates(positionM4, stateM4.getFrame(), stateM4.getDate()); + double delayM4 = model.pathDelay(trackingCoordinatesM4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), stateM4.getDate()); SpacecraftState stateM3 = shiftState(state, orbitType, angleType, -3 * steps[i], i); final Vector3D positionM3 = stateM3.getPosition(); - final double elevationM3 = station.getBaseFrame(). - getTrackingCoordinates(positionM3, stateM3.getFrame(), stateM3.getDate()). - getElevation(); - double delayM3 = model.pathDelay(elevationM3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final TrackingCoordinates trackingCoordinatesM3 = station.getBaseFrame(). + getTrackingCoordinates(positionM3, stateM3.getFrame(), stateM3.getDate()); + double delayM3 = model.pathDelay(trackingCoordinatesM3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), stateM3.getDate()); SpacecraftState stateM2 = shiftState(state, orbitType, angleType, -2 * steps[i], i); final Vector3D positionM2 = stateM2.getPosition(); - final double elevationM2 = station.getBaseFrame(). - getTrackingCoordinates(positionM2, stateM2.getFrame(), stateM2.getDate()). - getElevation(); - double delayM2 = model.pathDelay(elevationM2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final TrackingCoordinates trackingCoordinatesM2 = station.getBaseFrame(). + getTrackingCoordinates(positionM2, stateM2.getFrame(), stateM2.getDate()); + double delayM2 = model.pathDelay(trackingCoordinatesM2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), stateM2.getDate()); SpacecraftState stateM1 = shiftState(state, orbitType, angleType, -1 * steps[i], i); final Vector3D positionM1 = stateM1.getPosition(); - final double elevationM1 = station.getBaseFrame(). - getTrackingCoordinates(positionM1, stateM1.getFrame(), stateM1.getDate()). - getElevation(); - double delayM1 = model.pathDelay(elevationM1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final TrackingCoordinates trackingCoordinatesM1 = station.getBaseFrame(). + getTrackingCoordinates(positionM1, stateM1.getFrame(), stateM1.getDate()); + double delayM1 = model.pathDelay(trackingCoordinatesM1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), stateM1.getDate()); SpacecraftState stateP1 = shiftState(state, orbitType, angleType, 1 * steps[i], i); final Vector3D positionP1 = stateP1.getPosition(); - final double elevationP1 = station.getBaseFrame(). - getTrackingCoordinates(positionP1, stateP1.getFrame(), stateP1.getDate()). - getElevation(); - double delayP1 = model.pathDelay(elevationP1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final TrackingCoordinates trackingCoordinatesP1 = station.getBaseFrame(). + getTrackingCoordinates(positionP1, stateP1.getFrame(), stateP1.getDate()); + double delayP1 = model.pathDelay(trackingCoordinatesP1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), stateP1.getDate()); SpacecraftState stateP2 = shiftState(state, orbitType, angleType, 2 * steps[i], i); final Vector3D positionP2 = stateP2.getPosition(); - final double elevationP2 = station.getBaseFrame(). - getTrackingCoordinates(positionP2, stateP2.getFrame(), stateP2.getDate()). - getElevation(); - double delayP2 = model.pathDelay(elevationP2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final TrackingCoordinates trackingCoordinatesP2 = station.getBaseFrame(). + getTrackingCoordinates(positionP2, stateP2.getFrame(), stateP2.getDate()); + double delayP2 = model.pathDelay(trackingCoordinatesP2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), stateP2.getDate()); SpacecraftState stateP3 = shiftState(state, orbitType, angleType, 3 * steps[i], i); final Vector3D positionP3 = stateP3.getPosition(); - final double elevationP3 = station.getBaseFrame(). - getTrackingCoordinates(positionP3, stateP3.getFrame(), stateP3.getDate()). - getElevation(); - double delayP3 = model.pathDelay(elevationP3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final TrackingCoordinates trackingCoordinatesP3 = station.getBaseFrame(). + getTrackingCoordinates(positionP3, stateP3.getFrame(), stateP3.getDate()); + double delayP3 = model.pathDelay(trackingCoordinatesP3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), stateP3.getDate()); SpacecraftState stateP4 = shiftState(state, orbitType, angleType, 4 * steps[i], i); final Vector3D positionP4 = stateP4.getPosition(); - final double elevationP4 = station.getBaseFrame(). - getTrackingCoordinates(positionP4, stateP4.getFrame(), stateP4.getDate()). - getElevation(); - double delayP4 = model.pathDelay(elevationP4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final TrackingCoordinates trackingCoordinatesP4 = station.getBaseFrame(). + getTrackingCoordinates(positionP4, stateP4.getFrame(), stateP4.getDate()); + double delayP4 = model.pathDelay(trackingCoordinatesP4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), stateP4.getDate()); fillJacobianColumn(refDeriv, i, orbitType, angleType, steps[i], diff --git a/src/test/java/org/orekit/models/earth/troposphere/FixedTroposphericModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/FixedTroposphericModelTest.java index 7c1cbc7817..16c2b75b01 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/FixedTroposphericModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/FixedTroposphericModelTest.java @@ -31,6 +31,8 @@ import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; +import org.orekit.utils.FieldTrackingCoordinates; +import org.orekit.utils.TrackingCoordinates; public class FixedTroposphericModelTest { @@ -41,32 +43,39 @@ public class FixedTroposphericModelTest { @Test public void testModel() { // check with (artificial) test values from tropospheric-delay.txt - Assertions.assertEquals(2.5d, model.pathDelay(FastMath.toRadians(90d), new GeodeticPoint(0., 0., 0.), + Assertions.assertEquals(2.5d, model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(90d), 0.0), + new GeodeticPoint(0., 0., 0.), TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH), epsilon); - Assertions.assertEquals(20.8d, model.pathDelay(FastMath.toRadians(0d), new GeodeticPoint(0., 0., 0.), + Assertions.assertEquals(20.8d, model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(0d), 0.0), + new GeodeticPoint(0., 0., 0.), TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH), epsilon); - Assertions.assertEquals(12.1d, model.pathDelay(FastMath.toRadians(0d), new GeodeticPoint(0., 0., 5000.), + Assertions.assertEquals(12.1d, model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(0d), 0.0), + new GeodeticPoint(0., 0., 5000.), TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH), epsilon); - Assertions.assertEquals(2.5d, model.pathDelay(FastMath.toRadians(90d), new GeodeticPoint(0., 0., 5000.), + Assertions.assertEquals(2.5d, model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(90d), 0.0), + new GeodeticPoint(0., 0., 5000.), TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH), epsilon); // interpolation between two elevation angles in the table - final double delay = model.pathDelay(FastMath.toRadians(35d), new GeodeticPoint(0., 0., 1200.), + final double delay = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(35d), 0.0), + new GeodeticPoint(0., 0., 1200.), TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH); Assertions.assertTrue(Precision.compareTo(delay, 6.4d, epsilon) < 0); Assertions.assertTrue(Precision.compareTo(delay, 3.2d, epsilon) > 0); // sanity checks - Assertions.assertEquals(12.1d, model.pathDelay(FastMath.toRadians(-20d), new GeodeticPoint(0., 0., 5000.), + Assertions.assertEquals(12.1d, model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(-20d), 0.0), + new GeodeticPoint(0., 0., 5000.), TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH), epsilon); - Assertions.assertEquals(2.5d, model.pathDelay(FastMath.toRadians(90d), new GeodeticPoint(0., 0., 100000.), + Assertions.assertEquals(2.5d, model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(90d),0.0), + new GeodeticPoint(0., 0., 100000.), TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH), epsilon); } @@ -79,32 +88,39 @@ public void testFieldModel() { private > void doTestFieldModel(final Field field) { final T zero = field.getZero(); // check with (artificial) test values from tropospheric-delay.txt - Assertions.assertEquals(2.5d, model.pathDelay(zero.add(FastMath.toRadians(90d)), new FieldGeodeticPoint(zero, zero, zero), + Assertions.assertEquals(2.5d, model.pathDelay(new FieldTrackingCoordinates<>(zero, zero.newInstance(FastMath.toRadians(90d)), zero), + new FieldGeodeticPoint(zero, zero, zero), new FieldPressureTemperatureHumidity(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), epsilon); - Assertions.assertEquals(20.8d, model.pathDelay(zero.add(FastMath.toRadians(0d)), new FieldGeodeticPoint(zero, zero, zero), + Assertions.assertEquals(20.8d, model.pathDelay(new FieldTrackingCoordinates<>(zero, zero.newInstance(FastMath.toRadians(0d)), zero), + new FieldGeodeticPoint(zero, zero, zero), new FieldPressureTemperatureHumidity(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), epsilon); - Assertions.assertEquals(12.1d, model.pathDelay(zero.add(FastMath.toRadians(0d)), new FieldGeodeticPoint(zero, zero, zero.add(5000.0)), + Assertions.assertEquals(12.1d, model.pathDelay(new FieldTrackingCoordinates<>(zero, zero.newInstance(FastMath.toRadians(0d)), zero), + new FieldGeodeticPoint(zero, zero, zero.add(5000.0)), new FieldPressureTemperatureHumidity(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), epsilon); - Assertions.assertEquals(2.5d, model.pathDelay(zero.add(FastMath.toRadians(90d)), new FieldGeodeticPoint(zero, zero, zero.add(5000.0)), + Assertions.assertEquals(2.5d, model.pathDelay(new FieldTrackingCoordinates<>(zero, zero.newInstance(FastMath.toRadians(90d)), zero), + new FieldGeodeticPoint(zero, zero, zero.add(5000.0)), new FieldPressureTemperatureHumidity(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), epsilon); // interpolation between two elevation angles in the table - final double delay = model.pathDelay(zero.add(FastMath.toRadians(35d)), new FieldGeodeticPoint(zero, zero, zero.add(1200.0)), + final double delay = model.pathDelay(new FieldTrackingCoordinates<>(zero, zero.newInstance(FastMath.toRadians(35d)), zero), + new FieldGeodeticPoint(zero, zero, zero.add(1200.0)), new FieldPressureTemperatureHumidity(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(); Assertions.assertTrue(Precision.compareTo(delay, 6.4d, epsilon) < 0); Assertions.assertTrue(Precision.compareTo(delay, 3.2d, epsilon) > 0); // sanity checks - Assertions.assertEquals(12.1d, model.pathDelay(zero.add(FastMath.toRadians(-20d)), new FieldGeodeticPoint(zero, zero, zero.add(5000.0)), + Assertions.assertEquals(12.1d, model.pathDelay(new FieldTrackingCoordinates<>(zero, zero.newInstance(FastMath.toRadians(-20d)), zero), + new FieldGeodeticPoint(zero, zero, zero.add(5000.0)), new FieldPressureTemperatureHumidity(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), epsilon); - Assertions.assertEquals(2.5d, model.pathDelay(zero.add(FastMath.toRadians(90d)), new FieldGeodeticPoint(zero, zero, zero.add(100000.0)), + Assertions.assertEquals(2.5d, model.pathDelay(new FieldTrackingCoordinates<>(zero, zero.newInstance(FastMath.toRadians(90d)), zero), + new FieldGeodeticPoint(zero, zero, zero.add(100000.0)), new FieldPressureTemperatureHumidity(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), epsilon); } @@ -112,9 +128,11 @@ private > void doTestFieldModel(final Field @Test public void testSymmetry() { for (int elevation = 0; elevation < 90; elevation += 10) { - final double delay1 = model.pathDelay(FastMath.toRadians(elevation), new GeodeticPoint(0., 0., 100.), + final double delay1 = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elevation), 0.0), + new GeodeticPoint(0., 0., 100.), TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH); - final double delay2 = model.pathDelay(FastMath.toRadians(180 - elevation), new GeodeticPoint(0., 0., 100.), + final double delay2 = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(180 - elevation), 0.0), + new GeodeticPoint(0., 0., 100.), TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH); Assertions.assertEquals(delay1, delay2, epsilon); @@ -129,12 +147,12 @@ public void testFieldSymmetry() { private > void doTestFieldSymmetry(final Field field) { final T zero = field.getZero(); for (int elevation = 0; elevation < 90; elevation += 10) { - final T delay1 = model.pathDelay(zero.add(FastMath.toRadians(elevation)), + final T delay1 = model.pathDelay(new FieldTrackingCoordinates<>(zero, zero.newInstance(FastMath.toRadians(elevation)), zero), new FieldGeodeticPoint(zero, zero, zero.add(100.)), new FieldPressureTemperatureHumidity(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), null, FieldAbsoluteDate.getJ2000Epoch(field)); - final T delay2 = model.pathDelay(zero.add(FastMath.toRadians(180 - elevation)), + final T delay2 = model.pathDelay(new FieldTrackingCoordinates<>(zero, zero.newInstance(FastMath.toRadians(180 - elevation)), zero), new FieldGeodeticPoint(zero, zero, zero.add(100.)), new FieldPressureTemperatureHumidity(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), null, diff --git a/src/test/java/org/orekit/models/earth/troposphere/GlobalMappingFunctionModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/GlobalMappingFunctionModelTest.java index 83d3e7e1f5..fe536150e7 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/GlobalMappingFunctionModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/GlobalMappingFunctionModelTest.java @@ -27,6 +27,7 @@ import org.orekit.errors.OrekitException; import org.orekit.time.AbsoluteDate; import org.orekit.time.TimeScalesFactory; +import org.orekit.utils.TrackingCoordinates; public class GlobalMappingFunctionModelTest { @@ -62,13 +63,13 @@ public void testMappingFactors() { final double height = 844.715; final GeodeticPoint point = new GeodeticPoint(latitude, longitude, height); - final double elevation = 0.5 * FastMath.PI - 1.278564131; + final TrackingCoordinates trackingCoordinates = new TrackingCoordinates(0.0, 0.5 * FastMath.PI - 1.278564131, 0.0); final double expectedHydro = 3.425246; final double expectedWet = 3.449589; final TroposphereMappingFunction model = new GlobalMappingFunctionModel(); - final double[] computedMapping = model.mappingFactors(elevation, point, + final double[] computedMapping = model.mappingFactors(trackingCoordinates, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, date); @@ -87,7 +88,8 @@ public void testFixedHeight() { GeodeticPoint point = new GeodeticPoint(FastMath.toRadians(45.0), FastMath.toRadians(45.0), 350.0); // mapping functions shall decline with increasing elevation angle for (double elev = 10d; elev < 90d; elev += 8d) { - final double[] factors = model.mappingFactors(FastMath.toRadians(elev), point, + final double[] factors = model.mappingFactors(new TrackingCoordinates(0.0, FastMath.toRadians(elev), 0.0), + point, TroposphericModelUtils.STANDARD_ATMOSPHERE, date); Assertions.assertTrue(Precision.compareTo(factors[0], lastFactors[0], 1.0e-6) < 0); diff --git a/src/test/java/org/orekit/models/earth/troposphere/MariniMurrayModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/MariniMurrayModelTest.java index 982cdbe74c..b40f4025f2 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/MariniMurrayModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/MariniMurrayModelTest.java @@ -31,6 +31,8 @@ import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; +import org.orekit.utils.FieldTrackingCoordinates; +import org.orekit.utils.TrackingCoordinates; public class MariniMurrayModelTest { @@ -58,7 +60,8 @@ public void testDelay() { // ruby laser with wavelength 694.3 nm TroposphericModel model = MariniMurrayModel.getStandardModel(694.3, TroposphericModelUtils.NANO_M); - final double path = model.pathDelay(FastMath.toRadians(elevation), new GeodeticPoint(latitude, longitude, height), + final double path = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elevation), 0.0), + new GeodeticPoint(latitude, longitude, height), TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH); Assertions.assertTrue(Precision.compareTo(path, 20d, epsilon) < 0); @@ -73,7 +76,8 @@ public void testDeprecatedConstructor1() { // ruby laser with wavelength 694.3 nm TroposphericModel model = MariniMurrayModel.getStandardModel(694.3); - final double path = model.pathDelay(FastMath.toRadians(elevation), new GeodeticPoint(latitude, longitude, height), + final double path = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elevation), 0.0), + new GeodeticPoint(latitude, longitude, height), TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH); Assertions.assertTrue(Precision.compareTo(path, 20d, epsilon) < 0); @@ -88,7 +92,8 @@ public void testDeprecatedConstructor2() { // ruby laser with wavelength 694.3 nm TroposphericModel model = new MariniMurrayModel(273.15 + 20, 1013.25, 0.5, 694.3); - final double path = model.pathDelay(FastMath.toRadians(elevation), new GeodeticPoint(latitude, longitude, height), + final double path = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elevation), 0.0), + new GeodeticPoint(latitude, longitude, height), TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH); Assertions.assertTrue(Precision.compareTo(path, 20d, epsilon) < 0); @@ -102,12 +107,15 @@ public void testFieldDelay() { private > void doTestFieldDelay(final Field field) { final T zero = field.getZero(); - final T elevation = zero.add(FastMath.toRadians(10d)); + final FieldTrackingCoordinates trackingCoordinates = + new FieldTrackingCoordinates<>(zero, + zero.newInstance(FastMath.toRadians(10d)), + zero); final T height = zero.add(100d); // ruby laser with wavelength 694.3 nm TroposphericModel model = MariniMurrayModel.getStandardModel(694.3, TroposphericModelUtils.NANO_M); - final T path = model.pathDelay(elevation, new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), height), + final T path = model.pathDelay(trackingCoordinates, new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), height), new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), null, FieldAbsoluteDate.getJ2000Epoch(field)); @@ -122,7 +130,8 @@ public void testFixedHeight() { double lastDelay = Double.MAX_VALUE; // delay shall decline with increasing elevation angle for (double elev = 10d; elev < 90d; elev += 8d) { - final double delay = model.pathDelay(FastMath.toRadians(elev), new GeodeticPoint(latitude, longitude, 350.0), + final double delay = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elev), 0.0), + new GeodeticPoint(latitude, longitude, 350.0), TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH); Assertions.assertTrue(Precision.compareTo(delay, lastDelay, epsilon) < 0); lastDelay = delay; @@ -141,7 +150,8 @@ private > void doTestFieldFixedHeight(final Fi T lastDelay = zero.add(Double.MAX_VALUE); // delay shall decline with increasing elevation angle for (double elev = 10d; elev < 90d; elev += 8d) { - final T delay = model.pathDelay(zero.add(FastMath.toRadians(elev)), new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), zero.add(350.0)), + final T delay = model.pathDelay(new FieldTrackingCoordinates<>(zero, zero.newInstance(FastMath.toRadians(elev)), zero), + new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), zero.add(350.0)), new FieldPressureTemperatureHumidity(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), null, FieldAbsoluteDate.getJ2000Epoch(field)); Assertions.assertTrue(Precision.compareTo(delay.getReal(), lastDelay.getReal(), epsilon) < 0); @@ -158,7 +168,8 @@ public void compareExpectedValues() { double height = 0; double elevation = 10; double expectedValue = 13.26069; - double actualValue = model.pathDelay(FastMath.toRadians(elevation), new GeodeticPoint(latitude, longitude, height), + double actualValue = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elevation), 0.0), + new GeodeticPoint(latitude, longitude, height), TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH); Assertions.assertEquals(expectedValue, actualValue, 1.0e-5); @@ -176,9 +187,10 @@ private > void doCompareFieldExpectedValues(fi T zero = field.getZero(); T height = zero; - T elevation = zero.add(FastMath.toRadians(10)); + T elevation = zero.newInstance(FastMath.toRadians(10)); double expectedValue = 13.26069; - T actualValue = model.pathDelay(elevation, new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), height), + T actualValue = model.pathDelay(new FieldTrackingCoordinates<>(zero, elevation, zero), + new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), height), new FieldPressureTemperatureHumidity(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), null, FieldAbsoluteDate.getJ2000Epoch(field)); diff --git a/src/test/java/org/orekit/models/earth/troposphere/MendesPavlisModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/MendesPavlisModelTest.java index fc80fed82b..ed9778e33a 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/MendesPavlisModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/MendesPavlisModelTest.java @@ -30,6 +30,7 @@ import org.orekit.models.earth.weather.water.CIPM2007; import org.orekit.time.AbsoluteDate; import org.orekit.time.TimeScalesFactory; +import org.orekit.utils.TrackingCoordinates; ; @@ -135,7 +136,7 @@ public void testMappingFactors() { final double lambda = 0.532; final GeodeticPoint point = new GeodeticPoint(latitude, longitude, height); - final double elevation = FastMath.toRadians(15.0); + final TrackingCoordinates trackingCoordinates = new TrackingCoordinates(0.0, FastMath.toRadians(15.0), 0.0); // Expected mapping factor: 3.80024367 (Ref) final double expectedMapping = 3.80024367; @@ -143,7 +144,7 @@ public void testMappingFactors() { final MendesPavlisModel model = new MendesPavlisModel(new ConstantPressureTemperatureHumidityProvider(pth), lambda, TroposphericModelUtils.MICRO_M); - final double[] computedMapping = model.mappingFactors(elevation, point, + final double[] computedMapping = model.mappingFactors(trackingCoordinates, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, date); @@ -158,7 +159,8 @@ public void testDelay() { final AbsoluteDate date = new AbsoluteDate(); final GeodeticPoint point = new GeodeticPoint(FastMath.toRadians(45.0), FastMath.toRadians(45.0), height); MendesPavlisModel model = MendesPavlisModel.getStandardModel( 0.6943, TroposphericModelUtils.MICRO_M); - final double path = model.pathDelay(FastMath.toRadians(elevation), point, + final double path = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elevation), 0.0), + point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), date); Assertions.assertTrue(Precision.compareTo(path, 20d, epsilon) < 0); @@ -173,7 +175,8 @@ public void testFixedHeight() { double lastDelay = Double.MAX_VALUE; // delay shall decline with increasing elevation angle for (double elev = 10d; elev < 90d; elev += 8d) { - final double delay = model.pathDelay(FastMath.toRadians(elev), point, + final double delay = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elev), 0.0), + point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), date); Assertions.assertTrue(Precision.compareTo(delay, lastDelay, epsilon) < 0); diff --git a/src/test/java/org/orekit/models/earth/troposphere/ModifiedHopfieldModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/ModifiedHopfieldModelTest.java index 3b3cc18faf..f489aa201a 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/ModifiedHopfieldModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/ModifiedHopfieldModelTest.java @@ -32,6 +32,8 @@ import org.orekit.models.earth.weather.water.CIPM2007; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; +import org.orekit.utils.FieldTrackingCoordinates; +import org.orekit.utils.TrackingCoordinates; public class ModifiedHopfieldModelTest { @@ -53,7 +55,8 @@ public void testFixedElevation() { double lastDelay = Double.MAX_VALUE; // delay shall decline with increasing height of the station for (double height = 0; height < 5000; height += 100) { - final double delay = model.pathDelay(FastMath.toRadians(5), new GeodeticPoint(0.0, 0.0, height), + final double delay = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(5), 0.0), + new GeodeticPoint(0.0, 0.0, height), converter.convert(TroposphericModelUtils.STANDARD_ATMOSPHERE, height), null, AbsoluteDate.J2000_EPOCH); Assertions.assertTrue(Precision.compareTo(delay, lastDelay, epsilon) < 0); @@ -75,7 +78,10 @@ private > void doTestFieldFixedElevation(final T lastDelay = zero.newInstance(Double.MAX_VALUE); // delay shall decline with increasing height of the station for (double height = 0; height < 5000; height += 100) { - final T delay = model.pathDelay(zero.newInstance(FastMath.toRadians(5)), new FieldGeodeticPoint<>(zero, zero, zero.newInstance(height)), + final T delay = model.pathDelay(new FieldTrackingCoordinates<>(zero, + zero.newInstance(FastMath.toRadians(5)), + zero), + new FieldGeodeticPoint<>(zero, zero, zero.newInstance(height)), converter.convert(new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), zero.newInstance(height)), @@ -92,7 +98,8 @@ public void testFixedHeight() { double lastDelay = Double.MAX_VALUE; // delay shall decline with increasing elevation angle for (double elev = 10d; elev < 90d; elev += 8d) { - final double delay = model.pathDelay(FastMath.toRadians(elev), new GeodeticPoint(0.0, 0.0, 350.0), + final double delay = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elev), 0.0), + new GeodeticPoint(0.0, 0.0, 350.0), TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH); Assertions.assertTrue(Precision.compareTo(delay, lastDelay, epsilon) < 0); @@ -112,7 +119,10 @@ private > void doTestFieldFixedHeight(final Fi T lastDelay = zero.newInstance(Double.MAX_VALUE); // delay shall decline with increasing elevation angle for (double elev = 10d; elev < 90d; elev += 8d) { - final T delay = model.pathDelay(zero.newInstance(FastMath.toRadians(elev)), new FieldGeodeticPoint<>(zero, zero, zero.newInstance(350.0)), + final T delay = model.pathDelay(new FieldTrackingCoordinates<>(zero, + zero.newInstance(FastMath.toRadians(elev)), + zero), + new FieldGeodeticPoint<>(zero, zero, zero.newInstance(350.0)), new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), null, FieldAbsoluteDate.getJ2000Epoch(field)); Assertions.assertTrue(Precision.compareTo(delay.getReal(), lastDelay.getReal(), epsilon) < 0); @@ -133,10 +143,14 @@ private > void doTestFieldVsNative(final Field new HeightDependentPressureTemperatureHumidityConverter(new CIPM2007()); for (int h = 0; h < 5000.0; h += 100) { for (int e = 0; e < 90; e += 1.0) { - final double delayN = model.pathDelay(FastMath.toRadians(e), new GeodeticPoint(0, 0, h), + final double delayN = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(e), 0.0), + new GeodeticPoint(0, 0, h), converter.convert(TroposphericModelUtils.STANDARD_ATMOSPHERE, h), null, AbsoluteDate.J2000_EPOCH); - final T delayT = model.pathDelay(zero.newInstance(FastMath.toRadians(e)), new FieldGeodeticPoint<>(zero, zero, zero.newInstance(h)), + final T delayT = model.pathDelay(new FieldTrackingCoordinates<>(zero, + zero.newInstance(FastMath.toRadians(e)), + zero), + new FieldGeodeticPoint<>(zero, zero, zero.newInstance(h)), converter.convert(new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), zero.newInstance(h)), @@ -152,10 +166,12 @@ public void testNegativeHeight() { ModifiedHopfieldModel model = new ModifiedHopfieldModel(); final double height = -500.0; for (double elevation = 0; elevation < FastMath.PI; elevation += 0.1) { - Assertions.assertEquals(model.pathDelay(elevation, new GeodeticPoint(0.0, 0.0, 0.0), + Assertions.assertEquals(model.pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), + new GeodeticPoint(0.0, 0.0, 0.0), TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH), - model.pathDelay(elevation, new GeodeticPoint(0.0, 0.0, height), + model.pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), + new GeodeticPoint(0.0, 0.0, height), TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH), 1.e-10); @@ -173,10 +189,16 @@ private > void doTestFieldNegativeHeight(final ModifiedHopfieldModel model = new ModifiedHopfieldModel(); final T height = zero.subtract(500.0); for (double elevation = 0; elevation < FastMath.PI; elevation += 0.1) { - Assertions.assertEquals(model.pathDelay(zero.newInstance(elevation), new FieldGeodeticPoint<>(zero, zero, zero), + Assertions.assertEquals(model.pathDelay(new FieldTrackingCoordinates<>(zero, + zero.newInstance(elevation), + zero), + new FieldGeodeticPoint<>(zero, zero, zero), new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), - model.pathDelay(zero.newInstance(elevation), new FieldGeodeticPoint<>(zero, zero, height), + model.pathDelay(new FieldTrackingCoordinates<>(zero, + zero.newInstance(elevation), + zero), + new FieldGeodeticPoint<>(zero, zero, height), new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), 1.e-10); @@ -202,7 +224,8 @@ public void compareExpectedValues() { double expectedValue = expectedValues[h][e]; final GeodeticPoint location = new GeodeticPoint(0.0, 0.0, height); final AbsoluteDate date = AbsoluteDate.J2000_EPOCH; - double actualValue = model.pathDelay(elevation, location, + double actualValue = model.pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), + location, converter.convert(TroposphericModelUtils.STANDARD_ATMOSPHERE, height), null, date); Assertions.assertEquals(expectedValue, actualValue, epsilon, "For height=" + height + " elevation = " + @@ -235,7 +258,8 @@ private > void doCompareFieldExpectedValues(fi double expectedValue = expectedValues[h][e]; FieldGeodeticPoint location = new FieldGeodeticPoint<>(zero, zero, height); FieldAbsoluteDate date = FieldAbsoluteDate.getJ2000Epoch(field); - T actualValue = model.pathDelay(elevation, location, + T actualValue = model.pathDelay(new FieldTrackingCoordinates<>(zero, elevation, zero), + location, converter.convert(new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), height), diff --git a/src/test/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModelTest.java index 708786990c..6067c8db2d 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModelTest.java @@ -35,6 +35,8 @@ import org.orekit.models.earth.weather.PressureTemperatureHumidityProvider; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; +import org.orekit.utils.FieldTrackingCoordinates; +import org.orekit.utils.TrackingCoordinates; public class ModifiedSaastamoinenModelTest { @@ -54,7 +56,8 @@ public void testFixedElevation() { double lastDelay = Double.MAX_VALUE; // delay shall decline with increasing height of the station for (double height = 0; height < 5000; height += 100) { - final double delay = model.pathDelay(FastMath.toRadians(5), new GeodeticPoint(0.0, 0.0, height), + final double delay = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(5), 0.0), + new GeodeticPoint(0.0, 0.0, height), TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH); Assertions.assertTrue(Precision.compareTo(delay, lastDelay, epsilon) < 0); @@ -74,7 +77,10 @@ private > void doTestFieldFixedElevation(final T lastDelay = zero.add(Double.MAX_VALUE); // delay shall decline with increasing height of the station for (double height = 0; height < 5000; height += 100) { - final T delay = model.pathDelay(zero.add(FastMath.toRadians(5)), new FieldGeodeticPoint<>(zero, zero, zero.add(height)), + final T delay = model.pathDelay(new FieldTrackingCoordinates<>(zero, + zero.newInstance(FastMath.toRadians(5)), + zero), + new FieldGeodeticPoint<>(zero, zero, zero.add(height)), new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), null, FieldAbsoluteDate.getJ2000Epoch(field)); Assertions.assertTrue(Precision.compareTo(delay.getReal(), lastDelay.getReal(), epsilon) < 0); @@ -89,7 +95,8 @@ public void testFixedHeight() { double lastDelay = Double.MAX_VALUE; // delay shall decline with increasing elevation angle for (double elev = 10d; elev < 90d; elev += 8d) { - final double delay = model.pathDelay(FastMath.toRadians(elev), new GeodeticPoint(0.0, 0.0, 350.0), + final double delay = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elev), 0.0), + new GeodeticPoint(0.0, 0.0, 350.0), TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH); Assertions.assertTrue(Precision.compareTo(delay, lastDelay, epsilon) < 0); @@ -109,7 +116,10 @@ private > void doTestFieldFixedHeight(final Fi T lastDelay = zero.add(Double.MAX_VALUE); // delay shall decline with increasing elevation angle for (double elev = 10d; elev < 90d; elev += 8d) { - final T delay = model.pathDelay(zero.add(FastMath.toRadians(elev)), new FieldGeodeticPoint<>(zero, zero, zero.add(350.0)), + final T delay = model.pathDelay(new FieldTrackingCoordinates<>(zero, + zero.newInstance(FastMath.toRadians(elev)), + zero), + new FieldGeodeticPoint<>(zero, zero, zero.add(350.0)), new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), null, FieldAbsoluteDate.getJ2000Epoch(field)); Assertions.assertTrue(Precision.compareTo(delay.getReal(), lastDelay.getReal(), epsilon) < 0); @@ -168,10 +178,12 @@ public void compareDefaultAndLoaded() { for (int e = 0; e < elevations.length; e++) { double height = heights[h]; double elevation = elevations[e]; - double expectedValue = defaultModel.pathDelay(elevation, new GeodeticPoint(0.0, 0.0, height), + double expectedValue = defaultModel.pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), + new GeodeticPoint(0.0, 0.0, height), TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH); - double actualValue = loadedModel.pathDelay(elevation, new GeodeticPoint(0.0, 0.0, height), + double actualValue = loadedModel.pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), + new GeodeticPoint(0.0, 0.0, height), TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH); Assertions.assertEquals(expectedValue, actualValue, epsilon, "For height=" + height + " elevation = " + @@ -186,10 +198,12 @@ public void testNegativeHeight() { ModifiedSaastamoinenModel model = ModifiedSaastamoinenModel.getStandardModel(); final double height = -500.0; for (double elevation = 0; elevation < FastMath.PI; elevation += 0.1) { - Assertions.assertEquals(model.pathDelay(elevation, new GeodeticPoint(0.0, 0.0, 0.0), + Assertions.assertEquals(model.pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), + new GeodeticPoint(0.0, 0.0, 0.0), TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH), - model.pathDelay(elevation, new GeodeticPoint(0.0, 0.0, height), + model.pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), + new GeodeticPoint(0.0, 0.0, height), TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH), 1.e-10); @@ -207,10 +221,16 @@ private > void doTestFieldNegativeHeight(final ModifiedSaastamoinenModel model = ModifiedSaastamoinenModel.getStandardModel(); final T height = zero.subtract(500.0); for (double elevation = 0; elevation < FastMath.PI; elevation += 0.1) { - Assertions.assertEquals(model.pathDelay(zero.add(elevation), new FieldGeodeticPoint<>(zero, zero, zero), + Assertions.assertEquals(model.pathDelay(new FieldTrackingCoordinates<>(zero, + zero.newInstance(elevation), + zero), + new FieldGeodeticPoint<>(zero, zero, zero), new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), - model.pathDelay(zero.add(elevation), new FieldGeodeticPoint<>(zero, zero, zero.add(height)), + model.pathDelay(new FieldTrackingCoordinates<>(zero, + zero.newInstance(elevation), + zero), + new FieldGeodeticPoint<>(zero, zero, zero.add(height)), new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), 1.e-10); @@ -228,11 +248,13 @@ public void testIssue654LowElevation() { // Reset to default value model.setLowElevationThreshold(ModifiedSaastamoinenModel.DEFAULT_LOW_ELEVATION_THRESHOLD); - double lowElevationPathDelay = model.pathDelay(0.001, new GeodeticPoint(0.0, 0.0, 0.0), + double lowElevationPathDelay = model.pathDelay(new TrackingCoordinates(0.0, 0.001, 0.0), + new GeodeticPoint(0.0, 0.0, 0.0), TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH); Assertions.assertTrue(lowElevationPathDelay > 0.); - Assertions.assertEquals(model.pathDelay(model.getLowElevationThreshold(), new GeodeticPoint(0.0, 0.0, 0.0), + Assertions.assertEquals(model.pathDelay(new TrackingCoordinates(0.0, model.getLowElevationThreshold(), 0.0), + new GeodeticPoint(0.0, 0.0, 0.0), TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH), lowElevationPathDelay, 1.e-10); @@ -246,10 +268,14 @@ private > void doTestFieldLowElevation(final F Utils.setDataRoot("atmosphere"); ModifiedSaastamoinenModel model = ModifiedSaastamoinenModel.getStandardModel(); final T elevation = zero.add(0.001); - double lowElevationPathDelay = model.pathDelay(zero.add(elevation), new FieldGeodeticPoint<>(zero, zero, zero), + double lowElevationPathDelay = model.pathDelay(new FieldTrackingCoordinates<>(zero, elevation, zero), + new FieldGeodeticPoint<>(zero, zero, zero), new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(); - double thresholdElevationPathDelay = model.pathDelay(zero.add(model.getLowElevationThreshold()), new FieldGeodeticPoint<>(zero, zero, zero), + double thresholdElevationPathDelay = model.pathDelay(new FieldTrackingCoordinates<>(zero, + zero.newInstance(model.getLowElevationThreshold()), + zero), + new FieldGeodeticPoint<>(zero, zero, zero), new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(); Assertions.assertTrue(lowElevationPathDelay > 0.); @@ -284,7 +310,8 @@ public void compareExpectedValues() { double expectedValue = expectedValues[h][e]; final GeodeticPoint location = new GeodeticPoint(0.0, 0.0, height); final AbsoluteDate date = AbsoluteDate.J2000_EPOCH; - double actualValue = model.pathDelay(elevation, location, + double actualValue = model.pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), + location, pth0Provider.getWeatherParamerers(location, date), null, date); Assertions.assertEquals(expectedValue, actualValue, epsilon, "For height=" + height + " elevation = " + @@ -324,7 +351,8 @@ private > void doCompareFieldExpectedValues(fi double expectedValue = expectedValues[h][e]; FieldGeodeticPoint location = new FieldGeodeticPoint<>(zero, zero, zero.add(height)); FieldAbsoluteDate date = FieldAbsoluteDate.getJ2000Epoch(field); - T actualValue = model.pathDelay(elevation, location, + T actualValue = model.pathDelay(new FieldTrackingCoordinates<>(zero, elevation, zero), + location, pth0Provider.getWeatherParamerers(location, date), null, date); Assertions.assertEquals(expectedValue, actualValue.getReal(), epsilon, "For height=" + height + " elevation = " + @@ -339,10 +367,12 @@ public void testIssue572() { ModifiedSaastamoinenModel model = ModifiedSaastamoinenModel.getStandardModel(); final double height = 6000.0; for (double elevation = 0; elevation < FastMath.PI; elevation += 0.1) { - Assertions.assertEquals(model.pathDelay(elevation, new GeodeticPoint(0.0, 0.0, 5000.0), + Assertions.assertEquals(model.pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), + new GeodeticPoint(0.0, 0.0, 5000.0), TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH), - model.pathDelay(elevation, new GeodeticPoint(0.0, 0.0, height), + model.pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), + new GeodeticPoint(0.0, 0.0, height), TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH), 1.e-10); @@ -360,10 +390,16 @@ private > void doTestFieldIssue572(final Field ModifiedSaastamoinenModel model = ModifiedSaastamoinenModel.getStandardModel(); final T height = zero.add(6000.0); for (double elevation = 0; elevation < FastMath.PI; elevation += 0.1) { - Assertions.assertEquals(model.pathDelay(zero.add(elevation),new FieldGeodeticPoint<>(zero, zero, zero.add(5000.0)), + Assertions.assertEquals(model.pathDelay(new FieldTrackingCoordinates<>(zero, + zero.newInstance(elevation), + zero), + new FieldGeodeticPoint<>(zero, zero, zero.add(5000.0)), new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), - model.pathDelay(zero.add(elevation), new FieldGeodeticPoint<>(zero, zero, zero.add(height)), + model.pathDelay(new FieldTrackingCoordinates<>(zero, + zero.newInstance(elevation), + zero), + new FieldGeodeticPoint<>(zero, zero, zero.add(height)), new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), 1.e-10); diff --git a/src/test/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModelTest.java index 0122147cbd..aa1b025844 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModelTest.java @@ -54,9 +54,11 @@ import org.orekit.time.FieldAbsoluteDate; import org.orekit.time.TimeScalesFactory; import org.orekit.utils.Constants; +import org.orekit.utils.FieldTrackingCoordinates; import org.orekit.utils.IERSConventions; import org.orekit.utils.ParameterDriver; import org.orekit.utils.ParameterDriversList; +import org.orekit.utils.TrackingCoordinates; public class TimeSpanEstimatedModelTest { @@ -80,7 +82,8 @@ public void testFixedHeight() { double lastDelay = Double.MAX_VALUE; // delay shall decline with increasing elevation angle for (double elev = 10d; elev < 90d; elev += 8d) { - final double delay = timeSpanModel.pathDelay(FastMath.toRadians(elev), point, + final double delay = timeSpanModel.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elev), 0.0), + point, TroposphericModelUtils.STANDARD_ATMOSPHERE, timeSpanModel.getParameters(), date); Assertions.assertTrue(Precision.compareTo(delay, lastDelay, 1.0e-6) < 0); @@ -97,7 +100,8 @@ public void testDelay() { TroposphereMappingFunction mapping = new NiellMappingFunctionModel(); EstimatedModel model = new EstimatedModel(mapping, 2.0); TroposphericModel timeSpanModel = new TimeSpanEstimatedModel(model); - final double path = timeSpanModel.pathDelay(FastMath.toRadians(elevation), point, + final double path = timeSpanModel.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elevation), 0.0), + point, TroposphericModelUtils.STANDARD_ATMOSPHERE, timeSpanModel.getParameters(), date); Assertions.assertTrue(Precision.compareTo(path, 20d, 1.0e-6) < 0); @@ -161,7 +165,8 @@ private void doTestDelayStateDerivatives(final TroposphereMappingFunction func, // Initial satellite elevation final FieldVector3D position = dsState.getPosition(); - final DerivativeStructure dsElevation = baseFrame.getTrackingCoordinates(position, frame, dsDate).getElevation(); + final FieldTrackingCoordinates dsTrackingCoordinates = + baseFrame.getTrackingCoordinates(position, frame, dsDate); // Set drivers reference date for (final ParameterDriver driver : timeSpanModel.getParametersDrivers()) { @@ -170,7 +175,7 @@ private void doTestDelayStateDerivatives(final TroposphereMappingFunction func, // Compute Delay with state derivatives final FieldGeodeticPoint dsPoint = new FieldGeodeticPoint<>(zero.add(point.getLatitude()), zero.add(point.getLongitude()), zero.add(point.getAltitude())); - final DerivativeStructure delay = timeSpanModel.pathDelay(dsElevation, dsPoint, + final DerivativeStructure delay = timeSpanModel.pathDelay(dsTrackingCoordinates, dsPoint, new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), timeSpanModel.getParameters(field), dsDate); @@ -189,66 +194,58 @@ private void doTestDelayStateDerivatives(final TroposphereMappingFunction func, for (int i = 0; i < 6; i++) { SpacecraftState stateM4 = shiftState(state, orbitType, angleType, -4 * steps[i], i); final Vector3D positionM4 = stateM4.getPosition(); - final double elevationM4 = station.getBaseFrame(). - getTrackingCoordinates(positionM4, stateM4.getFrame(), stateM4.getDate()). - getElevation(); - double delayM4 = timeSpanModel.pathDelay(elevationM4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final TrackingCoordinates trackingCoordinatesM4 = station.getBaseFrame(). + getTrackingCoordinates(positionM4, stateM4.getFrame(), stateM4.getDate()); + double delayM4 = timeSpanModel.pathDelay(trackingCoordinatesM4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, timeSpanModel.getParameters(), stateM4.getDate()); SpacecraftState stateM3 = shiftState(state, orbitType, angleType, -3 * steps[i], i); final Vector3D positionM3 = stateM3.getPosition(); - final double elevationM3 = station.getBaseFrame(). - getTrackingCoordinates(positionM3, stateM3.getFrame(), stateM3.getDate()). - getElevation(); - double delayM3 = timeSpanModel.pathDelay(elevationM3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final TrackingCoordinates trackingCoordinatesM3 = station.getBaseFrame(). + getTrackingCoordinates(positionM3, stateM3.getFrame(), stateM3.getDate()); + double delayM3 = timeSpanModel.pathDelay(trackingCoordinatesM3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, timeSpanModel.getParameters(), stateM3.getDate()); SpacecraftState stateM2 = shiftState(state, orbitType, angleType, -2 * steps[i], i); final Vector3D positionM2 = stateM2.getPosition(); - final double elevationM2 = station.getBaseFrame(). - getTrackingCoordinates(positionM2, stateM2.getFrame(), stateM2.getDate()). - getElevation(); - double delayM2 = timeSpanModel.pathDelay(elevationM2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final TrackingCoordinates trackingCoordinatesM2 = station.getBaseFrame(). + getTrackingCoordinates(positionM2, stateM2.getFrame(), stateM2.getDate()); + double delayM2 = timeSpanModel.pathDelay(trackingCoordinatesM2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, timeSpanModel.getParameters(), stateM2.getDate()); SpacecraftState stateM1 = shiftState(state, orbitType, angleType, -1 * steps[i], i); final Vector3D positionM1 = stateM1.getPosition(); - final double elevationM1 = station.getBaseFrame(). - getTrackingCoordinates(positionM1, stateM1.getFrame(), stateM1.getDate()). - getElevation(); - double delayM1 = timeSpanModel.pathDelay(elevationM1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final TrackingCoordinates trackingCoordinatesM1 = station.getBaseFrame(). + getTrackingCoordinates(positionM1, stateM1.getFrame(), stateM1.getDate()); + double delayM1 = timeSpanModel.pathDelay(trackingCoordinatesM1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, timeSpanModel.getParameters(), stateM1.getDate()); SpacecraftState stateP1 = shiftState(state, orbitType, angleType, 1 * steps[i], i); final Vector3D positionP1 = stateP1.getPosition(); - final double elevationP1 = station.getBaseFrame(). - getTrackingCoordinates(positionP1, stateP1.getFrame(), stateP1.getDate()). - getElevation(); - double delayP1 = timeSpanModel.pathDelay(elevationP1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final TrackingCoordinates trackingCoordinatesP1 = station.getBaseFrame(). + getTrackingCoordinates(positionP1, stateP1.getFrame(), stateP1.getDate()); + double delayP1 = timeSpanModel.pathDelay(trackingCoordinatesP1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, timeSpanModel.getParameters(), stateP1.getDate()); SpacecraftState stateP2 = shiftState(state, orbitType, angleType, 2 * steps[i], i); final Vector3D positionP2 = stateP2.getPosition(); - final double elevationP2 = station.getBaseFrame(). - getTrackingCoordinates(positionP2, stateP2.getFrame(), stateP2.getDate()). - getElevation(); - double delayP2 = timeSpanModel.pathDelay(elevationP2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final TrackingCoordinates trackingCoordinatesP2 = station.getBaseFrame(). + getTrackingCoordinates(positionP2, stateP2.getFrame(), stateP2.getDate()); + double delayP2 = timeSpanModel.pathDelay(trackingCoordinatesP2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, timeSpanModel.getParameters(), stateP2.getDate()); SpacecraftState stateP3 = shiftState(state, orbitType, angleType, 3 * steps[i], i); final Vector3D positionP3 = stateP3.getPosition(); - final double elevationP3 = station.getBaseFrame(). - getTrackingCoordinates(positionP3, stateP3.getFrame(), stateP3.getDate()). - getElevation(); - double delayP3 = timeSpanModel.pathDelay(elevationP3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final TrackingCoordinates trackingCoordinatesP3 = station.getBaseFrame(). + getTrackingCoordinates(positionP3, stateP3.getFrame(), stateP3.getDate()); + double delayP3 = timeSpanModel.pathDelay(trackingCoordinatesP3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, timeSpanModel.getParameters(), stateP3.getDate()); SpacecraftState stateP4 = shiftState(state, orbitType, angleType, 4 * steps[i], i); final Vector3D positionP4 = stateP4.getPosition(); - final double elevationP4 = station.getBaseFrame(). - getTrackingCoordinates(positionP4, stateP4.getFrame(), stateP4.getDate()). - getElevation(); - double delayP4 = timeSpanModel.pathDelay(elevationP4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + final TrackingCoordinates trackingCoordinatesP4 = station.getBaseFrame(). + getTrackingCoordinates(positionP4, stateP4.getFrame(), stateP4.getDate()); + double delayP4 = timeSpanModel.pathDelay(trackingCoordinatesP4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, timeSpanModel.getParameters(), stateP4.getDate()); fillJacobianColumn(refDeriv, i, orbitType, angleType, steps[i], @@ -329,7 +326,8 @@ private void doTestParametersDerivatives(String parameterName, double tolerance) // Initial satellite elevation final FieldVector3D position = dsState.getPosition(); - final DerivativeStructure dsElevation = baseFrame.getTrackingCoordinates(position, frame, dsState.getDate()).getElevation(); + final FieldTrackingCoordinates dsTrackingCoordinates = + baseFrame.getTrackingCoordinates(position, frame, dsState.getDate()); // Add parameter as a variable final List drivers = model.getParametersDrivers(); @@ -343,7 +341,7 @@ private void doTestParametersDerivatives(String parameterName, double tolerance) // Compute delay state derivatives final FieldGeodeticPoint dsPoint = new FieldGeodeticPoint<>(zero.add(point.getLatitude()), zero.add(point.getLongitude()), zero.add(point.getAltitude())); - final DerivativeStructure delay = model.pathDelay(dsElevation, dsPoint, + final DerivativeStructure delay = model.pathDelay(dsTrackingCoordinates, dsPoint, new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), parameters, dsState.getDate()); @@ -351,7 +349,9 @@ private void doTestParametersDerivatives(String parameterName, double tolerance) // Field -> non-field final SpacecraftState state = dsState.toSpacecraftState(); - final double elevation = dsElevation.getReal(); + final TrackingCoordinates trackingCoordinates = new TrackingCoordinates(dsTrackingCoordinates.getAzimuth().getReal(), + dsTrackingCoordinates.getElevation().getReal(), + dsTrackingCoordinates.getRange().getReal()); // Finite differences for reference values final double[][] refDeriv = new double[1][1]; @@ -372,35 +372,35 @@ private void doTestParametersDerivatives(String parameterName, double tolerance) final PositionAngleType angleType = PositionAngleType.MEAN; selected.setValue(p0 - 4 * h); - double delayM4 = model.pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + double delayM4 = model.pathDelay(trackingCoordinates, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), state.getDate()); selected.setValue(p0 - 3 * h); - double delayM3 = model.pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + double delayM3 = model.pathDelay(trackingCoordinates, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), state.getDate()); selected.setValue(p0 - 2 * h); - double delayM2 = model.pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + double delayM2 = model.pathDelay(trackingCoordinates, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), state.getDate()); selected.setValue(p0 - 1 * h); - double delayM1 = model.pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + double delayM1 = model.pathDelay(trackingCoordinates, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), state.getDate()); selected.setValue(p0 + 1 * h); - double delayP1 = model.pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + double delayP1 = model.pathDelay(trackingCoordinates, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), state.getDate()); selected.setValue(p0 + 2 * h); - double delayP2 = model.pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + double delayP2 = model.pathDelay(trackingCoordinates, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), state.getDate()); selected.setValue(p0 + 3 * h); - double delayP3 = model.pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + double delayP3 = model.pathDelay(trackingCoordinates, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), state.getDate()); selected.setValue(p0 + 4 * h); - double delayP4 = model.pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + double delayP4 = model.pathDelay(trackingCoordinates, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(), state.getDate()); fillJacobianColumn(refDeriv, 0, orbitType, angleType, h, @@ -423,9 +423,11 @@ public void testComparisonWithEstimatedModel() { final double[] timeSpanParameters = estimatedModel.getParameters(); GeodeticPoint point = new GeodeticPoint(FastMath.toRadians(45.0), FastMath.toRadians(45.0), height); - Assertions.assertEquals(estimatedModel.pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + Assertions.assertEquals(estimatedModel.pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), + point, TroposphericModelUtils.STANDARD_ATMOSPHERE, estimatedParameters, date), - timeSpanModel.pathDelay(elevation, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + timeSpanModel.pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), + point, TroposphericModelUtils.STANDARD_ATMOSPHERE, timeSpanParameters, date), Double.MIN_VALUE); } @@ -441,16 +443,18 @@ private > void doTestFieldComparisonWithEstima TroposphereMappingFunction mapping = new NiellMappingFunctionModel(); EstimatedModel estimatedModel = new EstimatedModel(mapping, 2.0); TroposphericModel timeSpanModel = new TimeSpanEstimatedModel(estimatedModel); - final T elevation = zero.add(45.0); + final FieldTrackingCoordinates trackingCoordinates = new FieldTrackingCoordinates(zero, + zero.newInstance(FastMath.toRadians(45.0)), + zero); final T height = zero.add(100.0); final T[] estimatedParameters = estimatedModel.getParameters(field); final T[] timeSpanParameters = estimatedModel.getParameters(field); final FieldGeodeticPoint dsPoint = new FieldGeodeticPoint<>(zero.add(FastMath.toRadians(45.0)), zero.add(FastMath.toRadians(45.0)), height); - Assertions.assertEquals(estimatedModel.pathDelay(elevation, dsPoint, + Assertions.assertEquals(estimatedModel.pathDelay(trackingCoordinates, dsPoint, new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), estimatedParameters, date).getReal(), - timeSpanModel.pathDelay(elevation, dsPoint, + timeSpanModel.pathDelay(trackingCoordinates, dsPoint, new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), timeSpanParameters, date).getReal(), Double.MIN_VALUE); diff --git a/src/test/java/org/orekit/models/earth/troposphere/ViennaOneModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/ViennaOneModelTest.java index ccf56a84d2..3483c24af7 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/ViennaOneModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/ViennaOneModelTest.java @@ -27,6 +27,7 @@ import org.orekit.errors.OrekitException; import org.orekit.time.AbsoluteDate; import org.orekit.time.TimeScalesFactory; +import org.orekit.utils.TrackingCoordinates; public class ViennaOneModelTest { @@ -75,7 +76,7 @@ public void testMappingFactors() { final double height = 824.17; final GeodeticPoint point = new GeodeticPoint(latitude, longitude, height); - final double elevation = 0.5 * FastMath.PI - 1.278564131; + final TrackingCoordinates trackingCoordinates = new TrackingCoordinates(0.0, 0.5 * FastMath.PI - 1.278564131, 0.0); final double expectedHydro = 3.425088; final double expectedWet = 3.448300; @@ -84,7 +85,7 @@ public void testMappingFactors() { final ViennaOneModel model = new ViennaOneModel(a, z); - final double[] computedMapping = model.mappingFactors(elevation, point, + final double[] computedMapping = model.mappingFactors(trackingCoordinates, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, date); @@ -101,7 +102,8 @@ public void testDelay() { final double[] z = {2.0966, 0.2140}; final GeodeticPoint point = new GeodeticPoint(FastMath.toRadians(45.0), FastMath.toRadians(45.0), height); ViennaOneModel model = new ViennaOneModel(a, z); - final double path = model.pathDelay(FastMath.toRadians(elevation), point, + final double path = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elevation), 0.0), + point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(date), date); Assertions.assertTrue(Precision.compareTo(path, 20d, epsilon) < 0); @@ -118,7 +120,8 @@ public void testFixedHeight() { double lastDelay = Double.MAX_VALUE; // delay shall decline with increasing elevation angle for (double elev = 10d; elev < 90d; elev += 8d) { - final double delay = model.pathDelay(FastMath.toRadians(elev), point, + final double delay = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elev), 0.0), + point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(date), date); Assertions.assertTrue(Precision.compareTo(delay, lastDelay, epsilon) < 0); diff --git a/src/test/java/org/orekit/models/earth/troposphere/ViennaThreeModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/ViennaThreeModelTest.java index 8300b33b71..189d3e219c 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/ViennaThreeModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/ViennaThreeModelTest.java @@ -27,6 +27,7 @@ import org.orekit.errors.OrekitException; import org.orekit.time.AbsoluteDate; import org.orekit.time.TimeScalesFactory; +import org.orekit.utils.TrackingCoordinates; public class ViennaThreeModelTest { @@ -72,7 +73,7 @@ public void testMappingFactors() { final double height = 824.0; final GeodeticPoint point = new GeodeticPoint(latitude, longitude, height); - final double elevation = FastMath.toRadians(38.0); + final TrackingCoordinates trackingCoordinates = new TrackingCoordinates(0.0, FastMath.toRadians(38.0), 0.0); final double expectedHydro = 1.621024; final double expectedWet = 1.623023; @@ -81,7 +82,7 @@ public void testMappingFactors() { final ViennaThreeModel model = new ViennaThreeModel(a, z); - final double[] computedMapping = model.mappingFactors(elevation, point, + final double[] computedMapping = model.mappingFactors(trackingCoordinates, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, date); @@ -119,7 +120,7 @@ public void testLowElevation() { final double height = 824.0; final GeodeticPoint point = new GeodeticPoint(latitude, longitude, height); - final double elevation = FastMath.toRadians(5.0); + final TrackingCoordinates trackingCoordinates = new TrackingCoordinates(0.0, FastMath.toRadians(5.0), 0.0); final double expectedHydro = 10.132802; final double expectedWet = 10.879154; @@ -128,7 +129,7 @@ public void testLowElevation() { final ViennaThreeModel model = new ViennaThreeModel(a, z); - final double[] computedMapping = model.mappingFactors(elevation, point, + final double[] computedMapping = model.mappingFactors(trackingCoordinates, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, date); @@ -166,7 +167,7 @@ public void testHightElevation() { final double height = 824.0; final GeodeticPoint point = new GeodeticPoint(latitude, longitude, height); - final double elevation = FastMath.toRadians(85.0); + final TrackingCoordinates trackingCoordinates = new TrackingCoordinates(0.0, FastMath.toRadians(85.0), 0.0); final double expectedHydro = 1.003810; final double expectedWet = 1.003816; @@ -175,7 +176,7 @@ public void testHightElevation() { final ViennaThreeModel model = new ViennaThreeModel(a, z); - final double[] computedMapping = model.mappingFactors(elevation, point, + final double[] computedMapping = model.mappingFactors(trackingCoordinates, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, date); @@ -192,7 +193,8 @@ public void testDelay() { final double[] z = {2.1993, 0.0690}; final GeodeticPoint point = new GeodeticPoint(FastMath.toRadians(37.5), FastMath.toRadians(277.5), height); ViennaThreeModel model = new ViennaThreeModel(a, z); - final double path = model.pathDelay(FastMath.toRadians(elevation), point, + final double path = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elevation), 0.0), + point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(date), date); Assertions.assertTrue(Precision.compareTo(path, 20d, epsilon) < 0); @@ -209,7 +211,8 @@ public void testFixedHeight() { double lastDelay = Double.MAX_VALUE; // delay shall decline with increasing elevation angle for (double elev = 10d; elev < 90d; elev += 8d) { - final double delay = model.pathDelay(FastMath.toRadians(elev), point, + final double delay = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elev), 0.0), + point, TroposphericModelUtils.STANDARD_ATMOSPHERE, model.getParameters(date), date); Assertions.assertTrue(Precision.compareTo(delay, lastDelay, epsilon) < 0); From 1d415161d50dff44e887e2359cb1622d0821abaf Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Wed, 20 Dec 2023 16:10:03 +0100 Subject: [PATCH 052/359] Use GPT2 undulation instead of an external geoid. --- .../weather/GlobalPressureTemperature2.java | 86 ++++++++----------- .../GlobalPressureTemperature2Model.java | 10 +-- .../GlobalPressureTemperature2ModelTest.java | 2 +- .../GlobalPressureTemperature2Test.java | 54 ++++++------ 4 files changed, 68 insertions(+), 84 deletions(-) diff --git a/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2.java b/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2.java index 4c1011cb39..9c1ad3f0a0 100644 --- a/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2.java +++ b/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2.java @@ -16,12 +16,12 @@ */ package org.orekit.models.earth.weather; +import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; -import java.text.ParseException; import java.util.ArrayList; import java.util.List; import java.util.SortedSet; @@ -34,15 +34,13 @@ import org.hipparchus.util.FastMath; import org.hipparchus.util.MathUtils; import org.hipparchus.util.SinCos; -import org.orekit.annotation.DefaultDataContext; import org.orekit.bodies.FieldGeodeticPoint; import org.orekit.bodies.GeodeticPoint; -import org.orekit.data.DataContext; import org.orekit.data.DataLoader; import org.orekit.data.DataProvidersManager; +import org.orekit.data.DataSource; import org.orekit.errors.OrekitException; import org.orekit.errors.OrekitMessages; -import org.orekit.models.earth.Geoid; import org.orekit.models.earth.troposphere.TroposphericModelUtils; import org.orekit.models.earth.troposphere.ViennaOneModel; import org.orekit.time.AbsoluteDate; @@ -87,9 +85,6 @@ */ public class GlobalPressureTemperature2 implements PressureTemperatureHumidityProvider { - /** Default supported files name pattern. */ - public static final String DEFAULT_SUPPORTED_NAMES = "gpt2_\\d+.grd"; - /** Pattern for delimiting regular expressions. */ private static final Pattern SEPARATOR = Pattern.compile("\\s+"); @@ -105,59 +100,47 @@ public class GlobalPressureTemperature2 implements PressureTemperatureHumidityPr /** Loaded grid. */ private final Grid grid; - /** Geoid used to compute the undulations. */ - private final Geoid geoid; - /** UTC time scale. */ private final TimeScale utc; /** - * Constructor with supported names given by user. This constructor uses the {@link - * DataContext#getDefault() default data context}. + * Constructor with supported names and source of GPT2 auxiliary data given by user. * - * @param supportedNames supported names - * @param geoid level surface of the gravity potential of a body - * @see #GlobalPressureTemperature2(String, Geoid, DataProvidersManager, TimeScale) + * @param source grid data source + * @param utc UTC time scale. + * @exception IOException if grid data cannot be read */ - @DefaultDataContext - public GlobalPressureTemperature2(final String supportedNames, final Geoid geoid) { - this(supportedNames, geoid, - DataContext.getDefault().getDataProvidersManager(), - DataContext.getDefault().getTimeScales().getUTC()); + public GlobalPressureTemperature2(final DataSource source, + final TimeScale utc) + throws IOException { + this.utc = utc; + + // load the grid data + try (InputStream is = source.getOpener().openStreamOnce(); + BufferedInputStream bis = new BufferedInputStream(is)) { + final Parser parser = new Parser(); + parser.loadData(bis, source.getName()); + grid = parser.grid; + } + } /** * Constructor with supported names and source of GPT2 auxiliary data given by user. * * @param supportedNames supported names - * @param geoid level surface of the gravity potential of a body * @param dataProvidersManager provides access to auxiliary data. * @param utc UTC time scale. + * @deprecated as of 12.1 used only by {@link GlobalPressureTemperature2Model} */ - public GlobalPressureTemperature2(final String supportedNames, - final Geoid geoid, - final DataProvidersManager dataProvidersManager, - final TimeScale utc) { - this.geoid = geoid; - this.utc = utc; - - // load the grid data + @Deprecated + protected GlobalPressureTemperature2(final String supportedNames, + final DataProvidersManager dataProvidersManager, + final TimeScale utc) { + this.utc = utc; final Parser parser = new Parser(); dataProvidersManager.feed(supportedNames, parser); - this.grid = parser.grid; - - } - - /** - * Constructor with default supported names. This constructor uses the {@link - * DataContext#getDefault() default data context}. - * - * @param geoid level surface of the gravity potential of a body - * @see #GlobalPressureTemperature2String, Geoid, DataProvidersManager, TimeScale) - */ - @DefaultDataContext - public GlobalPressureTemperature2(final Geoid geoid) { - this(DEFAULT_SUPPORTED_NAMES, geoid); + grid = parser.grid; } /** Get coefficients array for VMF mapping function. @@ -190,7 +173,7 @@ public PressureTemperatureHumidity getWeatherParamerers(final GeodeticPoint loca final int dayOfYear = date.getComponents(utc).getDate().getDayOfYear(); // Corrected height (can be negative) - final double undu = geoid.getUndulation(neighbors.latitude, neighbors.longitude, date); + final double undu = neighbors.interpolate(e -> e.undulation); final double correctedheight = location.getAltitude() - undu - neighbors.interpolate(e -> e.hS); // Temperature gradient [K/m] @@ -232,7 +215,7 @@ public > FieldPressureTemperatureHumidity g final int dayOfYear = date.getComponents(utc).getDate().getDayOfYear(); // Corrected height (can be negative) - final double undu = geoid.getUndulation(neighbors.latitude, neighbors.longitude, date.toAbsoluteDate()); + final double undu = neighbors.interpolate(e -> e.undulation); final T correctedheight = location.getAltitude().subtract(undu).subtract(neighbors.interpolate(e -> e.hS)); // Temperature gradient [K/m] @@ -365,7 +348,7 @@ public boolean stillAcceptsData() { @Override public void loadData(final InputStream input, final String name) - throws IOException, ParseException { + throws IOException { final SortedSet latSample = new TreeSet<>(); final SortedSet lonSample = new TreeSet<>(); @@ -450,7 +433,8 @@ private static class Grid { row[nO - 1] = new GridEntry(row[0].latitude, row[0].latKey, row[0].longitude + 2 * FastMath.PI, row[0].lonKey + DEG_TO_MAS * 360, - row[0].hS, row[0].pressure0, row[0].temperature0, + row[0].undulation, row[0].hS, + row[0].pressure0, row[0].temperature0, row[0].qv0, row[0].dT, row[0].ah, row[0].aw); } @@ -502,6 +486,9 @@ private static class GridEntry { /** Longitude key (mas). */ private final int lonKey; + /** Undulation. */ + private final double undulation; + /** Height correction. */ private final double hS; @@ -535,6 +522,7 @@ private static class GridEntry { latKey = (int) FastMath.rint(latDegree * DEG_TO_MAS); lonKey = (int) FastMath.rint(lonDegree * DEG_TO_MAS); + undulation = Double.parseDouble(fields[22]); hS = Double.parseDouble(fields[23]); pressure0 = createModel(fields, 2); @@ -551,6 +539,7 @@ private static class GridEntry { * @param latKey latitude key (mas) * @param longitude longitude (radian) * @param lonKey longitude key (mas) + * @param undulation undulation (m) * @param hS height correction * @param pressure0 pressure model * @param temperature0 temperature model @@ -560,13 +549,14 @@ private static class GridEntry { * @param aw aw coefficient model */ GridEntry(final double latitude, final int latKey, final double longitude, final int lonKey, - final double hS, final double[] pressure0, final double[] temperature0, + final double undulation, final double hS, final double[] pressure0, final double[] temperature0, final double[] qv0, final double[] dT, final double[] ah, final double[] aw) { this.latitude = latitude; this.latKey = latKey; this.longitude = longitude; this.lonKey = lonKey; + this.undulation = undulation; this.hS = hS; this.pressure0 = pressure0.clone(); this.temperature0 = temperature0.clone(); diff --git a/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2Model.java b/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2Model.java index 04a9f7bf6c..9e50376acd 100644 --- a/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2Model.java +++ b/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2Model.java @@ -64,7 +64,7 @@ public class GlobalPressureTemperature2Model extends GlobalPressureTemperature2 implements WeatherModel { /** Default supported files name pattern. */ - public static final String DEFAULT_SUPPORTED_NAMES = GlobalPressureTemperature2.DEFAULT_SUPPORTED_NAMES; + public static final String DEFAULT_SUPPORTED_NAMES = "gpt2_\\d+.grd"; /** The hydrostatic and wet a coefficients loaded. */ private double[] coefficientsA; @@ -91,7 +91,7 @@ public class GlobalPressureTemperature2Model extends GlobalPressureTemperature2 * @param supportedNames supported names * @param latitude geodetic latitude of the station, in radians * @param longitude longitude geodetic longitude of the station, in radians - * @param geoid level surface of the gravity potential of a body + * @param geoid level surface of the gravity potential of a body (ignored since 12.1) * @see #GlobalPressureTemperature2Model(String, double, double, Geoid, * DataProvidersManager, TimeScale) */ @@ -109,7 +109,7 @@ public GlobalPressureTemperature2Model(final String supportedNames, final double * @param supportedNames supported names * @param latitude geodetic latitude of the station, in radians * @param longitude longitude geodetic longitude of the station, in radians - * @param geoid level surface of the gravity potential of a body + * @param geoid level surface of the gravity potential of a body (ignored since 12.1) * @param dataProvidersManager provides access to auxiliary data. * @param utc UTC time scale. * @since 10.1 @@ -120,7 +120,7 @@ public GlobalPressureTemperature2Model(final String supportedNames, final Geoid geoid, final DataProvidersManager dataProvidersManager, final TimeScale utc) { - super(supportedNames, geoid, dataProvidersManager, utc); + super(supportedNames, dataProvidersManager, utc); this.coefficientsA = null; this.temperature = Double.NaN; this.pressure = Double.NaN; @@ -136,7 +136,7 @@ public GlobalPressureTemperature2Model(final String supportedNames, * * @param latitude geodetic latitude of the station, in radians * @param longitude geodetic latitude of the station, in radians - * @param geoid level surface of the gravity potential of a body + * @param geoid level surface of the gravity potential of a body (ignored since 12.1) * @see #GlobalPressureTemperature2Model(String, double, double, Geoid, * DataProvidersManager, TimeScale) */ diff --git a/src/test/java/org/orekit/models/earth/weather/GlobalPressureTemperature2ModelTest.java b/src/test/java/org/orekit/models/earth/weather/GlobalPressureTemperature2ModelTest.java index a09ed3a0ab..2e56c90462 100644 --- a/src/test/java/org/orekit/models/earth/weather/GlobalPressureTemperature2ModelTest.java +++ b/src/test/java/org/orekit/models/earth/weather/GlobalPressureTemperature2ModelTest.java @@ -75,7 +75,7 @@ public void testWeatherParameters() { final double e = model.getWaterVaporPressure(); Assertions.assertEquals(22.12, temperature, 2.3e-1); - Assertions.assertEquals(1002.56, pressure, 5.1e-1); + Assertions.assertEquals(1002.56, pressure, 7.4e-1); Assertions.assertEquals(0.0012647, a[0], 1.1e-7); Assertions.assertEquals(0.0005726, a[1], 8.6e-8); Assertions.assertEquals(15.63, e, 5.0e-2); diff --git a/src/test/java/org/orekit/models/earth/weather/GlobalPressureTemperature2Test.java b/src/test/java/org/orekit/models/earth/weather/GlobalPressureTemperature2Test.java index 81dad43be9..c03b36f427 100644 --- a/src/test/java/org/orekit/models/earth/weather/GlobalPressureTemperature2Test.java +++ b/src/test/java/org/orekit/models/earth/weather/GlobalPressureTemperature2Test.java @@ -16,31 +16,32 @@ */ package org.orekit.models.earth.weather; +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; + import org.hipparchus.util.FastMath; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.orekit.Utils; import org.orekit.bodies.GeodeticPoint; +import org.orekit.data.DataSource; import org.orekit.errors.OrekitException; import org.orekit.errors.OrekitMessages; import org.orekit.forces.gravity.potential.GRGSFormatReader; import org.orekit.forces.gravity.potential.GravityFieldFactory; -import org.orekit.frames.FramesFactory; -import org.orekit.models.earth.Geoid; -import org.orekit.models.earth.ReferenceEllipsoid; import org.orekit.models.earth.troposphere.TroposphericModelUtils; import org.orekit.time.AbsoluteDate; import org.orekit.time.TimeScalesFactory; -import org.orekit.utils.IERSConventions; public class GlobalPressureTemperature2Test { private static double epsilon = 1.0e-12; @Test - public void testWeatherParameters() { + public void testWeatherParameters() throws IOException, URISyntaxException { - Utils.setDataRoot("regular-data:potential:gpt2-grid"); + Utils.setDataRoot("regular-data:potential"); GravityFieldFactory.addPotentialCoefficientsReader(new GRGSFormatReader("grim4s4_gr", true)); // Site Vienna: latitude: 48.20°N @@ -63,10 +64,10 @@ public void testWeatherParameters() { final double longitude = FastMath.toRadians(16.37); final double height = 156.0; final AbsoluteDate date = AbsoluteDate.createMJDDate(56141, 0.0, TimeScalesFactory.getUTC()); - final Geoid geoid = new Geoid(GravityFieldFactory.getNormalizedProvider(12, 12), - ReferenceEllipsoid.getWgs84(FramesFactory.getITRF(IERSConventions.IERS_2010, true))); + final URL url = GlobalPressureTemperature2Test.class.getClassLoader().getResource("gpt2-grid/gpt2_5_extract.grd"); final GlobalPressureTemperature2 model = - new GlobalPressureTemperature2("gpt2_5_extract.grd", geoid); + new GlobalPressureTemperature2(new DataSource(url.toURI()), + TimeScalesFactory.getUTC()); final GeodeticPoint location = new GeodeticPoint(latitude, longitude, height); final double a[] = model.getA(location, date); @@ -75,26 +76,25 @@ public void testWeatherParameters() { Assertions.assertEquals(0.0012647, a[0], 1.1e-7); Assertions.assertEquals(0.0005726, a[1], 8.6e-8); Assertions.assertEquals(273.15 + 22.12, pth.getTemperature(), 2.3e-1); - Assertions.assertEquals(1002.56, TroposphericModelUtils.HECTO_PASCAL.fromSI(pth.getPressure()), 5.1e-1); + Assertions.assertEquals(1002.56, TroposphericModelUtils.HECTO_PASCAL.fromSI(pth.getPressure()), 7.4e-1); Assertions.assertEquals(15.63, TroposphericModelUtils.HECTO_PASCAL.fromSI(pth.getWaterVaporPressure()), 5.0e-2); } @Test - public void testEquality() { + public void testEquality() throws IOException, URISyntaxException { - Utils.setDataRoot("regular-data:potential:gpt2-grid"); + Utils.setDataRoot("regular-data:potential"); GravityFieldFactory.addPotentialCoefficientsReader(new GRGSFormatReader("grim4s4_gr", true)); // Commons parameters - final Geoid geoid = new Geoid(GravityFieldFactory.getNormalizedProvider(12, 12), - ReferenceEllipsoid.getWgs84(FramesFactory.getITRF(IERSConventions.IERS_2010, true))); - final AbsoluteDate date = AbsoluteDate.createMJDDate(56141, 0.0, TimeScalesFactory.getUTC()); final double latitude = FastMath.toRadians(45.0); final double height = 0.0; - GlobalPressureTemperature2 model = new GlobalPressureTemperature2(geoid); + final URL url = GlobalPressureTemperature2Test.class.getClassLoader().getResource("gpt2-grid/gpt2_15.grd"); + GlobalPressureTemperature2 model = new GlobalPressureTemperature2(new DataSource(url.toURI()), + TimeScalesFactory.getUTC()); // Test longitude = 181° and longitude = -179° GeodeticPoint location1 = new GeodeticPoint(latitude, FastMath.toRadians(181.0), height); @@ -141,18 +141,15 @@ public void testEquality() { } @Test - public void testCorruptedFileBadData() { + public void testCorruptedFileBadData() throws IOException, URISyntaxException { - Utils.setDataRoot("regular-data:potential:gpt2-grid"); + Utils.setDataRoot("regular-data:potential"); GravityFieldFactory.addPotentialCoefficientsReader(new GRGSFormatReader("grim4s4_gr", true)); - // Date is not used here - final Geoid geoid = new Geoid(GravityFieldFactory.getNormalizedProvider(12, 12), - ReferenceEllipsoid.getWgs84(FramesFactory.getITRF(IERSConventions.IERS_2010, true))); - final String fileName = "corrupted-bad-data-gpt2_5.grd"; + final URL url = GlobalPressureTemperature2Test.class.getClassLoader().getResource("gpt2-grid/" + fileName); try { - new GlobalPressureTemperature2(fileName, geoid); + new GlobalPressureTemperature2(new DataSource(url.toURI()), TimeScalesFactory.getUTC()); Assertions.fail("An exception should have been thrown"); } catch (OrekitException oe) { Assertions.assertEquals(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE, oe.getSpecifier()); @@ -163,18 +160,15 @@ public void testCorruptedFileBadData() { } @Test - public void testCorruptedIrregularGrid() { + public void testCorruptedIrregularGrid() throws IOException, URISyntaxException { - Utils.setDataRoot("regular-data:potential:gpt2-grid"); + Utils.setDataRoot("regular-data:potential"); GravityFieldFactory.addPotentialCoefficientsReader(new GRGSFormatReader("grim4s4_gr", true)); - // Date is not used here - final Geoid geoid = new Geoid(GravityFieldFactory.getNormalizedProvider(12, 12), - ReferenceEllipsoid.getWgs84(FramesFactory.getITRF(IERSConventions.IERS_2010, true))); - final String fileName = "corrupted-irregular-grid-gpt2_5.grd"; + final URL url = GlobalPressureTemperature2Test.class.getClassLoader().getResource("gpt2-grid/" + fileName); try { - new GlobalPressureTemperature2(fileName, geoid); + new GlobalPressureTemperature2(new DataSource(url.toURI()), TimeScalesFactory.getUTC()); Assertions.fail("An exception should have been thrown"); } catch (OrekitException oe) { Assertions.assertEquals(OrekitMessages.IRREGULAR_OR_INCOMPLETE_GRID, oe.getSpecifier()); From 1d1b4d4e72cb4ad04e820207738969aaede31e3d Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Wed, 20 Dec 2023 17:31:44 +0100 Subject: [PATCH 053/359] Use Davis 1985 improved value for hydrostatic delay coefficient. --- .../models/earth/troposphere/CanonicalSaastamoinenModel.java | 4 ++-- .../earth/troposphere/CanonicalSaastamoinenModelTest.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java b/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java index ebb63353db..facd18939d 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java @@ -166,7 +166,7 @@ public double pathDelay(final TrackingCoordinates trackingCoordinates, final Geo // calculate the path delay in m final double tan = FastMath.tan(z); - final double delta = 2.277e-5 / FastMath.cos(z) * + final double delta = 2.2768e-5 / FastMath.cos(z) * (pth.getPressure() + (1255.0 / pth.getTemperature() + 0.05) * pth.getWaterVaporPressure() - B * tan * tan); @@ -211,7 +211,7 @@ public > T pathDelay(final FieldTrackingCoordi // calculate the path delay in m final T tan = FastMath.tan(z); - final T delta = FastMath.cos(z).divide(2.277e-5).reciprocal(). + final T delta = FastMath.cos(z).divide(2.2768e-5).reciprocal(). multiply(pth.getPressure(). add(pth.getTemperature().reciprocal().multiply(1255.0).add(0.05). multiply(pth.getWaterVaporPressure())). diff --git a/src/test/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModelTest.java index 4e0ae6fd01..90fab19c05 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModelTest.java @@ -30,7 +30,7 @@ public class CanonicalSaastamoinenModelTest { @Test public void testComparisonToModifiedModelLowElevation() { - doTestComparisonToModifiedModel(FastMath.toRadians(5), -13.24, -1.04); + doTestComparisonToModifiedModel(FastMath.toRadians(5), -13.24, -1.03); } @Test From 6343e5ecae0ffc56c5b0e63415ecdf7a72eda86d Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Wed, 20 Dec 2023 21:05:52 +0100 Subject: [PATCH 054/359] Added {Field}TroposphericDelay container. --- .../AngularTroposphericDelayModifier.java | 3 +- ...aseRangeRateTroposphericDelayModifier.java | 12 +- .../BaseRangeTroposphericDelayModifier.java | 6 +- .../PhaseTroposphericDelayModifier.java | 6 +- .../TDOATroposphericDelayModifier.java | 6 +- ...nAroundRangeTroposphericDelayModifier.java | 6 +- .../CanonicalSaastamoinenModel.java | 53 ++++--- .../earth/troposphere/EstimatedModel.java | 58 ++++---- .../EstimatedTroposphericModel.java | 4 +- .../troposphere/FieldTroposphericDelay.java | 88 ++++++++++++ .../troposphere/FixedTroposphericDelay.java | 44 ++++-- .../earth/troposphere/MariniMurrayModel.java | 51 +++++-- .../earth/troposphere/MendesPavlisModel.java | 33 +++-- .../troposphere/ModifiedHopfieldModel.java | 52 +++---- .../ModifiedSaastamoinenModel.java | 52 ++++--- .../earth/troposphere/SaastamoinenModel.java | 4 +- .../troposphere/TimeSpanEstimatedModel.java | 15 +- .../earth/troposphere/TroposphericDelay.java | 85 +++++++++++ .../earth/troposphere/TroposphericModel.java | 17 +-- .../troposphere/TroposphericModelAdapter.java | 51 +++++-- .../earth/troposphere/ViennaOneModel.java | 31 ++-- .../earth/troposphere/ViennaThreeModel.java | 31 ++-- .../measurements/gnss/PhaseTest.java | 10 +- .../CanonicalSaastamoinenModelTest.java | 4 +- .../earth/troposphere/EstimatedModelTest.java | 40 +++--- .../FieldMendesPavlisModelTest.java | 22 +-- .../troposphere/FieldViennaOneModelTest.java | 22 +-- .../FieldViennaThreeModelTest.java | 35 ++--- .../FixedTroposphericModelTest.java | 136 ++++++++++-------- .../troposphere/MariniMurrayModelTest.java | 16 +-- .../troposphere/MendesPavlisModelTest.java | 4 +- .../ModifiedHopfieldModelTest.java | 24 ++-- .../ModifiedSaastamoinenModelTest.java | 43 +++--- .../TimeSpanEstimatedModelTest.java | 54 +++---- .../earth/troposphere/ViennaOneModelTest.java | 4 +- .../troposphere/ViennaThreeModelTest.java | 17 ++- 36 files changed, 739 insertions(+), 400 deletions(-) create mode 100644 src/main/java/org/orekit/models/earth/troposphere/FieldTroposphericDelay.java create mode 100644 src/main/java/org/orekit/models/earth/troposphere/TroposphericDelay.java diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/AngularTroposphericDelayModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/AngularTroposphericDelayModifier.java index 86e8669fd9..3e38d92650 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/AngularTroposphericDelayModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/AngularTroposphericDelayModifier.java @@ -88,7 +88,8 @@ private double angularErrorTroposphericModel(final GroundStation station, final double delay = tropoModel.pathDelay(trackingCoordinates, station.getOffsetGeodeticPoint(state.getDate()), station.getPressureTemperatureHumidity(state.getDate()), - tropoModel.getParameters(state.getDate()), state.getDate()); + tropoModel.getParameters(state.getDate()), state.getDate()). + getDelay(); // one-way measurement. return delay; diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/BaseRangeRateTroposphericDelayModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/BaseRangeRateTroposphericDelayModifier.java index 8ad52494c8..05366c9e54 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/BaseRangeRateTroposphericDelayModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/BaseRangeRateTroposphericDelayModifier.java @@ -97,7 +97,8 @@ public double rangeRateErrorTroposphericModel(final GroundStation station, final double d1 = tropoModel.pathDelay(trackingCoordinates1, station.getOffsetGeodeticPoint(state.getDate()), station.getPressureTemperatureHumidity(state.getDate()), - tropoModel.getParameters(state.getDate()), state.getDate()); + tropoModel.getParameters(state.getDate()), state.getDate()). + getDelay(); // propagate spacecraft state forward by dt final SpacecraftState state2 = state.shiftedBy(dt); @@ -113,7 +114,8 @@ public double rangeRateErrorTroposphericModel(final GroundStation station, final double d2 = tropoModel.pathDelay(trackingCoordinates2, station.getOffsetGeodeticPoint(state.getDate()), station.getPressureTemperatureHumidity(state.getDate()), - tropoModel.getParameters(state2.getDate()), state2.getDate()); + tropoModel.getParameters(state2.getDate()), state2.getDate()). + getDelay(); return (d2 - d1) / dt; } @@ -152,7 +154,8 @@ public > T rangeRateErrorTroposphericModel(fin final T d1 = tropoModel.pathDelay(trackingCoordinates1, station.getOffsetGeodeticPoint(state.getDate()), station.getPressureTemperatureHumidity(state.getDate()), - parameters, state.getDate()); + parameters, state.getDate()). + getDelay(); // propagate spacecraft state forward by dt final FieldSpacecraftState state2 = state.shiftedBy(dt); @@ -169,7 +172,8 @@ public > T rangeRateErrorTroposphericModel(fin final T d2 = tropoModel.pathDelay(trackingCoordinates2, station.getOffsetGeodeticPoint(state.getDate()), station.getPressureTemperatureHumidity(state.getDate()), - parameters, state2.getDate()); + parameters, state2.getDate()). + getDelay(); return d2.subtract(d1).divide(dt); } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/BaseRangeTroposphericDelayModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/BaseRangeTroposphericDelayModifier.java index 085cbced4f..9b582a5f9c 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/BaseRangeTroposphericDelayModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/BaseRangeTroposphericDelayModifier.java @@ -90,7 +90,8 @@ public double rangeErrorTroposphericModel(final GroundStation station, final double delay = tropoModel.pathDelay(trackingCoordinates, station.getOffsetGeodeticPoint(state.getDate()), station.getPressureTemperatureHumidity(state.getDate()), - tropoModel.getParameters(), state.getDate()); + tropoModel.getParameters(), state.getDate()). + getDelay(); return delay; } @@ -124,7 +125,8 @@ public > T rangeErrorTroposphericModel(final G final T delay = tropoModel.pathDelay(trackingCoordinates, station.getOffsetGeodeticPoint(state.getDate()), station.getPressureTemperatureHumidity(state.getDate()), - parameters, state.getDate()); + parameters, state.getDate()). + getDelay(); return delay; } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseTroposphericDelayModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseTroposphericDelayModifier.java index df264a8dc1..3915be9e5a 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseTroposphericDelayModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseTroposphericDelayModifier.java @@ -88,7 +88,8 @@ private double phaseErrorTroposphericModel(final GroundStation station, final Sp final double delay = tropoModel.pathDelay(trackingCoordinates, station.getOffsetGeodeticPoint(state.getDate()), station.getPressureTemperatureHumidity(state.getDate()), - tropoModel.getParameters(state.getDate()), state.getDate()); + tropoModel.getParameters(state.getDate()), state.getDate()). + getDelay(); return delay / wavelength; } @@ -123,7 +124,8 @@ private > T phaseErrorTroposphericModel(final final T delay = tropoModel.pathDelay(trackingCoordinates, station.getOffsetGeodeticPoint(state.getDate()), station.getPressureTemperatureHumidity(state.getDate()), - parameters, state.getDate()); + parameters, state.getDate()). + getDelay(); return delay.divide(wavelength); } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/TDOATroposphericDelayModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/TDOATroposphericDelayModifier.java index ee3d770a9d..fe62000ee8 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/TDOATroposphericDelayModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/TDOATroposphericDelayModifier.java @@ -88,7 +88,8 @@ private double timeErrorTroposphericModel(final GroundStation station, final Spa final double delay = tropoModel.pathDelay(trackingCoordinates, station.getOffsetGeodeticPoint(state.getDate()), station.getPressureTemperatureHumidity(state.getDate()), - tropoModel.getParameters(state.getDate()), state.getDate()); + tropoModel.getParameters(state.getDate()), state.getDate()). + getDelay(); // return delay in seconds return delay / Constants.SPEED_OF_LIGHT; } @@ -121,7 +122,8 @@ private > T timeErrorTroposphericModel(final G final T delay = tropoModel.pathDelay(trackingCoordinates, station.getOffsetGeodeticPoint(state.getDate()), station.getPressureTemperatureHumidity(state.getDate()), - parameters, state.getDate()); + parameters, state.getDate()). + getDelay(); // return delay in seconds return delay.divide(Constants.SPEED_OF_LIGHT); } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/TurnAroundRangeTroposphericDelayModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/TurnAroundRangeTroposphericDelayModifier.java index 0f185f8e72..d48011f317 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/TurnAroundRangeTroposphericDelayModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/TurnAroundRangeTroposphericDelayModifier.java @@ -94,7 +94,8 @@ private double rangeErrorTroposphericModel(final GroundStation station, final Sp final double delay = tropoModel.pathDelay(trackingCoordinates, station.getOffsetGeodeticPoint(state.getDate()), station.getPressureTemperatureHumidity(state.getDate()), - tropoModel.getParameters(state.getDate()), state.getDate()); + tropoModel.getParameters(state.getDate()), state.getDate()). + getDelay(); return delay; } @@ -127,7 +128,8 @@ private > T rangeErrorTroposphericModel(final final T delay = tropoModel.pathDelay(trackingCoordinates, station.getOffsetGeodeticPoint(state.getDate()), station.getPressureTemperatureHumidity(state.getDate()), - parameters, state.getDate()); + parameters, state.getDate()). + getDelay(); return delay; } diff --git a/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java b/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java index facd18939d..cc5aff9a74 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java @@ -64,6 +64,15 @@ public class CanonicalSaastamoinenModel implements TroposphericModel { /** Default lowest acceptable elevation angle [rad]. */ public static final double DEFAULT_LOW_ELEVATION_THRESHOLD = 0.05; + /** Base delay coefficient. */ + private static final double L0 = 2.2768e-5; + + /** Temperature numerator. */ + private static final double T_NUM = 1255; + + /** Wet offset. */ + private static final double WET_OFFSET = 0.05; + /** X values for the B function (table 1 in reference paper). */ private static final double[] X_VALUES_FOR_B = { 0.0, 200.0, 400.0, 600.0, 800.0, 1000.0, 1500.0, 2000.0, 2500.0, 3000.0, 4000.0, 5000.0, 6000.0 @@ -146,9 +155,9 @@ public static CanonicalSaastamoinenModel getStandardModel() { * @see #setLowElevationThreshold(double) */ @Override - public double pathDelay(final TrackingCoordinates trackingCoordinates, final GeodeticPoint point, - final PressureTemperatureHumidity weather, - final double[] parameters, final AbsoluteDate date) { + public TroposphericDelay pathDelay(final TrackingCoordinates trackingCoordinates, final GeodeticPoint point, + final PressureTemperatureHumidity weather, + final double[] parameters, final AbsoluteDate date) { final PressureTemperatureHumidity pth = pthProvider.getWeatherParamerers(point, date); @@ -164,13 +173,15 @@ public double pathDelay(final TrackingCoordinates trackingCoordinates, final Geo final double z = FastMath.abs(0.5 * FastMath.PI - FastMath.max(trackingCoordinates.getElevation(), lowElevationThreshold)); - // calculate the path delay in m - final double tan = FastMath.tan(z); - final double delta = 2.2768e-5 / FastMath.cos(z) * - (pth.getPressure() + - (1255.0 / pth.getTemperature() + 0.05) * pth.getWaterVaporPressure() - B * tan * tan); + // calculate the path delay + final double invCos = 1.0 / FastMath.cos(z); + final double tan = FastMath.tan(z); + final double zh = L0 * pth.getPressure(); + final double zw = L0 * (T_NUM / pth.getTemperature() + WET_OFFSET) * pth.getWaterVaporPressure(); + final double sh = zh * invCos; + final double sw = (zw - L0 * B * tan * tan) * invCos; + return new TroposphericDelay(zh, zw, sh, sw); - return delta; } /** {@inheritDoc} @@ -187,10 +198,10 @@ public double pathDelay(final TrackingCoordinates trackingCoordinates, final Geo * @see #setLowElevationThreshold(double) */ @Override - public > T pathDelay(final FieldTrackingCoordinates trackingCoordinates, - final FieldGeodeticPoint point, - final FieldPressureTemperatureHumidity weather, - final T[] parameters, final FieldAbsoluteDate date) { + public > FieldTroposphericDelay pathDelay(final FieldTrackingCoordinates trackingCoordinates, + final FieldGeodeticPoint point, + final FieldPressureTemperatureHumidity weather, + final T[] parameters, final FieldAbsoluteDate date) { final Field field = date.getField(); final T zero = field.getZero(); @@ -210,14 +221,14 @@ public > T pathDelay(final FieldTrackingCoordi subtract(FastMath.max(trackingCoordinates.getElevation(), lowElevationThreshold))); // calculate the path delay in m - final T tan = FastMath.tan(z); - final T delta = FastMath.cos(z).divide(2.2768e-5).reciprocal(). - multiply(pth.getPressure(). - add(pth.getTemperature().reciprocal().multiply(1255.0).add(0.05). - multiply(pth.getWaterVaporPressure())). - subtract(B.multiply(tan).multiply(tan))); - - return delta; + final T invCos = FastMath.cos(z).reciprocal(); + final T tan = FastMath.tan(z); + final T zh = pth.getPressure().multiply(L0); + final T zw = pth.getTemperature().reciprocal().multiply(T_NUM).add(WET_OFFSET). + multiply(pth.getWaterVaporPressure()).multiply(L0); + final T sh = zh.multiply(invCos); + final T sw = zw.subtract(B.multiply(tan).multiply(tan).multiply(L0)).multiply(invCos); + return new FieldTroposphericDelay<>(zh, zw, sh, sw); } diff --git a/src/main/java/org/orekit/models/earth/troposphere/EstimatedModel.java b/src/main/java/org/orekit/models/earth/troposphere/EstimatedModel.java index 78507c33b6..0ed648a892 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/EstimatedModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/EstimatedModel.java @@ -130,38 +130,44 @@ public List getParametersDrivers() { /** {@inheritDoc} */ @Override - public double pathDelay(final TrackingCoordinates trackingCoordinates, - final GeodeticPoint point, - final PressureTemperatureHumidity weather, - final double[] parameters, final AbsoluteDate date) { - // Zenith delays. elevation = pi/2 because we compute the delay in the zenith direction - final double zhd = hydrostatic.pathDelay(new TrackingCoordinates(trackingCoordinates.getAzimuth(), - 0.5 * FastMath.PI, - trackingCoordinates.getRange()), - point, weather, parameters, date); - final double ztd = parameters[0]; - // Mapping functions + public TroposphericDelay pathDelay(final TrackingCoordinates trackingCoordinates, + final GeodeticPoint point, + final PressureTemperatureHumidity weather, + final double[] parameters, final AbsoluteDate date) { + + // zenith hydrostatic delay + final double zd = hydrostatic.pathDelay(trackingCoordinates, point, weather, parameters, date).getZh(); + + // zenith wet delay + final double wd = parameters[0] - zd; + + // mapping functions final double[] mf = model.mappingFactors(trackingCoordinates, point, weather, date); - // Total delay - return mf[0] * zhd + mf[1] * (ztd - zhd); + + // composite delay + return new TroposphericDelay(zd, wd, mf[0] * zd, mf[1] * wd); + } /** {@inheritDoc} */ @Override - public > T pathDelay(final FieldTrackingCoordinates trackingCoordinates, - final FieldGeodeticPoint point, - final FieldPressureTemperatureHumidity weather, - final T[] parameters, final FieldAbsoluteDate date) { - // Zenith delays. elevation = pi/2 because we compute the delay in the zenith direction - final T zhd = hydrostatic.pathDelay(new FieldTrackingCoordinates<>(trackingCoordinates.getAzimuth(), - trackingCoordinates.getElevation().getPi().multiply(0.5), - trackingCoordinates.getRange()), - point, weather, parameters, date); - final T ztd = parameters[0]; - // Mapping functions + public > FieldTroposphericDelay pathDelay(final FieldTrackingCoordinates trackingCoordinates, + final FieldGeodeticPoint point, + final FieldPressureTemperatureHumidity weather, + final T[] parameters, final FieldAbsoluteDate date) { + + // zenith hydrostatic delay + final T zd = hydrostatic.pathDelay(trackingCoordinates, point, weather, parameters, date).getZh(); + + // zenith wet delay + final T wd = parameters[0].subtract(zd); + + // mapping functions final T[] mf = model.mappingFactors(trackingCoordinates, point, weather, date); - // Total delay - return mf[0].multiply(zhd).add(mf[1].multiply(ztd.subtract(zhd))); + + // composite delay + return new FieldTroposphericDelay<>(zd, wd, mf[0].multiply(zd), mf[1].multiply(wd)); + } } diff --git a/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java b/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java index 409264bcba..480b276b3e 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/EstimatedTroposphericModel.java @@ -105,7 +105,7 @@ public EstimatedTroposphericModel(final MappingFunction model, final double tota public double pathDelay(final double elevation, final GeodeticPoint point, final double[] parameters, final AbsoluteDate date) { return pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), point, - TroposphericModelUtils.STANDARD_ATMOSPHERE, parameters, date); + TroposphericModelUtils.STANDARD_ATMOSPHERE, parameters, date).getDelay(); } /** {@inheritDoc} */ @@ -118,7 +118,7 @@ public > T pathDelay(final T elevation, return pathDelay(new FieldTrackingCoordinates<>(date.getField().getZero(), elevation, date.getField().getZero()), point, new FieldPressureTemperatureHumidity<>(date.getField(), TroposphericModelUtils.STANDARD_ATMOSPHERE), - parameters, date); + parameters, date).getDelay(); } } diff --git a/src/main/java/org/orekit/models/earth/troposphere/FieldTroposphericDelay.java b/src/main/java/org/orekit/models/earth/troposphere/FieldTroposphericDelay.java new file mode 100644 index 0000000000..173b67b324 --- /dev/null +++ b/src/main/java/org/orekit/models/earth/troposphere/FieldTroposphericDelay.java @@ -0,0 +1,88 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import org.hipparchus.CalculusFieldElement; + +/** Container for tropospheric delay. + * @param type of the field elements + * @author Luc Maisonobe + * @since 12.1 + */ +public class FieldTroposphericDelay> { + + /** Hydrostatic zenith delay (m). */ + private final T zh; + + /** Wet zenith delay (m). */ + private final T zw; + + /** Hydrostatic slanted delay (m). */ + private final T sh; + + /** Wet slanted delay (m). */ + private final T sw; + + /** Simple constructor. + * @param zh hydrostatic zenith delay (m) + * @param zw wet zenith delay (m) + * @param sh hydrostatic slanted delay (m) + * @param sw wet slanted delay (m) + */ + public FieldTroposphericDelay(final T zh, final T zw, final T sh, final T sw) { + this.zh = zh; + this.zw = zw; + this.sh = sh; + this.sw = sw; + } + + /** Get hydrostatic zenith delay (m). + * @return hydrostatic zenith delay (m) + */ + public T getZh() { + return zh; + } + + /** Get wet zenith delay (m). + * @return w et zenith delay (m) + */ + public T getZw() { + return zw; + } + + /** Get slanted delay (m). + * @return slanted delay (m) + */ + public T getSh() { + return sh; + } + + /** Get wet slanted delay (m). + * @return wet slanted delay (m) + */ + public T getSw() { + return sw; + } + + /** Get the total slanted delay (m). + * @return total slanted delay (m) + */ + public T getDelay() { + return sh.add(sw); + } + +} diff --git a/src/main/java/org/orekit/models/earth/troposphere/FixedTroposphericDelay.java b/src/main/java/org/orekit/models/earth/troposphere/FixedTroposphericDelay.java index 103e547aa8..8c0c4e4b47 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/FixedTroposphericDelay.java +++ b/src/main/java/org/orekit/models/earth/troposphere/FixedTroposphericDelay.java @@ -23,6 +23,7 @@ import org.hipparchus.analysis.interpolation.PiecewiseBicubicSplineInterpolatingFunction; import org.hipparchus.analysis.interpolation.PiecewiseBicubicSplineInterpolator; import org.hipparchus.util.FastMath; +import org.hipparchus.util.MathUtils; import org.orekit.annotation.DefaultDataContext; import org.orekit.bodies.FieldGeodeticPoint; import org.orekit.bodies.GeodeticPoint; @@ -137,14 +138,20 @@ public static FixedTroposphericDelay getDefaultModel() { public double pathDelay(final double elevation, final GeodeticPoint point, final double[] parameters, final AbsoluteDate date) { return pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), point, - TroposphericModelUtils.STANDARD_ATMOSPHERE, parameters, date); + TroposphericModelUtils.STANDARD_ATMOSPHERE, parameters, date).getDelay(); } - /** {@inheritDoc} */ + /** {@inheritDoc} + *

            + * All delays are affected to {@link TroposphericDelay#getZh() hydrostatic zenith} + * and {@link TroposphericDelay#getSh() hydrostatic slanted} delays, the wet delays + * are arbitrarily set to 0. + *

            + */ @Override - public double pathDelay(final TrackingCoordinates trackingCoordinates, final GeodeticPoint point, - final PressureTemperatureHumidity weather, - final double[] parameters, final AbsoluteDate date) { + public TroposphericDelay pathDelay(final TrackingCoordinates trackingCoordinates, final GeodeticPoint point, + final PressureTemperatureHumidity weather, + final double[] parameters, final AbsoluteDate date) { // limit the height to 5000 m final double h = FastMath.min(FastMath.max(0, point.getAltitude()), 5000); // limit the elevation to 0 - π @@ -152,7 +159,8 @@ public double pathDelay(final TrackingCoordinates trackingCoordinates, final Geo // mirror elevation at the right angle of π/2 final double e = ele > 0.5 * FastMath.PI ? FastMath.PI - ele : ele; - return delayFunction.value(h, e); + return new TroposphericDelay(delayFunction.value(h, MathUtils.SEMI_PI), 0.0, + delayFunction.value(h, e), 0.0); } /** {@inheritDoc} */ @@ -163,15 +171,21 @@ public > T pathDelay(final T elevation, final return pathDelay(new FieldTrackingCoordinates<>(date.getField().getZero(), elevation, date.getField().getZero()), point, new FieldPressureTemperatureHumidity<>(date.getField(), TroposphericModelUtils.STANDARD_ATMOSPHERE), - parameters, date); + parameters, date).getDelay(); } - /** {@inheritDoc} */ + /** {@inheritDoc} + *

            + * All delays are affected to {@link FieldTroposphericDelay#getZh() hydrostatic zenith} + * and {@link FieldTroposphericDelay#getSh() hydrostatic slanted} delays, the wet delays + * are arbitrarily set to 0. + *

            + */ @Override - public > T pathDelay(final FieldTrackingCoordinates trackingCoordinates, - final FieldGeodeticPoint point, - final FieldPressureTemperatureHumidity weather, - final T[] parameters, final FieldAbsoluteDate date) { + public > FieldTroposphericDelay pathDelay(final FieldTrackingCoordinates trackingCoordinates, + final FieldGeodeticPoint point, + final FieldPressureTemperatureHumidity weather, + final T[] parameters, final FieldAbsoluteDate date) { final T zero = date.getField().getZero(); final T pi = zero.getPi(); // limit the height to 5000 m @@ -181,7 +195,11 @@ public > T pathDelay(final FieldTrackingCoordi // mirror elevation at the right angle of π/2 final T e = ele.getReal() > pi.multiply(0.5).getReal() ? ele.negate().add(pi) : ele; - return delayFunction.value(h, e); + return new FieldTroposphericDelay<>(delayFunction.value(h, date.getField().getZero().newInstance(MathUtils.SEMI_PI)), + date.getField().getZero(), + delayFunction.value(h, e), + date.getField().getZero()); + } /** {@inheritDoc} */ diff --git a/src/main/java/org/orekit/models/earth/troposphere/MariniMurrayModel.java b/src/main/java/org/orekit/models/earth/troposphere/MariniMurrayModel.java index 756c8cb3c2..99ee5af618 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/MariniMurrayModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/MariniMurrayModel.java @@ -144,14 +144,15 @@ public static MariniMurrayModel getStandardModel(final double lambda, final Unit public double pathDelay(final double elevation, final GeodeticPoint point, final double[] parameters, final AbsoluteDate date) { return pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), point, - TroposphericModelUtils.STANDARD_ATMOSPHERE, parameters, date); + TroposphericModelUtils.STANDARD_ATMOSPHERE, parameters, date). + getDelay(); } /** {@inheritDoc} */ @Override - public double pathDelay(final TrackingCoordinates trackingCoordinates, final GeodeticPoint point, - final PressureTemperatureHumidity weather, - final double[] parameters, final AbsoluteDate date) { + public TroposphericDelay pathDelay(final TrackingCoordinates trackingCoordinates, final GeodeticPoint point, + final PressureTemperatureHumidity weather, + final double[] parameters, final AbsoluteDate date) { final PressureTemperatureHumidity pth = pthProvider.getWeatherParamerers(point, date); final double p = pth.getPressure(); @@ -159,7 +160,8 @@ public double pathDelay(final TrackingCoordinates trackingCoordinates, final Geo final double e = pth.getWaterVaporPressure(); // beware since version 12.1 pressures are in Pa and not in hPa, hence the scaling has changed - final double A = 0.00002357 * p + 0.00000141 * e; + final double Ah = 0.00002357 * p; + final double Aw = 0.00000141 * e; final double K = 1.163 - 0.00968 * FastMath.cos(2 * point.getLatitude()) - 0.00104 * t + 0.0000001435 * p; final double B = 1.084e-10 * p * t * K + 4.734e-12 * p * (p / t) * (2 * K) / (3 * K - 1); final double flambda = getLaserFrequencyParameter(); @@ -167,8 +169,12 @@ public double pathDelay(final TrackingCoordinates trackingCoordinates, final Geo final double fsite = getSiteFunctionValue(point); final double sinE = FastMath.sin(trackingCoordinates.getElevation()); - final double dR = (flambda / fsite) * (A + B) / (sinE + B / ((A + B) * (sinE + 0.01)) ); - return dR; + final double totalZenith = (flambda / fsite) * (Ah + Aw + B) / (1.0 + B / ((Ah + Aw + B) * (1.0 + 0.01))); + final double totalElev = (flambda / fsite) * (Ah + Aw + B) / (sinE + B / ((Ah + Aw + B) * (sinE + 0.01))); + final double hydrostaticZenith = (flambda / fsite) * (Ah + B) / (1.0 + B / ((Ah + B) * (1.0 + 0.01))); + final double hydrostaticElev = (flambda / fsite) * (Ah + B) / (sinE + B / ((Ah + B) * (sinE + 0.01))); + return new TroposphericDelay(hydrostaticZenith, totalZenith - hydrostaticZenith, + hydrostaticElev, totalElev - hydrostaticElev); } /** {@inheritDoc} */ @@ -181,15 +187,16 @@ public > T pathDelay(final T elevation, return pathDelay(new FieldTrackingCoordinates<>(date.getField().getZero(), elevation, date.getField().getZero()), point, new FieldPressureTemperatureHumidity<>(date.getField(), TroposphericModelUtils.STANDARD_ATMOSPHERE), - parameters, date); + parameters, date). + getDelay(); } /** {@inheritDoc} */ @Override - public > T pathDelay(final FieldTrackingCoordinates trackingCoordinates, - final FieldGeodeticPoint point, - final FieldPressureTemperatureHumidity weather, - final T[] parameters, final FieldAbsoluteDate date) { + public > FieldTroposphericDelay pathDelay(final FieldTrackingCoordinates trackingCoordinates, + final FieldGeodeticPoint point, + final FieldPressureTemperatureHumidity weather, + final T[] parameters, final FieldAbsoluteDate date) { final FieldPressureTemperatureHumidity pth = pthProvider.getWeatherParamerers(point, date); final T p = pth.getPressure(); @@ -197,7 +204,8 @@ public > T pathDelay(final FieldTrackingCoordi final T e = pth.getWaterVaporPressure(); // beware since version 12.1 pressures are in Pa and not in hPa, hence the scaling has changed - final T A = p.multiply(0.00002357).add(e.multiply(0.00000141)); + final T Ah = p.multiply(0.00002357); + final T Aw = e.multiply(0.00000141); final T K = FastMath.cos(point.getLatitude().multiply(2.)).multiply(0.00968).negate(). add(1.163). subtract(t.multiply(0.00104)). @@ -209,8 +217,21 @@ public > T pathDelay(final FieldTrackingCoordi final T fsite = getSiteFunctionValue(point); final T sinE = FastMath.sin(trackingCoordinates.getElevation()); - final T dR = fsite.divide(flambda).reciprocal().multiply(B.add(A)).divide(sinE.add(sinE.add(0.01).multiply(B.add(A)).divide(B).reciprocal())); - return dR; + final T one = date.getField().getOne(); + final T totalZenith = fsite.divide(flambda).reciprocal(). + multiply(B.add(Ah).add(Aw)). + divide(one.add(one.add(0.01).multiply(B.add(Ah).add(Aw)).divide(B).reciprocal())); + final T totalElev = fsite.divide(flambda).reciprocal(). + multiply(B.add(Ah).add(Aw)). + divide(sinE.add(sinE.add(0.01).multiply(B.add(Ah).add(Aw)).divide(B).reciprocal())); + final T hydrostaticZenith = fsite.divide(flambda).reciprocal(). + multiply(B.add(Ah)). + divide(one.add(one.add(0.01).multiply(B.add(Ah)).divide(B).reciprocal())); + final T hydrostaticElev = fsite.divide(flambda).reciprocal(). + multiply(B.add(Ah)). + divide(sinE.add(sinE.add(0.01).multiply(B.add(Ah)).divide(B).reciprocal())); + return new FieldTroposphericDelay<>(hydrostaticZenith, totalZenith.subtract(hydrostaticZenith), + hydrostaticElev, totalElev.subtract(hydrostaticElev)); } /** {@inheritDoc} */ diff --git a/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java b/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java index c59eac7fd5..b89fb08313 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java @@ -186,20 +186,25 @@ public static MendesPavlisModel getStandardModel(final double lambda, final Unit public double pathDelay(final double elevation, final GeodeticPoint point, final double[] parameters, final AbsoluteDate date) { return pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), point, - TroposphericModelUtils.STANDARD_ATMOSPHERE, parameters, date); + TroposphericModelUtils.STANDARD_ATMOSPHERE, parameters, date). + getDelay(); } /** {@inheritDoc} */ @Override - public double pathDelay(final TrackingCoordinates trackingCoordinates, final GeodeticPoint point, - final PressureTemperatureHumidity weather, - final double[] parameters, final AbsoluteDate date) { + public TroposphericDelay pathDelay(final TrackingCoordinates trackingCoordinates, + final GeodeticPoint point, + final PressureTemperatureHumidity weather, + final double[] parameters, final AbsoluteDate date) { // Zenith delay final double[] zenithDelay = computeZenithDelay(point, parameters, date); // Mapping function final double[] mappingFunction = mappingFactors(trackingCoordinates, point, weather, date); // Tropospheric path delay - return zenithDelay[0] * mappingFunction[0] + zenithDelay[1] * mappingFunction[1]; + return new TroposphericDelay(zenithDelay[0], + zenithDelay[1], + zenithDelay[0] * mappingFunction[0], + zenithDelay[1] * mappingFunction[1]); } /** {@inheritDoc} */ @@ -210,21 +215,25 @@ public > T pathDelay(final T elevation, final return pathDelay(new FieldTrackingCoordinates<>(date.getField().getZero(), elevation, date.getField().getZero()), point, new FieldPressureTemperatureHumidity<>(date.getField(), TroposphericModelUtils.STANDARD_ATMOSPHERE), - parameters, date); + parameters, date). + getDelay(); } /** {@inheritDoc} */ @Override - public > T pathDelay(final FieldTrackingCoordinates trackingCoordinates, - final FieldGeodeticPoint point, - final FieldPressureTemperatureHumidity weather, - final T[] parameters, final FieldAbsoluteDate date) { + public > FieldTroposphericDelay pathDelay(final FieldTrackingCoordinates trackingCoordinates, + final FieldGeodeticPoint point, + final FieldPressureTemperatureHumidity weather, + final T[] parameters, final FieldAbsoluteDate date) { // Zenith delay - final T[] delays = computeZenithDelay(point, parameters, date); + final T[] zenithDelay = computeZenithDelay(point, parameters, date); // Mapping function final T[] mappingFunction = mappingFactors(trackingCoordinates, point, weather, date); // Tropospheric path delay - return delays[0].multiply(mappingFunction[0]).add(delays[1].multiply(mappingFunction[1])); + return new FieldTroposphericDelay<>(zenithDelay[0], + zenithDelay[1], + zenithDelay[0].multiply(mappingFunction[0]), + zenithDelay[1].multiply(mappingFunction[1])); } /** This method allows the computation of the zenith hydrostatic and diff --git a/src/main/java/org/orekit/models/earth/troposphere/ModifiedHopfieldModel.java b/src/main/java/org/orekit/models/earth/troposphere/ModifiedHopfieldModel.java index 2b274f69f1..ce19ea903b 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/ModifiedHopfieldModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/ModifiedHopfieldModel.java @@ -78,26 +78,27 @@ public ModifiedHopfieldModel() { /** {@inheritDoc} */ @Override - public double pathDelay(final TrackingCoordinates trackingCoordinates, - final GeodeticPoint point, - final PressureTemperatureHumidity weather, - final double[] parameters, final AbsoluteDate date) { + public TroposphericDelay pathDelay(final TrackingCoordinates trackingCoordinates, + final GeodeticPoint point, + final PressureTemperatureHumidity weather, + final double[] parameters, final AbsoluteDate date) { // zenith angle final double zenithAngle = MathUtils.SEMI_PI - trackingCoordinates.getElevation(); // dry component - final double hd = HD0 + HD1 * (weather.getTemperature() - T0); - final double nd = ND * TroposphericModelUtils.HECTO_PASCAL.fromSI(weather.getPressure()) / - weather.getTemperature(); - final double deltaD = delay(zenithAngle, hd, nd); + final double hd = HD0 + HD1 * (weather.getTemperature() - T0); + final double nd = ND * TroposphericModelUtils.HECTO_PASCAL.fromSI(weather.getPressure()) / + weather.getTemperature(); // wet component - final double hw = HW0; - final double nw = (NW1 + NW2 / weather.getTemperature()) / weather.getTemperature(); - final double deltaW = delay(zenithAngle, hw, nw); + final double hw = HW0; + final double nw = (NW1 + NW2 / weather.getTemperature()) / weather.getTemperature(); - return deltaD + deltaW; + return new TroposphericDelay(delay(0.0, hd, nd), + delay(0.0, hw, nw), + delay(zenithAngle, hd, nd), + delay(zenithAngle, hw, nw)); } @@ -115,27 +116,28 @@ public double pathDelay(final TrackingCoordinates trackingCoordinates, * @see #setLowElevationThreshold(double) */ @Override - public > T pathDelay(final FieldTrackingCoordinates trackingCoordinates, - final FieldGeodeticPoint point, - final FieldPressureTemperatureHumidity weather, - final T[] parameters, final FieldAbsoluteDate date) { + public > FieldTroposphericDelay pathDelay(final FieldTrackingCoordinates trackingCoordinates, + final FieldGeodeticPoint point, + final FieldPressureTemperatureHumidity weather, + final T[] parameters, final FieldAbsoluteDate date) { // zenith angle final T zenithAngle = trackingCoordinates.getElevation().negate().add(MathUtils.SEMI_PI); // dry component - final T hd = weather.getTemperature().subtract(T0).multiply(HD1).add(HD0); - final T nd = TroposphericModelUtils.HECTO_PASCAL.fromSI(weather.getPressure()). - multiply(ND). - divide(weather.getTemperature()); - final T deltaD = delay(zenithAngle, hd, nd); + final T hd = weather.getTemperature().subtract(T0).multiply(HD1).add(HD0); + final T nd = TroposphericModelUtils.HECTO_PASCAL.fromSI(weather.getPressure()). + multiply(ND). + divide(weather.getTemperature()); // wet component - final T hw = date.getField().getZero().newInstance(HW0); - final T nw = weather.getTemperature().reciprocal().multiply(NW2).add(NW1).divide(weather.getTemperature()); - final T deltaW = delay(zenithAngle, hw, nw); + final T hw = date.getField().getZero().newInstance(HW0); + final T nw = weather.getTemperature().reciprocal().multiply(NW2).add(NW1).divide(weather.getTemperature()); - return deltaD.add(deltaW); + return new FieldTroposphericDelay<>(delay(date.getField().getZero(), hd, nd), + delay(date.getField().getZero(), hw, nw), + delay(zenithAngle, hd, nd), + delay(zenithAngle, hw, nw)); } diff --git a/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java b/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java index c74d736b91..10a8c64d17 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java @@ -85,6 +85,15 @@ public class ModifiedSaastamoinenModel implements TroposphericModel { /** Second pattern for δR correction term table. */ private static final Pattern SECOND_DELTA_R_PATTERN = Pattern.compile("\\$$"); + /** Base delay coefficient. */ + private static final double L0 = 2.277e-5; + + /** Temperature numerator. */ + private static final double T_NUM = 1255; + + /** Wet offset. */ + private static final double WET_OFFSET = 0.05; + /** X values for the B function. */ private static final double[] X_VALUES_FOR_B = { 0.0, 500.0, 1000.0, 1500.0, 2000.0, 2500.0, 3000.0, 4000.0, 5000.0 @@ -224,10 +233,10 @@ public PressureTemperatureHumidityProvider getPth0Provider() { * @see #setLowElevationThreshold(double) */ @Override - public double pathDelay(final TrackingCoordinates trackingCoordinates, - final GeodeticPoint point, - final PressureTemperatureHumidity weather, - final double[] parameters, final AbsoluteDate date) { + public TroposphericDelay pathDelay(final TrackingCoordinates trackingCoordinates, + final GeodeticPoint point, + final PressureTemperatureHumidity weather, + final double[] parameters, final AbsoluteDate date) { // limit the height to model range final double fixedHeight = FastMath.min(FastMath.max(point.getAltitude(), X_VALUES_FOR_B[0]), @@ -247,13 +256,14 @@ public double pathDelay(final TrackingCoordinates trackingCoordinates, // calculate the path delay in m // beware since version 12.1 pressures are in Pa and not in hPa, hence the scaling has changed - final double tan = FastMath.tan(z); - final double delta = 2.277e-5 / FastMath.cos(z) * - (pth.getPressure() + - (1255d / pth.getTemperature() + 5e-2) * pth.getWaterVaporPressure() - - B * tan * tan) + deltaR; + final double invCos = 1.0 / FastMath.cos(z); + final double tan = FastMath.tan(z); + final double zh = L0 * pth.getPressure(); + final double zw = L0 * (T_NUM / pth.getTemperature() + WET_OFFSET) * pth.getWaterVaporPressure(); + final double sh = zh * invCos; + final double sw = (zw - L0 * B * tan * tan) * invCos + deltaR; + return new TroposphericDelay(zh, zw, sh, sw); - return delta; } /** {@inheritDoc} @@ -270,10 +280,10 @@ public double pathDelay(final TrackingCoordinates trackingCoordinates, * @see #setLowElevationThreshold(double) */ @Override - public > T pathDelay(final FieldTrackingCoordinates trackingCoordinates, - final FieldGeodeticPoint point, - final FieldPressureTemperatureHumidity weather, - final T[] parameters, final FieldAbsoluteDate date) { + public > FieldTroposphericDelay pathDelay(final FieldTrackingCoordinates trackingCoordinates, + final FieldGeodeticPoint point, + final FieldPressureTemperatureHumidity weather, + final T[] parameters, final FieldAbsoluteDate date) { // limit the height to model range final T fixedHeight = FastMath.min(FastMath.max(point.getAltitude(), X_VALUES_FOR_B[0]), @@ -297,13 +307,15 @@ public > T pathDelay(final FieldTrackingCoordi // calculate the path delay in m // beware since version 12.1 pressures are in Pa and not in hPa, hence the scaling has changed - final T tan = FastMath.tan(z); - final T delta = FastMath.cos(z).divide(2.277e-5).reciprocal(). - multiply(pth.getPressure(). - add(pth.getTemperature().divide(1255d).reciprocal().add(5e-2).multiply(pth.getWaterVaporPressure())). - subtract(B.multiply(tan).multiply(tan))).add(deltaR); + final T invCos = FastMath.cos(z).reciprocal(); + final T tan = FastMath.tan(z); + final T zh = pth.getPressure().multiply(L0); + final T zw = pth.getTemperature().reciprocal().multiply(T_NUM).add(WET_OFFSET). + multiply(pth.getWaterVaporPressure()).multiply(L0); + final T sh = zh.multiply(invCos); + final T sw = zw.subtract(B.multiply(tan).multiply(tan).multiply(L0)).multiply(invCos).add(deltaR); + return new FieldTroposphericDelay<>(zh, zw, sh, sw); - return delta; } /** Calculates the delta R correction term using linear interpolation. diff --git a/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java b/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java index a8b71d9eda..bea870eb8a 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java @@ -127,7 +127,7 @@ public static SaastamoinenModel getStandardModel() { public double pathDelay(final double elevation, final GeodeticPoint point, final double[] parameters, final AbsoluteDate date) { return pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), point, - getPth0Provider().getWeatherParamerers(point, date), parameters, date); + getPth0Provider().getWeatherParamerers(point, date), parameters, date).getDelay(); } /** {@inheritDoc} */ @@ -140,7 +140,7 @@ public > T pathDelay(final T elevation, return pathDelay(new FieldTrackingCoordinates<>(date.getField().getZero(), elevation, date.getField().getZero()), point, getPth0Provider().getWeatherParamerers(point, date), - parameters, date); + parameters, date).getDelay(); } } diff --git a/src/main/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModel.java b/src/main/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModel.java index 21173a508e..421cda75fa 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModel.java @@ -210,9 +210,10 @@ public > T[] extractParameters(final T[] param /** {@inheritDoc} */ @Override - public double pathDelay(final TrackingCoordinates trackingCoordinates, final GeodeticPoint point, - final PressureTemperatureHumidity weather, - final double[] parameters, final AbsoluteDate date) { + public TroposphericDelay pathDelay(final TrackingCoordinates trackingCoordinates, + final GeodeticPoint point, + final PressureTemperatureHumidity weather, + final double[] parameters, final AbsoluteDate date) { // Extract the proper parameters valid at date from the input array final double[] extractedParameters = extractParameters(parameters, date); // Compute and return the path delay @@ -222,10 +223,10 @@ public double pathDelay(final TrackingCoordinates trackingCoordinates, final Geo /** {@inheritDoc} */ @Override - public > T pathDelay(final FieldTrackingCoordinates trackingCoordinates, - final FieldGeodeticPoint point, - final FieldPressureTemperatureHumidity weather, - final T[] parameters, final FieldAbsoluteDate date) { + public > FieldTroposphericDelay pathDelay(final FieldTrackingCoordinates trackingCoordinates, + final FieldGeodeticPoint point, + final FieldPressureTemperatureHumidity weather, + final T[] parameters, final FieldAbsoluteDate date) { // Extract the proper parameters valid at date from the input array final T[] extractedParameters = extractParameters(parameters, date); // Compute and return the path delay diff --git a/src/main/java/org/orekit/models/earth/troposphere/TroposphericDelay.java b/src/main/java/org/orekit/models/earth/troposphere/TroposphericDelay.java new file mode 100644 index 0000000000..fb67602f7f --- /dev/null +++ b/src/main/java/org/orekit/models/earth/troposphere/TroposphericDelay.java @@ -0,0 +1,85 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +/** Container for tropospheric delay. + * @author Luc Maisonobe + * @since 12.1 + */ +public class TroposphericDelay { + + /** Hydrostatic zenith delay (m). */ + private final double zh; + + /** Wet zenith delay (m). */ + private final double zw; + + /** Hydrostatic slanted delay (m). */ + private final double sh; + + /** Wet slanted delay (m). */ + private final double sw; + + /** Simple constructor. + * @param zh hydrostatic zenith delay (m) + * @param zw wet zenith delay (m) + * @param sh hydrostatic slanted delay (m) + * @param sw wet slanted delay (m) + */ + public TroposphericDelay(final double zh, final double zw, final double sh, final double sw) { + this.zh = zh; + this.zw = zw; + this.sh = sh; + this.sw = sw; + } + + /** Get hydrostatic zenith delay (m). + * @return hydrostatic zenith delay (m) + */ + public double getZh() { + return zh; + } + + /** Get wet zenith delay (m). + * @return w et zenith delay (m) + */ + public double getZw() { + return zw; + } + + /** Get slanted delay (m). + * @return slanted delay (m) + */ + public double getSh() { + return sh; + } + + /** Get wet slanted delay (m). + * @return wet slanted delay (m) + */ + public double getSw() { + return sw; + } + + /** Get the total slanted delay (m). + * @return total slanted delay (m) + */ + public double getDelay() { + return sh + sw; + } + +} diff --git a/src/main/java/org/orekit/models/earth/troposphere/TroposphericModel.java b/src/main/java/org/orekit/models/earth/troposphere/TroposphericModel.java index 82947f4eee..8e1a931e06 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/TroposphericModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/TroposphericModel.java @@ -43,10 +43,11 @@ public interface TroposphericModel extends ParameterDriversProvider { * for constant default values) * @param parameters tropospheric model parameters * @param date current date - * @return the path delay due to the troposphere in m + * @return the path delay due to the troposphere */ - double pathDelay(TrackingCoordinates trackingCoordinates, GeodeticPoint point, PressureTemperatureHumidity weather, - double[] parameters, AbsoluteDate date); + TroposphericDelay pathDelay(TrackingCoordinates trackingCoordinates, GeodeticPoint point, + PressureTemperatureHumidity weather, + double[] parameters, AbsoluteDate date); /** Calculates the tropospheric path delay for the signal path from a ground * station to a satellite. @@ -58,10 +59,10 @@ public interface TroposphericModel extends ParameterDriversProvider { * for constant default values) * @param parameters tropospheric model parameters at current date * @param date current date - * @return the path delay due to the troposphere in m + * @return the path delay due to the troposphere */ - > T pathDelay(FieldTrackingCoordinates trackingCoordinates, - FieldGeodeticPoint point, - FieldPressureTemperatureHumidity weather, - T[] parameters, FieldAbsoluteDate date); + > FieldTroposphericDelay pathDelay(FieldTrackingCoordinates trackingCoordinates, + FieldGeodeticPoint point, + FieldPressureTemperatureHumidity weather, + T[] parameters, FieldAbsoluteDate date); } diff --git a/src/main/java/org/orekit/models/earth/troposphere/TroposphericModelAdapter.java b/src/main/java/org/orekit/models/earth/troposphere/TroposphericModelAdapter.java index fea0a69e13..520f5593b3 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/TroposphericModelAdapter.java +++ b/src/main/java/org/orekit/models/earth/troposphere/TroposphericModelAdapter.java @@ -19,6 +19,7 @@ import java.util.List; import org.hipparchus.CalculusFieldElement; +import org.hipparchus.util.MathUtils; import org.orekit.bodies.FieldGeodeticPoint; import org.orekit.bodies.GeodeticPoint; import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; @@ -51,24 +52,46 @@ public TroposphericModelAdapter(final DiscreteTroposphericModel model) { this.model = model; } - /** {@inheritDoc} */ + /** {@inheritDoc} + *

            + * All delays are affected to {@link TroposphericDelay#getZh() hydrostatic zenith} + * and {@link TroposphericDelay#getSh() hydrostatic slanted} delays, the wet delays + * are arbitrarily set to 0. + *

            + */ @Override - public double pathDelay(final TrackingCoordinates trackingCoordinates, - final GeodeticPoint point, - final PressureTemperatureHumidity weather, - final double[] parameters, - final AbsoluteDate date) { - return model.pathDelay(trackingCoordinates.getElevation(), point, parameters, date); + public TroposphericDelay pathDelay(final TrackingCoordinates trackingCoordinates, + final GeodeticPoint point, + final PressureTemperatureHumidity weather, + final double[] parameters, + final AbsoluteDate date) { + return new TroposphericDelay(model.pathDelay(MathUtils.SEMI_PI, + point, parameters, date), + 0.0, + model.pathDelay(trackingCoordinates.getElevation(), + point, parameters, date), + 0.0); } - /** {@inheritDoc} */ + /** {@inheritDoc} + *

            + * All delays are affected to {@link FieldTroposphericDelay#getZh() hydrostatic zenith} + * and {@link FieldTroposphericDelay#getSh() hydrostatic slanted} delays, the wet delays + * are arbitrarily set to 0. + *

            + */ @Override - public > T pathDelay(final FieldTrackingCoordinates trackingCoordinates, - final FieldGeodeticPoint point, - final FieldPressureTemperatureHumidity weather, - final T[] parameters, - final FieldAbsoluteDate date) { - return model.pathDelay(trackingCoordinates.getElevation(), point, parameters, date); + public > FieldTroposphericDelay pathDelay(final FieldTrackingCoordinates trackingCoordinates, + final FieldGeodeticPoint point, + final FieldPressureTemperatureHumidity weather, + final T[] parameters, + final FieldAbsoluteDate date) { + return new FieldTroposphericDelay<>(model.pathDelay(date.getField().getZero().newInstance(MathUtils.SEMI_PI), + point, parameters, date), + date.getField().getZero(), + model.pathDelay(trackingCoordinates.getElevation(), + point, parameters, date), + date.getField().getZero()); } /** {@inheritDoc} */ diff --git a/src/main/java/org/orekit/models/earth/troposphere/ViennaOneModel.java b/src/main/java/org/orekit/models/earth/troposphere/ViennaOneModel.java index 6ec49ddf03..5cadc7fa14 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/ViennaOneModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/ViennaOneModel.java @@ -102,20 +102,25 @@ public ViennaOneModel(final double[] coefficientA, public double pathDelay(final double elevation, final GeodeticPoint point, final double[] parameters, final AbsoluteDate date) { return pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), - point, TroposphericModelUtils.STANDARD_ATMOSPHERE, parameters, date); + point, TroposphericModelUtils.STANDARD_ATMOSPHERE, parameters, date). + getDelay(); } /** {@inheritDoc} */ @Override - public double pathDelay(final TrackingCoordinates trackingCoordinates, final GeodeticPoint point, - final PressureTemperatureHumidity weather, - final double[] parameters, final AbsoluteDate date) { + public TroposphericDelay pathDelay(final TrackingCoordinates trackingCoordinates, + final GeodeticPoint point, + final PressureTemperatureHumidity weather, + final double[] parameters, final AbsoluteDate date) { // zenith delay final double[] delays = computeZenithDelay(point, parameters, date); // mapping function final double[] mappingFunction = mappingFactors(trackingCoordinates, point, weather, date); // Tropospheric path delay - return delays[0] * mappingFunction[0] + delays[1] * mappingFunction[1]; + return new TroposphericDelay(delays[0], + delays[1], + delays[0] * mappingFunction[0], + delays[1] * mappingFunction[1]); } /** {@inheritDoc} */ @@ -126,21 +131,25 @@ public > T pathDelay(final T elevation, final return pathDelay(new FieldTrackingCoordinates<>(date.getField().getZero(), elevation, date.getField().getZero()), point, new FieldPressureTemperatureHumidity<>(date.getField(), TroposphericModelUtils.STANDARD_ATMOSPHERE), - parameters, date); + parameters, date). + getDelay(); } /** {@inheritDoc} */ @Override - public > T pathDelay(final FieldTrackingCoordinates trackingCoordinates, - final FieldGeodeticPoint point, - final FieldPressureTemperatureHumidity weather, - final T[] parameters, final FieldAbsoluteDate date) { + public > FieldTroposphericDelay pathDelay(final FieldTrackingCoordinates trackingCoordinates, + final FieldGeodeticPoint point, + final FieldPressureTemperatureHumidity weather, + final T[] parameters, final FieldAbsoluteDate date) { // zenith delay final T[] delays = computeZenithDelay(point, parameters, date); // mapping function final T[] mappingFunction = mappingFactors(trackingCoordinates, point, weather, date); // Tropospheric path delay - return delays[0].multiply(mappingFunction[0]).add(delays[1].multiply(mappingFunction[1])); + return new FieldTroposphericDelay<>(delays[0], + delays[1], + delays[0].multiply(mappingFunction[0]), + delays[1].multiply(mappingFunction[1])); } /** This method allows the computation of the zenith hydrostatic and diff --git a/src/main/java/org/orekit/models/earth/troposphere/ViennaThreeModel.java b/src/main/java/org/orekit/models/earth/troposphere/ViennaThreeModel.java index 030abc1aa7..5980a21c27 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/ViennaThreeModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/ViennaThreeModel.java @@ -310,20 +310,25 @@ public > T[] mappingFactors(final FieldTrackin public double pathDelay(final double elevation, final GeodeticPoint point, final double[] parameters, final AbsoluteDate date) { return pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), point, - TroposphericModelUtils.STANDARD_ATMOSPHERE, parameters, date); + TroposphericModelUtils.STANDARD_ATMOSPHERE, parameters, date). + getDelay(); } /** {@inheritDoc} */ @Override - public double pathDelay(final TrackingCoordinates trackingCoordinates, final GeodeticPoint point, - final PressureTemperatureHumidity weather, - final double[] parameters, final AbsoluteDate date) { + public TroposphericDelay pathDelay(final TrackingCoordinates trackingCoordinates, + final GeodeticPoint point, + final PressureTemperatureHumidity weather, + final double[] parameters, final AbsoluteDate date) { // zenith delay final double[] delays = computeZenithDelay(point, parameters, date); // mapping function final double[] mappingFunction = mappingFactors(trackingCoordinates, point, weather, date); // Tropospheric path delay - return delays[0] * mappingFunction[0] + delays[1] * mappingFunction[1]; + return new TroposphericDelay(delays[0], + delays[1], + delays[0] * mappingFunction[0], + delays[1] * mappingFunction[1]); } /** {@inheritDoc} */ @@ -334,21 +339,25 @@ public > T pathDelay(final T elevation, final return pathDelay(new FieldTrackingCoordinates<>(date.getField().getZero(), elevation, date.getField().getZero()), point, new FieldPressureTemperatureHumidity<>(date.getField(), TroposphericModelUtils.STANDARD_ATMOSPHERE), - parameters, date); + parameters, date). + getDelay(); } /** {@inheritDoc} */ @Override - public > T pathDelay(final FieldTrackingCoordinates trackingCoordinates, - final FieldGeodeticPoint point, - final FieldPressureTemperatureHumidity weather, - final T[] parameters, final FieldAbsoluteDate date) { + public > FieldTroposphericDelay pathDelay(final FieldTrackingCoordinates trackingCoordinates, + final FieldGeodeticPoint point, + final FieldPressureTemperatureHumidity weather, + final T[] parameters, final FieldAbsoluteDate date) { // zenith delay final T[] delays = computeZenithDelay(point, parameters, date); // mapping function final T[] mappingFunction = mappingFactors(trackingCoordinates.getElevation(), point, date); // Tropospheric path delay - return delays[0].multiply(mappingFunction[0]).add(delays[1].multiply(mappingFunction[1])); + return new FieldTroposphericDelay<>(delays[0], + delays[1], + delays[0].multiply(mappingFunction[0]), + delays[1].multiply(mappingFunction[1])); } /** This method allows the computation of the zenith hydrostatic and diff --git a/src/test/java/org/orekit/estimation/measurements/gnss/PhaseTest.java b/src/test/java/org/orekit/estimation/measurements/gnss/PhaseTest.java index 4f84a98514..ba66fac3cb 100644 --- a/src/test/java/org/orekit/estimation/measurements/gnss/PhaseTest.java +++ b/src/test/java/org/orekit/estimation/measurements/gnss/PhaseTest.java @@ -578,11 +578,11 @@ public double value(final ParameterDriver parameterDriver, final AbsoluteDate da public void testStateDerivativesWithTroposphericModifier() { final boolean printResults = false; - final double refErrorsPMedian = 5.9e-10; - final double refErrorsPMean = 4.3e-9; - final double refErrorsPMax = 3.8e-7; - final double refErrorsVMedian = 2.0e-5; - final double refErrorsVMean = 8.3e-5; + final double refErrorsPMedian = 6.0e-10; + final double refErrorsPMean = 2.9e-9; + final double refErrorsPMax = 1.1e-7; + final double refErrorsVMedian = 1.5e-5; + final double refErrorsVMean = 7.8e-5; final double refErrorsVMax = 4.6e-3; Context context = EstimationTestUtils.eccentricContext("regular-data:potential:tides"); diff --git a/src/test/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModelTest.java index 90fab19c05..b0799fb28d 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModelTest.java @@ -47,10 +47,10 @@ private void doTestComparisonToModifiedModel(final double elevation, final GeodeticPoint location = new GeodeticPoint(0.0, 0.0, height); final double canonicalDelay = canonical.pathDelay(trackingCoordinates, location, TroposphericModelUtils.STANDARD_ATMOSPHERE, - null, AbsoluteDate.J2000_EPOCH); + null, AbsoluteDate.J2000_EPOCH).getDelay(); final double modifiedDelay = modified.pathDelay(trackingCoordinates, location, TroposphericModelUtils.STANDARD_ATMOSPHERE, - null, AbsoluteDate.J2000_EPOCH); + null, AbsoluteDate.J2000_EPOCH).getDelay(); Assertions.assertTrue(modifiedDelay - canonicalDelay > minDifference); Assertions.assertTrue(modifiedDelay - canonicalDelay < maxDifference); } diff --git a/src/test/java/org/orekit/models/earth/troposphere/EstimatedModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/EstimatedModelTest.java index 8ec472b01d..1df1f72b8f 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/EstimatedModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/EstimatedModelTest.java @@ -82,7 +82,7 @@ public void testFixedHeight() { final double delay = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elev), 0.0), point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), date); + model.getParameters(), date).getDelay(); Assertions.assertTrue(Precision.compareTo(delay, lastDelay, 1.0e-6) < 0); lastDelay = delay; } @@ -99,7 +99,7 @@ public void testDelay() { final double path = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elevation), 0.0), point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), date); + model.getParameters(), date).getDelay(); Assertions.assertTrue(Precision.compareTo(path, 20d, 1.0e-6) < 0); Assertions.assertTrue(Precision.compareTo(path, 0d, 1.0e-6) > 0); } @@ -173,7 +173,7 @@ private void doTestDelayStateDerivatives(final TroposphereMappingFunction func, final FieldGeodeticPoint dsPoint = new FieldGeodeticPoint<>(zero.add(point.getLatitude()), zero.add(point.getLongitude()), zero.add(point.getAltitude())); final DerivativeStructure delay = model.pathDelay(dsTrackingCoordinates, dsPoint, new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), - model.getParameters(field), dsDate); + model.getParameters(field), dsDate).getDelay(); final double[] compDeriv = delay.getAllDerivatives(); @@ -193,56 +193,56 @@ private void doTestDelayStateDerivatives(final TroposphereMappingFunction func, final TrackingCoordinates trackingCoordinatesM4 = station.getBaseFrame(). getTrackingCoordinates(positionM4, stateM4.getFrame(), stateM4.getDate()); double delayM4 = model.pathDelay(trackingCoordinatesM4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), stateM4.getDate()); + model.getParameters(), stateM4.getDate()).getDelay(); SpacecraftState stateM3 = shiftState(state, orbitType, angleType, -3 * steps[i], i); final Vector3D positionM3 = stateM3.getPosition(); final TrackingCoordinates trackingCoordinatesM3 = station.getBaseFrame(). getTrackingCoordinates(positionM3, stateM3.getFrame(), stateM3.getDate()); double delayM3 = model.pathDelay(trackingCoordinatesM3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), stateM3.getDate()); + model.getParameters(), stateM3.getDate()).getDelay(); SpacecraftState stateM2 = shiftState(state, orbitType, angleType, -2 * steps[i], i); final Vector3D positionM2 = stateM2.getPosition(); final TrackingCoordinates trackingCoordinatesM2 = station.getBaseFrame(). getTrackingCoordinates(positionM2, stateM2.getFrame(), stateM2.getDate()); double delayM2 = model.pathDelay(trackingCoordinatesM2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), stateM2.getDate()); + model.getParameters(), stateM2.getDate()).getDelay(); SpacecraftState stateM1 = shiftState(state, orbitType, angleType, -1 * steps[i], i); final Vector3D positionM1 = stateM1.getPosition(); final TrackingCoordinates trackingCoordinatesM1 = station.getBaseFrame(). getTrackingCoordinates(positionM1, stateM1.getFrame(), stateM1.getDate()); double delayM1 = model.pathDelay(trackingCoordinatesM1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), stateM1.getDate()); + model.getParameters(), stateM1.getDate()).getDelay(); SpacecraftState stateP1 = shiftState(state, orbitType, angleType, 1 * steps[i], i); final Vector3D positionP1 = stateP1.getPosition(); final TrackingCoordinates trackingCoordinatesP1 = station.getBaseFrame(). getTrackingCoordinates(positionP1, stateP1.getFrame(), stateP1.getDate()); double delayP1 = model.pathDelay(trackingCoordinatesP1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), stateP1.getDate()); + model.getParameters(), stateP1.getDate()).getDelay(); SpacecraftState stateP2 = shiftState(state, orbitType, angleType, 2 * steps[i], i); final Vector3D positionP2 = stateP2.getPosition(); final TrackingCoordinates trackingCoordinatesP2 = station.getBaseFrame(). getTrackingCoordinates(positionP2, stateP2.getFrame(), stateP2.getDate()); double delayP2 = model.pathDelay(trackingCoordinatesP2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), stateP2.getDate()); + model.getParameters(), stateP2.getDate()).getDelay(); SpacecraftState stateP3 = shiftState(state, orbitType, angleType, 3 * steps[i], i); final Vector3D positionP3 = stateP3.getPosition(); final TrackingCoordinates trackingCoordinatesP3 = station.getBaseFrame(). getTrackingCoordinates(positionP3, stateP3.getFrame(), stateP3.getDate()); double delayP3 = model.pathDelay(trackingCoordinatesP3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), stateP3.getDate()); + model.getParameters(), stateP3.getDate()).getDelay(); SpacecraftState stateP4 = shiftState(state, orbitType, angleType, 4 * steps[i], i); final Vector3D positionP4 = stateP4.getPosition(); final TrackingCoordinates trackingCoordinatesP4 = station.getBaseFrame(). getTrackingCoordinates(positionP4, stateP4.getFrame(), stateP4.getDate()); double delayP4 = model.pathDelay(trackingCoordinatesP4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), stateP4.getDate()); + model.getParameters(), stateP4.getDate()).getDelay(); fillJacobianColumn(refDeriv, i, orbitType, angleType, steps[i], delayM4, delayM3, delayM2, delayM1, @@ -339,7 +339,7 @@ private void doTestParametersDerivatives(String parameterName, double tolerance) final FieldGeodeticPoint dsPoint = new FieldGeodeticPoint<>(zero.add(point.getLatitude()), zero.add(point.getLongitude()), zero.add(point.getAltitude())); final DerivativeStructure delay = model.pathDelay(dsTrackingCoordinates, dsPoint, new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), - parameters, dsState.getDate()); + parameters, dsState.getDate()).getDelay(); final double[] compDeriv = delay.getAllDerivatives(); @@ -369,35 +369,35 @@ private void doTestParametersDerivatives(String parameterName, double tolerance) selected.setValue(p0 - 4 * h); double delayM4 = model.pathDelay(trackingCoordinates, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), state.getDate()); + model.getParameters(), state.getDate()).getDelay(); selected.setValue(p0 - 3 * h); double delayM3 = model.pathDelay(trackingCoordinates, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), state.getDate()); + model.getParameters(), state.getDate()).getDelay(); selected.setValue(p0 - 2 * h); double delayM2 = model.pathDelay(trackingCoordinates, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), state.getDate()); + model.getParameters(), state.getDate()).getDelay(); selected.setValue(p0 - 1 * h); double delayM1 = model.pathDelay(trackingCoordinates, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), state.getDate()); + model.getParameters(), state.getDate()).getDelay(); selected.setValue(p0 + 1 * h); double delayP1 = model.pathDelay(trackingCoordinates, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), state.getDate()); + model.getParameters(), state.getDate()).getDelay(); selected.setValue(p0 + 2 * h); double delayP2 = model.pathDelay(trackingCoordinates, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), state.getDate()); + model.getParameters(), state.getDate()).getDelay(); selected.setValue(p0 + 3 * h); double delayP3 = model.pathDelay(trackingCoordinates, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), state.getDate()); + model.getParameters(), state.getDate()).getDelay(); selected.setValue(p0 + 4 * h); double delayP4 = model.pathDelay(trackingCoordinates, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), state.getDate()); + model.getParameters(), state.getDate()).getDelay(); fillJacobianColumn(refDeriv, 0, orbitType, angleType, h, delayM4, delayM3, delayM2, delayM1, diff --git a/src/test/java/org/orekit/models/earth/troposphere/FieldMendesPavlisModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/FieldMendesPavlisModelTest.java index 9c99233ebf..c3f67e1d51 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/FieldMendesPavlisModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/FieldMendesPavlisModelTest.java @@ -206,7 +206,7 @@ private > void doTestDelay(final Field fiel zero), point, new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), - model.getParameters(field), date); + model.getParameters(field), date).getDelay(); Assertions.assertTrue(Precision.compareTo(path.getReal(), 20d, epsilon) < 0); Assertions.assertTrue(Precision.compareTo(path.getReal(), 0d, epsilon) > 0); } @@ -229,7 +229,7 @@ private > void doTestFixedHeight(final Field(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), - model.getParameters(field), date); + model.getParameters(field), date).getDelay(); Assertions.assertTrue(Precision.compareTo(delay.getReal(), lastDelay.getReal(), epsilon) < 0); lastDelay = delay; } @@ -287,7 +287,7 @@ public void testDelayStateDerivatives() { final FieldGeodeticPoint dsPoint = new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), zero.add(height)); final DerivativeStructure delay = model.pathDelay(dsTrackingCoordinates, dsPoint, new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), - model.getParameters(field, dsDate), dsDate); + model.getParameters(field, dsDate), dsDate).getDelay(); final double[] compDeriv = delay.getAllDerivatives(); @@ -307,56 +307,56 @@ public void testDelayStateDerivatives() { final TrackingCoordinates trackingCoordinatesM4 = station.getBaseFrame(). getTrackingCoordinates(positionM4, stateM4.getFrame(), stateM4.getDate()); double delayM4 = model.pathDelay(trackingCoordinatesM4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), stateM4.getDate()); + model.getParameters(), stateM4.getDate()).getDelay(); SpacecraftState stateM3 = shiftState(state, orbitType, angleType, -3 * steps[i], i); final Vector3D positionM3 = stateM3.getPosition(); final TrackingCoordinates trackingCoordinatesM3 = station.getBaseFrame(). getTrackingCoordinates(positionM3, stateM3.getFrame(), stateM3.getDate()); double delayM3 = model.pathDelay(trackingCoordinatesM3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), stateM3.getDate()); + model.getParameters(), stateM3.getDate()).getDelay(); SpacecraftState stateM2 = shiftState(state, orbitType, angleType, -2 * steps[i], i); final Vector3D positionM2 = stateM2.getPosition(); final TrackingCoordinates trackingCoordinatesM2 = station.getBaseFrame(). getTrackingCoordinates(positionM2, stateM2.getFrame(), stateM2.getDate()); double delayM2 = model.pathDelay(trackingCoordinatesM2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), stateM2.getDate()); + model.getParameters(), stateM2.getDate()).getDelay(); SpacecraftState stateM1 = shiftState(state, orbitType, angleType, -1 * steps[i], i); final Vector3D positionM1 = stateM1.getPosition(); final TrackingCoordinates trackingCoordinatesM1 = station.getBaseFrame(). getTrackingCoordinates(positionM1, stateM1.getFrame(), stateM1.getDate()); double delayM1 = model.pathDelay(trackingCoordinatesM1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), stateM1.getDate()); + model.getParameters(), stateM1.getDate()).getDelay(); SpacecraftState stateP1 = shiftState(state, orbitType, angleType, 1 * steps[i], i); final Vector3D positionP1 = stateP1.getPosition(); final TrackingCoordinates trackingCoordinatesP1 = station.getBaseFrame(). getTrackingCoordinates(positionP1, stateP1.getFrame(), stateP1.getDate()); double delayP1 = model.pathDelay(trackingCoordinatesP1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), stateP1.getDate()); + model.getParameters(), stateP1.getDate()).getDelay(); SpacecraftState stateP2 = shiftState(state, orbitType, angleType, 2 * steps[i], i); final Vector3D positionP2 = stateP2.getPosition(); final TrackingCoordinates trackingCoordinatesP2 = station.getBaseFrame(). getTrackingCoordinates(positionP2, stateP2.getFrame(), stateP2.getDate()); double delayP2 = model.pathDelay(trackingCoordinatesP2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), stateP2.getDate()); + model.getParameters(), stateP2.getDate()).getDelay(); SpacecraftState stateP3 = shiftState(state, orbitType, angleType, 3 * steps[i], i); final Vector3D positionP3 = stateP3.getPosition(); final TrackingCoordinates trackingCoordinatesP3 = station.getBaseFrame(). getTrackingCoordinates(positionP3, stateP3.getFrame(), stateP3.getDate()); double delayP3 = model.pathDelay(trackingCoordinatesP3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), stateP3.getDate()); + model.getParameters(), stateP3.getDate()).getDelay(); SpacecraftState stateP4 = shiftState(state, orbitType, angleType, 4 * steps[i], i); final Vector3D positionP4 = stateP4.getPosition(); final TrackingCoordinates trackingCoordinatesP4 = station.getBaseFrame(). getTrackingCoordinates(positionP4, stateP4.getFrame(), stateP4.getDate()); double delayP4 = model.pathDelay(trackingCoordinatesP4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), stateP4.getDate()); + model.getParameters(), stateP4.getDate()).getDelay(); fillJacobianColumn(refDeriv, i, orbitType, angleType, steps[i], delayM4, delayM3, delayM2, delayM1, diff --git a/src/test/java/org/orekit/models/earth/troposphere/FieldViennaOneModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/FieldViennaOneModelTest.java index aa15214191..7e318b7af9 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/FieldViennaOneModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/FieldViennaOneModelTest.java @@ -147,7 +147,7 @@ private > void doTestDelay(final Field fiel zero), point, new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), - model.getParameters(field), date); + model.getParameters(field), date).getDelay(); Assertions.assertTrue(Precision.compareTo(path.getReal(), 20d, epsilon) < 0); Assertions.assertTrue(Precision.compareTo(path.getReal(), 0d, epsilon) > 0); } @@ -172,7 +172,7 @@ private > void doTestFixedHeight(final Field(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), - model.getParameters(field), date); + model.getParameters(field), date).getDelay(); Assertions.assertTrue(Precision.compareTo(delay.getReal(), lastDelay.getReal(), epsilon) < 0); lastDelay = delay; } @@ -233,7 +233,7 @@ public void testDelayStateDerivatives() { final FieldGeodeticPoint dsPoint = new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), zero.add(height)); final DerivativeStructure delay = model.pathDelay(dsTrackingCoordinates, dsPoint, new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), - model.getParameters(field), dsDate); + model.getParameters(field), dsDate).getDelay(); final double[] compDelay = delay.getAllDerivatives(); @@ -253,56 +253,56 @@ public void testDelayStateDerivatives() { final TrackingCoordinates trackingCoordinatesM4 = station.getBaseFrame(). getTrackingCoordinates(positionM4, stateM4.getFrame(), stateM4.getDate()); double delayM4 = model.pathDelay(trackingCoordinatesM4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), stateM4.getDate()); + model.getParameters(), stateM4.getDate()).getDelay(); SpacecraftState stateM3 = shiftState(state, orbitType, angleType, -3 * steps[i], i); final Vector3D positionM3 = stateM3.getPosition(); final TrackingCoordinates trackingCoordinatesM3 = station.getBaseFrame(). getTrackingCoordinates(positionM3, stateM3.getFrame(), stateM3.getDate()); double delayM3 = model.pathDelay(trackingCoordinatesM3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), stateM3.getDate()); + model.getParameters(), stateM3.getDate()).getDelay(); SpacecraftState stateM2 = shiftState(state, orbitType, angleType, -2 * steps[i], i); final Vector3D positionM2 = stateM2.getPosition(); final TrackingCoordinates trackingCoordinatesM2 = station.getBaseFrame(). getTrackingCoordinates(positionM2, stateM2.getFrame(), stateM2.getDate()); double delayM2 = model.pathDelay(trackingCoordinatesM2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), stateM2.getDate()); + model.getParameters(), stateM2.getDate()).getDelay(); SpacecraftState stateM1 = shiftState(state, orbitType, angleType, -1 * steps[i], i); final Vector3D positionM1 = stateM1.getPosition(); final TrackingCoordinates trackingCoordinatesM1 = station.getBaseFrame(). getTrackingCoordinates(positionM1, stateM1.getFrame(), stateM1.getDate()); double delayM1 = model.pathDelay(trackingCoordinatesM1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), stateM1.getDate()); + model.getParameters(), stateM1.getDate()).getDelay(); SpacecraftState stateP1 = shiftState(state, orbitType, angleType, 1 * steps[i], i); final Vector3D positionP1 = stateP1.getPosition(); final TrackingCoordinates trackingCoordinatesP1 = station.getBaseFrame(). getTrackingCoordinates(positionP1, stateP1.getFrame(), stateP1.getDate()); double delayP1 = model.pathDelay(trackingCoordinatesP1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), stateP1.getDate()); + model.getParameters(), stateP1.getDate()).getDelay(); SpacecraftState stateP2 = shiftState(state, orbitType, angleType, 2 * steps[i], i); final Vector3D positionP2 = stateP2.getPosition(); final TrackingCoordinates trackingCoordinatesP2 = station.getBaseFrame(). getTrackingCoordinates(positionP2, stateP2.getFrame(), stateP2.getDate()); double delayP2 = model.pathDelay(trackingCoordinatesP2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), stateP2.getDate()); + model.getParameters(), stateP2.getDate()).getDelay(); SpacecraftState stateP3 = shiftState(state, orbitType, angleType, 3 * steps[i], i); final Vector3D positionP3 = stateP3.getPosition(); final TrackingCoordinates trackingCoordinatesP3 = station.getBaseFrame(). getTrackingCoordinates(positionP3, stateP3.getFrame(), stateP3.getDate()); double delayP3 = model.pathDelay(trackingCoordinatesP3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), stateP3.getDate()); + model.getParameters(), stateP3.getDate()).getDelay(); SpacecraftState stateP4 = shiftState(state, orbitType, angleType, 4 * steps[i], i); final Vector3D positionP4 = stateP4.getPosition(); final TrackingCoordinates trackingCoordinatesP4 = station.getBaseFrame(). getTrackingCoordinates(positionP4, stateP4.getFrame(), stateP4.getDate()); double delayP4 = model.pathDelay(trackingCoordinatesP4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), stateP4.getDate()); + model.getParameters(), stateP4.getDate()).getDelay(); fillJacobianColumn(refDeriv, i, orbitType, angleType, steps[i], delayM4, delayM3, delayM2, delayM1, diff --git a/src/test/java/org/orekit/models/earth/troposphere/FieldViennaThreeModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/FieldViennaThreeModelTest.java index 5ddd0bf6a5..b77d5a0d25 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/FieldViennaThreeModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/FieldViennaThreeModelTest.java @@ -252,12 +252,15 @@ private > void doTestDelay(final Field fiel final double[] z = {2.1993, 0.0690}; final FieldGeodeticPoint point = new FieldGeodeticPoint<>(zero.add(FastMath.toRadians(37.5)), zero.add(FastMath.toRadians(277.5)), zero.add(height)); ViennaThreeModel model = new ViennaThreeModel(a, z); - final T path = model.pathDelay(new FieldTrackingCoordinates(zero, zero.newInstance(FastMath.toRadians(elevation)), zero), - point, - new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), - model.getParameters(field), date); - Assertions.assertTrue(Precision.compareTo(path.getReal(), 20d, epsilon) < 0); - Assertions.assertTrue(Precision.compareTo(path.getReal(), 0d, epsilon) > 0); + final FieldTroposphericDelay delay = model.pathDelay(new FieldTrackingCoordinates(zero, zero.newInstance(FastMath.toRadians(elevation)), zero), + point, + new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + model.getParameters(field), date); + Assertions.assertEquals( 2.1993, delay.getZh().getReal(), 1.0e-4); + Assertions.assertEquals( 0.069, delay.getZw().getReal(), 1.0e-4); + Assertions.assertEquals(12.2124, delay.getSh().getReal(), 1.0e-4); + Assertions.assertEquals( 0.3916, delay.getSw().getReal(), 1.0e-4); + Assertions.assertEquals(12.6041, delay.getDelay().getReal(), 1.0e-4); } @Test @@ -278,7 +281,7 @@ private > void doTestFixedHeight(final Field(zero, zero.newInstance(FastMath.toRadians(elev)), zero), point, new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), - model.getParameters(field), date); + model.getParameters(field), date).getDelay(); Assertions.assertTrue(Precision.compareTo(delay.getReal(), lastDelay.getReal(), epsilon) < 0); lastDelay = delay; } @@ -339,7 +342,7 @@ public void testDelayStateDerivatives() { final FieldGeodeticPoint dsPoint = new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), zero.add(height)); final DerivativeStructure delay = model.pathDelay(dsTrackingCoordinates, dsPoint, new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), - model.getParameters(field), dsDate); + model.getParameters(field), dsDate).getDelay(); final double[] compDelay = delay.getAllDerivatives(); @@ -359,56 +362,56 @@ public void testDelayStateDerivatives() { final TrackingCoordinates trackingCoordinatesM4 = station.getBaseFrame(). getTrackingCoordinates(positionM4, stateM4.getFrame(), stateM4.getDate()); double delayM4 = model.pathDelay(trackingCoordinatesM4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), stateM4.getDate()); + model.getParameters(), stateM4.getDate()).getDelay(); SpacecraftState stateM3 = shiftState(state, orbitType, angleType, -3 * steps[i], i); final Vector3D positionM3 = stateM3.getPosition(); final TrackingCoordinates trackingCoordinatesM3 = station.getBaseFrame(). getTrackingCoordinates(positionM3, stateM3.getFrame(), stateM3.getDate()); double delayM3 = model.pathDelay(trackingCoordinatesM3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), stateM3.getDate()); + model.getParameters(), stateM3.getDate()).getDelay(); SpacecraftState stateM2 = shiftState(state, orbitType, angleType, -2 * steps[i], i); final Vector3D positionM2 = stateM2.getPosition(); final TrackingCoordinates trackingCoordinatesM2 = station.getBaseFrame(). getTrackingCoordinates(positionM2, stateM2.getFrame(), stateM2.getDate()); double delayM2 = model.pathDelay(trackingCoordinatesM2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), stateM2.getDate()); + model.getParameters(), stateM2.getDate()).getDelay(); SpacecraftState stateM1 = shiftState(state, orbitType, angleType, -1 * steps[i], i); final Vector3D positionM1 = stateM1.getPosition(); final TrackingCoordinates trackingCoordinatesM1 = station.getBaseFrame(). getTrackingCoordinates(positionM1, stateM1.getFrame(), stateM1.getDate()); double delayM1 = model.pathDelay(trackingCoordinatesM1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), stateM1.getDate()); + model.getParameters(), stateM1.getDate()).getDelay(); SpacecraftState stateP1 = shiftState(state, orbitType, angleType, 1 * steps[i], i); final Vector3D positionP1 = stateP1.getPosition(); final TrackingCoordinates trackingCoordinatesP1 = station.getBaseFrame(). getTrackingCoordinates(positionP1, stateP1.getFrame(), stateP1.getDate()); double delayP1 = model.pathDelay(trackingCoordinatesP1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), stateP1.getDate()); + model.getParameters(), stateP1.getDate()).getDelay(); SpacecraftState stateP2 = shiftState(state, orbitType, angleType, 2 * steps[i], i); final Vector3D positionP2 = stateP2.getPosition(); final TrackingCoordinates trackingCoordinatesP2 = station.getBaseFrame(). getTrackingCoordinates(positionP2, stateP2.getFrame(), stateP2.getDate()); double delayP2 = model.pathDelay(trackingCoordinatesP2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), stateP2.getDate()); + model.getParameters(), stateP2.getDate()).getDelay(); SpacecraftState stateP3 = shiftState(state, orbitType, angleType, 3 * steps[i], i); final Vector3D positionP3 = stateP3.getPosition(); final TrackingCoordinates trackingCoordinatesP3 = station.getBaseFrame(). getTrackingCoordinates(positionP3, stateP3.getFrame(), stateP3.getDate()); double delayP3 = model.pathDelay(trackingCoordinatesP3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), stateP3.getDate()); + model.getParameters(), stateP3.getDate()).getDelay(); SpacecraftState stateP4 = shiftState(state, orbitType, angleType, 4 * steps[i], i); final Vector3D positionP4 = stateP4.getPosition(); final TrackingCoordinates trackingCoordinatesP4 = station.getBaseFrame(). getTrackingCoordinates(positionP4, stateP4.getFrame(), stateP4.getDate()); double delayP4 = model.pathDelay(trackingCoordinatesP4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), stateP4.getDate()); + model.getParameters(), stateP4.getDate()).getDelay(); fillJacobianColumn(refDeriv, i, orbitType, angleType, steps[i], delayM4, delayM3, delayM2, delayM1, diff --git a/src/test/java/org/orekit/models/earth/troposphere/FixedTroposphericModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/FixedTroposphericModelTest.java index 16c2b75b01..6d4ffe1262 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/FixedTroposphericModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/FixedTroposphericModelTest.java @@ -43,41 +43,53 @@ public class FixedTroposphericModelTest { @Test public void testModel() { // check with (artificial) test values from tropospheric-delay.txt - Assertions.assertEquals(2.5d, model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(90d), 0.0), - new GeodeticPoint(0., 0., 0.), - TroposphericModelUtils.STANDARD_ATMOSPHERE, - null, AbsoluteDate.J2000_EPOCH), epsilon); - Assertions.assertEquals(20.8d, model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(0d), 0.0), - new GeodeticPoint(0., 0., 0.), - TroposphericModelUtils.STANDARD_ATMOSPHERE, - null, AbsoluteDate.J2000_EPOCH), epsilon); - - Assertions.assertEquals(12.1d, model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(0d), 0.0), - new GeodeticPoint(0., 0., 5000.), - TroposphericModelUtils.STANDARD_ATMOSPHERE, - null, AbsoluteDate.J2000_EPOCH), epsilon); - Assertions.assertEquals(2.5d, model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(90d), 0.0), - new GeodeticPoint(0., 0., 5000.), - TroposphericModelUtils.STANDARD_ATMOSPHERE, - null, AbsoluteDate.J2000_EPOCH), epsilon); + Assertions.assertEquals(2.5d, + model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(90d), 0.0), + new GeodeticPoint(0., 0., 0.), + TroposphericModelUtils.STANDARD_ATMOSPHERE, + null, AbsoluteDate.J2000_EPOCH).getDelay(), + epsilon); + Assertions.assertEquals(20.8d, + model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(0d), 0.0), + new GeodeticPoint(0., 0., 0.), + TroposphericModelUtils.STANDARD_ATMOSPHERE, + null, AbsoluteDate.J2000_EPOCH).getDelay(), + epsilon); + + Assertions.assertEquals(12.1d, + model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(0d), 0.0), + new GeodeticPoint(0., 0., 5000.), + TroposphericModelUtils.STANDARD_ATMOSPHERE, + null, AbsoluteDate.J2000_EPOCH).getDelay(), + epsilon); + Assertions.assertEquals(2.5d, + model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(90d), 0.0), + new GeodeticPoint(0., 0., 5000.), + TroposphericModelUtils.STANDARD_ATMOSPHERE, + null, AbsoluteDate.J2000_EPOCH).getDelay(), + epsilon); // interpolation between two elevation angles in the table final double delay = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(35d), 0.0), new GeodeticPoint(0., 0., 1200.), TroposphericModelUtils.STANDARD_ATMOSPHERE, - null, AbsoluteDate.J2000_EPOCH); + null, AbsoluteDate.J2000_EPOCH).getDelay(); Assertions.assertTrue(Precision.compareTo(delay, 6.4d, epsilon) < 0); Assertions.assertTrue(Precision.compareTo(delay, 3.2d, epsilon) > 0); // sanity checks - Assertions.assertEquals(12.1d, model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(-20d), 0.0), - new GeodeticPoint(0., 0., 5000.), - TroposphericModelUtils.STANDARD_ATMOSPHERE, - null, AbsoluteDate.J2000_EPOCH), epsilon); - Assertions.assertEquals(2.5d, model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(90d),0.0), - new GeodeticPoint(0., 0., 100000.), - TroposphericModelUtils.STANDARD_ATMOSPHERE, - null, AbsoluteDate.J2000_EPOCH), epsilon); + Assertions.assertEquals(12.1d, + model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(-20d), 0.0), + new GeodeticPoint(0., 0., 5000.), + TroposphericModelUtils.STANDARD_ATMOSPHERE, + null, AbsoluteDate.J2000_EPOCH).getDelay(), + epsilon); + Assertions.assertEquals(2.5d, + model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(90d),0.0), + new GeodeticPoint(0., 0., 100000.), + TroposphericModelUtils.STANDARD_ATMOSPHERE, + null, AbsoluteDate.J2000_EPOCH).getDelay(), + epsilon); } @Test @@ -88,41 +100,53 @@ public void testFieldModel() { private > void doTestFieldModel(final Field field) { final T zero = field.getZero(); // check with (artificial) test values from tropospheric-delay.txt - Assertions.assertEquals(2.5d, model.pathDelay(new FieldTrackingCoordinates<>(zero, zero.newInstance(FastMath.toRadians(90d)), zero), - new FieldGeodeticPoint(zero, zero, zero), - new FieldPressureTemperatureHumidity(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), - null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), epsilon); - Assertions.assertEquals(20.8d, model.pathDelay(new FieldTrackingCoordinates<>(zero, zero.newInstance(FastMath.toRadians(0d)), zero), - new FieldGeodeticPoint(zero, zero, zero), - new FieldPressureTemperatureHumidity(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), - null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), epsilon); - - Assertions.assertEquals(12.1d, model.pathDelay(new FieldTrackingCoordinates<>(zero, zero.newInstance(FastMath.toRadians(0d)), zero), - new FieldGeodeticPoint(zero, zero, zero.add(5000.0)), - new FieldPressureTemperatureHumidity(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), - null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), epsilon); - Assertions.assertEquals(2.5d, model.pathDelay(new FieldTrackingCoordinates<>(zero, zero.newInstance(FastMath.toRadians(90d)), zero), - new FieldGeodeticPoint(zero, zero, zero.add(5000.0)), - new FieldPressureTemperatureHumidity(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), - null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), epsilon); + Assertions.assertEquals(2.5d, + model.pathDelay(new FieldTrackingCoordinates<>(zero, zero.newInstance(FastMath.toRadians(90d)), zero), + new FieldGeodeticPoint(zero, zero, zero), + new FieldPressureTemperatureHumidity(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + null, FieldAbsoluteDate.getJ2000Epoch(field)).getDelay().getReal(), + epsilon); + Assertions.assertEquals(20.8d, + model.pathDelay(new FieldTrackingCoordinates<>(zero, zero.newInstance(FastMath.toRadians(0d)), zero), + new FieldGeodeticPoint(zero, zero, zero), + new FieldPressureTemperatureHumidity(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + null, FieldAbsoluteDate.getJ2000Epoch(field)).getDelay().getReal(), + epsilon); + + Assertions.assertEquals(12.1d, + model.pathDelay(new FieldTrackingCoordinates<>(zero, zero.newInstance(FastMath.toRadians(0d)), zero), + new FieldGeodeticPoint(zero, zero, zero.add(5000.0)), + new FieldPressureTemperatureHumidity(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + null, FieldAbsoluteDate.getJ2000Epoch(field)).getDelay().getReal(), + epsilon); + Assertions.assertEquals(2.5d, + model.pathDelay(new FieldTrackingCoordinates<>(zero, zero.newInstance(FastMath.toRadians(90d)), zero), + new FieldGeodeticPoint(zero, zero, zero.add(5000.0)), + new FieldPressureTemperatureHumidity(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + null, FieldAbsoluteDate.getJ2000Epoch(field)).getDelay().getReal(), + epsilon); // interpolation between two elevation angles in the table final double delay = model.pathDelay(new FieldTrackingCoordinates<>(zero, zero.newInstance(FastMath.toRadians(35d)), zero), new FieldGeodeticPoint(zero, zero, zero.add(1200.0)), new FieldPressureTemperatureHumidity(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), - null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(); + null, FieldAbsoluteDate.getJ2000Epoch(field)).getDelay().getReal(); Assertions.assertTrue(Precision.compareTo(delay, 6.4d, epsilon) < 0); Assertions.assertTrue(Precision.compareTo(delay, 3.2d, epsilon) > 0); // sanity checks - Assertions.assertEquals(12.1d, model.pathDelay(new FieldTrackingCoordinates<>(zero, zero.newInstance(FastMath.toRadians(-20d)), zero), - new FieldGeodeticPoint(zero, zero, zero.add(5000.0)), - new FieldPressureTemperatureHumidity(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), - null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), epsilon); - Assertions.assertEquals(2.5d, model.pathDelay(new FieldTrackingCoordinates<>(zero, zero.newInstance(FastMath.toRadians(90d)), zero), - new FieldGeodeticPoint(zero, zero, zero.add(100000.0)), - new FieldPressureTemperatureHumidity(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), - null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), epsilon); + Assertions.assertEquals(12.1d, + model.pathDelay(new FieldTrackingCoordinates<>(zero, zero.newInstance(FastMath.toRadians(-20d)), zero), + new FieldGeodeticPoint(zero, zero, zero.add(5000.0)), + new FieldPressureTemperatureHumidity(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + null, FieldAbsoluteDate.getJ2000Epoch(field)).getDelay().getReal(), + epsilon); + Assertions.assertEquals(2.5d, + model.pathDelay(new FieldTrackingCoordinates<>(zero, zero.newInstance(FastMath.toRadians(90d)), zero), + new FieldGeodeticPoint(zero, zero, zero.add(100000.0)), + new FieldPressureTemperatureHumidity(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + null, FieldAbsoluteDate.getJ2000Epoch(field)).getDelay().getReal(), + epsilon); } @Test @@ -130,10 +154,10 @@ public void testSymmetry() { for (int elevation = 0; elevation < 90; elevation += 10) { final double delay1 = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elevation), 0.0), new GeodeticPoint(0., 0., 100.), - TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH); + TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH).getDelay(); final double delay2 = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(180 - elevation), 0.0), new GeodeticPoint(0., 0., 100.), - TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH); + TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH).getDelay(); Assertions.assertEquals(delay1, delay2, epsilon); } @@ -151,12 +175,12 @@ private > void doTestFieldSymmetry(final Field new FieldGeodeticPoint(zero, zero, zero.add(100.)), new FieldPressureTemperatureHumidity(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), null, - FieldAbsoluteDate.getJ2000Epoch(field)); + FieldAbsoluteDate.getJ2000Epoch(field)).getDelay(); final T delay2 = model.pathDelay(new FieldTrackingCoordinates<>(zero, zero.newInstance(FastMath.toRadians(180 - elevation)), zero), new FieldGeodeticPoint(zero, zero, zero.add(100.)), new FieldPressureTemperatureHumidity(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), null, - FieldAbsoluteDate.getJ2000Epoch(field)); + FieldAbsoluteDate.getJ2000Epoch(field)).getDelay(); Assertions.assertEquals(delay1.getReal(), delay2.getReal(), epsilon); } diff --git a/src/test/java/org/orekit/models/earth/troposphere/MariniMurrayModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/MariniMurrayModelTest.java index b40f4025f2..30fc56cbf5 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/MariniMurrayModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/MariniMurrayModelTest.java @@ -62,7 +62,7 @@ public void testDelay() { TroposphericModel model = MariniMurrayModel.getStandardModel(694.3, TroposphericModelUtils.NANO_M); final double path = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elevation), 0.0), new GeodeticPoint(latitude, longitude, height), - TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH); + TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH).getDelay(); Assertions.assertTrue(Precision.compareTo(path, 20d, epsilon) < 0); Assertions.assertTrue(Precision.compareTo(path, 0d, epsilon) > 0); @@ -78,7 +78,7 @@ public void testDeprecatedConstructor1() { TroposphericModel model = MariniMurrayModel.getStandardModel(694.3); final double path = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elevation), 0.0), new GeodeticPoint(latitude, longitude, height), - TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH); + TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH).getDelay(); Assertions.assertTrue(Precision.compareTo(path, 20d, epsilon) < 0); Assertions.assertTrue(Precision.compareTo(path, 0d, epsilon) > 0); @@ -94,7 +94,7 @@ public void testDeprecatedConstructor2() { TroposphericModel model = new MariniMurrayModel(273.15 + 20, 1013.25, 0.5, 694.3); final double path = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elevation), 0.0), new GeodeticPoint(latitude, longitude, height), - TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH); + TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH).getDelay(); Assertions.assertTrue(Precision.compareTo(path, 20d, epsilon) < 0); Assertions.assertTrue(Precision.compareTo(path, 0d, epsilon) > 0); @@ -117,7 +117,7 @@ private > void doTestFieldDelay(final Field TroposphericModel model = MariniMurrayModel.getStandardModel(694.3, TroposphericModelUtils.NANO_M); final T path = model.pathDelay(trackingCoordinates, new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), height), new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), - null, FieldAbsoluteDate.getJ2000Epoch(field)); + null, FieldAbsoluteDate.getJ2000Epoch(field)).getDelay(); Assertions.assertTrue(Precision.compareTo(path.getReal(), 20d, epsilon) < 0); Assertions.assertTrue(Precision.compareTo(path.getReal(), 0d, epsilon) > 0); @@ -132,7 +132,7 @@ public void testFixedHeight() { for (double elev = 10d; elev < 90d; elev += 8d) { final double delay = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elev), 0.0), new GeodeticPoint(latitude, longitude, 350.0), - TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH); + TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH).getDelay(); Assertions.assertTrue(Precision.compareTo(delay, lastDelay, epsilon) < 0); lastDelay = delay; } @@ -153,7 +153,7 @@ private > void doTestFieldFixedHeight(final Fi final T delay = model.pathDelay(new FieldTrackingCoordinates<>(zero, zero.newInstance(FastMath.toRadians(elev)), zero), new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), zero.add(350.0)), new FieldPressureTemperatureHumidity(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), - null, FieldAbsoluteDate.getJ2000Epoch(field)); + null, FieldAbsoluteDate.getJ2000Epoch(field)).getDelay(); Assertions.assertTrue(Precision.compareTo(delay.getReal(), lastDelay.getReal(), epsilon) < 0); lastDelay = delay; } @@ -170,7 +170,7 @@ public void compareExpectedValues() { double expectedValue = 13.26069; double actualValue = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elevation), 0.0), new GeodeticPoint(latitude, longitude, height), - TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH); + TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH).getDelay(); Assertions.assertEquals(expectedValue, actualValue, 1.0e-5); } @@ -192,7 +192,7 @@ private > void doCompareFieldExpectedValues(fi T actualValue = model.pathDelay(new FieldTrackingCoordinates<>(zero, elevation, zero), new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), height), new FieldPressureTemperatureHumidity(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), - null, FieldAbsoluteDate.getJ2000Epoch(field)); + null, FieldAbsoluteDate.getJ2000Epoch(field)).getDelay(); Assertions.assertEquals(expectedValue, actualValue.getReal(), 1.0e-5); } diff --git a/src/test/java/org/orekit/models/earth/troposphere/MendesPavlisModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/MendesPavlisModelTest.java index ed9778e33a..85d537de21 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/MendesPavlisModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/MendesPavlisModelTest.java @@ -162,7 +162,7 @@ public void testDelay() { final double path = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elevation), 0.0), point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), date); + model.getParameters(), date).getDelay(); Assertions.assertTrue(Precision.compareTo(path, 20d, epsilon) < 0); Assertions.assertTrue(Precision.compareTo(path, 0d, epsilon) > 0); } @@ -178,7 +178,7 @@ public void testFixedHeight() { final double delay = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elev), 0.0), point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), date); + model.getParameters(), date).getDelay(); Assertions.assertTrue(Precision.compareTo(delay, lastDelay, epsilon) < 0); lastDelay = delay; } diff --git a/src/test/java/org/orekit/models/earth/troposphere/ModifiedHopfieldModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/ModifiedHopfieldModelTest.java index f489aa201a..31e1a6d0a5 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/ModifiedHopfieldModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/ModifiedHopfieldModelTest.java @@ -58,7 +58,7 @@ public void testFixedElevation() { final double delay = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(5), 0.0), new GeodeticPoint(0.0, 0.0, height), converter.convert(TroposphericModelUtils.STANDARD_ATMOSPHERE, height), - null, AbsoluteDate.J2000_EPOCH); + null, AbsoluteDate.J2000_EPOCH).getDelay(); Assertions.assertTrue(Precision.compareTo(delay, lastDelay, epsilon) < 0); lastDelay = delay; } @@ -85,7 +85,7 @@ private > void doTestFieldFixedElevation(final converter.convert(new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), zero.newInstance(height)), - null, FieldAbsoluteDate.getJ2000Epoch(field)); + null, FieldAbsoluteDate.getJ2000Epoch(field)).getDelay(); Assertions.assertTrue(Precision.compareTo(delay.getReal(), lastDelay.getReal(), epsilon) < 0); lastDelay = delay; } @@ -101,7 +101,7 @@ public void testFixedHeight() { final double delay = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elev), 0.0), new GeodeticPoint(0.0, 0.0, 350.0), TroposphericModelUtils.STANDARD_ATMOSPHERE, - null, AbsoluteDate.J2000_EPOCH); + null, AbsoluteDate.J2000_EPOCH).getDelay(); Assertions.assertTrue(Precision.compareTo(delay, lastDelay, epsilon) < 0); lastDelay = delay; } @@ -124,7 +124,7 @@ private > void doTestFieldFixedHeight(final Fi zero), new FieldGeodeticPoint<>(zero, zero, zero.newInstance(350.0)), new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), - null, FieldAbsoluteDate.getJ2000Epoch(field)); + null, FieldAbsoluteDate.getJ2000Epoch(field)).getDelay(); Assertions.assertTrue(Precision.compareTo(delay.getReal(), lastDelay.getReal(), epsilon) < 0); lastDelay = delay; } @@ -146,7 +146,7 @@ private > void doTestFieldVsNative(final Field final double delayN = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(e), 0.0), new GeodeticPoint(0, 0, h), converter.convert(TroposphericModelUtils.STANDARD_ATMOSPHERE, h), - null, AbsoluteDate.J2000_EPOCH); + null, AbsoluteDate.J2000_EPOCH).getDelay(); final T delayT = model.pathDelay(new FieldTrackingCoordinates<>(zero, zero.newInstance(FastMath.toRadians(e)), zero), @@ -154,7 +154,7 @@ private > void doTestFieldVsNative(final Field converter.convert(new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), zero.newInstance(h)), - null, FieldAbsoluteDate.getJ2000Epoch(field)); + null, FieldAbsoluteDate.getJ2000Epoch(field)).getDelay(); Assertions.assertEquals(delayN, delayT.getReal(), epsilon); } } @@ -169,11 +169,11 @@ public void testNegativeHeight() { Assertions.assertEquals(model.pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), new GeodeticPoint(0.0, 0.0, 0.0), TroposphericModelUtils.STANDARD_ATMOSPHERE, - null, AbsoluteDate.J2000_EPOCH), + null, AbsoluteDate.J2000_EPOCH).getDelay(), model.pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), new GeodeticPoint(0.0, 0.0, height), TroposphericModelUtils.STANDARD_ATMOSPHERE, - null, AbsoluteDate.J2000_EPOCH), + null, AbsoluteDate.J2000_EPOCH).getDelay(), 1.e-10); } } @@ -194,13 +194,13 @@ private > void doTestFieldNegativeHeight(final zero), new FieldGeodeticPoint<>(zero, zero, zero), new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), - null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), + null, FieldAbsoluteDate.getJ2000Epoch(field)).getDelay().getReal(), model.pathDelay(new FieldTrackingCoordinates<>(zero, zero.newInstance(elevation), zero), new FieldGeodeticPoint<>(zero, zero, height), new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), - null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), + null, FieldAbsoluteDate.getJ2000Epoch(field)).getDelay().getReal(), 1.e-10); } } @@ -227,7 +227,7 @@ public void compareExpectedValues() { double actualValue = model.pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), location, converter.convert(TroposphericModelUtils.STANDARD_ATMOSPHERE, height), - null, date); + null, date).getDelay(); Assertions.assertEquals(expectedValue, actualValue, epsilon, "For height=" + height + " elevation = " + FastMath.toDegrees(elevation) + " precision not met"); } @@ -263,7 +263,7 @@ private > void doCompareFieldExpectedValues(fi converter.convert(new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), height), - null, date); + null, date).getDelay(); Assertions.assertEquals(expectedValue, actualValue.getReal(), epsilon, "For height=" + height + " elevation = " + FastMath.toDegrees(elevation.getReal()) + " precision not met"); } diff --git a/src/test/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModelTest.java index 6067c8db2d..4a9971e269 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModelTest.java @@ -59,7 +59,7 @@ public void testFixedElevation() { final double delay = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(5), 0.0), new GeodeticPoint(0.0, 0.0, height), TroposphericModelUtils.STANDARD_ATMOSPHERE, - null, AbsoluteDate.J2000_EPOCH); + null, AbsoluteDate.J2000_EPOCH).getDelay(); Assertions.assertTrue(Precision.compareTo(delay, lastDelay, epsilon) < 0); lastDelay = delay; } @@ -82,7 +82,7 @@ private > void doTestFieldFixedElevation(final zero), new FieldGeodeticPoint<>(zero, zero, zero.add(height)), new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), - null, FieldAbsoluteDate.getJ2000Epoch(field)); + null, FieldAbsoluteDate.getJ2000Epoch(field)).getDelay(); Assertions.assertTrue(Precision.compareTo(delay.getReal(), lastDelay.getReal(), epsilon) < 0); lastDelay = delay; } @@ -98,7 +98,7 @@ public void testFixedHeight() { final double delay = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elev), 0.0), new GeodeticPoint(0.0, 0.0, 350.0), TroposphericModelUtils.STANDARD_ATMOSPHERE, - null, AbsoluteDate.J2000_EPOCH); + null, AbsoluteDate.J2000_EPOCH).getDelay(); Assertions.assertTrue(Precision.compareTo(delay, lastDelay, epsilon) < 0); lastDelay = delay; } @@ -121,7 +121,7 @@ private > void doTestFieldFixedHeight(final Fi zero), new FieldGeodeticPoint<>(zero, zero, zero.add(350.0)), new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), - null, FieldAbsoluteDate.getJ2000Epoch(field)); + null, FieldAbsoluteDate.getJ2000Epoch(field)).getDelay(); Assertions.assertTrue(Precision.compareTo(delay.getReal(), lastDelay.getReal(), epsilon) < 0); lastDelay = delay; } @@ -181,11 +181,11 @@ public void compareDefaultAndLoaded() { double expectedValue = defaultModel.pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), new GeodeticPoint(0.0, 0.0, height), TroposphericModelUtils.STANDARD_ATMOSPHERE, - null, AbsoluteDate.J2000_EPOCH); + null, AbsoluteDate.J2000_EPOCH).getDelay(); double actualValue = loadedModel.pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), new GeodeticPoint(0.0, 0.0, height), TroposphericModelUtils.STANDARD_ATMOSPHERE, - null, AbsoluteDate.J2000_EPOCH); + null, AbsoluteDate.J2000_EPOCH).getDelay(); Assertions.assertEquals(expectedValue, actualValue, epsilon, "For height=" + height + " elevation = " + FastMath.toDegrees(elevation) + " precision not met"); } @@ -201,11 +201,11 @@ public void testNegativeHeight() { Assertions.assertEquals(model.pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), new GeodeticPoint(0.0, 0.0, 0.0), TroposphericModelUtils.STANDARD_ATMOSPHERE, - null, AbsoluteDate.J2000_EPOCH), + null, AbsoluteDate.J2000_EPOCH).getDelay(), model.pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), new GeodeticPoint(0.0, 0.0, height), TroposphericModelUtils.STANDARD_ATMOSPHERE, - null, AbsoluteDate.J2000_EPOCH), + null, AbsoluteDate.J2000_EPOCH).getDelay(), 1.e-10); } } @@ -226,13 +226,13 @@ private > void doTestFieldNegativeHeight(final zero), new FieldGeodeticPoint<>(zero, zero, zero), new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), - null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), + null, FieldAbsoluteDate.getJ2000Epoch(field)).getDelay().getReal(), model.pathDelay(new FieldTrackingCoordinates<>(zero, zero.newInstance(elevation), zero), new FieldGeodeticPoint<>(zero, zero, zero.add(height)), new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), - null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), + null, FieldAbsoluteDate.getJ2000Epoch(field)).getDelay().getReal(), 1.e-10); } } @@ -251,13 +251,14 @@ public void testIssue654LowElevation() { double lowElevationPathDelay = model.pathDelay(new TrackingCoordinates(0.0, 0.001, 0.0), new GeodeticPoint(0.0, 0.0, 0.0), TroposphericModelUtils.STANDARD_ATMOSPHERE, - null, AbsoluteDate.J2000_EPOCH); + null, AbsoluteDate.J2000_EPOCH).getDelay(); Assertions.assertTrue(lowElevationPathDelay > 0.); Assertions.assertEquals(model.pathDelay(new TrackingCoordinates(0.0, model.getLowElevationThreshold(), 0.0), new GeodeticPoint(0.0, 0.0, 0.0), TroposphericModelUtils.STANDARD_ATMOSPHERE, - null, AbsoluteDate.J2000_EPOCH), - lowElevationPathDelay, 1.e-10); + null, AbsoluteDate.J2000_EPOCH).getDelay(), + lowElevationPathDelay, + 1.e-10); } @Test @@ -271,13 +272,13 @@ private > void doTestFieldLowElevation(final F double lowElevationPathDelay = model.pathDelay(new FieldTrackingCoordinates<>(zero, elevation, zero), new FieldGeodeticPoint<>(zero, zero, zero), new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), - null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(); + null, FieldAbsoluteDate.getJ2000Epoch(field)).getDelay().getReal(); double thresholdElevationPathDelay = model.pathDelay(new FieldTrackingCoordinates<>(zero, zero.newInstance(model.getLowElevationThreshold()), zero), new FieldGeodeticPoint<>(zero, zero, zero), new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), - null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(); + null, FieldAbsoluteDate.getJ2000Epoch(field)).getDelay().getReal(); Assertions.assertTrue(lowElevationPathDelay > 0.); Assertions.assertEquals(thresholdElevationPathDelay, lowElevationPathDelay, 1.e-10); } @@ -313,7 +314,7 @@ public void compareExpectedValues() { double actualValue = model.pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), location, pth0Provider.getWeatherParamerers(location, date), - null, date); + null, date).getDelay(); Assertions.assertEquals(expectedValue, actualValue, epsilon, "For height=" + height + " elevation = " + FastMath.toDegrees(elevation) + " precision not met"); } @@ -354,7 +355,7 @@ private > void doCompareFieldExpectedValues(fi T actualValue = model.pathDelay(new FieldTrackingCoordinates<>(zero, elevation, zero), location, pth0Provider.getWeatherParamerers(location, date), - null, date); + null, date).getDelay(); Assertions.assertEquals(expectedValue, actualValue.getReal(), epsilon, "For height=" + height + " elevation = " + FastMath.toDegrees(elevation.getReal()) + " precision not met"); } @@ -370,11 +371,11 @@ public void testIssue572() { Assertions.assertEquals(model.pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), new GeodeticPoint(0.0, 0.0, 5000.0), TroposphericModelUtils.STANDARD_ATMOSPHERE, - null, AbsoluteDate.J2000_EPOCH), + null, AbsoluteDate.J2000_EPOCH).getDelay(), model.pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), new GeodeticPoint(0.0, 0.0, height), TroposphericModelUtils.STANDARD_ATMOSPHERE, - null, AbsoluteDate.J2000_EPOCH), + null, AbsoluteDate.J2000_EPOCH).getDelay(), 1.e-10); } } @@ -395,13 +396,13 @@ private > void doTestFieldIssue572(final Field zero), new FieldGeodeticPoint<>(zero, zero, zero.add(5000.0)), new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), - null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), + null, FieldAbsoluteDate.getJ2000Epoch(field)).getDelay().getReal(), model.pathDelay(new FieldTrackingCoordinates<>(zero, zero.newInstance(elevation), zero), new FieldGeodeticPoint<>(zero, zero, zero.add(height)), new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), - null, FieldAbsoluteDate.getJ2000Epoch(field)).getReal(), + null, FieldAbsoluteDate.getJ2000Epoch(field)).getDelay().getReal(), 1.e-10); } } diff --git a/src/test/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModelTest.java index aa1b025844..35c8ddcedb 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModelTest.java @@ -85,7 +85,7 @@ public void testFixedHeight() { final double delay = timeSpanModel.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elev), 0.0), point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - timeSpanModel.getParameters(), date); + timeSpanModel.getParameters(), date).getDelay(); Assertions.assertTrue(Precision.compareTo(delay, lastDelay, 1.0e-6) < 0); lastDelay = delay; } @@ -103,7 +103,7 @@ public void testDelay() { final double path = timeSpanModel.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elevation), 0.0), point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - timeSpanModel.getParameters(), date); + timeSpanModel.getParameters(), date).getDelay(); Assertions.assertTrue(Precision.compareTo(path, 20d, 1.0e-6) < 0); Assertions.assertTrue(Precision.compareTo(path, 0d, 1.0e-6) > 0); } @@ -177,7 +177,7 @@ private void doTestDelayStateDerivatives(final TroposphereMappingFunction func, final FieldGeodeticPoint dsPoint = new FieldGeodeticPoint<>(zero.add(point.getLatitude()), zero.add(point.getLongitude()), zero.add(point.getAltitude())); final DerivativeStructure delay = timeSpanModel.pathDelay(dsTrackingCoordinates, dsPoint, new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), - timeSpanModel.getParameters(field), dsDate); + timeSpanModel.getParameters(field), dsDate).getDelay(); final double[] compDeriv = delay.getAllDerivatives(); @@ -197,56 +197,56 @@ private void doTestDelayStateDerivatives(final TroposphereMappingFunction func, final TrackingCoordinates trackingCoordinatesM4 = station.getBaseFrame(). getTrackingCoordinates(positionM4, stateM4.getFrame(), stateM4.getDate()); double delayM4 = timeSpanModel.pathDelay(trackingCoordinatesM4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - timeSpanModel.getParameters(), stateM4.getDate()); + timeSpanModel.getParameters(), stateM4.getDate()).getDelay(); SpacecraftState stateM3 = shiftState(state, orbitType, angleType, -3 * steps[i], i); final Vector3D positionM3 = stateM3.getPosition(); final TrackingCoordinates trackingCoordinatesM3 = station.getBaseFrame(). getTrackingCoordinates(positionM3, stateM3.getFrame(), stateM3.getDate()); double delayM3 = timeSpanModel.pathDelay(trackingCoordinatesM3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - timeSpanModel.getParameters(), stateM3.getDate()); + timeSpanModel.getParameters(), stateM3.getDate()).getDelay(); SpacecraftState stateM2 = shiftState(state, orbitType, angleType, -2 * steps[i], i); final Vector3D positionM2 = stateM2.getPosition(); final TrackingCoordinates trackingCoordinatesM2 = station.getBaseFrame(). getTrackingCoordinates(positionM2, stateM2.getFrame(), stateM2.getDate()); double delayM2 = timeSpanModel.pathDelay(trackingCoordinatesM2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - timeSpanModel.getParameters(), stateM2.getDate()); + timeSpanModel.getParameters(), stateM2.getDate()).getDelay(); SpacecraftState stateM1 = shiftState(state, orbitType, angleType, -1 * steps[i], i); final Vector3D positionM1 = stateM1.getPosition(); final TrackingCoordinates trackingCoordinatesM1 = station.getBaseFrame(). getTrackingCoordinates(positionM1, stateM1.getFrame(), stateM1.getDate()); double delayM1 = timeSpanModel.pathDelay(trackingCoordinatesM1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - timeSpanModel.getParameters(), stateM1.getDate()); + timeSpanModel.getParameters(), stateM1.getDate()).getDelay(); SpacecraftState stateP1 = shiftState(state, orbitType, angleType, 1 * steps[i], i); final Vector3D positionP1 = stateP1.getPosition(); final TrackingCoordinates trackingCoordinatesP1 = station.getBaseFrame(). getTrackingCoordinates(positionP1, stateP1.getFrame(), stateP1.getDate()); double delayP1 = timeSpanModel.pathDelay(trackingCoordinatesP1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - timeSpanModel.getParameters(), stateP1.getDate()); + timeSpanModel.getParameters(), stateP1.getDate()).getDelay(); SpacecraftState stateP2 = shiftState(state, orbitType, angleType, 2 * steps[i], i); final Vector3D positionP2 = stateP2.getPosition(); final TrackingCoordinates trackingCoordinatesP2 = station.getBaseFrame(). getTrackingCoordinates(positionP2, stateP2.getFrame(), stateP2.getDate()); double delayP2 = timeSpanModel.pathDelay(trackingCoordinatesP2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - timeSpanModel.getParameters(), stateP2.getDate()); + timeSpanModel.getParameters(), stateP2.getDate()).getDelay(); SpacecraftState stateP3 = shiftState(state, orbitType, angleType, 3 * steps[i], i); final Vector3D positionP3 = stateP3.getPosition(); final TrackingCoordinates trackingCoordinatesP3 = station.getBaseFrame(). getTrackingCoordinates(positionP3, stateP3.getFrame(), stateP3.getDate()); double delayP3 = timeSpanModel.pathDelay(trackingCoordinatesP3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - timeSpanModel.getParameters(), stateP3.getDate()); + timeSpanModel.getParameters(), stateP3.getDate()).getDelay(); SpacecraftState stateP4 = shiftState(state, orbitType, angleType, 4 * steps[i], i); final Vector3D positionP4 = stateP4.getPosition(); final TrackingCoordinates trackingCoordinatesP4 = station.getBaseFrame(). getTrackingCoordinates(positionP4, stateP4.getFrame(), stateP4.getDate()); double delayP4 = timeSpanModel.pathDelay(trackingCoordinatesP4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - timeSpanModel.getParameters(), stateP4.getDate()); + timeSpanModel.getParameters(), stateP4.getDate()).getDelay(); fillJacobianColumn(refDeriv, i, orbitType, angleType, steps[i], delayM4, delayM3, delayM2, delayM1, @@ -343,7 +343,7 @@ private void doTestParametersDerivatives(String parameterName, double tolerance) final FieldGeodeticPoint dsPoint = new FieldGeodeticPoint<>(zero.add(point.getLatitude()), zero.add(point.getLongitude()), zero.add(point.getAltitude())); final DerivativeStructure delay = model.pathDelay(dsTrackingCoordinates, dsPoint, new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), - parameters, dsState.getDate()); + parameters, dsState.getDate()).getDelay(); final double[] compDeriv = delay.getAllDerivatives(); @@ -373,35 +373,35 @@ private void doTestParametersDerivatives(String parameterName, double tolerance) selected.setValue(p0 - 4 * h); double delayM4 = model.pathDelay(trackingCoordinates, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), state.getDate()); + model.getParameters(), state.getDate()).getDelay(); selected.setValue(p0 - 3 * h); double delayM3 = model.pathDelay(trackingCoordinates, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), state.getDate()); + model.getParameters(), state.getDate()).getDelay(); selected.setValue(p0 - 2 * h); double delayM2 = model.pathDelay(trackingCoordinates, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), state.getDate()); + model.getParameters(), state.getDate()).getDelay(); selected.setValue(p0 - 1 * h); double delayM1 = model.pathDelay(trackingCoordinates, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), state.getDate()); + model.getParameters(), state.getDate()).getDelay(); selected.setValue(p0 + 1 * h); double delayP1 = model.pathDelay(trackingCoordinates, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), state.getDate()); + model.getParameters(), state.getDate()).getDelay(); selected.setValue(p0 + 2 * h); double delayP2 = model.pathDelay(trackingCoordinates, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), state.getDate()); + model.getParameters(), state.getDate()).getDelay(); selected.setValue(p0 + 3 * h); double delayP3 = model.pathDelay(trackingCoordinates, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), state.getDate()); + model.getParameters(), state.getDate()).getDelay(); selected.setValue(p0 + 4 * h); double delayP4 = model.pathDelay(trackingCoordinates, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(), state.getDate()); + model.getParameters(), state.getDate()).getDelay(); fillJacobianColumn(refDeriv, 0, orbitType, angleType, h, delayM4, delayM3, delayM2, delayM1, @@ -425,11 +425,11 @@ public void testComparisonWithEstimatedModel() { Assertions.assertEquals(estimatedModel.pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - estimatedParameters, date), - timeSpanModel.pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), - point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - timeSpanParameters, date), - Double.MIN_VALUE); + estimatedParameters, date).getDelay(), + timeSpanModel.pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), + point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + timeSpanParameters, date).getDelay(), + Double.MIN_VALUE); } @Test @@ -453,10 +453,10 @@ private > void doTestFieldComparisonWithEstima Assertions.assertEquals(estimatedModel.pathDelay(trackingCoordinates, dsPoint, new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), - estimatedParameters, date).getReal(), + estimatedParameters, date).getDelay().getReal(), timeSpanModel.pathDelay(trackingCoordinates, dsPoint, new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), - timeSpanParameters, date).getReal(), + timeSpanParameters, date).getDelay().getReal(), Double.MIN_VALUE); } diff --git a/src/test/java/org/orekit/models/earth/troposphere/ViennaOneModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/ViennaOneModelTest.java index 3483c24af7..c730e638ae 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/ViennaOneModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/ViennaOneModelTest.java @@ -105,7 +105,7 @@ public void testDelay() { final double path = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elevation), 0.0), point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(date), date); + model.getParameters(date), date).getDelay(); Assertions.assertTrue(Precision.compareTo(path, 20d, epsilon) < 0); Assertions.assertTrue(Precision.compareTo(path, 0d, epsilon) > 0); } @@ -123,7 +123,7 @@ public void testFixedHeight() { final double delay = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elev), 0.0), point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(date), date); + model.getParameters(date), date).getDelay(); Assertions.assertTrue(Precision.compareTo(delay, lastDelay, epsilon) < 0); lastDelay = delay; } diff --git a/src/test/java/org/orekit/models/earth/troposphere/ViennaThreeModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/ViennaThreeModelTest.java index 189d3e219c..44a10b9f39 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/ViennaThreeModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/ViennaThreeModelTest.java @@ -193,12 +193,15 @@ public void testDelay() { final double[] z = {2.1993, 0.0690}; final GeodeticPoint point = new GeodeticPoint(FastMath.toRadians(37.5), FastMath.toRadians(277.5), height); ViennaThreeModel model = new ViennaThreeModel(a, z); - final double path = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elevation), 0.0), - point, - TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(date), date); - Assertions.assertTrue(Precision.compareTo(path, 20d, epsilon) < 0); - Assertions.assertTrue(Precision.compareTo(path, 0d, epsilon) > 0); + final TroposphericDelay delay = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elevation), 0.0), + point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(date), date); + Assertions.assertEquals( 2.1993, delay.getZh(), 1.0e-4); + Assertions.assertEquals( 0.069, delay.getZw(), 1.0e-4); + Assertions.assertEquals(12.2124, delay.getSh(), 1.0e-4); + Assertions.assertEquals( 0.3916, delay.getSw(), 1.0e-4); + Assertions.assertEquals(12.6041, delay.getDelay(), 1.0e-4); } @Test @@ -214,7 +217,7 @@ public void testFixedHeight() { final double delay = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elev), 0.0), point, TroposphericModelUtils.STANDARD_ATMOSPHERE, - model.getParameters(date), date); + model.getParameters(date), date).getDelay(); Assertions.assertTrue(Precision.compareTo(delay, lastDelay, epsilon) < 0); lastDelay = delay; } From 9a44c0e32ac0daf74283b88910ad49648a0cc2ca Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Thu, 21 Dec 2023 12:01:23 +0100 Subject: [PATCH 055/359] Added {Field}ViennaACoefficients container and associated provider. --- .../troposphere/FieldTroposphericDelay.java | 2 +- .../troposphere/FieldViennaACoefficients.java | 57 +++ .../earth/troposphere/TroposphericDelay.java | 2 +- .../troposphere/ViennaACoefficients.java | 54 +++ .../earth/troposphere/ViennaAProvider.java | 55 +++ .../earth/weather/CellInterpolator.java | 96 +++++ .../earth/weather/FieldCellInterpolator.java | 98 +++++ .../weather/GlobalPressureTemperature2.java | 397 +++--------------- .../GlobalPressureTemperature2Model.java | 6 +- .../org/orekit/models/earth/weather/Grid.java | 171 ++++++++ .../models/earth/weather/GridEntry.java | 180 ++++++++ .../models/earth/weather/SeasonalModel.java | 75 ++++ .../GlobalPressureTemperature2Test.java | 23 +- 13 files changed, 874 insertions(+), 342 deletions(-) create mode 100644 src/main/java/org/orekit/models/earth/troposphere/FieldViennaACoefficients.java create mode 100644 src/main/java/org/orekit/models/earth/troposphere/ViennaACoefficients.java create mode 100644 src/main/java/org/orekit/models/earth/troposphere/ViennaAProvider.java create mode 100644 src/main/java/org/orekit/models/earth/weather/CellInterpolator.java create mode 100644 src/main/java/org/orekit/models/earth/weather/FieldCellInterpolator.java create mode 100644 src/main/java/org/orekit/models/earth/weather/Grid.java create mode 100644 src/main/java/org/orekit/models/earth/weather/GridEntry.java create mode 100644 src/main/java/org/orekit/models/earth/weather/SeasonalModel.java diff --git a/src/main/java/org/orekit/models/earth/troposphere/FieldTroposphericDelay.java b/src/main/java/org/orekit/models/earth/troposphere/FieldTroposphericDelay.java index 173b67b324..0e75e47d00 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/FieldTroposphericDelay.java +++ b/src/main/java/org/orekit/models/earth/troposphere/FieldTroposphericDelay.java @@ -58,7 +58,7 @@ public T getZh() { } /** Get wet zenith delay (m). - * @return w et zenith delay (m) + * @return wet zenith delay (m) */ public T getZw() { return zw; diff --git a/src/main/java/org/orekit/models/earth/troposphere/FieldViennaACoefficients.java b/src/main/java/org/orekit/models/earth/troposphere/FieldViennaACoefficients.java new file mode 100644 index 0000000000..a3531c352a --- /dev/null +++ b/src/main/java/org/orekit/models/earth/troposphere/FieldViennaACoefficients.java @@ -0,0 +1,57 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import org.hipparchus.CalculusFieldElement; + +/** Container for the {@link ViennaOne} and {@link ViennaThree} coefficients ah and aw. + * @param type of the field elements + * @author Luc Maisonobe + * @since 12.1 + */ +public class FieldViennaACoefficients> { + + /** Hydrostatic coefficient. */ + private final T ah; + + /** Wet coefficient. */ + private final T aw; + + /** Simple constructor. + * @param ah hydrostatic coefficient + * @param aw wet coefficient + */ + public FieldViennaACoefficients(final T ah, final T aw) { + this.ah = ah; + this.aw = aw; + } + + /** Get hydrostatic coefficient. + * @return hydrostatic coefficient + */ + public T getAh() { + return ah; + } + + /** Get wet coefficient. + * @return wet coefficient + */ + public T getAw() { + return aw; + } + +} diff --git a/src/main/java/org/orekit/models/earth/troposphere/TroposphericDelay.java b/src/main/java/org/orekit/models/earth/troposphere/TroposphericDelay.java index fb67602f7f..277723b428 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/TroposphericDelay.java +++ b/src/main/java/org/orekit/models/earth/troposphere/TroposphericDelay.java @@ -55,7 +55,7 @@ public double getZh() { } /** Get wet zenith delay (m). - * @return w et zenith delay (m) + * @return wet zenith delay (m) */ public double getZw() { return zw; diff --git a/src/main/java/org/orekit/models/earth/troposphere/ViennaACoefficients.java b/src/main/java/org/orekit/models/earth/troposphere/ViennaACoefficients.java new file mode 100644 index 0000000000..094e75b6ef --- /dev/null +++ b/src/main/java/org/orekit/models/earth/troposphere/ViennaACoefficients.java @@ -0,0 +1,54 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +/** Container for the {@link ViennaOne} and {@link ViennaThree} coefficients ah and aw. + * @author Luc Maisonobe + * @since 12.1 + */ +public class ViennaACoefficients { + + /** Hydrostatic coefficient. */ + private final double ah; + + /** Wet coefficient. */ + private final double aw; + + /** Simple constructor. + * @param ah hydrostatic coefficient + * @param aw wet coefficient + */ + public ViennaACoefficients(final double ah, final double aw) { + this.ah = ah; + this.aw = aw; + } + + /** Get hydrostatic coefficient. + * @return hydrostatic coefficient + */ + public double getAh() { + return ah; + } + + /** Get wet coefficient. + * @return wet coefficient + */ + public double getAw() { + return aw; + } + +} diff --git a/src/main/java/org/orekit/models/earth/troposphere/ViennaAProvider.java b/src/main/java/org/orekit/models/earth/troposphere/ViennaAProvider.java new file mode 100644 index 0000000000..9cf3a078aa --- /dev/null +++ b/src/main/java/org/orekit/models/earth/troposphere/ViennaAProvider.java @@ -0,0 +1,55 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import org.hipparchus.CalculusFieldElement; +import org.orekit.bodies.FieldGeodeticPoint; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; + +/** Provider for {@link ViennaOne} and {@link ViennaThree} coefficients ah and aw. + * @since 12.1 + * @author Luc Maisonobe + */ +public interface ViennaAProvider { + + /** Get coefficients array for VMF mapping function. + *
              + *
            • double[0] = ah + *
            • double[1] = aw + *
            + * @param location location at which parameters are requested + * @param date date at which parameters are requested + * @return the coefficients array for VMF mapping function + */ + ViennaACoefficients getA(GeodeticPoint location, AbsoluteDate date); + + /** Get coefficients array for VMF mapping function. + *
              + *
            • double[0] = ah + *
            • double[1] = aw + *
            + * @param type of the field elements + * @param location location at which parameters are requested + * @param date date at which parameters are requested + * @return the coefficients array for VMF mapping function + */ + > FieldViennaACoefficients getA(FieldGeodeticPoint location, + FieldAbsoluteDate date); + +} diff --git a/src/main/java/org/orekit/models/earth/weather/CellInterpolator.java b/src/main/java/org/orekit/models/earth/weather/CellInterpolator.java new file mode 100644 index 0000000000..4c91c4fb46 --- /dev/null +++ b/src/main/java/org/orekit/models/earth/weather/CellInterpolator.java @@ -0,0 +1,96 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.weather; + +import java.util.function.ToDoubleFunction; + +import org.hipparchus.analysis.interpolation.BilinearInterpolatingFunction; + +/** Interpolator within a grid cell. + * @author Luc Maisonobe + * @since 12.1 + */ +public class CellInterpolator { + + /** Latitude of point of interest. */ + private final double latitude; + + /** Longitude of point of interest. */ + private final double longitude; + + /** South-West grid entry. */ + private final GridEntry southWest; + + /** South-East grid entry. */ + private final GridEntry southEast; + + /** North-West grid entry. */ + private final GridEntry northWest; + + /** North-East grid entry. */ + private final GridEntry northEast; + + /** Simple constructor. + * @param latitude latitude of point of interest + * @param longitude longitude of point of interest + * @param southWest South-West grid entry + * @param southEast South-East grid entry + * @param northWest North-West grid entry + * @param northEast North-East grid entry + */ + CellInterpolator(final double latitude, final double longitude, + final GridEntry southWest, final GridEntry southEast, + final GridEntry northWest, final GridEntry northEast) { + this.latitude = latitude; + this.longitude = longitude; + this.southWest = southWest; + this.southEast = southEast; + this.northWest = northWest; + this.northEast = northEast; + } + + /** Interpolate a grid function. + * @param gridGetter getter for the grid function + * @return interpolated function" + */ + double interpolate(final ToDoubleFunction gridGetter) { + + // cell surrounding the point + final double[] xVal = new double[] { + southWest.getLongitude(), southEast.getLongitude() + }; + final double[] yVal = new double[] { + southWest.getLatitude(), northWest.getLatitude() + }; + + // evaluate grid points at specified day + final double[][] fval = new double[][] { + { + gridGetter.applyAsDouble(southWest), + gridGetter.applyAsDouble(northWest) + }, { + gridGetter.applyAsDouble(southEast), + gridGetter.applyAsDouble(northEast) + } + }; + + // perform interpolation in the grid + return new BilinearInterpolatingFunction(xVal, yVal, fval).value(longitude, latitude); + + } + +} diff --git a/src/main/java/org/orekit/models/earth/weather/FieldCellInterpolator.java b/src/main/java/org/orekit/models/earth/weather/FieldCellInterpolator.java new file mode 100644 index 0000000000..dea48a1a19 --- /dev/null +++ b/src/main/java/org/orekit/models/earth/weather/FieldCellInterpolator.java @@ -0,0 +1,98 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.weather; + +import java.util.function.ToDoubleFunction; + +import org.hipparchus.CalculusFieldElement; +import org.hipparchus.analysis.interpolation.BilinearInterpolatingFunction; + +/** Interpolator within a grid cell. + * @param type of the field elements + * @author Luc Maisonobe + * @since 12.1 + */ +public class FieldCellInterpolator> { + + /** Latitude of point of interest. */ + private final T latitude; + + /** Longitude of point of interest. */ + private final T longitude; + + /** South-West grid entry. */ + private final GridEntry southWest; + + /** South-East grid entry. */ + private final GridEntry southEast; + + /** North-West grid entry. */ + private final GridEntry northWest; + + /** North-East grid entry. */ + private final GridEntry northEast; + + /** Simple constructor. + * @param latitude latitude of point of interest + * @param longitude longitude of point of interest + * @param southWest South-West grid entry + * @param southEast South-East grid entry + * @param northWest North-West grid entry + * @param northEast North-East grid entry + */ + FieldCellInterpolator(final T latitude, final T longitude, + final GridEntry southWest, final GridEntry southEast, + final GridEntry northWest, final GridEntry northEast) { + this.latitude = latitude; + this.longitude = longitude; + this.southWest = southWest; + this.southEast = southEast; + this.northWest = northWest; + this.northEast = northEast; + } + + /** Interpolate a grid function. + * @param gridGetter getter for the grid function + * @return interpolated function" + */ + T interpolate(final ToDoubleFunction gridGetter) { + + // cell surrounding the point + final double[] xVal = new double[] { + southWest.getLongitude(), southEast.getLongitude() + }; + final double[] yVal = new double[] { + southWest.getLatitude(), northWest.getLatitude() + }; + + // evaluate grid points at specified day + final double[][] fval = new double[][] { + { + gridGetter.applyAsDouble(southWest), + gridGetter.applyAsDouble(northWest) + }, { + gridGetter.applyAsDouble(southEast), + gridGetter.applyAsDouble(northEast) + } + }; + + // perform interpolation in the grid + return new BilinearInterpolatingFunction(xVal, yVal, fval).value(longitude, latitude); + + } + +} diff --git a/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2.java b/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2.java index 9c1ad3f0a0..91c3580905 100644 --- a/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2.java +++ b/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2.java @@ -26,14 +26,10 @@ import java.util.List; import java.util.SortedSet; import java.util.TreeSet; -import java.util.function.ToDoubleFunction; import java.util.regex.Pattern; import org.hipparchus.CalculusFieldElement; -import org.hipparchus.analysis.interpolation.BilinearInterpolatingFunction; import org.hipparchus.util.FastMath; -import org.hipparchus.util.MathUtils; -import org.hipparchus.util.SinCos; import org.orekit.bodies.FieldGeodeticPoint; import org.orekit.bodies.GeodeticPoint; import org.orekit.data.DataLoader; @@ -41,7 +37,10 @@ import org.orekit.data.DataSource; import org.orekit.errors.OrekitException; import org.orekit.errors.OrekitMessages; +import org.orekit.models.earth.troposphere.FieldViennaACoefficients; import org.orekit.models.earth.troposphere.TroposphericModelUtils; +import org.orekit.models.earth.troposphere.ViennaACoefficients; +import org.orekit.models.earth.troposphere.ViennaAProvider; import org.orekit.models.earth.troposphere.ViennaOneModel; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; @@ -83,7 +82,7 @@ * @author Luc Maisonobe * @since 12.1 */ -public class GlobalPressureTemperature2 implements PressureTemperatureHumidityProvider { +public class GlobalPressureTemperature2 implements ViennaAProvider, PressureTemperatureHumidityProvider { /** Pattern for delimiting regular expressions. */ private static final Pattern SEPARATOR = Pattern.compile("\\s+"); @@ -110,8 +109,7 @@ public class GlobalPressureTemperature2 implements PressureTemperatureHumidityPr * @param utc UTC time scale. * @exception IOException if grid data cannot be read */ - public GlobalPressureTemperature2(final DataSource source, - final TimeScale utc) + public GlobalPressureTemperature2(final DataSource source, final TimeScale utc) throws IOException { this.utc = utc; @@ -143,25 +141,16 @@ protected GlobalPressureTemperature2(final String supportedNames, grid = parser.grid; } - /** Get coefficients array for VMF mapping function. - *
              - *
            • double[0] = ah - *
            • double[1] = aw - *
            - * @param location location at which parameters are requested - * @param date date at which parameters are requested - * @return the coefficients array for VMF mapping function - */ - public double[] getA(final GeodeticPoint location, final AbsoluteDate date) { + /** {@inheritDoc} */ + @Override + public ViennaACoefficients getA(final GeodeticPoint location, final AbsoluteDate date) { - final Neighbors neighbors = new Neighbors(location.getLatitude(), location.getLongitude(), grid); + final CellInterpolator interpolator = grid.getInterpolator(location.getLatitude(), location.getLongitude()); final int dayOfYear = date.getComponents(utc).getDate().getDayOfYear(); // ah and aw coefficients - return new double[] { - neighbors.interpolate(e -> evaluate(dayOfYear, e.ah)) * 0.001, - neighbors.interpolate(e -> evaluate(dayOfYear, e.aw)) * 0.001 - }; + return new ViennaACoefficients(interpolator.interpolate(e -> e.getAh().evaluate(dayOfYear)) * 0.001, + interpolator.interpolate(e -> e.getAw().evaluate(dayOfYear)) * 0.001); } @@ -169,28 +158,28 @@ public double[] getA(final GeodeticPoint location, final AbsoluteDate date) { @Override public PressureTemperatureHumidity getWeatherParamerers(final GeodeticPoint location, final AbsoluteDate date) { - final Neighbors neighbors = new Neighbors(location.getLatitude(), location.getLongitude(), grid); + final CellInterpolator interpolator = grid.getInterpolator(location.getLatitude(), location.getLongitude()); final int dayOfYear = date.getComponents(utc).getDate().getDayOfYear(); // Corrected height (can be negative) - final double undu = neighbors.interpolate(e -> e.undulation); - final double correctedheight = location.getAltitude() - undu - neighbors.interpolate(e -> e.hS); + final double undu = interpolator.interpolate(e -> e.getUndulation()); + final double correctedheight = location.getAltitude() - undu - interpolator.interpolate(e -> e.getHs()); // Temperature gradient [K/m] - final double dTdH = neighbors.interpolate(e -> evaluate(dayOfYear, e.dT)) * 0.001; + final double dTdH = interpolator.interpolate(e -> e.getDt().evaluate(dayOfYear)) * 0.001; // Specific humidity - final double qv = neighbors.interpolate(e -> evaluate(dayOfYear, e.qv0)) * 0.001; + final double qv = interpolator.interpolate(e -> e.getQv0().evaluate(dayOfYear)) * 0.001; // For the computation of the temperature and the pressure, we use // the standard ICAO atmosphere formulas. // Temperature [K] - final double t0 = neighbors.interpolate(e -> evaluate(dayOfYear, e.temperature0)); + final double t0 = interpolator.interpolate(e -> e.getTemperature0().evaluate(dayOfYear)); final double temperature = t0 + dTdH * correctedheight; // Pressure [hPa] - final double p0 = neighbors.interpolate(e -> evaluate(dayOfYear, e.pressure0)); + final double p0 = interpolator.interpolate(e -> e.getPressure0().evaluate(dayOfYear)); final double exponent = G / (dTdH * R); final double pressure = p0 * FastMath.pow(1 - (dTdH / t0) * correctedheight, exponent) * 0.01; @@ -204,40 +193,52 @@ public PressureTemperatureHumidity getWeatherParamerers(final GeodeticPoint loca } + /** {@inheritDoc} */ + @Override + public > FieldViennaACoefficients getA(final FieldGeodeticPoint location, + final FieldAbsoluteDate date) { + + final FieldCellInterpolator interpolator = grid.getInterpolator(location.getLatitude(), location.getLongitude()); + final int dayOfYear = date.getComponents(utc).getDate().getDayOfYear(); + + // ah and aw coefficients + return new FieldViennaACoefficients<>(interpolator.interpolate(e -> e.getAh().evaluate(dayOfYear)).multiply(0.001), + interpolator.interpolate(e -> e.getAw().evaluate(dayOfYear)).multiply(0.001)); + + } + /** {@inheritDoc} */ @Override public > FieldPressureTemperatureHumidity getWeatherParamerers(final FieldGeodeticPoint location, final FieldAbsoluteDate date) { - final Neighbors neighbors = new Neighbors(location.getLatitude().getReal(), - location.getLongitude().getReal(), - grid); + final FieldCellInterpolator interpolator = grid.getInterpolator(location.getLatitude(), location.getLongitude()); final int dayOfYear = date.getComponents(utc).getDate().getDayOfYear(); // Corrected height (can be negative) - final double undu = neighbors.interpolate(e -> e.undulation); - final T correctedheight = location.getAltitude().subtract(undu).subtract(neighbors.interpolate(e -> e.hS)); + final T undu = interpolator.interpolate(e -> e.getUndulation()); + final T correctedheight = location.getAltitude().subtract(undu).subtract(interpolator.interpolate(e -> e.getHs())); // Temperature gradient [K/m] - final double dTdH = neighbors.interpolate(e -> evaluate(dayOfYear, e.dT)) * 0.001; + final T dTdH = interpolator.interpolate(e -> e.getDt().evaluate(dayOfYear)).multiply(0.001); // Specific humidity - final double qv = neighbors.interpolate(e -> evaluate(dayOfYear, e.qv0)) * 0.001; + final T qv = interpolator.interpolate(e -> e.getQv0().evaluate(dayOfYear)).multiply(0.001); // For the computation of the temperature and the pressure, we use // the standard ICAO atmosphere formulas. // Temperature [K] - final double t0 = neighbors.interpolate(e -> evaluate(dayOfYear, e.temperature0)); + final T t0 = interpolator.interpolate(e -> e.getTemperature0().evaluate(dayOfYear)); final T temperature = correctedheight.multiply(dTdH).add(t0); // Pressure [hPa] - final double p0 = neighbors.interpolate(e -> evaluate(dayOfYear, e.pressure0)); - final double exponent = G / (dTdH * R); - final T pressure = FastMath.pow(correctedheight.multiply(-dTdH / t0).add(1), exponent).multiply(p0 * 0.01); + final T p0 = interpolator.interpolate(e -> e.getPressure0().evaluate(dayOfYear)); + final T exponent = dTdH.multiply(R).reciprocal().multiply(G); + final T pressure = FastMath.pow(correctedheight.multiply(dTdH.negate().divide(t0)).add(1), exponent).multiply(p0.multiply(0.001)); // Water vapor pressure [hPa] - final T e0 = pressure.multiply(qv / (0.622 + 0.378 * qv)); + final T e0 = pressure.multiply(qv.divide(qv.multiply(0.378).add(0.622 ))); return new FieldPressureTemperatureHumidity<>(location.getAltitude(), TroposphericModelUtils.HECTO_PASCAL.toSI(pressure), @@ -246,95 +247,6 @@ public > FieldPressureTemperatureHumidity g } - /** Evaluate a model for some day. - * @param dayOfYear day to evaluate - * @param model model array - * @return model value at specified day - */ - private double evaluate(final int dayOfYear, final double[] model) { - - final double coef = (dayOfYear / 365.25) * 2 * FastMath.PI; - final SinCos sc1 = FastMath.sinCos(coef); - final SinCos sc2 = FastMath.sinCos(2.0 * coef); - - return model[0] + - model[1] * sc1.cos() + model[2] * sc1.sin() + - model[3] * sc2.cos() + model[4] * sc2.sin(); - - } - - /** Container for neighboring grid entries. */ - private static class Neighbors { - - /** Latitude of point of interest. */ - private final double latitude; - - /** Longitude of point of interest. */ - private final double longitude; - - /** South-West grid entry. */ - private final GridEntry southWest; - - /** South-East grid entry. */ - private final GridEntry southEast; - - /** North-West grid entry. */ - private final GridEntry northWest; - - /** North-East grid entry. */ - private final GridEntry northEast; - - /** Simple constructor. - * @param latitude latitude of point of interest - * @param longitude longitude of point of interest - * @param grid global grid - */ - Neighbors(final double latitude, final double longitude, final Grid grid) { - this.latitude = latitude; - this.longitude = MathUtils.normalizeAngle(longitude, - grid.entries[0][0].longitude + FastMath.PI); - - final int southIndex = grid.getSouthIndex(this.latitude); - final int westIndex = grid.getWestIndex(this.longitude); - this.southWest = grid.entries[southIndex ][westIndex ]; - this.southEast = grid.entries[southIndex ][westIndex + 1]; - this.northWest = grid.entries[southIndex + 1][westIndex ]; - this.northEast = grid.entries[southIndex + 1][westIndex + 1]; - - } - - /** Interpolate a grid function. - * @param gridGetter getter for the grid function - * @return interpolated function" - */ - private double interpolate(final ToDoubleFunction gridGetter) { - - // cell surrounding the point - final double[] xVal = new double[] { - southWest.longitude, southEast.longitude - }; - final double[] yVal = new double[] { - southWest.latitude, northWest.latitude - }; - - // evaluate grid points at specified day - final double[][] fval = new double[][] { - { - gridGetter.applyAsDouble(southWest), - gridGetter.applyAsDouble(northWest) - }, { - gridGetter.applyAsDouble(southEast), - gridGetter.applyAsDouble(northEast) - } - }; - - // perform interpolation in the grid - return new BilinearInterpolatingFunction(xVal, yVal, fval).value(longitude, latitude); - - } - - } - /** Parser for GPT2 grid files. */ private static class Parser implements DataLoader { @@ -366,9 +278,23 @@ public void loadData(final InputStream input, final String name) // read grid data if (line.length() > 0 && !line.startsWith("%")) { - final GridEntry entry = new GridEntry(SEPARATOR.split(line)); - latSample.add(entry.latKey); - lonSample.add(entry.lonKey); + final String[] fields = SEPARATOR.split(line); + final double latDegree = Double.parseDouble(fields[0]); + final double lonDegree = Double.parseDouble(fields[1]); + final GridEntry entry = new GridEntry(FastMath.toRadians(latDegree), + (int) FastMath.rint(latDegree * DEG_TO_MAS), + FastMath.toRadians(lonDegree), + (int) FastMath.rint(lonDegree * DEG_TO_MAS), + Double.parseDouble(fields[22]), + Double.parseDouble(fields[23]), + createModel(fields, 2), + createModel(fields, 7), + createModel(fields, 12), + createModel(fields, 17), + createModel(fields, 24), + createModel(fields, 29)); + latSample.add(entry.getLatKey()); + lonSample.add(entry.getLonKey()); entries.add(entry); } @@ -383,202 +309,17 @@ public void loadData(final InputStream input, final String name) } - } - - /** Container for complete grid. */ - private static class Grid { - - /** Latitude sample. */ - private final SortedSet latitudeSample; - - /** Longitude sample. */ - private final SortedSet longitudeSample; - - /** Grid entries. */ - private final GridEntry[][] entries; - - /** Simple constructor. - * @param latitudeSample latitude sample - * @param longitudeSample longitude sample - * @param loadedEntries loaded entries, organized as a simple list - * @param name file name - */ - Grid(final SortedSet latitudeSample, final SortedSet longitudeSample, - final List loadedEntries, final String name) { - - final int nA = latitudeSample.size(); - final int nO = longitudeSample.size() + 1; // we add one here for wrapping the grid - this.entries = new GridEntry[nA][nO]; - this.latitudeSample = latitudeSample; - this.longitudeSample = longitudeSample; - - // organize entries in the regular grid - for (final GridEntry entry : loadedEntries) { - final int latitudeIndex = latitudeSample.headSet(entry.latKey + 1).size() - 1; - final int longitudeIndex = longitudeSample.headSet(entry.lonKey + 1).size() - 1; - entries[latitudeIndex][longitudeIndex] = entry; - } - - // finalize the grid - for (final GridEntry[] row : entries) { - - // check for missing entries - for (int longitudeIndex = 0; longitudeIndex < nO - 1; ++longitudeIndex) { - if (row[longitudeIndex] == null) { - throw new OrekitException(OrekitMessages.IRREGULAR_OR_INCOMPLETE_GRID, name); - } - } - - // wrap the grid around the Earth in longitude - row[nO - 1] = new GridEntry(row[0].latitude, row[0].latKey, - row[0].longitude + 2 * FastMath.PI, - row[0].lonKey + DEG_TO_MAS * 360, - row[0].undulation, row[0].hS, - row[0].pressure0, row[0].temperature0, - row[0].qv0, row[0].dT, row[0].ah, row[0].aw); - - } - - } - - /** Get index of South entries in the grid. - * @param latitude latitude to locate (radians) - * @return index of South entries in the grid - */ - public int getSouthIndex(final double latitude) { - - final int latKey = (int) FastMath.rint(FastMath.toDegrees(latitude) * DEG_TO_MAS); - final int index = latitudeSample.headSet(latKey + 1).size() - 1; - - // make sure we have at least one point remaining on North by clipping to size - 2 - return FastMath.min(index, latitudeSample.size() - 2); - - } - - /** Get index of West entries in the grid. - * @param longitude longitude to locate (radians) - * @return index of West entries in the grid - */ - public int getWestIndex(final double longitude) { - - final int lonKey = (int) FastMath.rint(FastMath.toDegrees(longitude) * DEG_TO_MAS); - final int index = longitudeSample.headSet(lonKey + 1).size() - 1; - - // we don't do clipping in longitude because we have added a row to wrap around the Earth - return index; - - } - - } - - /** Container for grid entries. */ - private static class GridEntry { - - /** Latitude (radian). */ - private final double latitude; - - /** Latitude key (mas). */ - private final int latKey; - - /** Longitude (radian). */ - private final double longitude; - - /** Longitude key (mas). */ - private final int lonKey; - - /** Undulation. */ - private final double undulation; - - /** Height correction. */ - private final double hS; - - /** Pressure model. */ - private final double[] pressure0; - - /** Temperature model. */ - private final double[] temperature0; - - /** Specific humidity model. */ - private final double[] qv0; - - /** Temperature gradient model. */ - private final double[] dT; - - /** ah coefficient model. */ - private final double[] ah; - - /** aw coefficient model. */ - private final double[] aw; - - /** Build an entry from a parsed line. - * @param fields line fields - */ - GridEntry(final String[] fields) { - - final double latDegree = Double.parseDouble(fields[0]); - final double lonDegree = Double.parseDouble(fields[1]); - latitude = FastMath.toRadians(latDegree); - longitude = FastMath.toRadians(lonDegree); - latKey = (int) FastMath.rint(latDegree * DEG_TO_MAS); - lonKey = (int) FastMath.rint(lonDegree * DEG_TO_MAS); - - undulation = Double.parseDouble(fields[22]); - hS = Double.parseDouble(fields[23]); - - pressure0 = createModel(fields, 2); - temperature0 = createModel(fields, 7); - qv0 = createModel(fields, 12); - dT = createModel(fields, 17); - ah = createModel(fields, 24); - aw = createModel(fields, 29); - - } - - /** Build an entry from its components. - * @param latitude latitude (radian) - * @param latKey latitude key (mas) - * @param longitude longitude (radian) - * @param lonKey longitude key (mas) - * @param undulation undulation (m) - * @param hS height correction - * @param pressure0 pressure model - * @param temperature0 temperature model - * @param qv0 specific humidity model - * @param dT temperature gradient model - * @param ah ah coefficient model - * @param aw aw coefficient model - */ - GridEntry(final double latitude, final int latKey, final double longitude, final int lonKey, - final double undulation, final double hS, final double[] pressure0, final double[] temperature0, - final double[] qv0, final double[] dT, final double[] ah, final double[] aw) { - - this.latitude = latitude; - this.latKey = latKey; - this.longitude = longitude; - this.lonKey = lonKey; - this.undulation = undulation; - this.hS = hS; - this.pressure0 = pressure0.clone(); - this.temperature0 = temperature0.clone(); - this.qv0 = qv0.clone(); - this.dT = dT.clone(); - this.ah = ah.clone(); - this.aw = aw.clone(); - } - - /** Create a time model array. - * @param fields line fields - * @param first index of the first component of the model - * @return time model array + /** Create a seasonal model. + * @param fields parsed fields + * @param first index of the constant field + * @return created model */ - private double[] createModel(final String[] fields, final int first) { - return new double[] { - Double.parseDouble(fields[first ]), - Double.parseDouble(fields[first + 1]), - Double.parseDouble(fields[first + 2]), - Double.parseDouble(fields[first + 3]), - Double.parseDouble(fields[first + 4]) - }; + private SeasonalModel createModel(final String[] fields, final int first) { + return new SeasonalModel(Double.parseDouble(fields[first ]), + Double.parseDouble(fields[first + 1]), + Double.parseDouble(fields[first + 2]), + Double.parseDouble(fields[first + 3]), + Double.parseDouble(fields[first + 4])); } } diff --git a/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2Model.java b/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2Model.java index 9e50376acd..6858230679 100644 --- a/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2Model.java +++ b/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2Model.java @@ -22,6 +22,7 @@ import org.orekit.data.DataProvidersManager; import org.orekit.models.earth.Geoid; import org.orekit.models.earth.troposphere.TroposphericModelUtils; +import org.orekit.models.earth.troposphere.ViennaACoefficients; import org.orekit.models.earth.troposphere.ViennaOneModel; import org.orekit.time.AbsoluteDate; import org.orekit.time.TimeScale; @@ -183,7 +184,10 @@ public void weatherParameters(final double stationHeight, final AbsoluteDate cur final GeodeticPoint location = new GeodeticPoint(latitude, longitude, stationHeight); // ah and aw coefficients - coefficientsA = getA(location, currentDate); + final ViennaACoefficients aC = getA(location, currentDate); + coefficientsA = new double[] { + aC.getAh(), aC.getAw() + }; // Pressure, temperature, humidity final PressureTemperatureHumidity pth = getWeatherParamerers(location, currentDate); diff --git a/src/main/java/org/orekit/models/earth/weather/Grid.java b/src/main/java/org/orekit/models/earth/weather/Grid.java new file mode 100644 index 0000000000..f817cf80c0 --- /dev/null +++ b/src/main/java/org/orekit/models/earth/weather/Grid.java @@ -0,0 +1,171 @@ +/* Copyright 2002-2023 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.weather; + +import java.util.List; +import java.util.SortedSet; + +import org.hipparchus.CalculusFieldElement; +import org.hipparchus.util.FastMath; +import org.hipparchus.util.MathUtils; +import org.orekit.errors.OrekitException; +import org.orekit.errors.OrekitMessages; + +/** Container for a complete grid. + * @author Bryan Cazabonne + * @author Luc Maisonobe + * @since 12.1 + */ +class Grid { + + /** Conversion factor from degrees to mill arcseconds. */ + private static final int DEG_TO_MAS = 3600000; + + /** Latitude sample. */ + private final SortedSet latitudeSample; + + /** Longitude sample. */ + private final SortedSet longitudeSample; + + /** Grid entries. */ + private final GridEntry[][] entries; + + /** Simple constructor. + * @param latitudeSample latitude sample + * @param longitudeSample longitude sample + * @param loadedEntries loaded entries, organized as a simple list + * @param name file name + */ + Grid(final SortedSet latitudeSample, final SortedSet longitudeSample, + final List loadedEntries, final String name) { + + final int nA = latitudeSample.size(); + final int nO = longitudeSample.size() + 1; // we add one here for wrapping the grid + this.entries = new GridEntry[nA][nO]; + this.latitudeSample = latitudeSample; + this.longitudeSample = longitudeSample; + + // organize entries in the regular grid + for (final GridEntry entry : loadedEntries) { + final int latitudeIndex = latitudeSample.headSet(entry.getLatKey() + 1).size() - 1; + final int longitudeIndex = longitudeSample.headSet(entry.getLonKey() + 1).size() - 1; + entries[latitudeIndex][longitudeIndex] = entry; + } + + // finalize the grid + for (final GridEntry[] row : entries) { + + // check for missing entries + for (int longitudeIndex = 0; longitudeIndex < nO - 1; ++longitudeIndex) { + if (row[longitudeIndex] == null) { + throw new OrekitException(OrekitMessages.IRREGULAR_OR_INCOMPLETE_GRID, name); + } + } + + // wrap the grid around the Earth in longitude + row[nO - 1] = new GridEntry(row[0].getLatitude(), row[0].getLatKey(), + row[0].getLongitude() + MathUtils.TWO_PI, + row[0].getLonKey() + DEG_TO_MAS * 360, + row[0].getUndulation(), row[0].getHs(), + row[0].getPressure0(), row[0].getTemperature0(), + row[0].getQv0(), row[0].getDt(), + row[0].getAh(), row[0].getAw()); + + } + + } + + /** Get index of South entries in the grid. + * @param latitude latitude to locate (radians) + * @return index of South entries in the grid + */ + private int getSouthIndex(final double latitude) { + + final int latKey = (int) FastMath.rint(FastMath.toDegrees(latitude) * DEG_TO_MAS); + final int index = latitudeSample.headSet(latKey + 1).size() - 1; + + // make sure we have at least one point remaining on North by clipping to size - 2 + return FastMath.min(index, latitudeSample.size() - 2); + + } + + /** Get index of West entries in the grid. + * @param longitude longitude to locate (radians) + * @return index of West entries in the grid + */ + private int getWestIndex(final double longitude) { + + final int lonKey = (int) FastMath.rint(FastMath.toDegrees(longitude) * DEG_TO_MAS); + final int index = longitudeSample.headSet(lonKey + 1).size() - 1; + + // we don't do clipping in longitude because we have added a row to wrap around the Earth + return index; + + } + + /** Get interpolator within a cell. + * @param latitude latitude of point of interest + * @param longitude longitude of point of interest + * @return interpolator for the cell + */ + CellInterpolator getInterpolator(final double latitude, final double longitude) { + + // keep longitude within grid range + final double normalizedLongitude = + MathUtils.normalizeAngle(longitude, + entries[0][0].getLongitude() + FastMath.PI); + + // find neighboring grid entries + final int southIndex = getSouthIndex(latitude); + final int westIndex = getWestIndex(normalizedLongitude); + + // build interpolator + return new CellInterpolator(latitude, normalizedLongitude, + entries[southIndex ][westIndex ], + entries[southIndex ][westIndex + 1], + entries[southIndex + 1][westIndex ], + entries[southIndex + 1][westIndex + 1]); + + } + + /** Get interpolator within a cell. + * @param type of the field elements + * @param latitude latitude of point of interest + * @param longitude longitude of point of interest + * @return interpolator for the cell + */ + > FieldCellInterpolator getInterpolator(final T latitude, final T longitude) { + + // keep longitude within grid range + final T normalizedLongitude = + MathUtils.normalizeAngle(longitude, + longitude.newInstance(entries[0][0].getLongitude() + FastMath.PI)); + + // find neighboring grid entries + final int southIndex = getSouthIndex(latitude.getReal()); + final int westIndex = getWestIndex(normalizedLongitude.getReal()); + + // build interpolator + return new FieldCellInterpolator<>(latitude, normalizedLongitude, + entries[southIndex ][westIndex ], + entries[southIndex ][westIndex + 1], + entries[southIndex + 1][westIndex ], + entries[southIndex + 1][westIndex + 1]); + + } + +} diff --git a/src/main/java/org/orekit/models/earth/weather/GridEntry.java b/src/main/java/org/orekit/models/earth/weather/GridEntry.java new file mode 100644 index 0000000000..5d5c8b6ee3 --- /dev/null +++ b/src/main/java/org/orekit/models/earth/weather/GridEntry.java @@ -0,0 +1,180 @@ +/* Copyright 2002-2023 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.weather; + +/** Grid entry in Global Pressure Temperature models. + * @author Bryan Cazabonne + * @author Luc Maisonobe + * @since 12.1 + */ +class GridEntry { + + /** Latitude (radian). */ + private final double latitude; + + /** Latitude key (mas). */ + private final int latKey; + + /** Longitude (radian). */ + private final double longitude; + + /** Longitude key (mas). */ + private final int lonKey; + + /** Undulation. */ + private final double undulation; + + /** Height correction. */ + private final double hS; + + /** Pressure model. */ + private final SeasonalModel pressure0; + + /** Temperature model. */ + private final SeasonalModel temperature0; + + /** Specific humidity model. */ + private final SeasonalModel qv0; + + /** Temperature gradient model. */ + private final SeasonalModel dT; + + /** ah coefficient model. */ + private final SeasonalModel ah; + + /** aw coefficient model. */ + private final SeasonalModel aw; + + /** Build an entry from its components. + * @param latitude latitude (radian) + * @param latKey latitude key (mas) + * @param longitude longitude (radian) + * @param lonKey longitude key (mas) + * @param undulation undulation (m) + * @param hS height correction + * @param pressure0 pressure model + * @param temperature0 temperature model + * @param qv0 specific humidity model + * @param dT temperature gradient model + * @param ah ah coefficient model + * @param aw aw coefficient model + */ + GridEntry(final double latitude, final int latKey, final double longitude, final int lonKey, + final double undulation, final double hS, + final SeasonalModel pressure0, final SeasonalModel temperature0, + final SeasonalModel qv0, final SeasonalModel dT, + final SeasonalModel ah, final SeasonalModel aw) { + + this.latitude = latitude; + this.latKey = latKey; + this.longitude = longitude; + this.lonKey = lonKey; + this.undulation = undulation; + this.hS = hS; + this.pressure0 = pressure0; + this.temperature0 = temperature0; + this.qv0 = qv0; + this.dT = dT; + this.ah = ah; + this.aw = aw; + } + + /** Get latitude (radian). + * @return latitude (radian) + */ + double getLatitude() { + return latitude; + } + + /** Get latitude key (mas). + * @return latitude key (mas) + */ + int getLatKey() { + return latKey; + } + + /** Get longitude (radian). + * @return longitude (radian) + */ + double getLongitude() { + return longitude; + } + + /** Get longitude key (mas). + * @return longitude key (mas) + */ + int getLonKey() { + return lonKey; + } + + /** Get undulation. + * @return undulation + */ + double getUndulation() { + return undulation; + } + + /** Get height correction. + * @return height correction + */ + double getHs() { + return hS; + } + + /** Get pressure model. + * @return pressure model + */ + SeasonalModel getPressure0() { + return pressure0; + } + + /** Get temperature model. + * @return temperature model + */ + SeasonalModel getTemperature0() { + return temperature0; + } + + /** Get specific humidity model. + * @return specific humidity model + */ + SeasonalModel getQv0() { + return qv0; + } + + /** Get temperature gradient model. + * @return temperature gradient model + */ + SeasonalModel getDt() { + return dT; + } + + /** Get ah coefficient model. + * @return ah coefficient model + */ + SeasonalModel getAh() { + return ah; + } + + /** Get aw coefficient model. + * @return aw coefficient model + */ + SeasonalModel getAw() { + return aw; + } + +} diff --git a/src/main/java/org/orekit/models/earth/weather/SeasonalModel.java b/src/main/java/org/orekit/models/earth/weather/SeasonalModel.java new file mode 100644 index 0000000000..e50039d9e0 --- /dev/null +++ b/src/main/java/org/orekit/models/earth/weather/SeasonalModel.java @@ -0,0 +1,75 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.weather; + +import org.hipparchus.util.FastMath; +import org.hipparchus.util.SinCos; + +/** Seasonal model used in Global Pressure Temperature models. + * @see "Landskron, D. & Böhm, J. J Geod (2018) + * VMF3/GPT3: refined discrete and empirical troposphere mapping functions + * 92: 349. https://doi.org/10.1007/s00190-017-1066-2" + * @author Luc Maisonobe + * @since 12.1 + */ +class SeasonalModel { + + /** Constant. */ + private final double a0; + + /** Annual cosine amplitude. */ + private final double a1; + + /** Annual sine amplitude. */ + private final double b1; + + /** Semi-nnual cosine amplitude. */ + private final double a2; + + /** Semi-nnual sine amplitude. */ + private final double b2; + + /** Simple constructor. + * @param a0 constant + * @param a1 annual cosine amplitude + * @param b1 annual sine amplitude + * @param a2 semi-annual cosine amplitude + * @param b2 semi-annual sine amplitude + */ + SeasonalModel(final double a0, final double a1, final double b1, final double a2, final double b2) { + this.a0 = a0; + this.a1 = a1; + this.b1 = b1; + this.a2 = a2; + this.b2 = b2; + } + + /** Evaluate a model for some day. + * @param dayOfYear day to evaluate + * @return model value at specified day + */ + public double evaluate(final int dayOfYear) { + + final double coef = (dayOfYear / 365.25) * 2 * FastMath.PI; + final SinCos sc1 = FastMath.sinCos(coef); + final SinCos sc2 = FastMath.sinCos(2.0 * coef); + + return a0 + a1 * sc1.cos() + b1 * sc1.sin() + a2 * sc2.cos() + b2 * sc2.sin(); + + } + +} diff --git a/src/test/java/org/orekit/models/earth/weather/GlobalPressureTemperature2Test.java b/src/test/java/org/orekit/models/earth/weather/GlobalPressureTemperature2Test.java index c03b36f427..f1e0daeb62 100644 --- a/src/test/java/org/orekit/models/earth/weather/GlobalPressureTemperature2Test.java +++ b/src/test/java/org/orekit/models/earth/weather/GlobalPressureTemperature2Test.java @@ -31,6 +31,7 @@ import org.orekit.forces.gravity.potential.GRGSFormatReader; import org.orekit.forces.gravity.potential.GravityFieldFactory; import org.orekit.models.earth.troposphere.TroposphericModelUtils; +import org.orekit.models.earth.troposphere.ViennaACoefficients; import org.orekit.time.AbsoluteDate; import org.orekit.time.TimeScalesFactory; @@ -70,11 +71,11 @@ public void testWeatherParameters() throws IOException, URISyntaxException { TimeScalesFactory.getUTC()); final GeodeticPoint location = new GeodeticPoint(latitude, longitude, height); - final double a[] = model.getA(location, date); + final ViennaACoefficients a = model.getA(location, date); final PressureTemperatureHumidity pth = model.getWeatherParamerers(location, date); - Assertions.assertEquals(0.0012647, a[0], 1.1e-7); - Assertions.assertEquals(0.0005726, a[1], 8.6e-8); + Assertions.assertEquals(0.0012647, a.getAh(), 1.1e-7); + Assertions.assertEquals(0.0005726, a.getAw(), 8.6e-8); Assertions.assertEquals(273.15 + 22.12, pth.getTemperature(), 2.3e-1); Assertions.assertEquals(1002.56, TroposphericModelUtils.HECTO_PASCAL.fromSI(pth.getPressure()), 7.4e-1); Assertions.assertEquals(15.63, TroposphericModelUtils.HECTO_PASCAL.fromSI(pth.getWaterVaporPressure()), 5.0e-2); @@ -98,17 +99,17 @@ public void testEquality() throws IOException, URISyntaxException { // Test longitude = 181° and longitude = -179° GeodeticPoint location1 = new GeodeticPoint(latitude, FastMath.toRadians(181.0), height); - double[] a1 = model.getA(location1, date); + ViennaACoefficients a1 = model.getA(location1, date); PressureTemperatureHumidity pth1 = model.getWeatherParamerers(location1, date); GeodeticPoint location2 = new GeodeticPoint(latitude, FastMath.toRadians(-179.0), height); - double[] a2 = model.getA(location2, date); + ViennaACoefficients a2 = model.getA(location2, date); PressureTemperatureHumidity pth2 = model.getWeatherParamerers(location2, date); Assertions.assertEquals(pth1.getTemperature(), pth2.getTemperature(), epsilon); Assertions.assertEquals(pth1.getPressure(), pth2.getPressure(), epsilon); Assertions.assertEquals(pth1.getWaterVaporPressure(), pth2.getWaterVaporPressure(), epsilon); - Assertions.assertEquals(a1[0], a2[0], epsilon); - Assertions.assertEquals(a1[1], a2[1], epsilon); + Assertions.assertEquals(a1.getAh(), a2.getAh(), epsilon); + Assertions.assertEquals(a1.getAw(), a2.getAw(), epsilon); // Test longitude = 180° and longitude = -180° location1 = new GeodeticPoint(latitude, FastMath.toRadians(180.0), height); @@ -121,8 +122,8 @@ public void testEquality() throws IOException, URISyntaxException { Assertions.assertEquals(pth1.getTemperature(), pth2.getTemperature(), epsilon); Assertions.assertEquals(pth1.getPressure(), pth2.getPressure(), epsilon); Assertions.assertEquals(pth1.getWaterVaporPressure(), pth2.getWaterVaporPressure(), epsilon); - Assertions.assertEquals(a1[0], a2[0], epsilon); - Assertions.assertEquals(a1[1], a2[1], epsilon); + Assertions.assertEquals(a1.getAh(), a2.getAh(), epsilon); + Assertions.assertEquals(a1.getAw(), a2.getAw(), epsilon); // Test longitude = 0° and longitude = 360° location1 = new GeodeticPoint(latitude, FastMath.toRadians(0.0), height); @@ -135,8 +136,8 @@ public void testEquality() throws IOException, URISyntaxException { Assertions.assertEquals(pth1.getTemperature(), pth2.getTemperature(), epsilon); Assertions.assertEquals(pth1.getPressure(), pth2.getPressure(), epsilon); Assertions.assertEquals(pth1.getWaterVaporPressure(), pth2.getWaterVaporPressure(), epsilon); - Assertions.assertEquals(a1[0], a2[0], epsilon); - Assertions.assertEquals(a1[1], a2[1], epsilon); + Assertions.assertEquals(a1.getAh(), a2.getAh(), epsilon); + Assertions.assertEquals(a1.getAw(), a2.getAw(), epsilon); } From 0b45832e711ce143f9990b2fea5401fc9a2f53ce Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Thu, 21 Dec 2023 13:34:08 +0100 Subject: [PATCH 056/359] Added ConstantTroposphericModel. --- src/changes/changes.xml | 3 + .../ConstantTroposphericModel.java | 79 +++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 src/main/java/org/orekit/models/earth/troposphere/ConstantTroposphericModel.java diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 07330e49ac..b3051b7888 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -21,6 +21,9 @@ + + Added ConstantTroposphericModel. + Added ChaoMappingFunction for tropospheric mapping function. diff --git a/src/main/java/org/orekit/models/earth/troposphere/ConstantTroposphericModel.java b/src/main/java/org/orekit/models/earth/troposphere/ConstantTroposphericModel.java new file mode 100644 index 0000000000..abe0922d44 --- /dev/null +++ b/src/main/java/org/orekit/models/earth/troposphere/ConstantTroposphericModel.java @@ -0,0 +1,79 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import java.util.Collections; +import java.util.List; + +import org.hipparchus.CalculusFieldElement; +import org.orekit.bodies.FieldGeodeticPoint; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; +import org.orekit.models.earth.weather.PressureTemperatureHumidity; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; +import org.orekit.utils.FieldTrackingCoordinates; +import org.orekit.utils.ParameterDriver; +import org.orekit.utils.TrackingCoordinates; + +/** Defines a constant tropospheric model. + * @author Luc Maisonobe + * @since 12.1 + */ +public class ConstantTroposphericModel implements TroposphericModel { + + /** Constant delay. */ + private final TroposphericDelay delay; + + /** Simple constructor. + * @param delay constant delay + */ + public ConstantTroposphericModel(final TroposphericDelay delay) { + this.delay = delay; + } + + /** {@inheritDoc} */ + @Override + public TroposphericDelay pathDelay(final TrackingCoordinates trackingCoordinates, + final GeodeticPoint point, + final PressureTemperatureHumidity weather, + final double[] parameters, + final AbsoluteDate date) { + return delay; + } + + /** {@inheritDoc} */ + @Override + public > FieldTroposphericDelay pathDelay(final FieldTrackingCoordinates trackingCoordinates, + final FieldGeodeticPoint point, + final FieldPressureTemperatureHumidity weather, + final T[] parameters, + final FieldAbsoluteDate date) { + final T zero = date.getField().getZero(); + return new FieldTroposphericDelay<>(zero.newInstance(delay.getZh()), + zero.newInstance(delay.getZw()), + zero.newInstance(delay.getSh()), + zero.newInstance(delay.getSw())); + } + + /** {@inheritDoc} */ + @Override + public List getParametersDrivers() { + return Collections.emptyList(); + } + +} From 1ec6943df84ae62673f783a96a4c491d090246a4 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Thu, 21 Dec 2023 13:37:24 +0100 Subject: [PATCH 057/359] Replaced Vienna{One|Three}Model by Vienna{One|Three}. --- src/changes/changes.xml | 3 + .../earth/troposphere/AbstractVienna.java | 128 ++ .../troposphere/ConstantViennaAProvider.java | 55 + .../models/earth/troposphere/ViennaOne.java | 200 +++ .../earth/troposphere/ViennaOneModel.java | 189 +-- .../models/earth/troposphere/ViennaThree.java | 1142 +++++++++++++++++ .../earth/troposphere/ViennaThreeModel.java | 1141 +--------------- .../weather/GlobalPressureTemperature2.java | 5 +- .../earth/troposphere/ViennaOneModelTest.java | 1 + .../earth/troposphere/ViennaOneTest.java | 131 ++ .../troposphere/ViennaThreeModelTest.java | 1 + .../earth/troposphere/ViennaThreeTest.java | 223 ++++ 12 files changed, 1903 insertions(+), 1316 deletions(-) create mode 100644 src/main/java/org/orekit/models/earth/troposphere/AbstractVienna.java create mode 100644 src/main/java/org/orekit/models/earth/troposphere/ConstantViennaAProvider.java create mode 100644 src/main/java/org/orekit/models/earth/troposphere/ViennaOne.java create mode 100644 src/main/java/org/orekit/models/earth/troposphere/ViennaThree.java create mode 100644 src/test/java/org/orekit/models/earth/troposphere/ViennaOneTest.java create mode 100644 src/test/java/org/orekit/models/earth/troposphere/ViennaThreeTest.java diff --git a/src/changes/changes.xml b/src/changes/changes.xml index b3051b7888..93783fdfb3 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -21,6 +21,9 @@ + + Replaced Vienna{One|Three}Model by Vienna{One|Three}. + Added ConstantTroposphericModel. diff --git a/src/main/java/org/orekit/models/earth/troposphere/AbstractVienna.java b/src/main/java/org/orekit/models/earth/troposphere/AbstractVienna.java new file mode 100644 index 0000000000..03db3ff848 --- /dev/null +++ b/src/main/java/org/orekit/models/earth/troposphere/AbstractVienna.java @@ -0,0 +1,128 @@ +/* Copyright 2002-2023 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import java.util.Collections; +import java.util.List; + +import org.hipparchus.CalculusFieldElement; +import org.orekit.bodies.FieldGeodeticPoint; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; +import org.orekit.models.earth.weather.PressureTemperatureHumidity; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; +import org.orekit.time.TimeScale; +import org.orekit.utils.FieldTrackingCoordinates; +import org.orekit.utils.ParameterDriver; +import org.orekit.utils.TrackingCoordinates; + +/** The Vienna tropospheric delay model for radio techniques. + * @since 12.1 + * @author Bryan Cazabonne + * @author Luc Maisonobe + */ +public abstract class AbstractVienna implements TroposphericModel, TroposphereMappingFunction { + + /** Provider for ah and aw coefficients. */ + private final ViennaAProvider aProvider; + + /** Provider for zenith delays. */ + private final TroposphericModel zenithDelayProvider; + + /** UTC time scale. */ + private final TimeScale utc; + + /** Build a new instance. + * @param aProvider provider for ah and aw coefficients + * @param zenithDelayProvider provider for zenith delays + * @param utc UTC time scale + */ + protected AbstractVienna(final ViennaAProvider aProvider, + final TroposphericModel zenithDelayProvider, + final TimeScale utc) { + this.aProvider = aProvider; + this.zenithDelayProvider = zenithDelayProvider; + this.utc = utc; + } + + /** {@inheritDoc} */ + @Override + public TroposphericDelay pathDelay(final TrackingCoordinates trackingCoordinates, + final GeodeticPoint point, + final PressureTemperatureHumidity weather, + final double[] parameters, final AbsoluteDate date) { + // zenith delay + final TroposphericDelay delays = + zenithDelayProvider.pathDelay(trackingCoordinates, point, weather, parameters, date); + + // mapping function + final double[] mappingFunction = + mappingFactors(trackingCoordinates, point, weather, date); + + // Tropospheric path delay + return new TroposphericDelay(delays.getZh(), + delays.getZw(), + delays.getZh() * mappingFunction[0], + delays.getZw() * mappingFunction[1]); + + } + + /** {@inheritDoc} */ + @Override + public > FieldTroposphericDelay pathDelay(final FieldTrackingCoordinates trackingCoordinates, + final FieldGeodeticPoint point, + final FieldPressureTemperatureHumidity weather, + final T[] parameters, final FieldAbsoluteDate date) { + // zenith delay + final FieldTroposphericDelay delays = + zenithDelayProvider.pathDelay(trackingCoordinates, point, weather, parameters, date); + + // mapping function + final T[] mappingFunction = + mappingFactors(trackingCoordinates, point, weather, date); + + // Tropospheric path delay + return new FieldTroposphericDelay<>(delays.getZh(), + delays.getZw(), + delays.getZh().multiply(mappingFunction[0]), + delays.getZw().multiply(mappingFunction[1])); + + } + + /** {@inheritDoc} */ + @Override + public List getParametersDrivers() { + return Collections.emptyList(); + } + + /** Get provider for Vienna ah and aw coefficients. + * @return provider for Vienna ah and aw coefficients + */ + protected ViennaAProvider getAProvider() { + return aProvider; + } + + /** Get day of year. + * @param date date + * @return day of year + */ + protected int getDayOfYear(final AbsoluteDate date) { + return date.getComponents(utc).getDate().getDayOfYear(); + } + +} diff --git a/src/main/java/org/orekit/models/earth/troposphere/ConstantViennaAProvider.java b/src/main/java/org/orekit/models/earth/troposphere/ConstantViennaAProvider.java new file mode 100644 index 0000000000..2ef72e20fb --- /dev/null +++ b/src/main/java/org/orekit/models/earth/troposphere/ConstantViennaAProvider.java @@ -0,0 +1,55 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS Communication & Systèmes (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import org.hipparchus.CalculusFieldElement; +import org.orekit.bodies.FieldGeodeticPoint; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; + +/** Provider for constant Vienna A coefficients. + * @author Luc Maisonobe + * @since 12.1 + */ +public class ConstantViennaAProvider implements ViennaAProvider { + + /** Constant parameters. */ + private final ViennaACoefficients a; + + /** Simple constructor. + * @param a constant parameters + */ + public ConstantViennaAProvider(final ViennaACoefficients a) { + this.a = a; + } + + /** {@inheritDoc} */ + @Override + public ViennaACoefficients getA(final GeodeticPoint location, final AbsoluteDate date) { + return a; + } + + /** {@inheritDoc} */ + @Override + public > FieldViennaACoefficients getA(final FieldGeodeticPoint location, + final FieldAbsoluteDate date) { + return new FieldViennaACoefficients(date.getField().getZero().newInstance(a.getAh()), + date.getField().getZero().newInstance(a.getAw())); + } + +} diff --git a/src/main/java/org/orekit/models/earth/troposphere/ViennaOne.java b/src/main/java/org/orekit/models/earth/troposphere/ViennaOne.java new file mode 100644 index 0000000000..3b3cb2ad50 --- /dev/null +++ b/src/main/java/org/orekit/models/earth/troposphere/ViennaOne.java @@ -0,0 +1,200 @@ +/* Copyright 2002-2023 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import java.util.Collections; +import java.util.List; + +import org.hipparchus.CalculusFieldElement; +import org.hipparchus.Field; +import org.hipparchus.util.FastMath; +import org.hipparchus.util.MathArrays; +import org.orekit.bodies.FieldGeodeticPoint; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; +import org.orekit.models.earth.weather.PressureTemperatureHumidity; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; +import org.orekit.time.TimeScale; +import org.orekit.utils.FieldTrackingCoordinates; +import org.orekit.utils.ParameterDriver; +import org.orekit.utils.TrackingCoordinates; + +/** The Vienna 1 tropospheric delay model for radio techniques. + * The Vienna model data are given with a time interval of 6 hours + * as well as on a global 2.5° * 2.0° grid. + * + * This version considered the height correction for the hydrostatic part + * developed by Niell, 1996. + * + * @see "Boehm, J., Werl, B., and Schuh, H., (2006), + * Troposhere mapping functions for GPS and very long baseline + * interferometry from European Centre for Medium-Range Weather + * Forecasts operational analysis data, J. Geophy. Res., Vol. 111, + * B02406, doi:10.1029/2005JB003629" + * @since 12.1 + * @author Bryan Cazabonne + * @author Luc Maisonobe + */ +public class ViennaOne extends AbstractVienna { + + /** Build a new instance. + * @param aProvider provider for ah and aw coefficients + * @param zenithDelayProvider provider for zenith delays + * @param utc UTC time scale + */ + public ViennaOne(final ViennaAProvider aProvider, + final TroposphericModel zenithDelayProvider, + final TimeScale utc) { + super(aProvider, zenithDelayProvider, utc); + } + + /** {@inheritDoc} */ + @Override + public double[] mappingFactors(final TrackingCoordinates trackingCoordinates, + final GeodeticPoint point, + final PressureTemperatureHumidity weather, + final AbsoluteDate date) { + + // a coefficients + final ViennaACoefficients a = getAProvider().getA(point, date); + + // Day of year computation + final int dofyear = getDayOfYear(date); + + // General constants | Hydrostatic part + final double bh = 0.0029; + final double c0h = 0.062; + final double c10h; + final double c11h; + final double psi; + + // Latitude of the station + final double latitude = point.getLatitude(); + + // sin(latitude) > 0 -> northern hemisphere + if (FastMath.sin(latitude) > 0) { + c10h = 0.001; + c11h = 0.005; + psi = 0; + } else { + c10h = 0.002; + c11h = 0.007; + psi = FastMath.PI; + } + + // Temporal factor + double t0 = 28; + if (latitude < 0) { + // southern hemisphere: t0 = 28 + an integer half of year + t0 += 183; + } + // Compute hydrostatique coefficient c + final double coef = ((dofyear - t0) / 365) * 2 * FastMath.PI + psi; + final double ch = c0h + ((FastMath.cos(coef) + 1) * (c11h / 2) + c10h) * (1 - FastMath.cos(latitude)); + + // General constants | Wet part + final double bw = 0.00146; + final double cw = 0.04391; + + final double[] function = new double[2]; + function[0] = TroposphericModelUtils.mappingFunction(a.getAh(), bh, ch, + trackingCoordinates.getElevation()); + function[1] = TroposphericModelUtils.mappingFunction(a.getAw(), bw, cw, + trackingCoordinates.getElevation()); + + // Apply height correction + final double correction = TroposphericModelUtils.computeHeightCorrection(trackingCoordinates.getElevation(), + point.getAltitude()); + function[0] = function[0] + correction; + + return function; + } + + /** {@inheritDoc} */ + @Override + public > T[] mappingFactors(final FieldTrackingCoordinates trackingCoordinates, + final FieldGeodeticPoint point, + final FieldPressureTemperatureHumidity weather, + final FieldAbsoluteDate date) { + + final Field field = date.getField(); + final T zero = field.getZero(); + + // a coefficients + final FieldViennaACoefficients a = getAProvider().getA(point, date); + + // Day of year computation + final int dofyear = getDayOfYear(date.toAbsoluteDate()); + + // General constants | Hydrostatic part + final T bh = zero.newInstance(0.0029); + final T c0h = zero.newInstance(0.062); + final T c10h; + final T c11h; + final T psi; + + // Latitude and longitude of the station + final T latitude = point.getLatitude(); + + // sin(latitude) > 0 -> northern hemisphere + if (FastMath.sin(latitude.getReal()) > 0) { + c10h = zero.newInstance(0.001); + c11h = zero.newInstance(0.005); + psi = zero; + } else { + c10h = zero.newInstance(0.002); + c11h = zero.newInstance(0.007); + psi = zero.getPi(); + } + + // Compute hydrostatique coefficient c + // Temporal factor + double t0 = 28; + if (latitude.getReal() < 0) { + // southern hemisphere: t0 = 28 + an integer half of year + t0 += 183; + } + final T coef = psi.add(zero.getPi().multiply(2.0).multiply((dofyear - t0) / 365)); + final T ch = c11h.divide(2.0).multiply(FastMath.cos(coef).add(1.0)).add(c10h).multiply(FastMath.cos(latitude).negate().add(1.)).add(c0h); + + // General constants | Wet part + final T bw = zero.newInstance(0.00146); + final T cw = zero.newInstance(0.04391); + + final T[] function = MathArrays.buildArray(field, 2); + function[0] = TroposphericModelUtils.mappingFunction(a.getAh(), bh, ch, + trackingCoordinates.getElevation()); + function[1] = TroposphericModelUtils.mappingFunction(a.getAw(), bw, cw, + trackingCoordinates.getElevation()); + + // Apply height correction + final T correction = TroposphericModelUtils.computeHeightCorrection(trackingCoordinates.getElevation(), + point.getAltitude(), + field); + function[0] = function[0].add(correction); + + return function; + } + + /** {@inheritDoc} */ + @Override + public List getParametersDrivers() { + return Collections.emptyList(); + } + +} diff --git a/src/main/java/org/orekit/models/earth/troposphere/ViennaOneModel.java b/src/main/java/org/orekit/models/earth/troposphere/ViennaOneModel.java index 5cadc7fa14..959235c335 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/ViennaOneModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/ViennaOneModel.java @@ -16,25 +16,18 @@ */ package org.orekit.models.earth.troposphere; -import java.util.Collections; -import java.util.List; - import org.hipparchus.CalculusFieldElement; import org.hipparchus.Field; -import org.hipparchus.util.FastMath; import org.hipparchus.util.MathArrays; import org.orekit.annotation.DefaultDataContext; import org.orekit.bodies.FieldGeodeticPoint; import org.orekit.bodies.GeodeticPoint; import org.orekit.data.DataContext; import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; -import org.orekit.models.earth.weather.PressureTemperatureHumidity; import org.orekit.time.AbsoluteDate; -import org.orekit.time.DateTimeComponents; import org.orekit.time.FieldAbsoluteDate; import org.orekit.time.TimeScale; import org.orekit.utils.FieldTrackingCoordinates; -import org.orekit.utils.ParameterDriver; import org.orekit.utils.TrackingCoordinates; /** The Vienna1 tropospheric delay model for radio techniques. @@ -51,20 +44,14 @@ * B02406, doi:10.1029/2005JB003629" * * @author Bryan Cazabonne + * @deprecated as of 12.1, replaced by {@link ViennaOne} */ -@SuppressWarnings("deprecation") -public class ViennaOneModel - implements DiscreteTroposphericModel, TroposphericModel, MappingFunction, TroposphereMappingFunction { - - /** The a coefficient for the computation of the wet and hydrostatic mapping functions.*/ - private final double[] coefficientsA; +@Deprecated +public class ViennaOneModel extends ViennaOne implements DiscreteTroposphericModel, MappingFunction { /** Values of hydrostatic and wet delays as provided by the Vienna model. */ private final double[] zenithDelay; - /** UTC time scale. */ - private final TimeScale utc; - /** Build a new instance. * *

            This constructor uses the {@link DataContext#getDefault() default data context}. @@ -91,9 +78,11 @@ public ViennaOneModel(final double[] coefficientA, final double[] zenithDelay) { public ViennaOneModel(final double[] coefficientA, final double[] zenithDelay, final TimeScale utc) { - this.coefficientsA = coefficientA.clone(); - this.zenithDelay = zenithDelay.clone(); - this.utc = utc; + super(new ConstantViennaAProvider(new ViennaACoefficients(coefficientA[0], coefficientA[1])), + new ConstantTroposphericModel(new TroposphericDelay(zenithDelay[0], zenithDelay[1], + zenithDelay[0], zenithDelay[1])), + utc); + this.zenithDelay = zenithDelay.clone(); } /** {@inheritDoc} */ @@ -106,23 +95,6 @@ public double pathDelay(final double elevation, final GeodeticPoint point, getDelay(); } - /** {@inheritDoc} */ - @Override - public TroposphericDelay pathDelay(final TrackingCoordinates trackingCoordinates, - final GeodeticPoint point, - final PressureTemperatureHumidity weather, - final double[] parameters, final AbsoluteDate date) { - // zenith delay - final double[] delays = computeZenithDelay(point, parameters, date); - // mapping function - final double[] mappingFunction = mappingFactors(trackingCoordinates, point, weather, date); - // Tropospheric path delay - return new TroposphericDelay(delays[0], - delays[1], - delays[0] * mappingFunction[0], - delays[1] * mappingFunction[1]); - } - /** {@inheritDoc} */ @Override @Deprecated @@ -135,23 +107,6 @@ public > T pathDelay(final T elevation, final getDelay(); } - /** {@inheritDoc} */ - @Override - public > FieldTroposphericDelay pathDelay(final FieldTrackingCoordinates trackingCoordinates, - final FieldGeodeticPoint point, - final FieldPressureTemperatureHumidity weather, - final T[] parameters, final FieldAbsoluteDate date) { - // zenith delay - final T[] delays = computeZenithDelay(point, parameters, date); - // mapping function - final T[] mappingFunction = mappingFactors(trackingCoordinates, point, weather, date); - // Tropospheric path delay - return new FieldTroposphericDelay<>(delays[0], - delays[1], - delays[0].multiply(mappingFunction[0]), - delays[1].multiply(mappingFunction[1])); - } - /** This method allows the computation of the zenith hydrostatic and * zenith wet delay. The resulting element is an array having the following form: *

              @@ -200,65 +155,6 @@ public double[] mappingFactors(final double elevation, final GeodeticPoint point date); } - /** {@inheritDoc} */ - @Override - public double[] mappingFactors(final TrackingCoordinates trackingCoordinates, - final GeodeticPoint point, - final PressureTemperatureHumidity weather, - final AbsoluteDate date) { - // Day of year computation - final DateTimeComponents dtc = date.getComponents(utc); - final int dofyear = dtc.getDate().getDayOfYear(); - - // General constants | Hydrostatic part - final double bh = 0.0029; - final double c0h = 0.062; - final double c10h; - final double c11h; - final double psi; - - // Latitude of the station - final double latitude = point.getLatitude(); - - // sin(latitude) > 0 -> northern hemisphere - if (FastMath.sin(latitude) > 0) { - c10h = 0.001; - c11h = 0.005; - psi = 0; - } else { - c10h = 0.002; - c11h = 0.007; - psi = FastMath.PI; - } - - // Temporal factor - double t0 = 28; - if (latitude < 0) { - // southern hemisphere: t0 = 28 + an integer half of year - t0 += 183; - } - // Compute hydrostatique coefficient c - final double coef = ((dofyear - t0) / 365) * 2 * FastMath.PI + psi; - final double ch = c0h + ((FastMath.cos(coef) + 1) * (c11h / 2) + c10h) * (1 - FastMath.cos(latitude)); - - // General constants | Wet part - final double bw = 0.00146; - final double cw = 0.04391; - - final double[] function = new double[2]; - function[0] = TroposphericModelUtils.mappingFunction(coefficientsA[0], bh, ch, - trackingCoordinates.getElevation()); - function[1] = TroposphericModelUtils.mappingFunction(coefficientsA[1], bw, cw, - trackingCoordinates.getElevation()); - - // Apply height correction - final double correction = TroposphericModelUtils.computeHeightCorrection(trackingCoordinates.getElevation(), - point.getAltitude()); - function[0] = function[0] + correction; - - return function; - } - /** {@inheritDoc} */ @Override @Deprecated @@ -271,73 +167,4 @@ public > T[] mappingFactors(final T elevation, date); } - /** {@inheritDoc} */ - @Override - public > T[] mappingFactors(final FieldTrackingCoordinates trackingCoordinates, - final FieldGeodeticPoint point, - final FieldPressureTemperatureHumidity weather, - final FieldAbsoluteDate date) { - final Field field = date.getField(); - final T zero = field.getZero(); - - // Day of year computation - final DateTimeComponents dtc = date.getComponents(utc); - final int dofyear = dtc.getDate().getDayOfYear(); - - // General constants | Hydrostatic part - final T bh = zero.newInstance(0.0029); - final T c0h = zero.newInstance(0.062); - final T c10h; - final T c11h; - final T psi; - - // Latitude and longitude of the station - final T latitude = point.getLatitude(); - - // sin(latitude) > 0 -> northern hemisphere - if (FastMath.sin(latitude.getReal()) > 0) { - c10h = zero.newInstance(0.001); - c11h = zero.newInstance(0.005); - psi = zero; - } else { - c10h = zero.newInstance(0.002); - c11h = zero.newInstance(0.007); - psi = zero.getPi(); - } - - // Compute hydrostatique coefficient c - // Temporal factor - double t0 = 28; - if (latitude.getReal() < 0) { - // southern hemisphere: t0 = 28 + an integer half of year - t0 += 183; - } - final T coef = psi.add(zero.getPi().multiply(2.0).multiply((dofyear - t0) / 365)); - final T ch = c11h.divide(2.0).multiply(FastMath.cos(coef).add(1.0)).add(c10h).multiply(FastMath.cos(latitude).negate().add(1.)).add(c0h); - - // General constants | Wet part - final T bw = zero.newInstance(0.00146); - final T cw = zero.newInstance(0.04391); - - final T[] function = MathArrays.buildArray(field, 2); - function[0] = TroposphericModelUtils.mappingFunction(zero.newInstance(coefficientsA[0]), bh, ch, - trackingCoordinates.getElevation()); - function[1] = TroposphericModelUtils.mappingFunction(zero.newInstance(coefficientsA[1]), bw, cw, - trackingCoordinates.getElevation()); - - // Apply height correction - final T correction = TroposphericModelUtils.computeHeightCorrection(trackingCoordinates.getElevation(), - point.getAltitude(), - field); - function[0] = function[0].add(correction); - - return function; - } - - /** {@inheritDoc} */ - @Override - public List getParametersDrivers() { - return Collections.emptyList(); - } - } diff --git a/src/main/java/org/orekit/models/earth/troposphere/ViennaThree.java b/src/main/java/org/orekit/models/earth/troposphere/ViennaThree.java new file mode 100644 index 0000000000..e3bd2a689c --- /dev/null +++ b/src/main/java/org/orekit/models/earth/troposphere/ViennaThree.java @@ -0,0 +1,1142 @@ +/* Copyright 2002-2023 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import org.hipparchus.CalculusFieldElement; +import org.hipparchus.Field; +import org.hipparchus.util.FastMath; +import org.hipparchus.util.FieldSinCos; +import org.hipparchus.util.MathArrays; +import org.hipparchus.util.SinCos; +import org.orekit.bodies.FieldGeodeticPoint; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; +import org.orekit.models.earth.weather.PressureTemperatureHumidity; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; +import org.orekit.time.TimeScale; +import org.orekit.utils.FieldLegendrePolynomials; +import org.orekit.utils.FieldTrackingCoordinates; +import org.orekit.utils.LegendrePolynomials; +import org.orekit.utils.TrackingCoordinates; + +/** The Vienna 3 tropospheric delay model for radio techniques. + * The Vienna model data are given with a time interval of 6 hours. + *

              + * The empirical coefficients bh, bw, ch + * and cw are computed with spherical harmonics. + * In that respect, they are considerably more advanced than those of + * {@link ViennaOneModel VMF1} model. + *

              + * + * @see "Landskron, D. & Böhm, J. J Geod (2018) + * VMF3/GPT3: refined discrete and empirical troposphere mapping functions + * 92: 349. https://doi.org/10.1007/s00190-017-1066-2" + * + * @see "Landskron D (2017) Modeling tropospheric delays for space geodetic + * techniques. Dissertation, Department of Geodesy and Geoinformation, TU Wien, Supervisor: J. Böhm. + * http://repositum.tuwien.ac.at/urn:nbn:at:at-ubtuw:1-100249" + * + * @author Bryan Cazabonne + */ +public class ViennaThree extends AbstractVienna { + + /** Build a new instance. + * @param aProvider provider for ah and aw coefficients + * @param zenithDelayProvider provider for zenith delays + * @param utc UTC time scale + */ + public ViennaThree(final ViennaAProvider aProvider, + final TroposphericModel zenithDelayProvider, + final TimeScale utc) { + super(aProvider, zenithDelayProvider, utc); + } + + /** {@inheritDoc} */ + @Override + public double[] mappingFactors(final TrackingCoordinates trackingCoordinates, + final GeodeticPoint point, + final PressureTemperatureHumidity weather, + final AbsoluteDate date) { + + // a coefficients + final ViennaACoefficients a = getAProvider().getA(point, date); + + // Day of year computation + final int dofyear = getDayOfYear(date); + + // Compute Legendre Polynomials Pnm(cos(0.5 * pi - phi)) + final int degree = 12; + final int order = 12; + final LegendrePolynomials p = new LegendrePolynomials(degree, order, FastMath.cos(0.5 * FastMath.PI - point.getLatitude())); + + // Compute coefficients bh, bw, ch and cw with spherical harmonics + double a0Bh = 0.; + double a0Bw = 0.; + double a0Ch = 0.; + double a0Cw = 0.; + double a1Bh = 0.; + double a1Bw = 0.; + double a1Ch = 0.; + double a1Cw = 0.; + double b1Bh = 0.; + double b1Bw = 0.; + double b1Ch = 0.; + double b1Cw = 0.; + double a2Bh = 0.; + double a2Bw = 0.; + double a2Ch = 0.; + double a2Cw = 0.; + double b2Bh = 0.; + double b2Bw = 0.; + double b2Ch = 0.; + double b2Cw = 0.; + final LegendreFunctions AnmBnm = new LegendreFunctions(); + int j = 0; + for (int n = 0; n <= 12; n++) { + for (int m = 0; m <= n; m++) { + final SinCos sc = FastMath.sinCos(m * point.getLongitude()); + final double pCosmLambda = p.getPnm(n, m) * sc.cos(); + final double pSinmLambda = p.getPnm(n, m) * sc.sin(); + + a0Bh = a0Bh + (AnmBnm.getAnmBh(j, 0) * pCosmLambda + AnmBnm.getBnmBh(j, 0) * pSinmLambda); + a0Bw = a0Bw + (AnmBnm.getAnmBw(j, 0) * pCosmLambda + AnmBnm.getBnmBw(j, 0) * pSinmLambda); + a0Ch = a0Ch + (AnmBnm.getAnmCh(j, 0) * pCosmLambda + AnmBnm.getBnmCh(j, 0) * pSinmLambda); + a0Cw = a0Cw + (AnmBnm.getAnmCw(j, 0) * pCosmLambda + AnmBnm.getBnmCw(j, 0) * pSinmLambda); + + a1Bh = a1Bh + (AnmBnm.getAnmBh(j, 1) * pCosmLambda + AnmBnm.getBnmBh(j, 1) * pSinmLambda); + a1Bw = a1Bw + (AnmBnm.getAnmBw(j, 1) * pCosmLambda + AnmBnm.getBnmBw(j, 1) * pSinmLambda); + a1Ch = a1Ch + (AnmBnm.getAnmCh(j, 1) * pCosmLambda + AnmBnm.getBnmCh(j, 1) * pSinmLambda); + a1Cw = a1Cw + (AnmBnm.getAnmCw(j, 1) * pCosmLambda + AnmBnm.getBnmCw(j, 1) * pSinmLambda); + + b1Bh = b1Bh + (AnmBnm.getAnmBh(j, 2) * pCosmLambda + AnmBnm.getBnmBh(j, 2) * pSinmLambda); + b1Bw = b1Bw + (AnmBnm.getAnmBw(j, 2) * pCosmLambda + AnmBnm.getBnmBw(j, 2) * pSinmLambda); + b1Ch = b1Ch + (AnmBnm.getAnmCh(j, 2) * pCosmLambda + AnmBnm.getBnmCh(j, 2) * pSinmLambda); + b1Cw = b1Cw + (AnmBnm.getAnmCw(j, 2) * pCosmLambda + AnmBnm.getBnmCw(j, 2) * pSinmLambda); + + a2Bh = a2Bh + (AnmBnm.getAnmBh(j, 3) * pCosmLambda + AnmBnm.getBnmBh(j, 3) * pSinmLambda); + a2Bw = a2Bw + (AnmBnm.getAnmBw(j, 3) * pCosmLambda + AnmBnm.getBnmBw(j, 3) * pSinmLambda); + a2Ch = a2Ch + (AnmBnm.getAnmCh(j, 3) * pCosmLambda + AnmBnm.getBnmCh(j, 3) * pSinmLambda); + a2Cw = a2Cw + (AnmBnm.getAnmCw(j, 3) * pCosmLambda + AnmBnm.getBnmCw(j, 3) * pSinmLambda); + + b2Bh = b2Bh + (AnmBnm.getAnmBh(j, 4) * pCosmLambda + AnmBnm.getBnmBh(j, 4) * pSinmLambda); + b2Bw = b2Bw + (AnmBnm.getAnmBw(j, 4) * pCosmLambda + AnmBnm.getBnmBw(j, 4) * pSinmLambda); + b2Ch = b2Ch + (AnmBnm.getAnmCh(j, 4) * pCosmLambda + AnmBnm.getBnmCh(j, 4) * pSinmLambda); + b2Cw = b2Cw + (AnmBnm.getAnmCw(j, 4) * pCosmLambda + AnmBnm.getBnmCw(j, 4) * pSinmLambda); + + j = j + 1; + } + } + + // Eq. 6 + final double bh = computeSeasonalFit(dofyear, a0Bh, a1Bh, a2Bh, b1Bh, b2Bh); + final double bw = computeSeasonalFit(dofyear, a0Bw, a1Bw, a2Bw, b1Bw, b2Bw); + final double ch = computeSeasonalFit(dofyear, a0Ch, a1Ch, a2Ch, b1Ch, b2Ch); + final double cw = computeSeasonalFit(dofyear, a0Cw, a1Cw, a2Cw, b1Cw, b2Cw); + + // Compute Mapping Function Eq. 4 + final double[] function = new double[2]; + function[0] = TroposphericModelUtils.mappingFunction(a.getAh(), bh, ch, + trackingCoordinates.getElevation()); + function[1] = TroposphericModelUtils.mappingFunction(a.getAw(), bw, cw, + trackingCoordinates.getElevation()); + + return function; + } + + /** {@inheritDoc} */ + @Override + public > T[] mappingFactors(final FieldTrackingCoordinates trackingCoordinates, + final FieldGeodeticPoint point, + final FieldPressureTemperatureHumidity weather, + final FieldAbsoluteDate date) { + final Field field = date.getField(); + final T zero = field.getZero(); + + // a coefficients + final FieldViennaACoefficients a = getAProvider().getA(point, date); + + // Day of year computation + final int dofyear = getDayOfYear(date.toAbsoluteDate()); + + // Compute Legendre Polynomials Pnm(cos(0.5 * pi - phi)) + final int degree = 12; + final int order = 12; + final FieldLegendrePolynomials p = new FieldLegendrePolynomials<>(degree, order, FastMath.cos(point.getLatitude().negate().add(zero.getPi().multiply(0.5)))); + + // Compute coefficients bh, bw, ch and cw with spherical harmonics + T a0Bh = zero; + T a0Bw = zero; + T a0Ch = zero; + T a0Cw = zero; + T a1Bh = zero; + T a1Bw = zero; + T a1Ch = zero; + T a1Cw = zero; + T b1Bh = zero; + T b1Bw = zero; + T b1Ch = zero; + T b1Cw = zero; + T a2Bh = zero; + T a2Bw = zero; + T a2Ch = zero; + T a2Cw = zero; + T b2Bh = zero; + T b2Bw = zero; + T b2Ch = zero; + T b2Cw = zero; + final LegendreFunctions AnmBnm = new LegendreFunctions(); + int j = 0; + for (int n = 0; n <= 12; n++) { + for (int m = 0; m <= n; m++) { + final FieldSinCos sc = FastMath.sinCos(point.getLongitude().multiply(m)); + final T pCosmLambda = p.getPnm(n, m).multiply(sc.cos()); + final T pSinmLambda = p.getPnm(n, m).multiply(sc.sin()); + + a0Bh = a0Bh.add(pCosmLambda.multiply(AnmBnm.getAnmBh(j, 0)).add(pSinmLambda.multiply(AnmBnm.getBnmBh(j, 0)))); + a0Bw = a0Bw.add(pCosmLambda.multiply(AnmBnm.getAnmBw(j, 0)).add(pSinmLambda.multiply(AnmBnm.getBnmBw(j, 0)))); + a0Ch = a0Ch.add(pCosmLambda.multiply(AnmBnm.getAnmCh(j, 0)).add(pSinmLambda.multiply(AnmBnm.getBnmCh(j, 0)))); + a0Cw = a0Cw.add(pCosmLambda.multiply(AnmBnm.getAnmCw(j, 0)).add(pSinmLambda.multiply(AnmBnm.getBnmCw(j, 0)))); + + a1Bh = a1Bh.add(pCosmLambda.multiply(AnmBnm.getAnmBh(j, 1)).add(pSinmLambda.multiply(AnmBnm.getBnmBh(j, 1)))); + a1Bw = a1Bw.add(pCosmLambda.multiply(AnmBnm.getAnmBw(j, 1)).add(pSinmLambda.multiply(AnmBnm.getBnmBw(j, 1)))); + a1Ch = a1Ch.add(pCosmLambda.multiply(AnmBnm.getAnmCh(j, 1)).add(pSinmLambda.multiply(AnmBnm.getBnmCh(j, 1)))); + a1Cw = a1Cw.add(pCosmLambda.multiply(AnmBnm.getAnmCw(j, 1)).add(pSinmLambda.multiply(AnmBnm.getBnmCw(j, 1)))); + + b1Bh = b1Bh.add(pCosmLambda.multiply(AnmBnm.getAnmBh(j, 2)).add(pSinmLambda.multiply(AnmBnm.getBnmBh(j, 2)))); + b1Bw = b1Bw.add(pCosmLambda.multiply(AnmBnm.getAnmBw(j, 2)).add(pSinmLambda.multiply(AnmBnm.getBnmBw(j, 2)))); + b1Ch = b1Ch.add(pCosmLambda.multiply(AnmBnm.getAnmCh(j, 2)).add(pSinmLambda.multiply(AnmBnm.getBnmCh(j, 2)))); + b1Cw = b1Cw.add(pCosmLambda.multiply(AnmBnm.getAnmCw(j, 2)).add(pSinmLambda.multiply(AnmBnm.getBnmCw(j, 2)))); + + a2Bh = a2Bh.add(pCosmLambda.multiply(AnmBnm.getAnmBh(j, 3)).add(pSinmLambda.multiply(AnmBnm.getBnmBh(j, 3)))); + a2Bw = a2Bw.add(pCosmLambda.multiply(AnmBnm.getAnmBw(j, 3)).add(pSinmLambda.multiply(AnmBnm.getBnmBw(j, 3)))); + a2Ch = a2Ch.add(pCosmLambda.multiply(AnmBnm.getAnmCh(j, 3)).add(pSinmLambda.multiply(AnmBnm.getBnmCh(j, 3)))); + a2Cw = a2Cw.add(pCosmLambda.multiply(AnmBnm.getAnmCw(j, 3)).add(pSinmLambda.multiply(AnmBnm.getBnmCw(j, 3)))); + + b2Bh = b2Bh.add(pCosmLambda.multiply(AnmBnm.getAnmBh(j, 4)).add(pSinmLambda.multiply(AnmBnm.getBnmBh(j, 4)))); + b2Bw = b2Bw.add(pCosmLambda.multiply(AnmBnm.getAnmBw(j, 4)).add(pSinmLambda.multiply(AnmBnm.getBnmBw(j, 4)))); + b2Ch = b2Ch.add(pCosmLambda.multiply(AnmBnm.getAnmCh(j, 4)).add(pSinmLambda.multiply(AnmBnm.getBnmCh(j, 4)))); + b2Cw = b2Cw.add(pCosmLambda.multiply(AnmBnm.getAnmCw(j, 4)).add(pSinmLambda.multiply(AnmBnm.getBnmCw(j, 4)))); + + j = j + 1; + } + } + + // Eq. 6 + final T bh = computeSeasonalFit(dofyear, a0Bh, a1Bh, a2Bh, b1Bh, b2Bh); + final T bw = computeSeasonalFit(dofyear, a0Bw, a1Bw, a2Bw, b1Bw, b2Bw); + final T ch = computeSeasonalFit(dofyear, a0Ch, a1Ch, a2Ch, b1Ch, b2Ch); + final T cw = computeSeasonalFit(dofyear, a0Cw, a1Cw, a2Cw, b1Cw, b2Cw); + + // Compute Mapping Function Eq. 4 + final T[] function = MathArrays.buildArray(field, 2); + function[0] = TroposphericModelUtils.mappingFunction(a.getAh(), bh, ch, + trackingCoordinates.getElevation()); + function[1] = TroposphericModelUtils.mappingFunction(a.getAw(), bw, cw, + trackingCoordinates.getElevation()); + + return function; + } + + /** Computes the empirical temporal information for the mapping function + * coefficients b and c. A seasonal fit formula is performed. + * @param doy day of year + * @param A0 Mean value of the coefficient + * @param A1 Annual amplitude of the coefficient + * @param A2 Semi-annual amplitude of the coefficient + * @param B1 Annual amplitude of the coefficient + * @param B2 Semi-annual amplitude of the coefficient + * @return the mapping function coefficient at a given day. + */ + private double computeSeasonalFit(final int doy, final double A0, final double A1, + final double A2, final double B1, final double B2) { + + final double coef = (doy / 365.25) * 2 * FastMath.PI; + final SinCos sc1 = FastMath.sinCos(coef); + final SinCos sc2 = FastMath.sinCos(2.0 * coef); + + return A0 + + A1 * sc1.cos() + B1 * sc1.sin() + + A2 * sc2.cos() + B2 * sc2.sin(); + } + + /** Computes the empirical temporal information for the mapping function + * coefficients b and c. A seasonal fit formula is performed. + * @param type of the elements + * @param doy day of year + * @param A0 Mean value of the coefficient + * @param A1 Annual amplitude of the coefficient + * @param A2 Semi-annual amplitude of the coefficient + * @param B1 Annual amplitude of the coefficient + * @param B2 Semi-annual amplitude of the coefficient + * @return the mapping function coefficient at a given day. + */ + private > T computeSeasonalFit(final int doy, final T A0, final T A1, + final T A2, final T B1, final T B2) { + final T coef = A0.getPi().multiply(2.0).multiply(doy / 365.25); + final FieldSinCos sc1 = FastMath.sinCos(coef); + final FieldSinCos sc2 = FastMath.sinCos(coef.multiply(2.0)); + + return A0.add( + A1.multiply(sc1.cos())).add(B1.multiply(sc1.sin())).add( + A2.multiply(sc2.cos())).add(B2.multiply(sc2.sin())); + } + + /** Class for the values of the coefficients anm and bnm + * of the spherical harmonics expansion. + */ + private static class LegendreFunctions { + + /** Legendre functions anm for coefficient bh.*/ + private static final double[][] BH_A = { + {0.00271285863109945, -1.39197786008938e-06, 1.34955672002719e-06, 2.71686279717968e-07, 1.56659301773925e-06}, + {9.80476624811974e-06, -5.83922611260673e-05, -2.07307023860417e-05, 1.14628726961148e-06, 4.93610283608719e-06}, + {-1.03443106534268e-05, -2.05536138785961e-06, 2.09692641914244e-06, -1.55491034130965e-08, -1.89706404675801e-07}, + {-3.00353961749658e-05, 2.37284447073503e-05, 2.02236885378918e-05, 1.69276006349609e-06, 8.72156681243892e-07}, + {-7.99121077044035e-07, -5.39048313389504e-06, -4.21234502039861e-06, -2.70944149806894e-06, -6.80894455531746e-07}, + {7.51439609883296e-07, 3.85509708865520e-07, 4.41508016098164e-08, -2.07507808307757e-08, 4.95354985050743e-08}, + {2.21790962160087e-05, -5.56986238775212e-05, -1.81287885563308e-05, -4.41076013532589e-06, 4.93573223917278e-06}, + {-4.47639989737328e-06, -2.60452893072120e-06, 2.56376320011189e-06, 4.41600992220479e-07, 2.93437730332869e-07}, + {8.14992682244945e-07, 2.03945571424434e-07, 1.11832498659806e-08, 3.25756664234497e-08, 3.01029040414968e-08}, + {-7.96927680907488e-08, -3.66953150925865e-08, -6.74742632186619e-09, -1.30315731273651e-08, -2.00748924306947e-09}, + {-2.16138375166934e-05, 1.67350317962556e-05, 1.93768260076821e-05, 1.99595120161850e-06, -2.42463528222014e-06}, + {5.34360283708044e-07, -3.64189022040600e-06, -2.99935375194279e-06, -2.06880962903922e-06, -9.40815692626002e-07}, + {6.80235884441822e-07, 1.33023436079845e-07, -1.80349593705226e-08, 2.51276252565192e-08, -1.43240592002794e-09}, + {-7.13790897253802e-08, 7.81998506267559e-09, 1.13826909570178e-09, -5.89629600214654e-09, -4.20760865522804e-09}, + {-5.80109372399116e-09, 1.13702284491976e-09, 7.29046067602764e-10, -9.10468988754012e-10, -2.58814364808642e-10}, + {1.75558618192965e-05, -2.85579168876063e-05, -1.47442190284602e-05, -6.29300414335248e-06, -5.12204538913460e-07}, + {-1.90788558291310e-06, -1.62144845155361e-06, 7.57239241641566e-07, 6.93365788711348e-07, 6.88855644570695e-07}, + {2.27050351488552e-07, 1.03925791277660e-07, -3.31105076632079e-09, 2.88065761026675e-08, -8.00256848229136e-09}, + {-2.77028851807614e-08, -5.96251132206930e-09, 2.95987495527251e-10, -5.87644249625625e-09, -3.28803981542337e-09}, + {-1.89918479865558e-08, 3.54083436578857e-09, 8.10617835854935e-10, 4.99207055948336e-10, -1.52691648387663e-10}, + {1.04022499586096e-09, -2.36437143845013e-10, -2.25110813484842e-10, -7.39850069252329e-11, 7.95929405440911e-11}, + {-3.11579421267630e-05, -3.43576336877494e-06, 5.81663608263384e-06, 8.31534700351802e-07, 4.02619520312154e-06}, + {6.00037066879001e-07, -1.12538760056168e-07, -3.86745332115590e-07, -3.88218746020826e-07, -6.83764967176388e-07}, + {-9.79583981249316e-08, 9.14964449851003e-08, 4.77779838549237e-09, 2.44283811750703e-09, -6.26361079345158e-09}, + {-2.37742207548109e-08, -5.53336301671633e-09, -3.73625445257115e-09, -1.92304189572886e-09, -7.18681390197449e-09}, + {-6.58203463929583e-09, 9.28456148541896e-10, 2.47218904311077e-10, 1.10664919110218e-10, -4.20390976974043e-11}, + {9.45857603373426e-10, -3.29683402990254e-11, -8.15440375865127e-11, -1.21615589356628e-12, -9.70713008848085e-12}, + {1.61377382316176e-10, 6.84326027598147e-12, -4.66898885683671e-12, 2.31211355085535e-12, 2.39195112937346e-12}, + {2.99634365075821e-07, 8.14391615472128e-06, 6.70458490942443e-06, -9.92542646762000e-07, -3.04078064992750e-06}, + {-6.52697933801393e-07, 2.87255329776428e-07, -1.78227609772085e-08, 2.65525429849935e-07, 8.60650570551813e-08}, + {-1.62727164011710e-07, 1.09102479325892e-07, 4.97827431850001e-09, 7.86649963082937e-11, -6.67193813407656e-09}, + {-2.96370000987760e-09, 1.20008401576557e-09, 1.75885448022883e-09, -1.74756709684384e-09, 3.21963061454248e-09}, + {-9.91101697778560e-10, 7.54541713140752e-10, -2.95880967800875e-10, 1.81009160501278e-10, 8.31547411640954e-11}, + {1.21268051949609e-10, -5.93572774509587e-11, -5.03295034994351e-11, 3.05383430975252e-11, 3.56280438509939e-11}, + {6.92012970333794e-11, -9.02885345797597e-12, -3.44151832744880e-12, 2.03164894681921e-12, -5.44852265137606e-12}, + {5.56731263672800e-12, 3.57272150106101e-12, 2.25885622368678e-12, -2.44508240047675e-13, -6.83314378535235e-13}, + {3.96883487797254e-06, -4.57100506169608e-06, -3.30208117813256e-06, 3.32599719134845e-06, 4.26539325549339e-06}, + {1.10123151770973e-06, 4.58046760144882e-07, 1.86831972581926e-07, -1.60092770735081e-07, -5.58956114867062e-07}, + {-3.40344900506653e-08, 2.87649741373047e-08, -1.83929753066251e-08, -9.74179203885847e-09, -2.42064137485043e-09}, + {-6.49731596932566e-09, -3.07048108404447e-09, -2.84380614669848e-09, 1.55123146524283e-09, 4.53694984588346e-10}, + {5.45175793803325e-10, -3.73287624700125e-10, -1.16293122618336e-10, 7.25845618602690e-11, -4.34112440021627e-11}, + {1.89481447552805e-10, 3.67431482211078e-12, -1.72180065021194e-11, 1.47046319023226e-11, 1.31920481414062e-11}, + {2.10125915737167e-12, -3.08420783495975e-12, -4.87748712363020e-12, 1.16363599902490e-14, 1.26698255558605e-13}, + {-8.07894928696254e-12, 9.19344620512607e-13, 3.26929173307443e-13, 2.00438149416495e-13, -9.57035765212079e-15}, + {1.38737151773284e-12, 1.09340178371420e-13, 5.15714202449053e-14, -5.92156438588931e-14, -3.29586752336143e-14}, + {6.38137197198254e-06, 4.62426300749908e-06, 4.42334454191034e-06, 1.15374736092349e-06, -2.61859702227253e-06}, + {-2.25320619636149e-07, 3.21907705479353e-07, -3.34834530764823e-07, -4.82132753601810e-07, -3.22410936343355e-07}, + {3.48894515496995e-09, 3.49951261408458e-08, -6.01128959281142e-09, 4.78213900943443e-09, 1.46012816168576e-08}, + {-9.66682871952083e-11, 3.75806627535317e-09, 2.38984004956705e-09, 2.07545049877203e-09, 1.58573595632766e-09}, + {1.06834370693917e-09, -4.07975055112153e-10, -2.37598937943957e-10, 5.89327007480137e-11, 1.18891820437634e-10}, + {5.22433722695807e-11, 6.02011995016293e-12, -7.80605402956048e-12, 1.50873145627341e-11, -1.40550093106311e-12}, + {2.13396242187279e-13, -1.71939313965536e-12, -3.57625378660975e-14, -5.01675184988446e-14, -1.07805487368797e-12}, + {-1.24352330043311e-12, 8.26105883301606e-13, 4.63606970128517e-13, 6.39517888984486e-14, -7.35135439920086e-14}, + {-5.39023859065631e-13, 2.54188315588243e-14, 1.30933833278664e-14, 6.06153473304781e-15, -4.24722717533726e-14}, + {3.12767756884813e-14, -2.29517847871632e-15, 2.53117304424948e-16, 7.07504914138118e-16, -1.20089065310688e-15}, + {2.08311178819214e-06, -1.22179185044174e-06, -2.98842190131044e-06, 3.07310218974299e-06, 2.27100346036619e-06}, + {-3.94601643855452e-07, -5.44014825116083e-07, -6.16955333162507e-08, -2.31954821580670e-07, 1.14010813005310e-07}, + {6.11067575043044e-08, -3.93240193194272e-08, -1.62979132528933e-08, 1.01339204652581e-08, 1.97319601566071e-08}, + {2.57770508710055e-09, 1.87799543582899e-09, 1.95407654714372e-09, 1.15276419281270e-09, 2.25397005402120e-09}, + {7.16926338026236e-10, -3.65857693313858e-10, -1.54864067050915e-11, 6.50770211276549e-11, -7.85160007413546e-12}, + {4.90007693914221e-12, 3.31649396536340e-12, 4.81664871165640e-13, 7.26080745617085e-12, 2.30960953372164e-12}, + {9.75489202240545e-13, -1.68967954531421e-13, 7.38383391334110e-13, -3.58435515913239e-13, -3.01564710027450e-13}, + {-3.79533601922805e-13, 2.76681830946617e-13, 1.21480375553803e-13, -1.57729077644850e-14, -8.87664977818700e-14}, + {-3.96462845480288e-14, 2.94155690934610e-14, 6.78413205760717e-15, -4.12135802787361e-15, -1.46373307795619e-14}, + {-8.64941937408121e-15, -1.91822620970386e-15, -8.01725413560744e-16, 5.02941051180784e-16, -1.07572628474344e-15}, + {-4.13816294742758e-15, -7.43602019785880e-17, -5.54248556346072e-17, -4.83999456005158e-17, -1.19622559730466e-16}, + {-8.34852132750364e-07, -7.45794677612056e-06, -6.58132648865533e-06, -1.38608110346732e-06, 5.32326534882584e-07}, + {-2.75513802414150e-07, 3.64713745106279e-08, -7.12385417940442e-08, -7.86206067228882e-08, 2.28048393207161e-08}, + {-4.26696415431918e-08, -4.65599668635087e-09, 7.35037936327566e-09, 1.17098354115804e-08, 1.44594777658035e-08}, + {1.12407689274199e-09, 7.62142529563709e-10, -6.72563708415472e-10, -1.18094592485992e-10, -1.17043815733292e-09}, + {1.76612225246125e-10, -1.01188552503192e-10, 7.32546072616968e-11, 1.79542821801610e-11, -2.23264859965402e-11}, + {-9.35960722512375e-12, 1.90894283812231e-12, -6.34792824525760e-13, 3.98597963877826e-12, -4.47591409078971e-12}, + {-3.34623858556099e-12, 4.56384903915853e-14, 2.72561108521416e-13, -3.57942733300468e-15, 1.99794810657713e-13}, + {-6.16775522568954e-14, 8.25316968328823e-14, 7.19845814260518e-14, -2.92415710855106e-14, -5.49570017444031e-15}, + {-8.50728802453217e-15, 8.38161600916267e-15, 3.43651657459983e-15, -8.19429434115910e-16, -4.08905746461100e-15}, + {4.39042894275548e-15, -3.69440485320477e-16, 1.22249256876779e-16, -2.09359444520984e-16, -3.34211740264257e-16}, + {-5.36054548134225e-16, 3.29794204041989e-17, 2.13564354374585e-17, -1.37838993720865e-18, -1.29188342867753e-17}, + {-3.26421841529845e-17, 7.38235405234126e-18, 2.49291659676210e-18, 8.18252735459593e-19, 1.73824952279230e-20}, + {4.67237509268208e-06, 1.93611283787239e-06, 9.39035455627622e-07, -5.84565118072823e-07, -1.76198705802101e-07}, + {-3.33739157421993e-07, 4.12139555299163e-07, 1.58754695700856e-07, 1.37448753329669e-07, 1.04722936936873e-07}, + {6.64200603076386e-09, 1.45412222625734e-08, 1.82498796118030e-08, 2.86633517581614e-09, 1.06066984548100e-09}, + {5.25549696746655e-09, -1.33677183394083e-09, 7.60804375937931e-11, -1.07918624219037e-10, 8.09178898247941e-10}, + {1.89318454110039e-10, 9.23092164791765e-11, 5.51434573131180e-11, 3.86696392289240e-11, -1.15208165047149e-11}, + {-1.02252706006226e-12, -7.25921015411136e-13, -1.98110126887620e-12, -2.18964868282672e-13, -7.18834476685625e-13}, + {-2.69770025318548e-12, -2.17850340796321e-14, 4.73040820865871e-13, 1.57947421572149e-13, 1.86925164972766e-13}, + {1.07831718354771e-13, 2.26681841611017e-14, 2.56046087047783e-14, -1.14995851659554e-14, -2.27056907624485e-14}, + {6.29825154734712e-15, 8.04458225889001e-16, 9.53173540411138e-16, 1.16892301877735e-15, -1.04324684545047e-15}, + {-5.57345639727027e-16, -2.93949227634932e-16, 7.47621406284534e-18, -5.36416885470756e-17, -2.87213280230513e-16}, + {1.73219775047208e-16, 2.05017387523061e-17, 9.08873886345587e-18, -2.86881547225742e-18, -1.25303645304992e-17}, + {-7.30829109684568e-18, 2.03711261415353e-18, 7.62162636124024e-19, -7.54847922012517e-19, -8.85105098195030e-19}, + {5.62039968280587e-18, -1.38144206573507e-19, 1.68028711767211e-20, 1.81223858251981e-19, -8.50245194985878e-20} + }; + + /** Legendre functions anm for coefficient bw.*/ + private static final double[][] BW_A = { + {0.00136127467401223, -6.83476317823061e-07, -1.37211986707674e-06, 7.02561866200582e-07, -2.16342338010651e-07}, + {-9.53197486400299e-06, 6.58703762338336e-06, 2.42000663952044e-06, -6.04283463108935e-07, 2.02144424676990e-07}, + {-6.76728911259359e-06, 6.03830755085583e-07, -8.72568628835897e-08, 2.21750344140938e-06, 1.05146032931020e-06}, + {-3.21102832397338e-05, -7.88685357568093e-06, -2.55495673641049e-06, -1.99601934456719e-06, -4.62005252198027e-07}, + {-7.84639263523250e-07, 3.11624739733849e-06, 9.02170019697389e-07, 6.37066632506008e-07, -9.44485038780872e-09}, + {2.19476873575507e-06, -2.20580510638233e-07, 6.94761415598378e-07, 4.80770865279717e-07, -1.34357837196401e-07}, + {2.18469215148328e-05, -1.80674174262038e-06, -1.52754285605060e-06, -3.51212288219241e-07, 2.73741237656351e-06}, + {2.85579058479116e-06, 1.57201369332361e-07, -2.80599072875081e-07, -4.91267304946072e-07, -2.11648188821805e-07}, + {2.81729255594770e-06, 3.02487362536122e-07, -1.64836481475431e-07, -2.11607615408593e-07, -6.47817762225366e-08}, + {1.31809947620223e-07, -1.58289524114549e-07, -7.05580919885505e-08, 5.56781440550867e-08, 1.23403290710365e-08}, + {-1.29252282695869e-05, -1.07247072037590e-05, -3.31109519638196e-06, 2.13776673779736e-06, -1.49519398373391e-07}, + {1.81685152305722e-06, -1.17362204417861e-06, -3.19205277136370e-08, 4.09166457255416e-07, 1.53286667406152e-07}, + {1.63477723125362e-06, -2.68584775517243e-08, 4.94662064805191e-09, -7.09027987928288e-08, 4.44353430574937e-08}, + {-2.13090618917978e-07, 4.05836983493219e-08, 2.94495876336549e-08, -1.75005469063176e-08, -3.03015988647002e-09}, + {-2.16074435298006e-09, 9.37631708987675e-09, -2.05996036369828e-08, 6.97068002894092e-09, -8.90988987979604e-09}, + {1.38047798906967e-05, 2.05528261553901e-05, 1.59072148872708e-05, 7.34088731264443e-07, 1.28226710383580e-06}, + {7.08175753966264e-07, -9.27988276636505e-07, 1.60535820026081e-07, -3.27296675122065e-07, -2.20518321170684e-07}, + {1.90932483086199e-07, -7.44215272759193e-08, 1.81330673333187e-08, 4.37149649043616e-08, 4.18884335594172e-08}, + {-5.37009063880924e-08, 2.22870057779431e-08, 1.73740123037651e-08, -4.45137302235032e-09, 9.44721910524571e-09}, + {-6.83406949047909e-08, -1.95046676795923e-10, 2.57535903049686e-09, 4.82643164083020e-09, 3.37657333705158e-09}, + {3.96128688448981e-09, -6.63809403270686e-10, 2.44781464212534e-10, 5.92280853590699e-11, -4.78502591970721e-10}, + {1.75859399041414e-05, -2.81238050668481e-06, -2.43670534594848e-06, 3.58244562699714e-06, -1.76547446732691e-06}, + {-1.06451311473304e-07, 1.54336689617184e-06, -2.00690000442673e-07, 1.38790047911880e-09, -1.62490619890017e-07}, + {-2.72757421686155e-07, 1.71139266205398e-07, -2.55080309401917e-08, -8.40793079489831e-09, -1.01129447760167e-08}, + {2.92966025844079e-08, -2.07556718857313e-08, 5.45985315647905e-09, 8.76857690274150e-09, 1.06785510440474e-08}, + {-1.22059608941331e-08, 6.52491630264276e-09, -1.79332492326928e-10, 3.75921793745396e-10, -7.06416506254786e-10}, + {1.63224355776652e-09, 4.95586028736232e-10, -3.07879011759040e-10, -7.78354087544277e-11, 1.43959047067250e-10}, + {3.86319414653663e-10, -2.06467134617933e-10, 4.37330971382694e-11, -5.00421056263711e-11, -9.40237773015723e-12}, + {-1.23856142706451e-05, 7.61047394008415e-06, -1.99104114578138e-07, 6.86177748886858e-07, -1.09466747592827e-07}, + {2.99866062403128e-07, 1.87525561397390e-07, 4.99374806994715e-08, 4.86229763781404e-07, 4.46570575517658e-07}, + {-5.05748332368430e-07, 1.95523624722285e-08, -9.17535435911345e-08, -2.56671607433547e-08, -7.11896201616653e-08}, + {-2.66062200406494e-08, -5.40470019739274e-09, -2.29718660244954e-09, -3.73328592264404e-09, 3.38748313712376e-09}, + {5.30855327954894e-10, 5.28851845648032e-10, -2.22278913745418e-10, -5.52628653064771e-11, -9.24825145219684e-10}, + {6.03737227573716e-10, -3.52190673510919e-12, -1.30371720641414e-10, -9.12787239944822e-12, 6.42187285537238e-12}, + {1.78081862458539e-10, 2.93772078656037e-12, -1.04698379945322e-11, -2.82260024833024e-11, -5.61810459067525e-12}, + {9.35003092299580e-12, -8.23133834521577e-13, 5.54878414224198e-13, -3.62943215777181e-13, 2.38858933771653e-12}, + {-1.31216096107331e-05, -5.70451670731759e-06, -5.11598683573971e-06, -4.99990779887599e-06, 1.27389320221511e-07}, + {-1.23108260369048e-06, 5.53093245213587e-07, 8.60093183929302e-07, 2.65569700925696e-07, 1.95485134805575e-07}, + {-2.29647072638049e-07, -5.45266515081825e-08, 2.85298129762263e-08, 1.98167939680185e-08, 5.52227340898335e-09}, + {-2.73844745019857e-08, -4.48345173291362e-10, -1.93967347049382e-09, -1.41508853776629e-09, -1.75456962391145e-09}, + {-2.68863184376108e-11, -2.20546981683293e-09, 6.56116990576877e-10, 1.27129855674922e-10, -2.32334506413213e-10}, + {1.98303136881156e-10, 6.04782006047075e-11, 2.91291115431570e-11, 6.18098615782757e-11, -3.82682292530379e-11}, + {9.48294455071158e-12, -3.05873596453015e-13, 5.31539408055057e-13, -7.31016438665600e-12, -1.19921002209198e-11}, + {-2.25188050845725e-11, -3.91627574966393e-13, -6.80217235976769e-13, 5.91033607278405e-13, 5.02991534452191e-13}, + {1.29532063896247e-12, 1.66337285851564e-13, 3.25543028344555e-13, 1.89143357962363e-13, 3.32288378169726e-13}, + {-2.45864358781728e-06, 4.49460524898260e-06, 1.03890496648813e-06, -2.73783420376785e-06, 7.12695730642593e-07}, + {-9.27805078535168e-07, -4.97733876686731e-07, 9.18680298906510e-08, -2.47200617423980e-07, 6.16163630140379e-08}, + {-1.39623661883136e-08, -1.12580495666505e-07, 2.61821435950379e-08, -2.31875562002885e-08, 5.72679835033659e-08}, + {-9.52538983318497e-09, -5.40909215302433e-09, 1.88698793952475e-09, -4.08127746406372e-09, 1.09534895853812e-10}, + {3.79767457525741e-09, 1.11549801373366e-10, -6.45504957274111e-10, 3.05477141010356e-10, 1.26261210565856e-10}, + {5.08813577945300e-11, 1.43250547678637e-11, 8.81616572082448e-12, 2.58968878880804e-11, 3.83421818249954e-11}, + {8.95094368142044e-12, -3.26220304555971e-12, -1.28047847191896e-12, 2.67562170258942e-12, 2.72195031576670e-12}, + {-6.47181697409757e-12, 1.13776457455685e-12, 2.84856274334969e-13, -7.63667272085395e-14, -1.34451657758826e-13}, + {-1.25291265888343e-12, 8.63500441050317e-14, -1.21307856635548e-13, 5.12570529540511e-14, 3.32389276976573e-14}, + {3.73573418085813e-14, -5.37808783042784e-16, -4.23430408270850e-16, -4.75110565740493e-15, 6.02553212780166e-15}, + {8.95483987262751e-06, -3.90778212666235e-06, -1.12115019808259e-06, 1.78678942093383e-06, 1.46806344157962e-06}, + {-4.59185232678613e-07, 1.09497995905419e-07, 1.31663977640045e-07, 4.20525791073626e-08, -9.71470741607431e-08}, + {1.63399802579572e-07, 1.50909360648645e-08, -1.11480472593347e-08, -1.84000857674573e-08, 7.82124614794256e-09}, + {1.22887452385094e-08, -4.06647399822746e-10, -6.49120327585597e-10, 8.63651225791194e-10, -2.73440085913102e-09}, + {2.51748630889583e-09, 4.79895880425564e-10, -2.44908073860844e-10, 2.56735882664876e-10, -1.64815306286912e-10}, + {4.85671381736718e-11, -2.51742732115131e-11, -2.60819437993179e-11, 6.12728324086123e-12, 2.16833310896138e-11}, + {4.11389702320298e-12, -8.09433180989935e-13, -1.19812498226024e-12, 1.46885737888520e-12, 3.15807685137836e-12}, + {-1.47614580597013e-12, 4.66726413909320e-13, 1.72089709006255e-13, 1.13854935381418e-13, 2.77741161317003e-13}, + {-1.02257724967727e-13, 1.10394382923502e-13, -3.14153505370805e-15, 2.41103099110106e-14, 2.13853053149771e-14}, + {-3.19080885842786e-14, -9.53904307973447e-15, 2.74542788156379e-15, 2.33797859107844e-15, -2.53192474907304e-15}, + {-5.87702222126367e-15, -1.80133850930249e-15, -3.09793125614454e-16, -1.04197538975295e-16, 3.72781664701327e-16}, + {1.86187054729085e-06, 8.33098045333428e-06, 3.18277735484232e-06, -7.68273797022231e-07, -1.52337222261696e-06}, + {-5.07076646593648e-07, -8.61959553442156e-07, -3.51690005432816e-07, -4.20797082902431e-07, -3.07652993252673e-07}, + {-7.38992472164147e-08, -8.39473083080280e-08, -2.51587083298935e-08, 7.30691259725451e-09, -3.19457155958983e-08}, + {-1.99777182012924e-09, -3.21265085916022e-09, -4.84477421865675e-10, -1.82924814205799e-09, -3.46664344655997e-10}, + {-7.05788559634927e-11, 1.21840735569025e-10, 7.97347726425926e-11, 1.08275679614409e-10, -1.17891254809785e-10}, + {1.10299718947774e-11, -3.22958261390263e-11, -1.43535798209229e-11, 6.87096504209595e-12, -6.64963212272352e-12}, + {-6.47393639740084e-12, 1.03156978325120e-12, -9.20099775082358e-14, -2.40150316641949e-13, 1.14008812047857e-12}, + {-1.23957846397250e-13, 2.85996703969692e-13, 1.91579874982553e-13, 5.20597174693064e-14, -4.06741434883370e-14}, + {-2.35479068911236e-14, 1.97847338186993e-14, 1.58935977518516e-15, -2.32217195254742e-15, -8.48611789490575e-15}, + {1.03992320391626e-14, 1.54017082092642e-15, 1.05950035082788e-16, -1.17870898461353e-15, -1.10937420707372e-15}, + {-1.09011948374520e-15, -6.04168007633584e-16, -9.10901998157436e-17, 1.98379116989461e-16, -1.03715496658498e-16}, + {-1.38171942108278e-16, -6.33037999097522e-17, -1.38777695011470e-17, 1.94191397045401e-17, 5.70055906754485e-18}, + {1.92989406002085e-06, -3.82662130483128e-06, -4.60189561036048e-07, 2.24290587856309e-06, 1.40544379451550e-06}, + {6.49033717633394e-08, 2.41396114435326e-07, 2.73948898223321e-07, 1.10633664439332e-07, -3.19555270171075e-08}, + {-2.91988966963297e-08, -6.03828192816571e-09, 1.18462386444840e-08, 1.32095545004128e-08, -5.06572721528914e-09}, + {7.31079058474148e-09, -8.42775299751834e-10, 1.10190810090667e-09, 1.96592273424306e-09, -2.13135932785688e-09}, + {7.06656405314388e-11, 1.43441125783756e-10, 1.46962246686924e-10, 7.44592776425197e-11, -3.64331892799173e-11}, + {-2.52393942119372e-11, 1.07520964869263e-11, 5.84669886072094e-12, 6.52029744217103e-12, 1.82947123132059e-12}, + {-4.15669940115121e-12, -1.95963254053648e-13, 2.16977822834301e-13, -2.84701408462031e-13, 4.27194601040231e-13}, + {3.07891105454129e-13, 1.91523190672955e-13, 1.05367297580989e-13, -5.28136363920236e-14, -3.53364110005917e-14}, + {7.02156663274738e-15, 9.52230536780849e-15, -3.41019408682733e-15, -3.59825303352899e-15, -2.62576411636150e-15}, + {-1.75110277413804e-15, 5.29265220719483e-16, 4.45015980897919e-16, -3.80179856341347e-16, -4.32917763829695e-16}, + {1.16038609651443e-16, -6.69643574373352e-17, 2.65667154817303e-17, -9.76010333683956e-17, 4.07312981076655e-17}, + {5.72659246346386e-18, 1.30357528108671e-18, 2.49193258417535e-18, 1.76247014075584e-18, 7.59614374197688e-19}, + {1.03352170833303e-17, -2.30633516638829e-18, 2.84777940620193e-18, -7.72161347944693e-19, 6.07028034506380e-19} + }; + + /** Legendre functions anm for coefficient ch.*/ + private static final double[][] CH_A = { + {0.0571481238161787, 3.35402081801137e-05, 3.15988141788728e-05, -1.34477341887086e-05, -2.61831023577773e-07}, + {5.77367395845715e-05, -0.000669057185209558, -6.51057691648904e-05, -1.61830149147091e-06, 8.96771209464758e-05}, + {-8.50773002452907e-05, -4.87106614880272e-05, 4.03431160775277e-05, 2.54090162741464e-06, -5.59109319864264e-06}, + {0.00150536423187709, 0.000611682258892697, 0.000369730024614855, -1.95658439780282e-05, -3.46246726553700e-05}, + {-2.32168718433966e-05, -0.000127478686553809, -9.00292451740728e-05, -6.07834315901830e-05, -1.04628419422714e-05}, + {-1.38607250922551e-06, -3.97271603842309e-06, -8.16155320152118e-07, 5.73266706046665e-07, 2.00366060212696e-07}, + {6.52491559188663e-05, -0.00112224323460183, -0.000344967958304075, -7.67282640947300e-05, 0.000107907110551939}, + {-0.000138870461448036, -7.29995695401936e-05, 5.35986591445824e-05, 9.03804869703890e-06, 8.61370129482732e-06}, + {-9.98524443968768e-07, -6.84966792665998e-08, 1.47478021860771e-07, 1.94857794008064e-06, 7.17176852732910e-07}, + {1.27066367911720e-06, 1.12113289164288e-06, 2.71525688515375e-07, -2.76125723009239e-07, -1.05429690305013e-07}, + {-0.000377264999981652, 0.000262691217024294, 0.000183639785837590, 3.93177048515576e-06, -6.66187081899168e-06}, + {-4.93720951871921e-05, -0.000102820030405771, -5.69904376301748e-05, -3.79603438055116e-05, -3.96726017834930e-06}, + {-2.21881958961135e-06, -1.40207117987894e-06, 1.60956630798516e-07, 2.06121145135022e-06, 6.50944708093149e-07}, + {2.21876332411271e-07, 1.92272880430386e-07, -6.44016558013941e-09, -1.40954921332410e-07, -4.26742169137667e-07}, + {-3.51738525149881e-08, 2.89616194332516e-08, -3.40343352397886e-08, -2.89763392721812e-08, -6.40980581663785e-10}, + {3.51240856823468e-05, -0.000725895015345786, -0.000322514037108045, -0.000106143759981636, 4.08153152459337e-05}, + {-2.36269716929413e-05, -4.20691836557932e-05, 1.43926743222922e-05, 2.61811210631784e-05, 2.09610762194903e-05}, + {-7.91765756673890e-07, 1.64556789159745e-06, -9.43930166276555e-07, 6.46641738736139e-07, -5.91509547299176e-07}, + {3.92768838766879e-07, -1.98027731703690e-07, -5.41303590057253e-08, -4.21705797874207e-07, -6.06042329660681e-08}, + {-1.56650141024305e-08, 7.61808165752027e-08, -1.81900460250934e-08, 1.30196216971675e-08, 1.08616031342379e-08}, + {-2.80964779829242e-08, -7.25951488826103e-09, -2.59789823306225e-09, -2.79271942407154e-09, 4.10558774868586e-09}, + {-0.000638227857648286, -0.000154814045363391, 7.78518327501759e-05, -2.95961469342381e-05, 1.15965225055757e-06}, + {4.47833146915112e-06, 1.33712284237555e-05, 3.61048816552123e-06, -2.50717844073547e-06, -1.28100822021734e-05}, + {-2.26958070007455e-06, 2.57779960912242e-06, 1.08395653197976e-06, 1.29403393862805e-07, -1.04854652812567e-06}, + {-3.98954043463392e-07, -2.26931182815454e-07, -1.09169545045028e-07, -1.49509536031939e-07, -3.98376793949903e-07}, + {2.30418911071110e-08, 1.23098508481555e-08, -1.71161401463708e-08, 2.35829696577657e-09, 1.31136164162040e-08}, + {3.69423793101582e-09, 3.49231027561927e-10, -1.18581468768647e-09, 5.43180735828820e-10, 5.43192337651588e-10}, + {-1.38608847117992e-09, -1.86719145546559e-10, -8.13477384765498e-10, 2.01919878240491e-10, 1.00067892622287e-10}, + {-4.35499078415956e-05, 0.000450727967957804, 0.000328978494268850, -3.05249478582848e-05, -3.21914834544310e-05}, + {1.24887940973241e-05, 1.34275239548403e-05, 1.11275518344713e-06, 7.46733554562851e-06, -2.12458664760353e-06}, + {9.50250784948476e-07, 2.34367372695203e-06, -5.43099244798980e-07, -4.35196904508734e-07, -8.31852234345897e-07}, + {5.91775478636535e-09, -1.48970922508592e-07, 2.99840061173840e-08, -1.30595933407792e-07, 1.27136765045597e-07}, + {-1.78491083554475e-08, 1.76864919393085e-08, -1.96740493482011e-08, 1.21096708004261e-08, 2.95518703155064e-10}, + {1.75053510088658e-09, -1.31414287871615e-09, -1.44689439791928e-09, 1.14682483668460e-09, 1.74488616540169e-09}, + {1.08152964586251e-09, -3.85678162063266e-10, -2.77851016629979e-10, 3.89890578625590e-11, -2.54627365853495e-10}, + {-1.88340955578221e-10, 5.19645384002867e-11, 2.14131326027631e-11, 1.24027770392728e-11, -9.42818962431967e-12}, + {0.000359777729843898, -0.000111692619996219, -6.87103418744904e-05, 0.000115128973879551, 7.59796247722486e-05}, + {5.23717968000879e-05, 1.32279078116467e-05, -5.72277317139479e-07, -7.56326558610214e-06, -1.95749622214651e-05}, + {1.00109213210139e-06, -2.75515216592735e-07, -1.13393194050846e-06, -4.75049734870663e-07, -3.21499480530932e-07}, + {-2.07013716598890e-07, -7.31392258077707e-08, -3.96445714084160e-08, 3.21390452929387e-08, -1.43738764991525e-08}, + {2.03081434931767e-09, -1.35423687136122e-08, -4.47637454261816e-09, 2.18409121726643e-09, -3.74845286805217e-09}, + {3.17469255318367e-09, 2.44221027314129e-10, -2.46820614760019e-10, 7.55851003884434e-10, 6.98980592550891e-10}, + {9.89541493531067e-11, -2.78762878057315e-11, -2.10947962916771e-10, 3.77882267360636e-11, -1.20009542671532e-12}, + {5.01720575730940e-11, 1.66470417102135e-11, -7.50624817938091e-12, 9.97880221482238e-12, 4.87141864438892e-12}, + {2.53137945301589e-11, 1.93030083090772e-12, -1.44708804231290e-12, -1.77837100743423e-12, -8.10068935490951e-13}, + {0.000115735341520738, 0.000116910591048350, 8.36315620479475e-05, 1.61095702669207e-05, -7.53084853489862e-05}, + {-9.76879433427199e-06, 9.16968438003335e-06, -8.72755127288830e-06, -1.30077933880053e-05, -9.78841937993320e-06}, + {1.04902782517565e-07, 2.14036988364936e-07, -7.19358686652888e-07, 1.12529592946332e-07, 7.07316352860448e-07}, + {7.63177265285080e-08, 1.22781974434290e-07, 8.99971272969286e-08, 5.63482239352990e-08, 4.31054352285547e-08}, + {3.29855763107355e-09, -6.95004336734441e-09, -6.52491370576354e-09, 1.97749180391742e-09, 3.51941791940498e-09}, + {3.85373745846559e-10, 1.65754130924183e-10, -3.31326088103057e-10, 5.93256024580436e-10, 1.27725220636915e-10}, + {-1.08840956376565e-10, -4.56042860268189e-11, -4.77254322645633e-12, -2.94405398621875e-12, -3.07199979999475e-11}, + {2.07389879095010e-11, 1.51186798732451e-11, 9.28139802941848e-12, 5.92738269687687e-12, 9.70337402306505e-13}, + {-2.85879708060306e-12, 1.92164314717053e-13, 4.02664678967890e-14, 5.18246319204277e-13, -7.91438726419423e-13}, + {6.91890667590734e-13, -8.49442290988352e-14, -5.54404947212402e-15, 9.71093377538790e-15, -5.33714333415971e-14}, + {-5.06132972789792e-05, -4.28348772058883e-05, -6.90746551020305e-05, 8.48380415176836e-05, 7.04135614675053e-05}, + {-1.27945598849788e-05, -1.92362865537803e-05, -2.30971771867138e-06, -8.98515975724166e-06, 5.25675205004752e-06}, + {-8.71907027470177e-07, -1.02091512861164e-06, -1.69548051683864e-07, 4.87239045855761e-07, 9.13163249899837e-07}, + {-6.23651943425918e-08, 6.98993315829649e-08, 5.91597766733390e-08, 4.36227124230661e-08, 6.45321798431575e-08}, + {-1.46315079552637e-10, -7.85142670184337e-09, 1.48788168857903e-09, 2.16870499912160e-09, -1.16723047065545e-09}, + {3.31888494450352e-10, 1.90931898336457e-10, -3.13671901557599e-11, 2.60711798190524e-10, 8.45240112207997e-11}, + {1.36645682588537e-11, -5.68830303783976e-12, 1.57518923848140e-11, -1.61935794656758e-11, -4.16568077748351e-12}, + {9.44684950971905e-13, 7.30313977131995e-12, 3.14451447892684e-12, 6.49029875639842e-13, -9.66911019905919e-13}, + {-8.13097374090024e-13, 5.23351897822186e-13, 8.94349188113951e-14, -1.33327759673270e-13, -4.04549450989029e-13}, + {-3.76176467005839e-14, -6.19953702289713e-14, -3.74537190139726e-14, 1.71275486301958e-14, -3.81946773167132e-14}, + {-4.81393385544160e-14, 3.66084990006325e-15, 3.10432030972253e-15, -4.10964475657416e-15, -6.58644244242900e-15}, + {-7.81077363746945e-05, -0.000254773632197303, -0.000214538508009518, -3.80780934346726e-05, 1.83495359193990e-05}, + {5.89140224113144e-06, -3.17312632433258e-06, -3.81872516710791e-06, -2.27592226861647e-06, 1.57044619888023e-06}, + {-1.44272505088690e-06, -1.10236588903758e-07, 2.64336813084693e-07, 4.76074163332460e-07, 4.28623587694570e-07}, + {3.98889120733904e-08, -1.29638005554027e-08, -4.13668481273828e-08, 1.27686793719542e-09, -3.54202962042383e-08}, + {1.60726837551750e-09, -2.70750776726156e-09, 2.79387092681070e-09, -3.01419734793998e-10, -1.29101669438296e-10}, + {-2.55708290234943e-10, 2.27878015173471e-11, -6.43063443462716e-12, 1.26531554846856e-10, -1.65822147437220e-10}, + {-3.35886470557484e-11, -3.51895009091595e-12, 5.80698399963198e-12, -2.84881487149207e-12, 8.91708061745902e-12}, + {-3.12788523950588e-12, 3.35366912964637e-12, 2.52236848033838e-12, -8.12801050709184e-13, -2.63510394773892e-13}, + {6.83791881183142e-14, 2.41583263270381e-13, 8.58807794189356e-14, -5.12528492761045e-14, -1.40961725631276e-13}, + {-1.28585349115321e-14, -2.11049721804969e-14, 5.26409596614749e-15, -4.31736582588616e-15, -1.60991602619068e-14}, + {-9.35623261461309e-15, -3.94384886372442e-16, 5.04633016896942e-16, -5.40268998456055e-16, -1.07857944298104e-15}, + {8.79756791888023e-16, 4.52529935675330e-16, 1.36886341163227e-16, -1.12984402980452e-16, 6.30354561057224e-18}, + {0.000117829256884757, 2.67013591698442e-05, 2.57913446775250e-05, -4.40766244878807e-05, -1.60651761172523e-06}, + {-1.87058092029105e-05, 1.34371169060024e-05, 5.59131416451555e-06, 4.50960364635647e-06, 2.87612873904633e-06}, + {2.79835536517287e-07, 8.93092708148293e-07, 8.37294601021795e-07, -1.99029785860896e-08, -8.87240405168977e-08}, + {4.95854313394905e-08, -1.44694570735912e-08, 2.51662229339375e-08, -3.87086600452258e-09, 2.29741919071270e-08}, + {4.71497840986162e-09, 2.47509999454076e-09, 1.67323845102824e-09, 8.14196768283530e-10, -3.71467396944165e-10}, + {-1.07340743907054e-10, -8.07691657949326e-11, -5.99381660248133e-11, 2.33173929639378e-12, -2.26994195544563e-11}, + {-3.83130441984224e-11, -5.82499946138714e-12, 1.43286311435124e-11, 3.15150503353387e-12, 5.97891025146774e-12}, + {-5.64389191072230e-13, 9.57258316335954e-13, 1.12055192185939e-12, -4.42417706775420e-13, -9.93190361616481e-13}, + {1.78188860269677e-13, 7.82582024904950e-14, 5.18061650118009e-14, 2.13456507353387e-14, -5.26202113779510e-14}, + {-8.18481324740893e-15, -3.71256746886786e-15, 4.23508855164371e-16, -2.91292502923102e-15, -1.15454205389350e-14}, + {6.16578691696810e-15, 6.74087154080877e-16, 5.71628946437034e-16, -2.05251213979975e-16, -7.25999138903781e-16}, + {9.35481959699383e-17, 6.23535830498083e-17, 3.18076728802060e-18, -2.92353209354587e-17, 7.65216088665263e-19}, + {2.34173078531701e-17, -8.30342420281772e-18, -4.33602329912952e-18, 1.90226281379981e-18, -7.85507922718903e-19} + }; + + /** Legendre functions anm for coefficient cw.*/ + private static final double[][] CW_A = { + {0.0395329695826997, -0.000131114380761895, -0.000116331009006233, 6.23548420410646e-05, 5.72641113425116e-05}, + {-0.000441837640880650, 0.000701288648654908, 0.000338489802858270, 3.76700309908602e-05, -8.70889013574699e-06}, + {1.30418530496887e-05, -0.000185046547597376, 4.31032103066723e-05, 0.000105583334124319, 3.23045436993589e-05}, + {3.68918433448519e-05, -0.000219433014681503, 3.46768613485000e-06, -9.17185187163528e-05, -3.69243242456081e-05}, + {-6.50227201116778e-06, 2.07614874282187e-05, -5.09131314798362e-05, -3.08053225174359e-05, -4.18483655873918e-05}, + {2.67879176459056e-05, -6.89303730743691e-05, 2.11046783217168e-06, 1.93163912538178e-05, -1.97877143887704e-06}, + {0.000393937595007422, -0.000452948381236406, -0.000136517846073846, 0.000138239247989489, 0.000133175232977863}, + {5.00214539435002e-05, 3.57229726719727e-05, -9.38010547535432e-07, -3.52586798317563e-05, -7.01218677681254e-06}, + {3.91965314099929e-05, 1.02236686806489e-05, -1.95710695226022e-05, -5.93904795230695e-06, 3.24339769876093e-06}, + {6.68158778290653e-06, -8.10468752307024e-06, -9.91192994096109e-06, -1.89755520007723e-07, -3.26799467595579e-06}, + {0.000314196817753895, -0.000296548447162009, -0.000218410153263575, -1.57318389871000e-05, 4.69789570185785e-05}, + {0.000104597721123977, -3.31000119089319e-05, 5.60326793626348e-05, 4.71895007710715e-05, 3.57432326236664e-05}, + {8.95483021572039e-06, 1.44019305383365e-05, 4.87912790492931e-06, -3.45826387853503e-06, 3.23960320438157e-06}, + {-1.35249651009930e-05, -2.49349762695977e-06, -2.51509483521132e-06, -9.14254874104858e-07, -8.57897406100890e-07}, + {-1.68143325235195e-06, 1.72073417594235e-06, 1.38765993969565e-06, 4.09770982137530e-07, -6.60908742097123e-07}, + {-0.000639889366487161, 0.00120194042474696, 0.000753258598887703, 3.87356377414663e-05, 1.31231811175345e-05}, + {2.77062763606783e-05, -9.51425270178477e-06, -6.61068056107547e-06, -1.38713669012109e-05, 9.84662092961671e-06}, + {-2.69398078539471e-06, 6.50860676783123e-06, 3.80855926988090e-06, -1.98076068364785e-06, 1.17187335666772e-06}, + {-2.63719028151905e-06, 5.03149473656743e-07, 7.38964893399716e-07, -8.38892485369078e-07, 1.30943917775613e-06}, + {-1.56634992245479e-06, -2.97026487417045e-08, 5.06602801102463e-08, -4.60436007958792e-08, -1.62536449440997e-07}, + {-2.37493912770935e-07, 1.69781593069938e-08, 8.35178275224265e-08, -4.83564044549811e-08, -4.96448864199318e-08}, + {0.00134012259587597, -0.000250989369253194, -2.97647945512547e-05, -6.47889968094926e-05, 8.41302130716859e-05}, + {-0.000113287184900929, 4.78918993866293e-05, -3.14572113583139e-05, -2.10518256626847e-05, -2.03933633847417e-05}, + {-4.97413321312139e-07, 3.72599822034753e-06, -3.53221588399266e-06, -1.05232048036416e-06, -2.74821498198519e-06}, + {4.81988542428155e-06, 4.21400219782474e-07, 1.02814808667637e-06, 4.40299068486188e-09, 3.37103399036634e-09}, + {1.10140301678818e-08, 1.90257670180182e-07, -1.00831353341885e-08, 1.44860642389714e-08, -5.29882089987747e-08}, + {6.12420414245775e-08, -4.48953461152996e-09, -1.38837603709003e-08, -2.05533675904779e-08, 1.49517908802329e-09}, + {9.17090243673643e-10, -9.24878857867367e-09, -2.30856560363943e-09, -4.36348789716735e-09, -4.45808881183025e-10}, + {-0.000424912699609112, -0.000114365438471564, -0.000403200981827193, 4.19949560550194e-05, -3.02068483713739e-05}, + {3.85435472851225e-05, -5.70726887668306e-05, 4.96313706308613e-07, 1.02395703617082e-05, 5.85550000567006e-06}, + {-7.38204470183331e-06, -4.56638770109511e-06, -3.94007992121367e-06, -2.16666812189101e-06, -4.55694264113194e-06}, + {5.89841165408527e-07, 1.40862905173449e-08, 1.08149086563211e-07, -2.18592601537944e-07, -3.78927431428119e-07}, + {4.85164687450468e-08, 8.34273921293655e-08, 1.47489605513673e-08, 6.01494125001291e-08, 6.43812884159484e-09}, + {1.13055580655363e-08, 3.50568765400469e-09, -5.09396162501750e-09, -1.83362063152411e-09, -4.11227251553035e-09}, + {3.16454132867156e-09, -1.39634794131087e-09, -7.34085003895929e-10, -7.55541371271796e-10, -1.57568747643705e-10}, + {1.27572900992112e-09, -3.51625955080441e-10, -4.84132020565098e-10, 1.52427274930711e-10, 1.27466120431317e-10}, + {-0.000481655666236529, -0.000245423313903835, -0.000239499902816719, -0.000157132947351028, 5.54583099258017e-05}, + {-1.52987254785589e-05, 2.78383892116245e-05, 4.32299123991860e-05, 1.70981319744327e-05, -1.35090841769225e-06}, + {-8.65400907717798e-06, -6.51882656990376e-06, -2.43810171017369e-07, 8.54348785752623e-07, 2.98371863248143e-07}, + {-1.68155571776752e-06, -3.53602587563318e-07, -1.00404435881759e-07, -2.14162249012859e-08, -2.42131535531526e-07}, + {-1.08048603277187e-08, -9.78850785763030e-08, -2.32906554437417e-08, 2.22003630858805e-08, -2.27230368089683e-09}, + {-5.98864391551041e-09, 7.38970926486848e-09, 3.61322835311957e-09, 3.70037329172919e-09, -3.41121137081362e-09}, + {-7.33113754909726e-10, -9.08374249335220e-11, -1.78204392133739e-10, 8.28618491929026e-11, -1.32966817912373e-10}, + {-5.23340481314676e-10, 1.36403528233346e-10, -7.04478837151279e-11, -6.83175201536443e-12, -2.86040864071134e-12}, + {3.75347503578356e-11, -1.08518134138781e-11, -2.53583751744508e-12, 1.00168232812303e-11, 1.74929602713312e-11}, + {-0.000686805336370570, 0.000591849814585706, 0.000475117378328026, -2.59339398048415e-05, 3.74825110514968e-05}, + {3.35231363034093e-05, 2.38331521146909e-05, 7.43545963794093e-06, -3.41430817541849e-06, 7.20180957675353e-06}, + {3.60564374432978e-07, -3.13300039589662e-06, -6.38974746108020e-07, -8.63985524672024e-07, 2.43367665208655e-06}, + {-4.09605238516094e-07, -2.51158699554904e-07, -1.29359217235188e-07, -2.27744642483133e-07, 7.04065989970205e-08}, + {6.74886341820129e-08, -1.02009407061935e-08, -3.30790296448812e-08, 1.64959795655031e-08, 1.40641779998855e-08}, + {1.31706886235108e-09, -1.06243701278671e-09, -2.85573799673944e-09, 3.72566568681289e-09, 2.48402582003925e-09}, + {-3.68427463251097e-11, -1.90028122983781e-10, -3.98586561768697e-11, 1.14458831693287e-11, -2.27722300377854e-12}, + {-7.90029729611056e-11, 3.81213646526419e-11, 4.63303426711788e-11, 1.52294835905903e-11, -2.99094751490726e-12}, + {-2.36146602045017e-11, 1.03852674709985e-11, -4.47242126307100e-12, 5.30884113537806e-12, 1.68499023262969e-12}, + {-3.30107358134527e-13, -4.73989085379655e-13, 5.17199549822684e-13, 2.34951744478255e-13, 2.05931351608192e-13}, + {0.000430215687511780, -0.000132831373000014, -3.41830835017045e-05, 4.70312161436033e-06, -3.84807179340006e-05}, + {1.66861163032403e-05, -8.10092908523550e-06, 8.20658107437905e-06, 6.12399025026683e-06, -1.85536495631911e-06}, + {1.53552093641337e-06, 2.19486495660361e-06, -1.07253805120137e-06, -4.72141767909137e-07, 4.00744581573216e-07}, + {2.56647305130757e-07, -8.07492046592274e-08, -2.05858469296168e-07, 1.09784168930599e-07, -7.76823030181225e-08}, + {1.77744008115031e-08, 1.64134677817420e-08, 4.86163044879020e-09, 1.13334251800856e-08, -7.17260621115426e-09}, + {1.61133063219326e-09, -1.85414677057024e-09, -2.13798537812651e-09, 1.15255123229679e-09, 2.24504700129464e-09}, + {1.23344223096739e-10, -1.20385012169848e-10, -2.18038256346433e-12, 3.23033120628279e-11, 8.01179568213400e-11}, + {-6.55745274387847e-12, 1.22127104697198e-11, 5.83805016355883e-12, -8.31201582509817e-12, 1.90985373872656e-12}, + {-2.89199983667265e-12, 5.05962500506667e-12, 1.28092925110279e-12, 5.60353813743813e-13, 1.76753731968770e-12}, + {-1.61678729774956e-13, -3.92206170988615e-13, -9.04941327579237e-14, 1.89847694200763e-13, 4.10008676756463e-14}, + {-1.16808369005656e-13, -9.97464591430510e-14, 7.46366550245722e-15, 2.53398578153179e-14, 1.06510689748906e-14}, + {-0.000113716921384790, -0.000131902722651488, -0.000162844886485788, 7.90171538739454e-06, -0.000178768066961413}, + {-2.13146535366500e-06, -3.57818705543597e-05, -1.50825855069298e-05, -2.17909259570022e-05, -8.19332236308581e-06}, + {-2.88001138617357e-06, -2.09957465440793e-06, 6.81466526687552e-08, 3.58308906974448e-07, -4.18502067223724e-07}, + {-1.10761444317605e-07, 6.91773860777929e-08, 8.17125372450372e-08, -2.16476237959181e-08, 7.59221970502074e-08}, + {-9.56994224818941e-09, 6.64104921728432e-09, 6.33077902928348e-09, 2.85721181743727e-09, -6.39666681678123e-09}, + {4.62558627839842e-10, -1.69014863754621e-09, -2.80260429599733e-10, 4.27558937623863e-11, -1.66926133269027e-10}, + {-7.23385132663753e-11, 5.51961193545280e-11, 3.04070791942335e-11, 3.23227055919062e-12, 8.47312431934829e-11}, + {-1.61189613765486e-11, 1.66868155925172e-11, 1.05370341694715e-11, -4.41495859079592e-12, -2.24939051401750e-12}, + {-8.72229568056267e-13, 1.88613726203286e-12, 1.21711137534390e-14, -1.13342372297867e-12, -6.87151975256052e-13}, + {7.99311988544090e-15, 4.46150979586709e-14, 7.50406779454998e-14, -3.20385428942275e-14, -1.26543636054393e-14}, + {4.80503817699514e-14, -3.35545623603729e-14, -1.18546423610485e-14, 4.19419209985980e-15, -1.73525614436880e-14}, + {-1.20464898830163e-15, -8.80752065000456e-16, -1.22214298993313e-15, 1.69928513019657e-15, 1.93593051311405e-16}, + {1.68528879784841e-05, 3.57144412031081e-05, -1.65999910125077e-05, 5.40370336805755e-05, 0.000118138122851376}, + {-3.28151779115881e-05, 1.04231790790798e-05, -2.80761862890640e-06, 2.98996152515593e-06, -2.67641158709985e-06}, + {-2.08664816151978e-06, -1.64463884697475e-06, 6.79099429284834e-08, 7.23955842946495e-07, -6.86378427465657e-07}, + {-2.88205823027255e-09, 2.38319699493291e-09, 1.14169347509045e-07, 8.12981074994402e-08, -1.56957943666988e-07}, + {-7.09711403570189e-09, 6.29470515502988e-09, 3.50833306577579e-09, 8.31289199649054e-09, -2.14221463168338e-09}, + {-8.11910123910038e-10, 3.34047829618955e-10, 3.70619377446490e-10, 3.30426088213373e-10, 4.86297305597865e-11}, + {1.98628160424161e-11, -4.98557831380098e-12, -5.90523187802174e-12, -1.27027116925122e-12, 1.49982368570355e-11}, + {2.62289263262748e-12, 3.91242360693861e-12, 6.56035499387192e-12, -1.17412941089401e-12, -9.40878197853394e-13}, + {-3.37805010124487e-13, 5.39454874299593e-13, -2.41569839991525e-13, -2.41572016820792e-13, -3.01983673057198e-13}, + {-1.85034053857964e-13, 4.31132161871815e-14, 4.13497222026824e-15, -4.60075514595980e-14, -1.92454846400146e-14}, + {2.96113888929854e-15, -1.11688534391626e-14, 3.76275373238932e-15, -3.72593295948136e-15, 1.98205490249604e-16}, + {1.40074667864629e-15, -5.15564234798333e-16, 3.56287382196512e-16, 5.07242777691587e-16, -2.30405782826134e-17}, + {2.96822530176851e-16, -4.77029898301223e-17, 1.12782285532775e-16, 1.58443229778573e-18, 8.22141904662969e-17} + }; + + /** Legendre functions bnm for coefficient bh.*/ + private static final double[][] BH_B = { + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {-2.29210587053658e-06, -2.33805004374529e-06, -7.49312880102168e-07, -5.12022747852006e-07, 5.88926055066172e-07}, + {0, 0, 0, 0, 0}, + {-4.63382754843690e-06, -2.23853015662938e-06, 8.14830531656518e-07, 1.15453269407116e-06, -4.53555450927571e-07}, + {-6.92432096320778e-07, -2.98734455136141e-07, 1.48085153955641e-08, 1.37881746148773e-07, -6.92492118460215e-09}, + {0, 0, 0, 0, 0}, + {-1.91507979850310e-06, -1.83614825459598e-06, -7.46807436870647e-07, -1.28329122348007e-06, 5.04937180063059e-07}, + {-8.07527103916713e-07, 2.83997840574570e-08, -6.01890498063025e-08, -2.48339507554546e-08, 2.46284627824308e-08}, + {-2.82995069303093e-07, 1.38818274596408e-09, 3.22731214161408e-09, 2.87731153972404e-10, 1.53895537278496e-08}, + {0, 0, 0, 0, 0}, + {-6.68210270956800e-07, -2.19104833297845e-06, 1.30116691657253e-07, 4.78445730433450e-07, -4.40344300914051e-07}, + {-2.36946755740436e-07, -1.32730991878204e-07, 1.83669593693860e-08, 7.90218931983569e-08, -4.70161979232584e-08}, + {1.07746083292179e-07, -4.17088637760330e-09, -1.83296035841109e-09, -5.80243971371211e-09, -2.11682361167439e-09}, + {-5.44712355496109e-08, 1.89717032256923e-09, 2.27327316287804e-10, 7.78400728280038e-10, 8.82380487618991e-12}, + {0, 0, 0, 0, 0}, + {-5.61707049615673e-08, -1.09066447089585e-06, -2.25742250174119e-07, -8.64367795924377e-07, 1.06411275240680e-08}, + {2.41782935157918e-08, -3.65762298303819e-08, -6.93420659586875e-08, -3.97316214341991e-08, -2.08767816486390e-08}, + {6.38293030383436e-08, 1.11377936334470e-08, 6.91424941454782e-09, 1.39887159955004e-09, 5.25428749022906e-09}, + {1.09291268489958e-08, 1.23935926756516e-10, 3.92917259954515e-10, -1.79144682483562e-10, -9.11802874917597e-10}, + {-4.40957607823325e-09, 1.45751390560667e-10, 1.24641258165301e-10, -6.45810339804674e-11, -8.92894658893326e-12}, + {0, 0, 0, 0, 0}, + {1.54754294162102e-08, -1.60154742388847e-06, -4.08425188394881e-07, 6.18170290113531e-09, -2.58919765162122e-07}, + {1.37130642286873e-08, -6.67813955828458e-08, -7.01410996605609e-09, 3.82732572660461e-08, -2.73381870915135e-08}, + {2.19113155379218e-08, 4.11027496396868e-09, 6.33816020485226e-09, -1.49242411327524e-09, -6.14224941851705e-10}, + {6.26573021218961e-09, 5.17137416480052e-10, -3.49784328298676e-10, 1.13578756343208e-10, 2.80414613398411e-10}, + {1.65048133258794e-11, 1.00047239417239e-10, 1.05124654878499e-10, -3.03826002621926e-11, 4.57155388334682e-11}, + {6.20221691418381e-11, 9.75852610098156e-12, -5.46716005756984e-12, 1.31643349569537e-11, 3.61618775715470e-12}, + {0, 0, 0, 0, 0}, + {-1.03938913012708e-06, -1.78417431315664e-07, 2.86040141364439e-07, 1.83508599345952e-08, -1.34452220464346e-07}, + {-4.36557481393662e-08, 7.49780206868834e-09, -8.62829428674082e-09, 5.50577793039009e-09, -9.46897502333254e-09}, + {3.43193738406672e-10, 1.13545447306468e-08, 1.25242388852214e-09, 6.03221501959620e-10, 1.57172070361180e-09}, + {-4.73307591021391e-10, 1.70855824051391e-10, -2.62470421477037e-11, 2.04525835988874e-10, -1.17859695928164e-10}, + {-3.36185995299839e-10, 3.19243054562183e-11, 1.17589412418126e-10, -1.35478747434514e-12, 5.11192214558542e-11}, + {3.19640547592136e-11, 2.94297823804643e-12, -1.00651526276990e-11, -1.67028733953153e-12, 3.03938833625503e-12}, + {1.68928641118173e-11, -7.90032886682002e-13, -1.40899773539137e-12, 7.76937592393354e-13, 7.32539820298651e-13}, + {0, 0, 0, 0, 0}, + {2.32949756055277e-07, 1.46237594908093e-07, -1.07770884952484e-07, 1.26824870644476e-07, -2.36345735961108e-08}, + {8.89572676497766e-08, 7.24810004121931e-08, 2.67583556180119e-08, 2.48434796111361e-08, -3.55004782858686e-09}, + {-1.00823909773603e-08, 8.84433929029076e-10, -2.55502517594511e-10, -5.48034274059119e-10, -8.50241938494079e-10}, + {1.13259819566467e-09, 5.55186945221216e-10, 7.63679807785295e-11, -1.70067998092043e-11, 1.57081965572493e-10}, + {-2.37748192185353e-10, 2.45463764948000e-11, 3.23208414802860e-11, -2.72624834520723e-12, 8.14449183666500e-12}, + {-1.54977633126025e-11, 4.58754903157884e-12, -1.25864665839074e-12, 2.44139868157872e-12, -1.82827441958193e-12}, + {3.28285563794513e-12, -1.10072329225465e-12, -7.23470501810935e-13, 5.85309745620389e-13, 4.11317589687125e-13}, + {4.57596974384170e-13, 9.84198128213558e-14, 3.34503817702830e-14, 7.08431086558307e-15, 2.79891177268807e-14}, + {0, 0, 0, 0, 0}, + {-3.67820719155580e-07, 6.98497901205902e-07, 1.83397388750300e-07, 2.39730262495372e-07, -2.58441984368194e-07}, + {5.17793954077994e-08, 5.54614175977835e-08, 1.75026214305232e-09, -2.55518450411346e-09, -6.12272723006537e-09}, + {-7.94292648157198e-09, -1.01709107852895e-09, -1.49251241812310e-09, 9.32827213605682e-10, -8.24490722043118e-10}, + {1.36410408475679e-11, 2.16390220454971e-10, 1.24934806872235e-10, -6.82507825145903e-11, -4.01575177719668e-11}, + {-1.41619917600555e-11, -1.54733230409082e-11, 1.36792829351538e-11, 1.11157862104733e-12, 2.08548465892268e-11}, + {-3.56521723755846e-12, 4.47877185884557e-12, -6.34096209274637e-16, -1.13010624512348e-12, -2.82018136861041e-13}, + {2.22758955943441e-12, -4.63876465559380e-13, -5.80688019272507e-13, 2.45878690598655e-13, 1.49997666808106e-13}, + {-6.26833903786958e-14, 2.73416335780807e-14, 1.91842340758425e-14, 1.67405061129010e-14, -2.45268543953704e-17}, + {1.81972870222228e-14, 5.43036245069085e-15, 1.92476637107321e-15, 8.78498602508626e-17, -1.42581647227657e-15}, + {0, 0, 0, 0, 0}, + {9.74322164613392e-07, -5.23101820582724e-07, -2.81997898176227e-07, 4.54762451707384e-08, -3.34645078118827e-08}, + {-6.75813194549663e-09, 3.49744702199583e-08, -5.09170419895883e-09, 5.24359476874755e-09, 4.96664262534662e-09}, + {4.53858847892396e-10, -1.49347392165963e-09, -2.00939511362154e-09, 9.30987163387955e-10, 9.74450200826854e-11}, + {-4.92900885858693e-10, 5.34223033225688e-12, 1.08501839729368e-10, -6.43526142089173e-11, -3.11063319142619e-11}, + {1.38469246386690e-11, -7.91180584906922e-12, 2.26641656746936e-13, 4.55251515177956e-12, 6.05270575117769e-12}, + {4.02247935664225e-12, 1.82776657951829e-12, -1.28348801405445e-13, -2.16257301300350e-13, -5.54363979435025e-14}, + {4.15005914461687e-13, -2.00647573581168e-13, -1.67278251942946e-13, 1.30332398257985e-13, 1.52742363652434e-13}, + {6.36376500056974e-14, 1.65794532815776e-14, -3.80832559052662e-15, -6.40262894005341e-16, 2.42577181848072e-15}, + {-5.55273521249151e-15, 3.69725182221479e-15, 2.02114207545759e-15, -4.50870833392161e-16, 9.62950493696677e-17}, + {1.00935904205024e-17, 6.54751873609395e-17, -1.09138810997186e-16, -8.62396750098759e-17, -3.82788257844306e-17}, + {0, 0, 0, 0, 0}, + {4.21958510903678e-07, -8.30678271007705e-08, -3.47006439555247e-07, -3.36442823712421e-08, 9.90739768222027e-08}, + {2.64389033612742e-08, 2.65825090066479e-09, -1.28895513428522e-08, -7.07182694980098e-10, 7.10907165301180e-09}, + {6.31203524153492e-09, -1.67038260990134e-09, 1.33104703539822e-09, 8.34376495185149e-10, -2.52478613522612e-10}, + {1.18414896299279e-10, -2.57745052288455e-11, 2.88295935685818e-11, -3.27782977418354e-11, -1.05705000036156e-11}, + {-4.20826459055091e-12, -6.97430607432268e-12, -3.90660545970607e-12, -3.90449239948755e-13, -4.60384797517466e-13}, + {-9.47668356558200e-13, 6.53305025354881e-13, 2.63240185434960e-13, 1.40129115015734e-13, 3.85788887132074e-14}, + {2.23947810407291e-13, 7.35262771548253e-15, -3.83348211931292e-14, 4.20376514344176e-14, 4.26445836468461e-14}, + {-3.88008154470596e-16, 2.28561424667750e-15, -8.73599966653373e-16, 2.14321147947665e-15, 6.38631825071920e-16}, + {-8.62165565535721e-15, 1.79742912149810e-15, 1.01541125038661e-15, -7.91027655831866e-17, -4.06505132825230e-16}, + {-2.35355054392189e-16, -6.13997759731013e-17, -2.73490528665965e-17, 2.63895177155121e-17, -4.47531057245187e-18}, + {6.01909706823530e-17, 5.35520010856833e-18, -2.15530106132531e-18, -2.46778496746231e-18, -7.09947296442799e-19}, + {0, 0, 0, 0, 0}, + {-3.75005956318736e-07, -5.39872297906819e-07, -1.19929654883034e-07, 4.52771083775007e-08, 1.82790552943564e-07}, + {7.82606642505646e-09, -1.68890832383153e-08, -8.45995188378997e-09, 1.42958730598502e-09, 3.21075754133531e-09}, + {4.28818421913782e-09, -1.07501469928219e-09, 8.84086350297418e-10, 9.74171228764155e-10, 8.59877149602304e-12}, + {1.28983712172521e-10, -6.96375160373676e-11, -2.13481436408896e-11, 1.33516375568179e-11, -1.65864626508258e-11}, + {-4.48914384622368e-12, 9.68953616831263e-13, -1.61372463422897e-12, -2.09683563440448e-12, -1.90096826314068e-12}, + {-1.12626619779175e-13, 3.34903159106509e-14, -1.21721528343657e-13, 7.46246339290354e-14, 3.68424909859186e-13}, + {5.08294274367790e-14, 2.83036159977090e-14, 1.48074873486387e-14, -9.59633528834945e-15, -1.26231060951100e-14}, + {-4.01464098583541e-16, 1.97047929526674e-15, -5.29967950447497e-16, -3.59120406619931e-16, 1.69690933982683e-16}, + {-1.73919209873841e-15, 7.52792462841274e-16, 3.65589287101147e-16, -7.79247612043812e-17, -8.24599670368999e-17}, + {-4.61555616150128e-17, 4.94529746019753e-19, -1.09858157212270e-17, 3.95550811124928e-18, 3.23972399884100e-18}, + {-2.27040686655766e-17, -3.27855689001215e-18, -3.30649011116861e-19, 9.08748546536849e-19, 8.92197599890994e-19}, + {5.67241944733762e-18, 3.84449400209976e-19, 1.77668058015537e-19, 2.00432838283455e-20, -2.00801461564767e-19} + }; + + /** Legendre functions bnm for coefficient bw.*/ + private static final double[][] BW_B = { + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {-9.56715196386889e-06, -3.68040633020420e-08, 1.27846786489883e-07, 1.32525487755973e-06, 1.53075361125066e-06}, + {0, 0, 0, 0, 0}, + {-7.17682617983607e-06, 2.89994188119445e-06, -2.97763578173405e-07, 8.95742089134942e-07, 3.44416325304006e-07}, + {-8.02661132285210e-07, 3.66738692077244e-07, -3.02880965723280e-07, 3.54144282036103e-07, -1.68873066391463e-07}, + {0, 0, 0, 0, 0}, + {-2.89640569283461e-06, -7.83566373343614e-07, -8.36667214682577e-07, -7.41891843549121e-07, -9.23922655636489e-08}, + {-1.06144662284862e-06, 1.57709930505924e-07, 1.04203025714319e-07, 1.20783300488461e-07, -1.38726055821134e-07}, + {-4.16549018672265e-07, -1.35220897698872e-07, -6.40269964829901e-08, 1.63258283210837e-08, -2.57958025095959e-08}, + {0, 0, 0, 0, 0}, + {3.52324885892419e-06, -2.26705543513814e-07, 1.53835589488292e-06, -3.75263061267433e-07, 3.69384057396017e-07}, + {-2.06569149157664e-07, -9.36260183227175e-08, -3.55985284353048e-08, -9.13671163891094e-08, 6.93156256562600e-09}, + {1.32437594740782e-07, 4.44349887272663e-08, -3.38192451721674e-08, -3.97263855781102e-08, -1.93087822995800e-09}, + {-1.29595244818942e-07, -1.40852985547683e-08, 1.42587592939760e-09, 7.05779876554001e-09, -1.00996269264535e-08}, + {0, 0, 0, 0, 0}, + {4.06960756215938e-06, -1.97898540226986e-06, 7.21905857553588e-08, -1.19908881538755e-06, -5.67561861536903e-08}, + {6.53369660286999e-08, -2.42818687866392e-07, -1.66203004559493e-08, -2.41512414151897e-08, 4.45426333411018e-08}, + {1.44650670663281e-07, 8.50666367433859e-09, -4.61165612004307e-09, 4.88527987491045e-09, 1.06277326713172e-08}, + {1.86770937103513e-08, -6.44197940288930e-10, -7.60456736846174e-09, -9.97186468682689e-10, 8.73229752697716e-10}, + {-1.00206566229113e-08, 1.33934372663121e-09, 1.41691503439220e-09, 8.72352590578753e-10, -8.04561626629829e-10}, + {0, 0, 0, 0, 0}, + {3.07161843116618e-06, 1.82962085656470e-06, 1.87728623016069e-07, 7.10611617623261e-07, 2.26499092250481e-07}, + {4.50766403064905e-08, -1.67752393078256e-07, 2.47844723639070e-08, -3.56484348424869e-09, -1.56634836636584e-08}, + {3.77011651881090e-08, -7.23045828480496e-09, 5.22995988863761e-09, -1.03740320341306e-09, 4.57839777217789e-09}, + {8.09495635883121e-09, -3.01977244420529e-10, -2.30104544933093e-09, 3.63658580939428e-10, 4.39320811714867e-10}, + {9.37087629961269e-11, 1.00780920426635e-09, 1.28140539913350e-10, -6.65795285522138e-12, 4.71732796198631e-11}, + {-8.88504487069155e-11, -1.63253810435461e-10, 7.22669710644299e-11, 5.64715132584527e-11, -1.08949308197617e-12}, + {0, 0, 0, 0, 0}, + {-2.64054293284174e-07, -2.37611606117256e-06, -1.83671059706264e-06, -3.12199354841993e-07, -1.05598289276114e-07}, + {7.41706968747147e-08, -1.64359098062646e-08, -3.09750224040234e-08, -9.68640079410317e-09, -7.90399057863403e-08}, + {-1.00254376564271e-08, 1.12528248631191e-08, -2.67841549174100e-09, -2.69481819323647e-09, 1.56550607475331e-09}, + {-2.18568129350729e-09, 6.26422056977450e-10, 1.95007291427316e-09, 3.14226463591125e-10, -3.62000388344482e-10}, + {-9.30451291747549e-10, 5.62175549482704e-11, 1.01022849902012e-10, 5.18675856498499e-11, 5.37561696283235e-11}, + {5.33151334468794e-11, 1.07571307336725e-10, -1.31714567944652e-11, -4.17524405900018e-11, -2.16737797893502e-12}, + {4.69916869001309e-11, -4.34516364859583e-12, -6.61054225868897e-12, -5.75845818545368e-12, -2.32180293529175e-12}, + {0, 0, 0, 0, 0}, + {-3.50305843086926e-06, 1.76085131953403e-06, 8.16661224478572e-07, 4.09111042640801e-07, -9.85414469804995e-08}, + {1.44670876127274e-07, -1.41331228923029e-08, -3.06530152369269e-08, -1.46732098927996e-08, -2.30660839364244e-08}, + {-2.00043052422933e-08, 1.72145861031776e-09, 2.13714615094209e-09, 1.02982676689194e-09, -1.64945224692217e-10}, + {1.23552540016991e-09, 1.42028470911613e-09, 8.79622616627508e-10, -7.44465600265154e-10, -7.17124672589442e-11}, + {-6.67749524914644e-10, -5.77722874934050e-11, 3.40077806879472e-11, 4.26176076541840e-11, 8.23189659748212e-11}, + {-4.62771648935992e-11, -7.24005305716782e-13, 1.18233730497485e-12, 5.18156973532267e-12, -1.53329687155297e-12}, + {4.75581699468619e-12, -3.79782291469732e-12, 1.33077109836853e-12, -1.02426020107120e-12, 3.10385019249130e-13}, + {1.66486090578792e-12, 1.08573672403649e-12, 1.26268044166279e-13, -1.23509297742757e-13, -1.81842007284038e-13}, + {0, 0, 0, 0, 0}, + {9.93870680202303e-08, -1.85264736035628e-06, -5.58942734710854e-07, -5.54183448316270e-07, -3.95581289689398e-08}, + {7.88329069002365e-08, 2.04810091451078e-08, 3.74588851000076e-09, 3.42429296613803e-08, -2.00840228416712e-08}, + {-5.93700447329696e-10, -6.57499436973459e-10, -6.90560448220751e-09, 3.56586371051089e-09, 7.33310245621566e-11}, + {-6.38101662363634e-11, 4.23668020216529e-10, -2.43764895979202e-10, -9.31466610703172e-11, -3.17491457845975e-10}, + {1.50943725382470e-11, -6.11641188685078e-11, -4.37018785685645e-11, -2.32871158949602e-11, 4.19757251950526e-11}, + {-1.18165328825853e-11, -9.91299557532438e-13, 6.40908678055865e-14, 2.41049422936434e-12, -8.20746054454953e-14}, + {6.01892101914838e-12, -8.78487122873450e-13, -1.58887481332294e-12, -3.13556902469604e-13, 5.14523727801645e-14}, + {-1.50791729401891e-13, -1.45234807159695e-13, 1.65302377570887e-13, -5.77094211651483e-15, 9.22218953528393e-14}, + {-1.85618902787381e-14, 5.64333811864051e-14, -9.94311377945570e-15, -2.40992156199999e-15, -2.19196760659665e-14}, + {0, 0, 0, 0, 0}, + {-8.16252352075899e-08, 1.61725487723444e-06, 9.55522506715921e-07, 4.02436267433511e-07, -2.80682052597712e-07}, + {7.68684790328630e-09, -5.00940723761353e-09, -2.43640127974386e-08, -2.59119930503129e-08, 3.35015169182094e-08}, + {7.97903115186673e-09, 3.73803883416618e-09, 3.27888334636662e-09, 1.37481300578804e-09, -1.10677168734482e-10}, + {-1.67853012769912e-09, -1.61405252173139e-10, -1.98841576520056e-10, -1.46591506832192e-11, 9.35710487804660e-11}, + {4.08807084343221e-11, -3.74514169689568e-11, -3.03638493323910e-11, -5.02332555734577e-12, -8.03417498408344e-12}, + {6.48922619024579e-12, 1.96166891023817e-12, -1.96968755122868e-12, -5.20970156382361e-12, -1.62656885103402e-12}, + {1.28603518902875e-12, -4.88146958435109e-13, -3.37034886991840e-13, 1.37393696103000e-14, 4.41398325716943e-14}, + {1.48670014793021e-13, 4.41636026364555e-14, 2.06210477976005e-14, -3.43717583585390e-14, -1.21693704024213e-14}, + {-1.67624180330244e-14, 6.59317111144238e-15, 2.57238525440646e-15, -3.21568425020512e-17, 5.29659568026553e-15}, + {7.85453466393227e-16, 6.91252183915939e-16, -1.20540764178454e-15, -3.85803892583301e-16, 3.46606994632006e-16}, + {0, 0, 0, 0, 0}, + {2.86710087625579e-06, -1.68179842305865e-06, -8.48306772016870e-07, -7.08798062479598e-07, -1.27469453733635e-07}, + {2.11824305734993e-09, 2.02274279084379e-08, 1.61862253091554e-08, 3.25597167111807e-08, 3.40868964045822e-09}, + {1.21757111431438e-08, 1.68405530472906e-09, 1.55379338018638e-09, -3.81467795805531e-10, 2.53316405545058e-09}, + {-9.98413758659768e-11, 5.38382145421318e-10, 3.92629628330704e-10, -1.43067134097778e-10, 3.74959329667113e-12}, + {-1.57270407028909e-11, -9.02797202317592e-12, 8.45997059887690e-12, 4.71474382524218e-12, 5.41880986596427e-12}, + {-1.20658618702054e-12, 7.12940685593433e-13, 1.02148613026937e-12, 1.63063852348169e-13, 1.74048793197708e-13}, + {3.80559390991789e-13, 1.19678271353485e-13, 9.72859455604188e-14, 5.42642400031729e-14, 8.18796710714586e-14}, + {-4.69629218656902e-14, 5.59889038686206e-15, 2.05363292795059e-15, 5.38599403288686e-15, -2.68929559474202e-15}, + {-1.88759348081742e-14, 5.20975954705924e-15, -4.43585653096395e-16, 5.57436617793556e-16, -3.95922805817677e-16}, + {-9.80871456373282e-16, 2.50857658461759e-17, -1.24253000050963e-16, 6.00857065211394e-17, 3.53799635311500e-18}, + {2.49370713054872e-16, -1.49119714269816e-17, -3.12276052640583e-17, -2.42001662334001e-17, -1.69766504318143e-17}, + {0, 0, 0, 0, 0}, + {-1.69222102455713e-06, 1.64277906173064e-06, 5.28855114364096e-07, 4.28159853268650e-07, -1.57362445882665e-07}, + {1.67656782413678e-08, -3.77746114074055e-08, -2.21564555842165e-08, -3.37071806992217e-08, 1.47454008739800e-08}, + {1.06080499491408e-08, 3.21990403709678e-09, 3.87301757435359e-09, 2.92241827834347e-10, -1.86619473655742e-11}, + {1.62399669665839e-10, 3.51322865845172e-10, 2.67086377702958e-11, -1.31596563625491e-10, 3.14164569507034e-11}, + {-2.02180016657259e-11, 2.03305178342732e-11, 6.34969032565839e-12, 5.99522296668787e-12, -4.46275273451008e-12}, + {-9.88409290158885e-13, -1.47692750858224e-13, 3.14655550730530e-13, -2.41857189187879e-13, 4.47727504501486e-13}, + {1.71430777754854e-13, 1.73950835042486e-13, 5.92323956541558e-14, 8.06625710171825e-15, 2.33252485755634e-14}, + {-1.74184545690134e-15, -8.18003353124179e-16, -6.62369006497819e-16, 4.16303374396147e-15, 7.06513748014024e-15}, + {-6.02936238677014e-15, 1.89241084885229e-15, 1.99097881944270e-17, -6.99974290696640e-16, -2.69504942597709e-17}, + {-4.65632962602379e-16, 3.70281995445114e-18, -9.04232973763345e-17, 2.20847370761932e-17, 7.62909453726566e-17}, + {-6.25921477907943e-17, -2.10532795609842e-17, -1.03808073867183e-17, 1.15091380049019e-18, 4.66794445408388e-19}, + {9.39427013576903e-18, 9.17044662931859e-19, 2.04132745117549e-18, -1.72364063154625e-19, -1.18098896532163e-18} + }; + + /** Legendre functions bnm for coefficient ch.*/ + private static final double[][] CH_B = { + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {3.44092035729033e-05, -1.21876825440561e-05, -1.87490665238967e-05, -2.60980336247863e-05, 4.31639313264615e-06}, + {0, 0, 0, 0, 0}, + {-2.60125613000133e-05, 1.70570295762269e-05, 3.08331896996832e-05, 1.66256596588688e-05, -1.07841055501996e-05}, + {8.74011641844073e-06, -2.25874169896607e-06, 6.50985196673747e-07, 1.30424765493752e-06, -1.85081244549542e-07}, + {0, 0, 0, 0, 0}, + {3.77496505484964e-05, -1.08198973553337e-05, -1.67717574544937e-05, -3.22476096673598e-05, 1.12281888201134e-05}, + {-7.68623378647958e-07, -4.01400837153063e-06, -2.16390246700835e-06, -1.76912959937924e-06, -1.12740084951955e-06}, + {-2.37092815818895e-06, -9.52317223759653e-07, -2.22722065579131e-07, -6.25157619772530e-08, 1.86582003894639e-08}, + {0, 0, 0, 0, 0}, + {-6.10254317785872e-05, -2.51815503068494e-05, 2.01046207874667e-05, 7.21107723367308e-06, -1.30692058660457e-05}, + {-9.60655417241537e-06, -7.31381721742373e-06, -2.52767927589636e-06, 9.09039973214621e-07, -6.76454911344246e-07}, + {-2.25743206384908e-08, 2.33058746737575e-07, 2.24746779293445e-07, 6.78551351968876e-08, 1.25076011387284e-07}, + {-2.25744112770133e-07, -1.44429560891636e-07, -2.96810417448652e-08, -5.93858519742856e-08, -2.43210229455420e-08}, + {0, 0, 0, 0, 0}, + {7.45721015256308e-06, -3.81396821676410e-05, -1.41086198468687e-05, -2.28514517574713e-05, 7.28638705683277e-06}, + {-5.77517778169692e-06, -3.93061211403839e-06, -2.17369763310752e-06, -1.48060935583664e-07, -2.74200485662814e-07}, + {4.52962035878238e-07, 9.80990375495214e-07, 4.67492045269286e-07, -8.31032252212116e-09, 1.69426023427740e-07}, + {7.20536791795515e-10, 2.75612253452141e-09, 2.47772119382536e-09, 4.30621825021233e-09, -2.86498479499428e-08}, + {-2.46253956492716e-08, -3.10300833499669e-09, 8.06559148724445e-09, 2.98197408430123e-10, 6.32503656532846e-09}, + {0, 0, 0, 0, 0}, + {-6.01147094179306e-05, -3.16631758509869e-05, 4.10038115100010e-06, 3.55215057231403e-07, -2.23606515237408e-06}, + {-2.85937516921923e-06, -3.67775706610630e-06, -5.06445540401637e-07, 8.21776759711184e-07, -5.98690271725558e-07}, + {7.77122595418965e-07, 3.60896376754085e-07, 3.88610487893381e-07, -4.39533892679537e-08, -6.26882227849174e-08}, + {1.05759993661891e-07, 2.58009912408833e-08, -1.51356049060972e-08, -1.13335813107412e-09, 5.37470857850370e-10}, + {7.99831506181984e-09, 1.67423735327465e-09, 2.94736760548677e-09, -1.56727133704788e-09, 8.46186800849124e-10}, + {3.07727104043851e-09, 3.93584215798484e-10, 3.86721562770643e-11, 1.72181091277391e-10, -2.16915737920145e-10}, + {0, 0, 0, 0, 0}, + {-1.16335389078126e-05, -1.39864676661484e-05, 2.52546278407717e-06, -8.79152625440188e-06, -8.97665132187974e-06}, + {-3.95874550504316e-06, -1.17976262528730e-07, 7.03189926369300e-07, 3.38907065351535e-07, -3.67714052493558e-07}, + {2.29082449370440e-07, 5.72961531093329e-07, 4.21969662578894e-08, 1.24112958141431e-08, 9.56404486571888e-08}, + {1.44631865298671e-09, 6.19368473895584e-09, 1.67110424041236e-09, 2.57979463602951e-09, -6.90806907510366e-09}, + {1.77235802019153e-09, -8.14388846228970e-10, 4.50421956523579e-09, 5.67452314909707e-10, 2.47610443675560e-09}, + {4.85932343880617e-10, 2.24864117422804e-10, -2.22534534468511e-10, -7.96395824973477e-11, 3.12587399902493e-12}, + {-3.20173937255409e-11, -1.29872402028088e-11, -4.24092901203818e-11, 2.66570185704416e-11, -5.25164954403909e-12}, + {0, 0, 0, 0, 0}, + {-1.36010179191872e-05, 1.77873053642413e-05, 4.80988546657119e-06, 3.46859608161212e-06, -1.73247520896541e-06}, + {2.00020483116258e-06, 2.43393064079673e-06, 1.21478843695862e-06, 1.95582820041644e-07, -3.11847995109088e-07}, + {-8.13287218979310e-09, 1.05206830238665e-08, 6.54040136224164e-09, -1.96402660575990e-08, -1.40379796070732e-08}, + {4.01291020310740e-08, 2.92634301047947e-08, 6.04179709273169e-09, 8.61849065020545e-10, 5.98065429697245e-09}, + {-1.06149335032911e-09, -4.39748495862323e-10, 8.83040310269353e-10, 3.49392227277679e-10, 8.57722299002622e-10}, + {-1.25049888909390e-11, 2.05203288281631e-10, 1.37817670505319e-11, 6.82057794430145e-11, -9.41515631694254e-11}, + {7.47196022644130e-12, -2.51369898528782e-11, -2.12196687809200e-11, 1.55282119505201e-11, 9.99224438231805e-12}, + {-7.90534019004874e-13, 3.55824506982589e-12, 8.00835777767281e-13, 8.73460019069655e-13, 1.34176126600106e-12}, + {0, 0, 0, 0, 0}, + {3.12855262465316e-05, 1.31629386003608e-05, 2.65598119437581e-06, 8.68923340949135e-06, -7.51164082949678e-06}, + {1.56870792650533e-06, 1.89227301685370e-06, 4.15620385341985e-07, -2.74253787880603e-07, -4.28826210119200e-07}, + {-9.99176994565587e-08, -1.10785129426286e-07, -1.10318125091182e-07, 6.22726507350764e-09, -3.39214566386250e-08}, + {1.24872975018433e-08, 1.10663206077249e-08, 5.40658975901469e-09, -2.79119137105115e-09, -2.47500096192502e-09}, + {1.11518917154060e-10, -4.21965763244849e-10, 3.26786005211229e-10, 1.93488254914545e-10, 7.00774679999972e-10}, + {1.50889220040757e-10, 1.03130002661366e-10, -3.09481760816903e-11, -4.47656630703759e-11, -7.36245021803800e-12}, + {-1.91144562110285e-12, -1.11355583995978e-11, -1.76207323352556e-11, 8.15289793192265e-12, 3.45078925412654e-12}, + {-2.73248710476019e-12, -1.65089342283056e-13, -2.20125355220819e-13, 5.32589191504356e-13, 5.70008982140874e-13}, + {8.06636928368811e-13, 1.30893069976672e-13, 9.72079137767479e-14, 3.87410156264322e-14, -5.56410013263563e-14}, + {0, 0, 0, 0, 0}, + {2.02454485403216e-05, -9.77720471118669e-06, -4.35467548126223e-06, 2.19599868869063e-06, -3.26670819043690e-06}, + {-3.21839256310540e-08, 8.38760368015005e-07, -5.08058835724060e-07, 4.16177282491396e-08, 1.53842592762120e-07}, + {-1.57377633165313e-07, -7.86803586842404e-08, -7.40444711426898e-08, 3.15259864117954e-08, 5.60536231567172e-09}, + {-3.26080428920229e-10, -3.14576780695439e-09, 8.46796096612981e-10, -2.59329379174262e-09, -8.01054756588382e-10}, + {-4.58725236153576e-11, -6.87847958546571e-11, 8.18226480126754e-12, 1.81082075625897e-10, 1.74510532938256e-10}, + {7.60233505328792e-11, 4.76463939581321e-11, -2.47198455442033e-11, -8.83439688929965e-12, 5.93967446277316e-13}, + {-8.92919292558887e-12, -4.38524572312029e-12, -4.02709146060896e-12, 4.84344426425295e-12, 5.12869042781520e-12}, + {1.91518361809952e-12, 3.06846255371817e-13, -2.44830265306345e-13, 7.86297493099244e-14, 2.72347805801980e-13}, + {9.09936624159538e-14, 7.20650818861447e-15, 2.45383991578283e-14, -4.79580974186462e-15, 3.64604724046944e-14}, + {-4.63611142770709e-14, 1.73908246420636e-15, -4.41651410674801e-15, -6.61409045306922e-16, -1.60016049099639e-15}, + {0, 0, 0, 0, 0}, + {6.17105245892845e-06, -1.04342983738457e-05, -1.72711741097994e-05, -8.16815967888426e-07, 3.42789959967593e-06}, + {-2.44014060833825e-07, 2.06991837444652e-07, -3.85805819475679e-07, 1.67162359832166e-08, 4.15139610402483e-07}, + {8.18199006804020e-08, -3.20013409049159e-08, 5.94000906771151e-08, 2.24122167188946e-08, -1.33796186160409e-08}, + {7.66269294674338e-11, -6.07862178874828e-10, 4.95795757186248e-10, -3.07589245481422e-10, 3.44456287710689e-10}, + {-1.84076250254929e-10, -1.30985312312781e-10, -1.52547325533276e-10, -2.51000125929512e-11, -1.93924012590455e-11}, + {-2.93307452197665e-11, 2.88627386757582e-11, 5.58812021182217e-12, -1.68692874069187e-13, 1.80464313900575e-12}, + {-9.59053874473003e-13, 6.04803122874761e-13, -9.80015608958536e-13, 1.70530372034214e-12, 1.70458664160775e-12}, + {2.80169588226043e-13, 9.09573148053551e-14, 2.16449186617004e-14, 1.15550091496353e-13, 4.97772796761321e-14}, + {-3.04524400761371e-14, 3.42845631349694e-14, 2.44230630602064e-14, 5.76017546103056e-16, -9.74409465961093e-15}, + {5.98765340844291e-15, -2.63942474859535e-15, -1.80204805804437e-15, -1.84981819321183e-16, -5.85073392163660e-16}, + {-2.37069441910133e-15, 2.87429226086856e-16, -1.67055963193389e-16, 2.72110684914090e-18, 8.46646962667892e-17}, + {0, 0, 0, 0, 0}, + {-2.71386164105722e-05, -1.41834938338454e-05, -2.00777928859929e-07, 5.94329804681196e-07, 8.61856994375586e-06}, + {-3.93656495458664e-08, -6.36432821807576e-07, -2.47887475106438e-07, -2.64906446204966e-08, 1.10689794197004e-07}, + {5.25319489188562e-08, 9.00866357158695e-09, 5.00693379572512e-08, 2.47269011056404e-08, -7.27648556194598e-09}, + {1.87207107149043e-09, -1.46428282396138e-09, -2.71812237167257e-10, 8.44902265891466e-10, -5.62683870906027e-10}, + {-1.08295119666184e-10, 4.75553388543793e-11, -5.49429386495686e-11, -6.60907871731611e-11, -5.97347322824822e-11}, + {-4.95118306815571e-12, 5.31083735234970e-13, -1.93679746327378e-12, -1.61770521840510e-12, 1.23276727202510e-11}, + {6.68582682909900e-13, 7.38288575160449e-13, 5.47630483499201e-13, -1.00770258118914e-13, -1.65564928475981e-13}, + {5.80963409268471e-14, 6.93474288078737e-14, 6.60728092794315e-15, -5.21029056725202e-15, -1.11283532854883e-16}, + {-4.10567742688903e-15, 1.62252646805882e-14, 1.00774699865989e-14, -2.44793214897877e-16, -1.59283906414563e-15}, + {1.84669506619904e-17, 8.28473337813919e-17, -1.53400662078899e-16, -5.01060672199689e-17, -2.20727935766132e-16}, + {2.65355116203636e-16, -3.70233146147684e-17, 3.52689394451586e-18, -8.62215942516328e-18, 9.26909361974526e-18}, + {9.94266950643135e-17, 4.17028699663441e-18, -7.65153491125819e-21, -5.62131270981041e-18, -3.03732817297438e-18} + }; + + /** Legendre functions bnm for coefficient cw.*/ + private static final double[][] CW_B = { + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {-0.000209104872912563, -1.41530274973540e-05, 3.00318745764815e-05, -1.82864291318284e-05, -7.62965409959238e-06}, + {0, 0, 0, 0, 0}, + {-0.000186336519900275, 0.000191256553935638, 7.28356195304996e-05, 3.59637869639906e-05, -2.53927226167388e-05}, + {0.000108195343799485, -6.97050977217619e-05, -6.68037133871099e-05, 2.30387653190503e-05, -1.22735483925784e-05}, + {0, 0, 0, 0, 0}, + {0.000119941091277039, -7.70547844186875e-05, -8.15376297964528e-05, 1.06005789545203e-05, 2.31177232268720e-05}, + {-1.77494760217164e-05, -1.37061385686605e-05, -1.74805936475816e-05, -6.91745900867532e-07, -7.10231790947787e-06}, + {-1.47564103733219e-05, 2.08890785485260e-06, 3.19876879447867e-06, 9.43984664503715e-07, -4.90480527577521e-06}, + {0, 0, 0, 0, 0}, + {4.93300138389457e-05, -6.77641298460617e-05, -3.25043347246397e-05, 8.33226714911921e-06, 8.11499972792905e-06}, + {-2.80449863471272e-05, -1.04367606414606e-05, 1.64473584641163e-07, -3.57420965807816e-06, 2.95887156564038e-06}, + {1.88835280111533e-06, 5.69125761193702e-07, -2.22757382799409e-06, -1.96699131032252e-07, -2.91861219283659e-07}, + {-4.69918971436680e-06, -7.00778948636735e-07, 2.97544157334673e-09, 3.86100512544410e-07, 2.30939653701027e-07}, + {0, 0, 0, 0, 0}, + {1.77050610394149e-05, -3.18353071311574e-05, 3.04232260950316e-05, -6.26821316488169e-05, -1.75094810002378e-06}, + {9.25605901565775e-06, -8.25179123302247e-06, 6.74032752408358e-06, 3.22192289084524e-06, 6.09414500075259e-06}, + {4.28233825242200e-06, 2.10470570087927e-07, -4.75050074985668e-07, -4.89382663470592e-07, 8.75232347469207e-07}, + {8.50393520366934e-07, 1.58764911467186e-07, -2.16267638321210e-07, -7.43341300487416e-10, 1.75131729813230e-07}, + {-2.87064111623119e-07, 4.50393893102830e-08, 6.63315044416690e-08, 7.61199387418853e-08, -6.05694385243652e-09}, + {0, 0, 0, 0, 0}, + {-1.95692079507947e-05, 5.15486098887851e-05, 3.00852761598173e-05, 1.21485028343416e-05, -6.72450521493428e-06}, + {5.34496867088158e-06, 3.90973451680699e-06, 3.70148924718425e-06, 5.73731499938212e-08, 5.52258220288780e-07}, + {3.39950838185315e-07, -5.63443976772634e-07, 4.52082211980595e-07, -2.57094645806243e-07, -6.84885762924729e-08}, + {2.15793276880684e-07, 2.05911354090873e-07, 1.33747872341142e-08, -2.07997626478952e-08, -3.69812938736019e-08}, + {2.11952749403224e-09, 4.04317822544732e-08, 2.40972024883650e-09, 8.56289126938059e-09, 2.31035283490200e-08}, + {-2.08402298813248e-09, -8.50243600879112e-09, 2.60895410117768e-09, -6.69156841738591e-10, -5.16280278087006e-09}, + {0, 0, 0, 0, 0}, + {0.000124901291436683, -5.70770326719086e-05, -8.44887248105015e-05, -3.11442665354698e-05, -1.12982893252046e-05}, + {-8.38934444233944e-06, 1.56860091415414e-06, -1.77704563531825e-06, -5.70219068898717e-08, -4.30377735031244e-06}, + {3.72965318017681e-07, 6.98175439446187e-07, 1.75760544807919e-08, 1.59731284857151e-07, 3.62363848767891e-07}, + {-2.32148850787091e-07, -4.21888751852973e-08, 8.35926113952108e-08, -2.24572480575674e-08, -6.92114100904503e-08}, + {-2.92635642210745e-09, 3.38086229163415e-09, 4.72186694662901e-09, -8.32354437305758e-11, 4.19673890995627e-09}, + {-1.26452887692900e-09, 1.91309690886864e-09, 1.54755631983655e-09, -1.09865169400249e-09, 1.83645326319994e-10}, + {9.92539437011905e-10, -2.96318203488300e-10, 1.17466020823486e-10, -5.00185957995526e-10, -8.54777591408537e-11}, + {0, 0, 0, 0, 0}, + {-0.000182885335404854, 7.27424724520089e-05, 3.05286278023427e-05, 2.55324463432562e-05, -6.39859510763234e-06}, + {-5.21449265232557e-06, -6.70572386081398e-06, -3.95473351292738e-06, -6.41023334372861e-07, -3.11616331059009e-06}, + {2.37090789071727e-07, 3.58427517014705e-07, 2.55709192777007e-07, 8.44593804408541e-08, 9.27243162355359e-09}, + {7.24370898432057e-08, -7.43945120337710e-09, 8.61751911975683e-10, -2.34651212610623e-08, 2.94052921681456e-09}, + {-1.22127317934425e-08, -3.89758984276768e-09, 4.12890383904924e-11, 2.06528068002723e-09, 1.73488696972270e-09}, + {-5.44137406907620e-10, -4.81034553189921e-10, -2.56101759039694e-11, 3.21880564410154e-10, -2.70195343165250e-11}, + {1.08394225300546e-10, -7.99525492688661e-11, 1.73850287030654e-10, -8.06390014426271e-11, -7.63143364291160e-13}, + {-3.41446959267441e-11, 2.72675729042792e-11, 5.69674704865345e-12, -3.38402998344892e-12, -2.96732381931007e-12}, + {0, 0, 0, 0, 0}, + {2.91161315987250e-05, -7.24641166590735e-05, -8.58323519857884e-06, -1.14037444255820e-05, 1.32244819451517e-05}, + {1.24266748259826e-06, -4.13127038469802e-06, -8.47496394492885e-07, 5.48722958754267e-07, -1.98288551821205e-06}, + {-1.70671245196917e-08, 1.36891127083540e-08, -2.80901972249870e-07, -5.45369793946222e-09, -9.58796303763498e-08}, + {1.14115335901746e-08, 2.79308166429178e-08, -1.71144803132413e-08, 4.86116243565380e-09, -8.13061459952280e-09}, + {-1.19144311035824e-09, -1.28197815211763e-09, -1.22313592972373e-09, 6.23116336753674e-10, 2.11527825898689e-09}, + {4.94618645030426e-10, -1.01554483531252e-10, -3.58808808952276e-10, 1.23499783028794e-10, -1.21017599361833e-10}, + {1.33959569836451e-10, -1.87140898812283e-11, -3.04265350158941e-11, -1.42907553051431e-11, -1.09873858099638e-11}, + {1.30277419203512e-11, -4.95312627777245e-12, 2.23070215544358e-12, 1.66450226016423e-12, 6.26222944728474e-12}, + {-4.40721204874728e-12, 2.99575133064885e-12, -1.54917262009097e-12, 8.90015664527060e-14, -1.59135267012937e-12}, + {0, 0, 0, 0, 0}, + {-4.17667211323160e-05, 1.39005215116294e-05, 1.46521361817829e-05, 3.23485458024416e-05, -8.57936261085263e-06}, + {9.48491026524450e-07, 1.67749735481991e-06, 6.80159475477603e-07, -1.34558044496631e-06, 1.62108231492249e-06}, + {-2.67545753355631e-07, -3.31848493018159e-08, 1.05837219557465e-07, 1.55587655479400e-07, -2.84996014386667e-08}, + {-5.15113778734878e-08, 8.83630725241303e-09, 3.36579455982772e-09, -6.22350102096402e-09, 5.03959133095369e-09}, + {2.04635880823035e-11, -1.07923589059151e-09, -6.96482137669712e-10, -4.70238500452793e-10, -6.60277903598297e-10}, + {-2.41897168749189e-11, 1.33547763615216e-10, -5.13534673658908e-11, -8.32767177662817e-11, 5.72614717082428e-11}, + {7.55170562359940e-12, -1.57123461699055e-11, -1.48874069619124e-11, -7.10529462981252e-13, -7.99006335025107e-12}, + {2.41883156738960e-12, 2.97346980183361e-12, 1.28719977731450e-12, -2.49240876894143e-12, 6.71155595793198e-13}, + {4.16995565336914e-13, -1.71584521275288e-13, -7.23064067359978e-14, 2.45405880599037e-13, 4.43532934905830e-13}, + {3.56937508828997e-14, 2.43012511260300e-14, -7.96090778289326e-14, -1.59548529636358e-14, 8.99103763000507e-15}, + {0, 0, 0, 0, 0}, + {0.000117579258399489, -4.52648448635772e-05, -2.69130037097862e-05, -3.82266335794366e-05, -4.36549257701084e-06}, + {-1.43270371215502e-06, 1.21565440183855e-06, 8.53701136074284e-07, 1.52709810023665e-06, 1.22382663462904e-06}, + {3.06089147519664e-07, 9.79084123751975e-08, 7.96524661441178e-08, 4.54770947973458e-08, 2.22842369458882e-07}, + {-9.94254707745127e-09, 1.43251376378012e-08, 1.93911753685160e-08, -6.52214645690987e-09, -1.97114016452408e-09}, + {-9.20751919828404e-10, -9.44312829629076e-10, 7.24196738163952e-11, -6.71801072324561e-11, 2.33146774065873e-10}, + {-1.43544298956410e-11, 1.78464235318769e-10, 7.69950023012326e-11, -4.22390057304453e-12, 3.05176324574816e-11}, + {-7.88053753973990e-12, -3.20207793051003e-12, 1.01527407317625e-12, 6.02788185858449e-12, 1.14919530900453e-11}, + {-1.21558899266069e-12, 5.31300597882986e-13, 3.44023865079264e-13, -6.22598216726224e-14, -5.47031650765402e-14}, + {-4.15627948750943e-13, 2.77620907292721e-13, -8.99784134364011e-14, 1.07254247320864e-13, 6.85990080564196e-14}, + {-3.91837863922901e-14, 9.74714976816180e-15, 6.79982450963903e-15, -2.41420876658572e-15, -2.20889384455344e-15}, + {9.25912068402776e-15, -4.02621719248224e-15, -2.43952036351187e-15, -1.97006876049866e-15, 1.03065621527869e-16}, + {0, 0, 0, 0, 0}, + {-0.000103762036940193, 4.38145356960292e-05, 2.43406920349913e-05, 7.89103527673736e-06, -1.66841465339160e-05}, + {-1.18428449371744e-06, -1.30188721737259e-06, -1.88013557116650e-06, -1.01342046295303e-06, 9.21813037802502e-07}, + {1.51836068712460e-07, 1.11362553803933e-07, 1.55375052233052e-07, 1.94450910788747e-09, -1.73093755828342e-08}, + {-3.77758211813121e-09, 1.23323969583610e-08, 1.72510045250302e-09, -1.88609789458597e-09, 1.28937597985937e-09}, + {-1.07947760393523e-09, 5.26051570105365e-10, -3.67657536332496e-11, 3.16110123523840e-10, -3.24273198242170e-10}, + {-2.00385649209820e-12, 2.54703869682390e-11, 4.08563622440851e-12, -4.83350348928636e-11, -3.98153443845079e-13}, + {2.73094467727215e-12, 5.08900664114903e-12, -7.66669089075134e-13, 2.50015592643012e-12, 4.29763262853853e-12}, + {6.53946487537890e-13, -2.24958413781008e-13, 6.74638861781238e-15, 3.28537647613903e-14, 2.54199700290116e-13}, + {-1.09122051193505e-13, 8.36362392931501e-14, -3.90750153912300e-14, -5.44915910741950e-14, 2.43816947219217e-14}, + {-1.41882561550134e-14, 1.00455397812713e-14, 2.63347255121581e-15, 1.53043256823601e-15, 2.49081021428095e-15}, + {-1.17256193152654e-15, 1.05648985031971e-16, 1.31778372453016e-16, 1.44815198666577e-16, -3.72532768618480e-16}, + {2.66203457773766e-16, -7.67224608659658e-17, 3.51487351031864e-18, 4.10287131339291e-17, -6.72171711728514e-17} + }; + + /** Build a new instance. */ + LegendreFunctions() { + + } + + /** Get the value of the anm coefficient for bh. + * @param n index + * @param m index + * @return the anm coefficient for bh + */ + public double getAnmBh(final int n, final int m) { + return BH_A[n][m]; + } + + /** Get the value of the anm coefficient for bw. + * @param n index + * @param m index + * @return the anm coefficient for bw + */ + public double getAnmBw(final int n, final int m) { + return BW_A[n][m]; + } + + /** Get the value of the anm coefficient for ch. + * @param n index + * @param m index + * @return the anm coefficient for ch + */ + public double getAnmCh(final int n, final int m) { + return CH_A[n][m]; + } + + /** Get the value of the anm coefficient for cw. + * @param n index + * @param m index + * @return the anm coefficient for cw + */ + public double getAnmCw(final int n, final int m) { + return CW_A[n][m]; + } + + /** Get the value of the bnm coefficient for bh. + * @param n index + * @param m index + * @return the bnm coefficient for bh + */ + public double getBnmBh(final int n, final int m) { + return BH_B[n][m]; + } + + /** Get the value of the bnm coefficient for bw. + * @param n index + * @param m index + * @return the bnm coefficient for bw + */ + public double getBnmBw(final int n, final int m) { + return BW_B[n][m]; + } + + /** Get the value of the bnm coefficient for ch. + * @param n index + * @param m index + * @return the bnm coefficient for ch + */ + public double getBnmCh(final int n, final int m) { + return CH_B[n][m]; + } + + /** Get the value of the bnm coefficient for cw. + * @param n index + * @param m index + * @return the bnm coefficient for cw + */ + public double getBnmCw(final int n, final int m) { + return CW_B[n][m]; + } + + } +} diff --git a/src/main/java/org/orekit/models/earth/troposphere/ViennaThreeModel.java b/src/main/java/org/orekit/models/earth/troposphere/ViennaThreeModel.java index 5980a21c27..2b1ddbb7de 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/ViennaThreeModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/ViennaThreeModel.java @@ -16,29 +16,18 @@ */ package org.orekit.models.earth.troposphere; -import java.util.Collections; -import java.util.List; - -import org.hipparchus.Field; import org.hipparchus.CalculusFieldElement; -import org.hipparchus.util.FastMath; -import org.hipparchus.util.FieldSinCos; +import org.hipparchus.Field; import org.hipparchus.util.MathArrays; -import org.hipparchus.util.SinCos; import org.orekit.annotation.DefaultDataContext; import org.orekit.bodies.FieldGeodeticPoint; import org.orekit.bodies.GeodeticPoint; import org.orekit.data.DataContext; import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; -import org.orekit.models.earth.weather.PressureTemperatureHumidity; import org.orekit.time.AbsoluteDate; -import org.orekit.time.DateTimeComponents; import org.orekit.time.FieldAbsoluteDate; import org.orekit.time.TimeScale; -import org.orekit.utils.FieldLegendrePolynomials; import org.orekit.utils.FieldTrackingCoordinates; -import org.orekit.utils.LegendrePolynomials; -import org.orekit.utils.ParameterDriver; import org.orekit.utils.TrackingCoordinates; /** The Vienna3 tropospheric delay model for radio techniques. @@ -59,20 +48,14 @@ * http://repositum.tuwien.ac.at/urn:nbn:at:at-ubtuw:1-100249" * * @author Bryan Cazabonne + * @deprecated as of 12.1, replaced by {@link ViennaThree} */ -@SuppressWarnings("deprecation") -public class ViennaThreeModel - implements DiscreteTroposphericModel, TroposphericModel, MappingFunction, TroposphereMappingFunction { - - /** The a coefficient for the computation of the wet and hydrostatic mapping functions.*/ - private final double[] coefficientsA; +@Deprecated +public class ViennaThreeModel extends ViennaThree implements DiscreteTroposphericModel, MappingFunction { /** Values of hydrostatic and wet delays as provided by the Vienna model. */ private final double[] zenithDelay; - /** UTC time scale. */ - private final TimeScale utc; - /** Build a new instance. * *

              This constructor uses the {@link DataContext#getDefault() default data context}. @@ -96,9 +79,11 @@ public ViennaThreeModel(final double[] coefficientA, final double[] zenithDelay) public ViennaThreeModel(final double[] coefficientA, final double[] zenithDelay, final TimeScale utc) { - this.coefficientsA = coefficientA.clone(); - this.zenithDelay = zenithDelay.clone(); - this.utc = utc; + super(new ConstantViennaAProvider(new ViennaACoefficients(coefficientA[0], coefficientA[1])), + new ConstantTroposphericModel(new TroposphericDelay(zenithDelay[0], zenithDelay[1], + zenithDelay[0], zenithDelay[1])), + utc); + this.zenithDelay = zenithDelay.clone(); } /** {@inheritDoc} */ @@ -111,95 +96,6 @@ public double[] mappingFactors(final double elevation, final GeodeticPoint point date); } - /** {@inheritDoc} */ - @Override - public double[] mappingFactors(final TrackingCoordinates trackingCoordinates, - final GeodeticPoint point, - final PressureTemperatureHumidity weather, - final AbsoluteDate date) { - // Day of year computation - final DateTimeComponents dtc = date.getComponents(utc); - final int dofyear = dtc.getDate().getDayOfYear(); - - // Compute Legendre Polynomials Pnm(cos(0.5 * pi - phi)) - final int degree = 12; - final int order = 12; - final LegendrePolynomials p = new LegendrePolynomials(degree, order, FastMath.cos(0.5 * FastMath.PI - point.getLatitude())); - - // Compute coefficients bh, bw, ch and cw with spherical harmonics - double a0Bh = 0.; - double a0Bw = 0.; - double a0Ch = 0.; - double a0Cw = 0.; - double a1Bh = 0.; - double a1Bw = 0.; - double a1Ch = 0.; - double a1Cw = 0.; - double b1Bh = 0.; - double b1Bw = 0.; - double b1Ch = 0.; - double b1Cw = 0.; - double a2Bh = 0.; - double a2Bw = 0.; - double a2Ch = 0.; - double a2Cw = 0.; - double b2Bh = 0.; - double b2Bw = 0.; - double b2Ch = 0.; - double b2Cw = 0.; - final LegendreFunctions AnmBnm = new LegendreFunctions(); - int j = 0; - for (int n = 0; n <= 12; n++) { - for (int m = 0; m <= n; m++) { - final SinCos sc = FastMath.sinCos(m * point.getLongitude()); - final double pCosmLambda = p.getPnm(n, m) * sc.cos(); - final double pSinmLambda = p.getPnm(n, m) * sc.sin(); - - a0Bh = a0Bh + (AnmBnm.getAnmBh(j, 0) * pCosmLambda + AnmBnm.getBnmBh(j, 0) * pSinmLambda); - a0Bw = a0Bw + (AnmBnm.getAnmBw(j, 0) * pCosmLambda + AnmBnm.getBnmBw(j, 0) * pSinmLambda); - a0Ch = a0Ch + (AnmBnm.getAnmCh(j, 0) * pCosmLambda + AnmBnm.getBnmCh(j, 0) * pSinmLambda); - a0Cw = a0Cw + (AnmBnm.getAnmCw(j, 0) * pCosmLambda + AnmBnm.getBnmCw(j, 0) * pSinmLambda); - - a1Bh = a1Bh + (AnmBnm.getAnmBh(j, 1) * pCosmLambda + AnmBnm.getBnmBh(j, 1) * pSinmLambda); - a1Bw = a1Bw + (AnmBnm.getAnmBw(j, 1) * pCosmLambda + AnmBnm.getBnmBw(j, 1) * pSinmLambda); - a1Ch = a1Ch + (AnmBnm.getAnmCh(j, 1) * pCosmLambda + AnmBnm.getBnmCh(j, 1) * pSinmLambda); - a1Cw = a1Cw + (AnmBnm.getAnmCw(j, 1) * pCosmLambda + AnmBnm.getBnmCw(j, 1) * pSinmLambda); - - b1Bh = b1Bh + (AnmBnm.getAnmBh(j, 2) * pCosmLambda + AnmBnm.getBnmBh(j, 2) * pSinmLambda); - b1Bw = b1Bw + (AnmBnm.getAnmBw(j, 2) * pCosmLambda + AnmBnm.getBnmBw(j, 2) * pSinmLambda); - b1Ch = b1Ch + (AnmBnm.getAnmCh(j, 2) * pCosmLambda + AnmBnm.getBnmCh(j, 2) * pSinmLambda); - b1Cw = b1Cw + (AnmBnm.getAnmCw(j, 2) * pCosmLambda + AnmBnm.getBnmCw(j, 2) * pSinmLambda); - - a2Bh = a2Bh + (AnmBnm.getAnmBh(j, 3) * pCosmLambda + AnmBnm.getBnmBh(j, 3) * pSinmLambda); - a2Bw = a2Bw + (AnmBnm.getAnmBw(j, 3) * pCosmLambda + AnmBnm.getBnmBw(j, 3) * pSinmLambda); - a2Ch = a2Ch + (AnmBnm.getAnmCh(j, 3) * pCosmLambda + AnmBnm.getBnmCh(j, 3) * pSinmLambda); - a2Cw = a2Cw + (AnmBnm.getAnmCw(j, 3) * pCosmLambda + AnmBnm.getBnmCw(j, 3) * pSinmLambda); - - b2Bh = b2Bh + (AnmBnm.getAnmBh(j, 4) * pCosmLambda + AnmBnm.getBnmBh(j, 4) * pSinmLambda); - b2Bw = b2Bw + (AnmBnm.getAnmBw(j, 4) * pCosmLambda + AnmBnm.getBnmBw(j, 4) * pSinmLambda); - b2Ch = b2Ch + (AnmBnm.getAnmCh(j, 4) * pCosmLambda + AnmBnm.getBnmCh(j, 4) * pSinmLambda); - b2Cw = b2Cw + (AnmBnm.getAnmCw(j, 4) * pCosmLambda + AnmBnm.getBnmCw(j, 4) * pSinmLambda); - - j = j + 1; - } - } - - // Eq. 6 - final double bh = computeSeasonalFit(dofyear, a0Bh, a1Bh, a2Bh, b1Bh, b2Bh); - final double bw = computeSeasonalFit(dofyear, a0Bw, a1Bw, a2Bw, b1Bw, b2Bw); - final double ch = computeSeasonalFit(dofyear, a0Ch, a1Ch, a2Ch, b1Ch, b2Ch); - final double cw = computeSeasonalFit(dofyear, a0Cw, a1Cw, a2Cw, b1Cw, b2Cw); - - // Compute Mapping Function Eq. 4 - final double[] function = new double[2]; - function[0] = TroposphericModelUtils.mappingFunction(coefficientsA[0], bh, ch, - trackingCoordinates.getElevation()); - function[1] = TroposphericModelUtils.mappingFunction(coefficientsA[1], bw, cw, - trackingCoordinates.getElevation()); - - return function; - } - /** {@inheritDoc} */ @Override @Deprecated @@ -212,98 +108,6 @@ public > T[] mappingFactors(final T elevation, date); } - /** {@inheritDoc} */ - @Override - public > T[] mappingFactors(final FieldTrackingCoordinates trackingCoordinates, - final FieldGeodeticPoint point, - final FieldPressureTemperatureHumidity weather, - final FieldAbsoluteDate date) { - final Field field = date.getField(); - final T zero = field.getZero(); - - // Day of year computation - final DateTimeComponents dtc = date.getComponents(utc); - final int dofyear = dtc.getDate().getDayOfYear(); - - // Compute Legendre Polynomials Pnm(cos(0.5 * pi - phi)) - final int degree = 12; - final int order = 12; - final FieldLegendrePolynomials p = new FieldLegendrePolynomials<>(degree, order, FastMath.cos(point.getLatitude().negate().add(zero.getPi().multiply(0.5)))); - - // Compute coefficients bh, bw, ch and cw with spherical harmonics - T a0Bh = zero; - T a0Bw = zero; - T a0Ch = zero; - T a0Cw = zero; - T a1Bh = zero; - T a1Bw = zero; - T a1Ch = zero; - T a1Cw = zero; - T b1Bh = zero; - T b1Bw = zero; - T b1Ch = zero; - T b1Cw = zero; - T a2Bh = zero; - T a2Bw = zero; - T a2Ch = zero; - T a2Cw = zero; - T b2Bh = zero; - T b2Bw = zero; - T b2Ch = zero; - T b2Cw = zero; - final LegendreFunctions AnmBnm = new LegendreFunctions(); - int j = 0; - for (int n = 0; n <= 12; n++) { - for (int m = 0; m <= n; m++) { - final FieldSinCos sc = FastMath.sinCos(point.getLongitude().multiply(m)); - final T pCosmLambda = p.getPnm(n, m).multiply(sc.cos()); - final T pSinmLambda = p.getPnm(n, m).multiply(sc.sin()); - - a0Bh = a0Bh.add(pCosmLambda.multiply(AnmBnm.getAnmBh(j, 0)).add(pSinmLambda.multiply(AnmBnm.getBnmBh(j, 0)))); - a0Bw = a0Bw.add(pCosmLambda.multiply(AnmBnm.getAnmBw(j, 0)).add(pSinmLambda.multiply(AnmBnm.getBnmBw(j, 0)))); - a0Ch = a0Ch.add(pCosmLambda.multiply(AnmBnm.getAnmCh(j, 0)).add(pSinmLambda.multiply(AnmBnm.getBnmCh(j, 0)))); - a0Cw = a0Cw.add(pCosmLambda.multiply(AnmBnm.getAnmCw(j, 0)).add(pSinmLambda.multiply(AnmBnm.getBnmCw(j, 0)))); - - a1Bh = a1Bh.add(pCosmLambda.multiply(AnmBnm.getAnmBh(j, 1)).add(pSinmLambda.multiply(AnmBnm.getBnmBh(j, 1)))); - a1Bw = a1Bw.add(pCosmLambda.multiply(AnmBnm.getAnmBw(j, 1)).add(pSinmLambda.multiply(AnmBnm.getBnmBw(j, 1)))); - a1Ch = a1Ch.add(pCosmLambda.multiply(AnmBnm.getAnmCh(j, 1)).add(pSinmLambda.multiply(AnmBnm.getBnmCh(j, 1)))); - a1Cw = a1Cw.add(pCosmLambda.multiply(AnmBnm.getAnmCw(j, 1)).add(pSinmLambda.multiply(AnmBnm.getBnmCw(j, 1)))); - - b1Bh = b1Bh.add(pCosmLambda.multiply(AnmBnm.getAnmBh(j, 2)).add(pSinmLambda.multiply(AnmBnm.getBnmBh(j, 2)))); - b1Bw = b1Bw.add(pCosmLambda.multiply(AnmBnm.getAnmBw(j, 2)).add(pSinmLambda.multiply(AnmBnm.getBnmBw(j, 2)))); - b1Ch = b1Ch.add(pCosmLambda.multiply(AnmBnm.getAnmCh(j, 2)).add(pSinmLambda.multiply(AnmBnm.getBnmCh(j, 2)))); - b1Cw = b1Cw.add(pCosmLambda.multiply(AnmBnm.getAnmCw(j, 2)).add(pSinmLambda.multiply(AnmBnm.getBnmCw(j, 2)))); - - a2Bh = a2Bh.add(pCosmLambda.multiply(AnmBnm.getAnmBh(j, 3)).add(pSinmLambda.multiply(AnmBnm.getBnmBh(j, 3)))); - a2Bw = a2Bw.add(pCosmLambda.multiply(AnmBnm.getAnmBw(j, 3)).add(pSinmLambda.multiply(AnmBnm.getBnmBw(j, 3)))); - a2Ch = a2Ch.add(pCosmLambda.multiply(AnmBnm.getAnmCh(j, 3)).add(pSinmLambda.multiply(AnmBnm.getBnmCh(j, 3)))); - a2Cw = a2Cw.add(pCosmLambda.multiply(AnmBnm.getAnmCw(j, 3)).add(pSinmLambda.multiply(AnmBnm.getBnmCw(j, 3)))); - - b2Bh = b2Bh.add(pCosmLambda.multiply(AnmBnm.getAnmBh(j, 4)).add(pSinmLambda.multiply(AnmBnm.getBnmBh(j, 4)))); - b2Bw = b2Bw.add(pCosmLambda.multiply(AnmBnm.getAnmBw(j, 4)).add(pSinmLambda.multiply(AnmBnm.getBnmBw(j, 4)))); - b2Ch = b2Ch.add(pCosmLambda.multiply(AnmBnm.getAnmCh(j, 4)).add(pSinmLambda.multiply(AnmBnm.getBnmCh(j, 4)))); - b2Cw = b2Cw.add(pCosmLambda.multiply(AnmBnm.getAnmCw(j, 4)).add(pSinmLambda.multiply(AnmBnm.getBnmCw(j, 4)))); - - j = j + 1; - } - } - - // Eq. 6 - final T bh = computeSeasonalFit(dofyear, a0Bh, a1Bh, a2Bh, b1Bh, b2Bh); - final T bw = computeSeasonalFit(dofyear, a0Bw, a1Bw, a2Bw, b1Bw, b2Bw); - final T ch = computeSeasonalFit(dofyear, a0Ch, a1Ch, a2Ch, b1Ch, b2Ch); - final T cw = computeSeasonalFit(dofyear, a0Cw, a1Cw, a2Cw, b1Cw, b2Cw); - - // Compute Mapping Function Eq. 4 - final T[] function = MathArrays.buildArray(field, 2); - function[0] = TroposphericModelUtils.mappingFunction(zero.newInstance(coefficientsA[0]), bh, ch, - trackingCoordinates.getElevation()); - function[1] = TroposphericModelUtils.mappingFunction(zero.newInstance(coefficientsA[1]), bw, cw, - trackingCoordinates.getElevation()); - - return function; - } - /** {@inheritDoc} */ @Override @Deprecated @@ -314,23 +118,6 @@ public double pathDelay(final double elevation, final GeodeticPoint point, getDelay(); } - /** {@inheritDoc} */ - @Override - public TroposphericDelay pathDelay(final TrackingCoordinates trackingCoordinates, - final GeodeticPoint point, - final PressureTemperatureHumidity weather, - final double[] parameters, final AbsoluteDate date) { - // zenith delay - final double[] delays = computeZenithDelay(point, parameters, date); - // mapping function - final double[] mappingFunction = mappingFactors(trackingCoordinates, point, weather, date); - // Tropospheric path delay - return new TroposphericDelay(delays[0], - delays[1], - delays[0] * mappingFunction[0], - delays[1] * mappingFunction[1]); - } - /** {@inheritDoc} */ @Override @Deprecated @@ -343,23 +130,6 @@ public > T pathDelay(final T elevation, final getDelay(); } - /** {@inheritDoc} */ - @Override - public > FieldTroposphericDelay pathDelay(final FieldTrackingCoordinates trackingCoordinates, - final FieldGeodeticPoint point, - final FieldPressureTemperatureHumidity weather, - final T[] parameters, final FieldAbsoluteDate date) { - // zenith delay - final T[] delays = computeZenithDelay(point, parameters, date); - // mapping function - final T[] mappingFunction = mappingFactors(trackingCoordinates.getElevation(), point, date); - // Tropospheric path delay - return new FieldTroposphericDelay<>(delays[0], - delays[1], - delays[0].multiply(mappingFunction[0]), - delays[1].multiply(mappingFunction[1])); - } - /** This method allows the computation of the zenith hydrostatic and * zenith wet delay. The resulting element is an array having the following form: *

                @@ -397,897 +167,4 @@ public > T[] computeZenithDelay(final FieldGeo return delays; } - /** {@inheritDoc} */ - @Override - public List getParametersDrivers() { - return Collections.emptyList(); - } - - /** Computes the empirical temporal information for the mapping function - * coefficients b and c. A seasonal fit formula is performed. - * @param doy day of year - * @param A0 Mean value of the coefficient - * @param A1 Annual amplitude of the coefficient - * @param A2 Semi-annual amplitude of the coefficient - * @param B1 Annual amplitude of the coefficient - * @param B2 Semi-annual amplitude of the coefficient - * @return the mapping function coefficient at a given day. - */ - private double computeSeasonalFit(final int doy, final double A0, final double A1, - final double A2, final double B1, final double B2) { - - final double coef = (doy / 365.25) * 2 * FastMath.PI; - final SinCos sc1 = FastMath.sinCos(coef); - final SinCos sc2 = FastMath.sinCos(2.0 * coef); - - return A0 + - A1 * sc1.cos() + B1 * sc1.sin() + - A2 * sc2.cos() + B2 * sc2.sin(); - } - - /** Computes the empirical temporal information for the mapping function - * coefficients b and c. A seasonal fit formula is performed. - * @param type of the elements - * @param doy day of year - * @param A0 Mean value of the coefficient - * @param A1 Annual amplitude of the coefficient - * @param A2 Semi-annual amplitude of the coefficient - * @param B1 Annual amplitude of the coefficient - * @param B2 Semi-annual amplitude of the coefficient - * @return the mapping function coefficient at a given day. - */ - private > T computeSeasonalFit(final int doy, final T A0, final T A1, - final T A2, final T B1, final T B2) { - final T coef = A0.getPi().multiply(2.0).multiply(doy / 365.25); - final FieldSinCos sc1 = FastMath.sinCos(coef); - final FieldSinCos sc2 = FastMath.sinCos(coef.multiply(2.0)); - - return A0.add( - A1.multiply(sc1.cos())).add(B1.multiply(sc1.sin())).add( - A2.multiply(sc2.cos())).add(B2.multiply(sc2.sin())); - } - - /** Class for the values of the coefficients anm and bnm - * of the spherical harmonics expansion. - */ - private static class LegendreFunctions { - - /** Legendre functions anm for coefficient bh.*/ - private static final double[][] BH_A = { - {0.00271285863109945, -1.39197786008938e-06, 1.34955672002719e-06, 2.71686279717968e-07, 1.56659301773925e-06}, - {9.80476624811974e-06, -5.83922611260673e-05, -2.07307023860417e-05, 1.14628726961148e-06, 4.93610283608719e-06}, - {-1.03443106534268e-05, -2.05536138785961e-06, 2.09692641914244e-06, -1.55491034130965e-08, -1.89706404675801e-07}, - {-3.00353961749658e-05, 2.37284447073503e-05, 2.02236885378918e-05, 1.69276006349609e-06, 8.72156681243892e-07}, - {-7.99121077044035e-07, -5.39048313389504e-06, -4.21234502039861e-06, -2.70944149806894e-06, -6.80894455531746e-07}, - {7.51439609883296e-07, 3.85509708865520e-07, 4.41508016098164e-08, -2.07507808307757e-08, 4.95354985050743e-08}, - {2.21790962160087e-05, -5.56986238775212e-05, -1.81287885563308e-05, -4.41076013532589e-06, 4.93573223917278e-06}, - {-4.47639989737328e-06, -2.60452893072120e-06, 2.56376320011189e-06, 4.41600992220479e-07, 2.93437730332869e-07}, - {8.14992682244945e-07, 2.03945571424434e-07, 1.11832498659806e-08, 3.25756664234497e-08, 3.01029040414968e-08}, - {-7.96927680907488e-08, -3.66953150925865e-08, -6.74742632186619e-09, -1.30315731273651e-08, -2.00748924306947e-09}, - {-2.16138375166934e-05, 1.67350317962556e-05, 1.93768260076821e-05, 1.99595120161850e-06, -2.42463528222014e-06}, - {5.34360283708044e-07, -3.64189022040600e-06, -2.99935375194279e-06, -2.06880962903922e-06, -9.40815692626002e-07}, - {6.80235884441822e-07, 1.33023436079845e-07, -1.80349593705226e-08, 2.51276252565192e-08, -1.43240592002794e-09}, - {-7.13790897253802e-08, 7.81998506267559e-09, 1.13826909570178e-09, -5.89629600214654e-09, -4.20760865522804e-09}, - {-5.80109372399116e-09, 1.13702284491976e-09, 7.29046067602764e-10, -9.10468988754012e-10, -2.58814364808642e-10}, - {1.75558618192965e-05, -2.85579168876063e-05, -1.47442190284602e-05, -6.29300414335248e-06, -5.12204538913460e-07}, - {-1.90788558291310e-06, -1.62144845155361e-06, 7.57239241641566e-07, 6.93365788711348e-07, 6.88855644570695e-07}, - {2.27050351488552e-07, 1.03925791277660e-07, -3.31105076632079e-09, 2.88065761026675e-08, -8.00256848229136e-09}, - {-2.77028851807614e-08, -5.96251132206930e-09, 2.95987495527251e-10, -5.87644249625625e-09, -3.28803981542337e-09}, - {-1.89918479865558e-08, 3.54083436578857e-09, 8.10617835854935e-10, 4.99207055948336e-10, -1.52691648387663e-10}, - {1.04022499586096e-09, -2.36437143845013e-10, -2.25110813484842e-10, -7.39850069252329e-11, 7.95929405440911e-11}, - {-3.11579421267630e-05, -3.43576336877494e-06, 5.81663608263384e-06, 8.31534700351802e-07, 4.02619520312154e-06}, - {6.00037066879001e-07, -1.12538760056168e-07, -3.86745332115590e-07, -3.88218746020826e-07, -6.83764967176388e-07}, - {-9.79583981249316e-08, 9.14964449851003e-08, 4.77779838549237e-09, 2.44283811750703e-09, -6.26361079345158e-09}, - {-2.37742207548109e-08, -5.53336301671633e-09, -3.73625445257115e-09, -1.92304189572886e-09, -7.18681390197449e-09}, - {-6.58203463929583e-09, 9.28456148541896e-10, 2.47218904311077e-10, 1.10664919110218e-10, -4.20390976974043e-11}, - {9.45857603373426e-10, -3.29683402990254e-11, -8.15440375865127e-11, -1.21615589356628e-12, -9.70713008848085e-12}, - {1.61377382316176e-10, 6.84326027598147e-12, -4.66898885683671e-12, 2.31211355085535e-12, 2.39195112937346e-12}, - {2.99634365075821e-07, 8.14391615472128e-06, 6.70458490942443e-06, -9.92542646762000e-07, -3.04078064992750e-06}, - {-6.52697933801393e-07, 2.87255329776428e-07, -1.78227609772085e-08, 2.65525429849935e-07, 8.60650570551813e-08}, - {-1.62727164011710e-07, 1.09102479325892e-07, 4.97827431850001e-09, 7.86649963082937e-11, -6.67193813407656e-09}, - {-2.96370000987760e-09, 1.20008401576557e-09, 1.75885448022883e-09, -1.74756709684384e-09, 3.21963061454248e-09}, - {-9.91101697778560e-10, 7.54541713140752e-10, -2.95880967800875e-10, 1.81009160501278e-10, 8.31547411640954e-11}, - {1.21268051949609e-10, -5.93572774509587e-11, -5.03295034994351e-11, 3.05383430975252e-11, 3.56280438509939e-11}, - {6.92012970333794e-11, -9.02885345797597e-12, -3.44151832744880e-12, 2.03164894681921e-12, -5.44852265137606e-12}, - {5.56731263672800e-12, 3.57272150106101e-12, 2.25885622368678e-12, -2.44508240047675e-13, -6.83314378535235e-13}, - {3.96883487797254e-06, -4.57100506169608e-06, -3.30208117813256e-06, 3.32599719134845e-06, 4.26539325549339e-06}, - {1.10123151770973e-06, 4.58046760144882e-07, 1.86831972581926e-07, -1.60092770735081e-07, -5.58956114867062e-07}, - {-3.40344900506653e-08, 2.87649741373047e-08, -1.83929753066251e-08, -9.74179203885847e-09, -2.42064137485043e-09}, - {-6.49731596932566e-09, -3.07048108404447e-09, -2.84380614669848e-09, 1.55123146524283e-09, 4.53694984588346e-10}, - {5.45175793803325e-10, -3.73287624700125e-10, -1.16293122618336e-10, 7.25845618602690e-11, -4.34112440021627e-11}, - {1.89481447552805e-10, 3.67431482211078e-12, -1.72180065021194e-11, 1.47046319023226e-11, 1.31920481414062e-11}, - {2.10125915737167e-12, -3.08420783495975e-12, -4.87748712363020e-12, 1.16363599902490e-14, 1.26698255558605e-13}, - {-8.07894928696254e-12, 9.19344620512607e-13, 3.26929173307443e-13, 2.00438149416495e-13, -9.57035765212079e-15}, - {1.38737151773284e-12, 1.09340178371420e-13, 5.15714202449053e-14, -5.92156438588931e-14, -3.29586752336143e-14}, - {6.38137197198254e-06, 4.62426300749908e-06, 4.42334454191034e-06, 1.15374736092349e-06, -2.61859702227253e-06}, - {-2.25320619636149e-07, 3.21907705479353e-07, -3.34834530764823e-07, -4.82132753601810e-07, -3.22410936343355e-07}, - {3.48894515496995e-09, 3.49951261408458e-08, -6.01128959281142e-09, 4.78213900943443e-09, 1.46012816168576e-08}, - {-9.66682871952083e-11, 3.75806627535317e-09, 2.38984004956705e-09, 2.07545049877203e-09, 1.58573595632766e-09}, - {1.06834370693917e-09, -4.07975055112153e-10, -2.37598937943957e-10, 5.89327007480137e-11, 1.18891820437634e-10}, - {5.22433722695807e-11, 6.02011995016293e-12, -7.80605402956048e-12, 1.50873145627341e-11, -1.40550093106311e-12}, - {2.13396242187279e-13, -1.71939313965536e-12, -3.57625378660975e-14, -5.01675184988446e-14, -1.07805487368797e-12}, - {-1.24352330043311e-12, 8.26105883301606e-13, 4.63606970128517e-13, 6.39517888984486e-14, -7.35135439920086e-14}, - {-5.39023859065631e-13, 2.54188315588243e-14, 1.30933833278664e-14, 6.06153473304781e-15, -4.24722717533726e-14}, - {3.12767756884813e-14, -2.29517847871632e-15, 2.53117304424948e-16, 7.07504914138118e-16, -1.20089065310688e-15}, - {2.08311178819214e-06, -1.22179185044174e-06, -2.98842190131044e-06, 3.07310218974299e-06, 2.27100346036619e-06}, - {-3.94601643855452e-07, -5.44014825116083e-07, -6.16955333162507e-08, -2.31954821580670e-07, 1.14010813005310e-07}, - {6.11067575043044e-08, -3.93240193194272e-08, -1.62979132528933e-08, 1.01339204652581e-08, 1.97319601566071e-08}, - {2.57770508710055e-09, 1.87799543582899e-09, 1.95407654714372e-09, 1.15276419281270e-09, 2.25397005402120e-09}, - {7.16926338026236e-10, -3.65857693313858e-10, -1.54864067050915e-11, 6.50770211276549e-11, -7.85160007413546e-12}, - {4.90007693914221e-12, 3.31649396536340e-12, 4.81664871165640e-13, 7.26080745617085e-12, 2.30960953372164e-12}, - {9.75489202240545e-13, -1.68967954531421e-13, 7.38383391334110e-13, -3.58435515913239e-13, -3.01564710027450e-13}, - {-3.79533601922805e-13, 2.76681830946617e-13, 1.21480375553803e-13, -1.57729077644850e-14, -8.87664977818700e-14}, - {-3.96462845480288e-14, 2.94155690934610e-14, 6.78413205760717e-15, -4.12135802787361e-15, -1.46373307795619e-14}, - {-8.64941937408121e-15, -1.91822620970386e-15, -8.01725413560744e-16, 5.02941051180784e-16, -1.07572628474344e-15}, - {-4.13816294742758e-15, -7.43602019785880e-17, -5.54248556346072e-17, -4.83999456005158e-17, -1.19622559730466e-16}, - {-8.34852132750364e-07, -7.45794677612056e-06, -6.58132648865533e-06, -1.38608110346732e-06, 5.32326534882584e-07}, - {-2.75513802414150e-07, 3.64713745106279e-08, -7.12385417940442e-08, -7.86206067228882e-08, 2.28048393207161e-08}, - {-4.26696415431918e-08, -4.65599668635087e-09, 7.35037936327566e-09, 1.17098354115804e-08, 1.44594777658035e-08}, - {1.12407689274199e-09, 7.62142529563709e-10, -6.72563708415472e-10, -1.18094592485992e-10, -1.17043815733292e-09}, - {1.76612225246125e-10, -1.01188552503192e-10, 7.32546072616968e-11, 1.79542821801610e-11, -2.23264859965402e-11}, - {-9.35960722512375e-12, 1.90894283812231e-12, -6.34792824525760e-13, 3.98597963877826e-12, -4.47591409078971e-12}, - {-3.34623858556099e-12, 4.56384903915853e-14, 2.72561108521416e-13, -3.57942733300468e-15, 1.99794810657713e-13}, - {-6.16775522568954e-14, 8.25316968328823e-14, 7.19845814260518e-14, -2.92415710855106e-14, -5.49570017444031e-15}, - {-8.50728802453217e-15, 8.38161600916267e-15, 3.43651657459983e-15, -8.19429434115910e-16, -4.08905746461100e-15}, - {4.39042894275548e-15, -3.69440485320477e-16, 1.22249256876779e-16, -2.09359444520984e-16, -3.34211740264257e-16}, - {-5.36054548134225e-16, 3.29794204041989e-17, 2.13564354374585e-17, -1.37838993720865e-18, -1.29188342867753e-17}, - {-3.26421841529845e-17, 7.38235405234126e-18, 2.49291659676210e-18, 8.18252735459593e-19, 1.73824952279230e-20}, - {4.67237509268208e-06, 1.93611283787239e-06, 9.39035455627622e-07, -5.84565118072823e-07, -1.76198705802101e-07}, - {-3.33739157421993e-07, 4.12139555299163e-07, 1.58754695700856e-07, 1.37448753329669e-07, 1.04722936936873e-07}, - {6.64200603076386e-09, 1.45412222625734e-08, 1.82498796118030e-08, 2.86633517581614e-09, 1.06066984548100e-09}, - {5.25549696746655e-09, -1.33677183394083e-09, 7.60804375937931e-11, -1.07918624219037e-10, 8.09178898247941e-10}, - {1.89318454110039e-10, 9.23092164791765e-11, 5.51434573131180e-11, 3.86696392289240e-11, -1.15208165047149e-11}, - {-1.02252706006226e-12, -7.25921015411136e-13, -1.98110126887620e-12, -2.18964868282672e-13, -7.18834476685625e-13}, - {-2.69770025318548e-12, -2.17850340796321e-14, 4.73040820865871e-13, 1.57947421572149e-13, 1.86925164972766e-13}, - {1.07831718354771e-13, 2.26681841611017e-14, 2.56046087047783e-14, -1.14995851659554e-14, -2.27056907624485e-14}, - {6.29825154734712e-15, 8.04458225889001e-16, 9.53173540411138e-16, 1.16892301877735e-15, -1.04324684545047e-15}, - {-5.57345639727027e-16, -2.93949227634932e-16, 7.47621406284534e-18, -5.36416885470756e-17, -2.87213280230513e-16}, - {1.73219775047208e-16, 2.05017387523061e-17, 9.08873886345587e-18, -2.86881547225742e-18, -1.25303645304992e-17}, - {-7.30829109684568e-18, 2.03711261415353e-18, 7.62162636124024e-19, -7.54847922012517e-19, -8.85105098195030e-19}, - {5.62039968280587e-18, -1.38144206573507e-19, 1.68028711767211e-20, 1.81223858251981e-19, -8.50245194985878e-20} - }; - - /** Legendre functions anm for coefficient bw.*/ - private static final double[][] BW_A = { - {0.00136127467401223, -6.83476317823061e-07, -1.37211986707674e-06, 7.02561866200582e-07, -2.16342338010651e-07}, - {-9.53197486400299e-06, 6.58703762338336e-06, 2.42000663952044e-06, -6.04283463108935e-07, 2.02144424676990e-07}, - {-6.76728911259359e-06, 6.03830755085583e-07, -8.72568628835897e-08, 2.21750344140938e-06, 1.05146032931020e-06}, - {-3.21102832397338e-05, -7.88685357568093e-06, -2.55495673641049e-06, -1.99601934456719e-06, -4.62005252198027e-07}, - {-7.84639263523250e-07, 3.11624739733849e-06, 9.02170019697389e-07, 6.37066632506008e-07, -9.44485038780872e-09}, - {2.19476873575507e-06, -2.20580510638233e-07, 6.94761415598378e-07, 4.80770865279717e-07, -1.34357837196401e-07}, - {2.18469215148328e-05, -1.80674174262038e-06, -1.52754285605060e-06, -3.51212288219241e-07, 2.73741237656351e-06}, - {2.85579058479116e-06, 1.57201369332361e-07, -2.80599072875081e-07, -4.91267304946072e-07, -2.11648188821805e-07}, - {2.81729255594770e-06, 3.02487362536122e-07, -1.64836481475431e-07, -2.11607615408593e-07, -6.47817762225366e-08}, - {1.31809947620223e-07, -1.58289524114549e-07, -7.05580919885505e-08, 5.56781440550867e-08, 1.23403290710365e-08}, - {-1.29252282695869e-05, -1.07247072037590e-05, -3.31109519638196e-06, 2.13776673779736e-06, -1.49519398373391e-07}, - {1.81685152305722e-06, -1.17362204417861e-06, -3.19205277136370e-08, 4.09166457255416e-07, 1.53286667406152e-07}, - {1.63477723125362e-06, -2.68584775517243e-08, 4.94662064805191e-09, -7.09027987928288e-08, 4.44353430574937e-08}, - {-2.13090618917978e-07, 4.05836983493219e-08, 2.94495876336549e-08, -1.75005469063176e-08, -3.03015988647002e-09}, - {-2.16074435298006e-09, 9.37631708987675e-09, -2.05996036369828e-08, 6.97068002894092e-09, -8.90988987979604e-09}, - {1.38047798906967e-05, 2.05528261553901e-05, 1.59072148872708e-05, 7.34088731264443e-07, 1.28226710383580e-06}, - {7.08175753966264e-07, -9.27988276636505e-07, 1.60535820026081e-07, -3.27296675122065e-07, -2.20518321170684e-07}, - {1.90932483086199e-07, -7.44215272759193e-08, 1.81330673333187e-08, 4.37149649043616e-08, 4.18884335594172e-08}, - {-5.37009063880924e-08, 2.22870057779431e-08, 1.73740123037651e-08, -4.45137302235032e-09, 9.44721910524571e-09}, - {-6.83406949047909e-08, -1.95046676795923e-10, 2.57535903049686e-09, 4.82643164083020e-09, 3.37657333705158e-09}, - {3.96128688448981e-09, -6.63809403270686e-10, 2.44781464212534e-10, 5.92280853590699e-11, -4.78502591970721e-10}, - {1.75859399041414e-05, -2.81238050668481e-06, -2.43670534594848e-06, 3.58244562699714e-06, -1.76547446732691e-06}, - {-1.06451311473304e-07, 1.54336689617184e-06, -2.00690000442673e-07, 1.38790047911880e-09, -1.62490619890017e-07}, - {-2.72757421686155e-07, 1.71139266205398e-07, -2.55080309401917e-08, -8.40793079489831e-09, -1.01129447760167e-08}, - {2.92966025844079e-08, -2.07556718857313e-08, 5.45985315647905e-09, 8.76857690274150e-09, 1.06785510440474e-08}, - {-1.22059608941331e-08, 6.52491630264276e-09, -1.79332492326928e-10, 3.75921793745396e-10, -7.06416506254786e-10}, - {1.63224355776652e-09, 4.95586028736232e-10, -3.07879011759040e-10, -7.78354087544277e-11, 1.43959047067250e-10}, - {3.86319414653663e-10, -2.06467134617933e-10, 4.37330971382694e-11, -5.00421056263711e-11, -9.40237773015723e-12}, - {-1.23856142706451e-05, 7.61047394008415e-06, -1.99104114578138e-07, 6.86177748886858e-07, -1.09466747592827e-07}, - {2.99866062403128e-07, 1.87525561397390e-07, 4.99374806994715e-08, 4.86229763781404e-07, 4.46570575517658e-07}, - {-5.05748332368430e-07, 1.95523624722285e-08, -9.17535435911345e-08, -2.56671607433547e-08, -7.11896201616653e-08}, - {-2.66062200406494e-08, -5.40470019739274e-09, -2.29718660244954e-09, -3.73328592264404e-09, 3.38748313712376e-09}, - {5.30855327954894e-10, 5.28851845648032e-10, -2.22278913745418e-10, -5.52628653064771e-11, -9.24825145219684e-10}, - {6.03737227573716e-10, -3.52190673510919e-12, -1.30371720641414e-10, -9.12787239944822e-12, 6.42187285537238e-12}, - {1.78081862458539e-10, 2.93772078656037e-12, -1.04698379945322e-11, -2.82260024833024e-11, -5.61810459067525e-12}, - {9.35003092299580e-12, -8.23133834521577e-13, 5.54878414224198e-13, -3.62943215777181e-13, 2.38858933771653e-12}, - {-1.31216096107331e-05, -5.70451670731759e-06, -5.11598683573971e-06, -4.99990779887599e-06, 1.27389320221511e-07}, - {-1.23108260369048e-06, 5.53093245213587e-07, 8.60093183929302e-07, 2.65569700925696e-07, 1.95485134805575e-07}, - {-2.29647072638049e-07, -5.45266515081825e-08, 2.85298129762263e-08, 1.98167939680185e-08, 5.52227340898335e-09}, - {-2.73844745019857e-08, -4.48345173291362e-10, -1.93967347049382e-09, -1.41508853776629e-09, -1.75456962391145e-09}, - {-2.68863184376108e-11, -2.20546981683293e-09, 6.56116990576877e-10, 1.27129855674922e-10, -2.32334506413213e-10}, - {1.98303136881156e-10, 6.04782006047075e-11, 2.91291115431570e-11, 6.18098615782757e-11, -3.82682292530379e-11}, - {9.48294455071158e-12, -3.05873596453015e-13, 5.31539408055057e-13, -7.31016438665600e-12, -1.19921002209198e-11}, - {-2.25188050845725e-11, -3.91627574966393e-13, -6.80217235976769e-13, 5.91033607278405e-13, 5.02991534452191e-13}, - {1.29532063896247e-12, 1.66337285851564e-13, 3.25543028344555e-13, 1.89143357962363e-13, 3.32288378169726e-13}, - {-2.45864358781728e-06, 4.49460524898260e-06, 1.03890496648813e-06, -2.73783420376785e-06, 7.12695730642593e-07}, - {-9.27805078535168e-07, -4.97733876686731e-07, 9.18680298906510e-08, -2.47200617423980e-07, 6.16163630140379e-08}, - {-1.39623661883136e-08, -1.12580495666505e-07, 2.61821435950379e-08, -2.31875562002885e-08, 5.72679835033659e-08}, - {-9.52538983318497e-09, -5.40909215302433e-09, 1.88698793952475e-09, -4.08127746406372e-09, 1.09534895853812e-10}, - {3.79767457525741e-09, 1.11549801373366e-10, -6.45504957274111e-10, 3.05477141010356e-10, 1.26261210565856e-10}, - {5.08813577945300e-11, 1.43250547678637e-11, 8.81616572082448e-12, 2.58968878880804e-11, 3.83421818249954e-11}, - {8.95094368142044e-12, -3.26220304555971e-12, -1.28047847191896e-12, 2.67562170258942e-12, 2.72195031576670e-12}, - {-6.47181697409757e-12, 1.13776457455685e-12, 2.84856274334969e-13, -7.63667272085395e-14, -1.34451657758826e-13}, - {-1.25291265888343e-12, 8.63500441050317e-14, -1.21307856635548e-13, 5.12570529540511e-14, 3.32389276976573e-14}, - {3.73573418085813e-14, -5.37808783042784e-16, -4.23430408270850e-16, -4.75110565740493e-15, 6.02553212780166e-15}, - {8.95483987262751e-06, -3.90778212666235e-06, -1.12115019808259e-06, 1.78678942093383e-06, 1.46806344157962e-06}, - {-4.59185232678613e-07, 1.09497995905419e-07, 1.31663977640045e-07, 4.20525791073626e-08, -9.71470741607431e-08}, - {1.63399802579572e-07, 1.50909360648645e-08, -1.11480472593347e-08, -1.84000857674573e-08, 7.82124614794256e-09}, - {1.22887452385094e-08, -4.06647399822746e-10, -6.49120327585597e-10, 8.63651225791194e-10, -2.73440085913102e-09}, - {2.51748630889583e-09, 4.79895880425564e-10, -2.44908073860844e-10, 2.56735882664876e-10, -1.64815306286912e-10}, - {4.85671381736718e-11, -2.51742732115131e-11, -2.60819437993179e-11, 6.12728324086123e-12, 2.16833310896138e-11}, - {4.11389702320298e-12, -8.09433180989935e-13, -1.19812498226024e-12, 1.46885737888520e-12, 3.15807685137836e-12}, - {-1.47614580597013e-12, 4.66726413909320e-13, 1.72089709006255e-13, 1.13854935381418e-13, 2.77741161317003e-13}, - {-1.02257724967727e-13, 1.10394382923502e-13, -3.14153505370805e-15, 2.41103099110106e-14, 2.13853053149771e-14}, - {-3.19080885842786e-14, -9.53904307973447e-15, 2.74542788156379e-15, 2.33797859107844e-15, -2.53192474907304e-15}, - {-5.87702222126367e-15, -1.80133850930249e-15, -3.09793125614454e-16, -1.04197538975295e-16, 3.72781664701327e-16}, - {1.86187054729085e-06, 8.33098045333428e-06, 3.18277735484232e-06, -7.68273797022231e-07, -1.52337222261696e-06}, - {-5.07076646593648e-07, -8.61959553442156e-07, -3.51690005432816e-07, -4.20797082902431e-07, -3.07652993252673e-07}, - {-7.38992472164147e-08, -8.39473083080280e-08, -2.51587083298935e-08, 7.30691259725451e-09, -3.19457155958983e-08}, - {-1.99777182012924e-09, -3.21265085916022e-09, -4.84477421865675e-10, -1.82924814205799e-09, -3.46664344655997e-10}, - {-7.05788559634927e-11, 1.21840735569025e-10, 7.97347726425926e-11, 1.08275679614409e-10, -1.17891254809785e-10}, - {1.10299718947774e-11, -3.22958261390263e-11, -1.43535798209229e-11, 6.87096504209595e-12, -6.64963212272352e-12}, - {-6.47393639740084e-12, 1.03156978325120e-12, -9.20099775082358e-14, -2.40150316641949e-13, 1.14008812047857e-12}, - {-1.23957846397250e-13, 2.85996703969692e-13, 1.91579874982553e-13, 5.20597174693064e-14, -4.06741434883370e-14}, - {-2.35479068911236e-14, 1.97847338186993e-14, 1.58935977518516e-15, -2.32217195254742e-15, -8.48611789490575e-15}, - {1.03992320391626e-14, 1.54017082092642e-15, 1.05950035082788e-16, -1.17870898461353e-15, -1.10937420707372e-15}, - {-1.09011948374520e-15, -6.04168007633584e-16, -9.10901998157436e-17, 1.98379116989461e-16, -1.03715496658498e-16}, - {-1.38171942108278e-16, -6.33037999097522e-17, -1.38777695011470e-17, 1.94191397045401e-17, 5.70055906754485e-18}, - {1.92989406002085e-06, -3.82662130483128e-06, -4.60189561036048e-07, 2.24290587856309e-06, 1.40544379451550e-06}, - {6.49033717633394e-08, 2.41396114435326e-07, 2.73948898223321e-07, 1.10633664439332e-07, -3.19555270171075e-08}, - {-2.91988966963297e-08, -6.03828192816571e-09, 1.18462386444840e-08, 1.32095545004128e-08, -5.06572721528914e-09}, - {7.31079058474148e-09, -8.42775299751834e-10, 1.10190810090667e-09, 1.96592273424306e-09, -2.13135932785688e-09}, - {7.06656405314388e-11, 1.43441125783756e-10, 1.46962246686924e-10, 7.44592776425197e-11, -3.64331892799173e-11}, - {-2.52393942119372e-11, 1.07520964869263e-11, 5.84669886072094e-12, 6.52029744217103e-12, 1.82947123132059e-12}, - {-4.15669940115121e-12, -1.95963254053648e-13, 2.16977822834301e-13, -2.84701408462031e-13, 4.27194601040231e-13}, - {3.07891105454129e-13, 1.91523190672955e-13, 1.05367297580989e-13, -5.28136363920236e-14, -3.53364110005917e-14}, - {7.02156663274738e-15, 9.52230536780849e-15, -3.41019408682733e-15, -3.59825303352899e-15, -2.62576411636150e-15}, - {-1.75110277413804e-15, 5.29265220719483e-16, 4.45015980897919e-16, -3.80179856341347e-16, -4.32917763829695e-16}, - {1.16038609651443e-16, -6.69643574373352e-17, 2.65667154817303e-17, -9.76010333683956e-17, 4.07312981076655e-17}, - {5.72659246346386e-18, 1.30357528108671e-18, 2.49193258417535e-18, 1.76247014075584e-18, 7.59614374197688e-19}, - {1.03352170833303e-17, -2.30633516638829e-18, 2.84777940620193e-18, -7.72161347944693e-19, 6.07028034506380e-19} - }; - - /** Legendre functions anm for coefficient ch.*/ - private static final double[][] CH_A = { - {0.0571481238161787, 3.35402081801137e-05, 3.15988141788728e-05, -1.34477341887086e-05, -2.61831023577773e-07}, - {5.77367395845715e-05, -0.000669057185209558, -6.51057691648904e-05, -1.61830149147091e-06, 8.96771209464758e-05}, - {-8.50773002452907e-05, -4.87106614880272e-05, 4.03431160775277e-05, 2.54090162741464e-06, -5.59109319864264e-06}, - {0.00150536423187709, 0.000611682258892697, 0.000369730024614855, -1.95658439780282e-05, -3.46246726553700e-05}, - {-2.32168718433966e-05, -0.000127478686553809, -9.00292451740728e-05, -6.07834315901830e-05, -1.04628419422714e-05}, - {-1.38607250922551e-06, -3.97271603842309e-06, -8.16155320152118e-07, 5.73266706046665e-07, 2.00366060212696e-07}, - {6.52491559188663e-05, -0.00112224323460183, -0.000344967958304075, -7.67282640947300e-05, 0.000107907110551939}, - {-0.000138870461448036, -7.29995695401936e-05, 5.35986591445824e-05, 9.03804869703890e-06, 8.61370129482732e-06}, - {-9.98524443968768e-07, -6.84966792665998e-08, 1.47478021860771e-07, 1.94857794008064e-06, 7.17176852732910e-07}, - {1.27066367911720e-06, 1.12113289164288e-06, 2.71525688515375e-07, -2.76125723009239e-07, -1.05429690305013e-07}, - {-0.000377264999981652, 0.000262691217024294, 0.000183639785837590, 3.93177048515576e-06, -6.66187081899168e-06}, - {-4.93720951871921e-05, -0.000102820030405771, -5.69904376301748e-05, -3.79603438055116e-05, -3.96726017834930e-06}, - {-2.21881958961135e-06, -1.40207117987894e-06, 1.60956630798516e-07, 2.06121145135022e-06, 6.50944708093149e-07}, - {2.21876332411271e-07, 1.92272880430386e-07, -6.44016558013941e-09, -1.40954921332410e-07, -4.26742169137667e-07}, - {-3.51738525149881e-08, 2.89616194332516e-08, -3.40343352397886e-08, -2.89763392721812e-08, -6.40980581663785e-10}, - {3.51240856823468e-05, -0.000725895015345786, -0.000322514037108045, -0.000106143759981636, 4.08153152459337e-05}, - {-2.36269716929413e-05, -4.20691836557932e-05, 1.43926743222922e-05, 2.61811210631784e-05, 2.09610762194903e-05}, - {-7.91765756673890e-07, 1.64556789159745e-06, -9.43930166276555e-07, 6.46641738736139e-07, -5.91509547299176e-07}, - {3.92768838766879e-07, -1.98027731703690e-07, -5.41303590057253e-08, -4.21705797874207e-07, -6.06042329660681e-08}, - {-1.56650141024305e-08, 7.61808165752027e-08, -1.81900460250934e-08, 1.30196216971675e-08, 1.08616031342379e-08}, - {-2.80964779829242e-08, -7.25951488826103e-09, -2.59789823306225e-09, -2.79271942407154e-09, 4.10558774868586e-09}, - {-0.000638227857648286, -0.000154814045363391, 7.78518327501759e-05, -2.95961469342381e-05, 1.15965225055757e-06}, - {4.47833146915112e-06, 1.33712284237555e-05, 3.61048816552123e-06, -2.50717844073547e-06, -1.28100822021734e-05}, - {-2.26958070007455e-06, 2.57779960912242e-06, 1.08395653197976e-06, 1.29403393862805e-07, -1.04854652812567e-06}, - {-3.98954043463392e-07, -2.26931182815454e-07, -1.09169545045028e-07, -1.49509536031939e-07, -3.98376793949903e-07}, - {2.30418911071110e-08, 1.23098508481555e-08, -1.71161401463708e-08, 2.35829696577657e-09, 1.31136164162040e-08}, - {3.69423793101582e-09, 3.49231027561927e-10, -1.18581468768647e-09, 5.43180735828820e-10, 5.43192337651588e-10}, - {-1.38608847117992e-09, -1.86719145546559e-10, -8.13477384765498e-10, 2.01919878240491e-10, 1.00067892622287e-10}, - {-4.35499078415956e-05, 0.000450727967957804, 0.000328978494268850, -3.05249478582848e-05, -3.21914834544310e-05}, - {1.24887940973241e-05, 1.34275239548403e-05, 1.11275518344713e-06, 7.46733554562851e-06, -2.12458664760353e-06}, - {9.50250784948476e-07, 2.34367372695203e-06, -5.43099244798980e-07, -4.35196904508734e-07, -8.31852234345897e-07}, - {5.91775478636535e-09, -1.48970922508592e-07, 2.99840061173840e-08, -1.30595933407792e-07, 1.27136765045597e-07}, - {-1.78491083554475e-08, 1.76864919393085e-08, -1.96740493482011e-08, 1.21096708004261e-08, 2.95518703155064e-10}, - {1.75053510088658e-09, -1.31414287871615e-09, -1.44689439791928e-09, 1.14682483668460e-09, 1.74488616540169e-09}, - {1.08152964586251e-09, -3.85678162063266e-10, -2.77851016629979e-10, 3.89890578625590e-11, -2.54627365853495e-10}, - {-1.88340955578221e-10, 5.19645384002867e-11, 2.14131326027631e-11, 1.24027770392728e-11, -9.42818962431967e-12}, - {0.000359777729843898, -0.000111692619996219, -6.87103418744904e-05, 0.000115128973879551, 7.59796247722486e-05}, - {5.23717968000879e-05, 1.32279078116467e-05, -5.72277317139479e-07, -7.56326558610214e-06, -1.95749622214651e-05}, - {1.00109213210139e-06, -2.75515216592735e-07, -1.13393194050846e-06, -4.75049734870663e-07, -3.21499480530932e-07}, - {-2.07013716598890e-07, -7.31392258077707e-08, -3.96445714084160e-08, 3.21390452929387e-08, -1.43738764991525e-08}, - {2.03081434931767e-09, -1.35423687136122e-08, -4.47637454261816e-09, 2.18409121726643e-09, -3.74845286805217e-09}, - {3.17469255318367e-09, 2.44221027314129e-10, -2.46820614760019e-10, 7.55851003884434e-10, 6.98980592550891e-10}, - {9.89541493531067e-11, -2.78762878057315e-11, -2.10947962916771e-10, 3.77882267360636e-11, -1.20009542671532e-12}, - {5.01720575730940e-11, 1.66470417102135e-11, -7.50624817938091e-12, 9.97880221482238e-12, 4.87141864438892e-12}, - {2.53137945301589e-11, 1.93030083090772e-12, -1.44708804231290e-12, -1.77837100743423e-12, -8.10068935490951e-13}, - {0.000115735341520738, 0.000116910591048350, 8.36315620479475e-05, 1.61095702669207e-05, -7.53084853489862e-05}, - {-9.76879433427199e-06, 9.16968438003335e-06, -8.72755127288830e-06, -1.30077933880053e-05, -9.78841937993320e-06}, - {1.04902782517565e-07, 2.14036988364936e-07, -7.19358686652888e-07, 1.12529592946332e-07, 7.07316352860448e-07}, - {7.63177265285080e-08, 1.22781974434290e-07, 8.99971272969286e-08, 5.63482239352990e-08, 4.31054352285547e-08}, - {3.29855763107355e-09, -6.95004336734441e-09, -6.52491370576354e-09, 1.97749180391742e-09, 3.51941791940498e-09}, - {3.85373745846559e-10, 1.65754130924183e-10, -3.31326088103057e-10, 5.93256024580436e-10, 1.27725220636915e-10}, - {-1.08840956376565e-10, -4.56042860268189e-11, -4.77254322645633e-12, -2.94405398621875e-12, -3.07199979999475e-11}, - {2.07389879095010e-11, 1.51186798732451e-11, 9.28139802941848e-12, 5.92738269687687e-12, 9.70337402306505e-13}, - {-2.85879708060306e-12, 1.92164314717053e-13, 4.02664678967890e-14, 5.18246319204277e-13, -7.91438726419423e-13}, - {6.91890667590734e-13, -8.49442290988352e-14, -5.54404947212402e-15, 9.71093377538790e-15, -5.33714333415971e-14}, - {-5.06132972789792e-05, -4.28348772058883e-05, -6.90746551020305e-05, 8.48380415176836e-05, 7.04135614675053e-05}, - {-1.27945598849788e-05, -1.92362865537803e-05, -2.30971771867138e-06, -8.98515975724166e-06, 5.25675205004752e-06}, - {-8.71907027470177e-07, -1.02091512861164e-06, -1.69548051683864e-07, 4.87239045855761e-07, 9.13163249899837e-07}, - {-6.23651943425918e-08, 6.98993315829649e-08, 5.91597766733390e-08, 4.36227124230661e-08, 6.45321798431575e-08}, - {-1.46315079552637e-10, -7.85142670184337e-09, 1.48788168857903e-09, 2.16870499912160e-09, -1.16723047065545e-09}, - {3.31888494450352e-10, 1.90931898336457e-10, -3.13671901557599e-11, 2.60711798190524e-10, 8.45240112207997e-11}, - {1.36645682588537e-11, -5.68830303783976e-12, 1.57518923848140e-11, -1.61935794656758e-11, -4.16568077748351e-12}, - {9.44684950971905e-13, 7.30313977131995e-12, 3.14451447892684e-12, 6.49029875639842e-13, -9.66911019905919e-13}, - {-8.13097374090024e-13, 5.23351897822186e-13, 8.94349188113951e-14, -1.33327759673270e-13, -4.04549450989029e-13}, - {-3.76176467005839e-14, -6.19953702289713e-14, -3.74537190139726e-14, 1.71275486301958e-14, -3.81946773167132e-14}, - {-4.81393385544160e-14, 3.66084990006325e-15, 3.10432030972253e-15, -4.10964475657416e-15, -6.58644244242900e-15}, - {-7.81077363746945e-05, -0.000254773632197303, -0.000214538508009518, -3.80780934346726e-05, 1.83495359193990e-05}, - {5.89140224113144e-06, -3.17312632433258e-06, -3.81872516710791e-06, -2.27592226861647e-06, 1.57044619888023e-06}, - {-1.44272505088690e-06, -1.10236588903758e-07, 2.64336813084693e-07, 4.76074163332460e-07, 4.28623587694570e-07}, - {3.98889120733904e-08, -1.29638005554027e-08, -4.13668481273828e-08, 1.27686793719542e-09, -3.54202962042383e-08}, - {1.60726837551750e-09, -2.70750776726156e-09, 2.79387092681070e-09, -3.01419734793998e-10, -1.29101669438296e-10}, - {-2.55708290234943e-10, 2.27878015173471e-11, -6.43063443462716e-12, 1.26531554846856e-10, -1.65822147437220e-10}, - {-3.35886470557484e-11, -3.51895009091595e-12, 5.80698399963198e-12, -2.84881487149207e-12, 8.91708061745902e-12}, - {-3.12788523950588e-12, 3.35366912964637e-12, 2.52236848033838e-12, -8.12801050709184e-13, -2.63510394773892e-13}, - {6.83791881183142e-14, 2.41583263270381e-13, 8.58807794189356e-14, -5.12528492761045e-14, -1.40961725631276e-13}, - {-1.28585349115321e-14, -2.11049721804969e-14, 5.26409596614749e-15, -4.31736582588616e-15, -1.60991602619068e-14}, - {-9.35623261461309e-15, -3.94384886372442e-16, 5.04633016896942e-16, -5.40268998456055e-16, -1.07857944298104e-15}, - {8.79756791888023e-16, 4.52529935675330e-16, 1.36886341163227e-16, -1.12984402980452e-16, 6.30354561057224e-18}, - {0.000117829256884757, 2.67013591698442e-05, 2.57913446775250e-05, -4.40766244878807e-05, -1.60651761172523e-06}, - {-1.87058092029105e-05, 1.34371169060024e-05, 5.59131416451555e-06, 4.50960364635647e-06, 2.87612873904633e-06}, - {2.79835536517287e-07, 8.93092708148293e-07, 8.37294601021795e-07, -1.99029785860896e-08, -8.87240405168977e-08}, - {4.95854313394905e-08, -1.44694570735912e-08, 2.51662229339375e-08, -3.87086600452258e-09, 2.29741919071270e-08}, - {4.71497840986162e-09, 2.47509999454076e-09, 1.67323845102824e-09, 8.14196768283530e-10, -3.71467396944165e-10}, - {-1.07340743907054e-10, -8.07691657949326e-11, -5.99381660248133e-11, 2.33173929639378e-12, -2.26994195544563e-11}, - {-3.83130441984224e-11, -5.82499946138714e-12, 1.43286311435124e-11, 3.15150503353387e-12, 5.97891025146774e-12}, - {-5.64389191072230e-13, 9.57258316335954e-13, 1.12055192185939e-12, -4.42417706775420e-13, -9.93190361616481e-13}, - {1.78188860269677e-13, 7.82582024904950e-14, 5.18061650118009e-14, 2.13456507353387e-14, -5.26202113779510e-14}, - {-8.18481324740893e-15, -3.71256746886786e-15, 4.23508855164371e-16, -2.91292502923102e-15, -1.15454205389350e-14}, - {6.16578691696810e-15, 6.74087154080877e-16, 5.71628946437034e-16, -2.05251213979975e-16, -7.25999138903781e-16}, - {9.35481959699383e-17, 6.23535830498083e-17, 3.18076728802060e-18, -2.92353209354587e-17, 7.65216088665263e-19}, - {2.34173078531701e-17, -8.30342420281772e-18, -4.33602329912952e-18, 1.90226281379981e-18, -7.85507922718903e-19} - }; - - /** Legendre functions anm for coefficient cw.*/ - private static final double[][] CW_A = { - {0.0395329695826997, -0.000131114380761895, -0.000116331009006233, 6.23548420410646e-05, 5.72641113425116e-05}, - {-0.000441837640880650, 0.000701288648654908, 0.000338489802858270, 3.76700309908602e-05, -8.70889013574699e-06}, - {1.30418530496887e-05, -0.000185046547597376, 4.31032103066723e-05, 0.000105583334124319, 3.23045436993589e-05}, - {3.68918433448519e-05, -0.000219433014681503, 3.46768613485000e-06, -9.17185187163528e-05, -3.69243242456081e-05}, - {-6.50227201116778e-06, 2.07614874282187e-05, -5.09131314798362e-05, -3.08053225174359e-05, -4.18483655873918e-05}, - {2.67879176459056e-05, -6.89303730743691e-05, 2.11046783217168e-06, 1.93163912538178e-05, -1.97877143887704e-06}, - {0.000393937595007422, -0.000452948381236406, -0.000136517846073846, 0.000138239247989489, 0.000133175232977863}, - {5.00214539435002e-05, 3.57229726719727e-05, -9.38010547535432e-07, -3.52586798317563e-05, -7.01218677681254e-06}, - {3.91965314099929e-05, 1.02236686806489e-05, -1.95710695226022e-05, -5.93904795230695e-06, 3.24339769876093e-06}, - {6.68158778290653e-06, -8.10468752307024e-06, -9.91192994096109e-06, -1.89755520007723e-07, -3.26799467595579e-06}, - {0.000314196817753895, -0.000296548447162009, -0.000218410153263575, -1.57318389871000e-05, 4.69789570185785e-05}, - {0.000104597721123977, -3.31000119089319e-05, 5.60326793626348e-05, 4.71895007710715e-05, 3.57432326236664e-05}, - {8.95483021572039e-06, 1.44019305383365e-05, 4.87912790492931e-06, -3.45826387853503e-06, 3.23960320438157e-06}, - {-1.35249651009930e-05, -2.49349762695977e-06, -2.51509483521132e-06, -9.14254874104858e-07, -8.57897406100890e-07}, - {-1.68143325235195e-06, 1.72073417594235e-06, 1.38765993969565e-06, 4.09770982137530e-07, -6.60908742097123e-07}, - {-0.000639889366487161, 0.00120194042474696, 0.000753258598887703, 3.87356377414663e-05, 1.31231811175345e-05}, - {2.77062763606783e-05, -9.51425270178477e-06, -6.61068056107547e-06, -1.38713669012109e-05, 9.84662092961671e-06}, - {-2.69398078539471e-06, 6.50860676783123e-06, 3.80855926988090e-06, -1.98076068364785e-06, 1.17187335666772e-06}, - {-2.63719028151905e-06, 5.03149473656743e-07, 7.38964893399716e-07, -8.38892485369078e-07, 1.30943917775613e-06}, - {-1.56634992245479e-06, -2.97026487417045e-08, 5.06602801102463e-08, -4.60436007958792e-08, -1.62536449440997e-07}, - {-2.37493912770935e-07, 1.69781593069938e-08, 8.35178275224265e-08, -4.83564044549811e-08, -4.96448864199318e-08}, - {0.00134012259587597, -0.000250989369253194, -2.97647945512547e-05, -6.47889968094926e-05, 8.41302130716859e-05}, - {-0.000113287184900929, 4.78918993866293e-05, -3.14572113583139e-05, -2.10518256626847e-05, -2.03933633847417e-05}, - {-4.97413321312139e-07, 3.72599822034753e-06, -3.53221588399266e-06, -1.05232048036416e-06, -2.74821498198519e-06}, - {4.81988542428155e-06, 4.21400219782474e-07, 1.02814808667637e-06, 4.40299068486188e-09, 3.37103399036634e-09}, - {1.10140301678818e-08, 1.90257670180182e-07, -1.00831353341885e-08, 1.44860642389714e-08, -5.29882089987747e-08}, - {6.12420414245775e-08, -4.48953461152996e-09, -1.38837603709003e-08, -2.05533675904779e-08, 1.49517908802329e-09}, - {9.17090243673643e-10, -9.24878857867367e-09, -2.30856560363943e-09, -4.36348789716735e-09, -4.45808881183025e-10}, - {-0.000424912699609112, -0.000114365438471564, -0.000403200981827193, 4.19949560550194e-05, -3.02068483713739e-05}, - {3.85435472851225e-05, -5.70726887668306e-05, 4.96313706308613e-07, 1.02395703617082e-05, 5.85550000567006e-06}, - {-7.38204470183331e-06, -4.56638770109511e-06, -3.94007992121367e-06, -2.16666812189101e-06, -4.55694264113194e-06}, - {5.89841165408527e-07, 1.40862905173449e-08, 1.08149086563211e-07, -2.18592601537944e-07, -3.78927431428119e-07}, - {4.85164687450468e-08, 8.34273921293655e-08, 1.47489605513673e-08, 6.01494125001291e-08, 6.43812884159484e-09}, - {1.13055580655363e-08, 3.50568765400469e-09, -5.09396162501750e-09, -1.83362063152411e-09, -4.11227251553035e-09}, - {3.16454132867156e-09, -1.39634794131087e-09, -7.34085003895929e-10, -7.55541371271796e-10, -1.57568747643705e-10}, - {1.27572900992112e-09, -3.51625955080441e-10, -4.84132020565098e-10, 1.52427274930711e-10, 1.27466120431317e-10}, - {-0.000481655666236529, -0.000245423313903835, -0.000239499902816719, -0.000157132947351028, 5.54583099258017e-05}, - {-1.52987254785589e-05, 2.78383892116245e-05, 4.32299123991860e-05, 1.70981319744327e-05, -1.35090841769225e-06}, - {-8.65400907717798e-06, -6.51882656990376e-06, -2.43810171017369e-07, 8.54348785752623e-07, 2.98371863248143e-07}, - {-1.68155571776752e-06, -3.53602587563318e-07, -1.00404435881759e-07, -2.14162249012859e-08, -2.42131535531526e-07}, - {-1.08048603277187e-08, -9.78850785763030e-08, -2.32906554437417e-08, 2.22003630858805e-08, -2.27230368089683e-09}, - {-5.98864391551041e-09, 7.38970926486848e-09, 3.61322835311957e-09, 3.70037329172919e-09, -3.41121137081362e-09}, - {-7.33113754909726e-10, -9.08374249335220e-11, -1.78204392133739e-10, 8.28618491929026e-11, -1.32966817912373e-10}, - {-5.23340481314676e-10, 1.36403528233346e-10, -7.04478837151279e-11, -6.83175201536443e-12, -2.86040864071134e-12}, - {3.75347503578356e-11, -1.08518134138781e-11, -2.53583751744508e-12, 1.00168232812303e-11, 1.74929602713312e-11}, - {-0.000686805336370570, 0.000591849814585706, 0.000475117378328026, -2.59339398048415e-05, 3.74825110514968e-05}, - {3.35231363034093e-05, 2.38331521146909e-05, 7.43545963794093e-06, -3.41430817541849e-06, 7.20180957675353e-06}, - {3.60564374432978e-07, -3.13300039589662e-06, -6.38974746108020e-07, -8.63985524672024e-07, 2.43367665208655e-06}, - {-4.09605238516094e-07, -2.51158699554904e-07, -1.29359217235188e-07, -2.27744642483133e-07, 7.04065989970205e-08}, - {6.74886341820129e-08, -1.02009407061935e-08, -3.30790296448812e-08, 1.64959795655031e-08, 1.40641779998855e-08}, - {1.31706886235108e-09, -1.06243701278671e-09, -2.85573799673944e-09, 3.72566568681289e-09, 2.48402582003925e-09}, - {-3.68427463251097e-11, -1.90028122983781e-10, -3.98586561768697e-11, 1.14458831693287e-11, -2.27722300377854e-12}, - {-7.90029729611056e-11, 3.81213646526419e-11, 4.63303426711788e-11, 1.52294835905903e-11, -2.99094751490726e-12}, - {-2.36146602045017e-11, 1.03852674709985e-11, -4.47242126307100e-12, 5.30884113537806e-12, 1.68499023262969e-12}, - {-3.30107358134527e-13, -4.73989085379655e-13, 5.17199549822684e-13, 2.34951744478255e-13, 2.05931351608192e-13}, - {0.000430215687511780, -0.000132831373000014, -3.41830835017045e-05, 4.70312161436033e-06, -3.84807179340006e-05}, - {1.66861163032403e-05, -8.10092908523550e-06, 8.20658107437905e-06, 6.12399025026683e-06, -1.85536495631911e-06}, - {1.53552093641337e-06, 2.19486495660361e-06, -1.07253805120137e-06, -4.72141767909137e-07, 4.00744581573216e-07}, - {2.56647305130757e-07, -8.07492046592274e-08, -2.05858469296168e-07, 1.09784168930599e-07, -7.76823030181225e-08}, - {1.77744008115031e-08, 1.64134677817420e-08, 4.86163044879020e-09, 1.13334251800856e-08, -7.17260621115426e-09}, - {1.61133063219326e-09, -1.85414677057024e-09, -2.13798537812651e-09, 1.15255123229679e-09, 2.24504700129464e-09}, - {1.23344223096739e-10, -1.20385012169848e-10, -2.18038256346433e-12, 3.23033120628279e-11, 8.01179568213400e-11}, - {-6.55745274387847e-12, 1.22127104697198e-11, 5.83805016355883e-12, -8.31201582509817e-12, 1.90985373872656e-12}, - {-2.89199983667265e-12, 5.05962500506667e-12, 1.28092925110279e-12, 5.60353813743813e-13, 1.76753731968770e-12}, - {-1.61678729774956e-13, -3.92206170988615e-13, -9.04941327579237e-14, 1.89847694200763e-13, 4.10008676756463e-14}, - {-1.16808369005656e-13, -9.97464591430510e-14, 7.46366550245722e-15, 2.53398578153179e-14, 1.06510689748906e-14}, - {-0.000113716921384790, -0.000131902722651488, -0.000162844886485788, 7.90171538739454e-06, -0.000178768066961413}, - {-2.13146535366500e-06, -3.57818705543597e-05, -1.50825855069298e-05, -2.17909259570022e-05, -8.19332236308581e-06}, - {-2.88001138617357e-06, -2.09957465440793e-06, 6.81466526687552e-08, 3.58308906974448e-07, -4.18502067223724e-07}, - {-1.10761444317605e-07, 6.91773860777929e-08, 8.17125372450372e-08, -2.16476237959181e-08, 7.59221970502074e-08}, - {-9.56994224818941e-09, 6.64104921728432e-09, 6.33077902928348e-09, 2.85721181743727e-09, -6.39666681678123e-09}, - {4.62558627839842e-10, -1.69014863754621e-09, -2.80260429599733e-10, 4.27558937623863e-11, -1.66926133269027e-10}, - {-7.23385132663753e-11, 5.51961193545280e-11, 3.04070791942335e-11, 3.23227055919062e-12, 8.47312431934829e-11}, - {-1.61189613765486e-11, 1.66868155925172e-11, 1.05370341694715e-11, -4.41495859079592e-12, -2.24939051401750e-12}, - {-8.72229568056267e-13, 1.88613726203286e-12, 1.21711137534390e-14, -1.13342372297867e-12, -6.87151975256052e-13}, - {7.99311988544090e-15, 4.46150979586709e-14, 7.50406779454998e-14, -3.20385428942275e-14, -1.26543636054393e-14}, - {4.80503817699514e-14, -3.35545623603729e-14, -1.18546423610485e-14, 4.19419209985980e-15, -1.73525614436880e-14}, - {-1.20464898830163e-15, -8.80752065000456e-16, -1.22214298993313e-15, 1.69928513019657e-15, 1.93593051311405e-16}, - {1.68528879784841e-05, 3.57144412031081e-05, -1.65999910125077e-05, 5.40370336805755e-05, 0.000118138122851376}, - {-3.28151779115881e-05, 1.04231790790798e-05, -2.80761862890640e-06, 2.98996152515593e-06, -2.67641158709985e-06}, - {-2.08664816151978e-06, -1.64463884697475e-06, 6.79099429284834e-08, 7.23955842946495e-07, -6.86378427465657e-07}, - {-2.88205823027255e-09, 2.38319699493291e-09, 1.14169347509045e-07, 8.12981074994402e-08, -1.56957943666988e-07}, - {-7.09711403570189e-09, 6.29470515502988e-09, 3.50833306577579e-09, 8.31289199649054e-09, -2.14221463168338e-09}, - {-8.11910123910038e-10, 3.34047829618955e-10, 3.70619377446490e-10, 3.30426088213373e-10, 4.86297305597865e-11}, - {1.98628160424161e-11, -4.98557831380098e-12, -5.90523187802174e-12, -1.27027116925122e-12, 1.49982368570355e-11}, - {2.62289263262748e-12, 3.91242360693861e-12, 6.56035499387192e-12, -1.17412941089401e-12, -9.40878197853394e-13}, - {-3.37805010124487e-13, 5.39454874299593e-13, -2.41569839991525e-13, -2.41572016820792e-13, -3.01983673057198e-13}, - {-1.85034053857964e-13, 4.31132161871815e-14, 4.13497222026824e-15, -4.60075514595980e-14, -1.92454846400146e-14}, - {2.96113888929854e-15, -1.11688534391626e-14, 3.76275373238932e-15, -3.72593295948136e-15, 1.98205490249604e-16}, - {1.40074667864629e-15, -5.15564234798333e-16, 3.56287382196512e-16, 5.07242777691587e-16, -2.30405782826134e-17}, - {2.96822530176851e-16, -4.77029898301223e-17, 1.12782285532775e-16, 1.58443229778573e-18, 8.22141904662969e-17} - }; - - /** Legendre functions bnm for coefficient bh.*/ - private static final double[][] BH_B = { - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {-2.29210587053658e-06, -2.33805004374529e-06, -7.49312880102168e-07, -5.12022747852006e-07, 5.88926055066172e-07}, - {0, 0, 0, 0, 0}, - {-4.63382754843690e-06, -2.23853015662938e-06, 8.14830531656518e-07, 1.15453269407116e-06, -4.53555450927571e-07}, - {-6.92432096320778e-07, -2.98734455136141e-07, 1.48085153955641e-08, 1.37881746148773e-07, -6.92492118460215e-09}, - {0, 0, 0, 0, 0}, - {-1.91507979850310e-06, -1.83614825459598e-06, -7.46807436870647e-07, -1.28329122348007e-06, 5.04937180063059e-07}, - {-8.07527103916713e-07, 2.83997840574570e-08, -6.01890498063025e-08, -2.48339507554546e-08, 2.46284627824308e-08}, - {-2.82995069303093e-07, 1.38818274596408e-09, 3.22731214161408e-09, 2.87731153972404e-10, 1.53895537278496e-08}, - {0, 0, 0, 0, 0}, - {-6.68210270956800e-07, -2.19104833297845e-06, 1.30116691657253e-07, 4.78445730433450e-07, -4.40344300914051e-07}, - {-2.36946755740436e-07, -1.32730991878204e-07, 1.83669593693860e-08, 7.90218931983569e-08, -4.70161979232584e-08}, - {1.07746083292179e-07, -4.17088637760330e-09, -1.83296035841109e-09, -5.80243971371211e-09, -2.11682361167439e-09}, - {-5.44712355496109e-08, 1.89717032256923e-09, 2.27327316287804e-10, 7.78400728280038e-10, 8.82380487618991e-12}, - {0, 0, 0, 0, 0}, - {-5.61707049615673e-08, -1.09066447089585e-06, -2.25742250174119e-07, -8.64367795924377e-07, 1.06411275240680e-08}, - {2.41782935157918e-08, -3.65762298303819e-08, -6.93420659586875e-08, -3.97316214341991e-08, -2.08767816486390e-08}, - {6.38293030383436e-08, 1.11377936334470e-08, 6.91424941454782e-09, 1.39887159955004e-09, 5.25428749022906e-09}, - {1.09291268489958e-08, 1.23935926756516e-10, 3.92917259954515e-10, -1.79144682483562e-10, -9.11802874917597e-10}, - {-4.40957607823325e-09, 1.45751390560667e-10, 1.24641258165301e-10, -6.45810339804674e-11, -8.92894658893326e-12}, - {0, 0, 0, 0, 0}, - {1.54754294162102e-08, -1.60154742388847e-06, -4.08425188394881e-07, 6.18170290113531e-09, -2.58919765162122e-07}, - {1.37130642286873e-08, -6.67813955828458e-08, -7.01410996605609e-09, 3.82732572660461e-08, -2.73381870915135e-08}, - {2.19113155379218e-08, 4.11027496396868e-09, 6.33816020485226e-09, -1.49242411327524e-09, -6.14224941851705e-10}, - {6.26573021218961e-09, 5.17137416480052e-10, -3.49784328298676e-10, 1.13578756343208e-10, 2.80414613398411e-10}, - {1.65048133258794e-11, 1.00047239417239e-10, 1.05124654878499e-10, -3.03826002621926e-11, 4.57155388334682e-11}, - {6.20221691418381e-11, 9.75852610098156e-12, -5.46716005756984e-12, 1.31643349569537e-11, 3.61618775715470e-12}, - {0, 0, 0, 0, 0}, - {-1.03938913012708e-06, -1.78417431315664e-07, 2.86040141364439e-07, 1.83508599345952e-08, -1.34452220464346e-07}, - {-4.36557481393662e-08, 7.49780206868834e-09, -8.62829428674082e-09, 5.50577793039009e-09, -9.46897502333254e-09}, - {3.43193738406672e-10, 1.13545447306468e-08, 1.25242388852214e-09, 6.03221501959620e-10, 1.57172070361180e-09}, - {-4.73307591021391e-10, 1.70855824051391e-10, -2.62470421477037e-11, 2.04525835988874e-10, -1.17859695928164e-10}, - {-3.36185995299839e-10, 3.19243054562183e-11, 1.17589412418126e-10, -1.35478747434514e-12, 5.11192214558542e-11}, - {3.19640547592136e-11, 2.94297823804643e-12, -1.00651526276990e-11, -1.67028733953153e-12, 3.03938833625503e-12}, - {1.68928641118173e-11, -7.90032886682002e-13, -1.40899773539137e-12, 7.76937592393354e-13, 7.32539820298651e-13}, - {0, 0, 0, 0, 0}, - {2.32949756055277e-07, 1.46237594908093e-07, -1.07770884952484e-07, 1.26824870644476e-07, -2.36345735961108e-08}, - {8.89572676497766e-08, 7.24810004121931e-08, 2.67583556180119e-08, 2.48434796111361e-08, -3.55004782858686e-09}, - {-1.00823909773603e-08, 8.84433929029076e-10, -2.55502517594511e-10, -5.48034274059119e-10, -8.50241938494079e-10}, - {1.13259819566467e-09, 5.55186945221216e-10, 7.63679807785295e-11, -1.70067998092043e-11, 1.57081965572493e-10}, - {-2.37748192185353e-10, 2.45463764948000e-11, 3.23208414802860e-11, -2.72624834520723e-12, 8.14449183666500e-12}, - {-1.54977633126025e-11, 4.58754903157884e-12, -1.25864665839074e-12, 2.44139868157872e-12, -1.82827441958193e-12}, - {3.28285563794513e-12, -1.10072329225465e-12, -7.23470501810935e-13, 5.85309745620389e-13, 4.11317589687125e-13}, - {4.57596974384170e-13, 9.84198128213558e-14, 3.34503817702830e-14, 7.08431086558307e-15, 2.79891177268807e-14}, - {0, 0, 0, 0, 0}, - {-3.67820719155580e-07, 6.98497901205902e-07, 1.83397388750300e-07, 2.39730262495372e-07, -2.58441984368194e-07}, - {5.17793954077994e-08, 5.54614175977835e-08, 1.75026214305232e-09, -2.55518450411346e-09, -6.12272723006537e-09}, - {-7.94292648157198e-09, -1.01709107852895e-09, -1.49251241812310e-09, 9.32827213605682e-10, -8.24490722043118e-10}, - {1.36410408475679e-11, 2.16390220454971e-10, 1.24934806872235e-10, -6.82507825145903e-11, -4.01575177719668e-11}, - {-1.41619917600555e-11, -1.54733230409082e-11, 1.36792829351538e-11, 1.11157862104733e-12, 2.08548465892268e-11}, - {-3.56521723755846e-12, 4.47877185884557e-12, -6.34096209274637e-16, -1.13010624512348e-12, -2.82018136861041e-13}, - {2.22758955943441e-12, -4.63876465559380e-13, -5.80688019272507e-13, 2.45878690598655e-13, 1.49997666808106e-13}, - {-6.26833903786958e-14, 2.73416335780807e-14, 1.91842340758425e-14, 1.67405061129010e-14, -2.45268543953704e-17}, - {1.81972870222228e-14, 5.43036245069085e-15, 1.92476637107321e-15, 8.78498602508626e-17, -1.42581647227657e-15}, - {0, 0, 0, 0, 0}, - {9.74322164613392e-07, -5.23101820582724e-07, -2.81997898176227e-07, 4.54762451707384e-08, -3.34645078118827e-08}, - {-6.75813194549663e-09, 3.49744702199583e-08, -5.09170419895883e-09, 5.24359476874755e-09, 4.96664262534662e-09}, - {4.53858847892396e-10, -1.49347392165963e-09, -2.00939511362154e-09, 9.30987163387955e-10, 9.74450200826854e-11}, - {-4.92900885858693e-10, 5.34223033225688e-12, 1.08501839729368e-10, -6.43526142089173e-11, -3.11063319142619e-11}, - {1.38469246386690e-11, -7.91180584906922e-12, 2.26641656746936e-13, 4.55251515177956e-12, 6.05270575117769e-12}, - {4.02247935664225e-12, 1.82776657951829e-12, -1.28348801405445e-13, -2.16257301300350e-13, -5.54363979435025e-14}, - {4.15005914461687e-13, -2.00647573581168e-13, -1.67278251942946e-13, 1.30332398257985e-13, 1.52742363652434e-13}, - {6.36376500056974e-14, 1.65794532815776e-14, -3.80832559052662e-15, -6.40262894005341e-16, 2.42577181848072e-15}, - {-5.55273521249151e-15, 3.69725182221479e-15, 2.02114207545759e-15, -4.50870833392161e-16, 9.62950493696677e-17}, - {1.00935904205024e-17, 6.54751873609395e-17, -1.09138810997186e-16, -8.62396750098759e-17, -3.82788257844306e-17}, - {0, 0, 0, 0, 0}, - {4.21958510903678e-07, -8.30678271007705e-08, -3.47006439555247e-07, -3.36442823712421e-08, 9.90739768222027e-08}, - {2.64389033612742e-08, 2.65825090066479e-09, -1.28895513428522e-08, -7.07182694980098e-10, 7.10907165301180e-09}, - {6.31203524153492e-09, -1.67038260990134e-09, 1.33104703539822e-09, 8.34376495185149e-10, -2.52478613522612e-10}, - {1.18414896299279e-10, -2.57745052288455e-11, 2.88295935685818e-11, -3.27782977418354e-11, -1.05705000036156e-11}, - {-4.20826459055091e-12, -6.97430607432268e-12, -3.90660545970607e-12, -3.90449239948755e-13, -4.60384797517466e-13}, - {-9.47668356558200e-13, 6.53305025354881e-13, 2.63240185434960e-13, 1.40129115015734e-13, 3.85788887132074e-14}, - {2.23947810407291e-13, 7.35262771548253e-15, -3.83348211931292e-14, 4.20376514344176e-14, 4.26445836468461e-14}, - {-3.88008154470596e-16, 2.28561424667750e-15, -8.73599966653373e-16, 2.14321147947665e-15, 6.38631825071920e-16}, - {-8.62165565535721e-15, 1.79742912149810e-15, 1.01541125038661e-15, -7.91027655831866e-17, -4.06505132825230e-16}, - {-2.35355054392189e-16, -6.13997759731013e-17, -2.73490528665965e-17, 2.63895177155121e-17, -4.47531057245187e-18}, - {6.01909706823530e-17, 5.35520010856833e-18, -2.15530106132531e-18, -2.46778496746231e-18, -7.09947296442799e-19}, - {0, 0, 0, 0, 0}, - {-3.75005956318736e-07, -5.39872297906819e-07, -1.19929654883034e-07, 4.52771083775007e-08, 1.82790552943564e-07}, - {7.82606642505646e-09, -1.68890832383153e-08, -8.45995188378997e-09, 1.42958730598502e-09, 3.21075754133531e-09}, - {4.28818421913782e-09, -1.07501469928219e-09, 8.84086350297418e-10, 9.74171228764155e-10, 8.59877149602304e-12}, - {1.28983712172521e-10, -6.96375160373676e-11, -2.13481436408896e-11, 1.33516375568179e-11, -1.65864626508258e-11}, - {-4.48914384622368e-12, 9.68953616831263e-13, -1.61372463422897e-12, -2.09683563440448e-12, -1.90096826314068e-12}, - {-1.12626619779175e-13, 3.34903159106509e-14, -1.21721528343657e-13, 7.46246339290354e-14, 3.68424909859186e-13}, - {5.08294274367790e-14, 2.83036159977090e-14, 1.48074873486387e-14, -9.59633528834945e-15, -1.26231060951100e-14}, - {-4.01464098583541e-16, 1.97047929526674e-15, -5.29967950447497e-16, -3.59120406619931e-16, 1.69690933982683e-16}, - {-1.73919209873841e-15, 7.52792462841274e-16, 3.65589287101147e-16, -7.79247612043812e-17, -8.24599670368999e-17}, - {-4.61555616150128e-17, 4.94529746019753e-19, -1.09858157212270e-17, 3.95550811124928e-18, 3.23972399884100e-18}, - {-2.27040686655766e-17, -3.27855689001215e-18, -3.30649011116861e-19, 9.08748546536849e-19, 8.92197599890994e-19}, - {5.67241944733762e-18, 3.84449400209976e-19, 1.77668058015537e-19, 2.00432838283455e-20, -2.00801461564767e-19} - }; - - /** Legendre functions bnm for coefficient bw.*/ - private static final double[][] BW_B = { - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {-9.56715196386889e-06, -3.68040633020420e-08, 1.27846786489883e-07, 1.32525487755973e-06, 1.53075361125066e-06}, - {0, 0, 0, 0, 0}, - {-7.17682617983607e-06, 2.89994188119445e-06, -2.97763578173405e-07, 8.95742089134942e-07, 3.44416325304006e-07}, - {-8.02661132285210e-07, 3.66738692077244e-07, -3.02880965723280e-07, 3.54144282036103e-07, -1.68873066391463e-07}, - {0, 0, 0, 0, 0}, - {-2.89640569283461e-06, -7.83566373343614e-07, -8.36667214682577e-07, -7.41891843549121e-07, -9.23922655636489e-08}, - {-1.06144662284862e-06, 1.57709930505924e-07, 1.04203025714319e-07, 1.20783300488461e-07, -1.38726055821134e-07}, - {-4.16549018672265e-07, -1.35220897698872e-07, -6.40269964829901e-08, 1.63258283210837e-08, -2.57958025095959e-08}, - {0, 0, 0, 0, 0}, - {3.52324885892419e-06, -2.26705543513814e-07, 1.53835589488292e-06, -3.75263061267433e-07, 3.69384057396017e-07}, - {-2.06569149157664e-07, -9.36260183227175e-08, -3.55985284353048e-08, -9.13671163891094e-08, 6.93156256562600e-09}, - {1.32437594740782e-07, 4.44349887272663e-08, -3.38192451721674e-08, -3.97263855781102e-08, -1.93087822995800e-09}, - {-1.29595244818942e-07, -1.40852985547683e-08, 1.42587592939760e-09, 7.05779876554001e-09, -1.00996269264535e-08}, - {0, 0, 0, 0, 0}, - {4.06960756215938e-06, -1.97898540226986e-06, 7.21905857553588e-08, -1.19908881538755e-06, -5.67561861536903e-08}, - {6.53369660286999e-08, -2.42818687866392e-07, -1.66203004559493e-08, -2.41512414151897e-08, 4.45426333411018e-08}, - {1.44650670663281e-07, 8.50666367433859e-09, -4.61165612004307e-09, 4.88527987491045e-09, 1.06277326713172e-08}, - {1.86770937103513e-08, -6.44197940288930e-10, -7.60456736846174e-09, -9.97186468682689e-10, 8.73229752697716e-10}, - {-1.00206566229113e-08, 1.33934372663121e-09, 1.41691503439220e-09, 8.72352590578753e-10, -8.04561626629829e-10}, - {0, 0, 0, 0, 0}, - {3.07161843116618e-06, 1.82962085656470e-06, 1.87728623016069e-07, 7.10611617623261e-07, 2.26499092250481e-07}, - {4.50766403064905e-08, -1.67752393078256e-07, 2.47844723639070e-08, -3.56484348424869e-09, -1.56634836636584e-08}, - {3.77011651881090e-08, -7.23045828480496e-09, 5.22995988863761e-09, -1.03740320341306e-09, 4.57839777217789e-09}, - {8.09495635883121e-09, -3.01977244420529e-10, -2.30104544933093e-09, 3.63658580939428e-10, 4.39320811714867e-10}, - {9.37087629961269e-11, 1.00780920426635e-09, 1.28140539913350e-10, -6.65795285522138e-12, 4.71732796198631e-11}, - {-8.88504487069155e-11, -1.63253810435461e-10, 7.22669710644299e-11, 5.64715132584527e-11, -1.08949308197617e-12}, - {0, 0, 0, 0, 0}, - {-2.64054293284174e-07, -2.37611606117256e-06, -1.83671059706264e-06, -3.12199354841993e-07, -1.05598289276114e-07}, - {7.41706968747147e-08, -1.64359098062646e-08, -3.09750224040234e-08, -9.68640079410317e-09, -7.90399057863403e-08}, - {-1.00254376564271e-08, 1.12528248631191e-08, -2.67841549174100e-09, -2.69481819323647e-09, 1.56550607475331e-09}, - {-2.18568129350729e-09, 6.26422056977450e-10, 1.95007291427316e-09, 3.14226463591125e-10, -3.62000388344482e-10}, - {-9.30451291747549e-10, 5.62175549482704e-11, 1.01022849902012e-10, 5.18675856498499e-11, 5.37561696283235e-11}, - {5.33151334468794e-11, 1.07571307336725e-10, -1.31714567944652e-11, -4.17524405900018e-11, -2.16737797893502e-12}, - {4.69916869001309e-11, -4.34516364859583e-12, -6.61054225868897e-12, -5.75845818545368e-12, -2.32180293529175e-12}, - {0, 0, 0, 0, 0}, - {-3.50305843086926e-06, 1.76085131953403e-06, 8.16661224478572e-07, 4.09111042640801e-07, -9.85414469804995e-08}, - {1.44670876127274e-07, -1.41331228923029e-08, -3.06530152369269e-08, -1.46732098927996e-08, -2.30660839364244e-08}, - {-2.00043052422933e-08, 1.72145861031776e-09, 2.13714615094209e-09, 1.02982676689194e-09, -1.64945224692217e-10}, - {1.23552540016991e-09, 1.42028470911613e-09, 8.79622616627508e-10, -7.44465600265154e-10, -7.17124672589442e-11}, - {-6.67749524914644e-10, -5.77722874934050e-11, 3.40077806879472e-11, 4.26176076541840e-11, 8.23189659748212e-11}, - {-4.62771648935992e-11, -7.24005305716782e-13, 1.18233730497485e-12, 5.18156973532267e-12, -1.53329687155297e-12}, - {4.75581699468619e-12, -3.79782291469732e-12, 1.33077109836853e-12, -1.02426020107120e-12, 3.10385019249130e-13}, - {1.66486090578792e-12, 1.08573672403649e-12, 1.26268044166279e-13, -1.23509297742757e-13, -1.81842007284038e-13}, - {0, 0, 0, 0, 0}, - {9.93870680202303e-08, -1.85264736035628e-06, -5.58942734710854e-07, -5.54183448316270e-07, -3.95581289689398e-08}, - {7.88329069002365e-08, 2.04810091451078e-08, 3.74588851000076e-09, 3.42429296613803e-08, -2.00840228416712e-08}, - {-5.93700447329696e-10, -6.57499436973459e-10, -6.90560448220751e-09, 3.56586371051089e-09, 7.33310245621566e-11}, - {-6.38101662363634e-11, 4.23668020216529e-10, -2.43764895979202e-10, -9.31466610703172e-11, -3.17491457845975e-10}, - {1.50943725382470e-11, -6.11641188685078e-11, -4.37018785685645e-11, -2.32871158949602e-11, 4.19757251950526e-11}, - {-1.18165328825853e-11, -9.91299557532438e-13, 6.40908678055865e-14, 2.41049422936434e-12, -8.20746054454953e-14}, - {6.01892101914838e-12, -8.78487122873450e-13, -1.58887481332294e-12, -3.13556902469604e-13, 5.14523727801645e-14}, - {-1.50791729401891e-13, -1.45234807159695e-13, 1.65302377570887e-13, -5.77094211651483e-15, 9.22218953528393e-14}, - {-1.85618902787381e-14, 5.64333811864051e-14, -9.94311377945570e-15, -2.40992156199999e-15, -2.19196760659665e-14}, - {0, 0, 0, 0, 0}, - {-8.16252352075899e-08, 1.61725487723444e-06, 9.55522506715921e-07, 4.02436267433511e-07, -2.80682052597712e-07}, - {7.68684790328630e-09, -5.00940723761353e-09, -2.43640127974386e-08, -2.59119930503129e-08, 3.35015169182094e-08}, - {7.97903115186673e-09, 3.73803883416618e-09, 3.27888334636662e-09, 1.37481300578804e-09, -1.10677168734482e-10}, - {-1.67853012769912e-09, -1.61405252173139e-10, -1.98841576520056e-10, -1.46591506832192e-11, 9.35710487804660e-11}, - {4.08807084343221e-11, -3.74514169689568e-11, -3.03638493323910e-11, -5.02332555734577e-12, -8.03417498408344e-12}, - {6.48922619024579e-12, 1.96166891023817e-12, -1.96968755122868e-12, -5.20970156382361e-12, -1.62656885103402e-12}, - {1.28603518902875e-12, -4.88146958435109e-13, -3.37034886991840e-13, 1.37393696103000e-14, 4.41398325716943e-14}, - {1.48670014793021e-13, 4.41636026364555e-14, 2.06210477976005e-14, -3.43717583585390e-14, -1.21693704024213e-14}, - {-1.67624180330244e-14, 6.59317111144238e-15, 2.57238525440646e-15, -3.21568425020512e-17, 5.29659568026553e-15}, - {7.85453466393227e-16, 6.91252183915939e-16, -1.20540764178454e-15, -3.85803892583301e-16, 3.46606994632006e-16}, - {0, 0, 0, 0, 0}, - {2.86710087625579e-06, -1.68179842305865e-06, -8.48306772016870e-07, -7.08798062479598e-07, -1.27469453733635e-07}, - {2.11824305734993e-09, 2.02274279084379e-08, 1.61862253091554e-08, 3.25597167111807e-08, 3.40868964045822e-09}, - {1.21757111431438e-08, 1.68405530472906e-09, 1.55379338018638e-09, -3.81467795805531e-10, 2.53316405545058e-09}, - {-9.98413758659768e-11, 5.38382145421318e-10, 3.92629628330704e-10, -1.43067134097778e-10, 3.74959329667113e-12}, - {-1.57270407028909e-11, -9.02797202317592e-12, 8.45997059887690e-12, 4.71474382524218e-12, 5.41880986596427e-12}, - {-1.20658618702054e-12, 7.12940685593433e-13, 1.02148613026937e-12, 1.63063852348169e-13, 1.74048793197708e-13}, - {3.80559390991789e-13, 1.19678271353485e-13, 9.72859455604188e-14, 5.42642400031729e-14, 8.18796710714586e-14}, - {-4.69629218656902e-14, 5.59889038686206e-15, 2.05363292795059e-15, 5.38599403288686e-15, -2.68929559474202e-15}, - {-1.88759348081742e-14, 5.20975954705924e-15, -4.43585653096395e-16, 5.57436617793556e-16, -3.95922805817677e-16}, - {-9.80871456373282e-16, 2.50857658461759e-17, -1.24253000050963e-16, 6.00857065211394e-17, 3.53799635311500e-18}, - {2.49370713054872e-16, -1.49119714269816e-17, -3.12276052640583e-17, -2.42001662334001e-17, -1.69766504318143e-17}, - {0, 0, 0, 0, 0}, - {-1.69222102455713e-06, 1.64277906173064e-06, 5.28855114364096e-07, 4.28159853268650e-07, -1.57362445882665e-07}, - {1.67656782413678e-08, -3.77746114074055e-08, -2.21564555842165e-08, -3.37071806992217e-08, 1.47454008739800e-08}, - {1.06080499491408e-08, 3.21990403709678e-09, 3.87301757435359e-09, 2.92241827834347e-10, -1.86619473655742e-11}, - {1.62399669665839e-10, 3.51322865845172e-10, 2.67086377702958e-11, -1.31596563625491e-10, 3.14164569507034e-11}, - {-2.02180016657259e-11, 2.03305178342732e-11, 6.34969032565839e-12, 5.99522296668787e-12, -4.46275273451008e-12}, - {-9.88409290158885e-13, -1.47692750858224e-13, 3.14655550730530e-13, -2.41857189187879e-13, 4.47727504501486e-13}, - {1.71430777754854e-13, 1.73950835042486e-13, 5.92323956541558e-14, 8.06625710171825e-15, 2.33252485755634e-14}, - {-1.74184545690134e-15, -8.18003353124179e-16, -6.62369006497819e-16, 4.16303374396147e-15, 7.06513748014024e-15}, - {-6.02936238677014e-15, 1.89241084885229e-15, 1.99097881944270e-17, -6.99974290696640e-16, -2.69504942597709e-17}, - {-4.65632962602379e-16, 3.70281995445114e-18, -9.04232973763345e-17, 2.20847370761932e-17, 7.62909453726566e-17}, - {-6.25921477907943e-17, -2.10532795609842e-17, -1.03808073867183e-17, 1.15091380049019e-18, 4.66794445408388e-19}, - {9.39427013576903e-18, 9.17044662931859e-19, 2.04132745117549e-18, -1.72364063154625e-19, -1.18098896532163e-18} - }; - - /** Legendre functions bnm for coefficient ch.*/ - private static final double[][] CH_B = { - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {3.44092035729033e-05, -1.21876825440561e-05, -1.87490665238967e-05, -2.60980336247863e-05, 4.31639313264615e-06}, - {0, 0, 0, 0, 0}, - {-2.60125613000133e-05, 1.70570295762269e-05, 3.08331896996832e-05, 1.66256596588688e-05, -1.07841055501996e-05}, - {8.74011641844073e-06, -2.25874169896607e-06, 6.50985196673747e-07, 1.30424765493752e-06, -1.85081244549542e-07}, - {0, 0, 0, 0, 0}, - {3.77496505484964e-05, -1.08198973553337e-05, -1.67717574544937e-05, -3.22476096673598e-05, 1.12281888201134e-05}, - {-7.68623378647958e-07, -4.01400837153063e-06, -2.16390246700835e-06, -1.76912959937924e-06, -1.12740084951955e-06}, - {-2.37092815818895e-06, -9.52317223759653e-07, -2.22722065579131e-07, -6.25157619772530e-08, 1.86582003894639e-08}, - {0, 0, 0, 0, 0}, - {-6.10254317785872e-05, -2.51815503068494e-05, 2.01046207874667e-05, 7.21107723367308e-06, -1.30692058660457e-05}, - {-9.60655417241537e-06, -7.31381721742373e-06, -2.52767927589636e-06, 9.09039973214621e-07, -6.76454911344246e-07}, - {-2.25743206384908e-08, 2.33058746737575e-07, 2.24746779293445e-07, 6.78551351968876e-08, 1.25076011387284e-07}, - {-2.25744112770133e-07, -1.44429560891636e-07, -2.96810417448652e-08, -5.93858519742856e-08, -2.43210229455420e-08}, - {0, 0, 0, 0, 0}, - {7.45721015256308e-06, -3.81396821676410e-05, -1.41086198468687e-05, -2.28514517574713e-05, 7.28638705683277e-06}, - {-5.77517778169692e-06, -3.93061211403839e-06, -2.17369763310752e-06, -1.48060935583664e-07, -2.74200485662814e-07}, - {4.52962035878238e-07, 9.80990375495214e-07, 4.67492045269286e-07, -8.31032252212116e-09, 1.69426023427740e-07}, - {7.20536791795515e-10, 2.75612253452141e-09, 2.47772119382536e-09, 4.30621825021233e-09, -2.86498479499428e-08}, - {-2.46253956492716e-08, -3.10300833499669e-09, 8.06559148724445e-09, 2.98197408430123e-10, 6.32503656532846e-09}, - {0, 0, 0, 0, 0}, - {-6.01147094179306e-05, -3.16631758509869e-05, 4.10038115100010e-06, 3.55215057231403e-07, -2.23606515237408e-06}, - {-2.85937516921923e-06, -3.67775706610630e-06, -5.06445540401637e-07, 8.21776759711184e-07, -5.98690271725558e-07}, - {7.77122595418965e-07, 3.60896376754085e-07, 3.88610487893381e-07, -4.39533892679537e-08, -6.26882227849174e-08}, - {1.05759993661891e-07, 2.58009912408833e-08, -1.51356049060972e-08, -1.13335813107412e-09, 5.37470857850370e-10}, - {7.99831506181984e-09, 1.67423735327465e-09, 2.94736760548677e-09, -1.56727133704788e-09, 8.46186800849124e-10}, - {3.07727104043851e-09, 3.93584215798484e-10, 3.86721562770643e-11, 1.72181091277391e-10, -2.16915737920145e-10}, - {0, 0, 0, 0, 0}, - {-1.16335389078126e-05, -1.39864676661484e-05, 2.52546278407717e-06, -8.79152625440188e-06, -8.97665132187974e-06}, - {-3.95874550504316e-06, -1.17976262528730e-07, 7.03189926369300e-07, 3.38907065351535e-07, -3.67714052493558e-07}, - {2.29082449370440e-07, 5.72961531093329e-07, 4.21969662578894e-08, 1.24112958141431e-08, 9.56404486571888e-08}, - {1.44631865298671e-09, 6.19368473895584e-09, 1.67110424041236e-09, 2.57979463602951e-09, -6.90806907510366e-09}, - {1.77235802019153e-09, -8.14388846228970e-10, 4.50421956523579e-09, 5.67452314909707e-10, 2.47610443675560e-09}, - {4.85932343880617e-10, 2.24864117422804e-10, -2.22534534468511e-10, -7.96395824973477e-11, 3.12587399902493e-12}, - {-3.20173937255409e-11, -1.29872402028088e-11, -4.24092901203818e-11, 2.66570185704416e-11, -5.25164954403909e-12}, - {0, 0, 0, 0, 0}, - {-1.36010179191872e-05, 1.77873053642413e-05, 4.80988546657119e-06, 3.46859608161212e-06, -1.73247520896541e-06}, - {2.00020483116258e-06, 2.43393064079673e-06, 1.21478843695862e-06, 1.95582820041644e-07, -3.11847995109088e-07}, - {-8.13287218979310e-09, 1.05206830238665e-08, 6.54040136224164e-09, -1.96402660575990e-08, -1.40379796070732e-08}, - {4.01291020310740e-08, 2.92634301047947e-08, 6.04179709273169e-09, 8.61849065020545e-10, 5.98065429697245e-09}, - {-1.06149335032911e-09, -4.39748495862323e-10, 8.83040310269353e-10, 3.49392227277679e-10, 8.57722299002622e-10}, - {-1.25049888909390e-11, 2.05203288281631e-10, 1.37817670505319e-11, 6.82057794430145e-11, -9.41515631694254e-11}, - {7.47196022644130e-12, -2.51369898528782e-11, -2.12196687809200e-11, 1.55282119505201e-11, 9.99224438231805e-12}, - {-7.90534019004874e-13, 3.55824506982589e-12, 8.00835777767281e-13, 8.73460019069655e-13, 1.34176126600106e-12}, - {0, 0, 0, 0, 0}, - {3.12855262465316e-05, 1.31629386003608e-05, 2.65598119437581e-06, 8.68923340949135e-06, -7.51164082949678e-06}, - {1.56870792650533e-06, 1.89227301685370e-06, 4.15620385341985e-07, -2.74253787880603e-07, -4.28826210119200e-07}, - {-9.99176994565587e-08, -1.10785129426286e-07, -1.10318125091182e-07, 6.22726507350764e-09, -3.39214566386250e-08}, - {1.24872975018433e-08, 1.10663206077249e-08, 5.40658975901469e-09, -2.79119137105115e-09, -2.47500096192502e-09}, - {1.11518917154060e-10, -4.21965763244849e-10, 3.26786005211229e-10, 1.93488254914545e-10, 7.00774679999972e-10}, - {1.50889220040757e-10, 1.03130002661366e-10, -3.09481760816903e-11, -4.47656630703759e-11, -7.36245021803800e-12}, - {-1.91144562110285e-12, -1.11355583995978e-11, -1.76207323352556e-11, 8.15289793192265e-12, 3.45078925412654e-12}, - {-2.73248710476019e-12, -1.65089342283056e-13, -2.20125355220819e-13, 5.32589191504356e-13, 5.70008982140874e-13}, - {8.06636928368811e-13, 1.30893069976672e-13, 9.72079137767479e-14, 3.87410156264322e-14, -5.56410013263563e-14}, - {0, 0, 0, 0, 0}, - {2.02454485403216e-05, -9.77720471118669e-06, -4.35467548126223e-06, 2.19599868869063e-06, -3.26670819043690e-06}, - {-3.21839256310540e-08, 8.38760368015005e-07, -5.08058835724060e-07, 4.16177282491396e-08, 1.53842592762120e-07}, - {-1.57377633165313e-07, -7.86803586842404e-08, -7.40444711426898e-08, 3.15259864117954e-08, 5.60536231567172e-09}, - {-3.26080428920229e-10, -3.14576780695439e-09, 8.46796096612981e-10, -2.59329379174262e-09, -8.01054756588382e-10}, - {-4.58725236153576e-11, -6.87847958546571e-11, 8.18226480126754e-12, 1.81082075625897e-10, 1.74510532938256e-10}, - {7.60233505328792e-11, 4.76463939581321e-11, -2.47198455442033e-11, -8.83439688929965e-12, 5.93967446277316e-13}, - {-8.92919292558887e-12, -4.38524572312029e-12, -4.02709146060896e-12, 4.84344426425295e-12, 5.12869042781520e-12}, - {1.91518361809952e-12, 3.06846255371817e-13, -2.44830265306345e-13, 7.86297493099244e-14, 2.72347805801980e-13}, - {9.09936624159538e-14, 7.20650818861447e-15, 2.45383991578283e-14, -4.79580974186462e-15, 3.64604724046944e-14}, - {-4.63611142770709e-14, 1.73908246420636e-15, -4.41651410674801e-15, -6.61409045306922e-16, -1.60016049099639e-15}, - {0, 0, 0, 0, 0}, - {6.17105245892845e-06, -1.04342983738457e-05, -1.72711741097994e-05, -8.16815967888426e-07, 3.42789959967593e-06}, - {-2.44014060833825e-07, 2.06991837444652e-07, -3.85805819475679e-07, 1.67162359832166e-08, 4.15139610402483e-07}, - {8.18199006804020e-08, -3.20013409049159e-08, 5.94000906771151e-08, 2.24122167188946e-08, -1.33796186160409e-08}, - {7.66269294674338e-11, -6.07862178874828e-10, 4.95795757186248e-10, -3.07589245481422e-10, 3.44456287710689e-10}, - {-1.84076250254929e-10, -1.30985312312781e-10, -1.52547325533276e-10, -2.51000125929512e-11, -1.93924012590455e-11}, - {-2.93307452197665e-11, 2.88627386757582e-11, 5.58812021182217e-12, -1.68692874069187e-13, 1.80464313900575e-12}, - {-9.59053874473003e-13, 6.04803122874761e-13, -9.80015608958536e-13, 1.70530372034214e-12, 1.70458664160775e-12}, - {2.80169588226043e-13, 9.09573148053551e-14, 2.16449186617004e-14, 1.15550091496353e-13, 4.97772796761321e-14}, - {-3.04524400761371e-14, 3.42845631349694e-14, 2.44230630602064e-14, 5.76017546103056e-16, -9.74409465961093e-15}, - {5.98765340844291e-15, -2.63942474859535e-15, -1.80204805804437e-15, -1.84981819321183e-16, -5.85073392163660e-16}, - {-2.37069441910133e-15, 2.87429226086856e-16, -1.67055963193389e-16, 2.72110684914090e-18, 8.46646962667892e-17}, - {0, 0, 0, 0, 0}, - {-2.71386164105722e-05, -1.41834938338454e-05, -2.00777928859929e-07, 5.94329804681196e-07, 8.61856994375586e-06}, - {-3.93656495458664e-08, -6.36432821807576e-07, -2.47887475106438e-07, -2.64906446204966e-08, 1.10689794197004e-07}, - {5.25319489188562e-08, 9.00866357158695e-09, 5.00693379572512e-08, 2.47269011056404e-08, -7.27648556194598e-09}, - {1.87207107149043e-09, -1.46428282396138e-09, -2.71812237167257e-10, 8.44902265891466e-10, -5.62683870906027e-10}, - {-1.08295119666184e-10, 4.75553388543793e-11, -5.49429386495686e-11, -6.60907871731611e-11, -5.97347322824822e-11}, - {-4.95118306815571e-12, 5.31083735234970e-13, -1.93679746327378e-12, -1.61770521840510e-12, 1.23276727202510e-11}, - {6.68582682909900e-13, 7.38288575160449e-13, 5.47630483499201e-13, -1.00770258118914e-13, -1.65564928475981e-13}, - {5.80963409268471e-14, 6.93474288078737e-14, 6.60728092794315e-15, -5.21029056725202e-15, -1.11283532854883e-16}, - {-4.10567742688903e-15, 1.62252646805882e-14, 1.00774699865989e-14, -2.44793214897877e-16, -1.59283906414563e-15}, - {1.84669506619904e-17, 8.28473337813919e-17, -1.53400662078899e-16, -5.01060672199689e-17, -2.20727935766132e-16}, - {2.65355116203636e-16, -3.70233146147684e-17, 3.52689394451586e-18, -8.62215942516328e-18, 9.26909361974526e-18}, - {9.94266950643135e-17, 4.17028699663441e-18, -7.65153491125819e-21, -5.62131270981041e-18, -3.03732817297438e-18} - }; - - /** Legendre functions bnm for coefficient cw.*/ - private static final double[][] CW_B = { - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {-0.000209104872912563, -1.41530274973540e-05, 3.00318745764815e-05, -1.82864291318284e-05, -7.62965409959238e-06}, - {0, 0, 0, 0, 0}, - {-0.000186336519900275, 0.000191256553935638, 7.28356195304996e-05, 3.59637869639906e-05, -2.53927226167388e-05}, - {0.000108195343799485, -6.97050977217619e-05, -6.68037133871099e-05, 2.30387653190503e-05, -1.22735483925784e-05}, - {0, 0, 0, 0, 0}, - {0.000119941091277039, -7.70547844186875e-05, -8.15376297964528e-05, 1.06005789545203e-05, 2.31177232268720e-05}, - {-1.77494760217164e-05, -1.37061385686605e-05, -1.74805936475816e-05, -6.91745900867532e-07, -7.10231790947787e-06}, - {-1.47564103733219e-05, 2.08890785485260e-06, 3.19876879447867e-06, 9.43984664503715e-07, -4.90480527577521e-06}, - {0, 0, 0, 0, 0}, - {4.93300138389457e-05, -6.77641298460617e-05, -3.25043347246397e-05, 8.33226714911921e-06, 8.11499972792905e-06}, - {-2.80449863471272e-05, -1.04367606414606e-05, 1.64473584641163e-07, -3.57420965807816e-06, 2.95887156564038e-06}, - {1.88835280111533e-06, 5.69125761193702e-07, -2.22757382799409e-06, -1.96699131032252e-07, -2.91861219283659e-07}, - {-4.69918971436680e-06, -7.00778948636735e-07, 2.97544157334673e-09, 3.86100512544410e-07, 2.30939653701027e-07}, - {0, 0, 0, 0, 0}, - {1.77050610394149e-05, -3.18353071311574e-05, 3.04232260950316e-05, -6.26821316488169e-05, -1.75094810002378e-06}, - {9.25605901565775e-06, -8.25179123302247e-06, 6.74032752408358e-06, 3.22192289084524e-06, 6.09414500075259e-06}, - {4.28233825242200e-06, 2.10470570087927e-07, -4.75050074985668e-07, -4.89382663470592e-07, 8.75232347469207e-07}, - {8.50393520366934e-07, 1.58764911467186e-07, -2.16267638321210e-07, -7.43341300487416e-10, 1.75131729813230e-07}, - {-2.87064111623119e-07, 4.50393893102830e-08, 6.63315044416690e-08, 7.61199387418853e-08, -6.05694385243652e-09}, - {0, 0, 0, 0, 0}, - {-1.95692079507947e-05, 5.15486098887851e-05, 3.00852761598173e-05, 1.21485028343416e-05, -6.72450521493428e-06}, - {5.34496867088158e-06, 3.90973451680699e-06, 3.70148924718425e-06, 5.73731499938212e-08, 5.52258220288780e-07}, - {3.39950838185315e-07, -5.63443976772634e-07, 4.52082211980595e-07, -2.57094645806243e-07, -6.84885762924729e-08}, - {2.15793276880684e-07, 2.05911354090873e-07, 1.33747872341142e-08, -2.07997626478952e-08, -3.69812938736019e-08}, - {2.11952749403224e-09, 4.04317822544732e-08, 2.40972024883650e-09, 8.56289126938059e-09, 2.31035283490200e-08}, - {-2.08402298813248e-09, -8.50243600879112e-09, 2.60895410117768e-09, -6.69156841738591e-10, -5.16280278087006e-09}, - {0, 0, 0, 0, 0}, - {0.000124901291436683, -5.70770326719086e-05, -8.44887248105015e-05, -3.11442665354698e-05, -1.12982893252046e-05}, - {-8.38934444233944e-06, 1.56860091415414e-06, -1.77704563531825e-06, -5.70219068898717e-08, -4.30377735031244e-06}, - {3.72965318017681e-07, 6.98175439446187e-07, 1.75760544807919e-08, 1.59731284857151e-07, 3.62363848767891e-07}, - {-2.32148850787091e-07, -4.21888751852973e-08, 8.35926113952108e-08, -2.24572480575674e-08, -6.92114100904503e-08}, - {-2.92635642210745e-09, 3.38086229163415e-09, 4.72186694662901e-09, -8.32354437305758e-11, 4.19673890995627e-09}, - {-1.26452887692900e-09, 1.91309690886864e-09, 1.54755631983655e-09, -1.09865169400249e-09, 1.83645326319994e-10}, - {9.92539437011905e-10, -2.96318203488300e-10, 1.17466020823486e-10, -5.00185957995526e-10, -8.54777591408537e-11}, - {0, 0, 0, 0, 0}, - {-0.000182885335404854, 7.27424724520089e-05, 3.05286278023427e-05, 2.55324463432562e-05, -6.39859510763234e-06}, - {-5.21449265232557e-06, -6.70572386081398e-06, -3.95473351292738e-06, -6.41023334372861e-07, -3.11616331059009e-06}, - {2.37090789071727e-07, 3.58427517014705e-07, 2.55709192777007e-07, 8.44593804408541e-08, 9.27243162355359e-09}, - {7.24370898432057e-08, -7.43945120337710e-09, 8.61751911975683e-10, -2.34651212610623e-08, 2.94052921681456e-09}, - {-1.22127317934425e-08, -3.89758984276768e-09, 4.12890383904924e-11, 2.06528068002723e-09, 1.73488696972270e-09}, - {-5.44137406907620e-10, -4.81034553189921e-10, -2.56101759039694e-11, 3.21880564410154e-10, -2.70195343165250e-11}, - {1.08394225300546e-10, -7.99525492688661e-11, 1.73850287030654e-10, -8.06390014426271e-11, -7.63143364291160e-13}, - {-3.41446959267441e-11, 2.72675729042792e-11, 5.69674704865345e-12, -3.38402998344892e-12, -2.96732381931007e-12}, - {0, 0, 0, 0, 0}, - {2.91161315987250e-05, -7.24641166590735e-05, -8.58323519857884e-06, -1.14037444255820e-05, 1.32244819451517e-05}, - {1.24266748259826e-06, -4.13127038469802e-06, -8.47496394492885e-07, 5.48722958754267e-07, -1.98288551821205e-06}, - {-1.70671245196917e-08, 1.36891127083540e-08, -2.80901972249870e-07, -5.45369793946222e-09, -9.58796303763498e-08}, - {1.14115335901746e-08, 2.79308166429178e-08, -1.71144803132413e-08, 4.86116243565380e-09, -8.13061459952280e-09}, - {-1.19144311035824e-09, -1.28197815211763e-09, -1.22313592972373e-09, 6.23116336753674e-10, 2.11527825898689e-09}, - {4.94618645030426e-10, -1.01554483531252e-10, -3.58808808952276e-10, 1.23499783028794e-10, -1.21017599361833e-10}, - {1.33959569836451e-10, -1.87140898812283e-11, -3.04265350158941e-11, -1.42907553051431e-11, -1.09873858099638e-11}, - {1.30277419203512e-11, -4.95312627777245e-12, 2.23070215544358e-12, 1.66450226016423e-12, 6.26222944728474e-12}, - {-4.40721204874728e-12, 2.99575133064885e-12, -1.54917262009097e-12, 8.90015664527060e-14, -1.59135267012937e-12}, - {0, 0, 0, 0, 0}, - {-4.17667211323160e-05, 1.39005215116294e-05, 1.46521361817829e-05, 3.23485458024416e-05, -8.57936261085263e-06}, - {9.48491026524450e-07, 1.67749735481991e-06, 6.80159475477603e-07, -1.34558044496631e-06, 1.62108231492249e-06}, - {-2.67545753355631e-07, -3.31848493018159e-08, 1.05837219557465e-07, 1.55587655479400e-07, -2.84996014386667e-08}, - {-5.15113778734878e-08, 8.83630725241303e-09, 3.36579455982772e-09, -6.22350102096402e-09, 5.03959133095369e-09}, - {2.04635880823035e-11, -1.07923589059151e-09, -6.96482137669712e-10, -4.70238500452793e-10, -6.60277903598297e-10}, - {-2.41897168749189e-11, 1.33547763615216e-10, -5.13534673658908e-11, -8.32767177662817e-11, 5.72614717082428e-11}, - {7.55170562359940e-12, -1.57123461699055e-11, -1.48874069619124e-11, -7.10529462981252e-13, -7.99006335025107e-12}, - {2.41883156738960e-12, 2.97346980183361e-12, 1.28719977731450e-12, -2.49240876894143e-12, 6.71155595793198e-13}, - {4.16995565336914e-13, -1.71584521275288e-13, -7.23064067359978e-14, 2.45405880599037e-13, 4.43532934905830e-13}, - {3.56937508828997e-14, 2.43012511260300e-14, -7.96090778289326e-14, -1.59548529636358e-14, 8.99103763000507e-15}, - {0, 0, 0, 0, 0}, - {0.000117579258399489, -4.52648448635772e-05, -2.69130037097862e-05, -3.82266335794366e-05, -4.36549257701084e-06}, - {-1.43270371215502e-06, 1.21565440183855e-06, 8.53701136074284e-07, 1.52709810023665e-06, 1.22382663462904e-06}, - {3.06089147519664e-07, 9.79084123751975e-08, 7.96524661441178e-08, 4.54770947973458e-08, 2.22842369458882e-07}, - {-9.94254707745127e-09, 1.43251376378012e-08, 1.93911753685160e-08, -6.52214645690987e-09, -1.97114016452408e-09}, - {-9.20751919828404e-10, -9.44312829629076e-10, 7.24196738163952e-11, -6.71801072324561e-11, 2.33146774065873e-10}, - {-1.43544298956410e-11, 1.78464235318769e-10, 7.69950023012326e-11, -4.22390057304453e-12, 3.05176324574816e-11}, - {-7.88053753973990e-12, -3.20207793051003e-12, 1.01527407317625e-12, 6.02788185858449e-12, 1.14919530900453e-11}, - {-1.21558899266069e-12, 5.31300597882986e-13, 3.44023865079264e-13, -6.22598216726224e-14, -5.47031650765402e-14}, - {-4.15627948750943e-13, 2.77620907292721e-13, -8.99784134364011e-14, 1.07254247320864e-13, 6.85990080564196e-14}, - {-3.91837863922901e-14, 9.74714976816180e-15, 6.79982450963903e-15, -2.41420876658572e-15, -2.20889384455344e-15}, - {9.25912068402776e-15, -4.02621719248224e-15, -2.43952036351187e-15, -1.97006876049866e-15, 1.03065621527869e-16}, - {0, 0, 0, 0, 0}, - {-0.000103762036940193, 4.38145356960292e-05, 2.43406920349913e-05, 7.89103527673736e-06, -1.66841465339160e-05}, - {-1.18428449371744e-06, -1.30188721737259e-06, -1.88013557116650e-06, -1.01342046295303e-06, 9.21813037802502e-07}, - {1.51836068712460e-07, 1.11362553803933e-07, 1.55375052233052e-07, 1.94450910788747e-09, -1.73093755828342e-08}, - {-3.77758211813121e-09, 1.23323969583610e-08, 1.72510045250302e-09, -1.88609789458597e-09, 1.28937597985937e-09}, - {-1.07947760393523e-09, 5.26051570105365e-10, -3.67657536332496e-11, 3.16110123523840e-10, -3.24273198242170e-10}, - {-2.00385649209820e-12, 2.54703869682390e-11, 4.08563622440851e-12, -4.83350348928636e-11, -3.98153443845079e-13}, - {2.73094467727215e-12, 5.08900664114903e-12, -7.66669089075134e-13, 2.50015592643012e-12, 4.29763262853853e-12}, - {6.53946487537890e-13, -2.24958413781008e-13, 6.74638861781238e-15, 3.28537647613903e-14, 2.54199700290116e-13}, - {-1.09122051193505e-13, 8.36362392931501e-14, -3.90750153912300e-14, -5.44915910741950e-14, 2.43816947219217e-14}, - {-1.41882561550134e-14, 1.00455397812713e-14, 2.63347255121581e-15, 1.53043256823601e-15, 2.49081021428095e-15}, - {-1.17256193152654e-15, 1.05648985031971e-16, 1.31778372453016e-16, 1.44815198666577e-16, -3.72532768618480e-16}, - {2.66203457773766e-16, -7.67224608659658e-17, 3.51487351031864e-18, 4.10287131339291e-17, -6.72171711728514e-17} - }; - - /** Build a new instance. */ - LegendreFunctions() { - - } - - /** Get the value of the anm coefficient for bh. - * @param n index - * @param m index - * @return the anm coefficient for bh - */ - public double getAnmBh(final int n, final int m) { - return BH_A[n][m]; - } - - /** Get the value of the anm coefficient for bw. - * @param n index - * @param m index - * @return the anm coefficient for bw - */ - public double getAnmBw(final int n, final int m) { - return BW_A[n][m]; - } - - /** Get the value of the anm coefficient for ch. - * @param n index - * @param m index - * @return the anm coefficient for ch - */ - public double getAnmCh(final int n, final int m) { - return CH_A[n][m]; - } - - /** Get the value of the anm coefficient for cw. - * @param n index - * @param m index - * @return the anm coefficient for cw - */ - public double getAnmCw(final int n, final int m) { - return CW_A[n][m]; - } - - /** Get the value of the bnm coefficient for bh. - * @param n index - * @param m index - * @return the bnm coefficient for bh - */ - public double getBnmBh(final int n, final int m) { - return BH_B[n][m]; - } - - /** Get the value of the bnm coefficient for bw. - * @param n index - * @param m index - * @return the bnm coefficient for bw - */ - public double getBnmBw(final int n, final int m) { - return BW_B[n][m]; - } - - /** Get the value of the bnm coefficient for ch. - * @param n index - * @param m index - * @return the bnm coefficient for ch - */ - public double getBnmCh(final int n, final int m) { - return CH_B[n][m]; - } - - /** Get the value of the bnm coefficient for cw. - * @param n index - * @param m index - * @return the bnm coefficient for cw - */ - public double getBnmCw(final int n, final int m) { - return CW_B[n][m]; - } - - } } diff --git a/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2.java b/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2.java index 91c3580905..30c6340705 100644 --- a/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2.java +++ b/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2.java @@ -41,7 +41,6 @@ import org.orekit.models.earth.troposphere.TroposphericModelUtils; import org.orekit.models.earth.troposphere.ViennaACoefficients; import org.orekit.models.earth.troposphere.ViennaAProvider; -import org.orekit.models.earth.troposphere.ViennaOneModel; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; import org.orekit.time.TimeScale; @@ -49,8 +48,8 @@ /** The Global Pressure and Temperature 2 (GPT2) model. * This model is an empirical model that provides the temperature, the pressure and the water vapor pressure - * of a site depending its latitude and longitude. This model also provides the ah - * and aw coefficients used for the {@link ViennaOneModel Vienna 1} model. + * of a site depending its latitude and longitude. This model also {@link ViennaACoefficients provides} + * the ah and aw coefficients for Vienna models. *

                * The requisite coefficients for the computation of the weather parameters are provided by the * Department of Geodesy and Geoinformation of the Vienna University. They are based on an diff --git a/src/test/java/org/orekit/models/earth/troposphere/ViennaOneModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/ViennaOneModelTest.java index c730e638ae..ecfdc6b180 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/ViennaOneModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/ViennaOneModelTest.java @@ -29,6 +29,7 @@ import org.orekit.time.TimeScalesFactory; import org.orekit.utils.TrackingCoordinates; +@Deprecated public class ViennaOneModelTest { private static double epsilon = 1e-6; diff --git a/src/test/java/org/orekit/models/earth/troposphere/ViennaOneTest.java b/src/test/java/org/orekit/models/earth/troposphere/ViennaOneTest.java new file mode 100644 index 0000000000..3b87916085 --- /dev/null +++ b/src/test/java/org/orekit/models/earth/troposphere/ViennaOneTest.java @@ -0,0 +1,131 @@ +/* Copyright 2002-2023 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import org.hipparchus.util.FastMath; +import org.hipparchus.util.Precision; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.orekit.Utils; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.errors.OrekitException; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.TimeScalesFactory; +import org.orekit.utils.TrackingCoordinates; + +public class ViennaOneTest { + + private static double epsilon = 1e-6; + + @BeforeAll + public static void setUpGlobal() { + Utils.setDataRoot("atmosphere"); + } + + @BeforeEach + public void setUp() throws OrekitException { + Utils.setDataRoot("regular-data:potential/shm-format"); + } + + @Test + public void testMappingFactors() { + + // Site (NRAO, Green Bank, WV): latitude: 38° + // longitude: 280° + // height: 824.17 m + // + // Date: MJD 55055 -> 12 August 2009 at 0h UT + // + // Ref for the inputs: Petit, G. and Luzum, B. (eds.), IERS Conventions (2010), + // IERS Technical Note No. 36, BKG (2010) + // + // Values: ah = 0.00127683 + // aw = 0.00060955 + // zhd = 2.0966 m + // zwd = 0.2140 m + // + // Values taken from: http://vmf.geo.tuwien.ac.at/trop_products/GRID/2.5x2/VMF1/VMF1_OP/2009/VMFG_20090812.H00 + // + // Expected mapping factors : hydrostatic -> 3.425088 + // wet -> 3.448300 + // + // Expected outputs are obtained by performing the Matlab script vmf1_ht.m provided by TU WIEN: + // http://vmf.geo.tuwien.ac.at/codes/ + // + + final AbsoluteDate date = AbsoluteDate.createMJDDate(55055, 0, TimeScalesFactory.getUTC()); + + final double latitude = FastMath.toRadians(38.0); + final double longitude = FastMath.toRadians(280.0); + final double height = 824.17; + final GeodeticPoint point = new GeodeticPoint(latitude, longitude, height); + + final TrackingCoordinates trackingCoordinates = new TrackingCoordinates(0.0, 0.5 * FastMath.PI - 1.278564131, 0.0); + final double expectedHydro = 3.425088; + final double expectedWet = 3.448300; + + final ViennaOne model = new ViennaOne(new ConstantViennaAProvider(new ViennaACoefficients(0.00127683, 0.00060955)), + new ConstantTroposphericModel(new TroposphericDelay(2.0966, 0.2140, 0, 0)), + TimeScalesFactory.getUTC()); + + final double[] computedMapping = model.mappingFactors(trackingCoordinates, point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + date); + + Assertions.assertEquals(expectedHydro, computedMapping[0], 4.1e-6); + Assertions.assertEquals(expectedWet, computedMapping[1], 1.0e-6); + } + + @Test + public void testDelay() { + final double elevation = 10d; + final double height = 100d; + final AbsoluteDate date = new AbsoluteDate(); + final GeodeticPoint point = new GeodeticPoint(FastMath.toRadians(45.0), FastMath.toRadians(45.0), height); + ViennaOne model = new ViennaOne(new ConstantViennaAProvider(new ViennaACoefficients(0.00127683, 0.00060955)), + new ConstantTroposphericModel(new TroposphericDelay(2.0966, 0.2140, 0, 0)), + TimeScalesFactory.getUTC()); + final double path = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elevation), 0.0), + point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(date), date).getDelay(); + Assertions.assertTrue(Precision.compareTo(path, 20d, epsilon) < 0); + Assertions.assertTrue(Precision.compareTo(path, 0d, epsilon) > 0); + } + + @Test + public void testFixedHeight() { + final AbsoluteDate date = new AbsoluteDate(); + final GeodeticPoint point = new GeodeticPoint(FastMath.toRadians(45.0), FastMath.toRadians(45.0), 350.0); + ViennaOne model = new ViennaOne(new ConstantViennaAProvider(new ViennaACoefficients(0.00127683, 0.00060955)), + new ConstantTroposphericModel(new TroposphericDelay(2.0966, 0.2140, 0, 0)), + TimeScalesFactory.getUTC()); + double lastDelay = Double.MAX_VALUE; + // delay shall decline with increasing elevation angle + for (double elev = 10d; elev < 90d; elev += 8d) { + final double delay = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elev), 0.0), + point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(date), date).getDelay(); + Assertions.assertTrue(Precision.compareTo(delay, lastDelay, epsilon) < 0); + lastDelay = delay; + } + } + +} diff --git a/src/test/java/org/orekit/models/earth/troposphere/ViennaThreeModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/ViennaThreeModelTest.java index 44a10b9f39..677849acc4 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/ViennaThreeModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/ViennaThreeModelTest.java @@ -29,6 +29,7 @@ import org.orekit.time.TimeScalesFactory; import org.orekit.utils.TrackingCoordinates; +@Deprecated public class ViennaThreeModelTest { private static double epsilon = 1e-6; diff --git a/src/test/java/org/orekit/models/earth/troposphere/ViennaThreeTest.java b/src/test/java/org/orekit/models/earth/troposphere/ViennaThreeTest.java new file mode 100644 index 0000000000..4779c3818c --- /dev/null +++ b/src/test/java/org/orekit/models/earth/troposphere/ViennaThreeTest.java @@ -0,0 +1,223 @@ +/* Copyright 2002-2023 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import org.hipparchus.util.FastMath; +import org.hipparchus.util.Precision; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.orekit.Utils; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.errors.OrekitException; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.TimeScalesFactory; +import org.orekit.utils.TrackingCoordinates; + +public class ViennaThreeTest { + + private static double epsilon = 1e-6; + + @BeforeAll + public static void setUpGlobal() { + Utils.setDataRoot("atmosphere"); + } + + @BeforeEach + public void setUp() throws OrekitException { + Utils.setDataRoot("regular-data:potential/shm-format"); + } + + @Test + public void testMappingFactors() { + + // Site: latitude: 37.5° + // longitude: 277.5° + // height: 824 m + // + // Date: 25 November 2018 at 0h UT + // + // Values: ah = 0.00123462 + // aw = 0.00047101 + // zhd = 2.1993 m + // zwd = 0.0690 m + // + // Values taken from: http://vmf.geo.tuwien.ac.at/trop_products/GRID/5x5/VMF3/VMF3_OP/2018/VMF3_20181125.H00 + // + // Expected mapping factors : hydrostatic -> 1.621024 + // wet -> 1.623023 + // + // Expected outputs are obtained by performing the Matlab script vmf3.m provided by TU WIEN: + // http://vmf.geo.tuwien.ac.at/codes/ + // + + final AbsoluteDate date = new AbsoluteDate(2018, 11, 25, TimeScalesFactory.getUTC()); + + final double latitude = FastMath.toRadians(37.5); + final double longitude = FastMath.toRadians(277.5); + final double height = 824.0; + final GeodeticPoint point = new GeodeticPoint(latitude, longitude, height); + + final TrackingCoordinates trackingCoordinates = new TrackingCoordinates(0.0, FastMath.toRadians(38.0), 0.0); + final double expectedHydro = 1.621024; + final double expectedWet = 1.623023; + + final ViennaThree model = new ViennaThree(new ConstantViennaAProvider(new ViennaACoefficients(0.00123462, 0.00047101)), + new ConstantTroposphericModel(new TroposphericDelay(2.1993, 0.0690, 0, 0)), + TimeScalesFactory.getUTC()); + + final double[] computedMapping = model.mappingFactors(trackingCoordinates, point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + date); + + Assertions.assertEquals(expectedHydro, computedMapping[0], epsilon); + Assertions.assertEquals(expectedWet, computedMapping[1], epsilon); + } + + @Test + public void testLowElevation() { + + // Site: latitude: 37.5° + // longitude: 277.5° + // height: 824 m + // + // Date: 25 November 2018 at 0h UT + // + // Values: ah = 0.00123462 + // aw = 0.00047101 + // zhd = 2.1993 m + // zwd = 0.0690 m + // + // Values taken from: http://vmf.geo.tuwien.ac.at/trop_products/GRID/5x5/VMF3/VMF3_OP/2018/VMF3_20181125.H00 + // + // Expected mapping factors : hydrostatic -> 10.132802 + // wet -> 10.879154 + // + // Expected outputs are obtained by performing the Matlab script vmf3.m provided by TU WIEN: + // http://vmf.geo.tuwien.ac.at/codes/ + // + + final AbsoluteDate date = new AbsoluteDate(2018, 11, 25, TimeScalesFactory.getUTC()); + + final double latitude = FastMath.toRadians(37.5); + final double longitude = FastMath.toRadians(277.5); + final double height = 824.0; + final GeodeticPoint point = new GeodeticPoint(latitude, longitude, height); + + final TrackingCoordinates trackingCoordinates = new TrackingCoordinates(0.0, FastMath.toRadians(5.0), 0.0); + final double expectedHydro = 10.132802; + final double expectedWet = 10.879154; + + final ViennaThree model = new ViennaThree(new ConstantViennaAProvider(new ViennaACoefficients(0.00123462, 0.00047101)), + new ConstantTroposphericModel(new TroposphericDelay(2.1993, 0.0690, 0, 0)), + TimeScalesFactory.getUTC()); + + final double[] computedMapping = model.mappingFactors(trackingCoordinates, point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + date); + + Assertions.assertEquals(expectedHydro, computedMapping[0], epsilon); + Assertions.assertEquals(expectedWet, computedMapping[1], epsilon); + } + + @Test + public void testHightElevation() { + + // Site: latitude: 37.5° + // longitude: 277.5° + // height: 824 m + // + // Date: 25 November 2018 at 0h UT + // + // Values: ah = 0.00123462 + // aw = 0.00047101 + // zhd = 2.1993 m + // zwd = 0.0690 m + // + // Values taken from: http://vmf.geo.tuwien.ac.at/trop_products/GRID/5x5/VMF3/VMF3_OP/2018/VMF3_20181125.H00 + // + // Expected mapping factors : hydrostatic -> 1.003810 + // wet -> 1.003816 + // + // Expected outputs are obtained by performing the Matlab script vmf3.m provided by TU WIEN: + // http://vmf.geo.tuwien.ac.at/codes/ + // + + final AbsoluteDate date = new AbsoluteDate(2018, 11, 25, TimeScalesFactory.getUTC()); + + final double latitude = FastMath.toRadians(37.5); + final double longitude = FastMath.toRadians(277.5); + final double height = 824.0; + final GeodeticPoint point = new GeodeticPoint(latitude, longitude, height); + + final TrackingCoordinates trackingCoordinates = new TrackingCoordinates(0.0, FastMath.toRadians(85.0), 0.0); + final double expectedHydro = 1.003810; + final double expectedWet = 1.003816; + + final ViennaThree model = new ViennaThree(new ConstantViennaAProvider(new ViennaACoefficients(0.00123462, 0.00047101)), + new ConstantTroposphericModel(new TroposphericDelay(2.1993, 0.0690, 0, 0)), + TimeScalesFactory.getUTC()); + + final double[] computedMapping = model.mappingFactors(trackingCoordinates, point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + date); + + Assertions.assertEquals(expectedHydro, computedMapping[0], epsilon); + Assertions.assertEquals(expectedWet, computedMapping[1], epsilon); + } + + @Test + public void testDelay() { + final double elevation = 10d; + final double height = 100d; + final AbsoluteDate date = new AbsoluteDate(); + final GeodeticPoint point = new GeodeticPoint(FastMath.toRadians(37.5), FastMath.toRadians(277.5), height); + ViennaThree model = new ViennaThree(new ConstantViennaAProvider(new ViennaACoefficients(0.00123462, 0.00047101)), + new ConstantTroposphericModel(new TroposphericDelay(2.1993, 0.0690, 0, 0)), + TimeScalesFactory.getUTC()); + final TroposphericDelay delay = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elevation), 0.0), + point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(date), date); + Assertions.assertEquals( 2.1993, delay.getZh(), 1.0e-4); + Assertions.assertEquals( 0.069, delay.getZw(), 1.0e-4); + Assertions.assertEquals(12.2124, delay.getSh(), 1.0e-4); + Assertions.assertEquals( 0.3916, delay.getSw(), 1.0e-4); + Assertions.assertEquals(12.6041, delay.getDelay(), 1.0e-4); + } + + @Test + public void testFixedHeight() { + final AbsoluteDate date = new AbsoluteDate(); + final GeodeticPoint point = new GeodeticPoint(FastMath.toRadians(37.5), FastMath.toRadians(277.5), 350.0); + ViennaThree model = new ViennaThree(new ConstantViennaAProvider(new ViennaACoefficients(0.00123462, 0.00047101)), + new ConstantTroposphericModel(new TroposphericDelay(2.1993, 0.0690, 0, 0)), + TimeScalesFactory.getUTC()); + double lastDelay = Double.MAX_VALUE; + // delay shall decline with increasing elevation angle + for (double elev = 10d; elev < 90d; elev += 8d) { + final double delay = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elev), 0.0), + point, + TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(date), date).getDelay(); + Assertions.assertTrue(Precision.compareTo(delay, lastDelay, epsilon) < 0); + lastDelay = delay; + } + } + +} From d3c27a7b6485c16c4632f22670a97190cc941741 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Thu, 21 Dec 2023 17:06:27 +0100 Subject: [PATCH 058/359] Added DummyMappingFunction. --- .../troposphere/DummyMappingFunction.java | 69 +++++++++++++++++++ .../AbstractMappingFunctionTest.java | 2 +- .../troposphere/DummyMappingFunctionTest.java | 37 ++++++++++ 3 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/orekit/models/earth/troposphere/DummyMappingFunction.java create mode 100644 src/test/java/org/orekit/models/earth/troposphere/DummyMappingFunctionTest.java diff --git a/src/main/java/org/orekit/models/earth/troposphere/DummyMappingFunction.java b/src/main/java/org/orekit/models/earth/troposphere/DummyMappingFunction.java new file mode 100644 index 0000000000..e840389ba7 --- /dev/null +++ b/src/main/java/org/orekit/models/earth/troposphere/DummyMappingFunction.java @@ -0,0 +1,69 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import org.hipparchus.CalculusFieldElement; +import org.hipparchus.util.MathArrays; +import org.orekit.bodies.FieldGeodeticPoint; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; +import org.orekit.models.earth.weather.PressureTemperatureHumidity; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; +import org.orekit.utils.FieldTrackingCoordinates; +import org.orekit.utils.TrackingCoordinates; + +/** Dummy mapping function. + *

                + * This mapping function just uses 1.0 as constant mapping factors, which + * implies the slanted tropospheric delays are equal to the zenith delays. + * This is mainly useful when only zenith delays are needed. + *

                + * @author Luc Maisonobe + * @since 12.1 + */ +public class DummyMappingFunction implements TroposphereMappingFunction { + + /** Builds a new instance. + */ + protected DummyMappingFunction() { + // nothing to do + } + + /** {@inheritDoc} */ + @Override + public double[] mappingFactors(final TrackingCoordinates trackingCoordinates, final GeodeticPoint point, + final PressureTemperatureHumidity weather, + final AbsoluteDate date) { + return new double[] { + 1.0, 1.0 + }; + } + + /** {@inheritDoc} */ + @Override + public > T[] mappingFactors(final FieldTrackingCoordinates trackingCoordinates, + final FieldGeodeticPoint point, + final FieldPressureTemperatureHumidity weather, + final FieldAbsoluteDate date) { + final T[] mapping = MathArrays.buildArray(date.getField(), 2); + mapping[0] = date.getField().getOne(); + mapping[1] = date.getField().getOne(); + return mapping; + } + +} diff --git a/src/test/java/org/orekit/models/earth/troposphere/AbstractMappingFunctionTest.java b/src/test/java/org/orekit/models/earth/troposphere/AbstractMappingFunctionTest.java index a0749d366d..cf82177716 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/AbstractMappingFunctionTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/AbstractMappingFunctionTest.java @@ -61,7 +61,7 @@ protected void doTestMappingFactors(final double expectedHydro, } @Test - public void doTestFixedHeight() { + public void testFixedHeight() { final AbsoluteDate date = new AbsoluteDate(); final GeodeticPoint point = new GeodeticPoint(FastMath.toRadians(45.0), FastMath.toRadians(45.0), 350.0); TroposphereMappingFunction model = buildMappingFunction(); diff --git a/src/test/java/org/orekit/models/earth/troposphere/DummyMappingFunctionTest.java b/src/test/java/org/orekit/models/earth/troposphere/DummyMappingFunctionTest.java new file mode 100644 index 0000000000..30b25250c0 --- /dev/null +++ b/src/test/java/org/orekit/models/earth/troposphere/DummyMappingFunctionTest.java @@ -0,0 +1,37 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import org.junit.jupiter.api.Test; + +public class DummyMappingFunctionTest extends AbstractMappingFunctionTest { + + protected TroposphereMappingFunction buildMappingFunction() { + return new DummyMappingFunction(); + } + + @Test + public void testMappingFactors() { + doTestMappingFactors(1.0, 1.0); + } + + @Test + public void testFixedHeight() { + // this function does *not* decrease with elevation + // so we disable this test + } +} From 12048b25af4a26f7d771a6c3518891f7447c4359 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Thu, 21 Dec 2023 18:12:56 +0100 Subject: [PATCH 059/359] Fixed wrong humidity in standard atmosphere. --- .../troposphere/TroposphericModelUtils.java | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/orekit/models/earth/troposphere/TroposphericModelUtils.java b/src/main/java/org/orekit/models/earth/troposphere/TroposphericModelUtils.java index 2e6b2efce3..23381614f7 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/TroposphericModelUtils.java +++ b/src/main/java/org/orekit/models/earth/troposphere/TroposphericModelUtils.java @@ -22,6 +22,7 @@ import org.orekit.models.earth.weather.ConstantPressureTemperatureHumidityProvider; import org.orekit.models.earth.weather.PressureTemperatureHumidity; import org.orekit.models.earth.weather.PressureTemperatureHumidityProvider; +import org.orekit.models.earth.weather.water.CIPM2007; import org.orekit.utils.units.Unit; /** @@ -56,14 +57,24 @@ public class TroposphericModelUtils { * @see #STANDARD_ATMOSPHERE_PROVIDER * @since 12.1 */ - public static final PressureTemperatureHumidity STANDARD_ATMOSPHERE = - new PressureTemperatureHumidity(0.0, HECTO_PASCAL.toSI(1013.25), 273.15 + 20, 0.5); + public static final PressureTemperatureHumidity STANDARD_ATMOSPHERE; /** Provider for {@link #STANDARD_ATMOSPHERE standard atmosphere}. * @since 12.1 */ - public static final PressureTemperatureHumidityProvider STANDARD_ATMOSPHERE_PROVIDER = - new ConstantPressureTemperatureHumidityProvider(STANDARD_ATMOSPHERE); + public static final PressureTemperatureHumidityProvider STANDARD_ATMOSPHERE_PROVIDER; + + static { + final double h = 0.0; + final double p = HECTO_PASCAL.toSI(1013.25); + final double t = 273.15 + 20; + final double rh = 0.5; + STANDARD_ATMOSPHERE = new PressureTemperatureHumidity(h, p, t, + new CIPM2007().waterVaporPressure(p, t, rh), + Double.NaN, Double.NaN); + STANDARD_ATMOSPHERE_PROVIDER = + new ConstantPressureTemperatureHumidityProvider(STANDARD_ATMOSPHERE); + } /** * Private constructor as class is a utility. From 5cfc68cd9f37e9ff1fbb653253f0887048c4c063 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Thu, 21 Dec 2023 18:15:36 +0100 Subject: [PATCH 060/359] Removed spurious PTH provider in some tropospheric models. --- .../CanonicalSaastamoinenModel.java | 54 +---- .../earth/troposphere/MariniMurray.java | 170 +++++++++++++++ .../earth/troposphere/MariniMurrayModel.java | 202 ++---------------- .../CanonicalSaastamoinenModelTest.java | 6 +- .../troposphere/MariniMurrayModelTest.java | 13 +- .../earth/troposphere/MariniMurrayTest.java | 168 +++++++++++++++ 6 files changed, 376 insertions(+), 237 deletions(-) create mode 100644 src/main/java/org/orekit/models/earth/troposphere/MariniMurray.java create mode 100644 src/test/java/org/orekit/models/earth/troposphere/MariniMurrayTest.java diff --git a/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java b/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java index cc5aff9a74..1e97fb1762 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java @@ -26,13 +26,9 @@ import org.hipparchus.util.FastMath; import org.orekit.bodies.FieldGeodeticPoint; import org.orekit.bodies.GeodeticPoint; -import org.orekit.models.earth.weather.ConstantPressureTemperatureHumidityProvider; import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; import org.orekit.models.earth.weather.HeightDependentPressureTemperatureHumidityConverter; import org.orekit.models.earth.weather.PressureTemperatureHumidity; -import org.orekit.models.earth.weather.PressureTemperatureHumidityProvider; -import org.orekit.models.earth.weather.water.NbsNrcSteamTable; -import org.orekit.models.earth.weather.water.WaterVaporPressureProvider; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; import org.orekit.utils.FieldTrackingCoordinates; @@ -90,9 +86,6 @@ public class CanonicalSaastamoinenModel implements TroposphericModel { /** Interpolation function for the B correction term. */ private static final PolynomialSplineFunction B_FUNCTION; - /** Provider for pressure, temperature and humidity. */ - private final PressureTemperatureHumidityProvider pthProvider; - static { B_FUNCTION = new LinearInterpolator().interpolate(X_VALUES_FOR_B, Y_VALUES_FOR_B); } @@ -104,43 +97,12 @@ public class CanonicalSaastamoinenModel implements TroposphericModel { * Create a new Saastamoinen model for the troposphere using the given environmental * conditions and table from the reference book. * - * @param pthProvider provider for pressure, temperature and humidity * @see HeightDependentPressureTemperatureHumidityConverter */ - public CanonicalSaastamoinenModel(final PressureTemperatureHumidityProvider pthProvider) { - this.pthProvider = pthProvider; + public CanonicalSaastamoinenModel() { this.lowElevationThreshold = DEFAULT_LOW_ELEVATION_THRESHOLD; } - /** Create a new Saastamoinen model using a standard atmosphere model. - * - *
                  - *
                • temperature: 18 degree Celsius - *
                • pressure: 1013.25 mbar - *
                • humidity: 50% - *
                - * - * @return a Saastamoinen model with standard environmental values - */ - public static CanonicalSaastamoinenModel getStandardModel() { - - // build standard meteorological data - final double altitude = 0.0; - final double pressure = TroposphericModelUtils.HECTO_PASCAL.toSI(1013.25); - final double temperature = 273.15 + 18; - final double relativeHumidity = 0.5; - final WaterVaporPressureProvider waterPressureProvider = new NbsNrcSteamTable(); - final double waterVaporPressure = waterPressureProvider.waterVaporPressure(pressure, - temperature, - relativeHumidity); - final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(altitude, - pressure, - temperature, - waterVaporPressure); - return new CanonicalSaastamoinenModel(new ConstantPressureTemperatureHumidityProvider(pth)); - - } - /** {@inheritDoc} *

                * The Saastamoinen model is not defined for altitudes below 0.0. for continuity @@ -159,8 +121,6 @@ public TroposphericDelay pathDelay(final TrackingCoordinates trackingCoordinates final PressureTemperatureHumidity weather, final double[] parameters, final AbsoluteDate date) { - final PressureTemperatureHumidity pth = pthProvider.getWeatherParamerers(point, date); - // there are no data in the model for negative altitudes and altitude bigger than 6000 m // limit the height to a range of [0, 5000] m final double fixedHeight = FastMath.min(FastMath.max(point.getAltitude(), X_VALUES_FOR_B[0]), @@ -176,8 +136,8 @@ public TroposphericDelay pathDelay(final TrackingCoordinates trackingCoordinates // calculate the path delay final double invCos = 1.0 / FastMath.cos(z); final double tan = FastMath.tan(z); - final double zh = L0 * pth.getPressure(); - final double zw = L0 * (T_NUM / pth.getTemperature() + WET_OFFSET) * pth.getWaterVaporPressure(); + final double zh = L0 * weather.getPressure(); + final double zw = L0 * (T_NUM / weather.getTemperature() + WET_OFFSET) * weather.getWaterVaporPressure(); final double sh = zh * invCos; final double sw = (zw - L0 * B * tan * tan) * invCos; return new TroposphericDelay(zh, zw, sh, sw); @@ -206,8 +166,6 @@ public > FieldTroposphericDelay pathDelay(f final Field field = date.getField(); final T zero = field.getZero(); - final FieldPressureTemperatureHumidity pth = pthProvider.getWeatherParamerers(point, date); - // there are no data in the model for negative altitudes and altitude bigger than 5000 m // limit the height to a range of [0, 5000] m final T fixedHeight = FastMath.min(FastMath.max(point.getAltitude(), X_VALUES_FOR_B[0]), @@ -223,9 +181,9 @@ public > FieldTroposphericDelay pathDelay(f // calculate the path delay in m final T invCos = FastMath.cos(z).reciprocal(); final T tan = FastMath.tan(z); - final T zh = pth.getPressure().multiply(L0); - final T zw = pth.getTemperature().reciprocal().multiply(T_NUM).add(WET_OFFSET). - multiply(pth.getWaterVaporPressure()).multiply(L0); + final T zh = weather.getPressure().multiply(L0); + final T zw = weather.getTemperature().reciprocal().multiply(T_NUM).add(WET_OFFSET). + multiply(weather.getWaterVaporPressure()).multiply(L0); final T sh = zh.multiply(invCos); final T sw = zw.subtract(B.multiply(tan).multiply(tan).multiply(L0)).multiply(invCos); return new FieldTroposphericDelay<>(zh, zw, sh, sw); diff --git a/src/main/java/org/orekit/models/earth/troposphere/MariniMurray.java b/src/main/java/org/orekit/models/earth/troposphere/MariniMurray.java new file mode 100644 index 0000000000..ce08784364 --- /dev/null +++ b/src/main/java/org/orekit/models/earth/troposphere/MariniMurray.java @@ -0,0 +1,170 @@ +/* Copyright 2011-2012 Space Applications Services + * Licensed to CS Communication & Systèmes (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import java.util.Collections; +import java.util.List; + +import org.hipparchus.CalculusFieldElement; +import org.hipparchus.util.FastMath; +import org.orekit.bodies.FieldGeodeticPoint; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; +import org.orekit.models.earth.weather.PressureTemperatureHumidity; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; +import org.orekit.utils.FieldTrackingCoordinates; +import org.orekit.utils.ParameterDriver; +import org.orekit.utils.TrackingCoordinates; +import org.orekit.utils.units.Unit; +import org.orekit.utils.units.UnitsConverter; + +/** The Marini-Murray tropospheric delay model for laser ranging. + * + * @see "Marini, J.W., and C.W. Murray, correction of Laser Range Tracking Data for + * Atmospheric Refraction at Elevations Above 10 degrees, X-591-73-351, NASA GSFC, 1973" + * + * @author Joris Olympio + * @author Luc Maisonobe + * @since 12.1 + */ +public class MariniMurray implements TroposphericModel { + + /** Laser frequency parameter. */ + private double fLambda; + + /** Create a new Marini-Murray model for the troposphere. + * @param lambda laser wavelength + * @param lambdaUnits units in which {@code lambda} is given + * @see TropoUnit + * @since 12.1 + * */ + public MariniMurray(final double lambda, final Unit lambdaUnits) { + + // compute laser frequency parameter + final double lambdaMicrometer = new UnitsConverter(lambdaUnits, TroposphericModelUtils.MICRO_M).convert(lambda); + final double l2 = lambdaMicrometer * lambdaMicrometer; + fLambda = 0.9650 + (0.0164 + 0.000228 / l2) / l2; + + } + + /** {@inheritDoc} */ + @Override + public TroposphericDelay pathDelay(final TrackingCoordinates trackingCoordinates, final GeodeticPoint point, + final PressureTemperatureHumidity weather, + final double[] parameters, final AbsoluteDate date) { + + final double p = weather.getPressure(); + final double t = weather.getTemperature(); + final double e = weather.getWaterVaporPressure(); + + // beware since version 12.1 pressures are in Pa and not in hPa, hence the scaling has changed + final double Ah = 0.00002357 * p; + final double Aw = 0.00000141 * e; + final double K = 1.163 - 0.00968 * FastMath.cos(2 * point.getLatitude()) - 0.00104 * t + 0.0000001435 * p; + final double B = 1.084e-10 * p * t * K + 4.734e-12 * p * (p / t) * (2 * K) / (3 * K - 1); + final double flambda = getLaserFrequencyParameter(); + + final double fsite = getSiteFunctionValue(point); + + final double sinE = FastMath.sin(trackingCoordinates.getElevation()); + final double totalZenith = (flambda / fsite) * (Ah + Aw + B) / (1.0 + B / ((Ah + Aw + B) * (1.0 + 0.01))); + final double totalElev = (flambda / fsite) * (Ah + Aw + B) / (sinE + B / ((Ah + Aw + B) * (sinE + 0.01))); + final double hydrostaticZenith = (flambda / fsite) * (Ah + B) / (1.0 + B / ((Ah + B) * (1.0 + 0.01))); + final double hydrostaticElev = (flambda / fsite) * (Ah + B) / (sinE + B / ((Ah + B) * (sinE + 0.01))); + return new TroposphericDelay(hydrostaticZenith, totalZenith - hydrostaticZenith, + hydrostaticElev, totalElev - hydrostaticElev); + } + + /** {@inheritDoc} */ + @Override + public > FieldTroposphericDelay pathDelay(final FieldTrackingCoordinates trackingCoordinates, + final FieldGeodeticPoint point, + final FieldPressureTemperatureHumidity weather, + final T[] parameters, final FieldAbsoluteDate date) { + + final T p = weather.getPressure(); + final T t = weather.getTemperature(); + final T e = weather.getWaterVaporPressure(); + + // beware since version 12.1 pressures are in Pa and not in hPa, hence the scaling has changed + final T Ah = p.multiply(0.00002357); + final T Aw = e.multiply(0.00000141); + final T K = FastMath.cos(point.getLatitude().multiply(2.)).multiply(0.00968).negate(). + add(1.163). + subtract(t.multiply(0.00104)). + add(p.multiply(0.0000001435)); + final T B = K.multiply(t.multiply(p).multiply(1.084e-10 )). + add(K.multiply(2.).multiply(p.multiply(p).divide(t).multiply(4.734e-12)).divide(K.multiply(3.).subtract(1.))); + final double flambda = getLaserFrequencyParameter(); + + final T fsite = getSiteFunctionValue(point); + + final T sinE = FastMath.sin(trackingCoordinates.getElevation()); + final T one = date.getField().getOne(); + final T totalZenith = fsite.divide(flambda).reciprocal(). + multiply(B.add(Ah).add(Aw)). + divide(one.add(one.add(0.01).multiply(B.add(Ah).add(Aw)).divide(B).reciprocal())); + final T totalElev = fsite.divide(flambda).reciprocal(). + multiply(B.add(Ah).add(Aw)). + divide(sinE.add(sinE.add(0.01).multiply(B.add(Ah).add(Aw)).divide(B).reciprocal())); + final T hydrostaticZenith = fsite.divide(flambda).reciprocal(). + multiply(B.add(Ah)). + divide(one.add(one.add(0.01).multiply(B.add(Ah)).divide(B).reciprocal())); + final T hydrostaticElev = fsite.divide(flambda).reciprocal(). + multiply(B.add(Ah)). + divide(sinE.add(sinE.add(0.01).multiply(B.add(Ah)).divide(B).reciprocal())); + return new FieldTroposphericDelay<>(hydrostaticZenith, totalZenith.subtract(hydrostaticZenith), + hydrostaticElev, totalElev.subtract(hydrostaticElev)); + } + + /** {@inheritDoc} */ + @Override + public List getParametersDrivers() { + return Collections.emptyList(); + } + + /** Get the laser frequency parameter f(lambda). + * It is one for Ruby laser (lambda = 0.6943 micron) + * For infrared lasers, f(lambda) = 0.97966. + * + * @return the laser frequency parameter f(lambda). + */ + private double getLaserFrequencyParameter() { + return fLambda; + } + + /** Get the site parameter. + * + * @param point station location + * @return the site parameter. + */ + private double getSiteFunctionValue(final GeodeticPoint point) { + return 1. - 0.0026 * FastMath.cos(2 * point.getLatitude()) - 0.00031 * 0.001 * point.getAltitude(); + } + + /** Get the site parameter. + * + * @param type of the elements + * @param point station location + * @return the site parameter. + */ + private > T getSiteFunctionValue(final FieldGeodeticPoint point) { + return FastMath.cos(point.getLatitude().multiply(2)).multiply(0.0026).add(point.getAltitude().multiply(0.001).multiply(0.00031)).negate().add(1.); + } + +} diff --git a/src/main/java/org/orekit/models/earth/troposphere/MariniMurrayModel.java b/src/main/java/org/orekit/models/earth/troposphere/MariniMurrayModel.java index 99ee5af618..afd1e616d5 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/MariniMurrayModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/MariniMurrayModel.java @@ -16,25 +16,17 @@ */ package org.orekit.models.earth.troposphere; -import java.util.Collections; -import java.util.List; - import org.hipparchus.CalculusFieldElement; -import org.hipparchus.util.FastMath; import org.orekit.bodies.FieldGeodeticPoint; import org.orekit.bodies.GeodeticPoint; -import org.orekit.models.earth.weather.ConstantPressureTemperatureHumidityProvider; import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; import org.orekit.models.earth.weather.PressureTemperatureHumidity; -import org.orekit.models.earth.weather.PressureTemperatureHumidityProvider; import org.orekit.models.earth.weather.water.CIPM2007; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; import org.orekit.utils.FieldTrackingCoordinates; -import org.orekit.utils.ParameterDriver; import org.orekit.utils.TrackingCoordinates; import org.orekit.utils.units.Unit; -import org.orekit.utils.units.UnitsConverter; /** The Marini-Murray tropospheric delay model for laser ranging. * @@ -42,15 +34,17 @@ * Atmospheric Refraction at Elevations Above 10 degrees, X-591-73-351, NASA GSFC, 1973" * * @author Joris Olympio + * @deprecated as of 12.1, replaced by {@link MariniMurray} */ -@SuppressWarnings("deprecation") -public class MariniMurrayModel implements DiscreteTroposphericModel, TroposphericModel { - - /** Provider for pressure, temperature and humidity. */ - private PressureTemperatureHumidityProvider pthProvider; +@Deprecated +public class MariniMurrayModel extends MariniMurray implements DiscreteTroposphericModel { - /** Laser frequency parameter. */ - private double fLambda; + /** Constant pressure, temperature and humidity. + * @deprecated as of 12.1 provided when calling {@link #pathDelay(TrackingCoordinates, + * GeodeticPoint, PressureTemperatureHumidity, double[], AbsoluteDate)} + */ + @Deprecated + private PressureTemperatureHumidity pth; /** Create a new Marini-Murray model for the troposphere using the given * environmental conditions. @@ -58,40 +52,18 @@ public class MariniMurrayModel implements DiscreteTroposphericModel, Tropospheri * @param p0 the atmospheric pressure at the station, mbar * @param rh the humidity at the station, as a ratio (50% → 0.5) * @param lambda laser wavelength (c/f), nm - * @deprecated as of 12.1, replaced by {@link #MariniMurrayModel(PressureTemperatureHumidityProvider, double, Unit)} */ - @Deprecated public MariniMurrayModel(final double t0, final double p0, final double rh, final double lambda) { - this(new ConstantPressureTemperatureHumidityProvider(new PressureTemperatureHumidity(0, - TroposphericModelUtils.HECTO_PASCAL.toSI(p0), - t0, - new CIPM2007(). - waterVaporPressure(TroposphericModelUtils.HECTO_PASCAL.toSI(p0), - t0, - rh))), - lambda, TroposphericModelUtils.NANO_M); - } - - /** Create a new Marini-Murray model for the troposphere. - *

                - * BEWARE: this constructor uses - *

                - * @param pthProvider provider for atmospheric pressure, temperature and humidity at the station - * @param lambda laser wavelength - * @param lambdaUnits units in which {@code lambda} is given - * @see TropoUnit - * @since 12.1 - * */ - public MariniMurrayModel(final PressureTemperatureHumidityProvider pthProvider, - final double lambda, final Unit lambdaUnits) { - - this.pthProvider = pthProvider; - - // compute laser frequency parameter - final double lambdaMicrometer = new UnitsConverter(lambdaUnits, TroposphericModelUtils.MICRO_M).convert(lambda); - final double l2 = lambdaMicrometer * lambdaMicrometer; - fLambda = 0.9650 + (0.0164 + 0.000228 / l2) / l2; - + super(lambda, TroposphericModelUtils.NANO_M); + this.pth = new PressureTemperatureHumidity(0, + TroposphericModelUtils.HECTO_PASCAL.toSI(p0), + t0, + new CIPM2007(). + waterVaporPressure(TroposphericModelUtils.HECTO_PASCAL.toSI(p0), + t0, + rh), + Double.NaN, + Double.NaN); } /** Create a new Marini-Murray model using a standard atmosphere model. @@ -109,33 +81,10 @@ public MariniMurrayModel(final PressureTemperatureHumidityProvider pthProvider, */ @Deprecated public static MariniMurrayModel getStandardModel(final double lambda) { - return getStandardModel(lambda, TroposphericModelUtils.NANO_M); - } - - /** Create a new Marini-Murray model using a standard atmosphere model. - * - *
                  - *
                • altitude: 0m
                • - *
                • temperature: 20 degree Celsius
                • - *
                • pressure: 1013.25 mbar
                • - *
                • humidity: 50%
                • - *
                - * - * @param lambda laser wavelength (c/f) - * @param lambdaUnits units in which {@code lambda} is given - * @return a Marini-Murray model with standard environmental values - * @see TropoUnit - * @since 12.1 - */ - public static MariniMurrayModel getStandardModel(final double lambda, final Unit lambdaUnits) { - final double h = 0.0; final double p = TroposphericModelUtils.HECTO_PASCAL.toSI(1013.25); final double t = 273.15 + 20; final double rh = 0.5; - final PressureTemperatureHumidity pth = - new PressureTemperatureHumidity(h, p, t, new CIPM2007().waterVaporPressure(p, t, rh)); - return new MariniMurrayModel(new ConstantPressureTemperatureHumidityProvider(pth), - lambda, TroposphericModelUtils.NANO_M); + return new MariniMurrayModel(t, p, rh, lambda); } /** {@inheritDoc} */ @@ -144,39 +93,10 @@ public static MariniMurrayModel getStandardModel(final double lambda, final Unit public double pathDelay(final double elevation, final GeodeticPoint point, final double[] parameters, final AbsoluteDate date) { return pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), point, - TroposphericModelUtils.STANDARD_ATMOSPHERE, parameters, date). + pth, parameters, date). getDelay(); } - /** {@inheritDoc} */ - @Override - public TroposphericDelay pathDelay(final TrackingCoordinates trackingCoordinates, final GeodeticPoint point, - final PressureTemperatureHumidity weather, - final double[] parameters, final AbsoluteDate date) { - - final PressureTemperatureHumidity pth = pthProvider.getWeatherParamerers(point, date); - final double p = pth.getPressure(); - final double t = pth.getTemperature(); - final double e = pth.getWaterVaporPressure(); - - // beware since version 12.1 pressures are in Pa and not in hPa, hence the scaling has changed - final double Ah = 0.00002357 * p; - final double Aw = 0.00000141 * e; - final double K = 1.163 - 0.00968 * FastMath.cos(2 * point.getLatitude()) - 0.00104 * t + 0.0000001435 * p; - final double B = 1.084e-10 * p * t * K + 4.734e-12 * p * (p / t) * (2 * K) / (3 * K - 1); - final double flambda = getLaserFrequencyParameter(); - - final double fsite = getSiteFunctionValue(point); - - final double sinE = FastMath.sin(trackingCoordinates.getElevation()); - final double totalZenith = (flambda / fsite) * (Ah + Aw + B) / (1.0 + B / ((Ah + Aw + B) * (1.0 + 0.01))); - final double totalElev = (flambda / fsite) * (Ah + Aw + B) / (sinE + B / ((Ah + Aw + B) * (sinE + 0.01))); - final double hydrostaticZenith = (flambda / fsite) * (Ah + B) / (1.0 + B / ((Ah + B) * (1.0 + 0.01))); - final double hydrostaticElev = (flambda / fsite) * (Ah + B) / (sinE + B / ((Ah + B) * (sinE + 0.01))); - return new TroposphericDelay(hydrostaticZenith, totalZenith - hydrostaticZenith, - hydrostaticElev, totalElev - hydrostaticElev); - } - /** {@inheritDoc} */ @Override @Deprecated @@ -186,87 +106,9 @@ public > T pathDelay(final T elevation, final FieldAbsoluteDate date) { return pathDelay(new FieldTrackingCoordinates<>(date.getField().getZero(), elevation, date.getField().getZero()), point, - new FieldPressureTemperatureHumidity<>(date.getField(), TroposphericModelUtils.STANDARD_ATMOSPHERE), + new FieldPressureTemperatureHumidity<>(date.getField(), pth), parameters, date). getDelay(); } - /** {@inheritDoc} */ - @Override - public > FieldTroposphericDelay pathDelay(final FieldTrackingCoordinates trackingCoordinates, - final FieldGeodeticPoint point, - final FieldPressureTemperatureHumidity weather, - final T[] parameters, final FieldAbsoluteDate date) { - - final FieldPressureTemperatureHumidity pth = pthProvider.getWeatherParamerers(point, date); - final T p = pth.getPressure(); - final T t = pth.getTemperature(); - final T e = pth.getWaterVaporPressure(); - - // beware since version 12.1 pressures are in Pa and not in hPa, hence the scaling has changed - final T Ah = p.multiply(0.00002357); - final T Aw = e.multiply(0.00000141); - final T K = FastMath.cos(point.getLatitude().multiply(2.)).multiply(0.00968).negate(). - add(1.163). - subtract(t.multiply(0.00104)). - add(p.multiply(0.0000001435)); - final T B = K.multiply(t.multiply(p).multiply(1.084e-10 )). - add(K.multiply(2.).multiply(p.multiply(p).divide(t).multiply(4.734e-12)).divide(K.multiply(3.).subtract(1.))); - final double flambda = getLaserFrequencyParameter(); - - final T fsite = getSiteFunctionValue(point); - - final T sinE = FastMath.sin(trackingCoordinates.getElevation()); - final T one = date.getField().getOne(); - final T totalZenith = fsite.divide(flambda).reciprocal(). - multiply(B.add(Ah).add(Aw)). - divide(one.add(one.add(0.01).multiply(B.add(Ah).add(Aw)).divide(B).reciprocal())); - final T totalElev = fsite.divide(flambda).reciprocal(). - multiply(B.add(Ah).add(Aw)). - divide(sinE.add(sinE.add(0.01).multiply(B.add(Ah).add(Aw)).divide(B).reciprocal())); - final T hydrostaticZenith = fsite.divide(flambda).reciprocal(). - multiply(B.add(Ah)). - divide(one.add(one.add(0.01).multiply(B.add(Ah)).divide(B).reciprocal())); - final T hydrostaticElev = fsite.divide(flambda).reciprocal(). - multiply(B.add(Ah)). - divide(sinE.add(sinE.add(0.01).multiply(B.add(Ah)).divide(B).reciprocal())); - return new FieldTroposphericDelay<>(hydrostaticZenith, totalZenith.subtract(hydrostaticZenith), - hydrostaticElev, totalElev.subtract(hydrostaticElev)); - } - - /** {@inheritDoc} */ - @Override - public List getParametersDrivers() { - return Collections.emptyList(); - } - - /** Get the laser frequency parameter f(lambda). - * It is one for Ruby laser (lambda = 0.6943 micron) - * For infrared lasers, f(lambda) = 0.97966. - * - * @return the laser frequency parameter f(lambda). - */ - private double getLaserFrequencyParameter() { - return fLambda; - } - - /** Get the site parameter. - * - * @param point station location - * @return the site parameter. - */ - private double getSiteFunctionValue(final GeodeticPoint point) { - return 1. - 0.0026 * FastMath.cos(2 * point.getLatitude()) - 0.00031 * 0.001 * point.getAltitude(); - } - - /** Get the site parameter. - * - * @param type of the elements - * @param point station location - * @return the site parameter. - */ - private > T getSiteFunctionValue(final FieldGeodeticPoint point) { - return FastMath.cos(point.getLatitude().multiply(2)).multiply(0.0026).add(point.getAltitude().multiply(0.001).multiply(0.00031)).negate().add(1.); - } - } diff --git a/src/test/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModelTest.java index b0799fb28d..7d5e72a399 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModelTest.java @@ -30,18 +30,18 @@ public class CanonicalSaastamoinenModelTest { @Test public void testComparisonToModifiedModelLowElevation() { - doTestComparisonToModifiedModel(FastMath.toRadians(5), -13.24, -1.03); + doTestComparisonToModifiedModel(FastMath.toRadians(5), -13.4, 0.14); } @Test public void testComparisonToModifiedModelHighElevation() { - doTestComparisonToModifiedModel(FastMath.toRadians(60), -1.35, -0.11); + doTestComparisonToModifiedModel(FastMath.toRadians(60), -1.36, 0.002); } private void doTestComparisonToModifiedModel(final double elevation, final double minDifference, final double maxDifference) { final TrackingCoordinates trackingCoordinates = new TrackingCoordinates(0.0, elevation, 0.0); - final CanonicalSaastamoinenModel canonical = CanonicalSaastamoinenModel.getStandardModel(); + final CanonicalSaastamoinenModel canonical = new CanonicalSaastamoinenModel(); final ModifiedSaastamoinenModel modified = ModifiedSaastamoinenModel.getStandardModel(); for (double height = 0; height < 5000; height += 100) { final GeodeticPoint location = new GeodeticPoint(0.0, 0.0, height); diff --git a/src/test/java/org/orekit/models/earth/troposphere/MariniMurrayModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/MariniMurrayModelTest.java index 30fc56cbf5..9153374aab 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/MariniMurrayModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/MariniMurrayModelTest.java @@ -34,6 +34,7 @@ import org.orekit.utils.FieldTrackingCoordinates; import org.orekit.utils.TrackingCoordinates; +@Deprecated public class MariniMurrayModelTest { private static double epsilon = 1e-6; @@ -59,7 +60,7 @@ public void testDelay() { final double height = 100d; // ruby laser with wavelength 694.3 nm - TroposphericModel model = MariniMurrayModel.getStandardModel(694.3, TroposphericModelUtils.NANO_M); + TroposphericModel model = MariniMurrayModel.getStandardModel(694.3); final double path = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elevation), 0.0), new GeodeticPoint(latitude, longitude, height), TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH).getDelay(); @@ -114,7 +115,7 @@ private > void doTestFieldDelay(final Field final T height = zero.add(100d); // ruby laser with wavelength 694.3 nm - TroposphericModel model = MariniMurrayModel.getStandardModel(694.3, TroposphericModelUtils.NANO_M); + TroposphericModel model = MariniMurrayModel.getStandardModel(694.3); final T path = model.pathDelay(trackingCoordinates, new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), height), new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), null, FieldAbsoluteDate.getJ2000Epoch(field)).getDelay(); @@ -126,7 +127,7 @@ private > void doTestFieldDelay(final Field @Test public void testFixedHeight() { // ruby laser with wavelength 694.3 nm - TroposphericModel model = MariniMurrayModel.getStandardModel(694.3, TroposphericModelUtils.NANO_M); + TroposphericModel model = MariniMurrayModel.getStandardModel(694.3); double lastDelay = Double.MAX_VALUE; // delay shall decline with increasing elevation angle for (double elev = 10d; elev < 90d; elev += 8d) { @@ -145,7 +146,7 @@ public void testFieldFixedHeight() { private > void doTestFieldFixedHeight(final Field field) { // ruby laser with wavelength 694.3 nm - TroposphericModel model = MariniMurrayModel.getStandardModel(694.3, TroposphericModelUtils.NANO_M); + TroposphericModel model = MariniMurrayModel.getStandardModel(694.3); final T zero = field.getZero(); T lastDelay = zero.add(Double.MAX_VALUE); // delay shall decline with increasing elevation angle @@ -163,7 +164,7 @@ private > void doTestFieldFixedHeight(final Fi public void compareExpectedValues() { // ruby laser with wavelength 694.3 nm - TroposphericModel model = MariniMurrayModel.getStandardModel(694.3, TroposphericModelUtils.NANO_M); + TroposphericModel model = MariniMurrayModel.getStandardModel(694.3); double height = 0; double elevation = 10; @@ -183,7 +184,7 @@ public void compareFieldExpectedValue() { private > void doCompareFieldExpectedValues(final Field field) { // ruby laser with wavelength 694.3 nm - TroposphericModel model = MariniMurrayModel.getStandardModel(694.3, TroposphericModelUtils.NANO_M); + TroposphericModel model = MariniMurrayModel.getStandardModel(694.3); T zero = field.getZero(); T height = zero; diff --git a/src/test/java/org/orekit/models/earth/troposphere/MariniMurrayTest.java b/src/test/java/org/orekit/models/earth/troposphere/MariniMurrayTest.java new file mode 100644 index 0000000000..4a98599b81 --- /dev/null +++ b/src/test/java/org/orekit/models/earth/troposphere/MariniMurrayTest.java @@ -0,0 +1,168 @@ +/* Copyright 2011-2012 Space Applications Services + * Licensed to CS Communication & Systèmes (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import org.hipparchus.CalculusFieldElement; +import org.hipparchus.Field; +import org.hipparchus.util.Binary64Field; +import org.hipparchus.util.FastMath; +import org.hipparchus.util.Precision; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.orekit.Utils; +import org.orekit.bodies.FieldGeodeticPoint; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; +import org.orekit.utils.FieldTrackingCoordinates; +import org.orekit.utils.TrackingCoordinates; + +public class MariniMurrayTest { + + private static double epsilon = 1e-6; + + private double latitude; + + private double longitude; + + @BeforeAll + public static void setUpGlobal() { + Utils.setDataRoot("atmosphere"); + } + + @BeforeEach + public void setUp() throws Exception { + latitude = FastMath.toRadians(45.0); + longitude = FastMath.toRadians(45.0); + } + + @Test + public void testDelay() { + final double elevation = 10d; + final double height = 100d; + + // ruby laser with wavelength 694.3 nm + TroposphericModel model = new MariniMurray(694.3, TroposphericModelUtils.NANO_M); + final double path = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elevation), 0.0), + new GeodeticPoint(latitude, longitude, height), + TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH).getDelay(); + + Assertions.assertTrue(Precision.compareTo(path, 20d, epsilon) < 0); + Assertions.assertTrue(Precision.compareTo(path, 0d, epsilon) > 0); + } + + @Test + public void testFieldDelay() { + doTestFieldDelay(Binary64Field.getInstance()); + } + + private > void doTestFieldDelay(final Field field) { + final T zero = field.getZero(); + final FieldTrackingCoordinates trackingCoordinates = + new FieldTrackingCoordinates<>(zero, + zero.newInstance(FastMath.toRadians(10d)), + zero); + final T height = zero.add(100d); + + // ruby laser with wavelength 694.3 nm + TroposphericModel model = new MariniMurray(694.3, TroposphericModelUtils.NANO_M); + final T path = model.pathDelay(trackingCoordinates, new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), height), + new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + null, FieldAbsoluteDate.getJ2000Epoch(field)).getDelay(); + + Assertions.assertTrue(Precision.compareTo(path.getReal(), 20d, epsilon) < 0); + Assertions.assertTrue(Precision.compareTo(path.getReal(), 0d, epsilon) > 0); + } + + @Test + public void testFixedHeight() { + // ruby laser with wavelength 694.3 nm + TroposphericModel model = new MariniMurray(694.3, TroposphericModelUtils.NANO_M); + double lastDelay = Double.MAX_VALUE; + // delay shall decline with increasing elevation angle + for (double elev = 10d; elev < 90d; elev += 8d) { + final double delay = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elev), 0.0), + new GeodeticPoint(latitude, longitude, 350.0), + TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH).getDelay(); + Assertions.assertTrue(Precision.compareTo(delay, lastDelay, epsilon) < 0); + lastDelay = delay; + } + } + + @Test + public void testFieldFixedHeight() { + doTestFieldFixedHeight(Binary64Field.getInstance()); + } + + private > void doTestFieldFixedHeight(final Field field) { + // ruby laser with wavelength 694.3 nm + TroposphericModel model = new MariniMurray(694.3, TroposphericModelUtils.NANO_M); + final T zero = field.getZero(); + T lastDelay = zero.add(Double.MAX_VALUE); + // delay shall decline with increasing elevation angle + for (double elev = 10d; elev < 90d; elev += 8d) { + final T delay = model.pathDelay(new FieldTrackingCoordinates<>(zero, zero.newInstance(FastMath.toRadians(elev)), zero), + new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), zero.add(350.0)), + new FieldPressureTemperatureHumidity(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + null, FieldAbsoluteDate.getJ2000Epoch(field)).getDelay(); + Assertions.assertTrue(Precision.compareTo(delay.getReal(), lastDelay.getReal(), epsilon) < 0); + lastDelay = delay; + } + } + + @Test + public void compareExpectedValues() { + + // ruby laser with wavelength 694.3 nm + TroposphericModel model = new MariniMurray(694.3, TroposphericModelUtils.NANO_M); + + double height = 0; + double elevation = 10; + double expectedValue = 13.26069; + double actualValue = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(elevation), 0.0), + new GeodeticPoint(latitude, longitude, height), + TroposphericModelUtils.STANDARD_ATMOSPHERE, null, AbsoluteDate.J2000_EPOCH).getDelay(); + + Assertions.assertEquals(expectedValue, actualValue, 1.0e-5); + } + + @Test + public void compareFieldExpectedValue() { + doCompareFieldExpectedValues(Binary64Field.getInstance()); + } + + private > void doCompareFieldExpectedValues(final Field field) { + + // ruby laser with wavelength 694.3 nm + TroposphericModel model = new MariniMurray(694.3, TroposphericModelUtils.NANO_M); + + T zero = field.getZero(); + T height = zero; + T elevation = zero.newInstance(FastMath.toRadians(10)); + double expectedValue = 13.26069; + T actualValue = model.pathDelay(new FieldTrackingCoordinates<>(zero, elevation, zero), + new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), height), + new FieldPressureTemperatureHumidity(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + null, FieldAbsoluteDate.getJ2000Epoch(field)).getDelay(); + + Assertions.assertEquals(expectedValue, actualValue.getReal(), 1.0e-5); + } + +} From b420d5f6328e7ab18e54600282822ae600561cb9 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Thu, 21 Dec 2023 18:17:04 +0100 Subject: [PATCH 061/359] Added Askne-Nordius tropospheric model. --- src/changes/changes.xml | 3 + .../earth/troposphere/AskneNordiusModel.java | 126 +++++++++++++++++ .../troposphere/AskneNordiusModelTest.java | 130 ++++++++++++++++++ 3 files changed, 259 insertions(+) create mode 100644 src/main/java/org/orekit/models/earth/troposphere/AskneNordiusModel.java create mode 100644 src/test/java/org/orekit/models/earth/troposphere/AskneNordiusModelTest.java diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 93783fdfb3..8a58731e1f 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -21,6 +21,9 @@ + + Added Askne-Nordius tropospheric model. + Replaced Vienna{One|Three}Model by Vienna{One|Three}. diff --git a/src/main/java/org/orekit/models/earth/troposphere/AskneNordiusModel.java b/src/main/java/org/orekit/models/earth/troposphere/AskneNordiusModel.java new file mode 100644 index 0000000000..c1128f6959 --- /dev/null +++ b/src/main/java/org/orekit/models/earth/troposphere/AskneNordiusModel.java @@ -0,0 +1,126 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS Communication & Systèmes (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import java.util.Collections; +import java.util.List; + +import org.hipparchus.CalculusFieldElement; +import org.orekit.bodies.FieldGeodeticPoint; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; +import org.orekit.models.earth.weather.PressureTemperatureHumidity; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; +import org.orekit.utils.Constants; +import org.orekit.utils.FieldTrackingCoordinates; +import org.orekit.utils.ParameterDriver; +import org.orekit.utils.TrackingCoordinates; + +/** The Askne Nordius model. + *

                + * The hydrostatic part is equivalent to Saastamoinen, whereas the wet part takes + * into account {@link PressureTemperatureHumidity#getTm() mean temperature weighted + * with water vapor pressure} and {@link PressureTemperatureHumidity#getLambda() water + * vapor decrease factor}. + *

                + * @author Luc Maisonobe + * @see "J. Askne and H. Nordius, Estimation of tropospheric delay for microwaves + * from surface weather data, Radio Science, volume 22, number 3, pages 379-386, + * May-June 1987" + * @see "Landskron D (2017) Modeling tropospheric delays for space geodetic + * techniques. Dissertation, Department of Geodesy and Geoinformation, TU Wien, Supervisor: J. Böhm. + * http://repositum.tuwien.ac.at/urn:nbn:at:at-ubtuw:1-100249" + * @since 12.1 + */ +public class AskneNordiusModel implements TroposphericModel { + + /** Lowest acceptable elevation angle [rad]. */ + public static final double LOW_ELEVATION_THRESHOLD = 0.05; + + /** Base delay coefficient (from Saastamoninen model). */ + private static final double L0 = 2.2768e-5; + + /** Askne-Nordius coefficient k'₂. */ + private static final double K_PRIME_2 = 16.5203; + + /** Askne-Nordius coefficient k₃. */ + private static final double K_3 = 377600; + + /** Gas constant for dry components. */ + private static final double RD = 287.0464; + + /** Unit consversion factor. */ + private static final double FACTOR = 1.0e-6; + + /** Mapping function. */ + private final TroposphereMappingFunction mappingFunction; + + /** Create a new Askne Nordius model. + * @param mappingFunction mapping function + */ + public AskneNordiusModel(final TroposphereMappingFunction mappingFunction) { + this.mappingFunction = mappingFunction; + } + + /** {@inheritDoc} */ + @Override + public TroposphericDelay pathDelay(final TrackingCoordinates trackingCoordinates, final GeodeticPoint point, + final PressureTemperatureHumidity weather, + final double[] parameters, final AbsoluteDate date) { + + final double[] mf = mappingFunction.mappingFactors(trackingCoordinates, point, weather, date); + + // calculate the path delay + final double zh = L0 * weather.getPressure(); + final double zw = FACTOR * (K_PRIME_2 + K_3 / weather.getTm()) * + RD * weather.getWaterVaporPressure() / + (Constants.G0_STANDARD_GRAVITY * (weather.getLambda() + 1.0)); + final double sh = zh * mf[0]; + final double sw = zw * mf[1]; + return new TroposphericDelay(zh, zw, sh, sw); + + } + + /** {@inheritDoc} */ + @Override + public > FieldTroposphericDelay pathDelay(final FieldTrackingCoordinates trackingCoordinates, + final FieldGeodeticPoint point, + final FieldPressureTemperatureHumidity weather, + final T[] parameters, final FieldAbsoluteDate date) { + + final T[] mf = mappingFunction.mappingFactors(trackingCoordinates, point, weather, date); + + // calculate the path delay in m + final T zh = weather.getPressure().multiply(L0); + final T zw = weather.getTm().reciprocal().multiply(K_3).add(K_PRIME_2). + multiply(weather.getWaterVaporPressure().multiply(RD)). + divide(weather.getLambda().add(1.0).multiply(Constants.G0_STANDARD_GRAVITY)). + multiply(FACTOR); + final T sh = zh.multiply(mf[0]); + final T sw = zw.multiply(mf[1]); + return new FieldTroposphericDelay<>(zh, zw, sh, sw); + + } + + /** {@inheritDoc} */ + @Override + public List getParametersDrivers() { + return Collections.emptyList(); + } + +} diff --git a/src/test/java/org/orekit/models/earth/troposphere/AskneNordiusModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/AskneNordiusModelTest.java new file mode 100644 index 0000000000..b6934ed1b6 --- /dev/null +++ b/src/test/java/org/orekit/models/earth/troposphere/AskneNordiusModelTest.java @@ -0,0 +1,130 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS Communication & Systèmes (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import org.hipparchus.CalculusFieldElement; +import org.hipparchus.Field; +import org.hipparchus.util.Binary64Field; +import org.hipparchus.util.FastMath; +import org.hipparchus.util.Precision; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.orekit.Utils; +import org.orekit.bodies.FieldGeodeticPoint; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; +import org.orekit.models.earth.weather.HeightDependentPressureTemperatureHumidityConverter; +import org.orekit.models.earth.weather.PressureTemperatureHumidity; +import org.orekit.models.earth.weather.water.CIPM2007; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; +import org.orekit.utils.FieldTrackingCoordinates; +import org.orekit.utils.TrackingCoordinates; + + +public class AskneNordiusModelTest { + + @Test + public void testFixedElevation() { + Utils.setDataRoot("atmosphere"); + // first line of GPT 2w grid + PressureTemperatureHumidity pth = new PressureTemperatureHumidity(0.0, + 101421, 259.2, + new CIPM2007().waterVaporPressure(101421, 259.2, 1.64), + 255.1, 1.665); + AskneNordiusModel model = new AskneNordiusModel(new DummyMappingFunction()); + + HeightDependentPressureTemperatureHumidityConverter converter = + new HeightDependentPressureTemperatureHumidityConverter(new CIPM2007()); + double lastDelay = Double.MAX_VALUE; + // delay shall decline with increasing height of the station + for (double height = 0; height < 5000; height += 100) { + final double delay = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(5), 0.0), + new GeodeticPoint(0.0, 0.0, height), + converter.convert(pth, height), + null, AbsoluteDate.J2000_EPOCH).getZw(); + Assertions.assertTrue(Precision.compareTo(delay, lastDelay, 1.0e-6) < 0); + lastDelay = delay; + } + } + + @Test + public void testFieldFixedElevation() { + doTestFieldFixedElevation(Binary64Field.getInstance()); + } + + private > void doTestFieldFixedElevation(final Field field) { + final T zero = field.getZero(); + Utils.setDataRoot("atmosphere"); + // first line of GPT 2w grid + PressureTemperatureHumidity pth = new PressureTemperatureHumidity(0.0, + 101421, 259.2, + new CIPM2007().waterVaporPressure(101421, 259.2, 1.64), + 255.1, 1.665); + AskneNordiusModel model = new AskneNordiusModel(new DummyMappingFunction()); + HeightDependentPressureTemperatureHumidityConverter converter = + new HeightDependentPressureTemperatureHumidityConverter(new CIPM2007()); + T lastDelay = zero.newInstance(Double.MAX_VALUE); + // delay shall decline with increasing height of the station + for (double height = 0; height < 5000; height += 100) { + final T delay = model.pathDelay(new FieldTrackingCoordinates<>(zero, + zero.newInstance(FastMath.toRadians(5)), + zero), + new FieldGeodeticPoint<>(zero, zero, zero.newInstance(height)), + converter.convert(new FieldPressureTemperatureHumidity<>(field, pth), + zero.newInstance(height)), + null, FieldAbsoluteDate.getJ2000Epoch(field)).getZw(); + Assertions.assertTrue(Precision.compareTo(delay.getReal(), lastDelay.getReal(), 1.0e-6) < 0); + lastDelay = delay; + } + } + + @Test + public void testFieldVsNative() { + doTestFieldVsNative(Binary64Field.getInstance()); + } + + private > void doTestFieldVsNative(final Field field) { + final T zero = field.getZero(); + Utils.setDataRoot("atmosphere"); + // first line of GPT 2w grid + PressureTemperatureHumidity pth = new PressureTemperatureHumidity(0.0, + 101421, 259.2, + new CIPM2007().waterVaporPressure(101421, 259.2, 1.64), + 255.1, 1.665); + AskneNordiusModel model = new AskneNordiusModel(new DummyMappingFunction()); + HeightDependentPressureTemperatureHumidityConverter converter = + new HeightDependentPressureTemperatureHumidityConverter(new CIPM2007()); + for (int h = 0; h < 5000.0; h += 100) { + for (int e = 0; e < 90; e += 1.0) { + final double delayN = model.pathDelay(new TrackingCoordinates(0.0, FastMath.toRadians(e), 0.0), + new GeodeticPoint(0, 0, h), + converter.convert(pth, h), + null, AbsoluteDate.J2000_EPOCH).getZw(); + final T delayT = model.pathDelay(new FieldTrackingCoordinates<>(zero, + zero.newInstance(FastMath.toRadians(e)), + zero), + new FieldGeodeticPoint<>(zero, zero, zero.newInstance(h)), + converter.convert(new FieldPressureTemperatureHumidity<>(field, pth), + zero.newInstance(h)), + null, FieldAbsoluteDate.getJ2000Epoch(field)).getZw(); + Assertions.assertEquals(delayN, delayT.getReal(), 1.0e-6); + } + } + } + +} From c091151aea833aadedfa20de514c07c044092d6f Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Thu, 21 Dec 2023 18:21:05 +0100 Subject: [PATCH 062/359] Added two humidity parameters. These parameters are used in GPT2w and Askne-Nordius model. --- .../earth/troposphere/EstimatedModel.java | 4 +- .../earth/troposphere/MendesPavlisModel.java | 9 +- .../ModifiedSaastamoinenModel.java | 4 +- .../earth/troposphere/SaastamoinenModel.java | 4 +- .../models/earth/troposphere/ViennaThree.java | 2 +- .../earth/weather/CellInterpolator.java | 17 +- .../earth/weather/FieldCellInterpolator.java | 17 +- .../FieldPressureTemperatureHumidity.java | 30 +- .../weather/GlobalPressureTemperature2.java | 51 +- .../GlobalPressureTemperature2Model.java | 1 - .../org/orekit/models/earth/weather/Grid.java | 43 +- .../models/earth/weather/Grid2Entry.java | 126 +++++ .../models/earth/weather/GridEntry.java | 91 +--- ...tPressureTemperatureHumidityConverter.java | 6 +- .../weather/PressureTemperatureHumidity.java | 28 +- .../common/AbstractOrbitDetermination.java | 3 +- .../FieldMendesPavlisModelTest.java | 8 +- .../troposphere/FieldViennaOneModelTest.java | 1 + .../earth/troposphere/FieldViennaOneTest.java | 360 ++++++++++++++ .../FieldViennaThreeModelTest.java | 1 + .../troposphere/FieldViennaThreeTest.java | 467 ++++++++++++++++++ .../troposphere/MendesPavlisModelTest.java | 8 +- .../ModifiedSaastamoinenModelTest.java | 16 +- 23 files changed, 1132 insertions(+), 165 deletions(-) create mode 100644 src/main/java/org/orekit/models/earth/weather/Grid2Entry.java create mode 100644 src/test/java/org/orekit/models/earth/troposphere/FieldViennaOneTest.java create mode 100644 src/test/java/org/orekit/models/earth/troposphere/FieldViennaThreeTest.java diff --git a/src/main/java/org/orekit/models/earth/troposphere/EstimatedModel.java b/src/main/java/org/orekit/models/earth/troposphere/EstimatedModel.java index 0ed648a892..1af9588ba7 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/EstimatedModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/EstimatedModel.java @@ -87,7 +87,9 @@ public EstimatedModel(final double h0, final double t0, final double p0, this(new ModifiedSaastamoinenModel(new ConstantPressureTemperatureHumidityProvider(new PressureTemperatureHumidity(h0, TroposphericModelUtils.HECTO_PASCAL.toSI(p0), t0, - 0.0))), + 0.0, + Double.NaN, + Double.NaN))), model, totalDelay); } diff --git a/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java b/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java index b89fb08313..c698dfda64 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java @@ -99,7 +99,9 @@ public MendesPavlisModel(final double t0, final double p0, t0, new CIPM2007(). waterVaporPressure(TroposphericModelUtils.HECTO_PASCAL.toSI(p0), - t0, rh))), + t0, rh), + Double.NaN, + Double.NaN)), lambda, TroposphericModelUtils.MICRO_M); } @@ -175,7 +177,10 @@ public static MendesPavlisModel getStandardModel(final double lambda, final Unit final double p = TroposphericModelUtils.HECTO_PASCAL.toSI(1013.25); final double t = 273.15 + 18; final double rh = 0.5; - final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(h, p, t, new CIPM2007().waterVaporPressure(p, t, rh)); + final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(h, p, t, + new CIPM2007().waterVaporPressure(p, t, rh), + Double.NaN, + Double.NaN); return new MendesPavlisModel(new ConstantPressureTemperatureHumidityProvider(pth), lambda, lambdaUnits); } diff --git a/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java b/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java index 10a8c64d17..5971280d6c 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java @@ -207,7 +207,9 @@ public static ModifiedSaastamoinenModel getStandardModel() { temperature, WATER.waterVaporPressure(pressure, temperature, - humidity)); + humidity), + Double.NaN, + Double.NaN); final PressureTemperatureHumidityProvider pth0Provider = new ConstantPressureTemperatureHumidityProvider(pth); return new ModifiedSaastamoinenModel(pth0Provider); } diff --git a/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java b/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java index bea870eb8a..bf0e8c5aec 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/SaastamoinenModel.java @@ -101,7 +101,9 @@ public SaastamoinenModel(final double t0, new Wang1988(). waterVaporPressure(TroposphericModelUtils.HECTO_PASCAL.toSI(p0), t0, - r0))), + r0), + Double.NaN, + Double.NaN)), deltaRFileName, dataProvidersManager); } diff --git a/src/main/java/org/orekit/models/earth/troposphere/ViennaThree.java b/src/main/java/org/orekit/models/earth/troposphere/ViennaThree.java index e3bd2a689c..edee0beda1 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/ViennaThree.java +++ b/src/main/java/org/orekit/models/earth/troposphere/ViennaThree.java @@ -40,7 +40,7 @@ * The empirical coefficients bh, bw, ch * and cw are computed with spherical harmonics. * In that respect, they are considerably more advanced than those of - * {@link ViennaOneModel VMF1} model. + * {@link ViennaOne VMF1} model. *

                * * @see "Landskron, D. & Böhm, J. J Geod (2018) diff --git a/src/main/java/org/orekit/models/earth/weather/CellInterpolator.java b/src/main/java/org/orekit/models/earth/weather/CellInterpolator.java index 4c91c4fb46..68bd9cc093 100644 --- a/src/main/java/org/orekit/models/earth/weather/CellInterpolator.java +++ b/src/main/java/org/orekit/models/earth/weather/CellInterpolator.java @@ -21,10 +21,11 @@ import org.hipparchus.analysis.interpolation.BilinearInterpolatingFunction; /** Interpolator within a grid cell. + * @param type of the grid entries * @author Luc Maisonobe * @since 12.1 */ -public class CellInterpolator { +public class CellInterpolator { /** Latitude of point of interest. */ private final double latitude; @@ -33,16 +34,16 @@ public class CellInterpolator { private final double longitude; /** South-West grid entry. */ - private final GridEntry southWest; + private final G southWest; /** South-East grid entry. */ - private final GridEntry southEast; + private final G southEast; /** North-West grid entry. */ - private final GridEntry northWest; + private final G northWest; /** North-East grid entry. */ - private final GridEntry northEast; + private final G northEast; /** Simple constructor. * @param latitude latitude of point of interest @@ -53,8 +54,8 @@ public class CellInterpolator { * @param northEast North-East grid entry */ CellInterpolator(final double latitude, final double longitude, - final GridEntry southWest, final GridEntry southEast, - final GridEntry northWest, final GridEntry northEast) { + final G southWest, final G southEast, + final G northWest, final G northEast) { this.latitude = latitude; this.longitude = longitude; this.southWest = southWest; @@ -67,7 +68,7 @@ public class CellInterpolator { * @param gridGetter getter for the grid function * @return interpolated function" */ - double interpolate(final ToDoubleFunction gridGetter) { + double interpolate(final ToDoubleFunction gridGetter) { // cell surrounding the point final double[] xVal = new double[] { diff --git a/src/main/java/org/orekit/models/earth/weather/FieldCellInterpolator.java b/src/main/java/org/orekit/models/earth/weather/FieldCellInterpolator.java index dea48a1a19..509d422a4f 100644 --- a/src/main/java/org/orekit/models/earth/weather/FieldCellInterpolator.java +++ b/src/main/java/org/orekit/models/earth/weather/FieldCellInterpolator.java @@ -23,10 +23,11 @@ /** Interpolator within a grid cell. * @param type of the field elements + * @param type of the grid entries * @author Luc Maisonobe * @since 12.1 */ -public class FieldCellInterpolator> { +public class FieldCellInterpolator, G extends GridEntry> { /** Latitude of point of interest. */ private final T latitude; @@ -35,16 +36,16 @@ public class FieldCellInterpolator> { private final T longitude; /** South-West grid entry. */ - private final GridEntry southWest; + private final G southWest; /** South-East grid entry. */ - private final GridEntry southEast; + private final G southEast; /** North-West grid entry. */ - private final GridEntry northWest; + private final G northWest; /** North-East grid entry. */ - private final GridEntry northEast; + private final G northEast; /** Simple constructor. * @param latitude latitude of point of interest @@ -55,8 +56,8 @@ public class FieldCellInterpolator> { * @param northEast North-East grid entry */ FieldCellInterpolator(final T latitude, final T longitude, - final GridEntry southWest, final GridEntry southEast, - final GridEntry northWest, final GridEntry northEast) { + final G southWest, final G southEast, + final G northWest, final G northEast) { this.latitude = latitude; this.longitude = longitude; this.southWest = southWest; @@ -69,7 +70,7 @@ public class FieldCellInterpolator> { * @param gridGetter getter for the grid function * @return interpolated function" */ - T interpolate(final ToDoubleFunction gridGetter) { + T interpolate(final ToDoubleFunction gridGetter) { // cell surrounding the point final double[] xVal = new double[] { diff --git a/src/main/java/org/orekit/models/earth/weather/FieldPressureTemperatureHumidity.java b/src/main/java/org/orekit/models/earth/weather/FieldPressureTemperatureHumidity.java index b9b4492451..2377256c98 100644 --- a/src/main/java/org/orekit/models/earth/weather/FieldPressureTemperatureHumidity.java +++ b/src/main/java/org/orekit/models/earth/weather/FieldPressureTemperatureHumidity.java @@ -29,18 +29,30 @@ public class FieldPressureTemperatureHumidity> /** Humidity as water vapor pressure (Pa). */ private final T waterVaporPressure; + /** Mean temperature weighted with water vapor pressure. */ + private final T tm; + + /** Water vapor decrease factor. */ + private final T lambda; + /** Simple constructor. * @param altitude altitude at which weather parameters have been computed (m) * @param pressure pressure (Pa) * @param temperature temperature (Kelvin) * @param waterVaporPressure humidity as water vapor pressure (Pa) + * @param tm mean temperature weighted with water vapor pressure + * @param lambda water vapor decrease factor */ public FieldPressureTemperatureHumidity(final T altitude, final T pressure, final T temperature, - final T waterVaporPressure) { + final T waterVaporPressure, + final T tm, + final T lambda) { super(altitude, pressure, temperature); this.waterVaporPressure = waterVaporPressure; + this.tm = tm; + this.lambda = lambda; } /** Simple constructor. @@ -50,6 +62,8 @@ public FieldPressureTemperatureHumidity(final T altitude, public FieldPressureTemperatureHumidity(final Field field, final PressureTemperatureHumidity weather) { super(field, weather); this.waterVaporPressure = field.getZero().newInstance(weather.getWaterVaporPressure()); + this.tm = field.getZero().newInstance(weather.getTm()); + this.lambda = field.getZero().newInstance(weather.getLambda()); } /** Get humidity as water vapor pressure. @@ -59,4 +73,18 @@ public T getWaterVaporPressure() { return waterVaporPressure; } + /** Get mean temperature weighted with water vapor pressure. + * @return mean temperature weighted with water vapor pressure + */ + public T getTm() { + return tm; + } + + /** Get water vapor decrease factor. + * @return water vapor decrease factor + */ + public T getLambda() { + return lambda; + } + } diff --git a/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2.java b/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2.java index 30c6340705..feb4c33bad 100644 --- a/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2.java +++ b/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2.java @@ -92,11 +92,8 @@ public class GlobalPressureTemperature2 implements ViennaAProvider, PressureTemp /** Ideal gas constant for dry air [J/kg/K]. */ private static final double R = 287.0; - /** Conversion factor from degrees to mill arcseconds. */ - private static final int DEG_TO_MAS = 3600000; - /** Loaded grid. */ - private final Grid grid; + private final Grid grid; /** UTC time scale. */ private final TimeScale utc; @@ -144,7 +141,7 @@ protected GlobalPressureTemperature2(final String supportedNames, @Override public ViennaACoefficients getA(final GeodeticPoint location, final AbsoluteDate date) { - final CellInterpolator interpolator = grid.getInterpolator(location.getLatitude(), location.getLongitude()); + final CellInterpolator interpolator = grid.getInterpolator(location.getLatitude(), location.getLongitude()); final int dayOfYear = date.getComponents(utc).getDate().getDayOfYear(); // ah and aw coefficients @@ -157,7 +154,7 @@ public ViennaACoefficients getA(final GeodeticPoint location, final AbsoluteDate @Override public PressureTemperatureHumidity getWeatherParamerers(final GeodeticPoint location, final AbsoluteDate date) { - final CellInterpolator interpolator = grid.getInterpolator(location.getLatitude(), location.getLongitude()); + final CellInterpolator interpolator = grid.getInterpolator(location.getLatitude(), location.getLongitude()); final int dayOfYear = date.getComponents(utc).getDate().getDayOfYear(); // Corrected height (can be negative) @@ -188,7 +185,9 @@ public PressureTemperatureHumidity getWeatherParamerers(final GeodeticPoint loca return new PressureTemperatureHumidity(location.getAltitude(), TroposphericModelUtils.HECTO_PASCAL.toSI(pressure), temperature, - TroposphericModelUtils.HECTO_PASCAL.toSI(e0)); + TroposphericModelUtils.HECTO_PASCAL.toSI(e0), + Double.NaN, + Double.NaN); } @@ -197,7 +196,7 @@ public PressureTemperatureHumidity getWeatherParamerers(final GeodeticPoint loca public > FieldViennaACoefficients getA(final FieldGeodeticPoint location, final FieldAbsoluteDate date) { - final FieldCellInterpolator interpolator = grid.getInterpolator(location.getLatitude(), location.getLongitude()); + final FieldCellInterpolator interpolator = grid.getInterpolator(location.getLatitude(), location.getLongitude()); final int dayOfYear = date.getComponents(utc).getDate().getDayOfYear(); // ah and aw coefficients @@ -211,7 +210,7 @@ public > FieldViennaACoefficients getA(fina public > FieldPressureTemperatureHumidity getWeatherParamerers(final FieldGeodeticPoint location, final FieldAbsoluteDate date) { - final FieldCellInterpolator interpolator = grid.getInterpolator(location.getLatitude(), location.getLongitude()); + final FieldCellInterpolator interpolator = grid.getInterpolator(location.getLatitude(), location.getLongitude()); final int dayOfYear = date.getComponents(utc).getDate().getDayOfYear(); // Corrected height (can be negative) @@ -242,7 +241,9 @@ public > FieldPressureTemperatureHumidity g return new FieldPressureTemperatureHumidity<>(location.getAltitude(), TroposphericModelUtils.HECTO_PASCAL.toSI(pressure), temperature, - TroposphericModelUtils.HECTO_PASCAL.toSI(e0)); + TroposphericModelUtils.HECTO_PASCAL.toSI(e0), + date.getField().getZero().newInstance(Double.NaN), + date.getField().getZero().newInstance(Double.NaN)); } @@ -250,7 +251,7 @@ public > FieldPressureTemperatureHumidity g private static class Parser implements DataLoader { /** Grid entries. */ - private Grid grid; + private Grid grid; @Override public boolean stillAcceptsData() { @@ -263,7 +264,7 @@ public void loadData(final InputStream input, final String name) final SortedSet latSample = new TreeSet<>(); final SortedSet lonSample = new TreeSet<>(); - final List entries = new ArrayList<>(); + final List entries = new ArrayList<>(); // Open stream and parse data int lineNumber = 0; @@ -280,18 +281,18 @@ public void loadData(final InputStream input, final String name) final String[] fields = SEPARATOR.split(line); final double latDegree = Double.parseDouble(fields[0]); final double lonDegree = Double.parseDouble(fields[1]); - final GridEntry entry = new GridEntry(FastMath.toRadians(latDegree), - (int) FastMath.rint(latDegree * DEG_TO_MAS), - FastMath.toRadians(lonDegree), - (int) FastMath.rint(lonDegree * DEG_TO_MAS), - Double.parseDouble(fields[22]), - Double.parseDouble(fields[23]), - createModel(fields, 2), - createModel(fields, 7), - createModel(fields, 12), - createModel(fields, 17), - createModel(fields, 24), - createModel(fields, 29)); + final Grid2Entry entry = new Grid2Entry(FastMath.toRadians(latDegree), + (int) FastMath.rint(latDegree * GridEntry.DEG_TO_MAS), + FastMath.toRadians(lonDegree), + (int) FastMath.rint(lonDegree * GridEntry.DEG_TO_MAS), + Double.parseDouble(fields[22]), + Double.parseDouble(fields[23]), + createModel(fields, 2), + createModel(fields, 7), + createModel(fields, 12), + createModel(fields, 17), + createModel(fields, 24), + createModel(fields, 29)); latSample.add(entry.getLatKey()); lonSample.add(entry.getLonKey()); entries.add(entry); @@ -304,7 +305,7 @@ public void loadData(final InputStream input, final String name) } // organize entries in a grid that wraps arouns Earth in longitude - grid = new Grid(latSample, lonSample, entries, name); + grid = new Grid<>(latSample, lonSample, entries, name); } diff --git a/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2Model.java b/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2Model.java index 6858230679..62c34a0e5a 100644 --- a/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2Model.java +++ b/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature2Model.java @@ -128,7 +128,6 @@ public GlobalPressureTemperature2Model(final String supportedNames, this.e0 = Double.NaN; this.latitude = latitude; this.longitude = longitude; - } /** diff --git a/src/main/java/org/orekit/models/earth/weather/Grid.java b/src/main/java/org/orekit/models/earth/weather/Grid.java index f817cf80c0..c4a169d405 100644 --- a/src/main/java/org/orekit/models/earth/weather/Grid.java +++ b/src/main/java/org/orekit/models/earth/weather/Grid.java @@ -16,6 +16,7 @@ */ package org.orekit.models.earth.weather; +import java.lang.reflect.Array; import java.util.List; import java.util.SortedSet; @@ -30,10 +31,7 @@ * @author Luc Maisonobe * @since 12.1 */ -class Grid { - - /** Conversion factor from degrees to mill arcseconds. */ - private static final int DEG_TO_MAS = 3600000; +class Grid { /** Latitude sample. */ private final SortedSet latitudeSample; @@ -42,7 +40,7 @@ class Grid { private final SortedSet longitudeSample; /** Grid entries. */ - private final GridEntry[][] entries; + private final G[][] entries; /** Simple constructor. * @param latitudeSample latitude sample @@ -50,24 +48,25 @@ class Grid { * @param loadedEntries loaded entries, organized as a simple list * @param name file name */ + @SuppressWarnings("unchecked") Grid(final SortedSet latitudeSample, final SortedSet longitudeSample, - final List loadedEntries, final String name) { + final List loadedEntries, final String name) { final int nA = latitudeSample.size(); final int nO = longitudeSample.size() + 1; // we add one here for wrapping the grid - this.entries = new GridEntry[nA][nO]; + this.entries = (G[][]) Array.newInstance(GridEntry.class, nA, nO); this.latitudeSample = latitudeSample; this.longitudeSample = longitudeSample; // organize entries in the regular grid - for (final GridEntry entry : loadedEntries) { + for (final G entry : loadedEntries) { final int latitudeIndex = latitudeSample.headSet(entry.getLatKey() + 1).size() - 1; final int longitudeIndex = longitudeSample.headSet(entry.getLonKey() + 1).size() - 1; entries[latitudeIndex][longitudeIndex] = entry; } // finalize the grid - for (final GridEntry[] row : entries) { + for (final G[] row : entries) { // check for missing entries for (int longitudeIndex = 0; longitudeIndex < nO - 1; ++longitudeIndex) { @@ -77,13 +76,7 @@ class Grid { } // wrap the grid around the Earth in longitude - row[nO - 1] = new GridEntry(row[0].getLatitude(), row[0].getLatKey(), - row[0].getLongitude() + MathUtils.TWO_PI, - row[0].getLonKey() + DEG_TO_MAS * 360, - row[0].getUndulation(), row[0].getHs(), - row[0].getPressure0(), row[0].getTemperature0(), - row[0].getQv0(), row[0].getDt(), - row[0].getAh(), row[0].getAw()); + row[nO - 1] = (G) row[0].buildWrappedEntry(); } @@ -95,7 +88,7 @@ class Grid { */ private int getSouthIndex(final double latitude) { - final int latKey = (int) FastMath.rint(FastMath.toDegrees(latitude) * DEG_TO_MAS); + final int latKey = (int) FastMath.rint(FastMath.toDegrees(latitude) * GridEntry.DEG_TO_MAS); final int index = latitudeSample.headSet(latKey + 1).size() - 1; // make sure we have at least one point remaining on North by clipping to size - 2 @@ -109,7 +102,7 @@ private int getSouthIndex(final double latitude) { */ private int getWestIndex(final double longitude) { - final int lonKey = (int) FastMath.rint(FastMath.toDegrees(longitude) * DEG_TO_MAS); + final int lonKey = (int) FastMath.rint(FastMath.toDegrees(longitude) * GridEntry.DEG_TO_MAS); final int index = longitudeSample.headSet(lonKey + 1).size() - 1; // we don't do clipping in longitude because we have added a row to wrap around the Earth @@ -122,7 +115,7 @@ private int getWestIndex(final double longitude) { * @param longitude longitude of point of interest * @return interpolator for the cell */ - CellInterpolator getInterpolator(final double latitude, final double longitude) { + CellInterpolator getInterpolator(final double latitude, final double longitude) { // keep longitude within grid range final double normalizedLongitude = @@ -134,11 +127,11 @@ CellInterpolator getInterpolator(final double latitude, final double longitude) final int westIndex = getWestIndex(normalizedLongitude); // build interpolator - return new CellInterpolator(latitude, normalizedLongitude, - entries[southIndex ][westIndex ], - entries[southIndex ][westIndex + 1], - entries[southIndex + 1][westIndex ], - entries[southIndex + 1][westIndex + 1]); + return new CellInterpolator<>(latitude, normalizedLongitude, + entries[southIndex ][westIndex ], + entries[southIndex ][westIndex + 1], + entries[southIndex + 1][westIndex ], + entries[southIndex + 1][westIndex + 1]); } @@ -148,7 +141,7 @@ CellInterpolator getInterpolator(final double latitude, final double longitude) * @param longitude longitude of point of interest * @return interpolator for the cell */ - > FieldCellInterpolator getInterpolator(final T latitude, final T longitude) { + > FieldCellInterpolator getInterpolator(final T latitude, final T longitude) { // keep longitude within grid range final T normalizedLongitude = diff --git a/src/main/java/org/orekit/models/earth/weather/Grid2Entry.java b/src/main/java/org/orekit/models/earth/weather/Grid2Entry.java new file mode 100644 index 0000000000..a8a7657148 --- /dev/null +++ b/src/main/java/org/orekit/models/earth/weather/Grid2Entry.java @@ -0,0 +1,126 @@ +/* Copyright 2023 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.weather; + +import org.hipparchus.util.MathUtils; + +/** Grid entry in Global Pressure Temperature models 2. + * @author Luc Maisonobe + * @since 12.1 + */ +class Grid2Entry extends GridEntry { + + /** Pressure model. */ + private final SeasonalModel pressure0; + + /** Temperature model. */ + private final SeasonalModel temperature0; + + /** Specific humidity model. */ + private final SeasonalModel qv0; + + /** Temperature gradient model. */ + private final SeasonalModel dT; + + /** ah coefficient model. */ + private final SeasonalModel ah; + + /** aw coefficient model. */ + private final SeasonalModel aw; + + /** Build an entry from its components. + * @param latitude latitude (radian) + * @param latKey latitude key (mas) + * @param longitude longitude (radian) + * @param lonKey longitude key (mas) + * @param undulation undulation (m) + * @param hS height correction + * @param pressure0 pressure model + * @param temperature0 temperature model + * @param qv0 specific humidity model + * @param dT temperature gradient model + * @param ah ah coefficient model + * @param aw aw coefficient model + */ + Grid2Entry(final double latitude, final int latKey, final double longitude, final int lonKey, + final double undulation, final double hS, + final SeasonalModel pressure0, final SeasonalModel temperature0, + final SeasonalModel qv0, final SeasonalModel dT, + final SeasonalModel ah, final SeasonalModel aw) { + + super(latitude, latKey, longitude, lonKey, undulation, hS); + this.pressure0 = pressure0; + this.temperature0 = temperature0; + this.qv0 = qv0; + this.dT = dT; + this.ah = ah; + this.aw = aw; + } + + /** {@inheritDoc} */ + @Override + public Grid2Entry buildWrappedEntry() { + return new Grid2Entry(getLatitude(), getLatKey(), + getLongitude() + MathUtils.TWO_PI, + getLonKey() + DEG_TO_MAS * 360, + getUndulation(), getHs(), + pressure0, temperature0, qv0, dT, ah, aw); + } + + /** Get pressure model. + * @return pressure model + */ + SeasonalModel getPressure0() { + return pressure0; + } + + /** Get temperature model. + * @return temperature model + */ + SeasonalModel getTemperature0() { + return temperature0; + } + + /** Get specific humidity model. + * @return specific humidity model + */ + SeasonalModel getQv0() { + return qv0; + } + + /** Get temperature gradient model. + * @return temperature gradient model + */ + SeasonalModel getDt() { + return dT; + } + + /** Get ah coefficient model. + * @return ah coefficient model + */ + SeasonalModel getAh() { + return ah; + } + + /** Get aw coefficient model. + * @return aw coefficient model + */ + SeasonalModel getAw() { + return aw; + } + +} diff --git a/src/main/java/org/orekit/models/earth/weather/GridEntry.java b/src/main/java/org/orekit/models/earth/weather/GridEntry.java index 5d5c8b6ee3..0a661116e7 100644 --- a/src/main/java/org/orekit/models/earth/weather/GridEntry.java +++ b/src/main/java/org/orekit/models/earth/weather/GridEntry.java @@ -1,4 +1,4 @@ -/* Copyright 2002-2023 CS GROUP +/* Copyright 2023 Thales Alenia Space * Licensed to CS GROUP (CS) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. @@ -16,12 +16,15 @@ */ package org.orekit.models.earth.weather; -/** Grid entry in Global Pressure Temperature models. +/** Base grid entry in Global Pressure Temperature models. * @author Bryan Cazabonne * @author Luc Maisonobe * @since 12.1 */ -class GridEntry { +abstract class GridEntry { + + /** Conversion factor from degrees to mill arcseconds. */ + public static final int DEG_TO_MAS = 3600000; /** Latitude (radian). */ private final double latitude; @@ -41,24 +44,6 @@ class GridEntry { /** Height correction. */ private final double hS; - /** Pressure model. */ - private final SeasonalModel pressure0; - - /** Temperature model. */ - private final SeasonalModel temperature0; - - /** Specific humidity model. */ - private final SeasonalModel qv0; - - /** Temperature gradient model. */ - private final SeasonalModel dT; - - /** ah coefficient model. */ - private final SeasonalModel ah; - - /** aw coefficient model. */ - private final SeasonalModel aw; - /** Build an entry from its components. * @param latitude latitude (radian) * @param latKey latitude key (mas) @@ -66,18 +51,9 @@ class GridEntry { * @param lonKey longitude key (mas) * @param undulation undulation (m) * @param hS height correction - * @param pressure0 pressure model - * @param temperature0 temperature model - * @param qv0 specific humidity model - * @param dT temperature gradient model - * @param ah ah coefficient model - * @param aw aw coefficient model */ GridEntry(final double latitude, final int latKey, final double longitude, final int lonKey, - final double undulation, final double hS, - final SeasonalModel pressure0, final SeasonalModel temperature0, - final SeasonalModel qv0, final SeasonalModel dT, - final SeasonalModel ah, final SeasonalModel aw) { + final double undulation, final double hS) { this.latitude = latitude; this.latKey = latKey; @@ -85,14 +61,13 @@ class GridEntry { this.lonKey = lonKey; this.undulation = undulation; this.hS = hS; - this.pressure0 = pressure0; - this.temperature0 = temperature0; - this.qv0 = qv0; - this.dT = dT; - this.ah = ah; - this.aw = aw; } + /** Build a new entry 360° to the East of instance. + * @return new wrapping entry + */ + public abstract GridEntry buildWrappedEntry(); + /** Get latitude (radian). * @return latitude (radian) */ @@ -135,46 +110,4 @@ int getLonKey() { return hS; } - /** Get pressure model. - * @return pressure model - */ - SeasonalModel getPressure0() { - return pressure0; - } - - /** Get temperature model. - * @return temperature model - */ - SeasonalModel getTemperature0() { - return temperature0; - } - - /** Get specific humidity model. - * @return specific humidity model - */ - SeasonalModel getQv0() { - return qv0; - } - - /** Get temperature gradient model. - * @return temperature gradient model - */ - SeasonalModel getDt() { - return dT; - } - - /** Get ah coefficient model. - * @return ah coefficient model - */ - SeasonalModel getAh() { - return ah; - } - - /** Get aw coefficient model. - * @return aw coefficient model - */ - SeasonalModel getAw() { - return aw; - } - } diff --git a/src/main/java/org/orekit/models/earth/weather/HeightDependentPressureTemperatureHumidityConverter.java b/src/main/java/org/orekit/models/earth/weather/HeightDependentPressureTemperatureHumidityConverter.java index 4d4b7aa6ea..6aba88014e 100644 --- a/src/main/java/org/orekit/models/earth/weather/HeightDependentPressureTemperatureHumidityConverter.java +++ b/src/main/java/org/orekit/models/earth/weather/HeightDependentPressureTemperatureHumidityConverter.java @@ -60,7 +60,8 @@ public PressureTemperatureHumidity convert(final PressureTemperatureHumidity pth final double t = pth0.getTemperature() - 6.5e-3 * dh; final double rh = rh0 * FastMath.exp(-6.396e-4 * dh); - return new PressureTemperatureHumidity(h, p, t, provider.waterVaporPressure(p, t, rh)); + return new PressureTemperatureHumidity(h, p, t, provider.waterVaporPressure(p, t, rh), + pth0.getTm(), pth0.getLambda()); } @@ -80,7 +81,8 @@ public > FieldPressureTemperatureHumidity c final T t = pth0.getTemperature().subtract(dh.multiply(6.5e-3)); final T p = pth0.getPressure().multiply(dh.multiply(2.26e-5).negate().add(1.0).pow(5.225)); final T rh = rh0.multiply(FastMath.exp(dh.multiply(-6.396e-4))); - return new FieldPressureTemperatureHumidity<>(h, p, t, provider.waterVaporPressure(p, t, rh)); + return new FieldPressureTemperatureHumidity<>(h, p, t, provider.waterVaporPressure(p, t, rh), + pth0.getTm(), pth0.getLambda()); } } diff --git a/src/main/java/org/orekit/models/earth/weather/PressureTemperatureHumidity.java b/src/main/java/org/orekit/models/earth/weather/PressureTemperatureHumidity.java index cbb94fb78f..0741a2cc8b 100644 --- a/src/main/java/org/orekit/models/earth/weather/PressureTemperatureHumidity.java +++ b/src/main/java/org/orekit/models/earth/weather/PressureTemperatureHumidity.java @@ -25,18 +25,30 @@ public class PressureTemperatureHumidity extends PressureTemperature { /** Humidity as water vapor pressure (Pa). */ private final double waterVaporPressure; + /** Mean temperature weighted with water vapor pressure. */ + private final double tm; + + /** Water vapor decrease factor. */ + private final double lambda; + /** Simple constructor. * @param altitude altitude at which weather parameters have been computed (m) * @param pressure pressure (Pa) * @param temperature temperature (Kelvin) * @param waterVaporPressure humidity as water vapor pressure (Pa) + * @param tm mean temperature weighted with water vapor pressure + * @param lambda water vapor decrease factor */ public PressureTemperatureHumidity(final double altitude, final double pressure, final double temperature, - final double waterVaporPressure) { + final double waterVaporPressure, + final double tm, + final double lambda) { super(altitude, pressure, temperature); this.waterVaporPressure = waterVaporPressure; + this.tm = tm; + this.lambda = lambda; } /** Get humidity as water vapor pressure. @@ -46,4 +58,18 @@ public double getWaterVaporPressure() { return waterVaporPressure; } + /** Get mean temperature weighted with water vapor pressure. + * @return mean temperature weighted with water vapor pressure + */ + public double getTm() { + return tm; + } + + /** Get water vapor decrease factor. + * @return water vapor decrease factor + */ + public double getLambda() { + return lambda; + } + } diff --git a/src/test/java/org/orekit/estimation/common/AbstractOrbitDetermination.java b/src/test/java/org/orekit/estimation/common/AbstractOrbitDetermination.java index 5c106d4adb..316f4939a7 100644 --- a/src/test/java/org/orekit/estimation/common/AbstractOrbitDetermination.java +++ b/src/test/java/org/orekit/estimation/common/AbstractOrbitDetermination.java @@ -2334,7 +2334,8 @@ private List> readCrd(final DataSource source, new CIPM2007(). waterVaporPressure(Unit.BAR.toSI(meteoData.getPressure()), meteoData.getTemperature(), - 0.01 * meteoData.getHumidity())); + 0.01 * meteoData.getHumidity()), + Double.NaN, Double.NaN); model = new MendesPavlisModel(new ConstantPressureTemperatureHumidityProvider(pth), wavelength, Unit.METRE); } else { diff --git a/src/test/java/org/orekit/models/earth/troposphere/FieldMendesPavlisModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/FieldMendesPavlisModelTest.java index c3f67e1d51..eb73263d48 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/FieldMendesPavlisModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/FieldMendesPavlisModelTest.java @@ -105,7 +105,9 @@ private > void doTestZenithDelay(final Field point = new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), zero.add(height)); @@ -166,7 +168,9 @@ private > void doTestMappingFactors(final Fiel new CIPM2007(). waterVaporPressure(pressure, temperature, - humidity)); + humidity), + Double.NaN, + Double.NaN); final double lambda = 0.532; final FieldGeodeticPoint point = new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), zero.add(height)); diff --git a/src/test/java/org/orekit/models/earth/troposphere/FieldViennaOneModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/FieldViennaOneModelTest.java index 7e318b7af9..6ac9be284c 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/FieldViennaOneModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/FieldViennaOneModelTest.java @@ -56,6 +56,7 @@ import org.orekit.utils.IERSConventions; import org.orekit.utils.TrackingCoordinates; +@Deprecated public class FieldViennaOneModelTest { private static double epsilon = 1e-6; diff --git a/src/test/java/org/orekit/models/earth/troposphere/FieldViennaOneTest.java b/src/test/java/org/orekit/models/earth/troposphere/FieldViennaOneTest.java new file mode 100644 index 0000000000..51c64292be --- /dev/null +++ b/src/test/java/org/orekit/models/earth/troposphere/FieldViennaOneTest.java @@ -0,0 +1,360 @@ +/* Copyright 2002-2023 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import org.hipparchus.CalculusFieldElement; +import org.hipparchus.Field; +import org.hipparchus.analysis.differentiation.DSFactory; +import org.hipparchus.analysis.differentiation.DerivativeStructure; +import org.hipparchus.geometry.euclidean.threed.FieldVector3D; +import org.hipparchus.geometry.euclidean.threed.Vector3D; +import org.hipparchus.util.Binary64Field; +import org.hipparchus.util.FastMath; +import org.hipparchus.util.Precision; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.orekit.Utils; +import org.orekit.attitudes.Attitude; +import org.orekit.bodies.FieldGeodeticPoint; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.bodies.OneAxisEllipsoid; +import org.orekit.errors.OrekitException; +import org.orekit.estimation.measurements.GroundStation; +import org.orekit.frames.Frame; +import org.orekit.frames.FramesFactory; +import org.orekit.frames.TopocentricFrame; +import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; +import org.orekit.orbits.FieldKeplerianOrbit; +import org.orekit.orbits.FieldOrbit; +import org.orekit.orbits.Orbit; +import org.orekit.orbits.OrbitType; +import org.orekit.orbits.PositionAngleType; +import org.orekit.propagation.FieldSpacecraftState; +import org.orekit.propagation.SpacecraftState; +import org.orekit.propagation.numerical.NumericalPropagator; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; +import org.orekit.time.TimeScalesFactory; +import org.orekit.utils.Constants; +import org.orekit.utils.FieldTrackingCoordinates; +import org.orekit.utils.IERSConventions; +import org.orekit.utils.TrackingCoordinates; + +public class FieldViennaOneTest { + + private static double epsilon = 1e-6; + + @BeforeAll + public static void setUpGlobal() { + Utils.setDataRoot("atmosphere"); + } + + @BeforeEach + public void setUp() throws OrekitException { + Utils.setDataRoot("regular-data:potential/shm-format"); + } + + @Test + public void testMappingFactors() { + doTestMappingFactors(Binary64Field.getInstance()); + } + + private > void doTestMappingFactors(final Field field) { + final T zero = field.getZero(); + // Site (NRAO, Green Bank, WV): latitude: 38° + // longitude: 280° + // height: 824.17 m + // + // Date: MJD 55055 -> 12 August 2009 at 0h UT + // + // Ref for the inputs: Petit, G. and Luzum, B. (eds.), IERS Conventions (2010), + // IERS Technical Note No. 36, BKG (2010) + // + // Values: ah = 0.00127683 + // aw = 0.00060955 + // zhd = 2.0966 m + // zwd = 0.2140 m + // + // Values taken from: http://vmf.geo.tuwien.ac.at/trop_products/GRID/2.5x2/VMF1/VMF1_OP/2009/VMFG_20090812.H00 + // + // Expected mapping factors : hydrostatic -> 3.425088 + // wet -> 3.448300 + // + // Expected outputs are obtained by performing the Matlab script vmf1_ht.m provided by TU WIEN: + // http://vmf.geo.tuwien.ac.at/codes/ + // + + final FieldAbsoluteDate date = FieldAbsoluteDate.createMJDDate(55055, zero, TimeScalesFactory.getUTC()); + + final double latitude = FastMath.toRadians(38.0); + final double longitude = FastMath.toRadians(280.0); + final double height = 824.17; + + final FieldTrackingCoordinates trackingCoordinates = + new FieldTrackingCoordinates<>(zero, + zero.newInstance(0.5 * FastMath.PI - 1.278564131), + zero); + final double expectedHydro = 3.425088; + final double expectedWet = 3.448300; + + final FieldGeodeticPoint point = new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), zero.add(height)); + final ViennaOne model = new ViennaOne(new ConstantViennaAProvider(new ViennaACoefficients(0.00127683, 0.00060955)), + new ConstantTroposphericModel(new TroposphericDelay(2.0966, 0.2140, 0, 0)), + TimeScalesFactory.getUTC()); + + final T[] computedMapping = model.mappingFactors(trackingCoordinates, point, + new FieldPressureTemperatureHumidity<>(field, + TroposphericModelUtils.STANDARD_ATMOSPHERE), + date); + + Assertions.assertEquals(expectedHydro, computedMapping[0].getReal(), 4.1e-6); + Assertions.assertEquals(expectedWet, computedMapping[1].getReal(), 1.0e-6); + } + + @Test + public void testDelay() { + doTestDelay(Binary64Field.getInstance()); + } + + private > void doTestDelay(final Field field) { + final T zero = field.getZero(); + final double elevation = 10d; + final double height = 100d; + final FieldAbsoluteDate date = new FieldAbsoluteDate<>(field); + final FieldGeodeticPoint point = new FieldGeodeticPoint<>(zero.add(FastMath.toRadians(45.0)), zero.add(FastMath.toRadians(45.0)), zero.add(height)); + ViennaOne model = new ViennaOne(new ConstantViennaAProvider(new ViennaACoefficients(0.00127683, 0.00060955)), + new ConstantTroposphericModel(new TroposphericDelay(2.0966, 0.2140, 0, 0)), + TimeScalesFactory.getUTC()); + final T path = model.pathDelay(new FieldTrackingCoordinates<>(zero, + zero.newInstance(FastMath.toRadians(elevation)), + zero), + point, + new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + model.getParameters(field), date).getDelay(); + Assertions.assertTrue(Precision.compareTo(path.getReal(), 20d, epsilon) < 0); + Assertions.assertTrue(Precision.compareTo(path.getReal(), 0d, epsilon) > 0); + } + + @Test + public void testFixedHeight() { + doTestFixedHeight(Binary64Field.getInstance()); + } + + private > void doTestFixedHeight(final Field field) { + final T zero = field.getZero(); + final FieldAbsoluteDate date = new FieldAbsoluteDate<>(field); + final FieldGeodeticPoint point = new FieldGeodeticPoint<>(zero.add(FastMath.toRadians(45.0)), zero.add(FastMath.toRadians(45.0)), zero.add(350.0)); + ViennaOne model = new ViennaOne(new ConstantViennaAProvider(new ViennaACoefficients(0.00127683, 0.00060955)), + new ConstantTroposphericModel(new TroposphericDelay(2.0966, 0.2140, 0, 0)), + TimeScalesFactory.getUTC()); + T lastDelay = zero.add(Double.MAX_VALUE); + // delay shall decline with increasing elevation angle + for (double elev = 10d; elev < 90d; elev += 8d) { + final T delay = model.pathDelay(new FieldTrackingCoordinates<>(zero, + zero.newInstance(FastMath.toRadians(elev)), + zero), + point, + new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + model.getParameters(field), date).getDelay(); + Assertions.assertTrue(Precision.compareTo(delay.getReal(), lastDelay.getReal(), epsilon) < 0); + lastDelay = delay; + } + } + + @Test + public void testDelayStateDerivatives() { + + // Geodetic point + final double latitude = FastMath.toRadians(45.0); + final double longitude = FastMath.toRadians(45.0); + final double height = 0.0; + final GeodeticPoint point = new GeodeticPoint(latitude, longitude, height); + // Body: earth + final OneAxisEllipsoid earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS, + Constants.WGS84_EARTH_FLATTENING, + FramesFactory.getITRF(IERSConventions.IERS_2010, true)); + // Topocentric frame + final TopocentricFrame baseFrame = new TopocentricFrame(earth, point, "topo"); + + // Station + final GroundStation station = new GroundStation(baseFrame, + TroposphericModelUtils.STANDARD_ATMOSPHERE_PROVIDER); + + // Tropospheric model + final TroposphericModel model = new ViennaOne(new ConstantViennaAProvider(new ViennaACoefficients(0.00127683, 0.00060955)), + new ConstantTroposphericModel(new TroposphericDelay(2.0966, 0.2140, 0, 0)), + TimeScalesFactory.getUTC()); + + // Derivative Structure + final DSFactory factory = new DSFactory(6, 1); + final DerivativeStructure a0 = factory.variable(0, 24464560.0); + final DerivativeStructure e0 = factory.variable(1, 0.05); + final DerivativeStructure i0 = factory.variable(2, 0.122138); + final DerivativeStructure pa0 = factory.variable(3, 3.10686); + final DerivativeStructure raan0 = factory.variable(4, 1.00681); + final DerivativeStructure anomaly0 = factory.variable(5, 0.048363); + final Field field = a0.getField(); + final DerivativeStructure zero = field.getZero(); + + // Field Date + final FieldAbsoluteDate dsDate = new FieldAbsoluteDate<>(field, 2018, 11, 19, 18, 0, 0.0, + TimeScalesFactory.getUTC()); + // Field Orbit + final Frame frame = FramesFactory.getEME2000(); + final FieldOrbit dsOrbit = new FieldKeplerianOrbit<>(a0, e0, i0, pa0, raan0, anomaly0, + PositionAngleType.MEAN, frame, + dsDate, zero.add(3.9860047e14)); + // Field State + final FieldSpacecraftState dsState = new FieldSpacecraftState<>(dsOrbit); + + // Initial satellite elevation + final FieldVector3D position = dsState.getPosition(); + final FieldTrackingCoordinates dsTrackingCoordinates = + baseFrame.getTrackingCoordinates(position, frame, dsDate); + + // Compute delay state derivatives + final FieldGeodeticPoint dsPoint = new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), zero.add(height)); + final DerivativeStructure delay = model.pathDelay(dsTrackingCoordinates, dsPoint, + new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + model.getParameters(field), dsDate).getDelay(); + + final double[] compDelay = delay.getAllDerivatives(); + + // Field -> non-field + final Orbit orbit = dsOrbit.toOrbit(); + final SpacecraftState state = dsState.toSpacecraftState(); + + // Finite differences for reference values + final double[][] refDeriv = new double[1][6]; + final OrbitType orbitType = OrbitType.KEPLERIAN; + final PositionAngleType angleType = PositionAngleType.MEAN; + double dP = 0.001; + double[] steps = NumericalPropagator.tolerances(1000000 * dP, orbit, orbitType)[0]; + for (int i = 0; i < 6; i++) { + SpacecraftState stateM4 = shiftState(state, orbitType, angleType, -4 * steps[i], i); + final Vector3D positionM4 = stateM4.getPosition(); + final TrackingCoordinates trackingCoordinatesM4 = station.getBaseFrame(). + getTrackingCoordinates(positionM4, stateM4.getFrame(), stateM4.getDate()); + double delayM4 = model.pathDelay(trackingCoordinatesM4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateM4.getDate()).getDelay(); + + SpacecraftState stateM3 = shiftState(state, orbitType, angleType, -3 * steps[i], i); + final Vector3D positionM3 = stateM3.getPosition(); + final TrackingCoordinates trackingCoordinatesM3 = station.getBaseFrame(). + getTrackingCoordinates(positionM3, stateM3.getFrame(), stateM3.getDate()); + double delayM3 = model.pathDelay(trackingCoordinatesM3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateM3.getDate()).getDelay(); + + SpacecraftState stateM2 = shiftState(state, orbitType, angleType, -2 * steps[i], i); + final Vector3D positionM2 = stateM2.getPosition(); + final TrackingCoordinates trackingCoordinatesM2 = station.getBaseFrame(). + getTrackingCoordinates(positionM2, stateM2.getFrame(), stateM2.getDate()); + double delayM2 = model.pathDelay(trackingCoordinatesM2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateM2.getDate()).getDelay(); + + SpacecraftState stateM1 = shiftState(state, orbitType, angleType, -1 * steps[i], i); + final Vector3D positionM1 = stateM1.getPosition(); + final TrackingCoordinates trackingCoordinatesM1 = station.getBaseFrame(). + getTrackingCoordinates(positionM1, stateM1.getFrame(), stateM1.getDate()); + double delayM1 = model.pathDelay(trackingCoordinatesM1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateM1.getDate()).getDelay(); + + SpacecraftState stateP1 = shiftState(state, orbitType, angleType, 1 * steps[i], i); + final Vector3D positionP1 = stateP1.getPosition(); + final TrackingCoordinates trackingCoordinatesP1 = station.getBaseFrame(). + getTrackingCoordinates(positionP1, stateP1.getFrame(), stateP1.getDate()); + double delayP1 = model.pathDelay(trackingCoordinatesP1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateP1.getDate()).getDelay(); + + SpacecraftState stateP2 = shiftState(state, orbitType, angleType, 2 * steps[i], i); + final Vector3D positionP2 = stateP2.getPosition(); + final TrackingCoordinates trackingCoordinatesP2 = station.getBaseFrame(). + getTrackingCoordinates(positionP2, stateP2.getFrame(), stateP2.getDate()); + double delayP2 = model.pathDelay(trackingCoordinatesP2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateP2.getDate()).getDelay(); + + SpacecraftState stateP3 = shiftState(state, orbitType, angleType, 3 * steps[i], i); + final Vector3D positionP3 = stateP3.getPosition(); + final TrackingCoordinates trackingCoordinatesP3 = station.getBaseFrame(). + getTrackingCoordinates(positionP3, stateP3.getFrame(), stateP3.getDate()); + double delayP3 = model.pathDelay(trackingCoordinatesP3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateP3.getDate()).getDelay(); + + SpacecraftState stateP4 = shiftState(state, orbitType, angleType, 4 * steps[i], i); + final Vector3D positionP4 = stateP4.getPosition(); + final TrackingCoordinates trackingCoordinatesP4 = station.getBaseFrame(). + getTrackingCoordinates(positionP4, stateP4.getFrame(), stateP4.getDate()); + double delayP4 = model.pathDelay(trackingCoordinatesP4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateP4.getDate()).getDelay(); + + fillJacobianColumn(refDeriv, i, orbitType, angleType, steps[i], + delayM4, delayM3, delayM2, delayM1, + delayP1, delayP2, delayP3, delayP4); + } + + for (int i = 0; i < 6; i++) { + Assertions.assertEquals(compDelay[i + 1], refDeriv[0][i], 3.0e-11); + } + } + + private void fillJacobianColumn(double[][] jacobian, int column, + OrbitType orbitType, PositionAngleType angleType, double h, + double sM4h, double sM3h, + double sM2h, double sM1h, + double sP1h, double sP2h, + double sP3h, double sP4h) { + for (int i = 0; i < jacobian.length; ++i) { + jacobian[i][column] = ( -3 * (sP4h - sM4h) + + 32 * (sP3h - sM3h) - + 168 * (sP2h - sM2h) + + 672 * (sP1h - sM1h)) / (840 * h); + } + } + + private SpacecraftState shiftState(SpacecraftState state, OrbitType orbitType, PositionAngleType angleType, + double delta, int column) { + + double[][] array = stateToArray(state, orbitType, angleType, true); + array[0][column] += delta; + + return arrayToState(array, orbitType, angleType, state.getFrame(), state.getDate(), + state.getMu(), state.getAttitude()); + + } + + private double[][] stateToArray(SpacecraftState state, OrbitType orbitType, PositionAngleType angleType, + boolean withMass) { + double[][] array = new double[2][withMass ? 7 : 6]; + orbitType.mapOrbitToArray(state.getOrbit(), angleType, array[0], array[1]); + if (withMass) { + array[0][6] = state.getMass(); + } + return array; + } + + private SpacecraftState arrayToState(double[][] array, OrbitType orbitType, PositionAngleType angleType, + Frame frame, AbsoluteDate date, double mu, + Attitude attitude) { + Orbit orbit = orbitType.mapArrayToOrbit(array[0], array[1], angleType, date, mu, frame); + return (array.length > 6) ? + new SpacecraftState(orbit, attitude) : + new SpacecraftState(orbit, attitude, array[0][6]); + } + +} diff --git a/src/test/java/org/orekit/models/earth/troposphere/FieldViennaThreeModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/FieldViennaThreeModelTest.java index b77d5a0d25..451880a120 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/FieldViennaThreeModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/FieldViennaThreeModelTest.java @@ -56,6 +56,7 @@ import org.orekit.utils.IERSConventions; import org.orekit.utils.TrackingCoordinates; +@Deprecated public class FieldViennaThreeModelTest { private static double epsilon = 1e-6; diff --git a/src/test/java/org/orekit/models/earth/troposphere/FieldViennaThreeTest.java b/src/test/java/org/orekit/models/earth/troposphere/FieldViennaThreeTest.java new file mode 100644 index 0000000000..96c0cedc2d --- /dev/null +++ b/src/test/java/org/orekit/models/earth/troposphere/FieldViennaThreeTest.java @@ -0,0 +1,467 @@ +/* Copyright 2002-2023 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.models.earth.troposphere; + +import org.hipparchus.CalculusFieldElement; +import org.hipparchus.Field; +import org.hipparchus.analysis.differentiation.DSFactory; +import org.hipparchus.analysis.differentiation.DerivativeStructure; +import org.hipparchus.geometry.euclidean.threed.FieldVector3D; +import org.hipparchus.geometry.euclidean.threed.Vector3D; +import org.hipparchus.util.Binary64Field; +import org.hipparchus.util.FastMath; +import org.hipparchus.util.Precision; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.orekit.Utils; +import org.orekit.attitudes.Attitude; +import org.orekit.bodies.FieldGeodeticPoint; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.bodies.OneAxisEllipsoid; +import org.orekit.errors.OrekitException; +import org.orekit.estimation.measurements.GroundStation; +import org.orekit.frames.Frame; +import org.orekit.frames.FramesFactory; +import org.orekit.frames.TopocentricFrame; +import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity; +import org.orekit.orbits.FieldKeplerianOrbit; +import org.orekit.orbits.FieldOrbit; +import org.orekit.orbits.Orbit; +import org.orekit.orbits.OrbitType; +import org.orekit.orbits.PositionAngleType; +import org.orekit.propagation.FieldSpacecraftState; +import org.orekit.propagation.SpacecraftState; +import org.orekit.propagation.numerical.NumericalPropagator; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; +import org.orekit.time.TimeScalesFactory; +import org.orekit.utils.Constants; +import org.orekit.utils.FieldTrackingCoordinates; +import org.orekit.utils.IERSConventions; +import org.orekit.utils.TrackingCoordinates; + +public class FieldViennaThreeTest { + + private static double epsilon = 1e-6; + + @BeforeAll + public static void setUpGlobal() { + Utils.setDataRoot("atmosphere"); + } + + @BeforeEach + public void setUp() throws OrekitException { + Utils.setDataRoot("regular-data:potential/shm-format"); + } + + @Test + public void testMappingFactors() { + doTestMappingFactors(Binary64Field.getInstance()); + } + + private > void doTestMappingFactors(final Field field) { + + final T zero = field.getZero(); + + // Site: latitude: 37.5° + // longitude: 277.5° + // height: 824 m + // + // Date: 25 November 2018 at 0h UT + // + // Values: ah = 0.00123462 + // aw = 0.00047101 + // zhd = 2.1993 m + // zwd = 0.0690 m + // + // Values taken from: http://vmf.geo.tuwien.ac.at/trop_products/GRID/5x5/VMF3/VMF3_OP/2018/VMF3_20181125.H00 + // + // Expected mapping factors : hydrostatic -> 1.621024 + // wet -> 1.623023 + // + // Expected outputs are obtained by performing the Matlab script vmf3.m provided by TU WIEN: + // http://vmf.geo.tuwien.ac.at/codes/ + // + + final FieldAbsoluteDate date = new FieldAbsoluteDate<>(field, 2018, 11, 25, TimeScalesFactory.getUTC()); + + final double latitude = FastMath.toRadians(37.5); + final double longitude = FastMath.toRadians(277.5); + final double height = 824.0; + + final FieldTrackingCoordinates trackingCoordinates = + new FieldTrackingCoordinates(zero, zero.newInstance(FastMath.toRadians(38.0)), zero); + final double expectedHydro = 1.621024; + final double expectedWet = 1.623023; + + final FieldGeodeticPoint point = new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), zero.add(height)); + + final ViennaThree model = new ViennaThree(new ConstantViennaAProvider(new ViennaACoefficients(0.00123462, 0.00047101)), + new ConstantTroposphericModel(new TroposphericDelay(2.1993, 0.0690, 0, 0)), + TimeScalesFactory.getUTC()); + + final T[] computedMapping = model.mappingFactors(trackingCoordinates, point, + new FieldPressureTemperatureHumidity<>(field, + TroposphericModelUtils.STANDARD_ATMOSPHERE), + date); + + Assertions.assertEquals(expectedHydro, computedMapping[0].getReal(), epsilon); + Assertions.assertEquals(expectedWet, computedMapping[1].getReal(), epsilon); + } + + @Test + public void testLowElevation() { + doTestLowElevation(Binary64Field.getInstance()); + } + + private > void doTestLowElevation(final Field field) { + + final T zero = field.getZero(); + + // Site: latitude: 37.5° + // longitude: 277.5° + // height: 824 m + // + // Date: 25 November 2018 at 0h UT + // + // Values: ah = 0.00123462 + // aw = 0.00047101 + // zhd = 2.1993 m + // zwd = 0.0690 m + // + // Values taken from: http://vmf.geo.tuwien.ac.at/trop_products/GRID/5x5/VMF3/VMF3_OP/2018/VMF3_20181125.H00 + // + // Expected mapping factors : hydrostatic -> 10.132802 + // wet -> 10.879154 + // + // Expected outputs are obtained by performing the Matlab script vmf3.m provided by TU WIEN: + // http://vmf.geo.tuwien.ac.at/codes/ + // + + final FieldAbsoluteDate date = new FieldAbsoluteDate<>(field, 2018, 11, 25, TimeScalesFactory.getUTC()); + + final double latitude = FastMath.toRadians(37.5); + final double longitude = FastMath.toRadians(277.5); + final double height = 824.0; + + final double elevation = FastMath.toRadians(5.0); + final double expectedHydro = 10.132802; + final double expectedWet = 10.879154; + + final FieldGeodeticPoint point = new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), zero.add(height)); + + final ViennaThree model = new ViennaThree(new ConstantViennaAProvider(new ViennaACoefficients(0.00123462, 0.00047101)), + new ConstantTroposphericModel(new TroposphericDelay(2.1993, 0.0690, 0, 0)), + TimeScalesFactory.getUTC()); + + final T[] computedMapping = model.mappingFactors(new FieldTrackingCoordinates(zero, zero.newInstance(elevation), zero), + point, + new FieldPressureTemperatureHumidity<>(field, + TroposphericModelUtils.STANDARD_ATMOSPHERE), + date); + + Assertions.assertEquals(expectedHydro, computedMapping[0].getReal(), epsilon); + Assertions.assertEquals(expectedWet, computedMapping[1].getReal(), epsilon); + } + + @Test + public void testHightElevation() { + doTestHightElevation(Binary64Field.getInstance()); + } + + private > void doTestHightElevation(final Field field) { + + final T zero = field.getZero(); + + // Site: latitude: 37.5° + // longitude: 277.5° + // height: 824 m + // + // Date: 25 November 2018 at 0h UT + // + // Values: ah = 0.00123462 + // aw = 0.00047101 + // zhd = 2.1993 m + // zwd = 0.0690 m + // + // Values taken from: http://vmf.geo.tuwien.ac.at/trop_products/GRID/5x5/VMF3/VMF3_OP/2018/VMF3_20181125.H00 + // + // Expected mapping factors : hydrostatic -> 1.003810 + // wet -> 1.003816 + // + // Expected outputs are obtained by performing the Matlab script vmf3.m provided by TU WIEN: + // http://vmf.geo.tuwien.ac.at/codes/ + // + + final FieldAbsoluteDate date = new FieldAbsoluteDate<>(field, 2018, 11, 25, TimeScalesFactory.getUTC()); + + final double latitude = FastMath.toRadians(37.5); + final double longitude = FastMath.toRadians(277.5); + final double height = 824.0; + + final double elevation = FastMath.toRadians(85.0); + final double expectedHydro = 1.003810; + final double expectedWet = 1.003816; + + final FieldGeodeticPoint point = new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), zero.add(height)); + + final ViennaThree model = new ViennaThree(new ConstantViennaAProvider(new ViennaACoefficients(0.00123462, 0.00047101)), + new ConstantTroposphericModel(new TroposphericDelay(2.1993, 0.0690, 0, 0)), + TimeScalesFactory.getUTC()); + + final T[] computedMapping = model.mappingFactors(new FieldTrackingCoordinates(zero, zero.newInstance(elevation), zero), + point, + new FieldPressureTemperatureHumidity<>(field, + TroposphericModelUtils.STANDARD_ATMOSPHERE), + date); + + Assertions.assertEquals(expectedHydro, computedMapping[0].getReal(), epsilon); + Assertions.assertEquals(expectedWet, computedMapping[1].getReal(), epsilon); + } + + @Test + public void testDelay() { + doTestDelay(Binary64Field.getInstance()); + } + + private > void doTestDelay(final Field field) { + final T zero = field.getZero(); + final double elevation = 10d; + final double height = 100d; + final FieldAbsoluteDate date = new FieldAbsoluteDate<>(field); + final FieldGeodeticPoint point = new FieldGeodeticPoint<>(zero.add(FastMath.toRadians(37.5)), zero.add(FastMath.toRadians(277.5)), zero.add(height)); + ViennaThree model = new ViennaThree(new ConstantViennaAProvider(new ViennaACoefficients(0.00123462, 0.00047101)), + new ConstantTroposphericModel(new TroposphericDelay(2.1993, 0.0690, 0, 0)), + TimeScalesFactory.getUTC()); + final FieldTroposphericDelay delay = model.pathDelay(new FieldTrackingCoordinates(zero, zero.newInstance(FastMath.toRadians(elevation)), zero), + point, + new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + model.getParameters(field), date); + Assertions.assertEquals( 2.1993, delay.getZh().getReal(), 1.0e-4); + Assertions.assertEquals( 0.069, delay.getZw().getReal(), 1.0e-4); + Assertions.assertEquals(12.2124, delay.getSh().getReal(), 1.0e-4); + Assertions.assertEquals( 0.3916, delay.getSw().getReal(), 1.0e-4); + Assertions.assertEquals(12.6041, delay.getDelay().getReal(), 1.0e-4); + } + + @Test + public void testFixedHeight() { + doTestFixedHeight(Binary64Field.getInstance()); + } + + private > void doTestFixedHeight(final Field field) { + final T zero = field.getZero(); + final FieldAbsoluteDate date = new FieldAbsoluteDate<>(field); + final FieldGeodeticPoint point = new FieldGeodeticPoint<>(zero.add(FastMath.toRadians(37.5)), zero.add(FastMath.toRadians(277.5)), zero.add(350.0)); + ViennaThree model = new ViennaThree(new ConstantViennaAProvider(new ViennaACoefficients(0.00123462, 0.00047101)), + new ConstantTroposphericModel(new TroposphericDelay(2.1993, 0.0690, 0, 0)), + TimeScalesFactory.getUTC()); + T lastDelay = zero.add(Double.MAX_VALUE); + // delay shall decline with increasing elevation angle + for (double elev = 10d; elev < 90d; elev += 8d) { + final T delay = model.pathDelay(new FieldTrackingCoordinates(zero, zero.newInstance(FastMath.toRadians(elev)), zero), + point, + new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + model.getParameters(field), date).getDelay(); + Assertions.assertTrue(Precision.compareTo(delay.getReal(), lastDelay.getReal(), epsilon) < 0); + lastDelay = delay; + } + } + + @Test + public void testDelayStateDerivatives() { + + // Geodetic point + final double latitude = FastMath.toRadians(45.0); + final double longitude = FastMath.toRadians(45.0); + final double height = 0.0; + final GeodeticPoint point = new GeodeticPoint(latitude, longitude, height); + // Body: earth + final OneAxisEllipsoid earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS, + Constants.WGS84_EARTH_FLATTENING, + FramesFactory.getITRF(IERSConventions.IERS_2010, true)); + // Topocentric frame + final TopocentricFrame baseFrame = new TopocentricFrame(earth, point, "topo"); + + // Station + final GroundStation station = new GroundStation(baseFrame, + TroposphericModelUtils.STANDARD_ATMOSPHERE_PROVIDER); + + // Tropospheric model + final TroposphericModel model = new ViennaThree(new ConstantViennaAProvider(new ViennaACoefficients(00.00127683, 0.00060955)), + new ConstantTroposphericModel(new TroposphericDelay(2.0966, 0.2140, 0, 0)), + TimeScalesFactory.getUTC()); + + // Derivative Structure + final DSFactory factory = new DSFactory(6, 1); + final DerivativeStructure a0 = factory.variable(0, 24464560.0); + final DerivativeStructure e0 = factory.variable(1, 0.05); + final DerivativeStructure i0 = factory.variable(2, 0.122138); + final DerivativeStructure pa0 = factory.variable(3, 3.10686); + final DerivativeStructure raan0 = factory.variable(4, 1.00681); + final DerivativeStructure anomaly0 = factory.variable(5, 0.048363); + final Field field = a0.getField(); + final DerivativeStructure zero = field.getZero(); + + // Field Date + final FieldAbsoluteDate dsDate = new FieldAbsoluteDate<>(field, 2018, 11, 19, 18, 0, 0.0, + TimeScalesFactory.getUTC()); + // Field Orbit + final Frame frame = FramesFactory.getEME2000(); + final FieldOrbit dsOrbit = new FieldKeplerianOrbit<>(a0, e0, i0, pa0, raan0, anomaly0, + PositionAngleType.MEAN, frame, + dsDate, zero.add(3.9860047e14)); + // Field State + final FieldSpacecraftState dsState = new FieldSpacecraftState<>(dsOrbit); + + // Initial satellite elevation + final FieldVector3D position = dsState.getPosition(); + final FieldTrackingCoordinates dsTrackingCoordinates = + baseFrame.getTrackingCoordinates(position, frame, dsDate); + + // Compute delay state derivatives + final FieldGeodeticPoint dsPoint = new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), zero.add(height)); + final DerivativeStructure delay = model.pathDelay(dsTrackingCoordinates, dsPoint, + new FieldPressureTemperatureHumidity<>(field, TroposphericModelUtils.STANDARD_ATMOSPHERE), + model.getParameters(field), dsDate).getDelay(); + + final double[] compDelay = delay.getAllDerivatives(); + + // Field -> non-field + final Orbit orbit = dsOrbit.toOrbit(); + final SpacecraftState state = dsState.toSpacecraftState(); + + // Finite differences for reference values + final double[][] refDeriv = new double[1][6]; + final OrbitType orbitType = OrbitType.KEPLERIAN; + final PositionAngleType angleType = PositionAngleType.MEAN; + double dP = 0.001; + double[] steps = NumericalPropagator.tolerances(1000000 * dP, orbit, orbitType)[0]; + for (int i = 0; i < 6; i++) { + SpacecraftState stateM4 = shiftState(state, orbitType, angleType, -4 * steps[i], i); + final Vector3D positionM4 = stateM4.getPosition(); + final TrackingCoordinates trackingCoordinatesM4 = station.getBaseFrame(). + getTrackingCoordinates(positionM4, stateM4.getFrame(), stateM4.getDate()); + double delayM4 = model.pathDelay(trackingCoordinatesM4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateM4.getDate()).getDelay(); + + SpacecraftState stateM3 = shiftState(state, orbitType, angleType, -3 * steps[i], i); + final Vector3D positionM3 = stateM3.getPosition(); + final TrackingCoordinates trackingCoordinatesM3 = station.getBaseFrame(). + getTrackingCoordinates(positionM3, stateM3.getFrame(), stateM3.getDate()); + double delayM3 = model.pathDelay(trackingCoordinatesM3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateM3.getDate()).getDelay(); + + SpacecraftState stateM2 = shiftState(state, orbitType, angleType, -2 * steps[i], i); + final Vector3D positionM2 = stateM2.getPosition(); + final TrackingCoordinates trackingCoordinatesM2 = station.getBaseFrame(). + getTrackingCoordinates(positionM2, stateM2.getFrame(), stateM2.getDate()); + double delayM2 = model.pathDelay(trackingCoordinatesM2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateM2.getDate()).getDelay(); + + SpacecraftState stateM1 = shiftState(state, orbitType, angleType, -1 * steps[i], i); + final Vector3D positionM1 = stateM1.getPosition(); + final TrackingCoordinates trackingCoordinatesM1 = station.getBaseFrame(). + getTrackingCoordinates(positionM1, stateM1.getFrame(), stateM1.getDate()); + double delayM1 = model.pathDelay(trackingCoordinatesM1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateM1.getDate()).getDelay(); + + SpacecraftState stateP1 = shiftState(state, orbitType, angleType, 1 * steps[i], i); + final Vector3D positionP1 = stateP1.getPosition(); + final TrackingCoordinates trackingCoordinatesP1 = station.getBaseFrame(). + getTrackingCoordinates(positionP1, stateP1.getFrame(), stateP1.getDate()); + double delayP1 = model.pathDelay(trackingCoordinatesP1, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateP1.getDate()).getDelay(); + + SpacecraftState stateP2 = shiftState(state, orbitType, angleType, 2 * steps[i], i); + final Vector3D positionP2 = stateP2.getPosition(); + final TrackingCoordinates trackingCoordinatesP2 = station.getBaseFrame(). + getTrackingCoordinates(positionP2, stateP2.getFrame(), stateP2.getDate()); + double delayP2 = model.pathDelay(trackingCoordinatesP2, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateP2.getDate()).getDelay(); + + SpacecraftState stateP3 = shiftState(state, orbitType, angleType, 3 * steps[i], i); + final Vector3D positionP3 = stateP3.getPosition(); + final TrackingCoordinates trackingCoordinatesP3 = station.getBaseFrame(). + getTrackingCoordinates(positionP3, stateP3.getFrame(), stateP3.getDate()); + double delayP3 = model.pathDelay(trackingCoordinatesP3, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateP3.getDate()).getDelay(); + + SpacecraftState stateP4 = shiftState(state, orbitType, angleType, 4 * steps[i], i); + final Vector3D positionP4 = stateP4.getPosition(); + final TrackingCoordinates trackingCoordinatesP4 = station.getBaseFrame(). + getTrackingCoordinates(positionP4, stateP4.getFrame(), stateP4.getDate()); + double delayP4 = model.pathDelay(trackingCoordinatesP4, point, TroposphericModelUtils.STANDARD_ATMOSPHERE, + model.getParameters(), stateP4.getDate()).getDelay(); + + fillJacobianColumn(refDeriv, i, orbitType, angleType, steps[i], + delayM4, delayM3, delayM2, delayM1, + delayP1, delayP2, delayP3, delayP4); + } + + for (int i = 0; i < 6; i++) { + Assertions.assertEquals(compDelay[i + 1], refDeriv[0][i], 6.2e-12); + } + } + + private void fillJacobianColumn(double[][] jacobian, int column, + OrbitType orbitType, PositionAngleType angleType, double h, + double sM4h, double sM3h, + double sM2h, double sM1h, + double sP1h, double sP2h, + double sP3h, double sP4h) { + for (int i = 0; i < jacobian.length; ++i) { + jacobian[i][column] = ( -3 * (sP4h - sM4h) + + 32 * (sP3h - sM3h) - + 168 * (sP2h - sM2h) + + 672 * (sP1h - sM1h)) / (840 * h); + } + } + + private SpacecraftState shiftState(SpacecraftState state, OrbitType orbitType, PositionAngleType angleType, + double delta, int column) { + + double[][] array = stateToArray(state, orbitType, angleType, true); + array[0][column] += delta; + + return arrayToState(array, orbitType, angleType, state.getFrame(), state.getDate(), + state.getMu(), state.getAttitude()); + + } + + private double[][] stateToArray(SpacecraftState state, OrbitType orbitType, PositionAngleType angleType, + boolean withMass) { + double[][] array = new double[2][withMass ? 7 : 6]; + orbitType.mapOrbitToArray(state.getOrbit(), angleType, array[0], array[1]); + if (withMass) { + array[0][6] = state.getMass(); + } + return array; + } + + private SpacecraftState arrayToState(double[][] array, OrbitType orbitType, PositionAngleType angleType, + Frame frame, AbsoluteDate date, double mu, + Attitude attitude) { + Orbit orbit = orbitType.mapArrayToOrbit(array[0], array[1], angleType, date, mu, frame); + return (array.length > 6) ? + new SpacecraftState(orbit, attitude) : + new SpacecraftState(orbit, attitude, array[0][6]); + } + +} diff --git a/src/test/java/org/orekit/models/earth/troposphere/MendesPavlisModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/MendesPavlisModelTest.java index 85d537de21..ea0c13117d 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/MendesPavlisModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/MendesPavlisModelTest.java @@ -76,7 +76,9 @@ public void testZenithDelay() { new CIPM2007(). waterVaporPressure(pressure, temperature, - humidity)); + humidity), + Double.NaN, + Double.NaN); final double lambda = 0.532; final GeodeticPoint point = new GeodeticPoint(latitude, longitude, height); @@ -132,7 +134,9 @@ public void testMappingFactors() { new CIPM2007(). waterVaporPressure(pressure, temperature, - humidity)); + humidity), + Double.NaN, + Double.NaN); final double lambda = 0.532; final GeodeticPoint point = new GeodeticPoint(latitude, longitude, height); diff --git a/src/test/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModelTest.java index 4a9971e269..b7b88a2c51 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModelTest.java @@ -138,7 +138,9 @@ public void NoFile() { final double waterPressure = ModifiedSaastamoinenModel.WATER.waterVaporPressure(pressure, temperature, humidity); - final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(altitude, pressure, temperature, waterPressure); + final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(altitude, pressure, temperature, waterPressure, + Double.NaN, + Double.NaN); final PressureTemperatureHumidityProvider pthProvider = new ConstantPressureTemperatureHumidityProvider(pth); new ModifiedSaastamoinenModel(pthProvider, "^non-existent-file$"); Assertions.fail("an exception should have been thrown"); @@ -158,7 +160,9 @@ public void compareDefaultAndLoaded() { final double waterPressure = ModifiedSaastamoinenModel.WATER.waterVaporPressure(pressure, temperature, humidity); - final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(altitude, pressure, temperature, waterPressure); + final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(altitude, pressure, temperature, waterPressure, + Double.NaN, + Double.NaN); final PressureTemperatureHumidityProvider pthProvider = new ConstantPressureTemperatureHumidityProvider(pth); ModifiedSaastamoinenModel defaultModel = new ModifiedSaastamoinenModel(pthProvider, null); ModifiedSaastamoinenModel loadedModel = new ModifiedSaastamoinenModel(pthProvider, ModifiedSaastamoinenModel.DELTA_R_FILE_NAME); @@ -300,7 +304,9 @@ public void compareExpectedValues() { temperature, ModifiedSaastamoinenModel.WATER.waterVaporPressure(pressure, temperature, - humidity)); + humidity), + Double.NaN, + Double.NaN); final PressureTemperatureHumidityProvider pth0Provider = new ConstantPressureTemperatureHumidityProvider(pth); ModifiedSaastamoinenModel model = new ModifiedSaastamoinenModel(pth0Provider); @@ -341,7 +347,9 @@ private > void doCompareFieldExpectedValues(fi temperature, ModifiedSaastamoinenModel.WATER.waterVaporPressure(pressure, temperature, - humidity)); + humidity), + Double.NaN, + Double.NaN); final PressureTemperatureHumidityProvider pth0Provider = new ConstantPressureTemperatureHumidityProvider(pth); ModifiedSaastamoinenModel model = new ModifiedSaastamoinenModel(pth0Provider); From 24a031acf6a99b5e131886927a1653f98e7575d8 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Thu, 21 Dec 2023 19:43:28 +0100 Subject: [PATCH 063/359] Updated tests after tropospheric model changes. --- .../NumericalOrbitDeterminationTest.java | 18 +++++++++--------- .../measurements/BistaticRangeRateTest.java | 2 +- .../estimation/measurements/Range2Test.java | 12 ++++++------ .../estimation/measurements/RangeTest.java | 4 ++-- .../TurnAroundRangeAnalyticTest.java | 2 +- .../measurements/TurnAroundRangeTest.java | 6 +++--- .../modifiers/TropoModifierTest.java | 4 ++-- .../KalmanNumericalOrbitDeterminationTest.java | 8 ++++---- ...UnscentedKalmanOrbitDeterminationTest2.java | 2 +- 9 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/test/java/org/orekit/estimation/leastsquares/NumericalOrbitDeterminationTest.java b/src/test/java/org/orekit/estimation/leastsquares/NumericalOrbitDeterminationTest.java index 2d02d83cd4..22c51fbb70 100644 --- a/src/test/java/org/orekit/estimation/leastsquares/NumericalOrbitDeterminationTest.java +++ b/src/test/java/org/orekit/estimation/leastsquares/NumericalOrbitDeterminationTest.java @@ -332,8 +332,8 @@ public void testW3B() //test on the estimated position and velocity final Vector3D estimatedPos = odsatW3.getEstimatedPV().getPosition(); final Vector3D estimatedVel = odsatW3.getEstimatedPV().getVelocity(); - final Vector3D refPos = new Vector3D(-40541446.380, -9905353.045, 206780.170); - final Vector3D refVel = new Vector3D(759.0684, -1476.5159, 54.7928); + final Vector3D refPos = new Vector3D(-40541446.236, -9905357.943, 206777.082); + final Vector3D refVel = new Vector3D(759.0685, -1476.5156, 54.7931); Assertions.assertEquals(0.0, Vector3D.distance(refPos, estimatedPos), distanceAccuracy); Assertions.assertEquals(0.0, Vector3D.distance(refVel, estimatedVel), velocityAccuracy); @@ -346,12 +346,12 @@ public void testW3B() propagatorParameters.getDrivers().get(3).getValue(), propagatorParameters.getDrivers().get(5).getValue()); //Assertions.assertEquals(7.215e-6, leakAcceleration.getNorm(), 1.0e-8); - Assertions.assertEquals(7.977e-6, leakAcceleration0.getNorm(), 1.0e-8); + Assertions.assertEquals(8.005e-6, leakAcceleration0.getNorm(), 1.0e-8); final Vector3D leakAcceleration1 = new Vector3D(propagatorParameters.getDrivers().get(2).getValue(), propagatorParameters.getDrivers().get(4).getValue(), propagatorParameters.getDrivers().get(6).getValue()); - Assertions.assertEquals(3.046e-10, leakAcceleration1.getNorm(), 1.0e-12); + Assertions.assertEquals(3.060e-10, leakAcceleration1.getNorm(), 1.0e-12); //test on measurements parameters final List list = new ArrayList(); @@ -360,35 +360,35 @@ public void testW3B() //station CastleRock final double[] CastleAzElBias = { 0.062701342, -0.003613508 }; - final double CastleRangeBias = 11274.8335; + final double CastleRangeBias = 11274.4195; Assertions.assertEquals(CastleAzElBias[0], FastMath.toDegrees(list.get(0).getValue()), angleAccuracy); Assertions.assertEquals(CastleAzElBias[1], FastMath.toDegrees(list.get(1).getValue()), angleAccuracy); Assertions.assertEquals(CastleRangeBias, list.get(2).getValue(), distanceAccuracy); //station Fucino final double[] FucAzElBias = { -0.053526137, 0.075483886 }; - final double FucRangeBias = 13467.7253; + final double FucRangeBias = 13467.8361; Assertions.assertEquals(FucAzElBias[0], FastMath.toDegrees(list.get(3).getValue()), angleAccuracy); Assertions.assertEquals(FucAzElBias[1], FastMath.toDegrees(list.get(4).getValue()), angleAccuracy); Assertions.assertEquals(FucRangeBias, list.get(5).getValue(), distanceAccuracy); //station Kumsan final double[] KumAzElBias = { -0.023574208, -0.054520756 }; - final double KumRangeBias = 13513.3007; + final double KumRangeBias = 13512.4898; Assertions.assertEquals(KumAzElBias[0], FastMath.toDegrees(list.get(6).getValue()), angleAccuracy); Assertions.assertEquals(KumAzElBias[1], FastMath.toDegrees(list.get(7).getValue()), angleAccuracy); Assertions.assertEquals(KumRangeBias, list.get(8).getValue(), distanceAccuracy); //station Pretoria final double[] PreAzElBias = { 0.030201539, 0.009747877 }; - final double PreRangeBias = 13593.6300; + final double PreRangeBias = 13594.1758; Assertions.assertEquals(PreAzElBias[0], FastMath.toDegrees(list.get( 9).getValue()), angleAccuracy); Assertions.assertEquals(PreAzElBias[1], FastMath.toDegrees(list.get(10).getValue()), angleAccuracy); Assertions.assertEquals(PreRangeBias, list.get(11).getValue(), distanceAccuracy); //station Uralla final double[] UraAzElBias = { 0.167814449, -0.12305252 }; - final double UraRangeBias = 13450.5792; + final double UraRangeBias = 13450.2320; Assertions.assertEquals(UraAzElBias[0], FastMath.toDegrees(list.get(12).getValue()), angleAccuracy); Assertions.assertEquals(UraAzElBias[1], FastMath.toDegrees(list.get(13).getValue()), angleAccuracy); Assertions.assertEquals(UraRangeBias, list.get(14).getValue(), distanceAccuracy); diff --git a/src/test/java/org/orekit/estimation/measurements/BistaticRangeRateTest.java b/src/test/java/org/orekit/estimation/measurements/BistaticRangeRateTest.java index 185f47776b..a7c2865701 100644 --- a/src/test/java/org/orekit/estimation/measurements/BistaticRangeRateTest.java +++ b/src/test/java/org/orekit/estimation/measurements/BistaticRangeRateTest.java @@ -373,7 +373,7 @@ public double value(final ParameterDriver parameterDriver, AbsoluteDate date) { } } - Assertions.assertEquals(0, maxRelativeError, 5.2e-6); + Assertions.assertEquals(0, maxRelativeError, 5.3e-6); } diff --git a/src/test/java/org/orekit/estimation/measurements/Range2Test.java b/src/test/java/org/orekit/estimation/measurements/Range2Test.java index 6b97fb5a91..582bb7efcf 100644 --- a/src/test/java/org/orekit/estimation/measurements/Range2Test.java +++ b/src/test/java/org/orekit/estimation/measurements/Range2Test.java @@ -106,12 +106,12 @@ public void testStateDerivativesWithModifier() { } // Run test boolean isModifier = true; - double refErrorsPMedian = 6.3e-10; - double refErrorsPMean = 4.2e-09; - double refErrorsPMax = 2.4e-07; - double refErrorsVMedian = 1.4e-04; - double refErrorsVMean = 9.6e-04; - double refErrorsVMax = 5.2e-02; + double refErrorsPMedian = 5.5e-10; + double refErrorsPMean = 4.6e-09; + double refErrorsPMax = 2.1e-07; + double refErrorsVMedian = 1.3e-04; + double refErrorsVMean = 9.4e-04; + double refErrorsVMax = 4.8e-02; this.genericTestStateDerivatives(isModifier, printResults, refErrorsPMedian, refErrorsPMean, refErrorsPMax, refErrorsVMedian, refErrorsVMean, refErrorsVMax); diff --git a/src/test/java/org/orekit/estimation/measurements/RangeTest.java b/src/test/java/org/orekit/estimation/measurements/RangeTest.java index 5353e17c68..2c875028cc 100644 --- a/src/test/java/org/orekit/estimation/measurements/RangeTest.java +++ b/src/test/java/org/orekit/estimation/measurements/RangeTest.java @@ -100,8 +100,8 @@ public void testStateDerivativesWithModifier() { } // Run test boolean isModifier = true; - double refErrorsPMedian = 6.6e-10; - double refErrorsPMean = 3.1e-09; + double refErrorsPMedian = 7.9e-10; + double refErrorsPMean = 2.6e-09; double refErrorsPMax = 9.3e-08; double refErrorsVMedian = 2.1e-04; double refErrorsVMean = 1.3e-03; diff --git a/src/test/java/org/orekit/estimation/measurements/TurnAroundRangeAnalyticTest.java b/src/test/java/org/orekit/estimation/measurements/TurnAroundRangeAnalyticTest.java index cc98b23d7b..ee2cbfecc2 100644 --- a/src/test/java/org/orekit/estimation/measurements/TurnAroundRangeAnalyticTest.java +++ b/src/test/java/org/orekit/estimation/measurements/TurnAroundRangeAnalyticTest.java @@ -213,7 +213,7 @@ public void testParameterDerivativesWithModifierFiniteDifferences() { boolean isModifier = true; boolean isFiniteDifferences = true; genericTestParameterDerivatives(isModifier, isFiniteDifferences, printResults, - 2.8e-06, 5.9e-06, 1.2e-04, 4.3e-6, 1.7e-5, 1.5e-4); + 2.8e-06, 5.9e-06, 1.2e-04, 4.3e-6, 2.3e-5, 2.2e-4); } diff --git a/src/test/java/org/orekit/estimation/measurements/TurnAroundRangeTest.java b/src/test/java/org/orekit/estimation/measurements/TurnAroundRangeTest.java index b63b942e28..37e1b4605f 100644 --- a/src/test/java/org/orekit/estimation/measurements/TurnAroundRangeTest.java +++ b/src/test/java/org/orekit/estimation/measurements/TurnAroundRangeTest.java @@ -157,9 +157,9 @@ public void testParameterDerivativesWithModifier() { double refErrorQMMedian = 1.3e-8; double refErrorQMMean = 8.9e-8; double refErrorQMMax = 5.1e-6; - double refErrorQSMedian = 3.4e-7; - double refErrorQSMean = 1.3e-5; - double refErrorQSMax = 1.5e-4; + double refErrorQSMedian = 3.4e-8; + double refErrorQSMean = 1.9e-5; + double refErrorQSMax = 2.2e-4; this.genericTestParameterDerivatives(isModifier, printResults, refErrorQMMedian, refErrorQMMean, refErrorQMMax, refErrorQSMedian, refErrorQSMean, refErrorQSMax); diff --git a/src/test/java/org/orekit/estimation/measurements/modifiers/TropoModifierTest.java b/src/test/java/org/orekit/estimation/measurements/modifiers/TropoModifierTest.java index 9d5e539273..f3dce9f081 100644 --- a/src/test/java/org/orekit/estimation/measurements/modifiers/TropoModifierTest.java +++ b/src/test/java/org/orekit/estimation/measurements/modifiers/TropoModifierTest.java @@ -376,8 +376,8 @@ public void testBistaticRangeTropoModifier() { final double diffMeters = eval.getEstimatedValue()[0] - evalNoMod.getEstimatedValue()[0]; - Assertions.assertTrue(diffMeters < 9.0); - Assertions.assertTrue(diffMeters > 5.0); + Assertions.assertTrue(diffMeters < 9.1); + Assertions.assertTrue(diffMeters > 5.8); } } diff --git a/src/test/java/org/orekit/estimation/sequential/KalmanNumericalOrbitDeterminationTest.java b/src/test/java/org/orekit/estimation/sequential/KalmanNumericalOrbitDeterminationTest.java index 607b29345b..9ec5ae9cf5 100644 --- a/src/test/java/org/orekit/estimation/sequential/KalmanNumericalOrbitDeterminationTest.java +++ b/src/test/java/org/orekit/estimation/sequential/KalmanNumericalOrbitDeterminationTest.java @@ -439,7 +439,7 @@ public void testW3B() throws URISyntaxException, IOException { // final double[] CastleAzElBias = { 0.062701342, -0.003613508 }; // final double CastleRangeBias = 11274.4677; final double[] CastleAzElBias = { 0.062635, -0.003672}; - final double CastleRangeBias = 11289.544; + final double CastleRangeBias = 11289.328; Assertions.assertEquals(CastleAzElBias[0], FastMath.toDegrees(list.get(0).getValue()), angleAccuracy); Assertions.assertEquals(CastleAzElBias[1], FastMath.toDegrees(list.get(1).getValue()), angleAccuracy); Assertions.assertEquals(CastleRangeBias, list.get(2).getValue(), distanceAccuracy); @@ -459,7 +459,7 @@ public void testW3B() throws URISyntaxException, IOException { // final double[] KumAzElBias = { -0.023574208, -0.054520756 }; // final double KumRangeBias = 13512.57594; final double[] KumAzElBias = { -0.022805, -0.055057 }; - final double KumRangeBias = 13503.273; + final double KumRangeBias = 13502.6772; Assertions.assertEquals(KumAzElBias[0], FastMath.toDegrees(list.get(6).getValue()), angleAccuracy); Assertions.assertEquals(KumAzElBias[1], FastMath.toDegrees(list.get(7).getValue()), angleAccuracy); Assertions.assertEquals(KumRangeBias, list.get(8).getValue(), distanceAccuracy); @@ -469,7 +469,7 @@ public void testW3B() throws URISyntaxException, IOException { // final double[] PreAzElBias = { 0.030201539, 0.009747877 }; // final double PreRangeBias = 13594.11889; final double[] PreAzElBias = { 0.030353, 0.009658 }; - final double PreRangeBias = 13609.012; + final double PreRangeBias = 13609.2919; Assertions.assertEquals(PreAzElBias[0], FastMath.toDegrees(list.get( 9).getValue()), angleAccuracy); Assertions.assertEquals(PreAzElBias[1], FastMath.toDegrees(list.get(10).getValue()), angleAccuracy); Assertions.assertEquals(PreRangeBias, list.get(11).getValue(), distanceAccuracy); @@ -479,7 +479,7 @@ public void testW3B() throws URISyntaxException, IOException { // final double[] UraAzElBias = { 0.167814449, -0.12305252 }; // final double UraRangeBias = 13450.26738; final double[] UraAzElBias = { 0.167519, -0.122842 }; - final double UraRangeBias = 13441.978; + final double UraRangeBias = 13441.6865; Assertions.assertEquals(UraAzElBias[0], FastMath.toDegrees(list.get(12).getValue()), angleAccuracy); Assertions.assertEquals(UraAzElBias[1], FastMath.toDegrees(list.get(13).getValue()), angleAccuracy); Assertions.assertEquals(UraRangeBias, list.get(14).getValue(), distanceAccuracy); diff --git a/src/test/java/org/orekit/estimation/sequential/UnscentedKalmanOrbitDeterminationTest2.java b/src/test/java/org/orekit/estimation/sequential/UnscentedKalmanOrbitDeterminationTest2.java index 0950ebd040..6448b358f5 100644 --- a/src/test/java/org/orekit/estimation/sequential/UnscentedKalmanOrbitDeterminationTest2.java +++ b/src/test/java/org/orekit/estimation/sequential/UnscentedKalmanOrbitDeterminationTest2.java @@ -249,7 +249,7 @@ public void testLageos2Slr() throws URISyntaxException, IOException { // Definition of the reference parameters for the tests - final double distanceAccuracy = 1.68; + final double distanceAccuracy = 1.71; final double velocityAccuracy = 2.71e-3; final double[] RefStatRange = { -1.698412, 1.529126, 0.029547, 0.338275 }; From 0d5627b2adff876e926770015b9297b6bd8cb589 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Sun, 24 Dec 2023 13:09:42 +0100 Subject: [PATCH 064/359] Added NsgfV00Filter to allow parsing some wrong SP3 files. --- src/changes/changes.xml | 3 + .../data/LineOrientedFilteringReader.java | 114 + .../files/rinex/HatanakaCompressFilter.java | 62 +- .../org/orekit/files/sp3/NsgfV00Filter.java | 101 + .../orekit/files/sp3/NsgfV00FilterTest.java | 65 + .../resources/sp3/nsgf.orb.stella.v00.sp3 | 5517 +++++++++++++++++ 6 files changed, 5806 insertions(+), 56 deletions(-) create mode 100644 src/main/java/org/orekit/data/LineOrientedFilteringReader.java create mode 100644 src/main/java/org/orekit/files/sp3/NsgfV00Filter.java create mode 100644 src/test/java/org/orekit/files/sp3/NsgfV00FilterTest.java create mode 100644 src/test/resources/sp3/nsgf.orb.stella.v00.sp3 diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 10659c11c0..1beb8c8582 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -21,6 +21,9 @@ + + Added NsgfV00Filter to allow parsing some wrong SP3 files. + Started using new square method for Field. diff --git a/src/main/java/org/orekit/data/LineOrientedFilteringReader.java b/src/main/java/org/orekit/data/LineOrientedFilteringReader.java new file mode 100644 index 0000000000..63da59bc83 --- /dev/null +++ b/src/main/java/org/orekit/data/LineOrientedFilteringReader.java @@ -0,0 +1,114 @@ +/* Copyright Luc Maisonobe + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.data; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.Reader; + +import org.hipparchus.util.FastMath; + +/** Base class for implementing line-oriented data filtering readers. + *

                + * This reader is intended to be used in {@link DataFilter}. + *

                + * @author Luc Maisonobe + * @since 12.1 + */ +public abstract class LineOrientedFilteringReader extends Reader { + + /** Line-oriented input. */ + private final BufferedReader reader; + + /** Line number. */ + private int lastLineNumber; + + /** Pending uncompressed output lines. */ + private CharSequence pending; + + /** Number of characters already output in pending lines. */ + private int countOut; + + /** Simple constructor. + * @param name file name + * @param input underlying compressed stream + * @exception IOException if first lines cannot be read + */ + public LineOrientedFilteringReader(final String name, final Reader input) throws IOException { + reader = new BufferedReader(input); + lastLineNumber = 0; + } + + /** Get the underlying line-oriented reader. + * @return underlying line-oriented reader + */ + protected BufferedReader getBufferedReader() { + return reader; + } + + /** {@inheritDoc} */ + @Override + public int read(final char[] b, final int offset, final int len) throws IOException { + + if (pending == null) { + // we need to read another line from the underlying characters stream and filter it + countOut = 0; + final String originalLine = reader.readLine(); + ++lastLineNumber; + if (originalLine == null) { + // there are no lines left + return -1; + } else { + pending = filterLine(lastLineNumber, originalLine); + } + } + + // copy as many characters as possible from current line + int n = FastMath.min(len, pending.length() - countOut); + for (int i = 0; i < n; ++i) { + b[offset + i] = pending.charAt(countOut + i); + } + + if (n < len) { + // line has been completed and we can still output end of line + b[offset + n] = '\n'; + pending = null; + ++n; + } else { + // there are still some pending characters + countOut += n; + } + + return n; + + } + + /** Filter one line. + * @param lineNumber line number + * @param originalLine original line + * @return filtered line + * @exception IOException if line cannot be parsed + */ + protected abstract CharSequence filterLine(int lineNumber, String originalLine) throws IOException; + + /** {@inheritDoc} */ + @Override + public void close() throws IOException { + reader.close(); + } + +} diff --git a/src/main/java/org/orekit/files/rinex/HatanakaCompressFilter.java b/src/main/java/org/orekit/files/rinex/HatanakaCompressFilter.java index f7d337a936..73761c6bab 100644 --- a/src/main/java/org/orekit/files/rinex/HatanakaCompressFilter.java +++ b/src/main/java/org/orekit/files/rinex/HatanakaCompressFilter.java @@ -29,6 +29,7 @@ import org.hipparchus.util.FastMath; import org.orekit.data.DataFilter; import org.orekit.data.DataSource; +import org.orekit.data.LineOrientedFilteringReader; import org.orekit.errors.OrekitException; import org.orekit.errors.OrekitMessages; import org.orekit.gnss.SatelliteSystem; @@ -86,20 +87,11 @@ public DataSource filter(final DataSource original) { } /** Filtering of Hatanaka compressed characters stream. */ - private static class HatanakaReader extends Reader { + private static class HatanakaReader extends LineOrientedFilteringReader { /** Format of the current file. */ private final CompactRinexFormat format; - /** Line-oriented input. */ - private final BufferedReader reader; - - /** Pending uncompressed output lines. */ - private CharSequence pending; - - /** Number of characters already output in pending lines. */ - private int countOut; - /** Simple constructor. * @param name file name * @param input underlying compressed stream @@ -107,56 +99,14 @@ private static class HatanakaReader extends Reader { */ HatanakaReader(final String name, final Reader input) throws IOException { - - reader = new BufferedReader(input); - - // check header - format = CompactRinexFormat.getFormat(name, reader); - - pending = null; - - } - - /** {@inheritDoc} */ - @Override - public int read(final char[] b, final int offset, final int len) throws IOException { - - if (pending == null) { - // we need to read another section from the underlying characters stream and uncompress it - countOut = 0; - final String firstLine = reader.readLine(); - if (firstLine == null) { - // there are no lines left - return -1; - } else { - pending = format.uncompressSection(firstLine); - } - } - - // copy as many characters as possible from current line - int n = FastMath.min(len, pending.length() - countOut); - for (int i = 0; i < n; ++i) { - b[offset + i] = pending.charAt(countOut + i); - } - - if (n < len) { - // line has been completed and we can still output end of line - b[offset + n] = '\n'; - pending = null; - ++n; - } else { - // there are still some pending characters - countOut += n; - } - - return n; - + super(name, input); + format = CompactRinexFormat.getFormat(name, getBufferedReader()); } /** {@inheritDoc} */ @Override - public void close() throws IOException { - reader.close(); + protected CharSequence filterLine(final int lineNumber, final String originalLine) throws IOException { + return format.uncompressSection(originalLine); } } diff --git a/src/main/java/org/orekit/files/sp3/NsgfV00Filter.java b/src/main/java/org/orekit/files/sp3/NsgfV00Filter.java new file mode 100644 index 0000000000..2a1c7dddba --- /dev/null +++ b/src/main/java/org/orekit/files/sp3/NsgfV00Filter.java @@ -0,0 +1,101 @@ +/* Copyright Luc Maisonobe + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.files.sp3; + +import java.io.IOException; +import java.util.function.Function; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.orekit.data.DataFilter; +import org.orekit.data.DataSource; +import org.orekit.data.LineOrientedFilteringReader; + +/** Filter for some non-official files from CDDIS. + *

                + * Some files produced by UKRI/NERC/British Geological Survey Space Geodesy Facility (SGF) + * claim to be SP3c but are really SP3d since they have more than 4 comments lines. This + * filter can be used to parse them. + *

                + * @see SP3 + * precise orbit file is not compliant with SP3 format c (extra comment line) + * @since 12.1 + */ +public class NsgfV00Filter implements DataFilter { + + /** Default regular expression for NSGF V00 files. */ + public static final String DEFAULT_V00_PATTERN = ".*nsgf\\.orb\\.[^.]+\\.v00\\.sp3$"; + + /** Pattern matching file names to which filtering should be applied. */ + private final Pattern pattern; + + /** Renaming function. */ + private final Function renaming; + + /** Simple constructor. + * @param nameRegexp regular expression matching file names to which filtering should be applied + * @param renaming function to apply for renaming files (and avoid the filter to be applied in infinite recursion) + */ + public NsgfV00Filter(final String nameRegexp, final Function renaming) { + this.pattern = Pattern.compile(nameRegexp); + this.renaming = renaming; + } + + /** Simple constructor. + *

                + * This uses {@link #DEFAULT_V00_PATTERN} as the regular expression matching files + * that must be filtered, and replaces "v00" by "v70" to generate the filtered name. + *

                + */ + public NsgfV00Filter() { + this(DEFAULT_V00_PATTERN, s -> s.replace("v00", "v70")); + } + + /** {@inheritDoc} */ + @Override + public DataSource filter(final DataSource original) throws IOException { + final Matcher matcher = pattern.matcher(original.getName()); + if (matcher.matches()) { + // this is a v00 file from NSGF + // we need to parse it as an SP3d file even if it claims being an SP3c file + final String oName = original.getName(); + final String fName = renaming.apply(oName); + return new DataSource(fName, + () -> new LineOrientedFilteringReader(oName, original.getOpener().openReaderOnce()) { + + /** {@inheritDoc} */ + @Override + protected CharSequence filterLine(final int lineNumber, final String originalLine) { + if (lineNumber == 1 && originalLine.startsWith("#c")) { + // the 'c' format marker appears in the first header line + // we replace it by a 'd' format marker + return "#d" + originalLine.substring(2); + } else { + // don't filter any other lines + return originalLine; + } + } + + }); + } else { + // this is a regular file, no need to filter it + return original; + } + } + +} + diff --git a/src/test/java/org/orekit/files/sp3/NsgfV00FilterTest.java b/src/test/java/org/orekit/files/sp3/NsgfV00FilterTest.java new file mode 100644 index 0000000000..1ad6fb3686 --- /dev/null +++ b/src/test/java/org/orekit/files/sp3/NsgfV00FilterTest.java @@ -0,0 +1,65 @@ +/* Copyright 2023 Luc Maisonobe + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.files.sp3; + +import java.io.IOException; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.orekit.Utils; +import org.orekit.data.DataSource; +import org.orekit.data.FiltersManager; +import org.orekit.frames.Frame; +import org.orekit.frames.FramesFactory; +import org.orekit.utils.Constants; +import org.orekit.utils.IERSConventions; + +public class NsgfV00FilterTest { + + @Test + public void testFiltered() throws IOException { + doTestFilter("/sp3/nsgf.orb.stella.v00.sp3", "L56", 1831); + } + + @Test + public void testNotFiltered() throws IOException { + doTestFilter("/sp3/example-c-1.sp3", "G04", 1, 1); + } + + private void doTestFilter(final String name, final String id, final int... nbCoords) throws IOException { + final DataSource original = new DataSource(name, () -> getClass().getResourceAsStream(name)); + final Frame frame = FramesFactory.getITRF(IERSConventions.IERS_2003, true); + final SP3Parser parser = new SP3Parser(Constants.EIGEN5C_EARTH_MU, 2, s -> frame); + + final FiltersManager manager = new FiltersManager(); + manager.addFilter(new NsgfV00Filter()); + + final SP3 file = parser.parse(manager.applyRelevantFilters(original)); + for (int i = 0; i < nbCoords.length; ++i) { + Assertions.assertEquals(nbCoords[i], + file.getEphemeris(id).getSegments().get(i).getCoordinates().size()); + } + + } + + @BeforeEach + public void setUp() { + Utils.setDataRoot("regular-data"); + } + +} diff --git a/src/test/resources/sp3/nsgf.orb.stella.v00.sp3 b/src/test/resources/sp3/nsgf.orb.stella.v00.sp3 new file mode 100644 index 0000000000..b4e68bd3fa --- /dev/null +++ b/src/test/resources/sp3/nsgf.orb.stella.v00.sp3 @@ -0,0 +1,5517 @@ +#cV2023 12 8 0 0 0.00000000 1831 SLR ECF FIT NSGF +## 2291 432000.00000000 180.00000000 60286 0.0000000000000 ++ 1 L56 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +++ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +++ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +++ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +++ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +++ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +%c L cc UTC ccc cccc cccc cccc cccc ccccc ccccc ccccc ccccc +%c cc cc ccc ccc cccc cccc cccc cccc ccccc ccccc ccccc ccccc +%f 0.0000000 0.000000000 0.00000000000 0.000000000000000 +%f 0.0000000 0.000000000 0.00000000000 0.000000000000000 +%i 0 0 0 0 0 0 0 0 0 +%i 0 0 0 0 0 0 0 0 0 +/* +/* Earth-centered-fixed orbital predictions from SGF ILRS AC +/* The underlying ECF frame is that of IERS/ITRF +/* Note: Solution based on 4-day long arc +/* +* 2023 12 8 0 0 0.00000000 +PL56 2447.693398 -1850.426620 -6499.605162 +VL56 32349.234000 -61096.609000 29639.195000 +* 2023 12 8 0 3 0.00000000 +PL56 2970.413679 -2919.143105 -5856.583173 +VL56 25579.191000 -57277.328000 41603.486000 +* 2023 12 8 0 6 0.00000000 +PL56 3363.975044 -3899.384139 -5010.442600 +VL56 18048.401000 -51289.767000 52142.155000 +* 2023 12 8 0 9 0.00000000 +PL56 3617.452805 -4753.649361 -3990.247045 +VL56 10067.462000 -43317.275000 60885.873000 +* 2023 12 8 0 12 0.00000000 +PL56 3725.637016 -5448.452940 -2831.199630 +VL56 1958.732800 -33621.656000 67523.916000 +* 2023 12 8 0 15 0.00000000 +PL56 3689.132971 -5955.677768 -1573.473615 +VL56 -5956.190700 -22536.108000 71816.766000 +* 2023 12 8 0 18 0.00000000 +PL56 3514.228021 -6253.763157 -260.832034 +VL56 -13369.740000 -10453.774000 73606.609000 +* 2023 12 8 0 21 0.00000000 +PL56 3212.522882 -6328.659872 1060.915139 +VL56 -20001.203000 2186.595300 72824.699000 +* 2023 12 8 0 24 0.00000000 +PL56 2800.339802 -6174.497858 2345.552918 +VL56 -25608.474000 14917.947000 69495.133000 +* 2023 12 8 0 27 0.00000000 +PL56 2297.935631 -5793.926051 3548.133425 +VL56 -29997.976000 27264.085000 63734.132000 +* 2023 12 8 0 30 0.00000000 +PL56 1728.557307 -5198.103524 4626.596695 +VL56 -33032.031000 38758.871000 55745.154000 +* 2023 12 8 0 33 0.00000000 +PL56 1117.392879 -4406.350206 5543.272722 +VL56 -34633.099000 48964.614000 45810.868000 +* 2023 12 8 0 36 0.00000000 +PL56 490.469813 -3445.474326 6266.209414 +VL56 -34785.485000 57489.649000 34281.905000 +* 2023 12 8 0 39 0.00000000 +PL56 -126.449387 -2348.807655 6770.274302 +VL56 -33533.855000 64003.026000 21562.969000 +* 2023 12 8 0 42 0.00000000 +PL56 -708.920796 -1155.002544 7037.996243 +VL56 -30979.190000 68246.274000 8098.116900 +* 2023 12 8 0 45 0.00000000 +PL56 -1234.781426 93.358984 7060.140515 +VL56 -27272.795000 70042.597000 -5644.155300 +* 2023 12 8 0 48 0.00000000 +PL56 -1684.989186 1351.302032 6836.006301 +VL56 -22608.758000 69303.778000 -19186.734000 +* 2023 12 8 0 51 0.00000000 +PL56 -2044.312373 2573.087972 6373.439409 +VL56 -17214.778000 66033.562000 -32059.750000 +* 2023 12 8 0 54 0.00000000 +PL56 -2301.847381 3713.883888 5688.564579 +VL56 -11342.289000 60328.712000 -43815.753000 +* 2023 12 8 0 57 0.00000000 +PL56 -2451.349383 4731.420873 4805.243489 +VL56 -5255.688400 52376.742000 -54044.963000 +* 2023 12 8 1 0 0.00000000 +PL56 -2491.366957 5587.587104 3754.267586 +VL56 778.721130 42450.832000 -62389.507000 +* 2023 12 8 1 3 0.00000000 +PL56 -2425.173963 6249.893878 2572.298614 +VL56 6504.058400 30900.868000 -68557.072000 +* 2023 12 8 1 6 0.00000000 +PL56 -2260.500460 6692.748305 1300.587212 +VL56 11683.833000 18140.850000 -72331.796000 +* 2023 12 8 1 9 0.00000000 +PL56 -2009.073282 6898.475494 -16.485585 +VL56 16112.038000 4633.712300 -73582.821000 +* 2023 12 8 1 12 0.00000000 +PL56 -1685.987241 6858.040391 -1332.990294 +VL56 19621.752000 -9126.613400 -72269.580000 +* 2023 12 8 1 15 0.00000000 +PL56 -1308.937468 6571.430128 -2603.095177 +VL56 22091.959000 -22635.179000 -68443.407000 +* 2023 12 8 1 18 0.00000000 +PL56 -897.350090 6047.666282 -3782.697826 +VL56 23451.741000 -35396.211000 -62244.125000 +* 2023 12 8 1 21 0.00000000 +PL56 -471.462151 5304.466157 -4830.962735 +VL56 23681.992000 -46942.262000 -53893.682000 +* 2023 12 8 1 24 0.00000000 +PL56 -51.395433 4367.582157 -5711.718181 +VL56 22814.345000 -56850.784000 -43686.586000 +* 2023 12 8 1 27 0.00000000 +PL56 343.736126 3269.852884 -6394.666441 +VL56 20928.442000 -64759.222000 -31978.873000 +* 2023 12 8 1 30 0.00000000 +PL56 696.646608 2050.009348 -6856.372398 +VL56 18146.766000 -70377.153000 -19174.769000 +* 2023 12 8 1 33 0.00000000 +PL56 992.592418 751.291754 -7081.007819 +VL56 14628.131000 -73495.248000 -5712.978600 +* 2023 12 8 1 36 0.00000000 +PL56 1219.958089 -580.072050 -7060.847680 +VL56 10559.950000 -73991.771000 7947.211700 +* 2023 12 8 1 39 0.00000000 +PL56 1370.695792 -1896.483495 -6796.512576 +VL56 6149.704700 -71836.567000 21340.194000 +* 2023 12 8 1 42 0.00000000 +PL56 1440.606420 -3150.636521 -6296.956172 +VL56 1616.038600 -67092.382000 34007.931000 +* 2023 12 8 1 45 0.00000000 +PL56 1429.457204 -4297.188304 -5579.204666 +VL56 -2820.561800 -59914.352000 45513.922000 +* 2023 12 8 1 48 0.00000000 +PL56 1340.929004 -5294.397694 -4667.837335 +VL56 -6947.286700 -50546.553000 55457.844000 +* 2023 12 8 1 51 0.00000000 +PL56 1182.394412 -6105.669292 -3594.209646 +VL56 -10568.313000 -39315.363000 63489.370000 +* 2023 12 8 1 54 0.00000000 +PL56 964.530101 -6700.950525 -2395.431022 +VL56 -13513.753000 -26619.439000 69321.613000 +* 2023 12 8 1 57 0.00000000 +PL56 700.777266 -7057.917324 -1113.114166 +VL56 -15647.550000 -12916.300000 72742.933000 +* 2023 12 8 2 0 0.00000000 +PL56 406.670786 -7162.886867 208.069041 +VL56 -16874.092000 1294.503900 73626.373000 +* 2023 12 8 2 3 0.00000000 +PL56 99.065850 -7011.401588 1521.971964 +VL56 -17142.892000 15490.844000 71935.717000 +* 2023 12 8 2 6 0.00000000 +PL56 -204.699506 -6608.450633 2782.632663 +VL56 -16450.984000 29148.803000 67727.791000 +* 2023 12 8 2 9 0.00000000 +PL56 -487.663940 -5968.308132 3945.939502 +VL56 -14842.976000 41764.192000 61150.608000 +* 2023 12 8 2 12 0.00000000 +PL56 -734.079940 -5113.990962 4971.220317 +VL56 -12408.544000 52872.911000 52436.989000 +* 2023 12 8 2 15 0.00000000 +PL56 -930.186107 -4076.376489 5822.686972 +VL56 -9277.699500 62068.446000 41894.945000 +* 2023 12 8 2 18 0.00000000 +PL56 -1064.876676 -2893.024568 6470.687467 +VL56 -5614.289000 69017.111000 29896.049000 +* 2023 12 8 2 21 0.00000000 +PL56 -1130.238654 -1606.757420 6892.718507 +VL56 -1607.788900 73469.368000 16860.582000 +* 2023 12 8 2 24 0.00000000 +PL56 -1121.934969 -264.070205 7074.173315 +VL56 2535.482300 75267.712000 3243.160300 +* 2023 12 8 2 27 0.00000000 +PL56 -1039.423384 1086.572769 7008.819655 +VL56 6601.825200 74351.397000 -10482.943000 +* 2023 12 8 2 30 0.00000000 +PL56 -886.000567 2396.499498 6698.996079 +VL56 10380.038000 70758.119000 -23841.339000 +* 2023 12 8 2 33 0.00000000 +PL56 -668.668700 3618.591573 6155.525512 +VL56 13671.180000 64622.284000 -36368.315000 +* 2023 12 8 2 36 0.00000000 +PL56 -397.832326 4708.990178 5397.349006 +VL56 16297.631000 56170.610000 -47628.068000 +* 2023 12 8 2 39 0.00000000 +PL56 -86.835880 5628.692645 4450.886935 +VL56 18111.682000 45714.517000 -57227.780000 +* 2023 12 8 2 42 0.00000000 +PL56 248.641933 6344.984134 3349.138240 +VL56 19002.785000 33639.011000 -64831.570000 +* 2023 12 8 2 45 0.00000000 +PL56 591.311977 6832.646901 2130.544109 +VL56 18903.389000 20389.784000 -70172.542000 +* 2023 12 8 2 48 0.00000000 +PL56 923.089437 7074.901663 837.636576 +VL56 17793.143000 6455.710100 -73064.620000 +* 2023 12 8 2 51 0.00000000 +PL56 1225.960278 7064.012737 -484.476889 +VL56 15700.336000 -7650.895600 -73408.721000 +* 2023 12 8 2 54 0.00000000 +PL56 1482.855018 6801.536940 -1789.724326 +VL56 12701.241000 -21413.236000 -71196.922000 +* 2023 12 8 2 57 0.00000000 +PL56 1678.484337 6298.205937 -3032.709851 +VL56 8916.686600 -34331.718000 -66511.941000 +* 2023 12 8 3 0 0.00000000 +PL56 1800.097797 5573.453324 -4170.316448 +VL56 4506.889300 -45942.266000 -59523.309000 +* 2023 12 8 3 3 0.00000000 +PL56 1838.130977 4654.610240 -5163.206653 +VL56 -335.679000 -55834.093000 -50479.914000 +* 2023 12 8 3 6 0.00000000 +PL56 1786.710924 3575.814770 -5977.159956 +VL56 -5394.835700 -63663.757000 -39699.515000 +* 2023 12 8 3 9 0.00000000 +PL56 1643.999700 2376.697017 -6584.205902 +VL56 -10440.053000 -69166.011000 -27556.640000 +* 2023 12 8 3 12 0.00000000 +PL56 1412.364505 1100.898353 -6963.526396 +VL56 -15236.228000 -72161.331000 -14469.201000 +* 2023 12 8 3 15 0.00000000 +PL56 1098.372660 -205.513704 -7102.112663 +VL56 -19553.408000 -72560.183000 -884.710080 +* 2023 12 8 3 18 0.00000000 +PL56 712.611056 -1495.685383 -6995.172425 +VL56 -23176.532000 -70364.843000 12733.811000 +* 2023 12 8 3 21 0.00000000 +PL56 269.335483 -2723.621414 -6646.281268 +VL56 -25914.454000 -65668.000000 25921.891000 +* 2023 12 8 3 24 0.00000000 +PL56 -214.038643 -3845.790631 -6067.285463 +VL56 -27608.649000 -58650.107000 38227.440000 +* 2023 12 8 3 27 0.00000000 +PL56 -717.594780 -4822.658120 -5277.949367 +VL56 -28140.923000 -49573.562000 49225.126000 +* 2023 12 8 3 30 0.00000000 +PL56 -1219.702365 -5620.092955 -4305.344888 +VL56 -27440.033000 -38774.836000 58530.679000 +* 2023 12 8 3 33 0.00000000 +PL56 -1697.910771 -6210.606049 -3182.987921 +VL56 -25486.790000 -26653.389000 65814.670000 +* 2023 12 8 3 36 0.00000000 +PL56 -2129.916742 -6574.364088 -1949.731974 +VL56 -22317.062000 -13657.873000 70815.434000 +* 2023 12 8 3 39 0.00000000 +PL56 -2494.564176 -6699.931077 -648.445714 +VL56 -18022.313000 -269.740930 73350.192000 +* 2023 12 8 3 42 0.00000000 +PL56 -2772.829430 -6584.693381 675.488055 +VL56 -12747.420000 13015.487000 73323.517000 +* 2023 12 8 3 45 0.00000000 +PL56 -2948.741807 -6234.933873 1975.793784 +VL56 -6685.653400 25708.191000 70732.092000 +* 2023 12 8 3 48 0.00000000 +PL56 -3010.189648 -5665.545117 3206.974057 +VL56 -71.045433 37344.619000 65665.438000 +* 2023 12 8 3 51 0.00000000 +PL56 -2949.568223 -4899.393410 4325.954466 +VL56 6831.445100 47505.463000 58302.330000 +* 2023 12 8 3 54 0.00000000 +PL56 -2764.236688 -3966.368907 5293.628830 +VL56 13737.178000 55832.054000 48903.415000 +* 2023 12 8 3 57 0.00000000 +PL56 -2456.765118 -2902.171667 6076.243079 +VL56 20353.890000 62039.433000 37800.733000 +* 2023 12 8 4 0 0.00000000 +PL56 -2034.958864 -1746.894725 6646.565890 +VL56 26394.178000 65925.618000 25384.677000 +* 2023 12 8 4 3 0.00000000 +PL56 -1511.662488 -543.474210 6984.813135 +VL56 31587.483000 67377.424000 12089.834000 +* 2023 12 8 4 6 0.00000000 +PL56 -904.354769 663.934995 7079.302121 +VL56 35691.186000 66372.635000 -1620.848400 +* 2023 12 8 4 9 0.00000000 +PL56 -234.553688 1831.591012 6926.825563 +VL56 38500.778000 62979.033000 -15271.157000 +* 2023 12 8 4 12 0.00000000 +PL56 472.953691 2917.755428 6532.748543 +VL56 39858.939000 57350.600000 -28387.432000 +* 2023 12 8 4 15 0.00000000 +PL56 1191.032004 3884.191730 5910.821619 +VL56 39663.123000 49721.103000 -40514.200000 +* 2023 12 8 4 18 0.00000000 +PL56 1891.236561 4697.524795 5082.717573 +VL56 37871.203000 40395.249000 -51229.196000 +* 2023 12 8 4 21 0.00000000 +PL56 2544.937678 5330.419242 4077.298692 +VL56 34505.188000 29737.331000 -60158.239000 +* 2023 12 8 4 24 0.00000000 +PL56 3124.489309 5762.530292 2929.629470 +VL56 29652.315000 18157.351000 -66988.452000 +* 2023 12 8 4 27 0.00000000 +PL56 3604.395171 5981.194224 1679.760417 +VL56 23463.714000 6096.010600 -71480.580000 +* 2023 12 8 4 30 0.00000000 +PL56 3962.417460 5981.818244 371.310862 +VL56 16149.233000 -5993.627000 -73478.656000 +* 2023 12 8 4 33 0.00000000 +PL56 4180.570815 5767.945868 -950.085678 +VL56 7970.011900 -17663.711000 -72915.571000 +* 2023 12 8 4 36 0.00000000 +PL56 4245.956882 5350.997033 -2238.410874 +VL56 -771.716950 -28489.741000 -69815.684000 +* 2023 12 8 4 39 0.00000000 +PL56 4151.397602 4749.698875 -3448.896879 +VL56 -9744.783100 -38086.935000 -64293.060000 +* 2023 12 8 4 42 0.00000000 +PL56 3895.835703 3989.237393 -4539.600719 +VL56 -18602.594000 -46124.605000 -56546.271000 +* 2023 12 8 4 45 0.00000000 +PL56 3484.487856 3100.177306 -5472.850851 +VL56 -26996.888000 -52337.386000 -46849.721000 +* 2023 12 8 4 48 0.00000000 +PL56 2928.751024 2117.207887 -6216.517216 +VL56 -34591.467000 -56533.424000 -35542.717000 +* 2023 12 8 4 51 0.00000000 +PL56 2245.869652 1077.773028 -6745.066216 +VL56 -41074.873000 -58599.025000 -23016.625000 +* 2023 12 8 4 54 0.00000000 +PL56 1458.383744 20.646092 -7040.375914 +VL56 -46171.898000 -58500.134000 -9701.345200 +* 2023 12 8 4 57 0.00000000 +PL56 593.382885 -1015.496689 -7092.305431 +VL56 -49653.915000 -56281.279000 3948.515200 +* 2023 12 8 5 0 0.00000000 +PL56 -318.414951 -1993.463478 -6899.013108 +VL56 -51347.723000 -52062.066000 17467.851000 +* 2023 12 8 5 3 0.00000000 +PL56 -1243.729753 -2878.851904 -6467.020489 +VL56 -51142.983000 -46031.817000 30394.835000 +* 2023 12 8 5 6 0.00000000 +PL56 -2147.905849 -3641.243387 -5811.024759 +VL56 -48997.962000 -38442.471000 42285.254000 +* 2023 12 8 5 9 0.00000000 +PL56 -2996.185329 -4255.251604 -4953.454558 +VL56 -44943.568000 -29599.655000 52726.616000 +* 2023 12 8 5 12 0.00000000 +PL56 -3755.035185 -4701.395304 -3923.771974 +VL56 -39085.076000 -19851.884000 61352.341000 +* 2023 12 8 5 15 0.00000000 +PL56 -4393.480673 -4966.758619 -2757.519788 +VL56 -31600.982000 -9577.839800 67855.517000 +* 2023 12 8 5 18 0.00000000 +PL56 -4884.388932 -5045.406715 -1495.134472 +VL56 -22738.666000 827.995380 72001.223000 +* 2023 12 8 5 21 0.00000000 +PL56 -5205.644170 -4938.531729 -180.554590 +VL56 -12806.619000 10970.861000 73636.746000 +* 2023 12 8 5 24 0.00000000 +PL56 -5341.152902 -4654.314730 1140.328612 +VL56 -2163.398900 20471.622000 72698.758000 +* 2023 12 8 5 27 0.00000000 +PL56 -5281.623238 -4207.502216 2421.319251 +VL56 8796.372000 28982.458000 69216.959000 +* 2023 12 8 5 30 0.00000000 +PL56 -5025.071199 -3618.711032 3617.588955 +VL56 19658.107000 36201.110000 63313.084000 +* 2023 12 8 5 33 0.00000000 +PL56 -4577.028288 -2913.499071 4687.295069 +VL56 30004.201000 41882.552000 55196.011000 +* 2023 12 8 5 36 0.00000000 +PL56 -3950.440236 -2121.249899 5593.076501 +VL56 39431.247000 45847.914000 45153.048000 +* 2023 12 8 5 39 0.00000000 +PL56 -3165.267377 -1273.931236 6303.363878 +VL56 47565.777000 47989.537000 33538.377000 +* 2023 12 8 5 42 0.00000000 +PL56 -2247.811713 -404.787931 6793.468121 +VL56 54078.957000 48273.314000 20759.930000 +* 2023 12 8 5 45 0.00000000 +PL56 -1229.794562 452.978796 7046.412212 +VL56 58699.394000 46737.752000 7264.032500 +* 2023 12 8 5 48 0.00000000 +PL56 -147.229610 1267.484680 7053.483971 +VL56 61223.015000 43489.861000 -6479.863400 +* 2023 12 8 5 51 0.00000000 +PL56 960.865253 2009.348251 6814.513140 +VL56 61521.237000 38699.547000 -19994.716000 +* 2023 12 8 5 54 0.00000000 +PL56 2053.881240 2652.753585 6337.866313 +VL56 59546.638000 32591.597000 -32811.639000 +* 2023 12 8 5 57 0.00000000 +PL56 3091.111090 3176.353104 5640.161694 +VL56 55336.024000 25436.023000 -44485.200000 +* 2023 12 8 6 0 0.00000000 +PL56 4033.275299 3563.986304 4745.711461 +VL56 49011.024000 17537.188000 -54608.461000 +* 2023 12 8 6 3 0.00000000 +PL56 4844.027517 3805.189235 3685.695964 +VL56 40775.207000 9221.567000 -62827.433000 +* 2023 12 8 6 6 0.00000000 +PL56 5491.384932 3895.476785 2497.093980 +VL56 30908.561000 824.726810 -68854.043000 +* 2023 12 8 6 9 0.00000000 +PL56 5949.021155 3836.381552 1221.387475 +VL56 19757.772000 -7322.507900 -72477.514000 +* 2023 12 8 6 12 0.00000000 +PL56 6197.355471 3635.245331 -96.907967 +VL56 7723.292400 -14907.715000 -73572.694000 +* 2023 12 8 6 15 0.00000000 +PL56 6224.386426 3304.772369 -1411.833519 +VL56 -4756.038000 -21649.570000 -72104.895000 +* 2023 12 8 6 18 0.00000000 +PL56 6026.226098 2862.365336 -2677.627587 +VL56 -17220.559000 -27309.006000 -68130.536000 +* 2023 12 8 6 21 0.00000000 +PL56 5607.312602 2329.282297 -3850.346085 +VL56 -29207.826000 -31697.982000 -61794.361000 +* 2023 12 8 6 24 0.00000000 +PL56 4980.297220 1729.656926 -4889.398654 +VL56 -40270.662000 -34685.848000 -53322.926000 +* 2023 12 8 6 27 0.00000000 +PL56 4165.613196 1089.429569 -5758.939976 +VL56 -49994.259000 -36202.797000 -43014.978000 +* 2023 12 8 6 30 0.00000000 +PL56 3190.756851 435.245410 -6429.064116 +VL56 -58010.940000 -36240.175000 -31229.666000 +* 2023 12 8 6 33 0.00000000 +PL56 2089.320676 -206.631044 -6876.776787 +VL56 -64012.945000 -34848.406000 -18373.574000 +* 2023 12 8 6 36 0.00000000 +PL56 899.819929 -811.344333 -7086.725206 +VL56 -67762.573000 -32132.775000 -4886.883200 +* 2023 12 8 6 39 0.00000000 +PL56 -335.645177 -1356.385524 -7051.680370 +VL56 -69100.392000 -28247.586000 8770.352100 +* 2023 12 8 6 42 0.00000000 +PL56 -1572.853455 -1822.408711 -6772.764809 +VL56 -67950.937000 -23388.700000 22132.488000 +* 2023 12 8 6 45 0.00000000 +PL56 -2767.011138 -2193.906277 -6259.428112 +VL56 -64326.475000 -17785.232000 34742.409000 +* 2023 12 8 6 48 0.00000000 +PL56 -3874.344167 -2459.724354 -5529.166638 +VL56 -58328.006000 -11690.186000 46165.441000 +* 2023 12 8 6 51 0.00000000 +PL56 -4853.693205 -2613.405201 -4606.991415 +VL56 -50144.670000 -5370.638400 56003.670000 +* 2023 12 8 6 54 0.00000000 +PL56 -5668.063719 -2653.343479 -3524.638429 +VL56 -40049.132000 903.141870 63910.092000 +* 2023 12 8 6 57 0.00000000 +PL56 -6286.068144 -2582.745294 -2319.530945 +VL56 -28390.120000 6868.695500 69601.919000 +* 2023 12 8 7 0 0.00000000 +PL56 -6683.196905 -2409.386753 -1033.514968 +VL56 -15580.935000 12282.509000 72872.301000 +* 2023 12 8 7 3 0.00000000 +PL56 -6842.852871 -2145.177860 288.594941 +VL56 -2084.683700 16930.450000 73599.538000 +* 2023 12 8 7 6 0.00000000 +PL56 -6757.091357 -1805.547501 1600.607658 +VL56 11603.524000 20637.089000 71753.073000 +* 2023 12 8 7 9 0.00000000 +PL56 -6427.019228 -1408.676828 2856.620436 +VL56 24976.503000 23273.081000 67395.451000 +* 2023 12 8 7 12 0.00000000 +PL56 -5862.825959 -974.620025 4012.680352 +VL56 37535.665000 24760.295000 60680.065000 +* 2023 12 8 7 15 0.00000000 +PL56 -5083.445923 -524.356371 5028.368898 +VL56 48811.287000 25074.259000 51844.827000 +* 2023 12 8 7 18 0.00000000 +PL56 -4115.869542 -78.823589 5868.237123 +VL56 58380.743000 24243.779000 41202.141000 +* 2023 12 8 7 21 0.00000000 +PL56 -2994.150518 342.019674 6503.040902 +VL56 65884.269000 22348.157000 29126.804000 +* 2023 12 8 7 24 0.00000000 +PL56 -1758.150375 720.059955 6910.740422 +VL56 71038.218000 19512.095000 16042.114000 +* 2023 12 8 7 27 0.00000000 +PL56 -452.077119 1039.785991 7077.234722 +VL56 73644.729000 15898.807000 2404.241400 +* 2023 12 8 7 30 0.00000000 +PL56 877.121964 1288.911304 6996.817689 +VL56 73598.096000 11701.917000 -11312.874000 +* 2023 12 8 7 33 0.00000000 +PL56 2181.457689 1458.840984 6672.354082 +VL56 70888.580000 7136.391600 -24633.377000 +* 2023 12 8 7 36 0.00000000 +PL56 3413.636348 1544.968249 6115.175812 +VL56 65603.115000 2428.718900 -37094.918000 +* 2023 12 8 7 39 0.00000000 +PL56 4528.785044 1546.791317 5344.700503 +VL56 57923.097000 -2193.175300 -48264.013000 +* 2023 12 8 7 42 0.00000000 +PL56 5486.106386 1467.848088 4387.776828 +VL56 48118.813000 -6510.006200 -57750.795000 +* 2023 12 8 7 45 0.00000000 +PL56 6250.408389 1315.472787 3277.772746 +VL56 36541.071000 -10320.823000 -65223.118000 +* 2023 12 8 7 48 0.00000000 +PL56 6793.444946 1100.382287 2053.417575 +VL56 23608.448000 -13452.184000 -70419.286000 +* 2023 12 8 7 51 0.00000000 +PL56 7095.002782 836.108527 757.441413 +VL56 9792.047000 -15765.913000 -73157.954000 +* 2023 12 8 7 54 0.00000000 +PL56 7143.685838 538.304718 -564.943185 +VL56 -4402.669900 -17165.333000 -73345.481000 +* 2023 12 8 7 57 0.00000000 +PL56 6937.354646 223.957498 -1867.657170 +VL56 -18456.134000 -17599.496000 -70979.546000 +* 2023 12 8 8 0 0.00000000 +PL56 6483.196377 -89.455610 -3105.398289 +VL56 -31855.093000 -17064.951000 -66148.383000 +* 2023 12 8 8 3 0.00000000 +PL56 5797.429385 -384.820898 -4235.239626 +VL56 -44112.497000 -15605.251000 -59026.641000 +* 2023 12 8 8 6 0.00000000 +PL56 4904.661730 -646.211735 -5218.120357 +VL56 -54786.046000 -13308.059000 -49867.673000 +* 2023 12 8 8 9 0.00000000 +PL56 3836.942521 -859.640307 -6020.169842 +VL56 -63493.599000 -10300.205000 -38992.933000 +* 2023 12 8 8 12 0.00000000 +PL56 2632.560891 -1013.708053 -6613.827721 +VL56 -69925.836000 -6741.367500 -26779.935000 +* 2023 12 8 8 15 0.00000000 +PL56 1334.643812 -1100.128823 -6978.732670 +VL56 -73855.842000 -2816.319500 -13648.770000 +* 2023 12 8 8 18 0.00000000 +PL56 -10.388631 -1114.105704 -7102.364821 +VL56 -75145.498000 1273.447100 -48.328547 +* 2023 12 8 8 21 0.00000000 +PL56 -1354.460972 -1054.551873 -6980.438320 +VL56 -73749.406000 5318.712600 13557.759000 +* 2023 12 8 8 24 0.00000000 +PL56 -2649.526094 -924.148270 -6617.040572 +VL56 -69716.129000 9111.612600 26705.124000 +* 2023 12 8 8 27 0.00000000 +PL56 -3849.249363 -729.235962 -6024.515151 +VL56 -63186.972000 12454.810000 38943.094000 +* 2023 12 8 8 30 0.00000000 +PL56 -4910.647359 -479.546542 -5223.093050 +VL56 -54392.238000 15170.369000 49848.413000 +* 2023 12 8 8 33 0.00000000 +PL56 -5795.640604 -187.777101 -4240.268477 +VL56 -43645.102000 17108.052000 59039.595000 +* 2023 12 8 8 36 0.00000000 +PL56 -6472.463332 130.977777 -3109.921275 +VL56 -31332.096000 18152.883000 66190.866000 +* 2023 12 8 8 39 0.00000000 +PL56 -6916.874052 459.919367 -1871.197128 +VL56 -17900.309000 18231.410000 71044.916000 +* 2023 12 8 8 42 0.00000000 +PL56 -7113.105620 781.336504 -567.171412 +VL56 -3841.325300 17316.255000 73424.089000 +* 2023 12 8 8 45 0.00000000 +PL56 -7054.499609 1077.459101 756.664648 +VL56 10327.802000 15428.457000 73238.699000 +* 2023 12 8 8 48 0.00000000 +PL56 -6743.778921 1331.331326 2054.030892 +VL56 24085.142000 12637.242000 70491.198000 +* 2023 12 8 8 51 0.00000000 +PL56 -6192.947085 1527.660789 3279.528073 +VL56 36924.984000 9057.541300 65276.741000 +* 2023 12 8 8 54 0.00000000 +PL56 -5422.810311 1653.598510 4390.281157 +VL56 48378.282000 4844.892100 57779.611000 +* 2023 12 8 8 57 0.00000000 +PL56 -4462.145888 1699.408652 5347.477124 +VL56 58031.173000 188.343330 48265.312000 +* 2023 12 8 9 0 0.00000000 +PL56 -3346.568697 1658.996318 6117.733686 +VL56 65540.050000 -4698.127400 37069.819000 +* 2023 12 8 9 3 0.00000000 +PL56 -2117.154288 1530.271001 6674.256615 +VL56 70643.590000 -9585.230500 24586.839000 +* 2023 12 8 9 6 0.00000000 +PL56 -818.874871 1315.330691 6997.749064 +VL56 73171.169000 -14238.652000 11253.063000 +* 2023 12 8 9 9 0.00000000 +PL56 501.080350 1020.459096 7077.044877 +VL56 73047.459000 -18429.306000 -2467.282400 +* 2023 12 8 9 12 0.00000000 +PL56 1795.033491 655.938771 6909.464793 +VL56 70293.554000 -21943.587000 -16098.022000 +* 2023 12 8 9 15 0.00000000 +PL56 3016.544158 235.687358 6500.894735 +VL56 65025.339000 -24592.763000 -29166.258000 +* 2023 12 8 9 18 0.00000000 +PL56 4122.082557 -223.272250 5865.585574 +VL56 57449.362000 -26221.923000 -41218.014000 +* 2023 12 8 9 21 0.00000000 +PL56 5072.597724 -701.491761 5025.674261 +VL56 47855.246000 -26717.673000 -51833.514000 +* 2023 12 8 9 24 0.00000000 +PL56 5834.926070 -1177.903949 4010.435247 +VL56 36605.577000 -26014.430000 -60641.863000 +* 2023 12 8 9 27 0.00000000 +PL56 6382.989927 -1630.725313 2855.277714 +VL56 24122.641000 -24098.719000 -67334.483000 +* 2023 12 8 9 30 0.00000000 +PL56 6698.734566 -2038.417820 1600.512362 +VL56 10872.725000 -21011.428000 -71677.033000 +* 2023 12 8 9 33 0.00000000 +PL56 6772.757745 -2380.665692 289.928962 +VL56 -2652.130100 -16847.252000 -73518.589000 +* 2023 12 8 9 36 0.00000000 +PL56 6604.600775 -2639.321914 -1030.763732 +VL56 -15953.617000 -11751.693000 -72797.647000 +* 2023 12 8 9 39 0.00000000 +PL56 6202.682995 -2799.275150 -2315.572840 +VL56 -28546.942000 -5915.410300 -69544.127000 +* 2023 12 8 9 42 0.00000000 +PL56 5583.883092 -2849.194253 -3519.857663 +VL56 -39979.925000 433.713610 -63877.644000 +* 2023 12 8 9 45 0.00000000 +PL56 4772.795883 -2782.114154 -4601.896015 +VL56 -49850.001000 7040.133300 -56001.686000 +* 2023 12 8 9 48 0.00000000 +PL56 3800.708783 -2595.840347 -5524.321740 +VL56 -57818.301000 13631.190000 -46195.082000 +* 2023 12 8 9 51 0.00000000 +PL56 2704.348445 -2293.155276 -6255.381355 +VL56 -63620.780000 19928.417000 -34800.569000 +* 2023 12 8 9 54 0.00000000 +PL56 1524.465806 -1881.822712 -6769.972268 +VL56 -67075.313000 25658.621000 -22212.309000 +* 2023 12 8 9 57 0.00000000 +PL56 304.316336 -1374.393710 -7050.448988 +VL56 -68086.255000 30564.873000 -8862.295200 +* 2023 12 8 10 0 0.00000000 +PL56 -911.912394 -787.822257 -7087.177455 +VL56 -66645.649000 34416.498000 4793.668100 +* 2023 12 8 10 3 0.00000000 +PL56 -2080.671327 -142.906541 -6878.836231 +VL56 -62831.964000 37018.512000 18290.031000 +* 2023 12 8 10 6 0.00000000 +PL56 -3160.577552 536.431513 -6432.464229 +VL56 -56806.618000 38220.146000 31165.783000 +* 2023 12 8 10 9 0.00000000 +PL56 -4113.856095 1224.008839 -5763.254438 +VL56 -48808.003000 37922.056000 42978.275000 +* 2023 12 8 10 12 0.00000000 +PL56 -4907.661933 1892.363354 -4894.096048 +VL56 -39144.008000 36082.333000 53317.396000 +* 2023 12 8 10 15 0.00000000 +PL56 -5515.242168 2513.830072 -3854.859872 +VL56 -28181.740000 32720.889000 61819.918000 +* 2023 12 8 10 18 0.00000000 +PL56 -5916.889731 3061.673090 -2681.430271 +VL56 -16334.637000 27921.124000 68183.019000 +* 2023 12 8 10 21 0.00000000 +PL56 -6100.646640 3511.225292 -1414.505480 +VL56 -4047.561900 21829.115000 72176.535000 +* 2023 12 8 10 24 0.00000000 +PL56 -6062.718722 3840.987179 -98.194812 +VL56 8220.253400 14649.812000 73653.108000 +* 2023 12 8 10 27 0.00000000 +PL56 -5807.570312 4033.627948 1221.540642 +VL56 20013.459000 6640.094500 72555.166000 +* 2023 12 8 10 30 0.00000000 +PL56 -5347.683661 4076.833390 2498.541600 +VL56 30899.624000 -1901.390900 68918.506000 +* 2023 12 8 10 33 0.00000000 +PL56 -4702.988921 3963.953880 3688.119925 +VL56 40486.500000 -10646.116000 62870.318000 +* 2023 12 8 10 36 0.00000000 +PL56 -3899.998128 3694.420145 4748.670665 +VL56 48437.362000 -19249.406000 54624.592000 +* 2023 12 8 10 39 0.00000000 +PL56 -2970.686905 3273.904872 5643.157460 +VL56 54483.589000 -27364.719000 44473.325000 +* 2023 12 8 10 42 0.00000000 +PL56 -1951.182169 2714.227096 6340.413214 +VL56 58433.758000 -34658.018000 32774.518000 +* 2023 12 8 10 45 0.00000000 +PL56 -880.318133 2033.004881 6816.211128 +VL56 60179.072000 -40821.174000 19938.876000 +* 2023 12 8 10 48 0.00000000 +PL56 201.870967 1253.074631 7054.073508 +VL56 59694.979000 -45584.377000 6414.244600 +* 2023 12 8 10 51 0.00000000 +PL56 1255.658915 401.704407 7045.809489 +VL56 57039.855000 -48726.712000 -7329.136600 +* 2023 12 8 10 54 0.00000000 +PL56 2243.089786 -490.371486 6791.774915 +VL56 52351.162000 -50085.339000 -20814.406000 +* 2023 12 8 10 57 0.00000000 +PL56 3129.347263 -1390.066875 6300.853067 +VL56 45839.037000 -49562.855000 -33573.508000 +* 2023 12 8 11 0 0.00000000 +PL56 3883.991054 -2263.173849 5590.155864 +VL56 37777.993000 -47132.758000 -45162.772000 +* 2023 12 8 11 3 0.00000000 +PL56 4482.020443 -3075.668180 4684.447654 +VL56 28495.931000 -42842.201000 -55178.092000 +* 2023 12 8 11 6 0.00000000 +PL56 4904.726657 -3795.044461 3615.304615 +VL56 18361.795000 -36812.600000 -63268.996000 +* 2023 12 8 11 9 0.00000000 +PL56 5140.303390 -4391.630934 2420.026678 +VL56 7771.095600 -29236.687000 -69152.021000 +* 2023 12 8 11 12 0.00000000 +PL56 5184.185624 -4839.823737 1140.329979 +VL56 -2869.833200 -20372.413000 -72621.549000 +* 2023 12 8 11 15 0.00000000 +PL56 5039.097268 -5119.182946 -179.131848 +VL56 -13160.151000 -10533.819000 -73557.859000 +* 2023 12 8 11 18 0.00000000 +PL56 4714.806413 -5215.337788 -1492.360075 +VL56 -22720.608000 -79.003208 -71931.698000 +* 2023 12 8 11 21 0.00000000 +PL56 4227.600340 -5120.654315 -2753.653171 +VL56 -31208.501000 10604.108000 -67805.116000 +* 2023 12 8 11 24 0.00000000 +PL56 3599.505995 -4834.633193 -3919.226982 +VL56 -38330.763000 21113.369000 -61328.284000 +* 2023 12 8 11 27 0.00000000 +PL56 2857.299332 -4364.022568 -4948.744216 +VL56 -43854.245000 31048.300000 -52732.612000 +* 2023 12 8 11 30 0.00000000 +PL56 2031.355513 -3722.646000 -5806.694406 +VL56 -47613.088000 40025.704000 -42321.115000 +* 2023 12 8 11 33 0.00000000 +PL56 1154.399122 -2930.961392 -6463.574604 +VL56 -49512.522000 47693.854000 -30456.258000 +* 2023 12 8 11 36 0.00000000 +PL56 260.212157 -2015.380759 -6896.847409 +VL56 -49529.791000 53744.953000 -17547.215000 +* 2023 12 8 11 39 0.00000000 +PL56 -617.653391 -1007.373702 -7091.658113 +VL56 -47712.667000 57926.470000 -4036.111600 +* 2023 12 8 11 42 0.00000000 +PL56 -1447.109582 57.610648 -7041.298191 +VL56 -44175.257000 60050.135000 9616.350300 +* 2023 12 8 11 45 0.00000000 +PL56 -2198.679379 1141.367500 -6747.416497 +VL56 -39092.445000 59999.092000 22944.641000 +* 2023 12 8 11 48 0.00000000 +PL56 -2846.525363 2204.274595 -6219.977068 +VL56 -32692.418000 57733.477000 35492.697000 +* 2023 12 8 11 51 0.00000000 +PL56 -3369.332449 3206.711738 -5476.965442 +VL56 -25247.903000 53293.806000 46827.694000 +* 2023 12 8 11 54 0.00000000 +PL56 -3751.023170 4110.525805 -4543.840263 +VL56 -17066.344000 46802.530000 56554.477000 +* 2023 12 8 11 57 0.00000000 +PL56 -3981.278901 4880.493183 -3452.725322 +VL56 -8478.105700 38462.152000 64329.946000 +* 2023 12 8 12 0 0.00000000 +PL56 -4055.838301 5485.719890 -2241.354328 +VL56 176.325710 28550.125000 69875.919000 +* 2023 12 8 12 3 0.00000000 +PL56 -3976.560555 5900.920470 -951.797111 +VL56 8559.687200 17410.480000 72990.578000 +* 2023 12 8 12 6 0.00000000 +PL56 -3751.244463 6107.516507 371.002396 +VL56 16351.602000 5442.055100 73557.695000 +* 2023 12 8 12 9 0.00000000 +PL56 -3393.202491 6094.488747 1680.824360 +VL56 23261.857000 -6916.745100 71552.284000 +* 2023 12 8 12 12 0.00000000 +PL56 -2920.605225 5858.935306 2931.842470 +VL56 29042.782000 -19205.449000 67042.991000 +* 2023 12 8 12 15 0.00000000 +PL56 -2355.621957 5406.295796 4080.285198 +VL56 33499.177000 -30960.916000 60188.712000 +* 2023 12 8 12 18 0.00000000 +PL56 -1723.409919 4750.234525 5086.007739 +VL56 36495.198000 -41735.539000 51232.147000 +* 2023 12 8 12 21 0.00000000 +PL56 -1051.004664 3912.195574 5913.916273 +VL56 37958.437000 -51115.332000 40489.937000 +* 2023 12 8 12 24 0.00000000 +PL56 -366.164250 2920.651836 6535.190506 +VL56 37880.846000 -58735.766000 28340.188000 +* 2023 12 8 12 27 0.00000000 +PL56 303.776224 1810.087013 6928.263846 +VL56 36316.946000 -64295.508000 15208.333000 +* 2023 12 8 12 30 0.00000000 +PL56 932.993436 619.758442 7079.540454 +VL56 33379.351000 -67567.160000 1552.011900 +* 2023 12 8 12 33 0.00000000 +PL56 1498.168686 -607.713820 6983.835896 +VL56 29232.506000 -68405.595000 -12154.366000 +* 2023 12 8 12 36 0.00000000 +PL56 1979.350408 -1827.882481 6644.539158 +VL56 24084.631000 -66753.699000 -25435.259000 +* 2023 12 8 12 39 0.00000000 +PL56 2360.660494 -2996.089279 6073.494349 +VL56 18178.449000 -62645.371000 -37829.313000 +* 2023 12 8 12 42 0.00000000 +PL56 2630.823163 -4069.110691 5290.602132 +VL56 11780.795000 -56205.880000 -48905.249000 +* 2023 12 8 12 45 0.00000000 +PL56 2783.498058 -5006.776221 4323.146550 +VL56 5171.336200 -47648.413000 -58276.374000 +* 2023 12 8 12 48 0.00000000 +PL56 2817.408733 -5773.501605 3204.863534 +VL56 -1368.916600 -37268.008000 -65614.742000 +* 2023 12 8 12 51 0.00000000 +PL56 2736.259963 -6339.676821 1974.770951 +VL56 -7569.464500 -25431.541000 -70663.340000 +* 2023 12 8 12 54 0.00000000 +PL56 2548.443890 -6682.843594 675.796306 +VL56 -13181.805000 -12564.191000 -73246.079000 +* 2023 12 8 12 57 0.00000000 +PL56 2266.551278 -6788.607364 -646.744984 +VL56 -17989.507000 865.922900 -73274.664000 +* 2023 12 8 13 0 0.00000000 +PL56 1906.709397 -6651.242633 -1946.768463 +VL56 -21817.474000 14367.057000 -70752.306000 +* 2023 12 8 13 3 0.00000000 +PL56 1487.774081 -6273.951054 -3179.067095 +VL56 -24538.524000 27442.346000 -65772.704000 +* 2023 12 8 13 6 0.00000000 +PL56 1030.420915 -5668.762865 -4300.908581 +VL56 -26078.127000 39610.899000 -58516.074000 +* 2023 12 8 13 9 0.00000000 +PL56 556.187730 -4856.094003 -5273.515969 +VL56 -26415.083000 50424.896000 -49240.136000 +* 2023 12 8 13 12 0.00000000 +PL56 86.512787 -3863.995259 -6063.380255 +VL56 -25581.200000 59486.150000 -38270.503000 +* 2023 12 8 13 15 0.00000000 +PL56 -358.188838 -2727.132306 -6643.366456 +VL56 -23657.693000 66459.906000 -25987.687000 +* 2023 12 8 13 18 0.00000000 +PL56 -759.372357 -1485.543690 -6993.586558 +VL56 -20770.148000 71085.563000 -12814.066000 +* 2023 12 8 13 21 0.00000000 +PL56 -1101.103275 -183.227233 -7102.026411 +VL56 -17081.801000 73184.976000 800.160490 +* 2023 12 8 13 24 0.00000000 +PL56 -1370.666793 1133.399070 -6964.921249 +VL56 -12785.782000 72668.082000 14390.995000 +* 2023 12 8 13 27 0.00000000 +PL56 -1559.029712 2417.115756 -6586.877190 +VL56 -8096.539900 69536.279000 27494.630000 +* 2023 12 8 13 30 0.00000000 +PL56 -1661.142359 3621.559497 -5980.741817 +VL56 -3240.710700 63883.311000 39661.450000 +* 2023 12 8 13 33 0.00000000 +PL56 -1676.072918 4702.880137 -5167.221090 +VL56 1552.424500 55894.167000 50470.342000 +* 2023 12 8 13 36 0.00000000 +PL56 -1606.968272 5621.347524 -4174.237808 +VL56 6060.584500 45840.692000 59543.001000 +* 2023 12 8 13 39 0.00000000 +PL56 -1460.840398 6342.850705 -3036.033841 +VL56 10078.189000 34073.783000 66557.810000 +* 2023 12 8 13 42 0.00000000 +PL56 -1248.181500 6840.224609 -1792.033400 +VL56 13425.583000 21012.180000 71262.491000 +* 2023 12 8 13 45 0.00000000 +PL56 -982.421882 7094.345485 -485.496075 +VL56 15957.241000 7127.859300 73484.765000 +* 2023 12 8 13 48 0.00000000 +PL56 -679.251715 7094.935116 837.999001 +VL56 17568.595000 -7071.406300 73140.264000 +* 2023 12 8 13 51 0.00000000 +PL56 -355.836289 6841.026372 2132.184303 +VL56 18200.921000 -21062.375000 70237.314000 +* 2023 12 8 13 54 0.00000000 +PL56 -29.965236 6341.047444 3351.779221 +VL56 17843.751000 -34327.959000 64876.797000 +* 2023 12 8 13 57 0.00000000 +PL56 280.819048 5612.524541 4454.122145 +VL56 16534.822000 -46377.710000 57247.857000 +* 2023 12 8 14 0 0.00000000 +PL56 560.071016 4681.428703 5400.700619 +VL56 14357.686000 -56766.778000 47620.887000 +* 2023 12 8 14 3 0.00000000 +PL56 793.228725 3581.183530 6158.513015 +VL56 11437.167000 -65114.462000 36335.721000 +* 2023 12 8 14 6 0.00000000 +PL56 968.299886 2351.404149 6701.204440 +VL56 7932.703800 -71115.709000 23788.599000 +* 2023 12 8 14 9 0.00000000 +PL56 1076.416092 1036.420799 7009.958006 +VL56 4030.521600 -74552.929000 10418.352000 +* 2023 12 8 14 12 0.00000000 +PL56 1112.235129 -316.353571 7074.114899 +VL56 -65.311883 -75302.107000 -3309.842000 +* 2023 12 8 14 15 0.00000000 +PL56 1074.177988 -1658.147859 6891.516917 +VL56 -4142.353300 -73336.753000 -16919.277000 +* 2023 12 8 14 18 0.00000000 +PL56 964.492217 -2940.599685 6468.571085 +VL56 -7989.507400 -68728.634000 -29937.635000 +* 2023 12 8 14 21 0.00000000 +PL56 789.139368 -4117.509832 5820.029631 +VL56 -11406.800000 -61645.579000 -41912.651000 +* 2023 12 8 14 24 0.00000000 +PL56 557.511504 -5146.521383 4968.487759 +VL56 -14214.461000 -52345.488000 -52427.453000 +* 2023 12 8 14 27 0.00000000 +PL56 281.991041 -5990.668154 3943.620394 +VL56 -16261.345000 -41167.901000 -61114.624000 +* 2023 12 8 14 30 0.00000000 +PL56 -22.633428 -6619.747213 2781.168343 +VL56 -17432.407000 -28522.437000 -67669.805000 +* 2023 12 8 14 33 0.00000000 +PL56 -339.873764 -7011.448675 1521.693366 +VL56 -17654.690000 -14873.697000 -71863.442000 +* 2023 12 8 14 36 0.00000000 +PL56 -652.338289 -7152.188997 209.148039 +VL56 -16901.257000 -723.642590 -73549.594000 +* 2023 12 8 14 39 0.00000000 +PL56 -942.580057 -7037.608795 -1110.692512 +VL56 -15192.939000 13408.334000 -72672.313000 +* 2023 12 8 14 42 0.00000000 +PL56 -1193.952677 -6672.698543 -2391.869643 +VL56 -12597.525000 27006.171000 -69267.117000 +* 2023 12 8 14 45 0.00000000 +PL56 -1391.430310 -6071.555274 -3589.873446 +VL56 -9226.631900 39577.320000 -63458.844000 +* 2023 12 8 14 48 0.00000000 +PL56 -1522.354602 -5256.788784 -4663.205545 +VL56 -5230.660500 50671.478000 -55456.007000 +* 2023 12 8 14 51 0.00000000 +PL56 -1577.071911 -4258.608275 -5574.807897 +VL56 -791.784960 59896.999000 -45541.695000 +* 2023 12 8 14 54 0.00000000 +PL56 -1549.433047 -3113.645606 -6293.305654 +VL56 3884.240100 66933.799000 -34062.292000 +* 2023 12 8 14 57 0.00000000 +PL56 -1437.137033 -1863.573250 -6794.034355 +VL56 8577.143800 71543.285000 -21414.783000 +* 2023 12 8 15 0 0.00000000 +PL56 -1241.907798 -553.573297 -7059.827422 +VL56 13061.554000 73574.890000 -8032.967200 +* 2023 12 8 15 3 0.00000000 +PL56 -969.500695 769.283245 -7081.553026 +VL56 17116.506000 72969.680000 5626.552600 +* 2023 12 8 15 6 0.00000000 +PL56 -629.538065 2057.695364 -6858.399434 +VL56 20534.829000 69760.982000 19098.236000 +* 2023 12 8 15 9 0.00000000 +PL56 -235.179305 3265.785452 -6397.909630 +VL56 23132.152000 64073.177000 31921.649000 +* 2023 12 8 15 12 0.00000000 +PL56 197.367046 4350.708764 -5715.764424 +VL56 24755.436000 56118.069000 43655.453000 +* 2023 12 8 15 15 0.00000000 +PL56 649.479061 5274.173777 -4835.306468 +VL56 25290.734000 46188.481000 53892.009000 +* 2023 12 8 15 18 0.00000000 +PL56 1100.884332 6003.823666 -3786.807896 +VL56 24669.572000 34649.242000 62271.367000 +* 2023 12 8 15 21 0.00000000 +PL56 1530.525598 6514.427803 -2606.486571 +VL56 22873.861000 21925.066000 68494.974000 +* 2023 12 8 15 24 0.00000000 +PL56 1917.495238 6788.827911 -1335.290761 +VL56 19938.599000 8485.450600 72337.699000 +* 2023 12 8 15 27 0.00000000 +PL56 2241.998047 6818.589728 -17.482969 +VL56 15952.200000 -5172.966600 73657.844000 +* 2023 12 8 15 30 0.00000000 +PL56 2486.294256 6604.314963 1300.927626 +VL56 11053.980000 -18546.185000 72403.778000 +* 2023 12 8 15 33 0.00000000 +PL56 2635.573181 6155.591880 2573.835636 +VL56 5429.022900 -31143.050000 68616.564000 +* 2023 12 8 15 36 0.00000000 +PL56 2678.713502 5490.585697 3756.702626 +VL56 -699.233770 -42504.888000 62428.704000 +* 2023 12 8 15 39 0.00000000 +PL56 2608.891598 4635.286970 4808.163514 +VL56 -7078.453800 -52223.770000 54059.147000 +* 2023 12 8 15 42 0.00000000 +PL56 2424.003424 3622.450949 5691.507614 +VL56 -13438.510000 -59958.406000 43804.215000 +* 2023 12 8 15 45 0.00000000 +PL56 2126.879375 2490.284456 6375.963327 +VL56 -19503.117000 -65445.911000 32025.427000 +* 2023 12 8 15 48 0.00000000 +PL56 1725.292565 1280.957486 6837.751265 +VL56 -25001.384000 -68509.947000 19135.794000 +* 2023 12 8 15 51 0.00000000 +PL56 1231.757475 38.995498 7060.881459 +VL56 -29679.243000 -69065.570000 5585.109600 +* 2023 12 8 15 54 0.00000000 +PL56 663.129176 -1190.378277 7037.674410 +VL56 -33310.140000 -67120.161000 -8155.467200 +* 2023 12 8 15 57 0.00000000 +PL56 40.017877 -2362.897819 6769.007874 +VL56 -35704.999000 -62772.240000 -21608.974000 +* 2023 12 8 16 0 0.00000000 +PL56 -613.965083 -3436.856644 6264.278046 +VL56 -36720.743000 -56206.682000 -34308.649000 +* 2023 12 8 16 3 0.00000000 +PL56 -1273.100865 -4374.600146 5541.074668 +VL56 -36267.211000 -47687.244000 -45813.251000 +* 2023 12 8 16 6 0.00000000 +PL56 -1910.565437 -5143.859826 4624.589952 +VL56 -34312.601000 -37546.923000 -55721.579000 +* 2023 12 8 16 9 0.00000000 +PL56 -2499.516176 -5718.898092 3546.770527 +VL56 -30887.048000 -26176.188000 -63686.776000 +* 2023 12 8 16 12 0.00000000 +PL56 -3014.217636 -6081.411415 2345.214589 +VL56 -26083.273000 -14007.829000 -69429.799000 +* 2023 12 8 16 15 0.00000000 +PL56 -3431.151996 -6221.143078 1061.852832 +VL56 -20054.342000 -1500.237200 -72749.852000 +* 2023 12 8 16 18 0.00000000 +PL56 -3730.063543 -6136.181952 -258.537134 +VL56 -13008.582000 10880.742000 -73532.428000 +* 2023 12 8 16 21 0.00000000 +PL56 -3894.887622 -5832.931657 -1569.928034 +VL56 -5201.831100 22680.190000 -71753.639000 +* 2023 12 8 16 24 0.00000000 +PL56 -3914.517798 -5325.748566 -2826.687033 +VL56 3072.702600 33472.303000 -67480.939000 +* 2023 12 8 16 27 0.00000000 +PL56 -3783.372518 -4636.265877 -3985.194332 +VL56 11496.478000 42876.912000 -60869.657000 +* 2023 12 8 16 30 0.00000000 +PL56 -3501.734416 -3792.444031 -5005.364978 +VL56 19738.659000 50573.167000 -52155.767000 +* 2023 12 8 16 33 0.00000000 +PL56 -3075.853053 -2827.403644 -5852.015891 +VL56 27469.262000 56310.046000 -41646.121000 +* 2023 12 8 16 36 0.00000000 +PL56 -2517.813714 -1778.099078 -6496.036440 +VL56 34371.944000 59913.517000 -29706.489000 +* 2023 12 8 16 39 0.00000000 +PL56 -1845.181508 -683.892052 -6915.333615 +VL56 40156.121000 61290.533000 -16748.535000 +* 2023 12 8 16 42 0.00000000 +PL56 -1080.436878 414.918324 -7095.530613 +VL56 44567.915000 60429.877000 -3215.616500 +* 2023 12 8 16 45 0.00000000 +PL56 -250.228276 1478.554076 -7030.412987 +VL56 47399.606000 57400.186000 10430.990000 +* 2023 12 8 16 48 0.00000000 +PL56 615.537126 2469.165385 -6722.127001 +VL56 48498.084000 52346.231000 23725.887000 +* 2023 12 8 16 51 0.00000000 +PL56 1484.743403 3352.152534 -6181.128548 +VL56 47772.205000 45483.326000 36213.603000 +* 2023 12 8 16 54 0.00000000 +PL56 2324.233270 4097.368787 -5425.873999 +VL56 45198.149000 37089.433000 47463.085000 +* 2023 12 8 16 57 0.00000000 +PL56 3101.055330 4680.163915 -4482.251958 +VL56 40822.952000 27495.535000 57081.900000 +* 2023 12 8 17 0 0.00000000 +PL56 3783.752466 5082.236771 -3382.761156 +VL56 34765.591000 17074.000000 64730.316000 +* 2023 12 8 17 3 0.00000000 +PL56 4343.644338 5292.259709 -2165.442132 +VL56 27215.068000 6224.832200 70134.429000 +* 2023 12 8 17 6 0.00000000 +PL56 4756.047936 5306.239458 -872.585544 +VL56 18425.342000 -4639.689600 73097.569000 +* 2023 12 8 17 9 0.00000000 +PL56 5001.375201 5127.591856 450.742966 +VL56 8706.870400 -15111.432000 73509.285000 +* 2023 12 8 17 12 0.00000000 +PL56 5066.047874 4766.916027 1758.306925 +VL56 -1585.183900 -24803.060000 71350.477000 +* 2023 12 8 17 15 0.00000000 +PL56 4943.181231 4241.478895 3004.361232 +VL56 -12064.691000 -33363.541000 66694.854000 +* 2023 12 8 17 18 0.00000000 +PL56 4633.001470 3574.429692 4145.307837 +VL56 -22330.504000 -40492.530000 59706.386000 +* 2023 12 8 17 21 0.00000000 +PL56 4142.966546 2793.780566 5141.264799 +VL56 -31982.977000 -45951.689000 50632.587000 +* 2023 12 8 17 24 0.00000000 +PL56 3487.592525 1931.211724 5957.481869 +VL56 -40640.288000 -49572.919000 39794.251000 +* 2023 12 8 17 27 0.00000000 +PL56 2687.991996 1020.760311 6565.550899 +VL56 -47953.510000 -51262.816000 27572.890000 +* 2023 12 8 17 30 0.00000000 +PL56 1771.156078 97.455184 6944.368540 +VL56 -53620.470000 -51004.476000 14396.247000 +* 2023 12 8 17 33 0.00000000 +PL56 769.013208 -804.040583 7080.836400 +VL56 -57396.670000 -48855.099000 723.508200 +* 2023 12 8 17 36 0.00000000 +PL56 -282.704295 -1650.735806 6970.289339 +VL56 -59105.320000 -44942.318000 -12970.163000 +* 2023 12 8 17 39 0.00000000 +PL56 -1345.747646 -2412.522765 6616.637467 +VL56 -58644.687000 -39457.674000 -26209.784000 +* 2023 12 8 17 42 0.00000000 +PL56 -2380.746517 -3063.250816 6032.222710 +VL56 -55992.369000 -32647.652000 -38536.000000 +* 2023 12 8 17 45 0.00000000 +PL56 -3348.666955 -3581.630448 5237.405670 +VL56 -51208.446000 -24804.120000 -49519.643000 +* 2023 12 8 17 48 0.00000000 +PL56 -4212.299296 -3951.946392 4259.883867 +VL56 -44435.250000 -16252.499000 -58777.182000 +* 2023 12 8 17 51 0.00000000 +PL56 -4937.711960 -4164.546254 3133.742186 +VL56 -35893.752000 -7338.757800 -65984.596000 +* 2023 12 8 17 54 0.00000000 +PL56 -5495.607469 -4216.086458 1898.271525 +VL56 -25876.512000 1584.417900 -70889.286000 +* 2023 12 8 17 57 0.00000000 +PL56 -5862.527832 -4109.526277 596.588610 +VL56 -14737.790000 10171.815000 -73320.185000 +* 2023 12 8 18 0 0.00000000 +PL56 -6021.847988 -3853.863823 -725.897309 +VL56 -2880.137300 18099.931000 -73194.499000 +* 2023 12 8 18 3 0.00000000 +PL56 -5964.506965 -3463.626548 -2023.107920 +VL56 9261.360800 25079.977000 -70520.922000 +* 2023 12 8 18 6 0.00000000 +PL56 -5689.436266 -2958.139894 -3249.941282 +VL56 21236.750000 30869.316000 -65398.664000 +* 2023 12 8 18 9 0.00000000 +PL56 -5203.667653 -2360.615152 -4363.861493 +VL56 32598.878000 35280.027000 -58012.545000 +* 2023 12 8 18 12 0.00000000 +PL56 -4522.125668 -1697.106975 -5326.370739 +VL56 42920.702000 38184.835000 -48624.893000 +* 2023 12 8 18 15 0.00000000 +PL56 -3667.121185 -995.392203 -6104.312804 +VL56 51811.085000 39519.928000 -37564.898000 +* 2023 12 8 18 18 0.00000000 +PL56 -2667.574399 -283.820836 -6670.966636 +VL56 58928.915000 39285.200000 -25216.180000 +* 2023 12 8 18 21 0.00000000 +PL56 -1558.006531 409.810315 -7006.903436 +VL56 63994.747000 37541.596000 -12003.081000 +* 2023 12 8 18 24 0.00000000 +PL56 -377.341874 1059.317415 -7100.595470 +VL56 66800.130000 34406.489000 1623.177900 +* 2023 12 8 18 27 0.00000000 +PL56 832.436898 1641.092017 -6948.775090 +VL56 67214.754000 30047.507000 15198.333000 +* 2023 12 8 18 30 0.00000000 +PL56 2027.746544 2134.940238 -6556.547295 +VL56 65191.901000 24675.107000 28258.711000 +* 2023 12 8 18 33 0.00000000 +PL56 3164.943868 2524.778350 -5937.248027 +VL56 60771.882000 18533.958000 40355.768000 +* 2023 12 8 18 36 0.00000000 +PL56 4201.900768 2799.161666 -5112.040518 +VL56 54082.605000 11893.139000 51070.744000 +* 2023 12 8 18 39 0.00000000 +PL56 5099.566706 2951.630723 -4109.257963 +VL56 45337.569000 5035.666900 60028.168000 +* 2023 12 8 18 42 0.00000000 +PL56 5823.469077 2980.861571 -2963.492065 +VL56 34830.813000 -1752.763500 66910.257000 +* 2023 12 8 18 45 0.00000000 +PL56 6345.085591 2890.609363 -1714.443485 +VL56 22927.743000 -8195.455600 71469.196000 +* 2023 12 8 18 48 0.00000000 +PL56 6643.028133 2689.442829 -405.561170 +VL56 10053.073000 -14036.207000 73537.824000 +* 2023 12 8 18 51 0.00000000 +PL56 6703.970825 2390.273408 917.486095 +VL56 -3324.933200 -19050.411000 73037.612000 +* 2023 12 8 18 54 0.00000000 +PL56 6523.267722 2009.698026 2208.443118 +VL56 -16713.165000 -23054.553000 69982.278000 +* 2023 12 8 18 57 0.00000000 +PL56 6105.228216 1567.190119 3422.136642 +VL56 -29613.221000 -25913.681000 64478.047000 +* 2023 12 8 19 0 0.00000000 +PL56 5463.028166 1084.175112 4516.109442 +VL56 -41541.714000 -27546.447000 56719.368000 +* 2023 12 8 19 3 0.00000000 +PL56 4618.259863 583.039397 5452.141540 +VL56 -52049.792000 -27927.503000 46980.945000 +* 2023 12 8 19 6 0.00000000 +PL56 3600.152172 86.124476 6197.597798 +VL56 -60740.606000 -27086.959000 35606.663000 +* 2023 12 8 19 9 0.00000000 +PL56 2444.497970 -385.246558 6726.555315 +VL56 -67283.891000 -25107.122000 22996.025000 +* 2023 12 8 19 12 0.00000000 +PL56 1192.346551 -811.664014 7020.675952 +VL56 -71427.560000 -22117.252000 9589.794600 +* 2023 12 8 19 15 0.00000000 +PL56 -111.488297 -1176.417703 7069.813296 +VL56 -73006.646000 -18286.732000 -4145.279300 +* 2023 12 8 19 18 0.00000000 +PL56 -1420.053439 -1466.145406 6872.336112 +VL56 -71949.008000 -13816.711000 -17732.363000 +* 2023 12 8 19 21 0.00000000 +PL56 -2685.954149 -1671.320780 6435.166968 +VL56 -68277.973000 -8930.612500 -30700.399000 +* 2023 12 8 19 24 0.00000000 +PL56 -3863.071782 -1786.564666 5773.546133 +VL56 -62111.863000 -3864.129300 -42598.809000 +* 2023 12 8 19 27 0.00000000 +PL56 -4908.259716 -1810.775983 4910.525525 +VL56 -53661.703000 1144.828500 -53012.825000 +* 2023 12 8 19 30 0.00000000 +PL56 -5782.956382 -1747.077680 3876.186790 +VL56 -43224.563000 5866.572400 -61578.483000 +* 2023 12 8 19 33 0.00000000 +PL56 -6454.646015 -1602.575237 2706.605570 +VL56 -31173.191000 10089.909000 -67995.729000 +* 2023 12 8 19 36 0.00000000 +PL56 -6898.110366 -1387.939785 1442.597102 +VL56 -17943.255000 13631.295000 -72039.725000 +* 2023 12 8 19 39 0.00000000 +PL56 -7096.418549 -1116.834882 128.274813 +VL56 -4016.860200 16343.034000 -73570.128000 +* 2023 12 8 19 42 0.00000000 +PL56 -7041.594359 -805.210326 -1190.525227 +VL56 10096.432000 18119.694000 -72536.484000 +* 2023 12 8 19 45 0.00000000 +PL56 -6734.928367 -470.499276 -2467.882881 +VL56 23879.947000 18902.395000 -68979.809000 +* 2023 12 8 19 48 0.00000000 +PL56 -6186.924020 -130.761206 -3659.424172 +VL56 36829.974000 18680.525000 -63030.221000 +* 2023 12 8 19 51 0.00000000 +PL56 -5416.886191 196.187293 -4723.879600 +VL56 48475.472000 17491.435000 -54901.233000 +* 2023 12 8 19 54 0.00000000 +PL56 -4452.173643 493.613641 -5624.504422 +VL56 58395.311000 15417.567000 -44880.326000 +* 2023 12 8 19 57 0.00000000 +PL56 -3327.163411 746.640706 -6330.310340 +VL56 66232.956000 12581.658000 -33317.538000 +* 2023 12 8 20 0 0.00000000 +PL56 -2081.980307 942.914159 -6817.074857 +VL56 71707.906000 9140.104300 -20612.370000 +* 2023 12 8 20 3 0.00000000 +PL56 -761.049819 1073.142658 -7068.110912 +VL56 74624.010000 5275.503400 -7200.293800 +* 2023 12 8 20 6 0.00000000 +PL56 588.474744 1131.494492 -7074.787674 +VL56 74874.981000 1188.223800 6461.292800 +* 2023 12 8 20 9 0.00000000 +PL56 1918.359966 1115.838536 -6836.803685 +VL56 72447.530000 -2912.422700 19906.573000 +* 2023 12 8 20 12 0.00000000 +PL56 3180.981486 1027.823670 -6362.211476 +VL56 67422.489000 -6817.297800 32675.677000 +* 2023 12 8 20 15 0.00000000 +PL56 4331.005871 872.792811 -5667.179898 +VL56 59973.009000 -10326.617000 44329.038000 +* 2023 12 8 20 18 0.00000000 +PL56 5327.013088 659.532557 -4775.500164 +VL56 50359.897000 -13258.976000 54461.577000 +* 2023 12 8 20 21 0.00000000 +PL56 6133.014838 399.866009 -3717.838175 +VL56 38924.373000 -15459.758000 62716.880000 +* 2023 12 8 20 24 0.00000000 +PL56 6719.809494 108.099947 -2530.736349 +VL56 26077.172000 -16808.786000 68800.554000 +* 2023 12 8 20 27 0.00000000 +PL56 7066.114573 -199.654006 -1255.386935 +VL56 12284.827000 -17226.621000 72492.216000 +* 2023 12 8 20 30 0.00000000 +PL56 7159.417151 -506.256205 63.794322 +VL56 -1947.896700 -16679.038000 73655.404000 +* 2023 12 8 20 33 0.00000000 +PL56 6996.489402 -794.377144 1380.740122 +VL56 -16097.482000 -15179.377000 72243.862000 +* 2023 12 8 20 36 0.00000000 +PL56 6583.538419 -1047.357399 2649.386538 +VL56 -29642.674000 -12788.532000 68304.370000 +* 2023 12 8 20 39 0.00000000 +PL56 5935.973266 -1250.044087 3825.340510 +VL56 -42085.854000 -9612.362200 61975.089000 +* 2023 12 8 20 42 0.00000000 +PL56 5077.798690 -1389.559794 4867.479829 +VL56 -52972.588000 -5796.898600 53480.063000 +* 2023 12 8 20 45 0.00000000 +PL56 4040.672860 -1455.966560 5739.418325 +VL56 -61909.636000 -1521.380000 43119.783000 +* 2023 12 8 20 48 0.00000000 +PL56 2862.677937 -1442.790084 6410.780390 +VL56 -68578.589000 3010.087000 31259.333000 +* 2023 12 8 20 51 0.00000000 +PL56 1586.864800 -1347.384569 6858.242218 +VL56 -72747.152000 7577.802500 18314.752000 +* 2023 12 8 20 54 0.00000000 +PL56 259.637030 -1171.124793 7066.313169 +VL56 -74276.143000 11956.406000 4737.836900 +* 2023 12 8 20 57 0.00000000 +PL56 -1070.964328 -919.416477 7027.840212 +VL56 -73123.090000 15925.068000 -8999.518200 +* 2023 12 8 21 0 0.00000000 +PL56 -2357.009614 -601.526436 6744.229420 +VL56 -69342.552000 19277.225000 -22420.751000 +* 2023 12 8 21 3 0.00000000 +PL56 -3552.408816 -230.238286 6225.389823 +VL56 -63083.787000 21830.181000 -35060.124000 +* 2023 12 8 21 6 0.00000000 +PL56 -4614.572204 178.655182 5489.402305 +VL56 -54585.430000 23433.658000 -46477.983000 +* 2023 12 8 21 9 0.00000000 +PL56 -5505.952378 607.005630 4561.912425 +VL56 -44167.434000 23977.357000 -56275.981000 +* 2023 12 8 21 12 0.00000000 +PL56 -6195.408798 1035.085919 3475.256516 +VL56 -32219.493000 23397.025000 -64111.319000 +* 2023 12 8 21 15 0.00000000 +PL56 -6659.338933 1442.460399 2267.344763 +VL56 -19186.926000 21678.721000 -69709.377000 +* 2023 12 8 21 18 0.00000000 +PL56 -6882.529572 1808.910936 980.334551 +VL56 -5553.605800 18860.669000 -72874.424000 +* 2023 12 8 21 21 0.00000000 +PL56 -6858.687351 2115.375984 -340.864503 +VL56 8176.602200 15032.841000 -73497.480000 +* 2023 12 8 21 24 0.00000000 +PL56 -6590.615076 2344.856207 -1650.196027 +VL56 21500.242000 10333.660000 -71560.469000 +* 2023 12 8 21 27 0.00000000 +PL56 -6090.026457 2483.240718 -2902.100788 +VL56 33933.912000 4944.535400 -67136.387000 +* 2023 12 8 21 30 0.00000000 +PL56 -5377.011296 2520.015581 -4053.132380 +VL56 45033.298000 -917.713540 -60386.067000 +* 2023 12 8 21 33 0.00000000 +PL56 -4479.178690 2448.817187 -5063.473476 +VL56 54409.768000 -7010.399000 -51550.464000 +* 2023 12 8 21 36 0.00000000 +PL56 -3430.532587 2267.808028 -5898.291229 +VL56 61743.339000 -13075.088000 -40940.514000 +* 2023 12 8 21 39 0.00000000 +PL56 -2270.141934 1979.864491 -6528.890826 +VL56 66792.517000 -18848.221000 -28925.219000 +* 2023 12 8 21 42 0.00000000 +PL56 -1040.664643 1592.572247 -6933.644019 +VL56 69400.890000 -24071.880000 -15918.434000 +* 2023 12 8 21 45 0.00000000 +PL56 213.217671 1118.031008 -7098.671049 +VL56 69500.248000 -28504.079000 -2364.964500 +* 2023 12 8 21 48 0.00000000 +PL56 1446.395414 572.479713 -7018.274173 +VL56 67111.160000 -31928.438000 11273.129000 +* 2023 12 8 21 51 0.00000000 +PL56 2614.920056 -24.247589 -6695.124663 +VL56 62341.638000 -34163.377000 24530.492000 +* 2023 12 8 21 54 0.00000000 +PL56 3677.543724 -649.424060 -6140.191319 +VL56 55382.913000 -35070.339000 36952.894000 +* 2023 12 8 21 57 0.00000000 +PL56 4597.163023 -1278.269741 -5372.411550 +VL56 46502.909000 -34560.809000 48111.473000 +* 2023 12 8 22 0 0.00000000 +PL56 5342.127585 -1884.906893 -4418.109150 +VL56 36037.984000 -32602.168000 57616.755000 +* 2023 12 8 22 3 0.00000000 +PL56 5887.372053 -2443.403215 -3310.157325 +VL56 24381.402000 -29221.428000 65132.791000 +* 2023 12 8 22 6 0.00000000 +PL56 6215.321403 -2928.862048 -2086.896403 +VL56 11969.593000 -24506.638000 70390.158000 +* 2023 12 8 22 9 0.00000000 +PL56 6316.524163 -3318.513299 -790.830329 +VL56 -734.144480 -18605.546000 73197.300000 +* 2023 12 8 22 12 0.00000000 +PL56 6189.975845 -3592.753066 532.856263 +VL56 -13257.645000 -11721.270000 73449.117000 +* 2023 12 8 22 15 0.00000000 +PL56 5843.109564 -3736.080082 1837.906473 +VL56 -25138.722000 -4105.117000 71132.149000 +* 2023 12 8 22 18 0.00000000 +PL56 5291.444287 -3737.877699 3078.660888 +VL56 -35944.284000 3953.399700 66326.030000 +* 2023 12 8 22 21 0.00000000 +PL56 4557.901660 -3592.995660 4211.708510 +VL56 -45287.570000 12138.528000 59200.124000 +* 2023 12 8 22 24 0.00000000 +PL56 3671.834389 -3302.104252 5197.445134 +VL56 -52842.962000 20121.480000 50006.621000 +* 2023 12 8 22 27 0.00000000 +PL56 2667.813280 -2871.806679 6001.478917 +VL56 -58358.004000 27574.190000 39070.481000 +* 2023 12 8 22 30 0.00000000 +PL56 1584.233833 -2314.502726 6595.826548 +VL56 -61661.258000 34182.868000 26776.544000 +* 2023 12 8 22 33 0.00000000 +PL56 461.810828 -1648.016153 6959.863743 +VL56 -62666.897000 39660.664000 13555.175000 +* 2023 12 8 22 36 0.00000000 +PL56 -657.975892 -895.003638 7081.008170 +VL56 -61375.594000 43759.246000 -133.061080 +* 2023 12 8 22 39 0.00000000 +PL56 -1734.424363 -82.167420 6955.124506 +VL56 -57872.553000 46279.007000 -13812.751000 +* 2023 12 8 22 42 0.00000000 +PL56 -2729.092083 760.701056 6586.649912 +VL56 -52322.655000 47077.614000 -27009.403000 +* 2023 12 8 22 45 0.00000000 +PL56 -3607.172569 1601.816490 5988.439686 +VL56 -44963.631000 46076.810000 -39264.745000 +* 2023 12 8 22 48 0.00000000 +PL56 -4338.725277 2408.599142 5181.336140 +VL56 -36096.733000 43267.202000 -50152.083000 +* 2023 12 8 22 51 0.00000000 +PL56 -4899.720507 3148.940660 4193.466611 +VL56 -26075.353000 38710.757000 -59291.096000 +* 2023 12 8 22 54 0.00000000 +PL56 -5272.858141 3792.489107 3059.280556 +VL56 -15291.420000 32540.356000 -66361.803000 +* 2023 12 8 22 57 0.00000000 +PL56 -5448.125283 4311.900024 1818.354383 +VL56 -4160.045700 24956.462000 -71116.373000 +* 2023 12 8 23 0 0.00000000 +PL56 -5423.069149 4684.000766 513.999285 +VL56 6896.710700 16220.812000 -73389.081000 +* 2023 12 8 23 3 0.00000000 +PL56 -5202.767015 4890.807589 -808.280581 +VL56 17466.999000 6646.380400 -73102.764000 +* 2023 12 8 23 6 0.00000000 +PL56 -4799.495135 4920.345604 -2102.414476 +VL56 27165.520000 -3414.441300 -70271.841000 +* 2023 12 8 23 9 0.00000000 +PL56 -4232.109513 4767.231033 -3323.410819 +VL56 35648.873000 -13584.220000 -65001.224000 +* 2023 12 8 23 12 0.00000000 +PL56 -3525.172163 4432.983415 -4428.945140 +VL56 42628.321000 -23475.888000 -57481.108000 +* 2023 12 8 23 15 0.00000000 +PL56 -2707.873840 3926.061044 -5380.821850 +VL56 47879.569000 -32707.998000 -47978.445000 +* 2023 12 8 23 18 0.00000000 +PL56 -1812.815193 3261.629674 -6146.259158 +VL56 51248.821000 -40919.008000 -36825.951000 +* 2023 12 8 23 21 0.00000000 +PL56 -874.702226 2461.081205 -6698.968183 +VL56 52656.287000 -47780.855000 -24410.125000 +* 2023 12 8 23 24 0.00000000 +PL56 70.993104 1551.321302 -7019.997089 +VL56 52096.474000 -53010.790000 -11157.408000 +* 2023 12 8 23 27 0.00000000 +PL56 989.353002 563.860094 -7098.326752 +VL56 49635.919000 -56381.538000 2479.533400 +* 2023 12 8 23 30 0.00000000 +PL56 1847.276070 -466.264901 -6931.218210 +VL56 45409.053000 -57729.766000 16035.770000 +* 2023 12 8 23 33 0.00000000 +PL56 2614.647110 -1501.706608 -6524.304353 +VL56 39612.009000 -56963.065000 29048.335000 +* 2023 12 8 23 36 0.00000000 +PL56 3265.379756 -2504.131452 -5891.426529 +VL56 32494.935000 -54064.945000 41070.452000 +* 2023 12 8 23 39 0.00000000 +PL56 3778.307450 -3435.614808 -5054.219621 +VL56 24352.721000 -49097.788000 51685.430000 +* 2023 12 8 23 42 0.00000000 +PL56 4137.895205 -4260.073918 -4041.437310 +VL56 15514.147000 -42203.553000 60521.313000 +* 2023 12 8 23 45 0.00000000 +PL56 4334.738354 -4944.678531 -2888.023333 +VL56 6329.477400 -33601.013000 67264.394000 +* 2023 12 8 23 48 0.00000000 +PL56 4365.832468 -5461.187778 -1633.951241 +VL56 -2842.727300 -23580.109000 71671.508000 +* 2023 12 8 23 51 0.00000000 +PL56 4234.592743 -5787.153597 -322.852710 +VL56 -11650.158000 -12492.680000 73580.896000 +* 2023 12 8 23 54 0.00000000 +PL56 3950.611429 -5906.922991 999.519301 +VL56 -19761.224000 -739.489810 72919.617000 +* 2023 12 8 23 57 0.00000000 +PL56 3529.160317 -5812.383721 2286.930008 +VL56 -26878.583000 11245.155000 69707.372000 +* 2023 12 9 0 0 0.00000000 +PL56 2990.458540 -5503.408147 3494.334876 +VL56 -32751.719000 23011.399000 64056.278000 +* 2023 12 9 0 3 0.00000000 +PL56 2358.741674 -4987.971962 4579.504216 +VL56 -37186.316000 34111.860000 56165.872000 +* 2023 12 9 0 6 0.00000000 +PL56 1661.184337 -4281.945006 5504.533168 +VL56 -40050.952000 44119.685000 46315.518000 +* 2023 12 9 0 9 0.00000000 +PL56 926.729923 -3408.565540 6237.177938 +VL56 -41280.853000 52645.693000 34852.843000 +* 2023 12 9 0 12 0.00000000 +PL56 184.881323 -2397.625074 6751.968899 +VL56 -40878.421000 59353.191000 22180.394000 +* 2023 12 9 0 15 0.00000000 +PL56 -535.489801 -1284.407367 7031.064616 +VL56 -38910.770000 63970.460000 8740.785700 +* 2023 12 9 0 18 0.00000000 +PL56 -1207.265901 -108.428047 7064.838198 +VL56 -35504.771000 66300.565000 -4998.438500 +* 2023 12 9 0 21 0.00000000 +PL56 -1806.102746 1087.985939 6852.187131 +VL56 -30840.412000 66229.060000 -18560.285000 +* 2023 12 9 0 24 0.00000000 +PL56 -2311.312060 2261.228477 6400.558980 +VL56 -25142.399000 63728.864000 -31474.345000 +* 2023 12 9 0 27 0.00000000 +PL56 -2706.579653 3368.008539 5725.696714 +VL56 -18670.299000 58862.204000 -43291.900000 +* 2023 12 9 0 30 0.00000000 +PL56 -2980.497662 4366.957996 4851.110107 +VL56 -11707.823000 51780.130000 -53601.147000 +* 2023 12 9 0 33 0.00000000 +PL56 -3126.895665 5220.200125 3807.281320 +VL56 -4551.160700 42718.585000 -62041.545000 +* 2023 12 9 0 36 0.00000000 +PL56 -3144.955865 5894.819642 2630.617790 +VL56 2503.184900 31991.384000 -68317.309000 +* 2023 12 9 0 39 0.00000000 +PL56 -3039.105428 6364.168032 1362.180718 +VL56 9170.936500 19978.974000 -72208.819000 +* 2023 12 9 0 42 0.00000000 +PL56 -2818.690629 6608.943951 46.234855 +VL56 15191.749000 7114.670600 -73580.943000 +* 2023 12 9 0 45 0.00000000 +PL56 -2497.447013 6617.998984 -1271.328199 +VL56 20339.917000 -6131.911100 -72388.647000 +* 2023 12 9 0 48 0.00000000 +PL56 -2092.791018 6388.823856 -2544.634633 +VL56 24433.542000 -19273.770000 -68678.974000 +* 2023 12 9 0 51 0.00000000 +PL56 -1624.964029 5927.680936 -3729.463374 +VL56 27341.553000 -31826.585000 -62587.556000 +* 2023 12 9 0 54 0.00000000 +PL56 -1116.080498 5249.392099 -4784.790110 +VL56 28987.269000 -43326.557000 -54332.598000 +* 2023 12 9 0 57 0.00000000 +PL56 -589.131354 4376.804958 -5674.191377 +VL56 29349.982000 -53348.319000 -44205.472000 +* 2023 12 9 1 0 0.00000000 +PL56 -66.986276 3339.969216 -6367.063663 +VL56 28463.556000 -61519.502000 -32559.441000 +* 2023 12 9 1 3 0.00000000 +PL56 428.563849 2175.059388 -6839.624586 +VL56 26413.198000 -67533.806000 -19796.813000 +* 2023 12 9 1 6 0.00000000 +PL56 877.683674 923.093127 -7075.669748 +VL56 23329.961000 -71160.784000 -6355.026900 +* 2023 12 9 1 9 0.00000000 +PL56 1263.259906 -371.504822 -7067.081732 +VL56 19384.017000 -72253.377000 7307.158200 +* 2023 12 9 1 12 0.00000000 +PL56 1571.535105 -1662.453001 -6814.085403 +VL56 14776.649000 -70753.011000 20723.995000 +* 2023 12 9 1 15 0.00000000 +PL56 1792.590048 -2903.231280 -6325.247444 +VL56 9731.547200 -66691.976000 33436.629000 +* 2023 12 9 1 18 0.00000000 +PL56 1920.664721 -4048.725996 -5617.226665 +VL56 4485.564700 -60194.206000 45007.122000 +* 2023 12 9 1 21 0.00000000 +PL56 1954.307228 -5056.866080 -4714.267556 +VL56 -721.142470 -51473.132000 55033.102000 +* 2023 12 9 1 24 0.00000000 +PL56 1896.343116 -5890.187863 -3647.433077 +VL56 -5655.140700 -40826.105000 63161.516000 +* 2023 12 9 1 27 0.00000000 +PL56 1753.663562 -6517.274577 -2453.593996 +VL56 -10099.785000 -28625.948000 69102.249000 +* 2023 12 9 1 30 0.00000000 +PL56 1536.835810 -6914.008927 -1174.187928 +VL56 -13864.774000 -15308.524000 72639.850000 +* 2023 12 9 1 33 0.00000000 +PL56 1259.550544 -7064.571486 146.217168 +VL56 -16794.686000 -1357.084400 73643.304000 +* 2023 12 9 1 36 0.00000000 +PL56 937.928594 -6962.127956 1461.503514 +VL56 -18775.927000 12716.581000 72072.075000 +* 2023 12 9 1 39 0.00000000 +PL56 589.719379 -6609.163267 2725.662168 +VL56 -19741.773000 26392.375000 67978.978000 +* 2023 12 9 1 42 0.00000000 +PL56 233.431075 -6017.437519 3894.460151 +VL56 -19674.897000 39163.380000 61507.770000 +* 2023 12 9 1 45 0.00000000 +PL56 -112.564918 -5207.563283 4927.033583 +VL56 -18607.583000 50555.973000 52887.693000 +* 2023 12 9 1 48 0.00000000 +PL56 -430.907294 -4208.235444 5787.340363 +VL56 -16619.199000 60148.667000 42423.571000 +* 2023 12 9 1 51 0.00000000 +PL56 -706.052034 -3055.152148 6445.421315 +VL56 -13831.334000 67587.298000 30484.216000 +* 2023 12 9 1 54 0.00000000 +PL56 -924.977483 -1789.678285 6878.424048 +VL56 -10401.424000 72598.027000 17487.959000 +* 2023 12 9 1 57 0.00000000 +PL56 -1077.758828 -457.319722 7071.362220 +VL56 -6514.750600 74995.872000 3888.026100 +* 2023 12 9 2 0 0.00000000 +PL56 -1157.992353 893.936979 7017.606539 +VL56 -2375.708700 74690.945000 -9842.899500 +* 2023 12 9 2 3 0.00000000 +PL56 -1163.053881 2215.366348 6719.094034 +VL56 1801.771200 71691.237000 -23228.287000 +* 2023 12 9 2 6 0.00000000 +PL56 -1094.181521 3459.268090 6186.254375 +VL56 5804.101500 66102.383000 -35803.621000 +* 2023 12 9 2 9 0.00000000 +PL56 -956.383256 4580.698852 5437.656822 +VL56 9427.602400 58124.241000 -47131.583000 +* 2023 12 9 2 12 0.00000000 +PL56 -758.172794 5539.116878 4499.384543 +VL56 12487.900000 48044.707000 -56817.000000 +* 2023 12 9 2 15 0.00000000 +PL56 -511.143717 6299.883133 3404.146494 +VL56 14828.551000 36229.793000 -64521.126000 +* 2023 12 9 2 18 0.00000000 +PL56 -229.399115 6835.557565 2190.150635 +VL56 16328.265000 23111.147000 -69973.631000 +* 2023 12 9 2 21 0.00000000 +PL56 71.140186 7126.941029 899.763761 +VL56 16907.232000 9169.725200 -72984.290000 +* 2023 12 9 2 24 0.00000000 +PL56 373.521793 7163.796332 -421.995220 +VL56 16531.163000 -5083.014600 -73449.730000 +* 2023 12 9 2 27 0.00000000 +PL56 660.599915 6945.218751 -1729.062933 +VL56 15212.924000 -19125.035000 -71357.545000 +* 2023 12 9 2 30 0.00000000 +PL56 915.880731 6479.634120 -2975.975394 +VL56 13011.732000 -32444.923000 -66786.324000 +* 2023 12 9 2 33 0.00000000 +PL56 1124.332410 5784.432412 -4119.473195 +VL56 10030.182000 -44561.285000 -59901.531000 +* 2023 12 9 2 36 0.00000000 +PL56 1273.125551 4885.261551 -5120.006592 +VL56 6409.413700 -55040.806000 -50948.404000 +* 2023 12 9 2 39 0.00000000 +PL56 1352.269235 3815.018900 -5943.082462 +VL56 2322.437100 -63513.586000 -40241.663000 +* 2023 12 9 2 42 0.00000000 +PL56 1355.114196 2612.596327 -6560.408938 +VL56 -2033.877100 -69685.231000 -28153.486000 +* 2023 12 9 2 45 0.00000000 +PL56 1278.703703 1321.436864 -6950.809998 +VL56 -6447.635000 -73345.585000 -15100.026000 +* 2023 12 9 2 48 0.00000000 +PL56 1123.962387 -12.035758 -7100.894459 +VL56 -10701.012000 -74374.321000 -1527.808300 +* 2023 12 9 2 51 0.00000000 +PL56 895.717891 -1340.064811 -7005.475881 +VL56 -14579.733000 -72743.944000 12100.369000 +* 2023 12 9 2 54 0.00000000 +PL56 602.553731 -2615.236109 -6667.736222 +VL56 -17882.248000 -68519.772000 25319.813000 +* 2023 12 9 2 57 0.00000000 +PL56 256.499984 -3792.134349 -6099.139896 +VL56 -20428.641000 -61858.184000 37677.301000 +* 2023 12 9 3 0 0.00000000 +PL56 -127.433809 -4828.946704 -5319.094389 +VL56 -22069.082000 -53002.038000 48745.929000 +* 2023 12 9 3 3 0.00000000 +PL56 -531.869244 -5688.960487 -4354.350535 +VL56 -22691.387000 -42273.718000 58139.020000 +* 2023 12 9 3 6 0.00000000 +PL56 -937.796172 -6341.906009 -3238.150187 +VL56 -22227.390000 -30064.833000 65524.271000 +* 2023 12 9 3 9 0.00000000 +PL56 -1325.410551 -6765.088838 -2009.130120 +VL56 -20657.657000 -16822.997000 70636.583000 +* 2023 12 9 3 12 0.00000000 +PL56 -1675.018398 -6944.257337 -710.007903 +VL56 -18014.071000 -3035.741900 73289.339000 +* 2023 12 9 3 15 0.00000000 +PL56 -1967.964033 -6874.155073 613.912942 +VL56 -14379.929000 10788.282000 73382.960000 +* 2023 12 9 3 18 0.00000000 +PL56 -2187.537242 -6558.719215 1916.359689 +VL56 -9887.473500 24139.660000 70909.839000 +* 2023 12 9 3 21 0.00000000 +PL56 -2319.812513 -6010.908241 3151.760574 +VL56 -4712.801700 36528.884000 65955.278000 +* 2023 12 9 3 24 0.00000000 +PL56 -2354.373854 -5252.162548 4276.893563 +VL56 931.665560 47506.168000 58694.121000 +* 2023 12 9 3 27 0.00000000 +PL56 -2284.887375 -4311.527910 5252.437500 +VL56 6806.425100 56678.906000 49383.467000 +* 2023 12 9 3 30 0.00000000 +PL56 -2109.497041 -3224.491559 6044.364055 +VL56 12655.251000 63726.172000 38352.402000 +* 2023 12 9 3 33 0.00000000 +PL56 -1831.024720 -2031.585950 6625.119683 +VL56 18216.523000 68409.774000 25988.881000 +* 2023 12 9 3 36 0.00000000 +PL56 -1456.966051 -776.831984 6974.559091 +VL56 23234.379000 70581.207000 12725.622000 +* 2023 12 9 3 39 0.00000000 +PL56 -999.288788 493.916218 7080.612268 +VL56 27469.505000 70185.588000 -975.455050 +* 2023 12 9 3 42 0.00000000 +PL56 -474.042736 1734.661848 6939.671937 +VL56 30709.356000 67261.813000 -14638.479000 +* 2023 12 9 3 45 0.00000000 +PL56 99.210197 2900.936767 6556.703312 +VL56 32777.736000 61940.151000 -27789.436000 +* 2023 12 9 3 48 0.00000000 +PL56 698.127456 3951.401790 5945.070490 +VL56 33543.121000 54436.871000 -39971.745000 +* 2023 12 9 3 51 0.00000000 +PL56 1298.452014 4849.325193 5126.085822 +VL56 32925.319000 45046.070000 -50761.384000 +* 2023 12 9 3 54 0.00000000 +PL56 1874.985879 5563.893072 4128.289554 +VL56 30900.646000 34129.190000 -59781.604000 +* 2023 12 9 3 57 0.00000000 +PL56 2402.635581 6071.302216 2986.475431 +VL56 27504.714000 22101.368000 -66716.386000 +* 2023 12 9 4 0 0.00000000 +PL56 2857.489397 6355.595989 1740.485192 +VL56 22833.025000 9416.472400 -71322.863000 +* 2023 12 9 4 3 0.00000000 +PL56 3217.874295 6409.197151 433.799729 +VL56 17038.106000 -3451.409100 -73440.901000 +* 2023 12 9 4 6 0.00000000 +PL56 3465.339696 6233.104661 -888.010369 +VL56 10324.389000 -16026.641000 -72999.093000 +* 2023 12 9 4 9 0.00000000 +PL56 3585.522590 5836.750886 -2178.910325 +VL56 2940.166800 -27850.897000 -70017.342000 +* 2023 12 9 4 12 0.00000000 +PL56 3568.852306 5237.527412 -3394.037287 +VL56 -4832.226900 -38501.010000 -64605.469000 +* 2023 12 9 4 15 0.00000000 +PL56 3411.059493 4460.003893 -4491.279789 +VL56 -12688.141000 -47605.046000 -56958.194000 +* 2023 12 9 4 18 0.00000000 +PL56 3113.465739 3534.883980 -5432.732250 +VL56 -20313.094000 -54855.231000 -47346.468000 +* 2023 12 9 4 21 0.00000000 +PL56 2683.047893 2497.757693 -6185.974253 +VL56 -27395.269000 -60017.770000 -36106.815000 +* 2023 12 9 4 24 0.00000000 +PL56 2132.279539 1387.707596 -6725.136901 +VL56 -33637.741000 -62939.222000 -23628.436000 +* 2023 12 9 4 27 0.00000000 +PL56 1478.760284 245.830920 -7031.730576 +VL56 -38769.635000 -63549.363000 -10339.735000 +* 2023 12 9 4 30 0.00000000 +PL56 744.651344 -886.265328 -7095.226367 +VL56 -42556.656000 -61861.612000 3305.422700 +* 2023 12 9 4 33 0.00000000 +PL56 -44.068611 -1967.952410 -6913.386704 +VL56 -44810.371000 -57970.685000 16842.050000 +* 2023 12 9 4 36 0.00000000 +PL56 -858.502364 -2961.005416 -6492.341092 +VL56 -45396.188000 -52048.093000 29807.760000 +* 2023 12 9 4 39 0.00000000 +PL56 -1667.866624 -3830.934404 -5846.411467 +VL56 -44240.089000 -44336.048000 41757.097000 +* 2023 12 9 4 42 0.00000000 +PL56 -2440.630132 -4548.183417 -4997.679438 +VL56 -41333.694000 -35139.066000 52275.631000 +* 2023 12 9 4 45 0.00000000 +PL56 -3145.726333 -5089.162039 -3975.299732 +VL56 -36737.371000 -24813.554000 60994.287000 +* 2023 12 9 4 48 0.00000000 +PL56 -3753.800110 -5437.068961 -2814.558668 +VL56 -30580.713000 -13755.113000 67603.046000 +* 2023 12 9 4 51 0.00000000 +PL56 -4238.435975 -5582.467708 -1555.697206 +VL56 -23060.090000 -2383.873500 71863.329000 +* 2023 12 9 4 54 0.00000000 +PL56 -4577.313657 -5523.583854 -242.527757 +VL56 -14432.921000 8871.762300 73618.410000 +* 2023 12 9 4 57 0.00000000 +PL56 -4753.230229 -5266.300053 1079.110727 +VL56 -5008.619400 19592.301000 72800.778000 +* 2023 12 9 5 0 0.00000000 +PL56 -4754.932930 -4823.840426 2362.998115 +VL56 4863.311800 29384.348000 69435.860000 +* 2023 12 9 5 3 0.00000000 +PL56 -4577.715082 -4216.152762 3564.205717 +VL56 14807.530000 37896.723000 63641.233000 +* 2023 12 9 5 6 0.00000000 +PL56 -4223.744043 -3469.021398 4640.718164 +VL56 24438.237000 44834.179000 55621.905000 +* 2023 12 9 5 9 0.00000000 +PL56 -3702.105290 -2612.956757 5554.936291 +VL56 33375.193000 49968.379000 45661.825000 +* 2023 12 9 5 12 0.00000000 +PL56 -3028.563680 -1681.920714 6274.996920 +VL56 41258.921000 53145.047000 34112.346000 +* 2023 12 9 5 15 0.00000000 +PL56 -2225.059946 -711.953379 6775.871229 +VL56 47764.980000 54287.984000 21379.147000 +* 2023 12 9 5 18 0.00000000 +PL56 -1318.961176 260.245579 7040.209678 +VL56 52616.868000 53399.927000 7907.179900 +* 2023 12 9 5 21 0.00000000 +PL56 -342.099910 1198.716761 7058.906842 +VL56 55596.489000 50559.753000 -5835.024900 +* 2023 12 9 5 24 0.00000000 +PL56 670.357842 2069.573161 6831.390833 +VL56 56552.857000 45917.858000 -19370.485000 +* 2023 12 9 5 27 0.00000000 +PL56 1681.185662 2842.227229 6365.631647 +VL56 55408.942000 39689.068000 -32229.667000 +* 2023 12 9 5 30 0.00000000 +PL56 2652.468884 3490.470026 5677.868461 +VL56 52165.859000 32143.476000 -43965.812000 +* 2023 12 9 5 33 0.00000000 +PL56 3547.033007 3993.373027 4792.064931 +VL56 46904.811000 23595.739000 -54169.938000 +* 2023 12 9 5 36 0.00000000 +PL56 4329.880228 4335.981116 3739.095678 +VL56 39785.986000 14392.723000 -62485.341000 +* 2023 12 9 5 39 0.00000000 +PL56 4969.578106 4509.771438 2555.687948 +VL56 31044.507000 4899.910800 -68620.736000 +* 2023 12 9 5 42 0.00000000 +PL56 5439.545494 4512.857326 1283.137428 +VL56 20982.505000 -4513.346600 -72361.273000 +* 2023 12 9 5 45 0.00000000 +PL56 5719.168269 4349.922605 -34.153176 +VL56 9958.788500 -13488.837000 -73577.652000 +* 2023 12 9 5 48 0.00000000 +PL56 5794.692360 4031.888574 -1350.259892 +VL56 -1625.616400 -21694.072000 -72230.776000 +* 2023 12 9 5 51 0.00000000 +PL56 5659.845564 3575.329359 -2619.377250 +VL56 -13343.176000 -28835.458000 -68372.784000 +* 2023 12 9 5 54 0.00000000 +PL56 5316.162645 3001.667907 -3797.440789 +VL56 -24756.872000 -34669.450000 -62144.216000 +* 2023 12 9 5 57 0.00000000 +PL56 4773.002940 2336.197676 -4843.667400 +VL56 -35437.192000 -39010.759000 -53767.809000 +* 2023 12 9 6 0 0.00000000 +PL56 4047.263183 1606.976896 -5721.955290 +VL56 -44978.797000 -41738.131000 -43539.081000 +* 2023 12 9 6 3 0.00000000 +PL56 3162.806536 843.651253 -6402.089863 +VL56 -53015.316000 -42796.572000 -31814.597000 +* 2023 12 9 6 6 0.00000000 +PL56 2149.640746 76.261417 -6860.727683 +VL56 -59232.344000 -42196.874000 -18999.024000 +* 2023 12 9 6 9 0.00000000 +PL56 1042.882636 -665.918632 -7082.138146 +VL56 -63378.225000 -40012.796000 -5531.311900 +* 2023 12 9 6 12 0.00000000 +PL56 -118.452704 -1355.474046 -7058.698323 +VL56 -65272.831000 -36376.188000 8129.050600 +* 2023 12 9 6 15 0.00000000 +PL56 -1292.804572 -1967.838040 -6791.132988 +VL56 -64814.342000 -31470.438000 21516.297000 +* 2023 12 9 6 18 0.00000000 +PL56 -2437.521147 -2482.151005 -6288.502695 +VL56 -61983.990000 -25522.694000 34172.416000 +* 2023 12 9 6 21 0.00000000 +PL56 -3510.379146 -2881.968147 -5567.935917 +VL56 -56848.351000 -18794.704000 45661.349000 +* 2023 12 9 6 24 0.00000000 +PL56 -4471.127942 -3155.795615 -4654.108536 +VL56 -49559.868000 -11573.081000 55582.930000 +* 2023 12 9 6 27 0.00000000 +PL56 -5283.013810 -3297.437606 -3578.465632 +VL56 -40353.892000 -4157.968500 63587.461000 +* 2023 12 9 6 30 0.00000000 +PL56 -5914.222470 -3306.134844 -2378.194179 +VL56 -29542.576000 3148.759800 69388.820000 +* 2023 12 9 6 33 0.00000000 +PL56 -6339.178316 -3186.484429 -1094.968013 +VL56 -17504.997000 10055.885000 72776.373000 +* 2023 12 9 6 36 0.00000000 +PL56 -6539.634011 -2948.138193 226.499041 +VL56 -4673.846800 16294.975000 73624.276000 +* 2023 12 9 6 39 0.00000000 +PL56 -6505.491650 -2605.288341 1540.040059 +VL56 8480.991900 21631.741000 71897.660000 +* 2023 12 9 6 42 0.00000000 +PL56 -6235.305171 -2175.961622 2799.699372 +VL56 21471.437000 25875.902000 67654.854000 +* 2023 12 9 6 45 0.00000000 +PL56 -5736.429821 -1681.155370 3961.396191 +VL56 33810.938000 28888.721000 61045.159000 +* 2023 12 9 6 48 0.00000000 +PL56 -5024.814637 -1143.860727 4984.514018 +VL56 45034.495000 30587.998000 52302.810000 +* 2023 12 9 6 51 0.00000000 +PL56 -4124.446712 -588.022807 5833.344010 +VL56 54716.793000 30949.991000 41737.027000 +* 2023 12 9 6 54 0.00000000 +PL56 -3066.488903 -37.492576 6478.329778 +VL56 62488.364000 30008.577000 29720.005000 +* 2023 12 9 6 57 0.00000000 +PL56 -1888.146271 484.984394 6897.078917 +VL56 68049.308000 27851.886000 16673.092000 +* 2023 12 9 7 0 0.00000000 +PL56 -631.312061 958.695732 7075.108633 +VL56 71180.154000 24616.650000 3051.262900 +* 2023 12 9 7 3 0.00000000 +PL56 658.948227 1365.774374 7006.314790 +VL56 71748.963000 20480.961000 -10672.146000 +* 2023 12 9 7 6 0.00000000 +PL56 1936.023509 1691.869023 6693.160971 +VL56 69716.459000 15655.838000 -24021.104000 +* 2023 12 9 7 9 0.00000000 +PL56 3153.445636 1926.650805 6146.586978 +VL56 65137.916000 10375.533000 -36532.389000 +* 2023 12 9 7 12 0.00000000 +PL56 4266.588548 2064.140199 5385.640427 +VL56 58162.344000 4887.295100 -47770.919000 +* 2023 12 9 7 15 0.00000000 +PL56 5234.322582 2102.845442 4436.834982 +VL56 49028.259000 -559.237250 -57344.545000 +* 2023 12 9 7 18 0.00000000 +PL56 6020.566893 2045.710090 3333.250906 +VL56 38056.694000 -5722.684600 -64918.104000 +* 2023 12 9 7 21 0.00000000 +PL56 6595.679117 1899.868105 2113.388740 +VL56 25639.835000 -10380.527000 -70226.458000 +* 2023 12 9 7 24 0.00000000 +PL56 6937.613426 1676.216870 819.818151 +VL56 12226.784000 -14338.654000 -73084.240000 +* 2023 12 9 7 27 0.00000000 +PL56 7032.795957 1388.827099 -502.334148 +VL56 -1693.298300 -17439.806000 -73393.467000 +* 2023 12 9 7 30 0.00000000 +PL56 6876.669138 1054.218778 -1806.996871 +VL56 -15610.947000 -19570.060000 -71147.413000 +* 2023 12 9 7 33 0.00000000 +PL56 6473.878555 690.536309 -3048.795845 +VL56 -29016.443000 -20663.386000 -66430.015000 +* 2023 12 9 7 36 0.00000000 +PL56 5838.098918 316.666432 -4184.656441 +VL56 -41419.572000 -20703.421000 -59411.825000 +* 2023 12 9 7 39 0.00000000 +PL56 4991.509893 -48.654583 -5175.301835 +VL56 -52368.499000 -19722.948000 -50342.682000 +* 2023 12 9 7 42 0.00000000 +PL56 3963.955803 -387.702338 -5986.586306 +VL56 -61465.855000 -17800.954000 -39541.020000 +* 2023 12 9 7 45 0.00000000 +PL56 2791.841185 -684.554964 -6590.625129 +VL56 -68382.127000 -15057.804000 -27381.954000 +* 2023 12 9 7 48 0.00000000 +PL56 1516.809216 -925.782772 -6966.696125 +VL56 -72866.244000 -11648.845000 -14283.864000 +* 2023 12 9 7 51 0.00000000 +PL56 184.258348 -1101.011323 -7101.894088 +VL56 -74753.071000 -7756.866900 -694.637950 +* 2023 12 9 7 54 0.00000000 +PL56 -1158.254202 -1203.340371 -6991.536040 +VL56 -73968.486000 -3583.648800 12922.376000 +* 2023 12 9 7 57 0.00000000 +PL56 -2462.676057 -1229.606299 -6639.312831 +VL56 -70531.798000 658.931100 26102.487000 +* 2023 12 9 8 0 0.00000000 +PL56 -3682.145782 -1180.481219 -6057.184857 +VL56 -64555.799000 4758.090700 38393.837000 +* 2023 12 9 8 3 0.00000000 +PL56 -4772.654542 -1060.405728 -5265.024823 +VL56 -56244.168000 8509.407500 49371.528000 +* 2023 12 9 8 6 0.00000000 +PL56 -5694.643604 -877.357032 -4290.006175 +VL56 -45886.442000 11725.850000 58651.672000 +* 2023 12 9 8 9 0.00000000 +PL56 -6414.478983 -642.457349 -3165.735896 +VL56 -33849.717000 14246.388000 65905.544000 +* 2023 12 9 8 12 0.00000000 +PL56 -6905.745014 -369.434108 -1931.144833 +VL56 -20566.665000 15943.774000 70872.360000 +* 2023 12 9 8 15 0.00000000 +PL56 -7150.293371 -73.951646 -629.160146 +VL56 -6520.459000 16730.997000 73370.551000 +* 2023 12 9 8 18 0.00000000 +PL56 -7138.989250 227.158526 694.801312 +VL56 7773.984900 16565.978000 73306.173000 +* 2023 12 9 8 21 0.00000000 +PL56 -6872.102008 516.732114 1994.456651 +VL56 21790.103000 15453.999000 70677.349000 +* 2023 12 9 8 24 0.00000000 +PL56 -6359.322128 778.126902 3224.326885 +VL56 35011.193000 13447.603000 65575.061000 +* 2023 12 9 8 27 0.00000000 +PL56 -5619.395391 996.055420 4341.383315 +VL56 46951.282000 10644.159000 58179.627000 +* 2023 12 9 8 30 0.00000000 +PL56 -4679.391509 1157.352194 5306.592094 +VL56 57174.405000 7181.099800 48753.040000 +* 2023 12 9 8 33 0.00000000 +PL56 -3573.652889 1251.636746 6086.291828 +VL56 65310.881000 3229.184700 37628.269000 +* 2023 12 9 8 36 0.00000000 +PL56 -2342.480259 1271.842524 6653.359847 +VL56 71070.263000 -1015.594000 25196.610000 +* 2023 12 9 8 39 0.00000000 +PL56 -1030.610748 1214.590230 6988.133735 +VL56 74251.464000 -5341.079900 11893.153000 +* 2023 12 9 8 42 0.00000000 +PL56 314.446005 1080.390916 7079.058270 +VL56 74748.144000 -9528.817100 -1819.009600 +* 2023 12 9 8 45 0.00000000 +PL56 1644.144247 873.671887 6923.053635 +VL56 72551.666000 -13363.790000 -15463.853000 +* 2023 12 9 8 48 0.00000000 +PL56 2910.658796 602.626497 6525.606047 +VL56 67750.470000 -16644.155000 -28568.182000 +* 2023 12 9 8 51 0.00000000 +PL56 4068.610625 278.892454 5900.579969 +VL56 60527.143000 -19190.543000 -40676.858000 +* 2023 12 9 8 54 0.00000000 +PL56 5076.708463 -82.931504 5069.752193 +VL56 51151.963000 -20854.669000 -51368.347000 +* 2023 12 9 8 57 0.00000000 +PL56 5899.249082 -465.914795 4062.076332 +VL56 39973.740000 -21526.846000 -60269.145000 +* 2023 12 9 9 0 0.00000000 +PL56 6507.423903 -851.545513 2912.692693 +VL56 27407.464000 -21141.926000 -67067.545000 +* 2023 12 9 9 3 0.00000000 +PL56 6880.376160 -1220.571240 1661.705730 +VL56 13918.752000 -19683.257000 -71525.447000 +* 2023 12 9 9 6 0.00000000 +PL56 7005.954941 -1553.892975 352.769393 +VL56 6.304000 -17184.645000 -73487.753000 +* 2023 12 9 9 9 0.00000000 +PL56 6881.133124 -1833.471171 -968.465923 +VL56 -13818.170000 -13729.719000 -72888.633000 +* 2023 12 9 9 12 0.00000000 +PL56 6512.062275 -2043.197576 -2255.986196 +VL56 -27050.036000 -9448.677400 -69753.518000 +* 2023 12 9 9 15 0.00000000 +PL56 5913.762302 -2169.688433 -3465.051271 +VL56 -39211.722000 -4512.942300 -64197.804000 +* 2023 12 9 9 18 0.00000000 +PL56 5109.467548 -2202.960806 -4553.766183 +VL56 -49870.870000 872.390010 -56421.135000 +* 2023 12 9 9 21 0.00000000 +PL56 4129.671667 -2136.961548 -5484.525378 +VL56 -58655.643000 6477.339600 -46698.839000 +* 2023 12 9 9 24 0.00000000 +PL56 3010.919593 -1969.928451 -6225.280235 +VL56 -65267.268000 12056.811000 -35370.922000 +* 2023 12 9 9 27 0.00000000 +PL56 1794.408931 -1704.570079 -6750.589073 +VL56 -69488.658000 17360.852000 -22829.359000 +* 2023 12 9 9 30 0.00000000 +PL56 524.463135 -1348.060062 -7042.434154 +VL56 -71190.389000 22145.001000 -9504.743400 +* 2023 12 9 9 33 0.00000000 +PL56 -753.072499 -911.849144 -7090.789078 +VL56 -70333.013000 26180.123000 4147.953000 +* 2023 12 9 9 36 0.00000000 +PL56 -1992.456956 -411.302924 -6893.933159 +VL56 -66967.284000 29261.876000 17663.217000 +* 2023 12 9 9 39 0.00000000 +PL56 -3149.658275 134.826777 -6458.511951 +VL56 -61231.699000 31219.763000 30579.332000 +* 2023 12 9 9 42 0.00000000 +PL56 -4183.891726 705.082749 -5799.342616 +VL56 -53347.646000 31924.966000 42452.343000 +* 2023 12 9 9 45 0.00000000 +PL56 -5059.054352 1276.117085 -4938.967446 +VL56 -43612.593000 31297.240000 52870.272000 +* 2023 12 9 9 48 0.00000000 +PL56 -5745.013526 1823.617884 -3906.951406 +VL56 -32390.668000 29310.523000 61467.165000 +* 2023 12 9 9 51 0.00000000 +PL56 -6218.699399 2323.319453 -2738.926552 +VL56 -20100.184000 25996.368000 67937.020000 +* 2023 12 9 9 54 0.00000000 +PL56 -6464.950164 2752.051743 -1475.400871 +VL56 -7198.772600 21444.909000 72045.979000 +* 2023 12 9 9 57 0.00000000 +PL56 -6477.067371 3088.784243 -160.362988 +VL56 5833.866800 15803.216000 73642.665000 +* 2023 12 9 10 0 0.00000000 +PL56 -6257.043430 3315.612680 1160.272573 +VL56 18515.057000 9270.548400 72665.355000 +* 2023 12 9 10 3 0.00000000 +PL56 -5815.437492 3418.635480 2440.315965 +VL56 30378.812000 2090.947200 69145.383000 +* 2023 12 9 10 6 0.00000000 +PL56 -5170.901461 3388.673317 3634.972508 +VL56 40994.988000 -5456.757200 63205.962000 +* 2023 12 9 10 9 0.00000000 +PL56 -4349.382143 3221.792960 4702.459446 +VL56 49985.899000 -13070.612000 55057.320000 +* 2023 12 9 10 12 0.00000000 +PL56 -3383.040404 2919.608697 5605.498073 +VL56 57040.758000 -20438.300000 44987.965000 +* 2023 12 9 10 15 0.00000000 +PL56 -2308.946721 2489.352142 6312.622886 +VL56 61926.418000 -27250.183000 33353.213000 +* 2023 12 9 10 18 0.00000000 +PL56 -1167.612718 1943.708440 6799.264856 +VL56 64494.516000 -33212.016000 20561.604000 +* 2023 12 9 10 21 0.00000000 +PL56 -1.427448 1300.426597 7048.573038 +VL56 64685.012000 -38057.303000 7059.601100 +* 2023 12 9 10 24 0.00000000 +PL56 1146.932809 581.724150 7051.963065 +VL56 62525.873000 -41557.783000 -6683.345800 +* 2023 12 9 10 27 0.00000000 +PL56 2236.071306 -186.491780 6809.389343 +VL56 58130.614000 -43533.201000 -20190.453000 +* 2023 12 9 10 30 0.00000000 +PL56 3227.365160 -975.562820 6329.338310 +VL56 51692.842000 -43859.367000 -32993.097000 +* 2023 12 9 10 33 0.00000000 +PL56 4086.343471 -1755.149650 5628.542880 +VL56 43478.793000 -42474.588000 -44646.194000 +* 2023 12 9 10 36 0.00000000 +PL56 4783.904721 -2494.399340 4731.419195 +VL56 33816.945000 -39384.025000 -54743.635000 +* 2023 12 9 10 39 0.00000000 +PL56 5297.329880 -3163.168651 3669.238860 +VL56 23085.749000 -34661.480000 -62932.136000 +* 2023 12 9 10 42 0.00000000 +PL56 5611.056293 -3733.258031 2479.053113 +VL56 11699.299000 -28448.661000 -68924.814000 +* 2023 12 9 10 45 0.00000000 +PL56 5717.172380 -4179.600676 1202.395202 +VL56 90.826080 -20951.063000 -72512.129000 +* 2023 12 9 10 48 0.00000000 +PL56 5615.608730 -4481.352315 -116.189788 +VL56 -11304.455000 -12430.938000 -73570.129000 +* 2023 12 9 10 51 0.00000000 +PL56 5314.017357 -4622.827694 -1430.733216 +VL56 -22066.680000 -3197.404100 -72065.132000 +* 2023 12 9 10 54 0.00000000 +PL56 4827.343001 -4594.236311 -2695.484619 +VL56 -31808.097000 6405.920900 -68054.828000 +* 2023 12 9 10 57 0.00000000 +PL56 4177.108516 -4392.180846 -3866.534143 +VL56 -40187.821000 16014.702000 -61685.176000 +* 2023 12 9 11 0 0.00000000 +PL56 3390.455083 -4019.898257 -4903.347320 +VL56 -46924.257000 25258.572000 -53183.941000 +* 2023 12 9 11 3 0.00000000 +PL56 2498.988717 -3487.236551 -5770.152702 +VL56 -51804.211000 33775.747000 -42850.774000 +* 2023 12 9 11 6 0.00000000 +PL56 1537.492837 -2810.376492 -6437.133586 +VL56 -54688.455000 41226.519000 -31045.578000 +* 2023 12 9 11 9 0.00000000 +PL56 542.568270 -2011.319129 -6881.398130 +VL56 -55514.539000 47305.926000 -18175.650000 +* 2023 12 9 11 12 0.00000000 +PL56 -448.751046 -1117.156286 -7087.710480 +VL56 -54296.495000 51755.002000 -4681.975500 +* 2023 12 9 11 15 0.00000000 +PL56 -1400.354009 -159.152839 -7048.966407 +VL56 -51122.178000 54370.508000 8975.224900 +* 2023 12 9 11 18 0.00000000 +PL56 -2278.339615 828.327451 -6766.416916 +VL56 -46148.354000 55012.574000 22330.227000 +* 2023 12 9 11 21 0.00000000 +PL56 -3052.202310 1809.025493 -6249.638059 +VL56 -39594.269000 53611.375000 34926.000000 +* 2023 12 9 11 24 0.00000000 +PL56 -3695.882555 2746.089359 -5516.248857 +VL56 -31733.241000 50171.516000 46328.291000 +* 2023 12 9 11 27 0.00000000 +PL56 -4188.658076 3603.443235 -4591.375186 +VL56 -22883.182000 44774.807000 56139.707000 +* 2023 12 9 11 30 0.00000000 +PL56 -4515.843383 4347.179062 -3506.853345 +VL56 -13394.827000 37580.021000 64014.292000 +* 2023 12 9 11 33 0.00000000 +PL56 -4669.262406 4946.916011 -2300.186575 +VL56 -3638.435800 28819.498000 69670.433000 +* 2023 12 9 11 36 0.00000000 +PL56 -4647.473857 5377.070144 -1013.279238 +VL56 6010.401000 18792.491000 72902.484000 +* 2023 12 9 11 39 0.00000000 +PL56 -4455.733366 5617.974367 309.018481 +VL56 15185.717000 7855.218100 73590.134000 +* 2023 12 9 11 42 0.00000000 +PL56 -4105.681803 5656.786210 1620.505721 +VL56 23546.482000 -3592.727800 71704.308000 +* 2023 12 9 11 45 0.00000000 +PL56 -3614.770936 5488.130728 2875.297848 +VL56 30790.338000 -15124.169000 67309.107000 +* 2023 12 9 11 48 0.00000000 +PL56 -3005.448197 5114.438455 4029.489916 +VL56 36666.362000 -26301.939000 60559.578000 +* 2023 12 9 11 51 0.00000000 +PL56 -2304.145913 4545.963975 5042.734741 +VL56 40983.998000 -36696.718000 51694.672000 +* 2023 12 9 11 54 0.00000000 +PL56 -1540.131219 3800.488921 5879.675523 +VL56 43619.537000 -45904.245000 41028.073000 +* 2023 12 9 11 57 0.00000000 +PL56 -744.272082 2902.724218 6511.178827 +VL56 44519.109000 -53561.416000 28935.341000 +* 2023 12 9 12 0 0.00000000 +PL56 52.220983 1883.444103 6915.325220 +VL56 43698.239000 -59359.743000 15839.961000 +* 2023 12 9 12 3 0.00000000 +PL56 819.022979 778.394943 7078.137307 +VL56 41239.115000 -63056.975000 2198.395900 +* 2023 12 9 12 6 0.00000000 +PL56 1527.849881 -372.981257 6994.033198 +VL56 37285.257000 -64486.004000 -11515.541000 +* 2023 12 9 12 9 0.00000000 +PL56 2153.501231 -1528.964220 6666.000657 +VL56 32034.424000 -63561.767000 -24826.105000 +* 2023 12 9 12 12 0.00000000 +PL56 2674.758143 -2647.072759 6105.491828 +VL56 25729.662000 -60285.240000 -37271.181000 +* 2023 12 9 12 15 0.00000000 +PL56 3075.110390 -3685.634401 5332.038387 +VL56 18649.280000 -54745.273000 -48417.674000 +* 2023 12 9 12 18 0.00000000 +PL56 3343.287455 -4605.354444 4372.592105 +VL56 11095.194000 -47116.720000 -57876.640000 +* 2023 12 9 12 21 0.00000000 +PL56 3473.576420 -5370.828275 3260.605660 +VL56 3380.875400 -37655.871000 -65316.963000 +* 2023 12 9 12 24 0.00000000 +PL56 3465.913140 -5951.936300 2034.873266 +VL56 -4181.625800 -26692.050000 -70478.084000 +* 2023 12 9 12 27 0.00000000 +PL56 3325.739992 -6325.058347 738.167309 +VL56 -11294.673000 -14615.831000 -73180.052000 +* 2023 12 9 12 30 0.00000000 +PL56 3063.637028 -6474.048287 -584.278456 +VL56 -17687.004000 -1864.361100 -73330.153000 +* 2023 12 9 12 33 0.00000000 +PL56 2694.745148 -6390.925516 -1886.382466 +VL56 -23124.797000 11095.182000 -70927.243000 +* 2023 12 9 12 36 0.00000000 +PL56 2238.004208 -6076.242065 -3122.860233 +VL56 -27421.121000 23784.978000 -66060.696000 +* 2023 12 9 12 39 0.00000000 +PL56 1715.247539 -5539.111475 -4250.825730 +VL56 -30442.351000 35734.883000 -58906.455000 +* 2023 12 9 12 42 0.00000000 +PL56 1150.199185 -4796.898599 -5231.281581 +VL56 -32112.328000 46500.980000 -49719.140000 +* 2023 12 9 12 45 0.00000000 +PL56 567.431136 -3874.599178 -6030.439779 +VL56 -32412.995000 55681.848000 -38821.101000 +* 2023 12 9 12 48 0.00000000 +PL56 -8.674542 -2803.947984 -6620.838475 +VL56 -31383.071000 62932.337000 -26590.648000 +* 2023 12 9 12 51 0.00000000 +PL56 -554.916583 -1622.295284 -6982.227043 +VL56 -29114.247000 67975.343000 -13448.466000 +* 2023 12 9 12 54 0.00000000 +PL56 -1050.180507 -371.297497 -7102.205727 +VL56 -25745.621000 70610.835000 156.131420 +* 2023 12 9 12 57 0.00000000 +PL56 -1476.230611 904.534548 -6976.613967 +VL56 -21456.708000 70722.588000 13759.396000 +* 2023 12 9 13 0 0.00000000 +PL56 -1818.366457 2159.386095 -6609.664152 +VL56 -16459.348000 68282.492000 26897.042000 +* 2023 12 9 13 3 0.00000000 +PL56 -2065.925261 3347.747973 -6013.823732 +VL56 -10988.807000 63352.795000 39118.412000 +* 2023 12 9 13 6 0.00000000 +PL56 -2212.618126 4426.046798 -5209.444208 +VL56 -5294.159700 56086.090000 50000.614000 +* 2023 12 9 13 9 0.00000000 +PL56 -2256.688660 5354.248807 -4224.131593 +VL56 371.777240 46722.352000 59162.920000 +* 2023 12 9 13 12 0.00000000 +PL56 -2200.885803 6097.379822 -3091.859483 +VL56 5763.010500 35582.381000 66280.754000 +* 2023 12 9 13 15 0.00000000 +PL56 -2052.245774 6626.896301 -1851.842646 +VL56 10650.884000 23057.959000 71098.255000 +* 2023 12 9 13 18 0.00000000 +PL56 -1821.690301 6921.848503 -547.198906 +VL56 14833.911000 9598.535100 73439.242000 +* 2023 12 9 13 21 0.00000000 +PL56 -1523.455584 6969.772560 776.560017 +VL56 18146.667000 -4305.390100 73215.001000 +* 2023 12 9 13 24 0.00000000 +PL56 -1174.374682 6767.263105 2073.156249 +VL56 20467.072000 -18141.322000 70429.639000 +* 2023 12 9 13 27 0.00000000 +PL56 -793.046104 6320.173999 3297.223829 +VL56 21721.694000 -31396.465000 65179.972000 +* 2023 12 9 13 30 0.00000000 +PL56 -398.933691 5643.440675 4405.945117 +VL56 21888.043000 -43577.913000 57651.370000 +* 2023 12 9 13 33 0.00000000 +PL56 -11.446020 4760.544831 5360.585156 +VL56 20994.533000 -54232.185000 48110.536000 +* 2023 12 9 13 36 0.00000000 +PL56 350.963454 3702.637504 6127.861198 +VL56 19118.205000 -62963.058000 36894.454000 +* 2023 12 9 13 39 0.00000000 +PL56 671.629745 2507.379053 6681.090080 +VL56 16379.818000 -69445.844000 24397.222000 +* 2023 12 9 13 42 0.00000000 +PL56 936.405331 1217.547062 7001.090777 +VL56 12937.123000 -73438.296000 11055.790000 +* 2023 12 9 13 45 0.00000000 +PL56 1134.257870 -120.530490 7076.816668 +VL56 8977.046300 -74789.088000 -2665.561100 +* 2023 12 9 13 48 0.00000000 +PL56 1257.715543 -1458.655834 6905.710039 +VL56 4706.730200 -73442.434000 -16290.436000 +* 2023 12 9 13 51 0.00000000 +PL56 1303.145435 -2748.505470 6493.779266 +VL56 343.957580 -69440.275000 -29346.086000 +* 2023 12 9 13 54 0.00000000 +PL56 1270.856271 -3943.385171 5855.392883 +VL56 -3892.771300 -62921.223000 -41379.059000 +* 2023 12 9 13 57 0.00000000 +PL56 1165.022220 -4999.935579 5012.791752 +VL56 -7794.047500 -54116.124000 -51970.510000 +* 2023 12 9 14 0 0.00000000 +PL56 993.434737 -5879.728009 3995.336349 +VL56 -11168.873000 -43340.610000 -60750.447000 +* 2023 12 9 14 3 0.00000000 +PL56 767.091228 -6550.703280 2838.504155 +VL56 -13853.440000 -30984.711000 -67411.425000 +* 2023 12 9 14 6 0.00000000 +PL56 499.634105 -6988.387430 1582.655279 +VL56 -15718.847000 -17498.577000 -71720.126000 +* 2023 12 9 14 9 0.00000000 +PL56 206.664020 -7176.826920 271.611686 +VL56 -16677.249000 -3375.783400 -73526.472000 +* 2023 12 9 14 12 0.00000000 +PL56 -95.040248 -7109.200633 -1048.903804 +VL56 -16686.118000 10866.005000 -72770.151000 +* 2023 12 9 14 15 0.00000000 +PL56 -388.356620 -6788.064483 -2332.906094 +VL56 -15749.923000 24706.049000 -69482.236000 +* 2023 12 9 14 18 0.00000000 +PL56 -656.663380 -6225.222285 -3535.781937 +VL56 -13919.502000 37640.790000 -63783.420000 +* 2023 12 9 14 21 0.00000000 +PL56 -884.652372 -5441.241029 -4615.856387 +VL56 -11289.323000 49203.198000 -55878.332000 +* 2023 12 9 14 24 0.00000000 +PL56 -1059.073192 -4464.634637 -5535.829826 +VL56 -7992.591200 58979.943000 -46046.738000 +* 2023 12 9 14 27 0.00000000 +PL56 -1169.373694 -3330.766192 -6264.031170 +VL56 -4194.692800 66625.439000 -34632.272000 +* 2023 12 9 14 30 0.00000000 +PL56 -1208.210608 -2080.525138 -6775.456016 +VL56 -85.408740 71872.798000 -22029.825000 +* 2023 12 9 14 33 0.00000000 +PL56 -1171.812371 -758.834726 -7052.566444 +VL56 4129.649600 74541.706000 -8671.795000 +* 2023 12 9 14 36 0.00000000 +PL56 -1060.183834 586.952943 -7085.841177 +VL56 8238.026200 74543.203000 4985.804000 +* 2023 12 9 14 39 0.00000000 +PL56 -877.145932 1908.723200 -6874.073298 +VL56 12029.698000 71881.646000 18477.492000 +* 2023 12 9 14 42 0.00000000 +PL56 -630.209866 3159.280593 -6424.416463 +VL56 15306.174000 66654.586000 31342.147000 +* 2023 12 9 14 45 0.00000000 +PL56 -330.289050 4294.006852 -5752.179623 +VL56 17889.383000 59050.221000 43137.165000 +* 2023 12 9 14 48 0.00000000 +PL56 8.746427 5272.450690 -4880.363618 +VL56 19630.206000 49342.222000 53452.843000 +* 2023 12 9 14 51 0.00000000 +PL56 370.659105 6059.797118 -3838.940281 +VL56 20415.900000 37881.561000 61926.682000 +* 2023 12 9 14 54 0.00000000 +PL56 737.558373 6628.162513 -2663.879313 +VL56 20176.433000 25085.242000 68256.913000 +* 2023 12 9 14 57 0.00000000 +PL56 1090.713655 6957.656123 -1395.942319 +VL56 18889.116000 11421.745000 72214.749000 +* 2023 12 9 15 0 0.00000000 +PL56 1411.432246 7037.154749 -79.274987 +VL56 16581.075000 -2606.381800 73654.441000 +* 2023 12 9 15 3 0.00000000 +PL56 1681.960363 6864.740484 1240.155185 +VL56 13329.271000 -16482.351000 72520.134000 +* 2023 12 9 15 6 0.00000000 +PL56 1886.359344 6447.770388 2516.208519 +VL56 9257.777200 -29695.830000 68848.661000 +* 2023 12 9 15 9 0.00000000 +PL56 2011.312293 5802.575332 3704.237422 +VL56 4532.805500 -41763.386000 62768.474000 +* 2023 12 9 15 12 0.00000000 +PL56 2046.821490 4953.800694 4762.696870 +VL56 -644.421870 -52247.747000 54494.748000 +* 2023 12 9 15 15 0.00000000 +PL56 1986.759330 3933.416211 5654.632102 +VL56 -6046.755400 -60774.974000 44320.482000 +* 2023 12 9 15 18 0.00000000 +PL56 1829.244934 2779.447846 6348.973605 +VL56 -11431.173000 -67047.741000 32604.447000 +* 2023 12 9 15 21 0.00000000 +PL56 1576.834983 1534.508502 6821.600070 +VL56 -16549.446000 -70855.189000 19757.596000 +* 2023 12 9 15 24 0.00000000 +PL56 1236.521572 244.183651 7056.147731 +VL56 -21158.793000 -72078.702000 6228.265500 +* 2023 12 9 15 27 0.00000000 +PL56 819.538118 -1044.660262 7044.543250 +VL56 -25032.400000 -70694.622000 -7513.204000 +* 2023 12 9 15 30 0.00000000 +PL56 340.981145 -2285.586671 6787.262771 +VL56 -27969.479000 -66774.126000 -20989.826000 +* 2023 12 9 15 33 0.00000000 +PL56 -180.742349 -3434.270531 6293.307515 +VL56 -29804.472000 -60479.937000 -33734.054000 +* 2023 12 9 15 36 0.00000000 +PL56 -724.621450 -4450.091489 5579.892492 +VL56 -30414.748000 -52059.530000 -45303.361000 +* 2023 12 9 15 39 0.00000000 +PL56 -1267.874477 -5297.583067 4671.865488 +VL56 -29727.134000 -41836.384000 -55294.472000 +* 2023 12 9 15 42 0.00000000 +PL56 -1786.887080 -5947.704672 3600.871821 +VL56 -27722.949000 -30198.904000 -63357.744000 +* 2023 12 9 15 45 0.00000000 +PL56 -2258.220315 -6378.883030 2404.264591 +VL56 -24440.619000 -17585.765000 -69210.637000 +* 2023 12 9 15 48 0.00000000 +PL56 -2659.642381 -6577.766958 1123.797034 +VL56 -19975.610000 -4468.889900 -72648.418000 +* 2023 12 9 15 51 0.00000000 +PL56 -2971.134793 -6539.663038 -195.856552 +VL56 -14477.652000 8664.861000 -73552.303000 +* 2023 12 9 15 54 0.00000000 +PL56 -3175.822606 -6268.629836 -1508.694661 +VL56 -8145.192100 21333.123000 -71894.069000 +* 2023 12 9 15 57 0.00000000 +PL56 -3260.784601 -5777.224860 -2769.030646 +VL56 -1217.598700 33077.074000 -67736.735000 +* 2023 12 9 16 0 0.00000000 +PL56 -3217.704207 -5085.917195 -3933.113321 +VL56 6034.662200 43479.284000 -61231.478000 +* 2023 12 9 16 3 0.00000000 +PL56 -3043.328417 -4222.198333 -4960.655975 +VL56 13321.388000 52179.202000 -52610.613000 +* 2023 12 9 16 6 0.00000000 +PL56 -2739.717135 -3219.445250 -5816.211898 +VL56 20344.433000 58885.177000 -42177.799000 +* 2023 12 9 16 9 0.00000000 +PL56 -2314.279524 -2115.595970 -6470.355425 +VL56 26809.553000 63383.278000 -30296.303000 +* 2023 12 9 16 12 0.00000000 +PL56 -1779.598281 -951.695997 -6900.639281 +VL56 32438.051000 65542.812000 -17375.931000 +* 2023 12 9 16 15 0.00000000 +PL56 -1153.051076 229.625991 -7092.306196 +VL56 36977.539000 65318.661000 -3858.986900 +* 2023 12 9 16 18 0.00000000 +PL56 -456.248042 1385.696079 -7038.747880 +VL56 40211.699000 62750.636000 9793.665300 +* 2023 12 9 16 21 0.00000000 +PL56 285.699144 2475.302379 -6741.715298 +VL56 41969.146000 57960.728000 23116.433000 +* 2023 12 9 16 24 0.00000000 +PL56 1045.058035 3460.135637 -6211.278881 +VL56 42131.343000 51148.586000 35652.885000 +* 2023 12 9 16 27 0.00000000 +PL56 1792.488059 4306.127416 -5465.532251 +VL56 40639.072000 42584.388000 46970.401000 +* 2023 12 9 16 30 0.00000000 +PL56 2498.153225 4984.641740 -4530.036019 +VL56 37497.115000 32599.836000 56674.330000 +* 2023 12 9 16 33 0.00000000 +PL56 3132.900518 5473.483386 -3437.006657 +VL56 32776.759000 21576.765000 64422.051000 +* 2023 12 9 16 36 0.00000000 +PL56 3669.460147 5757.679651 -2224.258115 +VL56 26615.752000 9933.410100 69936.318000 +* 2023 12 9 16 39 0.00000000 +PL56 4083.618457 5829.996181 -933.919831 +VL56 19215.126000 -1891.438500 73016.660000 +* 2023 12 9 16 42 0.00000000 +PL56 4355.304761 5691.154287 389.032368 +VL56 10832.806000 -13455.624000 73548.500000 +* 2023 12 9 16 45 0.00000000 +PL56 4469.534622 5349.729613 1698.376982 +VL56 1774.193900 -24331.552000 71508.560000 +* 2023 12 9 16 48 0.00000000 +PL56 4417.158990 4821.731964 2948.308787 +VL56 -7619.836600 -34123.478000 66966.329000 +* 2023 12 9 16 51 0.00000000 +PL56 4195.381042 4129.887761 4095.095357 +VL56 -16986.913000 -42483.503000 60081.833000 +* 2023 12 9 16 54 0.00000000 +PL56 3808.008211 3302.652645 5098.651241 +VL56 -25958.055000 -49124.848000 51098.932000 +* 2023 12 9 16 57 0.00000000 +PL56 3265.432806 2373.013397 5923.962309 +VL56 -34173.158000 -53832.253000 40335.416000 +* 2023 12 9 17 0 0.00000000 +PL56 2584.339147 1377.136446 6542.305706 +VL56 -41295.497000 -56468.443000 28170.089000 +* 2023 12 9 17 3 0.00000000 +PL56 1787.162824 352.930515 6932.223907 +VL56 -47024.869000 -56977.286000 15028.923000 +* 2023 12 9 17 6 0.00000000 +PL56 901.324514 -661.413027 7080.236184 +VL56 -51109.415000 -55383.287000 1369.833700 +* 2023 12 9 17 9 0.00000000 +PL56 -41.732977 -1628.850697 6981.278709 +VL56 -53355.629000 -51788.814000 -12332.555000 +* 2023 12 9 17 12 0.00000000 +PL56 -1007.673471 -2514.845292 6638.860996 +VL56 -53636.716000 -46368.860000 -25602.833000 +* 2023 12 9 17 15 0.00000000 +PL56 -1960.522455 -3288.603027 6064.935703 +VL56 -51898.193000 -39362.872000 -37980.907000 +* 2023 12 9 17 18 0.00000000 +PL56 -2864.004334 -3924.150125 5279.495311 +VL56 -48161.562000 -31065.218000 -49036.017000 +* 2023 12 9 17 21 0.00000000 +PL56 -3682.932022 -4401.223519 4309.904785 +VL56 -42526.303000 -21813.987000 -58382.201000 +* 2023 12 9 17 24 0.00000000 +PL56 -4384.596379 -4705.938781 3189.966819 +VL56 -35167.621000 -11977.488000 -65692.363000 +* 2023 12 9 17 27 0.00000000 +PL56 -4940.088456 -4831.206084 1958.749658 +VL56 -26331.428000 -1939.877300 -70710.349000 +* 2023 12 9 17 30 0.00000000 +PL56 -5325.502628 -4776.878580 659.215954 +VL56 -16326.111000 7914.179400 -73261.057000 +* 2023 12 9 17 33 0.00000000 +PL56 -5522.963626 -4549.620749 -663.303045 +VL56 -5511.212200 17215.073000 -73257.298000 +* 2023 12 9 17 36 0.00000000 +PL56 -5521.424808 -4162.501888 -1962.726956 +VL56 5716.596000 25623.146000 -70703.286000 +* 2023 12 9 17 39 0.00000000 +PL56 -5317.194575 -3634.332724 -3193.871993 +VL56 16939.568000 32842.198000 -65693.916000 +* 2023 12 9 17 42 0.00000000 +PL56 -4914.165380 -2988.781498 -4314.045342 +VL56 27735.519000 38630.257000 -58409.991000 +* 2023 12 9 17 45 0.00000000 +PL56 -4323.744753 -2253.321485 -5284.524047 +VL56 37694.299000 42807.582000 -49110.292000 +* 2023 12 9 17 48 0.00000000 +PL56 -3564.497726 -1458.062540 -6071.867637 +VL56 46433.286000 45261.551000 -38121.027000 +* 2023 12 9 17 51 0.00000000 +PL56 -2661.523197 -634.521129 -6649.023195 +VL56 53611.282000 45948.556000 -25823.511000 +* 2023 12 9 17 54 0.00000000 +PL56 -1645.595385 185.618015 -6996.195955 +VL56 58940.742000 44893.115000 -12640.574000 +* 2023 12 9 17 57 0.00000000 +PL56 -552.106484 971.698983 -7101.470384 +VL56 62197.549000 42184.293000 977.445360 +* 2023 12 9 18 0 0.00000000 +PL56 580.149367 1695.213212 -6961.181532 +VL56 63229.034000 37970.624000 14566.470000 +* 2023 12 9 18 3 0.00000000 +PL56 1710.320241 2330.810470 -6580.039080 +VL56 61960.209000 32453.301000 27662.369000 +* 2023 12 9 18 6 0.00000000 +PL56 2796.941001 2857.177707 -5970.998658 +VL56 58398.346000 25878.164000 39815.483000 +* 2023 12 9 18 9 0.00000000 +PL56 3799.435014 3257.758247 -5154.870663 +VL56 52635.015000 18526.187000 50605.099000 +* 2023 12 9 18 12 0.00000000 +PL56 4679.626234 3521.288569 -4159.674191 +VL56 44845.136000 10702.676000 59653.387000 +* 2023 12 9 18 15 0.00000000 +PL56 5403.216047 3642.134456 -3019.737676 +VL56 35283.641000 2725.738700 66639.308000 +* 2023 12 9 18 18 0.00000000 +PL56 5941.160225 3620.406317 -1774.557426 +VL56 24277.956000 -5086.502000 71311.604000 +* 2023 12 9 18 21 0.00000000 +PL56 6270.883242 3461.844927 -467.444673 +VL56 12217.297000 -12428.815000 73499.350000 +* 2023 12 9 18 24 0.00000000 +PL56 6377.266703 3177.473307 855.995981 +VL56 -461.655730 -19021.625000 73119.680000 +* 2023 12 9 18 27 0.00000000 +PL56 6253.356265 2783.026457 2149.496751 +VL56 -13291.486000 -24622.699000 70182.032000 +* 2023 12 9 18 30 0.00000000 +PL56 5900.744264 2298.187183 3367.796212 +VL56 -25793.119000 -29037.088000 64788.539000 +* 2023 12 9 18 33 0.00000000 +PL56 5329.605556 1745.664230 4468.276454 +VL56 -37495.376000 -32124.601000 57129.806000 +* 2023 12 9 18 36 0.00000000 +PL56 4558.381807 1150.159050 5412.490954 +VL56 -47953.942000 -33804.538000 47476.997000 +* 2023 12 9 18 39 0.00000000 +PL56 3613.139728 537.276235 6167.520381 +VL56 -56768.619000 -34057.276000 36171.166000 +* 2023 12 9 18 42 0.00000000 +PL56 2526.632568 -67.570290 6707.111552 +VL56 -63598.895000 -32923.131000 23609.567000 +* 2023 12 9 18 45 0.00000000 +PL56 1337.116062 -640.202980 7012.559825 +VL56 -68175.777000 -30498.399000 10231.209000 +* 2023 12 9 18 48 0.00000000 +PL56 86.968892 -1158.640316 7073.328000 +VL56 -70311.601000 -26929.698000 -3498.105200 +* 2023 12 9 18 51 0.00000000 +PL56 -1178.838945 -1603.937553 6887.383846 +VL56 -69906.867000 -22406.397000 -17101.816000 +* 2023 12 9 18 54 0.00000000 +PL56 -2414.372027 -1960.878373 6461.251563 +VL56 -66954.177000 -17151.805000 -30108.263000 +* 2023 12 9 18 57 0.00000000 +PL56 -3574.396479 -2218.494262 5809.786871 +VL56 -61538.998000 -11412.948000 -42065.837000 +* 2023 12 9 19 0 0.00000000 +PL56 -4616.048139 -2370.402131 4955.684789 +VL56 -53838.615000 -5450.449200 -52557.849000 +* 2023 12 9 19 3 0.00000000 +PL56 -5500.444888 -2414.949253 3928.710712 +VL56 -44117.036000 472.589220 -61217.657000 +* 2023 12 9 19 6 0.00000000 +PL56 -6194.172164 -2355.154537 2764.676769 +VL56 -32716.044000 6102.035900 -67742.056000 +* 2023 12 9 19 9 0.00000000 +PL56 -6670.584696 -2198.451011 1504.198074 +VL56 -20043.768000 11203.300000 -71902.385000 +* 2023 12 9 19 12 0.00000000 +PL56 -6910.869364 -1956.242179 191.260348 +VL56 -6559.477700 15571.427000 -73554.084000 +* 2023 12 9 19 15 0.00000000 +PL56 -6904.807149 -1643.286985 -1128.349486 +VL56 7244.276200 19039.846000 -72642.232000 +* 2023 12 9 19 18 0.00000000 +PL56 -6651.196119 -1276.944780 -2408.680433 +VL56 20861.504000 21487.097000 -69203.450000 +* 2023 12 9 19 21 0.00000000 +PL56 -6157.914988 -876.321296 -3605.250709 +VL56 33792.580000 22841.108000 -63363.668000 +* 2023 12 9 19 24 0.00000000 +PL56 -5441.632199 -461.359200 -4676.608827 +VL56 45563.584000 23081.097000 -55332.434000 +* 2023 12 9 19 27 0.00000000 +PL56 -4527.180480 -51.915431 -5585.761593 +VL56 55744.089000 22237.068000 -45393.857000 +* 2023 12 9 19 30 0.00000000 +PL56 -3446.633222 333.128848 -6301.417565 +VL56 63962.309000 20386.747000 -33895.244000 +* 2023 12 9 19 33 0.00000000 +PL56 -2238.131393 676.685659 -6799.008679 +VL56 69917.590000 17650.669000 -21234.138000 +* 2023 12 9 19 36 0.00000000 +PL56 -944.517679 964.172756 -7061.471879 +VL56 73389.563000 14185.534000 -7844.588800 +* 2023 12 9 19 39 0.00000000 +PL56 388.173729 1184.098783 -7079.783044 +VL56 74244.800000 10176.717000 5816.581100 +* 2023 12 9 19 42 0.00000000 +PL56 1712.322343 1328.503949 -6853.241415 +VL56 72441.056000 5829.818300 19283.556000 +* 2023 12 9 19 45 0.00000000 +PL56 2980.387500 1393.245001 -6389.507107 +VL56 68029.633000 1361.758800 32095.722000 +* 2023 12 9 19 48 0.00000000 +PL56 4146.590742 1378.115475 -5704.376463 +VL56 61154.663000 -3008.555600 43812.090000 +* 2023 12 9 19 51 0.00000000 +PL56 5168.560425 1286.795735 -4821.299550 +VL56 52049.809000 -7069.702800 54025.476000 +* 2023 12 9 19 54 0.00000000 +PL56 6008.893469 1126.634673 -3770.644042 +VL56 41032.167000 -10627.014000 62376.787000 +* 2023 12 9 19 57 0.00000000 +PL56 6636.574699 908.267346 -2588.707660 +VL56 28492.503000 -13511.455000 68568.406000 +* 2023 12 9 20 0 0.00000000 +PL56 7028.192456 645.080475 -1316.500908 +VL56 14882.411000 -15587.549000 72376.203000 +* 2023 12 9 20 3 0.00000000 +PL56 7168.889042 352.546223 1.671876 +VL56 697.717850 -16760.016000 73659.673000 +* 2023 12 9 20 6 0.00000000 +PL56 7052.986184 47.453671 1319.780632 +VL56 -13540.779000 -16978.415000 72368.369000 +* 2023 12 9 20 9 0.00000000 +PL56 6684.251491 -252.925083 2591.721945 +VL56 -27307.900000 -16239.756000 68544.814000 +* 2023 12 9 20 12 0.00000000 +PL56 6075.782892 -531.693365 3772.987822 +VL56 -40095.762000 -14588.554000 62323.104000 +* 2023 12 9 20 15 0.00000000 +PL56 5249.512989 -773.167046 4822.270407 +VL56 -51433.779000 -12114.379000 53923.381000 +* 2023 12 9 20 18 0.00000000 +PL56 4235.366871 -963.647688 5702.934817 +VL56 -60907.229000 -8947.382600 43643.129000 +* 2023 12 9 20 21 0.00000000 +PL56 3070.113821 -1092.094226 6384.303242 +VL56 -68172.798000 -5251.465400 31844.603000 +* 2023 12 9 20 24 0.00000000 +PL56 1795.975020 -1150.661841 6842.705780 +VL56 -72969.715000 -1216.399200 18941.618000 +* 2023 12 9 20 27 0.00000000 +PL56 459.049385 -1135.089367 7062.274169 +VL56 -75128.889000 2950.956900 5384.744100 +* 2023 12 9 20 30 0.00000000 +PL56 -892.384256 -1044.919264 7035.459601 +VL56 -74577.816000 7036.416600 -8354.773100 +* 2023 12 9 20 33 0.00000000 +PL56 -2209.622723 -883.542922 6763.266411 +VL56 -71341.837000 10828.173000 -21800.531000 +* 2023 12 9 20 36 0.00000000 +PL56 -3445.295196 -658.070359 6255.207591 +VL56 -65543.161000 14126.430000 -34486.007000 +* 2023 12 9 20 39 0.00000000 +PL56 -4555.073450 -379.028926 5528.986900 +VL56 -57396.832000 16752.749000 -45970.125000 +* 2023 12 9 20 42 0.00000000 +PL56 -5499.285707 -59.902527 4609.905842 +VL56 -47203.744000 18558.425000 -55852.337000 +* 2023 12 9 20 45 0.00000000 +PL56 -6244.371528 283.473095 3530.002069 +VL56 -35339.958000 19431.971000 -63787.013000 +* 2023 12 9 20 48 0.00000000 +PL56 -6764.118217 633.635944 2326.944020 +VL56 -22243.349000 19305.020000 -69496.030000 +* 2023 12 9 20 51 0.00000000 +PL56 -7040.629216 972.314125 1042.714510 +VL56 -8397.155100 18156.423000 -72779.730000 +* 2023 12 9 20 54 0.00000000 +PL56 -7064.977146 1281.294327 -277.876996 +VL56 5688.600000 16013.957000 -73524.848000 +* 2023 12 9 20 57 0.00000000 +PL56 -6837.503232 1543.300633 -1588.795627 +VL56 19497.540000 12953.669000 -71708.871000 +* 2023 12 9 21 0 0.00000000 +PL56 -6367.747367 1742.839100 -2844.423764 +VL56 32527.270000 9096.831200 -67400.383000 +* 2023 12 9 21 3 0.00000000 +PL56 -5674.019546 1866.968749 -4001.178017 +VL56 44308.971000 4604.764800 -60755.979000 +* 2023 12 9 21 6 0.00000000 +PL56 -4782.630753 1905.958679 -5019.033286 +VL56 54425.131000 -328.510330 -52012.940000 +* 2023 12 9 21 9 0.00000000 +PL56 -3726.832896 1853.801218 -5862.887661 +VL56 62524.159000 -5484.835200 -41479.130000 +* 2023 12 9 21 12 0.00000000 +PL56 -2545.529371 1708.562766 -6503.727186 +VL56 68331.287000 -10631.310000 -29521.053000 +* 2023 12 9 21 15 0.00000000 +PL56 -1281.815665 1472.560874 -6919.566067 +VL56 71656.585000 -15530.140000 -16550.816000 +* 2023 12 9 21 18 0.00000000 +PL56 18.594643 1152.363346 -7096.141453 +VL56 72399.515000 -19948.507000 -3012.079800 +* 2023 12 9 21 21 0.00000000 +PL56 1308.997722 758.611904 -7027.358308 +VL56 70550.692000 -23668.123000 10633.525000 +* 2023 12 9 21 24 0.00000000 +PL56 2543.341311 305.676528 -6715.489348 +VL56 66191.726000 -26494.559000 23920.302000 +* 2023 12 9 21 27 0.00000000 +PL56 3677.840206 -188.853963 -6171.117066 +VL56 59492.232000 -28265.968000 36393.003000 +* 2023 12 9 21 30 0.00000000 +PL56 4672.514840 -704.830227 -5412.816559 +VL56 50704.237000 -28860.927000 47621.168000 +* 2023 12 9 21 33 0.00000000 +PL56 5492.609966 -1220.332221 -4466.584471 +VL56 40154.690000 -28205.128000 57213.001000 +* 2023 12 9 21 36 0.00000000 +PL56 6109.851181 -1712.567458 -3365.013483 +VL56 28234.771000 -26276.632000 64829.662000 +* 2023 12 9 21 39 0.00000000 +PL56 6503.483771 -2158.844772 -2146.220102 +VL56 15386.349000 -23108.990000 70198.352000 +* 2023 12 9 21 42 0.00000000 +PL56 6661.043659 -2537.583717 -852.550402 +VL56 2085.790700 -18791.939000 73123.640000 +* 2023 12 9 21 45 0.00000000 +PL56 6578.815973 -2829.311617 470.896616 +VL56 -11174.293000 -13469.375000 73496.249000 +* 2023 12 9 21 48 0.00000000 +PL56 6261.951354 -3017.598507 1777.873847 +VL56 -23904.773000 -7334.434800 71298.500000 +* 2023 12 9 21 51 0.00000000 +PL56 5724.224711 -3089.880346 3022.654471 +VL56 -35639.898000 -622.055350 66605.734000 +* 2023 12 9 21 54 0.00000000 +PL56 4987.441283 -3038.125982 4161.686467 +VL56 -45956.075000 6400.825900 59583.410000 +* 2023 12 9 21 57 0.00000000 +PL56 4080.524486 -2859.311471 5155.156635 +VL56 -54488.385000 13446.712000 50480.087000 +* 2023 12 9 22 0 0.00000000 +PL56 3038.336994 -2555.683711 5968.403160 +VL56 -60943.901000 20219.575000 39617.653000 +* 2023 12 9 22 3 0.00000000 +PL56 1900.288426 -2134.799860 6573.123001 +VL56 -65111.622000 26427.483000 27378.493000 +* 2023 12 9 22 6 0.00000000 +PL56 708.801765 -1609.343800 6948.333349 +VL56 -66868.451000 31794.695000 14191.117000 +* 2023 12 9 22 9 0.00000000 +PL56 -492.297501 -996.731158 7081.067142 +VL56 -66181.799000 36073.053000 514.993320 +* 2023 12 9 22 12 0.00000000 +PL56 -1659.406970 -318.517477 6966.789959 +VL56 -63108.641000 39052.323000 -13174.939000 +* 2023 12 9 22 15 0.00000000 +PL56 -2750.732821 400.369143 6609.537553 +VL56 -57792.143000 40569.440000 -26403.948000 +* 2023 12 9 22 18 0.00000000 +PL56 -3727.789265 1132.547224 6021.775037 +VL56 -50455.509000 40516.009000 -38712.754000 +* 2023 12 9 22 21 0.00000000 +PL56 -4556.767832 1849.223384 5223.979275 +VL56 -41393.628000 38844.348000 -49672.942000 +* 2023 12 9 22 24 0.00000000 +PL56 -5209.732916 2521.322505 4243.949368 +VL56 -30962.112000 35571.320000 -58901.776000 +* 2023 12 9 22 27 0.00000000 +PL56 -5665.596786 3120.666550 3115.855955 +VL56 -19563.788000 30779.710000 -66076.221000 +* 2023 12 9 22 30 0.00000000 +PL56 -5910.832537 3621.152253 1879.056855 +VL56 -7633.203800 24616.802000 -70944.819000 +* 2023 12 9 22 33 0.00000000 +PL56 -5939.896737 3999.878169 576.714847 +VL56 4380.089200 17290.083000 -73337.665000 +* 2023 12 9 22 36 0.00000000 +PL56 -5755.335131 4238.165039 -745.738124 +VL56 16029.767000 9059.747600 -73173.322000 +* 2023 12 9 22 39 0.00000000 +PL56 -5367.565222 4322.417352 -2042.223700 +VL56 26890.506000 228.592700 -70461.724000 +* 2023 12 9 22 42 0.00000000 +PL56 -4794.346379 4244.785090 -3267.662674 +VL56 36574.620000 -8870.085100 -65303.399000 +* 2023 12 9 22 45 0.00000000 +PL56 -4059.961772 4003.589346 -4379.567843 +VL56 44747.050000 -17886.172000 -57884.650000 +* 2023 12 9 22 48 0.00000000 +PL56 -3194.163184 3603.497260 -5339.514072 +VL56 51136.861000 -26466.944000 -48468.902000 +* 2023 12 9 22 51 0.00000000 +PL56 -2230.939296 3055.447019 -6114.433590 +VL56 55545.267000 -34270.588000 -37386.028000 +* 2023 12 9 22 54 0.00000000 +PL56 -1207.167907 2376.333894 -6677.705144 +VL56 57850.666000 -40979.139000 -25020.273000 +* 2023 12 9 22 57 0.00000000 +PL56 -161.203642 1588.470637 -7010.010151 +VL56 58010.607000 -46310.432000 -11796.528000 +* 2023 12 9 23 0 0.00000000 +PL56 868.540694 718.848378 -7099.940303 +VL56 56060.755000 -50028.456000 1833.445400 +* 2023 12 9 23 3 0.00000000 +PL56 1844.976267 -201.776692 -6944.357729 +VL56 52111.935000 -51952.339000 15404.867000 +* 2023 12 9 23 6 0.00000000 +PL56 2733.648551 -1139.948956 -6548.500490 +VL56 46344.897000 -51964.067000 28454.260000 +* 2023 12 9 23 9 0.00000000 +PL56 3503.935595 -2060.700976 -5925.831303 +VL56 39003.419000 -50014.501000 40533.556000 +* 2023 12 9 23 12 0.00000000 +PL56 4130.104534 -2928.831398 -5097.633186 +VL56 30385.472000 -46127.456000 51224.267000 +* 2023 12 9 23 15 0.00000000 +PL56 4592.196051 -3710.242504 -4092.347729 +VL56 20832.519000 -40401.755000 60151.932000 +* 2023 12 9 23 18 0.00000000 +PL56 4876.696997 -4373.285568 -2944.657523 +VL56 10717.144000 -33010.250000 66999.697000 +* 2023 12 9 23 21 0.00000000 +PL56 4976.976553 -4890.060563 -1694.334309 +VL56 429.053670 -24195.688000 71520.954000 +* 2023 12 9 23 24 0.00000000 +PL56 4893.459681 -5237.614101 -384.875953 +VL56 -9640.138600 -14263.421000 73549.848000 +* 2023 12 9 23 27 0.00000000 +PL56 4633.517222 -5398.973270 938.024223 +VL56 -19112.883000 -3570.542400 73009.261000 +* 2023 12 9 23 30 0.00000000 +PL56 4211.071639 -5363.955652 2228.114518 +VL56 -27641.281000 7488.052500 69914.651000 +* 2023 12 9 23 33 0.00000000 +PL56 3645.933239 -5129.709066 3440.256545 +VL56 -34921.253000 18495.576000 64373.836000 +* 2023 12 9 23 36 0.00000000 +PL56 2962.900410 -4700.953899 4532.054026 +VL56 -40704.428000 29030.344000 56582.632000 +* 2023 12 9 23 39 0.00000000 +PL56 2190.671629 -4089.915209 5465.370284 +VL56 -44807.029000 38682.990000 46816.910000 +* 2023 12 9 23 42 0.00000000 +PL56 1360.625593 -3315.950899 6207.672661 +VL56 -47115.718000 47072.975000 35421.450000 +* 2023 12 9 23 45 0.00000000 +PL56 505.527255 -2404.896980 6733.156241 +VL56 -47589.944000 53863.366000 22796.490000 +* 2023 12 9 23 48 0.00000000 +PL56 -341.780448 -1388.164260 7023.610849 +VL56 -46261.169000 58773.584000 9383.166200 +* 2023 12 9 23 51 0.00000000 +PL56 -1149.643124 -301.626750 7069.018594 +VL56 -43229.227000 61589.910000 -4351.866200 +* 2023 12 9 23 54 0.00000000 +PL56 -1888.777536 815.661747 6867.875492 +VL56 -38656.622000 62173.896000 -17931.920000 +* 2023 12 9 23 57 0.00000000 +PL56 -2533.333700 1922.879746 6427.230278 +VL56 -32760.896000 60468.382000 -30885.975000 +* 2023 12 10 0 0 0.00000000 +PL56 -3061.802707 2978.933243 5762.442911 +VL56 -25805.165000 56500.631000 -42764.145000 +* 2023 12 10 0 3 0.00000000 +PL56 -3457.743255 3943.988462 4896.669392 +VL56 -18087.494000 50383.270000 -53152.588000 +* 2023 12 10 0 6 0.00000000 +PL56 -3710.304851 4780.991735 3860.079681 +VL56 -9928.919200 42311.942000 -61688.148000 +* 2023 12 10 0 9 0.00000000 +PL56 -3814.526075 5457.119790 2688.823221 +VL56 -1660.519400 32559.814000 -68071.696000 +* 2023 12 10 0 12 0.00000000 +PL56 -3771.392742 5945.097311 1423.767961 +VL56 6390.238700 21468.317000 -72079.805000 +* 2023 12 10 0 15 0.00000000 +PL56 -3587.652386 6224.318068 109.057792 +VL56 13912.820000 9434.732800 -73573.072000 +* 2023 12 10 0 18 0.00000000 +PL56 -3275.395003 6281.720905 -1209.458445 +VL56 20626.165000 -3102.586100 -72502.126000 +* 2023 12 10 0 21 0.00000000 +PL56 -2851.416459 6112.370396 -2485.869925 +VL56 26290.214000 -15682.206000 -68909.445000 +* 2023 12 10 0 24 0.00000000 +PL56 -2336.392385 5719.706717 -3675.840157 +VL56 30715.265000 -27838.073000 -62926.627000 +* 2023 12 10 0 27 0.00000000 +PL56 -1753.912949 5115.463924 -4738.158337 +VL56 33767.984000 -39117.645000 -54768.070000 +* 2023 12 10 0 30 0.00000000 +PL56 -1129.432284 4319.270335 -5636.151791 +VL56 35374.871000 -49098.965000 -44721.860000 +* 2023 12 10 0 33 0.00000000 +PL56 -489.182034 3357.960509 -6338.913290 +VL56 35522.988000 -57405.707000 -33138.620000 +* 2023 12 10 0 36 0.00000000 +PL56 140.906867 2264.630426 -6822.314122 +VL56 34258.200000 -63720.514000 -20418.586000 +* 2023 12 10 0 39 0.00000000 +PL56 736.229239 1077.476587 -7069.773825 +VL56 31681.081000 -67795.535000 -6997.895100 +* 2023 12 10 0 42 0.00000000 +PL56 1274.440511 -161.533060 -7072.781777 +VL56 27941.157000 -69460.761000 6665.283600 +* 2023 12 10 0 45 0.00000000 +PL56 1736.275204 -1408.119429 -6831.165650 +VL56 23229.718000 -68630.283000 20105.018000 +* 2023 12 10 0 48 0.00000000 +PL56 2106.223851 -2617.240738 -6353.103389 +VL56 17771.360000 -65305.687000 32861.748000 +* 2023 12 10 0 51 0.00000000 +PL56 2373.052959 -3744.687916 -5654.884512 +VL56 11814.984000 -59578.015000 44496.062000 +* 2023 12 10 0 54 0.00000000 +PL56 2530.153949 -4748.693053 -4760.416398 +VL56 5623.850600 -51627.083000 54603.475000 +* 2023 12 10 0 57 0.00000000 +PL56 2575.705438 -5591.492230 -3700.467386 +VL56 -535.206430 -41716.957000 62828.357000 +* 2023 12 10 1 0 0.00000000 +PL56 2512.640488 -6240.784592 -2511.666329 +VL56 -6402.562800 -30189.149000 68877.286000 +* 2023 12 10 1 3 0.00000000 +PL56 2348.417033 -6671.031668 -1235.272631 +VL56 -11736.877000 -17451.450000 72531.092000 +* 2023 12 10 1 6 0.00000000 +PL56 2094.595301 -6864.528467 84.252599 +VL56 -16325.348000 -3963.642000 73654.616000 +* 2023 12 10 1 9 0.00000000 +PL56 1766.237285 -6812.181135 1400.824165 +VL56 -19993.116000 9780.430600 72203.176000 +* 2023 12 10 1 12 0.00000000 +PL56 1381.155567 -6513.948310 2668.390029 +VL56 -22610.492000 23272.136000 68225.368000 +* 2023 12 10 1 15 0.00000000 +PL56 959.047487 -5978.914750 3842.599491 +VL56 -24098.375000 36009.562000 61860.957000 +* 2023 12 10 1 18 0.00000000 +PL56 520.558939 -5224.993999 4882.399804 +VL56 -24430.646000 47516.907000 53335.216000 +* 2023 12 10 1 21 0.00000000 +PL56 86.326637 -4278.282238 5751.496973 +VL56 -23634.225000 57363.682000 42949.946000 +* 2023 12 10 1 24 0.00000000 +PL56 -323.953679 -3172.094529 6419.626804 +VL56 -21786.098000 65180.854000 31071.186000 +* 2023 12 10 1 27 0.00000000 +PL56 -692.388137 -1945.730999 6863.589212 +VL56 -19008.486000 70674.311000 18115.238000 +* 2023 12 10 1 30 0.00000000 +PL56 -1003.640242 -643.037641 7068.019387 +VL56 -15462.087000 73634.484000 4533.955300 +* 2023 12 10 1 33 0.00000000 +PL56 -1245.553200 689.186018 7025.891157 +VL56 -11338.079000 73943.778000 -9200.620500 +* 2023 12 10 1 36 0.00000000 +PL56 -1409.618255 2002.882632 6738.739267 +VL56 -6849.014600 71580.407000 -22611.952000 +* 2023 12 10 1 39 0.00000000 +PL56 -1491.272363 3250.477375 6216.598392 +VL56 -2219.116800 66619.670000 -35234.692000 +* 2023 12 10 1 42 0.00000000 +PL56 -1490.018261 4386.609150 5477.663173 +VL56 2325.763200 59231.685000 -46630.075000 +* 2023 12 10 1 45 0.00000000 +PL56 -1409.363756 5369.798407 4547.676095 +VL56 6568.116300 49676.501000 -56400.668000 +* 2023 12 10 1 48 0.00000000 +PL56 -1256.583184 6163.995204 3459.052587 +VL56 10308.527000 38295.653000 -64204.703000 +* 2023 12 10 1 51 0.00000000 +PL56 -1042.310896 6739.943524 2249.763553 +VL56 13374.441000 25500.306000 -69768.651000 +* 2023 12 10 1 54 0.00000000 +PL56 -779.983970 7076.307033 962.006097 +VL56 15628.260000 11756.392000 -72898.028000 +* 2023 12 10 1 57 0.00000000 +PL56 -485.152521 7160.494676 -359.293855 +VL56 16973.705000 -2433.429600 -73485.112000 +* 2023 12 10 2 0 0.00000000 +PL56 -174.695047 6989.147254 -1668.084895 +VL56 17359.965000 -16549.476000 -71513.039000 +* 2023 12 10 2 3 0.00000000 +PL56 134.021107 6568.254508 -2918.837312 +VL56 16783.587000 -30076.159000 -67056.199000 +* 2023 12 10 2 6 0.00000000 +PL56 423.988417 5912.899801 -4068.152065 +VL56 15287.746000 -42521.852000 -60276.036000 +* 2023 12 10 2 9 0.00000000 +PL56 679.378572 5046.661599 -5076.269669 +VL56 12959.672000 -53437.190000 -51414.070000 +* 2023 12 10 2 12 0.00000000 +PL56 886.296154 4000.702631 -5908.425711 +VL56 9925.969600 -62431.286000 -40781.928000 +* 2023 12 10 2 15 0.00000000 +PL56 1033.431718 2812.594856 -6536.007313 +VL56 6346.161600 -69184.841000 -28749.359000 +* 2023 12 10 2 18 0.00000000 +PL56 1112.586730 1524.935707 -6937.480311 +VL56 2405.031700 -73460.133000 -15730.822000 +* 2023 12 10 2 21 0.00000000 +PL56 1119.053164 183.815778 -7099.070608 +VL56 -1695.807800 -75107.664000 -2171.810300 +* 2023 12 10 2 24 0.00000000 +PL56 1051.836359 -1162.811841 -7015.196791 +VL56 -5746.914900 -74070.427000 11465.233000 +* 2023 12 10 2 27 0.00000000 +PL56 913.713726 -2466.812889 -6688.646474 +VL56 -9540.127800 -70385.290000 24715.228000 +* 2023 12 10 2 30 0.00000000 +PL56 711.130000 -3681.554706 -6130.501259 +VL56 -12877.623000 -64181.987000 37123.955000 +* 2023 12 10 2 33 0.00000000 +PL56 453.929540 -4763.556906 -5359.810447 +VL56 -15580.963000 -55680.245000 48262.836000 +* 2023 12 10 2 36 0.00000000 +PL56 154.932198 -5674.057328 -4403.002548 +VL56 -17499.325000 -45183.325000 57742.895000 +* 2023 12 10 2 39 0.00000000 +PL56 -170.634781 -6380.440099 -3293.043862 +VL56 -18517.191000 -33069.067000 65228.920000 +* 2023 12 10 2 42 0.00000000 +PL56 -505.830776 -6857.469340 -2068.352408 +VL56 -18560.624000 -19777.304000 70452.406000 +* 2023 12 10 2 45 0.00000000 +PL56 -832.793969 -7088.270179 -771.492291 +VL56 -17601.807000 -5794.323100 73222.943000 +* 2023 12 10 2 48 0.00000000 +PL56 -1133.596761 -7065.000982 552.315015 +VL56 -15661.448000 8365.760300 73436.818000 +* 2023 12 10 2 51 0.00000000 +PL56 -1391.123234 -6789.172831 1856.802843 +VL56 -12808.830000 22181.328000 71082.123000 +* 2023 12 10 2 54 0.00000000 +PL56 -1589.924882 -6271.595291 3096.328387 +VL56 -9159.300700 35144.372000 66239.950000 +* 2023 12 10 2 57 0.00000000 +PL56 -1717.008175 -5531.943346 4227.525351 +VL56 -4869.250200 46781.204000 59081.272000 +* 2023 12 10 3 0 0.00000000 +PL56 -1762.511697 -4597.967850 5210.861672 +VL56 -128.998270 56671.027000 49859.620000 +* 2023 12 10 3 3 0.00000000 +PL56 -1720.242314 -3504.398433 6012.038314 +VL56 4845.716900 64461.572000 38901.049000 +* 2023 12 10 3 6 0.00000000 +PL56 -1588.046109 -2291.590902 6603.182189 +VL56 9823.563700 69881.759000 26591.136000 +* 2023 12 10 3 9 0.00000000 +PL56 -1367.995698 -1003.986524 6963.789243 +VL56 14567.960000 72749.832000 13360.633000 +* 2023 12 10 3 12 0.00000000 +PL56 -1066.393104 311.548586 7081.403286 +VL56 18847.249000 72978.693000 -329.617850 +* 2023 12 10 3 15 0.00000000 +PL56 -693.589795 1607.446703 6952.017425 +VL56 22444.848000 70577.510000 -14004.179000 +* 2023 12 10 3 18 0.00000000 +PL56 -263.625235 2837.165700 6580.196349 +VL56 25169.132000 65650.571000 -27188.719000 +* 2023 12 10 3 21 0.00000000 +PL56 206.304005 3956.866971 5978.916040 +VL56 26862.309000 58393.067000 -39425.548000 +* 2023 12 10 3 24 0.00000000 +PL56 696.524069 4926.990828 5169.125889 +VL56 27408.122000 49083.857000 -50288.969000 +* 2023 12 10 3 27 0.00000000 +PL56 1185.691327 5713.679792 4179.041368 +VL56 26738.196000 38075.735000 -59399.732000 +* 2023 12 10 3 30 0.00000000 +PL56 1651.696945 6289.996863 3043.180936 +VL56 24836.436000 25782.429000 -66438.816000 +* 2023 12 10 3 33 0.00000000 +PL56 2072.636366 6636.895560 1801.173512 +VL56 21741.789000 12664.214000 -71159.324000 +* 2023 12 10 3 36 0.00000000 +PL56 2427.797450 6743.889010 496.357673 +VL56 17547.723000 -791.015150 -73397.338000 +* 2023 12 10 3 39 0.00000000 +PL56 2698.617092 6609.377050 -825.762482 +VL56 12398.771000 -14087.207000 -73077.014000 +* 2023 12 10 3 42 0.00000000 +PL56 2869.560848 6240.622255 -2119.139641 +VL56 6485.668100 -26739.030000 -70213.832000 +* 2023 12 10 3 45 0.00000000 +PL56 2928.884550 5653.379633 -3338.819295 +VL56 37.431874 -38291.181000 -64913.305000 +* 2023 12 10 3 48 0.00000000 +PL56 2869.240564 4871.197865 -4442.523678 +VL56 -6688.178900 -48335.738000 -57366.196000 +* 2023 12 10 3 51 0.00000000 +PL56 2688.098341 3924.428765 -5392.115255 +VL56 -13415.545000 -56526.834000 -47840.123000 +* 2023 12 10 3 54 0.00000000 +PL56 2387.964208 2849.004525 -6154.884673 +VL56 -19862.516000 -62591.882000 -36668.648000 +* 2023 12 10 3 57 0.00000000 +PL56 1976.397673 1685.042620 -6704.628391 +VL56 -25751.677000 -66339.511000 -24238.857000 +* 2023 12 10 4 0 0.00000000 +PL56 1465.826527 475.338335 -7022.489244 +VL56 -30821.245000 -67664.026000 -10977.646000 +* 2023 12 10 4 3 0.00000000 +PL56 873.171948 -736.195559 -7097.550407 +VL56 -34835.454000 -66546.998000 2661.951100 +* 2023 12 10 4 6 0.00000000 +PL56 219.292291 -1906.095366 -6927.178303 +VL56 -37594.092000 -63056.354000 16214.987000 +* 2023 12 10 4 9 0.00000000 +PL56 -471.735028 -2992.871407 -6517.110122 +VL56 -38941.035000 -57342.815000 29218.586000 +* 2023 12 10 4 12 0.00000000 +PL56 -1173.476261 -3958.456037 -5881.291916 +VL56 -38771.751000 -49634.799000 41226.011000 +* 2023 12 10 4 15 0.00000000 +PL56 -1858.126631 -4769.535996 -5041.457612 +VL56 -37039.297000 -40230.715000 51820.959000 +* 2023 12 10 4 18 0.00000000 +PL56 -2497.589878 -5398.727709 -4026.453383 +VL56 -33758.803000 -29489.168000 60631.863000 +* 2023 12 10 4 21 0.00000000 +PL56 -3064.618153 -5825.552437 -2871.307469 +VL56 -29009.533000 -17816.442000 67345.628000 +* 2023 12 10 4 24 0.00000000 +PL56 -3533.964974 -6037.164717 -1616.063069 +VL56 -22934.260000 -5651.773400 71720.054000 +* 2023 12 10 4 27 0.00000000 +PL56 -3883.501203 -6028.798003 -304.403700 +VL56 -15735.712000 6549.347500 73594.420000 +* 2023 12 10 4 30 0.00000000 +PL56 -4095.236931 -5803.894775 1017.887090 +VL56 -7669.676500 18333.387000 72897.054000 +* 2023 12 10 4 33 0.00000000 +PL56 -4156.193154 -5373.904889 2304.568490 +VL56 964.701680 29267.225000 69649.125000 +* 2023 12 10 4 36 0.00000000 +PL56 -4059.076004 -4757.756196 3510.615288 +VL56 9837.070000 38955.901000 63964.076000 +* 2023 12 10 4 39 0.00000000 +PL56 -3802.717555 -3981.024626 4593.843298 +VL56 18599.498000 47058.096000 56043.044000 +* 2023 12 10 4 42 0.00000000 +PL56 -3392.262158 -3074.847595 5516.418738 +VL56 26900.979000 53299.042000 46166.577000 +* 2023 12 10 4 45 0.00000000 +PL56 -2839.091212 -2074.637120 6246.188015 +VL56 34401.853000 57479.743000 34683.208000 +* 2023 12 10 4 48 0.00000000 +PL56 -2160.494696 -1018.661272 6757.785575 +VL56 40787.490000 59482.567000 21996.326000 +* 2023 12 10 4 51 0.00000000 +PL56 -1379.104316 53.449023 7033.491130 +VL56 45780.991000 59273.817000 8549.383500 +* 2023 12 10 4 54 0.00000000 +PL56 -522.112995 1102.204686 7063.807184 +VL56 49154.095000 56902.506000 -5189.948700 +* 2023 12 10 4 57 0.00000000 +PL56 379.684287 2089.716799 6847.760441 +VL56 50736.285000 52496.631000 -18744.869000 +* 2023 12 10 5 0 0.00000000 +PL56 1293.004148 2981.069286 6392.923621 +VL56 50422.654000 46257.234000 -31645.231000 +* 2023 12 10 5 3 0.00000000 +PL56 2183.305981 3745.558516 5715.155583 +VL56 48179.165000 38449.826000 -43442.959000 +* 2023 12 10 5 6 0.00000000 +PL56 3016.100678 4357.764781 4838.068977 +VL56 44045.929000 29394.102000 -53727.108000 +* 2023 12 10 5 9 0.00000000 +PL56 3758.295124 4798.419756 3792.229926 +VL56 38137.707000 19451.570000 -62138.314000 +* 2023 12 10 5 12 0.00000000 +PL56 4379.518439 5055.035680 2614.110796 +VL56 30641.691000 9011.831100 -68381.753000 +* 2023 12 10 5 15 0.00000000 +PL56 4853.380602 5122.272908 1344.817790 +VL56 21811.671000 -1523.262600 -72239.151000 +* 2023 12 10 5 18 0.00000000 +PL56 5158.594043 5002.019273 28.636390 +VL56 11959.126000 -11755.266000 -73576.824000 +* 2023 12 10 5 21 0.00000000 +PL56 5279.910538 4703.180060 -1288.548682 +VL56 1441.299900 -21305.532000 -72351.082000 +* 2023 12 10 5 24 0.00000000 +PL56 5208.819370 4241.182459 -2560.891888 +VL56 -9352.873000 -29830.336000 -68609.834000 +* 2023 12 10 5 27 0.00000000 +PL56 4943.979575 3637.227280 -3744.211009 +VL56 -20018.310000 -37033.877000 -62489.377000 +* 2023 12 10 5 30 0.00000000 +PL56 4491.366275 2917.328131 -4797.533424 +VL56 -30149.918000 -42678.743000 -54208.672000 +* 2023 12 10 5 33 0.00000000 +PL56 3864.128873 2111.187435 -5684.503098 +VL56 -39358.173000 -46593.482000 -44059.962000 +* 2023 12 10 5 36 0.00000000 +PL56 3082.176189 1250.964390 -6374.598440 +VL56 -47283.873000 -48677.004000 -32397.216000 +* 2023 12 10 5 39 0.00000000 +PL56 2171.511109 369.994418 -6844.128149 +VL56 -53611.120000 -48899.673000 -19623.108000 +* 2023 12 10 5 42 0.00000000 +PL56 1163.348014 -498.487730 -7076.984645 +VL56 -58078.437000 -47301.866000 -6175.347900 +* 2023 12 10 5 45 0.00000000 +PL56 93.046879 -1322.578383 -7065.151377 +VL56 -60488.171000 -43990.333000 7487.168300 +* 2023 12 10 5 48 0.00000000 +PL56 -1001.107869 -2072.851390 -6808.955356 +VL56 -60714.075000 -39132.503000 20898.563000 +* 2023 12 10 5 51 0.00000000 +PL56 -2079.246143 -2723.388246 -6317.067534 +VL56 -58707.020000 -32949.423000 33599.987000 +* 2023 12 10 5 54 0.00000000 +PL56 -3101.336089 -3252.667762 -5606.247519 +VL56 -54498.599000 -25707.064000 45153.935000 +* 2023 12 10 5 57 0.00000000 +PL56 -4028.653834 -3644.288713 -4700.834501 +VL56 -48202.615000 -17706.582000 55158.131000 +* 2023 12 10 6 0 0.00000000 +PL56 -4825.258369 -3887.503413 -3631.980753 +VL56 -40013.927000 -9272.975700 63260.128000 +* 2023 12 10 6 3 0.00000000 +PL56 -5459.412325 -3977.535199 -2436.634751 +VL56 -30203.730000 -742.545330 69170.514000 +* 2023 12 10 6 6 0.00000000 +PL56 -5904.888669 -3915.662672 -1156.295516 +VL56 -19111.421000 7550.486800 72674.888000 +* 2023 12 10 6 9 0.00000000 +PL56 -6142.098068 -3709.059222 164.426932 +VL56 -7132.904600 15287.619000 73643.306000 +* 2023 12 10 6 12 0.00000000 +PL56 -6158.977331 -3370.389940 1479.393566 +VL56 5294.172600 22179.266000 72036.588000 +* 2023 12 10 6 15 0.00000000 +PL56 -5951.585735 -2917.179775 2742.599651 +VL56 17708.089000 27976.943000 67908.860000 +* 2023 12 10 6 18 0.00000000 +PL56 -5524.369930 -2370.980498 3909.840530 +VL56 29641.797000 32483.135000 61405.339000 +* 2023 12 10 6 21 0.00000000 +PL56 -4890.087747 -1756.382519 4940.305298 +VL56 40642.072000 35558.765000 52756.559000 +* 2023 12 10 6 24 0.00000000 +PL56 -4069.393804 -1099.920086 5798.028387 +VL56 50287.520000 37127.323000 42268.516000 +* 2023 12 10 6 27 0.00000000 +PL56 -3090.119159 -428.930262 6453.143694 +VL56 58204.721000 37176.103000 30310.808000 +* 2023 12 10 6 30 0.00000000 +PL56 -1986.276740 229.585787 6882.908152 +VL56 64082.357000 35754.596000 17302.724000 +* 2023 12 10 6 33 0.00000000 +PL56 -796.834387 850.047633 7072.458891 +VL56 67682.787000 32970.266000 3698.068100 +* 2023 12 10 6 36 0.00000000 +PL56 435.687478 1409.284071 7015.294357 +VL56 68850.175000 28982.215000 -10030.509000 +* 2023 12 10 6 39 0.00000000 +PL56 1666.747248 1887.396547 6713.476718 +VL56 67516.540000 23993.527000 -23406.802000 +* 2023 12 10 6 42 0.00000000 +PL56 2851.396537 2268.468338 6177.552802 +VL56 63704.946000 18241.892000 -35966.803000 +* 2023 12 10 6 45 0.00000000 +PL56 3945.927475 2541.096952 5426.198431 +VL56 57530.031000 11989.422000 -47273.838000 +* 2023 12 10 6 48 0.00000000 +PL56 4909.501460 2698.735362 4485.589983 +VL56 49195.191000 5511.641300 -56933.579000 +* 2023 12 10 6 51 0.00000000 +PL56 5705.699981 2739.831851 3388.516428 +VL56 38986.949000 -913.893550 -64607.847000 +* 2023 12 10 6 54 0.00000000 +PL56 6303.942311 2667.760168 2173.246234 +VL56 27265.544000 -7019.371000 -70027.905000 +* 2023 12 10 6 57 0.00000000 +PL56 6680.696113 2490.540984 882.184529 +VL56 14451.582000 -12558.114000 -73004.712000 +* 2023 12 10 7 0 0.00000000 +PL56 6820.430826 2220.368378 -439.631413 +VL56 1010.433500 -17314.776000 -73435.717000 +* 2023 12 10 7 3 0.00000000 +PL56 6716.257673 1872.961180 -1746.142066 +VL56 -12566.237000 -21114.335000 -71309.868000 +* 2023 12 10 7 6 0.00000000 +PL56 6370.228431 1466.773150 -2991.904931 +VL56 -25779.780000 -23828.847000 -66706.663000 +* 2023 12 10 7 9 0.00000000 +PL56 5793.286172 1022.101864 -4133.700840 +VL56 -38144.265000 -25381.945000 -59792.670000 +* 2023 12 10 7 12 0.00000000 +PL56 5004.865807 560.140749 -5132.039303 +VL56 -49205.136000 -25750.528000 -50814.087000 +* 2023 12 10 7 15 0.00000000 +PL56 4032.175180 102.023944 -5952.501284 +VL56 -58555.750000 -24963.917000 -40086.333000 +* 2023 12 10 7 18 0.00000000 +PL56 2909.202968 -332.091624 -6566.879447 +VL56 -65851.434000 -23100.682000 -27982.101000 +* 2023 12 10 7 21 0.00000000 +PL56 1675.497294 -723.870131 -6954.091477 +VL56 -70820.820000 -20283.632000 -14918.035000 +* 2023 12 10 7 24 0.00000000 +PL56 374.766243 -1057.536556 -7100.847283 +VL56 -73274.302000 -16673.299000 -1340.998300 +* 2023 12 10 7 27 0.00000000 +PL56 -946.653646 -1320.487226 -7002.066879 +VL56 -73110.192000 -12460.125000 12286.006000 +* 2023 12 10 7 30 0.00000000 +PL56 -2241.416031 -1503.752945 -6661.044160 +VL56 -70318.408000 -7856.030200 25497.934000 +* 2023 12 10 7 33 0.00000000 +PL56 -3462.827341 -1602.303659 -6089.355617 +VL56 -64981.492000 -3085.224700 37841.837000 +* 2023 12 10 7 36 0.00000000 +PL56 -4566.506793 -1615.185135 -5306.514604 +VL56 -57273.582000 1625.179100 48891.094000 +* 2023 12 10 7 39 0.00000000 +PL56 -5512.004146 -1545.484942 -4339.372155 +VL56 -47456.322000 6054.845700 58259.521000 +* 2023 12 10 7 42 0.00000000 +PL56 -6264.317642 -1400.124664 -3221.260651 +VL56 -35871.936000 9999.693400 65615.393000 +* 2023 12 10 7 45 0.00000000 +PL56 -6795.251352 -1189.483349 -1990.894004 +VL56 -22932.329000 13281.100000 70694.534000 +* 2023 12 10 7 48 0.00000000 +PL56 -7084.546679 -926.863577 -691.048018 +VL56 -9104.864100 15754.113000 73311.467000 +* 2023 12 10 7 51 0.00000000 +PL56 -7120.727536 -627.820735 632.938125 +VL56 5105.166100 17314.404000 73368.005000 +* 2023 12 10 7 54 0.00000000 +PL56 -6901.605265 -309.383967 1934.781890 +VL56 19174.555000 17903.151000 70857.967000 +* 2023 12 10 7 57 0.00000000 +PL56 -6434.412458 10.788974 3168.928044 +VL56 32583.265000 17509.564000 65868.140000 +* 2023 12 10 8 0 0.00000000 +PL56 -5735.554498 315.281673 4292.197561 +VL56 44835.635000 16171.063000 58574.861000 +* 2023 12 10 8 3 0.00000000 +PL56 -4829.989688 587.768823 5265.338963 +VL56 55480.063000 13970.865000 49236.629000 +* 2023 12 10 8 6 0.00000000 +PL56 -3750.276473 813.802044 6054.414732 +VL56 64126.271000 11033.372000 38183.440000 +* 2023 12 10 8 9 0.00000000 +PL56 -2535.341145 981.495550 6631.976980 +VL56 70459.146000 7517.688900 25804.091000 +* 2023 12 10 8 12 0.00000000 +PL56 -1229.020063 1082.081089 6977.999717 +VL56 74249.722000 3609.695800 12531.927000 +* 2023 12 10 8 15 0.00000000 +PL56 121.562251 1110.312274 7080.539721 +VL56 75362.467000 -486.715330 -1170.910000 +* 2023 12 10 8 18 0.00000000 +PL56 1467.711592 1064.702540 6936.117094 +VL56 73758.938000 -4559.262200 -14828.778000 +* 2023 12 10 8 21 0.00000000 +PL56 2760.925004 947.590666 6549.818217 +VL56 69498.759000 -8396.834100 -27968.105000 +* 2023 12 10 8 24 0.00000000 +PL56 3954.642978 765.032069 5935.120369 +VL56 62737.672000 -11799.150000 -40132.692000 +* 2023 12 10 8 27 0.00000000 +PL56 5005.939652 526.519440 5113.438442 +VL56 53722.508000 -14586.066000 -50899.271000 +* 2023 12 10 8 30 0.00000000 +PL56 5877.092259 244.541720 4113.403011 +VL56 42782.996000 -16606.177000 -59891.784000 +* 2023 12 10 8 33 0.00000000 +PL56 6536.977157 -66.001488 2969.882965 +VL56 30320.420000 -17744.128000 -66795.306000 +* 2023 12 10 8 36 0.00000000 +PL56 6962.230044 -388.504659 1722.772655 +VL56 16792.926000 -17926.602000 -71368.160000 +* 2023 12 10 8 39 0.00000000 +PL56 7138.114564 -705.452927 415.586748 +VL56 2698.030000 -17126.334000 -73451.098000 +* 2023 12 10 8 42 0.00000000 +PL56 7059.060565 -999.270285 -906.086918 +VL56 -11446.676000 -15363.919000 -72973.812000 +* 2023 12 10 8 45 0.00000000 +PL56 6728.839529 -1253.178959 -2196.217273 +VL56 -25124.383000 -12707.156000 -69957.429000 +* 2023 12 10 8 48 0.00000000 +PL56 6160.367737 -1452.026396 -3409.968310 +VL56 -37839.157000 -9268.130900 -64512.977000 +* 2023 12 10 8 51 0.00000000 +PL56 5375.153750 -1583.038761 -4505.275381 +VL56 -49135.134000 -5198.036400 -56836.225000 +* 2023 12 10 8 54 0.00000000 +PL56 4402.425793 -1636.464489 -5444.296848 +VL56 -58612.956000 -680.215350 -47199.038000 +* 2023 12 10 8 57 0.00000000 +PL56 3277.987742 -1606.081410 -6194.691015 +VL56 -65943.385000 4077.955800 -35938.627000 +* 2023 12 10 9 0 0.00000000 +PL56 2042.859691 -1489.548416 -6730.678870 +VL56 -70877.461000 8854.219600 -23444.749000 +* 2023 12 10 9 3 0.00000000 +PL56 741.766316 -1288.587361 -7033.871699 +VL56 -73253.423000 13420.980000 -10146.533000 +* 2023 12 10 9 6 0.00000000 +PL56 -578.473976 -1008.993338 -7093.851364 +VL56 -73000.854000 17554.843000 3501.828700 +* 2023 12 10 9 9 0.00000000 +PL56 -1870.606056 -660.473975 -6908.497793 +VL56 -70141.670000 21046.018000 17034.928000 +* 2023 12 10 9 12 0.00000000 +PL56 -3088.595822 -256.320717 -6484.062407 +VL56 -64789.137000 23707.578000 29990.445000 +* 2023 12 10 9 15 0.00000000 +PL56 -4189.241924 187.079577 -5834.985287 +VL56 -57143.943000 25383.894000 41923.097000 +* 2023 12 10 9 18 0.00000000 +PL56 -5133.701780 650.879169 -4983.460574 +VL56 -47488.521000 25958.350000 52418.991000 +* 2023 12 10 9 21 0.00000000 +PL56 -5888.887405 1114.532611 -3958.745066 +VL56 -36178.231000 25359.929000 61109.634000 +* 2023 12 10 9 24 0.00000000 +PL56 -6428.680085 1556.666631 -2796.215365 +VL56 -23629.836000 23568.337000 67685.747000 +* 2023 12 10 9 27 0.00000000 +PL56 -6734.906942 1956.022025 -1536.186175 +VL56 -10306.730000 20616.812000 71909.881000 +* 2023 12 10 9 30 0.00000000 +PL56 -6798.029572 2292.425493 -222.522259 +VL56 3298.169500 16592.632000 73626.578000 +* 2023 12 10 9 33 0.00000000 +PL56 -6617.501001 2547.744496 1098.912048 +VL56 16682.068000 11634.653000 72769.973000 +* 2023 12 10 9 36 0.00000000 +PL56 -6201.761505 2706.775903 2381.899841 +VL56 29352.579000 5928.474800 69367.008000 +* 2023 12 10 9 39 0.00000000 +PL56 -5567.869832 2758.023273 3581.543085 +VL56 40847.731000 -301.096830 63536.800000 +* 2023 12 10 9 42 0.00000000 +PL56 -4740.786716 2694.318575 4655.884372 +VL56 50754.415000 -6799.690600 55485.830000 +* 2023 12 10 9 45 0.00000000 +PL56 -3752.348749 2513.257140 5567.405691 +VL56 58724.012000 -13294.288000 45499.181000 +* 2023 12 10 9 48 0.00000000 +PL56 -2639.991506 2217.429507 6284.345604 +VL56 64484.847000 -19504.821000 33929.426000 +* 2023 12 10 9 51 0.00000000 +PL56 -1445.280645 1814.441318 6781.794180 +VL56 67850.916000 -25156.185000 21182.709000 +* 2023 12 10 9 54 0.00000000 +PL56 -212.316580 1316.719714 7042.528118 +VL56 68727.008000 -29989.626000 7704.356300 +* 2023 12 10 9 57 0.00000000 +PL56 1013.914478 741.117810 7057.570395 +VL56 67109.923000 -33773.806000 -6037.135000 +* 2023 12 10 10 0 0.00000000 +PL56 2189.188171 108.333449 6826.474421 +VL56 63087.013000 -36314.430000 -19565.048000 +* 2023 12 10 10 3 0.00000000 +PL56 3271.638896 -557.839324 6357.329706 +VL56 56832.107000 -37463.130000 -32410.199000 +* 2023 12 10 10 6 0.00000000 +PL56 4223.258989 -1231.404486 5666.489379 +VL56 48598.696000 -37124.694000 -44126.217000 +* 2023 12 10 10 9 0.00000000 +PL56 5011.251988 -1885.175192 4778.020133 +VL56 38710.522000 -35262.786000 -54304.851000 +* 2023 12 10 10 12 0.00000000 +PL56 5609.192144 -2491.866351 3722.887002 +VL56 27549.557000 -31903.235000 -62590.201000 +* 2023 12 10 10 15 0.00000000 +PL56 5997.949468 -3025.227165 2537.889103 +VL56 15541.792000 -27135.027000 -68692.042000 +* 2023 12 10 10 18 0.00000000 +PL56 6166.334157 -3461.165481 1264.373014 +VL56 3140.605600 -21108.443000 -72396.893000 +* 2023 12 10 10 21 0.00000000 +PL56 6111.431156 -3778.811820 -53.228647 +VL56 -9190.999400 -14030.246000 -73576.487000 +* 2023 12 10 10 24 0.00000000 +PL56 5838.606829 -3961.470682 -1368.981428 +VL56 -20998.870000 -6156.000200 -72192.768000 +* 2023 12 10 10 27 0.00000000 +PL56 5361.185198 -3997.410117 -2637.090200 +VL56 -31855.948000 2220.270300 -68299.108000 +* 2023 12 10 10 30 0.00000000 +PL56 4699.810848 -3880.450527 -3813.523362 +VL56 -41378.510000 10777.776000 -62037.295000 +* 2023 12 10 10 33 0.00000000 +PL56 3881.536719 -3610.329026 -4857.552593 +VL56 -49240.315000 19182.088000 -53631.232000 +* 2023 12 10 10 36 0.00000000 +PL56 2938.685554 -3192.824449 -5733.148641 +VL56 -55183.608000 27098.585000 -43377.349000 +* 2023 12 10 10 39 0.00000000 +PL56 1907.545734 -2639.643302 -6410.183768 +VL56 -59026.428000 34205.320000 -31632.855000 +* 2023 12 10 10 42 0.00000000 +PL56 826.964675 -1968.081276 -6865.413539 +VL56 -60666.898000 40205.213000 -18803.170000 +* 2023 12 10 10 45 0.00000000 +PL56 -263.110041 -1200.470920 -7083.221245 +VL56 -60084.602000 44837.430000 -5328.012400 +* 2023 12 10 10 48 0.00000000 +PL56 -1323.087466 -363.438252 -7056.106524 +VL56 -57339.159000 47887.310000 8332.824600 +* 2023 12 10 10 51 0.00000000 +PL56 -2315.141833 513.005465 -6784.921466 +VL56 -52566.342000 49194.736000 21713.517000 +* 2023 12 10 10 54 0.00000000 +PL56 -3204.536873 1396.514466 -6278.852659 +VL56 -45972.454000 48661.441000 34356.130000 +* 2023 12 10 10 57 0.00000000 +PL56 -3960.829027 2253.574193 -5555.150711 +VL56 -37826.825000 46256.652000 45824.898000 +* 2023 12 10 11 0 0.00000000 +PL56 -4558.921758 3050.752911 -4638.606220 +VL56 -28452.509000 42020.814000 55720.312000 +* 2023 12 10 11 3 0.00000000 +PL56 -4979.933453 3756.001176 -3560.765205 +VL56 -18214.864000 36067.002000 63693.540000 +* 2023 12 10 11 6 0.00000000 +PL56 -5211.839045 4339.948192 -2358.897237 +VL56 -7508.038200 28579.278000 69459.564000 +* 2023 12 10 11 9 0.00000000 +PL56 -5249.856493 4777.141747 -1074.738147 +VL56 3259.911300 19807.913000 72808.890000 +* 2023 12 10 11 12 0.00000000 +PL56 -5096.553469 5047.171645 246.958976 +VL56 13683.191000 10061.236000 73617.146000 +* 2023 12 10 11 15 0.00000000 +PL56 -4761.658522 5135.618011 1560.014785 +VL56 23374.699000 -305.696180 71850.996000 +* 2023 12 10 11 18 0.00000000 +PL56 -4261.577857 5034.767528 2818.490095 +VL56 31982.152000 -10905.279000 67570.374000 +* 2023 12 10 11 21 0.00000000 +PL56 -3618.636867 4744.057536 3978.349663 +VL56 39202.294000 -21333.306000 60926.120000 +* 2023 12 10 11 24 0.00000000 +PL56 -2860.088833 4270.227479 4999.046112 +VL56 44792.456000 -31185.406000 52153.639000 +* 2023 12 10 11 27 0.00000000 +PL56 -2016.945007 3627.172666 5844.961416 +VL56 48578.940000 -40073.564000 41563.387000 +* 2023 12 10 11 30 0.00000000 +PL56 -1122.682172 2835.508283 6486.650308 +VL56 50462.064000 -47641.662000 29528.497000 +* 2023 12 10 11 33 0.00000000 +PL56 -211.891142 1921.868087 6901.842151 +VL56 50417.624000 -53579.164000 16470.520000 +* 2023 12 10 11 36 0.00000000 +PL56 681.072052 917.974243 7076.179410 +VL56 48495.483000 -57632.991000 2844.713300 +* 2023 12 10 11 39 0.00000000 +PL56 1523.385883 -140.486126 7003.683618 +VL56 44815.421000 -59617.108000 -10875.772000 +* 2023 12 10 11 42 0.00000000 +PL56 2284.970006 -1215.139314 6686.941784 +VL56 39561.010000 -59420.165000 -24214.989000 +* 2023 12 10 11 45 0.00000000 +PL56 2939.561399 -2266.320932 6137.014014 +VL56 32971.346000 -57010.805000 -36710.035000 +* 2023 12 10 11 48 0.00000000 +PL56 3465.628747 -3254.545741 5373.061978 +VL56 25331.248000 -52440.479000 -47926.216000 +* 2023 12 10 11 51 0.00000000 +PL56 3847.094016 -4142.002820 4421.702932 +VL56 16959.819000 -45843.550000 -57472.198000 +* 2023 12 10 11 54 0.00000000 +PL56 4073.836493 -4894.022612 3316.103066 +VL56 8197.674300 -37433.912000 -65013.909000 +* 2023 12 10 11 57 0.00000000 +PL56 4141.958575 -5480.457552 2094.829632 +VL56 -606.684400 -27498.696000 -70287.187000 +* 2023 12 10 12 0 0.00000000 +PL56 4053.799602 -5876.913800 800.496676 +VL56 -9111.123500 -16388.158000 -73108.046000 +* 2023 12 10 12 3 0.00000000 +PL56 3817.695338 -6065.773841 -521.746887 +VL56 -16993.781000 -4502.540800 -73379.726000 +* 2023 12 10 12 6 0.00000000 +PL56 3447.496316 -6036.962053 -1825.826517 +VL56 -23965.822000 7723.120300 -71096.515000 +* 2023 12 10 12 9 0.00000000 +PL56 2961.865030 -5788.413912 -3066.385600 +VL56 -29783.080000 19836.690000 -66343.501000 +* 2023 12 10 12 12 0.00000000 +PL56 2383.389796 -5326.226193 -4200.389112 +VL56 -34254.880000 31386.608000 -59292.557000 +* 2023 12 10 12 15 0.00000000 +PL56 1737.559833 -4664.484231 -5188.621770 +VL56 -37250.326000 41939.612000 -50194.616000 +* 2023 12 10 12 18 0.00000000 +PL56 1051.657399 -3824.782814 -5997.019063 +VL56 -38701.312000 51097.093000 -39369.194000 +* 2023 12 10 12 21 0.00000000 +PL56 353.622602 -2835.474537 -6597.794011 +VL56 -38602.695000 58509.000000 -27192.126000 +* 2023 12 10 12 24 0.00000000 +PL56 -329.065130 -1730.681653 -6970.334590 +VL56 -37010.225000 63886.128000 -14082.515000 +* 2023 12 10 12 27 0.00000000 +PL56 -970.444792 -549.109976 -7101.856032 +VL56 -34035.982000 67009.858000 -488.658940 +* 2023 12 10 12 30 0.00000000 +PL56 -1547.035934 667.293815 -6987.801613 +VL56 -29842.400000 67739.800000 13125.914000 +* 2023 12 10 12 33 0.00000000 +PL56 -2038.679783 1874.800957 -6631.988841 +VL56 -24634.753000 66019.050000 26296.596000 +* 2023 12 10 12 36 0.00000000 +PL56 -2429.234981 3029.437809 -6046.503216 +VL56 -18652.625000 61877.651000 38571.635000 +* 2023 12 10 12 39 0.00000000 +PL56 -2707.111021 4088.564496 -5251.339187 +VL56 -12160.437000 55433.783000 49526.421000 +* 2023 12 10 12 42 0.00000000 +PL56 -2865.623193 5012.451243 -4273.782973 +VL56 -5437.084200 46892.119000 58777.817000 +* 2023 12 10 12 45 0.00000000 +PL56 -2903.153522 5765.796069 -3147.536759 +VL56 1235.300400 36538.777000 65998.300000 +* 2023 12 10 12 48 0.00000000 +PL56 -2823.105005 6319.118876 -1911.602525 +VL56 7582.898300 24732.827000 70928.467000 +* 2023 12 10 12 51 0.00000000 +PL56 -2633.649126 6649.975210 -608.953476 +VL56 13351.576000 11894.592000 73388.103000 +* 2023 12 10 12 54 0.00000000 +PL56 -2347.272199 6743.921848 714.969910 +VL56 18317.675000 -1509.839600 73284.322000 +* 2023 12 10 12 57 0.00000000 +PL56 -1980.139524 6595.184887 2013.883425 +VL56 22297.631000 -14986.691000 70617.021000 +* 2023 12 10 13 0 0.00000000 +PL56 -1551.298644 6206.974791 3242.338379 +VL56 25155.837000 -28034.969000 65478.680000 +* 2023 12 10 13 3 0.00000000 +PL56 -1081.767405 5591.431349 4357.362953 +VL56 26809.546000 -40166.742000 58050.957000 +* 2023 12 10 13 6 0.00000000 +PL56 -593.558221 4769.213760 5320.001494 +VL56 27231.228000 -50926.520000 48597.092000 +* 2023 12 10 13 9 0.00000000 +PL56 -108.681236 3768.751841 6096.691606 +VL56 26448.340000 -59909.119000 37450.904000 +* 2023 12 10 13 12 0.00000000 +PL56 351.822031 2625.203523 6660.423287 +VL56 24540.353000 -66774.501000 25004.382000 +* 2023 12 10 13 15 0.00000000 +PL56 768.770065 1379.167580 6991.652369 +VL56 21633.477000 -71259.844000 11692.648000 +* 2023 12 10 13 18 0.00000000 +PL56 1125.624623 75.205805 7078.945083 +VL56 17893.906000 -73188.843000 -2020.926700 +* 2023 12 10 13 21 0.00000000 +PL56 1409.137162 -1239.768734 6919.344650 +VL56 13519.504000 -72477.365000 -15660.331000 +* 2023 12 10 13 24 0.00000000 +PL56 1609.837651 -2518.187046 6518.460803 +VL56 8730.650100 -69136.968000 -28752.355000 +* 2023 12 10 13 27 0.00000000 +PL56 1722.350951 -3713.553321 5890.277468 +VL56 3760.261600 -63275.180000 -40842.417000 +* 2023 12 10 13 30 0.00000000 +PL56 1745.530418 -4782.150520 5056.679712 +VL56 -1156.485900 -55092.402000 -51509.697000 +* 2023 12 10 13 33 0.00000000 +PL56 1682.406911 -5684.660547 4046.712396 +VL56 -5792.260100 -44875.712000 -60381.715000 +* 2023 12 10 13 36 0.00000000 +PL56 1539.957581 -6387.648485 2895.588485 +VL56 -9937.548700 -32989.845000 -67147.823000 +* 2023 12 10 13 39 0.00000000 +PL56 1328.699139 -6864.845024 1643.463956 +VL56 -13410.037000 -19863.877000 -71571.166000 +* 2023 12 10 13 42 0.00000000 +PL56 1062.124106 -7098.167744 334.026072 +VL56 -16062.622000 -5975.539800 -73497.562000 +* 2023 12 10 13 45 0.00000000 +PL56 756.004946 -7078.436509 -987.059311 +VL56 -17790.059000 8167.052500 -72862.216000 +* 2023 12 10 13 48 0.00000000 +PL56 427.596689 -6805.736020 -2273.784027 +VL56 -18533.354000 22046.184000 -69691.789000 +* 2023 12 10 13 51 0.00000000 +PL56 94.784012 -6289.403229 -3481.435245 +VL56 -18281.628000 35154.785000 -64102.871000 +* 2023 12 10 13 54 0.00000000 +PL56 -224.782950 -5547.657194 -4568.165559 +VL56 -17071.587000 47016.117000 -56296.202000 +* 2023 12 10 13 57 0.00000000 +PL56 -514.525157 -4606.892218 -5496.437302 +VL56 -14984.897000 57201.344000 -46548.154000 +* 2023 12 10 14 0 0.00000000 +PL56 -759.703975 -3500.676238 -6234.285934 +VL56 -12143.445000 65344.477000 -35199.621000 +* 2023 12 10 14 3 0.00000000 +PL56 -948.089479 -2268.507399 -6756.369314 +VL56 -8702.916500 71154.337000 -22643.319000 +* 2023 12 10 14 6 0.00000000 +PL56 -1070.502740 -954.382411 -7044.779543 +VL56 -4845.285300 74423.477000 -9310.221300 +* 2023 12 10 14 9 0.00000000 +PL56 -1121.214859 394.768259 -7089.606173 +VL56 -770.467580 75034.143000 4344.360300 +* 2023 12 10 14 12 0.00000000 +PL56 -1098.189989 1730.728732 -6889.246614 +VL56 3312.614900 72961.592000 17854.977000 +* 2023 12 10 14 15 0.00000000 +PL56 -1003.165842 3005.682714 -6450.464000 +VL56 7195.125500 68274.942000 30759.894000 +* 2023 12 10 14 18 0.00000000 +PL56 -841.569945 4173.895260 -5788.193612 +VL56 10677.458000 61135.955000 42615.235000 +* 2023 12 10 14 21 0.00000000 +PL56 -622.271743 5193.347942 -4925.092033 +VL56 13578.245000 51794.863000 53009.326000 +* 2023 12 10 14 24 0.00000000 +PL56 -357.177056 6027.274353 -3890.827936 +VL56 15742.827000 40583.523000 61577.068000 +* 2023 12 10 14 27 0.00000000 +PL56 -60.677377 6645.539208 -2721.119397 +VL56 17050.862000 27904.856000 68013.589000 +* 2023 12 10 14 30 0.00000000 +PL56 251.027811 7025.799234 -1456.537559 +VL56 17422.718000 14219.187000 72086.421000 +* 2023 12 10 14 33 0.00000000 +PL56 560.707968 7154.389516 -141.107558 +VL56 16824.086000 27.422366 73645.715000 +* 2023 12 10 14 36 0.00000000 +PL56 850.943391 7026.881733 1179.247188 +VL56 15268.474000 -14148.492000 72631.295000 +* 2023 12 10 14 39 0.00000000 +PL56 1104.989385 6648.275269 2458.354281 +VL56 12817.100000 -27786.547000 69075.807000 +* 2023 12 10 14 42 0.00000000 +PL56 1307.614077 6032.807299 3651.459469 +VL56 9576.237400 -40385.729000 63103.676000 +* 2023 12 10 14 45 0.00000000 +PL56 1445.870663 5203.395133 4716.839756 +VL56 5692.563700 -51485.860000 54926.169000 +* 2023 12 10 14 48 0.00000000 +PL56 1509.767546 4190.733865 5617.297901 +VL56 1346.401800 -60685.728000 44833.194000 +* 2023 12 10 14 51 0.00000000 +PL56 1492.797486 3032.092586 6321.468195 +VL56 -3256.763400 -67657.988000 33180.626000 +* 2023 12 10 14 54 0.00000000 +PL56 1392.307730 1769.885836 6804.888784 +VL56 -7895.843100 -72159.995000 20377.284000 +* 2023 12 10 14 57 0.00000000 +PL56 1209.695519 450.077435 7050.822949 +VL56 -12343.683000 -74041.047000 6870.084300 +* 2023 12 10 15 0 0.00000000 +PL56 950.422734 -879.519304 7050.804633 +VL56 -16377.414000 -73246.577000 -6871.424200 +* 2023 12 10 15 3 0.00000000 +PL56 623.849826 -2170.983095 6804.909297 +VL56 -19788.376000 -69819.128000 -20370.348000 +* 2023 12 10 15 6 0.00000000 +PL56 242.892799 -3378.020144 6321.743488 +VL56 -22391.727000 -63896.470000 -33158.263000 +* 2023 12 10 15 9 0.00000000 +PL56 -176.484746 -4457.634297 5618.147886 +VL56 -24035.028000 -55706.052000 -44791.292000 +* 2023 12 10 15 12 0.00000000 +PL56 -615.923194 -5371.671081 4718.626726 +VL56 -24605.627000 -45556.824000 -54864.212000 +* 2023 12 10 15 15 0.00000000 +PL56 -1055.442203 -6088.197624 3654.523954 +VL56 -24037.029000 -33829.114000 -63024.632000 +* 2023 12 10 15 18 0.00000000 +PL56 -1474.315036 -6582.665853 2462.946077 +VL56 -22313.323000 -20960.544000 -68986.609000 +* 2023 12 10 15 21 0.00000000 +PL56 -1852.001203 -6838.797710 1185.465853 +VL56 -19471.283000 -7429.488100 -72541.460000 +* 2023 12 10 15 24 0.00000000 +PL56 -2169.096112 -6849.154496 -133.348446 +VL56 -15600.039000 6263.573800 -73566.227000 +* 2023 12 10 15 27 0.00000000 +PL56 -2408.247548 -6615.355875 -1447.524476 +VL56 -10837.768000 19616.003000 -72028.325000 +* 2023 12 10 15 30 0.00000000 +PL56 -2554.993630 -6147.939615 -2711.326418 +VL56 -5366.356500 32142.760000 -67986.409000 +* 2023 12 10 15 33 0.00000000 +PL56 -2598.484172 -5465.872116 -3880.876881 +VL56 596.194220 43395.377000 -61587.509000 +* 2023 12 10 15 36 0.00000000 +PL56 -2532.049369 -4595.734895 -4915.692116 +VL56 6805.073100 52978.772000 -53060.246000 +* 2023 12 10 15 39 0.00000000 +PL56 -2353.590327 -3570.636232 -5780.066249 +VL56 12998.968000 60564.790000 -42705.077000 +* 2023 12 10 15 42 0.00000000 +PL56 -2065.780071 -2428.909594 -6444.262413 +VL56 18910.787000 65902.459000 -30882.723000 +* 2023 12 10 15 45 0.00000000 +PL56 -1676.069301 -1212.655749 -6885.482120 +VL56 24278.580000 68825.074000 -18001.101000 +* 2023 12 10 15 48 0.00000000 +PL56 -1196.498787 33.812298 -7088.589467 +VL56 28855.970000 69253.881000 -4501.339000 +* 2023 12 10 15 51 0.00000000 +PL56 -643.329903 1265.562969 -7046.583187 +VL56 32421.968000 67198.786000 9156.135600 +* 2023 12 10 15 54 0.00000000 +PL56 -36.503112 2438.631011 -6760.818833 +VL56 34790.216000 62756.814000 22505.565000 +* 2023 12 10 15 57 0.00000000 +PL56 601.060580 3511.555131 -6240.980330 +VL56 35817.262000 56108.443000 35089.639000 +* 2023 12 10 16 0 0.00000000 +PL56 1244.301655 4446.831291 -5504.796470 +VL56 35410.030000 47511.635000 46474.229000 +* 2023 12 10 16 3 0.00000000 +PL56 1866.982587 5212.234956 -4577.496801 +VL56 33531.564000 37293.472000 56262.424000 +* 2023 12 10 16 6 0.00000000 +PL56 2442.736864 5781.970899 -3491.012126 +VL56 30204.954000 25839.168000 64108.903000 +* 2023 12 10 16 9 0.00000000 +PL56 2946.168524 6137.601879 -2282.926295 +VL56 25514.982000 13578.599000 69732.939000 +* 2023 12 10 16 12 0.00000000 +PL56 3353.957251 6268.712527 -995.203886 +VL56 19607.070000 970.386290 72930.255000 +* 2023 12 10 16 15 0.00000000 +PL56 3645.916377 6173.268343 327.272697 +VL56 12683.017000 -11516.010000 73582.220000 +* 2023 12 10 16 18 0.00000000 +PL56 3805.946800 5857.640588 1638.300322 +VL56 4993.779300 -23419.235000 71661.313000 +* 2023 12 10 16 21 0.00000000 +PL56 3822.838671 5336.292290 2892.016345 +VL56 -3170.171800 -34304.575000 67232.840000 +* 2023 12 10 16 24 0.00000000 +PL56 3690.878184 4631.139545 4044.556282 +VL56 -11490.739000 -43781.432000 60452.777000 +* 2023 12 10 16 27 0.00000000 +PL56 3410.226733 3770.613351 5055.633029 +VL56 -19635.506000 -51518.716000 51561.336000 +* 2023 12 10 16 30 0.00000000 +PL56 2987.051815 2788.476870 5889.970687 +VL56 -27271.960000 -57256.836000 40873.089000 +* 2023 12 10 16 33 0.00000000 +PL56 2433.405297 1722.455791 6518.532550 +VL56 -34080.945000 -60816.223000 28764.518000 +* 2023 12 10 16 36 0.00000000 +PL56 1766.867553 612.752164 6919.507745 +VL56 -39769.461000 -62101.827000 15659.535000 +* 2023 12 10 16 39 0.00000000 +PL56 1009.967087 -499.495456 7079.034679 +VL56 -44082.506000 -61104.472000 2014.931600 +* 2023 12 10 16 42 0.00000000 +PL56 189.401342 -1573.745726 6991.651971 +VL56 -46813.488000 -57899.287000 -11695.285000 +* 2023 12 10 16 45 0.00000000 +PL56 -664.916623 -2571.538660 6660.469252 +VL56 -47813.011000 -52641.407000 -24995.426000 +* 2023 12 10 16 48 0.00000000 +PL56 -1520.954210 -3457.878001 6097.050794 +VL56 -46995.937000 -45559.194000 -37424.332000 +* 2023 12 10 16 51 0.00000000 +PL56 -2345.756715 -4202.464942 5321.021946 +VL56 -44345.662000 -36944.613000 -48549.966000 +* 2023 12 10 16 54 0.00000000 +PL56 -3106.717021 -4780.752552 4359.414591 +VL56 -39917.665000 -27142.767000 -57983.859000 +* 2023 12 10 16 57 0.00000000 +PL56 -3772.877099 -5174.784551 3245.748304 +VL56 -33839.411000 -16538.463000 -65395.901000 +* 2023 12 10 17 0 0.00000000 +PL56 -4316.196796 -5373.777098 2018.867644 +VL56 -26306.822000 -5541.197000 -70526.409000 +* 2023 12 10 17 3 0.00000000 +PL56 -4712.734991 -5374.419768 721.578974 +VL56 -17578.128000 5430.914800 -73196.299000 +* 2023 12 10 17 6 0.00000000 +PL56 -4943.692082 -5180.879859 -600.867854 +VL56 -7964.615100 15967.887000 -73314.058000 +* 2023 12 10 17 9 0.00000000 +PL56 -4996.260761 -4804.507282 -1902.394627 +VL56 2181.389500 25684.303000 -70879.455000 +* 2023 12 10 17 12 0.00000000 +PL56 -4864.239583 -4263.251937 -3137.740195 +VL56 12480.746000 34234.670000 -65983.079000 +* 2023 12 10 17 15 0.00000000 +PL56 -4548.378370 -3580.824260 -4264.059398 +VL56 22542.815000 41326.323000 -58801.701000 +* 2023 12 10 17 18 0.00000000 +PL56 -4056.446536 -2785.650434 -5242.408779 +VL56 31980.814000 46729.349000 -49590.530000 +* 2023 12 10 17 21 0.00000000 +PL56 -3403.028394 -1909.676159 -6039.068102 +VL56 40426.699000 50283.467000 -38672.819000 +* 2023 12 10 17 24 0.00000000 +PL56 -2609.060702 -987.075789 -6626.656298 +VL56 47544.861000 51901.713000 -26427.521000 +* 2023 12 10 17 27 0.00000000 +PL56 -1701.136322 -52.922347 -6985.015298 +VL56 53044.371000 51571.062000 -13275.884000 +* 2023 12 10 17 30 0.00000000 +PL56 -710.603337 858.128371 -7101.843643 +VL56 56689.319000 49350.317000 332.698160 +* 2023 12 10 17 33 0.00000000 +PL56 327.504180 1713.095383 -6973.079971 +VL56 58307.396000 45365.975000 13934.343000 +* 2023 12 10 17 36 0.00000000 +PL56 1375.676670 2481.839959 -6603.038664 +VL56 57796.963000 39806.253000 27064.566000 +* 2023 12 10 17 39 0.00000000 +PL56 2395.255559 3138.114542 -6004.293891 +VL56 55132.665000 32913.822000 39272.614000 +* 2023 12 10 17 42 0.00000000 +PL56 3347.838403 3660.461995 -5197.301221 +VL56 50368.637000 24976.641000 50135.896000 +* 2023 12 10 17 45 0.00000000 +PL56 4196.717637 4032.935678 -4209.762725 +VL56 43639.041000 16317.216000 59274.178000 +* 2023 12 10 17 48 0.00000000 +PL56 4908.309535 4245.617764 -3075.739514 +VL56 35156.161000 7280.744200 66363.378000 +* 2023 12 10 17 51 0.00000000 +PL56 5453.514889 4294.907272 -1834.520127 +VL56 25204.697000 -1778.426700 71148.759000 +* 2023 12 10 17 54 0.00000000 +PL56 5808.945979 4183.559209 -529.274995 +VL56 14132.770000 -10510.816000 73455.336000 +* 2023 12 10 17 57 0.00000000 +PL56 5957.958498 3920.466749 794.459004 +VL56 2339.270700 -18586.185000 73196.171000 +* 2023 12 10 18 0 0.00000000 +PL56 5891.433052 3520.191198 2090.404746 +VL56 -9741.407400 -25707.241000 70376.416000 +* 2023 12 10 18 3 0.00000000 +PL56 5608.260536 3002.257012 3313.215427 +VL56 -21656.687000 -31621.646000 65093.949000 +* 2023 12 10 18 6 0.00000000 +PL56 5115.500470 2390.247935 4420.114984 +VL56 -32954.644000 -36132.141000 57535.560000 +* 2023 12 10 18 9 0.00000000 +PL56 4428.203515 1710.748920 5372.432147 +VL56 -43202.238000 -39103.381000 47968.828000 +* 2023 12 10 18 12 0.00000000 +PL56 3568.916378 992.192076 6136.965213 +VL56 -52002.306000 -40465.858000 36732.172000 +* 2023 12 10 18 15 0.00000000 +PL56 2566.890039 263.661102 6687.132010 +VL56 -59009.505000 -40216.585000 24220.267000 +* 2023 12 10 18 18 0.00000000 +PL56 1457.036881 -446.288956 7003.862735 +VL56 -63942.077000 -38416.672000 10870.519000 +* 2023 12 10 18 21 0.00000000 +PL56 278.683267 -1110.749474 7076.230609 +VL56 -66592.822000 -35187.020000 -2852.218400 +* 2023 12 10 18 24 0.00000000 +PL56 -925.845709 -1705.478023 6901.803384 +VL56 -66836.820000 -30701.713000 -16471.668000 +* 2023 12 10 18 27 0.00000000 +PL56 -2112.756060 -2209.783304 6486.708131 +VL56 -64636.282000 -25179.679000 -29515.634000 +* 2023 12 10 18 30 0.00000000 +PL56 -3238.376952 -2607.245267 5845.417335 +VL56 -60042.941000 -18874.942000 -41531.388000 +* 2023 12 10 18 33 0.00000000 +PL56 -4260.775381 -2886.254619 5000.269579 +VL56 -53198.013000 -12066.187000 -52100.348000 +* 2023 12 10 18 36 0.00000000 +PL56 -5141.343436 -3040.355289 3980.714082 +VL56 -44328.718000 -5045.282400 -60853.348000 +* 2023 12 10 18 39 0.00000000 +PL56 -5846.285779 -3068.370747 2822.298808 +VL56 -33741.127000 1895.044400 -67483.954000 +* 2023 12 10 18 42 0.00000000 +PL56 -6347.951126 -2974.311843 1565.437158 +VL56 -21809.887000 8473.135300 -71759.831000 +* 2023 12 10 18 45 0.00000000 +PL56 -6625.950423 -2767.071256 253.984111 +VL56 -8964.677800 14430.167000 -73532.218000 +* 2023 12 10 18 48 0.00000000 +PL56 -6668.000299 -2459.911983 -1066.326437 +VL56 4326.448600 19541.005000 -72741.734000 +* 2023 12 10 18 51 0.00000000 +PL56 -6470.449590 -2069.775912 -2349.516899 +VL56 17575.686000 23623.376000 -69420.705000 +* 2023 12 10 18 54 0.00000000 +PL56 -6038.459188 -1616.448317 -3551.002100 +VL56 30294.951000 26544.566000 -63690.868000 +* 2023 12 10 18 57 0.00000000 +PL56 -5385.835726 -1121.623460 -4629.153954 +VL56 42014.739000 28225.640000 -55757.821000 +* 2023 12 10 19 0 0.00000000 +PL56 -4534.535078 -607.917735 -5546.736201 +VL56 52301.871000 28643.126000 -45902.294000 +* 2023 12 10 19 3 0.00000000 +PL56 -3513.864292 -97.876933 -6272.158538 +VL56 60775.176000 27827.986000 -34468.806000 +* 2023 12 10 19 6 0.00000000 +PL56 -2359.424399 386.976740 -6780.510628 +VL56 67118.395000 25862.225000 -21852.802000 +* 2023 12 10 19 9 0.00000000 +PL56 -1111.845942 827.018003 -7054.356173 +VL56 71090.445000 22873.580000 -8487.010700 +* 2023 12 10 19 12 0.00000000 +PL56 184.635889 1205.282526 -7084.279237 +VL56 72532.906000 19028.786000 5172.481300 +* 2023 12 10 19 15 0.00000000 +PL56 1483.719739 1508.100542 -6869.180388 +VL56 71375.318000 14525.781000 18659.916000 +* 2023 12 10 19 18 0.00000000 +PL56 2738.655918 1725.582948 -6416.326529 +VL56 67638.776000 9585.220300 31513.941000 +* 2023 12 10 19 21 0.00000000 +PL56 3903.903522 1851.946537 -5741.139674 +VL56 61436.380000 4441.056100 43292.227000 +* 2023 12 10 19 24 0.00000000 +PL56 4936.772487 1885.665972 -4866.726263 +VL56 52971.203000 -669.212370 53585.559000 +* 2023 12 10 19 27 0.00000000 +PL56 5799.005033 1829.448949 -3823.152693 +VL56 42531.517000 -5514.412100 62032.160000 +* 2023 12 10 19 30 0.00000000 +PL56 6458.237893 1690.031652 -2646.468445 +VL56 30482.342000 -9879.741800 68331.189000 +* 2023 12 10 19 33 0.00000000 +PL56 6889.282722 1477.798790 -1377.498507 +VL56 17253.626000 -13576.134000 72254.825000 +* 2023 12 10 19 36 0.00000000 +PL56 7075.161752 1206.241026 -60.432303 +VL56 3324.809100 -16448.885000 73658.471000 +* 2023 12 10 19 39 0.00000000 +PL56 7007.835035 891.270284 1258.740571 +VL56 -10793.769000 -18384.647000 72487.468000 +* 2023 12 10 19 42 0.00000000 +PL56 6688.577938 550.427169 2533.880211 +VL56 -24580.798000 -19316.483000 68780.019000 +* 2023 12 10 19 45 0.00000000 +PL56 6127.985669 202.016859 3720.365927 +VL56 -37525.627000 -19226.629000 62666.144000 +* 2023 12 10 19 48 0.00000000 +PL56 5345.596533 -135.780995 4776.706420 +VL56 -49148.655000 -18146.578000 54362.248000 +* 2023 12 10 19 51 0.00000000 +PL56 4369.160344 -445.780397 5666.019488 +VL56 -59019.854000 -16154.677000 44162.383000 +* 2023 12 10 19 54 0.00000000 +PL56 3233.590837 -712.595237 6357.326402 +VL56 -66775.642000 -13371.586000 32426.323000 +* 2023 12 10 19 57 0.00000000 +PL56 1979.655817 -923.343508 6826.612883 +VL56 -72131.190000 -9953.712300 19565.682000 +* 2023 12 10 20 0 0.00000000 +PL56 652.468219 -1068.222473 7057.634357 +VL56 -74889.858000 -6085.398900 6029.562500 +* 2023 12 10 20 3 0.00000000 +PL56 -700.168385 -1140.933907 7042.447388 +VL56 -74949.981000 -1970.125500 -7711.359200 +* 2023 12 10 20 6 0.00000000 +PL56 -2029.496075 -1138.943576 6781.656127 +VL56 -72307.493000 2178.992900 -21180.702000 +* 2023 12 10 20 9 0.00000000 +PL56 -3287.561990 -1063.566771 6284.379215 +VL56 -67055.605000 6148.972300 -33911.325000 +* 2023 12 10 20 12 0.00000000 +PL56 -4428.952534 -919.877831 5567.944557 +VL56 -59382.555000 9736.683100 -45460.683000 +* 2023 12 10 20 15 0.00000000 +PL56 -5412.454674 -716.450065 4657.310274 +VL56 -49565.651000 12757.996000 -55426.045000 +* 2023 12 10 20 18 0.00000000 +PL56 -6202.579783 -464.933562 3584.215488 +VL56 -37961.702000 15056.543000 -63459.009000 +* 2023 12 10 20 21 0.00000000 +PL56 -6770.886381 -179.486414 2386.085790 +VL56 -24994.579000 16511.166000 -69278.067000 +* 2023 12 10 20 24 0.00000000 +PL56 -7097.050874 123.916892 1104.727605 +VL56 -11139.594000 17042.046000 -72679.635000 +* 2023 12 10 20 27 0.00000000 +PL56 -7169.634180 428.268061 -215.152602 +VL56 3094.636800 16614.638000 -73546.173000 +* 2023 12 10 20 30 0.00000000 +PL56 -6986.499064 716.360554 -1527.545167 +VL56 17186.641000 15241.568000 -71850.832000 +* 2023 12 10 20 33 0.00000000 +PL56 -6554.857201 971.637072 -2786.778890 +VL56 30622.542000 12982.059000 -67657.816000 +* 2023 12 10 20 36 0.00000000 +PL56 -5890.952570 1179.006692 -3949.138850 +VL56 42915.895000 9939.186900 -61119.536000 +* 2023 12 10 20 39 0.00000000 +PL56 -5019.392975 1325.592423 -4974.397295 +VL56 53626.698000 6254.856900 -52469.535000 +* 2023 12 10 20 42 0.00000000 +PL56 -3972.171441 1401.371978 -5827.188044 +VL56 62376.717000 2103.101000 -42012.565000 +* 2023 12 10 20 45 0.00000000 +PL56 -2787.436893 1399.684856 -6478.182554 +VL56 68861.935000 -2317.994100 -30112.664000 +* 2023 12 10 20 48 0.00000000 +PL56 -1508.073124 1317.586656 -6905.040888 +VL56 72861.572000 -6795.106300 -17180.074000 +* 2023 12 10 20 51 0.00000000 +PL56 -180.141101 1156.041513 -7093.119376 +VL56 74244.099000 -11108.862000 -3657.291700 +* 2023 12 10 20 54 0.00000000 +PL56 1148.756644 919.946738 -7035.927224 +VL56 72970.055000 -15043.150000 9994.557300 +* 2023 12 10 20 57 0.00000000 +PL56 2431.145740 617.990353 -6735.338747 +VL56 69093.152000 -18394.437000 23309.502000 +* 2023 12 10 21 0 0.00000000 +PL56 3621.346621 262.342599 -6201.549165 +VL56 62758.594000 -20980.794000 35831.319000 +* 2023 12 10 21 3 0.00000000 +PL56 4677.084959 -131.810221 -5452.769561 +VL56 54198.536000 -22650.406000 47127.983000 +* 2023 12 10 21 6 0.00000000 +PL56 5560.999959 -546.877454 -4514.667236 +VL56 43725.410000 -23289.115000 56805.471000 +* 2023 12 10 21 9 0.00000000 +PL56 6242.006437 -963.602927 -3419.551337 +VL56 31722.168000 -22826.951000 64522.066000 +* 2023 12 10 21 12 0.00000000 +PL56 6696.451719 -1361.906160 -2205.311147 +VL56 18629.337000 -21242.956000 70001.540000 +* 2023 12 10 21 15 0.00000000 +PL56 6909.013866 -1721.792369 -914.131555 +VL56 4929.163100 -18567.869000 73044.600000 +* 2023 12 10 21 18 0.00000000 +PL56 6873.290323 -2024.288756 408.977279 +VL56 -8872.787200 -14884.325000 73537.827000 +* 2023 12 10 21 21 0.00000000 +PL56 6592.039695 -2252.361543 1717.781154 +VL56 -22267.627000 -10324.511000 71459.293000 +* 2023 12 10 21 24 0.00000000 +PL56 6077.055000 -2391.766288 2966.488975 +VL56 -34763.867000 -5065.128600 66880.056000 +* 2023 12 10 21 27 0.00000000 +PL56 5348.669262 -2431.785987 4111.410249 +VL56 -45907.294000 680.015070 59961.580000 +* 2023 12 10 21 30 0.00000000 +PL56 4434.918405 -2365.817459 5112.525442 +VL56 -55298.880000 6669.300800 50948.885000 +* 2023 12 10 21 33 0.00000000 +PL56 3370.413043 -2191.779021 5934.904999 +VL56 -62609.407000 12643.762000 40160.700000 +* 2023 12 10 21 36 0.00000000 +PL56 2194.971284 -1912.322574 6549.927961 +VL56 -67591.061000 18338.328000 27976.915000 +* 2023 12 10 21 39 0.00000000 +PL56 952.079750 -1534.841133 6936.254723 +VL56 -70084.996000 23493.143000 14824.234000 +* 2023 12 10 21 42 0.00000000 +PL56 -312.749147 -1071.275011 7080.535089 +VL56 -70025.383000 27864.615000 1161.088100 +* 2023 12 10 21 45 0.00000000 +PL56 -1553.661095 -537.723680 6977.837402 +VL56 -67439.877000 31235.846000 -12538.163000 +* 2023 12 10 21 48 0.00000000 +PL56 -2726.125834 46.121594 6631.797833 +VL56 -62447.327000 33426.192000 -25798.495000 +* 2023 12 10 21 51 0.00000000 +PL56 -3788.537033 657.706970 6054.492602 +VL56 -55252.724000 34299.521000 -38159.694000 +* 2023 12 10 21 54 0.00000000 +PL56 -4703.700574 1272.483591 5266.033875 +VL56 -46139.826000 33771.280000 -49191.632000 +* 2023 12 10 21 57 0.00000000 +PL56 -5440.162827 1864.884898 4293.892441 +VL56 -35460.768000 31813.676000 -58509.197000 +* 2023 12 10 22 0 0.00000000 +PL56 -5973.327891 2409.379785 3171.959274 +VL56 -23622.976000 28458.739000 -65786.375000 +* 2023 12 10 22 3 0.00000000 +PL56 -6286.316570 2881.557801 1939.371972 +VL56 -11073.732000 23798.825000 -70768.101000 +* 2023 12 10 22 6 0.00000000 +PL56 -6370.532720 3259.199826 639.141934 +VL56 1716.944600 17984.448000 -73280.444000 +* 2023 12 10 22 9 0.00000000 +PL56 -6225.904973 3523.283384 -683.374615 +VL56 14275.033000 11219.179000 -73237.601000 +* 2023 12 10 22 12 0.00000000 +PL56 -5860.787709 3658.870310 -1982.096597 +VL56 26141.415000 3751.793900 -70645.128000 +* 2023 12 10 22 15 0.00000000 +PL56 -5291.528919 3655.834085 -3211.862495 +VL56 36890.118000 -4133.751100 -65599.291000 +* 2023 12 10 22 18 0.00000000 +PL56 -4541.723564 3509.389871 -4330.027265 +VL56 46144.310000 -12129.905000 -58282.190000 +* 2023 12 10 22 21 0.00000000 +PL56 -3641.198365 3220.403956 -5297.940643 +VL56 53590.242000 -19918.417000 -48953.941000 +* 2023 12 10 22 24 0.00000000 +PL56 -2624.787589 2795.474832 -6082.252997 +VL56 58986.680000 -27182.743000 -37941.536000 +* 2023 12 10 22 27 0.00000000 +PL56 -1530.962673 2246.790025 -6656.014209 +VL56 62171.656000 -33620.441000 -25626.887000 +* 2023 12 10 22 30 0.00000000 +PL56 -400.369435 1591.766572 -6999.541744 +VL56 63065.788000 -38954.727000 -12433.252000 +* 2023 12 10 22 33 0.00000000 +PL56 725.667384 852.492541 -7101.040046 +VL56 61672.837000 -42945.027000 1188.561300 +* 2023 12 10 22 36 0.00000000 +PL56 1806.624887 54.990709 -6956.972927 +VL56 58077.764000 -45396.248000 14773.951000 +* 2023 12 10 22 39 0.00000000 +PL56 2804.212594 -771.678599 -6572.183085 +VL56 52442.700000 -46167.217000 27858.987000 +* 2023 12 10 22 42 0.00000000 +PL56 3683.708795 -1596.451164 -5959.753282 +VL56 45000.824000 -45177.431000 39994.421000 +* 2023 12 10 22 45 0.00000000 +PL56 4415.167299 -2387.400031 -5140.612698 +VL56 36048.171000 -42412.321000 50759.945000 +* 2023 12 10 22 48 0.00000000 +PL56 4974.461178 -3112.956579 -4142.887781 +VL56 25933.313000 -37926.602000 59778.635000 +* 2023 12 10 22 51 0.00000000 +PL56 5344.121024 -3743.168453 -3000.996984 +VL56 15045.143000 -31844.991000 66730.504000 +* 2023 12 10 22 54 0.00000000 +PL56 5513.933163 -4250.942192 -1754.507760 +VL56 3798.480400 -24359.822000 71365.414000 +* 2023 12 10 22 57 0.00000000 +PL56 5481.264968 -4613.216446 -446.781107 +VL56 -7381.935600 -15725.583000 73513.559000 +* 2023 12 10 23 0 0.00000000 +PL56 5251.091871 -4812.008289 876.551977 +VL56 -18078.394000 -6250.344500 73093.524000 +* 2023 12 10 23 3 0.00000000 +PL56 4835.715123 -4835.275233 2169.224720 +VL56 -27897.436000 3716.133500 70116.483000 +* 2023 12 10 23 6 0.00000000 +PL56 4254.178523 -4677.541043 3386.006840 +VL56 -36485.857000 13796.533000 64686.039000 +* 2023 12 10 23 9 0.00000000 +PL56 3531.415627 -4340.254008 4484.337255 +VL56 -43544.558000 23601.388000 56994.166000 +* 2023 12 10 23 12 0.00000000 +PL56 2697.169962 -3831.861132 5425.848867 +VL56 -48839.764000 32745.212000 47313.296000 +* 2023 12 10 23 15 0.00000000 +PL56 1784.745082 -3167.594533 6177.721782 +VL56 -52210.700000 40862.134000 35985.328000 +* 2023 12 10 23 18 0.00000000 +PL56 829.646529 -2368.985252 6713.817637 +VL56 -53573.914000 47620.447000 23408.319000 +* 2023 12 10 23 21 0.00000000 +PL56 -131.822853 -1463.130192 7015.559333 +VL56 -52924.145000 52735.406000 10021.864000 +* 2023 12 10 23 24 0.00000000 +PL56 -1063.953997 -481.745488 7072.540436 +VL56 -50332.024000 55980.197000 -3708.308100 +* 2023 12 10 23 27 0.00000000 +PL56 -1932.959952 539.961293 6882.858151 +VL56 -45939.508000 57194.982000 -17305.718000 +* 2023 12 10 23 30 0.00000000 +PL56 -2708.201249 1564.562389 6453.165114 +VL56 -39953.060000 56293.867000 -30298.808000 +* 2023 12 10 23 33 0.00000000 +PL56 -3363.270035 2553.783776 5798.441081 +VL56 -32634.799000 53269.327000 -42236.444000 +* 2023 12 10 23 36 0.00000000 +PL56 -3876.900461 3469.939712 4941.490823 +VL56 -24292.064000 48194.377000 -52702.833000 +* 2023 12 10 23 39 0.00000000 +PL56 -4233.676842 4277.380855 3912.173847 +VL56 -15265.402000 41221.890000 -61332.221000 +* 2023 12 10 23 42 0.00000000 +PL56 -4424.511650 4943.901512 2746.381762 +VL56 -5915.052800 32580.705000 -67822.274000 +* 2023 12 10 23 45 0.00000000 +PL56 -4446.870509 5442.047736 1484.788411 +VL56 3393.599600 22568.413000 -71945.698000 +* 2023 12 10 23 48 0.00000000 +PL56 -4304.731773 5750.262261 171.414406 +VL56 12304.714000 11540.625000 -73559.124000 +* 2023 12 10 23 51 0.00000000 +PL56 -4008.285520 5853.813348 -1147.938704 +VL56 20486.277000 -102.335710 -72608.737000 +* 2023 12 10 23 54 0.00000000 +PL56 -3573.380762 5745.459906 -2427.328491 +VL56 27643.612000 -11931.294000 -69132.706000 +* 2023 12 10 23 57 0.00000000 +PL56 -3020.745443 5425.813159 -3622.308538 +VL56 33531.058000 -23505.922000 -63258.348000 +* 2023 12 11 0 0 0.00000000 +PL56 -2375.026133 4903.384930 -4691.487567 +VL56 37960.028000 -34391.612000 -55196.405000 +* 2023 12 11 0 3 0.00000000 +PL56 -1663.701444 4194.327079 -5597.949875 +VL56 40805.020000 -44176.588000 -45231.718000 +* 2023 12 11 0 6 0.00000000 +PL56 -915.923514 3321.888728 -6310.490870 +VL56 42005.843000 -52486.472000 -33712.176000 +* 2023 12 11 0 9 0.00000000 +PL56 -161.337338 2315.616673 -6804.640858 +VL56 41567.707000 -58997.990000 -21035.922000 +* 2023 12 11 0 12 0.00000000 +PL56 571.075618 1210.332563 -7063.447314 +VL56 39558.469000 -63449.981000 -7637.687300 +* 2023 12 11 0 15 0.00000000 +PL56 1254.085607 44.930669 -7078.008636 +VL56 36103.992000 -65652.405000 6025.058300 +* 2023 12 11 0 18 0.00000000 +PL56 1863.204859 -1138.969873 -6847.755894 +VL56 31381.885000 -65493.558000 19486.265000 +* 2023 12 11 0 21 0.00000000 +PL56 2377.549197 -2298.480138 -6380.477531 +VL56 25613.576000 -62944.700000 32285.720000 +* 2023 12 11 0 24 0.00000000 +PL56 2780.549679 -3390.963113 -5692.091909 +VL56 19055.514000 -58062.831000 43982.663000 +* 2023 12 11 0 27 0.00000000 +PL56 3060.496731 -4375.589463 -4806.166283 +VL56 11989.431000 -50991.671000 54170.465000 +* 2023 12 11 0 30 0.00000000 +PL56 3210.894386 -5214.874713 -3753.171250 +VL56 4710.971200 -41958.401000 62490.971000 +* 2023 12 11 0 33 0.00000000 +PL56 3230.608534 -5876.136524 -2569.490736 +VL56 -2481.714200 -31268.224000 68647.423000 +* 2023 12 11 0 36 0.00000000 +PL56 3123.802239 -6332.820508 -1296.202224 +VL56 -9300.212700 -19294.928000 72416.968000 +* 2023 12 11 0 39 0.00000000 +PL56 2899.653058 -6565.623725 22.344901 +VL56 -15477.800000 -6467.947500 73660.340000 +* 2023 12 11 0 42 0.00000000 +PL56 2571.857089 -6563.352218 1340.101991 +VL56 -20780.891000 6744.064400 72328.745000 +* 2023 12 11 0 45 0.00000000 +PL56 2157.942016 -6323.462547 2610.976977 +VL56 -25018.819000 19851.854000 68466.342000 +* 2023 12 11 0 48 0.00000000 +PL56 1678.421482 -5852.253023 3790.503770 +VL56 -28051.553000 32365.634000 62208.998000 +* 2023 12 11 0 51 0.00000000 +PL56 1155.834276 -5164.694043 4837.442976 +VL56 -29794.743000 43814.858000 53778.061000 +* 2023 12 11 0 54 0.00000000 +PL56 613.719710 -4283.914619 5715.249893 +VL56 -30221.678000 53766.490000 43472.059000 +* 2023 12 11 0 57 0.00000000 +PL56 75.578425 -3240.369150 6393.356613 +VL56 -29362.987000 61842.247000 31654.413000 +* 2023 12 11 1 0 0.00000000 +PL56 -436.131210 -2070.723862 6848.217140 +VL56 -27303.143000 67732.251000 18739.428000 +* 2023 12 11 1 3 0.00000000 +PL56 -900.916848 -816.524992 7064.090364 +VL56 -24175.049000 71205.683000 5177.551400 +* 2023 12 11 1 6 0.00000000 +PL56 -1301.062571 477.302491 7033.555323 +VL56 -20153.008000 72119.137000 -8559.777700 +* 2023 12 11 1 9 0.00000000 +PL56 -1622.299497 1764.079174 6757.746311 +VL56 -15444.191000 70421.684000 -21996.093000 +* 2023 12 11 1 12 0.00000000 +PL56 -1854.313797 2997.061870 6246.304492 +VL56 -10279.235000 66157.251000 -34665.232000 +* 2023 12 11 1 15 0.00000000 +PL56 -1991.077633 4131.148260 5517.050816 +VL56 -4902.004800 59463.884000 -46126.986000 +* 2023 12 11 1 18 0.00000000 +PL56 -2030.993624 5124.542490 4595.387168 +VL56 440.862700 50570.094000 -55981.669000 +* 2023 12 11 1 21 0.00000000 +PL56 -1976.849127 5940.326452 3513.434931 +VL56 5510.579300 39787.867000 -63884.637000 +* 2023 12 11 1 24 0.00000000 +PL56 -1835.581196 6547.872505 2308.927601 +VL56 10086.491000 27502.090000 -69558.993000 +* 2023 12 11 1 27 0.00000000 +PL56 -1617.862460 6924.035517 1023.890636 +VL56 13975.764000 14156.692000 -72806.321000 +* 2023 12 11 1 30 0.00000000 +PL56 -1337.522079 7054.068575 -296.846502 +VL56 17021.756000 237.905610 -73514.472000 +* 2023 12 11 1 33 0.00000000 +PL56 -1010.830844 6932.216581 -1607.248860 +VL56 19110.752000 -13744.717000 -71662.147000 +* 2023 12 11 1 36 0.00000000 +PL56 -655.684788 6561.951849 -2861.724722 +VL56 20176.434000 -27279.026000 -67319.549000 +* 2023 12 11 1 39 0.00000000 +PL56 -290.732018 5955.835099 -4016.740005 +VL56 20201.638000 -39870.532000 -60644.163000 +* 2023 12 11 1 42 0.00000000 +PL56 65.511734 5135.031452 -5032.330819 +VL56 19217.974000 -51060.625000 -51873.816000 +* 2023 12 11 1 45 0.00000000 +PL56 395.519588 4128.510195 -5873.466475 +VL56 17303.111000 -60443.320000 -41316.970000 +* 2023 12 11 1 48 0.00000000 +PL56 683.544053 2971.967990 -6511.217245 +VL56 14576.133000 -67679.243000 -29340.920000 +* 2023 12 11 1 51 0.00000000 +PL56 916.306693 1706.525705 -6923.693932 +VL56 11191.128000 -72506.633000 -16358.367000 +* 2023 12 11 1 54 0.00000000 +PL56 1083.561849 377.257688 -7096.741822 +VL56 7329.641100 -74749.049000 -2813.702500 +* 2023 12 11 1 57 0.00000000 +PL56 1178.516893 -968.397279 -7024.385812 +VL56 3192.344600 -74320.875000 10831.003000 +* 2023 12 11 2 0 0.00000000 +PL56 1198.095963 -2282.297533 -6709.019641 +VL56 -1009.962400 -71229.845000 24110.310000 +* 2023 12 11 2 3 0.00000000 +PL56 1143.041372 -3517.282869 -6161.341841 +VL56 -5065.355700 -65577.156000 36569.178000 +* 2023 12 11 2 6 0.00000000 +PL56 1017.850047 -4628.846768 -5400.041959 +VL56 -8770.141900 -57555.930000 47777.229000 +* 2023 12 11 2 9 0.00000000 +PL56 830.543589 -5576.747591 -4451.224095 +VL56 -11937.869000 -47445.842000 57343.303000 +* 2023 12 11 2 12 0.00000000 +PL56 592.279061 -6326.500414 -3347.576355 +VL56 -14407.991000 -35605.216000 64929.343000 +* 2023 12 11 2 15 0.00000000 +PL56 316.810634 -6850.694030 -2127.295148 +VL56 -16053.663000 -22459.473000 70263.419000 +* 2023 12 11 2 18 0.00000000 +PL56 19.823376 -7130.070594 -832.788034 +VL56 -16788.139000 -8486.383700 73151.279000 +* 2023 12 11 2 21 0.00000000 +PL56 -281.833880 -7154.308458 490.808301 +VL56 -16569.462000 5802.133200 73485.122000 +* 2023 12 11 2 24 0.00000000 +PL56 -570.980782 -6922.458806 1797.236006 +VL56 -15402.972000 19880.030000 71248.728000 +* 2023 12 11 2 27 0.00000000 +PL56 -830.961353 -6443.010469 3040.784220 +VL56 -13341.401000 33228.338000 66519.010000 +* 2023 12 11 2 30 0.00000000 +PL56 -1046.478468 -5733.569555 4177.945693 +VL56 -10482.375000 45356.480000 59463.009000 +* 2023 12 11 2 33 0.00000000 +PL56 -1204.362754 -4820.169184 5168.980107 +VL56 -6963.761100 55821.606000 50330.752000 +* 2023 12 11 2 36 0.00000000 +PL56 -1294.239937 -3736.256254 5979.320195 +VL56 -2957.008800 64245.360000 39445.143000 +* 2023 12 11 2 39 0.00000000 +PL56 -1309.064345 -2521.403737 6580.775100 +VL56 1340.983800 70327.490000 27189.387000 +* 2023 12 11 2 42 0.00000000 +PL56 -1245.494252 -1219.809428 6952.484539 +VL56 5717.128900 73855.612000 13992.384000 +* 2023 12 11 2 45 0.00000000 +PL56 -1104.097601 121.345977 7081.608487 +VL56 9951.712000 74711.546000 313.822460 +* 2023 12 11 2 48 0.00000000 +PL56 -889.383835 1453.628396 6963.742638 +VL56 13828.185000 72874.441000 -13371.291000 +* 2023 12 11 2 51 0.00000000 +PL56 -609.656079 2729.107867 6603.053048 +VL56 17143.200000 68420.872000 -26588.350000 +* 2023 12 11 2 54 0.00000000 +PL56 -276.688899 3902.088912 6012.128934 +VL56 19715.871000 61521.785000 -38878.596000 +* 2023 12 11 2 57 0.00000000 +PL56 94.754667 4930.759341 5211.557546 +VL56 21396.383000 52436.525000 -49814.613000 +* 2023 12 11 3 0 0.00000000 +PL56 487.551203 5778.705425 4229.229764 +VL56 22073.429000 41503.816000 -59014.752000 +* 2023 12 11 3 3 0.00000000 +PL56 882.967204 6416.237707 3099.387878 +VL56 21680.289000 29129.769000 -66156.996000 +* 2023 12 11 3 6 0.00000000 +PL56 1261.502323 6821.479265 1861.445456 +VL56 20199.103000 15773.791000 -70990.971000 +* 2023 12 11 3 9 0.00000000 +PL56 1603.791367 6981.163251 558.595834 +VL56 17662.672000 1929.837300 -73348.148000 +* 2023 12 11 3 12 0.00000000 +PL56 1891.516945 6891.086638 -763.726268 +VL56 14154.357000 -11892.256000 -73148.699000 +* 2023 12 11 3 15 0.00000000 +PL56 2108.289056 6556.206291 -2059.465060 +VL56 9804.330700 -25187.823000 -70403.791000 +* 2023 12 11 3 18 0.00000000 +PL56 2240.448176 5990.377253 -3283.579654 +VL56 4784.700500 -37476.147000 -65214.623000 +* 2023 12 11 3 21 0.00000000 +PL56 2277.754702 5215.747576 -4393.631152 +VL56 -697.995760 -48319.370000 -57767.995000 +* 2023 12 11 3 24 0.00000000 +PL56 2213.931338 4261.839259 -5351.254338 +VL56 -6411.661500 -57338.443000 -48328.069000 +* 2023 12 11 3 27 0.00000000 +PL56 2047.034439 3164.369775 -6123.455203 +VL56 -12108.559000 -64225.835000 -37225.535000 +* 2023 12 11 3 30 0.00000000 +PL56 1779.643089 1963.876726 -6683.699165 +VL56 -17535.642000 -68754.812000 -24845.241000 +* 2023 12 11 3 33 0.00000000 +PL56 1418.861277 704.204418 -7012.764153 +VL56 -22444.866000 -70785.381000 -11612.561000 +* 2023 12 11 3 36 0.00000000 +PL56 976.137482 -569.087740 -7099.347275 +VL56 -26603.260000 -70267.286000 2020.321100 +* 2023 12 11 3 39 0.00000000 +PL56 466.904732 -1810.346667 -6940.419954 +VL56 -29802.599000 -67240.156000 15588.629000 +* 2023 12 11 3 42 0.00000000 +PL56 -89.945930 -2975.427130 -6541.327322 +VL56 -31868.276000 -61831.346000 28628.966000 +* 2023 12 11 3 45 0.00000000 +PL56 -672.745078 -4023.234748 -5915.638813 +VL56 -32667.501000 -54251.626000 40693.365000 +* 2023 12 11 3 48 0.00000000 +PL56 -1257.861875 -4917.172173 -5084.739470 +VL56 -32116.170000 -44788.533000 51363.720000 +* 2023 12 11 3 51 0.00000000 +PL56 -1820.633688 -5626.441071 -4077.165195 +VL56 -30184.527000 -33797.130000 60265.975000 +* 2023 12 11 3 54 0.00000000 +PL56 -2336.380692 -6127.154739 -2927.684008 +VL56 -26900.835000 -21688.060000 67083.964000 +* 2023 12 11 3 57 0.00000000 +PL56 -2781.464670 -6403.209656 -1676.138853 +VL56 -22352.564000 -8912.866200 71571.917000 +* 2023 12 11 4 0 0.00000000 +PL56 -3134.345972 -6446.873589 -366.081210 +VL56 -16684.921000 4052.862500 73565.131000 +* 2023 12 11 4 3 0.00000000 +PL56 -3376.587134 -6259.050858 956.763670 +VL56 -10096.374000 16728.354000 72987.746000 +* 2023 12 11 4 6 0.00000000 +PL56 -3493.748732 -5849.199524 2246.136992 +VL56 -2831.245400 28647.190000 69856.658000 +* 2023 12 11 4 9 0.00000000 +PL56 -3476.129446 -5234.900100 3456.919534 +VL56 4830.155300 39376.353000 64281.181000 +* 2023 12 11 4 12 0.00000000 +PL56 -3319.310610 -4441.096702 4546.761001 +VL56 12583.248000 48533.357000 56458.601000 +* 2023 12 11 4 15 0.00000000 +PL56 -3024.479262 -3499.052114 5477.595480 +VL56 20111.944000 55800.784000 46666.023000 +* 2023 12 11 4 18 0.00000000 +PL56 -2598.516045 -2445.070081 6216.981507 +VL56 27101.923000 60937.446000 35249.199000 +* 2023 12 11 4 21 0.00000000 +PL56 -2053.845226 -1319.052594 6739.220006 +VL56 33253.643000 63785.662000 22609.259000 +* 2023 12 11 4 24 0.00000000 +PL56 -1408.056853 -162.955464 7026.222398 +VL56 38294.650000 64275.321000 9188.053200 +* 2023 12 11 4 27 0.00000000 +PL56 -683.318253 980.797496 7068.101470 +VL56 41990.501000 62424.273000 -4547.535300 +* 2023 12 11 4 30 0.00000000 +PL56 94.398502 2070.877419 6863.484780 +VL56 44154.443000 58335.761000 -18120.930000 +* 2023 12 11 4 33 0.00000000 +PL56 896.254339 3068.547950 6419.549733 +VL56 44655.910000 52193.503000 -31061.380000 +* 2023 12 11 4 36 0.00000000 +PL56 1691.614789 3939.047046 5751.776555 +VL56 43426.882000 44253.932000 -42919.532000 +* 2023 12 11 4 39 0.00000000 +PL56 2449.219510 4652.812325 4883.427935 +VL56 40466.413000 34836.534000 -53282.515000 +* 2023 12 11 4 42 0.00000000 +PL56 3138.412923 5186.510185 3844.761597 +VL56 35842.751000 24311.659000 -61788.346000 +* 2023 12 11 4 45 0.00000000 +PL56 3730.387721 5523.827243 2671.994079 +VL56 29692.747000 13086.621000 -68138.917000 +* 2023 12 11 4 48 0.00000000 +PL56 4199.393826 5655.997515 1406.040631 +VL56 22218.287000 1589.785500 -72112.136000 +* 2023 12 11 4 51 0.00000000 +PL56 4523.850069 5582.027627 91.066679 +VL56 13679.358000 -9746.314500 -73570.099000 +* 2023 12 11 4 54 0.00000000 +PL56 4687.304713 5308.612261 -1227.086497 +VL56 4384.037400 -20502.978000 -72465.006000 +* 2023 12 11 4 57 0.00000000 +PL56 4679.199054 4849.739118 -2502.537142 +VL56 -5323.202100 -30291.293000 -68840.144000 +* 2023 12 11 5 0 0.00000000 +PL56 4495.397440 4226.010647 -3690.989508 +VL56 -15075.520000 -38767.394000 -62827.717000 +* 2023 12 11 5 3 0.00000000 +PL56 4138.457911 3463.717772 -4751.286232 +VL56 -24498.501000 -45644.956000 -54642.926000 +* 2023 12 11 5 6 0.00000000 +PL56 3617.636290 2593.714898 -5646.822078 +VL56 -33224.756000 -50704.557000 -44574.686000 +* 2023 12 11 5 9 0.00000000 +PL56 2948.631300 1650.154330 -6346.772768 +VL56 -40908.083000 -53799.953000 -32974.328000 +* 2023 12 11 5 12 0.00000000 +PL56 2153.085312 669.138396 -6827.102778 +VL56 -47236.291000 -54860.935000 -20242.556000 +* 2023 12 11 5 15 0.00000000 +PL56 1257.867604 -312.652937 -7071.330543 +VL56 -51942.530000 -53893.298000 -6815.743900 +* 2023 12 11 5 18 0.00000000 +PL56 294.168863 -1259.311211 -7071.048070 +VL56 -54815.098000 -50976.422000 6847.817100 +* 2023 12 11 5 21 0.00000000 +PL56 -703.570106 -2136.985962 -6826.186136 +VL56 -55705.728000 -46258.608000 20282.187000 +* 2023 12 11 5 24 0.00000000 +PL56 -1698.861339 -2915.070458 -6345.026783 +VL56 -54536.196000 -39950.820000 33027.751000 +* 2023 12 11 5 27 0.00000000 +PL56 -2654.476085 -3567.260283 -5643.960804 +VL56 -51303.055000 -32318.656000 44645.528000 +* 2023 12 11 5 30 0.00000000 +PL56 -3533.817634 -4072.452388 -4746.989915 +VL56 -46080.279000 -23672.726000 54731.234000 +* 2023 12 11 5 33 0.00000000 +PL56 -4302.323876 -4415.458128 -3684.972363 +VL56 -39019.675000 -14357.497000 62929.670000 +* 2023 12 11 5 36 0.00000000 +PL56 -4928.844184 -4587.496579 -2494.616456 +VL56 -30347.761000 -4738.234900 68948.154000 +* 2023 12 11 5 39 0.00000000 +PL56 -5386.932779 -4586.443359 -1217.244335 +VL56 -20359.417000 4813.165100 72568.540000 +* 2023 12 11 5 42 0.00000000 +PL56 -5655.995825 -4416.816076 102.640147 +VL56 -9408.050700 13933.102000 73656.812000 +* 2023 12 11 5 45 0.00000000 +PL56 -5722.231977 -4089.490935 1418.928944 +VL56 2107.444100 22281.102000 72169.544000 +* 2023 12 11 5 48 0.00000000 +PL56 -5579.311340 -3621.156826 2685.571602 +VL56 13758.640000 29554.041000 68156.611000 +* 2023 12 11 5 51 0.00000000 +PL56 -5228.750917 -3033.528867 3858.243089 +VL56 25105.062000 35498.394000 61759.202000 +* 2023 12 11 5 54 0.00000000 +PL56 -4679.969310 -2352.365210 4895.941680 +VL56 35712.253000 39919.852000 53204.111000 +* 2023 12 11 5 57 0.00000000 +PL56 -3950.018504 -1606.336843 5762.448718 +VL56 45169.303000 42689.838000 42794.119000 +* 2023 12 11 6 0 0.00000000 +PL56 -3063.014857 -825.812059 6427.592070 +VL56 53104.715000 43748.631000 30896.208000 +* 2023 12 11 6 3 0.00000000 +PL56 -2049.297531 -41.609693 6868.281090 +VL56 59200.844000 43105.724000 17927.705000 +* 2023 12 11 6 6 0.00000000 +PL56 -944.346998 716.225816 7069.276291 +VL56 63205.748000 40836.887000 4341.053700 +* 2023 12 11 6 9 0.00000000 +PL56 212.483647 1419.574337 7023.681785 +VL56 64942.426000 37079.200000 -9391.641600 +* 2023 12 11 6 12 0.00000000 +PL56 1379.381901 2043.282712 6733.160863 +VL56 64315.601000 32023.971000 -22794.094000 +* 2023 12 11 6 15 0.00000000 +PL56 2513.592101 2566.065878 6207.869524 +VL56 61316.222000 25908.044000 -35401.543000 +* 2023 12 11 6 18 0.00000000 +PL56 3572.986224 2971.236921 5466.113116 +VL56 56023.175000 19003.723000 -46775.773000 +* 2023 12 11 6 21 0.00000000 +PL56 4517.641813 3247.246861 4533.731159 +VL56 48602.128000 11607.638000 -56520.312000 +* 2023 12 11 6 24 0.00000000 +PL56 5311.367792 3388.015067 3443.220122 +VL56 39301.062000 4028.677900 -64294.171000 +* 2023 12 11 6 27 0.00000000 +PL56 5923.126442 3393.037680 2232.614408 +VL56 28442.932000 -3424.542600 -69825.008000 +* 2023 12 11 6 30 0.00000000 +PL56 6328.279413 3267.263984 944.151936 +VL56 16413.825000 -10456.721000 -72919.759000 +* 2023 12 11 6 33 0.00000000 +PL56 6509.601048 3020.749107 -377.223286 +VL56 3648.519500 -16797.936000 -73471.846000 +* 2023 12 11 6 36 0.00000000 +PL56 6458.005975 2668.094137 -1685.466858 +VL56 -9386.375500 -22214.736000 -71465.739000 +* 2023 12 11 6 39 0.00000000 +PL56 6172.954067 2227.703746 -2935.073322 +VL56 -22211.016000 -26519.163000 -66976.585000 +* 2023 12 11 6 42 0.00000000 +PL56 5662.521075 1720.903700 -4082.683977 +VL56 -34351.098000 -29575.579000 -60166.869000 +* 2023 12 11 6 45 0.00000000 +PL56 4943.131951 1170.956963 -5088.598759 +VL56 -45356.247000 -31304.877000 -51279.197000 +* 2023 12 11 6 48 0.00000000 +PL56 4038.974152 602.030685 -5918.129175 +VL56 -54816.870000 -31685.634000 -40625.888000 +* 2023 12 11 6 51 0.00000000 +PL56 2981.132143 38.166445 -6542.749010 +VL56 -62378.440000 -30752.784000 -28577.206000 +* 2023 12 11 6 54 0.00000000 +PL56 1806.483907 -497.704297 -6941.018932 +VL56 -67753.544000 -28593.994000 -15548.036000 +* 2023 12 11 6 57 0.00000000 +PL56 556.406267 -984.663748 -7099.266411 +VL56 -70731.107000 -25344.317000 -1984.200600 +* 2023 12 11 7 0 0.00000000 +PL56 -724.668601 -1404.600399 -7012.016314 +VL56 -71183.677000 -21179.223000 11651.720000 +* 2023 12 11 7 3 0.00000000 +PL56 -1990.802653 -1742.865897 -6682.166736 +VL56 -69072.038000 -16306.646000 24894.292000 +* 2023 12 11 7 6 0.00000000 +PL56 -3196.165785 -1988.780804 -6120.910751 +VL56 -64447.489000 -10958.073000 37289.636000 +* 2023 12 11 7 9 0.00000000 +PL56 -4296.669468 -2135.973902 -5347.402432 +VL56 -57452.094000 -5379.143100 48409.348000 +* 2023 12 11 7 12 0.00000000 +PL56 -5251.580017 -2182.547235 -4388.169678 +VL56 -48315.906000 180.470350 57864.981000 +* 2023 12 11 7 15 0.00000000 +PL56 -6025.056778 -2131.057163 -3276.269009 +VL56 -37351.248000 5477.282300 65321.877000 +* 2023 12 11 7 18 0.00000000 +PL56 -6587.552541 -1988.308298 -2050.195554 +VL56 -24943.187000 10284.448000 70512.460000 +* 2023 12 11 7 21 0.00000000 +PL56 -6917.010805 -1764.963786 -752.571915 +VL56 -11536.477000 14401.673000 73247.382000 +* 2023 12 11 7 24 0.00000000 +PL56 -6999.796847 -1474.985475 571.342948 +VL56 2380.871600 17664.106000 73424.211000 +* 2023 12 11 7 27 0.00000000 +PL56 -6831.307894 -1134.926605 1875.269600 +VL56 16296.685000 19949.711000 71032.506000 +* 2023 12 11 7 30 0.00000000 +PL56 -6416.222192 -763.111714 3113.579572 +VL56 29695.406000 21184.373000 66154.873000 +* 2023 12 11 7 33 0.00000000 +PL56 -5768.371339 -378.745743 4242.946871 +VL56 42079.041000 21344.644000 58963.674000 +* 2023 12 11 7 36 0.00000000 +PL56 -4910.240620 -0.997147 5223.906084 +VL56 52987.223000 20457.784000 49713.915000 +* 2023 12 11 7 39 0.00000000 +PL56 -3872.128619 351.896356 6022.246866 +VL56 62014.836000 18599.361000 38732.591000 +* 2023 12 11 7 42 0.00000000 +PL56 -2691.016295 663.458110 6610.199943 +VL56 68826.807000 15888.545000 26406.154000 +* 2023 12 11 7 45 0.00000000 +PL56 -1409.193738 919.700139 6967.379701 +VL56 73170.020000 12481.454000 13166.019000 +* 2023 12 11 7 48 0.00000000 +PL56 -72.704862 1109.720560 7081.458101 +VL56 74881.539000 8563.435400 -526.623770 +* 2023 12 11 7 51 0.00000000 +PL56 1270.327270 1226.149475 6948.558112 +VL56 73893.864000 4340.074700 -14196.467000 +* 2023 12 11 7 54 0.00000000 +PL56 2571.439421 1265.429089 6573.368864 +VL56 70236.894000 27.733325 -27369.592000 +* 2023 12 11 7 57 0.00000000 +PL56 3783.580831 1227.919743 5968.982431 +VL56 64037.280000 -4156.252600 -39588.826000 +* 2023 12 11 8 0 0.00000000 +PL56 4862.826754 1117.828644 5156.453326 +VL56 55514.747000 -8003.400000 -50429.160000 +* 2023 12 11 8 3 0.00000000 +PL56 5769.993205 942.964693 4164.089251 +VL56 44975.022000 -11323.538000 -59512.021000 +* 2023 12 11 8 6 0.00000000 +PL56 6472.101100 714.328979 3026.486707 +VL56 32799.717000 -13953.532000 -66519.508000 +* 2023 12 11 8 9 0.00000000 +PL56 6943.621917 445.557022 1783.328167 +VL56 19432.466000 -15764.969000 -71206.161000 +* 2023 12 11 8 12 0.00000000 +PL56 7167.448544 152.235580 477.986498 +VL56 5362.440600 -16670.312000 -73408.762000 +* 2023 12 11 8 15 0.00000000 +PL56 7135.545179 -148.872678 -844.016926 +VL56 -8894.867900 -16626.967000 -73052.665000 +* 2023 12 11 8 18 0.00000000 +PL56 6849.240068 -440.660017 -2136.638557 +VL56 -22818.092000 -15639.300000 -70154.545000 +* 2023 12 11 8 21 0.00000000 +PL56 6319.145643 -706.518005 -3354.951518 +VL56 -35900.403000 -13758.172000 -64821.205000 +* 2023 12 11 8 24 0.00000000 +PL56 5564.716389 -931.153397 -4456.726239 +VL56 -47669.243000 -11078.202000 -57244.483000 +* 2023 12 11 8 27 0.00000000 +PL56 4613.472612 -1101.334422 -5403.890084 +VL56 -57703.645000 -7732.840800 -47692.799000 +* 2023 12 11 8 30 0.00000000 +PL56 3499.936710 -1206.533552 -6163.812799 +VL56 -65648.719000 -3887.945400 -36500.483000 +* 2023 12 11 8 33 0.00000000 +PL56 2264.335401 -1239.443342 -6710.381661 +VL56 -71227.192000 265.949500 -24055.170000 +* 2023 12 11 8 36 0.00000000 +PL56 951.125781 -1196.342872 -7024.840508 +VL56 -74247.393000 4522.349400 -10784.314000 +* 2023 12 11 8 39 0.00000000 +PL56 -392.598029 -1077.305038 -7096.382187 +VL56 -74608.620000 8667.759600 2858.628600 +* 2023 12 11 8 42 0.00000000 +PL56 -1718.767682 -886.239402 -6922.489077 +VL56 -72303.531000 12490.911000 16408.387000 +* 2023 12 11 8 45 0.00000000 +PL56 -2980.026165 -630.768322 -6509.019371 +VL56 -67418.317000 15792.062000 29402.042000 +* 2023 12 11 8 48 0.00000000 +PL56 -4131.389035 -321.938808 -5870.036257 +VL56 -60129.751000 18391.892000 41393.148000 +* 2023 12 11 8 51 0.00000000 +PL56 -5131.839103 26.221425 -5027.385464 +VL56 -50700.806000 20139.875000 51965.822000 +* 2023 12 11 8 54 0.00000000 +PL56 -5945.809610 397.292080 -4010.015023 +VL56 -39472.663000 20921.857000 60749.085000 +* 2023 12 11 8 57 0.00000000 +PL56 -6544.501751 773.175016 -2853.043866 +VL56 -26854.023000 20666.514000 67430.508000 +* 2023 12 11 9 0 0.00000000 +PL56 -6906.978673 1134.910914 -1596.590579 +VL56 -13307.172000 19350.142000 71768.975000 +* 2023 12 11 9 3 0.00000000 +PL56 -7020.978468 1463.562326 -284.393092 +VL56 669.369230 16999.106000 73605.055000 +* 2023 12 11 9 6 0.00000000 +PL56 -6883.396675 1741.120602 1037.737557 +VL56 14560.136000 13689.989000 72868.644000 +* 2023 12 11 9 9 0.00000000 +PL56 -6500.401739 1951.390864 2323.560937 +VL56 27853.672000 9547.141600 69582.450000 +* 2023 12 11 9 12 0.00000000 +PL56 -5887.178513 2080.811412 3528.078991 +VL56 40063.039000 4737.756800 63861.403000 +* 2023 12 11 9 15 0.00000000 +PL56 -5067.305335 2119.161527 4609.162967 +VL56 50745.649000 -535.510760 55908.221000 +* 2023 12 11 9 18 0.00000000 +PL56 -4071.798881 2060.121294 5529.058912 +VL56 59520.178000 -6043.503500 46004.602000 +* 2023 12 11 9 21 0.00000000 +PL56 -2937.884219 1901.659720 6255.713071 +VL56 66080.077000 -11540.583000 34500.147000 +* 2023 12 11 9 24 0.00000000 +PL56 -1707.548323 1646.235708 6763.877802 +VL56 70204.287000 -16775.326000 21799.139000 +* 2023 12 11 9 27 0.00000000 +PL56 -425.938103 1300.802201 7035.959986 +VL56 71763.543000 -21501.603000 8345.196800 +* 2023 12 11 9 30 0.00000000 +PL56 860.322417 876.615929 7062.592602 +VL56 70723.149000 -25489.099000 -5393.860400 +* 2023 12 11 9 33 0.00000000 +PL56 2104.836207 388.862116 6842.930556 +VL56 67142.704000 -28533.217000 -18941.543000 +* 2023 12 11 9 36 0.00000000 +PL56 3263.108782 -143.893395 6384.668613 +VL56 61173.295000 -30464.373000 -31828.028000 +* 2023 12 11 9 39 0.00000000 +PL56 4294.145993 -700.408768 5703.781619 +VL56 53051.606000 -31156.088000 -43605.716000 +* 2023 12 11 9 42 0.00000000 +PL56 5161.923018 -1257.605354 4823.987474 +VL56 43091.424000 -30531.735000 -53864.332000 +* 2023 12 11 9 45 0.00000000 +PL56 5836.673354 -1791.512052 3775.944357 +VL56 31672.229000 -28569.399000 -62245.310000 +* 2023 12 11 9 48 0.00000000 +PL56 6295.950882 -2278.278659 2596.198062 +VL56 19225.379000 -25304.727000 -68455.141000 +* 2023 12 11 9 51 0.00000000 +PL56 6525.416368 -2695.216433 1325.906741 +VL56 6217.350700 -20830.921000 -72276.523000 +* 2023 12 11 9 54 0.00000000 +PL56 6519.310718 -3021.816994 9.387270 +VL56 -6868.181700 -15296.352000 -73576.978000 +* 2023 12 11 9 57 0.00000000 +PL56 6280.590526 -3240.700681 -1307.464263 +VL56 -19549.670000 -8899.164200 -72313.990000 +* 2023 12 11 10 0 0.00000000 +PL56 5820.715682 -3338.445705 -2578.812455 +VL56 -31366.977000 -1879.500600 -68536.693000 +* 2023 12 11 10 3 0.00000000 +PL56 5159.100623 -3306.256343 -3760.508595 +VL56 -41899.208000 5490.526600 -62382.695000 +* 2023 12 11 10 6 0.00000000 +PL56 4322.265824 -3140.441318 -4811.634879 +VL56 -50780.066000 12917.820000 -54072.033000 +* 2023 12 11 10 9 0.00000000 +PL56 3342.733862 -2842.683423 -5695.908876 +VL56 -57710.798000 20100.418000 -43897.913000 +* 2023 12 11 10 12 0.00000000 +PL56 2257.728020 -2420.090115 -6382.896570 +VL56 -62469.051000 26739.500000 -32214.903000 +* 2023 12 11 10 15 0.00000000 +PL56 1107.741005 -1885.032080 -6849.005214 +VL56 -64914.643000 32551.004000 -19426.387000 +* 2023 12 11 10 18 0.00000000 +PL56 -64.975631 -1254.775575 -7078.240170 +VL56 -64992.504000 37276.784000 -5970.808600 +* 2023 12 11 10 21 0.00000000 +PL56 -1217.946084 -550.924226 -7062.706783 +VL56 -62732.533000 40694.633000 7692.557600 +* 2023 12 11 10 24 0.00000000 +PL56 -2309.978933 201.309563 -6802.859344 +VL56 -58247.027000 42627.257000 21097.688000 +* 2023 12 11 10 27 0.00000000 +PL56 -3302.610677 973.986521 -6307.495477 +VL56 -51725.757000 42950.121000 33785.952000 +* 2023 12 11 10 30 0.00000000 +PL56 -4161.443951 1737.451687 -5593.497231 +VL56 -43429.478000 41598.079000 45320.025000 +* 2023 12 11 10 33 0.00000000 +PL56 -4857.349325 2461.449177 -4685.318781 +VL56 -33681.142000 38570.238000 55298.307000 +* 2023 12 11 10 36 0.00000000 +PL56 -5367.489554 3116.309308 -3614.214614 +VL56 -22854.824000 33932.824000 63369.174000 +* 2023 12 11 10 39 0.00000000 +PL56 -5676.121130 3674.160820 -2417.218063 +VL56 -11362.295000 27819.237000 69244.217000 +* 2023 12 11 10 42 0.00000000 +PL56 -5775.138080 4110.119800 -1135.893667 +VL56 362.341100 20427.274000 72710.204000 +* 2023 12 11 10 45 0.00000000 +PL56 -5664.323892 4403.398861 185.105706 +VL56 11879.515000 12013.010000 73638.562000 +* 2023 12 11 10 48 0.00000000 +PL56 -5351.289966 4538.278433 1499.625732 +VL56 22761.990000 2881.683200 71991.844000 +* 2023 12 11 10 51 0.00000000 +PL56 -4851.092635 4504.884471 2761.676197 +VL56 32612.646000 -6624.672800 67825.673000 +* 2023 12 11 10 54 0.00000000 +PL56 -4185.545229 4299.730072 3927.095157 +VL56 41080.313000 -16140.853000 61286.768000 +* 2023 12 11 10 57 0.00000000 +PL56 -3382.263142 3925.995307 4955.139066 +VL56 47873.468000 -25293.806000 52606.982000 +* 2023 12 11 11 0 0.00000000 +PL56 -2473.493068 3393.530857 5809.932083 +VL56 52770.514000 -33717.962000 42093.530000 +* 2023 12 11 11 3 0.00000000 +PL56 -1494.784163 2718.589268 6461.719625 +VL56 55626.997000 -41069.967000 30117.149000 +* 2023 12 11 11 6 0.00000000 +PL56 -483.565066 1923.298795 6887.882399 +VL56 56378.830000 -47042.485000 17097.377000 +* 2023 12 11 11 9 0.00000000 +PL56 522.305911 1034.907274 7073.685525 +VL56 55042.050000 -51375.818000 3488.197900 +* 2023 12 11 11 12 0.00000000 +PL56 1485.964601 84.827683 7012.756356 +VL56 51710.387000 -53868.372000 -10237.781000 +* 2023 12 11 11 15 0.00000000 +PL56 2372.893260 -892.482527 6707.283166 +VL56 46549.804000 -54384.749000 -23604.558000 +* 2023 12 11 11 18 0.00000000 +PL56 3152.158643 -1860.775096 6167.935505 +VL56 39791.244000 -52862.257000 -36148.346000 +* 2023 12 11 11 21 0.00000000 +PL56 3797.500016 -2783.358939 5413.505723 +VL56 31721.177000 -49314.854000 -47433.004000 +* 2023 12 11 11 24 0.00000000 +PL56 4288.230819 -3624.498013 4470.275939 +VL56 22670.453000 -43834.693000 -57064.837000 +* 2023 12 11 11 27 0.00000000 +PL56 4609.921926 -4350.809834 3371.124184 +VL56 13001.245000 -36590.631000 -64706.912000 +* 2023 12 11 11 30 0.00000000 +PL56 4754.840189 -4932.609669 2154.388412 +VL56 3092.878900 -27823.577000 -70091.489000 +* 2023 12 11 11 33 0.00000000 +PL56 4722.120575 -5345.138964 862.521096 +VL56 -6673.434000 -17838.370000 -73030.606000 +* 2023 12 11 11 36 0.00000000 +PL56 4517.660226 -5569.619283 -459.416614 +VL56 -15930.089000 -6992.521000 -73423.326000 +* 2023 12 11 11 39 0.00000000 +PL56 4153.741009 -5594.080483 -1765.360795 +VL56 -24337.605000 4317.457100 -71259.513000 +* 2023 12 11 11 42 0.00000000 +PL56 3648.398872 -5413.922404 -3009.887246 +VL56 -31598.169000 15671.939000 -66620.005000 +* 2023 12 11 11 45 0.00000000 +PL56 3024.571168 -5032.181566 -4149.817601 +VL56 -37466.687000 26644.891000 -59672.581000 +* 2023 12 11 11 48 0.00000000 +PL56 2309.067880 -4459.495489 -5145.722943 +VL56 -41759.110000 36820.516000 -50664.561000 +* 2023 12 11 11 51 0.00000000 +PL56 1531.419937 -3713.771818 -5963.265756 +VL56 -44357.686000 45809.328000 -39912.406000 +* 2023 12 11 11 54 0.00000000 +PL56 722.664869 -2819.587254 -6574.336656 +VL56 -45212.903000 53262.000000 -27789.558000 +* 2023 12 11 11 57 0.00000000 +PL56 -85.880623 -1807.349632 -6957.964575 +VL56 -44342.940000 58881.864000 -14713.446000 +* 2023 12 11 12 0 0.00000000 +PL56 -863.814206 -712.252411 -7100.981940 +VL56 -41830.487000 62435.420000 -1131.367500 +* 2023 12 11 12 3 0.00000000 +PL56 -1582.765482 426.939139 -6998.437277 +VL56 -37817.667000 63760.525000 12493.430000 +* 2023 12 11 12 6 0.00000000 +PL56 -2217.408896 1569.233005 -6653.753956 +VL56 -32499.435000 62772.800000 25696.014000 +* 2023 12 11 12 9 0.00000000 +PL56 -2746.342710 2672.852164 -6078.635605 +VL56 -26115.346000 59469.945000 38023.643000 +* 2023 12 11 12 12 0.00000000 +PL56 -3152.811896 3696.737819 -5292.718900 +VL56 -18940.505000 53934.293000 49049.951000 +* 2023 12 11 12 15 0.00000000 +PL56 -3425.255058 4602.073953 -4322.968947 +VL56 -11275.090000 46332.470000 58389.470000 +* 2023 12 11 12 18 0.00000000 +PL56 -3557.652560 5353.779557 -3202.815085 +VL56 -3432.603900 36911.914000 65711.701000 +* 2023 12 11 12 21 0.00000000 +PL56 -3549.654872 5921.904721 -1971.044321 +VL56 4272.540400 25993.882000 70753.807000 +* 2023 12 11 12 24 0.00000000 +PL56 -3406.485863 6282.873965 -670.482366 +VL56 11537.664000 13963.351000 73331.538000 +* 2023 12 11 12 27 0.00000000 +PL56 -3138.616229 6420.512116 653.504905 +VL56 18084.423000 1255.047700 73347.941000 +* 2023 12 11 12 30 0.00000000 +PL56 -2761.220156 6326.793664 1954.631380 +VL56 23670.439000 -11663.193000 70798.489000 +* 2023 12 11 12 33 0.00000000 +PL56 -2293.430423 6002.267301 3187.369016 +VL56 28099.816000 -24309.903000 65771.618000 +* 2023 12 11 12 36 0.00000000 +PL56 -1757.431035 5456.124683 4308.594858 +VL56 31230.410000 -36209.480000 58445.029000 +* 2023 12 11 12 39 0.00000000 +PL56 -1177.442051 4705.921384 5279.135596 +VL56 32978.636000 -46911.246000 49078.394000 +* 2023 12 11 12 42 0.00000000 +PL56 -578.643768 3776.966060 6065.152174 +VL56 33321.494000 -56007.208000 38002.793000 +* 2023 12 11 12 45 0.00000000 +PL56 13.906259 2701.410308 6639.310698 +VL56 32295.247000 -63147.431000 25607.683000 +* 2023 12 11 12 48 0.00000000 +PL56 576.312418 1517.084929 6981.706356 +VL56 29991.909000 -68052.658000 12326.507000 +* 2023 12 11 12 51 0.00000000 +PL56 1086.796883 266.133127 7080.520275 +VL56 26553.664000 -70524.395000 -1378.336700 +* 2023 12 11 12 54 0.00000000 +PL56 1526.537001 -1006.508404 6932.398355 +VL56 22165.345000 -70451.722000 -15031.232000 +* 2023 12 11 12 57 0.00000000 +PL56 1880.356828 -2254.731012 6542.552946 +VL56 17045.753000 -67815.815000 -28158.600000 +* 2023 12 11 13 0 0.00000000 +PL56 2137.252277 -3432.931401 5924.583789 +VL56 11437.950000 -62691.748000 -40304.650000 +* 2023 12 11 13 3 0.00000000 +PL56 2290.733464 -4497.690536 5100.019513 +VL56 5598.641500 -55246.592000 -51046.699000 +* 2023 12 11 13 6 0.00000000 +PL56 2338.973299 -5409.394098 4097.588607 +VL56 -212.604970 -45734.928000 -60009.799000 +* 2023 12 11 13 9 0.00000000 +PL56 2284.761106 -6133.739398 2952.238025 +VL56 -5744.281700 -34490.743000 -66880.156000 +* 2023 12 11 13 12 0.00000000 +PL56 2135.257743 -6643.066746 1703.918775 +VL56 -10763.871000 -21915.914000 -71417.292000 +* 2023 12 11 13 15 0.00000000 +PL56 1901.563728 -6917.450168 396.180804 +VL56 -15067.705000 -8465.298900 -73463.121000 +* 2023 12 11 13 18 0.00000000 +PL56 1598.121096 -6945.501725 -925.371469 +VL56 -18489.510000 5370.472800 -72948.317000 +* 2023 12 11 13 21 0.00000000 +PL56 1241.972940 -6724.845382 -2214.710761 +VL56 -20907.595000 19084.219000 -69895.254000 +* 2023 12 11 13 24 0.00000000 +PL56 851.916696 -6262.224992 -3427.027884 +VL56 -22249.192000 32173.003000 -64416.277000 +* 2023 12 11 13 27 0.00000000 +PL56 447.602417 -5573.252823 -4520.307280 +VL56 -22492.403000 44157.449000 -56708.301000 +* 2023 12 11 13 30 0.00000000 +PL56 48.619835 -4681.820834 -5456.777380 +VL56 -21665.595000 54599.838000 -47044.301000 +* 2023 12 11 13 33 0.00000000 +PL56 -326.385476 -3619.210621 -6204.183825 +VL56 -19844.638000 63119.251000 -35762.350000 +* 2023 12 11 13 36 0.00000000 +PL56 -660.526178 -2422.948205 -6736.849997 +VL56 -17148.073000 69404.611000 -23253.036000 +* 2023 12 11 13 39 0.00000000 +PL56 -939.385613 -1135.454678 -7036.500748 +VL56 -13730.714000 73224.516000 -9945.848200 +* 2023 12 11 13 42 0.00000000 +PL56 -1151.604386 197.454919 -7092.838394 +VL56 -9776.100700 74434.228000 3704.666300 +* 2023 12 11 13 45 0.00000000 +PL56 -1289.322729 1528.177021 -6903.865901 +VL56 -5488.091800 72980.261000 17233.090000 +* 2023 12 11 13 48 0.00000000 +PL56 -1348.466352 2808.982501 -6475.956473 +VL56 -1081.922400 68902.333000 30177.164000 +* 2023 12 11 13 51 0.00000000 +PL56 -1328.868500 3993.697133 -5823.671651 +VL56 3225.038500 62333.323000 42091.700000 +* 2023 12 11 13 54 0.00000000 +PL56 -1234.223959 5039.357396 -4969.322897 +VL56 7222.677000 53496.355000 52563.163000 +* 2023 12 11 13 57 0.00000000 +PL56 -1071.874650 5907.789020 -3942.274150 +VL56 10717.381000 42699.136000 61223.889000 +* 2023 12 11 14 0 0.00000000 +PL56 -852.431992 6567.049381 -2777.989544 +VL56 13540.902000 30324.537000 67765.910000 +* 2023 12 11 14 3 0.00000000 +PL56 -589.246685 6992.670192 -1516.846972 +VL56 15558.351000 16817.807000 71953.129000 +* 2023 12 11 14 6 0.00000000 +PL56 -297.746643 7168.642024 -202.747760 +VL56 16674.784000 2670.625100 73631.585000 +* 2023 12 11 14 9 0.00000000 +PL56 5.329418 7088.084522 1118.431739 +VL56 16840.134000 -11597.665000 72736.759000 +* 2023 12 11 14 12 0.00000000 +PL56 302.765953 6753.558355 2400.488601 +VL56 16051.696000 -25461.044000 69297.146000 +* 2023 12 11 14 15 0.00000000 +PL56 577.726095 6176.990390 3598.565097 +VL56 14354.046000 -38408.362000 63433.122000 +* 2023 12 11 14 18 0.00000000 +PL56 814.585740 5379.223774 4670.763715 +VL56 11836.825000 -49963.256000 55352.074000 +* 2023 12 11 14 21 0.00000000 +PL56 999.707682 4389.217613 5579.648508 +VL56 8630.153200 -59703.439000 45340.850000 +* 2023 12 11 14 24 0.00000000 +PL56 1122.113587 3242.925478 6293.559895 +VL56 4898.151000 -67276.035000 33752.157000 +* 2023 12 11 14 27 0.00000000 +PL56 1174.027125 1981.930653 6787.697997 +VL56 831.053950 -72410.208000 20993.077000 +* 2023 12 11 14 30 0.00000000 +PL56 1151.262594 651.891435 7044.955324 +VL56 -3363.942400 -74925.403000 7508.802900 +* 2023 12 11 14 33 0.00000000 +PL56 1053.446904 -699.140912 7056.475212 +VL56 -7472.053300 -74736.764000 -6231.826300 +* 2023 12 11 14 36 0.00000000 +PL56 884.067553 -2022.468698 6821.934284 +VL56 -11280.739000 -71857.482000 -19752.040000 +* 2023 12 11 14 39 0.00000000 +PL56 650.344163 -3270.510834 6349.545439 +VL56 -14589.461000 -66398.040000 -32582.693000 +* 2023 12 11 14 42 0.00000000 +PL56 362.927724 -4398.524548 5655.775565 +VL56 -17218.979000 -58562.342000 -44278.399000 +* 2023 12 11 14 45 0.00000000 +PL56 35.440948 -5366.222435 4764.786311 +VL56 -19019.655000 -48640.209000 -54431.979000 +* 2023 12 11 14 48 0.00000000 +PL56 -316.122622 -6139.239707 3707.620328 +VL56 -19878.873000 -36998.033000 -62688.426000 +* 2023 12 11 14 51 0.00000000 +PL56 -674.124228 -6690.401963 2521.137185 +VL56 -19727.293000 -24065.819000 -68758.444000 +* 2023 12 11 14 54 0.00000000 +PL56 -1020.098314 -7000.727213 1246.726956 +VL56 -18542.883000 -10320.922000 -72429.551000 +* 2023 12 11 14 57 0.00000000 +PL56 -1335.625459 -7060.118734 -71.151328 +VL56 -16352.966000 3729.944400 -73574.465000 +* 2023 12 11 15 0 0.00000000 +PL56 -1603.219116 -6867.709885 -1386.557520 +VL56 -13233.538000 17571.300000 -72156.369000 +* 2023 12 11 15 3 0.00000000 +PL56 -1807.176955 -6431.838637 -2653.710907 +VL56 -9306.148200 30699.300000 -68229.625000 +* 2023 12 11 15 6 0.00000000 +PL56 -1934.358151 -5769.662701 -3828.612864 +VL56 -4732.824000 42641.027000 -61937.115000 +* 2023 12 11 15 9 0.00000000 +PL56 -1974.850046 -4906.435383 -4870.587303 +VL56 291.109420 52972.630000 -53503.748000 +* 2023 12 11 15 12 0.00000000 +PL56 -1922.491672 -3874.483697 -5743.673930 +VL56 5545.632900 61334.173000 -43226.789000 +* 2023 12 11 15 15 0.00000000 +PL56 -1775.234306 -2711.949283 -6417.829287 +VL56 10795.480000 67441.195000 -31464.362000 +* 2023 12 11 15 18 0.00000000 +PL56 -1535.326856 -1461.348909 -6869.907485 +VL56 15800.082000 71093.168000 -18622.464000 +* 2023 12 11 15 21 0.00000000 +PL56 -1209.321225 -168.012698 -7084.396974 +VL56 20323.531000 72178.614000 -5141.031800 +* 2023 12 11 15 24 0.00000000 +PL56 -807.901017 1121.540826 -7053.905634 +VL56 24144.263000 70677.060000 8520.058200 +* 2023 12 11 15 27 0.00000000 +PL56 -345.537614 2361.243526 -6779.394836 +VL56 27064.470000 66658.780000 21894.857000 +* 2023 12 11 15 30 0.00000000 +PL56 160.015826 3507.089269 -6270.162391 +VL56 28918.735000 60282.025000 34525.315000 +* 2023 12 11 15 33 0.00000000 +PL56 688.382707 4518.680333 -5543.571540 +VL56 29582.238000 51788.398000 45975.797000 +* 2023 12 11 15 36 0.00000000 +PL56 1217.356102 5360.660682 -4624.519030 +VL56 28977.451000 41495.058000 55847.230000 +* 2023 12 11 15 39 0.00000000 +PL56 1723.801091 6003.990176 -3544.647313 +VL56 27079.535000 29784.662000 63791.504000 +* 2023 12 11 15 42 0.00000000 +PL56 2184.635567 6427.007786 -2341.307172 +VL56 23919.551000 17092.021000 69524.601000 +* 2023 12 11 15 45 0.00000000 +PL56 2577.848988 6616.234168 -1056.294522 +VL56 19585.418000 3888.532300 72838.421000 +* 2023 12 11 15 48 0.00000000 +PL56 2883.512619 6566.867905 265.605665 +VL56 14219.964000 -9336.176700 73610.226000 +* 2023 12 11 15 51 0.00000000 +PL56 3084.728610 6282.937906 1578.212555 +VL56 8016.094900 -22093.895000 71808.283000 +* 2023 12 11 15 54 0.00000000 +PL56 3168.468552 5777.101319 2835.609799 +VL56 1209.416300 -33917.357000 67493.690000 +* 2023 12 11 15 57 0.00000000 +PL56 3126.258734 5070.095053 3993.803861 +VL56 -5931.338400 -44379.063000 60818.327000 +* 2023 12 11 16 0 0.00000000 +PL56 2954.677200 4189.865067 5012.309007 +VL56 -13115.645000 -53108.113000 52018.765000 +* 2023 12 11 16 3 0.00000000 +PL56 2655.632154 3170.415962 5855.590537 +VL56 -20043.916000 -59804.268000 41406.493000 +* 2023 12 11 16 6 0.00000000 +PL56 2236.412333 2050.444176 6494.300366 +VL56 -26419.924000 -64247.741000 29355.333000 +* 2023 12 11 16 9 0.00000000 +PL56 1709.518147 871.827262 6906.276002 +VL56 -31962.892000 -66305.732000 16287.435000 +* 2023 12 11 16 12 0.00000000 +PL56 1092.275578 -321.972204 7077.276587 +VL56 -36419.213000 -65935.017000 2658.201900 +* 2023 12 11 16 15 0.00000000 +PL56 406.251736 -1487.521023 7001.444484 +VL56 -39572.935000 -63181.859000 -11058.822000 +* 2023 12 11 16 18 0.00000000 +PL56 -323.509126 -2583.002366 6681.489962 +VL56 -41255.098000 -58178.800000 -24387.888000 +* 2023 12 11 16 21 0.00000000 +PL56 -1069.405731 -3569.722567 6128.589124 +VL56 -41351.630000 -51139.034000 -36866.687000 +* 2023 12 11 16 24 0.00000000 +PL56 -1802.319952 -4413.484509 5362.000841 +VL56 -39808.968000 -42347.486000 -48061.770000 +* 2023 12 11 16 27 0.00000000 +PL56 -2492.747821 -5085.789865 4408.423496 +VL56 -36638.388000 -32150.546000 -57582.476000 +* 2023 12 11 16 30 0.00000000 +PL56 -3111.990344 -5564.836252 3301.091689 +VL56 -31918.049000 -20943.410000 -65095.554000 +* 2023 12 11 16 33 0.00000000 +PL56 -3633.347882 -5836.258680 2078.624630 +VL56 -25791.459000 -9154.540400 -70337.821000 +* 2023 12 11 16 36 0.00000000 +PL56 -4033.261819 -5893.579737 783.670473 +VL56 -18463.173000 2770.998900 -73126.265000 +* 2023 12 11 16 39 0.00000000 +PL56 -4292.354403 -5738.350837 -538.605044 +VL56 -10191.751000 14389.137000 -73365.098000 +* 2023 12 11 16 42 0.00000000 +PL56 -4396.315931 -5379.974773 -1842.129516 +VL56 -1279.908100 25274.484000 -71049.681000 +* 2023 12 11 16 45 0.00000000 +PL56 -4336.593158 -4835.214754 -3081.568316 +VL56 7937.643500 35037.298000 -66266.253000 +* 2023 12 11 16 48 0.00000000 +PL56 -4110.843809 -4127.415065 -4213.927691 +VL56 17107.863000 43338.331000 -59187.622000 +* 2023 12 11 16 51 0.00000000 +PL56 -3723.139264 -3285.481318 -5200.047663 +VL56 25873.517000 49900.621000 -50065.444000 +* 2023 12 11 16 54 0.00000000 +PL56 -3183.913884 -2342.676216 -6005.932151 +VL56 33887.125000 54518.186000 -39219.914000 +* 2023 12 11 16 57 0.00000000 +PL56 -2509.669213 -1335.288321 -6603.875590 +VL56 40824.144000 57061.424000 -27027.667000 +* 2023 12 11 17 0 0.00000000 +PL56 -1722.449262 -301.231840 -6973.359410 +VL56 46395.222000 57479.444000 -13908.282000 +* 2023 12 11 17 3 0.00000000 +PL56 -849.109504 721.367484 -7101.698517 +VL56 50356.718000 55799.271000 -310.212250 +* 2023 12 11 17 6 0.00000000 +PL56 79.589793 1695.550104 -6984.436838 +VL56 52519.813000 52122.810000 13302.916000 +* 2023 12 11 17 9 0.00000000 +PL56 1030.042508 2586.828906 -6625.494587 +VL56 52758.321000 46621.918000 26466.300000 +* 2023 12 11 17 12 0.00000000 +PL56 1966.984914 3364.392456 -6037.064572 +VL56 51015.181000 39531.843000 38728.108000 +* 2023 12 11 17 15 0.00000000 +PL56 2854.782487 4002.171135 -5239.246740 +VL56 47306.775000 31142.599000 49663.950000 +* 2023 12 11 17 18 0.00000000 +PL56 3658.773468 4479.730551 -4259.424811 +VL56 41724.965000 21788.512000 58891.235000 +* 2023 12 11 17 21 0.00000000 +PL56 4346.627304 4782.964652 -3131.389742 +VL56 34436.547000 11836.201000 66082.917000 +* 2023 12 11 17 24 0.00000000 +PL56 4889.665744 4904.554032 -1894.218861 +VL56 25679.629000 1670.676900 70980.697000 +* 2023 12 11 17 27 0.00000000 +PL56 5264.084080 4844.161461 -590.938877 +VL56 15756.176000 -8319.854400 73405.710000 +* 2023 12 11 17 30 0.00000000 +PL56 5452.011599 4608.349023 732.984413 +VL56 5021.387400 -17759.666000 73266.822000 +* 2023 12 11 17 33 0.00000000 +PL56 5442.350903 4210.214655 2031.269321 +VL56 -6129.726600 -26300.721000 70564.929000 +* 2023 12 11 17 36 0.00000000 +PL56 5231.356418 3668.762854 3258.487325 +VL56 -17278.105000 -33637.018000 65393.715000 +* 2023 12 11 17 39 0.00000000 +PL56 4822.912814 3008.034609 4371.707577 +VL56 -27997.942000 -39516.756000 57936.045000 +* 2023 12 11 17 42 0.00000000 +PL56 4228.497657 2256.043075 5332.037152 +VL56 -37874.245000 -43751.687000 48456.100000 +* 2023 12 11 17 45 0.00000000 +PL56 3466.838067 1443.573650 6105.995286 +VL56 -46519.158000 -46222.639000 37289.093000 +* 2023 12 11 17 48 0.00000000 +PL56 2563.276480 602.906237 6666.672866 +VL56 -53587.828000 -46882.940000 24827.785000 +* 2023 12 11 17 51 0.00000000 +PL56 1548.884928 -233.480777 6994.636807 +VL56 -58790.557000 -45756.934000 11507.560000 +* 2023 12 11 17 54 0.00000000 +PL56 459.366871 -1034.168624 7078.572047 +VL56 -61904.051000 -42937.247000 -2207.670400 +* 2023 12 11 17 57 0.00000000 +PL56 -666.220380 -1769.980857 6915.646929 +VL56 -62780.211000 -38579.325000 -15841.804000 +* 2023 12 11 18 0 0.00000000 +PL56 -1786.876390 -2415.048267 6511.591751 +VL56 -61351.950000 -32893.704000 -28922.309000 +* 2023 12 11 18 3 0.00000000 +PL56 -2861.151422 -2947.719443 5880.496158 +VL56 -57636.805000 -26136.853000 -40995.217000 +* 2023 12 11 18 6 0.00000000 +PL56 -3848.682872 -3351.294239 5044.341521 +VL56 -51738.151000 -18600.677000 -51640.187000 +* 2023 12 11 18 9 0.00000000 +PL56 -4711.732939 -3614.559469 4032.260002 +VL56 -43843.537000 -10600.800000 -60485.501000 +* 2023 12 11 18 12 0.00000000 +PL56 -5416.655702 -3732.099713 2879.534115 +VL56 -34218.886000 -2463.618700 -67221.532000 +* 2023 12 11 18 15 0.00000000 +PL56 -5935.236839 -3704.373981 1626.373511 +VL56 -23200.136000 5486.734100 -71612.259000 +* 2023 12 11 18 18 0.00000000 +PL56 -6245.849402 -3537.554604 316.499722 +VL56 -11180.982000 12941.803000 -73504.817000 +* 2023 12 11 18 21 0.00000000 +PL56 -6334.364360 -3243.129666 -1004.409857 +VL56 1401.909400 19621.420000 -72835.459000 +* 2023 12 11 18 24 0.00000000 +PL56 -6194.770272 -2837.288983 -2290.354715 +VL56 14086.290000 25285.085000 -69632.092000 +* 2023 12 11 18 27 0.00000000 +PL56 -5829.466614 -2340.123180 -3496.649621 +VL56 26402.926000 29741.175000 -64012.291000 +* 2023 12 11 18 30 0.00000000 +PL56 -5249.223932 -1774.681366 -4581.493746 +VL56 37893.968000 32853.462000 -56177.779000 +* 2023 12 11 18 33 0.00000000 +PL56 -4472.821787 -1165.936366 -5507.411966 +VL56 48130.153000 34544.814000 -46405.812000 +* 2023 12 11 18 36 0.00000000 +PL56 -3526.387423 -539.706886 -6242.518763 +VL56 56726.770000 34798.318000 -35038.168000 +* 2023 12 11 18 39 0.00000000 +PL56 -2442.470132 78.414567 -6761.564572 +VL56 63357.010000 33655.548000 -22468.184000 +* 2023 12 11 18 42 0.00000000 +PL56 -1258.896946 664.081625 -7046.742571 +VL56 67762.891000 31212.543000 -9127.173100 +* 2023 12 11 18 45 0.00000000 +PL56 -17.454167 1195.125046 -7088.246894 +VL56 69763.642000 27614.112000 4529.504600 +* 2023 12 11 18 48 0.00000000 +PL56 1237.561214 1652.369264 -6884.580825 +VL56 69261.925000 23046.771000 18036.241000 +* 2023 12 11 18 51 0.00000000 +PL56 2460.886892 2020.312180 -6442.618418 +VL56 66248.453000 17730.765000 30930.981000 +* 2023 12 11 18 54 0.00000000 +PL56 3607.901701 2287.650832 -5777.406750 +VL56 60803.884000 11910.842000 42770.071000 +* 2023 12 11 18 57 0.00000000 +PL56 4636.240279 2447.634038 -4911.707308 +VL56 53097.808000 5846.289600 53142.309000 +* 2023 12 11 19 0 0.00000000 +PL56 5507.370207 2498.232240 -3875.283350 +VL56 43385.629000 -199.362060 61683.347000 +* 2023 12 11 19 3 0.00000000 +PL56 6188.075114 2442.115357 -2703.933760 +VL56 32001.135000 -5969.272700 68089.089000 +* 2023 12 11 19 6 0.00000000 +PL56 6651.779995 2286.435342 -1438.294888 +VL56 19346.442000 -11224.045000 72127.992000 +* 2023 12 11 19 9 0.00000000 +PL56 6879.655107 2042.417703 -122.437088 +VL56 5877.446900 -15752.127000 73651.475000 +* 2023 12 11 19 12 0.00000000 +PL56 6861.433646 1724.774709 1197.694499 +VL56 -7913.532800 -19379.082000 72600.725000 +* 2023 12 11 19 15 0.00000000 +PL56 6595.894360 1350.967575 2475.927895 +VL56 -21517.024000 -21974.949000 69009.559000 +* 2023 12 11 19 18 0.00000000 +PL56 6090.985406 940.353810 3667.533524 +VL56 -34427.226000 -23459.686000 63003.838000 +* 2023 12 11 19 21 0.00000000 +PL56 5363.572458 513.261079 4730.840015 +VL56 -46162.503000 -23805.795000 54796.372000 +* 2023 12 11 19 24 0.00000000 +PL56 4438.828321 90.038127 5628.721297 +VL56 -56284.372000 -23038.175000 44677.691000 +* 2023 12 11 19 27 0.00000000 +PL56 3349.301425 -309.870552 6329.900130 +VL56 -64414.398000 -21231.732000 33004.826000 +* 2023 12 11 19 30 0.00000000 +PL56 2133.707843 -668.782435 6810.020298 +VL56 -70247.677000 -18506.372000 20187.467000 +EOF From 1c36a01c400847a4c59f81c3c14c19fa7858627b Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Mon, 25 Dec 2023 10:33:51 +0100 Subject: [PATCH 065/359] Changed NSGF test to check filtering can be mixed with other filters. --- .../orekit/files/sp3/NsgfV00FilterTest.java | 4 +- .../resources/sp3/nsgf.orb.stella.v00.sp3 | 5517 ----------------- .../resources/sp3/nsgf.orb.stella.v00.sp3.gz | Bin 0 -> 4916 bytes 3 files changed, 3 insertions(+), 5518 deletions(-) delete mode 100644 src/test/resources/sp3/nsgf.orb.stella.v00.sp3 create mode 100644 src/test/resources/sp3/nsgf.orb.stella.v00.sp3.gz diff --git a/src/test/java/org/orekit/files/sp3/NsgfV00FilterTest.java b/src/test/java/org/orekit/files/sp3/NsgfV00FilterTest.java index 1ad6fb3686..729ff629eb 100644 --- a/src/test/java/org/orekit/files/sp3/NsgfV00FilterTest.java +++ b/src/test/java/org/orekit/files/sp3/NsgfV00FilterTest.java @@ -24,6 +24,7 @@ import org.orekit.Utils; import org.orekit.data.DataSource; import org.orekit.data.FiltersManager; +import org.orekit.data.GzipFilter; import org.orekit.frames.Frame; import org.orekit.frames.FramesFactory; import org.orekit.utils.Constants; @@ -33,7 +34,7 @@ public class NsgfV00FilterTest { @Test public void testFiltered() throws IOException { - doTestFilter("/sp3/nsgf.orb.stella.v00.sp3", "L56", 1831); + doTestFilter("/sp3/nsgf.orb.stella.v00.sp3.gz", "L56", 100); } @Test @@ -48,6 +49,7 @@ private void doTestFilter(final String name, final String id, final int... nbCoo final FiltersManager manager = new FiltersManager(); manager.addFilter(new NsgfV00Filter()); + manager.addFilter(new GzipFilter()); final SP3 file = parser.parse(manager.applyRelevantFilters(original)); for (int i = 0; i < nbCoords.length; ++i) { diff --git a/src/test/resources/sp3/nsgf.orb.stella.v00.sp3 b/src/test/resources/sp3/nsgf.orb.stella.v00.sp3 deleted file mode 100644 index b4e68bd3fa..0000000000 --- a/src/test/resources/sp3/nsgf.orb.stella.v00.sp3 +++ /dev/null @@ -1,5517 +0,0 @@ -#cV2023 12 8 0 0 0.00000000 1831 SLR ECF FIT NSGF -## 2291 432000.00000000 180.00000000 60286 0.0000000000000 -+ 1 L56 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -++ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -++ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -++ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -++ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -++ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -%c L cc UTC ccc cccc cccc cccc cccc ccccc ccccc ccccc ccccc -%c cc cc ccc ccc cccc cccc cccc cccc ccccc ccccc ccccc ccccc -%f 0.0000000 0.000000000 0.00000000000 0.000000000000000 -%f 0.0000000 0.000000000 0.00000000000 0.000000000000000 -%i 0 0 0 0 0 0 0 0 0 -%i 0 0 0 0 0 0 0 0 0 -/* -/* Earth-centered-fixed orbital predictions from SGF ILRS AC -/* The underlying ECF frame is that of IERS/ITRF -/* Note: Solution based on 4-day long arc -/* -* 2023 12 8 0 0 0.00000000 -PL56 2447.693398 -1850.426620 -6499.605162 -VL56 32349.234000 -61096.609000 29639.195000 -* 2023 12 8 0 3 0.00000000 -PL56 2970.413679 -2919.143105 -5856.583173 -VL56 25579.191000 -57277.328000 41603.486000 -* 2023 12 8 0 6 0.00000000 -PL56 3363.975044 -3899.384139 -5010.442600 -VL56 18048.401000 -51289.767000 52142.155000 -* 2023 12 8 0 9 0.00000000 -PL56 3617.452805 -4753.649361 -3990.247045 -VL56 10067.462000 -43317.275000 60885.873000 -* 2023 12 8 0 12 0.00000000 -PL56 3725.637016 -5448.452940 -2831.199630 -VL56 1958.732800 -33621.656000 67523.916000 -* 2023 12 8 0 15 0.00000000 -PL56 3689.132971 -5955.677768 -1573.473615 -VL56 -5956.190700 -22536.108000 71816.766000 -* 2023 12 8 0 18 0.00000000 -PL56 3514.228021 -6253.763157 -260.832034 -VL56 -13369.740000 -10453.774000 73606.609000 -* 2023 12 8 0 21 0.00000000 -PL56 3212.522882 -6328.659872 1060.915139 -VL56 -20001.203000 2186.595300 72824.699000 -* 2023 12 8 0 24 0.00000000 -PL56 2800.339802 -6174.497858 2345.552918 -VL56 -25608.474000 14917.947000 69495.133000 -* 2023 12 8 0 27 0.00000000 -PL56 2297.935631 -5793.926051 3548.133425 -VL56 -29997.976000 27264.085000 63734.132000 -* 2023 12 8 0 30 0.00000000 -PL56 1728.557307 -5198.103524 4626.596695 -VL56 -33032.031000 38758.871000 55745.154000 -* 2023 12 8 0 33 0.00000000 -PL56 1117.392879 -4406.350206 5543.272722 -VL56 -34633.099000 48964.614000 45810.868000 -* 2023 12 8 0 36 0.00000000 -PL56 490.469813 -3445.474326 6266.209414 -VL56 -34785.485000 57489.649000 34281.905000 -* 2023 12 8 0 39 0.00000000 -PL56 -126.449387 -2348.807655 6770.274302 -VL56 -33533.855000 64003.026000 21562.969000 -* 2023 12 8 0 42 0.00000000 -PL56 -708.920796 -1155.002544 7037.996243 -VL56 -30979.190000 68246.274000 8098.116900 -* 2023 12 8 0 45 0.00000000 -PL56 -1234.781426 93.358984 7060.140515 -VL56 -27272.795000 70042.597000 -5644.155300 -* 2023 12 8 0 48 0.00000000 -PL56 -1684.989186 1351.302032 6836.006301 -VL56 -22608.758000 69303.778000 -19186.734000 -* 2023 12 8 0 51 0.00000000 -PL56 -2044.312373 2573.087972 6373.439409 -VL56 -17214.778000 66033.562000 -32059.750000 -* 2023 12 8 0 54 0.00000000 -PL56 -2301.847381 3713.883888 5688.564579 -VL56 -11342.289000 60328.712000 -43815.753000 -* 2023 12 8 0 57 0.00000000 -PL56 -2451.349383 4731.420873 4805.243489 -VL56 -5255.688400 52376.742000 -54044.963000 -* 2023 12 8 1 0 0.00000000 -PL56 -2491.366957 5587.587104 3754.267586 -VL56 778.721130 42450.832000 -62389.507000 -* 2023 12 8 1 3 0.00000000 -PL56 -2425.173963 6249.893878 2572.298614 -VL56 6504.058400 30900.868000 -68557.072000 -* 2023 12 8 1 6 0.00000000 -PL56 -2260.500460 6692.748305 1300.587212 -VL56 11683.833000 18140.850000 -72331.796000 -* 2023 12 8 1 9 0.00000000 -PL56 -2009.073282 6898.475494 -16.485585 -VL56 16112.038000 4633.712300 -73582.821000 -* 2023 12 8 1 12 0.00000000 -PL56 -1685.987241 6858.040391 -1332.990294 -VL56 19621.752000 -9126.613400 -72269.580000 -* 2023 12 8 1 15 0.00000000 -PL56 -1308.937468 6571.430128 -2603.095177 -VL56 22091.959000 -22635.179000 -68443.407000 -* 2023 12 8 1 18 0.00000000 -PL56 -897.350090 6047.666282 -3782.697826 -VL56 23451.741000 -35396.211000 -62244.125000 -* 2023 12 8 1 21 0.00000000 -PL56 -471.462151 5304.466157 -4830.962735 -VL56 23681.992000 -46942.262000 -53893.682000 -* 2023 12 8 1 24 0.00000000 -PL56 -51.395433 4367.582157 -5711.718181 -VL56 22814.345000 -56850.784000 -43686.586000 -* 2023 12 8 1 27 0.00000000 -PL56 343.736126 3269.852884 -6394.666441 -VL56 20928.442000 -64759.222000 -31978.873000 -* 2023 12 8 1 30 0.00000000 -PL56 696.646608 2050.009348 -6856.372398 -VL56 18146.766000 -70377.153000 -19174.769000 -* 2023 12 8 1 33 0.00000000 -PL56 992.592418 751.291754 -7081.007819 -VL56 14628.131000 -73495.248000 -5712.978600 -* 2023 12 8 1 36 0.00000000 -PL56 1219.958089 -580.072050 -7060.847680 -VL56 10559.950000 -73991.771000 7947.211700 -* 2023 12 8 1 39 0.00000000 -PL56 1370.695792 -1896.483495 -6796.512576 -VL56 6149.704700 -71836.567000 21340.194000 -* 2023 12 8 1 42 0.00000000 -PL56 1440.606420 -3150.636521 -6296.956172 -VL56 1616.038600 -67092.382000 34007.931000 -* 2023 12 8 1 45 0.00000000 -PL56 1429.457204 -4297.188304 -5579.204666 -VL56 -2820.561800 -59914.352000 45513.922000 -* 2023 12 8 1 48 0.00000000 -PL56 1340.929004 -5294.397694 -4667.837335 -VL56 -6947.286700 -50546.553000 55457.844000 -* 2023 12 8 1 51 0.00000000 -PL56 1182.394412 -6105.669292 -3594.209646 -VL56 -10568.313000 -39315.363000 63489.370000 -* 2023 12 8 1 54 0.00000000 -PL56 964.530101 -6700.950525 -2395.431022 -VL56 -13513.753000 -26619.439000 69321.613000 -* 2023 12 8 1 57 0.00000000 -PL56 700.777266 -7057.917324 -1113.114166 -VL56 -15647.550000 -12916.300000 72742.933000 -* 2023 12 8 2 0 0.00000000 -PL56 406.670786 -7162.886867 208.069041 -VL56 -16874.092000 1294.503900 73626.373000 -* 2023 12 8 2 3 0.00000000 -PL56 99.065850 -7011.401588 1521.971964 -VL56 -17142.892000 15490.844000 71935.717000 -* 2023 12 8 2 6 0.00000000 -PL56 -204.699506 -6608.450633 2782.632663 -VL56 -16450.984000 29148.803000 67727.791000 -* 2023 12 8 2 9 0.00000000 -PL56 -487.663940 -5968.308132 3945.939502 -VL56 -14842.976000 41764.192000 61150.608000 -* 2023 12 8 2 12 0.00000000 -PL56 -734.079940 -5113.990962 4971.220317 -VL56 -12408.544000 52872.911000 52436.989000 -* 2023 12 8 2 15 0.00000000 -PL56 -930.186107 -4076.376489 5822.686972 -VL56 -9277.699500 62068.446000 41894.945000 -* 2023 12 8 2 18 0.00000000 -PL56 -1064.876676 -2893.024568 6470.687467 -VL56 -5614.289000 69017.111000 29896.049000 -* 2023 12 8 2 21 0.00000000 -PL56 -1130.238654 -1606.757420 6892.718507 -VL56 -1607.788900 73469.368000 16860.582000 -* 2023 12 8 2 24 0.00000000 -PL56 -1121.934969 -264.070205 7074.173315 -VL56 2535.482300 75267.712000 3243.160300 -* 2023 12 8 2 27 0.00000000 -PL56 -1039.423384 1086.572769 7008.819655 -VL56 6601.825200 74351.397000 -10482.943000 -* 2023 12 8 2 30 0.00000000 -PL56 -886.000567 2396.499498 6698.996079 -VL56 10380.038000 70758.119000 -23841.339000 -* 2023 12 8 2 33 0.00000000 -PL56 -668.668700 3618.591573 6155.525512 -VL56 13671.180000 64622.284000 -36368.315000 -* 2023 12 8 2 36 0.00000000 -PL56 -397.832326 4708.990178 5397.349006 -VL56 16297.631000 56170.610000 -47628.068000 -* 2023 12 8 2 39 0.00000000 -PL56 -86.835880 5628.692645 4450.886935 -VL56 18111.682000 45714.517000 -57227.780000 -* 2023 12 8 2 42 0.00000000 -PL56 248.641933 6344.984134 3349.138240 -VL56 19002.785000 33639.011000 -64831.570000 -* 2023 12 8 2 45 0.00000000 -PL56 591.311977 6832.646901 2130.544109 -VL56 18903.389000 20389.784000 -70172.542000 -* 2023 12 8 2 48 0.00000000 -PL56 923.089437 7074.901663 837.636576 -VL56 17793.143000 6455.710100 -73064.620000 -* 2023 12 8 2 51 0.00000000 -PL56 1225.960278 7064.012737 -484.476889 -VL56 15700.336000 -7650.895600 -73408.721000 -* 2023 12 8 2 54 0.00000000 -PL56 1482.855018 6801.536940 -1789.724326 -VL56 12701.241000 -21413.236000 -71196.922000 -* 2023 12 8 2 57 0.00000000 -PL56 1678.484337 6298.205937 -3032.709851 -VL56 8916.686600 -34331.718000 -66511.941000 -* 2023 12 8 3 0 0.00000000 -PL56 1800.097797 5573.453324 -4170.316448 -VL56 4506.889300 -45942.266000 -59523.309000 -* 2023 12 8 3 3 0.00000000 -PL56 1838.130977 4654.610240 -5163.206653 -VL56 -335.679000 -55834.093000 -50479.914000 -* 2023 12 8 3 6 0.00000000 -PL56 1786.710924 3575.814770 -5977.159956 -VL56 -5394.835700 -63663.757000 -39699.515000 -* 2023 12 8 3 9 0.00000000 -PL56 1643.999700 2376.697017 -6584.205902 -VL56 -10440.053000 -69166.011000 -27556.640000 -* 2023 12 8 3 12 0.00000000 -PL56 1412.364505 1100.898353 -6963.526396 -VL56 -15236.228000 -72161.331000 -14469.201000 -* 2023 12 8 3 15 0.00000000 -PL56 1098.372660 -205.513704 -7102.112663 -VL56 -19553.408000 -72560.183000 -884.710080 -* 2023 12 8 3 18 0.00000000 -PL56 712.611056 -1495.685383 -6995.172425 -VL56 -23176.532000 -70364.843000 12733.811000 -* 2023 12 8 3 21 0.00000000 -PL56 269.335483 -2723.621414 -6646.281268 -VL56 -25914.454000 -65668.000000 25921.891000 -* 2023 12 8 3 24 0.00000000 -PL56 -214.038643 -3845.790631 -6067.285463 -VL56 -27608.649000 -58650.107000 38227.440000 -* 2023 12 8 3 27 0.00000000 -PL56 -717.594780 -4822.658120 -5277.949367 -VL56 -28140.923000 -49573.562000 49225.126000 -* 2023 12 8 3 30 0.00000000 -PL56 -1219.702365 -5620.092955 -4305.344888 -VL56 -27440.033000 -38774.836000 58530.679000 -* 2023 12 8 3 33 0.00000000 -PL56 -1697.910771 -6210.606049 -3182.987921 -VL56 -25486.790000 -26653.389000 65814.670000 -* 2023 12 8 3 36 0.00000000 -PL56 -2129.916742 -6574.364088 -1949.731974 -VL56 -22317.062000 -13657.873000 70815.434000 -* 2023 12 8 3 39 0.00000000 -PL56 -2494.564176 -6699.931077 -648.445714 -VL56 -18022.313000 -269.740930 73350.192000 -* 2023 12 8 3 42 0.00000000 -PL56 -2772.829430 -6584.693381 675.488055 -VL56 -12747.420000 13015.487000 73323.517000 -* 2023 12 8 3 45 0.00000000 -PL56 -2948.741807 -6234.933873 1975.793784 -VL56 -6685.653400 25708.191000 70732.092000 -* 2023 12 8 3 48 0.00000000 -PL56 -3010.189648 -5665.545117 3206.974057 -VL56 -71.045433 37344.619000 65665.438000 -* 2023 12 8 3 51 0.00000000 -PL56 -2949.568223 -4899.393410 4325.954466 -VL56 6831.445100 47505.463000 58302.330000 -* 2023 12 8 3 54 0.00000000 -PL56 -2764.236688 -3966.368907 5293.628830 -VL56 13737.178000 55832.054000 48903.415000 -* 2023 12 8 3 57 0.00000000 -PL56 -2456.765118 -2902.171667 6076.243079 -VL56 20353.890000 62039.433000 37800.733000 -* 2023 12 8 4 0 0.00000000 -PL56 -2034.958864 -1746.894725 6646.565890 -VL56 26394.178000 65925.618000 25384.677000 -* 2023 12 8 4 3 0.00000000 -PL56 -1511.662488 -543.474210 6984.813135 -VL56 31587.483000 67377.424000 12089.834000 -* 2023 12 8 4 6 0.00000000 -PL56 -904.354769 663.934995 7079.302121 -VL56 35691.186000 66372.635000 -1620.848400 -* 2023 12 8 4 9 0.00000000 -PL56 -234.553688 1831.591012 6926.825563 -VL56 38500.778000 62979.033000 -15271.157000 -* 2023 12 8 4 12 0.00000000 -PL56 472.953691 2917.755428 6532.748543 -VL56 39858.939000 57350.600000 -28387.432000 -* 2023 12 8 4 15 0.00000000 -PL56 1191.032004 3884.191730 5910.821619 -VL56 39663.123000 49721.103000 -40514.200000 -* 2023 12 8 4 18 0.00000000 -PL56 1891.236561 4697.524795 5082.717573 -VL56 37871.203000 40395.249000 -51229.196000 -* 2023 12 8 4 21 0.00000000 -PL56 2544.937678 5330.419242 4077.298692 -VL56 34505.188000 29737.331000 -60158.239000 -* 2023 12 8 4 24 0.00000000 -PL56 3124.489309 5762.530292 2929.629470 -VL56 29652.315000 18157.351000 -66988.452000 -* 2023 12 8 4 27 0.00000000 -PL56 3604.395171 5981.194224 1679.760417 -VL56 23463.714000 6096.010600 -71480.580000 -* 2023 12 8 4 30 0.00000000 -PL56 3962.417460 5981.818244 371.310862 -VL56 16149.233000 -5993.627000 -73478.656000 -* 2023 12 8 4 33 0.00000000 -PL56 4180.570815 5767.945868 -950.085678 -VL56 7970.011900 -17663.711000 -72915.571000 -* 2023 12 8 4 36 0.00000000 -PL56 4245.956882 5350.997033 -2238.410874 -VL56 -771.716950 -28489.741000 -69815.684000 -* 2023 12 8 4 39 0.00000000 -PL56 4151.397602 4749.698875 -3448.896879 -VL56 -9744.783100 -38086.935000 -64293.060000 -* 2023 12 8 4 42 0.00000000 -PL56 3895.835703 3989.237393 -4539.600719 -VL56 -18602.594000 -46124.605000 -56546.271000 -* 2023 12 8 4 45 0.00000000 -PL56 3484.487856 3100.177306 -5472.850851 -VL56 -26996.888000 -52337.386000 -46849.721000 -* 2023 12 8 4 48 0.00000000 -PL56 2928.751024 2117.207887 -6216.517216 -VL56 -34591.467000 -56533.424000 -35542.717000 -* 2023 12 8 4 51 0.00000000 -PL56 2245.869652 1077.773028 -6745.066216 -VL56 -41074.873000 -58599.025000 -23016.625000 -* 2023 12 8 4 54 0.00000000 -PL56 1458.383744 20.646092 -7040.375914 -VL56 -46171.898000 -58500.134000 -9701.345200 -* 2023 12 8 4 57 0.00000000 -PL56 593.382885 -1015.496689 -7092.305431 -VL56 -49653.915000 -56281.279000 3948.515200 -* 2023 12 8 5 0 0.00000000 -PL56 -318.414951 -1993.463478 -6899.013108 -VL56 -51347.723000 -52062.066000 17467.851000 -* 2023 12 8 5 3 0.00000000 -PL56 -1243.729753 -2878.851904 -6467.020489 -VL56 -51142.983000 -46031.817000 30394.835000 -* 2023 12 8 5 6 0.00000000 -PL56 -2147.905849 -3641.243387 -5811.024759 -VL56 -48997.962000 -38442.471000 42285.254000 -* 2023 12 8 5 9 0.00000000 -PL56 -2996.185329 -4255.251604 -4953.454558 -VL56 -44943.568000 -29599.655000 52726.616000 -* 2023 12 8 5 12 0.00000000 -PL56 -3755.035185 -4701.395304 -3923.771974 -VL56 -39085.076000 -19851.884000 61352.341000 -* 2023 12 8 5 15 0.00000000 -PL56 -4393.480673 -4966.758619 -2757.519788 -VL56 -31600.982000 -9577.839800 67855.517000 -* 2023 12 8 5 18 0.00000000 -PL56 -4884.388932 -5045.406715 -1495.134472 -VL56 -22738.666000 827.995380 72001.223000 -* 2023 12 8 5 21 0.00000000 -PL56 -5205.644170 -4938.531729 -180.554590 -VL56 -12806.619000 10970.861000 73636.746000 -* 2023 12 8 5 24 0.00000000 -PL56 -5341.152902 -4654.314730 1140.328612 -VL56 -2163.398900 20471.622000 72698.758000 -* 2023 12 8 5 27 0.00000000 -PL56 -5281.623238 -4207.502216 2421.319251 -VL56 8796.372000 28982.458000 69216.959000 -* 2023 12 8 5 30 0.00000000 -PL56 -5025.071199 -3618.711032 3617.588955 -VL56 19658.107000 36201.110000 63313.084000 -* 2023 12 8 5 33 0.00000000 -PL56 -4577.028288 -2913.499071 4687.295069 -VL56 30004.201000 41882.552000 55196.011000 -* 2023 12 8 5 36 0.00000000 -PL56 -3950.440236 -2121.249899 5593.076501 -VL56 39431.247000 45847.914000 45153.048000 -* 2023 12 8 5 39 0.00000000 -PL56 -3165.267377 -1273.931236 6303.363878 -VL56 47565.777000 47989.537000 33538.377000 -* 2023 12 8 5 42 0.00000000 -PL56 -2247.811713 -404.787931 6793.468121 -VL56 54078.957000 48273.314000 20759.930000 -* 2023 12 8 5 45 0.00000000 -PL56 -1229.794562 452.978796 7046.412212 -VL56 58699.394000 46737.752000 7264.032500 -* 2023 12 8 5 48 0.00000000 -PL56 -147.229610 1267.484680 7053.483971 -VL56 61223.015000 43489.861000 -6479.863400 -* 2023 12 8 5 51 0.00000000 -PL56 960.865253 2009.348251 6814.513140 -VL56 61521.237000 38699.547000 -19994.716000 -* 2023 12 8 5 54 0.00000000 -PL56 2053.881240 2652.753585 6337.866313 -VL56 59546.638000 32591.597000 -32811.639000 -* 2023 12 8 5 57 0.00000000 -PL56 3091.111090 3176.353104 5640.161694 -VL56 55336.024000 25436.023000 -44485.200000 -* 2023 12 8 6 0 0.00000000 -PL56 4033.275299 3563.986304 4745.711461 -VL56 49011.024000 17537.188000 -54608.461000 -* 2023 12 8 6 3 0.00000000 -PL56 4844.027517 3805.189235 3685.695964 -VL56 40775.207000 9221.567000 -62827.433000 -* 2023 12 8 6 6 0.00000000 -PL56 5491.384932 3895.476785 2497.093980 -VL56 30908.561000 824.726810 -68854.043000 -* 2023 12 8 6 9 0.00000000 -PL56 5949.021155 3836.381552 1221.387475 -VL56 19757.772000 -7322.507900 -72477.514000 -* 2023 12 8 6 12 0.00000000 -PL56 6197.355471 3635.245331 -96.907967 -VL56 7723.292400 -14907.715000 -73572.694000 -* 2023 12 8 6 15 0.00000000 -PL56 6224.386426 3304.772369 -1411.833519 -VL56 -4756.038000 -21649.570000 -72104.895000 -* 2023 12 8 6 18 0.00000000 -PL56 6026.226098 2862.365336 -2677.627587 -VL56 -17220.559000 -27309.006000 -68130.536000 -* 2023 12 8 6 21 0.00000000 -PL56 5607.312602 2329.282297 -3850.346085 -VL56 -29207.826000 -31697.982000 -61794.361000 -* 2023 12 8 6 24 0.00000000 -PL56 4980.297220 1729.656926 -4889.398654 -VL56 -40270.662000 -34685.848000 -53322.926000 -* 2023 12 8 6 27 0.00000000 -PL56 4165.613196 1089.429569 -5758.939976 -VL56 -49994.259000 -36202.797000 -43014.978000 -* 2023 12 8 6 30 0.00000000 -PL56 3190.756851 435.245410 -6429.064116 -VL56 -58010.940000 -36240.175000 -31229.666000 -* 2023 12 8 6 33 0.00000000 -PL56 2089.320676 -206.631044 -6876.776787 -VL56 -64012.945000 -34848.406000 -18373.574000 -* 2023 12 8 6 36 0.00000000 -PL56 899.819929 -811.344333 -7086.725206 -VL56 -67762.573000 -32132.775000 -4886.883200 -* 2023 12 8 6 39 0.00000000 -PL56 -335.645177 -1356.385524 -7051.680370 -VL56 -69100.392000 -28247.586000 8770.352100 -* 2023 12 8 6 42 0.00000000 -PL56 -1572.853455 -1822.408711 -6772.764809 -VL56 -67950.937000 -23388.700000 22132.488000 -* 2023 12 8 6 45 0.00000000 -PL56 -2767.011138 -2193.906277 -6259.428112 -VL56 -64326.475000 -17785.232000 34742.409000 -* 2023 12 8 6 48 0.00000000 -PL56 -3874.344167 -2459.724354 -5529.166638 -VL56 -58328.006000 -11690.186000 46165.441000 -* 2023 12 8 6 51 0.00000000 -PL56 -4853.693205 -2613.405201 -4606.991415 -VL56 -50144.670000 -5370.638400 56003.670000 -* 2023 12 8 6 54 0.00000000 -PL56 -5668.063719 -2653.343479 -3524.638429 -VL56 -40049.132000 903.141870 63910.092000 -* 2023 12 8 6 57 0.00000000 -PL56 -6286.068144 -2582.745294 -2319.530945 -VL56 -28390.120000 6868.695500 69601.919000 -* 2023 12 8 7 0 0.00000000 -PL56 -6683.196905 -2409.386753 -1033.514968 -VL56 -15580.935000 12282.509000 72872.301000 -* 2023 12 8 7 3 0.00000000 -PL56 -6842.852871 -2145.177860 288.594941 -VL56 -2084.683700 16930.450000 73599.538000 -* 2023 12 8 7 6 0.00000000 -PL56 -6757.091357 -1805.547501 1600.607658 -VL56 11603.524000 20637.089000 71753.073000 -* 2023 12 8 7 9 0.00000000 -PL56 -6427.019228 -1408.676828 2856.620436 -VL56 24976.503000 23273.081000 67395.451000 -* 2023 12 8 7 12 0.00000000 -PL56 -5862.825959 -974.620025 4012.680352 -VL56 37535.665000 24760.295000 60680.065000 -* 2023 12 8 7 15 0.00000000 -PL56 -5083.445923 -524.356371 5028.368898 -VL56 48811.287000 25074.259000 51844.827000 -* 2023 12 8 7 18 0.00000000 -PL56 -4115.869542 -78.823589 5868.237123 -VL56 58380.743000 24243.779000 41202.141000 -* 2023 12 8 7 21 0.00000000 -PL56 -2994.150518 342.019674 6503.040902 -VL56 65884.269000 22348.157000 29126.804000 -* 2023 12 8 7 24 0.00000000 -PL56 -1758.150375 720.059955 6910.740422 -VL56 71038.218000 19512.095000 16042.114000 -* 2023 12 8 7 27 0.00000000 -PL56 -452.077119 1039.785991 7077.234722 -VL56 73644.729000 15898.807000 2404.241400 -* 2023 12 8 7 30 0.00000000 -PL56 877.121964 1288.911304 6996.817689 -VL56 73598.096000 11701.917000 -11312.874000 -* 2023 12 8 7 33 0.00000000 -PL56 2181.457689 1458.840984 6672.354082 -VL56 70888.580000 7136.391600 -24633.377000 -* 2023 12 8 7 36 0.00000000 -PL56 3413.636348 1544.968249 6115.175812 -VL56 65603.115000 2428.718900 -37094.918000 -* 2023 12 8 7 39 0.00000000 -PL56 4528.785044 1546.791317 5344.700503 -VL56 57923.097000 -2193.175300 -48264.013000 -* 2023 12 8 7 42 0.00000000 -PL56 5486.106386 1467.848088 4387.776828 -VL56 48118.813000 -6510.006200 -57750.795000 -* 2023 12 8 7 45 0.00000000 -PL56 6250.408389 1315.472787 3277.772746 -VL56 36541.071000 -10320.823000 -65223.118000 -* 2023 12 8 7 48 0.00000000 -PL56 6793.444946 1100.382287 2053.417575 -VL56 23608.448000 -13452.184000 -70419.286000 -* 2023 12 8 7 51 0.00000000 -PL56 7095.002782 836.108527 757.441413 -VL56 9792.047000 -15765.913000 -73157.954000 -* 2023 12 8 7 54 0.00000000 -PL56 7143.685838 538.304718 -564.943185 -VL56 -4402.669900 -17165.333000 -73345.481000 -* 2023 12 8 7 57 0.00000000 -PL56 6937.354646 223.957498 -1867.657170 -VL56 -18456.134000 -17599.496000 -70979.546000 -* 2023 12 8 8 0 0.00000000 -PL56 6483.196377 -89.455610 -3105.398289 -VL56 -31855.093000 -17064.951000 -66148.383000 -* 2023 12 8 8 3 0.00000000 -PL56 5797.429385 -384.820898 -4235.239626 -VL56 -44112.497000 -15605.251000 -59026.641000 -* 2023 12 8 8 6 0.00000000 -PL56 4904.661730 -646.211735 -5218.120357 -VL56 -54786.046000 -13308.059000 -49867.673000 -* 2023 12 8 8 9 0.00000000 -PL56 3836.942521 -859.640307 -6020.169842 -VL56 -63493.599000 -10300.205000 -38992.933000 -* 2023 12 8 8 12 0.00000000 -PL56 2632.560891 -1013.708053 -6613.827721 -VL56 -69925.836000 -6741.367500 -26779.935000 -* 2023 12 8 8 15 0.00000000 -PL56 1334.643812 -1100.128823 -6978.732670 -VL56 -73855.842000 -2816.319500 -13648.770000 -* 2023 12 8 8 18 0.00000000 -PL56 -10.388631 -1114.105704 -7102.364821 -VL56 -75145.498000 1273.447100 -48.328547 -* 2023 12 8 8 21 0.00000000 -PL56 -1354.460972 -1054.551873 -6980.438320 -VL56 -73749.406000 5318.712600 13557.759000 -* 2023 12 8 8 24 0.00000000 -PL56 -2649.526094 -924.148270 -6617.040572 -VL56 -69716.129000 9111.612600 26705.124000 -* 2023 12 8 8 27 0.00000000 -PL56 -3849.249363 -729.235962 -6024.515151 -VL56 -63186.972000 12454.810000 38943.094000 -* 2023 12 8 8 30 0.00000000 -PL56 -4910.647359 -479.546542 -5223.093050 -VL56 -54392.238000 15170.369000 49848.413000 -* 2023 12 8 8 33 0.00000000 -PL56 -5795.640604 -187.777101 -4240.268477 -VL56 -43645.102000 17108.052000 59039.595000 -* 2023 12 8 8 36 0.00000000 -PL56 -6472.463332 130.977777 -3109.921275 -VL56 -31332.096000 18152.883000 66190.866000 -* 2023 12 8 8 39 0.00000000 -PL56 -6916.874052 459.919367 -1871.197128 -VL56 -17900.309000 18231.410000 71044.916000 -* 2023 12 8 8 42 0.00000000 -PL56 -7113.105620 781.336504 -567.171412 -VL56 -3841.325300 17316.255000 73424.089000 -* 2023 12 8 8 45 0.00000000 -PL56 -7054.499609 1077.459101 756.664648 -VL56 10327.802000 15428.457000 73238.699000 -* 2023 12 8 8 48 0.00000000 -PL56 -6743.778921 1331.331326 2054.030892 -VL56 24085.142000 12637.242000 70491.198000 -* 2023 12 8 8 51 0.00000000 -PL56 -6192.947085 1527.660789 3279.528073 -VL56 36924.984000 9057.541300 65276.741000 -* 2023 12 8 8 54 0.00000000 -PL56 -5422.810311 1653.598510 4390.281157 -VL56 48378.282000 4844.892100 57779.611000 -* 2023 12 8 8 57 0.00000000 -PL56 -4462.145888 1699.408652 5347.477124 -VL56 58031.173000 188.343330 48265.312000 -* 2023 12 8 9 0 0.00000000 -PL56 -3346.568697 1658.996318 6117.733686 -VL56 65540.050000 -4698.127400 37069.819000 -* 2023 12 8 9 3 0.00000000 -PL56 -2117.154288 1530.271001 6674.256615 -VL56 70643.590000 -9585.230500 24586.839000 -* 2023 12 8 9 6 0.00000000 -PL56 -818.874871 1315.330691 6997.749064 -VL56 73171.169000 -14238.652000 11253.063000 -* 2023 12 8 9 9 0.00000000 -PL56 501.080350 1020.459096 7077.044877 -VL56 73047.459000 -18429.306000 -2467.282400 -* 2023 12 8 9 12 0.00000000 -PL56 1795.033491 655.938771 6909.464793 -VL56 70293.554000 -21943.587000 -16098.022000 -* 2023 12 8 9 15 0.00000000 -PL56 3016.544158 235.687358 6500.894735 -VL56 65025.339000 -24592.763000 -29166.258000 -* 2023 12 8 9 18 0.00000000 -PL56 4122.082557 -223.272250 5865.585574 -VL56 57449.362000 -26221.923000 -41218.014000 -* 2023 12 8 9 21 0.00000000 -PL56 5072.597724 -701.491761 5025.674261 -VL56 47855.246000 -26717.673000 -51833.514000 -* 2023 12 8 9 24 0.00000000 -PL56 5834.926070 -1177.903949 4010.435247 -VL56 36605.577000 -26014.430000 -60641.863000 -* 2023 12 8 9 27 0.00000000 -PL56 6382.989927 -1630.725313 2855.277714 -VL56 24122.641000 -24098.719000 -67334.483000 -* 2023 12 8 9 30 0.00000000 -PL56 6698.734566 -2038.417820 1600.512362 -VL56 10872.725000 -21011.428000 -71677.033000 -* 2023 12 8 9 33 0.00000000 -PL56 6772.757745 -2380.665692 289.928962 -VL56 -2652.130100 -16847.252000 -73518.589000 -* 2023 12 8 9 36 0.00000000 -PL56 6604.600775 -2639.321914 -1030.763732 -VL56 -15953.617000 -11751.693000 -72797.647000 -* 2023 12 8 9 39 0.00000000 -PL56 6202.682995 -2799.275150 -2315.572840 -VL56 -28546.942000 -5915.410300 -69544.127000 -* 2023 12 8 9 42 0.00000000 -PL56 5583.883092 -2849.194253 -3519.857663 -VL56 -39979.925000 433.713610 -63877.644000 -* 2023 12 8 9 45 0.00000000 -PL56 4772.795883 -2782.114154 -4601.896015 -VL56 -49850.001000 7040.133300 -56001.686000 -* 2023 12 8 9 48 0.00000000 -PL56 3800.708783 -2595.840347 -5524.321740 -VL56 -57818.301000 13631.190000 -46195.082000 -* 2023 12 8 9 51 0.00000000 -PL56 2704.348445 -2293.155276 -6255.381355 -VL56 -63620.780000 19928.417000 -34800.569000 -* 2023 12 8 9 54 0.00000000 -PL56 1524.465806 -1881.822712 -6769.972268 -VL56 -67075.313000 25658.621000 -22212.309000 -* 2023 12 8 9 57 0.00000000 -PL56 304.316336 -1374.393710 -7050.448988 -VL56 -68086.255000 30564.873000 -8862.295200 -* 2023 12 8 10 0 0.00000000 -PL56 -911.912394 -787.822257 -7087.177455 -VL56 -66645.649000 34416.498000 4793.668100 -* 2023 12 8 10 3 0.00000000 -PL56 -2080.671327 -142.906541 -6878.836231 -VL56 -62831.964000 37018.512000 18290.031000 -* 2023 12 8 10 6 0.00000000 -PL56 -3160.577552 536.431513 -6432.464229 -VL56 -56806.618000 38220.146000 31165.783000 -* 2023 12 8 10 9 0.00000000 -PL56 -4113.856095 1224.008839 -5763.254438 -VL56 -48808.003000 37922.056000 42978.275000 -* 2023 12 8 10 12 0.00000000 -PL56 -4907.661933 1892.363354 -4894.096048 -VL56 -39144.008000 36082.333000 53317.396000 -* 2023 12 8 10 15 0.00000000 -PL56 -5515.242168 2513.830072 -3854.859872 -VL56 -28181.740000 32720.889000 61819.918000 -* 2023 12 8 10 18 0.00000000 -PL56 -5916.889731 3061.673090 -2681.430271 -VL56 -16334.637000 27921.124000 68183.019000 -* 2023 12 8 10 21 0.00000000 -PL56 -6100.646640 3511.225292 -1414.505480 -VL56 -4047.561900 21829.115000 72176.535000 -* 2023 12 8 10 24 0.00000000 -PL56 -6062.718722 3840.987179 -98.194812 -VL56 8220.253400 14649.812000 73653.108000 -* 2023 12 8 10 27 0.00000000 -PL56 -5807.570312 4033.627948 1221.540642 -VL56 20013.459000 6640.094500 72555.166000 -* 2023 12 8 10 30 0.00000000 -PL56 -5347.683661 4076.833390 2498.541600 -VL56 30899.624000 -1901.390900 68918.506000 -* 2023 12 8 10 33 0.00000000 -PL56 -4702.988921 3963.953880 3688.119925 -VL56 40486.500000 -10646.116000 62870.318000 -* 2023 12 8 10 36 0.00000000 -PL56 -3899.998128 3694.420145 4748.670665 -VL56 48437.362000 -19249.406000 54624.592000 -* 2023 12 8 10 39 0.00000000 -PL56 -2970.686905 3273.904872 5643.157460 -VL56 54483.589000 -27364.719000 44473.325000 -* 2023 12 8 10 42 0.00000000 -PL56 -1951.182169 2714.227096 6340.413214 -VL56 58433.758000 -34658.018000 32774.518000 -* 2023 12 8 10 45 0.00000000 -PL56 -880.318133 2033.004881 6816.211128 -VL56 60179.072000 -40821.174000 19938.876000 -* 2023 12 8 10 48 0.00000000 -PL56 201.870967 1253.074631 7054.073508 -VL56 59694.979000 -45584.377000 6414.244600 -* 2023 12 8 10 51 0.00000000 -PL56 1255.658915 401.704407 7045.809489 -VL56 57039.855000 -48726.712000 -7329.136600 -* 2023 12 8 10 54 0.00000000 -PL56 2243.089786 -490.371486 6791.774915 -VL56 52351.162000 -50085.339000 -20814.406000 -* 2023 12 8 10 57 0.00000000 -PL56 3129.347263 -1390.066875 6300.853067 -VL56 45839.037000 -49562.855000 -33573.508000 -* 2023 12 8 11 0 0.00000000 -PL56 3883.991054 -2263.173849 5590.155864 -VL56 37777.993000 -47132.758000 -45162.772000 -* 2023 12 8 11 3 0.00000000 -PL56 4482.020443 -3075.668180 4684.447654 -VL56 28495.931000 -42842.201000 -55178.092000 -* 2023 12 8 11 6 0.00000000 -PL56 4904.726657 -3795.044461 3615.304615 -VL56 18361.795000 -36812.600000 -63268.996000 -* 2023 12 8 11 9 0.00000000 -PL56 5140.303390 -4391.630934 2420.026678 -VL56 7771.095600 -29236.687000 -69152.021000 -* 2023 12 8 11 12 0.00000000 -PL56 5184.185624 -4839.823737 1140.329979 -VL56 -2869.833200 -20372.413000 -72621.549000 -* 2023 12 8 11 15 0.00000000 -PL56 5039.097268 -5119.182946 -179.131848 -VL56 -13160.151000 -10533.819000 -73557.859000 -* 2023 12 8 11 18 0.00000000 -PL56 4714.806413 -5215.337788 -1492.360075 -VL56 -22720.608000 -79.003208 -71931.698000 -* 2023 12 8 11 21 0.00000000 -PL56 4227.600340 -5120.654315 -2753.653171 -VL56 -31208.501000 10604.108000 -67805.116000 -* 2023 12 8 11 24 0.00000000 -PL56 3599.505995 -4834.633193 -3919.226982 -VL56 -38330.763000 21113.369000 -61328.284000 -* 2023 12 8 11 27 0.00000000 -PL56 2857.299332 -4364.022568 -4948.744216 -VL56 -43854.245000 31048.300000 -52732.612000 -* 2023 12 8 11 30 0.00000000 -PL56 2031.355513 -3722.646000 -5806.694406 -VL56 -47613.088000 40025.704000 -42321.115000 -* 2023 12 8 11 33 0.00000000 -PL56 1154.399122 -2930.961392 -6463.574604 -VL56 -49512.522000 47693.854000 -30456.258000 -* 2023 12 8 11 36 0.00000000 -PL56 260.212157 -2015.380759 -6896.847409 -VL56 -49529.791000 53744.953000 -17547.215000 -* 2023 12 8 11 39 0.00000000 -PL56 -617.653391 -1007.373702 -7091.658113 -VL56 -47712.667000 57926.470000 -4036.111600 -* 2023 12 8 11 42 0.00000000 -PL56 -1447.109582 57.610648 -7041.298191 -VL56 -44175.257000 60050.135000 9616.350300 -* 2023 12 8 11 45 0.00000000 -PL56 -2198.679379 1141.367500 -6747.416497 -VL56 -39092.445000 59999.092000 22944.641000 -* 2023 12 8 11 48 0.00000000 -PL56 -2846.525363 2204.274595 -6219.977068 -VL56 -32692.418000 57733.477000 35492.697000 -* 2023 12 8 11 51 0.00000000 -PL56 -3369.332449 3206.711738 -5476.965442 -VL56 -25247.903000 53293.806000 46827.694000 -* 2023 12 8 11 54 0.00000000 -PL56 -3751.023170 4110.525805 -4543.840263 -VL56 -17066.344000 46802.530000 56554.477000 -* 2023 12 8 11 57 0.00000000 -PL56 -3981.278901 4880.493183 -3452.725322 -VL56 -8478.105700 38462.152000 64329.946000 -* 2023 12 8 12 0 0.00000000 -PL56 -4055.838301 5485.719890 -2241.354328 -VL56 176.325710 28550.125000 69875.919000 -* 2023 12 8 12 3 0.00000000 -PL56 -3976.560555 5900.920470 -951.797111 -VL56 8559.687200 17410.480000 72990.578000 -* 2023 12 8 12 6 0.00000000 -PL56 -3751.244463 6107.516507 371.002396 -VL56 16351.602000 5442.055100 73557.695000 -* 2023 12 8 12 9 0.00000000 -PL56 -3393.202491 6094.488747 1680.824360 -VL56 23261.857000 -6916.745100 71552.284000 -* 2023 12 8 12 12 0.00000000 -PL56 -2920.605225 5858.935306 2931.842470 -VL56 29042.782000 -19205.449000 67042.991000 -* 2023 12 8 12 15 0.00000000 -PL56 -2355.621957 5406.295796 4080.285198 -VL56 33499.177000 -30960.916000 60188.712000 -* 2023 12 8 12 18 0.00000000 -PL56 -1723.409919 4750.234525 5086.007739 -VL56 36495.198000 -41735.539000 51232.147000 -* 2023 12 8 12 21 0.00000000 -PL56 -1051.004664 3912.195574 5913.916273 -VL56 37958.437000 -51115.332000 40489.937000 -* 2023 12 8 12 24 0.00000000 -PL56 -366.164250 2920.651836 6535.190506 -VL56 37880.846000 -58735.766000 28340.188000 -* 2023 12 8 12 27 0.00000000 -PL56 303.776224 1810.087013 6928.263846 -VL56 36316.946000 -64295.508000 15208.333000 -* 2023 12 8 12 30 0.00000000 -PL56 932.993436 619.758442 7079.540454 -VL56 33379.351000 -67567.160000 1552.011900 -* 2023 12 8 12 33 0.00000000 -PL56 1498.168686 -607.713820 6983.835896 -VL56 29232.506000 -68405.595000 -12154.366000 -* 2023 12 8 12 36 0.00000000 -PL56 1979.350408 -1827.882481 6644.539158 -VL56 24084.631000 -66753.699000 -25435.259000 -* 2023 12 8 12 39 0.00000000 -PL56 2360.660494 -2996.089279 6073.494349 -VL56 18178.449000 -62645.371000 -37829.313000 -* 2023 12 8 12 42 0.00000000 -PL56 2630.823163 -4069.110691 5290.602132 -VL56 11780.795000 -56205.880000 -48905.249000 -* 2023 12 8 12 45 0.00000000 -PL56 2783.498058 -5006.776221 4323.146550 -VL56 5171.336200 -47648.413000 -58276.374000 -* 2023 12 8 12 48 0.00000000 -PL56 2817.408733 -5773.501605 3204.863534 -VL56 -1368.916600 -37268.008000 -65614.742000 -* 2023 12 8 12 51 0.00000000 -PL56 2736.259963 -6339.676821 1974.770951 -VL56 -7569.464500 -25431.541000 -70663.340000 -* 2023 12 8 12 54 0.00000000 -PL56 2548.443890 -6682.843594 675.796306 -VL56 -13181.805000 -12564.191000 -73246.079000 -* 2023 12 8 12 57 0.00000000 -PL56 2266.551278 -6788.607364 -646.744984 -VL56 -17989.507000 865.922900 -73274.664000 -* 2023 12 8 13 0 0.00000000 -PL56 1906.709397 -6651.242633 -1946.768463 -VL56 -21817.474000 14367.057000 -70752.306000 -* 2023 12 8 13 3 0.00000000 -PL56 1487.774081 -6273.951054 -3179.067095 -VL56 -24538.524000 27442.346000 -65772.704000 -* 2023 12 8 13 6 0.00000000 -PL56 1030.420915 -5668.762865 -4300.908581 -VL56 -26078.127000 39610.899000 -58516.074000 -* 2023 12 8 13 9 0.00000000 -PL56 556.187730 -4856.094003 -5273.515969 -VL56 -26415.083000 50424.896000 -49240.136000 -* 2023 12 8 13 12 0.00000000 -PL56 86.512787 -3863.995259 -6063.380255 -VL56 -25581.200000 59486.150000 -38270.503000 -* 2023 12 8 13 15 0.00000000 -PL56 -358.188838 -2727.132306 -6643.366456 -VL56 -23657.693000 66459.906000 -25987.687000 -* 2023 12 8 13 18 0.00000000 -PL56 -759.372357 -1485.543690 -6993.586558 -VL56 -20770.148000 71085.563000 -12814.066000 -* 2023 12 8 13 21 0.00000000 -PL56 -1101.103275 -183.227233 -7102.026411 -VL56 -17081.801000 73184.976000 800.160490 -* 2023 12 8 13 24 0.00000000 -PL56 -1370.666793 1133.399070 -6964.921249 -VL56 -12785.782000 72668.082000 14390.995000 -* 2023 12 8 13 27 0.00000000 -PL56 -1559.029712 2417.115756 -6586.877190 -VL56 -8096.539900 69536.279000 27494.630000 -* 2023 12 8 13 30 0.00000000 -PL56 -1661.142359 3621.559497 -5980.741817 -VL56 -3240.710700 63883.311000 39661.450000 -* 2023 12 8 13 33 0.00000000 -PL56 -1676.072918 4702.880137 -5167.221090 -VL56 1552.424500 55894.167000 50470.342000 -* 2023 12 8 13 36 0.00000000 -PL56 -1606.968272 5621.347524 -4174.237808 -VL56 6060.584500 45840.692000 59543.001000 -* 2023 12 8 13 39 0.00000000 -PL56 -1460.840398 6342.850705 -3036.033841 -VL56 10078.189000 34073.783000 66557.810000 -* 2023 12 8 13 42 0.00000000 -PL56 -1248.181500 6840.224609 -1792.033400 -VL56 13425.583000 21012.180000 71262.491000 -* 2023 12 8 13 45 0.00000000 -PL56 -982.421882 7094.345485 -485.496075 -VL56 15957.241000 7127.859300 73484.765000 -* 2023 12 8 13 48 0.00000000 -PL56 -679.251715 7094.935116 837.999001 -VL56 17568.595000 -7071.406300 73140.264000 -* 2023 12 8 13 51 0.00000000 -PL56 -355.836289 6841.026372 2132.184303 -VL56 18200.921000 -21062.375000 70237.314000 -* 2023 12 8 13 54 0.00000000 -PL56 -29.965236 6341.047444 3351.779221 -VL56 17843.751000 -34327.959000 64876.797000 -* 2023 12 8 13 57 0.00000000 -PL56 280.819048 5612.524541 4454.122145 -VL56 16534.822000 -46377.710000 57247.857000 -* 2023 12 8 14 0 0.00000000 -PL56 560.071016 4681.428703 5400.700619 -VL56 14357.686000 -56766.778000 47620.887000 -* 2023 12 8 14 3 0.00000000 -PL56 793.228725 3581.183530 6158.513015 -VL56 11437.167000 -65114.462000 36335.721000 -* 2023 12 8 14 6 0.00000000 -PL56 968.299886 2351.404149 6701.204440 -VL56 7932.703800 -71115.709000 23788.599000 -* 2023 12 8 14 9 0.00000000 -PL56 1076.416092 1036.420799 7009.958006 -VL56 4030.521600 -74552.929000 10418.352000 -* 2023 12 8 14 12 0.00000000 -PL56 1112.235129 -316.353571 7074.114899 -VL56 -65.311883 -75302.107000 -3309.842000 -* 2023 12 8 14 15 0.00000000 -PL56 1074.177988 -1658.147859 6891.516917 -VL56 -4142.353300 -73336.753000 -16919.277000 -* 2023 12 8 14 18 0.00000000 -PL56 964.492217 -2940.599685 6468.571085 -VL56 -7989.507400 -68728.634000 -29937.635000 -* 2023 12 8 14 21 0.00000000 -PL56 789.139368 -4117.509832 5820.029631 -VL56 -11406.800000 -61645.579000 -41912.651000 -* 2023 12 8 14 24 0.00000000 -PL56 557.511504 -5146.521383 4968.487759 -VL56 -14214.461000 -52345.488000 -52427.453000 -* 2023 12 8 14 27 0.00000000 -PL56 281.991041 -5990.668154 3943.620394 -VL56 -16261.345000 -41167.901000 -61114.624000 -* 2023 12 8 14 30 0.00000000 -PL56 -22.633428 -6619.747213 2781.168343 -VL56 -17432.407000 -28522.437000 -67669.805000 -* 2023 12 8 14 33 0.00000000 -PL56 -339.873764 -7011.448675 1521.693366 -VL56 -17654.690000 -14873.697000 -71863.442000 -* 2023 12 8 14 36 0.00000000 -PL56 -652.338289 -7152.188997 209.148039 -VL56 -16901.257000 -723.642590 -73549.594000 -* 2023 12 8 14 39 0.00000000 -PL56 -942.580057 -7037.608795 -1110.692512 -VL56 -15192.939000 13408.334000 -72672.313000 -* 2023 12 8 14 42 0.00000000 -PL56 -1193.952677 -6672.698543 -2391.869643 -VL56 -12597.525000 27006.171000 -69267.117000 -* 2023 12 8 14 45 0.00000000 -PL56 -1391.430310 -6071.555274 -3589.873446 -VL56 -9226.631900 39577.320000 -63458.844000 -* 2023 12 8 14 48 0.00000000 -PL56 -1522.354602 -5256.788784 -4663.205545 -VL56 -5230.660500 50671.478000 -55456.007000 -* 2023 12 8 14 51 0.00000000 -PL56 -1577.071911 -4258.608275 -5574.807897 -VL56 -791.784960 59896.999000 -45541.695000 -* 2023 12 8 14 54 0.00000000 -PL56 -1549.433047 -3113.645606 -6293.305654 -VL56 3884.240100 66933.799000 -34062.292000 -* 2023 12 8 14 57 0.00000000 -PL56 -1437.137033 -1863.573250 -6794.034355 -VL56 8577.143800 71543.285000 -21414.783000 -* 2023 12 8 15 0 0.00000000 -PL56 -1241.907798 -553.573297 -7059.827422 -VL56 13061.554000 73574.890000 -8032.967200 -* 2023 12 8 15 3 0.00000000 -PL56 -969.500695 769.283245 -7081.553026 -VL56 17116.506000 72969.680000 5626.552600 -* 2023 12 8 15 6 0.00000000 -PL56 -629.538065 2057.695364 -6858.399434 -VL56 20534.829000 69760.982000 19098.236000 -* 2023 12 8 15 9 0.00000000 -PL56 -235.179305 3265.785452 -6397.909630 -VL56 23132.152000 64073.177000 31921.649000 -* 2023 12 8 15 12 0.00000000 -PL56 197.367046 4350.708764 -5715.764424 -VL56 24755.436000 56118.069000 43655.453000 -* 2023 12 8 15 15 0.00000000 -PL56 649.479061 5274.173777 -4835.306468 -VL56 25290.734000 46188.481000 53892.009000 -* 2023 12 8 15 18 0.00000000 -PL56 1100.884332 6003.823666 -3786.807896 -VL56 24669.572000 34649.242000 62271.367000 -* 2023 12 8 15 21 0.00000000 -PL56 1530.525598 6514.427803 -2606.486571 -VL56 22873.861000 21925.066000 68494.974000 -* 2023 12 8 15 24 0.00000000 -PL56 1917.495238 6788.827911 -1335.290761 -VL56 19938.599000 8485.450600 72337.699000 -* 2023 12 8 15 27 0.00000000 -PL56 2241.998047 6818.589728 -17.482969 -VL56 15952.200000 -5172.966600 73657.844000 -* 2023 12 8 15 30 0.00000000 -PL56 2486.294256 6604.314963 1300.927626 -VL56 11053.980000 -18546.185000 72403.778000 -* 2023 12 8 15 33 0.00000000 -PL56 2635.573181 6155.591880 2573.835636 -VL56 5429.022900 -31143.050000 68616.564000 -* 2023 12 8 15 36 0.00000000 -PL56 2678.713502 5490.585697 3756.702626 -VL56 -699.233770 -42504.888000 62428.704000 -* 2023 12 8 15 39 0.00000000 -PL56 2608.891598 4635.286970 4808.163514 -VL56 -7078.453800 -52223.770000 54059.147000 -* 2023 12 8 15 42 0.00000000 -PL56 2424.003424 3622.450949 5691.507614 -VL56 -13438.510000 -59958.406000 43804.215000 -* 2023 12 8 15 45 0.00000000 -PL56 2126.879375 2490.284456 6375.963327 -VL56 -19503.117000 -65445.911000 32025.427000 -* 2023 12 8 15 48 0.00000000 -PL56 1725.292565 1280.957486 6837.751265 -VL56 -25001.384000 -68509.947000 19135.794000 -* 2023 12 8 15 51 0.00000000 -PL56 1231.757475 38.995498 7060.881459 -VL56 -29679.243000 -69065.570000 5585.109600 -* 2023 12 8 15 54 0.00000000 -PL56 663.129176 -1190.378277 7037.674410 -VL56 -33310.140000 -67120.161000 -8155.467200 -* 2023 12 8 15 57 0.00000000 -PL56 40.017877 -2362.897819 6769.007874 -VL56 -35704.999000 -62772.240000 -21608.974000 -* 2023 12 8 16 0 0.00000000 -PL56 -613.965083 -3436.856644 6264.278046 -VL56 -36720.743000 -56206.682000 -34308.649000 -* 2023 12 8 16 3 0.00000000 -PL56 -1273.100865 -4374.600146 5541.074668 -VL56 -36267.211000 -47687.244000 -45813.251000 -* 2023 12 8 16 6 0.00000000 -PL56 -1910.565437 -5143.859826 4624.589952 -VL56 -34312.601000 -37546.923000 -55721.579000 -* 2023 12 8 16 9 0.00000000 -PL56 -2499.516176 -5718.898092 3546.770527 -VL56 -30887.048000 -26176.188000 -63686.776000 -* 2023 12 8 16 12 0.00000000 -PL56 -3014.217636 -6081.411415 2345.214589 -VL56 -26083.273000 -14007.829000 -69429.799000 -* 2023 12 8 16 15 0.00000000 -PL56 -3431.151996 -6221.143078 1061.852832 -VL56 -20054.342000 -1500.237200 -72749.852000 -* 2023 12 8 16 18 0.00000000 -PL56 -3730.063543 -6136.181952 -258.537134 -VL56 -13008.582000 10880.742000 -73532.428000 -* 2023 12 8 16 21 0.00000000 -PL56 -3894.887622 -5832.931657 -1569.928034 -VL56 -5201.831100 22680.190000 -71753.639000 -* 2023 12 8 16 24 0.00000000 -PL56 -3914.517798 -5325.748566 -2826.687033 -VL56 3072.702600 33472.303000 -67480.939000 -* 2023 12 8 16 27 0.00000000 -PL56 -3783.372518 -4636.265877 -3985.194332 -VL56 11496.478000 42876.912000 -60869.657000 -* 2023 12 8 16 30 0.00000000 -PL56 -3501.734416 -3792.444031 -5005.364978 -VL56 19738.659000 50573.167000 -52155.767000 -* 2023 12 8 16 33 0.00000000 -PL56 -3075.853053 -2827.403644 -5852.015891 -VL56 27469.262000 56310.046000 -41646.121000 -* 2023 12 8 16 36 0.00000000 -PL56 -2517.813714 -1778.099078 -6496.036440 -VL56 34371.944000 59913.517000 -29706.489000 -* 2023 12 8 16 39 0.00000000 -PL56 -1845.181508 -683.892052 -6915.333615 -VL56 40156.121000 61290.533000 -16748.535000 -* 2023 12 8 16 42 0.00000000 -PL56 -1080.436878 414.918324 -7095.530613 -VL56 44567.915000 60429.877000 -3215.616500 -* 2023 12 8 16 45 0.00000000 -PL56 -250.228276 1478.554076 -7030.412987 -VL56 47399.606000 57400.186000 10430.990000 -* 2023 12 8 16 48 0.00000000 -PL56 615.537126 2469.165385 -6722.127001 -VL56 48498.084000 52346.231000 23725.887000 -* 2023 12 8 16 51 0.00000000 -PL56 1484.743403 3352.152534 -6181.128548 -VL56 47772.205000 45483.326000 36213.603000 -* 2023 12 8 16 54 0.00000000 -PL56 2324.233270 4097.368787 -5425.873999 -VL56 45198.149000 37089.433000 47463.085000 -* 2023 12 8 16 57 0.00000000 -PL56 3101.055330 4680.163915 -4482.251958 -VL56 40822.952000 27495.535000 57081.900000 -* 2023 12 8 17 0 0.00000000 -PL56 3783.752466 5082.236771 -3382.761156 -VL56 34765.591000 17074.000000 64730.316000 -* 2023 12 8 17 3 0.00000000 -PL56 4343.644338 5292.259709 -2165.442132 -VL56 27215.068000 6224.832200 70134.429000 -* 2023 12 8 17 6 0.00000000 -PL56 4756.047936 5306.239458 -872.585544 -VL56 18425.342000 -4639.689600 73097.569000 -* 2023 12 8 17 9 0.00000000 -PL56 5001.375201 5127.591856 450.742966 -VL56 8706.870400 -15111.432000 73509.285000 -* 2023 12 8 17 12 0.00000000 -PL56 5066.047874 4766.916027 1758.306925 -VL56 -1585.183900 -24803.060000 71350.477000 -* 2023 12 8 17 15 0.00000000 -PL56 4943.181231 4241.478895 3004.361232 -VL56 -12064.691000 -33363.541000 66694.854000 -* 2023 12 8 17 18 0.00000000 -PL56 4633.001470 3574.429692 4145.307837 -VL56 -22330.504000 -40492.530000 59706.386000 -* 2023 12 8 17 21 0.00000000 -PL56 4142.966546 2793.780566 5141.264799 -VL56 -31982.977000 -45951.689000 50632.587000 -* 2023 12 8 17 24 0.00000000 -PL56 3487.592525 1931.211724 5957.481869 -VL56 -40640.288000 -49572.919000 39794.251000 -* 2023 12 8 17 27 0.00000000 -PL56 2687.991996 1020.760311 6565.550899 -VL56 -47953.510000 -51262.816000 27572.890000 -* 2023 12 8 17 30 0.00000000 -PL56 1771.156078 97.455184 6944.368540 -VL56 -53620.470000 -51004.476000 14396.247000 -* 2023 12 8 17 33 0.00000000 -PL56 769.013208 -804.040583 7080.836400 -VL56 -57396.670000 -48855.099000 723.508200 -* 2023 12 8 17 36 0.00000000 -PL56 -282.704295 -1650.735806 6970.289339 -VL56 -59105.320000 -44942.318000 -12970.163000 -* 2023 12 8 17 39 0.00000000 -PL56 -1345.747646 -2412.522765 6616.637467 -VL56 -58644.687000 -39457.674000 -26209.784000 -* 2023 12 8 17 42 0.00000000 -PL56 -2380.746517 -3063.250816 6032.222710 -VL56 -55992.369000 -32647.652000 -38536.000000 -* 2023 12 8 17 45 0.00000000 -PL56 -3348.666955 -3581.630448 5237.405670 -VL56 -51208.446000 -24804.120000 -49519.643000 -* 2023 12 8 17 48 0.00000000 -PL56 -4212.299296 -3951.946392 4259.883867 -VL56 -44435.250000 -16252.499000 -58777.182000 -* 2023 12 8 17 51 0.00000000 -PL56 -4937.711960 -4164.546254 3133.742186 -VL56 -35893.752000 -7338.757800 -65984.596000 -* 2023 12 8 17 54 0.00000000 -PL56 -5495.607469 -4216.086458 1898.271525 -VL56 -25876.512000 1584.417900 -70889.286000 -* 2023 12 8 17 57 0.00000000 -PL56 -5862.527832 -4109.526277 596.588610 -VL56 -14737.790000 10171.815000 -73320.185000 -* 2023 12 8 18 0 0.00000000 -PL56 -6021.847988 -3853.863823 -725.897309 -VL56 -2880.137300 18099.931000 -73194.499000 -* 2023 12 8 18 3 0.00000000 -PL56 -5964.506965 -3463.626548 -2023.107920 -VL56 9261.360800 25079.977000 -70520.922000 -* 2023 12 8 18 6 0.00000000 -PL56 -5689.436266 -2958.139894 -3249.941282 -VL56 21236.750000 30869.316000 -65398.664000 -* 2023 12 8 18 9 0.00000000 -PL56 -5203.667653 -2360.615152 -4363.861493 -VL56 32598.878000 35280.027000 -58012.545000 -* 2023 12 8 18 12 0.00000000 -PL56 -4522.125668 -1697.106975 -5326.370739 -VL56 42920.702000 38184.835000 -48624.893000 -* 2023 12 8 18 15 0.00000000 -PL56 -3667.121185 -995.392203 -6104.312804 -VL56 51811.085000 39519.928000 -37564.898000 -* 2023 12 8 18 18 0.00000000 -PL56 -2667.574399 -283.820836 -6670.966636 -VL56 58928.915000 39285.200000 -25216.180000 -* 2023 12 8 18 21 0.00000000 -PL56 -1558.006531 409.810315 -7006.903436 -VL56 63994.747000 37541.596000 -12003.081000 -* 2023 12 8 18 24 0.00000000 -PL56 -377.341874 1059.317415 -7100.595470 -VL56 66800.130000 34406.489000 1623.177900 -* 2023 12 8 18 27 0.00000000 -PL56 832.436898 1641.092017 -6948.775090 -VL56 67214.754000 30047.507000 15198.333000 -* 2023 12 8 18 30 0.00000000 -PL56 2027.746544 2134.940238 -6556.547295 -VL56 65191.901000 24675.107000 28258.711000 -* 2023 12 8 18 33 0.00000000 -PL56 3164.943868 2524.778350 -5937.248027 -VL56 60771.882000 18533.958000 40355.768000 -* 2023 12 8 18 36 0.00000000 -PL56 4201.900768 2799.161666 -5112.040518 -VL56 54082.605000 11893.139000 51070.744000 -* 2023 12 8 18 39 0.00000000 -PL56 5099.566706 2951.630723 -4109.257963 -VL56 45337.569000 5035.666900 60028.168000 -* 2023 12 8 18 42 0.00000000 -PL56 5823.469077 2980.861571 -2963.492065 -VL56 34830.813000 -1752.763500 66910.257000 -* 2023 12 8 18 45 0.00000000 -PL56 6345.085591 2890.609363 -1714.443485 -VL56 22927.743000 -8195.455600 71469.196000 -* 2023 12 8 18 48 0.00000000 -PL56 6643.028133 2689.442829 -405.561170 -VL56 10053.073000 -14036.207000 73537.824000 -* 2023 12 8 18 51 0.00000000 -PL56 6703.970825 2390.273408 917.486095 -VL56 -3324.933200 -19050.411000 73037.612000 -* 2023 12 8 18 54 0.00000000 -PL56 6523.267722 2009.698026 2208.443118 -VL56 -16713.165000 -23054.553000 69982.278000 -* 2023 12 8 18 57 0.00000000 -PL56 6105.228216 1567.190119 3422.136642 -VL56 -29613.221000 -25913.681000 64478.047000 -* 2023 12 8 19 0 0.00000000 -PL56 5463.028166 1084.175112 4516.109442 -VL56 -41541.714000 -27546.447000 56719.368000 -* 2023 12 8 19 3 0.00000000 -PL56 4618.259863 583.039397 5452.141540 -VL56 -52049.792000 -27927.503000 46980.945000 -* 2023 12 8 19 6 0.00000000 -PL56 3600.152172 86.124476 6197.597798 -VL56 -60740.606000 -27086.959000 35606.663000 -* 2023 12 8 19 9 0.00000000 -PL56 2444.497970 -385.246558 6726.555315 -VL56 -67283.891000 -25107.122000 22996.025000 -* 2023 12 8 19 12 0.00000000 -PL56 1192.346551 -811.664014 7020.675952 -VL56 -71427.560000 -22117.252000 9589.794600 -* 2023 12 8 19 15 0.00000000 -PL56 -111.488297 -1176.417703 7069.813296 -VL56 -73006.646000 -18286.732000 -4145.279300 -* 2023 12 8 19 18 0.00000000 -PL56 -1420.053439 -1466.145406 6872.336112 -VL56 -71949.008000 -13816.711000 -17732.363000 -* 2023 12 8 19 21 0.00000000 -PL56 -2685.954149 -1671.320780 6435.166968 -VL56 -68277.973000 -8930.612500 -30700.399000 -* 2023 12 8 19 24 0.00000000 -PL56 -3863.071782 -1786.564666 5773.546133 -VL56 -62111.863000 -3864.129300 -42598.809000 -* 2023 12 8 19 27 0.00000000 -PL56 -4908.259716 -1810.775983 4910.525525 -VL56 -53661.703000 1144.828500 -53012.825000 -* 2023 12 8 19 30 0.00000000 -PL56 -5782.956382 -1747.077680 3876.186790 -VL56 -43224.563000 5866.572400 -61578.483000 -* 2023 12 8 19 33 0.00000000 -PL56 -6454.646015 -1602.575237 2706.605570 -VL56 -31173.191000 10089.909000 -67995.729000 -* 2023 12 8 19 36 0.00000000 -PL56 -6898.110366 -1387.939785 1442.597102 -VL56 -17943.255000 13631.295000 -72039.725000 -* 2023 12 8 19 39 0.00000000 -PL56 -7096.418549 -1116.834882 128.274813 -VL56 -4016.860200 16343.034000 -73570.128000 -* 2023 12 8 19 42 0.00000000 -PL56 -7041.594359 -805.210326 -1190.525227 -VL56 10096.432000 18119.694000 -72536.484000 -* 2023 12 8 19 45 0.00000000 -PL56 -6734.928367 -470.499276 -2467.882881 -VL56 23879.947000 18902.395000 -68979.809000 -* 2023 12 8 19 48 0.00000000 -PL56 -6186.924020 -130.761206 -3659.424172 -VL56 36829.974000 18680.525000 -63030.221000 -* 2023 12 8 19 51 0.00000000 -PL56 -5416.886191 196.187293 -4723.879600 -VL56 48475.472000 17491.435000 -54901.233000 -* 2023 12 8 19 54 0.00000000 -PL56 -4452.173643 493.613641 -5624.504422 -VL56 58395.311000 15417.567000 -44880.326000 -* 2023 12 8 19 57 0.00000000 -PL56 -3327.163411 746.640706 -6330.310340 -VL56 66232.956000 12581.658000 -33317.538000 -* 2023 12 8 20 0 0.00000000 -PL56 -2081.980307 942.914159 -6817.074857 -VL56 71707.906000 9140.104300 -20612.370000 -* 2023 12 8 20 3 0.00000000 -PL56 -761.049819 1073.142658 -7068.110912 -VL56 74624.010000 5275.503400 -7200.293800 -* 2023 12 8 20 6 0.00000000 -PL56 588.474744 1131.494492 -7074.787674 -VL56 74874.981000 1188.223800 6461.292800 -* 2023 12 8 20 9 0.00000000 -PL56 1918.359966 1115.838536 -6836.803685 -VL56 72447.530000 -2912.422700 19906.573000 -* 2023 12 8 20 12 0.00000000 -PL56 3180.981486 1027.823670 -6362.211476 -VL56 67422.489000 -6817.297800 32675.677000 -* 2023 12 8 20 15 0.00000000 -PL56 4331.005871 872.792811 -5667.179898 -VL56 59973.009000 -10326.617000 44329.038000 -* 2023 12 8 20 18 0.00000000 -PL56 5327.013088 659.532557 -4775.500164 -VL56 50359.897000 -13258.976000 54461.577000 -* 2023 12 8 20 21 0.00000000 -PL56 6133.014838 399.866009 -3717.838175 -VL56 38924.373000 -15459.758000 62716.880000 -* 2023 12 8 20 24 0.00000000 -PL56 6719.809494 108.099947 -2530.736349 -VL56 26077.172000 -16808.786000 68800.554000 -* 2023 12 8 20 27 0.00000000 -PL56 7066.114573 -199.654006 -1255.386935 -VL56 12284.827000 -17226.621000 72492.216000 -* 2023 12 8 20 30 0.00000000 -PL56 7159.417151 -506.256205 63.794322 -VL56 -1947.896700 -16679.038000 73655.404000 -* 2023 12 8 20 33 0.00000000 -PL56 6996.489402 -794.377144 1380.740122 -VL56 -16097.482000 -15179.377000 72243.862000 -* 2023 12 8 20 36 0.00000000 -PL56 6583.538419 -1047.357399 2649.386538 -VL56 -29642.674000 -12788.532000 68304.370000 -* 2023 12 8 20 39 0.00000000 -PL56 5935.973266 -1250.044087 3825.340510 -VL56 -42085.854000 -9612.362200 61975.089000 -* 2023 12 8 20 42 0.00000000 -PL56 5077.798690 -1389.559794 4867.479829 -VL56 -52972.588000 -5796.898600 53480.063000 -* 2023 12 8 20 45 0.00000000 -PL56 4040.672860 -1455.966560 5739.418325 -VL56 -61909.636000 -1521.380000 43119.783000 -* 2023 12 8 20 48 0.00000000 -PL56 2862.677937 -1442.790084 6410.780390 -VL56 -68578.589000 3010.087000 31259.333000 -* 2023 12 8 20 51 0.00000000 -PL56 1586.864800 -1347.384569 6858.242218 -VL56 -72747.152000 7577.802500 18314.752000 -* 2023 12 8 20 54 0.00000000 -PL56 259.637030 -1171.124793 7066.313169 -VL56 -74276.143000 11956.406000 4737.836900 -* 2023 12 8 20 57 0.00000000 -PL56 -1070.964328 -919.416477 7027.840212 -VL56 -73123.090000 15925.068000 -8999.518200 -* 2023 12 8 21 0 0.00000000 -PL56 -2357.009614 -601.526436 6744.229420 -VL56 -69342.552000 19277.225000 -22420.751000 -* 2023 12 8 21 3 0.00000000 -PL56 -3552.408816 -230.238286 6225.389823 -VL56 -63083.787000 21830.181000 -35060.124000 -* 2023 12 8 21 6 0.00000000 -PL56 -4614.572204 178.655182 5489.402305 -VL56 -54585.430000 23433.658000 -46477.983000 -* 2023 12 8 21 9 0.00000000 -PL56 -5505.952378 607.005630 4561.912425 -VL56 -44167.434000 23977.357000 -56275.981000 -* 2023 12 8 21 12 0.00000000 -PL56 -6195.408798 1035.085919 3475.256516 -VL56 -32219.493000 23397.025000 -64111.319000 -* 2023 12 8 21 15 0.00000000 -PL56 -6659.338933 1442.460399 2267.344763 -VL56 -19186.926000 21678.721000 -69709.377000 -* 2023 12 8 21 18 0.00000000 -PL56 -6882.529572 1808.910936 980.334551 -VL56 -5553.605800 18860.669000 -72874.424000 -* 2023 12 8 21 21 0.00000000 -PL56 -6858.687351 2115.375984 -340.864503 -VL56 8176.602200 15032.841000 -73497.480000 -* 2023 12 8 21 24 0.00000000 -PL56 -6590.615076 2344.856207 -1650.196027 -VL56 21500.242000 10333.660000 -71560.469000 -* 2023 12 8 21 27 0.00000000 -PL56 -6090.026457 2483.240718 -2902.100788 -VL56 33933.912000 4944.535400 -67136.387000 -* 2023 12 8 21 30 0.00000000 -PL56 -5377.011296 2520.015581 -4053.132380 -VL56 45033.298000 -917.713540 -60386.067000 -* 2023 12 8 21 33 0.00000000 -PL56 -4479.178690 2448.817187 -5063.473476 -VL56 54409.768000 -7010.399000 -51550.464000 -* 2023 12 8 21 36 0.00000000 -PL56 -3430.532587 2267.808028 -5898.291229 -VL56 61743.339000 -13075.088000 -40940.514000 -* 2023 12 8 21 39 0.00000000 -PL56 -2270.141934 1979.864491 -6528.890826 -VL56 66792.517000 -18848.221000 -28925.219000 -* 2023 12 8 21 42 0.00000000 -PL56 -1040.664643 1592.572247 -6933.644019 -VL56 69400.890000 -24071.880000 -15918.434000 -* 2023 12 8 21 45 0.00000000 -PL56 213.217671 1118.031008 -7098.671049 -VL56 69500.248000 -28504.079000 -2364.964500 -* 2023 12 8 21 48 0.00000000 -PL56 1446.395414 572.479713 -7018.274173 -VL56 67111.160000 -31928.438000 11273.129000 -* 2023 12 8 21 51 0.00000000 -PL56 2614.920056 -24.247589 -6695.124663 -VL56 62341.638000 -34163.377000 24530.492000 -* 2023 12 8 21 54 0.00000000 -PL56 3677.543724 -649.424060 -6140.191319 -VL56 55382.913000 -35070.339000 36952.894000 -* 2023 12 8 21 57 0.00000000 -PL56 4597.163023 -1278.269741 -5372.411550 -VL56 46502.909000 -34560.809000 48111.473000 -* 2023 12 8 22 0 0.00000000 -PL56 5342.127585 -1884.906893 -4418.109150 -VL56 36037.984000 -32602.168000 57616.755000 -* 2023 12 8 22 3 0.00000000 -PL56 5887.372053 -2443.403215 -3310.157325 -VL56 24381.402000 -29221.428000 65132.791000 -* 2023 12 8 22 6 0.00000000 -PL56 6215.321403 -2928.862048 -2086.896403 -VL56 11969.593000 -24506.638000 70390.158000 -* 2023 12 8 22 9 0.00000000 -PL56 6316.524163 -3318.513299 -790.830329 -VL56 -734.144480 -18605.546000 73197.300000 -* 2023 12 8 22 12 0.00000000 -PL56 6189.975845 -3592.753066 532.856263 -VL56 -13257.645000 -11721.270000 73449.117000 -* 2023 12 8 22 15 0.00000000 -PL56 5843.109564 -3736.080082 1837.906473 -VL56 -25138.722000 -4105.117000 71132.149000 -* 2023 12 8 22 18 0.00000000 -PL56 5291.444287 -3737.877699 3078.660888 -VL56 -35944.284000 3953.399700 66326.030000 -* 2023 12 8 22 21 0.00000000 -PL56 4557.901660 -3592.995660 4211.708510 -VL56 -45287.570000 12138.528000 59200.124000 -* 2023 12 8 22 24 0.00000000 -PL56 3671.834389 -3302.104252 5197.445134 -VL56 -52842.962000 20121.480000 50006.621000 -* 2023 12 8 22 27 0.00000000 -PL56 2667.813280 -2871.806679 6001.478917 -VL56 -58358.004000 27574.190000 39070.481000 -* 2023 12 8 22 30 0.00000000 -PL56 1584.233833 -2314.502726 6595.826548 -VL56 -61661.258000 34182.868000 26776.544000 -* 2023 12 8 22 33 0.00000000 -PL56 461.810828 -1648.016153 6959.863743 -VL56 -62666.897000 39660.664000 13555.175000 -* 2023 12 8 22 36 0.00000000 -PL56 -657.975892 -895.003638 7081.008170 -VL56 -61375.594000 43759.246000 -133.061080 -* 2023 12 8 22 39 0.00000000 -PL56 -1734.424363 -82.167420 6955.124506 -VL56 -57872.553000 46279.007000 -13812.751000 -* 2023 12 8 22 42 0.00000000 -PL56 -2729.092083 760.701056 6586.649912 -VL56 -52322.655000 47077.614000 -27009.403000 -* 2023 12 8 22 45 0.00000000 -PL56 -3607.172569 1601.816490 5988.439686 -VL56 -44963.631000 46076.810000 -39264.745000 -* 2023 12 8 22 48 0.00000000 -PL56 -4338.725277 2408.599142 5181.336140 -VL56 -36096.733000 43267.202000 -50152.083000 -* 2023 12 8 22 51 0.00000000 -PL56 -4899.720507 3148.940660 4193.466611 -VL56 -26075.353000 38710.757000 -59291.096000 -* 2023 12 8 22 54 0.00000000 -PL56 -5272.858141 3792.489107 3059.280556 -VL56 -15291.420000 32540.356000 -66361.803000 -* 2023 12 8 22 57 0.00000000 -PL56 -5448.125283 4311.900024 1818.354383 -VL56 -4160.045700 24956.462000 -71116.373000 -* 2023 12 8 23 0 0.00000000 -PL56 -5423.069149 4684.000766 513.999285 -VL56 6896.710700 16220.812000 -73389.081000 -* 2023 12 8 23 3 0.00000000 -PL56 -5202.767015 4890.807589 -808.280581 -VL56 17466.999000 6646.380400 -73102.764000 -* 2023 12 8 23 6 0.00000000 -PL56 -4799.495135 4920.345604 -2102.414476 -VL56 27165.520000 -3414.441300 -70271.841000 -* 2023 12 8 23 9 0.00000000 -PL56 -4232.109513 4767.231033 -3323.410819 -VL56 35648.873000 -13584.220000 -65001.224000 -* 2023 12 8 23 12 0.00000000 -PL56 -3525.172163 4432.983415 -4428.945140 -VL56 42628.321000 -23475.888000 -57481.108000 -* 2023 12 8 23 15 0.00000000 -PL56 -2707.873840 3926.061044 -5380.821850 -VL56 47879.569000 -32707.998000 -47978.445000 -* 2023 12 8 23 18 0.00000000 -PL56 -1812.815193 3261.629674 -6146.259158 -VL56 51248.821000 -40919.008000 -36825.951000 -* 2023 12 8 23 21 0.00000000 -PL56 -874.702226 2461.081205 -6698.968183 -VL56 52656.287000 -47780.855000 -24410.125000 -* 2023 12 8 23 24 0.00000000 -PL56 70.993104 1551.321302 -7019.997089 -VL56 52096.474000 -53010.790000 -11157.408000 -* 2023 12 8 23 27 0.00000000 -PL56 989.353002 563.860094 -7098.326752 -VL56 49635.919000 -56381.538000 2479.533400 -* 2023 12 8 23 30 0.00000000 -PL56 1847.276070 -466.264901 -6931.218210 -VL56 45409.053000 -57729.766000 16035.770000 -* 2023 12 8 23 33 0.00000000 -PL56 2614.647110 -1501.706608 -6524.304353 -VL56 39612.009000 -56963.065000 29048.335000 -* 2023 12 8 23 36 0.00000000 -PL56 3265.379756 -2504.131452 -5891.426529 -VL56 32494.935000 -54064.945000 41070.452000 -* 2023 12 8 23 39 0.00000000 -PL56 3778.307450 -3435.614808 -5054.219621 -VL56 24352.721000 -49097.788000 51685.430000 -* 2023 12 8 23 42 0.00000000 -PL56 4137.895205 -4260.073918 -4041.437310 -VL56 15514.147000 -42203.553000 60521.313000 -* 2023 12 8 23 45 0.00000000 -PL56 4334.738354 -4944.678531 -2888.023333 -VL56 6329.477400 -33601.013000 67264.394000 -* 2023 12 8 23 48 0.00000000 -PL56 4365.832468 -5461.187778 -1633.951241 -VL56 -2842.727300 -23580.109000 71671.508000 -* 2023 12 8 23 51 0.00000000 -PL56 4234.592743 -5787.153597 -322.852710 -VL56 -11650.158000 -12492.680000 73580.896000 -* 2023 12 8 23 54 0.00000000 -PL56 3950.611429 -5906.922991 999.519301 -VL56 -19761.224000 -739.489810 72919.617000 -* 2023 12 8 23 57 0.00000000 -PL56 3529.160317 -5812.383721 2286.930008 -VL56 -26878.583000 11245.155000 69707.372000 -* 2023 12 9 0 0 0.00000000 -PL56 2990.458540 -5503.408147 3494.334876 -VL56 -32751.719000 23011.399000 64056.278000 -* 2023 12 9 0 3 0.00000000 -PL56 2358.741674 -4987.971962 4579.504216 -VL56 -37186.316000 34111.860000 56165.872000 -* 2023 12 9 0 6 0.00000000 -PL56 1661.184337 -4281.945006 5504.533168 -VL56 -40050.952000 44119.685000 46315.518000 -* 2023 12 9 0 9 0.00000000 -PL56 926.729923 -3408.565540 6237.177938 -VL56 -41280.853000 52645.693000 34852.843000 -* 2023 12 9 0 12 0.00000000 -PL56 184.881323 -2397.625074 6751.968899 -VL56 -40878.421000 59353.191000 22180.394000 -* 2023 12 9 0 15 0.00000000 -PL56 -535.489801 -1284.407367 7031.064616 -VL56 -38910.770000 63970.460000 8740.785700 -* 2023 12 9 0 18 0.00000000 -PL56 -1207.265901 -108.428047 7064.838198 -VL56 -35504.771000 66300.565000 -4998.438500 -* 2023 12 9 0 21 0.00000000 -PL56 -1806.102746 1087.985939 6852.187131 -VL56 -30840.412000 66229.060000 -18560.285000 -* 2023 12 9 0 24 0.00000000 -PL56 -2311.312060 2261.228477 6400.558980 -VL56 -25142.399000 63728.864000 -31474.345000 -* 2023 12 9 0 27 0.00000000 -PL56 -2706.579653 3368.008539 5725.696714 -VL56 -18670.299000 58862.204000 -43291.900000 -* 2023 12 9 0 30 0.00000000 -PL56 -2980.497662 4366.957996 4851.110107 -VL56 -11707.823000 51780.130000 -53601.147000 -* 2023 12 9 0 33 0.00000000 -PL56 -3126.895665 5220.200125 3807.281320 -VL56 -4551.160700 42718.585000 -62041.545000 -* 2023 12 9 0 36 0.00000000 -PL56 -3144.955865 5894.819642 2630.617790 -VL56 2503.184900 31991.384000 -68317.309000 -* 2023 12 9 0 39 0.00000000 -PL56 -3039.105428 6364.168032 1362.180718 -VL56 9170.936500 19978.974000 -72208.819000 -* 2023 12 9 0 42 0.00000000 -PL56 -2818.690629 6608.943951 46.234855 -VL56 15191.749000 7114.670600 -73580.943000 -* 2023 12 9 0 45 0.00000000 -PL56 -2497.447013 6617.998984 -1271.328199 -VL56 20339.917000 -6131.911100 -72388.647000 -* 2023 12 9 0 48 0.00000000 -PL56 -2092.791018 6388.823856 -2544.634633 -VL56 24433.542000 -19273.770000 -68678.974000 -* 2023 12 9 0 51 0.00000000 -PL56 -1624.964029 5927.680936 -3729.463374 -VL56 27341.553000 -31826.585000 -62587.556000 -* 2023 12 9 0 54 0.00000000 -PL56 -1116.080498 5249.392099 -4784.790110 -VL56 28987.269000 -43326.557000 -54332.598000 -* 2023 12 9 0 57 0.00000000 -PL56 -589.131354 4376.804958 -5674.191377 -VL56 29349.982000 -53348.319000 -44205.472000 -* 2023 12 9 1 0 0.00000000 -PL56 -66.986276 3339.969216 -6367.063663 -VL56 28463.556000 -61519.502000 -32559.441000 -* 2023 12 9 1 3 0.00000000 -PL56 428.563849 2175.059388 -6839.624586 -VL56 26413.198000 -67533.806000 -19796.813000 -* 2023 12 9 1 6 0.00000000 -PL56 877.683674 923.093127 -7075.669748 -VL56 23329.961000 -71160.784000 -6355.026900 -* 2023 12 9 1 9 0.00000000 -PL56 1263.259906 -371.504822 -7067.081732 -VL56 19384.017000 -72253.377000 7307.158200 -* 2023 12 9 1 12 0.00000000 -PL56 1571.535105 -1662.453001 -6814.085403 -VL56 14776.649000 -70753.011000 20723.995000 -* 2023 12 9 1 15 0.00000000 -PL56 1792.590048 -2903.231280 -6325.247444 -VL56 9731.547200 -66691.976000 33436.629000 -* 2023 12 9 1 18 0.00000000 -PL56 1920.664721 -4048.725996 -5617.226665 -VL56 4485.564700 -60194.206000 45007.122000 -* 2023 12 9 1 21 0.00000000 -PL56 1954.307228 -5056.866080 -4714.267556 -VL56 -721.142470 -51473.132000 55033.102000 -* 2023 12 9 1 24 0.00000000 -PL56 1896.343116 -5890.187863 -3647.433077 -VL56 -5655.140700 -40826.105000 63161.516000 -* 2023 12 9 1 27 0.00000000 -PL56 1753.663562 -6517.274577 -2453.593996 -VL56 -10099.785000 -28625.948000 69102.249000 -* 2023 12 9 1 30 0.00000000 -PL56 1536.835810 -6914.008927 -1174.187928 -VL56 -13864.774000 -15308.524000 72639.850000 -* 2023 12 9 1 33 0.00000000 -PL56 1259.550544 -7064.571486 146.217168 -VL56 -16794.686000 -1357.084400 73643.304000 -* 2023 12 9 1 36 0.00000000 -PL56 937.928594 -6962.127956 1461.503514 -VL56 -18775.927000 12716.581000 72072.075000 -* 2023 12 9 1 39 0.00000000 -PL56 589.719379 -6609.163267 2725.662168 -VL56 -19741.773000 26392.375000 67978.978000 -* 2023 12 9 1 42 0.00000000 -PL56 233.431075 -6017.437519 3894.460151 -VL56 -19674.897000 39163.380000 61507.770000 -* 2023 12 9 1 45 0.00000000 -PL56 -112.564918 -5207.563283 4927.033583 -VL56 -18607.583000 50555.973000 52887.693000 -* 2023 12 9 1 48 0.00000000 -PL56 -430.907294 -4208.235444 5787.340363 -VL56 -16619.199000 60148.667000 42423.571000 -* 2023 12 9 1 51 0.00000000 -PL56 -706.052034 -3055.152148 6445.421315 -VL56 -13831.334000 67587.298000 30484.216000 -* 2023 12 9 1 54 0.00000000 -PL56 -924.977483 -1789.678285 6878.424048 -VL56 -10401.424000 72598.027000 17487.959000 -* 2023 12 9 1 57 0.00000000 -PL56 -1077.758828 -457.319722 7071.362220 -VL56 -6514.750600 74995.872000 3888.026100 -* 2023 12 9 2 0 0.00000000 -PL56 -1157.992353 893.936979 7017.606539 -VL56 -2375.708700 74690.945000 -9842.899500 -* 2023 12 9 2 3 0.00000000 -PL56 -1163.053881 2215.366348 6719.094034 -VL56 1801.771200 71691.237000 -23228.287000 -* 2023 12 9 2 6 0.00000000 -PL56 -1094.181521 3459.268090 6186.254375 -VL56 5804.101500 66102.383000 -35803.621000 -* 2023 12 9 2 9 0.00000000 -PL56 -956.383256 4580.698852 5437.656822 -VL56 9427.602400 58124.241000 -47131.583000 -* 2023 12 9 2 12 0.00000000 -PL56 -758.172794 5539.116878 4499.384543 -VL56 12487.900000 48044.707000 -56817.000000 -* 2023 12 9 2 15 0.00000000 -PL56 -511.143717 6299.883133 3404.146494 -VL56 14828.551000 36229.793000 -64521.126000 -* 2023 12 9 2 18 0.00000000 -PL56 -229.399115 6835.557565 2190.150635 -VL56 16328.265000 23111.147000 -69973.631000 -* 2023 12 9 2 21 0.00000000 -PL56 71.140186 7126.941029 899.763761 -VL56 16907.232000 9169.725200 -72984.290000 -* 2023 12 9 2 24 0.00000000 -PL56 373.521793 7163.796332 -421.995220 -VL56 16531.163000 -5083.014600 -73449.730000 -* 2023 12 9 2 27 0.00000000 -PL56 660.599915 6945.218751 -1729.062933 -VL56 15212.924000 -19125.035000 -71357.545000 -* 2023 12 9 2 30 0.00000000 -PL56 915.880731 6479.634120 -2975.975394 -VL56 13011.732000 -32444.923000 -66786.324000 -* 2023 12 9 2 33 0.00000000 -PL56 1124.332410 5784.432412 -4119.473195 -VL56 10030.182000 -44561.285000 -59901.531000 -* 2023 12 9 2 36 0.00000000 -PL56 1273.125551 4885.261551 -5120.006592 -VL56 6409.413700 -55040.806000 -50948.404000 -* 2023 12 9 2 39 0.00000000 -PL56 1352.269235 3815.018900 -5943.082462 -VL56 2322.437100 -63513.586000 -40241.663000 -* 2023 12 9 2 42 0.00000000 -PL56 1355.114196 2612.596327 -6560.408938 -VL56 -2033.877100 -69685.231000 -28153.486000 -* 2023 12 9 2 45 0.00000000 -PL56 1278.703703 1321.436864 -6950.809998 -VL56 -6447.635000 -73345.585000 -15100.026000 -* 2023 12 9 2 48 0.00000000 -PL56 1123.962387 -12.035758 -7100.894459 -VL56 -10701.012000 -74374.321000 -1527.808300 -* 2023 12 9 2 51 0.00000000 -PL56 895.717891 -1340.064811 -7005.475881 -VL56 -14579.733000 -72743.944000 12100.369000 -* 2023 12 9 2 54 0.00000000 -PL56 602.553731 -2615.236109 -6667.736222 -VL56 -17882.248000 -68519.772000 25319.813000 -* 2023 12 9 2 57 0.00000000 -PL56 256.499984 -3792.134349 -6099.139896 -VL56 -20428.641000 -61858.184000 37677.301000 -* 2023 12 9 3 0 0.00000000 -PL56 -127.433809 -4828.946704 -5319.094389 -VL56 -22069.082000 -53002.038000 48745.929000 -* 2023 12 9 3 3 0.00000000 -PL56 -531.869244 -5688.960487 -4354.350535 -VL56 -22691.387000 -42273.718000 58139.020000 -* 2023 12 9 3 6 0.00000000 -PL56 -937.796172 -6341.906009 -3238.150187 -VL56 -22227.390000 -30064.833000 65524.271000 -* 2023 12 9 3 9 0.00000000 -PL56 -1325.410551 -6765.088838 -2009.130120 -VL56 -20657.657000 -16822.997000 70636.583000 -* 2023 12 9 3 12 0.00000000 -PL56 -1675.018398 -6944.257337 -710.007903 -VL56 -18014.071000 -3035.741900 73289.339000 -* 2023 12 9 3 15 0.00000000 -PL56 -1967.964033 -6874.155073 613.912942 -VL56 -14379.929000 10788.282000 73382.960000 -* 2023 12 9 3 18 0.00000000 -PL56 -2187.537242 -6558.719215 1916.359689 -VL56 -9887.473500 24139.660000 70909.839000 -* 2023 12 9 3 21 0.00000000 -PL56 -2319.812513 -6010.908241 3151.760574 -VL56 -4712.801700 36528.884000 65955.278000 -* 2023 12 9 3 24 0.00000000 -PL56 -2354.373854 -5252.162548 4276.893563 -VL56 931.665560 47506.168000 58694.121000 -* 2023 12 9 3 27 0.00000000 -PL56 -2284.887375 -4311.527910 5252.437500 -VL56 6806.425100 56678.906000 49383.467000 -* 2023 12 9 3 30 0.00000000 -PL56 -2109.497041 -3224.491559 6044.364055 -VL56 12655.251000 63726.172000 38352.402000 -* 2023 12 9 3 33 0.00000000 -PL56 -1831.024720 -2031.585950 6625.119683 -VL56 18216.523000 68409.774000 25988.881000 -* 2023 12 9 3 36 0.00000000 -PL56 -1456.966051 -776.831984 6974.559091 -VL56 23234.379000 70581.207000 12725.622000 -* 2023 12 9 3 39 0.00000000 -PL56 -999.288788 493.916218 7080.612268 -VL56 27469.505000 70185.588000 -975.455050 -* 2023 12 9 3 42 0.00000000 -PL56 -474.042736 1734.661848 6939.671937 -VL56 30709.356000 67261.813000 -14638.479000 -* 2023 12 9 3 45 0.00000000 -PL56 99.210197 2900.936767 6556.703312 -VL56 32777.736000 61940.151000 -27789.436000 -* 2023 12 9 3 48 0.00000000 -PL56 698.127456 3951.401790 5945.070490 -VL56 33543.121000 54436.871000 -39971.745000 -* 2023 12 9 3 51 0.00000000 -PL56 1298.452014 4849.325193 5126.085822 -VL56 32925.319000 45046.070000 -50761.384000 -* 2023 12 9 3 54 0.00000000 -PL56 1874.985879 5563.893072 4128.289554 -VL56 30900.646000 34129.190000 -59781.604000 -* 2023 12 9 3 57 0.00000000 -PL56 2402.635581 6071.302216 2986.475431 -VL56 27504.714000 22101.368000 -66716.386000 -* 2023 12 9 4 0 0.00000000 -PL56 2857.489397 6355.595989 1740.485192 -VL56 22833.025000 9416.472400 -71322.863000 -* 2023 12 9 4 3 0.00000000 -PL56 3217.874295 6409.197151 433.799729 -VL56 17038.106000 -3451.409100 -73440.901000 -* 2023 12 9 4 6 0.00000000 -PL56 3465.339696 6233.104661 -888.010369 -VL56 10324.389000 -16026.641000 -72999.093000 -* 2023 12 9 4 9 0.00000000 -PL56 3585.522590 5836.750886 -2178.910325 -VL56 2940.166800 -27850.897000 -70017.342000 -* 2023 12 9 4 12 0.00000000 -PL56 3568.852306 5237.527412 -3394.037287 -VL56 -4832.226900 -38501.010000 -64605.469000 -* 2023 12 9 4 15 0.00000000 -PL56 3411.059493 4460.003893 -4491.279789 -VL56 -12688.141000 -47605.046000 -56958.194000 -* 2023 12 9 4 18 0.00000000 -PL56 3113.465739 3534.883980 -5432.732250 -VL56 -20313.094000 -54855.231000 -47346.468000 -* 2023 12 9 4 21 0.00000000 -PL56 2683.047893 2497.757693 -6185.974253 -VL56 -27395.269000 -60017.770000 -36106.815000 -* 2023 12 9 4 24 0.00000000 -PL56 2132.279539 1387.707596 -6725.136901 -VL56 -33637.741000 -62939.222000 -23628.436000 -* 2023 12 9 4 27 0.00000000 -PL56 1478.760284 245.830920 -7031.730576 -VL56 -38769.635000 -63549.363000 -10339.735000 -* 2023 12 9 4 30 0.00000000 -PL56 744.651344 -886.265328 -7095.226367 -VL56 -42556.656000 -61861.612000 3305.422700 -* 2023 12 9 4 33 0.00000000 -PL56 -44.068611 -1967.952410 -6913.386704 -VL56 -44810.371000 -57970.685000 16842.050000 -* 2023 12 9 4 36 0.00000000 -PL56 -858.502364 -2961.005416 -6492.341092 -VL56 -45396.188000 -52048.093000 29807.760000 -* 2023 12 9 4 39 0.00000000 -PL56 -1667.866624 -3830.934404 -5846.411467 -VL56 -44240.089000 -44336.048000 41757.097000 -* 2023 12 9 4 42 0.00000000 -PL56 -2440.630132 -4548.183417 -4997.679438 -VL56 -41333.694000 -35139.066000 52275.631000 -* 2023 12 9 4 45 0.00000000 -PL56 -3145.726333 -5089.162039 -3975.299732 -VL56 -36737.371000 -24813.554000 60994.287000 -* 2023 12 9 4 48 0.00000000 -PL56 -3753.800110 -5437.068961 -2814.558668 -VL56 -30580.713000 -13755.113000 67603.046000 -* 2023 12 9 4 51 0.00000000 -PL56 -4238.435975 -5582.467708 -1555.697206 -VL56 -23060.090000 -2383.873500 71863.329000 -* 2023 12 9 4 54 0.00000000 -PL56 -4577.313657 -5523.583854 -242.527757 -VL56 -14432.921000 8871.762300 73618.410000 -* 2023 12 9 4 57 0.00000000 -PL56 -4753.230229 -5266.300053 1079.110727 -VL56 -5008.619400 19592.301000 72800.778000 -* 2023 12 9 5 0 0.00000000 -PL56 -4754.932930 -4823.840426 2362.998115 -VL56 4863.311800 29384.348000 69435.860000 -* 2023 12 9 5 3 0.00000000 -PL56 -4577.715082 -4216.152762 3564.205717 -VL56 14807.530000 37896.723000 63641.233000 -* 2023 12 9 5 6 0.00000000 -PL56 -4223.744043 -3469.021398 4640.718164 -VL56 24438.237000 44834.179000 55621.905000 -* 2023 12 9 5 9 0.00000000 -PL56 -3702.105290 -2612.956757 5554.936291 -VL56 33375.193000 49968.379000 45661.825000 -* 2023 12 9 5 12 0.00000000 -PL56 -3028.563680 -1681.920714 6274.996920 -VL56 41258.921000 53145.047000 34112.346000 -* 2023 12 9 5 15 0.00000000 -PL56 -2225.059946 -711.953379 6775.871229 -VL56 47764.980000 54287.984000 21379.147000 -* 2023 12 9 5 18 0.00000000 -PL56 -1318.961176 260.245579 7040.209678 -VL56 52616.868000 53399.927000 7907.179900 -* 2023 12 9 5 21 0.00000000 -PL56 -342.099910 1198.716761 7058.906842 -VL56 55596.489000 50559.753000 -5835.024900 -* 2023 12 9 5 24 0.00000000 -PL56 670.357842 2069.573161 6831.390833 -VL56 56552.857000 45917.858000 -19370.485000 -* 2023 12 9 5 27 0.00000000 -PL56 1681.185662 2842.227229 6365.631647 -VL56 55408.942000 39689.068000 -32229.667000 -* 2023 12 9 5 30 0.00000000 -PL56 2652.468884 3490.470026 5677.868461 -VL56 52165.859000 32143.476000 -43965.812000 -* 2023 12 9 5 33 0.00000000 -PL56 3547.033007 3993.373027 4792.064931 -VL56 46904.811000 23595.739000 -54169.938000 -* 2023 12 9 5 36 0.00000000 -PL56 4329.880228 4335.981116 3739.095678 -VL56 39785.986000 14392.723000 -62485.341000 -* 2023 12 9 5 39 0.00000000 -PL56 4969.578106 4509.771438 2555.687948 -VL56 31044.507000 4899.910800 -68620.736000 -* 2023 12 9 5 42 0.00000000 -PL56 5439.545494 4512.857326 1283.137428 -VL56 20982.505000 -4513.346600 -72361.273000 -* 2023 12 9 5 45 0.00000000 -PL56 5719.168269 4349.922605 -34.153176 -VL56 9958.788500 -13488.837000 -73577.652000 -* 2023 12 9 5 48 0.00000000 -PL56 5794.692360 4031.888574 -1350.259892 -VL56 -1625.616400 -21694.072000 -72230.776000 -* 2023 12 9 5 51 0.00000000 -PL56 5659.845564 3575.329359 -2619.377250 -VL56 -13343.176000 -28835.458000 -68372.784000 -* 2023 12 9 5 54 0.00000000 -PL56 5316.162645 3001.667907 -3797.440789 -VL56 -24756.872000 -34669.450000 -62144.216000 -* 2023 12 9 5 57 0.00000000 -PL56 4773.002940 2336.197676 -4843.667400 -VL56 -35437.192000 -39010.759000 -53767.809000 -* 2023 12 9 6 0 0.00000000 -PL56 4047.263183 1606.976896 -5721.955290 -VL56 -44978.797000 -41738.131000 -43539.081000 -* 2023 12 9 6 3 0.00000000 -PL56 3162.806536 843.651253 -6402.089863 -VL56 -53015.316000 -42796.572000 -31814.597000 -* 2023 12 9 6 6 0.00000000 -PL56 2149.640746 76.261417 -6860.727683 -VL56 -59232.344000 -42196.874000 -18999.024000 -* 2023 12 9 6 9 0.00000000 -PL56 1042.882636 -665.918632 -7082.138146 -VL56 -63378.225000 -40012.796000 -5531.311900 -* 2023 12 9 6 12 0.00000000 -PL56 -118.452704 -1355.474046 -7058.698323 -VL56 -65272.831000 -36376.188000 8129.050600 -* 2023 12 9 6 15 0.00000000 -PL56 -1292.804572 -1967.838040 -6791.132988 -VL56 -64814.342000 -31470.438000 21516.297000 -* 2023 12 9 6 18 0.00000000 -PL56 -2437.521147 -2482.151005 -6288.502695 -VL56 -61983.990000 -25522.694000 34172.416000 -* 2023 12 9 6 21 0.00000000 -PL56 -3510.379146 -2881.968147 -5567.935917 -VL56 -56848.351000 -18794.704000 45661.349000 -* 2023 12 9 6 24 0.00000000 -PL56 -4471.127942 -3155.795615 -4654.108536 -VL56 -49559.868000 -11573.081000 55582.930000 -* 2023 12 9 6 27 0.00000000 -PL56 -5283.013810 -3297.437606 -3578.465632 -VL56 -40353.892000 -4157.968500 63587.461000 -* 2023 12 9 6 30 0.00000000 -PL56 -5914.222470 -3306.134844 -2378.194179 -VL56 -29542.576000 3148.759800 69388.820000 -* 2023 12 9 6 33 0.00000000 -PL56 -6339.178316 -3186.484429 -1094.968013 -VL56 -17504.997000 10055.885000 72776.373000 -* 2023 12 9 6 36 0.00000000 -PL56 -6539.634011 -2948.138193 226.499041 -VL56 -4673.846800 16294.975000 73624.276000 -* 2023 12 9 6 39 0.00000000 -PL56 -6505.491650 -2605.288341 1540.040059 -VL56 8480.991900 21631.741000 71897.660000 -* 2023 12 9 6 42 0.00000000 -PL56 -6235.305171 -2175.961622 2799.699372 -VL56 21471.437000 25875.902000 67654.854000 -* 2023 12 9 6 45 0.00000000 -PL56 -5736.429821 -1681.155370 3961.396191 -VL56 33810.938000 28888.721000 61045.159000 -* 2023 12 9 6 48 0.00000000 -PL56 -5024.814637 -1143.860727 4984.514018 -VL56 45034.495000 30587.998000 52302.810000 -* 2023 12 9 6 51 0.00000000 -PL56 -4124.446712 -588.022807 5833.344010 -VL56 54716.793000 30949.991000 41737.027000 -* 2023 12 9 6 54 0.00000000 -PL56 -3066.488903 -37.492576 6478.329778 -VL56 62488.364000 30008.577000 29720.005000 -* 2023 12 9 6 57 0.00000000 -PL56 -1888.146271 484.984394 6897.078917 -VL56 68049.308000 27851.886000 16673.092000 -* 2023 12 9 7 0 0.00000000 -PL56 -631.312061 958.695732 7075.108633 -VL56 71180.154000 24616.650000 3051.262900 -* 2023 12 9 7 3 0.00000000 -PL56 658.948227 1365.774374 7006.314790 -VL56 71748.963000 20480.961000 -10672.146000 -* 2023 12 9 7 6 0.00000000 -PL56 1936.023509 1691.869023 6693.160971 -VL56 69716.459000 15655.838000 -24021.104000 -* 2023 12 9 7 9 0.00000000 -PL56 3153.445636 1926.650805 6146.586978 -VL56 65137.916000 10375.533000 -36532.389000 -* 2023 12 9 7 12 0.00000000 -PL56 4266.588548 2064.140199 5385.640427 -VL56 58162.344000 4887.295100 -47770.919000 -* 2023 12 9 7 15 0.00000000 -PL56 5234.322582 2102.845442 4436.834982 -VL56 49028.259000 -559.237250 -57344.545000 -* 2023 12 9 7 18 0.00000000 -PL56 6020.566893 2045.710090 3333.250906 -VL56 38056.694000 -5722.684600 -64918.104000 -* 2023 12 9 7 21 0.00000000 -PL56 6595.679117 1899.868105 2113.388740 -VL56 25639.835000 -10380.527000 -70226.458000 -* 2023 12 9 7 24 0.00000000 -PL56 6937.613426 1676.216870 819.818151 -VL56 12226.784000 -14338.654000 -73084.240000 -* 2023 12 9 7 27 0.00000000 -PL56 7032.795957 1388.827099 -502.334148 -VL56 -1693.298300 -17439.806000 -73393.467000 -* 2023 12 9 7 30 0.00000000 -PL56 6876.669138 1054.218778 -1806.996871 -VL56 -15610.947000 -19570.060000 -71147.413000 -* 2023 12 9 7 33 0.00000000 -PL56 6473.878555 690.536309 -3048.795845 -VL56 -29016.443000 -20663.386000 -66430.015000 -* 2023 12 9 7 36 0.00000000 -PL56 5838.098918 316.666432 -4184.656441 -VL56 -41419.572000 -20703.421000 -59411.825000 -* 2023 12 9 7 39 0.00000000 -PL56 4991.509893 -48.654583 -5175.301835 -VL56 -52368.499000 -19722.948000 -50342.682000 -* 2023 12 9 7 42 0.00000000 -PL56 3963.955803 -387.702338 -5986.586306 -VL56 -61465.855000 -17800.954000 -39541.020000 -* 2023 12 9 7 45 0.00000000 -PL56 2791.841185 -684.554964 -6590.625129 -VL56 -68382.127000 -15057.804000 -27381.954000 -* 2023 12 9 7 48 0.00000000 -PL56 1516.809216 -925.782772 -6966.696125 -VL56 -72866.244000 -11648.845000 -14283.864000 -* 2023 12 9 7 51 0.00000000 -PL56 184.258348 -1101.011323 -7101.894088 -VL56 -74753.071000 -7756.866900 -694.637950 -* 2023 12 9 7 54 0.00000000 -PL56 -1158.254202 -1203.340371 -6991.536040 -VL56 -73968.486000 -3583.648800 12922.376000 -* 2023 12 9 7 57 0.00000000 -PL56 -2462.676057 -1229.606299 -6639.312831 -VL56 -70531.798000 658.931100 26102.487000 -* 2023 12 9 8 0 0.00000000 -PL56 -3682.145782 -1180.481219 -6057.184857 -VL56 -64555.799000 4758.090700 38393.837000 -* 2023 12 9 8 3 0.00000000 -PL56 -4772.654542 -1060.405728 -5265.024823 -VL56 -56244.168000 8509.407500 49371.528000 -* 2023 12 9 8 6 0.00000000 -PL56 -5694.643604 -877.357032 -4290.006175 -VL56 -45886.442000 11725.850000 58651.672000 -* 2023 12 9 8 9 0.00000000 -PL56 -6414.478983 -642.457349 -3165.735896 -VL56 -33849.717000 14246.388000 65905.544000 -* 2023 12 9 8 12 0.00000000 -PL56 -6905.745014 -369.434108 -1931.144833 -VL56 -20566.665000 15943.774000 70872.360000 -* 2023 12 9 8 15 0.00000000 -PL56 -7150.293371 -73.951646 -629.160146 -VL56 -6520.459000 16730.997000 73370.551000 -* 2023 12 9 8 18 0.00000000 -PL56 -7138.989250 227.158526 694.801312 -VL56 7773.984900 16565.978000 73306.173000 -* 2023 12 9 8 21 0.00000000 -PL56 -6872.102008 516.732114 1994.456651 -VL56 21790.103000 15453.999000 70677.349000 -* 2023 12 9 8 24 0.00000000 -PL56 -6359.322128 778.126902 3224.326885 -VL56 35011.193000 13447.603000 65575.061000 -* 2023 12 9 8 27 0.00000000 -PL56 -5619.395391 996.055420 4341.383315 -VL56 46951.282000 10644.159000 58179.627000 -* 2023 12 9 8 30 0.00000000 -PL56 -4679.391509 1157.352194 5306.592094 -VL56 57174.405000 7181.099800 48753.040000 -* 2023 12 9 8 33 0.00000000 -PL56 -3573.652889 1251.636746 6086.291828 -VL56 65310.881000 3229.184700 37628.269000 -* 2023 12 9 8 36 0.00000000 -PL56 -2342.480259 1271.842524 6653.359847 -VL56 71070.263000 -1015.594000 25196.610000 -* 2023 12 9 8 39 0.00000000 -PL56 -1030.610748 1214.590230 6988.133735 -VL56 74251.464000 -5341.079900 11893.153000 -* 2023 12 9 8 42 0.00000000 -PL56 314.446005 1080.390916 7079.058270 -VL56 74748.144000 -9528.817100 -1819.009600 -* 2023 12 9 8 45 0.00000000 -PL56 1644.144247 873.671887 6923.053635 -VL56 72551.666000 -13363.790000 -15463.853000 -* 2023 12 9 8 48 0.00000000 -PL56 2910.658796 602.626497 6525.606047 -VL56 67750.470000 -16644.155000 -28568.182000 -* 2023 12 9 8 51 0.00000000 -PL56 4068.610625 278.892454 5900.579969 -VL56 60527.143000 -19190.543000 -40676.858000 -* 2023 12 9 8 54 0.00000000 -PL56 5076.708463 -82.931504 5069.752193 -VL56 51151.963000 -20854.669000 -51368.347000 -* 2023 12 9 8 57 0.00000000 -PL56 5899.249082 -465.914795 4062.076332 -VL56 39973.740000 -21526.846000 -60269.145000 -* 2023 12 9 9 0 0.00000000 -PL56 6507.423903 -851.545513 2912.692693 -VL56 27407.464000 -21141.926000 -67067.545000 -* 2023 12 9 9 3 0.00000000 -PL56 6880.376160 -1220.571240 1661.705730 -VL56 13918.752000 -19683.257000 -71525.447000 -* 2023 12 9 9 6 0.00000000 -PL56 7005.954941 -1553.892975 352.769393 -VL56 6.304000 -17184.645000 -73487.753000 -* 2023 12 9 9 9 0.00000000 -PL56 6881.133124 -1833.471171 -968.465923 -VL56 -13818.170000 -13729.719000 -72888.633000 -* 2023 12 9 9 12 0.00000000 -PL56 6512.062275 -2043.197576 -2255.986196 -VL56 -27050.036000 -9448.677400 -69753.518000 -* 2023 12 9 9 15 0.00000000 -PL56 5913.762302 -2169.688433 -3465.051271 -VL56 -39211.722000 -4512.942300 -64197.804000 -* 2023 12 9 9 18 0.00000000 -PL56 5109.467548 -2202.960806 -4553.766183 -VL56 -49870.870000 872.390010 -56421.135000 -* 2023 12 9 9 21 0.00000000 -PL56 4129.671667 -2136.961548 -5484.525378 -VL56 -58655.643000 6477.339600 -46698.839000 -* 2023 12 9 9 24 0.00000000 -PL56 3010.919593 -1969.928451 -6225.280235 -VL56 -65267.268000 12056.811000 -35370.922000 -* 2023 12 9 9 27 0.00000000 -PL56 1794.408931 -1704.570079 -6750.589073 -VL56 -69488.658000 17360.852000 -22829.359000 -* 2023 12 9 9 30 0.00000000 -PL56 524.463135 -1348.060062 -7042.434154 -VL56 -71190.389000 22145.001000 -9504.743400 -* 2023 12 9 9 33 0.00000000 -PL56 -753.072499 -911.849144 -7090.789078 -VL56 -70333.013000 26180.123000 4147.953000 -* 2023 12 9 9 36 0.00000000 -PL56 -1992.456956 -411.302924 -6893.933159 -VL56 -66967.284000 29261.876000 17663.217000 -* 2023 12 9 9 39 0.00000000 -PL56 -3149.658275 134.826777 -6458.511951 -VL56 -61231.699000 31219.763000 30579.332000 -* 2023 12 9 9 42 0.00000000 -PL56 -4183.891726 705.082749 -5799.342616 -VL56 -53347.646000 31924.966000 42452.343000 -* 2023 12 9 9 45 0.00000000 -PL56 -5059.054352 1276.117085 -4938.967446 -VL56 -43612.593000 31297.240000 52870.272000 -* 2023 12 9 9 48 0.00000000 -PL56 -5745.013526 1823.617884 -3906.951406 -VL56 -32390.668000 29310.523000 61467.165000 -* 2023 12 9 9 51 0.00000000 -PL56 -6218.699399 2323.319453 -2738.926552 -VL56 -20100.184000 25996.368000 67937.020000 -* 2023 12 9 9 54 0.00000000 -PL56 -6464.950164 2752.051743 -1475.400871 -VL56 -7198.772600 21444.909000 72045.979000 -* 2023 12 9 9 57 0.00000000 -PL56 -6477.067371 3088.784243 -160.362988 -VL56 5833.866800 15803.216000 73642.665000 -* 2023 12 9 10 0 0.00000000 -PL56 -6257.043430 3315.612680 1160.272573 -VL56 18515.057000 9270.548400 72665.355000 -* 2023 12 9 10 3 0.00000000 -PL56 -5815.437492 3418.635480 2440.315965 -VL56 30378.812000 2090.947200 69145.383000 -* 2023 12 9 10 6 0.00000000 -PL56 -5170.901461 3388.673317 3634.972508 -VL56 40994.988000 -5456.757200 63205.962000 -* 2023 12 9 10 9 0.00000000 -PL56 -4349.382143 3221.792960 4702.459446 -VL56 49985.899000 -13070.612000 55057.320000 -* 2023 12 9 10 12 0.00000000 -PL56 -3383.040404 2919.608697 5605.498073 -VL56 57040.758000 -20438.300000 44987.965000 -* 2023 12 9 10 15 0.00000000 -PL56 -2308.946721 2489.352142 6312.622886 -VL56 61926.418000 -27250.183000 33353.213000 -* 2023 12 9 10 18 0.00000000 -PL56 -1167.612718 1943.708440 6799.264856 -VL56 64494.516000 -33212.016000 20561.604000 -* 2023 12 9 10 21 0.00000000 -PL56 -1.427448 1300.426597 7048.573038 -VL56 64685.012000 -38057.303000 7059.601100 -* 2023 12 9 10 24 0.00000000 -PL56 1146.932809 581.724150 7051.963065 -VL56 62525.873000 -41557.783000 -6683.345800 -* 2023 12 9 10 27 0.00000000 -PL56 2236.071306 -186.491780 6809.389343 -VL56 58130.614000 -43533.201000 -20190.453000 -* 2023 12 9 10 30 0.00000000 -PL56 3227.365160 -975.562820 6329.338310 -VL56 51692.842000 -43859.367000 -32993.097000 -* 2023 12 9 10 33 0.00000000 -PL56 4086.343471 -1755.149650 5628.542880 -VL56 43478.793000 -42474.588000 -44646.194000 -* 2023 12 9 10 36 0.00000000 -PL56 4783.904721 -2494.399340 4731.419195 -VL56 33816.945000 -39384.025000 -54743.635000 -* 2023 12 9 10 39 0.00000000 -PL56 5297.329880 -3163.168651 3669.238860 -VL56 23085.749000 -34661.480000 -62932.136000 -* 2023 12 9 10 42 0.00000000 -PL56 5611.056293 -3733.258031 2479.053113 -VL56 11699.299000 -28448.661000 -68924.814000 -* 2023 12 9 10 45 0.00000000 -PL56 5717.172380 -4179.600676 1202.395202 -VL56 90.826080 -20951.063000 -72512.129000 -* 2023 12 9 10 48 0.00000000 -PL56 5615.608730 -4481.352315 -116.189788 -VL56 -11304.455000 -12430.938000 -73570.129000 -* 2023 12 9 10 51 0.00000000 -PL56 5314.017357 -4622.827694 -1430.733216 -VL56 -22066.680000 -3197.404100 -72065.132000 -* 2023 12 9 10 54 0.00000000 -PL56 4827.343001 -4594.236311 -2695.484619 -VL56 -31808.097000 6405.920900 -68054.828000 -* 2023 12 9 10 57 0.00000000 -PL56 4177.108516 -4392.180846 -3866.534143 -VL56 -40187.821000 16014.702000 -61685.176000 -* 2023 12 9 11 0 0.00000000 -PL56 3390.455083 -4019.898257 -4903.347320 -VL56 -46924.257000 25258.572000 -53183.941000 -* 2023 12 9 11 3 0.00000000 -PL56 2498.988717 -3487.236551 -5770.152702 -VL56 -51804.211000 33775.747000 -42850.774000 -* 2023 12 9 11 6 0.00000000 -PL56 1537.492837 -2810.376492 -6437.133586 -VL56 -54688.455000 41226.519000 -31045.578000 -* 2023 12 9 11 9 0.00000000 -PL56 542.568270 -2011.319129 -6881.398130 -VL56 -55514.539000 47305.926000 -18175.650000 -* 2023 12 9 11 12 0.00000000 -PL56 -448.751046 -1117.156286 -7087.710480 -VL56 -54296.495000 51755.002000 -4681.975500 -* 2023 12 9 11 15 0.00000000 -PL56 -1400.354009 -159.152839 -7048.966407 -VL56 -51122.178000 54370.508000 8975.224900 -* 2023 12 9 11 18 0.00000000 -PL56 -2278.339615 828.327451 -6766.416916 -VL56 -46148.354000 55012.574000 22330.227000 -* 2023 12 9 11 21 0.00000000 -PL56 -3052.202310 1809.025493 -6249.638059 -VL56 -39594.269000 53611.375000 34926.000000 -* 2023 12 9 11 24 0.00000000 -PL56 -3695.882555 2746.089359 -5516.248857 -VL56 -31733.241000 50171.516000 46328.291000 -* 2023 12 9 11 27 0.00000000 -PL56 -4188.658076 3603.443235 -4591.375186 -VL56 -22883.182000 44774.807000 56139.707000 -* 2023 12 9 11 30 0.00000000 -PL56 -4515.843383 4347.179062 -3506.853345 -VL56 -13394.827000 37580.021000 64014.292000 -* 2023 12 9 11 33 0.00000000 -PL56 -4669.262406 4946.916011 -2300.186575 -VL56 -3638.435800 28819.498000 69670.433000 -* 2023 12 9 11 36 0.00000000 -PL56 -4647.473857 5377.070144 -1013.279238 -VL56 6010.401000 18792.491000 72902.484000 -* 2023 12 9 11 39 0.00000000 -PL56 -4455.733366 5617.974367 309.018481 -VL56 15185.717000 7855.218100 73590.134000 -* 2023 12 9 11 42 0.00000000 -PL56 -4105.681803 5656.786210 1620.505721 -VL56 23546.482000 -3592.727800 71704.308000 -* 2023 12 9 11 45 0.00000000 -PL56 -3614.770936 5488.130728 2875.297848 -VL56 30790.338000 -15124.169000 67309.107000 -* 2023 12 9 11 48 0.00000000 -PL56 -3005.448197 5114.438455 4029.489916 -VL56 36666.362000 -26301.939000 60559.578000 -* 2023 12 9 11 51 0.00000000 -PL56 -2304.145913 4545.963975 5042.734741 -VL56 40983.998000 -36696.718000 51694.672000 -* 2023 12 9 11 54 0.00000000 -PL56 -1540.131219 3800.488921 5879.675523 -VL56 43619.537000 -45904.245000 41028.073000 -* 2023 12 9 11 57 0.00000000 -PL56 -744.272082 2902.724218 6511.178827 -VL56 44519.109000 -53561.416000 28935.341000 -* 2023 12 9 12 0 0.00000000 -PL56 52.220983 1883.444103 6915.325220 -VL56 43698.239000 -59359.743000 15839.961000 -* 2023 12 9 12 3 0.00000000 -PL56 819.022979 778.394943 7078.137307 -VL56 41239.115000 -63056.975000 2198.395900 -* 2023 12 9 12 6 0.00000000 -PL56 1527.849881 -372.981257 6994.033198 -VL56 37285.257000 -64486.004000 -11515.541000 -* 2023 12 9 12 9 0.00000000 -PL56 2153.501231 -1528.964220 6666.000657 -VL56 32034.424000 -63561.767000 -24826.105000 -* 2023 12 9 12 12 0.00000000 -PL56 2674.758143 -2647.072759 6105.491828 -VL56 25729.662000 -60285.240000 -37271.181000 -* 2023 12 9 12 15 0.00000000 -PL56 3075.110390 -3685.634401 5332.038387 -VL56 18649.280000 -54745.273000 -48417.674000 -* 2023 12 9 12 18 0.00000000 -PL56 3343.287455 -4605.354444 4372.592105 -VL56 11095.194000 -47116.720000 -57876.640000 -* 2023 12 9 12 21 0.00000000 -PL56 3473.576420 -5370.828275 3260.605660 -VL56 3380.875400 -37655.871000 -65316.963000 -* 2023 12 9 12 24 0.00000000 -PL56 3465.913140 -5951.936300 2034.873266 -VL56 -4181.625800 -26692.050000 -70478.084000 -* 2023 12 9 12 27 0.00000000 -PL56 3325.739992 -6325.058347 738.167309 -VL56 -11294.673000 -14615.831000 -73180.052000 -* 2023 12 9 12 30 0.00000000 -PL56 3063.637028 -6474.048287 -584.278456 -VL56 -17687.004000 -1864.361100 -73330.153000 -* 2023 12 9 12 33 0.00000000 -PL56 2694.745148 -6390.925516 -1886.382466 -VL56 -23124.797000 11095.182000 -70927.243000 -* 2023 12 9 12 36 0.00000000 -PL56 2238.004208 -6076.242065 -3122.860233 -VL56 -27421.121000 23784.978000 -66060.696000 -* 2023 12 9 12 39 0.00000000 -PL56 1715.247539 -5539.111475 -4250.825730 -VL56 -30442.351000 35734.883000 -58906.455000 -* 2023 12 9 12 42 0.00000000 -PL56 1150.199185 -4796.898599 -5231.281581 -VL56 -32112.328000 46500.980000 -49719.140000 -* 2023 12 9 12 45 0.00000000 -PL56 567.431136 -3874.599178 -6030.439779 -VL56 -32412.995000 55681.848000 -38821.101000 -* 2023 12 9 12 48 0.00000000 -PL56 -8.674542 -2803.947984 -6620.838475 -VL56 -31383.071000 62932.337000 -26590.648000 -* 2023 12 9 12 51 0.00000000 -PL56 -554.916583 -1622.295284 -6982.227043 -VL56 -29114.247000 67975.343000 -13448.466000 -* 2023 12 9 12 54 0.00000000 -PL56 -1050.180507 -371.297497 -7102.205727 -VL56 -25745.621000 70610.835000 156.131420 -* 2023 12 9 12 57 0.00000000 -PL56 -1476.230611 904.534548 -6976.613967 -VL56 -21456.708000 70722.588000 13759.396000 -* 2023 12 9 13 0 0.00000000 -PL56 -1818.366457 2159.386095 -6609.664152 -VL56 -16459.348000 68282.492000 26897.042000 -* 2023 12 9 13 3 0.00000000 -PL56 -2065.925261 3347.747973 -6013.823732 -VL56 -10988.807000 63352.795000 39118.412000 -* 2023 12 9 13 6 0.00000000 -PL56 -2212.618126 4426.046798 -5209.444208 -VL56 -5294.159700 56086.090000 50000.614000 -* 2023 12 9 13 9 0.00000000 -PL56 -2256.688660 5354.248807 -4224.131593 -VL56 371.777240 46722.352000 59162.920000 -* 2023 12 9 13 12 0.00000000 -PL56 -2200.885803 6097.379822 -3091.859483 -VL56 5763.010500 35582.381000 66280.754000 -* 2023 12 9 13 15 0.00000000 -PL56 -2052.245774 6626.896301 -1851.842646 -VL56 10650.884000 23057.959000 71098.255000 -* 2023 12 9 13 18 0.00000000 -PL56 -1821.690301 6921.848503 -547.198906 -VL56 14833.911000 9598.535100 73439.242000 -* 2023 12 9 13 21 0.00000000 -PL56 -1523.455584 6969.772560 776.560017 -VL56 18146.667000 -4305.390100 73215.001000 -* 2023 12 9 13 24 0.00000000 -PL56 -1174.374682 6767.263105 2073.156249 -VL56 20467.072000 -18141.322000 70429.639000 -* 2023 12 9 13 27 0.00000000 -PL56 -793.046104 6320.173999 3297.223829 -VL56 21721.694000 -31396.465000 65179.972000 -* 2023 12 9 13 30 0.00000000 -PL56 -398.933691 5643.440675 4405.945117 -VL56 21888.043000 -43577.913000 57651.370000 -* 2023 12 9 13 33 0.00000000 -PL56 -11.446020 4760.544831 5360.585156 -VL56 20994.533000 -54232.185000 48110.536000 -* 2023 12 9 13 36 0.00000000 -PL56 350.963454 3702.637504 6127.861198 -VL56 19118.205000 -62963.058000 36894.454000 -* 2023 12 9 13 39 0.00000000 -PL56 671.629745 2507.379053 6681.090080 -VL56 16379.818000 -69445.844000 24397.222000 -* 2023 12 9 13 42 0.00000000 -PL56 936.405331 1217.547062 7001.090777 -VL56 12937.123000 -73438.296000 11055.790000 -* 2023 12 9 13 45 0.00000000 -PL56 1134.257870 -120.530490 7076.816668 -VL56 8977.046300 -74789.088000 -2665.561100 -* 2023 12 9 13 48 0.00000000 -PL56 1257.715543 -1458.655834 6905.710039 -VL56 4706.730200 -73442.434000 -16290.436000 -* 2023 12 9 13 51 0.00000000 -PL56 1303.145435 -2748.505470 6493.779266 -VL56 343.957580 -69440.275000 -29346.086000 -* 2023 12 9 13 54 0.00000000 -PL56 1270.856271 -3943.385171 5855.392883 -VL56 -3892.771300 -62921.223000 -41379.059000 -* 2023 12 9 13 57 0.00000000 -PL56 1165.022220 -4999.935579 5012.791752 -VL56 -7794.047500 -54116.124000 -51970.510000 -* 2023 12 9 14 0 0.00000000 -PL56 993.434737 -5879.728009 3995.336349 -VL56 -11168.873000 -43340.610000 -60750.447000 -* 2023 12 9 14 3 0.00000000 -PL56 767.091228 -6550.703280 2838.504155 -VL56 -13853.440000 -30984.711000 -67411.425000 -* 2023 12 9 14 6 0.00000000 -PL56 499.634105 -6988.387430 1582.655279 -VL56 -15718.847000 -17498.577000 -71720.126000 -* 2023 12 9 14 9 0.00000000 -PL56 206.664020 -7176.826920 271.611686 -VL56 -16677.249000 -3375.783400 -73526.472000 -* 2023 12 9 14 12 0.00000000 -PL56 -95.040248 -7109.200633 -1048.903804 -VL56 -16686.118000 10866.005000 -72770.151000 -* 2023 12 9 14 15 0.00000000 -PL56 -388.356620 -6788.064483 -2332.906094 -VL56 -15749.923000 24706.049000 -69482.236000 -* 2023 12 9 14 18 0.00000000 -PL56 -656.663380 -6225.222285 -3535.781937 -VL56 -13919.502000 37640.790000 -63783.420000 -* 2023 12 9 14 21 0.00000000 -PL56 -884.652372 -5441.241029 -4615.856387 -VL56 -11289.323000 49203.198000 -55878.332000 -* 2023 12 9 14 24 0.00000000 -PL56 -1059.073192 -4464.634637 -5535.829826 -VL56 -7992.591200 58979.943000 -46046.738000 -* 2023 12 9 14 27 0.00000000 -PL56 -1169.373694 -3330.766192 -6264.031170 -VL56 -4194.692800 66625.439000 -34632.272000 -* 2023 12 9 14 30 0.00000000 -PL56 -1208.210608 -2080.525138 -6775.456016 -VL56 -85.408740 71872.798000 -22029.825000 -* 2023 12 9 14 33 0.00000000 -PL56 -1171.812371 -758.834726 -7052.566444 -VL56 4129.649600 74541.706000 -8671.795000 -* 2023 12 9 14 36 0.00000000 -PL56 -1060.183834 586.952943 -7085.841177 -VL56 8238.026200 74543.203000 4985.804000 -* 2023 12 9 14 39 0.00000000 -PL56 -877.145932 1908.723200 -6874.073298 -VL56 12029.698000 71881.646000 18477.492000 -* 2023 12 9 14 42 0.00000000 -PL56 -630.209866 3159.280593 -6424.416463 -VL56 15306.174000 66654.586000 31342.147000 -* 2023 12 9 14 45 0.00000000 -PL56 -330.289050 4294.006852 -5752.179623 -VL56 17889.383000 59050.221000 43137.165000 -* 2023 12 9 14 48 0.00000000 -PL56 8.746427 5272.450690 -4880.363618 -VL56 19630.206000 49342.222000 53452.843000 -* 2023 12 9 14 51 0.00000000 -PL56 370.659105 6059.797118 -3838.940281 -VL56 20415.900000 37881.561000 61926.682000 -* 2023 12 9 14 54 0.00000000 -PL56 737.558373 6628.162513 -2663.879313 -VL56 20176.433000 25085.242000 68256.913000 -* 2023 12 9 14 57 0.00000000 -PL56 1090.713655 6957.656123 -1395.942319 -VL56 18889.116000 11421.745000 72214.749000 -* 2023 12 9 15 0 0.00000000 -PL56 1411.432246 7037.154749 -79.274987 -VL56 16581.075000 -2606.381800 73654.441000 -* 2023 12 9 15 3 0.00000000 -PL56 1681.960363 6864.740484 1240.155185 -VL56 13329.271000 -16482.351000 72520.134000 -* 2023 12 9 15 6 0.00000000 -PL56 1886.359344 6447.770388 2516.208519 -VL56 9257.777200 -29695.830000 68848.661000 -* 2023 12 9 15 9 0.00000000 -PL56 2011.312293 5802.575332 3704.237422 -VL56 4532.805500 -41763.386000 62768.474000 -* 2023 12 9 15 12 0.00000000 -PL56 2046.821490 4953.800694 4762.696870 -VL56 -644.421870 -52247.747000 54494.748000 -* 2023 12 9 15 15 0.00000000 -PL56 1986.759330 3933.416211 5654.632102 -VL56 -6046.755400 -60774.974000 44320.482000 -* 2023 12 9 15 18 0.00000000 -PL56 1829.244934 2779.447846 6348.973605 -VL56 -11431.173000 -67047.741000 32604.447000 -* 2023 12 9 15 21 0.00000000 -PL56 1576.834983 1534.508502 6821.600070 -VL56 -16549.446000 -70855.189000 19757.596000 -* 2023 12 9 15 24 0.00000000 -PL56 1236.521572 244.183651 7056.147731 -VL56 -21158.793000 -72078.702000 6228.265500 -* 2023 12 9 15 27 0.00000000 -PL56 819.538118 -1044.660262 7044.543250 -VL56 -25032.400000 -70694.622000 -7513.204000 -* 2023 12 9 15 30 0.00000000 -PL56 340.981145 -2285.586671 6787.262771 -VL56 -27969.479000 -66774.126000 -20989.826000 -* 2023 12 9 15 33 0.00000000 -PL56 -180.742349 -3434.270531 6293.307515 -VL56 -29804.472000 -60479.937000 -33734.054000 -* 2023 12 9 15 36 0.00000000 -PL56 -724.621450 -4450.091489 5579.892492 -VL56 -30414.748000 -52059.530000 -45303.361000 -* 2023 12 9 15 39 0.00000000 -PL56 -1267.874477 -5297.583067 4671.865488 -VL56 -29727.134000 -41836.384000 -55294.472000 -* 2023 12 9 15 42 0.00000000 -PL56 -1786.887080 -5947.704672 3600.871821 -VL56 -27722.949000 -30198.904000 -63357.744000 -* 2023 12 9 15 45 0.00000000 -PL56 -2258.220315 -6378.883030 2404.264591 -VL56 -24440.619000 -17585.765000 -69210.637000 -* 2023 12 9 15 48 0.00000000 -PL56 -2659.642381 -6577.766958 1123.797034 -VL56 -19975.610000 -4468.889900 -72648.418000 -* 2023 12 9 15 51 0.00000000 -PL56 -2971.134793 -6539.663038 -195.856552 -VL56 -14477.652000 8664.861000 -73552.303000 -* 2023 12 9 15 54 0.00000000 -PL56 -3175.822606 -6268.629836 -1508.694661 -VL56 -8145.192100 21333.123000 -71894.069000 -* 2023 12 9 15 57 0.00000000 -PL56 -3260.784601 -5777.224860 -2769.030646 -VL56 -1217.598700 33077.074000 -67736.735000 -* 2023 12 9 16 0 0.00000000 -PL56 -3217.704207 -5085.917195 -3933.113321 -VL56 6034.662200 43479.284000 -61231.478000 -* 2023 12 9 16 3 0.00000000 -PL56 -3043.328417 -4222.198333 -4960.655975 -VL56 13321.388000 52179.202000 -52610.613000 -* 2023 12 9 16 6 0.00000000 -PL56 -2739.717135 -3219.445250 -5816.211898 -VL56 20344.433000 58885.177000 -42177.799000 -* 2023 12 9 16 9 0.00000000 -PL56 -2314.279524 -2115.595970 -6470.355425 -VL56 26809.553000 63383.278000 -30296.303000 -* 2023 12 9 16 12 0.00000000 -PL56 -1779.598281 -951.695997 -6900.639281 -VL56 32438.051000 65542.812000 -17375.931000 -* 2023 12 9 16 15 0.00000000 -PL56 -1153.051076 229.625991 -7092.306196 -VL56 36977.539000 65318.661000 -3858.986900 -* 2023 12 9 16 18 0.00000000 -PL56 -456.248042 1385.696079 -7038.747880 -VL56 40211.699000 62750.636000 9793.665300 -* 2023 12 9 16 21 0.00000000 -PL56 285.699144 2475.302379 -6741.715298 -VL56 41969.146000 57960.728000 23116.433000 -* 2023 12 9 16 24 0.00000000 -PL56 1045.058035 3460.135637 -6211.278881 -VL56 42131.343000 51148.586000 35652.885000 -* 2023 12 9 16 27 0.00000000 -PL56 1792.488059 4306.127416 -5465.532251 -VL56 40639.072000 42584.388000 46970.401000 -* 2023 12 9 16 30 0.00000000 -PL56 2498.153225 4984.641740 -4530.036019 -VL56 37497.115000 32599.836000 56674.330000 -* 2023 12 9 16 33 0.00000000 -PL56 3132.900518 5473.483386 -3437.006657 -VL56 32776.759000 21576.765000 64422.051000 -* 2023 12 9 16 36 0.00000000 -PL56 3669.460147 5757.679651 -2224.258115 -VL56 26615.752000 9933.410100 69936.318000 -* 2023 12 9 16 39 0.00000000 -PL56 4083.618457 5829.996181 -933.919831 -VL56 19215.126000 -1891.438500 73016.660000 -* 2023 12 9 16 42 0.00000000 -PL56 4355.304761 5691.154287 389.032368 -VL56 10832.806000 -13455.624000 73548.500000 -* 2023 12 9 16 45 0.00000000 -PL56 4469.534622 5349.729613 1698.376982 -VL56 1774.193900 -24331.552000 71508.560000 -* 2023 12 9 16 48 0.00000000 -PL56 4417.158990 4821.731964 2948.308787 -VL56 -7619.836600 -34123.478000 66966.329000 -* 2023 12 9 16 51 0.00000000 -PL56 4195.381042 4129.887761 4095.095357 -VL56 -16986.913000 -42483.503000 60081.833000 -* 2023 12 9 16 54 0.00000000 -PL56 3808.008211 3302.652645 5098.651241 -VL56 -25958.055000 -49124.848000 51098.932000 -* 2023 12 9 16 57 0.00000000 -PL56 3265.432806 2373.013397 5923.962309 -VL56 -34173.158000 -53832.253000 40335.416000 -* 2023 12 9 17 0 0.00000000 -PL56 2584.339147 1377.136446 6542.305706 -VL56 -41295.497000 -56468.443000 28170.089000 -* 2023 12 9 17 3 0.00000000 -PL56 1787.162824 352.930515 6932.223907 -VL56 -47024.869000 -56977.286000 15028.923000 -* 2023 12 9 17 6 0.00000000 -PL56 901.324514 -661.413027 7080.236184 -VL56 -51109.415000 -55383.287000 1369.833700 -* 2023 12 9 17 9 0.00000000 -PL56 -41.732977 -1628.850697 6981.278709 -VL56 -53355.629000 -51788.814000 -12332.555000 -* 2023 12 9 17 12 0.00000000 -PL56 -1007.673471 -2514.845292 6638.860996 -VL56 -53636.716000 -46368.860000 -25602.833000 -* 2023 12 9 17 15 0.00000000 -PL56 -1960.522455 -3288.603027 6064.935703 -VL56 -51898.193000 -39362.872000 -37980.907000 -* 2023 12 9 17 18 0.00000000 -PL56 -2864.004334 -3924.150125 5279.495311 -VL56 -48161.562000 -31065.218000 -49036.017000 -* 2023 12 9 17 21 0.00000000 -PL56 -3682.932022 -4401.223519 4309.904785 -VL56 -42526.303000 -21813.987000 -58382.201000 -* 2023 12 9 17 24 0.00000000 -PL56 -4384.596379 -4705.938781 3189.966819 -VL56 -35167.621000 -11977.488000 -65692.363000 -* 2023 12 9 17 27 0.00000000 -PL56 -4940.088456 -4831.206084 1958.749658 -VL56 -26331.428000 -1939.877300 -70710.349000 -* 2023 12 9 17 30 0.00000000 -PL56 -5325.502628 -4776.878580 659.215954 -VL56 -16326.111000 7914.179400 -73261.057000 -* 2023 12 9 17 33 0.00000000 -PL56 -5522.963626 -4549.620749 -663.303045 -VL56 -5511.212200 17215.073000 -73257.298000 -* 2023 12 9 17 36 0.00000000 -PL56 -5521.424808 -4162.501888 -1962.726956 -VL56 5716.596000 25623.146000 -70703.286000 -* 2023 12 9 17 39 0.00000000 -PL56 -5317.194575 -3634.332724 -3193.871993 -VL56 16939.568000 32842.198000 -65693.916000 -* 2023 12 9 17 42 0.00000000 -PL56 -4914.165380 -2988.781498 -4314.045342 -VL56 27735.519000 38630.257000 -58409.991000 -* 2023 12 9 17 45 0.00000000 -PL56 -4323.744753 -2253.321485 -5284.524047 -VL56 37694.299000 42807.582000 -49110.292000 -* 2023 12 9 17 48 0.00000000 -PL56 -3564.497726 -1458.062540 -6071.867637 -VL56 46433.286000 45261.551000 -38121.027000 -* 2023 12 9 17 51 0.00000000 -PL56 -2661.523197 -634.521129 -6649.023195 -VL56 53611.282000 45948.556000 -25823.511000 -* 2023 12 9 17 54 0.00000000 -PL56 -1645.595385 185.618015 -6996.195955 -VL56 58940.742000 44893.115000 -12640.574000 -* 2023 12 9 17 57 0.00000000 -PL56 -552.106484 971.698983 -7101.470384 -VL56 62197.549000 42184.293000 977.445360 -* 2023 12 9 18 0 0.00000000 -PL56 580.149367 1695.213212 -6961.181532 -VL56 63229.034000 37970.624000 14566.470000 -* 2023 12 9 18 3 0.00000000 -PL56 1710.320241 2330.810470 -6580.039080 -VL56 61960.209000 32453.301000 27662.369000 -* 2023 12 9 18 6 0.00000000 -PL56 2796.941001 2857.177707 -5970.998658 -VL56 58398.346000 25878.164000 39815.483000 -* 2023 12 9 18 9 0.00000000 -PL56 3799.435014 3257.758247 -5154.870663 -VL56 52635.015000 18526.187000 50605.099000 -* 2023 12 9 18 12 0.00000000 -PL56 4679.626234 3521.288569 -4159.674191 -VL56 44845.136000 10702.676000 59653.387000 -* 2023 12 9 18 15 0.00000000 -PL56 5403.216047 3642.134456 -3019.737676 -VL56 35283.641000 2725.738700 66639.308000 -* 2023 12 9 18 18 0.00000000 -PL56 5941.160225 3620.406317 -1774.557426 -VL56 24277.956000 -5086.502000 71311.604000 -* 2023 12 9 18 21 0.00000000 -PL56 6270.883242 3461.844927 -467.444673 -VL56 12217.297000 -12428.815000 73499.350000 -* 2023 12 9 18 24 0.00000000 -PL56 6377.266703 3177.473307 855.995981 -VL56 -461.655730 -19021.625000 73119.680000 -* 2023 12 9 18 27 0.00000000 -PL56 6253.356265 2783.026457 2149.496751 -VL56 -13291.486000 -24622.699000 70182.032000 -* 2023 12 9 18 30 0.00000000 -PL56 5900.744264 2298.187183 3367.796212 -VL56 -25793.119000 -29037.088000 64788.539000 -* 2023 12 9 18 33 0.00000000 -PL56 5329.605556 1745.664230 4468.276454 -VL56 -37495.376000 -32124.601000 57129.806000 -* 2023 12 9 18 36 0.00000000 -PL56 4558.381807 1150.159050 5412.490954 -VL56 -47953.942000 -33804.538000 47476.997000 -* 2023 12 9 18 39 0.00000000 -PL56 3613.139728 537.276235 6167.520381 -VL56 -56768.619000 -34057.276000 36171.166000 -* 2023 12 9 18 42 0.00000000 -PL56 2526.632568 -67.570290 6707.111552 -VL56 -63598.895000 -32923.131000 23609.567000 -* 2023 12 9 18 45 0.00000000 -PL56 1337.116062 -640.202980 7012.559825 -VL56 -68175.777000 -30498.399000 10231.209000 -* 2023 12 9 18 48 0.00000000 -PL56 86.968892 -1158.640316 7073.328000 -VL56 -70311.601000 -26929.698000 -3498.105200 -* 2023 12 9 18 51 0.00000000 -PL56 -1178.838945 -1603.937553 6887.383846 -VL56 -69906.867000 -22406.397000 -17101.816000 -* 2023 12 9 18 54 0.00000000 -PL56 -2414.372027 -1960.878373 6461.251563 -VL56 -66954.177000 -17151.805000 -30108.263000 -* 2023 12 9 18 57 0.00000000 -PL56 -3574.396479 -2218.494262 5809.786871 -VL56 -61538.998000 -11412.948000 -42065.837000 -* 2023 12 9 19 0 0.00000000 -PL56 -4616.048139 -2370.402131 4955.684789 -VL56 -53838.615000 -5450.449200 -52557.849000 -* 2023 12 9 19 3 0.00000000 -PL56 -5500.444888 -2414.949253 3928.710712 -VL56 -44117.036000 472.589220 -61217.657000 -* 2023 12 9 19 6 0.00000000 -PL56 -6194.172164 -2355.154537 2764.676769 -VL56 -32716.044000 6102.035900 -67742.056000 -* 2023 12 9 19 9 0.00000000 -PL56 -6670.584696 -2198.451011 1504.198074 -VL56 -20043.768000 11203.300000 -71902.385000 -* 2023 12 9 19 12 0.00000000 -PL56 -6910.869364 -1956.242179 191.260348 -VL56 -6559.477700 15571.427000 -73554.084000 -* 2023 12 9 19 15 0.00000000 -PL56 -6904.807149 -1643.286985 -1128.349486 -VL56 7244.276200 19039.846000 -72642.232000 -* 2023 12 9 19 18 0.00000000 -PL56 -6651.196119 -1276.944780 -2408.680433 -VL56 20861.504000 21487.097000 -69203.450000 -* 2023 12 9 19 21 0.00000000 -PL56 -6157.914988 -876.321296 -3605.250709 -VL56 33792.580000 22841.108000 -63363.668000 -* 2023 12 9 19 24 0.00000000 -PL56 -5441.632199 -461.359200 -4676.608827 -VL56 45563.584000 23081.097000 -55332.434000 -* 2023 12 9 19 27 0.00000000 -PL56 -4527.180480 -51.915431 -5585.761593 -VL56 55744.089000 22237.068000 -45393.857000 -* 2023 12 9 19 30 0.00000000 -PL56 -3446.633222 333.128848 -6301.417565 -VL56 63962.309000 20386.747000 -33895.244000 -* 2023 12 9 19 33 0.00000000 -PL56 -2238.131393 676.685659 -6799.008679 -VL56 69917.590000 17650.669000 -21234.138000 -* 2023 12 9 19 36 0.00000000 -PL56 -944.517679 964.172756 -7061.471879 -VL56 73389.563000 14185.534000 -7844.588800 -* 2023 12 9 19 39 0.00000000 -PL56 388.173729 1184.098783 -7079.783044 -VL56 74244.800000 10176.717000 5816.581100 -* 2023 12 9 19 42 0.00000000 -PL56 1712.322343 1328.503949 -6853.241415 -VL56 72441.056000 5829.818300 19283.556000 -* 2023 12 9 19 45 0.00000000 -PL56 2980.387500 1393.245001 -6389.507107 -VL56 68029.633000 1361.758800 32095.722000 -* 2023 12 9 19 48 0.00000000 -PL56 4146.590742 1378.115475 -5704.376463 -VL56 61154.663000 -3008.555600 43812.090000 -* 2023 12 9 19 51 0.00000000 -PL56 5168.560425 1286.795735 -4821.299550 -VL56 52049.809000 -7069.702800 54025.476000 -* 2023 12 9 19 54 0.00000000 -PL56 6008.893469 1126.634673 -3770.644042 -VL56 41032.167000 -10627.014000 62376.787000 -* 2023 12 9 19 57 0.00000000 -PL56 6636.574699 908.267346 -2588.707660 -VL56 28492.503000 -13511.455000 68568.406000 -* 2023 12 9 20 0 0.00000000 -PL56 7028.192456 645.080475 -1316.500908 -VL56 14882.411000 -15587.549000 72376.203000 -* 2023 12 9 20 3 0.00000000 -PL56 7168.889042 352.546223 1.671876 -VL56 697.717850 -16760.016000 73659.673000 -* 2023 12 9 20 6 0.00000000 -PL56 7052.986184 47.453671 1319.780632 -VL56 -13540.779000 -16978.415000 72368.369000 -* 2023 12 9 20 9 0.00000000 -PL56 6684.251491 -252.925083 2591.721945 -VL56 -27307.900000 -16239.756000 68544.814000 -* 2023 12 9 20 12 0.00000000 -PL56 6075.782892 -531.693365 3772.987822 -VL56 -40095.762000 -14588.554000 62323.104000 -* 2023 12 9 20 15 0.00000000 -PL56 5249.512989 -773.167046 4822.270407 -VL56 -51433.779000 -12114.379000 53923.381000 -* 2023 12 9 20 18 0.00000000 -PL56 4235.366871 -963.647688 5702.934817 -VL56 -60907.229000 -8947.382600 43643.129000 -* 2023 12 9 20 21 0.00000000 -PL56 3070.113821 -1092.094226 6384.303242 -VL56 -68172.798000 -5251.465400 31844.603000 -* 2023 12 9 20 24 0.00000000 -PL56 1795.975020 -1150.661841 6842.705780 -VL56 -72969.715000 -1216.399200 18941.618000 -* 2023 12 9 20 27 0.00000000 -PL56 459.049385 -1135.089367 7062.274169 -VL56 -75128.889000 2950.956900 5384.744100 -* 2023 12 9 20 30 0.00000000 -PL56 -892.384256 -1044.919264 7035.459601 -VL56 -74577.816000 7036.416600 -8354.773100 -* 2023 12 9 20 33 0.00000000 -PL56 -2209.622723 -883.542922 6763.266411 -VL56 -71341.837000 10828.173000 -21800.531000 -* 2023 12 9 20 36 0.00000000 -PL56 -3445.295196 -658.070359 6255.207591 -VL56 -65543.161000 14126.430000 -34486.007000 -* 2023 12 9 20 39 0.00000000 -PL56 -4555.073450 -379.028926 5528.986900 -VL56 -57396.832000 16752.749000 -45970.125000 -* 2023 12 9 20 42 0.00000000 -PL56 -5499.285707 -59.902527 4609.905842 -VL56 -47203.744000 18558.425000 -55852.337000 -* 2023 12 9 20 45 0.00000000 -PL56 -6244.371528 283.473095 3530.002069 -VL56 -35339.958000 19431.971000 -63787.013000 -* 2023 12 9 20 48 0.00000000 -PL56 -6764.118217 633.635944 2326.944020 -VL56 -22243.349000 19305.020000 -69496.030000 -* 2023 12 9 20 51 0.00000000 -PL56 -7040.629216 972.314125 1042.714510 -VL56 -8397.155100 18156.423000 -72779.730000 -* 2023 12 9 20 54 0.00000000 -PL56 -7064.977146 1281.294327 -277.876996 -VL56 5688.600000 16013.957000 -73524.848000 -* 2023 12 9 20 57 0.00000000 -PL56 -6837.503232 1543.300633 -1588.795627 -VL56 19497.540000 12953.669000 -71708.871000 -* 2023 12 9 21 0 0.00000000 -PL56 -6367.747367 1742.839100 -2844.423764 -VL56 32527.270000 9096.831200 -67400.383000 -* 2023 12 9 21 3 0.00000000 -PL56 -5674.019546 1866.968749 -4001.178017 -VL56 44308.971000 4604.764800 -60755.979000 -* 2023 12 9 21 6 0.00000000 -PL56 -4782.630753 1905.958679 -5019.033286 -VL56 54425.131000 -328.510330 -52012.940000 -* 2023 12 9 21 9 0.00000000 -PL56 -3726.832896 1853.801218 -5862.887661 -VL56 62524.159000 -5484.835200 -41479.130000 -* 2023 12 9 21 12 0.00000000 -PL56 -2545.529371 1708.562766 -6503.727186 -VL56 68331.287000 -10631.310000 -29521.053000 -* 2023 12 9 21 15 0.00000000 -PL56 -1281.815665 1472.560874 -6919.566067 -VL56 71656.585000 -15530.140000 -16550.816000 -* 2023 12 9 21 18 0.00000000 -PL56 18.594643 1152.363346 -7096.141453 -VL56 72399.515000 -19948.507000 -3012.079800 -* 2023 12 9 21 21 0.00000000 -PL56 1308.997722 758.611904 -7027.358308 -VL56 70550.692000 -23668.123000 10633.525000 -* 2023 12 9 21 24 0.00000000 -PL56 2543.341311 305.676528 -6715.489348 -VL56 66191.726000 -26494.559000 23920.302000 -* 2023 12 9 21 27 0.00000000 -PL56 3677.840206 -188.853963 -6171.117066 -VL56 59492.232000 -28265.968000 36393.003000 -* 2023 12 9 21 30 0.00000000 -PL56 4672.514840 -704.830227 -5412.816559 -VL56 50704.237000 -28860.927000 47621.168000 -* 2023 12 9 21 33 0.00000000 -PL56 5492.609966 -1220.332221 -4466.584471 -VL56 40154.690000 -28205.128000 57213.001000 -* 2023 12 9 21 36 0.00000000 -PL56 6109.851181 -1712.567458 -3365.013483 -VL56 28234.771000 -26276.632000 64829.662000 -* 2023 12 9 21 39 0.00000000 -PL56 6503.483771 -2158.844772 -2146.220102 -VL56 15386.349000 -23108.990000 70198.352000 -* 2023 12 9 21 42 0.00000000 -PL56 6661.043659 -2537.583717 -852.550402 -VL56 2085.790700 -18791.939000 73123.640000 -* 2023 12 9 21 45 0.00000000 -PL56 6578.815973 -2829.311617 470.896616 -VL56 -11174.293000 -13469.375000 73496.249000 -* 2023 12 9 21 48 0.00000000 -PL56 6261.951354 -3017.598507 1777.873847 -VL56 -23904.773000 -7334.434800 71298.500000 -* 2023 12 9 21 51 0.00000000 -PL56 5724.224711 -3089.880346 3022.654471 -VL56 -35639.898000 -622.055350 66605.734000 -* 2023 12 9 21 54 0.00000000 -PL56 4987.441283 -3038.125982 4161.686467 -VL56 -45956.075000 6400.825900 59583.410000 -* 2023 12 9 21 57 0.00000000 -PL56 4080.524486 -2859.311471 5155.156635 -VL56 -54488.385000 13446.712000 50480.087000 -* 2023 12 9 22 0 0.00000000 -PL56 3038.336994 -2555.683711 5968.403160 -VL56 -60943.901000 20219.575000 39617.653000 -* 2023 12 9 22 3 0.00000000 -PL56 1900.288426 -2134.799860 6573.123001 -VL56 -65111.622000 26427.483000 27378.493000 -* 2023 12 9 22 6 0.00000000 -PL56 708.801765 -1609.343800 6948.333349 -VL56 -66868.451000 31794.695000 14191.117000 -* 2023 12 9 22 9 0.00000000 -PL56 -492.297501 -996.731158 7081.067142 -VL56 -66181.799000 36073.053000 514.993320 -* 2023 12 9 22 12 0.00000000 -PL56 -1659.406970 -318.517477 6966.789959 -VL56 -63108.641000 39052.323000 -13174.939000 -* 2023 12 9 22 15 0.00000000 -PL56 -2750.732821 400.369143 6609.537553 -VL56 -57792.143000 40569.440000 -26403.948000 -* 2023 12 9 22 18 0.00000000 -PL56 -3727.789265 1132.547224 6021.775037 -VL56 -50455.509000 40516.009000 -38712.754000 -* 2023 12 9 22 21 0.00000000 -PL56 -4556.767832 1849.223384 5223.979275 -VL56 -41393.628000 38844.348000 -49672.942000 -* 2023 12 9 22 24 0.00000000 -PL56 -5209.732916 2521.322505 4243.949368 -VL56 -30962.112000 35571.320000 -58901.776000 -* 2023 12 9 22 27 0.00000000 -PL56 -5665.596786 3120.666550 3115.855955 -VL56 -19563.788000 30779.710000 -66076.221000 -* 2023 12 9 22 30 0.00000000 -PL56 -5910.832537 3621.152253 1879.056855 -VL56 -7633.203800 24616.802000 -70944.819000 -* 2023 12 9 22 33 0.00000000 -PL56 -5939.896737 3999.878169 576.714847 -VL56 4380.089200 17290.083000 -73337.665000 -* 2023 12 9 22 36 0.00000000 -PL56 -5755.335131 4238.165039 -745.738124 -VL56 16029.767000 9059.747600 -73173.322000 -* 2023 12 9 22 39 0.00000000 -PL56 -5367.565222 4322.417352 -2042.223700 -VL56 26890.506000 228.592700 -70461.724000 -* 2023 12 9 22 42 0.00000000 -PL56 -4794.346379 4244.785090 -3267.662674 -VL56 36574.620000 -8870.085100 -65303.399000 -* 2023 12 9 22 45 0.00000000 -PL56 -4059.961772 4003.589346 -4379.567843 -VL56 44747.050000 -17886.172000 -57884.650000 -* 2023 12 9 22 48 0.00000000 -PL56 -3194.163184 3603.497260 -5339.514072 -VL56 51136.861000 -26466.944000 -48468.902000 -* 2023 12 9 22 51 0.00000000 -PL56 -2230.939296 3055.447019 -6114.433590 -VL56 55545.267000 -34270.588000 -37386.028000 -* 2023 12 9 22 54 0.00000000 -PL56 -1207.167907 2376.333894 -6677.705144 -VL56 57850.666000 -40979.139000 -25020.273000 -* 2023 12 9 22 57 0.00000000 -PL56 -161.203642 1588.470637 -7010.010151 -VL56 58010.607000 -46310.432000 -11796.528000 -* 2023 12 9 23 0 0.00000000 -PL56 868.540694 718.848378 -7099.940303 -VL56 56060.755000 -50028.456000 1833.445400 -* 2023 12 9 23 3 0.00000000 -PL56 1844.976267 -201.776692 -6944.357729 -VL56 52111.935000 -51952.339000 15404.867000 -* 2023 12 9 23 6 0.00000000 -PL56 2733.648551 -1139.948956 -6548.500490 -VL56 46344.897000 -51964.067000 28454.260000 -* 2023 12 9 23 9 0.00000000 -PL56 3503.935595 -2060.700976 -5925.831303 -VL56 39003.419000 -50014.501000 40533.556000 -* 2023 12 9 23 12 0.00000000 -PL56 4130.104534 -2928.831398 -5097.633186 -VL56 30385.472000 -46127.456000 51224.267000 -* 2023 12 9 23 15 0.00000000 -PL56 4592.196051 -3710.242504 -4092.347729 -VL56 20832.519000 -40401.755000 60151.932000 -* 2023 12 9 23 18 0.00000000 -PL56 4876.696997 -4373.285568 -2944.657523 -VL56 10717.144000 -33010.250000 66999.697000 -* 2023 12 9 23 21 0.00000000 -PL56 4976.976553 -4890.060563 -1694.334309 -VL56 429.053670 -24195.688000 71520.954000 -* 2023 12 9 23 24 0.00000000 -PL56 4893.459681 -5237.614101 -384.875953 -VL56 -9640.138600 -14263.421000 73549.848000 -* 2023 12 9 23 27 0.00000000 -PL56 4633.517222 -5398.973270 938.024223 -VL56 -19112.883000 -3570.542400 73009.261000 -* 2023 12 9 23 30 0.00000000 -PL56 4211.071639 -5363.955652 2228.114518 -VL56 -27641.281000 7488.052500 69914.651000 -* 2023 12 9 23 33 0.00000000 -PL56 3645.933239 -5129.709066 3440.256545 -VL56 -34921.253000 18495.576000 64373.836000 -* 2023 12 9 23 36 0.00000000 -PL56 2962.900410 -4700.953899 4532.054026 -VL56 -40704.428000 29030.344000 56582.632000 -* 2023 12 9 23 39 0.00000000 -PL56 2190.671629 -4089.915209 5465.370284 -VL56 -44807.029000 38682.990000 46816.910000 -* 2023 12 9 23 42 0.00000000 -PL56 1360.625593 -3315.950899 6207.672661 -VL56 -47115.718000 47072.975000 35421.450000 -* 2023 12 9 23 45 0.00000000 -PL56 505.527255 -2404.896980 6733.156241 -VL56 -47589.944000 53863.366000 22796.490000 -* 2023 12 9 23 48 0.00000000 -PL56 -341.780448 -1388.164260 7023.610849 -VL56 -46261.169000 58773.584000 9383.166200 -* 2023 12 9 23 51 0.00000000 -PL56 -1149.643124 -301.626750 7069.018594 -VL56 -43229.227000 61589.910000 -4351.866200 -* 2023 12 9 23 54 0.00000000 -PL56 -1888.777536 815.661747 6867.875492 -VL56 -38656.622000 62173.896000 -17931.920000 -* 2023 12 9 23 57 0.00000000 -PL56 -2533.333700 1922.879746 6427.230278 -VL56 -32760.896000 60468.382000 -30885.975000 -* 2023 12 10 0 0 0.00000000 -PL56 -3061.802707 2978.933243 5762.442911 -VL56 -25805.165000 56500.631000 -42764.145000 -* 2023 12 10 0 3 0.00000000 -PL56 -3457.743255 3943.988462 4896.669392 -VL56 -18087.494000 50383.270000 -53152.588000 -* 2023 12 10 0 6 0.00000000 -PL56 -3710.304851 4780.991735 3860.079681 -VL56 -9928.919200 42311.942000 -61688.148000 -* 2023 12 10 0 9 0.00000000 -PL56 -3814.526075 5457.119790 2688.823221 -VL56 -1660.519400 32559.814000 -68071.696000 -* 2023 12 10 0 12 0.00000000 -PL56 -3771.392742 5945.097311 1423.767961 -VL56 6390.238700 21468.317000 -72079.805000 -* 2023 12 10 0 15 0.00000000 -PL56 -3587.652386 6224.318068 109.057792 -VL56 13912.820000 9434.732800 -73573.072000 -* 2023 12 10 0 18 0.00000000 -PL56 -3275.395003 6281.720905 -1209.458445 -VL56 20626.165000 -3102.586100 -72502.126000 -* 2023 12 10 0 21 0.00000000 -PL56 -2851.416459 6112.370396 -2485.869925 -VL56 26290.214000 -15682.206000 -68909.445000 -* 2023 12 10 0 24 0.00000000 -PL56 -2336.392385 5719.706717 -3675.840157 -VL56 30715.265000 -27838.073000 -62926.627000 -* 2023 12 10 0 27 0.00000000 -PL56 -1753.912949 5115.463924 -4738.158337 -VL56 33767.984000 -39117.645000 -54768.070000 -* 2023 12 10 0 30 0.00000000 -PL56 -1129.432284 4319.270335 -5636.151791 -VL56 35374.871000 -49098.965000 -44721.860000 -* 2023 12 10 0 33 0.00000000 -PL56 -489.182034 3357.960509 -6338.913290 -VL56 35522.988000 -57405.707000 -33138.620000 -* 2023 12 10 0 36 0.00000000 -PL56 140.906867 2264.630426 -6822.314122 -VL56 34258.200000 -63720.514000 -20418.586000 -* 2023 12 10 0 39 0.00000000 -PL56 736.229239 1077.476587 -7069.773825 -VL56 31681.081000 -67795.535000 -6997.895100 -* 2023 12 10 0 42 0.00000000 -PL56 1274.440511 -161.533060 -7072.781777 -VL56 27941.157000 -69460.761000 6665.283600 -* 2023 12 10 0 45 0.00000000 -PL56 1736.275204 -1408.119429 -6831.165650 -VL56 23229.718000 -68630.283000 20105.018000 -* 2023 12 10 0 48 0.00000000 -PL56 2106.223851 -2617.240738 -6353.103389 -VL56 17771.360000 -65305.687000 32861.748000 -* 2023 12 10 0 51 0.00000000 -PL56 2373.052959 -3744.687916 -5654.884512 -VL56 11814.984000 -59578.015000 44496.062000 -* 2023 12 10 0 54 0.00000000 -PL56 2530.153949 -4748.693053 -4760.416398 -VL56 5623.850600 -51627.083000 54603.475000 -* 2023 12 10 0 57 0.00000000 -PL56 2575.705438 -5591.492230 -3700.467386 -VL56 -535.206430 -41716.957000 62828.357000 -* 2023 12 10 1 0 0.00000000 -PL56 2512.640488 -6240.784592 -2511.666329 -VL56 -6402.562800 -30189.149000 68877.286000 -* 2023 12 10 1 3 0.00000000 -PL56 2348.417033 -6671.031668 -1235.272631 -VL56 -11736.877000 -17451.450000 72531.092000 -* 2023 12 10 1 6 0.00000000 -PL56 2094.595301 -6864.528467 84.252599 -VL56 -16325.348000 -3963.642000 73654.616000 -* 2023 12 10 1 9 0.00000000 -PL56 1766.237285 -6812.181135 1400.824165 -VL56 -19993.116000 9780.430600 72203.176000 -* 2023 12 10 1 12 0.00000000 -PL56 1381.155567 -6513.948310 2668.390029 -VL56 -22610.492000 23272.136000 68225.368000 -* 2023 12 10 1 15 0.00000000 -PL56 959.047487 -5978.914750 3842.599491 -VL56 -24098.375000 36009.562000 61860.957000 -* 2023 12 10 1 18 0.00000000 -PL56 520.558939 -5224.993999 4882.399804 -VL56 -24430.646000 47516.907000 53335.216000 -* 2023 12 10 1 21 0.00000000 -PL56 86.326637 -4278.282238 5751.496973 -VL56 -23634.225000 57363.682000 42949.946000 -* 2023 12 10 1 24 0.00000000 -PL56 -323.953679 -3172.094529 6419.626804 -VL56 -21786.098000 65180.854000 31071.186000 -* 2023 12 10 1 27 0.00000000 -PL56 -692.388137 -1945.730999 6863.589212 -VL56 -19008.486000 70674.311000 18115.238000 -* 2023 12 10 1 30 0.00000000 -PL56 -1003.640242 -643.037641 7068.019387 -VL56 -15462.087000 73634.484000 4533.955300 -* 2023 12 10 1 33 0.00000000 -PL56 -1245.553200 689.186018 7025.891157 -VL56 -11338.079000 73943.778000 -9200.620500 -* 2023 12 10 1 36 0.00000000 -PL56 -1409.618255 2002.882632 6738.739267 -VL56 -6849.014600 71580.407000 -22611.952000 -* 2023 12 10 1 39 0.00000000 -PL56 -1491.272363 3250.477375 6216.598392 -VL56 -2219.116800 66619.670000 -35234.692000 -* 2023 12 10 1 42 0.00000000 -PL56 -1490.018261 4386.609150 5477.663173 -VL56 2325.763200 59231.685000 -46630.075000 -* 2023 12 10 1 45 0.00000000 -PL56 -1409.363756 5369.798407 4547.676095 -VL56 6568.116300 49676.501000 -56400.668000 -* 2023 12 10 1 48 0.00000000 -PL56 -1256.583184 6163.995204 3459.052587 -VL56 10308.527000 38295.653000 -64204.703000 -* 2023 12 10 1 51 0.00000000 -PL56 -1042.310896 6739.943524 2249.763553 -VL56 13374.441000 25500.306000 -69768.651000 -* 2023 12 10 1 54 0.00000000 -PL56 -779.983970 7076.307033 962.006097 -VL56 15628.260000 11756.392000 -72898.028000 -* 2023 12 10 1 57 0.00000000 -PL56 -485.152521 7160.494676 -359.293855 -VL56 16973.705000 -2433.429600 -73485.112000 -* 2023 12 10 2 0 0.00000000 -PL56 -174.695047 6989.147254 -1668.084895 -VL56 17359.965000 -16549.476000 -71513.039000 -* 2023 12 10 2 3 0.00000000 -PL56 134.021107 6568.254508 -2918.837312 -VL56 16783.587000 -30076.159000 -67056.199000 -* 2023 12 10 2 6 0.00000000 -PL56 423.988417 5912.899801 -4068.152065 -VL56 15287.746000 -42521.852000 -60276.036000 -* 2023 12 10 2 9 0.00000000 -PL56 679.378572 5046.661599 -5076.269669 -VL56 12959.672000 -53437.190000 -51414.070000 -* 2023 12 10 2 12 0.00000000 -PL56 886.296154 4000.702631 -5908.425711 -VL56 9925.969600 -62431.286000 -40781.928000 -* 2023 12 10 2 15 0.00000000 -PL56 1033.431718 2812.594856 -6536.007313 -VL56 6346.161600 -69184.841000 -28749.359000 -* 2023 12 10 2 18 0.00000000 -PL56 1112.586730 1524.935707 -6937.480311 -VL56 2405.031700 -73460.133000 -15730.822000 -* 2023 12 10 2 21 0.00000000 -PL56 1119.053164 183.815778 -7099.070608 -VL56 -1695.807800 -75107.664000 -2171.810300 -* 2023 12 10 2 24 0.00000000 -PL56 1051.836359 -1162.811841 -7015.196791 -VL56 -5746.914900 -74070.427000 11465.233000 -* 2023 12 10 2 27 0.00000000 -PL56 913.713726 -2466.812889 -6688.646474 -VL56 -9540.127800 -70385.290000 24715.228000 -* 2023 12 10 2 30 0.00000000 -PL56 711.130000 -3681.554706 -6130.501259 -VL56 -12877.623000 -64181.987000 37123.955000 -* 2023 12 10 2 33 0.00000000 -PL56 453.929540 -4763.556906 -5359.810447 -VL56 -15580.963000 -55680.245000 48262.836000 -* 2023 12 10 2 36 0.00000000 -PL56 154.932198 -5674.057328 -4403.002548 -VL56 -17499.325000 -45183.325000 57742.895000 -* 2023 12 10 2 39 0.00000000 -PL56 -170.634781 -6380.440099 -3293.043862 -VL56 -18517.191000 -33069.067000 65228.920000 -* 2023 12 10 2 42 0.00000000 -PL56 -505.830776 -6857.469340 -2068.352408 -VL56 -18560.624000 -19777.304000 70452.406000 -* 2023 12 10 2 45 0.00000000 -PL56 -832.793969 -7088.270179 -771.492291 -VL56 -17601.807000 -5794.323100 73222.943000 -* 2023 12 10 2 48 0.00000000 -PL56 -1133.596761 -7065.000982 552.315015 -VL56 -15661.448000 8365.760300 73436.818000 -* 2023 12 10 2 51 0.00000000 -PL56 -1391.123234 -6789.172831 1856.802843 -VL56 -12808.830000 22181.328000 71082.123000 -* 2023 12 10 2 54 0.00000000 -PL56 -1589.924882 -6271.595291 3096.328387 -VL56 -9159.300700 35144.372000 66239.950000 -* 2023 12 10 2 57 0.00000000 -PL56 -1717.008175 -5531.943346 4227.525351 -VL56 -4869.250200 46781.204000 59081.272000 -* 2023 12 10 3 0 0.00000000 -PL56 -1762.511697 -4597.967850 5210.861672 -VL56 -128.998270 56671.027000 49859.620000 -* 2023 12 10 3 3 0.00000000 -PL56 -1720.242314 -3504.398433 6012.038314 -VL56 4845.716900 64461.572000 38901.049000 -* 2023 12 10 3 6 0.00000000 -PL56 -1588.046109 -2291.590902 6603.182189 -VL56 9823.563700 69881.759000 26591.136000 -* 2023 12 10 3 9 0.00000000 -PL56 -1367.995698 -1003.986524 6963.789243 -VL56 14567.960000 72749.832000 13360.633000 -* 2023 12 10 3 12 0.00000000 -PL56 -1066.393104 311.548586 7081.403286 -VL56 18847.249000 72978.693000 -329.617850 -* 2023 12 10 3 15 0.00000000 -PL56 -693.589795 1607.446703 6952.017425 -VL56 22444.848000 70577.510000 -14004.179000 -* 2023 12 10 3 18 0.00000000 -PL56 -263.625235 2837.165700 6580.196349 -VL56 25169.132000 65650.571000 -27188.719000 -* 2023 12 10 3 21 0.00000000 -PL56 206.304005 3956.866971 5978.916040 -VL56 26862.309000 58393.067000 -39425.548000 -* 2023 12 10 3 24 0.00000000 -PL56 696.524069 4926.990828 5169.125889 -VL56 27408.122000 49083.857000 -50288.969000 -* 2023 12 10 3 27 0.00000000 -PL56 1185.691327 5713.679792 4179.041368 -VL56 26738.196000 38075.735000 -59399.732000 -* 2023 12 10 3 30 0.00000000 -PL56 1651.696945 6289.996863 3043.180936 -VL56 24836.436000 25782.429000 -66438.816000 -* 2023 12 10 3 33 0.00000000 -PL56 2072.636366 6636.895560 1801.173512 -VL56 21741.789000 12664.214000 -71159.324000 -* 2023 12 10 3 36 0.00000000 -PL56 2427.797450 6743.889010 496.357673 -VL56 17547.723000 -791.015150 -73397.338000 -* 2023 12 10 3 39 0.00000000 -PL56 2698.617092 6609.377050 -825.762482 -VL56 12398.771000 -14087.207000 -73077.014000 -* 2023 12 10 3 42 0.00000000 -PL56 2869.560848 6240.622255 -2119.139641 -VL56 6485.668100 -26739.030000 -70213.832000 -* 2023 12 10 3 45 0.00000000 -PL56 2928.884550 5653.379633 -3338.819295 -VL56 37.431874 -38291.181000 -64913.305000 -* 2023 12 10 3 48 0.00000000 -PL56 2869.240564 4871.197865 -4442.523678 -VL56 -6688.178900 -48335.738000 -57366.196000 -* 2023 12 10 3 51 0.00000000 -PL56 2688.098341 3924.428765 -5392.115255 -VL56 -13415.545000 -56526.834000 -47840.123000 -* 2023 12 10 3 54 0.00000000 -PL56 2387.964208 2849.004525 -6154.884673 -VL56 -19862.516000 -62591.882000 -36668.648000 -* 2023 12 10 3 57 0.00000000 -PL56 1976.397673 1685.042620 -6704.628391 -VL56 -25751.677000 -66339.511000 -24238.857000 -* 2023 12 10 4 0 0.00000000 -PL56 1465.826527 475.338335 -7022.489244 -VL56 -30821.245000 -67664.026000 -10977.646000 -* 2023 12 10 4 3 0.00000000 -PL56 873.171948 -736.195559 -7097.550407 -VL56 -34835.454000 -66546.998000 2661.951100 -* 2023 12 10 4 6 0.00000000 -PL56 219.292291 -1906.095366 -6927.178303 -VL56 -37594.092000 -63056.354000 16214.987000 -* 2023 12 10 4 9 0.00000000 -PL56 -471.735028 -2992.871407 -6517.110122 -VL56 -38941.035000 -57342.815000 29218.586000 -* 2023 12 10 4 12 0.00000000 -PL56 -1173.476261 -3958.456037 -5881.291916 -VL56 -38771.751000 -49634.799000 41226.011000 -* 2023 12 10 4 15 0.00000000 -PL56 -1858.126631 -4769.535996 -5041.457612 -VL56 -37039.297000 -40230.715000 51820.959000 -* 2023 12 10 4 18 0.00000000 -PL56 -2497.589878 -5398.727709 -4026.453383 -VL56 -33758.803000 -29489.168000 60631.863000 -* 2023 12 10 4 21 0.00000000 -PL56 -3064.618153 -5825.552437 -2871.307469 -VL56 -29009.533000 -17816.442000 67345.628000 -* 2023 12 10 4 24 0.00000000 -PL56 -3533.964974 -6037.164717 -1616.063069 -VL56 -22934.260000 -5651.773400 71720.054000 -* 2023 12 10 4 27 0.00000000 -PL56 -3883.501203 -6028.798003 -304.403700 -VL56 -15735.712000 6549.347500 73594.420000 -* 2023 12 10 4 30 0.00000000 -PL56 -4095.236931 -5803.894775 1017.887090 -VL56 -7669.676500 18333.387000 72897.054000 -* 2023 12 10 4 33 0.00000000 -PL56 -4156.193154 -5373.904889 2304.568490 -VL56 964.701680 29267.225000 69649.125000 -* 2023 12 10 4 36 0.00000000 -PL56 -4059.076004 -4757.756196 3510.615288 -VL56 9837.070000 38955.901000 63964.076000 -* 2023 12 10 4 39 0.00000000 -PL56 -3802.717555 -3981.024626 4593.843298 -VL56 18599.498000 47058.096000 56043.044000 -* 2023 12 10 4 42 0.00000000 -PL56 -3392.262158 -3074.847595 5516.418738 -VL56 26900.979000 53299.042000 46166.577000 -* 2023 12 10 4 45 0.00000000 -PL56 -2839.091212 -2074.637120 6246.188015 -VL56 34401.853000 57479.743000 34683.208000 -* 2023 12 10 4 48 0.00000000 -PL56 -2160.494696 -1018.661272 6757.785575 -VL56 40787.490000 59482.567000 21996.326000 -* 2023 12 10 4 51 0.00000000 -PL56 -1379.104316 53.449023 7033.491130 -VL56 45780.991000 59273.817000 8549.383500 -* 2023 12 10 4 54 0.00000000 -PL56 -522.112995 1102.204686 7063.807184 -VL56 49154.095000 56902.506000 -5189.948700 -* 2023 12 10 4 57 0.00000000 -PL56 379.684287 2089.716799 6847.760441 -VL56 50736.285000 52496.631000 -18744.869000 -* 2023 12 10 5 0 0.00000000 -PL56 1293.004148 2981.069286 6392.923621 -VL56 50422.654000 46257.234000 -31645.231000 -* 2023 12 10 5 3 0.00000000 -PL56 2183.305981 3745.558516 5715.155583 -VL56 48179.165000 38449.826000 -43442.959000 -* 2023 12 10 5 6 0.00000000 -PL56 3016.100678 4357.764781 4838.068977 -VL56 44045.929000 29394.102000 -53727.108000 -* 2023 12 10 5 9 0.00000000 -PL56 3758.295124 4798.419756 3792.229926 -VL56 38137.707000 19451.570000 -62138.314000 -* 2023 12 10 5 12 0.00000000 -PL56 4379.518439 5055.035680 2614.110796 -VL56 30641.691000 9011.831100 -68381.753000 -* 2023 12 10 5 15 0.00000000 -PL56 4853.380602 5122.272908 1344.817790 -VL56 21811.671000 -1523.262600 -72239.151000 -* 2023 12 10 5 18 0.00000000 -PL56 5158.594043 5002.019273 28.636390 -VL56 11959.126000 -11755.266000 -73576.824000 -* 2023 12 10 5 21 0.00000000 -PL56 5279.910538 4703.180060 -1288.548682 -VL56 1441.299900 -21305.532000 -72351.082000 -* 2023 12 10 5 24 0.00000000 -PL56 5208.819370 4241.182459 -2560.891888 -VL56 -9352.873000 -29830.336000 -68609.834000 -* 2023 12 10 5 27 0.00000000 -PL56 4943.979575 3637.227280 -3744.211009 -VL56 -20018.310000 -37033.877000 -62489.377000 -* 2023 12 10 5 30 0.00000000 -PL56 4491.366275 2917.328131 -4797.533424 -VL56 -30149.918000 -42678.743000 -54208.672000 -* 2023 12 10 5 33 0.00000000 -PL56 3864.128873 2111.187435 -5684.503098 -VL56 -39358.173000 -46593.482000 -44059.962000 -* 2023 12 10 5 36 0.00000000 -PL56 3082.176189 1250.964390 -6374.598440 -VL56 -47283.873000 -48677.004000 -32397.216000 -* 2023 12 10 5 39 0.00000000 -PL56 2171.511109 369.994418 -6844.128149 -VL56 -53611.120000 -48899.673000 -19623.108000 -* 2023 12 10 5 42 0.00000000 -PL56 1163.348014 -498.487730 -7076.984645 -VL56 -58078.437000 -47301.866000 -6175.347900 -* 2023 12 10 5 45 0.00000000 -PL56 93.046879 -1322.578383 -7065.151377 -VL56 -60488.171000 -43990.333000 7487.168300 -* 2023 12 10 5 48 0.00000000 -PL56 -1001.107869 -2072.851390 -6808.955356 -VL56 -60714.075000 -39132.503000 20898.563000 -* 2023 12 10 5 51 0.00000000 -PL56 -2079.246143 -2723.388246 -6317.067534 -VL56 -58707.020000 -32949.423000 33599.987000 -* 2023 12 10 5 54 0.00000000 -PL56 -3101.336089 -3252.667762 -5606.247519 -VL56 -54498.599000 -25707.064000 45153.935000 -* 2023 12 10 5 57 0.00000000 -PL56 -4028.653834 -3644.288713 -4700.834501 -VL56 -48202.615000 -17706.582000 55158.131000 -* 2023 12 10 6 0 0.00000000 -PL56 -4825.258369 -3887.503413 -3631.980753 -VL56 -40013.927000 -9272.975700 63260.128000 -* 2023 12 10 6 3 0.00000000 -PL56 -5459.412325 -3977.535199 -2436.634751 -VL56 -30203.730000 -742.545330 69170.514000 -* 2023 12 10 6 6 0.00000000 -PL56 -5904.888669 -3915.662672 -1156.295516 -VL56 -19111.421000 7550.486800 72674.888000 -* 2023 12 10 6 9 0.00000000 -PL56 -6142.098068 -3709.059222 164.426932 -VL56 -7132.904600 15287.619000 73643.306000 -* 2023 12 10 6 12 0.00000000 -PL56 -6158.977331 -3370.389940 1479.393566 -VL56 5294.172600 22179.266000 72036.588000 -* 2023 12 10 6 15 0.00000000 -PL56 -5951.585735 -2917.179775 2742.599651 -VL56 17708.089000 27976.943000 67908.860000 -* 2023 12 10 6 18 0.00000000 -PL56 -5524.369930 -2370.980498 3909.840530 -VL56 29641.797000 32483.135000 61405.339000 -* 2023 12 10 6 21 0.00000000 -PL56 -4890.087747 -1756.382519 4940.305298 -VL56 40642.072000 35558.765000 52756.559000 -* 2023 12 10 6 24 0.00000000 -PL56 -4069.393804 -1099.920086 5798.028387 -VL56 50287.520000 37127.323000 42268.516000 -* 2023 12 10 6 27 0.00000000 -PL56 -3090.119159 -428.930262 6453.143694 -VL56 58204.721000 37176.103000 30310.808000 -* 2023 12 10 6 30 0.00000000 -PL56 -1986.276740 229.585787 6882.908152 -VL56 64082.357000 35754.596000 17302.724000 -* 2023 12 10 6 33 0.00000000 -PL56 -796.834387 850.047633 7072.458891 -VL56 67682.787000 32970.266000 3698.068100 -* 2023 12 10 6 36 0.00000000 -PL56 435.687478 1409.284071 7015.294357 -VL56 68850.175000 28982.215000 -10030.509000 -* 2023 12 10 6 39 0.00000000 -PL56 1666.747248 1887.396547 6713.476718 -VL56 67516.540000 23993.527000 -23406.802000 -* 2023 12 10 6 42 0.00000000 -PL56 2851.396537 2268.468338 6177.552802 -VL56 63704.946000 18241.892000 -35966.803000 -* 2023 12 10 6 45 0.00000000 -PL56 3945.927475 2541.096952 5426.198431 -VL56 57530.031000 11989.422000 -47273.838000 -* 2023 12 10 6 48 0.00000000 -PL56 4909.501460 2698.735362 4485.589983 -VL56 49195.191000 5511.641300 -56933.579000 -* 2023 12 10 6 51 0.00000000 -PL56 5705.699981 2739.831851 3388.516428 -VL56 38986.949000 -913.893550 -64607.847000 -* 2023 12 10 6 54 0.00000000 -PL56 6303.942311 2667.760168 2173.246234 -VL56 27265.544000 -7019.371000 -70027.905000 -* 2023 12 10 6 57 0.00000000 -PL56 6680.696113 2490.540984 882.184529 -VL56 14451.582000 -12558.114000 -73004.712000 -* 2023 12 10 7 0 0.00000000 -PL56 6820.430826 2220.368378 -439.631413 -VL56 1010.433500 -17314.776000 -73435.717000 -* 2023 12 10 7 3 0.00000000 -PL56 6716.257673 1872.961180 -1746.142066 -VL56 -12566.237000 -21114.335000 -71309.868000 -* 2023 12 10 7 6 0.00000000 -PL56 6370.228431 1466.773150 -2991.904931 -VL56 -25779.780000 -23828.847000 -66706.663000 -* 2023 12 10 7 9 0.00000000 -PL56 5793.286172 1022.101864 -4133.700840 -VL56 -38144.265000 -25381.945000 -59792.670000 -* 2023 12 10 7 12 0.00000000 -PL56 5004.865807 560.140749 -5132.039303 -VL56 -49205.136000 -25750.528000 -50814.087000 -* 2023 12 10 7 15 0.00000000 -PL56 4032.175180 102.023944 -5952.501284 -VL56 -58555.750000 -24963.917000 -40086.333000 -* 2023 12 10 7 18 0.00000000 -PL56 2909.202968 -332.091624 -6566.879447 -VL56 -65851.434000 -23100.682000 -27982.101000 -* 2023 12 10 7 21 0.00000000 -PL56 1675.497294 -723.870131 -6954.091477 -VL56 -70820.820000 -20283.632000 -14918.035000 -* 2023 12 10 7 24 0.00000000 -PL56 374.766243 -1057.536556 -7100.847283 -VL56 -73274.302000 -16673.299000 -1340.998300 -* 2023 12 10 7 27 0.00000000 -PL56 -946.653646 -1320.487226 -7002.066879 -VL56 -73110.192000 -12460.125000 12286.006000 -* 2023 12 10 7 30 0.00000000 -PL56 -2241.416031 -1503.752945 -6661.044160 -VL56 -70318.408000 -7856.030200 25497.934000 -* 2023 12 10 7 33 0.00000000 -PL56 -3462.827341 -1602.303659 -6089.355617 -VL56 -64981.492000 -3085.224700 37841.837000 -* 2023 12 10 7 36 0.00000000 -PL56 -4566.506793 -1615.185135 -5306.514604 -VL56 -57273.582000 1625.179100 48891.094000 -* 2023 12 10 7 39 0.00000000 -PL56 -5512.004146 -1545.484942 -4339.372155 -VL56 -47456.322000 6054.845700 58259.521000 -* 2023 12 10 7 42 0.00000000 -PL56 -6264.317642 -1400.124664 -3221.260651 -VL56 -35871.936000 9999.693400 65615.393000 -* 2023 12 10 7 45 0.00000000 -PL56 -6795.251352 -1189.483349 -1990.894004 -VL56 -22932.329000 13281.100000 70694.534000 -* 2023 12 10 7 48 0.00000000 -PL56 -7084.546679 -926.863577 -691.048018 -VL56 -9104.864100 15754.113000 73311.467000 -* 2023 12 10 7 51 0.00000000 -PL56 -7120.727536 -627.820735 632.938125 -VL56 5105.166100 17314.404000 73368.005000 -* 2023 12 10 7 54 0.00000000 -PL56 -6901.605265 -309.383967 1934.781890 -VL56 19174.555000 17903.151000 70857.967000 -* 2023 12 10 7 57 0.00000000 -PL56 -6434.412458 10.788974 3168.928044 -VL56 32583.265000 17509.564000 65868.140000 -* 2023 12 10 8 0 0.00000000 -PL56 -5735.554498 315.281673 4292.197561 -VL56 44835.635000 16171.063000 58574.861000 -* 2023 12 10 8 3 0.00000000 -PL56 -4829.989688 587.768823 5265.338963 -VL56 55480.063000 13970.865000 49236.629000 -* 2023 12 10 8 6 0.00000000 -PL56 -3750.276473 813.802044 6054.414732 -VL56 64126.271000 11033.372000 38183.440000 -* 2023 12 10 8 9 0.00000000 -PL56 -2535.341145 981.495550 6631.976980 -VL56 70459.146000 7517.688900 25804.091000 -* 2023 12 10 8 12 0.00000000 -PL56 -1229.020063 1082.081089 6977.999717 -VL56 74249.722000 3609.695800 12531.927000 -* 2023 12 10 8 15 0.00000000 -PL56 121.562251 1110.312274 7080.539721 -VL56 75362.467000 -486.715330 -1170.910000 -* 2023 12 10 8 18 0.00000000 -PL56 1467.711592 1064.702540 6936.117094 -VL56 73758.938000 -4559.262200 -14828.778000 -* 2023 12 10 8 21 0.00000000 -PL56 2760.925004 947.590666 6549.818217 -VL56 69498.759000 -8396.834100 -27968.105000 -* 2023 12 10 8 24 0.00000000 -PL56 3954.642978 765.032069 5935.120369 -VL56 62737.672000 -11799.150000 -40132.692000 -* 2023 12 10 8 27 0.00000000 -PL56 5005.939652 526.519440 5113.438442 -VL56 53722.508000 -14586.066000 -50899.271000 -* 2023 12 10 8 30 0.00000000 -PL56 5877.092259 244.541720 4113.403011 -VL56 42782.996000 -16606.177000 -59891.784000 -* 2023 12 10 8 33 0.00000000 -PL56 6536.977157 -66.001488 2969.882965 -VL56 30320.420000 -17744.128000 -66795.306000 -* 2023 12 10 8 36 0.00000000 -PL56 6962.230044 -388.504659 1722.772655 -VL56 16792.926000 -17926.602000 -71368.160000 -* 2023 12 10 8 39 0.00000000 -PL56 7138.114564 -705.452927 415.586748 -VL56 2698.030000 -17126.334000 -73451.098000 -* 2023 12 10 8 42 0.00000000 -PL56 7059.060565 -999.270285 -906.086918 -VL56 -11446.676000 -15363.919000 -72973.812000 -* 2023 12 10 8 45 0.00000000 -PL56 6728.839529 -1253.178959 -2196.217273 -VL56 -25124.383000 -12707.156000 -69957.429000 -* 2023 12 10 8 48 0.00000000 -PL56 6160.367737 -1452.026396 -3409.968310 -VL56 -37839.157000 -9268.130900 -64512.977000 -* 2023 12 10 8 51 0.00000000 -PL56 5375.153750 -1583.038761 -4505.275381 -VL56 -49135.134000 -5198.036400 -56836.225000 -* 2023 12 10 8 54 0.00000000 -PL56 4402.425793 -1636.464489 -5444.296848 -VL56 -58612.956000 -680.215350 -47199.038000 -* 2023 12 10 8 57 0.00000000 -PL56 3277.987742 -1606.081410 -6194.691015 -VL56 -65943.385000 4077.955800 -35938.627000 -* 2023 12 10 9 0 0.00000000 -PL56 2042.859691 -1489.548416 -6730.678870 -VL56 -70877.461000 8854.219600 -23444.749000 -* 2023 12 10 9 3 0.00000000 -PL56 741.766316 -1288.587361 -7033.871699 -VL56 -73253.423000 13420.980000 -10146.533000 -* 2023 12 10 9 6 0.00000000 -PL56 -578.473976 -1008.993338 -7093.851364 -VL56 -73000.854000 17554.843000 3501.828700 -* 2023 12 10 9 9 0.00000000 -PL56 -1870.606056 -660.473975 -6908.497793 -VL56 -70141.670000 21046.018000 17034.928000 -* 2023 12 10 9 12 0.00000000 -PL56 -3088.595822 -256.320717 -6484.062407 -VL56 -64789.137000 23707.578000 29990.445000 -* 2023 12 10 9 15 0.00000000 -PL56 -4189.241924 187.079577 -5834.985287 -VL56 -57143.943000 25383.894000 41923.097000 -* 2023 12 10 9 18 0.00000000 -PL56 -5133.701780 650.879169 -4983.460574 -VL56 -47488.521000 25958.350000 52418.991000 -* 2023 12 10 9 21 0.00000000 -PL56 -5888.887405 1114.532611 -3958.745066 -VL56 -36178.231000 25359.929000 61109.634000 -* 2023 12 10 9 24 0.00000000 -PL56 -6428.680085 1556.666631 -2796.215365 -VL56 -23629.836000 23568.337000 67685.747000 -* 2023 12 10 9 27 0.00000000 -PL56 -6734.906942 1956.022025 -1536.186175 -VL56 -10306.730000 20616.812000 71909.881000 -* 2023 12 10 9 30 0.00000000 -PL56 -6798.029572 2292.425493 -222.522259 -VL56 3298.169500 16592.632000 73626.578000 -* 2023 12 10 9 33 0.00000000 -PL56 -6617.501001 2547.744496 1098.912048 -VL56 16682.068000 11634.653000 72769.973000 -* 2023 12 10 9 36 0.00000000 -PL56 -6201.761505 2706.775903 2381.899841 -VL56 29352.579000 5928.474800 69367.008000 -* 2023 12 10 9 39 0.00000000 -PL56 -5567.869832 2758.023273 3581.543085 -VL56 40847.731000 -301.096830 63536.800000 -* 2023 12 10 9 42 0.00000000 -PL56 -4740.786716 2694.318575 4655.884372 -VL56 50754.415000 -6799.690600 55485.830000 -* 2023 12 10 9 45 0.00000000 -PL56 -3752.348749 2513.257140 5567.405691 -VL56 58724.012000 -13294.288000 45499.181000 -* 2023 12 10 9 48 0.00000000 -PL56 -2639.991506 2217.429507 6284.345604 -VL56 64484.847000 -19504.821000 33929.426000 -* 2023 12 10 9 51 0.00000000 -PL56 -1445.280645 1814.441318 6781.794180 -VL56 67850.916000 -25156.185000 21182.709000 -* 2023 12 10 9 54 0.00000000 -PL56 -212.316580 1316.719714 7042.528118 -VL56 68727.008000 -29989.626000 7704.356300 -* 2023 12 10 9 57 0.00000000 -PL56 1013.914478 741.117810 7057.570395 -VL56 67109.923000 -33773.806000 -6037.135000 -* 2023 12 10 10 0 0.00000000 -PL56 2189.188171 108.333449 6826.474421 -VL56 63087.013000 -36314.430000 -19565.048000 -* 2023 12 10 10 3 0.00000000 -PL56 3271.638896 -557.839324 6357.329706 -VL56 56832.107000 -37463.130000 -32410.199000 -* 2023 12 10 10 6 0.00000000 -PL56 4223.258989 -1231.404486 5666.489379 -VL56 48598.696000 -37124.694000 -44126.217000 -* 2023 12 10 10 9 0.00000000 -PL56 5011.251988 -1885.175192 4778.020133 -VL56 38710.522000 -35262.786000 -54304.851000 -* 2023 12 10 10 12 0.00000000 -PL56 5609.192144 -2491.866351 3722.887002 -VL56 27549.557000 -31903.235000 -62590.201000 -* 2023 12 10 10 15 0.00000000 -PL56 5997.949468 -3025.227165 2537.889103 -VL56 15541.792000 -27135.027000 -68692.042000 -* 2023 12 10 10 18 0.00000000 -PL56 6166.334157 -3461.165481 1264.373014 -VL56 3140.605600 -21108.443000 -72396.893000 -* 2023 12 10 10 21 0.00000000 -PL56 6111.431156 -3778.811820 -53.228647 -VL56 -9190.999400 -14030.246000 -73576.487000 -* 2023 12 10 10 24 0.00000000 -PL56 5838.606829 -3961.470682 -1368.981428 -VL56 -20998.870000 -6156.000200 -72192.768000 -* 2023 12 10 10 27 0.00000000 -PL56 5361.185198 -3997.410117 -2637.090200 -VL56 -31855.948000 2220.270300 -68299.108000 -* 2023 12 10 10 30 0.00000000 -PL56 4699.810848 -3880.450527 -3813.523362 -VL56 -41378.510000 10777.776000 -62037.295000 -* 2023 12 10 10 33 0.00000000 -PL56 3881.536719 -3610.329026 -4857.552593 -VL56 -49240.315000 19182.088000 -53631.232000 -* 2023 12 10 10 36 0.00000000 -PL56 2938.685554 -3192.824449 -5733.148641 -VL56 -55183.608000 27098.585000 -43377.349000 -* 2023 12 10 10 39 0.00000000 -PL56 1907.545734 -2639.643302 -6410.183768 -VL56 -59026.428000 34205.320000 -31632.855000 -* 2023 12 10 10 42 0.00000000 -PL56 826.964675 -1968.081276 -6865.413539 -VL56 -60666.898000 40205.213000 -18803.170000 -* 2023 12 10 10 45 0.00000000 -PL56 -263.110041 -1200.470920 -7083.221245 -VL56 -60084.602000 44837.430000 -5328.012400 -* 2023 12 10 10 48 0.00000000 -PL56 -1323.087466 -363.438252 -7056.106524 -VL56 -57339.159000 47887.310000 8332.824600 -* 2023 12 10 10 51 0.00000000 -PL56 -2315.141833 513.005465 -6784.921466 -VL56 -52566.342000 49194.736000 21713.517000 -* 2023 12 10 10 54 0.00000000 -PL56 -3204.536873 1396.514466 -6278.852659 -VL56 -45972.454000 48661.441000 34356.130000 -* 2023 12 10 10 57 0.00000000 -PL56 -3960.829027 2253.574193 -5555.150711 -VL56 -37826.825000 46256.652000 45824.898000 -* 2023 12 10 11 0 0.00000000 -PL56 -4558.921758 3050.752911 -4638.606220 -VL56 -28452.509000 42020.814000 55720.312000 -* 2023 12 10 11 3 0.00000000 -PL56 -4979.933453 3756.001176 -3560.765205 -VL56 -18214.864000 36067.002000 63693.540000 -* 2023 12 10 11 6 0.00000000 -PL56 -5211.839045 4339.948192 -2358.897237 -VL56 -7508.038200 28579.278000 69459.564000 -* 2023 12 10 11 9 0.00000000 -PL56 -5249.856493 4777.141747 -1074.738147 -VL56 3259.911300 19807.913000 72808.890000 -* 2023 12 10 11 12 0.00000000 -PL56 -5096.553469 5047.171645 246.958976 -VL56 13683.191000 10061.236000 73617.146000 -* 2023 12 10 11 15 0.00000000 -PL56 -4761.658522 5135.618011 1560.014785 -VL56 23374.699000 -305.696180 71850.996000 -* 2023 12 10 11 18 0.00000000 -PL56 -4261.577857 5034.767528 2818.490095 -VL56 31982.152000 -10905.279000 67570.374000 -* 2023 12 10 11 21 0.00000000 -PL56 -3618.636867 4744.057536 3978.349663 -VL56 39202.294000 -21333.306000 60926.120000 -* 2023 12 10 11 24 0.00000000 -PL56 -2860.088833 4270.227479 4999.046112 -VL56 44792.456000 -31185.406000 52153.639000 -* 2023 12 10 11 27 0.00000000 -PL56 -2016.945007 3627.172666 5844.961416 -VL56 48578.940000 -40073.564000 41563.387000 -* 2023 12 10 11 30 0.00000000 -PL56 -1122.682172 2835.508283 6486.650308 -VL56 50462.064000 -47641.662000 29528.497000 -* 2023 12 10 11 33 0.00000000 -PL56 -211.891142 1921.868087 6901.842151 -VL56 50417.624000 -53579.164000 16470.520000 -* 2023 12 10 11 36 0.00000000 -PL56 681.072052 917.974243 7076.179410 -VL56 48495.483000 -57632.991000 2844.713300 -* 2023 12 10 11 39 0.00000000 -PL56 1523.385883 -140.486126 7003.683618 -VL56 44815.421000 -59617.108000 -10875.772000 -* 2023 12 10 11 42 0.00000000 -PL56 2284.970006 -1215.139314 6686.941784 -VL56 39561.010000 -59420.165000 -24214.989000 -* 2023 12 10 11 45 0.00000000 -PL56 2939.561399 -2266.320932 6137.014014 -VL56 32971.346000 -57010.805000 -36710.035000 -* 2023 12 10 11 48 0.00000000 -PL56 3465.628747 -3254.545741 5373.061978 -VL56 25331.248000 -52440.479000 -47926.216000 -* 2023 12 10 11 51 0.00000000 -PL56 3847.094016 -4142.002820 4421.702932 -VL56 16959.819000 -45843.550000 -57472.198000 -* 2023 12 10 11 54 0.00000000 -PL56 4073.836493 -4894.022612 3316.103066 -VL56 8197.674300 -37433.912000 -65013.909000 -* 2023 12 10 11 57 0.00000000 -PL56 4141.958575 -5480.457552 2094.829632 -VL56 -606.684400 -27498.696000 -70287.187000 -* 2023 12 10 12 0 0.00000000 -PL56 4053.799602 -5876.913800 800.496676 -VL56 -9111.123500 -16388.158000 -73108.046000 -* 2023 12 10 12 3 0.00000000 -PL56 3817.695338 -6065.773841 -521.746887 -VL56 -16993.781000 -4502.540800 -73379.726000 -* 2023 12 10 12 6 0.00000000 -PL56 3447.496316 -6036.962053 -1825.826517 -VL56 -23965.822000 7723.120300 -71096.515000 -* 2023 12 10 12 9 0.00000000 -PL56 2961.865030 -5788.413912 -3066.385600 -VL56 -29783.080000 19836.690000 -66343.501000 -* 2023 12 10 12 12 0.00000000 -PL56 2383.389796 -5326.226193 -4200.389112 -VL56 -34254.880000 31386.608000 -59292.557000 -* 2023 12 10 12 15 0.00000000 -PL56 1737.559833 -4664.484231 -5188.621770 -VL56 -37250.326000 41939.612000 -50194.616000 -* 2023 12 10 12 18 0.00000000 -PL56 1051.657399 -3824.782814 -5997.019063 -VL56 -38701.312000 51097.093000 -39369.194000 -* 2023 12 10 12 21 0.00000000 -PL56 353.622602 -2835.474537 -6597.794011 -VL56 -38602.695000 58509.000000 -27192.126000 -* 2023 12 10 12 24 0.00000000 -PL56 -329.065130 -1730.681653 -6970.334590 -VL56 -37010.225000 63886.128000 -14082.515000 -* 2023 12 10 12 27 0.00000000 -PL56 -970.444792 -549.109976 -7101.856032 -VL56 -34035.982000 67009.858000 -488.658940 -* 2023 12 10 12 30 0.00000000 -PL56 -1547.035934 667.293815 -6987.801613 -VL56 -29842.400000 67739.800000 13125.914000 -* 2023 12 10 12 33 0.00000000 -PL56 -2038.679783 1874.800957 -6631.988841 -VL56 -24634.753000 66019.050000 26296.596000 -* 2023 12 10 12 36 0.00000000 -PL56 -2429.234981 3029.437809 -6046.503216 -VL56 -18652.625000 61877.651000 38571.635000 -* 2023 12 10 12 39 0.00000000 -PL56 -2707.111021 4088.564496 -5251.339187 -VL56 -12160.437000 55433.783000 49526.421000 -* 2023 12 10 12 42 0.00000000 -PL56 -2865.623193 5012.451243 -4273.782973 -VL56 -5437.084200 46892.119000 58777.817000 -* 2023 12 10 12 45 0.00000000 -PL56 -2903.153522 5765.796069 -3147.536759 -VL56 1235.300400 36538.777000 65998.300000 -* 2023 12 10 12 48 0.00000000 -PL56 -2823.105005 6319.118876 -1911.602525 -VL56 7582.898300 24732.827000 70928.467000 -* 2023 12 10 12 51 0.00000000 -PL56 -2633.649126 6649.975210 -608.953476 -VL56 13351.576000 11894.592000 73388.103000 -* 2023 12 10 12 54 0.00000000 -PL56 -2347.272199 6743.921848 714.969910 -VL56 18317.675000 -1509.839600 73284.322000 -* 2023 12 10 12 57 0.00000000 -PL56 -1980.139524 6595.184887 2013.883425 -VL56 22297.631000 -14986.691000 70617.021000 -* 2023 12 10 13 0 0.00000000 -PL56 -1551.298644 6206.974791 3242.338379 -VL56 25155.837000 -28034.969000 65478.680000 -* 2023 12 10 13 3 0.00000000 -PL56 -1081.767405 5591.431349 4357.362953 -VL56 26809.546000 -40166.742000 58050.957000 -* 2023 12 10 13 6 0.00000000 -PL56 -593.558221 4769.213760 5320.001494 -VL56 27231.228000 -50926.520000 48597.092000 -* 2023 12 10 13 9 0.00000000 -PL56 -108.681236 3768.751841 6096.691606 -VL56 26448.340000 -59909.119000 37450.904000 -* 2023 12 10 13 12 0.00000000 -PL56 351.822031 2625.203523 6660.423287 -VL56 24540.353000 -66774.501000 25004.382000 -* 2023 12 10 13 15 0.00000000 -PL56 768.770065 1379.167580 6991.652369 -VL56 21633.477000 -71259.844000 11692.648000 -* 2023 12 10 13 18 0.00000000 -PL56 1125.624623 75.205805 7078.945083 -VL56 17893.906000 -73188.843000 -2020.926700 -* 2023 12 10 13 21 0.00000000 -PL56 1409.137162 -1239.768734 6919.344650 -VL56 13519.504000 -72477.365000 -15660.331000 -* 2023 12 10 13 24 0.00000000 -PL56 1609.837651 -2518.187046 6518.460803 -VL56 8730.650100 -69136.968000 -28752.355000 -* 2023 12 10 13 27 0.00000000 -PL56 1722.350951 -3713.553321 5890.277468 -VL56 3760.261600 -63275.180000 -40842.417000 -* 2023 12 10 13 30 0.00000000 -PL56 1745.530418 -4782.150520 5056.679712 -VL56 -1156.485900 -55092.402000 -51509.697000 -* 2023 12 10 13 33 0.00000000 -PL56 1682.406911 -5684.660547 4046.712396 -VL56 -5792.260100 -44875.712000 -60381.715000 -* 2023 12 10 13 36 0.00000000 -PL56 1539.957581 -6387.648485 2895.588485 -VL56 -9937.548700 -32989.845000 -67147.823000 -* 2023 12 10 13 39 0.00000000 -PL56 1328.699139 -6864.845024 1643.463956 -VL56 -13410.037000 -19863.877000 -71571.166000 -* 2023 12 10 13 42 0.00000000 -PL56 1062.124106 -7098.167744 334.026072 -VL56 -16062.622000 -5975.539800 -73497.562000 -* 2023 12 10 13 45 0.00000000 -PL56 756.004946 -7078.436509 -987.059311 -VL56 -17790.059000 8167.052500 -72862.216000 -* 2023 12 10 13 48 0.00000000 -PL56 427.596689 -6805.736020 -2273.784027 -VL56 -18533.354000 22046.184000 -69691.789000 -* 2023 12 10 13 51 0.00000000 -PL56 94.784012 -6289.403229 -3481.435245 -VL56 -18281.628000 35154.785000 -64102.871000 -* 2023 12 10 13 54 0.00000000 -PL56 -224.782950 -5547.657194 -4568.165559 -VL56 -17071.587000 47016.117000 -56296.202000 -* 2023 12 10 13 57 0.00000000 -PL56 -514.525157 -4606.892218 -5496.437302 -VL56 -14984.897000 57201.344000 -46548.154000 -* 2023 12 10 14 0 0.00000000 -PL56 -759.703975 -3500.676238 -6234.285934 -VL56 -12143.445000 65344.477000 -35199.621000 -* 2023 12 10 14 3 0.00000000 -PL56 -948.089479 -2268.507399 -6756.369314 -VL56 -8702.916500 71154.337000 -22643.319000 -* 2023 12 10 14 6 0.00000000 -PL56 -1070.502740 -954.382411 -7044.779543 -VL56 -4845.285300 74423.477000 -9310.221300 -* 2023 12 10 14 9 0.00000000 -PL56 -1121.214859 394.768259 -7089.606173 -VL56 -770.467580 75034.143000 4344.360300 -* 2023 12 10 14 12 0.00000000 -PL56 -1098.189989 1730.728732 -6889.246614 -VL56 3312.614900 72961.592000 17854.977000 -* 2023 12 10 14 15 0.00000000 -PL56 -1003.165842 3005.682714 -6450.464000 -VL56 7195.125500 68274.942000 30759.894000 -* 2023 12 10 14 18 0.00000000 -PL56 -841.569945 4173.895260 -5788.193612 -VL56 10677.458000 61135.955000 42615.235000 -* 2023 12 10 14 21 0.00000000 -PL56 -622.271743 5193.347942 -4925.092033 -VL56 13578.245000 51794.863000 53009.326000 -* 2023 12 10 14 24 0.00000000 -PL56 -357.177056 6027.274353 -3890.827936 -VL56 15742.827000 40583.523000 61577.068000 -* 2023 12 10 14 27 0.00000000 -PL56 -60.677377 6645.539208 -2721.119397 -VL56 17050.862000 27904.856000 68013.589000 -* 2023 12 10 14 30 0.00000000 -PL56 251.027811 7025.799234 -1456.537559 -VL56 17422.718000 14219.187000 72086.421000 -* 2023 12 10 14 33 0.00000000 -PL56 560.707968 7154.389516 -141.107558 -VL56 16824.086000 27.422366 73645.715000 -* 2023 12 10 14 36 0.00000000 -PL56 850.943391 7026.881733 1179.247188 -VL56 15268.474000 -14148.492000 72631.295000 -* 2023 12 10 14 39 0.00000000 -PL56 1104.989385 6648.275269 2458.354281 -VL56 12817.100000 -27786.547000 69075.807000 -* 2023 12 10 14 42 0.00000000 -PL56 1307.614077 6032.807299 3651.459469 -VL56 9576.237400 -40385.729000 63103.676000 -* 2023 12 10 14 45 0.00000000 -PL56 1445.870663 5203.395133 4716.839756 -VL56 5692.563700 -51485.860000 54926.169000 -* 2023 12 10 14 48 0.00000000 -PL56 1509.767546 4190.733865 5617.297901 -VL56 1346.401800 -60685.728000 44833.194000 -* 2023 12 10 14 51 0.00000000 -PL56 1492.797486 3032.092586 6321.468195 -VL56 -3256.763400 -67657.988000 33180.626000 -* 2023 12 10 14 54 0.00000000 -PL56 1392.307730 1769.885836 6804.888784 -VL56 -7895.843100 -72159.995000 20377.284000 -* 2023 12 10 14 57 0.00000000 -PL56 1209.695519 450.077435 7050.822949 -VL56 -12343.683000 -74041.047000 6870.084300 -* 2023 12 10 15 0 0.00000000 -PL56 950.422734 -879.519304 7050.804633 -VL56 -16377.414000 -73246.577000 -6871.424200 -* 2023 12 10 15 3 0.00000000 -PL56 623.849826 -2170.983095 6804.909297 -VL56 -19788.376000 -69819.128000 -20370.348000 -* 2023 12 10 15 6 0.00000000 -PL56 242.892799 -3378.020144 6321.743488 -VL56 -22391.727000 -63896.470000 -33158.263000 -* 2023 12 10 15 9 0.00000000 -PL56 -176.484746 -4457.634297 5618.147886 -VL56 -24035.028000 -55706.052000 -44791.292000 -* 2023 12 10 15 12 0.00000000 -PL56 -615.923194 -5371.671081 4718.626726 -VL56 -24605.627000 -45556.824000 -54864.212000 -* 2023 12 10 15 15 0.00000000 -PL56 -1055.442203 -6088.197624 3654.523954 -VL56 -24037.029000 -33829.114000 -63024.632000 -* 2023 12 10 15 18 0.00000000 -PL56 -1474.315036 -6582.665853 2462.946077 -VL56 -22313.323000 -20960.544000 -68986.609000 -* 2023 12 10 15 21 0.00000000 -PL56 -1852.001203 -6838.797710 1185.465853 -VL56 -19471.283000 -7429.488100 -72541.460000 -* 2023 12 10 15 24 0.00000000 -PL56 -2169.096112 -6849.154496 -133.348446 -VL56 -15600.039000 6263.573800 -73566.227000 -* 2023 12 10 15 27 0.00000000 -PL56 -2408.247548 -6615.355875 -1447.524476 -VL56 -10837.768000 19616.003000 -72028.325000 -* 2023 12 10 15 30 0.00000000 -PL56 -2554.993630 -6147.939615 -2711.326418 -VL56 -5366.356500 32142.760000 -67986.409000 -* 2023 12 10 15 33 0.00000000 -PL56 -2598.484172 -5465.872116 -3880.876881 -VL56 596.194220 43395.377000 -61587.509000 -* 2023 12 10 15 36 0.00000000 -PL56 -2532.049369 -4595.734895 -4915.692116 -VL56 6805.073100 52978.772000 -53060.246000 -* 2023 12 10 15 39 0.00000000 -PL56 -2353.590327 -3570.636232 -5780.066249 -VL56 12998.968000 60564.790000 -42705.077000 -* 2023 12 10 15 42 0.00000000 -PL56 -2065.780071 -2428.909594 -6444.262413 -VL56 18910.787000 65902.459000 -30882.723000 -* 2023 12 10 15 45 0.00000000 -PL56 -1676.069301 -1212.655749 -6885.482120 -VL56 24278.580000 68825.074000 -18001.101000 -* 2023 12 10 15 48 0.00000000 -PL56 -1196.498787 33.812298 -7088.589467 -VL56 28855.970000 69253.881000 -4501.339000 -* 2023 12 10 15 51 0.00000000 -PL56 -643.329903 1265.562969 -7046.583187 -VL56 32421.968000 67198.786000 9156.135600 -* 2023 12 10 15 54 0.00000000 -PL56 -36.503112 2438.631011 -6760.818833 -VL56 34790.216000 62756.814000 22505.565000 -* 2023 12 10 15 57 0.00000000 -PL56 601.060580 3511.555131 -6240.980330 -VL56 35817.262000 56108.443000 35089.639000 -* 2023 12 10 16 0 0.00000000 -PL56 1244.301655 4446.831291 -5504.796470 -VL56 35410.030000 47511.635000 46474.229000 -* 2023 12 10 16 3 0.00000000 -PL56 1866.982587 5212.234956 -4577.496801 -VL56 33531.564000 37293.472000 56262.424000 -* 2023 12 10 16 6 0.00000000 -PL56 2442.736864 5781.970899 -3491.012126 -VL56 30204.954000 25839.168000 64108.903000 -* 2023 12 10 16 9 0.00000000 -PL56 2946.168524 6137.601879 -2282.926295 -VL56 25514.982000 13578.599000 69732.939000 -* 2023 12 10 16 12 0.00000000 -PL56 3353.957251 6268.712527 -995.203886 -VL56 19607.070000 970.386290 72930.255000 -* 2023 12 10 16 15 0.00000000 -PL56 3645.916377 6173.268343 327.272697 -VL56 12683.017000 -11516.010000 73582.220000 -* 2023 12 10 16 18 0.00000000 -PL56 3805.946800 5857.640588 1638.300322 -VL56 4993.779300 -23419.235000 71661.313000 -* 2023 12 10 16 21 0.00000000 -PL56 3822.838671 5336.292290 2892.016345 -VL56 -3170.171800 -34304.575000 67232.840000 -* 2023 12 10 16 24 0.00000000 -PL56 3690.878184 4631.139545 4044.556282 -VL56 -11490.739000 -43781.432000 60452.777000 -* 2023 12 10 16 27 0.00000000 -PL56 3410.226733 3770.613351 5055.633029 -VL56 -19635.506000 -51518.716000 51561.336000 -* 2023 12 10 16 30 0.00000000 -PL56 2987.051815 2788.476870 5889.970687 -VL56 -27271.960000 -57256.836000 40873.089000 -* 2023 12 10 16 33 0.00000000 -PL56 2433.405297 1722.455791 6518.532550 -VL56 -34080.945000 -60816.223000 28764.518000 -* 2023 12 10 16 36 0.00000000 -PL56 1766.867553 612.752164 6919.507745 -VL56 -39769.461000 -62101.827000 15659.535000 -* 2023 12 10 16 39 0.00000000 -PL56 1009.967087 -499.495456 7079.034679 -VL56 -44082.506000 -61104.472000 2014.931600 -* 2023 12 10 16 42 0.00000000 -PL56 189.401342 -1573.745726 6991.651971 -VL56 -46813.488000 -57899.287000 -11695.285000 -* 2023 12 10 16 45 0.00000000 -PL56 -664.916623 -2571.538660 6660.469252 -VL56 -47813.011000 -52641.407000 -24995.426000 -* 2023 12 10 16 48 0.00000000 -PL56 -1520.954210 -3457.878001 6097.050794 -VL56 -46995.937000 -45559.194000 -37424.332000 -* 2023 12 10 16 51 0.00000000 -PL56 -2345.756715 -4202.464942 5321.021946 -VL56 -44345.662000 -36944.613000 -48549.966000 -* 2023 12 10 16 54 0.00000000 -PL56 -3106.717021 -4780.752552 4359.414591 -VL56 -39917.665000 -27142.767000 -57983.859000 -* 2023 12 10 16 57 0.00000000 -PL56 -3772.877099 -5174.784551 3245.748304 -VL56 -33839.411000 -16538.463000 -65395.901000 -* 2023 12 10 17 0 0.00000000 -PL56 -4316.196796 -5373.777098 2018.867644 -VL56 -26306.822000 -5541.197000 -70526.409000 -* 2023 12 10 17 3 0.00000000 -PL56 -4712.734991 -5374.419768 721.578974 -VL56 -17578.128000 5430.914800 -73196.299000 -* 2023 12 10 17 6 0.00000000 -PL56 -4943.692082 -5180.879859 -600.867854 -VL56 -7964.615100 15967.887000 -73314.058000 -* 2023 12 10 17 9 0.00000000 -PL56 -4996.260761 -4804.507282 -1902.394627 -VL56 2181.389500 25684.303000 -70879.455000 -* 2023 12 10 17 12 0.00000000 -PL56 -4864.239583 -4263.251937 -3137.740195 -VL56 12480.746000 34234.670000 -65983.079000 -* 2023 12 10 17 15 0.00000000 -PL56 -4548.378370 -3580.824260 -4264.059398 -VL56 22542.815000 41326.323000 -58801.701000 -* 2023 12 10 17 18 0.00000000 -PL56 -4056.446536 -2785.650434 -5242.408779 -VL56 31980.814000 46729.349000 -49590.530000 -* 2023 12 10 17 21 0.00000000 -PL56 -3403.028394 -1909.676159 -6039.068102 -VL56 40426.699000 50283.467000 -38672.819000 -* 2023 12 10 17 24 0.00000000 -PL56 -2609.060702 -987.075789 -6626.656298 -VL56 47544.861000 51901.713000 -26427.521000 -* 2023 12 10 17 27 0.00000000 -PL56 -1701.136322 -52.922347 -6985.015298 -VL56 53044.371000 51571.062000 -13275.884000 -* 2023 12 10 17 30 0.00000000 -PL56 -710.603337 858.128371 -7101.843643 -VL56 56689.319000 49350.317000 332.698160 -* 2023 12 10 17 33 0.00000000 -PL56 327.504180 1713.095383 -6973.079971 -VL56 58307.396000 45365.975000 13934.343000 -* 2023 12 10 17 36 0.00000000 -PL56 1375.676670 2481.839959 -6603.038664 -VL56 57796.963000 39806.253000 27064.566000 -* 2023 12 10 17 39 0.00000000 -PL56 2395.255559 3138.114542 -6004.293891 -VL56 55132.665000 32913.822000 39272.614000 -* 2023 12 10 17 42 0.00000000 -PL56 3347.838403 3660.461995 -5197.301221 -VL56 50368.637000 24976.641000 50135.896000 -* 2023 12 10 17 45 0.00000000 -PL56 4196.717637 4032.935678 -4209.762725 -VL56 43639.041000 16317.216000 59274.178000 -* 2023 12 10 17 48 0.00000000 -PL56 4908.309535 4245.617764 -3075.739514 -VL56 35156.161000 7280.744200 66363.378000 -* 2023 12 10 17 51 0.00000000 -PL56 5453.514889 4294.907272 -1834.520127 -VL56 25204.697000 -1778.426700 71148.759000 -* 2023 12 10 17 54 0.00000000 -PL56 5808.945979 4183.559209 -529.274995 -VL56 14132.770000 -10510.816000 73455.336000 -* 2023 12 10 17 57 0.00000000 -PL56 5957.958498 3920.466749 794.459004 -VL56 2339.270700 -18586.185000 73196.171000 -* 2023 12 10 18 0 0.00000000 -PL56 5891.433052 3520.191198 2090.404746 -VL56 -9741.407400 -25707.241000 70376.416000 -* 2023 12 10 18 3 0.00000000 -PL56 5608.260536 3002.257012 3313.215427 -VL56 -21656.687000 -31621.646000 65093.949000 -* 2023 12 10 18 6 0.00000000 -PL56 5115.500470 2390.247935 4420.114984 -VL56 -32954.644000 -36132.141000 57535.560000 -* 2023 12 10 18 9 0.00000000 -PL56 4428.203515 1710.748920 5372.432147 -VL56 -43202.238000 -39103.381000 47968.828000 -* 2023 12 10 18 12 0.00000000 -PL56 3568.916378 992.192076 6136.965213 -VL56 -52002.306000 -40465.858000 36732.172000 -* 2023 12 10 18 15 0.00000000 -PL56 2566.890039 263.661102 6687.132010 -VL56 -59009.505000 -40216.585000 24220.267000 -* 2023 12 10 18 18 0.00000000 -PL56 1457.036881 -446.288956 7003.862735 -VL56 -63942.077000 -38416.672000 10870.519000 -* 2023 12 10 18 21 0.00000000 -PL56 278.683267 -1110.749474 7076.230609 -VL56 -66592.822000 -35187.020000 -2852.218400 -* 2023 12 10 18 24 0.00000000 -PL56 -925.845709 -1705.478023 6901.803384 -VL56 -66836.820000 -30701.713000 -16471.668000 -* 2023 12 10 18 27 0.00000000 -PL56 -2112.756060 -2209.783304 6486.708131 -VL56 -64636.282000 -25179.679000 -29515.634000 -* 2023 12 10 18 30 0.00000000 -PL56 -3238.376952 -2607.245267 5845.417335 -VL56 -60042.941000 -18874.942000 -41531.388000 -* 2023 12 10 18 33 0.00000000 -PL56 -4260.775381 -2886.254619 5000.269579 -VL56 -53198.013000 -12066.187000 -52100.348000 -* 2023 12 10 18 36 0.00000000 -PL56 -5141.343436 -3040.355289 3980.714082 -VL56 -44328.718000 -5045.282400 -60853.348000 -* 2023 12 10 18 39 0.00000000 -PL56 -5846.285779 -3068.370747 2822.298808 -VL56 -33741.127000 1895.044400 -67483.954000 -* 2023 12 10 18 42 0.00000000 -PL56 -6347.951126 -2974.311843 1565.437158 -VL56 -21809.887000 8473.135300 -71759.831000 -* 2023 12 10 18 45 0.00000000 -PL56 -6625.950423 -2767.071256 253.984111 -VL56 -8964.677800 14430.167000 -73532.218000 -* 2023 12 10 18 48 0.00000000 -PL56 -6668.000299 -2459.911983 -1066.326437 -VL56 4326.448600 19541.005000 -72741.734000 -* 2023 12 10 18 51 0.00000000 -PL56 -6470.449590 -2069.775912 -2349.516899 -VL56 17575.686000 23623.376000 -69420.705000 -* 2023 12 10 18 54 0.00000000 -PL56 -6038.459188 -1616.448317 -3551.002100 -VL56 30294.951000 26544.566000 -63690.868000 -* 2023 12 10 18 57 0.00000000 -PL56 -5385.835726 -1121.623460 -4629.153954 -VL56 42014.739000 28225.640000 -55757.821000 -* 2023 12 10 19 0 0.00000000 -PL56 -4534.535078 -607.917735 -5546.736201 -VL56 52301.871000 28643.126000 -45902.294000 -* 2023 12 10 19 3 0.00000000 -PL56 -3513.864292 -97.876933 -6272.158538 -VL56 60775.176000 27827.986000 -34468.806000 -* 2023 12 10 19 6 0.00000000 -PL56 -2359.424399 386.976740 -6780.510628 -VL56 67118.395000 25862.225000 -21852.802000 -* 2023 12 10 19 9 0.00000000 -PL56 -1111.845942 827.018003 -7054.356173 -VL56 71090.445000 22873.580000 -8487.010700 -* 2023 12 10 19 12 0.00000000 -PL56 184.635889 1205.282526 -7084.279237 -VL56 72532.906000 19028.786000 5172.481300 -* 2023 12 10 19 15 0.00000000 -PL56 1483.719739 1508.100542 -6869.180388 -VL56 71375.318000 14525.781000 18659.916000 -* 2023 12 10 19 18 0.00000000 -PL56 2738.655918 1725.582948 -6416.326529 -VL56 67638.776000 9585.220300 31513.941000 -* 2023 12 10 19 21 0.00000000 -PL56 3903.903522 1851.946537 -5741.139674 -VL56 61436.380000 4441.056100 43292.227000 -* 2023 12 10 19 24 0.00000000 -PL56 4936.772487 1885.665972 -4866.726263 -VL56 52971.203000 -669.212370 53585.559000 -* 2023 12 10 19 27 0.00000000 -PL56 5799.005033 1829.448949 -3823.152693 -VL56 42531.517000 -5514.412100 62032.160000 -* 2023 12 10 19 30 0.00000000 -PL56 6458.237893 1690.031652 -2646.468445 -VL56 30482.342000 -9879.741800 68331.189000 -* 2023 12 10 19 33 0.00000000 -PL56 6889.282722 1477.798790 -1377.498507 -VL56 17253.626000 -13576.134000 72254.825000 -* 2023 12 10 19 36 0.00000000 -PL56 7075.161752 1206.241026 -60.432303 -VL56 3324.809100 -16448.885000 73658.471000 -* 2023 12 10 19 39 0.00000000 -PL56 7007.835035 891.270284 1258.740571 -VL56 -10793.769000 -18384.647000 72487.468000 -* 2023 12 10 19 42 0.00000000 -PL56 6688.577938 550.427169 2533.880211 -VL56 -24580.798000 -19316.483000 68780.019000 -* 2023 12 10 19 45 0.00000000 -PL56 6127.985669 202.016859 3720.365927 -VL56 -37525.627000 -19226.629000 62666.144000 -* 2023 12 10 19 48 0.00000000 -PL56 5345.596533 -135.780995 4776.706420 -VL56 -49148.655000 -18146.578000 54362.248000 -* 2023 12 10 19 51 0.00000000 -PL56 4369.160344 -445.780397 5666.019488 -VL56 -59019.854000 -16154.677000 44162.383000 -* 2023 12 10 19 54 0.00000000 -PL56 3233.590837 -712.595237 6357.326402 -VL56 -66775.642000 -13371.586000 32426.323000 -* 2023 12 10 19 57 0.00000000 -PL56 1979.655817 -923.343508 6826.612883 -VL56 -72131.190000 -9953.712300 19565.682000 -* 2023 12 10 20 0 0.00000000 -PL56 652.468219 -1068.222473 7057.634357 -VL56 -74889.858000 -6085.398900 6029.562500 -* 2023 12 10 20 3 0.00000000 -PL56 -700.168385 -1140.933907 7042.447388 -VL56 -74949.981000 -1970.125500 -7711.359200 -* 2023 12 10 20 6 0.00000000 -PL56 -2029.496075 -1138.943576 6781.656127 -VL56 -72307.493000 2178.992900 -21180.702000 -* 2023 12 10 20 9 0.00000000 -PL56 -3287.561990 -1063.566771 6284.379215 -VL56 -67055.605000 6148.972300 -33911.325000 -* 2023 12 10 20 12 0.00000000 -PL56 -4428.952534 -919.877831 5567.944557 -VL56 -59382.555000 9736.683100 -45460.683000 -* 2023 12 10 20 15 0.00000000 -PL56 -5412.454674 -716.450065 4657.310274 -VL56 -49565.651000 12757.996000 -55426.045000 -* 2023 12 10 20 18 0.00000000 -PL56 -6202.579783 -464.933562 3584.215488 -VL56 -37961.702000 15056.543000 -63459.009000 -* 2023 12 10 20 21 0.00000000 -PL56 -6770.886381 -179.486414 2386.085790 -VL56 -24994.579000 16511.166000 -69278.067000 -* 2023 12 10 20 24 0.00000000 -PL56 -7097.050874 123.916892 1104.727605 -VL56 -11139.594000 17042.046000 -72679.635000 -* 2023 12 10 20 27 0.00000000 -PL56 -7169.634180 428.268061 -215.152602 -VL56 3094.636800 16614.638000 -73546.173000 -* 2023 12 10 20 30 0.00000000 -PL56 -6986.499064 716.360554 -1527.545167 -VL56 17186.641000 15241.568000 -71850.832000 -* 2023 12 10 20 33 0.00000000 -PL56 -6554.857201 971.637072 -2786.778890 -VL56 30622.542000 12982.059000 -67657.816000 -* 2023 12 10 20 36 0.00000000 -PL56 -5890.952570 1179.006692 -3949.138850 -VL56 42915.895000 9939.186900 -61119.536000 -* 2023 12 10 20 39 0.00000000 -PL56 -5019.392975 1325.592423 -4974.397295 -VL56 53626.698000 6254.856900 -52469.535000 -* 2023 12 10 20 42 0.00000000 -PL56 -3972.171441 1401.371978 -5827.188044 -VL56 62376.717000 2103.101000 -42012.565000 -* 2023 12 10 20 45 0.00000000 -PL56 -2787.436893 1399.684856 -6478.182554 -VL56 68861.935000 -2317.994100 -30112.664000 -* 2023 12 10 20 48 0.00000000 -PL56 -1508.073124 1317.586656 -6905.040888 -VL56 72861.572000 -6795.106300 -17180.074000 -* 2023 12 10 20 51 0.00000000 -PL56 -180.141101 1156.041513 -7093.119376 -VL56 74244.099000 -11108.862000 -3657.291700 -* 2023 12 10 20 54 0.00000000 -PL56 1148.756644 919.946738 -7035.927224 -VL56 72970.055000 -15043.150000 9994.557300 -* 2023 12 10 20 57 0.00000000 -PL56 2431.145740 617.990353 -6735.338747 -VL56 69093.152000 -18394.437000 23309.502000 -* 2023 12 10 21 0 0.00000000 -PL56 3621.346621 262.342599 -6201.549165 -VL56 62758.594000 -20980.794000 35831.319000 -* 2023 12 10 21 3 0.00000000 -PL56 4677.084959 -131.810221 -5452.769561 -VL56 54198.536000 -22650.406000 47127.983000 -* 2023 12 10 21 6 0.00000000 -PL56 5560.999959 -546.877454 -4514.667236 -VL56 43725.410000 -23289.115000 56805.471000 -* 2023 12 10 21 9 0.00000000 -PL56 6242.006437 -963.602927 -3419.551337 -VL56 31722.168000 -22826.951000 64522.066000 -* 2023 12 10 21 12 0.00000000 -PL56 6696.451719 -1361.906160 -2205.311147 -VL56 18629.337000 -21242.956000 70001.540000 -* 2023 12 10 21 15 0.00000000 -PL56 6909.013866 -1721.792369 -914.131555 -VL56 4929.163100 -18567.869000 73044.600000 -* 2023 12 10 21 18 0.00000000 -PL56 6873.290323 -2024.288756 408.977279 -VL56 -8872.787200 -14884.325000 73537.827000 -* 2023 12 10 21 21 0.00000000 -PL56 6592.039695 -2252.361543 1717.781154 -VL56 -22267.627000 -10324.511000 71459.293000 -* 2023 12 10 21 24 0.00000000 -PL56 6077.055000 -2391.766288 2966.488975 -VL56 -34763.867000 -5065.128600 66880.056000 -* 2023 12 10 21 27 0.00000000 -PL56 5348.669262 -2431.785987 4111.410249 -VL56 -45907.294000 680.015070 59961.580000 -* 2023 12 10 21 30 0.00000000 -PL56 4434.918405 -2365.817459 5112.525442 -VL56 -55298.880000 6669.300800 50948.885000 -* 2023 12 10 21 33 0.00000000 -PL56 3370.413043 -2191.779021 5934.904999 -VL56 -62609.407000 12643.762000 40160.700000 -* 2023 12 10 21 36 0.00000000 -PL56 2194.971284 -1912.322574 6549.927961 -VL56 -67591.061000 18338.328000 27976.915000 -* 2023 12 10 21 39 0.00000000 -PL56 952.079750 -1534.841133 6936.254723 -VL56 -70084.996000 23493.143000 14824.234000 -* 2023 12 10 21 42 0.00000000 -PL56 -312.749147 -1071.275011 7080.535089 -VL56 -70025.383000 27864.615000 1161.088100 -* 2023 12 10 21 45 0.00000000 -PL56 -1553.661095 -537.723680 6977.837402 -VL56 -67439.877000 31235.846000 -12538.163000 -* 2023 12 10 21 48 0.00000000 -PL56 -2726.125834 46.121594 6631.797833 -VL56 -62447.327000 33426.192000 -25798.495000 -* 2023 12 10 21 51 0.00000000 -PL56 -3788.537033 657.706970 6054.492602 -VL56 -55252.724000 34299.521000 -38159.694000 -* 2023 12 10 21 54 0.00000000 -PL56 -4703.700574 1272.483591 5266.033875 -VL56 -46139.826000 33771.280000 -49191.632000 -* 2023 12 10 21 57 0.00000000 -PL56 -5440.162827 1864.884898 4293.892441 -VL56 -35460.768000 31813.676000 -58509.197000 -* 2023 12 10 22 0 0.00000000 -PL56 -5973.327891 2409.379785 3171.959274 -VL56 -23622.976000 28458.739000 -65786.375000 -* 2023 12 10 22 3 0.00000000 -PL56 -6286.316570 2881.557801 1939.371972 -VL56 -11073.732000 23798.825000 -70768.101000 -* 2023 12 10 22 6 0.00000000 -PL56 -6370.532720 3259.199826 639.141934 -VL56 1716.944600 17984.448000 -73280.444000 -* 2023 12 10 22 9 0.00000000 -PL56 -6225.904973 3523.283384 -683.374615 -VL56 14275.033000 11219.179000 -73237.601000 -* 2023 12 10 22 12 0.00000000 -PL56 -5860.787709 3658.870310 -1982.096597 -VL56 26141.415000 3751.793900 -70645.128000 -* 2023 12 10 22 15 0.00000000 -PL56 -5291.528919 3655.834085 -3211.862495 -VL56 36890.118000 -4133.751100 -65599.291000 -* 2023 12 10 22 18 0.00000000 -PL56 -4541.723564 3509.389871 -4330.027265 -VL56 46144.310000 -12129.905000 -58282.190000 -* 2023 12 10 22 21 0.00000000 -PL56 -3641.198365 3220.403956 -5297.940643 -VL56 53590.242000 -19918.417000 -48953.941000 -* 2023 12 10 22 24 0.00000000 -PL56 -2624.787589 2795.474832 -6082.252997 -VL56 58986.680000 -27182.743000 -37941.536000 -* 2023 12 10 22 27 0.00000000 -PL56 -1530.962673 2246.790025 -6656.014209 -VL56 62171.656000 -33620.441000 -25626.887000 -* 2023 12 10 22 30 0.00000000 -PL56 -400.369435 1591.766572 -6999.541744 -VL56 63065.788000 -38954.727000 -12433.252000 -* 2023 12 10 22 33 0.00000000 -PL56 725.667384 852.492541 -7101.040046 -VL56 61672.837000 -42945.027000 1188.561300 -* 2023 12 10 22 36 0.00000000 -PL56 1806.624887 54.990709 -6956.972927 -VL56 58077.764000 -45396.248000 14773.951000 -* 2023 12 10 22 39 0.00000000 -PL56 2804.212594 -771.678599 -6572.183085 -VL56 52442.700000 -46167.217000 27858.987000 -* 2023 12 10 22 42 0.00000000 -PL56 3683.708795 -1596.451164 -5959.753282 -VL56 45000.824000 -45177.431000 39994.421000 -* 2023 12 10 22 45 0.00000000 -PL56 4415.167299 -2387.400031 -5140.612698 -VL56 36048.171000 -42412.321000 50759.945000 -* 2023 12 10 22 48 0.00000000 -PL56 4974.461178 -3112.956579 -4142.887781 -VL56 25933.313000 -37926.602000 59778.635000 -* 2023 12 10 22 51 0.00000000 -PL56 5344.121024 -3743.168453 -3000.996984 -VL56 15045.143000 -31844.991000 66730.504000 -* 2023 12 10 22 54 0.00000000 -PL56 5513.933163 -4250.942192 -1754.507760 -VL56 3798.480400 -24359.822000 71365.414000 -* 2023 12 10 22 57 0.00000000 -PL56 5481.264968 -4613.216446 -446.781107 -VL56 -7381.935600 -15725.583000 73513.559000 -* 2023 12 10 23 0 0.00000000 -PL56 5251.091871 -4812.008289 876.551977 -VL56 -18078.394000 -6250.344500 73093.524000 -* 2023 12 10 23 3 0.00000000 -PL56 4835.715123 -4835.275233 2169.224720 -VL56 -27897.436000 3716.133500 70116.483000 -* 2023 12 10 23 6 0.00000000 -PL56 4254.178523 -4677.541043 3386.006840 -VL56 -36485.857000 13796.533000 64686.039000 -* 2023 12 10 23 9 0.00000000 -PL56 3531.415627 -4340.254008 4484.337255 -VL56 -43544.558000 23601.388000 56994.166000 -* 2023 12 10 23 12 0.00000000 -PL56 2697.169962 -3831.861132 5425.848867 -VL56 -48839.764000 32745.212000 47313.296000 -* 2023 12 10 23 15 0.00000000 -PL56 1784.745082 -3167.594533 6177.721782 -VL56 -52210.700000 40862.134000 35985.328000 -* 2023 12 10 23 18 0.00000000 -PL56 829.646529 -2368.985252 6713.817637 -VL56 -53573.914000 47620.447000 23408.319000 -* 2023 12 10 23 21 0.00000000 -PL56 -131.822853 -1463.130192 7015.559333 -VL56 -52924.145000 52735.406000 10021.864000 -* 2023 12 10 23 24 0.00000000 -PL56 -1063.953997 -481.745488 7072.540436 -VL56 -50332.024000 55980.197000 -3708.308100 -* 2023 12 10 23 27 0.00000000 -PL56 -1932.959952 539.961293 6882.858151 -VL56 -45939.508000 57194.982000 -17305.718000 -* 2023 12 10 23 30 0.00000000 -PL56 -2708.201249 1564.562389 6453.165114 -VL56 -39953.060000 56293.867000 -30298.808000 -* 2023 12 10 23 33 0.00000000 -PL56 -3363.270035 2553.783776 5798.441081 -VL56 -32634.799000 53269.327000 -42236.444000 -* 2023 12 10 23 36 0.00000000 -PL56 -3876.900461 3469.939712 4941.490823 -VL56 -24292.064000 48194.377000 -52702.833000 -* 2023 12 10 23 39 0.00000000 -PL56 -4233.676842 4277.380855 3912.173847 -VL56 -15265.402000 41221.890000 -61332.221000 -* 2023 12 10 23 42 0.00000000 -PL56 -4424.511650 4943.901512 2746.381762 -VL56 -5915.052800 32580.705000 -67822.274000 -* 2023 12 10 23 45 0.00000000 -PL56 -4446.870509 5442.047736 1484.788411 -VL56 3393.599600 22568.413000 -71945.698000 -* 2023 12 10 23 48 0.00000000 -PL56 -4304.731773 5750.262261 171.414406 -VL56 12304.714000 11540.625000 -73559.124000 -* 2023 12 10 23 51 0.00000000 -PL56 -4008.285520 5853.813348 -1147.938704 -VL56 20486.277000 -102.335710 -72608.737000 -* 2023 12 10 23 54 0.00000000 -PL56 -3573.380762 5745.459906 -2427.328491 -VL56 27643.612000 -11931.294000 -69132.706000 -* 2023 12 10 23 57 0.00000000 -PL56 -3020.745443 5425.813159 -3622.308538 -VL56 33531.058000 -23505.922000 -63258.348000 -* 2023 12 11 0 0 0.00000000 -PL56 -2375.026133 4903.384930 -4691.487567 -VL56 37960.028000 -34391.612000 -55196.405000 -* 2023 12 11 0 3 0.00000000 -PL56 -1663.701444 4194.327079 -5597.949875 -VL56 40805.020000 -44176.588000 -45231.718000 -* 2023 12 11 0 6 0.00000000 -PL56 -915.923514 3321.888728 -6310.490870 -VL56 42005.843000 -52486.472000 -33712.176000 -* 2023 12 11 0 9 0.00000000 -PL56 -161.337338 2315.616673 -6804.640858 -VL56 41567.707000 -58997.990000 -21035.922000 -* 2023 12 11 0 12 0.00000000 -PL56 571.075618 1210.332563 -7063.447314 -VL56 39558.469000 -63449.981000 -7637.687300 -* 2023 12 11 0 15 0.00000000 -PL56 1254.085607 44.930669 -7078.008636 -VL56 36103.992000 -65652.405000 6025.058300 -* 2023 12 11 0 18 0.00000000 -PL56 1863.204859 -1138.969873 -6847.755894 -VL56 31381.885000 -65493.558000 19486.265000 -* 2023 12 11 0 21 0.00000000 -PL56 2377.549197 -2298.480138 -6380.477531 -VL56 25613.576000 -62944.700000 32285.720000 -* 2023 12 11 0 24 0.00000000 -PL56 2780.549679 -3390.963113 -5692.091909 -VL56 19055.514000 -58062.831000 43982.663000 -* 2023 12 11 0 27 0.00000000 -PL56 3060.496731 -4375.589463 -4806.166283 -VL56 11989.431000 -50991.671000 54170.465000 -* 2023 12 11 0 30 0.00000000 -PL56 3210.894386 -5214.874713 -3753.171250 -VL56 4710.971200 -41958.401000 62490.971000 -* 2023 12 11 0 33 0.00000000 -PL56 3230.608534 -5876.136524 -2569.490736 -VL56 -2481.714200 -31268.224000 68647.423000 -* 2023 12 11 0 36 0.00000000 -PL56 3123.802239 -6332.820508 -1296.202224 -VL56 -9300.212700 -19294.928000 72416.968000 -* 2023 12 11 0 39 0.00000000 -PL56 2899.653058 -6565.623725 22.344901 -VL56 -15477.800000 -6467.947500 73660.340000 -* 2023 12 11 0 42 0.00000000 -PL56 2571.857089 -6563.352218 1340.101991 -VL56 -20780.891000 6744.064400 72328.745000 -* 2023 12 11 0 45 0.00000000 -PL56 2157.942016 -6323.462547 2610.976977 -VL56 -25018.819000 19851.854000 68466.342000 -* 2023 12 11 0 48 0.00000000 -PL56 1678.421482 -5852.253023 3790.503770 -VL56 -28051.553000 32365.634000 62208.998000 -* 2023 12 11 0 51 0.00000000 -PL56 1155.834276 -5164.694043 4837.442976 -VL56 -29794.743000 43814.858000 53778.061000 -* 2023 12 11 0 54 0.00000000 -PL56 613.719710 -4283.914619 5715.249893 -VL56 -30221.678000 53766.490000 43472.059000 -* 2023 12 11 0 57 0.00000000 -PL56 75.578425 -3240.369150 6393.356613 -VL56 -29362.987000 61842.247000 31654.413000 -* 2023 12 11 1 0 0.00000000 -PL56 -436.131210 -2070.723862 6848.217140 -VL56 -27303.143000 67732.251000 18739.428000 -* 2023 12 11 1 3 0.00000000 -PL56 -900.916848 -816.524992 7064.090364 -VL56 -24175.049000 71205.683000 5177.551400 -* 2023 12 11 1 6 0.00000000 -PL56 -1301.062571 477.302491 7033.555323 -VL56 -20153.008000 72119.137000 -8559.777700 -* 2023 12 11 1 9 0.00000000 -PL56 -1622.299497 1764.079174 6757.746311 -VL56 -15444.191000 70421.684000 -21996.093000 -* 2023 12 11 1 12 0.00000000 -PL56 -1854.313797 2997.061870 6246.304492 -VL56 -10279.235000 66157.251000 -34665.232000 -* 2023 12 11 1 15 0.00000000 -PL56 -1991.077633 4131.148260 5517.050816 -VL56 -4902.004800 59463.884000 -46126.986000 -* 2023 12 11 1 18 0.00000000 -PL56 -2030.993624 5124.542490 4595.387168 -VL56 440.862700 50570.094000 -55981.669000 -* 2023 12 11 1 21 0.00000000 -PL56 -1976.849127 5940.326452 3513.434931 -VL56 5510.579300 39787.867000 -63884.637000 -* 2023 12 11 1 24 0.00000000 -PL56 -1835.581196 6547.872505 2308.927601 -VL56 10086.491000 27502.090000 -69558.993000 -* 2023 12 11 1 27 0.00000000 -PL56 -1617.862460 6924.035517 1023.890636 -VL56 13975.764000 14156.692000 -72806.321000 -* 2023 12 11 1 30 0.00000000 -PL56 -1337.522079 7054.068575 -296.846502 -VL56 17021.756000 237.905610 -73514.472000 -* 2023 12 11 1 33 0.00000000 -PL56 -1010.830844 6932.216581 -1607.248860 -VL56 19110.752000 -13744.717000 -71662.147000 -* 2023 12 11 1 36 0.00000000 -PL56 -655.684788 6561.951849 -2861.724722 -VL56 20176.434000 -27279.026000 -67319.549000 -* 2023 12 11 1 39 0.00000000 -PL56 -290.732018 5955.835099 -4016.740005 -VL56 20201.638000 -39870.532000 -60644.163000 -* 2023 12 11 1 42 0.00000000 -PL56 65.511734 5135.031452 -5032.330819 -VL56 19217.974000 -51060.625000 -51873.816000 -* 2023 12 11 1 45 0.00000000 -PL56 395.519588 4128.510195 -5873.466475 -VL56 17303.111000 -60443.320000 -41316.970000 -* 2023 12 11 1 48 0.00000000 -PL56 683.544053 2971.967990 -6511.217245 -VL56 14576.133000 -67679.243000 -29340.920000 -* 2023 12 11 1 51 0.00000000 -PL56 916.306693 1706.525705 -6923.693932 -VL56 11191.128000 -72506.633000 -16358.367000 -* 2023 12 11 1 54 0.00000000 -PL56 1083.561849 377.257688 -7096.741822 -VL56 7329.641100 -74749.049000 -2813.702500 -* 2023 12 11 1 57 0.00000000 -PL56 1178.516893 -968.397279 -7024.385812 -VL56 3192.344600 -74320.875000 10831.003000 -* 2023 12 11 2 0 0.00000000 -PL56 1198.095963 -2282.297533 -6709.019641 -VL56 -1009.962400 -71229.845000 24110.310000 -* 2023 12 11 2 3 0.00000000 -PL56 1143.041372 -3517.282869 -6161.341841 -VL56 -5065.355700 -65577.156000 36569.178000 -* 2023 12 11 2 6 0.00000000 -PL56 1017.850047 -4628.846768 -5400.041959 -VL56 -8770.141900 -57555.930000 47777.229000 -* 2023 12 11 2 9 0.00000000 -PL56 830.543589 -5576.747591 -4451.224095 -VL56 -11937.869000 -47445.842000 57343.303000 -* 2023 12 11 2 12 0.00000000 -PL56 592.279061 -6326.500414 -3347.576355 -VL56 -14407.991000 -35605.216000 64929.343000 -* 2023 12 11 2 15 0.00000000 -PL56 316.810634 -6850.694030 -2127.295148 -VL56 -16053.663000 -22459.473000 70263.419000 -* 2023 12 11 2 18 0.00000000 -PL56 19.823376 -7130.070594 -832.788034 -VL56 -16788.139000 -8486.383700 73151.279000 -* 2023 12 11 2 21 0.00000000 -PL56 -281.833880 -7154.308458 490.808301 -VL56 -16569.462000 5802.133200 73485.122000 -* 2023 12 11 2 24 0.00000000 -PL56 -570.980782 -6922.458806 1797.236006 -VL56 -15402.972000 19880.030000 71248.728000 -* 2023 12 11 2 27 0.00000000 -PL56 -830.961353 -6443.010469 3040.784220 -VL56 -13341.401000 33228.338000 66519.010000 -* 2023 12 11 2 30 0.00000000 -PL56 -1046.478468 -5733.569555 4177.945693 -VL56 -10482.375000 45356.480000 59463.009000 -* 2023 12 11 2 33 0.00000000 -PL56 -1204.362754 -4820.169184 5168.980107 -VL56 -6963.761100 55821.606000 50330.752000 -* 2023 12 11 2 36 0.00000000 -PL56 -1294.239937 -3736.256254 5979.320195 -VL56 -2957.008800 64245.360000 39445.143000 -* 2023 12 11 2 39 0.00000000 -PL56 -1309.064345 -2521.403737 6580.775100 -VL56 1340.983800 70327.490000 27189.387000 -* 2023 12 11 2 42 0.00000000 -PL56 -1245.494252 -1219.809428 6952.484539 -VL56 5717.128900 73855.612000 13992.384000 -* 2023 12 11 2 45 0.00000000 -PL56 -1104.097601 121.345977 7081.608487 -VL56 9951.712000 74711.546000 313.822460 -* 2023 12 11 2 48 0.00000000 -PL56 -889.383835 1453.628396 6963.742638 -VL56 13828.185000 72874.441000 -13371.291000 -* 2023 12 11 2 51 0.00000000 -PL56 -609.656079 2729.107867 6603.053048 -VL56 17143.200000 68420.872000 -26588.350000 -* 2023 12 11 2 54 0.00000000 -PL56 -276.688899 3902.088912 6012.128934 -VL56 19715.871000 61521.785000 -38878.596000 -* 2023 12 11 2 57 0.00000000 -PL56 94.754667 4930.759341 5211.557546 -VL56 21396.383000 52436.525000 -49814.613000 -* 2023 12 11 3 0 0.00000000 -PL56 487.551203 5778.705425 4229.229764 -VL56 22073.429000 41503.816000 -59014.752000 -* 2023 12 11 3 3 0.00000000 -PL56 882.967204 6416.237707 3099.387878 -VL56 21680.289000 29129.769000 -66156.996000 -* 2023 12 11 3 6 0.00000000 -PL56 1261.502323 6821.479265 1861.445456 -VL56 20199.103000 15773.791000 -70990.971000 -* 2023 12 11 3 9 0.00000000 -PL56 1603.791367 6981.163251 558.595834 -VL56 17662.672000 1929.837300 -73348.148000 -* 2023 12 11 3 12 0.00000000 -PL56 1891.516945 6891.086638 -763.726268 -VL56 14154.357000 -11892.256000 -73148.699000 -* 2023 12 11 3 15 0.00000000 -PL56 2108.289056 6556.206291 -2059.465060 -VL56 9804.330700 -25187.823000 -70403.791000 -* 2023 12 11 3 18 0.00000000 -PL56 2240.448176 5990.377253 -3283.579654 -VL56 4784.700500 -37476.147000 -65214.623000 -* 2023 12 11 3 21 0.00000000 -PL56 2277.754702 5215.747576 -4393.631152 -VL56 -697.995760 -48319.370000 -57767.995000 -* 2023 12 11 3 24 0.00000000 -PL56 2213.931338 4261.839259 -5351.254338 -VL56 -6411.661500 -57338.443000 -48328.069000 -* 2023 12 11 3 27 0.00000000 -PL56 2047.034439 3164.369775 -6123.455203 -VL56 -12108.559000 -64225.835000 -37225.535000 -* 2023 12 11 3 30 0.00000000 -PL56 1779.643089 1963.876726 -6683.699165 -VL56 -17535.642000 -68754.812000 -24845.241000 -* 2023 12 11 3 33 0.00000000 -PL56 1418.861277 704.204418 -7012.764153 -VL56 -22444.866000 -70785.381000 -11612.561000 -* 2023 12 11 3 36 0.00000000 -PL56 976.137482 -569.087740 -7099.347275 -VL56 -26603.260000 -70267.286000 2020.321100 -* 2023 12 11 3 39 0.00000000 -PL56 466.904732 -1810.346667 -6940.419954 -VL56 -29802.599000 -67240.156000 15588.629000 -* 2023 12 11 3 42 0.00000000 -PL56 -89.945930 -2975.427130 -6541.327322 -VL56 -31868.276000 -61831.346000 28628.966000 -* 2023 12 11 3 45 0.00000000 -PL56 -672.745078 -4023.234748 -5915.638813 -VL56 -32667.501000 -54251.626000 40693.365000 -* 2023 12 11 3 48 0.00000000 -PL56 -1257.861875 -4917.172173 -5084.739470 -VL56 -32116.170000 -44788.533000 51363.720000 -* 2023 12 11 3 51 0.00000000 -PL56 -1820.633688 -5626.441071 -4077.165195 -VL56 -30184.527000 -33797.130000 60265.975000 -* 2023 12 11 3 54 0.00000000 -PL56 -2336.380692 -6127.154739 -2927.684008 -VL56 -26900.835000 -21688.060000 67083.964000 -* 2023 12 11 3 57 0.00000000 -PL56 -2781.464670 -6403.209656 -1676.138853 -VL56 -22352.564000 -8912.866200 71571.917000 -* 2023 12 11 4 0 0.00000000 -PL56 -3134.345972 -6446.873589 -366.081210 -VL56 -16684.921000 4052.862500 73565.131000 -* 2023 12 11 4 3 0.00000000 -PL56 -3376.587134 -6259.050858 956.763670 -VL56 -10096.374000 16728.354000 72987.746000 -* 2023 12 11 4 6 0.00000000 -PL56 -3493.748732 -5849.199524 2246.136992 -VL56 -2831.245400 28647.190000 69856.658000 -* 2023 12 11 4 9 0.00000000 -PL56 -3476.129446 -5234.900100 3456.919534 -VL56 4830.155300 39376.353000 64281.181000 -* 2023 12 11 4 12 0.00000000 -PL56 -3319.310610 -4441.096702 4546.761001 -VL56 12583.248000 48533.357000 56458.601000 -* 2023 12 11 4 15 0.00000000 -PL56 -3024.479262 -3499.052114 5477.595480 -VL56 20111.944000 55800.784000 46666.023000 -* 2023 12 11 4 18 0.00000000 -PL56 -2598.516045 -2445.070081 6216.981507 -VL56 27101.923000 60937.446000 35249.199000 -* 2023 12 11 4 21 0.00000000 -PL56 -2053.845226 -1319.052594 6739.220006 -VL56 33253.643000 63785.662000 22609.259000 -* 2023 12 11 4 24 0.00000000 -PL56 -1408.056853 -162.955464 7026.222398 -VL56 38294.650000 64275.321000 9188.053200 -* 2023 12 11 4 27 0.00000000 -PL56 -683.318253 980.797496 7068.101470 -VL56 41990.501000 62424.273000 -4547.535300 -* 2023 12 11 4 30 0.00000000 -PL56 94.398502 2070.877419 6863.484780 -VL56 44154.443000 58335.761000 -18120.930000 -* 2023 12 11 4 33 0.00000000 -PL56 896.254339 3068.547950 6419.549733 -VL56 44655.910000 52193.503000 -31061.380000 -* 2023 12 11 4 36 0.00000000 -PL56 1691.614789 3939.047046 5751.776555 -VL56 43426.882000 44253.932000 -42919.532000 -* 2023 12 11 4 39 0.00000000 -PL56 2449.219510 4652.812325 4883.427935 -VL56 40466.413000 34836.534000 -53282.515000 -* 2023 12 11 4 42 0.00000000 -PL56 3138.412923 5186.510185 3844.761597 -VL56 35842.751000 24311.659000 -61788.346000 -* 2023 12 11 4 45 0.00000000 -PL56 3730.387721 5523.827243 2671.994079 -VL56 29692.747000 13086.621000 -68138.917000 -* 2023 12 11 4 48 0.00000000 -PL56 4199.393826 5655.997515 1406.040631 -VL56 22218.287000 1589.785500 -72112.136000 -* 2023 12 11 4 51 0.00000000 -PL56 4523.850069 5582.027627 91.066679 -VL56 13679.358000 -9746.314500 -73570.099000 -* 2023 12 11 4 54 0.00000000 -PL56 4687.304713 5308.612261 -1227.086497 -VL56 4384.037400 -20502.978000 -72465.006000 -* 2023 12 11 4 57 0.00000000 -PL56 4679.199054 4849.739118 -2502.537142 -VL56 -5323.202100 -30291.293000 -68840.144000 -* 2023 12 11 5 0 0.00000000 -PL56 4495.397440 4226.010647 -3690.989508 -VL56 -15075.520000 -38767.394000 -62827.717000 -* 2023 12 11 5 3 0.00000000 -PL56 4138.457911 3463.717772 -4751.286232 -VL56 -24498.501000 -45644.956000 -54642.926000 -* 2023 12 11 5 6 0.00000000 -PL56 3617.636290 2593.714898 -5646.822078 -VL56 -33224.756000 -50704.557000 -44574.686000 -* 2023 12 11 5 9 0.00000000 -PL56 2948.631300 1650.154330 -6346.772768 -VL56 -40908.083000 -53799.953000 -32974.328000 -* 2023 12 11 5 12 0.00000000 -PL56 2153.085312 669.138396 -6827.102778 -VL56 -47236.291000 -54860.935000 -20242.556000 -* 2023 12 11 5 15 0.00000000 -PL56 1257.867604 -312.652937 -7071.330543 -VL56 -51942.530000 -53893.298000 -6815.743900 -* 2023 12 11 5 18 0.00000000 -PL56 294.168863 -1259.311211 -7071.048070 -VL56 -54815.098000 -50976.422000 6847.817100 -* 2023 12 11 5 21 0.00000000 -PL56 -703.570106 -2136.985962 -6826.186136 -VL56 -55705.728000 -46258.608000 20282.187000 -* 2023 12 11 5 24 0.00000000 -PL56 -1698.861339 -2915.070458 -6345.026783 -VL56 -54536.196000 -39950.820000 33027.751000 -* 2023 12 11 5 27 0.00000000 -PL56 -2654.476085 -3567.260283 -5643.960804 -VL56 -51303.055000 -32318.656000 44645.528000 -* 2023 12 11 5 30 0.00000000 -PL56 -3533.817634 -4072.452388 -4746.989915 -VL56 -46080.279000 -23672.726000 54731.234000 -* 2023 12 11 5 33 0.00000000 -PL56 -4302.323876 -4415.458128 -3684.972363 -VL56 -39019.675000 -14357.497000 62929.670000 -* 2023 12 11 5 36 0.00000000 -PL56 -4928.844184 -4587.496579 -2494.616456 -VL56 -30347.761000 -4738.234900 68948.154000 -* 2023 12 11 5 39 0.00000000 -PL56 -5386.932779 -4586.443359 -1217.244335 -VL56 -20359.417000 4813.165100 72568.540000 -* 2023 12 11 5 42 0.00000000 -PL56 -5655.995825 -4416.816076 102.640147 -VL56 -9408.050700 13933.102000 73656.812000 -* 2023 12 11 5 45 0.00000000 -PL56 -5722.231977 -4089.490935 1418.928944 -VL56 2107.444100 22281.102000 72169.544000 -* 2023 12 11 5 48 0.00000000 -PL56 -5579.311340 -3621.156826 2685.571602 -VL56 13758.640000 29554.041000 68156.611000 -* 2023 12 11 5 51 0.00000000 -PL56 -5228.750917 -3033.528867 3858.243089 -VL56 25105.062000 35498.394000 61759.202000 -* 2023 12 11 5 54 0.00000000 -PL56 -4679.969310 -2352.365210 4895.941680 -VL56 35712.253000 39919.852000 53204.111000 -* 2023 12 11 5 57 0.00000000 -PL56 -3950.018504 -1606.336843 5762.448718 -VL56 45169.303000 42689.838000 42794.119000 -* 2023 12 11 6 0 0.00000000 -PL56 -3063.014857 -825.812059 6427.592070 -VL56 53104.715000 43748.631000 30896.208000 -* 2023 12 11 6 3 0.00000000 -PL56 -2049.297531 -41.609693 6868.281090 -VL56 59200.844000 43105.724000 17927.705000 -* 2023 12 11 6 6 0.00000000 -PL56 -944.346998 716.225816 7069.276291 -VL56 63205.748000 40836.887000 4341.053700 -* 2023 12 11 6 9 0.00000000 -PL56 212.483647 1419.574337 7023.681785 -VL56 64942.426000 37079.200000 -9391.641600 -* 2023 12 11 6 12 0.00000000 -PL56 1379.381901 2043.282712 6733.160863 -VL56 64315.601000 32023.971000 -22794.094000 -* 2023 12 11 6 15 0.00000000 -PL56 2513.592101 2566.065878 6207.869524 -VL56 61316.222000 25908.044000 -35401.543000 -* 2023 12 11 6 18 0.00000000 -PL56 3572.986224 2971.236921 5466.113116 -VL56 56023.175000 19003.723000 -46775.773000 -* 2023 12 11 6 21 0.00000000 -PL56 4517.641813 3247.246861 4533.731159 -VL56 48602.128000 11607.638000 -56520.312000 -* 2023 12 11 6 24 0.00000000 -PL56 5311.367792 3388.015067 3443.220122 -VL56 39301.062000 4028.677900 -64294.171000 -* 2023 12 11 6 27 0.00000000 -PL56 5923.126442 3393.037680 2232.614408 -VL56 28442.932000 -3424.542600 -69825.008000 -* 2023 12 11 6 30 0.00000000 -PL56 6328.279413 3267.263984 944.151936 -VL56 16413.825000 -10456.721000 -72919.759000 -* 2023 12 11 6 33 0.00000000 -PL56 6509.601048 3020.749107 -377.223286 -VL56 3648.519500 -16797.936000 -73471.846000 -* 2023 12 11 6 36 0.00000000 -PL56 6458.005975 2668.094137 -1685.466858 -VL56 -9386.375500 -22214.736000 -71465.739000 -* 2023 12 11 6 39 0.00000000 -PL56 6172.954067 2227.703746 -2935.073322 -VL56 -22211.016000 -26519.163000 -66976.585000 -* 2023 12 11 6 42 0.00000000 -PL56 5662.521075 1720.903700 -4082.683977 -VL56 -34351.098000 -29575.579000 -60166.869000 -* 2023 12 11 6 45 0.00000000 -PL56 4943.131951 1170.956963 -5088.598759 -VL56 -45356.247000 -31304.877000 -51279.197000 -* 2023 12 11 6 48 0.00000000 -PL56 4038.974152 602.030685 -5918.129175 -VL56 -54816.870000 -31685.634000 -40625.888000 -* 2023 12 11 6 51 0.00000000 -PL56 2981.132143 38.166445 -6542.749010 -VL56 -62378.440000 -30752.784000 -28577.206000 -* 2023 12 11 6 54 0.00000000 -PL56 1806.483907 -497.704297 -6941.018932 -VL56 -67753.544000 -28593.994000 -15548.036000 -* 2023 12 11 6 57 0.00000000 -PL56 556.406267 -984.663748 -7099.266411 -VL56 -70731.107000 -25344.317000 -1984.200600 -* 2023 12 11 7 0 0.00000000 -PL56 -724.668601 -1404.600399 -7012.016314 -VL56 -71183.677000 -21179.223000 11651.720000 -* 2023 12 11 7 3 0.00000000 -PL56 -1990.802653 -1742.865897 -6682.166736 -VL56 -69072.038000 -16306.646000 24894.292000 -* 2023 12 11 7 6 0.00000000 -PL56 -3196.165785 -1988.780804 -6120.910751 -VL56 -64447.489000 -10958.073000 37289.636000 -* 2023 12 11 7 9 0.00000000 -PL56 -4296.669468 -2135.973902 -5347.402432 -VL56 -57452.094000 -5379.143100 48409.348000 -* 2023 12 11 7 12 0.00000000 -PL56 -5251.580017 -2182.547235 -4388.169678 -VL56 -48315.906000 180.470350 57864.981000 -* 2023 12 11 7 15 0.00000000 -PL56 -6025.056778 -2131.057163 -3276.269009 -VL56 -37351.248000 5477.282300 65321.877000 -* 2023 12 11 7 18 0.00000000 -PL56 -6587.552541 -1988.308298 -2050.195554 -VL56 -24943.187000 10284.448000 70512.460000 -* 2023 12 11 7 21 0.00000000 -PL56 -6917.010805 -1764.963786 -752.571915 -VL56 -11536.477000 14401.673000 73247.382000 -* 2023 12 11 7 24 0.00000000 -PL56 -6999.796847 -1474.985475 571.342948 -VL56 2380.871600 17664.106000 73424.211000 -* 2023 12 11 7 27 0.00000000 -PL56 -6831.307894 -1134.926605 1875.269600 -VL56 16296.685000 19949.711000 71032.506000 -* 2023 12 11 7 30 0.00000000 -PL56 -6416.222192 -763.111714 3113.579572 -VL56 29695.406000 21184.373000 66154.873000 -* 2023 12 11 7 33 0.00000000 -PL56 -5768.371339 -378.745743 4242.946871 -VL56 42079.041000 21344.644000 58963.674000 -* 2023 12 11 7 36 0.00000000 -PL56 -4910.240620 -0.997147 5223.906084 -VL56 52987.223000 20457.784000 49713.915000 -* 2023 12 11 7 39 0.00000000 -PL56 -3872.128619 351.896356 6022.246866 -VL56 62014.836000 18599.361000 38732.591000 -* 2023 12 11 7 42 0.00000000 -PL56 -2691.016295 663.458110 6610.199943 -VL56 68826.807000 15888.545000 26406.154000 -* 2023 12 11 7 45 0.00000000 -PL56 -1409.193738 919.700139 6967.379701 -VL56 73170.020000 12481.454000 13166.019000 -* 2023 12 11 7 48 0.00000000 -PL56 -72.704862 1109.720560 7081.458101 -VL56 74881.539000 8563.435400 -526.623770 -* 2023 12 11 7 51 0.00000000 -PL56 1270.327270 1226.149475 6948.558112 -VL56 73893.864000 4340.074700 -14196.467000 -* 2023 12 11 7 54 0.00000000 -PL56 2571.439421 1265.429089 6573.368864 -VL56 70236.894000 27.733325 -27369.592000 -* 2023 12 11 7 57 0.00000000 -PL56 3783.580831 1227.919743 5968.982431 -VL56 64037.280000 -4156.252600 -39588.826000 -* 2023 12 11 8 0 0.00000000 -PL56 4862.826754 1117.828644 5156.453326 -VL56 55514.747000 -8003.400000 -50429.160000 -* 2023 12 11 8 3 0.00000000 -PL56 5769.993205 942.964693 4164.089251 -VL56 44975.022000 -11323.538000 -59512.021000 -* 2023 12 11 8 6 0.00000000 -PL56 6472.101100 714.328979 3026.486707 -VL56 32799.717000 -13953.532000 -66519.508000 -* 2023 12 11 8 9 0.00000000 -PL56 6943.621917 445.557022 1783.328167 -VL56 19432.466000 -15764.969000 -71206.161000 -* 2023 12 11 8 12 0.00000000 -PL56 7167.448544 152.235580 477.986498 -VL56 5362.440600 -16670.312000 -73408.762000 -* 2023 12 11 8 15 0.00000000 -PL56 7135.545179 -148.872678 -844.016926 -VL56 -8894.867900 -16626.967000 -73052.665000 -* 2023 12 11 8 18 0.00000000 -PL56 6849.240068 -440.660017 -2136.638557 -VL56 -22818.092000 -15639.300000 -70154.545000 -* 2023 12 11 8 21 0.00000000 -PL56 6319.145643 -706.518005 -3354.951518 -VL56 -35900.403000 -13758.172000 -64821.205000 -* 2023 12 11 8 24 0.00000000 -PL56 5564.716389 -931.153397 -4456.726239 -VL56 -47669.243000 -11078.202000 -57244.483000 -* 2023 12 11 8 27 0.00000000 -PL56 4613.472612 -1101.334422 -5403.890084 -VL56 -57703.645000 -7732.840800 -47692.799000 -* 2023 12 11 8 30 0.00000000 -PL56 3499.936710 -1206.533552 -6163.812799 -VL56 -65648.719000 -3887.945400 -36500.483000 -* 2023 12 11 8 33 0.00000000 -PL56 2264.335401 -1239.443342 -6710.381661 -VL56 -71227.192000 265.949500 -24055.170000 -* 2023 12 11 8 36 0.00000000 -PL56 951.125781 -1196.342872 -7024.840508 -VL56 -74247.393000 4522.349400 -10784.314000 -* 2023 12 11 8 39 0.00000000 -PL56 -392.598029 -1077.305038 -7096.382187 -VL56 -74608.620000 8667.759600 2858.628600 -* 2023 12 11 8 42 0.00000000 -PL56 -1718.767682 -886.239402 -6922.489077 -VL56 -72303.531000 12490.911000 16408.387000 -* 2023 12 11 8 45 0.00000000 -PL56 -2980.026165 -630.768322 -6509.019371 -VL56 -67418.317000 15792.062000 29402.042000 -* 2023 12 11 8 48 0.00000000 -PL56 -4131.389035 -321.938808 -5870.036257 -VL56 -60129.751000 18391.892000 41393.148000 -* 2023 12 11 8 51 0.00000000 -PL56 -5131.839103 26.221425 -5027.385464 -VL56 -50700.806000 20139.875000 51965.822000 -* 2023 12 11 8 54 0.00000000 -PL56 -5945.809610 397.292080 -4010.015023 -VL56 -39472.663000 20921.857000 60749.085000 -* 2023 12 11 8 57 0.00000000 -PL56 -6544.501751 773.175016 -2853.043866 -VL56 -26854.023000 20666.514000 67430.508000 -* 2023 12 11 9 0 0.00000000 -PL56 -6906.978673 1134.910914 -1596.590579 -VL56 -13307.172000 19350.142000 71768.975000 -* 2023 12 11 9 3 0.00000000 -PL56 -7020.978468 1463.562326 -284.393092 -VL56 669.369230 16999.106000 73605.055000 -* 2023 12 11 9 6 0.00000000 -PL56 -6883.396675 1741.120602 1037.737557 -VL56 14560.136000 13689.989000 72868.644000 -* 2023 12 11 9 9 0.00000000 -PL56 -6500.401739 1951.390864 2323.560937 -VL56 27853.672000 9547.141600 69582.450000 -* 2023 12 11 9 12 0.00000000 -PL56 -5887.178513 2080.811412 3528.078991 -VL56 40063.039000 4737.756800 63861.403000 -* 2023 12 11 9 15 0.00000000 -PL56 -5067.305335 2119.161527 4609.162967 -VL56 50745.649000 -535.510760 55908.221000 -* 2023 12 11 9 18 0.00000000 -PL56 -4071.798881 2060.121294 5529.058912 -VL56 59520.178000 -6043.503500 46004.602000 -* 2023 12 11 9 21 0.00000000 -PL56 -2937.884219 1901.659720 6255.713071 -VL56 66080.077000 -11540.583000 34500.147000 -* 2023 12 11 9 24 0.00000000 -PL56 -1707.548323 1646.235708 6763.877802 -VL56 70204.287000 -16775.326000 21799.139000 -* 2023 12 11 9 27 0.00000000 -PL56 -425.938103 1300.802201 7035.959986 -VL56 71763.543000 -21501.603000 8345.196800 -* 2023 12 11 9 30 0.00000000 -PL56 860.322417 876.615929 7062.592602 -VL56 70723.149000 -25489.099000 -5393.860400 -* 2023 12 11 9 33 0.00000000 -PL56 2104.836207 388.862116 6842.930556 -VL56 67142.704000 -28533.217000 -18941.543000 -* 2023 12 11 9 36 0.00000000 -PL56 3263.108782 -143.893395 6384.668613 -VL56 61173.295000 -30464.373000 -31828.028000 -* 2023 12 11 9 39 0.00000000 -PL56 4294.145993 -700.408768 5703.781619 -VL56 53051.606000 -31156.088000 -43605.716000 -* 2023 12 11 9 42 0.00000000 -PL56 5161.923018 -1257.605354 4823.987474 -VL56 43091.424000 -30531.735000 -53864.332000 -* 2023 12 11 9 45 0.00000000 -PL56 5836.673354 -1791.512052 3775.944357 -VL56 31672.229000 -28569.399000 -62245.310000 -* 2023 12 11 9 48 0.00000000 -PL56 6295.950882 -2278.278659 2596.198062 -VL56 19225.379000 -25304.727000 -68455.141000 -* 2023 12 11 9 51 0.00000000 -PL56 6525.416368 -2695.216433 1325.906741 -VL56 6217.350700 -20830.921000 -72276.523000 -* 2023 12 11 9 54 0.00000000 -PL56 6519.310718 -3021.816994 9.387270 -VL56 -6868.181700 -15296.352000 -73576.978000 -* 2023 12 11 9 57 0.00000000 -PL56 6280.590526 -3240.700681 -1307.464263 -VL56 -19549.670000 -8899.164200 -72313.990000 -* 2023 12 11 10 0 0.00000000 -PL56 5820.715682 -3338.445705 -2578.812455 -VL56 -31366.977000 -1879.500600 -68536.693000 -* 2023 12 11 10 3 0.00000000 -PL56 5159.100623 -3306.256343 -3760.508595 -VL56 -41899.208000 5490.526600 -62382.695000 -* 2023 12 11 10 6 0.00000000 -PL56 4322.265824 -3140.441318 -4811.634879 -VL56 -50780.066000 12917.820000 -54072.033000 -* 2023 12 11 10 9 0.00000000 -PL56 3342.733862 -2842.683423 -5695.908876 -VL56 -57710.798000 20100.418000 -43897.913000 -* 2023 12 11 10 12 0.00000000 -PL56 2257.728020 -2420.090115 -6382.896570 -VL56 -62469.051000 26739.500000 -32214.903000 -* 2023 12 11 10 15 0.00000000 -PL56 1107.741005 -1885.032080 -6849.005214 -VL56 -64914.643000 32551.004000 -19426.387000 -* 2023 12 11 10 18 0.00000000 -PL56 -64.975631 -1254.775575 -7078.240170 -VL56 -64992.504000 37276.784000 -5970.808600 -* 2023 12 11 10 21 0.00000000 -PL56 -1217.946084 -550.924226 -7062.706783 -VL56 -62732.533000 40694.633000 7692.557600 -* 2023 12 11 10 24 0.00000000 -PL56 -2309.978933 201.309563 -6802.859344 -VL56 -58247.027000 42627.257000 21097.688000 -* 2023 12 11 10 27 0.00000000 -PL56 -3302.610677 973.986521 -6307.495477 -VL56 -51725.757000 42950.121000 33785.952000 -* 2023 12 11 10 30 0.00000000 -PL56 -4161.443951 1737.451687 -5593.497231 -VL56 -43429.478000 41598.079000 45320.025000 -* 2023 12 11 10 33 0.00000000 -PL56 -4857.349325 2461.449177 -4685.318781 -VL56 -33681.142000 38570.238000 55298.307000 -* 2023 12 11 10 36 0.00000000 -PL56 -5367.489554 3116.309308 -3614.214614 -VL56 -22854.824000 33932.824000 63369.174000 -* 2023 12 11 10 39 0.00000000 -PL56 -5676.121130 3674.160820 -2417.218063 -VL56 -11362.295000 27819.237000 69244.217000 -* 2023 12 11 10 42 0.00000000 -PL56 -5775.138080 4110.119800 -1135.893667 -VL56 362.341100 20427.274000 72710.204000 -* 2023 12 11 10 45 0.00000000 -PL56 -5664.323892 4403.398861 185.105706 -VL56 11879.515000 12013.010000 73638.562000 -* 2023 12 11 10 48 0.00000000 -PL56 -5351.289966 4538.278433 1499.625732 -VL56 22761.990000 2881.683200 71991.844000 -* 2023 12 11 10 51 0.00000000 -PL56 -4851.092635 4504.884471 2761.676197 -VL56 32612.646000 -6624.672800 67825.673000 -* 2023 12 11 10 54 0.00000000 -PL56 -4185.545229 4299.730072 3927.095157 -VL56 41080.313000 -16140.853000 61286.768000 -* 2023 12 11 10 57 0.00000000 -PL56 -3382.263142 3925.995307 4955.139066 -VL56 47873.468000 -25293.806000 52606.982000 -* 2023 12 11 11 0 0.00000000 -PL56 -2473.493068 3393.530857 5809.932083 -VL56 52770.514000 -33717.962000 42093.530000 -* 2023 12 11 11 3 0.00000000 -PL56 -1494.784163 2718.589268 6461.719625 -VL56 55626.997000 -41069.967000 30117.149000 -* 2023 12 11 11 6 0.00000000 -PL56 -483.565066 1923.298795 6887.882399 -VL56 56378.830000 -47042.485000 17097.377000 -* 2023 12 11 11 9 0.00000000 -PL56 522.305911 1034.907274 7073.685525 -VL56 55042.050000 -51375.818000 3488.197900 -* 2023 12 11 11 12 0.00000000 -PL56 1485.964601 84.827683 7012.756356 -VL56 51710.387000 -53868.372000 -10237.781000 -* 2023 12 11 11 15 0.00000000 -PL56 2372.893260 -892.482527 6707.283166 -VL56 46549.804000 -54384.749000 -23604.558000 -* 2023 12 11 11 18 0.00000000 -PL56 3152.158643 -1860.775096 6167.935505 -VL56 39791.244000 -52862.257000 -36148.346000 -* 2023 12 11 11 21 0.00000000 -PL56 3797.500016 -2783.358939 5413.505723 -VL56 31721.177000 -49314.854000 -47433.004000 -* 2023 12 11 11 24 0.00000000 -PL56 4288.230819 -3624.498013 4470.275939 -VL56 22670.453000 -43834.693000 -57064.837000 -* 2023 12 11 11 27 0.00000000 -PL56 4609.921926 -4350.809834 3371.124184 -VL56 13001.245000 -36590.631000 -64706.912000 -* 2023 12 11 11 30 0.00000000 -PL56 4754.840189 -4932.609669 2154.388412 -VL56 3092.878900 -27823.577000 -70091.489000 -* 2023 12 11 11 33 0.00000000 -PL56 4722.120575 -5345.138964 862.521096 -VL56 -6673.434000 -17838.370000 -73030.606000 -* 2023 12 11 11 36 0.00000000 -PL56 4517.660226 -5569.619283 -459.416614 -VL56 -15930.089000 -6992.521000 -73423.326000 -* 2023 12 11 11 39 0.00000000 -PL56 4153.741009 -5594.080483 -1765.360795 -VL56 -24337.605000 4317.457100 -71259.513000 -* 2023 12 11 11 42 0.00000000 -PL56 3648.398872 -5413.922404 -3009.887246 -VL56 -31598.169000 15671.939000 -66620.005000 -* 2023 12 11 11 45 0.00000000 -PL56 3024.571168 -5032.181566 -4149.817601 -VL56 -37466.687000 26644.891000 -59672.581000 -* 2023 12 11 11 48 0.00000000 -PL56 2309.067880 -4459.495489 -5145.722943 -VL56 -41759.110000 36820.516000 -50664.561000 -* 2023 12 11 11 51 0.00000000 -PL56 1531.419937 -3713.771818 -5963.265756 -VL56 -44357.686000 45809.328000 -39912.406000 -* 2023 12 11 11 54 0.00000000 -PL56 722.664869 -2819.587254 -6574.336656 -VL56 -45212.903000 53262.000000 -27789.558000 -* 2023 12 11 11 57 0.00000000 -PL56 -85.880623 -1807.349632 -6957.964575 -VL56 -44342.940000 58881.864000 -14713.446000 -* 2023 12 11 12 0 0.00000000 -PL56 -863.814206 -712.252411 -7100.981940 -VL56 -41830.487000 62435.420000 -1131.367500 -* 2023 12 11 12 3 0.00000000 -PL56 -1582.765482 426.939139 -6998.437277 -VL56 -37817.667000 63760.525000 12493.430000 -* 2023 12 11 12 6 0.00000000 -PL56 -2217.408896 1569.233005 -6653.753956 -VL56 -32499.435000 62772.800000 25696.014000 -* 2023 12 11 12 9 0.00000000 -PL56 -2746.342710 2672.852164 -6078.635605 -VL56 -26115.346000 59469.945000 38023.643000 -* 2023 12 11 12 12 0.00000000 -PL56 -3152.811896 3696.737819 -5292.718900 -VL56 -18940.505000 53934.293000 49049.951000 -* 2023 12 11 12 15 0.00000000 -PL56 -3425.255058 4602.073953 -4322.968947 -VL56 -11275.090000 46332.470000 58389.470000 -* 2023 12 11 12 18 0.00000000 -PL56 -3557.652560 5353.779557 -3202.815085 -VL56 -3432.603900 36911.914000 65711.701000 -* 2023 12 11 12 21 0.00000000 -PL56 -3549.654872 5921.904721 -1971.044321 -VL56 4272.540400 25993.882000 70753.807000 -* 2023 12 11 12 24 0.00000000 -PL56 -3406.485863 6282.873965 -670.482366 -VL56 11537.664000 13963.351000 73331.538000 -* 2023 12 11 12 27 0.00000000 -PL56 -3138.616229 6420.512116 653.504905 -VL56 18084.423000 1255.047700 73347.941000 -* 2023 12 11 12 30 0.00000000 -PL56 -2761.220156 6326.793664 1954.631380 -VL56 23670.439000 -11663.193000 70798.489000 -* 2023 12 11 12 33 0.00000000 -PL56 -2293.430423 6002.267301 3187.369016 -VL56 28099.816000 -24309.903000 65771.618000 -* 2023 12 11 12 36 0.00000000 -PL56 -1757.431035 5456.124683 4308.594858 -VL56 31230.410000 -36209.480000 58445.029000 -* 2023 12 11 12 39 0.00000000 -PL56 -1177.442051 4705.921384 5279.135596 -VL56 32978.636000 -46911.246000 49078.394000 -* 2023 12 11 12 42 0.00000000 -PL56 -578.643768 3776.966060 6065.152174 -VL56 33321.494000 -56007.208000 38002.793000 -* 2023 12 11 12 45 0.00000000 -PL56 13.906259 2701.410308 6639.310698 -VL56 32295.247000 -63147.431000 25607.683000 -* 2023 12 11 12 48 0.00000000 -PL56 576.312418 1517.084929 6981.706356 -VL56 29991.909000 -68052.658000 12326.507000 -* 2023 12 11 12 51 0.00000000 -PL56 1086.796883 266.133127 7080.520275 -VL56 26553.664000 -70524.395000 -1378.336700 -* 2023 12 11 12 54 0.00000000 -PL56 1526.537001 -1006.508404 6932.398355 -VL56 22165.345000 -70451.722000 -15031.232000 -* 2023 12 11 12 57 0.00000000 -PL56 1880.356828 -2254.731012 6542.552946 -VL56 17045.753000 -67815.815000 -28158.600000 -* 2023 12 11 13 0 0.00000000 -PL56 2137.252277 -3432.931401 5924.583789 -VL56 11437.950000 -62691.748000 -40304.650000 -* 2023 12 11 13 3 0.00000000 -PL56 2290.733464 -4497.690536 5100.019513 -VL56 5598.641500 -55246.592000 -51046.699000 -* 2023 12 11 13 6 0.00000000 -PL56 2338.973299 -5409.394098 4097.588607 -VL56 -212.604970 -45734.928000 -60009.799000 -* 2023 12 11 13 9 0.00000000 -PL56 2284.761106 -6133.739398 2952.238025 -VL56 -5744.281700 -34490.743000 -66880.156000 -* 2023 12 11 13 12 0.00000000 -PL56 2135.257743 -6643.066746 1703.918775 -VL56 -10763.871000 -21915.914000 -71417.292000 -* 2023 12 11 13 15 0.00000000 -PL56 1901.563728 -6917.450168 396.180804 -VL56 -15067.705000 -8465.298900 -73463.121000 -* 2023 12 11 13 18 0.00000000 -PL56 1598.121096 -6945.501725 -925.371469 -VL56 -18489.510000 5370.472800 -72948.317000 -* 2023 12 11 13 21 0.00000000 -PL56 1241.972940 -6724.845382 -2214.710761 -VL56 -20907.595000 19084.219000 -69895.254000 -* 2023 12 11 13 24 0.00000000 -PL56 851.916696 -6262.224992 -3427.027884 -VL56 -22249.192000 32173.003000 -64416.277000 -* 2023 12 11 13 27 0.00000000 -PL56 447.602417 -5573.252823 -4520.307280 -VL56 -22492.403000 44157.449000 -56708.301000 -* 2023 12 11 13 30 0.00000000 -PL56 48.619835 -4681.820834 -5456.777380 -VL56 -21665.595000 54599.838000 -47044.301000 -* 2023 12 11 13 33 0.00000000 -PL56 -326.385476 -3619.210621 -6204.183825 -VL56 -19844.638000 63119.251000 -35762.350000 -* 2023 12 11 13 36 0.00000000 -PL56 -660.526178 -2422.948205 -6736.849997 -VL56 -17148.073000 69404.611000 -23253.036000 -* 2023 12 11 13 39 0.00000000 -PL56 -939.385613 -1135.454678 -7036.500748 -VL56 -13730.714000 73224.516000 -9945.848200 -* 2023 12 11 13 42 0.00000000 -PL56 -1151.604386 197.454919 -7092.838394 -VL56 -9776.100700 74434.228000 3704.666300 -* 2023 12 11 13 45 0.00000000 -PL56 -1289.322729 1528.177021 -6903.865901 -VL56 -5488.091800 72980.261000 17233.090000 -* 2023 12 11 13 48 0.00000000 -PL56 -1348.466352 2808.982501 -6475.956473 -VL56 -1081.922400 68902.333000 30177.164000 -* 2023 12 11 13 51 0.00000000 -PL56 -1328.868500 3993.697133 -5823.671651 -VL56 3225.038500 62333.323000 42091.700000 -* 2023 12 11 13 54 0.00000000 -PL56 -1234.223959 5039.357396 -4969.322897 -VL56 7222.677000 53496.355000 52563.163000 -* 2023 12 11 13 57 0.00000000 -PL56 -1071.874650 5907.789020 -3942.274150 -VL56 10717.381000 42699.136000 61223.889000 -* 2023 12 11 14 0 0.00000000 -PL56 -852.431992 6567.049381 -2777.989544 -VL56 13540.902000 30324.537000 67765.910000 -* 2023 12 11 14 3 0.00000000 -PL56 -589.246685 6992.670192 -1516.846972 -VL56 15558.351000 16817.807000 71953.129000 -* 2023 12 11 14 6 0.00000000 -PL56 -297.746643 7168.642024 -202.747760 -VL56 16674.784000 2670.625100 73631.585000 -* 2023 12 11 14 9 0.00000000 -PL56 5.329418 7088.084522 1118.431739 -VL56 16840.134000 -11597.665000 72736.759000 -* 2023 12 11 14 12 0.00000000 -PL56 302.765953 6753.558355 2400.488601 -VL56 16051.696000 -25461.044000 69297.146000 -* 2023 12 11 14 15 0.00000000 -PL56 577.726095 6176.990390 3598.565097 -VL56 14354.046000 -38408.362000 63433.122000 -* 2023 12 11 14 18 0.00000000 -PL56 814.585740 5379.223774 4670.763715 -VL56 11836.825000 -49963.256000 55352.074000 -* 2023 12 11 14 21 0.00000000 -PL56 999.707682 4389.217613 5579.648508 -VL56 8630.153200 -59703.439000 45340.850000 -* 2023 12 11 14 24 0.00000000 -PL56 1122.113587 3242.925478 6293.559895 -VL56 4898.151000 -67276.035000 33752.157000 -* 2023 12 11 14 27 0.00000000 -PL56 1174.027125 1981.930653 6787.697997 -VL56 831.053950 -72410.208000 20993.077000 -* 2023 12 11 14 30 0.00000000 -PL56 1151.262594 651.891435 7044.955324 -VL56 -3363.942400 -74925.403000 7508.802900 -* 2023 12 11 14 33 0.00000000 -PL56 1053.446904 -699.140912 7056.475212 -VL56 -7472.053300 -74736.764000 -6231.826300 -* 2023 12 11 14 36 0.00000000 -PL56 884.067553 -2022.468698 6821.934284 -VL56 -11280.739000 -71857.482000 -19752.040000 -* 2023 12 11 14 39 0.00000000 -PL56 650.344163 -3270.510834 6349.545439 -VL56 -14589.461000 -66398.040000 -32582.693000 -* 2023 12 11 14 42 0.00000000 -PL56 362.927724 -4398.524548 5655.775565 -VL56 -17218.979000 -58562.342000 -44278.399000 -* 2023 12 11 14 45 0.00000000 -PL56 35.440948 -5366.222435 4764.786311 -VL56 -19019.655000 -48640.209000 -54431.979000 -* 2023 12 11 14 48 0.00000000 -PL56 -316.122622 -6139.239707 3707.620328 -VL56 -19878.873000 -36998.033000 -62688.426000 -* 2023 12 11 14 51 0.00000000 -PL56 -674.124228 -6690.401963 2521.137185 -VL56 -19727.293000 -24065.819000 -68758.444000 -* 2023 12 11 14 54 0.00000000 -PL56 -1020.098314 -7000.727213 1246.726956 -VL56 -18542.883000 -10320.922000 -72429.551000 -* 2023 12 11 14 57 0.00000000 -PL56 -1335.625459 -7060.118734 -71.151328 -VL56 -16352.966000 3729.944400 -73574.465000 -* 2023 12 11 15 0 0.00000000 -PL56 -1603.219116 -6867.709885 -1386.557520 -VL56 -13233.538000 17571.300000 -72156.369000 -* 2023 12 11 15 3 0.00000000 -PL56 -1807.176955 -6431.838637 -2653.710907 -VL56 -9306.148200 30699.300000 -68229.625000 -* 2023 12 11 15 6 0.00000000 -PL56 -1934.358151 -5769.662701 -3828.612864 -VL56 -4732.824000 42641.027000 -61937.115000 -* 2023 12 11 15 9 0.00000000 -PL56 -1974.850046 -4906.435383 -4870.587303 -VL56 291.109420 52972.630000 -53503.748000 -* 2023 12 11 15 12 0.00000000 -PL56 -1922.491672 -3874.483697 -5743.673930 -VL56 5545.632900 61334.173000 -43226.789000 -* 2023 12 11 15 15 0.00000000 -PL56 -1775.234306 -2711.949283 -6417.829287 -VL56 10795.480000 67441.195000 -31464.362000 -* 2023 12 11 15 18 0.00000000 -PL56 -1535.326856 -1461.348909 -6869.907485 -VL56 15800.082000 71093.168000 -18622.464000 -* 2023 12 11 15 21 0.00000000 -PL56 -1209.321225 -168.012698 -7084.396974 -VL56 20323.531000 72178.614000 -5141.031800 -* 2023 12 11 15 24 0.00000000 -PL56 -807.901017 1121.540826 -7053.905634 -VL56 24144.263000 70677.060000 8520.058200 -* 2023 12 11 15 27 0.00000000 -PL56 -345.537614 2361.243526 -6779.394836 -VL56 27064.470000 66658.780000 21894.857000 -* 2023 12 11 15 30 0.00000000 -PL56 160.015826 3507.089269 -6270.162391 -VL56 28918.735000 60282.025000 34525.315000 -* 2023 12 11 15 33 0.00000000 -PL56 688.382707 4518.680333 -5543.571540 -VL56 29582.238000 51788.398000 45975.797000 -* 2023 12 11 15 36 0.00000000 -PL56 1217.356102 5360.660682 -4624.519030 -VL56 28977.451000 41495.058000 55847.230000 -* 2023 12 11 15 39 0.00000000 -PL56 1723.801091 6003.990176 -3544.647313 -VL56 27079.535000 29784.662000 63791.504000 -* 2023 12 11 15 42 0.00000000 -PL56 2184.635567 6427.007786 -2341.307172 -VL56 23919.551000 17092.021000 69524.601000 -* 2023 12 11 15 45 0.00000000 -PL56 2577.848988 6616.234168 -1056.294522 -VL56 19585.418000 3888.532300 72838.421000 -* 2023 12 11 15 48 0.00000000 -PL56 2883.512619 6566.867905 265.605665 -VL56 14219.964000 -9336.176700 73610.226000 -* 2023 12 11 15 51 0.00000000 -PL56 3084.728610 6282.937906 1578.212555 -VL56 8016.094900 -22093.895000 71808.283000 -* 2023 12 11 15 54 0.00000000 -PL56 3168.468552 5777.101319 2835.609799 -VL56 1209.416300 -33917.357000 67493.690000 -* 2023 12 11 15 57 0.00000000 -PL56 3126.258734 5070.095053 3993.803861 -VL56 -5931.338400 -44379.063000 60818.327000 -* 2023 12 11 16 0 0.00000000 -PL56 2954.677200 4189.865067 5012.309007 -VL56 -13115.645000 -53108.113000 52018.765000 -* 2023 12 11 16 3 0.00000000 -PL56 2655.632154 3170.415962 5855.590537 -VL56 -20043.916000 -59804.268000 41406.493000 -* 2023 12 11 16 6 0.00000000 -PL56 2236.412333 2050.444176 6494.300366 -VL56 -26419.924000 -64247.741000 29355.333000 -* 2023 12 11 16 9 0.00000000 -PL56 1709.518147 871.827262 6906.276002 -VL56 -31962.892000 -66305.732000 16287.435000 -* 2023 12 11 16 12 0.00000000 -PL56 1092.275578 -321.972204 7077.276587 -VL56 -36419.213000 -65935.017000 2658.201900 -* 2023 12 11 16 15 0.00000000 -PL56 406.251736 -1487.521023 7001.444484 -VL56 -39572.935000 -63181.859000 -11058.822000 -* 2023 12 11 16 18 0.00000000 -PL56 -323.509126 -2583.002366 6681.489962 -VL56 -41255.098000 -58178.800000 -24387.888000 -* 2023 12 11 16 21 0.00000000 -PL56 -1069.405731 -3569.722567 6128.589124 -VL56 -41351.630000 -51139.034000 -36866.687000 -* 2023 12 11 16 24 0.00000000 -PL56 -1802.319952 -4413.484509 5362.000841 -VL56 -39808.968000 -42347.486000 -48061.770000 -* 2023 12 11 16 27 0.00000000 -PL56 -2492.747821 -5085.789865 4408.423496 -VL56 -36638.388000 -32150.546000 -57582.476000 -* 2023 12 11 16 30 0.00000000 -PL56 -3111.990344 -5564.836252 3301.091689 -VL56 -31918.049000 -20943.410000 -65095.554000 -* 2023 12 11 16 33 0.00000000 -PL56 -3633.347882 -5836.258680 2078.624630 -VL56 -25791.459000 -9154.540400 -70337.821000 -* 2023 12 11 16 36 0.00000000 -PL56 -4033.261819 -5893.579737 783.670473 -VL56 -18463.173000 2770.998900 -73126.265000 -* 2023 12 11 16 39 0.00000000 -PL56 -4292.354403 -5738.350837 -538.605044 -VL56 -10191.751000 14389.137000 -73365.098000 -* 2023 12 11 16 42 0.00000000 -PL56 -4396.315931 -5379.974773 -1842.129516 -VL56 -1279.908100 25274.484000 -71049.681000 -* 2023 12 11 16 45 0.00000000 -PL56 -4336.593158 -4835.214754 -3081.568316 -VL56 7937.643500 35037.298000 -66266.253000 -* 2023 12 11 16 48 0.00000000 -PL56 -4110.843809 -4127.415065 -4213.927691 -VL56 17107.863000 43338.331000 -59187.622000 -* 2023 12 11 16 51 0.00000000 -PL56 -3723.139264 -3285.481318 -5200.047663 -VL56 25873.517000 49900.621000 -50065.444000 -* 2023 12 11 16 54 0.00000000 -PL56 -3183.913884 -2342.676216 -6005.932151 -VL56 33887.125000 54518.186000 -39219.914000 -* 2023 12 11 16 57 0.00000000 -PL56 -2509.669213 -1335.288321 -6603.875590 -VL56 40824.144000 57061.424000 -27027.667000 -* 2023 12 11 17 0 0.00000000 -PL56 -1722.449262 -301.231840 -6973.359410 -VL56 46395.222000 57479.444000 -13908.282000 -* 2023 12 11 17 3 0.00000000 -PL56 -849.109504 721.367484 -7101.698517 -VL56 50356.718000 55799.271000 -310.212250 -* 2023 12 11 17 6 0.00000000 -PL56 79.589793 1695.550104 -6984.436838 -VL56 52519.813000 52122.810000 13302.916000 -* 2023 12 11 17 9 0.00000000 -PL56 1030.042508 2586.828906 -6625.494587 -VL56 52758.321000 46621.918000 26466.300000 -* 2023 12 11 17 12 0.00000000 -PL56 1966.984914 3364.392456 -6037.064572 -VL56 51015.181000 39531.843000 38728.108000 -* 2023 12 11 17 15 0.00000000 -PL56 2854.782487 4002.171135 -5239.246740 -VL56 47306.775000 31142.599000 49663.950000 -* 2023 12 11 17 18 0.00000000 -PL56 3658.773468 4479.730551 -4259.424811 -VL56 41724.965000 21788.512000 58891.235000 -* 2023 12 11 17 21 0.00000000 -PL56 4346.627304 4782.964652 -3131.389742 -VL56 34436.547000 11836.201000 66082.917000 -* 2023 12 11 17 24 0.00000000 -PL56 4889.665744 4904.554032 -1894.218861 -VL56 25679.629000 1670.676900 70980.697000 -* 2023 12 11 17 27 0.00000000 -PL56 5264.084080 4844.161461 -590.938877 -VL56 15756.176000 -8319.854400 73405.710000 -* 2023 12 11 17 30 0.00000000 -PL56 5452.011599 4608.349023 732.984413 -VL56 5021.387400 -17759.666000 73266.822000 -* 2023 12 11 17 33 0.00000000 -PL56 5442.350903 4210.214655 2031.269321 -VL56 -6129.726600 -26300.721000 70564.929000 -* 2023 12 11 17 36 0.00000000 -PL56 5231.356418 3668.762854 3258.487325 -VL56 -17278.105000 -33637.018000 65393.715000 -* 2023 12 11 17 39 0.00000000 -PL56 4822.912814 3008.034609 4371.707577 -VL56 -27997.942000 -39516.756000 57936.045000 -* 2023 12 11 17 42 0.00000000 -PL56 4228.497657 2256.043075 5332.037152 -VL56 -37874.245000 -43751.687000 48456.100000 -* 2023 12 11 17 45 0.00000000 -PL56 3466.838067 1443.573650 6105.995286 -VL56 -46519.158000 -46222.639000 37289.093000 -* 2023 12 11 17 48 0.00000000 -PL56 2563.276480 602.906237 6666.672866 -VL56 -53587.828000 -46882.940000 24827.785000 -* 2023 12 11 17 51 0.00000000 -PL56 1548.884928 -233.480777 6994.636807 -VL56 -58790.557000 -45756.934000 11507.560000 -* 2023 12 11 17 54 0.00000000 -PL56 459.366871 -1034.168624 7078.572047 -VL56 -61904.051000 -42937.247000 -2207.670400 -* 2023 12 11 17 57 0.00000000 -PL56 -666.220380 -1769.980857 6915.646929 -VL56 -62780.211000 -38579.325000 -15841.804000 -* 2023 12 11 18 0 0.00000000 -PL56 -1786.876390 -2415.048267 6511.591751 -VL56 -61351.950000 -32893.704000 -28922.309000 -* 2023 12 11 18 3 0.00000000 -PL56 -2861.151422 -2947.719443 5880.496158 -VL56 -57636.805000 -26136.853000 -40995.217000 -* 2023 12 11 18 6 0.00000000 -PL56 -3848.682872 -3351.294239 5044.341521 -VL56 -51738.151000 -18600.677000 -51640.187000 -* 2023 12 11 18 9 0.00000000 -PL56 -4711.732939 -3614.559469 4032.260002 -VL56 -43843.537000 -10600.800000 -60485.501000 -* 2023 12 11 18 12 0.00000000 -PL56 -5416.655702 -3732.099713 2879.534115 -VL56 -34218.886000 -2463.618700 -67221.532000 -* 2023 12 11 18 15 0.00000000 -PL56 -5935.236839 -3704.373981 1626.373511 -VL56 -23200.136000 5486.734100 -71612.259000 -* 2023 12 11 18 18 0.00000000 -PL56 -6245.849402 -3537.554604 316.499722 -VL56 -11180.982000 12941.803000 -73504.817000 -* 2023 12 11 18 21 0.00000000 -PL56 -6334.364360 -3243.129666 -1004.409857 -VL56 1401.909400 19621.420000 -72835.459000 -* 2023 12 11 18 24 0.00000000 -PL56 -6194.770272 -2837.288983 -2290.354715 -VL56 14086.290000 25285.085000 -69632.092000 -* 2023 12 11 18 27 0.00000000 -PL56 -5829.466614 -2340.123180 -3496.649621 -VL56 26402.926000 29741.175000 -64012.291000 -* 2023 12 11 18 30 0.00000000 -PL56 -5249.223932 -1774.681366 -4581.493746 -VL56 37893.968000 32853.462000 -56177.779000 -* 2023 12 11 18 33 0.00000000 -PL56 -4472.821787 -1165.936366 -5507.411966 -VL56 48130.153000 34544.814000 -46405.812000 -* 2023 12 11 18 36 0.00000000 -PL56 -3526.387423 -539.706886 -6242.518763 -VL56 56726.770000 34798.318000 -35038.168000 -* 2023 12 11 18 39 0.00000000 -PL56 -2442.470132 78.414567 -6761.564572 -VL56 63357.010000 33655.548000 -22468.184000 -* 2023 12 11 18 42 0.00000000 -PL56 -1258.896946 664.081625 -7046.742571 -VL56 67762.891000 31212.543000 -9127.173100 -* 2023 12 11 18 45 0.00000000 -PL56 -17.454167 1195.125046 -7088.246894 -VL56 69763.642000 27614.112000 4529.504600 -* 2023 12 11 18 48 0.00000000 -PL56 1237.561214 1652.369264 -6884.580825 -VL56 69261.925000 23046.771000 18036.241000 -* 2023 12 11 18 51 0.00000000 -PL56 2460.886892 2020.312180 -6442.618418 -VL56 66248.453000 17730.765000 30930.981000 -* 2023 12 11 18 54 0.00000000 -PL56 3607.901701 2287.650832 -5777.406750 -VL56 60803.884000 11910.842000 42770.071000 -* 2023 12 11 18 57 0.00000000 -PL56 4636.240279 2447.634038 -4911.707308 -VL56 53097.808000 5846.289600 53142.309000 -* 2023 12 11 19 0 0.00000000 -PL56 5507.370207 2498.232240 -3875.283350 -VL56 43385.629000 -199.362060 61683.347000 -* 2023 12 11 19 3 0.00000000 -PL56 6188.075114 2442.115357 -2703.933760 -VL56 32001.135000 -5969.272700 68089.089000 -* 2023 12 11 19 6 0.00000000 -PL56 6651.779995 2286.435342 -1438.294888 -VL56 19346.442000 -11224.045000 72127.992000 -* 2023 12 11 19 9 0.00000000 -PL56 6879.655107 2042.417703 -122.437088 -VL56 5877.446900 -15752.127000 73651.475000 -* 2023 12 11 19 12 0.00000000 -PL56 6861.433646 1724.774709 1197.694499 -VL56 -7913.532800 -19379.082000 72600.725000 -* 2023 12 11 19 15 0.00000000 -PL56 6595.894360 1350.967575 2475.927895 -VL56 -21517.024000 -21974.949000 69009.559000 -* 2023 12 11 19 18 0.00000000 -PL56 6090.985406 940.353810 3667.533524 -VL56 -34427.226000 -23459.686000 63003.838000 -* 2023 12 11 19 21 0.00000000 -PL56 5363.572458 513.261079 4730.840015 -VL56 -46162.503000 -23805.795000 54796.372000 -* 2023 12 11 19 24 0.00000000 -PL56 4438.828321 90.038127 5628.721297 -VL56 -56284.372000 -23038.175000 44677.691000 -* 2023 12 11 19 27 0.00000000 -PL56 3349.301425 -309.870552 6329.900130 -VL56 -64414.398000 -21231.732000 33004.826000 -* 2023 12 11 19 30 0.00000000 -PL56 2133.707843 -668.782435 6810.020298 -VL56 -70247.677000 -18506.372000 20187.467000 -EOF diff --git a/src/test/resources/sp3/nsgf.orb.stella.v00.sp3.gz b/src/test/resources/sp3/nsgf.orb.stella.v00.sp3.gz new file mode 100644 index 0000000000000000000000000000000000000000..0e0e041b45cd4c973ddec929ffd06132040e6d65 GIT binary patch literal 4916 zcmV-46U*!$iwFp-M~P(u18#F?W-f1XVlH!ZWo&F=E_N_5E^}}*0PUMi&s@iGh4=au z7ZALOG1vY5kzF82fdIh?B*lB0A|nDa8BjD3|NA_ry6+_&)fln8jA@C~@ST}+ySwVt zIaTe?U;ZwIl#iH>V;o0V|D0j}I`k{rpWl7+Ex&*H#aG8yUw?o6_Pc-m>a)*3KT?|U zC^_-oPd^mLCofw_qkZzF_Up4>+gJ1NH?`fs|HpsUhu5$0|K`KL{>O*^st^C_KDKLiw%99zR-ui|MAuF$G1PcdjHd(-n{)!W2x8gU;N?K@#g2_ z!;ddM9PeHqUw`@Scfa}i`)|Mc-^jmx_u5l?9e*fZUA-_G!dB$1w?Y~6NF8b`?#oYP?53=VAN{*rOs*c*uI&$oJqo-QC z5Tc>io_arX8irnC3;8Ug`RL6<&$;Du_8Lk7FAr9m2T!ACsUh-YYz1#$=oFnY&Js3y zOkrY|EK? zHS`w7sORX}Mc02g=snf5&oaeRngJT_Mx6S71a!c`SwJr2s z6WbX5osZRDJDV3X$FJ4aS$US;d$SmXboP|3oTDexLZHuBiNTGo^NuHvvy@MYgQS=>8+sb4ki1XOi<@z5+o^01h8}x4 z%j}~L{VbPyR-zz|3!O72F!pL=nMBXBmEG2{_DSF*F^ruG zG04}IR4?>7_4dBvEcMjN8ODzJ+;dR~x#-#Dy2ysHKJugsJx=gKuG*-B%+kiTHZOD* zmeU!s<@=FGCj&-bulN$SD%RqoyIdC|o0n%A#&x9-IJt%t^s`z^CY||Ty3k9@`3!S$ zYZ;TZx46!s)B!n-HhgrK>y84Wlr~4q;+MkXbF4Y(XDq!DVzb0@qZ1Oa>Dp@+OS(c% zYbQz?@tncuy6ke@BeJ^%b{pDx;*6~fz11r8P7O#rOSspbD{CKhpEQeRC(@3BSX(-0 z^JBiaT=(b%@l2slkx7K6c}uEd{iBCWh|QKtzR<(8Dzh|DBgL8?Z{^;>RcK3sI3%Lne3tu7rl*g&Ou6B z3_^V;8%<m}|m`~q94e(>WdRzy4@xYlK=vmn>W)H-_ zah)>wESZvXaUJ;yF>kyBN+$~Hu6QJRg@tSI(Tj`D!p=b{8OAR?5>z9PA+D=!zy+kVg=pjy4qdzqPk}4JT4cQ_8XjBvct$I*Sb8%h?Hv@TIIs5dtHx3X7a5px0IHdqQZDjm<}&e$0o- z0~0sfiK|ouU;= z$W!%};tF-nfXutlr<5E5Zt=?$O}D5N*V+@h$Ed(V_qi^MX>%`9avW&r@@#B-JubrI2_T^dIUB5u>8#w@%7)TOSIkT8 zu=cX_JS7J&LjvrWPh#3sU36d9A>pG0dNefyRiLa|GgbLe^pU`c6TQ)!s_5MOf|w#H zHrG`W4l^+PnD=#^^bG0(9bx=}qvGh&LgyG*D3Lwlz4L@Qi0 zFn&Rq@RpfX5XB$pEb@4c+sDOnIR;6CjEjuM>{jCt#NAaF@rkZGI7CV`2{(*LIR_MU zS4ooah5H5Lz^cyx%RutK>5`0 zP|U{>kjRg^9dr`wpt_2?^S-W&h-l1LE7q;R!0{@#x?LUU*hVzP?O_|_3)41>x=s*c z_tVz291_IkGp(!ZKu;6T%x3GPi=0hFUf3&ZRPY1B{;KcL5QV2jbI_HIC;v9@mWts+ zp!)gl>bk?WYbFBK@St?EpTMjV^3UcLHNO2PKQdR+mK?bfI%WQK+n&j={m4`REXUY9(mjio(U3sJ zSYo@^j>d$Fcg97S0Xo|KRir+wKV1i%p7iSu`9_x9hoMKz&_F9SsXV@bY7co`Oe-}2 zpM_OrL>3%P4O+bQE|RG63A)d9kR1rfm&GsCl@ek#MIA{z$O}nvcTT#xVq>G@mS@;; zroPRj+V|LfbeHR7C)Dn!!9vfUQAF_L@6-MhedG+9C)-Q~ImP7rn@(M`=@-3gpltmYsy z*!h9Bx|sGc)tR+}(rQy^s`l4T3}SGW>ZAJ}7K%p_z-o&~r`iFfE{$1Kfr#?fZzt8% z-n)F<3=v}9YsYp_7DDmY?&>=E!f@h&npO0uhF`DUYL3)>lCr`bUFf`l$Qonk7|IT= zTlJl6lreF2UGjAu=*lWeYMZM&sVKm}S0f^l8|uk-rxbIQ)wfBjKUgt&mxq-sL!_xq z?xJ^p=QCu939@cQ3=)Q9jy(&ROG1(E^+qQpG2BUIjh`25Hmu%-`lcl4EI!-#y6yq9 z=`X9XTarL8B)}ZY)eZG+Lcf)jOw{e9*qf?O&Gr`R>#ObQqq|%O!3^?!^tE|ZZd9I{ z(vHTLT_lP-o^kB15h_o;gr%sdbyolUnD=!ZWl}XftqxtW4wgdMdKdaxRuH$_ zMM{3O-K&)9At~ajIq1Knvf#6guj|wfmSjnMZj`&xvh#v9! z9qS7{bxlULe@}?63{7uW$MLl%iaI^fb+KVQS!1@84=?r@l~ z_~^ce?P@HOQ#OgowO8s&>3!)ev*&1u+euY56d)(_GNeP3y6@XtpgQ25>ZAJ}wiRiq zxp>|huV@)kS0$j1Vo~r>*9Do*u-!x>2-?jysn@DTL~zmL6Az2!&yuRvos4RIP8OHV zw6Qd5IIFtd1QBkd%hjR7(vp7*9XH%$I{m2gbzRgrBg@K!rLU=K^7PibAOI+!pDOB! zXGHK{=vBjuvAKt0U37^2)Is;TPVElFa9CPHt&ldV^~)bpk7%3p$utmoi~QJK=^nB~ z;buN@R3>Qrwfp_LLtUz@siW{xCuy2k#ClduL!ZIoKTbmB*h}3vAF9N`bx($$A=1Wt zf?j+t!`G=9QEVPJ@DJqEnu|7#`qRLq=X)w7v$H2~k2=J(G4wr|RD~^1qR#Kvak!Y$ zS-R>w#4ZJ2S*~TA#QW4ugv(7N>xs{_VxD8__gn_=p^_0(bJ1O0_pqK7B9=;Kay^Op z(yVq5A`^pD{4wsG@0M|ScMnGI%KlYzFrpOX#Y7Hz_B-SnDzkfi^@*bOknjZ7Ly|}x zo%6iUy@;IFG*I1x`mx$;%gWihzw_CjP2jJiMN_ZXmxG2Z)$}sfmslcN-xcYn&kyaB-_{9@%tG*GQTKWd&|}o-J4YWt7|9G1DN0(=IE+CBXO1BdIdo40yJ7*Tbq?b*e#X zU1{h8rY*>XZpMsa&Y_3e?|B>@nrd~n@*U@ zXd|aA&4;LMAN#aY&4hwo%`KhUbe7$(qu5gxEEzp?e-5kW2ie{%%Bf~emUsqJI!U9B zq{iv(q|lpC|JdD03Gh(Mbq_+fyq?ter*l}f``K%oLQPe*PT4k~Od{C9Cy+UL zmbSW+W&}y#Xj56ttQr;ds<2eiYHi)U^GSC=u9}1DlDDt^&ilHKw4sv7zL;;+#VOQb zNoy{eZ6aOEjXpJ~ox3YdeYO7Jt~qFP&cVIuRG#TNsEWr=Va@v`%{1D|VcFZDp>n%t zQp!kN0*y&&~5ihvTm4SEv!>Ysk6HW^S;q4<*mWZ?hlH4E=Aqc z+GZisM|X8yjtQA4V`jb4-jXI2HW}gDSq!07`kn8y)wDZ9)<>xtU~hC1)GlTE=-t0p zsf^Q%-Dc2p=pJWD=Bv;gy098b>>nrK@=p6!8Dyy5sIDNIgDxXHnf{k2{W{_(vDbaw zyD;>Dpt5^bx_-k#!?^DfN1Fzw&8-@VsSxyQF51VwVd|i}9#)lIt)3C<+Igv1q_Q#J z)J%9(V&bZCU008TH3-Ga<|4O`>!d5?xkn$})fs30~v5l;N6zT{jVQM^8q`XIj5sM@6(&YYP_TosCuW^t$f)4Qfssca3|XHFPB{ z$EB#%)}4!K5rHbmq50?T_v_HZbs6$(Q809@9f2XOfm;`q^?2X2g5fnV-?t5#5~hXg zCPKB_cK*)${km*@snN&IKWIF5HNULjNpZqC_15!fUUg2Ehs91S-&f7yS%w67dV)Uu z8|=C!R@E%A{-Ca9hd##Am{AjO+4TEfrJ9SS^=q}b)?HyAS>@r$M65jN*Cj_UoWW?0R1r&S%sq4K@Yt z0n?VdT=RwAU?nv-E_5B#`hOBAB7-i=iR>Ko{-jSUD~5EeHmQ(3ppa=M^;pAwRAau* mogY=*QorI%cUaTvVA=R?sB0wjFaPbU&;AGK8z2z3HUI!^`8Q1f literal 0 HcmV?d00001 From 5fc935e69ac05d3237fd5d257ea8ced151e94849 Mon Sep 17 00:00:00 2001 From: Bryan Cazabonne Date: Sat, 30 Dec 2023 12:31:35 +0100 Subject: [PATCH 066/359] As always, merging changes.xml is prone to conflicts. --- src/changes/changes.xml | 89 ++++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 46 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 05ccb22d75..0a08c10008 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -20,6 +20,32 @@ Orekit Changes + + + Added NsgfV00Filter to allow parsing some wrong SP3 files. + + + Started using new square method for Field. + + + Fixed parsing of SP3 files with partly missing standard deviations. + + + Added field versions of unit conversions from and to SI units. + + + Removed uses of scalar multiply on Field one. + + + Added utility classes for position angle conversions for (Field) CircularOrbit and EquinoctialOrbit. + + + Fixed exceptions occurring in EOP prediction with ill chosen fitting parameters. + + + Added translation of error messages in Catalan language. + + Fixed exceptions occurring in EOP prediction with ill chosen fitting parameters. - - Added translation of error messages in Catalan language. - Fixed regression in computation speed when using Ephemeris. @@ -65,32 +88,6 @@ Fixed bad caching of the ocean tides model. - - - Added NsgfV00Filter to allow parsing some wrong SP3 files. - - - Started using new square method for Field. - - - Fixed parsing of SP3 files with partly missing standard deviations. - - - Added field versions of unit conversions from and to SI units. - - - Removed uses of scalar multiply on Field one. - - - Added utility classes for position angle conversions for (Field) CircularOrbit and EquinoctialOrbit. - - - Fixed exceptions occurring in EOP prediction with ill chosen fitting parameters. - - - Added translation of error messages in Catalan language. - - - Allowed custom setting of state to TLE conversion in propagator builder. + Allowed custom setting of state to TLE conversion in propagator builder. Fixed handling of comments in CRD files. @@ -1881,13 +1878,13 @@ Improve performance of ZipJarCrawler. - Added default constructors for DSSTZonal and DSSTTesseral. - + Added default constructors for DSSTZonal and DSSTTesseral. + - Added OrekitException for unknown number of frequencies in ANTEX files. + Added OrekitException for unknown number of frequencies in ANTEX files. - Added OrekitException in the case where IONEX header is corrupted. + Added OrekitException in the case where IONEX header is corrupted. Added a specific test for issue 359 in BatchLSEstimatorTest. @@ -2134,7 +2131,7 @@ Changing AbstractGNSSAttitudeProvider from public to package-private. - Fix the bug of attitude transition with analytical propagator + Fix the bug of attitude transition with analytical propagator by refreshing the attitude after the events triggering @@ -2182,7 +2179,7 @@ Deprecated unused DerivativeStructure acceleration computation methods. - In interfaces radiationPressureAcceleration and dragAcceleration, and all their implementations and their tests. + In interfaces radiationPressureAcceleration and dragAcceleration, and all their implementations and their tests. Take target radius into account in CircularFieldOfViewDetector and FieldOfViewDetector. @@ -2359,7 +2356,7 @@ Fixes issue #492. - Fixed reference value of parameter drivers updating in Kalman filter. + Fixed reference value of parameter drivers updating in Kalman filter. When resetting the orbit in the propagator builder, the reference values of the drivers are now reset too. Fixes issue #490. @@ -2741,7 +2738,7 @@ Forced states derivatives to be dimension 6 rather than either 6 or 7. The additional mass was not really useful, it was intended for maneuvers calibration, but in fact during maneuver calibration we adjust either flow rate or specific - impulse but not directly mass itself. + impulse but not directly mass itself. Added parametric acceleration force models, where acceleration amplitude is a @@ -2997,7 +2994,7 @@ file formats, and implemented the OEMWriter for CCSDS OEM file export support. - Added OrekitEphemerisFile object for encapsulating propagator outputs into an + Added OrekitEphemerisFile object for encapsulating propagator outputs into an EphemerisFile which can then be exported with EphemerisFileWriter classes. @@ -3483,7 +3480,7 @@ provided by NOAA. - Fixed javadoc of method "GeoMagneticField#calculateField(...)": + Fixed javadoc of method "GeoMagneticField#calculateField(...)": the provided altitude is expected to be a height above the WGS84 ellipsoid. @@ -3594,7 +3591,7 @@ Allow attitude overriding during impulsive maneuvers. - Fixes issue #176. + Fixes issue #176. Added general relativity force model. @@ -3760,7 +3757,7 @@ Merged all elevation detectors into one. The new detector supports all features from the previous (and now deprecated) ApparentElevationDetector and GroundMaskElevationDetector. - Fixes issue #144. + Fixes issue #144. Added a DetectorEventHandler interface aimed at handling only the @@ -4016,7 +4013,7 @@ IERS does not provide anymore data to link TIRF 2003 with ITRF, ITRF based on 2003 convention is not available. ITRF can only be based on either 2010 conventions for CIO-based paradigm or on 1996 conventions - for equinox-based paradigm. + for equinox-based paradigm. Atmosphere models now provide their central body frame. @@ -4068,7 +4065,7 @@ Streamlined the force models partial derivatives computation for numerical propagation. It is now far simpler to compute analytically the derivatives with respect to state and with respect to force models specific parameters, - thanks to the new Apache Commons Math differentiation framework. + thanks to the new Apache Commons Math differentiation framework. Added a new force model for central body gravity field, based on Holmes and Featherstone @@ -4153,7 +4150,7 @@ (fixes bug #116). - Make TidalCorrections class thread-safe by using the new TimeStampedCache. + Make TidalCorrections class thread-safe by using the new TimeStampedCache. (fixes bug #117). @@ -4230,7 +4227,7 @@ Removed too stringent test on trajectory in TLE propagator (fixes bug #86). - + Set the initial state for a TLEPropagator (fixes bug #85). From 39e121527512c1032f718fdc170cba7230f79394 Mon Sep 17 00:00:00 2001 From: Bryan Cazabonne Date: Sat, 30 Dec 2023 12:35:09 +0100 Subject: [PATCH 067/359] Ant support is not yet removed, so dependencies shall be upgraded in build.xml too. --- build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.xml b/build.xml index 458a80cd39..35ff750107 100644 --- a/build.xml +++ b/build.xml @@ -17,7 +17,7 @@ - + From 4314309b071f9ab340b7740b1a7da4e46e003aa2 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Mon, 1 Jan 2024 09:46:59 +0100 Subject: [PATCH 068/359] Updated copyright years. --- NOTICE.txt | 2 +- build.xml | 2 +- src/changes/changes.xml | 2 +- src/design/attitude-class-diagram.puml | 2 +- src/design/available-propagators-class-diagram.puml | 2 +- src/design/bodyshape-class-diagram.puml | 2 +- src/design/ccsds-lexical-analysis-sequence-diagram.puml | 2 +- src/design/ccsds-lexical-class-diagram.puml | 2 +- src/design/ccsds-parsing-class-diagram.puml | 2 +- src/design/ccsds-structure-class-diagram.puml | 2 +- src/design/ccsds-writing-class-diagram.puml | 2 +- src/design/celestial-bodies-class-diagram.puml | 2 +- src/design/continuous-maneuver-class-diagram.puml | 2 +- src/design/custom-parser-class-diagram.puml | 2 +- src/design/data-context-class-diagram.puml | 2 +- src/design/data-filtering-class-diagram.puml | 2 +- src/design/data-filtering-sequence-diagram.puml | 2 +- src/design/data-loaders-data-providers-class-diagram.puml | 2 +- src/design/dsst-partial-derivatives-class-diagram.puml | 2 +- src/design/dsst-propagation-sequence-diagram.puml | 2 +- src/design/dsst-propagator-class-diagram.puml | 2 +- src/design/dsst-tesseral-contribution-class-diagram.puml | 2 +- src/design/dsst-third-body-class-diagram.puml | 2 +- src/design/dsst-zonal-contribution-class-diagram.puml | 2 +- src/design/ephemeris-generation-sequence-diagram.puml | 2 +- src/design/events-class-diagram.puml | 2 +- src/design/events-sequence-diagram.puml | 2 +- src/design/extended-semi-analytical-kalman-filter-diagram.puml | 2 +- src/design/field.puml | 2 +- src/design/frames-class-diagram.puml | 2 +- src/design/generic-ephemeris-writing-class-diagram.puml | 2 +- src/design/gnss-antenna-class-diagram.puml | 2 +- src/design/gnss-rinex-class-diagram.puml | 2 +- src/design/kalman-overview-class-diagram.puml | 2 +- src/design/maneuver-triggers-class-diagram.puml | 2 +- src/design/measurements-generation-class-diagram.puml | 2 +- src/design/metric-ntrip-class-diagram.puml | 2 +- src/design/metric-parser-class-diagram.puml | 2 +- src/design/numerical-propagation-sequence-diagram.puml | 2 +- src/design/orbit-determination-measurements-class-diagram.puml | 2 +- src/design/orbit-determination-overview-class-diagram.puml | 2 +- src/design/orbit-determination-parameters-class-diagram.puml | 2 +- src/design/orbits-class-diagram.puml | 2 +- src/design/partial-derivatives-class-diagram.puml | 2 +- src/design/propagation-class-diagram.puml | 2 +- src/design/propagator-conversion-class-diagram.puml | 2 +- src/design/propulsion-class-diagram.puml | 2 +- src/design/sampling-class-diagram.puml | 2 +- src/design/small-maneuver-class-diagram.puml | 2 +- src/design/small-maneuver-sequence-diagram.puml | 2 +- src/design/tessellation-class-diagram.puml | 2 +- src/design/time-class-diagram.puml | 2 +- src/design/top-packages.puml | 2 +- src/design/unscented-kalman-filter-diagram.puml | 2 +- src/design/unscented-semi-analytical-kalman-filter-diagram.puml | 2 +- src/design/utils-class-diagram.puml | 2 +- src/design/with-step-handlers-sequence-diagram.puml | 2 +- src/design/without-step-handlers-sequence-diagram.puml | 2 +- src/main/java/org/orekit/annotation/package-info.java | 2 +- .../org/orekit/attitudes/AggregateBoundedAttitudeProvider.java | 2 +- src/main/java/org/orekit/attitudes/Attitude.java | 2 +- src/main/java/org/orekit/attitudes/AttitudeBuilder.java | 2 +- src/main/java/org/orekit/attitudes/AttitudeInterpolator.java | 2 +- src/main/java/org/orekit/attitudes/AttitudeProvider.java | 2 +- .../java/org/orekit/attitudes/AttitudeProviderModifier.java | 2 +- src/main/java/org/orekit/attitudes/AttitudesSequence.java | 2 +- src/main/java/org/orekit/attitudes/BodyCenterPointing.java | 2 +- src/main/java/org/orekit/attitudes/BoundedAttitudeProvider.java | 2 +- src/main/java/org/orekit/attitudes/CelestialBodyPointed.java | 2 +- src/main/java/org/orekit/attitudes/FieldAttitude.java | 2 +- .../java/org/orekit/attitudes/FieldAttitudeInterpolator.java | 2 +- src/main/java/org/orekit/attitudes/FieldInertia.java | 2 +- src/main/java/org/orekit/attitudes/FieldInertiaAxis.java | 2 +- src/main/java/org/orekit/attitudes/FixedFrameBuilder.java | 2 +- src/main/java/org/orekit/attitudes/FixedRate.java | 2 +- src/main/java/org/orekit/attitudes/FrameAlignedProvider.java | 2 +- src/main/java/org/orekit/attitudes/GroundPointing.java | 2 +- src/main/java/org/orekit/attitudes/Inertia.java | 2 +- src/main/java/org/orekit/attitudes/InertiaAxis.java | 2 +- src/main/java/org/orekit/attitudes/LofOffset.java | 2 +- src/main/java/org/orekit/attitudes/LofOffsetPointing.java | 2 +- src/main/java/org/orekit/attitudes/NadirPointing.java | 2 +- src/main/java/org/orekit/attitudes/SpinStabilized.java | 2 +- src/main/java/org/orekit/attitudes/TabulatedLofOffset.java | 2 +- src/main/java/org/orekit/attitudes/TabulatedProvider.java | 2 +- src/main/java/org/orekit/attitudes/TargetPointing.java | 2 +- src/main/java/org/orekit/attitudes/TorqueFree.java | 2 +- src/main/java/org/orekit/attitudes/YawCompensation.java | 2 +- src/main/java/org/orekit/attitudes/YawSteering.java | 2 +- src/main/java/org/orekit/attitudes/package-info.java | 2 +- src/main/java/org/orekit/bodies/BodyShape.java | 2 +- src/main/java/org/orekit/bodies/CR3BPFactory.java | 2 +- src/main/java/org/orekit/bodies/CR3BPSystem.java | 2 +- src/main/java/org/orekit/bodies/CelestialBody.java | 2 +- src/main/java/org/orekit/bodies/CelestialBodyFactory.java | 2 +- src/main/java/org/orekit/bodies/CelestialBodyLoader.java | 2 +- src/main/java/org/orekit/bodies/Ellipse.java | 2 +- src/main/java/org/orekit/bodies/Ellipsoid.java | 2 +- src/main/java/org/orekit/bodies/FieldEllipse.java | 2 +- src/main/java/org/orekit/bodies/FieldGeodeticPoint.java | 2 +- src/main/java/org/orekit/bodies/GeodeticPoint.java | 2 +- src/main/java/org/orekit/bodies/IAUPole.java | 2 +- src/main/java/org/orekit/bodies/JPLCelestialBody.java | 2 +- src/main/java/org/orekit/bodies/JPLEphemeridesLoader.java | 2 +- src/main/java/org/orekit/bodies/OneAxisEllipsoid.java | 2 +- src/main/java/org/orekit/bodies/PosVelChebyshev.java | 2 +- src/main/java/org/orekit/bodies/PredefinedIAUPoles.java | 2 +- src/main/java/org/orekit/bodies/package-info.java | 2 +- src/main/java/org/orekit/compiler/plugin/package-info.java | 2 +- src/main/java/org/orekit/data/AbstractListCrawler.java | 2 +- src/main/java/org/orekit/data/BodiesElements.java | 2 +- src/main/java/org/orekit/data/ClasspathCrawler.java | 2 +- src/main/java/org/orekit/data/DataFilter.java | 2 +- src/main/java/org/orekit/data/DataLoader.java | 2 +- src/main/java/org/orekit/data/DataProvider.java | 2 +- src/main/java/org/orekit/data/DataProvidersManager.java | 2 +- src/main/java/org/orekit/data/DataSource.java | 2 +- src/main/java/org/orekit/data/DelaunayArguments.java | 2 +- src/main/java/org/orekit/data/DirectoryCrawler.java | 2 +- src/main/java/org/orekit/data/FieldBodiesElements.java | 2 +- src/main/java/org/orekit/data/FieldDelaunayArguments.java | 2 +- src/main/java/org/orekit/data/FilesListCrawler.java | 2 +- src/main/java/org/orekit/data/FiltersManager.java | 2 +- src/main/java/org/orekit/data/FundamentalNutationArguments.java | 2 +- src/main/java/org/orekit/data/GeneralTerm.java | 2 +- src/main/java/org/orekit/data/GzipFilter.java | 2 +- src/main/java/org/orekit/data/LuniSolarTerm.java | 2 +- src/main/java/org/orekit/data/NetworkCrawler.java | 2 +- src/main/java/org/orekit/data/NoFarPlanetsTerm.java | 2 +- src/main/java/org/orekit/data/NutationCodec.java | 2 +- src/main/java/org/orekit/data/PlanetaryTerm.java | 2 +- src/main/java/org/orekit/data/PoissonSeries.java | 2 +- src/main/java/org/orekit/data/PoissonSeriesParser.java | 2 +- src/main/java/org/orekit/data/PolynomialNutation.java | 2 +- src/main/java/org/orekit/data/PolynomialParser.java | 2 +- src/main/java/org/orekit/data/SeriesTerm.java | 2 +- src/main/java/org/orekit/data/SimpleTimeStampedTableParser.java | 2 +- src/main/java/org/orekit/data/TideTerm.java | 2 +- src/main/java/org/orekit/data/TruncatingFilter.java | 2 +- src/main/java/org/orekit/data/UnixCompressFilter.java | 2 +- src/main/java/org/orekit/data/ZipJarCrawler.java | 2 +- src/main/java/org/orekit/data/package-info.java | 2 +- src/main/java/org/orekit/errors/FrameAncestorException.java | 2 +- src/main/java/org/orekit/errors/LocalizedException.java | 2 +- src/main/java/org/orekit/errors/OrekitException.java | 2 +- src/main/java/org/orekit/errors/OrekitIOException.java | 2 +- .../java/org/orekit/errors/OrekitIllegalArgumentException.java | 2 +- .../java/org/orekit/errors/OrekitIllegalStateException.java | 2 +- src/main/java/org/orekit/errors/OrekitInternalError.java | 2 +- src/main/java/org/orekit/errors/OrekitMessages.java | 2 +- src/main/java/org/orekit/errors/OrekitParseException.java | 2 +- src/main/java/org/orekit/errors/TimeStampedCacheException.java | 2 +- .../java/org/orekit/errors/UnsupportedParameterException.java | 2 +- src/main/java/org/orekit/errors/package-info.java | 2 +- src/main/java/org/orekit/estimation/iod/IodGauss.java | 2 +- src/main/java/org/orekit/estimation/iod/IodGibbs.java | 2 +- src/main/java/org/orekit/estimation/iod/IodGooding.java | 2 +- src/main/java/org/orekit/estimation/iod/IodLambert.java | 2 +- src/main/java/org/orekit/estimation/iod/IodLaplace.java | 2 +- src/main/java/org/orekit/estimation/iod/package-info.java | 2 +- .../orekit/estimation/leastsquares/AbstractBatchLSModel.java | 2 +- .../org/orekit/estimation/leastsquares/BatchLSEstimator.java | 2 +- .../java/org/orekit/estimation/leastsquares/BatchLSModel.java | 2 +- .../org/orekit/estimation/leastsquares/BatchLSObserver.java | 2 +- .../org/orekit/estimation/leastsquares/DSSTBatchLSModel.java | 2 +- .../org/orekit/estimation/leastsquares/MeasurementHandler.java | 2 +- .../java/org/orekit/estimation/leastsquares/ModelObserver.java | 2 +- .../org/orekit/estimation/leastsquares/PreCompensation.java | 2 +- .../estimation/leastsquares/SequentialBatchLSEstimator.java | 2 +- .../java/org/orekit/estimation/leastsquares/package-info.java | 2 +- .../org/orekit/estimation/measurements/AbstractMeasurement.java | 2 +- .../java/org/orekit/estimation/measurements/AngularAzEl.java | 2 +- .../java/org/orekit/estimation/measurements/AngularRaDec.java | 2 +- .../java/org/orekit/estimation/measurements/BistaticRange.java | 2 +- .../org/orekit/estimation/measurements/BistaticRangeRate.java | 2 +- .../orekit/estimation/measurements/ComparableMeasurement.java | 2 +- .../estimation/measurements/EstimatedEarthFrameProvider.java | 2 +- .../orekit/estimation/measurements/EstimatedMeasurement.java | 2 +- .../estimation/measurements/EstimatedMeasurementBase.java | 2 +- .../org/orekit/estimation/measurements/EstimationModifier.java | 2 +- .../org/orekit/estimation/measurements/EstimationsProvider.java | 2 +- src/main/java/org/orekit/estimation/measurements/FDOA.java | 2 +- .../GroundReceiverCommonParametersWithDerivatives.java | 2 +- .../GroundReceiverCommonParametersWithoutDerivatives.java | 2 +- .../estimation/measurements/GroundReceiverMeasurement.java | 2 +- .../java/org/orekit/estimation/measurements/GroundStation.java | 2 +- .../orekit/estimation/measurements/InterSatellitesRange.java | 2 +- .../orekit/estimation/measurements/MultiplexedMeasurement.java | 2 +- .../org/orekit/estimation/measurements/ObservableSatellite.java | 2 +- .../org/orekit/estimation/measurements/ObservedMeasurement.java | 2 +- src/main/java/org/orekit/estimation/measurements/PV.java | 2 +- src/main/java/org/orekit/estimation/measurements/Position.java | 2 +- src/main/java/org/orekit/estimation/measurements/Range.java | 2 +- src/main/java/org/orekit/estimation/measurements/RangeRate.java | 2 +- src/main/java/org/orekit/estimation/measurements/TDOA.java | 2 +- .../org/orekit/estimation/measurements/TurnAroundRange.java | 2 +- .../measurements/filtering/DualFrequencyHatchFilter.java | 2 +- .../measurements/filtering/DualFrequencySmoother.java | 2 +- .../estimation/measurements/filtering/ElevationFilter.java | 2 +- .../orekit/estimation/measurements/filtering/HatchFilter.java | 2 +- .../estimation/measurements/filtering/MeasurementFilter.java | 2 +- .../estimation/measurements/filtering/ResidualFilter.java | 2 +- .../measurements/filtering/SingleFrequencyHatchFilter.java | 2 +- .../measurements/filtering/SingleFrequencySmoother.java | 2 +- .../measurements/filtering/SmoothedObservationDataSet.java | 2 +- .../orekit/estimation/measurements/filtering/package-info.java | 2 +- .../measurements/generation/AbstractMeasurementBuilder.java | 2 +- .../estimation/measurements/generation/AbstractScheduler.java | 2 +- .../estimation/measurements/generation/AngularAzElBuilder.java | 2 +- .../estimation/measurements/generation/AngularRaDecBuilder.java | 2 +- .../measurements/generation/BistaticRangeBuilder.java | 2 +- .../measurements/generation/BistaticRangeRateBuilder.java | 2 +- .../estimation/measurements/generation/ContinuousScheduler.java | 2 +- .../estimation/measurements/generation/EventBasedScheduler.java | 2 +- .../orekit/estimation/measurements/generation/FDOABuilder.java | 2 +- .../estimation/measurements/generation/GatheringSubscriber.java | 2 +- .../measurements/generation/GeneratedMeasurementSubscriber.java | 2 +- .../orekit/estimation/measurements/generation/Generator.java | 2 +- .../measurements/generation/InterSatellitesPhaseBuilder.java | 2 +- .../measurements/generation/InterSatellitesRangeBuilder.java | 2 +- .../estimation/measurements/generation/MeasurementBuilder.java | 2 +- .../measurements/generation/MultiplexedMeasurementBuilder.java | 2 +- .../measurements/generation/OneWayGNSSPhaseBuilder.java | 2 +- .../measurements/generation/OneWayGNSSRangeBuilder.java | 2 +- .../orekit/estimation/measurements/generation/PVBuilder.java | 2 +- .../estimation/measurements/generation/PositionBuilder.java | 2 +- .../orekit/estimation/measurements/generation/RangeBuilder.java | 2 +- .../estimation/measurements/generation/RangeRateBuilder.java | 2 +- .../orekit/estimation/measurements/generation/Scheduler.java | 2 +- .../orekit/estimation/measurements/generation/SignSemantic.java | 2 +- .../orekit/estimation/measurements/generation/TDOABuilder.java | 2 +- .../measurements/generation/TurnAroundRangeBuilder.java | 2 +- .../orekit/estimation/measurements/generation/package-info.java | 2 +- .../estimation/measurements/gnss/AbstractCycleSlipDetector.java | 2 +- .../measurements/gnss/AbstractDualFrequencyCombination.java | 2 +- .../estimation/measurements/gnss/AbstractLambdaMethod.java | 2 +- .../measurements/gnss/AbstractSingleFrequencyCombination.java | 2 +- .../org/orekit/estimation/measurements/gnss/AbstractWindUp.java | 2 +- .../orekit/estimation/measurements/gnss/AlternatingSampler.java | 2 +- .../estimation/measurements/gnss/AmbiguityAcceptance.java | 2 +- .../orekit/estimation/measurements/gnss/AmbiguitySolver.java | 2 +- .../orekit/estimation/measurements/gnss/CombinationType.java | 2 +- .../estimation/measurements/gnss/CombinedObservationData.java | 2 +- .../measurements/gnss/CombinedObservationDataSet.java | 2 +- .../estimation/measurements/gnss/CycleSlipDetectorResults.java | 2 +- .../orekit/estimation/measurements/gnss/CycleSlipDetectors.java | 2 +- .../java/org/orekit/estimation/measurements/gnss/Dipole.java | 2 +- .../orekit/estimation/measurements/gnss/GRAPHICCombination.java | 2 +- .../estimation/measurements/gnss/GeometryFreeCombination.java | 2 +- .../measurements/gnss/GeometryFreeCycleSlipDetector.java | 2 +- .../estimation/measurements/gnss/IntegerBootstrapping.java | 2 +- .../measurements/gnss/IntegerLeastSquareComparator.java | 2 +- .../measurements/gnss/IntegerLeastSquareSolution.java | 2 +- .../estimation/measurements/gnss/IntegerLeastSquareSolver.java | 2 +- .../estimation/measurements/gnss/InterSatellitesPhase.java | 2 +- .../estimation/measurements/gnss/InterSatellitesWindUp.java | 2 +- .../measurements/gnss/InterSatellitesWindUpFactory.java | 2 +- .../estimation/measurements/gnss/IonosphereFreeCombination.java | 2 +- .../org/orekit/estimation/measurements/gnss/LambdaMethod.java | 2 +- .../estimation/measurements/gnss/MeasurementCombination.java | 2 +- .../measurements/gnss/MeasurementCombinationFactory.java | 2 +- .../measurements/gnss/MelbourneWubbenaCombination.java | 2 +- .../estimation/measurements/gnss/ModifiedLambdaMethod.java | 2 +- .../estimation/measurements/gnss/NarrowLaneCombination.java | 2 +- .../orekit/estimation/measurements/gnss/OneWayGNSSPhase.java | 2 +- .../orekit/estimation/measurements/gnss/OneWayGNSSRange.java | 2 +- .../java/org/orekit/estimation/measurements/gnss/Phase.java | 2 +- .../org/orekit/estimation/measurements/gnss/PhaseBuilder.java | 2 +- .../estimation/measurements/gnss/PhaseMinusCodeCombination.java | 2 +- .../measurements/gnss/PhaseMinusCodeCycleSlipDetector.java | 2 +- .../measurements/gnss/SimpleRatioAmbiguityAcceptance.java | 2 +- .../estimation/measurements/gnss/WideLaneCombination.java | 2 +- .../java/org/orekit/estimation/measurements/gnss/WindUp.java | 2 +- .../org/orekit/estimation/measurements/gnss/WindUpFactory.java | 2 +- .../org/orekit/estimation/measurements/gnss/package-info.java | 2 +- .../estimation/measurements/modifiers/AberrationModifier.java | 2 +- .../measurements/modifiers/AbstractAmbiguityModifier.java | 2 +- .../modifiers/AbstractRelativisticClockModifier.java | 2 +- .../modifiers/AbstractRelativisticJ2ClockModifier.java | 2 +- .../measurements/modifiers/AbstractShapiroBaseModifier.java | 2 +- .../measurements/modifiers/AngularIonosphericDelayModifier.java | 2 +- .../measurements/modifiers/AngularRadioRefractionModifier.java | 2 +- .../modifiers/AngularTroposphericDelayModifier.java | 2 +- .../modifiers/BaseRangeIonosphericDelayModifier.java | 2 +- .../modifiers/BaseRangeRateIonosphericDelayModifier.java | 2 +- .../modifiers/BaseRangeRateTroposphericDelayModifier.java | 2 +- .../modifiers/BaseRangeTroposphericDelayModifier.java | 2 +- .../java/org/orekit/estimation/measurements/modifiers/Bias.java | 2 +- .../estimation/measurements/modifiers/BistaticModifierUtil.java | 2 +- .../modifiers/BistaticRangeIonosphericDelayModifier.java | 2 +- .../modifiers/BistaticRangeRateIonosphericDelayModifier.java | 2 +- .../modifiers/BistaticRangeRateTroposphericDelayModifier.java | 2 +- .../modifiers/BistaticRangeTroposphericDelayModifier.java | 2 +- .../estimation/measurements/modifiers/DynamicOutlierFilter.java | 2 +- .../modifiers/InterSatellitesPhaseAmbiguityModifier.java | 2 +- .../measurements/modifiers/ModifierGradientConverter.java | 2 +- .../modifiers/OnBoardAntennaInterSatellitesPhaseModifier.java | 2 +- .../modifiers/OnBoardAntennaInterSatellitesRangeModifier.java | 2 +- .../modifiers/OnBoardAntennaOneWayGNSSPhaseModifier.java | 2 +- .../modifiers/OnBoardAntennaOneWayGNSSRangeModifier.java | 2 +- .../modifiers/OnBoardAntennaTurnAroundRangeModifier.java | 2 +- .../modifiers/OneWayGNSSPhaseAmbiguityModifier.java | 2 +- .../orekit/estimation/measurements/modifiers/OutlierFilter.java | 2 +- .../measurements/modifiers/ParametricModelEffect.java | 2 +- .../measurements/modifiers/ParametricModelEffectGradient.java | 2 +- .../measurements/modifiers/PhaseAmbiguityModifier.java | 2 +- .../modifiers/PhaseCentersGroundReceiverBaseModifier.java | 2 +- .../measurements/modifiers/PhaseCentersOffsetComputer.java | 2 +- .../measurements/modifiers/PhaseCentersPhaseModifier.java | 2 +- .../measurements/modifiers/PhaseCentersRangeModifier.java | 2 +- .../measurements/modifiers/PhaseIonosphericDelayModifier.java | 2 +- .../measurements/modifiers/PhaseTroposphericDelayModifier.java | 2 +- .../measurements/modifiers/RangeIonosphericDelayModifier.java | 2 +- .../estimation/measurements/modifiers/RangeModifierUtil.java | 2 +- .../modifiers/RangeRateIonosphericDelayModifier.java | 2 +- .../measurements/modifiers/RangeRateModifierUtil.java | 2 +- .../modifiers/RangeRateTroposphericDelayModifier.java | 2 +- .../measurements/modifiers/RangeTroposphericDelayModifier.java | 2 +- .../RelativisticClockInterSatellitesPhaseModifier.java | 2 +- .../RelativisticClockInterSatellitesRangeModifier.java | 2 +- .../modifiers/RelativisticClockOneWayGNSSPhaseModifier.java | 2 +- .../modifiers/RelativisticClockOneWayGNSSRangeModifier.java | 2 +- .../measurements/modifiers/RelativisticClockPhaseModifier.java | 2 +- .../measurements/modifiers/RelativisticClockRangeModifier.java | 2 +- .../modifiers/RelativisticClockRangeRateModifier.java | 2 +- .../RelativisticJ2ClockInterSatellitesPhaseModifier.java | 2 +- .../RelativisticJ2ClockInterSatellitesRangeModifier.java | 2 +- .../modifiers/RelativisticJ2ClockOneWayGNSSPhaseModifier.java | 2 +- .../modifiers/RelativisticJ2ClockOneWayGNSSRangeModifier.java | 2 +- .../modifiers/RelativisticJ2ClockPhaseModifier.java | 2 +- .../modifiers/RelativisticJ2ClockRangeModifier.java | 2 +- .../modifiers/ShapiroInterSatellitePhaseModifier.java | 2 +- .../modifiers/ShapiroInterSatelliteRangeModifier.java | 2 +- .../measurements/modifiers/ShapiroOneWayGNSSPhaseModifier.java | 2 +- .../measurements/modifiers/ShapiroOneWayGNSSRangeModifier.java | 2 +- .../estimation/measurements/modifiers/ShapiroPhaseModifier.java | 2 +- .../estimation/measurements/modifiers/ShapiroRangeModifier.java | 2 +- .../measurements/modifiers/TDOAIonosphericDelayModifier.java | 2 +- .../estimation/measurements/modifiers/TDOAModifierUtil.java | 2 +- .../measurements/modifiers/TDOATroposphericDelayModifier.java | 2 +- .../modifiers/TurnAroundRangeIonosphericDelayModifier.java | 2 +- .../modifiers/TurnAroundRangeTroposphericDelayModifier.java | 2 +- .../orekit/estimation/measurements/modifiers/package-info.java | 2 +- .../java/org/orekit/estimation/measurements/package-info.java | 2 +- src/main/java/org/orekit/estimation/package-info.java | 2 +- .../estimation/sequential/AbstractCovarianceMatrixProvider.java | 2 +- .../orekit/estimation/sequential/AbstractKalmanEstimator.java | 2 +- .../org/orekit/estimation/sequential/ConstantProcessNoise.java | 2 +- .../orekit/estimation/sequential/CovarianceMatrixProvider.java | 2 +- .../java/org/orekit/estimation/sequential/KalmanEstimation.java | 2 +- .../java/org/orekit/estimation/sequential/KalmanEstimator.java | 2 +- .../orekit/estimation/sequential/KalmanEstimatorBuilder.java | 2 +- .../org/orekit/estimation/sequential/KalmanEstimatorUtil.java | 2 +- src/main/java/org/orekit/estimation/sequential/KalmanModel.java | 2 +- .../java/org/orekit/estimation/sequential/KalmanObserver.java | 2 +- .../org/orekit/estimation/sequential/MeasurementDecorator.java | 2 +- .../estimation/sequential/SemiAnalyticalKalmanEstimator.java | 2 +- .../sequential/SemiAnalyticalKalmanEstimatorBuilder.java | 2 +- .../orekit/estimation/sequential/SemiAnalyticalKalmanModel.java | 2 +- .../estimation/sequential/SemiAnalyticalMeasurementHandler.java | 2 +- .../org/orekit/estimation/sequential/SemiAnalyticalProcess.java | 2 +- .../sequential/SemiAnalyticalUnscentedKalmanEstimator.java | 2 +- .../SemiAnalyticalUnscentedKalmanEstimatorBuilder.java | 2 +- .../sequential/SemiAnalyticalUnscentedKalmanModel.java | 2 +- .../orekit/estimation/sequential/UnivariateProcessNoise.java | 2 +- .../orekit/estimation/sequential/UnscentedKalmanEstimator.java | 2 +- .../estimation/sequential/UnscentedKalmanEstimatorBuilder.java | 2 +- .../org/orekit/estimation/sequential/UnscentedKalmanModel.java | 2 +- .../java/org/orekit/estimation/sequential/package-info.java | 2 +- .../java/org/orekit/files/ccsds/definitions/AdMethodType.java | 2 +- .../java/org/orekit/files/ccsds/definitions/BodyFacade.java | 2 +- .../org/orekit/files/ccsds/definitions/CelestialBodyFrame.java | 2 +- .../java/org/orekit/files/ccsds/definitions/CenterName.java | 2 +- .../java/org/orekit/files/ccsds/definitions/DutyCycleType.java | 2 +- .../java/org/orekit/files/ccsds/definitions/FrameFacade.java | 2 +- .../java/org/orekit/files/ccsds/definitions/OdMethodFacade.java | 2 +- .../java/org/orekit/files/ccsds/definitions/OdMethodType.java | 2 +- src/main/java/org/orekit/files/ccsds/definitions/OnOff.java | 2 +- .../org/orekit/files/ccsds/definitions/OrbitRelativeFrame.java | 2 +- .../org/orekit/files/ccsds/definitions/PocMethodFacade.java | 2 +- .../java/org/orekit/files/ccsds/definitions/PocMethodType.java | 2 +- .../org/orekit/files/ccsds/definitions/SpacecraftBodyFrame.java | 2 +- .../java/org/orekit/files/ccsds/definitions/TimeConverter.java | 2 +- src/main/java/org/orekit/files/ccsds/definitions/Units.java | 2 +- .../java/org/orekit/files/ccsds/definitions/YesNoUnknown.java | 2 +- .../java/org/orekit/files/ccsds/definitions/package-info.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/AbstractBuilder.java | 2 +- .../org/orekit/files/ccsds/ndm/CommonPhysicalProperties.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/Ndm.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/NdmConstituent.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/NdmParser.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/NdmStructureKey.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/NdmWriter.java | 2 +- .../java/org/orekit/files/ccsds/ndm/ParsedUnitsBehavior.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/ParserBuilder.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/WriterBuilder.java | 2 +- .../org/orekit/files/ccsds/ndm/adm/AdmCommonMetadataKey.java | 2 +- .../org/orekit/files/ccsds/ndm/adm/AdmCommonMetadataWriter.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/adm/AdmHeader.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/adm/AdmMetadata.java | 2 +- .../java/org/orekit/files/ccsds/ndm/adm/AdmMetadataKey.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/adm/AdmParser.java | 2 +- .../java/org/orekit/files/ccsds/ndm/adm/AttitudeEndpoints.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/adm/AttitudeType.java | 2 +- .../java/org/orekit/files/ccsds/ndm/adm/PrecessionFinder.java | 2 +- .../org/orekit/files/ccsds/ndm/adm/RotationXmlTokenBuilder.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/adm/SpinFinder.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/adm/acm/Acm.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/adm/acm/AcmData.java | 2 +- .../orekit/files/ccsds/ndm/adm/acm/AcmDataSubStructureKey.java | 2 +- .../java/org/orekit/files/ccsds/ndm/adm/acm/AcmElements.java | 2 +- .../java/org/orekit/files/ccsds/ndm/adm/acm/AcmMetadata.java | 2 +- .../java/org/orekit/files/ccsds/ndm/adm/acm/AcmMetadataKey.java | 2 +- .../org/orekit/files/ccsds/ndm/adm/acm/AcmMetadataWriter.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/adm/acm/AcmParser.java | 2 +- .../orekit/files/ccsds/ndm/adm/acm/AcmSatelliteEphemeris.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/adm/acm/AcmWriter.java | 2 +- .../org/orekit/files/ccsds/ndm/adm/acm/AttitudeCovariance.java | 2 +- .../files/ccsds/ndm/adm/acm/AttitudeCovarianceHistory.java | 2 +- .../ccsds/ndm/adm/acm/AttitudeCovarianceHistoryMetadata.java | 2 +- .../ccsds/ndm/adm/acm/AttitudeCovarianceHistoryMetadataKey.java | 2 +- .../ccsds/ndm/adm/acm/AttitudeCovarianceHistoryWriter.java | 2 +- .../orekit/files/ccsds/ndm/adm/acm/AttitudeCovarianceType.java | 2 +- .../orekit/files/ccsds/ndm/adm/acm/AttitudeDetermination.java | 2 +- .../files/ccsds/ndm/adm/acm/AttitudeDeterminationKey.java | 2 +- .../files/ccsds/ndm/adm/acm/AttitudeDeterminationSensor.java | 2 +- .../files/ccsds/ndm/adm/acm/AttitudeDeterminationSensorKey.java | 2 +- .../files/ccsds/ndm/adm/acm/AttitudeDeterminationWriter.java | 2 +- .../orekit/files/ccsds/ndm/adm/acm/AttitudeElementsType.java | 2 +- .../org/orekit/files/ccsds/ndm/adm/acm/AttitudeManeuver.java | 2 +- .../org/orekit/files/ccsds/ndm/adm/acm/AttitudeManeuverKey.java | 2 +- .../orekit/files/ccsds/ndm/adm/acm/AttitudeManeuverWriter.java | 2 +- .../files/ccsds/ndm/adm/acm/AttitudePhysicalProperties.java | 2 +- .../files/ccsds/ndm/adm/acm/AttitudePhysicalPropertiesKey.java | 2 +- .../ccsds/ndm/adm/acm/AttitudePhysicalPropertiesWriter.java | 2 +- .../java/org/orekit/files/ccsds/ndm/adm/acm/AttitudeState.java | 2 +- .../orekit/files/ccsds/ndm/adm/acm/AttitudeStateHistory.java | 2 +- .../files/ccsds/ndm/adm/acm/AttitudeStateHistoryMetadata.java | 2 +- .../ccsds/ndm/adm/acm/AttitudeStateHistoryMetadataKey.java | 2 +- .../files/ccsds/ndm/adm/acm/AttitudeStateHistoryWriter.java | 2 +- .../org/orekit/files/ccsds/ndm/adm/acm/RateElementsType.java | 2 +- .../java/org/orekit/files/ccsds/ndm/adm/acm/package-info.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/adm/aem/Aem.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/adm/aem/AemData.java | 2 +- .../java/org/orekit/files/ccsds/ndm/adm/aem/AemMetadata.java | 2 +- .../java/org/orekit/files/ccsds/ndm/adm/aem/AemMetadataKey.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/adm/aem/AemParser.java | 2 +- .../orekit/files/ccsds/ndm/adm/aem/AemSatelliteEphemeris.java | 2 +- .../java/org/orekit/files/ccsds/ndm/adm/aem/AemSegment.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/adm/aem/AemWriter.java | 2 +- .../java/org/orekit/files/ccsds/ndm/adm/aem/AttitudeEntry.java | 2 +- .../org/orekit/files/ccsds/ndm/adm/aem/AttitudeEntryKey.java | 2 +- .../java/org/orekit/files/ccsds/ndm/adm/aem/AttitudeWriter.java | 2 +- .../org/orekit/files/ccsds/ndm/adm/aem/StreamingAemWriter.java | 2 +- .../org/orekit/files/ccsds/ndm/adm/aem/XmlSubStructureKey.java | 2 +- .../java/org/orekit/files/ccsds/ndm/adm/aem/package-info.java | 2 +- .../org/orekit/files/ccsds/ndm/adm/apm/AngularVelocity.java | 2 +- .../org/orekit/files/ccsds/ndm/adm/apm/AngularVelocityKey.java | 2 +- .../orekit/files/ccsds/ndm/adm/apm/AngularVelocityWriter.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/adm/apm/Apm.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/adm/apm/ApmData.java | 2 +- .../orekit/files/ccsds/ndm/adm/apm/ApmDataSubStructureKey.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/adm/apm/ApmParser.java | 2 +- .../java/org/orekit/files/ccsds/ndm/adm/apm/ApmQuaternion.java | 2 +- .../org/orekit/files/ccsds/ndm/adm/apm/ApmQuaternionKey.java | 2 +- .../org/orekit/files/ccsds/ndm/adm/apm/ApmQuaternionWriter.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/adm/apm/ApmWriter.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/adm/apm/Euler.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/adm/apm/EulerKey.java | 2 +- .../java/org/orekit/files/ccsds/ndm/adm/apm/EulerWriter.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/adm/apm/Inertia.java | 2 +- .../java/org/orekit/files/ccsds/ndm/adm/apm/InertiaKey.java | 2 +- .../java/org/orekit/files/ccsds/ndm/adm/apm/InertiaWriter.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/adm/apm/Maneuver.java | 2 +- .../java/org/orekit/files/ccsds/ndm/adm/apm/ManeuverKey.java | 2 +- .../java/org/orekit/files/ccsds/ndm/adm/apm/ManeuverWriter.java | 2 +- .../java/org/orekit/files/ccsds/ndm/adm/apm/SpinStabilized.java | 2 +- .../org/orekit/files/ccsds/ndm/adm/apm/SpinStabilizedKey.java | 2 +- .../orekit/files/ccsds/ndm/adm/apm/SpinStabilizedWriter.java | 2 +- .../java/org/orekit/files/ccsds/ndm/adm/apm/package-info.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/adm/package-info.java | 2 +- .../files/ccsds/ndm/cdm/AdditionalCovarianceMetadata.java | 2 +- .../files/ccsds/ndm/cdm/AdditionalCovarianceMetadataKey.java | 2 +- .../org/orekit/files/ccsds/ndm/cdm/AdditionalParameters.java | 2 +- .../org/orekit/files/ccsds/ndm/cdm/AdditionalParametersKey.java | 2 +- .../orekit/files/ccsds/ndm/cdm/AdditionalParametersWriter.java | 2 +- .../java/org/orekit/files/ccsds/ndm/cdm/AltCovarianceType.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/cdm/Cdm.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/cdm/CdmData.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/cdm/CdmHeader.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/cdm/CdmHeaderKey.java | 2 +- .../orekit/files/ccsds/ndm/cdm/CdmHeaderProcessingState.java | 2 +- .../java/org/orekit/files/ccsds/ndm/cdm/CdmMessageWriter.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/cdm/CdmMetadata.java | 2 +- .../java/org/orekit/files/ccsds/ndm/cdm/CdmMetadataKey.java | 2 +- .../java/org/orekit/files/ccsds/ndm/cdm/CdmMetadataWriter.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/cdm/CdmParser.java | 2 +- .../org/orekit/files/ccsds/ndm/cdm/CdmRelativeMetadata.java | 2 +- .../org/orekit/files/ccsds/ndm/cdm/CdmRelativeMetadataKey.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/cdm/CdmSegment.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/cdm/CdmWriter.java | 2 +- .../java/org/orekit/files/ccsds/ndm/cdm/CovarianceMethod.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/cdm/Maneuvrable.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/cdm/ODParameters.java | 2 +- .../java/org/orekit/files/ccsds/ndm/cdm/ODParametersKey.java | 2 +- .../java/org/orekit/files/ccsds/ndm/cdm/ODParametersWriter.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/cdm/RTNCovariance.java | 2 +- .../java/org/orekit/files/ccsds/ndm/cdm/RTNCovarianceKey.java | 2 +- .../org/orekit/files/ccsds/ndm/cdm/RTNCovarianceWriter.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/cdm/ScreenType.java | 2 +- .../java/org/orekit/files/ccsds/ndm/cdm/ScreenVolumeFrame.java | 2 +- .../java/org/orekit/files/ccsds/ndm/cdm/ScreenVolumeShape.java | 2 +- .../orekit/files/ccsds/ndm/cdm/SigmaEigenvectorsCovariance.java | 2 +- .../files/ccsds/ndm/cdm/SigmaEigenvectorsCovarianceKey.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/cdm/StateVector.java | 2 +- .../java/org/orekit/files/ccsds/ndm/cdm/StateVectorKey.java | 2 +- .../java/org/orekit/files/ccsds/ndm/cdm/StateVectorWriter.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/cdm/XYZCovariance.java | 2 +- .../java/org/orekit/files/ccsds/ndm/cdm/XYZCovarianceKey.java | 2 +- .../java/org/orekit/files/ccsds/ndm/cdm/XmlSubStructureKey.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/cdm/package-info.java | 2 +- .../org/orekit/files/ccsds/ndm/odm/CartesianCovariance.java | 2 +- .../org/orekit/files/ccsds/ndm/odm/CartesianCovarianceKey.java | 2 +- .../orekit/files/ccsds/ndm/odm/CartesianCovarianceWriter.java | 2 +- .../java/org/orekit/files/ccsds/ndm/odm/CommonMetadataKey.java | 2 +- .../org/orekit/files/ccsds/ndm/odm/CommonMetadataWriter.java | 2 +- .../java/org/orekit/files/ccsds/ndm/odm/KeplerianElements.java | 2 +- .../org/orekit/files/ccsds/ndm/odm/KeplerianElementsKey.java | 2 +- .../java/org/orekit/files/ccsds/ndm/odm/OdmCommonMetadata.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/odm/OdmHeader.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/odm/OdmMetadata.java | 2 +- .../java/org/orekit/files/ccsds/ndm/odm/OdmMetadataKey.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/odm/OdmParser.java | 2 +- .../org/orekit/files/ccsds/ndm/odm/SpacecraftParameters.java | 2 +- .../org/orekit/files/ccsds/ndm/odm/SpacecraftParametersKey.java | 2 +- .../orekit/files/ccsds/ndm/odm/SpacecraftParametersWriter.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/odm/StateVector.java | 2 +- .../java/org/orekit/files/ccsds/ndm/odm/StateVectorKey.java | 2 +- .../java/org/orekit/files/ccsds/ndm/odm/StateVectorWriter.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/odm/UserDefined.java | 2 +- .../java/org/orekit/files/ccsds/ndm/odm/UserDefinedWriter.java | 2 +- .../org/orekit/files/ccsds/ndm/odm/ocm/CovarianceIndexer.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/odm/ocm/ManBasis.java | 2 +- .../org/orekit/files/ccsds/ndm/odm/ocm/ManeuverFieldType.java | 2 +- .../java/org/orekit/files/ccsds/ndm/odm/ocm/ObjectType.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/odm/ocm/Ocm.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/odm/ocm/OcmData.java | 2 +- .../orekit/files/ccsds/ndm/odm/ocm/OcmDataSubStructureKey.java | 2 +- .../java/org/orekit/files/ccsds/ndm/odm/ocm/OcmElements.java | 2 +- .../java/org/orekit/files/ccsds/ndm/odm/ocm/OcmMetadata.java | 2 +- .../java/org/orekit/files/ccsds/ndm/odm/ocm/OcmMetadataKey.java | 2 +- .../org/orekit/files/ccsds/ndm/odm/ocm/OcmMetadataWriter.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/odm/ocm/OcmParser.java | 2 +- .../orekit/files/ccsds/ndm/odm/ocm/OcmSatelliteEphemeris.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/odm/ocm/OcmWriter.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/odm/ocm/OpsStatus.java | 2 +- .../java/org/orekit/files/ccsds/ndm/odm/ocm/OrbitCategory.java | 2 +- .../org/orekit/files/ccsds/ndm/odm/ocm/OrbitCovariance.java | 2 +- .../orekit/files/ccsds/ndm/odm/ocm/OrbitCovarianceHistory.java | 2 +- .../files/ccsds/ndm/odm/ocm/OrbitCovarianceHistoryMetadata.java | 2 +- .../ccsds/ndm/odm/ocm/OrbitCovarianceHistoryMetadataKey.java | 2 +- .../files/ccsds/ndm/odm/ocm/OrbitCovarianceHistoryWriter.java | 2 +- .../org/orekit/files/ccsds/ndm/odm/ocm/OrbitDetermination.java | 2 +- .../orekit/files/ccsds/ndm/odm/ocm/OrbitDeterminationKey.java | 2 +- .../files/ccsds/ndm/odm/ocm/OrbitDeterminationWriter.java | 2 +- .../org/orekit/files/ccsds/ndm/odm/ocm/OrbitElementsType.java | 2 +- .../java/org/orekit/files/ccsds/ndm/odm/ocm/OrbitManeuver.java | 2 +- .../orekit/files/ccsds/ndm/odm/ocm/OrbitManeuverHistory.java | 2 +- .../files/ccsds/ndm/odm/ocm/OrbitManeuverHistoryMetadata.java | 2 +- .../ccsds/ndm/odm/ocm/OrbitManeuverHistoryMetadataKey.java | 2 +- .../files/ccsds/ndm/odm/ocm/OrbitManeuverHistoryWriter.java | 2 +- .../orekit/files/ccsds/ndm/odm/ocm/OrbitPhysicalProperties.java | 2 +- .../files/ccsds/ndm/odm/ocm/OrbitPhysicalPropertiesKey.java | 2 +- .../files/ccsds/ndm/odm/ocm/OrbitPhysicalPropertiesWriter.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/odm/ocm/Ordering.java | 2 +- .../java/org/orekit/files/ccsds/ndm/odm/ocm/Perturbations.java | 2 +- .../org/orekit/files/ccsds/ndm/odm/ocm/PerturbationsKey.java | 2 +- .../org/orekit/files/ccsds/ndm/odm/ocm/PerturbationsWriter.java | 2 +- .../java/org/orekit/files/ccsds/ndm/odm/ocm/ShadowModel.java | 2 +- .../org/orekit/files/ccsds/ndm/odm/ocm/TrajectoryState.java | 2 +- .../orekit/files/ccsds/ndm/odm/ocm/TrajectoryStateHistory.java | 2 +- .../files/ccsds/ndm/odm/ocm/TrajectoryStateHistoryMetadata.java | 2 +- .../ccsds/ndm/odm/ocm/TrajectoryStateHistoryMetadataKey.java | 2 +- .../files/ccsds/ndm/odm/ocm/TrajectoryStateHistoryWriter.java | 2 +- .../java/org/orekit/files/ccsds/ndm/odm/ocm/package-info.java | 2 +- .../org/orekit/files/ccsds/ndm/odm/oem/InterpolationMethod.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/odm/oem/Oem.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/odm/oem/OemData.java | 2 +- .../orekit/files/ccsds/ndm/odm/oem/OemDataSubStructureKey.java | 2 +- .../java/org/orekit/files/ccsds/ndm/odm/oem/OemMetadata.java | 2 +- .../java/org/orekit/files/ccsds/ndm/odm/oem/OemMetadataKey.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/odm/oem/OemParser.java | 2 +- .../orekit/files/ccsds/ndm/odm/oem/OemSatelliteEphemeris.java | 2 +- .../java/org/orekit/files/ccsds/ndm/odm/oem/OemSegment.java | 2 +- .../java/org/orekit/files/ccsds/ndm/odm/oem/package-info.java | 2 +- .../files/ccsds/ndm/odm/omm/MeanKeplerianElementsWriter.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/odm/omm/Omm.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/odm/omm/OmmData.java | 2 +- .../java/org/orekit/files/ccsds/ndm/odm/omm/OmmMetadata.java | 2 +- .../java/org/orekit/files/ccsds/ndm/odm/omm/OmmMetadataKey.java | 2 +- .../org/orekit/files/ccsds/ndm/odm/omm/OmmMetadataWriter.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/odm/omm/OmmParser.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/odm/omm/OmmTle.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/odm/omm/OmmTleKey.java | 2 +- .../java/org/orekit/files/ccsds/ndm/odm/omm/OmmTleWriter.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/odm/omm/OmmWriter.java | 2 +- .../org/orekit/files/ccsds/ndm/odm/omm/XmlSubStructureKey.java | 2 +- .../java/org/orekit/files/ccsds/ndm/odm/omm/package-info.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/odm/opm/Maneuver.java | 2 +- .../java/org/orekit/files/ccsds/ndm/odm/opm/ManeuverKey.java | 2 +- .../java/org/orekit/files/ccsds/ndm/odm/opm/ManeuverWriter.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/odm/opm/Opm.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/odm/opm/OpmData.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/odm/opm/OpmParser.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/odm/opm/OpmWriter.java | 2 +- .../ccsds/ndm/odm/opm/OsculationgKeplerianElementsWriter.java | 2 +- .../org/orekit/files/ccsds/ndm/odm/opm/XmlSubStructureKey.java | 2 +- .../java/org/orekit/files/ccsds/ndm/odm/opm/package-info.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/odm/package-info.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/package-info.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/tdm/AngleType.java | 2 +- .../java/org/orekit/files/ccsds/ndm/tdm/CorrectionApplied.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/tdm/DataQuality.java | 2 +- .../java/org/orekit/files/ccsds/ndm/tdm/IdentityConverter.java | 2 +- .../org/orekit/files/ccsds/ndm/tdm/IntegrationReference.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/tdm/Observation.java | 2 +- .../java/org/orekit/files/ccsds/ndm/tdm/ObservationType.java | 2 +- .../java/org/orekit/files/ccsds/ndm/tdm/ObservationsBlock.java | 2 +- .../org/orekit/files/ccsds/ndm/tdm/ObservationsBlockWriter.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/tdm/RangeMode.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/tdm/RangeUnits.java | 2 +- .../org/orekit/files/ccsds/ndm/tdm/RangeUnitsConverter.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/tdm/Tdm.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/tdm/TdmDataKey.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/tdm/TdmHeader.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/tdm/TdmMetadata.java | 2 +- .../java/org/orekit/files/ccsds/ndm/tdm/TdmMetadataKey.java | 2 +- .../java/org/orekit/files/ccsds/ndm/tdm/TdmMetadataWriter.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/tdm/TdmParser.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/tdm/TdmWriter.java | 2 +- .../java/org/orekit/files/ccsds/ndm/tdm/TimetagReference.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/tdm/TrackingMode.java | 2 +- src/main/java/org/orekit/files/ccsds/ndm/tdm/package-info.java | 2 +- src/main/java/org/orekit/files/ccsds/package-info.java | 2 +- .../java/org/orekit/files/ccsds/section/AbstractWriter.java | 2 +- .../java/org/orekit/files/ccsds/section/CommentsContainer.java | 2 +- src/main/java/org/orekit/files/ccsds/section/Data.java | 2 +- src/main/java/org/orekit/files/ccsds/section/Header.java | 2 +- src/main/java/org/orekit/files/ccsds/section/HeaderKey.java | 2 +- .../org/orekit/files/ccsds/section/HeaderProcessingState.java | 2 +- .../java/org/orekit/files/ccsds/section/KvnStructureKey.java | 2 +- .../orekit/files/ccsds/section/KvnStructureProcessingState.java | 2 +- src/main/java/org/orekit/files/ccsds/section/Metadata.java | 2 +- src/main/java/org/orekit/files/ccsds/section/MetadataKey.java | 2 +- src/main/java/org/orekit/files/ccsds/section/Section.java | 2 +- src/main/java/org/orekit/files/ccsds/section/Segment.java | 2 +- .../java/org/orekit/files/ccsds/section/XmlStructureKey.java | 2 +- .../orekit/files/ccsds/section/XmlStructureProcessingState.java | 2 +- src/main/java/org/orekit/files/ccsds/section/package-info.java | 2 +- src/main/java/org/orekit/files/ccsds/utils/ContextBinding.java | 2 +- src/main/java/org/orekit/files/ccsds/utils/FileFormat.java | 2 +- .../orekit/files/ccsds/utils/generation/AbstractGenerator.java | 2 +- .../files/ccsds/utils/generation/AbstractMessageWriter.java | 2 +- .../java/org/orekit/files/ccsds/utils/generation/Generator.java | 2 +- .../org/orekit/files/ccsds/utils/generation/KvnGenerator.java | 2 +- .../org/orekit/files/ccsds/utils/generation/MessageWriter.java | 2 +- .../org/orekit/files/ccsds/utils/generation/XmlGenerator.java | 2 +- .../org/orekit/files/ccsds/utils/generation/package-info.java | 2 +- .../orekit/files/ccsds/utils/lexical/KvnLexicalAnalyzer.java | 2 +- .../org/orekit/files/ccsds/utils/lexical/LexicalAnalyzer.java | 2 +- .../files/ccsds/utils/lexical/LexicalAnalyzerSelector.java | 2 +- .../org/orekit/files/ccsds/utils/lexical/MessageParser.java | 2 +- .../ccsds/utils/lexical/MessageVersionXmlTokenBuilder.java | 2 +- .../java/org/orekit/files/ccsds/utils/lexical/ParseToken.java | 2 +- .../files/ccsds/utils/lexical/RegularXmlTokenBuilder.java | 2 +- .../java/org/orekit/files/ccsds/utils/lexical/TokenType.java | 2 +- .../files/ccsds/utils/lexical/UserDefinedXmlTokenBuilder.java | 2 +- .../orekit/files/ccsds/utils/lexical/XmlLexicalAnalyzer.java | 2 +- .../org/orekit/files/ccsds/utils/lexical/XmlTokenBuilder.java | 2 +- .../java/org/orekit/files/ccsds/utils/lexical/package-info.java | 2 +- src/main/java/org/orekit/files/ccsds/utils/package-info.java | 2 +- .../files/ccsds/utils/parsing/AbstractConstituentParser.java | 2 +- .../orekit/files/ccsds/utils/parsing/AbstractMessageParser.java | 2 +- .../java/org/orekit/files/ccsds/utils/parsing/ErrorState.java | 2 +- .../org/orekit/files/ccsds/utils/parsing/ProcessingState.java | 2 +- .../java/org/orekit/files/ccsds/utils/parsing/package-info.java | 2 +- .../org/orekit/files/general/OrekitAttitudeEphemerisFile.java | 2 +- src/main/java/org/orekit/files/general/package-info.java | 2 +- src/main/java/org/orekit/files/ilrs/CPF.java | 2 +- src/main/java/org/orekit/files/ilrs/CPFHeader.java | 2 +- src/main/java/org/orekit/files/ilrs/CPFParser.java | 2 +- src/main/java/org/orekit/files/ilrs/CPFWriter.java | 2 +- src/main/java/org/orekit/files/ilrs/CRD.java | 2 +- src/main/java/org/orekit/files/ilrs/CRDConfiguration.java | 2 +- src/main/java/org/orekit/files/ilrs/CRDHeader.java | 2 +- src/main/java/org/orekit/files/ilrs/CRDParser.java | 2 +- src/main/java/org/orekit/files/ilrs/ILRSHeader.java | 2 +- src/main/java/org/orekit/files/ilrs/StreamingCpfWriter.java | 2 +- src/main/java/org/orekit/files/ilrs/package-info.java | 2 +- src/main/java/org/orekit/files/package-info.java | 2 +- src/main/java/org/orekit/files/rinex/AppliedDCBS.java | 2 +- src/main/java/org/orekit/files/rinex/AppliedPCVS.java | 2 +- .../java/org/orekit/files/rinex/HatanakaCompressFilter.java | 2 +- src/main/java/org/orekit/files/rinex/RinexFile.java | 2 +- src/main/java/org/orekit/files/rinex/clock/RinexClock.java | 2 +- .../java/org/orekit/files/rinex/clock/RinexClockParser.java | 2 +- src/main/java/org/orekit/files/rinex/clock/package-info.java | 2 +- .../rinex/navigation/EarthOrientationParameterMessage.java | 2 +- .../orekit/files/rinex/navigation/IonosphereBDGIMMessage.java | 2 +- .../orekit/files/rinex/navigation/IonosphereBaseMessage.java | 2 +- .../files/rinex/navigation/IonosphereKlobucharMessage.java | 2 +- .../files/rinex/navigation/IonosphereNequickGMessage.java | 2 +- .../files/rinex/navigation/IonosphericCorrectionType.java | 2 +- src/main/java/org/orekit/files/rinex/navigation/RegionCode.java | 2 +- .../java/org/orekit/files/rinex/navigation/RinexNavigation.java | 2 +- .../orekit/files/rinex/navigation/RinexNavigationHeader.java | 2 +- .../orekit/files/rinex/navigation/RinexNavigationParser.java | 2 +- src/main/java/org/orekit/files/rinex/navigation/SbasId.java | 2 +- .../orekit/files/rinex/navigation/SystemTimeOffsetMessage.java | 2 +- .../org/orekit/files/rinex/navigation/TimeSystemCorrection.java | 2 +- .../java/org/orekit/files/rinex/navigation/TypeSvMessage.java | 2 +- src/main/java/org/orekit/files/rinex/navigation/UtcId.java | 2 +- .../java/org/orekit/files/rinex/navigation/package-info.java | 2 +- .../orekit/files/rinex/observation/GlonassSatelliteChannel.java | 2 +- .../org/orekit/files/rinex/observation/ObservationData.java | 2 +- .../org/orekit/files/rinex/observation/ObservationDataSet.java | 2 +- .../orekit/files/rinex/observation/PhaseShiftCorrection.java | 2 +- .../org/orekit/files/rinex/observation/RinexObservation.java | 2 +- .../orekit/files/rinex/observation/RinexObservationHeader.java | 2 +- .../orekit/files/rinex/observation/RinexObservationParser.java | 2 +- .../orekit/files/rinex/observation/RinexObservationWriter.java | 2 +- .../orekit/files/rinex/observation/ScaleFactorCorrection.java | 2 +- .../java/org/orekit/files/rinex/observation/package-info.java | 2 +- src/main/java/org/orekit/files/rinex/package-info.java | 2 +- .../java/org/orekit/files/rinex/section/RinexBaseHeader.java | 2 +- src/main/java/org/orekit/files/rinex/section/RinexComment.java | 2 +- src/main/java/org/orekit/files/rinex/section/RinexLabels.java | 2 +- src/main/java/org/orekit/files/rinex/section/package-info.java | 2 +- src/main/java/org/orekit/files/rinex/utils/RinexFileType.java | 2 +- src/main/java/org/orekit/files/rinex/utils/package-info.java | 2 +- .../java/org/orekit/files/rinex/utils/parsing/RinexUtils.java | 2 +- .../java/org/orekit/files/rinex/utils/parsing/package-info.java | 2 +- src/main/java/org/orekit/files/sinex/Dcb.java | 2 +- src/main/java/org/orekit/files/sinex/DcbDescription.java | 2 +- src/main/java/org/orekit/files/sinex/DcbSatellite.java | 2 +- src/main/java/org/orekit/files/sinex/DcbStation.java | 2 +- src/main/java/org/orekit/files/sinex/SinexEopEntry.java | 2 +- src/main/java/org/orekit/files/sinex/SinexLoader.java | 2 +- src/main/java/org/orekit/files/sinex/Station.java | 2 +- src/main/java/org/orekit/files/sinex/package-info.java | 2 +- src/main/java/org/orekit/files/sp3/DataUsed.java | 2 +- .../org/orekit/files/sp3/SP3CoordinateHermiteInterpolator.java | 2 +- src/main/java/org/orekit/files/sp3/SP3Ephemeris.java | 2 +- src/main/java/org/orekit/files/sp3/SP3Header.java | 2 +- src/main/java/org/orekit/files/sp3/SP3Utils.java | 2 +- src/main/java/org/orekit/files/sp3/SP3Writer.java | 2 +- src/main/java/org/orekit/files/sp3/package-info.java | 2 +- src/main/java/org/orekit/files/stk/STKEphemerisFile.java | 2 +- src/main/java/org/orekit/files/stk/STKEphemerisFileParser.java | 2 +- src/main/java/org/orekit/files/stk/package-info.java | 2 +- src/main/java/org/orekit/forces/BoxAndSolarArraySpacecraft.java | 2 +- src/main/java/org/orekit/forces/FixedPanel.java | 2 +- src/main/java/org/orekit/forces/ForceModel.java | 2 +- src/main/java/org/orekit/forces/Panel.java | 2 +- src/main/java/org/orekit/forces/PointingPanel.java | 2 +- src/main/java/org/orekit/forces/SlewingPanel.java | 2 +- .../java/org/orekit/forces/drag/AbstractDragForceModel.java | 2 +- src/main/java/org/orekit/forces/drag/DragForce.java | 2 +- src/main/java/org/orekit/forces/drag/DragSensitive.java | 2 +- src/main/java/org/orekit/forces/drag/IsotropicDrag.java | 2 +- src/main/java/org/orekit/forces/drag/TimeSpanDragForce.java | 2 +- src/main/java/org/orekit/forces/drag/package-info.java | 2 +- .../java/org/orekit/forces/empirical/AccelerationModel.java | 2 +- .../org/orekit/forces/empirical/HarmonicAccelerationModel.java | 2 +- .../org/orekit/forces/empirical/ParametricAcceleration.java | 2 +- .../orekit/forces/empirical/PolynomialAccelerationModel.java | 2 +- .../orekit/forces/empirical/TimeSpanParametricAcceleration.java | 2 +- src/main/java/org/orekit/forces/empirical/package-info.java | 2 +- .../forces/gravity/HolmesFeatherstoneAttractionModel.java | 2 +- .../java/org/orekit/forces/gravity/LenseThirringRelativity.java | 2 +- src/main/java/org/orekit/forces/gravity/OceanTides.java | 2 +- src/main/java/org/orekit/forces/gravity/OceanTidesField.java | 2 +- .../org/orekit/forces/gravity/SingleBodyAbsoluteAttraction.java | 2 +- .../org/orekit/forces/gravity/SingleBodyRelativeAttraction.java | 2 +- src/main/java/org/orekit/forces/gravity/SolidTides.java | 2 +- src/main/java/org/orekit/forces/gravity/SolidTidesField.java | 2 +- .../java/org/orekit/forces/gravity/ThirdBodyAttraction.java | 2 +- .../org/orekit/forces/gravity/ThirdBodyAttractionEpoch.java | 2 +- src/main/java/org/orekit/forces/gravity/package-info.java | 2 +- .../forces/gravity/potential/AstronomicalAmplitudeReader.java | 2 +- .../potential/CachedNormalizedSphericalHarmonicsProvider.java | 2 +- .../forces/gravity/potential/ConstantSphericalHarmonics.java | 2 +- .../org/orekit/forces/gravity/potential/EGMFormatReader.java | 2 +- .../orekit/forces/gravity/potential/FESCHatEpsilonReader.java | 2 +- .../org/orekit/forces/gravity/potential/FESCnmSnmReader.java | 2 +- .../java/org/orekit/forces/gravity/potential/Flattener.java | 2 +- .../org/orekit/forces/gravity/potential/GRGSFormatReader.java | 2 +- .../orekit/forces/gravity/potential/GravityFieldFactory.java | 2 +- .../org/orekit/forces/gravity/potential/ICGEMFormatReader.java | 2 +- .../gravity/potential/NormalizedSphericalHarmonicsProvider.java | 2 +- .../java/org/orekit/forces/gravity/potential/Normalizer.java | 2 +- .../gravity/potential/OceanLoadDeformationCoefficients.java | 2 +- .../org/orekit/forces/gravity/potential/OceanTidesReader.java | 2 +- .../org/orekit/forces/gravity/potential/OceanTidesWave.java | 2 +- .../java/org/orekit/forces/gravity/potential/PiecewisePart.java | 2 +- .../forces/gravity/potential/PiecewiseSphericalHarmonics.java | 2 +- .../forces/gravity/potential/PotentialCoefficientsReader.java | 2 +- .../forces/gravity/potential/RawSphericalHarmonicsProvider.java | 2 +- .../org/orekit/forces/gravity/potential/SHMFormatReader.java | 2 +- .../gravity/potential/SecularTrendSphericalHarmonics.java | 2 +- .../forces/gravity/potential/SphericalHarmonicsProvider.java | 2 +- .../java/org/orekit/forces/gravity/potential/TideSystem.java | 2 +- .../org/orekit/forces/gravity/potential/TideSystemProvider.java | 2 +- .../orekit/forces/gravity/potential/TimeDependentHarmonic.java | 2 +- .../potential/UnnormalizedSphericalHarmonicsProvider.java | 2 +- .../java/org/orekit/forces/gravity/potential/Unnormalizer.java | 2 +- .../forces/gravity/potential/WrappingNormalizedProvider.java | 2 +- .../forces/gravity/potential/WrappingUnnormalizedProvider.java | 2 +- .../java/org/orekit/forces/gravity/potential/package-info.java | 2 +- src/main/java/org/orekit/forces/inertia/InertialForces.java | 2 +- src/main/java/org/orekit/forces/inertia/package-info.java | 2 +- .../org/orekit/forces/maneuvers/ConstantThrustManeuver.java | 2 +- .../org/orekit/forces/maneuvers/Control3DVectorCostType.java | 2 +- .../java/org/orekit/forces/maneuvers/FieldImpulseManeuver.java | 2 +- src/main/java/org/orekit/forces/maneuvers/ImpulseManeuver.java | 2 +- src/main/java/org/orekit/forces/maneuvers/Maneuver.java | 2 +- .../orekit/forces/maneuvers/SmallManeuverAnalyticalModel.java | 2 +- .../java/org/orekit/forces/maneuvers/jacobians/Duration.java | 2 +- .../orekit/forces/maneuvers/jacobians/MassDepletionDelay.java | 2 +- .../java/org/orekit/forces/maneuvers/jacobians/MedianDate.java | 2 +- .../java/org/orekit/forces/maneuvers/jacobians/TriggerDate.java | 2 +- .../org/orekit/forces/maneuvers/jacobians/package-info.java | 2 +- src/main/java/org/orekit/forces/maneuvers/package-info.java | 2 +- .../propulsion/AbstractConstantThrustPropulsionModel.java | 2 +- .../propulsion/BasicConstantThrustPropulsionModel.java | 2 +- .../forces/maneuvers/propulsion/PolynomialThrustSegment.java | 2 +- .../maneuvers/propulsion/ProfileThrustPropulsionModel.java | 2 +- .../org/orekit/forces/maneuvers/propulsion/PropulsionModel.java | 2 +- .../propulsion/ScaledConstantThrustPropulsionModel.java | 2 +- .../forces/maneuvers/propulsion/ThrustPropulsionModel.java | 2 +- .../org/orekit/forces/maneuvers/propulsion/package-info.java | 2 +- .../forces/maneuvers/trigger/AbstractManeuverTriggers.java | 2 +- .../forces/maneuvers/trigger/DateBasedManeuverTriggers.java | 2 +- .../forces/maneuvers/trigger/FieldManeuverTriggersResetter.java | 2 +- .../orekit/forces/maneuvers/trigger/IntervalEventTrigger.java | 2 +- .../org/orekit/forces/maneuvers/trigger/ManeuverTriggers.java | 2 +- .../forces/maneuvers/trigger/ManeuverTriggersResetter.java | 2 +- .../orekit/forces/maneuvers/trigger/StartStopEventsTrigger.java | 2 +- .../java/org/orekit/forces/maneuvers/trigger/package-info.java | 2 +- src/main/java/org/orekit/forces/package-info.java | 2 +- .../orekit/forces/radiation/AbstractRadiationForceModel.java | 2 +- src/main/java/org/orekit/forces/radiation/ECOM2.java | 2 +- .../forces/radiation/IsotropicRadiationCNES95Convention.java | 2 +- .../forces/radiation/IsotropicRadiationClassicalConvention.java | 2 +- .../forces/radiation/IsotropicRadiationSingleCoefficient.java | 2 +- .../org/orekit/forces/radiation/KnockeRediffusedForceModel.java | 2 +- .../java/org/orekit/forces/radiation/RadiationSensitive.java | 2 +- .../org/orekit/forces/radiation/SolarRadiationPressure.java | 2 +- src/main/java/org/orekit/forces/radiation/package-info.java | 2 +- src/main/java/org/orekit/frames/BulletinAFilesLoader.java | 2 +- src/main/java/org/orekit/frames/BulletinBFilesLoader.java | 2 +- src/main/java/org/orekit/frames/CIRFProvider.java | 2 +- src/main/java/org/orekit/frames/CR3BPRotatingFrame.java | 2 +- .../java/org/orekit/frames/CR3BPRotatingTransformProvider.java | 2 +- src/main/java/org/orekit/frames/EME2000Provider.java | 2 +- src/main/java/org/orekit/frames/EOPBasedTransformProvider.java | 2 +- src/main/java/org/orekit/frames/EOPEntry.java | 2 +- src/main/java/org/orekit/frames/EOPFittedModel.java | 2 +- src/main/java/org/orekit/frames/EOPFitter.java | 2 +- src/main/java/org/orekit/frames/EOPHistory.java | 2 +- src/main/java/org/orekit/frames/EopC04FilesLoader.java | 2 +- src/main/java/org/orekit/frames/EopCsvFilesLoader.java | 2 +- src/main/java/org/orekit/frames/EopHistoryLoader.java | 2 +- src/main/java/org/orekit/frames/EopXmlLoader.java | 2 +- src/main/java/org/orekit/frames/FactoryManagedFrame.java | 2 +- src/main/java/org/orekit/frames/FieldPoleCorrection.java | 2 +- src/main/java/org/orekit/frames/FieldStaticTransform.java | 2 +- src/main/java/org/orekit/frames/FieldTransform.java | 2 +- src/main/java/org/orekit/frames/FieldTransformGenerator.java | 2 +- src/main/java/org/orekit/frames/FixedTransformProvider.java | 2 +- src/main/java/org/orekit/frames/Frame.java | 2 +- src/main/java/org/orekit/frames/FramesFactory.java | 2 +- src/main/java/org/orekit/frames/GTODProvider.java | 2 +- src/main/java/org/orekit/frames/HelmertTransformation.java | 2 +- src/main/java/org/orekit/frames/ITRFProvider.java | 2 +- src/main/java/org/orekit/frames/ITRFVersion.java | 2 +- src/main/java/org/orekit/frames/ITRFVersionLoader.java | 2 +- .../java/org/orekit/frames/InterpolatingTransformProvider.java | 2 +- src/main/java/org/orekit/frames/L1Frame.java | 2 +- src/main/java/org/orekit/frames/L1TransformProvider.java | 2 +- src/main/java/org/orekit/frames/L2Frame.java | 2 +- src/main/java/org/orekit/frames/L2TransformProvider.java | 2 +- src/main/java/org/orekit/frames/LOF.java | 2 +- src/main/java/org/orekit/frames/LOFType.java | 2 +- src/main/java/org/orekit/frames/LocalMagneticFieldFrame.java | 2 +- src/main/java/org/orekit/frames/LocalOrbitalFrame.java | 2 +- src/main/java/org/orekit/frames/MODProvider.java | 2 +- src/main/java/org/orekit/frames/OrphanFrame.java | 2 +- src/main/java/org/orekit/frames/PoleCorrection.java | 2 +- src/main/java/org/orekit/frames/Predefined.java | 2 +- src/main/java/org/orekit/frames/PredictedEOPHistory.java | 2 +- .../org/orekit/frames/RapidDataAndPredictionColumnsLoader.java | 2 +- src/main/java/org/orekit/frames/ShiftingTransformProvider.java | 2 +- src/main/java/org/orekit/frames/SingleParameterFitter.java | 2 +- src/main/java/org/orekit/frames/TEMEProvider.java | 2 +- src/main/java/org/orekit/frames/TIRFProvider.java | 2 +- src/main/java/org/orekit/frames/TODProvider.java | 2 +- src/main/java/org/orekit/frames/TopocentricFrame.java | 2 +- src/main/java/org/orekit/frames/Transform.java | 2 +- src/main/java/org/orekit/frames/TransformGenerator.java | 2 +- src/main/java/org/orekit/frames/TransformProvider.java | 2 +- src/main/java/org/orekit/frames/TransformProviderUtils.java | 2 +- src/main/java/org/orekit/frames/TwoBodiesBaryFrame.java | 2 +- .../java/org/orekit/frames/TwoBodiesBaryTransformProvider.java | 2 +- src/main/java/org/orekit/frames/UpdatableFrame.java | 2 +- src/main/java/org/orekit/frames/VEISProvider.java | 2 +- src/main/java/org/orekit/frames/VersionedITRF.java | 2 +- src/main/java/org/orekit/frames/VersionedITRFProvider.java | 2 +- .../java/org/orekit/frames/encounter/AbstractEncounterLOF.java | 2 +- .../java/org/orekit/frames/encounter/DefaultEncounterLOF.java | 2 +- src/main/java/org/orekit/frames/encounter/EncounterLOF.java | 2 +- src/main/java/org/orekit/frames/encounter/EncounterLOFType.java | 2 +- .../org/orekit/frames/encounter/ValsecchiEncounterFrame.java | 2 +- src/main/java/org/orekit/frames/encounter/package-info.java | 2 +- src/main/java/org/orekit/frames/package-info.java | 2 +- src/main/java/org/orekit/geometry/fov/AbstractFieldOfView.java | 2 +- src/main/java/org/orekit/geometry/fov/CircularFieldOfView.java | 2 +- .../java/org/orekit/geometry/fov/DoubleDihedraFieldOfView.java | 2 +- .../java/org/orekit/geometry/fov/EllipticalFieldOfView.java | 2 +- src/main/java/org/orekit/geometry/fov/FieldOfView.java | 2 +- src/main/java/org/orekit/geometry/fov/PolygonalFieldOfView.java | 2 +- src/main/java/org/orekit/geometry/fov/SmoothFieldOfView.java | 2 +- src/main/java/org/orekit/geometry/fov/package-info.java | 2 +- src/main/java/org/orekit/gnss/DOP.java | 2 +- src/main/java/org/orekit/gnss/DOPComputer.java | 2 +- src/main/java/org/orekit/gnss/Frequency.java | 2 +- src/main/java/org/orekit/gnss/MeasurementType.java | 2 +- src/main/java/org/orekit/gnss/ObservationTimeScale.java | 2 +- src/main/java/org/orekit/gnss/ObservationType.java | 2 +- src/main/java/org/orekit/gnss/SEMParser.java | 2 +- src/main/java/org/orekit/gnss/SatInSystem.java | 2 +- src/main/java/org/orekit/gnss/SatelliteSystem.java | 2 +- src/main/java/org/orekit/gnss/SignalCode.java | 2 +- src/main/java/org/orekit/gnss/TimeSystem.java | 2 +- src/main/java/org/orekit/gnss/YUMAParser.java | 2 +- src/main/java/org/orekit/gnss/antenna/Antenna.java | 2 +- src/main/java/org/orekit/gnss/antenna/AntexLoader.java | 2 +- src/main/java/org/orekit/gnss/antenna/FrequencyPattern.java | 2 +- src/main/java/org/orekit/gnss/antenna/OneDVariation.java | 2 +- .../org/orekit/gnss/antenna/PhaseCenterVariationFunction.java | 2 +- src/main/java/org/orekit/gnss/antenna/ReceiverAntenna.java | 2 +- src/main/java/org/orekit/gnss/antenna/SatelliteAntenna.java | 2 +- src/main/java/org/orekit/gnss/antenna/SatelliteType.java | 2 +- src/main/java/org/orekit/gnss/antenna/TwoDVariation.java | 2 +- src/main/java/org/orekit/gnss/antenna/package-info.java | 2 +- .../org/orekit/gnss/attitude/AbstractGNSSAttitudeProvider.java | 2 +- src/main/java/org/orekit/gnss/attitude/BeidouGeo.java | 2 +- src/main/java/org/orekit/gnss/attitude/BeidouIGSO.java | 2 +- src/main/java/org/orekit/gnss/attitude/BeidouMeo.java | 2 +- src/main/java/org/orekit/gnss/attitude/FieldTurnSpan.java | 2 +- src/main/java/org/orekit/gnss/attitude/GNSSAttitudeContext.java | 2 +- .../java/org/orekit/gnss/attitude/GNSSAttitudeProvider.java | 2 +- .../java/org/orekit/gnss/attitude/GNSSFieldAttitudeContext.java | 2 +- src/main/java/org/orekit/gnss/attitude/GPSBlockIIA.java | 2 +- src/main/java/org/orekit/gnss/attitude/GPSBlockIIF.java | 2 +- src/main/java/org/orekit/gnss/attitude/GPSBlockIIR.java | 2 +- src/main/java/org/orekit/gnss/attitude/Galileo.java | 2 +- src/main/java/org/orekit/gnss/attitude/GenericGNSS.java | 2 +- src/main/java/org/orekit/gnss/attitude/Glonass.java | 2 +- src/main/java/org/orekit/gnss/attitude/TurnSpan.java | 2 +- src/main/java/org/orekit/gnss/attitude/package-info.java | 2 +- .../java/org/orekit/gnss/metric/messages/ParsedMessage.java | 2 +- .../orekit/gnss/metric/messages/common/AccuracyProvider.java | 2 +- .../org/orekit/gnss/metric/messages/common/ClockCorrection.java | 2 +- .../java/org/orekit/gnss/metric/messages/common/CodeBias.java | 2 +- .../gnss/metric/messages/common/GlonassUserRangeAccuracy.java | 2 +- .../org/orekit/gnss/metric/messages/common/OrbitCorrection.java | 2 +- .../java/org/orekit/gnss/metric/messages/common/PhaseBias.java | 2 +- .../gnss/metric/messages/common/SignalInSpaceAccuracy.java | 2 +- .../orekit/gnss/metric/messages/common/SsrUpdateInterval.java | 2 +- .../orekit/gnss/metric/messages/common/UserRangeAccuracy.java | 2 +- .../org/orekit/gnss/metric/messages/common/package-info.java | 2 +- src/main/java/org/orekit/gnss/metric/messages/package-info.java | 2 +- .../java/org/orekit/gnss/metric/messages/rtcm/RtcmData.java | 2 +- .../java/org/orekit/gnss/metric/messages/rtcm/RtcmMessage.java | 2 +- .../orekit/gnss/metric/messages/rtcm/correction/Rtcm1057.java | 2 +- .../orekit/gnss/metric/messages/rtcm/correction/Rtcm1058.java | 2 +- .../orekit/gnss/metric/messages/rtcm/correction/Rtcm1060.java | 2 +- .../orekit/gnss/metric/messages/rtcm/correction/Rtcm1063.java | 2 +- .../orekit/gnss/metric/messages/rtcm/correction/Rtcm1064.java | 2 +- .../orekit/gnss/metric/messages/rtcm/correction/Rtcm1066.java | 2 +- .../orekit/gnss/metric/messages/rtcm/correction/Rtcm1240.java | 2 +- .../orekit/gnss/metric/messages/rtcm/correction/Rtcm1241.java | 2 +- .../orekit/gnss/metric/messages/rtcm/correction/Rtcm1243.java | 2 +- .../messages/rtcm/correction/RtcmClockCorrectionData.java | 2 +- .../messages/rtcm/correction/RtcmCombinedCorrectionData.java | 2 +- .../metric/messages/rtcm/correction/RtcmCorrectionData.java | 2 +- .../metric/messages/rtcm/correction/RtcmCorrectionHeader.java | 2 +- .../metric/messages/rtcm/correction/RtcmCorrectionMessage.java | 2 +- .../messages/rtcm/correction/RtcmOrbitCorrectionData.java | 2 +- .../messages/rtcm/correction/RtcmOrbitCorrectionHeader.java | 2 +- .../gnss/metric/messages/rtcm/correction/package-info.java | 2 +- .../orekit/gnss/metric/messages/rtcm/ephemeris/Rtcm1019.java | 2 +- .../gnss/metric/messages/rtcm/ephemeris/Rtcm1019Data.java | 2 +- .../orekit/gnss/metric/messages/rtcm/ephemeris/Rtcm1020.java | 2 +- .../gnss/metric/messages/rtcm/ephemeris/Rtcm1020Data.java | 2 +- .../orekit/gnss/metric/messages/rtcm/ephemeris/Rtcm1042.java | 2 +- .../gnss/metric/messages/rtcm/ephemeris/Rtcm1042Data.java | 2 +- .../orekit/gnss/metric/messages/rtcm/ephemeris/Rtcm1044.java | 2 +- .../gnss/metric/messages/rtcm/ephemeris/Rtcm1044Data.java | 2 +- .../orekit/gnss/metric/messages/rtcm/ephemeris/Rtcm1045.java | 2 +- .../gnss/metric/messages/rtcm/ephemeris/Rtcm1045Data.java | 2 +- .../gnss/metric/messages/rtcm/ephemeris/RtcmEphemerisData.java | 2 +- .../metric/messages/rtcm/ephemeris/RtcmEphemerisMessage.java | 2 +- .../gnss/metric/messages/rtcm/ephemeris/package-info.java | 2 +- .../java/org/orekit/gnss/metric/messages/rtcm/package-info.java | 2 +- src/main/java/org/orekit/gnss/metric/messages/ssr/SsrData.java | 2 +- .../java/org/orekit/gnss/metric/messages/ssr/SsrHeader.java | 2 +- .../java/org/orekit/gnss/metric/messages/ssr/SsrMessage.java | 2 +- .../java/org/orekit/gnss/metric/messages/ssr/igm/SsrIgm01.java | 2 +- .../org/orekit/gnss/metric/messages/ssr/igm/SsrIgm01Data.java | 2 +- .../org/orekit/gnss/metric/messages/ssr/igm/SsrIgm01Header.java | 2 +- .../java/org/orekit/gnss/metric/messages/ssr/igm/SsrIgm02.java | 2 +- .../org/orekit/gnss/metric/messages/ssr/igm/SsrIgm02Data.java | 2 +- .../org/orekit/gnss/metric/messages/ssr/igm/SsrIgm02Header.java | 2 +- .../java/org/orekit/gnss/metric/messages/ssr/igm/SsrIgm03.java | 2 +- .../org/orekit/gnss/metric/messages/ssr/igm/SsrIgm03Data.java | 2 +- .../org/orekit/gnss/metric/messages/ssr/igm/SsrIgm03Header.java | 2 +- .../java/org/orekit/gnss/metric/messages/ssr/igm/SsrIgm04.java | 2 +- .../org/orekit/gnss/metric/messages/ssr/igm/SsrIgm04Data.java | 2 +- .../org/orekit/gnss/metric/messages/ssr/igm/SsrIgm04Header.java | 2 +- .../java/org/orekit/gnss/metric/messages/ssr/igm/SsrIgm05.java | 2 +- .../org/orekit/gnss/metric/messages/ssr/igm/SsrIgm05Data.java | 2 +- .../org/orekit/gnss/metric/messages/ssr/igm/SsrIgm05Header.java | 2 +- .../java/org/orekit/gnss/metric/messages/ssr/igm/SsrIgm06.java | 2 +- .../org/orekit/gnss/metric/messages/ssr/igm/SsrIgm06Data.java | 2 +- .../org/orekit/gnss/metric/messages/ssr/igm/SsrIgm06Header.java | 2 +- .../java/org/orekit/gnss/metric/messages/ssr/igm/SsrIgm07.java | 2 +- .../org/orekit/gnss/metric/messages/ssr/igm/SsrIgm07Data.java | 2 +- .../org/orekit/gnss/metric/messages/ssr/igm/SsrIgm07Header.java | 2 +- .../org/orekit/gnss/metric/messages/ssr/igm/SsrIgmData.java | 2 +- .../org/orekit/gnss/metric/messages/ssr/igm/SsrIgmHeader.java | 2 +- .../org/orekit/gnss/metric/messages/ssr/igm/SsrIgmMessage.java | 2 +- .../org/orekit/gnss/metric/messages/ssr/igm/package-info.java | 2 +- .../java/org/orekit/gnss/metric/messages/ssr/package-info.java | 2 +- .../org/orekit/gnss/metric/messages/ssr/subtype/SsrIm201.java | 2 +- .../orekit/gnss/metric/messages/ssr/subtype/SsrIm201Data.java | 2 +- .../orekit/gnss/metric/messages/ssr/subtype/SsrIm201Header.java | 2 +- .../orekit/gnss/metric/messages/ssr/subtype/package-info.java | 2 +- src/main/java/org/orekit/gnss/metric/ntrip/Authentication.java | 2 +- src/main/java/org/orekit/gnss/metric/ntrip/CarrierPhase.java | 2 +- src/main/java/org/orekit/gnss/metric/ntrip/CasterRecord.java | 2 +- src/main/java/org/orekit/gnss/metric/ntrip/DataFormat.java | 2 +- .../java/org/orekit/gnss/metric/ntrip/DataStreamRecord.java | 2 +- src/main/java/org/orekit/gnss/metric/ntrip/GnssData.java | 2 +- src/main/java/org/orekit/gnss/metric/ntrip/MessageObserver.java | 2 +- .../java/org/orekit/gnss/metric/ntrip/NavigationSystem.java | 2 +- src/main/java/org/orekit/gnss/metric/ntrip/NetworkRecord.java | 2 +- src/main/java/org/orekit/gnss/metric/ntrip/NtripClient.java | 2 +- src/main/java/org/orekit/gnss/metric/ntrip/Record.java | 2 +- src/main/java/org/orekit/gnss/metric/ntrip/RecordType.java | 2 +- src/main/java/org/orekit/gnss/metric/ntrip/SourceTable.java | 2 +- src/main/java/org/orekit/gnss/metric/ntrip/StreamMonitor.java | 2 +- src/main/java/org/orekit/gnss/metric/ntrip/StreamedMessage.java | 2 +- src/main/java/org/orekit/gnss/metric/ntrip/Type.java | 2 +- src/main/java/org/orekit/gnss/metric/ntrip/package-info.java | 2 +- src/main/java/org/orekit/gnss/metric/package-info.java | 2 +- .../org/orekit/gnss/metric/parser/AbstractEncodedMessage.java | 2 +- .../org/orekit/gnss/metric/parser/ByteArrayEncodedMessage.java | 2 +- src/main/java/org/orekit/gnss/metric/parser/DataField.java | 2 +- src/main/java/org/orekit/gnss/metric/parser/DataType.java | 2 +- src/main/java/org/orekit/gnss/metric/parser/EncodedMessage.java | 2 +- .../gnss/metric/parser/HexadecimalSequenceEncodedMessage.java | 2 +- .../java/org/orekit/gnss/metric/parser/IgsSsrDataField.java | 2 +- .../java/org/orekit/gnss/metric/parser/IgsSsrMessageType.java | 2 +- .../org/orekit/gnss/metric/parser/IgsSsrMessagesParser.java | 2 +- .../orekit/gnss/metric/parser/InputStreamEncodedMessage.java | 2 +- src/main/java/org/orekit/gnss/metric/parser/MessageType.java | 2 +- src/main/java/org/orekit/gnss/metric/parser/MessagesParser.java | 2 +- src/main/java/org/orekit/gnss/metric/parser/RtcmDataField.java | 2 +- .../java/org/orekit/gnss/metric/parser/RtcmMessageType.java | 2 +- .../java/org/orekit/gnss/metric/parser/RtcmMessagesParser.java | 2 +- src/main/java/org/orekit/gnss/metric/parser/Units.java | 2 +- src/main/java/org/orekit/gnss/metric/parser/package-info.java | 2 +- src/main/java/org/orekit/gnss/package-info.java | 2 +- src/main/java/org/orekit/gnss/rflink/gps/SubFrame.java | 2 +- src/main/java/org/orekit/gnss/rflink/gps/SubFrame1.java | 2 +- src/main/java/org/orekit/gnss/rflink/gps/SubFrame2.java | 2 +- src/main/java/org/orekit/gnss/rflink/gps/SubFrame3.java | 2 +- src/main/java/org/orekit/gnss/rflink/gps/SubFrame45.java | 2 +- src/main/java/org/orekit/gnss/rflink/gps/SubFrame4A.java | 2 +- src/main/java/org/orekit/gnss/rflink/gps/SubFrame4A0.java | 2 +- src/main/java/org/orekit/gnss/rflink/gps/SubFrame4A1.java | 2 +- src/main/java/org/orekit/gnss/rflink/gps/SubFrame4B.java | 2 +- src/main/java/org/orekit/gnss/rflink/gps/SubFrame4C.java | 2 +- src/main/java/org/orekit/gnss/rflink/gps/SubFrame4D.java | 2 +- src/main/java/org/orekit/gnss/rflink/gps/SubFrame4E.java | 2 +- src/main/java/org/orekit/gnss/rflink/gps/SubFrame5B.java | 2 +- src/main/java/org/orekit/gnss/rflink/gps/SubFrameAlmanac.java | 2 +- .../java/org/orekit/gnss/rflink/gps/SubFrameDummyAlmanac.java | 2 +- src/main/java/org/orekit/gnss/rflink/gps/package-info.java | 2 +- src/main/java/org/orekit/gnss/rflink/package-info.java | 2 +- .../java/org/orekit/models/earth/atmosphere/Atmosphere.java | 2 +- src/main/java/org/orekit/models/earth/atmosphere/DTM2000.java | 2 +- .../orekit/models/earth/atmosphere/DTM2000InputParameters.java | 2 +- .../java/org/orekit/models/earth/atmosphere/HarrisPriester.java | 2 +- src/main/java/org/orekit/models/earth/atmosphere/JB2008.java | 2 +- .../orekit/models/earth/atmosphere/JB2008InputParameters.java | 2 +- .../java/org/orekit/models/earth/atmosphere/NRLMSISE00.java | 2 +- .../models/earth/atmosphere/NRLMSISE00InputParameters.java | 2 +- .../models/earth/atmosphere/SimpleExponentialAtmosphere.java | 2 +- .../models/earth/atmosphere/data/AbstractSolarActivityData.java | 2 +- .../earth/atmosphere/data/AbstractSolarActivityDataLoader.java | 2 +- .../orekit/models/earth/atmosphere/data/CommonLineReader.java | 2 +- .../org/orekit/models/earth/atmosphere/data/DtcDataLoader.java | 2 +- .../earth/atmosphere/data/JB2008SpaceEnvironmentData.java | 2 +- .../atmosphere/data/MarshallSolarActivityFutureEstimation.java | 2 +- .../data/MarshallSolarActivityFutureEstimationLoader.java | 2 +- .../orekit/models/earth/atmosphere/data/SOLFSMYDataLoader.java | 2 +- .../org/orekit/models/earth/atmosphere/data/package-info.java | 2 +- .../java/org/orekit/models/earth/atmosphere/package-info.java | 2 +- .../java/org/orekit/models/earth/displacement/OceanLoading.java | 2 +- .../models/earth/displacement/OceanLoadingCoefficients.java | 2 +- .../earth/displacement/OceanLoadingCoefficientsBLQFactory.java | 2 +- .../orekit/models/earth/displacement/StationDisplacement.java | 2 +- .../orekit/models/earth/displacement/TectonicsDisplacement.java | 2 +- .../org/orekit/models/earth/displacement/TidalDisplacement.java | 2 +- src/main/java/org/orekit/models/earth/displacement/Tide.java | 2 +- .../java/org/orekit/models/earth/displacement/package-info.java | 2 +- .../models/earth/ionosphere/EstimatedIonosphericModel.java | 2 +- .../orekit/models/earth/ionosphere/FieldNeQuickParameters.java | 2 +- .../models/earth/ionosphere/GlobalIonosphereMapModel.java | 2 +- .../models/earth/ionosphere/IonosphericMappingFunction.java | 2 +- .../org/orekit/models/earth/ionosphere/IonosphericModel.java | 2 +- .../earth/ionosphere/KlobucharIonoCoefficientsLoader.java | 2 +- .../org/orekit/models/earth/ionosphere/KlobucharIonoModel.java | 2 +- .../java/org/orekit/models/earth/ionosphere/NeQuickModel.java | 2 +- .../org/orekit/models/earth/ionosphere/NeQuickParameters.java | 2 +- .../earth/ionosphere/SingleLayerModelMappingFunction.java | 2 +- .../orekit/models/earth/ionosphere/SsrVtecIonosphericModel.java | 2 +- .../java/org/orekit/models/earth/ionosphere/package-info.java | 2 +- src/main/java/org/orekit/models/earth/package-info.java | 2 +- .../org/orekit/models/earth/tessellation/AlongTrackAiming.java | 2 +- .../orekit/models/earth/tessellation/ConstantAzimuthAiming.java | 2 +- .../java/org/orekit/models/earth/tessellation/Direction.java | 2 +- .../models/earth/tessellation/DivertedSingularityAiming.java | 2 +- .../orekit/models/earth/tessellation/EllipsoidTessellator.java | 2 +- .../org/orekit/models/earth/tessellation/HalfTrackSampler.java | 2 +- .../orekit/models/earth/tessellation/HalfTrackSpanHandler.java | 2 +- .../org/orekit/models/earth/tessellation/InsidePointFinder.java | 2 +- src/main/java/org/orekit/models/earth/tessellation/Mesh.java | 2 +- src/main/java/org/orekit/models/earth/tessellation/Tile.java | 2 +- .../java/org/orekit/models/earth/tessellation/TileAiming.java | 2 +- .../java/org/orekit/models/earth/tessellation/package-info.java | 2 +- .../models/earth/troposphere/DiscreteTroposphericModel.java | 2 +- .../models/earth/troposphere/EstimatedTroposphericModel.java | 2 +- .../models/earth/troposphere/GlobalMappingFunctionModel.java | 2 +- .../org/orekit/models/earth/troposphere/MappingFunction.java | 2 +- .../org/orekit/models/earth/troposphere/MendesPavlisModel.java | 2 +- .../models/earth/troposphere/NiellMappingFunctionModel.java | 2 +- .../earth/troposphere/TimeSpanEstimatedTroposphericModel.java | 2 +- .../orekit/models/earth/troposphere/TroposphericModelUtils.java | 2 +- .../models/earth/troposphere/ViennaModelCoefficientsLoader.java | 2 +- .../org/orekit/models/earth/troposphere/ViennaModelType.java | 2 +- .../org/orekit/models/earth/troposphere/ViennaOneModel.java | 2 +- .../org/orekit/models/earth/troposphere/ViennaThreeModel.java | 2 +- .../java/org/orekit/models/earth/troposphere/package-info.java | 2 +- .../models/earth/weather/GlobalPressureTemperature2Model.java | 2 +- .../models/earth/weather/GlobalPressureTemperatureModel.java | 2 +- src/main/java/org/orekit/models/earth/weather/WeatherModel.java | 2 +- src/main/java/org/orekit/models/earth/weather/package-info.java | 2 +- src/main/java/org/orekit/models/package-info.java | 2 +- .../java/org/orekit/orbits/AbstractFieldOrbitInterpolator.java | 2 +- src/main/java/org/orekit/orbits/AbstractOrbitInterpolator.java | 2 +- .../java/org/orekit/orbits/CR3BPDifferentialCorrection.java | 2 +- src/main/java/org/orekit/orbits/CartesianOrbit.java | 2 +- .../java/org/orekit/orbits/CircularLatitudeArgumentUtility.java | 2 +- src/main/java/org/orekit/orbits/CircularOrbit.java | 2 +- .../org/orekit/orbits/EquinoctialLongitudeArgumentUtility.java | 2 +- src/main/java/org/orekit/orbits/EquinoctialOrbit.java | 2 +- src/main/java/org/orekit/orbits/FieldCartesianOrbit.java | 2 +- .../org/orekit/orbits/FieldCircularLatitudeArgumentUtility.java | 2 +- src/main/java/org/orekit/orbits/FieldCircularOrbit.java | 2 +- .../orekit/orbits/FieldEquinoctialLongitudeArgumentUtility.java | 2 +- src/main/java/org/orekit/orbits/FieldEquinoctialOrbit.java | 2 +- .../java/org/orekit/orbits/FieldKeplerianAnomalyUtility.java | 2 +- src/main/java/org/orekit/orbits/FieldKeplerianOrbit.java | 2 +- src/main/java/org/orekit/orbits/FieldOrbit.java | 2 +- src/main/java/org/orekit/orbits/FieldOrbitBlender.java | 2 +- .../java/org/orekit/orbits/FieldOrbitHermiteInterpolator.java | 2 +- src/main/java/org/orekit/orbits/HaloOrbit.java | 2 +- src/main/java/org/orekit/orbits/KeplerianAnomalyUtility.java | 2 +- src/main/java/org/orekit/orbits/KeplerianOrbit.java | 2 +- src/main/java/org/orekit/orbits/LibrationOrbit.java | 2 +- src/main/java/org/orekit/orbits/LibrationOrbitFamily.java | 2 +- src/main/java/org/orekit/orbits/LibrationOrbitType.java | 2 +- src/main/java/org/orekit/orbits/LyapunovOrbit.java | 2 +- src/main/java/org/orekit/orbits/Orbit.java | 2 +- src/main/java/org/orekit/orbits/OrbitBlender.java | 2 +- src/main/java/org/orekit/orbits/OrbitHermiteInterpolator.java | 2 +- src/main/java/org/orekit/orbits/OrbitType.java | 2 +- src/main/java/org/orekit/orbits/PositionAngleBased.java | 2 +- src/main/java/org/orekit/orbits/PositionAngleType.java | 2 +- src/main/java/org/orekit/orbits/RichardsonExpansion.java | 2 +- src/main/java/org/orekit/orbits/package-info.java | 2 +- .../java/org/orekit/propagation/AbstractMatricesHarvester.java | 2 +- src/main/java/org/orekit/propagation/AbstractPropagator.java | 2 +- .../orekit/propagation/AbstractStateCovarianceInterpolator.java | 2 +- .../java/org/orekit/propagation/AdditionalStateProvider.java | 2 +- src/main/java/org/orekit/propagation/BoundedPropagator.java | 2 +- src/main/java/org/orekit/propagation/EphemerisGenerator.java | 2 +- .../java/org/orekit/propagation/FieldAbstractPropagator.java | 2 +- .../org/orekit/propagation/FieldAdditionalStateProvider.java | 2 +- .../java/org/orekit/propagation/FieldBoundedPropagator.java | 2 +- .../java/org/orekit/propagation/FieldEphemerisGenerator.java | 2 +- src/main/java/org/orekit/propagation/FieldPropagator.java | 2 +- src/main/java/org/orekit/propagation/FieldSpacecraftState.java | 2 +- .../orekit/propagation/FieldSpacecraftStateInterpolator.java | 2 +- src/main/java/org/orekit/propagation/FieldStateCovariance.java | 2 +- src/main/java/org/orekit/propagation/MatricesHarvester.java | 2 +- src/main/java/org/orekit/propagation/PropagationType.java | 2 +- src/main/java/org/orekit/propagation/Propagator.java | 2 +- .../java/org/orekit/propagation/PropagatorsParallelizer.java | 2 +- src/main/java/org/orekit/propagation/SpacecraftState.java | 2 +- .../org/orekit/propagation/SpacecraftStateInterpolator.java | 2 +- src/main/java/org/orekit/propagation/StateCovariance.java | 2 +- .../java/org/orekit/propagation/StateCovarianceBlender.java | 2 +- .../StateCovarianceKeplerianHermiteInterpolator.java | 2 +- .../org/orekit/propagation/StateCovarianceMatrixProvider.java | 2 +- .../analytical/AbstractAnalyticalGradientConverter.java | 2 +- .../analytical/AbstractAnalyticalMatricesHarvester.java | 2 +- .../propagation/analytical/AbstractAnalyticalPropagator.java | 2 +- .../org/orekit/propagation/analytical/AdapterPropagator.java | 2 +- .../propagation/analytical/BrouwerLyddaneGradientConverter.java | 2 +- .../orekit/propagation/analytical/BrouwerLyddaneHarvester.java | 2 +- .../orekit/propagation/analytical/BrouwerLyddanePropagator.java | 2 +- .../analytical/EcksteinHechlerGradientConverter.java | 2 +- .../orekit/propagation/analytical/EcksteinHechlerHarvester.java | 2 +- .../propagation/analytical/EcksteinHechlerPropagator.java | 2 +- src/main/java/org/orekit/propagation/analytical/Ephemeris.java | 2 +- .../analytical/FieldAbstractAnalyticalPropagator.java | 2 +- .../propagation/analytical/FieldBrouwerLyddanePropagator.java | 2 +- .../propagation/analytical/FieldEcksteinHechlerPropagator.java | 2 +- .../orekit/propagation/analytical/FieldKeplerianPropagator.java | 2 +- .../org/orekit/propagation/analytical/J2DifferentialEffect.java | 2 +- .../propagation/analytical/KeplerianGradientConverter.java | 2 +- .../org/orekit/propagation/analytical/KeplerianHarvester.java | 2 +- .../org/orekit/propagation/analytical/KeplerianPropagator.java | 2 +- .../propagation/analytical/gnss/ClockCorrectionsProvider.java | 2 +- .../analytical/gnss/GLONASSAnalyticalPropagator.java | 2 +- .../analytical/gnss/GLONASSAnalyticalPropagatorBuilder.java | 2 +- .../org/orekit/propagation/analytical/gnss/GNSSPropagator.java | 2 +- .../propagation/analytical/gnss/GNSSPropagatorBuilder.java | 2 +- .../org/orekit/propagation/analytical/gnss/SBASPropagator.java | 2 +- .../propagation/analytical/gnss/SBASPropagatorBuilder.java | 2 +- .../propagation/analytical/gnss/data/AbstractAlmanac.java | 2 +- .../analytical/gnss/data/AbstractEphemerisMessage.java | 2 +- .../analytical/gnss/data/AbstractNavigationMessage.java | 2 +- .../orekit/propagation/analytical/gnss/data/BeidouAlmanac.java | 2 +- .../analytical/gnss/data/BeidouCivilianNavigationMessage.java | 2 +- .../analytical/gnss/data/BeidouLegacyNavigationMessage.java | 2 +- .../propagation/analytical/gnss/data/BeidouSatelliteType.java | 2 +- .../analytical/gnss/data/CivilianNavigationMessage.java | 2 +- .../orekit/propagation/analytical/gnss/data/CommonGnssData.java | 2 +- .../orekit/propagation/analytical/gnss/data/GLONASSAlmanac.java | 2 +- .../propagation/analytical/gnss/data/GLONASSEphemeris.java | 2 +- .../analytical/gnss/data/GLONASSNavigationMessage.java | 2 +- .../analytical/gnss/data/GLONASSOrbitalElements.java | 2 +- .../propagation/analytical/gnss/data/GNSSClockElements.java | 2 +- .../orekit/propagation/analytical/gnss/data/GNSSConstants.java | 2 +- .../propagation/analytical/gnss/data/GNSSOrbitalElements.java | 2 +- .../org/orekit/propagation/analytical/gnss/data/GPSAlmanac.java | 2 +- .../analytical/gnss/data/GPSCivilianNavigationMessage.java | 2 +- .../analytical/gnss/data/GPSLegacyNavigationMessage.java | 2 +- .../orekit/propagation/analytical/gnss/data/GalileoAlmanac.java | 2 +- .../analytical/gnss/data/GalileoNavigationMessage.java | 2 +- .../orekit/propagation/analytical/gnss/data/IRNSSAlmanac.java | 2 +- .../analytical/gnss/data/IRNSSNavigationMessage.java | 2 +- .../analytical/gnss/data/LegacyNavigationMessage.java | 2 +- .../orekit/propagation/analytical/gnss/data/QZSSAlmanac.java | 2 +- .../analytical/gnss/data/QZSSCivilianNavigationMessage.java | 2 +- .../analytical/gnss/data/QZSSLegacyNavigationMessage.java | 2 +- .../propagation/analytical/gnss/data/SBASNavigationMessage.java | 2 +- .../propagation/analytical/gnss/data/SBASOrbitalElements.java | 2 +- .../orekit/propagation/analytical/gnss/data/package-info.java | 2 +- .../org/orekit/propagation/analytical/gnss/package-info.java | 2 +- .../java/org/orekit/propagation/analytical/package-info.java | 2 +- .../java/org/orekit/propagation/analytical/tle/DeepSDP4.java | 2 +- .../org/orekit/propagation/analytical/tle/FieldDeepSDP4.java | 2 +- .../java/org/orekit/propagation/analytical/tle/FieldSDP4.java | 2 +- .../java/org/orekit/propagation/analytical/tle/FieldSGP4.java | 2 +- .../java/org/orekit/propagation/analytical/tle/FieldTLE.java | 2 +- .../orekit/propagation/analytical/tle/FieldTLEPropagator.java | 2 +- .../java/org/orekit/propagation/analytical/tle/ParseUtils.java | 2 +- src/main/java/org/orekit/propagation/analytical/tle/SDP4.java | 2 +- src/main/java/org/orekit/propagation/analytical/tle/SGP4.java | 2 +- src/main/java/org/orekit/propagation/analytical/tle/TLE.java | 2 +- .../org/orekit/propagation/analytical/tle/TLEConstants.java | 2 +- .../orekit/propagation/analytical/tle/TLEGradientConverter.java | 2 +- .../org/orekit/propagation/analytical/tle/TLEHarvester.java | 2 +- .../org/orekit/propagation/analytical/tle/TLEPropagator.java | 2 +- .../tle/generation/FixedPointTleGenerationAlgorithm.java | 2 +- .../tle/generation/LeastSquaresTleGenerationAlgorithm.java | 2 +- .../analytical/tle/generation/TleGenerationAlgorithm.java | 2 +- .../analytical/tle/generation/TleGenerationUtil.java | 2 +- .../propagation/analytical/tle/generation/package-info.java | 2 +- .../org/orekit/propagation/analytical/tle/package-info.java | 2 +- .../propagation/conversion/AbstractFieldIntegratorBuilder.java | 2 +- .../conversion/AbstractFixedStepFieldIntegratorBuilder.java | 2 +- .../AbstractLimitedVariableStepFieldIntegratorBuilder.java | 2 +- .../propagation/conversion/AbstractPropagatorBuilder.java | 2 +- .../propagation/conversion/AbstractPropagatorConverter.java | 2 +- .../conversion/AbstractVariableStepFieldIntegratorBuilder.java | 2 +- .../conversion/AdamsBashforthFieldIntegratorBuilder.java | 2 +- .../propagation/conversion/AdamsBashforthIntegratorBuilder.java | 2 +- .../conversion/AdamsMoultonFieldIntegratorBuilder.java | 2 +- .../propagation/conversion/AdamsMoultonIntegratorBuilder.java | 2 +- .../propagation/conversion/BrouwerLyddanePropagatorBuilder.java | 2 +- .../conversion/ClassicalRungeKuttaFieldIntegratorBuilder.java | 2 +- .../conversion/ClassicalRungeKuttaIntegratorBuilder.java | 2 +- .../orekit/propagation/conversion/DSSTPropagatorBuilder.java | 2 +- .../conversion/DormandPrince54FieldIntegratorBuilder.java | 2 +- .../conversion/DormandPrince54IntegratorBuilder.java | 2 +- .../conversion/DormandPrince853FieldIntegratorBuilder.java | 2 +- .../conversion/DormandPrince853IntegratorBuilder.java | 2 +- .../conversion/EcksteinHechlerPropagatorBuilder.java | 2 +- .../propagation/conversion/EulerFieldIntegratorBuilder.java | 2 +- .../orekit/propagation/conversion/EulerIntegratorBuilder.java | 2 +- .../propagation/conversion/FieldODEIntegratorBuilder.java | 2 +- .../conversion/FiniteDifferencePropagatorConverter.java | 2 +- .../propagation/conversion/GillFieldIntegratorBuilder.java | 2 +- .../orekit/propagation/conversion/GillIntegratorBuilder.java | 2 +- .../conversion/GraggBulirschStoerIntegratorBuilder.java | 2 +- .../conversion/HighamHall54FieldIntegratorBuilder.java | 2 +- .../propagation/conversion/HighamHall54IntegratorBuilder.java | 2 +- .../propagation/conversion/JacobianPropagatorConverter.java | 2 +- .../propagation/conversion/KeplerianPropagatorBuilder.java | 2 +- .../propagation/conversion/LutherFieldIntegratorBuilder.java | 2 +- .../orekit/propagation/conversion/LutherIntegratorBuilder.java | 2 +- .../propagation/conversion/MidpointFieldIntegratorBuilder.java | 2 +- .../propagation/conversion/MidpointIntegratorBuilder.java | 2 +- .../propagation/conversion/NumericalPropagatorBuilder.java | 2 +- .../org/orekit/propagation/conversion/ODEIntegratorBuilder.java | 2 +- .../conversion/OsculatingToMeanElementsConverter.java | 2 +- .../org/orekit/propagation/conversion/PropagatorBuilder.java | 2 +- .../org/orekit/propagation/conversion/PropagatorConverter.java | 2 +- .../org/orekit/propagation/conversion/TLEPropagatorBuilder.java | 2 +- .../conversion/ThreeEighthesFieldIntegratorBuilder.java | 2 +- .../propagation/conversion/ThreeEighthesIntegratorBuilder.java | 2 +- .../java/org/orekit/propagation/conversion/package-info.java | 2 +- .../java/org/orekit/propagation/events/AbstractDetector.java | 2 +- .../java/org/orekit/propagation/events/AdaptableInterval.java | 2 +- .../java/org/orekit/propagation/events/AdapterDetector.java | 2 +- .../java/org/orekit/propagation/events/AlignmentDetector.java | 2 +- .../java/org/orekit/propagation/events/AltitudeDetector.java | 2 +- .../orekit/propagation/events/AngularSeparationDetector.java | 2 +- src/main/java/org/orekit/propagation/events/ApsideDetector.java | 2 +- src/main/java/org/orekit/propagation/events/DateDetector.java | 2 +- .../java/org/orekit/propagation/events/EclipseDetector.java | 2 +- .../java/org/orekit/propagation/events/ElevationDetector.java | 2 +- .../orekit/propagation/events/ElevationExtremumDetector.java | 2 +- .../java/org/orekit/propagation/events/EnablingPredicate.java | 2 +- src/main/java/org/orekit/propagation/events/EventDetector.java | 2 +- .../org/orekit/propagation/events/EventDetectorsProvider.java | 2 +- .../orekit/propagation/events/EventEnablingPredicateFilter.java | 2 +- src/main/java/org/orekit/propagation/events/EventShifter.java | 2 +- src/main/java/org/orekit/propagation/events/EventsLogger.java | 2 +- .../org/orekit/propagation/events/ExtremumApproachDetector.java | 2 +- .../org/orekit/propagation/events/FieldAbstractDetector.java | 2 +- .../org/orekit/propagation/events/FieldAdaptableInterval.java | 2 +- .../org/orekit/propagation/events/FieldAdapterDetector.java | 2 +- .../org/orekit/propagation/events/FieldAltitudeDetector.java | 2 +- .../java/org/orekit/propagation/events/FieldApsideDetector.java | 2 +- .../java/org/orekit/propagation/events/FieldDateDetector.java | 2 +- .../org/orekit/propagation/events/FieldEclipseDetector.java | 2 +- .../org/orekit/propagation/events/FieldElevationDetector.java | 2 +- .../propagation/events/FieldElevationExtremumDetector.java | 2 +- .../org/orekit/propagation/events/FieldEnablingPredicate.java | 2 +- .../java/org/orekit/propagation/events/FieldEventDetector.java | 2 +- .../propagation/events/FieldEventEnablingPredicateFilter.java | 2 +- .../java/org/orekit/propagation/events/FieldEventsLogger.java | 2 +- .../propagation/events/FieldLatitudeCrossingDetector.java | 2 +- .../propagation/events/FieldLongitudeCrossingDetector.java | 2 +- .../java/org/orekit/propagation/events/FieldNodeDetector.java | 2 +- .../java/org/orekit/propagation/events/FieldOfViewDetector.java | 2 +- .../events/FieldParameterDrivenDateIntervalDetector.java | 2 +- .../org/orekit/propagation/events/FootprintOverlapDetector.java | 2 +- .../org/orekit/propagation/events/GeographicZoneDetector.java | 2 +- .../org/orekit/propagation/events/GroundAtNightDetector.java | 2 +- .../orekit/propagation/events/GroundFieldOfViewDetector.java | 2 +- .../orekit/propagation/events/HaloXZPlaneCrossingDetector.java | 2 +- .../orekit/propagation/events/InterSatDirectViewDetector.java | 2 +- .../org/orekit/propagation/events/LatitudeCrossingDetector.java | 2 +- .../org/orekit/propagation/events/LatitudeExtremumDetector.java | 2 +- .../orekit/propagation/events/LongitudeCrossingDetector.java | 2 +- .../orekit/propagation/events/LongitudeExtremumDetector.java | 2 +- .../org/orekit/propagation/events/MagneticFieldDetector.java | 2 +- src/main/java/org/orekit/propagation/events/NodeDetector.java | 2 +- .../propagation/events/ParameterDrivenDateIntervalDetector.java | 2 +- .../org/orekit/propagation/events/PositionAngleDetector.java | 2 +- .../java/org/orekit/propagation/events/VisibilityTrigger.java | 2 +- .../org/orekit/propagation/events/handlers/package-info.java | 2 +- src/main/java/org/orekit/propagation/events/package-info.java | 2 +- .../propagation/integration/AbstractGradientConverter.java | 2 +- .../propagation/integration/AbstractIntegratedPropagator.java | 2 +- .../propagation/integration/AdditionalDerivativesProvider.java | 2 +- .../org/orekit/propagation/integration/CombinedDerivatives.java | 2 +- .../integration/FieldAbstractIntegratedPropagator.java | 2 +- .../integration/FieldAdditionalDerivativesProvider.java | 2 +- .../propagation/integration/FieldCombinedDerivatives.java | 2 +- .../propagation/integration/FieldIntegratedEphemeris.java | 2 +- .../org/orekit/propagation/integration/FieldStateMapper.java | 2 +- .../org/orekit/propagation/integration/IntegratedEphemeris.java | 2 +- .../java/org/orekit/propagation/integration/StateMapper.java | 2 +- .../java/org/orekit/propagation/integration/package-info.java | 2 +- .../orekit/propagation/numerical/EpochDerivativesEquations.java | 2 +- .../orekit/propagation/numerical/FieldNumericalPropagator.java | 2 +- .../propagation/numerical/FieldTimeDerivativesEquations.java | 2 +- .../propagation/numerical/GLONASSNumericalPropagator.java | 2 +- .../numerical/GLONASSNumericalPropagatorBuilder.java | 2 +- .../numerical/IntegrableJacobianColumnGenerator.java | 2 +- .../propagation/numerical/NumericalGradientConverter.java | 2 +- .../propagation/numerical/NumericalPropagationHarvester.java | 2 +- .../org/orekit/propagation/numerical/NumericalPropagator.java | 2 +- .../propagation/numerical/StateTransitionMatrixGenerator.java | 2 +- .../orekit/propagation/numerical/TimeDerivativesEquations.java | 2 +- .../org/orekit/propagation/numerical/cr3bp/CR3BPConstants.java | 2 +- .../org/orekit/propagation/numerical/cr3bp/CR3BPForceModel.java | 2 +- .../propagation/numerical/cr3bp/CR3BPMultipleShooter.java | 2 +- .../org/orekit/propagation/numerical/cr3bp/STMEquations.java | 2 +- .../org/orekit/propagation/numerical/cr3bp/package-info.java | 2 +- .../java/org/orekit/propagation/numerical/package-info.java | 2 +- src/main/java/org/orekit/propagation/package-info.java | 2 +- .../propagation/sampling/FieldOrekitFixedStepHandler.java | 2 +- .../org/orekit/propagation/sampling/FieldOrekitStepHandler.java | 2 +- .../propagation/sampling/FieldOrekitStepInterpolator.java | 2 +- .../propagation/sampling/FieldStepHandlerMultiplexer.java | 2 +- .../orekit/propagation/sampling/MultiSatFixedStepHandler.java | 2 +- .../org/orekit/propagation/sampling/MultiSatStepHandler.java | 2 +- .../org/orekit/propagation/sampling/MultisatStepNormalizer.java | 2 +- .../org/orekit/propagation/sampling/OrekitFixedStepHandler.java | 2 +- .../java/org/orekit/propagation/sampling/OrekitStepHandler.java | 2 +- .../org/orekit/propagation/sampling/OrekitStepInterpolator.java | 2 +- .../org/orekit/propagation/sampling/StepHandlerMultiplexer.java | 2 +- src/main/java/org/orekit/propagation/sampling/package-info.java | 2 +- .../propagation/semianalytical/dsst/DSSTGradientConverter.java | 2 +- .../orekit/propagation/semianalytical/dsst/DSSTHarvester.java | 2 +- .../dsst/DSSTIntegrableJacobianColumnGenerator.java | 2 +- .../orekit/propagation/semianalytical/dsst/DSSTPropagator.java | 2 +- .../semianalytical/dsst/DSSTStateTransitionMatrixGenerator.java | 2 +- .../propagation/semianalytical/dsst/FieldDSSTPropagator.java | 2 +- .../dsst/forces/AbstractGaussianContribution.java | 2 +- .../dsst/forces/AbstractGaussianContributionContext.java | 2 +- .../semianalytical/dsst/forces/DSSTAtmosphericDrag.java | 2 +- .../propagation/semianalytical/dsst/forces/DSSTForceModel.java | 2 +- .../semianalytical/dsst/forces/DSSTNewtonianAttraction.java | 2 +- .../dsst/forces/DSSTNewtonianAttractionContext.java | 2 +- .../semianalytical/dsst/forces/DSSTSolarRadiationPressure.java | 2 +- .../propagation/semianalytical/dsst/forces/DSSTTesseral.java | 2 +- .../semianalytical/dsst/forces/DSSTTesseralContext.java | 2 +- .../propagation/semianalytical/dsst/forces/DSSTThirdBody.java | 2 +- .../semianalytical/dsst/forces/DSSTThirdBodyDynamicContext.java | 2 +- .../semianalytical/dsst/forces/DSSTThirdBodyStaticContext.java | 2 +- .../propagation/semianalytical/dsst/forces/DSSTZonal.java | 2 +- .../semianalytical/dsst/forces/DSSTZonalContext.java | 2 +- .../dsst/forces/FieldAbstractGaussianContributionContext.java | 2 +- .../dsst/forces/FieldDSSTNewtonianAttractionContext.java | 2 +- .../semianalytical/dsst/forces/FieldDSSTTesseralContext.java | 2 +- .../dsst/forces/FieldDSSTThirdBodyDynamicContext.java | 2 +- .../semianalytical/dsst/forces/FieldDSSTZonalContext.java | 2 +- .../semianalytical/dsst/forces/FieldForceModelContext.java | 2 +- .../semianalytical/dsst/forces/FieldShortPeriodTerms.java | 2 +- .../semianalytical/dsst/forces/ForceModelContext.java | 2 +- .../semianalytical/dsst/forces/ShortPeriodTerms.java | 2 +- .../propagation/semianalytical/dsst/forces/package-info.java | 2 +- .../orekit/propagation/semianalytical/dsst/package-info.java | 2 +- .../semianalytical/dsst/utilities/AuxiliaryElements.java | 2 +- .../semianalytical/dsst/utilities/CjSjCoefficient.java | 2 +- .../semianalytical/dsst/utilities/CoefficientsFactory.java | 2 +- .../semianalytical/dsst/utilities/FieldAuxiliaryElements.java | 2 +- .../semianalytical/dsst/utilities/FieldCjSjCoefficient.java | 2 +- .../dsst/utilities/FieldFixedNumberInterpolationGrid.java | 2 +- .../semianalytical/dsst/utilities/FieldGHIJjsPolynomials.java | 2 +- .../semianalytical/dsst/utilities/FieldGHmsjPolynomials.java | 2 +- .../semianalytical/dsst/utilities/FieldGammaMnsFunction.java | 2 +- .../semianalytical/dsst/utilities/FieldInterpolationGrid.java | 2 +- .../semianalytical/dsst/utilities/FieldLnsCoefficients.java | 2 +- .../dsst/utilities/FieldMaxGapInterpolationGrid.java | 2 +- .../utilities/FieldShortPeriodicsInterpolatedCoefficient.java | 2 +- .../dsst/utilities/FixedNumberInterpolationGrid.java | 2 +- .../semianalytical/dsst/utilities/GHIJjsPolynomials.java | 2 +- .../semianalytical/dsst/utilities/GHmsjPolynomials.java | 2 +- .../semianalytical/dsst/utilities/GammaMnsFunction.java | 2 +- .../semianalytical/dsst/utilities/InterpolationGrid.java | 2 +- .../semianalytical/dsst/utilities/JacobiPolynomials.java | 2 +- .../semianalytical/dsst/utilities/LnsCoefficients.java | 2 +- .../semianalytical/dsst/utilities/MaxGapInterpolationGrid.java | 2 +- .../semianalytical/dsst/utilities/NewcombOperators.java | 2 +- .../dsst/utilities/ShortPeriodicsInterpolatedCoefficient.java | 2 +- .../propagation/semianalytical/dsst/utilities/UpperBounds.java | 2 +- .../dsst/utilities/hansen/FieldHansenTesseralLinear.java | 2 +- .../dsst/utilities/hansen/FieldHansenThirdBodyLinear.java | 2 +- .../dsst/utilities/hansen/FieldHansenZonalLinear.java | 2 +- .../dsst/utilities/hansen/HansenTesseralLinear.java | 2 +- .../dsst/utilities/hansen/HansenThirdBodyLinear.java | 2 +- .../semianalytical/dsst/utilities/hansen/HansenUtilities.java | 2 +- .../semianalytical/dsst/utilities/hansen/HansenZonalLinear.java | 2 +- .../dsst/utilities/hansen/PolynomialFunctionMatrix.java | 2 +- .../semianalytical/dsst/utilities/hansen/package-info.java | 2 +- .../propagation/semianalytical/dsst/utilities/package-info.java | 2 +- .../org/orekit/propagation/semianalytical/package-info.java | 2 +- .../probability/twod/AbstractAlfriend1999.java | 2 +- .../twod/AbstractShortTermEncounter1DNumerical2DPOCMethod.java | 2 +- .../probability/twod/AbstractShortTermEncounter2DPOCMethod.java | 2 +- .../shorttermencounter/probability/twod/Alfano2005.java | 2 +- .../shorttermencounter/probability/twod/Alfriend1999.java | 2 +- .../shorttermencounter/probability/twod/Alfriend1999Max.java | 2 +- .../collision/shorttermencounter/probability/twod/Chan1997.java | 2 +- .../probability/twod/FieldShortTermEncounter2DDefinition.java | 2 +- .../collision/shorttermencounter/probability/twod/Laas2015.java | 2 +- .../shorttermencounter/probability/twod/Patera2005.java | 2 +- .../probability/twod/ShortTermEncounter2DDefinition.java | 2 +- .../probability/twod/ShortTermEncounter2DPOCMethod.java | 2 +- .../probability/twod/ShortTermEncounter2DPOCMethodType.java | 2 +- .../shorttermencounter/probability/twod/package-info.java | 2 +- .../org/orekit/ssa/metrics/FieldProbabilityOfCollision.java | 2 +- .../java/org/orekit/ssa/metrics/ProbabilityOfCollision.java | 2 +- src/main/java/org/orekit/ssa/metrics/package-info.java | 2 +- src/main/java/org/orekit/ssa/package-info.java | 2 +- src/main/java/org/orekit/time/AGILeapSecondFilesLoader.java | 2 +- src/main/java/org/orekit/time/AbsoluteDate.java | 2 +- .../java/org/orekit/time/AbstractFieldTimeInterpolator.java | 2 +- src/main/java/org/orekit/time/AbstractTimeInterpolator.java | 2 +- src/main/java/org/orekit/time/BDTScale.java | 2 +- src/main/java/org/orekit/time/BurstSelector.java | 2 +- src/main/java/org/orekit/time/ChronologicalComparator.java | 2 +- src/main/java/org/orekit/time/DateComponents.java | 2 +- src/main/java/org/orekit/time/DateTimeComponents.java | 2 +- src/main/java/org/orekit/time/DatesSelector.java | 2 +- src/main/java/org/orekit/time/FieldAbsoluteDate.java | 2 +- src/main/java/org/orekit/time/FieldChronologicalComparator.java | 2 +- src/main/java/org/orekit/time/FieldTimeInterpolator.java | 2 +- src/main/java/org/orekit/time/FieldTimeShiftable.java | 2 +- src/main/java/org/orekit/time/FieldTimeStamped.java | 2 +- src/main/java/org/orekit/time/FieldTimeStampedPair.java | 2 +- src/main/java/org/orekit/time/FixedStepSelector.java | 2 +- src/main/java/org/orekit/time/GLONASSDate.java | 2 +- src/main/java/org/orekit/time/GLONASSScale.java | 2 +- src/main/java/org/orekit/time/GMSTScale.java | 2 +- src/main/java/org/orekit/time/GNSSDate.java | 2 +- src/main/java/org/orekit/time/GPSScale.java | 2 +- src/main/java/org/orekit/time/GalileoScale.java | 2 +- src/main/java/org/orekit/time/IRNSSScale.java | 2 +- src/main/java/org/orekit/time/Month.java | 2 +- src/main/java/org/orekit/time/OffsetModel.java | 2 +- src/main/java/org/orekit/time/QZSSScale.java | 2 +- src/main/java/org/orekit/time/SatelliteClockScale.java | 2 +- src/main/java/org/orekit/time/TAIScale.java | 2 +- src/main/java/org/orekit/time/TAIUTCDatFilesLoader.java | 2 +- src/main/java/org/orekit/time/TCBScale.java | 2 +- src/main/java/org/orekit/time/TCGScale.java | 2 +- src/main/java/org/orekit/time/TDBScale.java | 2 +- src/main/java/org/orekit/time/TTScale.java | 2 +- src/main/java/org/orekit/time/TimeComponents.java | 2 +- src/main/java/org/orekit/time/TimeInterpolator.java | 2 +- src/main/java/org/orekit/time/TimeScalarFunction.java | 2 +- src/main/java/org/orekit/time/TimeScale.java | 2 +- src/main/java/org/orekit/time/TimeScalesFactory.java | 2 +- src/main/java/org/orekit/time/TimeShiftable.java | 2 +- src/main/java/org/orekit/time/TimeStamped.java | 2 +- src/main/java/org/orekit/time/TimeStampedDouble.java | 2 +- .../org/orekit/time/TimeStampedDoubleHermiteInterpolator.java | 2 +- src/main/java/org/orekit/time/TimeStampedField.java | 2 +- .../org/orekit/time/TimeStampedFieldHermiteInterpolator.java | 2 +- src/main/java/org/orekit/time/TimeStampedPair.java | 2 +- src/main/java/org/orekit/time/TimeVectorFunction.java | 2 +- src/main/java/org/orekit/time/UT1Scale.java | 2 +- src/main/java/org/orekit/time/UTCScale.java | 2 +- src/main/java/org/orekit/time/UTCTAIBulletinAFilesLoader.java | 2 +- src/main/java/org/orekit/time/UTCTAIHistoryFilesLoader.java | 2 +- src/main/java/org/orekit/time/UTCTAIOffset.java | 2 +- src/main/java/org/orekit/time/UTCTAIOffsetsLoader.java | 2 +- src/main/java/org/orekit/time/package-info.java | 2 +- src/main/java/org/orekit/utils/AbsolutePVCoordinates.java | 2 +- .../orekit/utils/AbsolutePVCoordinatesHermiteInterpolator.java | 2 +- src/main/java/org/orekit/utils/AbstractMultipleShooting.java | 2 +- src/main/java/org/orekit/utils/AccurateFormatter.java | 2 +- .../java/org/orekit/utils/AggregatedPVCoordinatesProvider.java | 2 +- src/main/java/org/orekit/utils/AngularCoordinates.java | 2 +- src/main/java/org/orekit/utils/AngularDerivativesFilter.java | 2 +- src/main/java/org/orekit/utils/CartesianDerivativesFilter.java | 2 +- .../java/org/orekit/utils/ConstantPVCoordinatesProvider.java | 2 +- src/main/java/org/orekit/utils/Constants.java | 2 +- src/main/java/org/orekit/utils/DateDriver.java | 2 +- src/main/java/org/orekit/utils/Differentiation.java | 2 +- src/main/java/org/orekit/utils/DoubleArrayDictionary.java | 2 +- .../java/org/orekit/utils/ExtendedPVCoordinatesProvider.java | 2 +- .../org/orekit/utils/ExtendedPVCoordinatesProviderAdapter.java | 2 +- src/main/java/org/orekit/utils/FieldAbsolutePVCoordinates.java | 2 +- .../utils/FieldAbsolutePVCoordinatesHermiteInterpolator.java | 2 +- src/main/java/org/orekit/utils/FieldAngularCoordinates.java | 2 +- src/main/java/org/orekit/utils/FieldArrayDictionary.java | 2 +- src/main/java/org/orekit/utils/FieldLegendrePolynomials.java | 2 +- src/main/java/org/orekit/utils/FieldPVCoordinates.java | 2 +- src/main/java/org/orekit/utils/FieldPVCoordinatesProvider.java | 2 +- src/main/java/org/orekit/utils/FieldTimeSpanMap.java | 2 +- src/main/java/org/orekit/utils/FieldTimeStampedCache.java | 2 +- src/main/java/org/orekit/utils/FieldTrackingCoordinates.java | 2 +- src/main/java/org/orekit/utils/Fieldifier.java | 2 +- src/main/java/org/orekit/utils/FrameAdapter.java | 2 +- src/main/java/org/orekit/utils/GenericTimeStampedCache.java | 2 +- src/main/java/org/orekit/utils/IERSConventions.java | 2 +- .../java/org/orekit/utils/ImmutableFieldTimeStampedCache.java | 2 +- src/main/java/org/orekit/utils/LagrangianPoints.java | 2 +- src/main/java/org/orekit/utils/LegendrePolynomials.java | 2 +- src/main/java/org/orekit/utils/LoveNumbers.java | 2 +- src/main/java/org/orekit/utils/MultipleShooter.java | 2 +- src/main/java/org/orekit/utils/MultipleShooting.java | 2 +- src/main/java/org/orekit/utils/OccultationEngine.java | 2 +- src/main/java/org/orekit/utils/OrekitConfiguration.java | 2 +- src/main/java/org/orekit/utils/PVCoordinates.java | 2 +- src/main/java/org/orekit/utils/PVCoordinatesProvider.java | 2 +- src/main/java/org/orekit/utils/ParameterDriver.java | 2 +- src/main/java/org/orekit/utils/ParameterDriversList.java | 2 +- src/main/java/org/orekit/utils/ParameterDriversProvider.java | 2 +- src/main/java/org/orekit/utils/ParameterFunction.java | 2 +- src/main/java/org/orekit/utils/ParameterObserver.java | 2 +- src/main/java/org/orekit/utils/SecularAndHarmonic.java | 2 +- src/main/java/org/orekit/utils/StateFunction.java | 2 +- src/main/java/org/orekit/utils/StateJacobian.java | 2 +- src/main/java/org/orekit/utils/TimeSpanMap.java | 2 +- .../java/org/orekit/utils/TimeStampedAngularCoordinates.java | 2 +- .../utils/TimeStampedAngularCoordinatesHermiteInterpolator.java | 2 +- src/main/java/org/orekit/utils/TimeStampedCache.java | 2 +- .../org/orekit/utils/TimeStampedFieldAngularCoordinates.java | 2 +- .../TimeStampedFieldAngularCoordinatesHermiteInterpolator.java | 2 +- .../java/org/orekit/utils/TimeStampedFieldPVCoordinates.java | 2 +- .../utils/TimeStampedFieldPVCoordinatesHermiteInterpolator.java | 2 +- src/main/java/org/orekit/utils/TimeStampedGenerator.java | 2 +- src/main/java/org/orekit/utils/TimeStampedPVCoordinates.java | 2 +- .../utils/TimeStampedPVCoordinatesHermiteInterpolator.java | 2 +- src/main/java/org/orekit/utils/TrackingCoordinates.java | 2 +- src/main/java/org/orekit/utils/WaypointPVBuilder.java | 2 +- src/main/java/org/orekit/utils/package-info.java | 2 +- src/main/java/org/orekit/utils/units/Lexer.java | 2 +- src/main/java/org/orekit/utils/units/Parser.java | 2 +- src/main/java/org/orekit/utils/units/PowerTerm.java | 2 +- src/main/java/org/orekit/utils/units/Prefix.java | 2 +- src/main/java/org/orekit/utils/units/PrefixedUnit.java | 2 +- src/main/java/org/orekit/utils/units/Token.java | 2 +- src/main/java/org/orekit/utils/units/TokenType.java | 2 +- src/main/java/org/orekit/utils/units/Unit.java | 2 +- src/main/java/org/orekit/utils/units/UnitsCache.java | 2 +- src/main/java/org/orekit/utils/units/UnitsConverter.java | 2 +- src/main/java/org/orekit/utils/units/package-info.java | 2 +- src/site/markdown/architecture/attitudes.md | 2 +- src/site/markdown/architecture/bodies.md | 2 +- src/site/markdown/architecture/ccsds.md | 2 +- src/site/markdown/architecture/errors.md | 2 +- src/site/markdown/architecture/estimation.md | 2 +- src/site/markdown/architecture/forces.md | 2 +- src/site/markdown/architecture/frames.md | 2 +- src/site/markdown/architecture/gnss.md | 2 +- src/site/markdown/architecture/maneuvers.md | 2 +- src/site/markdown/architecture/orbits.md | 2 +- src/site/markdown/architecture/propagation.md | 2 +- src/site/markdown/architecture/tessellation.md | 2 +- src/site/markdown/architecture/time.md | 2 +- src/site/markdown/architecture/tle.md | 2 +- src/site/markdown/architecture/utils.md | 2 +- src/site/markdown/building.md | 2 +- src/site/markdown/contact.md | 2 +- src/site/markdown/contributing.md | 2 +- src/site/markdown/data/application-data.md | 2 +- src/site/markdown/data/contexts.md | 2 +- src/site/markdown/data/custom-filters.md | 2 +- src/site/markdown/data/default-configuration.md | 2 +- src/site/markdown/data/filtering.md | 2 +- src/site/markdown/data/supported-data-types.md | 2 +- src/site/markdown/downloads.md.vm | 2 +- src/site/markdown/faq.md | 2 +- src/site/markdown/guidelines.md | 2 +- src/site/markdown/index.md | 2 +- src/site/markdown/sources.md | 2 +- src/site/site.xml | 2 +- src/test/java/org/orekit/KeyValueFileParser.java | 2 +- src/test/java/org/orekit/SolarInputs97to05.java | 2 +- src/test/java/org/orekit/TestUtils.java | 2 +- src/test/java/org/orekit/Utils.java | 2 +- .../orekit/attitudes/AggregateBoundedAttitudeProviderTest.java | 2 +- .../java/org/orekit/attitudes/AttitudeInterpolatorTest.java | 2 +- src/test/java/org/orekit/attitudes/AttitudeProviderTest.java | 2 +- src/test/java/org/orekit/attitudes/AttitudeTest.java | 2 +- src/test/java/org/orekit/attitudes/AttitudesSequenceTest.java | 2 +- src/test/java/org/orekit/attitudes/BodyCenterPointingTest.java | 2 +- .../java/org/orekit/attitudes/CelestialBodyPointingTest.java | 2 +- .../org/orekit/attitudes/FieldAttitudeInterpolatorTest.java | 2 +- src/test/java/org/orekit/attitudes/FieldAttitudeTest.java | 2 +- src/test/java/org/orekit/attitudes/FixedRateTest.java | 2 +- .../java/org/orekit/attitudes/FrameAlignedProviderTest.java | 2 +- src/test/java/org/orekit/attitudes/GroundPointingTest.java | 2 +- src/test/java/org/orekit/attitudes/LofOffsetPointingTest.java | 2 +- src/test/java/org/orekit/attitudes/LofOffsetTest.java | 2 +- src/test/java/org/orekit/attitudes/NadirPointingTest.java | 2 +- src/test/java/org/orekit/attitudes/SpinStabilizedTest.java | 2 +- src/test/java/org/orekit/attitudes/TabulatedLofOffsetTest.java | 2 +- src/test/java/org/orekit/attitudes/TabulatedProviderTest.java | 2 +- src/test/java/org/orekit/attitudes/TargetPointingTest.java | 2 +- src/test/java/org/orekit/attitudes/TorqueFreeTest.java | 2 +- src/test/java/org/orekit/attitudes/YawCompensationTest.java | 2 +- src/test/java/org/orekit/attitudes/YawSteeringTest.java | 2 +- src/test/java/org/orekit/bodies/CR3BPFactoryTest.java | 2 +- src/test/java/org/orekit/bodies/CR3BPSystemTest.java | 2 +- src/test/java/org/orekit/bodies/CelestialBodyFactoryTest.java | 2 +- src/test/java/org/orekit/bodies/EllipseTest.java | 2 +- src/test/java/org/orekit/bodies/EllipsoidTest.java | 2 +- src/test/java/org/orekit/bodies/FieldEllipseTest.java | 2 +- src/test/java/org/orekit/bodies/IAUPoleFactory.java | 2 +- src/test/java/org/orekit/bodies/JPLEphemeridesLoaderTest.java | 2 +- src/test/java/org/orekit/bodies/LoxodromeTest.java | 2 +- src/test/java/org/orekit/bodies/OneAxisEllipsoidTest.java | 2 +- src/test/java/org/orekit/bodies/PredefinedIAUPolesTest.java | 2 +- src/test/java/org/orekit/bodies/SolarBodyTest.java | 2 +- src/test/java/org/orekit/data/AbstractFilesLoaderTest.java | 2 +- src/test/java/org/orekit/data/AbstractListCrawlerTest.java | 2 +- src/test/java/org/orekit/data/AuthenticatorDialog.java | 2 +- src/test/java/org/orekit/data/ClasspathCrawlerTest.java | 2 +- src/test/java/org/orekit/data/CompositeDataContextTest.java | 2 +- src/test/java/org/orekit/data/DataProvidersManagerTest.java | 2 +- src/test/java/org/orekit/data/DataSourceTest.java | 2 +- src/test/java/org/orekit/data/DirectoryCrawlerTest.java | 2 +- src/test/java/org/orekit/data/FilesListCrawlerTest.java | 2 +- .../java/org/orekit/data/FundamentalNutationArgumentsTest.java | 2 +- src/test/java/org/orekit/data/NetworkCrawlerTest.java | 2 +- src/test/java/org/orekit/data/NutationCodecTest.java | 2 +- src/test/java/org/orekit/data/PoissonSeriesParserTest.java | 2 +- src/test/java/org/orekit/data/PolynomialParserTest.java | 2 +- src/test/java/org/orekit/data/TruncatingFilterTest.java | 2 +- src/test/java/org/orekit/data/UnixCompressFilterTest.java | 2 +- src/test/java/org/orekit/data/ZipJarCrawlerTest.java | 2 +- src/test/java/org/orekit/errors/OrekitExceptionTest.java | 2 +- .../org/orekit/errors/OrekitIllegalArgumentExceptionTest.java | 2 +- .../java/org/orekit/errors/OrekitIllegalStateExceptionTest.java | 2 +- src/test/java/org/orekit/errors/OrekitInternalErrorTest.java | 2 +- src/test/java/org/orekit/errors/OrekitMessagesTest.java | 2 +- src/test/java/org/orekit/errors/OrekitParseExceptionTest.java | 2 +- .../java/org/orekit/errors/TimeStampedCacheExceptionTest.java | 2 +- .../org/orekit/errors/UnsupportedParameterExceptionTest.java | 2 +- .../orekit/estimation/BrouwerLyddaneEstimationTestUtils.java | 2 +- src/test/java/org/orekit/estimation/Context.java | 2 +- src/test/java/org/orekit/estimation/DSSTContext.java | 2 +- .../java/org/orekit/estimation/DSSTEstimationTestUtils.java | 2 +- src/test/java/org/orekit/estimation/DSSTForce.java | 2 +- src/test/java/org/orekit/estimation/EcksteinHechlerContext.java | 2 +- .../orekit/estimation/EcksteinHechlerEstimationTestUtils.java | 2 +- src/test/java/org/orekit/estimation/EphemerisContext.java | 2 +- src/test/java/org/orekit/estimation/EstimationTestUtils.java | 2 +- src/test/java/org/orekit/estimation/Force.java | 2 +- .../org/orekit/estimation/KeplerianEstimationTestUtils.java | 2 +- src/test/java/org/orekit/estimation/TLEContext.java | 2 +- src/test/java/org/orekit/estimation/TLEEstimationTestUtils.java | 2 +- .../orekit/estimation/common/AbstractOrbitDetermination.java | 2 +- src/test/java/org/orekit/estimation/common/AttitudeMode.java | 2 +- src/test/java/org/orekit/estimation/common/AzElParser.java | 2 +- src/test/java/org/orekit/estimation/common/AzimuthLog.java | 2 +- .../org/orekit/estimation/common/BatchLeastSquaresObserver.java | 2 +- src/test/java/org/orekit/estimation/common/ElevationLog.java | 2 +- .../java/org/orekit/estimation/common/EvaluationCounter.java | 2 +- .../java/org/orekit/estimation/common/EvaluationLogger.java | 2 +- src/test/java/org/orekit/estimation/common/Iono.java | 2 +- src/test/java/org/orekit/estimation/common/MeasurementLog.java | 2 +- .../java/org/orekit/estimation/common/MeasurementsParser.java | 2 +- src/test/java/org/orekit/estimation/common/PVData.java | 2 +- src/test/java/org/orekit/estimation/common/PVParser.java | 2 +- src/test/java/org/orekit/estimation/common/ParameterKey.java | 2 +- src/test/java/org/orekit/estimation/common/PositionLog.java | 2 +- src/test/java/org/orekit/estimation/common/PositionOnlyLog.java | 2 +- src/test/java/org/orekit/estimation/common/RangeLog.java | 2 +- src/test/java/org/orekit/estimation/common/RangeParser.java | 2 +- src/test/java/org/orekit/estimation/common/RangeRateLog.java | 2 +- src/test/java/org/orekit/estimation/common/RangeRateParser.java | 2 +- .../org/orekit/estimation/common/ResultBatchLeastSquares.java | 2 +- src/test/java/org/orekit/estimation/common/ResultKalman.java | 2 +- .../estimation/common/ResultSequentialBatchLeastSquares.java | 2 +- src/test/java/org/orekit/estimation/common/StationData.java | 2 +- src/test/java/org/orekit/estimation/common/VelocityLog.java | 2 +- src/test/java/org/orekit/estimation/common/Weights.java | 2 +- src/test/java/org/orekit/estimation/iod/AbstractIodTest.java | 2 +- src/test/java/org/orekit/estimation/iod/IodGaussTest.java | 2 +- src/test/java/org/orekit/estimation/iod/IodGibbsTest.java | 2 +- src/test/java/org/orekit/estimation/iod/IodGoodingTest.java | 2 +- src/test/java/org/orekit/estimation/iod/IodLambertTest.java | 2 +- src/test/java/org/orekit/estimation/iod/IodLaplaceTest.java | 2 +- .../orekit/estimation/leastsquares/BatchLSEstimatorTest.java | 2 +- .../org/orekit/estimation/leastsquares/BatchLSModelTest.java | 2 +- .../leastsquares/BrouwerLyddaneBatchLSEstimatorTest.java | 2 +- .../estimation/leastsquares/DSSTBatchLSEstimatorTest.java | 2 +- .../orekit/estimation/leastsquares/DSSTBatchLSModelTest.java | 2 +- .../estimation/leastsquares/DSSTOrbitDeterminationTest.java | 2 +- .../leastsquares/EcksteinHechlerBatchLSEstimatorTest.java | 2 +- .../estimation/leastsquares/KeplerianBatchLSEstimatorTest.java | 2 +- .../leastsquares/NumericalOrbitDeterminationTest.java | 2 +- .../leastsquares/NumericalSequentialOrbitDeterminationTest.java | 2 +- .../orekit/estimation/leastsquares/TLEBatchLSEstimatorTest.java | 2 +- .../estimation/leastsquares/TLEOrbitDeterminationTest.java | 2 +- .../estimation/measurements/AngularAzElMeasurementCreator.java | 2 +- .../org/orekit/estimation/measurements/AngularAzElTest.java | 2 +- .../estimation/measurements/AngularRaDecMeasurementCreator.java | 2 +- .../org/orekit/estimation/measurements/AngularRaDecTest.java | 2 +- .../measurements/BistaticRangeMeasurementCreator.java | 2 +- .../measurements/BistaticRangeRateMeasurementCreator.java | 2 +- .../orekit/estimation/measurements/BistaticRangeRateTest.java | 2 +- .../org/orekit/estimation/measurements/BistaticRangeTest.java | 2 +- .../estimation/measurements/ComparableMeasurementTest.java | 2 +- .../java/org/orekit/estimation/measurements/DSSTPVTest.java | 2 +- .../orekit/estimation/measurements/FDOAMeasurementCreator.java | 2 +- src/test/java/org/orekit/estimation/measurements/FDOATest.java | 2 +- .../org/orekit/estimation/measurements/GroundStationTest.java | 2 +- .../measurements/InterSatellitesRangeMeasurementCreator.java | 2 +- .../estimation/measurements/InterSatellitesRangeTest.java | 2 +- .../org/orekit/estimation/measurements/MeasurementCreator.java | 2 +- .../estimation/measurements/OneWayRangeMeasurementCreator.java | 2 +- .../orekit/estimation/measurements/PVMeasurementCreator.java | 2 +- src/test/java/org/orekit/estimation/measurements/PVTest.java | 2 +- .../estimation/measurements/PositionMeasurementCreator.java | 2 +- .../java/org/orekit/estimation/measurements/PositionTest.java | 2 +- .../java/org/orekit/estimation/measurements/Range2Test.java | 2 +- .../java/org/orekit/estimation/measurements/RangeAnalytic.java | 2 +- .../org/orekit/estimation/measurements/RangeAnalyticTest.java | 2 +- .../estimation/measurements/RangeRateMeasurementCreator.java | 2 +- .../java/org/orekit/estimation/measurements/RangeRateTest.java | 2 +- src/test/java/org/orekit/estimation/measurements/RangeTest.java | 2 +- .../orekit/estimation/measurements/TDOAMeasurementCreator.java | 2 +- src/test/java/org/orekit/estimation/measurements/TDOATest.java | 2 +- src/test/java/org/orekit/estimation/measurements/TLEPVTest.java | 2 +- .../orekit/estimation/measurements/TurnAroundRangeAnalytic.java | 2 +- .../estimation/measurements/TurnAroundRangeAnalyticTest.java | 2 +- .../measurements/TurnAroundRangeMeasurementCreator.java | 2 +- .../org/orekit/estimation/measurements/TurnAroundRangeTest.java | 2 +- .../estimation/measurements/TwoWayRangeMeasurementCreator.java | 2 +- .../measurements/filtering/ElevationFilteringTest.java | 2 +- .../measurements/filtering/ResidualsFilteringTest.java | 2 +- .../generation/AbstractGroundMeasurementBuilderTest.java | 2 +- .../measurements/generation/AngularAzElBuilderTest.java | 2 +- .../measurements/generation/AngularRaDecBuilderTest.java | 2 +- .../measurements/generation/BistaticRangeBuilderTest.java | 2 +- .../measurements/generation/BistaticRangeRateBuilderTest.java | 2 +- .../estimation/measurements/generation/FDOABuilderTest.java | 2 +- .../estimation/measurements/generation/GeneratorTest.java | 2 +- .../generation/InterSatellitesPhaseBuilderTest.java | 2 +- .../generation/InterSatellitesRangeBuilderTest.java | 2 +- .../generation/MultiplexedMeasurementBuilderTest.java | 2 +- .../measurements/generation/OneWayGNSSPhaseBuilderTest.java | 2 +- .../measurements/generation/OneWayGNSSRangeBuilderTest.java | 2 +- .../estimation/measurements/generation/PVBuilderTest.java | 2 +- .../estimation/measurements/generation/PositionBuilderTest.java | 2 +- .../estimation/measurements/generation/RangeBuilderTest.java | 2 +- .../measurements/generation/RangeRateBuilderTest.java | 2 +- .../estimation/measurements/generation/TDOABuilderTest.java | 2 +- .../measurements/generation/TurnAroundRangeBuilderTest.java | 2 +- .../estimation/measurements/gnss/AbstractLambdaMethodTest.java | 2 +- .../estimation/measurements/gnss/AlternatingSamplerTest.java | 2 +- .../estimation/measurements/gnss/AmbiguitySolverTest.java | 2 +- .../measurements/gnss/GeometryFreeCycleSlipDetectorTest.java | 2 +- .../estimation/measurements/gnss/IntegerBootstrappingTest.java | 2 +- .../measurements/gnss/IntegerLeastSquareComparatorTest.java | 2 +- .../gnss/InterSatellitesPhaseMeasurementCreator.java | 2 +- .../estimation/measurements/gnss/InterSatellitesPhaseTest.java | 2 +- .../measurements/gnss/InterSatellitesWindUpFactoryTest.java | 2 +- .../estimation/measurements/gnss/InterSatellitesWindUpTest.java | 2 +- .../orekit/estimation/measurements/gnss/LambdaMethodTest.java | 2 +- .../measurements/gnss/MeasurementCombinationFactoryTest.java | 2 +- .../estimation/measurements/gnss/ModifiedLambdaMethodTest.java | 2 +- .../estimation/measurements/gnss/OneWayGNSSPhaseCreator.java | 2 +- .../estimation/measurements/gnss/OneWayGNSSPhaseTest.java | 2 +- .../estimation/measurements/gnss/OneWayGNSSRangeCreator.java | 2 +- .../estimation/measurements/gnss/OneWayGNSSRangeTest.java | 2 +- .../estimation/measurements/gnss/PhaseMeasurementCreator.java | 2 +- .../measurements/gnss/PhaseMinusCodeCycleSlipDetectorTest.java | 2 +- .../java/org/orekit/estimation/measurements/gnss/PhaseTest.java | 2 +- .../orekit/estimation/measurements/gnss/WindUpFactoryTest.java | 2 +- .../org/orekit/estimation/measurements/gnss/WindUpTest.java | 2 +- .../measurements/modifiers/AberrationModifierTest.java | 2 +- .../org/orekit/estimation/measurements/modifiers/BiasTest.java | 2 +- .../estimation/measurements/modifiers/IonoModifierTest.java | 2 +- .../OnBoardAntennaInterSatellitesPhaseModifierTest.java | 2 +- .../OnBoardAntennaInterSatellitesRangeModifierTest.java | 2 +- .../modifiers/OnBoardAntennaOneWayGNSSPhaseModifierTest.java | 2 +- .../modifiers/OnBoardAntennaOneWayGNSSRangeModifierTest.java | 2 +- .../modifiers/OnBoardAntennaTurnAroundRangeModifierTest.java | 2 +- .../measurements/modifiers/PhaseCentersOffsetComputerTest.java | 2 +- .../measurements/modifiers/PhaseCentersPhaseModifierTest.java | 2 +- .../measurements/modifiers/PhaseCentersRangeModifierTest.java | 2 +- .../RelativisticClockInterSatellitesPhaseModifierTest.java | 2 +- .../RelativisticClockInterSatellitesRangeModifierTest.java | 2 +- .../modifiers/RelativisticClockOneWayGNSSPhaseModifierTest.java | 2 +- .../modifiers/RelativisticClockOneWayGNSSRangeModifierTest.java | 2 +- .../modifiers/RelativisticClockPhaseModifierTest.java | 2 +- .../modifiers/RelativisticClockRangeModifierTest.java | 2 +- .../modifiers/RelativisticClockRangeRateModifierTest.java | 2 +- .../RelativisticJ2ClockInterSatellitesPhaseModifierTest.java | 2 +- .../RelativisticJ2ClockInterSatellitesRangeModifierTest.java | 2 +- .../RelativisticJ2ClockOneWayGNSSPhaseModifierTest.java | 2 +- .../RelativisticJ2ClockOneWayGNSSRangeModifierTest.java | 2 +- .../modifiers/RelativisticJ2ClockPhaseModifierTest.java | 2 +- .../modifiers/RelativisticJ2ClockRangeModifierTest.java | 2 +- .../modifiers/ShapiroInterSatellitePhaseModifierTest.java | 2 +- .../modifiers/ShapiroInterSatelliteRangeModifierTest.java | 2 +- .../modifiers/ShapiroOneWayGNSSPhaseModifierTest.java | 2 +- .../modifiers/ShapiroOneWayGNSSRangeModifierTest.java | 2 +- .../measurements/modifiers/ShapiroPhaseModifierTest.java | 2 +- .../measurements/modifiers/ShapiroRangeModifierTest.java | 2 +- .../estimation/measurements/modifiers/TropoModifierTest.java | 2 +- .../sequential/BrouwerLyddaneKalmanEstimatorTest.java | 2 +- .../org/orekit/estimation/sequential/KalmanEstimatorTest.java | 2 +- .../orekit/estimation/sequential/KalmanEstimatorUtilTest.java | 2 +- .../java/org/orekit/estimation/sequential/KalmanModelTest.java | 2 +- .../sequential/KalmanNumericalOrbitDeterminationTest.java | 2 +- .../sequential/SemiAnalyticalKalmanEstimatorTest.java | 2 +- .../sequential/SemiAnalyticalUnscentedKalmanModelTest.java | 2 +- .../orekit/estimation/sequential/TLEKalmanEstimatorTest.java | 2 +- .../estimation/sequential/TLEKalmanOrbitDeterminationTest.java | 2 +- .../estimation/sequential/UnivariateprocessNoiseTest.java | 2 +- .../estimation/sequential/UnscentedKalmanEstimatorTest.java | 2 +- .../orekit/estimation/sequential/UnscentedKalmanModelTest.java | 2 +- .../sequential/UnscentedKalmanOrbitDeterminationTest.java | 2 +- .../sequential/UnscentedKalmanOrbitDeterminationTest2.java | 2 +- .../UnscentedSemiAnalyticalKalmanOrbitDeterminationTest.java | 2 +- .../java/org/orekit/files/ccsds/definitions/BodyFacadeTest.java | 2 +- .../orekit/files/ccsds/definitions/CelestialBodyFrameTest.java | 2 +- .../java/org/orekit/files/ccsds/definitions/CenterNameTest.java | 2 +- .../org/orekit/files/ccsds/definitions/FrameFacadeTest.java | 2 +- .../orekit/files/ccsds/definitions/OrbitRelativeFrameTest.java | 2 +- .../org/orekit/files/ccsds/definitions/PocMethodTypeTest.java | 2 +- .../java/org/orekit/files/ccsds/ndm/AbstractWriterTest.java | 2 +- src/test/java/org/orekit/files/ccsds/ndm/NdmParserTest.java | 2 +- src/test/java/org/orekit/files/ccsds/ndm/NdmTestUtils.java | 2 +- src/test/java/org/orekit/files/ccsds/ndm/NdmWriterTest.java | 2 +- .../org/orekit/files/ccsds/ndm/adm/PrecessionFinderTest.java | 2 +- .../java/org/orekit/files/ccsds/ndm/adm/acm/AcmParserTest.java | 2 +- .../java/org/orekit/files/ccsds/ndm/adm/acm/AcmWriterTest.java | 2 +- .../java/org/orekit/files/ccsds/ndm/adm/aem/AEMParserTest.java | 2 +- .../java/org/orekit/files/ccsds/ndm/adm/aem/AemWriterTest.java | 2 +- .../org/orekit/files/ccsds/ndm/adm/aem/AttitudeTypeTest.java | 2 +- .../org/orekit/files/ccsds/ndm/adm/aem/AttitudeWriterTest.java | 2 +- .../orekit/files/ccsds/ndm/adm/aem/StreamingAemWriterTest.java | 2 +- .../java/org/orekit/files/ccsds/ndm/adm/apm/APMParserTest.java | 2 +- .../java/org/orekit/files/ccsds/ndm/adm/apm/ApmWriterTest.java | 2 +- .../java/org/orekit/files/ccsds/ndm/cdm/CdmMetaDataTest.java | 2 +- src/test/java/org/orekit/files/ccsds/ndm/cdm/CdmParserTest.java | 2 +- .../org/orekit/files/ccsds/ndm/cdm/CdmRelativeMetaDataTest.java | 2 +- src/test/java/org/orekit/files/ccsds/ndm/cdm/CdmWriterTest.java | 2 +- .../files/ccsds/ndm/cdm/SigmaEigenvectorsCovarianceTest.java | 2 +- .../orekit/files/ccsds/ndm/odm/ocm/EphemerisOcmWriterTest.java | 2 +- .../java/org/orekit/files/ccsds/ndm/odm/ocm/OcmParserTest.java | 2 +- .../java/org/orekit/files/ccsds/ndm/odm/ocm/OcmWriterTest.java | 2 +- .../orekit/files/ccsds/ndm/odm/ocm/OrbitElementsTypeTest.java | 2 +- .../java/org/orekit/files/ccsds/ndm/odm/ocm/OrderingTest.java | 2 +- .../orekit/files/ccsds/ndm/odm/ocm/StreamingOcmWriterTest.java | 2 +- .../orekit/files/ccsds/ndm/odm/oem/EphemerisOemWriterTest.java | 2 +- .../java/org/orekit/files/ccsds/ndm/odm/oem/OemParserTest.java | 2 +- .../java/org/orekit/files/ccsds/ndm/odm/oem/OemWriterTest.java | 2 +- .../orekit/files/ccsds/ndm/odm/oem/StreamingOemWriterTest.java | 2 +- .../java/org/orekit/files/ccsds/ndm/odm/omm/OmmParserTest.java | 2 +- .../java/org/orekit/files/ccsds/ndm/odm/omm/OmmWriterTest.java | 2 +- .../java/org/orekit/files/ccsds/ndm/odm/opm/OpmParserTest.java | 2 +- .../java/org/orekit/files/ccsds/ndm/odm/opm/OpmWriterTest.java | 2 +- src/test/java/org/orekit/files/ccsds/ndm/tdm/TdmParserTest.java | 2 +- src/test/java/org/orekit/files/ccsds/ndm/tdm/TdmWriterTest.java | 2 +- .../orekit/files/ccsds/utils/generation/KvnGeneratorTest.java | 2 +- .../orekit/files/ccsds/utils/generation/XmlGeneratorTest.java | 2 +- .../files/ccsds/utils/lexical/LexicalAnalyzerSelectorTest.java | 2 +- .../files/ccsds/utils/lexical/XmlLexicalAnalyzerTest.java | 2 +- .../orekit/files/general/EphemerisSegmentPropagatorTest.java | 2 +- .../orekit/files/general/OrekitAttitudeEphemerisFileTest.java | 2 +- .../java/org/orekit/files/general/OrekitEphemerisFileTest.java | 2 +- src/test/java/org/orekit/files/ilrs/CPFWriterTest.java | 2 +- src/test/java/org/orekit/files/ilrs/StreamingCpfWriterTest.java | 2 +- .../java/org/orekit/files/rinex/HatanakaCompressFilterTest.java | 2 +- .../java/org/orekit/files/rinex/clock/ClockFileParserTest.java | 2 +- .../orekit/files/rinex/navigation/NavigationFileParserTest.java | 2 +- .../org/orekit/files/rinex/observation/ObservationTypeTest.java | 2 +- .../files/rinex/observation/RinexObservationParserTest.java | 2 +- .../orekit/files/rinex/observation/RinexObservationTest.java | 2 +- .../files/rinex/observation/RinexObservationWriterTest.java | 2 +- src/test/java/org/orekit/files/sinex/SinexLoaderEopTest.java | 2 +- src/test/java/org/orekit/files/sinex/SinexLoaderTest.java | 2 +- src/test/java/org/orekit/files/sp3/NsgfV00FilterTest.java | 2 +- .../orekit/files/sp3/SP3CoordinateHermiteInterpolatorTest.java | 2 +- src/test/java/org/orekit/files/sp3/SP3TestUtils.java | 2 +- src/test/java/org/orekit/files/sp3/SP3WriterTest.java | 2 +- src/test/java/org/orekit/forces/AbstractForceModelTest.java | 2 +- .../java/org/orekit/forces/AbstractLegacyForceModelTest.java | 2 +- .../java/org/orekit/forces/BoxAndSolarArraySpacecraftTest.java | 2 +- src/test/java/org/orekit/forces/PointingPanelTest.java | 2 +- src/test/java/org/orekit/forces/SlewingPanelTest.java | 2 +- src/test/java/org/orekit/forces/drag/DragForceTest.java | 2 +- src/test/java/org/orekit/forces/drag/TimeSpanDragForceTest.java | 2 +- .../orekit/forces/empirical/HarmonicAccelerationModelTest.java | 2 +- .../forces/empirical/PolynomialAccelerationModelTest.java | 2 +- .../forces/empirical/TimeSpanParametricAccelerationTest.java | 2 +- .../org/orekit/forces/gravity/AssociatedLegendreFunction.java | 2 +- .../java/org/orekit/forces/gravity/DeSitterRelativityTest.java | 2 +- .../forces/gravity/HolmesFeatherstoneAttractionModelTest.java | 2 +- .../org/orekit/forces/gravity/LenseThirringRelativityTest.java | 2 +- .../java/org/orekit/forces/gravity/OceanTidesFieldTest.java | 2 +- src/test/java/org/orekit/forces/gravity/OceanTidesTest.java | 2 +- src/test/java/org/orekit/forces/gravity/OceanTidesWaveTest.java | 2 +- .../java/org/orekit/forces/gravity/ReferenceFieldModel.java | 2 +- .../orekit/forces/gravity/SingleBodyAbsoluteAttractionTest.java | 2 +- .../orekit/forces/gravity/SingleBodyRelativeAttractionTest.java | 2 +- .../java/org/orekit/forces/gravity/SolidTidesFieldTest.java | 2 +- src/test/java/org/orekit/forces/gravity/SolidTidesTest.java | 2 +- .../java/org/orekit/forces/gravity/ThirdBodyAttractionTest.java | 2 +- .../gravity/potential/AstronomicalAmplitudeReaderTest.java | 2 +- .../orekit/forces/gravity/potential/EGMFormatReaderTest.java | 2 +- .../forces/gravity/potential/FESCHatEpsilonReaderTest.java | 2 +- .../orekit/forces/gravity/potential/FESCnmSnmReaderTest.java | 2 +- .../java/org/orekit/forces/gravity/potential/FlattenerTest.java | 2 +- .../orekit/forces/gravity/potential/GRGSFormatReaderTest.java | 2 +- .../forces/gravity/potential/GravityFieldFactoryTest.java | 2 +- .../orekit/forces/gravity/potential/ICGEMFormatReaderTest.java | 2 +- .../gravity/potential/OceanLoadDeformationCoefficientsTest.java | 2 +- .../orekit/forces/gravity/potential/SHMFormatReaderTest.java | 2 +- src/test/java/org/orekit/forces/inertia/InertialForcesTest.java | 2 +- .../org/orekit/forces/maneuvers/ConstantThrustManeuverTest.java | 2 +- .../orekit/forces/maneuvers/Control3DVectorCostTypeTest.java | 2 +- .../org/orekit/forces/maneuvers/FieldImpulseManeuverTest.java | 2 +- .../java/org/orekit/forces/maneuvers/ImpulseManeuverTest.java | 2 +- src/test/java/org/orekit/forces/maneuvers/ManeuverTest.java | 2 +- .../forces/maneuvers/SmallManeuverAnalyticalModelTest.java | 2 +- .../forces/maneuvers/jacobians/TriggersDerivativesTest.java | 2 +- .../propulsion/AbstractConstantThrustPropulsionModelTest.java | 2 +- .../maneuvers/propulsion/ProfileThrustPropulsionModelTest.java | 2 +- .../triggers/AbstractManeuverTriggersInitializationTest.java | 2 +- .../forces/maneuvers/triggers/AbstractManeuverTriggersTest.java | 2 +- .../triggers/IntervalEventTriggerInitializationTest.java | 2 +- .../forces/maneuvers/triggers/IntervalEventTriggerTest.java | 2 +- .../orekit/forces/maneuvers/triggers/ManeuverTriggersTest.java | 2 +- .../triggers/StartStopEventTriggerInitializationTest.java | 2 +- .../forces/maneuvers/triggers/StartStopEventTriggerTest.java | 2 +- src/test/java/org/orekit/forces/radiation/ECOM2Test.java | 2 +- .../orekit/forces/radiation/KnockeRediffusedForceModelTest.java | 2 +- .../org/orekit/forces/radiation/SolarRadiationPressureTest.java | 2 +- src/test/java/org/orekit/frames/BulletinAFilesLoaderTest.java | 2 +- src/test/java/org/orekit/frames/BulletinBFilesLoaderTest.java | 2 +- src/test/java/org/orekit/frames/CIRFProviderTest.java | 2 +- .../org/orekit/frames/CR3BPRotatingTransformProviderTest.java | 2 +- src/test/java/org/orekit/frames/EME2000ProviderTest.java | 2 +- src/test/java/org/orekit/frames/EOPHistoryTest.java | 2 +- src/test/java/org/orekit/frames/EopC04FilesLoaderTest.java | 2 +- src/test/java/org/orekit/frames/EopCsvFilesLoaderTest.java | 2 +- src/test/java/org/orekit/frames/EopXmlLoaderTest.java | 2 +- src/test/java/org/orekit/frames/FieldTransformTest.java | 2 +- src/test/java/org/orekit/frames/FixedTransformProviderTest.java | 2 +- src/test/java/org/orekit/frames/FrameTest.java | 2 +- src/test/java/org/orekit/frames/FramesFactoryTest.java | 2 +- src/test/java/org/orekit/frames/FramesTest.java | 2 +- src/test/java/org/orekit/frames/GTODProviderTest.java | 2 +- src/test/java/org/orekit/frames/HelmertTransformationTest.java | 2 +- src/test/java/org/orekit/frames/ITRFEquinoxProviderTest.java | 2 +- src/test/java/org/orekit/frames/ITRFProviderTest.java | 2 +- .../org/orekit/frames/ITRFProviderWithoutTidalEffectsTest.java | 2 +- src/test/java/org/orekit/frames/ITRFVersionLoaderTest.java | 2 +- src/test/java/org/orekit/frames/ITRFVersionTest.java | 2 +- .../org/orekit/frames/InterpolatingTransformProviderTest.java | 2 +- src/test/java/org/orekit/frames/L1TransformProviderTest.java | 2 +- src/test/java/org/orekit/frames/L2TransformProviderTest.java | 2 +- src/test/java/org/orekit/frames/LazyLoadedFramesTest.java | 2 +- src/test/java/org/orekit/frames/LocalOrbitalFrameTest.java | 2 +- src/test/java/org/orekit/frames/MODProviderTest.java | 2 +- src/test/java/org/orekit/frames/OrphanFrameTest.java | 2 +- src/test/java/org/orekit/frames/PredictedEOPHistoryTest.java | 2 +- .../orekit/frames/RapidDataAndPredictionColumnsLoaderTest.java | 2 +- .../java/org/orekit/frames/ShiftingTransformProviderTest.java | 2 +- src/test/java/org/orekit/frames/TEMEProviderTest.java | 2 +- src/test/java/org/orekit/frames/TIRFProviderTest.java | 2 +- src/test/java/org/orekit/frames/TODProviderTest.java | 2 +- src/test/java/org/orekit/frames/TopocentricFrameTest.java | 2 +- src/test/java/org/orekit/frames/TransformProviderUtilTest.java | 2 +- src/test/java/org/orekit/frames/TransformTest.java | 2 +- src/test/java/org/orekit/frames/TwoBodiesBaryFrameTest.java | 2 +- src/test/java/org/orekit/frames/UpdatableFrameTest.java | 2 +- src/test/java/org/orekit/frames/VEISFrameTest.java | 2 +- src/test/java/org/orekit/frames/VersionedITRFFrameTest.java | 2 +- .../org/orekit/frames/encounter/DefaultEncounterLOFTest.java | 2 +- .../java/org/orekit/frames/encounter/EncounterLOFTypeTest.java | 2 +- .../orekit/frames/encounter/ValsecchiEncounterFrameTest.java | 2 +- .../org/orekit/geometry/fov/AbstractSmoothFieldOfViewTest.java | 2 +- .../java/org/orekit/geometry/fov/CircularFieldOfViewTest.java | 2 +- .../org/orekit/geometry/fov/DoubleDihedraFieldOfViewTest.java | 2 +- .../java/org/orekit/geometry/fov/EllipticalFieldOfViewTest.java | 2 +- .../java/org/orekit/geometry/fov/PolygonalFieldOfViewTest.java | 2 +- src/test/java/org/orekit/gnss/DOPComputerTest.java | 2 +- src/test/java/org/orekit/gnss/SEMParserTest.java | 2 +- src/test/java/org/orekit/gnss/SatelliteSystemParserTest.java | 2 +- src/test/java/org/orekit/gnss/YUMAParserTest.java | 2 +- src/test/java/org/orekit/gnss/antenna/AntexLoaderTest.java | 2 +- src/test/java/org/orekit/gnss/antenna/SatelliteTypeTest.java | 2 +- .../orekit/gnss/attitude/AbstractGNSSAttitudeProviderTest.java | 2 +- src/test/java/org/orekit/gnss/attitude/BeidouGeoTest.java | 2 +- src/test/java/org/orekit/gnss/attitude/BeidouIGSOTest.java | 2 +- src/test/java/org/orekit/gnss/attitude/BeidouMeoTest.java | 2 +- src/test/java/org/orekit/gnss/attitude/GPSBlockIIATest.java | 2 +- src/test/java/org/orekit/gnss/attitude/GPSBlockIIFTest.java | 2 +- src/test/java/org/orekit/gnss/attitude/GPSBlockIIRTest.java | 2 +- src/test/java/org/orekit/gnss/attitude/GalileoTest.java | 2 +- src/test/java/org/orekit/gnss/attitude/GenericGNSSTest.java | 2 +- src/test/java/org/orekit/gnss/attitude/GlonassTest.java | 2 +- .../gnss/metric/messages/rtcm/GlonassUserRangeAccuracyTest.java | 2 +- .../java/org/orekit/gnss/metric/messages/rtcm/Rtcm1019Test.java | 2 +- .../java/org/orekit/gnss/metric/messages/rtcm/Rtcm1020Test.java | 2 +- .../java/org/orekit/gnss/metric/messages/rtcm/Rtcm1042Test.java | 2 +- .../java/org/orekit/gnss/metric/messages/rtcm/Rtcm1044Test.java | 2 +- .../java/org/orekit/gnss/metric/messages/rtcm/Rtcm1045Test.java | 2 +- .../java/org/orekit/gnss/metric/messages/rtcm/Rtcm1057Test.java | 2 +- .../java/org/orekit/gnss/metric/messages/rtcm/Rtcm1058Test.java | 2 +- .../java/org/orekit/gnss/metric/messages/rtcm/Rtcm1060Test.java | 2 +- .../java/org/orekit/gnss/metric/messages/rtcm/Rtcm1063Test.java | 2 +- .../java/org/orekit/gnss/metric/messages/rtcm/Rtcm1064Test.java | 2 +- .../java/org/orekit/gnss/metric/messages/rtcm/Rtcm1066Test.java | 2 +- .../java/org/orekit/gnss/metric/messages/rtcm/Rtcm1240Test.java | 2 +- .../java/org/orekit/gnss/metric/messages/rtcm/Rtcm1241Test.java | 2 +- .../java/org/orekit/gnss/metric/messages/rtcm/Rtcm1243Test.java | 2 +- .../gnss/metric/messages/rtcm/SignalInSpaceAccuracyTest.java | 2 +- .../orekit/gnss/metric/messages/rtcm/SsrUpdateIntervalTest.java | 2 +- .../orekit/gnss/metric/messages/rtcm/UserRangeAccuracyTest.java | 2 +- .../java/org/orekit/gnss/metric/messages/ssr/SsrIgm01Test.java | 2 +- .../java/org/orekit/gnss/metric/messages/ssr/SsrIgm02Test.java | 2 +- .../java/org/orekit/gnss/metric/messages/ssr/SsrIgm03Test.java | 2 +- .../java/org/orekit/gnss/metric/messages/ssr/SsrIgm04Test.java | 2 +- .../java/org/orekit/gnss/metric/messages/ssr/SsrIgm05Test.java | 2 +- .../java/org/orekit/gnss/metric/messages/ssr/SsrIgm06Test.java | 2 +- .../java/org/orekit/gnss/metric/messages/ssr/SsrIgm07Test.java | 2 +- .../java/org/orekit/gnss/metric/messages/ssr/SsrIm201Test.java | 2 +- .../java/org/orekit/gnss/metric/ntrip/CasterRecordTest.java | 2 +- .../java/org/orekit/gnss/metric/ntrip/CountingObserver.java | 2 +- .../java/org/orekit/gnss/metric/ntrip/DataStreamRecordTest.java | 2 +- src/test/java/org/orekit/gnss/metric/ntrip/DummyServer.java | 2 +- src/test/java/org/orekit/gnss/metric/ntrip/GnssDataTest.java | 2 +- .../java/org/orekit/gnss/metric/ntrip/NetworkRecordTest.java | 2 +- src/test/java/org/orekit/gnss/metric/ntrip/NtripClientTest.java | 2 +- .../orekit/gnss/metric/parser/AbstractEncodedMessageTest.java | 2 +- .../orekit/gnss/metric/parser/ByteArrayEncodedMessageTest.java | 2 +- src/test/java/org/orekit/gnss/metric/parser/DataFieldTest.java | 2 +- src/test/java/org/orekit/gnss/metric/parser/DataTypeTest.java | 2 +- .../java/org/orekit/gnss/metric/parser/EncodedMessagesTest.java | 2 +- .../metric/parser/HexadecimalSequenceEncodedMessageTest.java | 2 +- .../org/orekit/gnss/metric/parser/IgsSsrMessageTypeTest.java | 2 +- .../gnss/metric/parser/InputStreamEncodedMessageTest.java | 2 +- .../java/org/orekit/gnss/metric/parser/RtcmMessageTypeTest.java | 2 +- src/test/java/org/orekit/gnss/rflink/gps/SubFramesTest.java | 2 +- .../models/earth/EarthITU453AtmosphereRefractionTest.java | 2 +- .../org/orekit/models/earth/EarthStandardAtmosphereTest.java | 2 +- .../java/org/orekit/models/earth/atmosphere/AtmosphereTest.java | 2 +- .../java/org/orekit/models/earth/atmosphere/DTM2000Test.java | 2 +- .../org/orekit/models/earth/atmosphere/HarrisPriesterTest.java | 2 +- .../java/org/orekit/models/earth/atmosphere/JB2008Test.java | 2 +- .../java/org/orekit/models/earth/atmosphere/NRLMSISE00Test.java | 2 +- .../earth/atmosphere/SimpleExponentialAtmosphereTest.java | 2 +- .../models/earth/atmosphere/data/CommonLineReaderTest.java | 2 +- .../orekit/models/earth/atmosphere/data/DtcDataLoaderTest.java | 2 +- .../earth/atmosphere/data/JB2008SpaceEnvironmentDataTest.java | 2 +- .../data/MarshallSolarActivityFutureEstimationTest.java | 2 +- .../models/earth/atmosphere/data/SOLFSMYDataLoaderTest.java | 2 +- .../models/earth/displacement/TectonicsDisplacementTest.java | 2 +- .../models/earth/ionosphere/EstimatedIonosphericModelTest.java | 2 +- .../models/earth/ionosphere/GlobalIonosphereMapModelTest.java | 2 +- .../earth/ionosphere/KlobucharIonoCoefficientsLoaderTest.java | 2 +- .../org/orekit/models/earth/ionosphere/KlobucharModelTest.java | 2 +- .../org/orekit/models/earth/ionosphere/NeQuickModelTest.java | 2 +- .../earth/ionosphere/SingleLayerModelMappingFunctionTest.java | 2 +- .../models/earth/ionosphere/SsrVtecIonosphericModelTest.java | 2 +- .../orekit/models/earth/tessellation/AlongTrackAimingTest.java | 2 +- .../earth/tessellation/DivertedSingularityAimingTest.java | 2 +- .../models/earth/tessellation/EllipsoidTessellatorTest.java | 2 +- .../java/org/orekit/models/earth/tessellation/TileTest.java | 2 +- .../earth/troposphere/EstimatedTroposphericModelTest.java | 2 +- .../earth/troposphere/FieldGlobalMappingFunctionModelTest.java | 2 +- .../models/earth/troposphere/FieldMendesPavlisModelTest.java | 2 +- .../earth/troposphere/FieldNiellMappingFunctionModelTest.java | 2 +- .../models/earth/troposphere/FieldViennaOneModelTest.java | 2 +- .../models/earth/troposphere/FieldViennaThreeModelTest.java | 2 +- .../earth/troposphere/GlobalMappingFunctionModelTest.java | 2 +- .../orekit/models/earth/troposphere/MendesPavlisModelTest.java | 2 +- .../models/earth/troposphere/NiellMappingFunctionModelTest.java | 2 +- .../troposphere/TimeSpanEstimatedTroposphericModelTest.java | 2 +- .../earth/troposphere/ViennaModelCoefficientsLoaderTest.java | 2 +- .../org/orekit/models/earth/troposphere/ViennaOneModelTest.java | 2 +- .../orekit/models/earth/troposphere/ViennaThreeModelTest.java | 2 +- .../earth/weather/GlobalPressureTemperature2ModelTest.java | 2 +- .../earth/weather/GlobalPressureTemperatureModelTest.java | 2 +- src/test/java/org/orekit/orbits/CartesianOrbitTest.java | 2 +- .../org/orekit/orbits/CircularLatitudeArgumentUtilityTest.java | 2 +- src/test/java/org/orekit/orbits/CircularOrbitTest.java | 2 +- .../orekit/orbits/EquinoctialLongitudeArgumentUtilityTest.java | 2 +- src/test/java/org/orekit/orbits/EquinoctialOrbitTest.java | 2 +- src/test/java/org/orekit/orbits/FieldCartesianOrbitTest.java | 2 +- .../orekit/orbits/FieldCircularLatitudeArgumentUtilityTest.java | 2 +- src/test/java/org/orekit/orbits/FieldCircularOrbitTest.java | 2 +- .../orbits/FieldEquinoctialLongitudeArgumentUtilityTest.java | 2 +- src/test/java/org/orekit/orbits/FieldEquinoctialOrbitTest.java | 2 +- .../org/orekit/orbits/FieldKeplerianAnomalyUtilityTest.java | 2 +- src/test/java/org/orekit/orbits/FieldKeplerianOrbitTest.java | 2 +- src/test/java/org/orekit/orbits/FieldOrbitBlenderTest.java | 2 +- .../org/orekit/orbits/FieldOrbitHermiteInterpolatorTest.java | 2 +- src/test/java/org/orekit/orbits/FieldOrbitTest.java | 2 +- src/test/java/org/orekit/orbits/HaloOrbitTest.java | 2 +- .../java/org/orekit/orbits/KeplerianAnomalyUtilityTest.java | 2 +- src/test/java/org/orekit/orbits/KeplerianOrbitTest.java | 2 +- src/test/java/org/orekit/orbits/LyapunovOrbitTest.java | 2 +- src/test/java/org/orekit/orbits/OrbitBlenderTest.java | 2 +- .../java/org/orekit/orbits/OrbitHermiteInterpolatorTest.java | 2 +- src/test/java/org/orekit/orbits/OrbitTest.java | 2 +- src/test/java/org/orekit/orbits/OrbitTypeTest.java | 2 +- .../org/orekit/propagation/AdditionalStateProviderTest.java | 2 +- .../orekit/propagation/FieldAdditionalStateProviderTest.java | 2 +- .../propagation/FieldSpacecraftStateInterpolatorTest.java | 2 +- .../java/org/orekit/propagation/FieldSpacecraftStateTest.java | 2 +- .../java/org/orekit/propagation/FieldStateCovarianceTest.java | 2 +- .../propagation/PropagatorsParallelizerEphemerisTest.java | 2 +- .../org/orekit/propagation/PropagatorsParallelizerTest.java | 2 +- .../org/orekit/propagation/SpacecraftStateInterpolatorTest.java | 2 +- src/test/java/org/orekit/propagation/SpacecraftStateTest.java | 2 +- .../java/org/orekit/propagation/StateCovarianceBlenderTest.java | 2 +- .../StateCovarianceKeplerianHermiteInterpolatorTest.java | 2 +- .../orekit/propagation/StateCovarianceMatrixProviderTest.java | 2 +- src/test/java/org/orekit/propagation/StateCovarianceTest.java | 2 +- .../orekit/propagation/analytical/AdapterPropagatorTest.java | 2 +- .../propagation/analytical/AggregateBoundedPropagatorTest.java | 2 +- .../propagation/analytical/EcksteinHechlerPropagatorTest.java | 2 +- .../org/orekit/propagation/analytical/EphemerisEventsTest.java | 2 +- .../java/org/orekit/propagation/analytical/EphemerisTest.java | 2 +- .../analytical/FieldEcksteinHechlerPropagatorTest.java | 2 +- .../propagation/analytical/FieldKeplerianPropagatorTest.java | 2 +- .../orekit/propagation/analytical/KeplerianPropagatorTest.java | 2 +- .../orekit/propagation/analytical/TabulatedEphemerisTest.java | 2 +- .../propagation/analytical/gnss/BeidouPropagatorTest.java | 2 +- .../analytical/gnss/GLONASSAnalyticalPropagatorTest.java | 2 +- .../propagation/analytical/gnss/GLONASSOrbitalElementsTest.java | 2 +- .../orekit/propagation/analytical/gnss/GPSPropagatorTest.java | 2 +- .../propagation/analytical/gnss/GalileoPropagatorTest.java | 2 +- .../orekit/propagation/analytical/gnss/IRNSSPropagatorTest.java | 2 +- .../org/orekit/propagation/analytical/gnss/QZSSAlmanacTest.java | 2 +- .../orekit/propagation/analytical/gnss/QZSSPropagatorTest.java | 2 +- .../propagation/analytical/gnss/SBASOrbitalElementsTest.java | 2 +- .../orekit/propagation/analytical/gnss/SBASPropagatorTest.java | 2 +- .../propagation/analytical/tle/FieldTLEPropagatorTest.java | 2 +- .../org/orekit/propagation/analytical/tle/FieldTLETest.java | 2 +- .../orekit/propagation/analytical/tle/TLEPropagatorTest.java | 2 +- .../java/org/orekit/propagation/analytical/tle/TLETest.java | 2 +- .../tle/generation/FixedPointTleGenerationAlgorithmTest.java | 2 +- .../tle/generation/LeastSquaresTleGenerationAlgorithmTest.java | 2 +- .../propagation/conversion/AbstractPropagatorBuilderTest.java | 2 +- .../conversion/BrouwerLyddanePropagatorBuilderTest.java | 2 +- .../propagation/conversion/DSSTPropagatorBuilderTest.java | 2 +- .../propagation/conversion/EcksteinHechlerConverterTest.java | 2 +- .../conversion/EcksteinHechlerPropagatorBuilderTest.java | 2 +- .../propagation/conversion/JacobianPropagatorConverterTest.java | 2 +- .../orekit/propagation/conversion/KeplerianConverterTest.java | 2 +- .../propagation/conversion/KeplerianPropagatorBuilderTest.java | 2 +- .../orekit/propagation/conversion/NumericalConverterTest.java | 2 +- .../propagation/conversion/NumericalPropagatorBuilderTest.java | 2 +- .../conversion/OsculatingToMeanElementsConverterTest.java | 2 +- .../org/orekit/propagation/conversion/TLEConverterTest.java | 2 +- .../orekit/propagation/conversion/TLEPropagatorBuilderTest.java | 2 +- .../java/org/orekit/propagation/events/AdapterDetectorTest.java | 2 +- .../org/orekit/propagation/events/AlignmentDetectorTest.java | 2 +- .../org/orekit/propagation/events/AltitudeDetectorTest.java | 2 +- .../java/org/orekit/propagation/events/AndDetectorTest.java | 2 +- .../propagation/events/AngularSeparationDetectorTest.java | 2 +- .../java/org/orekit/propagation/events/ApsideDetectorTest.java | 2 +- .../org/orekit/propagation/events/BackAndForthDetectorTest.java | 2 +- .../java/org/orekit/propagation/events/DateDetectorTest.java | 2 +- .../java/org/orekit/propagation/events/EclipseDetectorTest.java | 2 +- .../org/orekit/propagation/events/ElevationDetectorTest.java | 2 +- .../propagation/events/ElevationExtremumDetectorTest.java | 2 +- .../java/org/orekit/propagation/events/EventDetectorTest.java | 2 +- .../orekit/propagation/events/EventDetectorsProviderTest.java | 2 +- .../propagation/events/EventEnablingPredicateFilterTest.java | 2 +- .../java/org/orekit/propagation/events/EventShifterTest.java | 2 +- .../org/orekit/propagation/events/EventSlopeFilterTest.java | 2 +- .../java/org/orekit/propagation/events/EventsLoggerTest.java | 2 +- .../orekit/propagation/events/ExtremumApproachDetectorTest.java | 2 +- .../org/orekit/propagation/events/FieldAndDetectorTest.java | 2 +- .../org/orekit/propagation/events/FieldApsideDetectorTest.java | 2 +- .../org/orekit/propagation/events/FieldDateDetectorTest.java | 2 +- .../org/orekit/propagation/events/FieldEclipseDetectorTest.java | 2 +- .../propagation/events/FieldElevationExtremumDetectorTest.java | 2 +- .../org/orekit/propagation/events/FieldEventDetectorTest.java | 2 +- .../events/FieldEventEnablingPredicateFilterTest.java | 2 +- .../orekit/propagation/events/FieldEventSlopeFilterTest.java | 2 +- .../org/orekit/propagation/events/FieldEventsLoggerTest.java | 2 +- .../propagation/events/FieldLatitudeCrossingDetectorTest.java | 2 +- .../org/orekit/propagation/events/FieldNegateDetectorTest.java | 2 +- .../org/orekit/propagation/events/FieldNodeDetectorTest.java | 2 +- .../org/orekit/propagation/events/FieldOfViewDetectorTest.java | 2 +- .../java/org/orekit/propagation/events/FieldOrDetectorTest.java | 2 +- .../events/FieldParameterDrivenDateIntervalDetectorTest.java | 2 +- .../orekit/propagation/events/FootprintOverlapDetectorTest.java | 2 +- .../orekit/propagation/events/GeographicZoneDetectorTest.java | 2 +- .../orekit/propagation/events/GroundAtNightDetectorTest.java | 2 +- .../propagation/events/InterSatDirectViewDetectorTest.java | 2 +- .../orekit/propagation/events/LatitudeCrossingDetectorTest.java | 2 +- .../orekit/propagation/events/LatitudeExtremumDetectorTest.java | 2 +- .../propagation/events/LongitudeCrossingDetectorTest.java | 2 +- .../propagation/events/LongitudeExtremumDetectorTest.java | 2 +- .../orekit/propagation/events/MagneticFieldDetectorTest.java | 2 +- .../java/org/orekit/propagation/events/NegateDetectorTest.java | 2 +- .../java/org/orekit/propagation/events/NodeDetectorTest.java | 2 +- src/test/java/org/orekit/propagation/events/OrDetectorTest.java | 2 +- .../events/ParameterDrivenDateIntervalDetectorTest.java | 2 +- .../orekit/propagation/events/PositionAngleDetectorTest.java | 2 +- .../orekit/propagation/events/handlers/ContinueOnEventTest.java | 2 +- .../orekit/propagation/events/handlers/EventHandlerTest.java | 2 +- .../propagation/events/handlers/FieldStopOnDecreasingTest.java | 2 +- .../propagation/events/handlers/FieldStopOnIncreasingTest.java | 2 +- .../propagation/events/handlers/StopOnDecreasingTest.java | 2 +- .../org/orekit/propagation/events/handlers/StopOnEventTest.java | 2 +- .../propagation/events/handlers/StopOnIncreasingTest.java | 2 +- .../propagation/integration/AbstractGradientConverterTest.java | 2 +- .../integration/AbstractIntegratedPropagatorTest.java | 2 +- .../integration/AdditionalDerivativesProvidersTest.java | 2 +- .../integration/FieldAbstractIntegratedPropagatorTest.java | 2 +- .../integration/FieldAdditionalDerivativesProvidersTest.java | 2 +- .../propagation/integration/FieldIntegratedEphemerisTest.java | 2 +- .../orekit/propagation/integration/IntegratedEphemerisTest.java | 2 +- .../propagation/numerical/FieldNumericalPropagatorTest.java | 2 +- .../propagation/numerical/GLONASSNumericalPropagatorTest.java | 2 +- .../numerical/IntegrableJacobianColumnGeneratorTest.java | 2 +- .../numerical/NumericalPropagationHarvesterTest.java | 2 +- .../orekit/propagation/numerical/NumericalPropagatorTest.java | 2 +- .../java/org/orekit/propagation/numerical/PickupHandler.java | 2 +- .../numerical/StateTransitionMatrixGeneratorTest.java | 2 +- .../orekit/propagation/numerical/cr3bp/CR3BPForceModelTest.java | 2 +- .../propagation/numerical/cr3bp/CR3BPMultipleShooterTest.java | 2 +- .../org/orekit/propagation/sampling/OrekitStepHandlerTest.java | 2 +- .../orekit/propagation/sampling/StepHandlerMultiplexerTest.java | 2 +- .../semianalytical/dsst/DSSTAtmosphericDragTest.java | 2 +- .../dsst/DSSTIntegrableJacobianColumnGeneratorTest.java | 2 +- .../semianalytical/dsst/DSSTNewtonianAttractionTest.java | 2 +- .../propagation/semianalytical/dsst/DSSTPropagatorTest.java | 2 +- .../semianalytical/dsst/DSSTSolarRadiationPressureTest.java | 2 +- .../dsst/DSSTStateTransitionMatrixGeneratorTest.java | 2 +- .../propagation/semianalytical/dsst/DSSTTesseralTest.java | 2 +- .../propagation/semianalytical/dsst/DSSTThirdBodyTest.java | 2 +- .../orekit/propagation/semianalytical/dsst/DSSTZonalTest.java | 2 +- .../semianalytical/dsst/FieldDSSTAtmosphericDragTest.java | 2 +- .../semianalytical/dsst/FieldDSSTNewtonianAttractionTest.java | 2 +- .../semianalytical/dsst/FieldDSSTPropagatorTest.java | 2 +- .../dsst/FieldDSSTSolarRadiationPressureTest.java | 2 +- .../propagation/semianalytical/dsst/FieldDSSTTesseralTest.java | 2 +- .../propagation/semianalytical/dsst/FieldDSSTThirdBodyTest.java | 2 +- .../propagation/semianalytical/dsst/FieldDSSTZonalTest.java | 2 +- .../orekit/propagation/semianalytical/dsst/PickupHandler.java | 2 +- .../semianalytical/dsst/utilities/CoefficientFactoryTest.java | 2 +- .../semianalytical/dsst/utilities/FieldGHmjTest.java | 2 +- .../dsst/utilities/FieldGammaMnsFunctionTest.java | 2 +- .../propagation/semianalytical/dsst/utilities/GHmsjTest.java | 2 +- .../semianalytical/dsst/utilities/GammaMnsFunctionTest.java | 2 +- .../semianalytical/dsst/utilities/JacobiPolynomialsTest.java | 2 +- .../semianalytical/dsst/utilities/NewcombOperatorTest.java | 2 +- .../dsst/utilities/hansen/FieldHansenThirdBodyLinearTest.java | 2 +- .../dsst/utilities/hansen/HansenThirdBodyLinearTest.java | 2 +- .../shorttermencounter/probability/twod/Alfano2005Test.java | 2 +- .../probability/twod/Alfriend1999MaxTest.java | 2 +- .../shorttermencounter/probability/twod/Alfriend1999Test.java | 2 +- .../shorttermencounter/probability/twod/Chan1997Test.java | 2 +- .../twod/FieldShortTermEncounter2DDefinitionTest.java | 2 +- .../shorttermencounter/probability/twod/Laas2015Test.java | 2 +- .../shorttermencounter/probability/twod/Patera2005Test.java | 2 +- .../probability/twod/ShortTermEncounter2DDefinitionTest.java | 2 +- .../probability/twod/ShortTermEncounter2DPOCMethodTypeTest.java | 2 +- .../probability/twod/armellinutils/ArmellinDataLoader.java | 2 +- .../probability/twod/armellinutils/ArmellinDataRow.java | 2 +- .../probability/twod/armellinutils/ArmellinStatistics.java | 2 +- .../org/orekit/ssa/metrics/FieldProbabilityOfCollisionTest.java | 2 +- .../java/org/orekit/ssa/metrics/ProbabilityOfCollisionTest.java | 2 +- src/test/java/org/orekit/time/AGILeapSecondFilesLoaderTest.java | 2 +- .../java/org/orekit/time/AbsoluteDateInitializationTest.java | 2 +- src/test/java/org/orekit/time/AbsoluteDateTest.java | 2 +- src/test/java/org/orekit/time/BDSScaleTest.java | 2 +- src/test/java/org/orekit/time/BurstSelectorStepTest.java | 2 +- src/test/java/org/orekit/time/DateComponentsTest.java | 2 +- src/test/java/org/orekit/time/DateTimeComponentsTest.java | 2 +- src/test/java/org/orekit/time/FieldAbsoluteDateTest.java | 2 +- src/test/java/org/orekit/time/FieldTimeStampedPairTest.java | 2 +- src/test/java/org/orekit/time/FixedStepSelectorTest.java | 2 +- src/test/java/org/orekit/time/GLONASSDateTest.java | 2 +- src/test/java/org/orekit/time/GLONASSScaleTest.java | 2 +- src/test/java/org/orekit/time/GMSTScaleTest.java | 2 +- src/test/java/org/orekit/time/GNSSDateTest.java | 2 +- src/test/java/org/orekit/time/GPSScaleTest.java | 2 +- src/test/java/org/orekit/time/GalileoScaleTest.java | 2 +- src/test/java/org/orekit/time/IRNSSScaleTest.java | 2 +- src/test/java/org/orekit/time/MonthTest.java | 2 +- src/test/java/org/orekit/time/PreloadedTimeScalesTest.java | 2 +- src/test/java/org/orekit/time/QZSSScaleTest.java | 2 +- src/test/java/org/orekit/time/SatelliteClockScaleTest.java | 2 +- src/test/java/org/orekit/time/TAIScaleTest.java | 2 +- src/test/java/org/orekit/time/TAIUTCDatAFilesLoaderTest.java | 2 +- src/test/java/org/orekit/time/TCBScaleTest.java | 2 +- src/test/java/org/orekit/time/TCGScaleTest.java | 2 +- src/test/java/org/orekit/time/TDBScaleTest.java | 2 +- src/test/java/org/orekit/time/TTScaleTest.java | 2 +- src/test/java/org/orekit/time/TimeComponentsTest.java | 2 +- .../orekit/time/TimeStampedFieldHermiteInterpolatorTest.java | 2 +- src/test/java/org/orekit/time/TimeStampedFieldTest.java | 2 +- src/test/java/org/orekit/time/TimeStampedPairTest.java | 2 +- src/test/java/org/orekit/time/UT1ScaleTest.java | 2 +- src/test/java/org/orekit/time/UTCScaleTest.java | 2 +- .../java/org/orekit/time/UTCTAIBulletinAFilesLoaderTest.java | 2 +- .../orekit/time/UTCTAIHistoryFilesLoaderCompressedDataTest.java | 2 +- .../org/orekit/time/UTCTAIHistoryFilesLoaderNoDataTest.java | 2 +- .../orekit/time/UTCTAIHistoryFilesLoaderRegularDataTest.java | 2 +- .../utils/AbsolutePVCoordinatesHermiteInterpolatorTest.java | 2 +- src/test/java/org/orekit/utils/AbsolutePVCoordinatesTest.java | 2 +- src/test/java/org/orekit/utils/AccurateFormatterTest.java | 2 +- .../org/orekit/utils/AggregatedPVCoordinatesProviderTest.java | 2 +- src/test/java/org/orekit/utils/AngularCoordinatesTest.java | 2 +- .../java/org/orekit/utils/AngularDerivativesFilterTest.java | 2 +- .../java/org/orekit/utils/CartesianDerivativesFilterTest.java | 2 +- .../org/orekit/utils/ConstantPVCoordinatesProviderTest.java | 2 +- src/test/java/org/orekit/utils/DateDriverTest.java | 2 +- src/test/java/org/orekit/utils/DifferentiationTest.java | 2 +- src/test/java/org/orekit/utils/DoubleArrayDictionaryTest.java | 2 +- src/test/java/org/orekit/utils/ElevationMaskTest.java | 2 +- .../java/org/orekit/utils/ExtendedPVCoordinatesAdapterTest.java | 2 +- src/test/java/org/orekit/utils/ExtendedPVCoordinatesTest.java | 2 +- .../java/org/orekit/utils/FieldAbsolutePVCoordinatesTest.java | 2 +- src/test/java/org/orekit/utils/FieldAngularCoordinatesTest.java | 2 +- src/test/java/org/orekit/utils/FieldArrayDictionaryTest.java | 2 +- src/test/java/org/orekit/utils/FieldPVCoordinatesTest.java | 2 +- src/test/java/org/orekit/utils/FrameAdapterTest.java | 2 +- src/test/java/org/orekit/utils/GenericTimeStampedCacheTest.java | 2 +- src/test/java/org/orekit/utils/IERSConventionsTest.java | 2 +- src/test/java/org/orekit/utils/MultipleShooterTest.java | 2 +- src/test/java/org/orekit/utils/PVCoordinatesTest.java | 2 +- src/test/java/org/orekit/utils/ParameterDriverTest.java | 2 +- src/test/java/org/orekit/utils/ParameterDriversListTest.java | 2 +- src/test/java/org/orekit/utils/SecularAndHarmonicTest.java | 2 +- src/test/java/org/orekit/utils/TimeSpanMapTest.java | 2 +- .../org/orekit/utils/TimeStampedAngularCoordinatesTest.java | 2 +- .../orekit/utils/TimeStampedFieldAngularCoordinatesTest.java | 2 +- .../org/orekit/utils/TimeStampedFieldPVCoordinatesTest.java | 2 +- .../java/org/orekit/utils/TimeStampedPVCoordinatesTest.java | 2 +- src/test/java/org/orekit/utils/WaypointPVBuilderTest.java | 2 +- src/test/java/org/orekit/utils/units/LexerTest.java | 2 +- src/test/java/org/orekit/utils/units/ParserTest.java | 2 +- src/test/java/org/orekit/utils/units/UnitTest.java | 2 +- src/test/java/org/orekit/utils/units/UnitsConverterTest.java | 2 +- .../attitude/reference-attitude-generator/FindBaseSamples.java | 2 +- .../reference-attitude-generator/GenerateBaseSamples.java | 2 +- 2453 files changed, 2453 insertions(+), 2453 deletions(-) diff --git a/NOTICE.txt b/NOTICE.txt index d3583b1785..577769bdd1 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -1,5 +1,5 @@ OREKIT -Copyright 2002-2023 CS GROUP +Copyright 2002-2024 CS GROUP This product includes software developed by CS GROUP (https://www.csgroup.eu/) diff --git a/build.xml b/build.xml index 35ff750107..7602bcb3bf 100644 --- a/build.xml +++ b/build.xml @@ -64,7 +64,7 @@ - + diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 0a08c10008..4c766d7fc1 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -1,5 +1,5 @@ - @@ -641,8 +641,8 @@ org.apache.maven.wagon - wagon-ssh - ${orekit.maven-wagon-ssh-plugin.version} + wagon-ssh-external + ${orekit.maven-wagon-ssh-external-plugin.version} From 069f1d9355650fa25e8e8ae460b3d7d1ea85180a Mon Sep 17 00:00:00 2001 From: Sebastien Dinot Date: Fri, 2 Feb 2024 10:30:54 +0100 Subject: [PATCH 106/359] Adjusting the site deployment protocol Initially, the uri identifying the deployment target referred to the 'scp:' protocol, but the Wagon SSH External plugin documentation seemed to indicate that it should point to the 'scpexe:' protocol. This doesn't work in the CI context. Signed-off-by: Sebastien Dinot --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9c689f56c0..3106db61ce 100644 --- a/pom.xml +++ b/pom.xml @@ -70,7 +70,7 @@ website - scpexe://cochise@ganymede.orekit.org/var/www/mvn-sites/site-orekit-${project.version} + scp://cochise@ganymede.orekit.org/var/www/mvn-sites/site-orekit-${project.version} From d80d70fb64f9238f6a7a0c3efbe27f5cd1d28a42 Mon Sep 17 00:00:00 2001 From: Sebastien Dinot Date: Fri, 2 Feb 2024 11:16:12 +0100 Subject: [PATCH 107/359] Update CS GROUP website url Signed-off-by: Sebastien Dinot --- pom.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 3106db61ce..bea0bb03d2 100644 --- a/pom.xml +++ b/pom.xml @@ -386,7 +386,7 @@ CS GROUP - http://www.c-s.fr/ + https://www.csgroup.eu/ @@ -685,7 +685,7 @@ - CS GROUP. All rights reserved.]]> + CS GROUP. All rights reserved.]]> https://docs.oracle.com/javase/8/docs/api/ https://www.hipparchus.org/apidocs/ @@ -911,7 +911,7 @@ ${orekit.maven-jxr-plugin.version} false - CS GROUP. All rights reserved.]]> + CS GROUP. All rights reserved.]]> @@ -927,7 +927,7 @@ - CS GROUP. All rights reserved.]]> + CS GROUP. All rights reserved.]]> https://docs.oracle.com/javase/8/docs/api/ https://www.hipparchus.org/apidocs/ From a7524799a6f102e82d80382ee3e99615e844857f Mon Sep 17 00:00:00 2001 From: Sebastien Dinot Date: Fri, 2 Feb 2024 15:33:05 +0100 Subject: [PATCH 108/359] Rely on rsync to deploy Maven site Signed-off-by: Sebastien Dinot --- .gitlab-ci.yml | 21 +++++++++++++-------- pom.xml | 7 ------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 92d7a22484..60411ca7ad 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -27,6 +27,8 @@ variables: MAVEN_CLI_OPTS: "-s .CI/maven-settings.xml --batch-mode --errors --fail-at-end --show-version -DinstallAtEnd=true -DdeployAtEnd=true" SONAR_PROJECT_KEY: "${CI_PROJECT_NAMESPACE}:${CI_PROJECT_NAME}" SONAR_PROJECT_NAME: "${CI_PROJECT_TITLE} (${CI_PROJECT_NAMESPACE}:${CI_PROJECT_NAME})" + # Deployment target properties + TARGET_URL_PREFIX: "cochise@ganymede.orekit.org:/var/www/mvn-sites/site-orekit" verify: stage: verify @@ -101,23 +103,26 @@ deploy:artifacts: paths: - target/*.jar only: - - develop@orekit/orekit - - /^release-[.0-9]+$/@orekit/orekit - master@orekit/orekit + - /^release-[.0-9]+$/@orekit/orekit + - develop@orekit/orekit deploy:site: stage: deploy before_script: - # Create the SSH directory and give it the right permissions + # Prepare the SSH environment required to push documentation onto the server + - eval $(ssh-agent -s) + - echo "$SSH_SECRET_KEY" | ssh-add - - mkdir -p ~/.ssh - chmod 700 ~/.ssh - - echo "$SSH_SECRET_KEY" > ~/.ssh/id_website - - chmod 600 ~/.ssh/id_website - - # Add known hosts - cp $SSH_KNOWN_HOSTS ~/.ssh/known_hosts script: - - mvn $MAVEN_CLI_OPTS site:deploy + - | + PROJECT_VERSION=$(mvn $MAVEN_CLI_OPTS help:evaluate \ + -Dexpression=project.version -q -DforceStdout) + - | + rsync -rz --links --checksum --no-perms --chmod=u=rwX,go=rX --delete-after \ + target/site/ ${TARGET_URL_PREFIX}-${PROJECT_VERSION} only: - master@orekit/orekit - /^release-[.0-9]+$/@orekit/orekit diff --git a/pom.xml b/pom.xml index bea0bb03d2..9ef33f2e10 100644 --- a/pom.xml +++ b/pom.xml @@ -67,13 +67,6 @@ ${tools.jar.dir}/tools.jar - - - website - scp://cochise@ganymede.orekit.org/var/www/mvn-sites/site-orekit-${project.version} - - - Luc Maisonobe From ad4f4dc3640ac0127c7050e775fa4203679fc462 Mon Sep 17 00:00:00 2001 From: Sebastien Dinot Date: Fri, 2 Feb 2024 17:21:36 +0100 Subject: [PATCH 109/359] Specify the remote shell to use The last pipeline failed because rsync could not process the given url. Signed-off-by: Sebastien Dinot --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 60411ca7ad..318276e1ca 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -121,7 +121,7 @@ deploy:site: PROJECT_VERSION=$(mvn $MAVEN_CLI_OPTS help:evaluate \ -Dexpression=project.version -q -DforceStdout) - | - rsync -rz --links --checksum --no-perms --chmod=u=rwX,go=rX --delete-after \ + rsync -rze ssh --links --checksum --no-perms --chmod=u=rwX,go=rX --delete-after \ target/site/ ${TARGET_URL_PREFIX}-${PROJECT_VERSION} only: - master@orekit/orekit From 41687354220d82ee20abbb4063574697fc9d16d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Dinot?= Date: Fri, 2 Feb 2024 21:19:57 +0000 Subject: [PATCH 110/359] Fix syntax error in CI/CD script --- .gitlab-ci.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 318276e1ca..f34567ad10 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -117,11 +117,8 @@ deploy:site: - chmod 700 ~/.ssh - cp $SSH_KNOWN_HOSTS ~/.ssh/known_hosts script: - - | - PROJECT_VERSION=$(mvn $MAVEN_CLI_OPTS help:evaluate \ - -Dexpression=project.version -q -DforceStdout) - - | - rsync -rze ssh --links --checksum --no-perms --chmod=u=rwX,go=rX --delete-after \ + - PROJECT_VERSION=$(mvn $MAVEN_CLI_OPTS help:evaluate -Dexpression=project.version -q -DforceStdout) + - rsync -rze ssh --links --checksum --no-perms --chmod=u=rwX,go=rX --delete-after target/site/ ${TARGET_URL_PREFIX}-${PROJECT_VERSION} only: - master@orekit/orekit From acfc6b9779b162718ce1eddbcfffdd35ce15d164 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Dinot?= Date: Fri, 2 Feb 2024 22:40:41 +0000 Subject: [PATCH 111/359] Temporary code added for deployment debugging purpose --- .gitlab-ci.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f34567ad10..c0847ec78c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -33,6 +33,14 @@ variables: verify: stage: verify script: + # >>> SDT 2024-02-02: code for debugging purpose + - pwd + - ZOINX=$(pwd) + - echo ${ZOINX} + - echo $ZOINX + - PROJECT_VERSION=$(mvn $MAVEN_CLI_OPTS help:evaluate -Dexpression=project.version -q -DforceStdout) + - echo ${PROJECT_VERSION} + # <<< SDT 2024-02-02: code for debugging purpose - mvn $MAVEN_CLI_OPTS checkstyle:check verify site - test -z "$SONAR_TOKEN" || mvn $MAVEN_CLI_OPTS sonar:sonar -Dsonar.login=${SONAR_TOKEN} From e1c2fabe802beaf6eb1b664dccff9e08daa47b77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Dinot?= Date: Fri, 2 Feb 2024 22:44:57 +0000 Subject: [PATCH 112/359] Temporary code added for deployment debugging purpose --- .gitlab-ci.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c0847ec78c..5e466a16b3 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -34,11 +34,7 @@ verify: stage: verify script: # >>> SDT 2024-02-02: code for debugging purpose - - pwd - - ZOINX=$(pwd) - - echo ${ZOINX} - - echo $ZOINX - - PROJECT_VERSION=$(mvn $MAVEN_CLI_OPTS help:evaluate -Dexpression=project.version -q -DforceStdout) + - PROJECT_VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout) - echo ${PROJECT_VERSION} # <<< SDT 2024-02-02: code for debugging purpose - mvn $MAVEN_CLI_OPTS checkstyle:check verify site From 9b94aff622944c616add36d7a22a070294896bb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Dinot?= Date: Fri, 2 Feb 2024 22:49:24 +0000 Subject: [PATCH 113/359] Temporary code added for deployment debugging purpose --- .gitlab-ci.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5e466a16b3..9eacb17442 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -32,10 +32,22 @@ variables: verify: stage: verify + before_script: + # >>> SDT 2024-02-02: code for debugging purpose + - eval $(ssh-agent -s) + - echo "$SSH_SECRET_KEY" | ssh-add - + - mkdir -p ~/.ssh + - chmod 700 ~/.ssh + - cp $SSH_KNOWN_HOSTS ~/.ssh/known_hosts + # <<< SDT 2024-02-02: code for debugging purpose script: # >>> SDT 2024-02-02: code for debugging purpose - PROJECT_VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout) - echo ${PROJECT_VERSION} + - mkdir zoinx + - ls -l > zoinx/list.txt + - rsync -rze ssh --links --checksum --no-perms --chmod=u=rwX,go=rX --delete-after + zoinx/ ${TARGET_URL_PREFIX}-zoinx # <<< SDT 2024-02-02: code for debugging purpose - mvn $MAVEN_CLI_OPTS checkstyle:check verify site - test -z "$SONAR_TOKEN" || mvn $MAVEN_CLI_OPTS sonar:sonar From 3b7871b37b1b5a0e7e0689e43ba07d5b0f4951a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Dinot?= Date: Fri, 2 Feb 2024 22:53:28 +0000 Subject: [PATCH 114/359] Temporary code added for deployment debugging purpose --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9eacb17442..250d82960c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -46,8 +46,8 @@ verify: - echo ${PROJECT_VERSION} - mkdir zoinx - ls -l > zoinx/list.txt - - rsync -rze ssh --links --checksum --no-perms --chmod=u=rwX,go=rX --delete-after - zoinx/ ${TARGET_URL_PREFIX}-zoinx + - rsync -rz --links --checksum --no-perms --chmod=u=rwX,go=rX --delete-after + zoinx/ ${TARGET_URL_PREFIX}-${PROJECT_VERSION} # <<< SDT 2024-02-02: code for debugging purpose - mvn $MAVEN_CLI_OPTS checkstyle:check verify site - test -z "$SONAR_TOKEN" || mvn $MAVEN_CLI_OPTS sonar:sonar From c2291ef42b5a6141d95da6845287f519c659f366 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Dinot?= Date: Fri, 2 Feb 2024 22:57:17 +0000 Subject: [PATCH 115/359] Remove temporary code --- .gitlab-ci.yml | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 250d82960c..fed0decb12 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -32,23 +32,7 @@ variables: verify: stage: verify - before_script: - # >>> SDT 2024-02-02: code for debugging purpose - - eval $(ssh-agent -s) - - echo "$SSH_SECRET_KEY" | ssh-add - - - mkdir -p ~/.ssh - - chmod 700 ~/.ssh - - cp $SSH_KNOWN_HOSTS ~/.ssh/known_hosts - # <<< SDT 2024-02-02: code for debugging purpose script: - # >>> SDT 2024-02-02: code for debugging purpose - - PROJECT_VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout) - - echo ${PROJECT_VERSION} - - mkdir zoinx - - ls -l > zoinx/list.txt - - rsync -rz --links --checksum --no-perms --chmod=u=rwX,go=rX --delete-after - zoinx/ ${TARGET_URL_PREFIX}-${PROJECT_VERSION} - # <<< SDT 2024-02-02: code for debugging purpose - mvn $MAVEN_CLI_OPTS checkstyle:check verify site - test -z "$SONAR_TOKEN" || mvn $MAVEN_CLI_OPTS sonar:sonar -Dsonar.login=${SONAR_TOKEN} @@ -133,8 +117,8 @@ deploy:site: - chmod 700 ~/.ssh - cp $SSH_KNOWN_HOSTS ~/.ssh/known_hosts script: - - PROJECT_VERSION=$(mvn $MAVEN_CLI_OPTS help:evaluate -Dexpression=project.version -q -DforceStdout) - - rsync -rze ssh --links --checksum --no-perms --chmod=u=rwX,go=rX --delete-after + - PROJECT_VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout) + - rsync -rz --links --checksum --no-perms --chmod=u=rwX,go=rX --delete-after target/site/ ${TARGET_URL_PREFIX}-${PROJECT_VERSION} only: - master@orekit/orekit From 7f1a00452ee65ff523b101af58cdd391ded0e336 Mon Sep 17 00:00:00 2001 From: Serrof Date: Fri, 19 Jan 2024 21:12:35 +0100 Subject: [PATCH 116/359] fixes #1306: implement resetIntermediateState in (Field)TLEPropagator --- src/changes/changes.xml | 3 + .../analytical/tle/FieldTLEPropagator.java | 96 +++++++++++++------ .../analytical/tle/TLEPropagator.java | 65 ++++++++++--- .../tle/FieldTLEPropagatorTest.java | 64 ++++++++++++- .../analytical/tle/TLEPropagatorTest.java | 84 ++++++++++++++++ 5 files changed, 265 insertions(+), 47 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 8ee6b6aea0..0688961db5 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -21,6 +21,9 @@ + + Implement resetIntermediateState in (Field)TLEPropagator. + Add default implementation of getPosition in (Field)Propagator. diff --git a/src/main/java/org/orekit/propagation/analytical/tle/FieldTLEPropagator.java b/src/main/java/org/orekit/propagation/analytical/tle/FieldTLEPropagator.java index adb65cf9b2..0ba4ce2479 100644 --- a/src/main/java/org/orekit/propagation/analytical/tle/FieldTLEPropagator.java +++ b/src/main/java/org/orekit/propagation/analytical/tle/FieldTLEPropagator.java @@ -17,7 +17,9 @@ package org.orekit.propagation.analytical.tle; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.hipparchus.CalculusFieldElement; import org.hipparchus.geometry.euclidean.threed.FieldVector3D; @@ -41,6 +43,7 @@ import org.orekit.utils.FieldPVCoordinates; import org.orekit.utils.PVCoordinates; import org.orekit.utils.ParameterDriver; +import org.orekit.utils.TimeSpanMap; /** This class provides elements to propagate TLE's. @@ -175,8 +178,11 @@ public abstract class FieldTLEPropagator> exte /** TLE frame. */ private final Frame teme; - /** Spacecraft mass (kg). */ - private final T mass; + /** Spacecraft masses (kg) mapped to TLEs. */ + private Map, T> masses; + + /** All TLEs. */ + private TimeSpanMap> tles; /** Protected constructor for derived classes. * @@ -189,12 +195,9 @@ public abstract class FieldTLEPropagator> exte * @see #FieldTLEPropagator(FieldTLE, AttitudeProvider, CalculusFieldElement, Frame, CalculusFieldElement[]) */ @DefaultDataContext - protected FieldTLEPropagator(final FieldTLE initialTLE, - final AttitudeProvider attitudeProvider, - final T mass, - final T[] parameters) { - this(initialTLE, attitudeProvider, mass, - DataContext.getDefault().getFrames().getTEME(), parameters); + protected FieldTLEPropagator(final FieldTLE initialTLE, final AttitudeProvider attitudeProvider, final T mass, + final T[] parameters) { + this(initialTLE, attitudeProvider, mass, DataContext.getDefault().getFrames().getTEME(), parameters); } /** Protected constructor for derived classes. @@ -204,17 +207,16 @@ protected FieldTLEPropagator(final FieldTLE initialTLE, * @param teme the TEME frame to use for propagation. * @param parameters SGP4 and SDP4 model parameters */ - protected FieldTLEPropagator(final FieldTLE initialTLE, - final AttitudeProvider attitudeProvider, - final T mass, - final Frame teme, - final T[] parameters) { + protected FieldTLEPropagator(final FieldTLE initialTLE, final AttitudeProvider attitudeProvider, final T mass, + final Frame teme, final T[] parameters) { super(initialTLE.getE().getField(), attitudeProvider); setStartDate(initialTLE.getDate()); - this.tle = initialTLE; - this.teme = teme; - this.mass = mass; - this.utc = initialTLE.getUtc(); + this.utc = initialTLE.getUtc(); + initializeTle(initialTLE); + this.teme = teme; + this.tles = new TimeSpanMap<>(tle); + this.masses = new HashMap<>(); + this.masses.put(tle, mass); initializeCommons(parameters); sxpInitialize(parameters); @@ -341,7 +343,7 @@ public FieldPVCoordinates getPVCoordinates(final FieldAbsoluteDate date, f */ private void initializeCommons(final T[] parameters) { - final T zero = mass.getField().getZero(); + final T zero = tle.getDate().getField().getZero(); final T bStar = parameters[0]; final T a1 = tle.getMeanMotion().multiply(60.0).reciprocal().multiply(TLEConstants.XKE).pow(TLEConstants.TWO_THIRD); cosi0 = FastMath.cos(tle.getI()); @@ -441,7 +443,7 @@ private void initializeCommons(final T[] parameters) { */ private FieldPVCoordinates computePVCoordinates() { - final T zero = mass.getField().getZero(); + final T zero = tle.getDate().getField().getZero(); // Long period periodics final T axn = e.multiply(FastMath.cos(omega)); T temp = a.multiply(e.multiply(e).negate().add(1.0)).reciprocal(); @@ -542,9 +544,10 @@ private FieldPVCoordinates computePVCoordinates() { final T cr = rk.multiply(1000 * TLEConstants.EARTH_RADIUS); final FieldVector3D pos = new FieldVector3D<>(cr.multiply(ux), cr.multiply(uy), cr.multiply(uz)); - final T rdot = FastMath.sqrt(a).multiply(esinE.divide(r)).multiply(TLEConstants.XKE); + final T sqrtA = FastMath.sqrt(a); + final T rdot = sqrtA.multiply(esinE.divide(r)).multiply(TLEConstants.XKE); final T rfdot = FastMath.sqrt(pl).divide(r).multiply(TLEConstants.XKE); - final T xn = a.multiply(FastMath.sqrt(a)).reciprocal().multiply(TLEConstants.XKE); + final T xn = a.multiply(sqrtA).reciprocal().multiply(TLEConstants.XKE); final T rdotk = rdot.subtract(xn.multiply(temp1).multiply(x1mth2).multiply(sin2u)); final T rfdotk = rfdot.add(xn.multiply(temp1).multiply(x1mth2.multiply(cos2u).add(x3thm1.multiply(1.5)))); final T vx = xmx.multiply(cosuk).subtract(cosnok.multiply(sinuk)); @@ -555,7 +558,7 @@ private FieldPVCoordinates computePVCoordinates() { final FieldVector3D vel = new FieldVector3D<>(rdotk.multiply(ux).add(rfdotk.multiply(vx)).multiply(cv), rdotk.multiply(uy).add(rfdotk.multiply(vy)).multiply(cv), rdotk.multiply(uz).add(rfdotk.multiply(vz)).multiply(cv)); - return new FieldPVCoordinates(pos, vel); + return new FieldPVCoordinates<>(pos, vel); } @@ -586,30 +589,61 @@ public List getParametersDrivers() { */ public void resetInitialState(final FieldSpacecraftState state) { super.resetInitialState(state); - super.setStartDate(state.getDate()); - final TleGenerationAlgorithm algorithm = TLEPropagator.getDefaultTleGenerationAlgorithm(utc, teme); - final FieldTLE newTLE = algorithm.generate(state, tle); - this.tle = newTLE; - initializeCommons(tle.getParameters(state.getDate().getField())); - sxpInitialize(tle.getParameters(state.getDate().getField())); + resetTle(state); + masses = new HashMap<>(); + masses.put(tle, state.getMass()); + tles = new TimeSpanMap<>(tle); } /** {@inheritDoc} */ protected void resetIntermediateState(final FieldSpacecraftState state, final boolean forward) { - throw new OrekitException(OrekitMessages.NON_RESETABLE_STATE); + resetTle(state); + if (forward) { + tles.addValidAfter(tle, state.getDate().toAbsoluteDate(), false); + } else { + tles.addValidBefore(tle, state.getDate().toAbsoluteDate(), false); + } + stateChanged(state); + masses.put(tle, state.getMass()); + } + + /** Reset internal TLE from a SpacecraftState. + * @param state spacecraft state on which to base new TLE + */ + private void resetTle(final FieldSpacecraftState state) { + final TleGenerationAlgorithm algorithm = TLEPropagator.getDefaultTleGenerationAlgorithm(utc, teme); + final FieldTLE newTle = algorithm.generate(state, tle); + initializeTle(newTle); + } + + /** Initialize internal TLE. + * @param newTle tle to replace current one + */ + private void initializeTle(final FieldTLE newTle) { + tle = newTle; + final T[] parameters = tle.getParameters(tle.getDate().getField()); + initializeCommons(parameters); + sxpInitialize(parameters); } /** {@inheritDoc} */ protected T getMass(final FieldAbsoluteDate date) { - return mass; + return masses.get(tles.get(date.toAbsoluteDate())); } /** {@inheritDoc} */ public FieldOrbit propagateOrbit(final FieldAbsoluteDate date, final T[] parameters) { - return new FieldCartesianOrbit<>(getPVCoordinates(date, parameters), teme, date, date.getField().getZero().newInstance(TLEConstants.MU)); + final FieldTLE closestTle = tles.get(date.toAbsoluteDate()); + if (!tle.equals(closestTle)) { + initializeTle(closestTle); + } + final T mu = date.getField().getZero().newInstance(TLEConstants.MU); + return new FieldCartesianOrbit<>(getPVCoordinates(date, parameters), teme, date, mu); } /** Get the underlying TLE. + * If there has been calls to #resetInitialState or #resetIntermediateState, + * it will not be the same as given to the constructor. * @return underlying TLE */ public FieldTLE getTLE() { diff --git a/src/main/java/org/orekit/propagation/analytical/tle/TLEPropagator.java b/src/main/java/org/orekit/propagation/analytical/tle/TLEPropagator.java index 029db82a18..d3e253629d 100644 --- a/src/main/java/org/orekit/propagation/analytical/tle/TLEPropagator.java +++ b/src/main/java/org/orekit/propagation/analytical/tle/TLEPropagator.java @@ -18,7 +18,9 @@ import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.hipparchus.geometry.euclidean.threed.Vector3D; import org.hipparchus.linear.RealMatrix; @@ -46,6 +48,7 @@ import org.orekit.utils.DoubleArrayDictionary; import org.orekit.utils.PVCoordinates; import org.orekit.utils.ParameterDriver; +import org.orekit.utils.TimeSpanMap; import org.orekit.utils.TimeSpanMap.Span; @@ -178,8 +181,11 @@ public abstract class TLEPropagator extends AbstractAnalyticalPropagator { /** TLE frame. */ private final Frame teme; - /** Spacecraft mass (kg). */ - private final double mass; + /** Spacecraft masses (kg) mapped to TLEs. */ + private Map masses; + + /** All TLEs. */ + private TimeSpanMap tles; /** Protected constructor for derived classes. * @@ -210,13 +216,13 @@ protected TLEPropagator(final TLE initialTLE, final Frame teme) { super(attitudeProvider); setStartDate(initialTLE.getDate()); - this.tle = initialTLE; - this.teme = teme; - this.mass = mass; this.utc = initialTLE.getUtc(); + initializeTle(initialTLE); + this.teme = teme; + this.tles = new TimeSpanMap<>(tle); + this.masses = new HashMap<>(); + this.masses.put(tle, mass); - initializeCommons(); - sxpInitialize(); // set the initial state final Orbit orbit = propagateOrbit(initialTLE.getDate()); final Attitude attitude = attitudeProvider.getAttitude(orbit, orbit.getDate(), orbit.getFrame()); @@ -558,30 +564,59 @@ private PVCoordinates computePVCoordinates() { */ public void resetInitialState(final SpacecraftState state) { super.resetInitialState(state); - super.setStartDate(state.getDate()); - final TleGenerationAlgorithm algorithm = getDefaultTleGenerationAlgorithm(utc, teme); - final TLE newTLE = algorithm.generate(state, tle); - this.tle = newTLE; - initializeCommons(); - sxpInitialize(); + resetTle(state); + masses = new HashMap<>(); + masses.put(tle, state.getMass()); + tles = new TimeSpanMap<>(tle); } /** {@inheritDoc} */ protected void resetIntermediateState(final SpacecraftState state, final boolean forward) { - throw new OrekitException(OrekitMessages.NON_RESETABLE_STATE); + resetTle(state); + if (forward) { + tles.addValidAfter(tle, state.getDate(), false); + } else { + tles.addValidBefore(tle, state.getDate(), false); + } + stateChanged(state); + masses.put(tle, state.getMass()); + } + + /** Reset internal TLE from a SpacecraftState. + * @param state spacecraft state on which to base new TLE + */ + private void resetTle(final SpacecraftState state) { + final TleGenerationAlgorithm algorithm = getDefaultTleGenerationAlgorithm(utc, teme); + final TLE newTle = algorithm.generate(state, tle); + initializeTle(newTle); + } + + /** Initialize internal TLE. + * @param newTle tle to replace current one + */ + private void initializeTle(final TLE newTle) { + tle = newTle; + initializeCommons(); + sxpInitialize(); } /** {@inheritDoc} */ protected double getMass(final AbsoluteDate date) { - return mass; + return masses.get(tles.get(date)); } /** {@inheritDoc} */ protected Orbit propagateOrbit(final AbsoluteDate date) { + final TLE closestTle = tles.get(date); + if (!tle.equals(closestTle)) { + initializeTle(closestTle); + } return new CartesianOrbit(getPVCoordinates(date), teme, date, TLEConstants.MU); } /** Get the underlying TLE. + * If there has been calls to #resetInitialState or #resetIntermediateState, + * it will not be the same as given to the constructor. * @return underlying TLE */ public TLE getTLE() { diff --git a/src/test/java/org/orekit/propagation/analytical/tle/FieldTLEPropagatorTest.java b/src/test/java/org/orekit/propagation/analytical/tle/FieldTLEPropagatorTest.java index 3d76426cf2..2cea0637ce 100644 --- a/src/test/java/org/orekit/propagation/analytical/tle/FieldTLEPropagatorTest.java +++ b/src/test/java/org/orekit/propagation/analytical/tle/FieldTLEPropagatorTest.java @@ -19,6 +19,8 @@ import org.hamcrest.MatcherAssert; import org.hipparchus.CalculusFieldElement; import org.hipparchus.Field; +import org.hipparchus.analysis.differentiation.Gradient; +import org.hipparchus.analysis.differentiation.GradientField; import org.hipparchus.geometry.euclidean.threed.FieldLine; import org.hipparchus.geometry.euclidean.threed.FieldRotation; import org.hipparchus.geometry.euclidean.threed.FieldVector3D; @@ -288,11 +290,71 @@ public > void doTestComparisonWithNonField(Fie } + @Test + void testResetInitialState() { + // GIVEN + final FieldTLE tle = getGradientTLE(); + final Field field = tle.getDate().getField(); + final Gradient[] parameters = tle.getParameters(field); + final FieldTLEPropagator tlePropagator = FieldTLEPropagator.selectExtrapolator(tle, parameters); + final FieldSpacecraftState initialState = tlePropagator.getInitialState(); + final Gradient unexpectedMass = initialState.getMass(); + final Gradient expectedMass = unexpectedMass.multiply(2); + final FieldSpacecraftState newState = new FieldSpacecraftState<>(initialState.getOrbit(), + initialState.getAttitude(), expectedMass); + + // WHEN + tlePropagator.resetInitialState(newState); + + // THEN + final FieldSpacecraftState actualState = tlePropagator.getInitialState(); + Assertions.assertEquals(expectedMass.getReal(), tlePropagator.getMass(actualState.getDate()).getReal()); + Assertions.assertEquals(expectedMass.getReal(), actualState.getMass().getReal()); + Assertions.assertNotEquals(unexpectedMass.getReal(), actualState.getMass().getReal()); + } + + private FieldTLE getGradientTLE() { + final String line1 = "1 37753U 11036A 12090.13205652 -.00000006 00000-0 00000+0 0 2272"; + final String line2 = "2 37753 55.0032 176.5796 0004733 13.2285 346.8266 2.00565440 5153"; + final GradientField field = GradientField.getField(1); + return new FieldTLE<>(field, line1, line2); + } + + @Test + void testResetIntermediateStateForward() { + testResetIntermediateStateTemplate(true); + } + + @Test + void testResetIntermediateStateBackward() { + testResetIntermediateStateTemplate(false); + } + + void testResetIntermediateStateTemplate(final boolean isForward) { + // GIVEN + final FieldTLE tle = getGradientTLE(); + final Field field = tle.getDate().getField(); + final Gradient[] parameters = tle.getParameters(field); + final FieldTLEPropagator tlePropagator = FieldTLEPropagator.selectExtrapolator(tle, parameters); + final double expectedMass = 2000.; + final FieldSpacecraftState propagatedState = tlePropagator.propagate(tle.getDate().shiftedBy(1)); + final FieldSpacecraftState modifiedState = new FieldSpacecraftState<>(propagatedState.getOrbit(), + field.getZero().newInstance(expectedMass)); + + // WHEN + tlePropagator.resetIntermediateState(modifiedState, isForward); + + // THEN + final double tinyTimeShift = (isForward) ? 1e-3 : -1e-3; + final double actualMass = tlePropagator.getMass(modifiedState.getDate().shiftedBy(tinyTimeShift)).getReal(); + Assertions.assertEquals(expectedMass, actualMass); + } + @BeforeEach public void setUp() { Utils.setDataRoot("regular-data"); - // the period of the GPS satellite + // the period of the GPS satellite period = 717.97 * 60.0; } diff --git a/src/test/java/org/orekit/propagation/analytical/tle/TLEPropagatorTest.java b/src/test/java/org/orekit/propagation/analytical/tle/TLEPropagatorTest.java index 268713f223..d1031f03d1 100644 --- a/src/test/java/org/orekit/propagation/analytical/tle/TLEPropagatorTest.java +++ b/src/test/java/org/orekit/propagation/analytical/tle/TLEPropagatorTest.java @@ -20,6 +20,7 @@ import org.hipparchus.geometry.euclidean.threed.Line; import org.hipparchus.geometry.euclidean.threed.Rotation; import org.hipparchus.geometry.euclidean.threed.Vector3D; +import org.hipparchus.ode.events.Action; import org.hipparchus.util.FastMath; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; @@ -35,6 +36,8 @@ import org.orekit.propagation.EphemerisGenerator; import org.orekit.propagation.Propagator; import org.orekit.propagation.SpacecraftState; +import org.orekit.propagation.events.DateDetector; +import org.orekit.propagation.events.handlers.EventHandler; import org.orekit.propagation.sampling.OrekitFixedStepHandler; import org.orekit.time.AbsoluteDate; import org.orekit.utils.Constants; @@ -188,6 +191,87 @@ public void handleStep(SpacecraftState currentState) { } + @Test + void testResetInitialState() { + // GIVEN + final TLEPropagator tlePropagator = TLEPropagator.selectExtrapolator(tle); + final SpacecraftState initialState = tlePropagator.getInitialState(); + final double unexpectedMass = initialState.getMass(); + final double expectedMass = 2. * unexpectedMass; + final SpacecraftState newState = new SpacecraftState(initialState.getOrbit(), initialState.getAttitude(), + expectedMass); + + // WHEN + tlePropagator.resetInitialState(newState); + + // THEN + final SpacecraftState actualState = tlePropagator.getInitialState(); + Assertions.assertEquals(expectedMass, tlePropagator.getMass(actualState.getDate())); + Assertions.assertEquals(expectedMass, actualState.getMass()); + Assertions.assertNotEquals(unexpectedMass, actualState.getMass()); + } + + @Test + void testResetIntermediateStateForward() { + testResetIntermediateStateTemplate(true); + } + + @Test + void testResetIntermediateStateBackward() { + testResetIntermediateStateTemplate(false); + } + + void testResetIntermediateStateTemplate(final boolean isForward) { + // GIVEN + final TLEPropagator tlePropagator = TLEPropagator.selectExtrapolator(tle); + final double expectedMass = 2000.; + final SpacecraftState propagatedState = tlePropagator.propagate(tle.getDate().shiftedBy(1)); + final SpacecraftState modifiedState = new SpacecraftState(propagatedState.getOrbit(), expectedMass); + + // WHEN + tlePropagator.resetIntermediateState(modifiedState, isForward); + + // THEN + final double tinyTimeShift = (isForward) ? 1e-3 : -1e-3; + final double actualMass = tlePropagator.getMass(modifiedState.getDate().shiftedBy(tinyTimeShift)); + Assertions.assertEquals(expectedMass, actualMass); + } + + @Test + void testResetIntermediateStateHighLevelForward() { + testResetIntermediateStateHighLevelTemplate(true); + } + + @Test + void testResetIntermediateStateHighLevelBackward() { + testResetIntermediateStateHighLevelTemplate(false); + } + + void testResetIntermediateStateHighLevelTemplate(final boolean isForward) { + // GIVEN + final TLEPropagator tlePropagator = TLEPropagator.selectExtrapolator(tle); + final AbsoluteDate epoch = tlePropagator.getInitialState().getDate(); + final double totalShift = 1e4; + final double shiftSign = isForward ? 1 : -1; + final AbsoluteDate targetDate = epoch.shiftedBy(totalShift * shiftSign); + final EventHandler stateResetter = (s, detector, increasing) -> Action.RESET_STATE; + final DateDetector detector = new DateDetector(targetDate) + .withThreshold(1e-8).withHandler(stateResetter); + tlePropagator.addEventDetector(detector); + + // WHEN + final SpacecraftState actualState = tlePropagator.propagate(targetDate); + + // THEN + final SpacecraftState expectedState = TLEPropagator.selectExtrapolator(tle).propagate(targetDate); + final Vector3D expectedPosition = expectedState.getPosition(); + final Vector3D actualPosition = actualState.getPosition(); + final double tolerance = 1e-1; + Assertions.assertEquals(expectedPosition.getX(), actualPosition.getX(), tolerance); + Assertions.assertEquals(expectedPosition.getY(), actualPosition.getY(), tolerance); + Assertions.assertEquals(expectedPosition.getZ(), actualPosition.getZ(), tolerance); + } + @BeforeEach public void setUp() { Utils.setDataRoot("regular-data"); From 02c7649e28b6016824808c318cfe36482598e2fe Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Tue, 6 Feb 2024 13:23:26 +0100 Subject: [PATCH 117/359] Fixed wrong key for Beidou System Time in SP3 files. Fixes #1321 --- src/changes/changes.xml | 3 +++ src/main/java/org/orekit/gnss/TimeSystem.java | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 0688961db5..fbb9d293ea 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -21,6 +21,9 @@ + + Fixed wrong key for Beidou System Time in SP3 files. + Implement resetIntermediateState in (Field)TLEPropagator. diff --git a/src/main/java/org/orekit/gnss/TimeSystem.java b/src/main/java/org/orekit/gnss/TimeSystem.java index 44b05b2127..d16c3db70b 100644 --- a/src/main/java/org/orekit/gnss/TimeSystem.java +++ b/src/main/java/org/orekit/gnss/TimeSystem.java @@ -53,7 +53,7 @@ public enum TimeSystem { QZSS("QZS", "QZ", "J", ts -> ts.getQZSS()), /** Beidou. */ - BEIDOU("BDS", "BD", "C", ts -> ts.getBDT()), + BEIDOU("BDT", "BD", "C", ts -> ts.getBDT()), /** IRNSS. */ IRNSS("IRN", "IR", "I", ts -> ts.getIRNSS()), @@ -115,7 +115,7 @@ public enum TimeSystem { private final Function timeScaleProvider; /** Simple constructor. - * @param key key letter + * @param key key letter (may be null) * @param twoLettersCode two letters code (may be null) * @param oneLetterCode one letter code (may be null) * @param timeScaleProvider time scale provider From 77b43653e64dd94c86f69fdfe36cb595cc6567c7 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Tue, 6 Feb 2024 13:31:02 +0100 Subject: [PATCH 118/359] Fixed forbidden SBAS System Time in SP3 files. Fixes #1322 --- src/changes/changes.xml | 3 +++ src/main/java/org/orekit/files/sp3/SP3Writer.java | 7 +++++-- src/main/java/org/orekit/gnss/TimeSystem.java | 6 ++++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index fbb9d293ea..6a8052fb98 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -21,6 +21,9 @@ + + Fixed forbidden SBAS System Time in SP3 files. + Fixed wrong key for Beidou System Time in SP3 files. diff --git a/src/main/java/org/orekit/files/sp3/SP3Writer.java b/src/main/java/org/orekit/files/sp3/SP3Writer.java index 7b0ee4c4ce..10a5442868 100644 --- a/src/main/java/org/orekit/files/sp3/SP3Writer.java +++ b/src/main/java/org/orekit/files/sp3/SP3Writer.java @@ -23,6 +23,7 @@ import java.util.Map; import org.hipparchus.util.FastMath; +import org.orekit.gnss.TimeSystem; import org.orekit.time.AbsoluteDate; import org.orekit.time.DateTimeComponents; import org.orekit.time.TimeScale; @@ -396,9 +397,11 @@ private void writeHeader(final SP3Header header) if (header.getVersion() == 'a') { output.append(TIME_SYSTEM_DEFAULT).append(EOL); } else { + final TimeSystem ts = header.getTimeSystem().getKey() == null ? + TimeSystem.UTC : + header.getTimeSystem(); output.append(String.format(Locale.US, "%%c %1s cc %3s ccc cccc cccc cccc cccc ccccc ccccc ccccc ccccc%n", - header.getType().getKey(), - header.getTimeSystem().getKey())); + header.getType().getKey(), ts.getKey())); } output.append(TIME_SYSTEM_DEFAULT).append(EOL); diff --git a/src/main/java/org/orekit/gnss/TimeSystem.java b/src/main/java/org/orekit/gnss/TimeSystem.java index d16c3db70b..5bc132e02b 100644 --- a/src/main/java/org/orekit/gnss/TimeSystem.java +++ b/src/main/java/org/orekit/gnss/TimeSystem.java @@ -61,7 +61,7 @@ public enum TimeSystem { /** SBAS. * @since 12.0 */ - SBAS("SBAS", "SB", "S", ts -> ts.getUTC()), + SBAS(null, "SB", "S", ts -> ts.getUTC()), /** GMT (should only by used in RUN BY / DATE entries). * @since 12.0 @@ -86,7 +86,9 @@ public enum TimeSystem { static { for (final TimeSystem timeSystem : values()) { - KEYS_MAP.put(timeSystem.key, timeSystem); + if (timeSystem.key != null) { + KEYS_MAP.put(timeSystem.key, timeSystem); + } if (timeSystem.twoLettersCode != null) { TLC_MAP.put(timeSystem.twoLettersCode, timeSystem); } From 26e321299693899c528e3511c0739d4369e08deb Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Tue, 6 Feb 2024 13:33:56 +0100 Subject: [PATCH 119/359] Fixed warnings identified by IntelliJ code analysis. --- src/main/java/org/orekit/gnss/TimeSystem.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/orekit/gnss/TimeSystem.java b/src/main/java/org/orekit/gnss/TimeSystem.java index 5bc132e02b..3ede2749ac 100644 --- a/src/main/java/org/orekit/gnss/TimeSystem.java +++ b/src/main/java/org/orekit/gnss/TimeSystem.java @@ -35,41 +35,41 @@ public enum TimeSystem { /** Global Positioning System. */ - GPS("GPS", "GP", "G", ts -> ts.getGPS()), + GPS("GPS", "GP", "G", TimeScales::getGPS), /** GLONASS. */ - GLONASS("GLO", "GL", "R", ts -> ts.getGLONASS()), + GLONASS("GLO", "GL", "R", TimeScales::getGLONASS), /** GALILEO. */ - GALILEO("GAL", "GA", "E", ts -> ts.getGST()), + GALILEO("GAL", "GA", "E", TimeScales::getGST), /** International Atomic Time. */ - TAI("TAI", null, null, ts -> ts.getTAI()), + TAI("TAI", null, null, TimeScales::getTAI), /** Coordinated Universal Time. */ - UTC("UTC", "UT", null, ts -> ts.getUTC()), + UTC("UTC", "UT", null, TimeScales::getUTC), /** Quasi-Zenith System. */ - QZSS("QZS", "QZ", "J", ts -> ts.getQZSS()), + QZSS("QZS", "QZ", "J", TimeScales::getQZSS), /** Beidou. */ - BEIDOU("BDT", "BD", "C", ts -> ts.getBDT()), + BEIDOU("BDT", "BD", "C", TimeScales::getBDT), /** IRNSS. */ - IRNSS("IRN", "IR", "I", ts -> ts.getIRNSS()), + IRNSS("IRN", "IR", "I", TimeScales::getIRNSS), /** SBAS. * @since 12.0 */ - SBAS(null, "SB", "S", ts -> ts.getUTC()), + SBAS(null, "SB", "S", TimeScales::getUTC), /** GMT (should only by used in RUN BY / DATE entries). * @since 12.0 */ - GMT("GMT", null, null, ts -> ts.getUTC()), + GMT("GMT", null, null, TimeScales::getUTC), /** Unknown (should only by used in RUN BY / DATE entries). */ - UNKNOWN("LCL", null, null, ts -> ts.getGPS()); + UNKNOWN("LCL", null, null, TimeScales::getGPS); /** Parsing key map. */ private static final Map KEYS_MAP = new HashMap<>(); From 68ee4ab82c92ef38925ca34c0cbb7147e7ab2b26 Mon Sep 17 00:00:00 2001 From: Serrof Date: Thu, 14 Dec 2023 23:25:05 +0100 Subject: [PATCH 120/359] set up cache in KeplerianOrbit --- .../org/orekit/orbits/KeplerianOrbit.java | 613 +++++++++++++----- .../java/org/orekit/orbits/OrbitType.java | 13 +- .../analytical/BrouwerLyddanePropagator.java | 4 +- .../org/orekit/orbits/KeplerianOrbitTest.java | 50 ++ 4 files changed, 510 insertions(+), 170 deletions(-) diff --git a/src/main/java/org/orekit/orbits/KeplerianOrbit.java b/src/main/java/org/orekit/orbits/KeplerianOrbit.java index ea9ae6e7e6..9d93e139ae 100644 --- a/src/main/java/org/orekit/orbits/KeplerianOrbit.java +++ b/src/main/java/org/orekit/orbits/KeplerianOrbit.java @@ -96,8 +96,8 @@ public class KeplerianOrbit extends Orbit implements PositionAngleBased { /** Right Ascension of Ascending Node (rad). */ private final double raan; - /** True anomaly (rad). */ - private final double v; + /** Cached anomaly (rad). */ + private final double cachedAnomaly; /** Semi-major axis derivative (m/s). */ private final double aDot; @@ -114,8 +114,11 @@ public class KeplerianOrbit extends Orbit implements PositionAngleBased { /** Right Ascension of Ascending Node derivative (rad/s). */ private final double raanDot; - /** True anomaly derivative (rad/s). */ - private final double vDot; + /** Derivative of cached anomaly (rad/s). */ + private final double cachedAnomalyDot; + + /** Cached type of position angle. */ + private final PositionAngleType cachedPositionAngleType; /** Partial Cartesian coordinates (position and velocity are valid, acceleration may be missing). */ private transient PVCoordinates partialPV; @@ -128,6 +131,7 @@ public class KeplerianOrbit extends Orbit implements PositionAngleBased { * @param raan right ascension of ascending node (Ω, rad) * @param anomaly mean, eccentric or true anomaly (rad) * @param type type of anomaly + * @param cachedPositionAngleType type of cached anomaly * @param frame the frame in which the parameters are defined * (must be a {@link Frame#isPseudoInertial pseudo-inertial frame}) * @param date date of the orbital parameters @@ -135,15 +139,40 @@ public class KeplerianOrbit extends Orbit implements PositionAngleBased { * @exception IllegalArgumentException if frame is not a {@link * Frame#isPseudoInertial pseudo-inertial frame} or a and e don't match for hyperbolic orbits, * or v is out of range for hyperbolic orbits + * @since 12.1 */ public KeplerianOrbit(final double a, final double e, final double i, final double pa, final double raan, final double anomaly, - final PositionAngleType type, + final PositionAngleType type, final PositionAngleType cachedPositionAngleType, final Frame frame, final AbsoluteDate date, final double mu) - throws IllegalArgumentException { + throws IllegalArgumentException { this(a, e, i, pa, raan, anomaly, - Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN, - type, frame, date, mu); + Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN, + type, cachedPositionAngleType, frame, date, mu); + } + + /** Creates a new instance without derivatives and with cached position angle same as value inputted. + * @param a semi-major axis (m), negative for hyperbolic orbits + * @param e eccentricity (positive or equal to 0) + * @param i inclination (rad) + * @param pa perigee argument (ω, rad) + * @param raan right ascension of ascending node (Ω, rad) + * @param anomaly mean, eccentric or true anomaly (rad) + * @param type type of anomaly + * @param frame the frame in which the parameters are defined + * (must be a {@link Frame#isPseudoInertial pseudo-inertial frame}) + * @param date date of the orbital parameters + * @param mu central attraction coefficient (m³/s²) + * @exception IllegalArgumentException if frame is not a {@link + * Frame#isPseudoInertial pseudo-inertial frame} or a and e don't match for hyperbolic orbits, + * or v is out of range for hyperbolic orbits + */ + public KeplerianOrbit(final double a, final double e, final double i, + final double pa, final double raan, final double anomaly, + final PositionAngleType type, + final Frame frame, final AbsoluteDate date, final double mu) + throws IllegalArgumentException { + this(a, e, i, pa, raan, anomaly, type, type, frame, date, mu); } /** Creates a new instance. @@ -159,7 +188,8 @@ public KeplerianOrbit(final double a, final double e, final double i, * @param paDot perigee argument derivative (rad/s) * @param raanDot right ascension of ascending node derivative (rad/s) * @param anomalyDot mean, eccentric or true anomaly derivative (rad/s) - * @param type type of anomaly + * @param type type of input anomaly + * @param cachedPositionAngleType type of cached anomaly * @param frame the frame in which the parameters are defined * (must be a {@link Frame#isPseudoInertial pseudo-inertial frame}) * @param date date of the orbital parameters @@ -167,16 +197,17 @@ public KeplerianOrbit(final double a, final double e, final double i, * @exception IllegalArgumentException if frame is not a {@link * Frame#isPseudoInertial pseudo-inertial frame} or a and e don't match for hyperbolic orbits, * or v is out of range for hyperbolic orbits - * @since 9.0 + * @since 12.1 */ public KeplerianOrbit(final double a, final double e, final double i, final double pa, final double raan, final double anomaly, final double aDot, final double eDot, final double iDot, final double paDot, final double raanDot, final double anomalyDot, - final PositionAngleType type, + final PositionAngleType type, final PositionAngleType cachedPositionAngleType, final Frame frame, final AbsoluteDate date, final double mu) - throws IllegalArgumentException { + throws IllegalArgumentException { super(frame, date, mu); + this.cachedPositionAngleType = cachedPositionAngleType; if (a * (1 - e) < 0) { throw new OrekitIllegalArgumentException(OrekitMessages.ORBIT_A_E_MISMATCH_WITH_CONIC_TYPE, a, e); @@ -197,60 +228,62 @@ public KeplerianOrbit(final double a, final double e, final double i, this.raanDot = raanDot; if (hasDerivatives()) { - final UnivariateDerivative1 eUD = new UnivariateDerivative1(e, eDot); - final UnivariateDerivative1 anomalyUD = new UnivariateDerivative1(anomaly, anomalyDot); - final UnivariateDerivative1 vUD; - switch (type) { - case MEAN : - vUD = (a < 0) ? - FieldKeplerianAnomalyUtility.hyperbolicMeanToTrue(eUD, anomalyUD) : - FieldKeplerianAnomalyUtility.ellipticMeanToTrue(eUD, anomalyUD); - break; - case ECCENTRIC : - vUD = (a < 0) ? - FieldKeplerianAnomalyUtility.hyperbolicEccentricToTrue(eUD, anomalyUD) : - FieldKeplerianAnomalyUtility.ellipticEccentricToTrue(eUD, anomalyUD); - break; - case TRUE : - vUD = anomalyUD; - break; - default : // this should never happen - throw new OrekitInternalError(null); - } - this.v = vUD.getValue(); - this.vDot = vUD.getDerivative(1); + final UnivariateDerivative1 cachedAnomalyUD = initializeCachedAnomaly(anomaly, anomalyDot, type); + this.cachedAnomaly = cachedAnomalyUD.getValue(); + this.cachedAnomalyDot = cachedAnomalyUD.getFirstDerivative(); } else { - switch (type) { - case MEAN : - this.v = (a < 0) ? - KeplerianAnomalyUtility.hyperbolicMeanToTrue(e, anomaly) : - KeplerianAnomalyUtility.ellipticMeanToTrue(e, anomaly); - break; - case ECCENTRIC : - this.v = (a < 0) ? - KeplerianAnomalyUtility.hyperbolicEccentricToTrue(e, anomaly) : - KeplerianAnomalyUtility.ellipticEccentricToTrue(e, anomaly); - break; - case TRUE : - this.v = anomaly; - break; - default : // this should never happen - throw new OrekitInternalError(null); - } - this.vDot = Double.NaN; + this.cachedAnomaly = initializeCachedAnomaly(anomaly, type); + this.cachedAnomalyDot = Double.NaN; } // check true anomaly range - if (1 + e * FastMath.cos(v) <= 0) { - final double vMax = FastMath.acos(-1 / e); - throw new OrekitIllegalArgumentException(OrekitMessages.ORBIT_ANOMALY_OUT_OF_HYPERBOLIC_RANGE, - v, e, -vMax, vMax); + if (!isElliptical()) { + final double trueAnomaly = getTrueAnomaly(); + if (1 + e * FastMath.cos(trueAnomaly) <= 0) { + final double vMax = FastMath.acos(-1 / e); + throw new OrekitIllegalArgumentException(OrekitMessages.ORBIT_ANOMALY_OUT_OF_HYPERBOLIC_RANGE, + trueAnomaly, e, -vMax, vMax); + } } this.partialPV = null; } + /** Creates a new instance with cached position angle same as value inputted. + * @param a semi-major axis (m), negative for hyperbolic orbits + * @param e eccentricity (positive or equal to 0) + * @param i inclination (rad) + * @param pa perigee argument (ω, rad) + * @param raan right ascension of ascending node (Ω, rad) + * @param anomaly mean, eccentric or true anomaly (rad) + * @param aDot semi-major axis derivative (m/s) + * @param eDot eccentricity derivative + * @param iDot inclination derivative (rad/s) + * @param paDot perigee argument derivative (rad/s) + * @param raanDot right ascension of ascending node derivative (rad/s) + * @param anomalyDot mean, eccentric or true anomaly derivative (rad/s) + * @param type type of anomaly + * @param frame the frame in which the parameters are defined + * (must be a {@link Frame#isPseudoInertial pseudo-inertial frame}) + * @param date date of the orbital parameters + * @param mu central attraction coefficient (m³/s²) + * @exception IllegalArgumentException if frame is not a {@link + * Frame#isPseudoInertial pseudo-inertial frame} or a and e don't match for hyperbolic orbits, + * or v is out of range for hyperbolic orbits + * @since 9.0 + */ + public KeplerianOrbit(final double a, final double e, final double i, + final double pa, final double raan, final double anomaly, + final double aDot, final double eDot, final double iDot, + final double paDot, final double raanDot, final double anomalyDot, + final PositionAngleType type, + final Frame frame, final AbsoluteDate date, final double mu) + throws IllegalArgumentException { + this(a, e, i, pa, raan, anomaly, aDot, eDot, iDot, paDot, raanDot, anomalyDot, type, type, + frame, date, mu); + } + /** Constructor from Cartesian parameters. * *

                The acceleration provided in {@code pvCoordinates} is accessible using @@ -267,7 +300,7 @@ public KeplerianOrbit(final double a, final double e, final double i, */ public KeplerianOrbit(final TimeStampedPVCoordinates pvCoordinates, final Frame frame, final double mu) - throws IllegalArgumentException { + throws IllegalArgumentException { this(pvCoordinates, frame, mu, hasNonKeplerianAcceleration(pvCoordinates, mu)); } @@ -289,7 +322,7 @@ public KeplerianOrbit(final TimeStampedPVCoordinates pvCoordinates, private KeplerianOrbit(final TimeStampedPVCoordinates pvCoordinates, final Frame frame, final double mu, final boolean reliableAcceleration) - throws IllegalArgumentException { + throws IllegalArgumentException { super(pvCoordinates, frame, mu); // compute inclination @@ -313,19 +346,21 @@ private KeplerianOrbit(final TimeStampedPVCoordinates pvCoordinates, a = r / (2 - rV2OnMu); final double muA = mu * a; - // compute true anomaly + // compute cached anomaly if (isElliptical()) { // elliptic or circular orbit final double eSE = Vector3D.dotProduct(pvP, pvV) / FastMath.sqrt(muA); final double eCE = rV2OnMu - 1; e = FastMath.sqrt(eSE * eSE + eCE * eCE); - v = KeplerianAnomalyUtility.ellipticEccentricToTrue(e, FastMath.atan2(eSE, eCE)); + this.cachedPositionAngleType = PositionAngleType.ECCENTRIC; + cachedAnomaly = FastMath.atan2(eSE, eCE); } else { // hyperbolic orbit final double eSH = Vector3D.dotProduct(pvP, pvV) / FastMath.sqrt(-muA); final double eCH = rV2OnMu - 1; e = FastMath.sqrt(1 - m2 / muA); - v = KeplerianAnomalyUtility.hyperbolicEccentricToTrue(e, FastMath.log((eCH + eSH) / (eCH - eSH)) / 2); + this.cachedPositionAngleType = PositionAngleType.TRUE; + cachedAnomaly = KeplerianAnomalyUtility.hyperbolicEccentricToTrue(e, FastMath.log((eCH + eSH) / (eCH - eSH)) / 2); } // Checking eccentricity range @@ -335,7 +370,7 @@ private KeplerianOrbit(final TimeStampedPVCoordinates pvCoordinates, final Vector3D node = new Vector3D(raan, 0.0); final double px = Vector3D.dotProduct(pvP, node); final double py = Vector3D.dotProduct(pvP, Vector3D.crossProduct(momentum, node)) / FastMath.sqrt(m2); - pa = FastMath.atan2(py, px) - v; + pa = FastMath.atan2(py, px) - getTrueAnomaly(); partialPV = pvCoordinates; @@ -356,16 +391,23 @@ private KeplerianOrbit(final TimeStampedPVCoordinates pvCoordinates, paDot = jacobian[3][3] * aX + jacobian[3][4] * aY + jacobian[3][5] * aZ; raanDot = jacobian[4][3] * aX + jacobian[4][4] * aY + jacobian[4][5] * aZ; - // in order to compute true anomaly derivative, we must compute - // mean anomaly derivative including Keplerian motion and convert to true anomaly + // in order to compute cached anomaly derivative, we must compute + // mean anomaly derivative including Keplerian motion and convert to required anomaly final double MDot = getKeplerianMeanMotion() + - jacobian[5][3] * aX + jacobian[5][4] * aY + jacobian[5][5] * aZ; + jacobian[5][3] * aX + jacobian[5][4] * aY + jacobian[5][5] * aZ; final UnivariateDerivative1 eUD = new UnivariateDerivative1(e, eDot); final UnivariateDerivative1 MUD = new UnivariateDerivative1(getMeanAnomaly(), MDot); - final UnivariateDerivative1 vUD = (a < 0) ? - FieldKeplerianAnomalyUtility.hyperbolicMeanToTrue(eUD, MUD) : - FieldKeplerianAnomalyUtility.ellipticMeanToTrue(eUD, MUD); - vDot = vUD.getDerivative(1); + if (cachedPositionAngleType == PositionAngleType.ECCENTRIC) { + final UnivariateDerivative1 EUD = (a < 0) ? + FieldKeplerianAnomalyUtility.hyperbolicMeanToEccentric(eUD, MUD) : + FieldKeplerianAnomalyUtility.ellipticMeanToEccentric(eUD, MUD); + cachedAnomalyDot = EUD.getFirstDerivative(); + } else { // TRUE + final UnivariateDerivative1 vUD = (a < 0) ? + FieldKeplerianAnomalyUtility.hyperbolicMeanToTrue(eUD, MUD) : + FieldKeplerianAnomalyUtility.ellipticMeanToTrue(eUD, MUD); + cachedAnomalyDot = vUD.getFirstDerivative(); + } } else { // acceleration is either almost zero or NaN, @@ -376,7 +418,7 @@ private KeplerianOrbit(final TimeStampedPVCoordinates pvCoordinates, iDot = Double.NaN; paDot = Double.NaN; raanDot = Double.NaN; - vDot = Double.NaN; + cachedAnomalyDot = Double.NaN; } } @@ -398,7 +440,7 @@ private KeplerianOrbit(final TimeStampedPVCoordinates pvCoordinates, */ public KeplerianOrbit(final PVCoordinates pvCoordinates, final Frame frame, final AbsoluteDate date, final double mu) - throws IllegalArgumentException { + throws IllegalArgumentException { this(new TimeStampedPVCoordinates(date, pvCoordinates), frame, mu); } @@ -484,23 +526,71 @@ public double getRightAscensionOfAscendingNodeDot() { * @return true anomaly (rad) */ public double getTrueAnomaly() { - return v; + switch (cachedPositionAngleType) { + case MEAN: return (a < 0.) ? KeplerianAnomalyUtility.hyperbolicMeanToTrue(e, cachedAnomaly) : + KeplerianAnomalyUtility.ellipticMeanToTrue(e, cachedAnomaly); + + case TRUE: return cachedAnomaly; + + case ECCENTRIC: return (a < 0.) ? KeplerianAnomalyUtility.hyperbolicEccentricToTrue(e, cachedAnomaly) : + KeplerianAnomalyUtility.ellipticEccentricToTrue(e, cachedAnomaly); + + default: throw new OrekitInternalError(null); + } } /** Get the true anomaly derivative. * @return true anomaly derivative (rad/s) */ public double getTrueAnomalyDot() { - return vDot; + if (hasDerivatives()) { + switch (cachedPositionAngleType) { + case MEAN: + final UnivariateDerivative1 eUD = new UnivariateDerivative1(e, eDot); + final UnivariateDerivative1 MUD = new UnivariateDerivative1(cachedAnomaly, cachedAnomalyDot); + final UnivariateDerivative1 vUD = (a < 0) ? + FieldKeplerianAnomalyUtility.hyperbolicMeanToTrue(eUD, MUD) : + FieldKeplerianAnomalyUtility.ellipticMeanToTrue(eUD, MUD); + return vUD.getFirstDerivative(); + + case TRUE: + return cachedAnomalyDot; + + case ECCENTRIC: + final UnivariateDerivative1 eUD2 = new UnivariateDerivative1(e, eDot); + final UnivariateDerivative1 EUD = new UnivariateDerivative1(cachedAnomaly, cachedAnomalyDot); + final UnivariateDerivative1 vUD2 = (a < 0) ? + FieldKeplerianAnomalyUtility.hyperbolicEccentricToTrue(eUD2, EUD) : + FieldKeplerianAnomalyUtility.ellipticEccentricToTrue(eUD2, EUD); + return vUD2.getFirstDerivative(); + + default: + throw new OrekitInternalError(null); + } + } else { + return Double.NaN; + } } /** Get the eccentric anomaly. * @return eccentric anomaly (rad) */ public double getEccentricAnomaly() { - return (a < 0) ? - KeplerianAnomalyUtility.hyperbolicTrueToEccentric(e, v) : - KeplerianAnomalyUtility.ellipticTrueToEccentric(e, v); + switch (cachedPositionAngleType) { + case MEAN: + return (a < 0.) ? KeplerianAnomalyUtility.hyperbolicMeanToEccentric(e, cachedAnomaly) : + KeplerianAnomalyUtility.ellipticMeanToEccentric(e, cachedAnomaly); + + case ECCENTRIC: + return cachedAnomaly; + + case TRUE: + return (a < 0.) ? KeplerianAnomalyUtility.hyperbolicTrueToEccentric(e, cachedAnomaly) : + KeplerianAnomalyUtility.ellipticTrueToEccentric(e, cachedAnomaly); + + default: + throw new OrekitInternalError(null); + } } /** Get the eccentric anomaly derivative. @@ -508,21 +598,50 @@ public double getEccentricAnomaly() { * @since 9.0 */ public double getEccentricAnomalyDot() { - final UnivariateDerivative1 eUD = new UnivariateDerivative1(e, eDot); - final UnivariateDerivative1 vUD = new UnivariateDerivative1(v, vDot); - final UnivariateDerivative1 EUD = (a < 0) ? - FieldKeplerianAnomalyUtility.hyperbolicTrueToEccentric(eUD, vUD) : - FieldKeplerianAnomalyUtility.ellipticTrueToEccentric(eUD, vUD); - return EUD.getDerivative(1); + if (hasDerivatives()) { + switch (cachedPositionAngleType) { + case ECCENTRIC: + return cachedAnomalyDot; + + case TRUE: + final UnivariateDerivative1 eUD = new UnivariateDerivative1(e, eDot); + final UnivariateDerivative1 vUD = new UnivariateDerivative1(cachedAnomaly, cachedAnomalyDot); + final UnivariateDerivative1 EUD = (a < 0) ? + FieldKeplerianAnomalyUtility.hyperbolicTrueToEccentric(eUD, vUD) : + FieldKeplerianAnomalyUtility.ellipticTrueToEccentric(eUD, vUD); + return EUD.getFirstDerivative(); + + case MEAN: + final UnivariateDerivative1 eUD2 = new UnivariateDerivative1(e, eDot); + final UnivariateDerivative1 MUD = new UnivariateDerivative1(cachedAnomaly, cachedAnomalyDot); + final UnivariateDerivative1 EUD2 = (a < 0) ? + FieldKeplerianAnomalyUtility.hyperbolicMeanToEccentric(eUD2, MUD) : + FieldKeplerianAnomalyUtility.ellipticMeanToEccentric(eUD2, MUD); + return EUD2.getFirstDerivative(); + + default: + throw new OrekitInternalError(null); + } + } else { + return Double.NaN; + } } /** Get the mean anomaly. * @return mean anomaly (rad) */ public double getMeanAnomaly() { - return (a < 0) ? - KeplerianAnomalyUtility.hyperbolicTrueToMean(e, v) : - KeplerianAnomalyUtility.ellipticTrueToMean(e, v); + switch (cachedPositionAngleType) { + case ECCENTRIC: return (a < 0.) ? KeplerianAnomalyUtility.hyperbolicEccentricToMean(e, cachedAnomaly) : + KeplerianAnomalyUtility.ellipticEccentricToMean(e, cachedAnomaly); + + case MEAN: return cachedAnomaly; + + case TRUE: return (a < 0.) ? KeplerianAnomalyUtility.hyperbolicTrueToMean(e, cachedAnomaly) : + KeplerianAnomalyUtility.ellipticTrueToMean(e, cachedAnomaly); + + default: throw new OrekitInternalError(null); + } } /** Get the mean anomaly derivative. @@ -530,12 +649,33 @@ public double getMeanAnomaly() { * @since 9.0 */ public double getMeanAnomalyDot() { - final UnivariateDerivative1 eUD = new UnivariateDerivative1(e, eDot); - final UnivariateDerivative1 vUD = new UnivariateDerivative1(v, vDot); - final UnivariateDerivative1 MUD = (a < 0) ? - FieldKeplerianAnomalyUtility.hyperbolicTrueToMean(eUD, vUD) : - FieldKeplerianAnomalyUtility.ellipticTrueToMean(eUD, vUD); - return MUD.getDerivative(1); + if (hasDerivatives()) { + switch (cachedPositionAngleType) { + case MEAN: + return cachedAnomalyDot; + + case ECCENTRIC: + final UnivariateDerivative1 eUD = new UnivariateDerivative1(e, eDot); + final UnivariateDerivative1 EUD = new UnivariateDerivative1(cachedAnomaly, cachedAnomalyDot); + final UnivariateDerivative1 MUD = (a < 0) ? + FieldKeplerianAnomalyUtility.hyperbolicEccentricToMean(eUD, EUD) : + FieldKeplerianAnomalyUtility.ellipticEccentricToMean(eUD, EUD); + return MUD.getFirstDerivative(); + + case TRUE: + final UnivariateDerivative1 eUD2 = new UnivariateDerivative1(e, eDot); + final UnivariateDerivative1 vUD = new UnivariateDerivative1(cachedAnomaly, cachedAnomalyDot); + final UnivariateDerivative1 MUD2 = (a < 0) ? + FieldKeplerianAnomalyUtility.hyperbolicTrueToMean(eUD2, vUD) : + FieldKeplerianAnomalyUtility.ellipticTrueToMean(eUD2, vUD); + return MUD2.getFirstDerivative(); + + default: + throw new OrekitInternalError(null); + } + } else { + return Double.NaN; + } } /** Get the anomaly. @@ -544,8 +684,8 @@ public double getMeanAnomalyDot() { */ public double getAnomaly(final PositionAngleType type) { return (type == PositionAngleType.MEAN) ? getMeanAnomaly() : - ((type == PositionAngleType.ECCENTRIC) ? getEccentricAnomaly() : - getTrueAnomaly()); + ((type == PositionAngleType.ECCENTRIC) ? getEccentricAnomaly() : + getTrueAnomaly()); } /** Get the anomaly derivative. @@ -555,8 +695,8 @@ public double getAnomaly(final PositionAngleType type) { */ public double getAnomalyDot(final PositionAngleType type) { return (type == PositionAngleType.MEAN) ? getMeanAnomalyDot() : - ((type == PositionAngleType.ECCENTRIC) ? getEccentricAnomalyDot() : - getTrueAnomalyDot()); + ((type == PositionAngleType.ECCENTRIC) ? getEccentricAnomalyDot() : + getTrueAnomalyDot()); } /** {@inheritDoc} */ @@ -625,12 +765,12 @@ public double getHyDot() { /** {@inheritDoc} */ public double getLv() { - return pa + raan + v; + return pa + raan + getTrueAnomaly(); } /** {@inheritDoc} */ public double getLvDot() { - return paDot + raanDot + vDot; + return paDot + raanDot + getTrueAnomalyDot(); } /** {@inheritDoc} */ @@ -653,6 +793,151 @@ public double getLMDot() { return paDot + raanDot + getMeanAnomalyDot(); } + /** Initialize cached anomaly with rate. + * @param anomaly input anomaly + * @param anomalyDot rate of input anomaly + * @param inputType position angle type passed as input + * @return anomaly to cache with rate + * @since 12.1 + */ + private UnivariateDerivative1 initializeCachedAnomaly(final double anomaly, final double anomalyDot, + final PositionAngleType inputType) { + if (cachedPositionAngleType == inputType) { + return new UnivariateDerivative1(anomaly, anomalyDot); + + } else { + final UnivariateDerivative1 eUD = new UnivariateDerivative1(e, eDot); + final UnivariateDerivative1 anomalyUD = new UnivariateDerivative1(anomaly, anomalyDot); + + if (a < 0) { + switch (cachedPositionAngleType) { + case MEAN: + if (inputType == PositionAngleType.ECCENTRIC) { + return FieldKeplerianAnomalyUtility.hyperbolicEccentricToMean(eUD, anomalyUD); + } else { + return FieldKeplerianAnomalyUtility.hyperbolicTrueToMean(eUD, anomalyUD); + } + + case ECCENTRIC: + if (inputType == PositionAngleType.MEAN) { + return FieldKeplerianAnomalyUtility.hyperbolicMeanToEccentric(eUD, anomalyUD); + } else { + return FieldKeplerianAnomalyUtility.hyperbolicTrueToEccentric(eUD, anomalyUD); + } + + case TRUE: + if (inputType == PositionAngleType.MEAN) { + return FieldKeplerianAnomalyUtility.hyperbolicMeanToTrue(eUD, anomalyUD); + } else { + return FieldKeplerianAnomalyUtility.hyperbolicEccentricToTrue(eUD, anomalyUD); + } + + default: + break; + } + + } else { + switch (cachedPositionAngleType) { + case MEAN: + if (inputType == PositionAngleType.ECCENTRIC) { + return FieldKeplerianAnomalyUtility.ellipticEccentricToMean(eUD, anomalyUD); + } else { + return FieldKeplerianAnomalyUtility.ellipticTrueToMean(eUD, anomalyUD); + } + + case ECCENTRIC: + if (inputType == PositionAngleType.MEAN) { + return FieldKeplerianAnomalyUtility.ellipticMeanToEccentric(eUD, anomalyUD); + } else { + return FieldKeplerianAnomalyUtility.ellipticTrueToEccentric(eUD, anomalyUD); + } + + case TRUE: + if (inputType == PositionAngleType.MEAN) { + return FieldKeplerianAnomalyUtility.ellipticMeanToTrue(eUD, anomalyUD); + } else { + return FieldKeplerianAnomalyUtility.ellipticEccentricToTrue(eUD, anomalyUD); + } + + default: + break; + } + + } + throw new OrekitInternalError(null); + } + + } + + /** Initialize cached anomaly. + * @param anomaly input anomaly + * @param inputType position angle type passed as input + * @return anomaly to cache + * @since 12.1 + */ + private double initializeCachedAnomaly(final double anomaly, final PositionAngleType inputType) { + if (inputType == cachedPositionAngleType) { + return anomaly; + + } else { + if (a < 0) { + switch (cachedPositionAngleType) { + case MEAN: + if (inputType == PositionAngleType.ECCENTRIC) { + return KeplerianAnomalyUtility.hyperbolicEccentricToMean(e, anomaly); + } else { + return KeplerianAnomalyUtility.hyperbolicTrueToMean(e, anomaly); + } + + case ECCENTRIC: + if (inputType == PositionAngleType.MEAN) { + return KeplerianAnomalyUtility.hyperbolicMeanToEccentric(e, anomaly); + } else { + return KeplerianAnomalyUtility.hyperbolicTrueToEccentric(e, anomaly); + } + + case TRUE: + if (inputType == PositionAngleType.ECCENTRIC) { + return KeplerianAnomalyUtility.hyperbolicEccentricToTrue(e, anomaly); + } else { + return KeplerianAnomalyUtility.hyperbolicMeanToTrue(e, anomaly); + } + + default: + break; + } + + } else { + switch (cachedPositionAngleType) { + case MEAN: + if (inputType == PositionAngleType.ECCENTRIC) { + return KeplerianAnomalyUtility.ellipticEccentricToMean(e, anomaly); + } else { + return KeplerianAnomalyUtility.ellipticTrueToMean(e, anomaly); + } + + case ECCENTRIC: + if (inputType == PositionAngleType.MEAN) { + return KeplerianAnomalyUtility.ellipticMeanToEccentric(e, anomaly); + } else { + return KeplerianAnomalyUtility.ellipticTrueToEccentric(e, anomaly); + } + + case TRUE: + if (inputType == PositionAngleType.ECCENTRIC) { + return KeplerianAnomalyUtility.ellipticEccentricToTrue(e, anomaly); + } else { + return KeplerianAnomalyUtility.ellipticMeanToTrue(e, anomaly); + } + + default: + break; + } + } + throw new OrekitInternalError(null); + } + } + /** Compute reference axes. * @return referecne axes * @since 12.0 @@ -720,7 +1005,7 @@ private void computePVWithoutA() { // hyperbolic case // compute position and velocity factors - final SinCos scV = FastMath.sinCos(v); + final SinCos scV = FastMath.sinCos(getTrueAnomaly()); final double sinV = scV.sin(); final double cosV = scV.cos(); final double f = a * (1 - e * e); @@ -753,11 +1038,11 @@ private Vector3D nonKeplerianAcceleration() { final double nonKeplerianMeanMotion = getMeanAnomalyDot() - getKeplerianMeanMotion(); final double nonKeplerianAx = dCdP[3][0] * aDot + dCdP[3][1] * eDot + dCdP[3][2] * iDot + - dCdP[3][3] * paDot + dCdP[3][4] * raanDot + dCdP[3][5] * nonKeplerianMeanMotion; + dCdP[3][3] * paDot + dCdP[3][4] * raanDot + dCdP[3][5] * nonKeplerianMeanMotion; final double nonKeplerianAy = dCdP[4][0] * aDot + dCdP[4][1] * eDot + dCdP[4][2] * iDot + - dCdP[4][3] * paDot + dCdP[4][4] * raanDot + dCdP[4][5] * nonKeplerianMeanMotion; + dCdP[4][3] * paDot + dCdP[4][4] * raanDot + dCdP[4][5] * nonKeplerianMeanMotion; final double nonKeplerianAz = dCdP[5][0] * aDot + dCdP[5][1] * eDot + dCdP[5][2] * iDot + - dCdP[5][3] * paDot + dCdP[5][4] * raanDot + dCdP[5][5] * nonKeplerianMeanMotion; + dCdP[5][3] * paDot + dCdP[5][4] * raanDot + dCdP[5][5] * nonKeplerianMeanMotion; return new Vector3D(nonKeplerianAx, nonKeplerianAy, nonKeplerianAz); @@ -786,7 +1071,7 @@ protected Vector3D initPosition() { // hyperbolic case // compute position and velocity factors - final SinCos scV = FastMath.sinCos(v); + final SinCos scV = FastMath.sinCos(getTrueAnomaly()); final double sinV = scV.sin(); final double cosV = scV.cos(); final double f = a * (1 - e * e); @@ -808,8 +1093,8 @@ protected TimeStampedPVCoordinates initPVCoordinates() { final double r2 = partialPV.getPosition().getNormSq(); final Vector3D keplerianAcceleration = new Vector3D(-getMu() / (r2 * FastMath.sqrt(r2)), partialPV.getPosition()); final Vector3D acceleration = hasDerivatives() ? - keplerianAcceleration.add(nonKeplerianAcceleration()) : - keplerianAcceleration; + keplerianAcceleration.add(nonKeplerianAcceleration()) : + keplerianAcceleration; return new TimeStampedPVCoordinates(getDate(), partialPV.getPosition(), partialPV.getVelocity(), acceleration); @@ -820,9 +1105,8 @@ public KeplerianOrbit shiftedBy(final double dt) { // use Keplerian-only motion final KeplerianOrbit keplerianShifted = new KeplerianOrbit(a, e, i, pa, raan, - getMeanAnomaly() + getKeplerianMeanMotion() * dt, - PositionAngleType.MEAN, getFrame(), - getDate().shiftedBy(dt), getMu()); + getMeanAnomaly() + getKeplerianMeanMotion() * dt, PositionAngleType.MEAN, + cachedPositionAngleType, getFrame(), getDate().shiftedBy(dt), getMu()); if (hasDerivatives()) { @@ -832,18 +1116,18 @@ PositionAngleType.MEAN, getFrame(), // add quadratic effect of non-Keplerian acceleration to Keplerian-only shift keplerianShifted.computePVWithoutA(); final Vector3D fixedP = new Vector3D(1, keplerianShifted.partialPV.getPosition(), - 0.5 * dt * dt, nonKeplerianAcceleration); + 0.5 * dt * dt, nonKeplerianAcceleration); final double fixedR2 = fixedP.getNormSq(); final double fixedR = FastMath.sqrt(fixedR2); final Vector3D fixedV = new Vector3D(1, keplerianShifted.partialPV.getVelocity(), - dt, nonKeplerianAcceleration); + dt, nonKeplerianAcceleration); final Vector3D fixedA = new Vector3D(-getMu() / (fixedR2 * fixedR), keplerianShifted.partialPV.getPosition(), - 1, nonKeplerianAcceleration); + 1, nonKeplerianAcceleration); // build a new orbit, taking non-Keplerian acceleration into account return new KeplerianOrbit(new TimeStampedPVCoordinates(keplerianShifted.getDate(), - fixedP, fixedV, fixedA), - keplerianShifted.getFrame(), keplerianShifted.getMu()); + fixedP, fixedV, fixedA), + keplerianShifted.getFrame(), keplerianShifted.getMu()); } else { // Keplerian-only motion is all we can do @@ -924,24 +1208,24 @@ private double[][] computeJacobianMeanWrtCartesianElliptical() { // de final double factorER3 = pv / twoA; final Vector3D vectorER = new Vector3D(cosE * v2 / (r * mu), position, - sinE / sqrtMuA, velocity, - -factorER3 * sinE / sqrtMuA, vectorAR); + sinE / sqrtMuA, velocity, + -factorER3 * sinE / sqrtMuA, vectorAR); final Vector3D vectorERDot = new Vector3D(sinE / sqrtMuA, position, - cosE * 2 * r / mu, velocity, - -factorER3 * sinE / sqrtMuA, vectorARDot); + cosE * 2 * r / mu, velocity, + -factorER3 * sinE / sqrtMuA, vectorARDot); fillHalfRow(1, vectorER, jacobian[1], 0); fillHalfRow(1, vectorERDot, jacobian[1], 3); // dE / dr (Eccentric anomaly) final double coefE = cosE / (e * sqrtMuA); final Vector3D vectorEAnR = - new Vector3D(-sinE * v2 / (e * r * mu), position, coefE, velocity, - -factorER3 * coefE, vectorAR); + new Vector3D(-sinE * v2 / (e * r * mu), position, coefE, velocity, + -factorER3 * coefE, vectorAR); // dE / drDot final Vector3D vectorEAnRDot = - new Vector3D(-sinE * 2 * r / (e * mu), velocity, coefE, position, - -factorER3 * coefE, vectorARDot); + new Vector3D(-sinE * 2 * r / (e * mu), velocity, coefE, position, + -factorER3 * coefE, vectorARDot); // precomputing some more factors final double s1 = -sinE * pz / r - cosE * vz * sqrtAoMu; @@ -952,21 +1236,21 @@ private double[][] computeJacobianMeanWrtCartesianElliptical() { final double t3 = sqrtRec * (cosE - e) * vz / (2 * sqrtMuA); final double t4 = sqrtRec * (e * sinI * cosPA * sqrtRec - vz * sqrtAoMu); final Vector3D s = new Vector3D(cosE / r, Vector3D.PLUS_K, - s1, vectorEAnR, - s2, position, - s3, vectorAR); + s1, vectorEAnR, + s2, position, + s3, vectorAR); final Vector3D sDot = new Vector3D(-sinE * sqrtAoMu, Vector3D.PLUS_K, - s1, vectorEAnRDot, - s3, vectorARDot); + s1, vectorEAnRDot, + s3, vectorARDot); final Vector3D t = - new Vector3D(sqrtRec * sinE / r, Vector3D.PLUS_K).add(new Vector3D(t1, vectorEAnR, - t2, position, - t3, vectorAR, - t4, vectorER)); + new Vector3D(sqrtRec * sinE / r, Vector3D.PLUS_K).add(new Vector3D(t1, vectorEAnR, + t2, position, + t3, vectorAR, + t4, vectorER)); final Vector3D tDot = new Vector3D(sqrtRec * (cosE - e) * sqrtAoMu, Vector3D.PLUS_K, - t1, vectorEAnRDot, - t3, vectorARDot, - t4, vectorERDot); + t1, vectorEAnRDot, + t3, vectorARDot, + t4, vectorERDot); // di final double factorI1 = -sinI * sqrtRec / sqrtMuA; @@ -976,9 +1260,9 @@ private double[][] computeJacobianMeanWrtCartesianElliptical() { final double i4 = cosI * sinPA; final double i5 = cosI * cosPA; fillHalfRow(i1, new Vector3D(vy, -vx, 0), i2, vectorAR, i3, vectorER, i4, s, i5, t, - jacobian[2], 0); + jacobian[2], 0); fillHalfRow(i1, new Vector3D(-py, px, 0), i2, vectorARDot, i3, vectorERDot, i4, sDot, i5, tDot, - jacobian[2], 3); + jacobian[2], 3); // dpa fillHalfRow(cosPA / sinI, s, -sinPA / sinI, t, jacobian[3], 0); @@ -987,11 +1271,11 @@ private double[][] computeJacobianMeanWrtCartesianElliptical() { // dRaan final double factorRaanR = 1 / (mu * a * oMe2 * sinI * sinI); fillHalfRow(-factorRaanR * my, new Vector3D( 0, vz, -vy), - factorRaanR * mx, new Vector3D(-vz, 0, vx), - jacobian[4], 0); + factorRaanR * mx, new Vector3D(-vz, 0, vx), + jacobian[4], 0); fillHalfRow(-factorRaanR * my, new Vector3D( 0, -pz, py), - factorRaanR * mx, new Vector3D(pz, 0, -px), - jacobian[4], 3); + factorRaanR * mx, new Vector3D(pz, 0, -px), + jacobian[4], 3); // dM fillHalfRow(rOnA, vectorEAnR, -sinE, vectorER, jacobian[5], 0); @@ -1298,12 +1582,12 @@ public void addKeplerContribution(final PositionAngleType type, final double gm, break; case ECCENTRIC : oMe2 = FastMath.abs(1 - e * e); - ksi = 1 + e * FastMath.cos(v); + ksi = 1 + e * FastMath.cos(getTrueAnomaly()); pDot[5] += n * ksi / oMe2; break; case TRUE : oMe2 = FastMath.abs(1 - e * e); - ksi = 1 + e * FastMath.cos(v); + ksi = 1 + e * FastMath.cos(getTrueAnomaly()); pDot[5] += n * ksi * ksi / (oMe2 * FastMath.sqrt(oMe2)); break; default : @@ -1316,19 +1600,19 @@ public void addKeplerContribution(final PositionAngleType type, final double gm, */ public String toString() { return new StringBuilder().append("Keplerian parameters: ").append('{'). - append("a: ").append(a). - append("; e: ").append(e). - append("; i: ").append(FastMath.toDegrees(i)). - append("; pa: ").append(FastMath.toDegrees(pa)). - append("; raan: ").append(FastMath.toDegrees(raan)). - append("; v: ").append(FastMath.toDegrees(v)). - append(";}").toString(); + append("a: ").append(a). + append("; e: ").append(e). + append("; i: ").append(FastMath.toDegrees(i)). + append("; pa: ").append(FastMath.toDegrees(pa)). + append("; raan: ").append(FastMath.toDegrees(raan)). + append("; v: ").append(FastMath.toDegrees(getTrueAnomaly())). + append(";}").toString(); } /** {@inheritDoc} */ @Override public PositionAngleType getCachedPositionAngleType() { - return PositionAngleType.TRUE; + return cachedPositionAngleType; } /** {@inheritDoc} */ @@ -1341,8 +1625,8 @@ public boolean hasRates() { @Override public KeplerianOrbit removeRates() { final PositionAngleType positionAngleType = getCachedPositionAngleType(); - return new KeplerianOrbit(getA(), getE(), getI(), getPerigeeArgument(), getRightAscensionOfAscendingNode(), - getAnomaly(positionAngleType), positionAngleType, getFrame(), getDate(), getMu()); + return new KeplerianOrbit(a, e, i, pa, raan, cachedAnomaly, positionAngleType, positionAngleType, + getFrame(), getDate(), getMu()); } /** Check if the given parameter is within an acceptable range. @@ -1363,7 +1647,7 @@ private void checkParameterRangeInclusive(final String parameterName, final doub final double lowerBound, final double upperBound) { if (parameter < lowerBound || parameter > upperBound) { throw new OrekitException(OrekitMessages.INVALID_PARAMETER_RANGE, parameterName, - parameter, lowerBound, upperBound); + parameter, lowerBound, upperBound); } } @@ -1380,10 +1664,13 @@ private Object writeReplace() { private static class DTO implements Serializable { /** Serializable UID. */ - private static final long serialVersionUID = 20170414L; + private static final long serialVersionUID = 20231217L; /** Double values. */ - private double[] d; + private final double[] d; + + /** Type of position angle whose value is cached. */ + private final PositionAngleType positionAngleType; /** Frame in which are defined the orbital parameters. */ private final Frame frame; @@ -1394,6 +1681,7 @@ private static class DTO implements Serializable { private DTO(final KeplerianOrbit orbit) { final TimeStampedPVCoordinates pv = orbit.getPVCoordinates(); + this.positionAngleType = orbit.cachedPositionAngleType; // decompose date final AbsoluteDate j2000Epoch = @@ -1406,16 +1694,16 @@ private DTO(final KeplerianOrbit orbit) { this.d = new double[] { epoch, offset, orbit.getMu(), orbit.a, orbit.e, orbit.i, - orbit.pa, orbit.raan, orbit.v, + orbit.pa, orbit.raan, orbit.cachedAnomaly, orbit.aDot, orbit.eDot, orbit.iDot, - orbit.paDot, orbit.raanDot, orbit.vDot + orbit.paDot, orbit.raanDot, orbit.cachedAnomalyDot }; } else { // we don't have derivatives this.d = new double[] { epoch, offset, orbit.getMu(), orbit.a, orbit.e, orbit.i, - orbit.pa, orbit.raan, orbit.v + orbit.pa, orbit.raan, orbit.cachedAnomaly }; } @@ -1432,15 +1720,14 @@ private Object readResolve() { if (d.length >= 15) { // we have derivatives return new KeplerianOrbit(d[ 3], d[ 4], d[ 5], d[ 6], d[ 7], d[ 8], - d[ 9], d[10], d[11], d[12], d[13], d[14], - PositionAngleType.TRUE, - frame, j2000Epoch.shiftedBy(d[0]).shiftedBy(d[1]), - d[2]); + d[ 9], d[10], d[11], d[12], d[13], d[14], + positionAngleType, positionAngleType, + frame, j2000Epoch.shiftedBy(d[0]).shiftedBy(d[1]), d[2]); } else { // we don't have derivatives - return new KeplerianOrbit(d[3], d[4], d[5], d[6], d[7], d[8], PositionAngleType.TRUE, - frame, j2000Epoch.shiftedBy(d[0]).shiftedBy(d[1]), - d[2]); + return new KeplerianOrbit(d[3], d[4], d[5], d[6], d[7], d[8], + positionAngleType, positionAngleType, + frame, j2000Epoch.shiftedBy(d[0]).shiftedBy(d[1]), d[2]); } } diff --git a/src/main/java/org/orekit/orbits/OrbitType.java b/src/main/java/org/orekit/orbits/OrbitType.java index 28a87bd4ca..e6105a1611 100644 --- a/src/main/java/org/orekit/orbits/OrbitType.java +++ b/src/main/java/org/orekit/orbits/OrbitType.java @@ -812,6 +812,7 @@ public KeplerianOrbit normalize(final Orbit orbit, final Orbit reference) { // convert input to proper type final KeplerianOrbit kO = convertType(orbit); final KeplerianOrbit kR = convertType(reference); + final PositionAngleType cachedPositionAngleType = kR.getCachedPositionAngleType(); // perform normalization if (kO.hasDerivatives()) { @@ -820,14 +821,15 @@ public KeplerianOrbit normalize(final Orbit orbit, final Orbit reference) { kO.getI(), MathUtils.normalizeAngle(kO.getPerigeeArgument(), kR.getPerigeeArgument()), MathUtils.normalizeAngle(kO.getRightAscensionOfAscendingNode(), kR.getRightAscensionOfAscendingNode()), - MathUtils.normalizeAngle(kO.getTrueAnomaly(), kR.getTrueAnomaly()), + MathUtils.normalizeAngle(kO.getAnomaly(cachedPositionAngleType), + kR.getAnomaly(cachedPositionAngleType)), kO.getADot(), kO.getEDot(), kO.getIDot(), kO.getPerigeeArgumentDot(), kO.getRightAscensionOfAscendingNodeDot(), - kO.getTrueAnomalyDot(), - PositionAngleType.TRUE, + kO.getAnomalyDot(cachedPositionAngleType), + cachedPositionAngleType, kO.getFrame(), kO.getDate(), kO.getMu()); @@ -837,8 +839,9 @@ public KeplerianOrbit normalize(final Orbit orbit, final Orbit reference) { kO.getI(), MathUtils.normalizeAngle(kO.getPerigeeArgument(), kR.getPerigeeArgument()), MathUtils.normalizeAngle(kO.getRightAscensionOfAscendingNode(), kR.getRightAscensionOfAscendingNode()), - MathUtils.normalizeAngle(kO.getTrueAnomaly(), kR.getTrueAnomaly()), - PositionAngleType.TRUE, + MathUtils.normalizeAngle(kO.getAnomaly(cachedPositionAngleType), + kR.getAnomaly(cachedPositionAngleType)), + cachedPositionAngleType, kO.getFrame(), kO.getDate(), kO.getMu()); diff --git a/src/main/java/org/orekit/propagation/analytical/BrouwerLyddanePropagator.java b/src/main/java/org/orekit/propagation/analytical/BrouwerLyddanePropagator.java index 96b84b4834..ee247aea4d 100644 --- a/src/main/java/org/orekit/propagation/analytical/BrouwerLyddanePropagator.java +++ b/src/main/java/org/orekit/propagation/analytical/BrouwerLyddanePropagator.java @@ -761,7 +761,7 @@ private BLModel computeMeanParameters(final KeplerianOrbit osculating, final dou current.mean.getPerigeeArgument() + deltaOmega, current.mean.getRightAscensionOfAscendingNode() + deltaRAAN, current.mean.getMeanAnomaly() + deltaAnom, - PositionAngleType.MEAN, + PositionAngleType.MEAN, PositionAngleType.TRUE, current.mean.getFrame(), current.mean.getDate(), mu), mass, referenceRadius, mu, ck0); @@ -1435,7 +1435,7 @@ public KeplerianOrbit propagateParameters(final AbsoluteDate date) { g.getValue(), h.getValue(), l.getValue(), a.getFirstDerivative(), e.getFirstDerivative(), i.getFirstDerivative(), g.getFirstDerivative(), h.getFirstDerivative(), l.getFirstDerivative(), - PositionAngleType.MEAN, mean.getFrame(), date, mu); + PositionAngleType.MEAN, PositionAngleType.TRUE, mean.getFrame(), date, mu); } diff --git a/src/test/java/org/orekit/orbits/KeplerianOrbitTest.java b/src/test/java/org/orekit/orbits/KeplerianOrbitTest.java index 98ad05fc85..d902719113 100644 --- a/src/test/java/org/orekit/orbits/KeplerianOrbitTest.java +++ b/src/test/java/org/orekit/orbits/KeplerianOrbitTest.java @@ -1592,6 +1592,56 @@ public void testKeplerianToPvToKeplerian() { } + @Test + void testCoverageCachedPositionAngleTypeElliptic() { + testCoverageCachedPositionAngleType(1e4, 0.5); + } + + @Test + void testCoverageCachedPositionAngleTypeHyperbolic() { + testCoverageCachedPositionAngleType(-1e4, 2); + } + + private void testCoverageCachedPositionAngleType(final double a, final double e) { + // GIVEN + final double expectedAnomaly = 0.; + // WHEN & THEN + for (final PositionAngleType inputPositionAngleType: PositionAngleType.values()) { + for (final PositionAngleType cachedPositionAngleType: PositionAngleType.values()) { + final KeplerianOrbit keplerianOrbit = new KeplerianOrbit(a, e, 0., 0., 0., + expectedAnomaly, inputPositionAngleType, cachedPositionAngleType, FramesFactory.getGCRF(), date, mu); + Assertions.assertEquals(expectedAnomaly, keplerianOrbit.getTrueAnomaly()); + Assertions.assertEquals(expectedAnomaly, keplerianOrbit.getEccentricAnomaly()); + Assertions.assertEquals(expectedAnomaly, keplerianOrbit.getMeanAnomaly()); + Assertions.assertTrue(Double.isNaN(keplerianOrbit.getTrueAnomalyDot())); + Assertions.assertTrue(Double.isNaN(keplerianOrbit.getEccentricAnomalyDot())); + Assertions.assertTrue(Double.isNaN(keplerianOrbit.getMeanAnomalyDot())); + } + } + } + + @Test + void testCoverageCachedPositionAngleTypeWithRates() { + // GIVEN + final double semiMajorAxis = 1e4; + final double eccentricity = 0.; + final double expectedAnomaly = 0.; + final double expectedAnomalyDot = 0.; + // WHEN & THEN + for (final PositionAngleType inputPositionAngleType: PositionAngleType.values()) { + for (final PositionAngleType cachedPositionAngleType: PositionAngleType.values()) { + final KeplerianOrbit keplerianOrbit = new KeplerianOrbit(semiMajorAxis, eccentricity, 0., 0., 0., + expectedAnomaly, 0., 0., 0., 0., 0., expectedAnomalyDot, + inputPositionAngleType, cachedPositionAngleType, FramesFactory.getGCRF(), date, mu); + Assertions.assertEquals(expectedAnomaly, keplerianOrbit.getTrueAnomaly()); + Assertions.assertEquals(expectedAnomaly, keplerianOrbit.getEccentricAnomaly()); + Assertions.assertEquals(expectedAnomaly, keplerianOrbit.getMeanAnomaly()); + Assertions.assertEquals(expectedAnomalyDot, keplerianOrbit.getTrueAnomalyDot()); + Assertions.assertEquals(expectedAnomalyDot, keplerianOrbit.getEccentricAnomalyDot()); + Assertions.assertEquals(expectedAnomalyDot, keplerianOrbit.getMeanAnomalyDot()); + } + } + } @BeforeEach public void setUp() { From 489df5253ab1582b00e330ed8a7c085f72fc7e85 Mon Sep 17 00:00:00 2001 From: Serrof Date: Sun, 17 Dec 2023 22:20:57 +0100 Subject: [PATCH 121/359] set up cache in CircularOrbit --- .../java/org/orekit/orbits/CircularOrbit.java | 408 ++++++++++++++---- .../org/orekit/orbits/KeplerianOrbit.java | 2 +- .../java/org/orekit/orbits/OrbitType.java | 19 +- .../org/orekit/orbits/CircularOrbitTest.java | 22 + 4 files changed, 352 insertions(+), 99 deletions(-) diff --git a/src/main/java/org/orekit/orbits/CircularOrbit.java b/src/main/java/org/orekit/orbits/CircularOrbit.java index 3985be0562..647da74315 100644 --- a/src/main/java/org/orekit/orbits/CircularOrbit.java +++ b/src/main/java/org/orekit/orbits/CircularOrbit.java @@ -75,7 +75,7 @@ public class CircularOrbit extends Orbit implements PositionAngleBased { /** Serializable UID. */ - private static final long serialVersionUID = 20170414L; + private static final long serialVersionUID = 20231217L; /** Semi-major axis (m). */ private final double a; @@ -92,8 +92,11 @@ public class CircularOrbit extends Orbit implements PositionAngleBased { /** Right Ascension of Ascending Node (rad). */ private final double raan; - /** True latitude argument (rad). */ - private final double alphaV; + /** Cached latitude argument (rad). */ + private final double cachedAlpha; + + /** Type of cached position angle (latitude argument). */ + private final PositionAngleType cachedPositionAngleType; /** Semi-major axis derivative (m/s). */ private final double aDot; @@ -111,7 +114,7 @@ public class CircularOrbit extends Orbit implements PositionAngleBased { private final double raanDot; /** True latitude argument derivative (rad/s). */ - private final double alphaVDot; + private final double cachedAlphaDot; /** Indicator for {@link PVCoordinates} serialization. */ private final boolean serializePV; @@ -127,21 +130,46 @@ public class CircularOrbit extends Orbit implements PositionAngleBased { * @param raan right ascension of ascending node (Ω, rad) * @param alpha an + ω, mean, eccentric or true latitude argument (rad) * @param type type of latitude argument + * @param cachedPositionAngleType type of cached latitude argument * @param frame the frame in which are defined the parameters * (must be a {@link Frame#isPseudoInertial pseudo-inertial frame}) * @param date date of the orbital parameters * @param mu central attraction coefficient (m³/s²) * @exception IllegalArgumentException if eccentricity is equal to 1 or larger or * if frame is not a {@link Frame#isPseudoInertial pseudo-inertial frame} + * @since 12.1 */ public CircularOrbit(final double a, final double ex, final double ey, final double i, final double raan, final double alpha, - final PositionAngleType type, + final PositionAngleType type, final PositionAngleType cachedPositionAngleType, final Frame frame, final AbsoluteDate date, final double mu) throws IllegalArgumentException { this(a, ex, ey, i, raan, alpha, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN, - type, frame, date, mu); + type, cachedPositionAngleType, frame, date, mu); + } + + /** Creates a new instance without derivatives and with cached position angle same as value inputted. + * @param a semi-major axis (m) + * @param ex e cos(ω), first component of circular eccentricity vector + * @param ey e sin(ω), second component of circular eccentricity vector + * @param i inclination (rad) + * @param raan right ascension of ascending node (Ω, rad) + * @param alpha an + ω, mean, eccentric or true latitude argument (rad) + * @param type type of latitude argument + * @param frame the frame in which are defined the parameters + * (must be a {@link Frame#isPseudoInertial pseudo-inertial frame}) + * @param date date of the orbital parameters + * @param mu central attraction coefficient (m³/s²) + * @exception IllegalArgumentException if eccentricity is equal to 1 or larger or + * if frame is not a {@link Frame#isPseudoInertial pseudo-inertial frame} + */ + public CircularOrbit(final double a, final double ex, final double ey, + final double i, final double raan, final double alpha, + final PositionAngleType type, + final Frame frame, final AbsoluteDate date, final double mu) + throws IllegalArgumentException { + this(a, ex, ey, i, raan, alpha, type, type, frame, date, mu); } /** Creates a new instance. @@ -158,18 +186,20 @@ public CircularOrbit(final double a, final double ex, final double ey, * @param raanDot right ascension of ascending node derivative (rad/s) * @param alphaDot d(an + ω), mean, eccentric or true latitude argument derivative (rad/s) * @param type type of latitude argument + * @param cachedPositionAngleType type of cached latitude argument * @param frame the frame in which are defined the parameters * (must be a {@link Frame#isPseudoInertial pseudo-inertial frame}) * @param date date of the orbital parameters * @param mu central attraction coefficient (m³/s²) * @exception IllegalArgumentException if eccentricity is equal to 1 or larger or * if frame is not a {@link Frame#isPseudoInertial pseudo-inertial frame} + * @since 12.1 */ public CircularOrbit(final double a, final double ex, final double ey, final double i, final double raan, final double alpha, final double aDot, final double exDot, final double eyDot, final double iDot, final double raanDot, final double alphaDot, - final PositionAngleType type, + final PositionAngleType type, final PositionAngleType cachedPositionAngleType, final Frame frame, final AbsoluteDate date, final double mu) throws IllegalArgumentException { super(frame, date, mu); @@ -187,42 +217,15 @@ public CircularOrbit(final double a, final double ex, final double ey, this.iDot = iDot; this.raan = raan; this.raanDot = raanDot; + this.cachedPositionAngleType = cachedPositionAngleType; if (hasDerivatives()) { - final UnivariateDerivative1 exUD = new UnivariateDerivative1(ex, exDot); - final UnivariateDerivative1 eyUD = new UnivariateDerivative1(ey, eyDot); - final UnivariateDerivative1 alphaUD = new UnivariateDerivative1(alpha, alphaDot); - final UnivariateDerivative1 alphavUD; - switch (type) { - case MEAN : - alphavUD = FieldCircularLatitudeArgumentUtility.meanToTrue(exUD, eyUD, alphaUD); - break; - case ECCENTRIC : - alphavUD = FieldCircularLatitudeArgumentUtility.eccentricToTrue(exUD, eyUD, alphaUD); - break; - case TRUE : - alphavUD = alphaUD; - break; - default : - throw new OrekitInternalError(null); - } - this.alphaV = alphavUD.getValue(); - this.alphaVDot = alphavUD.getDerivative(1); + final UnivariateDerivative1 alphaUD = initializeCachedAlpha(alpha, alphaDot, type); + this.cachedAlpha = alphaUD.getValue(); + this.cachedAlphaDot = alphaUD.getFirstDerivative(); } else { - switch (type) { - case MEAN : - this.alphaV = CircularLatitudeArgumentUtility.meanToTrue(ex, ey, alpha); - break; - case ECCENTRIC : - this.alphaV = CircularLatitudeArgumentUtility.eccentricToTrue(ex, ey, alpha); - break; - case TRUE : - this.alphaV = alpha; - break; - default : - throw new OrekitInternalError(null); - } - this.alphaVDot = Double.NaN; + this.cachedAlpha = initializeCachedAlpha(alpha, type); + this.cachedAlphaDot = Double.NaN; } serializePV = false; @@ -230,20 +233,53 @@ public CircularOrbit(final double a, final double ex, final double ey, } + /** Creates a new instance with derivatives and with cached position angle same as value inputted. + * @param a semi-major axis (m) + * @param ex e cos(ω), first component of circular eccentricity vector + * @param ey e sin(ω), second component of circular eccentricity vector + * @param i inclination (rad) + * @param raan right ascension of ascending node (Ω, rad) + * @param alpha an + ω, mean, eccentric or true latitude argument (rad) + * @param aDot semi-major axis derivative (m/s) + * @param exDot d(e cos(ω))/dt, first component of circular eccentricity vector derivative + * @param eyDot d(e sin(ω))/dt, second component of circular eccentricity vector derivative + * @param iDot inclination derivative(rad/s) + * @param raanDot right ascension of ascending node derivative (rad/s) + * @param alphaDot d(an + ω), mean, eccentric or true latitude argument derivative (rad/s) + * @param type type of latitude argument + * @param frame the frame in which are defined the parameters + * (must be a {@link Frame#isPseudoInertial pseudo-inertial frame}) + * @param date date of the orbital parameters + * @param mu central attraction coefficient (m³/s²) + * @exception IllegalArgumentException if eccentricity is equal to 1 or larger or + * if frame is not a {@link Frame#isPseudoInertial pseudo-inertial frame} + */ + public CircularOrbit(final double a, final double ex, final double ey, + final double i, final double raan, final double alpha, + final double aDot, final double exDot, final double eyDot, + final double iDot, final double raanDot, final double alphaDot, + final PositionAngleType type, + final Frame frame, final AbsoluteDate date, final double mu) + throws IllegalArgumentException { + this(a, ex, ey, i, raan, alpha, aDot, exDot, eyDot, iDot, raanDot, alphaDot, type, type, + frame, date, mu); + } + /** Creates a new instance. * @param a semi-major axis (m) * @param ex e cos(ω), first component of circular eccentricity vector * @param ey e sin(ω), second component of circular eccentricity vector * @param i inclination (rad) * @param raan right ascension of ascending node (Ω, rad) - * @param alphaV v + ω, true latitude argument (rad) + * @param alpha input latitude argument (rad) * @param aDot semi-major axis derivative (m/s) * @param exDot d(e cos(ω))/dt, first component of circular eccentricity vector derivative * @param eyDot d(e sin(ω))/dt, second component of circular eccentricity vector derivative * @param iDot inclination derivative(rad/s) * @param raanDot right ascension of ascending node derivative (rad/s) - * @param alphaVDot d(v + ω), true latitude argument derivative (rad/s) + * @param alphaDot input latitude argument derivative (rad/s) * @param pvCoordinates the {@link PVCoordinates} in inertial frame + * @param positionAngleType type of position angle * @param frame the frame in which are defined the parameters * (must be a {@link Frame#isPseudoInertial pseudo-inertial frame}) * @param mu central attraction coefficient (m³/s²) @@ -251,11 +287,11 @@ public CircularOrbit(final double a, final double ex, final double ey, * if frame is not a {@link Frame#isPseudoInertial pseudo-inertial frame} */ private CircularOrbit(final double a, final double ex, final double ey, - final double i, final double raan, final double alphaV, + final double i, final double raan, final double alpha, final double aDot, final double exDot, final double eyDot, - final double iDot, final double raanDot, final double alphaVDot, - final TimeStampedPVCoordinates pvCoordinates, final Frame frame, - final double mu) + final double iDot, final double raanDot, final double alphaDot, + final TimeStampedPVCoordinates pvCoordinates, + final PositionAngleType positionAngleType, final Frame frame, final double mu) throws IllegalArgumentException { super(pvCoordinates, frame, mu); this.a = a; @@ -268,8 +304,9 @@ private CircularOrbit(final double a, final double ex, final double ey, this.iDot = iDot; this.raan = raan; this.raanDot = raanDot; - this.alphaV = alphaV; - this.alphaVDot = alphaVDot; + this.cachedAlpha = alpha; + this.cachedAlphaDot = alphaDot; + this.cachedPositionAngleType = positionAngleType; this.serializePV = true; this.partialPV = null; } @@ -291,6 +328,7 @@ private CircularOrbit(final double a, final double ex, final double ey, public CircularOrbit(final TimeStampedPVCoordinates pvCoordinates, final Frame frame, final double mu) throws IllegalArgumentException { super(pvCoordinates, frame, mu); + this.cachedPositionAngleType = PositionAngleType.TRUE; // compute semi-major axis final Vector3D pvP = pvCoordinates.getPosition(); @@ -337,7 +375,7 @@ public CircularOrbit(final TimeStampedPVCoordinates pvCoordinates, final Frame f // compute latitude argument final double beta = 1 / (1 + FastMath.sqrt(1 - ex * ex - ey * ey)); - alphaV = CircularLatitudeArgumentUtility.eccentricToTrue(ex, ey, FastMath.atan2(y2 + ey + eSE * beta * ex, x2 + ex - eSE * beta * ey)); + cachedAlpha = CircularLatitudeArgumentUtility.eccentricToTrue(ex, ey, FastMath.atan2(y2 + ey + eSE * beta * ex, x2 + ex - eSE * beta * ey)); partialPV = pvCoordinates; @@ -358,15 +396,15 @@ public CircularOrbit(final TimeStampedPVCoordinates pvCoordinates, final Frame f iDot = jacobian[3][3] * aX + jacobian[3][4] * aY + jacobian[3][5] * aZ; raanDot = jacobian[4][3] * aX + jacobian[4][4] * aY + jacobian[4][5] * aZ; - // in order to compute true anomaly derivative, we must compute - // mean anomaly derivative including Keplerian motion and convert to true anomaly + // in order to compute latitude argument derivative, we must compute + // mean latitude argument derivative including Keplerian motion and convert to true latitude argument final double alphaMDot = getKeplerianMeanMotion() + jacobian[5][3] * aX + jacobian[5][4] * aY + jacobian[5][5] * aZ; final UnivariateDerivative1 exUD = new UnivariateDerivative1(ex, exDot); final UnivariateDerivative1 eyUD = new UnivariateDerivative1(ey, eyDot); final UnivariateDerivative1 alphaMUD = new UnivariateDerivative1(getAlphaM(), alphaMDot); final UnivariateDerivative1 alphavUD = FieldCircularLatitudeArgumentUtility.meanToTrue(exUD, eyUD, alphaMUD); - alphaVDot = alphavUD.getDerivative(1); + cachedAlphaDot = alphavUD.getFirstDerivative(); } else { // acceleration is either almost zero or NaN, @@ -377,7 +415,7 @@ public CircularOrbit(final TimeStampedPVCoordinates pvCoordinates, final Frame f eyDot = Double.NaN; iDot = Double.NaN; raanDot = Double.NaN; - alphaVDot = Double.NaN; + cachedAlphaDot = Double.NaN; } serializePV = true; @@ -426,7 +464,8 @@ public CircularOrbit(final Orbit op) { final double equiEy = op.getEquinoctialEy(); ex = equiEx * cosRaan + equiEy * sinRaan; ey = equiEy * cosRaan - equiEx * sinRaan; - alphaV = op.getLv() - raan; + cachedPositionAngleType = PositionAngleType.TRUE; + cachedAlpha = op.getLv() - raan; if (op.hasDerivatives()) { aDot = op.getADot(); @@ -440,14 +479,14 @@ public CircularOrbit(final Orbit op) { (equiEyDot - equiEx * raanDot) * sinRaan; eyDot = (equiEyDot - equiEx * raanDot) * cosRaan - (equiExDot + equiEy * raanDot) * sinRaan; - alphaVDot = op.getLvDot() - raanDot; + cachedAlphaDot = op.getLvDot() - raanDot; } else { aDot = Double.NaN; exDot = Double.NaN; eyDot = Double.NaN; iDot = Double.NaN; raanDot = Double.NaN; - alphaVDot = Double.NaN; + cachedAlphaDot = Double.NaN; } serializePV = false; @@ -567,7 +606,19 @@ public double getHyDot() { * @return v + ω true latitude argument (rad) */ public double getAlphaV() { - return alphaV; + switch (cachedPositionAngleType) { + case TRUE: + return cachedAlpha; + + case ECCENTRIC: + return CircularLatitudeArgumentUtility.eccentricToTrue(ex, ey, cachedAlpha); + + case MEAN: + return CircularLatitudeArgumentUtility.meanToTrue(ex, ey, cachedAlpha); + + default: + throw new OrekitInternalError(null); + } } /** Get the true latitude argument derivative. @@ -578,14 +629,48 @@ public double getAlphaV() { * @since 9.0 */ public double getAlphaVDot() { - return alphaVDot; + switch (cachedPositionAngleType) { + case ECCENTRIC: + final UnivariateDerivative1 alphaEUD = new UnivariateDerivative1(cachedAlpha, cachedAlphaDot); + final UnivariateDerivative1 exUD = new UnivariateDerivative1(ex, exDot); + final UnivariateDerivative1 eyUD = new UnivariateDerivative1(ey, eyDot); + final UnivariateDerivative1 alphaVUD = FieldCircularLatitudeArgumentUtility.eccentricToTrue(exUD, eyUD, + alphaEUD); + return alphaVUD.getFirstDerivative(); + + case TRUE: + return cachedAlphaDot; + + case MEAN: + final UnivariateDerivative1 alphaMUD = new UnivariateDerivative1(cachedAlpha, cachedAlphaDot); + final UnivariateDerivative1 exUD2 = new UnivariateDerivative1(ex, exDot); + final UnivariateDerivative1 eyUD2 = new UnivariateDerivative1(ey, eyDot); + final UnivariateDerivative1 alphaVUD2 = FieldCircularLatitudeArgumentUtility.meanToTrue(exUD2, + eyUD2, alphaMUD); + return alphaVUD2.getFirstDerivative(); + + default: + throw new OrekitInternalError(null); + } } /** Get the eccentric latitude argument. * @return E + ω eccentric latitude argument (rad) */ public double getAlphaE() { - return CircularLatitudeArgumentUtility.trueToEccentric(ex, ey, alphaV); + switch (cachedPositionAngleType) { + case TRUE: + return CircularLatitudeArgumentUtility.trueToEccentric(ex, ey, cachedAlpha); + + case ECCENTRIC: + return cachedAlpha; + + case MEAN: + return CircularLatitudeArgumentUtility.meanToEccentric(ex, ey, cachedAlpha); + + default: + throw new OrekitInternalError(null); + } } /** Get the eccentric latitude argument derivative. @@ -596,18 +681,48 @@ public double getAlphaE() { * @since 9.0 */ public double getAlphaEDot() { - final UnivariateDerivative1 alphaVUD = new UnivariateDerivative1(alphaV, alphaVDot); - final UnivariateDerivative1 exUD = new UnivariateDerivative1(ex, exDot); - final UnivariateDerivative1 eyUD = new UnivariateDerivative1(ey, eyDot); - final UnivariateDerivative1 alphaEUD = FieldCircularLatitudeArgumentUtility.trueToEccentric(exUD, eyUD, alphaVUD); - return alphaEUD.getDerivative(1); + switch (cachedPositionAngleType) { + case TRUE: + final UnivariateDerivative1 alphaVUD = new UnivariateDerivative1(cachedAlpha, cachedAlphaDot); + final UnivariateDerivative1 exUD = new UnivariateDerivative1(ex, exDot); + final UnivariateDerivative1 eyUD = new UnivariateDerivative1(ey, eyDot); + final UnivariateDerivative1 alphaEUD = FieldCircularLatitudeArgumentUtility.trueToEccentric(exUD, eyUD, + alphaVUD); + return alphaEUD.getFirstDerivative(); + + case ECCENTRIC: + return cachedAlphaDot; + + case MEAN: + final UnivariateDerivative1 alphaMUD = new UnivariateDerivative1(cachedAlpha, cachedAlphaDot); + final UnivariateDerivative1 exUD2 = new UnivariateDerivative1(ex, exDot); + final UnivariateDerivative1 eyUD2 = new UnivariateDerivative1(ey, eyDot); + final UnivariateDerivative1 alphaVUD2 = FieldCircularLatitudeArgumentUtility.meanToEccentric(exUD2, + eyUD2, alphaMUD); + return alphaVUD2.getFirstDerivative(); + + default: + throw new OrekitInternalError(null); + } } /** Get the mean latitude argument. * @return M + ω mean latitude argument (rad) */ public double getAlphaM() { - return CircularLatitudeArgumentUtility.trueToMean(ex, ey, alphaV); + switch (cachedPositionAngleType) { + case TRUE: + return CircularLatitudeArgumentUtility.trueToMean(ex, ey, cachedAlpha); + + case MEAN: + return cachedAlpha; + + case ECCENTRIC: + return CircularLatitudeArgumentUtility.eccentricToMean(ex, ey, cachedAlpha); + + default: + throw new OrekitInternalError(null); + } } /** Get the mean latitude argument derivative. @@ -618,11 +733,29 @@ public double getAlphaM() { * @since 9.0 */ public double getAlphaMDot() { - final UnivariateDerivative1 alphaVUD = new UnivariateDerivative1(alphaV, alphaVDot); - final UnivariateDerivative1 exUD = new UnivariateDerivative1(ex, exDot); - final UnivariateDerivative1 eyUD = new UnivariateDerivative1(ey, eyDot); - final UnivariateDerivative1 alphaMUD = FieldCircularLatitudeArgumentUtility.trueToMean(exUD, eyUD, alphaVUD); - return alphaMUD.getDerivative(1); + switch (cachedPositionAngleType) { + case TRUE: + final UnivariateDerivative1 alphaVUD = new UnivariateDerivative1(cachedAlpha, cachedAlphaDot); + final UnivariateDerivative1 exUD = new UnivariateDerivative1(ex, exDot); + final UnivariateDerivative1 eyUD = new UnivariateDerivative1(ey, eyDot); + final UnivariateDerivative1 alphaMUD = FieldCircularLatitudeArgumentUtility.trueToMean(exUD, eyUD, + alphaVUD); + return alphaMUD.getFirstDerivative(); + + case MEAN: + return cachedAlphaDot; + + case ECCENTRIC: + final UnivariateDerivative1 alphaEUD = new UnivariateDerivative1(cachedAlpha, cachedAlphaDot); + final UnivariateDerivative1 exUD2 = new UnivariateDerivative1(ex, exDot); + final UnivariateDerivative1 eyUD2 = new UnivariateDerivative1(ey, eyDot); + final UnivariateDerivative1 alphaMUD2 = FieldCircularLatitudeArgumentUtility.eccentricToMean(exUD2, + eyUD2, alphaEUD); + return alphaMUD2.getFirstDerivative(); + + default: + throw new OrekitInternalError(null); + } } /** Get the latitude argument. @@ -733,12 +866,12 @@ public double getRightAscensionOfAscendingNodeDot() { /** {@inheritDoc} */ public double getLv() { - return alphaV + raan; + return getAlphaV() + raan; } /** {@inheritDoc} */ public double getLvDot() { - return alphaVDot + raanDot; + return getAlphaVDot() + raanDot; } /** {@inheritDoc} */ @@ -822,6 +955,95 @@ private void computePVWithoutA() { } + /** Initialize cached alpha with rate. + * @param alpha input alpha + * @param alphaDot rate of input alpha + * @param inputType position angle type passed as input + * @return alpha to cache with rate + * @since 12.1 + */ + private UnivariateDerivative1 initializeCachedAlpha(final double alpha, final double alphaDot, + final PositionAngleType inputType) { + if (cachedPositionAngleType == inputType) { + return new UnivariateDerivative1(alpha, alphaDot); + + } else { + final UnivariateDerivative1 exUD = new UnivariateDerivative1(ex, exDot); + final UnivariateDerivative1 eyUD = new UnivariateDerivative1(ey, eyDot); + final UnivariateDerivative1 alphaUD = new UnivariateDerivative1(alpha, alphaDot); + + switch (cachedPositionAngleType) { + + case ECCENTRIC: + if (inputType == PositionAngleType.MEAN) { + return FieldCircularLatitudeArgumentUtility.meanToEccentric(exUD, eyUD, alphaUD); + } else { + return FieldCircularLatitudeArgumentUtility.trueToEccentric(exUD, eyUD, alphaUD); + } + + case TRUE: + if (inputType == PositionAngleType.MEAN) { + return FieldCircularLatitudeArgumentUtility.meanToTrue(exUD, eyUD, alphaUD); + } else { + return FieldCircularLatitudeArgumentUtility.eccentricToTrue(exUD, eyUD, alphaUD); + } + + case MEAN: + if (inputType == PositionAngleType.TRUE) { + return FieldCircularLatitudeArgumentUtility.trueToMean(exUD, eyUD, alphaUD); + } else { + return FieldCircularLatitudeArgumentUtility.eccentricToMean(exUD, eyUD, alphaUD); + } + + default: + throw new OrekitInternalError(null); + + } + + } + + } + + /** Initialize cached alpha. + * @param alpha input alpha + * @param positionAngleType position angle type passed as input + * @return alpha to cache + * @since 12.1 + */ + private double initializeCachedAlpha(final double alpha, final PositionAngleType positionAngleType) { + if (positionAngleType == cachedPositionAngleType) { + return alpha; + + } else { + switch (cachedPositionAngleType) { + + case ECCENTRIC: + if (positionAngleType == PositionAngleType.MEAN) { + return CircularLatitudeArgumentUtility.meanToEccentric(ex, ey, alpha); + } else { + return CircularLatitudeArgumentUtility.trueToEccentric(ex, ey, alpha); + } + + case MEAN: + if (positionAngleType == PositionAngleType.TRUE) { + return CircularLatitudeArgumentUtility.trueToMean(ex, ey, alpha); + } else { + return CircularLatitudeArgumentUtility.eccentricToMean(ex, ey, alpha); + } + + case TRUE: + if (positionAngleType == PositionAngleType.MEAN) { + return CircularLatitudeArgumentUtility.meanToTrue(ex, ey, alpha); + } else { + return CircularLatitudeArgumentUtility.eccentricToTrue(ex, ey, alpha); + } + + default: + throw new OrekitInternalError(null); + } + } + } + /** Compute non-Keplerian part of the acceleration from first time derivatives. *

                * This method should be called only when {@link #hasDerivatives()} returns true. @@ -913,8 +1135,8 @@ public CircularOrbit shiftedBy(final double dt) { // use Keplerian-only motion final CircularOrbit keplerianShifted = new CircularOrbit(a, ex, ey, i, raan, getAlphaM() + getKeplerianMeanMotion() * dt, - PositionAngleType.MEAN, getFrame(), - getDate().shiftedBy(dt), getMu()); + PositionAngleType.MEAN, cachedPositionAngleType, + getFrame(), getDate().shiftedBy(dt), getMu()); if (hasDerivatives()) { @@ -1155,7 +1377,7 @@ public void addKeplerContribution(final PositionAngleType type, final double gm, final double oMe2; final double ksi; final double n = FastMath.sqrt(gm / a) / a; - final SinCos sc = FastMath.sinCos(alphaV); + final SinCos sc = FastMath.sinCos(getAlphaV()); switch (type) { case MEAN : pDot[5] += n; @@ -1184,14 +1406,14 @@ public String toString() { append(", ex: ").append(ex).append(", ey: ").append(ey). append(", i: ").append(FastMath.toDegrees(i)). append(", raan: ").append(FastMath.toDegrees(raan)). - append(", alphaV: ").append(FastMath.toDegrees(alphaV)). + append(", alphaV: ").append(FastMath.toDegrees(getAlphaV())). append(";}").toString(); } /** {@inheritDoc} */ @Override public PositionAngleType getCachedPositionAngleType() { - return PositionAngleType.TRUE; + return cachedPositionAngleType; } /** {@inheritDoc} */ @@ -1204,8 +1426,8 @@ public boolean hasRates() { @Override public CircularOrbit removeRates() { final PositionAngleType positionAngleType = getCachedPositionAngleType(); - return new CircularOrbit(getA(), getCircularEx(), getCircularEy(), getI(), getRightAscensionOfAscendingNode(), - getAlpha(positionAngleType), positionAngleType, getFrame(), getDate(), getMu()); + return new CircularOrbit(a, ex, ey, i, raan, cachedAlpha, positionAngleType, positionAngleType, + getFrame(), getDate(), getMu()); } /** Replace the instance with a data transfer object for serialization. @@ -1221,20 +1443,24 @@ private Object writeReplace() { private static class DTO implements Serializable { /** Serializable UID. */ - private static final long serialVersionUID = 20170414L; + private static final long serialVersionUID = 20231217L; /** Double values. */ - private double[] d; + private final double[] d; /** Frame in which are defined the orbital parameters. */ private final Frame frame; + /** Type of cached position angle. */ + private final PositionAngleType positionAngleType; + /** Simple constructor. * @param orbit instance to serialize */ private DTO(final CircularOrbit orbit) { final AbsoluteDate date = orbit.getDate(); + positionAngleType = orbit.getCachedPositionAngleType(); // decompose date final AbsoluteDate j2000Epoch = @@ -1249,9 +1475,9 @@ private DTO(final CircularOrbit orbit) { // date + mu + orbit + derivatives + Cartesian : 24 parameters epoch, offset, orbit.getMu(), orbit.a, orbit.ex, orbit.ey, - orbit.i, orbit.raan, orbit.alphaV, + orbit.i, orbit.raan, orbit.cachedAlpha, orbit.aDot, orbit.exDot, orbit.eyDot, - orbit.iDot, orbit.raanDot, orbit.alphaVDot, + orbit.iDot, orbit.raanDot, orbit.cachedAlphaDot, pv.getPosition().getX(), pv.getPosition().getY(), pv.getPosition().getZ(), pv.getVelocity().getX(), pv.getVelocity().getY(), pv.getVelocity().getZ(), pv.getAcceleration().getX(), pv.getAcceleration().getY(), pv.getAcceleration().getZ(), @@ -1261,7 +1487,7 @@ private DTO(final CircularOrbit orbit) { // date + mu + orbit + Cartesian : 18 parameters epoch, offset, orbit.getMu(), orbit.a, orbit.ex, orbit.ey, - orbit.i, orbit.raan, orbit.alphaV, + orbit.i, orbit.raan, orbit.cachedAlpha, pv.getPosition().getX(), pv.getPosition().getY(), pv.getPosition().getZ(), pv.getVelocity().getX(), pv.getVelocity().getY(), pv.getVelocity().getZ(), pv.getAcceleration().getX(), pv.getAcceleration().getY(), pv.getAcceleration().getZ(), @@ -1273,16 +1499,16 @@ private DTO(final CircularOrbit orbit) { this.d = new double[] { epoch, offset, orbit.getMu(), orbit.a, orbit.ex, orbit.ey, - orbit.i, orbit.raan, orbit.alphaV, + orbit.i, orbit.raan, orbit.cachedAlpha, orbit.aDot, orbit.exDot, orbit.eyDot, - orbit.iDot, orbit.raanDot, orbit.alphaVDot + orbit.iDot, orbit.raanDot, orbit.cachedAlphaDot }; } else { // date + mu + orbit: 9 parameters this.d = new double[] { epoch, offset, orbit.getMu(), orbit.a, orbit.ex, orbit.ey, - orbit.i, orbit.raan, orbit.alphaV + orbit.i, orbit.raan, orbit.cachedAlpha }; } } @@ -1305,7 +1531,7 @@ private Object readResolve() { new Vector3D(d[15], d[16], d[17]), new Vector3D(d[18], d[19], d[20]), new Vector3D(d[21], d[22], d[23])), - frame, + positionAngleType, frame, d[2]); case 18 : // date + mu + orbit + Cartesian return new CircularOrbit(d[3], d[4], d[5], d[6], d[7], d[8], @@ -1314,16 +1540,16 @@ private Object readResolve() { new Vector3D(d[ 9], d[10], d[11]), new Vector3D(d[12], d[13], d[14]), new Vector3D(d[15], d[16], d[17])), - frame, + positionAngleType, frame, d[2]); case 15 : // date + mu + orbit + derivatives return new CircularOrbit(d[ 3], d[ 4], d[ 5], d[ 6], d[ 7], d[ 8], d[ 9], d[10], d[11], d[12], d[13], d[14], - PositionAngleType.TRUE, + positionAngleType, positionAngleType, frame, j2000Epoch.shiftedBy(d[0]).shiftedBy(d[1]), d[2]); default : // date + mu + orbit - return new CircularOrbit(d[3], d[4], d[5], d[6], d[7], d[8], PositionAngleType.TRUE, + return new CircularOrbit(d[3], d[4], d[5], d[6], d[7], d[8], positionAngleType, positionAngleType, frame, j2000Epoch.shiftedBy(d[0]).shiftedBy(d[1]), d[2]); diff --git a/src/main/java/org/orekit/orbits/KeplerianOrbit.java b/src/main/java/org/orekit/orbits/KeplerianOrbit.java index 9d93e139ae..80e74457bf 100644 --- a/src/main/java/org/orekit/orbits/KeplerianOrbit.java +++ b/src/main/java/org/orekit/orbits/KeplerianOrbit.java @@ -76,7 +76,7 @@ public class KeplerianOrbit extends Orbit implements PositionAngleBased { /** Serializable UID. */ - private static final long serialVersionUID = 20170414L; + private static final long serialVersionUID = 20231217L; /** Name of the eccentricity parameter. */ private static final String ECCENTRICITY = "eccentricity"; diff --git a/src/main/java/org/orekit/orbits/OrbitType.java b/src/main/java/org/orekit/orbits/OrbitType.java index e6105a1611..58775d5010 100644 --- a/src/main/java/org/orekit/orbits/OrbitType.java +++ b/src/main/java/org/orekit/orbits/OrbitType.java @@ -345,6 +345,7 @@ public CircularOrbit normalize(final Orbit orbit, final Orbit reference) { // convert input to proper type final CircularOrbit cO = convertType(orbit); final CircularOrbit cR = convertType(reference); + final PositionAngleType cachedPositionAngle = cR.getCachedPositionAngleType(); // perform normalization if (cO.hasDerivatives()) { @@ -352,15 +353,17 @@ public CircularOrbit normalize(final Orbit orbit, final Orbit reference) { cO.getCircularEx(), cO.getCircularEy(), cO.getI(), - MathUtils.normalizeAngle(cO.getRightAscensionOfAscendingNode(), cR.getRightAscensionOfAscendingNode()), - MathUtils.normalizeAngle(cO.getAlphaV(), cR.getAlphaV()), + MathUtils.normalizeAngle(cO.getRightAscensionOfAscendingNode(), + cR.getRightAscensionOfAscendingNode()), + MathUtils.normalizeAngle(cO.getAlpha(cachedPositionAngle), + cR.getAlpha(cachedPositionAngle)), cO.getADot(), cO.getCircularExDot(), cO.getCircularEyDot(), cO.getIDot(), cO.getRightAscensionOfAscendingNodeDot(), - cO.getAlphaVDot(), - PositionAngleType.TRUE, + cO.getAlphaDot(cachedPositionAngle), + cachedPositionAngle, cO.getFrame(), cO.getDate(), cO.getMu()); @@ -369,9 +372,11 @@ public CircularOrbit normalize(final Orbit orbit, final Orbit reference) { cO.getCircularEx(), cO.getCircularEy(), cO.getI(), - MathUtils.normalizeAngle(cO.getRightAscensionOfAscendingNode(), cR.getRightAscensionOfAscendingNode()), - MathUtils.normalizeAngle(cO.getAlphaV(), cR.getAlphaV()), - PositionAngleType.TRUE, + MathUtils.normalizeAngle(cO.getRightAscensionOfAscendingNode(), + cR.getRightAscensionOfAscendingNode()), + MathUtils.normalizeAngle(cO.getAlpha(cachedPositionAngle), + cR.getAlpha(cachedPositionAngle)), + cachedPositionAngle, cO.getFrame(), cO.getDate(), cO.getMu()); diff --git a/src/test/java/org/orekit/orbits/CircularOrbitTest.java b/src/test/java/org/orekit/orbits/CircularOrbitTest.java index ee414ce916..d6e072f883 100644 --- a/src/test/java/org/orekit/orbits/CircularOrbitTest.java +++ b/src/test/java/org/orekit/orbits/CircularOrbitTest.java @@ -1199,6 +1199,28 @@ void positionAngleNonRegressionOnDeprecated() { actualTrueToEccentric); } + @Test + void testCoverageCachedPositionAngleTypeWithRates() { + // GIVEN + final double semiMajorAxis = 1e4; + final double eccentricity = 0.; + final double expectedAlpha = 0.; + final double expectedAlphaDot = 0.; + // WHEN & THEN + for (final PositionAngleType inputPositionAngleType: PositionAngleType.values()) { + for (final PositionAngleType cachedPositionAngleType: PositionAngleType.values()) { + final CircularOrbit circularOrbit = new CircularOrbit(semiMajorAxis, eccentricity, 0., 0., 0., + expectedAlpha, 0., 0., 0., 0., 0., expectedAlphaDot, + inputPositionAngleType, cachedPositionAngleType, FramesFactory.getGCRF(), date, mu); + Assertions.assertEquals(expectedAlpha, circularOrbit.getAlphaV()); + Assertions.assertEquals(expectedAlpha, circularOrbit.getAlphaM()); + Assertions.assertEquals(expectedAlpha, circularOrbit.getAlphaE()); + Assertions.assertEquals(expectedAlphaDot, circularOrbit.getAlphaVDot()); + Assertions.assertEquals(expectedAlphaDot, circularOrbit.getAlphaMDot()); + Assertions.assertEquals(expectedAlphaDot, circularOrbit.getAlphaEDot()); + } + } + } @BeforeEach public void setUp() { From a7898e317fbec0e36288085f410663f43f17b543 Mon Sep 17 00:00:00 2001 From: Serrof Date: Thu, 4 Jan 2024 21:19:38 +0100 Subject: [PATCH 122/359] set up cache in EquinoctialOrbit --- .../org/orekit/orbits/EquinoctialOrbit.java | 373 ++++++++++++++---- .../org/orekit/orbits/FieldCircularOrbit.java | 12 +- .../orekit/orbits/FieldEquinoctialOrbit.java | 12 +- .../orekit/orbits/FieldKeplerianOrbit.java | 13 +- .../java/org/orekit/orbits/OrbitType.java | 24 +- .../semianalytical/dsst/DSSTPropagator.java | 8 +- .../DSSTBatchLSEstimatorTest.java | 8 +- .../FieldNiellMappingFunctionModelTest.java | 2 +- .../org/orekit/orbits/CircularOrbitTest.java | 10 +- .../orekit/orbits/EquinoctialOrbitTest.java | 129 +++++- .../org/orekit/orbits/KeplerianOrbitTest.java | 6 +- .../java/org/orekit/utils/FieldifierTest.java | 4 +- 12 files changed, 475 insertions(+), 126 deletions(-) diff --git a/src/main/java/org/orekit/orbits/EquinoctialOrbit.java b/src/main/java/org/orekit/orbits/EquinoctialOrbit.java index bd9f5add1c..17aaa8f471 100644 --- a/src/main/java/org/orekit/orbits/EquinoctialOrbit.java +++ b/src/main/java/org/orekit/orbits/EquinoctialOrbit.java @@ -92,8 +92,11 @@ public class EquinoctialOrbit extends Orbit implements PositionAngleBased { /** Second component of the inclination vector. */ private final double hy; - /** True longitude argument (rad). */ - private final double lv; + /** Cached longitude argument (rad). */ + private final double cachedL; + + /** Cache type of position angle (longitude argument). */ + private final PositionAngleType cachedPositionAngleType; /** Semi-major axis derivative (m/s). */ private final double aDot; @@ -110,8 +113,8 @@ public class EquinoctialOrbit extends Orbit implements PositionAngleBased { /** Second component of the inclination vector derivative. */ private final double hyDot; - /** True longitude argument derivative (rad/s). */ - private final double lvDot; + /** Derivative of cached longitude argument (rad/s). */ + private final double cachedLDot; /** Partial Cartesian coordinates (position and velocity are valid, acceleration may be missing). */ private transient PVCoordinates partialPV; @@ -124,21 +127,46 @@ public class EquinoctialOrbit extends Orbit implements PositionAngleBased { * @param hy tan(i/2) sin(Ω), second component of inclination vector * @param l (M or E or v) + ω + Ω, mean, eccentric or true longitude argument (rad) * @param type type of longitude argument + * @param cachedPositionAngleType type of cached longitude argument * @param frame the frame in which the parameters are defined * (must be a {@link Frame#isPseudoInertial pseudo-inertial frame}) * @param date date of the orbital parameters * @param mu central attraction coefficient (m³/s²) * @exception IllegalArgumentException if eccentricity is equal to 1 or larger or * if frame is not a {@link Frame#isPseudoInertial pseudo-inertial frame} + * @since 12.1 */ public EquinoctialOrbit(final double a, final double ex, final double ey, final double hx, final double hy, final double l, - final PositionAngleType type, + final PositionAngleType type, final PositionAngleType cachedPositionAngleType, final Frame frame, final AbsoluteDate date, final double mu) throws IllegalArgumentException { this(a, ex, ey, hx, hy, l, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN, - type, frame, date, mu); + type, cachedPositionAngleType, frame, date, mu); + } + + /** Creates a new instance without derivatives and with cached position angle same as value inputted. + * @param a semi-major axis (m) + * @param ex e cos(ω + Ω), first component of eccentricity vector + * @param ey e sin(ω + Ω), second component of eccentricity vector + * @param hx tan(i/2) cos(Ω), first component of inclination vector + * @param hy tan(i/2) sin(Ω), second component of inclination vector + * @param l (M or E or v) + ω + Ω, mean, eccentric or true longitude argument (rad) + * @param type type of longitude argument + * @param frame the frame in which the parameters are defined + * (must be a {@link Frame#isPseudoInertial pseudo-inertial frame}) + * @param date date of the orbital parameters + * @param mu central attraction coefficient (m³/s²) + * @exception IllegalArgumentException if eccentricity is equal to 1 or larger or + * if frame is not a {@link Frame#isPseudoInertial pseudo-inertial frame} + */ + public EquinoctialOrbit(final double a, final double ex, final double ey, + final double hx, final double hy, final double l, + final PositionAngleType type, + final Frame frame, final AbsoluteDate date, final double mu) + throws IllegalArgumentException { + this(a, ex, ey, hx, hy, l, type, type, frame, date, mu); } /** Creates a new instance. @@ -155,18 +183,20 @@ public EquinoctialOrbit(final double a, final double ex, final double ey, * @param hyDot d(tan(i/2) sin(Ω))/dt, second component of inclination vector derivative * @param lDot d(M or E or v) + ω + Ω)/dr, mean, eccentric or true longitude argument derivative (rad/s) * @param type type of longitude argument + * @param cachedPositionAngleType of cached longitude argument * @param frame the frame in which the parameters are defined * (must be a {@link Frame#isPseudoInertial pseudo-inertial frame}) * @param date date of the orbital parameters * @param mu central attraction coefficient (m³/s²) * @exception IllegalArgumentException if eccentricity is equal to 1 or larger or * if frame is not a {@link Frame#isPseudoInertial pseudo-inertial frame} + * @since 12.1 */ public EquinoctialOrbit(final double a, final double ex, final double ey, final double hx, final double hy, final double l, final double aDot, final double exDot, final double eyDot, final double hxDot, final double hyDot, final double lDot, - final PositionAngleType type, + final PositionAngleType type, final PositionAngleType cachedPositionAngleType, final Frame frame, final AbsoluteDate date, final double mu) throws IllegalArgumentException { super(frame, date, mu); @@ -174,6 +204,7 @@ public EquinoctialOrbit(final double a, final double ex, final double ey, throw new OrekitIllegalArgumentException(OrekitMessages.HYPERBOLIC_ORBIT_NOT_HANDLED_AS, getClass().getName()); } + this.cachedPositionAngleType = cachedPositionAngleType; this.a = a; this.aDot = aDot; this.ex = ex; @@ -186,46 +217,49 @@ public EquinoctialOrbit(final double a, final double ex, final double ey, this.hyDot = hyDot; if (hasDerivatives()) { - final UnivariateDerivative1 exUD = new UnivariateDerivative1(ex, exDot); - final UnivariateDerivative1 eyUD = new UnivariateDerivative1(ey, eyDot); - final UnivariateDerivative1 lUD = new UnivariateDerivative1(l, lDot); - final UnivariateDerivative1 lvUD; - switch (type) { - case MEAN : - lvUD = FieldEquinoctialLongitudeArgumentUtility.meanToTrue(exUD, eyUD, lUD); - break; - case ECCENTRIC : - lvUD = FieldEquinoctialLongitudeArgumentUtility.eccentricToTrue(exUD, eyUD, lUD); - break; - case TRUE : - lvUD = lUD; - break; - default : // this should never happen - throw new OrekitInternalError(null); - } - this.lv = lvUD.getValue(); - this.lvDot = lvUD.getDerivative(1); + final UnivariateDerivative1 alphaUD = initializeCachedL(l, lDot, type); + this.cachedL = alphaUD.getValue(); + this.cachedLDot = alphaUD.getFirstDerivative(); } else { - switch (type) { - case MEAN : - this.lv = EquinoctialLongitudeArgumentUtility.meanToTrue(ex, ey, l); - break; - case ECCENTRIC : - this.lv = EquinoctialLongitudeArgumentUtility.eccentricToTrue(ex, ey, l); - break; - case TRUE : - this.lv = l; - break; - default : // this should never happen - throw new OrekitInternalError(null); - } - this.lvDot = Double.NaN; + this.cachedL = initializeCachedL(l, type); + this.cachedLDot = Double.NaN; } this.partialPV = null; } + /** Creates a new instance with derivatives and with cached position angle same as value inputted. + * @param a semi-major axis (m) + * @param ex e cos(ω + Ω), first component of eccentricity vector + * @param ey e sin(ω + Ω), second component of eccentricity vector + * @param hx tan(i/2) cos(Ω), first component of inclination vector + * @param hy tan(i/2) sin(Ω), second component of inclination vector + * @param l (M or E or v) + ω + Ω, mean, eccentric or true longitude argument (rad) + * @param aDot semi-major axis derivative (m/s) + * @param exDot d(e cos(ω + Ω))/dt, first component of eccentricity vector derivative + * @param eyDot d(e sin(ω + Ω))/dt, second component of eccentricity vector derivative + * @param hxDot d(tan(i/2) cos(Ω))/dt, first component of inclination vector derivative + * @param hyDot d(tan(i/2) sin(Ω))/dt, second component of inclination vector derivative + * @param lDot d(M or E or v) + ω + Ω)/dr, mean, eccentric or true longitude argument derivative (rad/s) + * @param type type of longitude argument + * @param frame the frame in which the parameters are defined + * (must be a {@link Frame#isPseudoInertial pseudo-inertial frame}) + * @param date date of the orbital parameters + * @param mu central attraction coefficient (m³/s²) + * @exception IllegalArgumentException if eccentricity is equal to 1 or larger or + * if frame is not a {@link Frame#isPseudoInertial pseudo-inertial frame} + */ + public EquinoctialOrbit(final double a, final double ex, final double ey, + final double hx, final double hy, final double l, + final double aDot, final double exDot, final double eyDot, + final double hxDot, final double hyDot, final double lDot, + final PositionAngleType type, + final Frame frame, final AbsoluteDate date, final double mu) + throws IllegalArgumentException { + this(a, ex, ey, hx, hy, l, aDot, exDot, eyDot, hxDot, hyDot, lDot, type, type, frame, date, mu); + } + /** Constructor from Cartesian parameters. * *

                The acceleration provided in {@code pvCoordinates} is accessible using @@ -269,9 +303,10 @@ public EquinoctialOrbit(final TimeStampedPVCoordinates pvCoordinates, hy = d * w.getX(); // compute true longitude argument + cachedPositionAngleType = PositionAngleType.TRUE; final double cLv = (pvP.getX() - d * pvP.getZ() * w.getX()) / r; final double sLv = (pvP.getY() - d * pvP.getZ() * w.getY()) / r; - lv = FastMath.atan2(sLv, cLv); + cachedL = FastMath.atan2(sLv, cLv); // compute eccentricity vector final double eSE = Vector3D.dotProduct(pvP, pvV) / FastMath.sqrt(mu * a); @@ -301,15 +336,15 @@ public EquinoctialOrbit(final TimeStampedPVCoordinates pvCoordinates, hxDot = jacobian[3][3] * aX + jacobian[3][4] * aY + jacobian[3][5] * aZ; hyDot = jacobian[4][3] * aX + jacobian[4][4] * aY + jacobian[4][5] * aZ; - // in order to compute true anomaly derivative, we must compute - // mean anomaly derivative including Keplerian motion and convert to true anomaly + // in order to compute true longitude argument derivative, we must compute + // mean longitude argument derivative including Keplerian motion and convert to true longitude argument final double lMDot = getKeplerianMeanMotion() + jacobian[5][3] * aX + jacobian[5][4] * aY + jacobian[5][5] * aZ; final UnivariateDerivative1 exUD = new UnivariateDerivative1(ex, exDot); final UnivariateDerivative1 eyUD = new UnivariateDerivative1(ey, eyDot); final UnivariateDerivative1 lMUD = new UnivariateDerivative1(getLM(), lMDot); final UnivariateDerivative1 lvUD = FieldEquinoctialLongitudeArgumentUtility.meanToTrue(exUD, eyUD, lMUD); - lvDot = lvUD.getDerivative(1); + cachedLDot = lvUD.getFirstDerivative(); } else { // acceleration is either almost zero or NaN, @@ -320,7 +355,7 @@ public EquinoctialOrbit(final TimeStampedPVCoordinates pvCoordinates, eyDot = Double.NaN; hxDot = Double.NaN; hyDot = Double.NaN; - lvDot = Double.NaN; + cachedLDot = Double.NaN; } } @@ -361,8 +396,9 @@ public EquinoctialOrbit(final Orbit op) { hxDot = op.getHxDot(); hy = op.getHy(); hyDot = op.getHyDot(); - lv = op.getLv(); - lvDot = op.getLvDot(); + cachedPositionAngleType = PositionAngleType.TRUE; + cachedL = op.getLv(); + cachedLDot = op.getLvDot(); partialPV = null; } @@ -423,40 +459,133 @@ public double getHyDot() { /** {@inheritDoc} */ public double getLv() { - return lv; + switch (cachedPositionAngleType) { + case TRUE: + return cachedL; + + case ECCENTRIC: + return EquinoctialLongitudeArgumentUtility.eccentricToTrue(ex, ey, cachedL); + + case MEAN: + return EquinoctialLongitudeArgumentUtility.meanToTrue(ex, ey, cachedL); + + default: + throw new OrekitInternalError(null); + } } /** {@inheritDoc} */ public double getLvDot() { - return lvDot; + switch (cachedPositionAngleType) { + case ECCENTRIC: + final UnivariateDerivative1 lEUD = new UnivariateDerivative1(cachedL, cachedLDot); + final UnivariateDerivative1 exUD = new UnivariateDerivative1(ex, exDot); + final UnivariateDerivative1 eyUD = new UnivariateDerivative1(ey, eyDot); + final UnivariateDerivative1 lvUD = FieldEquinoctialLongitudeArgumentUtility.eccentricToTrue(exUD, eyUD, + lEUD); + return lvUD.getFirstDerivative(); + + case TRUE: + return cachedLDot; + + case MEAN: + final UnivariateDerivative1 lMUD = new UnivariateDerivative1(cachedL, cachedLDot); + final UnivariateDerivative1 exUD2 = new UnivariateDerivative1(ex, exDot); + final UnivariateDerivative1 eyUD2 = new UnivariateDerivative1(ey, eyDot); + final UnivariateDerivative1 lvUD2 = FieldEquinoctialLongitudeArgumentUtility.meanToTrue(exUD2, + eyUD2, lMUD); + return lvUD2.getFirstDerivative(); + + default: + throw new OrekitInternalError(null); + } } /** {@inheritDoc} */ public double getLE() { - return EquinoctialLongitudeArgumentUtility.trueToEccentric(ex, ey, lv); + switch (cachedPositionAngleType) { + case TRUE: + return EquinoctialLongitudeArgumentUtility.trueToEccentric(ex, ey, cachedL); + + case ECCENTRIC: + return cachedL; + + case MEAN: + return EquinoctialLongitudeArgumentUtility.meanToEccentric(ex, ey, cachedL); + + default: + throw new OrekitInternalError(null); + } } /** {@inheritDoc} */ public double getLEDot() { - final UnivariateDerivative1 lVUD = new UnivariateDerivative1(lv, lvDot); - final UnivariateDerivative1 exUD = new UnivariateDerivative1(ex, exDot); - final UnivariateDerivative1 eyUD = new UnivariateDerivative1(ey, eyDot); - final UnivariateDerivative1 lEUD = FieldEquinoctialLongitudeArgumentUtility.trueToEccentric(exUD, eyUD, lVUD); - return lEUD.getDerivative(1); + switch (cachedPositionAngleType) { + case TRUE: + final UnivariateDerivative1 lvUD = new UnivariateDerivative1(cachedL, cachedLDot); + final UnivariateDerivative1 exUD = new UnivariateDerivative1(ex, exDot); + final UnivariateDerivative1 eyUD = new UnivariateDerivative1(ey, eyDot); + final UnivariateDerivative1 lEUD = FieldEquinoctialLongitudeArgumentUtility.trueToEccentric(exUD, eyUD, + lvUD); + return lEUD.getFirstDerivative(); + + case ECCENTRIC: + return cachedLDot; + + case MEAN: + final UnivariateDerivative1 lMUD = new UnivariateDerivative1(cachedL, cachedLDot); + final UnivariateDerivative1 exUD2 = new UnivariateDerivative1(ex, exDot); + final UnivariateDerivative1 eyUD2 = new UnivariateDerivative1(ey, eyDot); + final UnivariateDerivative1 lEUD2 = FieldEquinoctialLongitudeArgumentUtility.meanToEccentric(exUD2, + eyUD2, lMUD); + return lEUD2.getFirstDerivative(); + + default: + throw new OrekitInternalError(null); + } } /** {@inheritDoc} */ public double getLM() { - return EquinoctialLongitudeArgumentUtility.trueToMean(ex, ey, lv); + switch (cachedPositionAngleType) { + case TRUE: + return EquinoctialLongitudeArgumentUtility.trueToMean(ex, ey, cachedL); + + case MEAN: + return cachedL; + + case ECCENTRIC: + return EquinoctialLongitudeArgumentUtility.eccentricToMean(ex, ey, cachedL); + + default: + throw new OrekitInternalError(null); + } } /** {@inheritDoc} */ public double getLMDot() { - final UnivariateDerivative1 lVUD = new UnivariateDerivative1(lv, lvDot); - final UnivariateDerivative1 exUD = new UnivariateDerivative1(ex, exDot); - final UnivariateDerivative1 eyUD = new UnivariateDerivative1(ey, eyDot); - final UnivariateDerivative1 lMUD = FieldEquinoctialLongitudeArgumentUtility.trueToMean(exUD, eyUD, lVUD); - return lMUD.getDerivative(1); + switch (cachedPositionAngleType) { + case TRUE: + final UnivariateDerivative1 lvUD = new UnivariateDerivative1(cachedL, cachedLDot); + final UnivariateDerivative1 exUD = new UnivariateDerivative1(ex, exDot); + final UnivariateDerivative1 eyUD = new UnivariateDerivative1(ey, eyDot); + final UnivariateDerivative1 lMUD = FieldEquinoctialLongitudeArgumentUtility.trueToMean(exUD, eyUD, lvUD); + return lMUD.getFirstDerivative(); + + case MEAN: + return cachedLDot; + + case ECCENTRIC: + final UnivariateDerivative1 lEUD = new UnivariateDerivative1(cachedL, cachedLDot); + final UnivariateDerivative1 exUD2 = new UnivariateDerivative1(ex, exDot); + final UnivariateDerivative1 eyUD2 = new UnivariateDerivative1(ey, eyDot); + final UnivariateDerivative1 lMUD2 = FieldEquinoctialLongitudeArgumentUtility.eccentricToMean(exUD2, + eyUD2, lEUD); + return lMUD2.getFirstDerivative(); + + default: + throw new OrekitInternalError(null); + } } /** Get the longitude argument. @@ -601,6 +730,95 @@ private void computePVWithoutA() { } + /** Initialize cached argument of longitude with rate. + * @param l input argument of longitude + * @param lDot rate of input argument of longitude + * @param inputType position angle type passed as input + * @return argument of longitude to cache with rate + * @since 12.1 + */ + private UnivariateDerivative1 initializeCachedL(final double l, final double lDot, + final PositionAngleType inputType) { + if (cachedPositionAngleType == inputType) { + return new UnivariateDerivative1(l, lDot); + + } else { + final UnivariateDerivative1 exUD = new UnivariateDerivative1(ex, exDot); + final UnivariateDerivative1 eyUD = new UnivariateDerivative1(ey, eyDot); + final UnivariateDerivative1 lUD = new UnivariateDerivative1(l, lDot); + + switch (cachedPositionAngleType) { + + case ECCENTRIC: + if (inputType == PositionAngleType.MEAN) { + return FieldEquinoctialLongitudeArgumentUtility.meanToEccentric(exUD, eyUD, lUD); + } else { + return FieldEquinoctialLongitudeArgumentUtility.trueToEccentric(exUD, eyUD, lUD); + } + + case TRUE: + if (inputType == PositionAngleType.MEAN) { + return FieldEquinoctialLongitudeArgumentUtility.meanToTrue(exUD, eyUD, lUD); + } else { + return FieldEquinoctialLongitudeArgumentUtility.eccentricToTrue(exUD, eyUD, lUD); + } + + case MEAN: + if (inputType == PositionAngleType.TRUE) { + return FieldEquinoctialLongitudeArgumentUtility.trueToMean(exUD, eyUD, lUD); + } else { + return FieldEquinoctialLongitudeArgumentUtility.eccentricToMean(exUD, eyUD, lUD); + } + + default: + throw new OrekitInternalError(null); + + } + + } + + } + + /** Initialize cached argument of longitude. + * @param l input argument of longitude + * @param positionAngleType position angle type passed as input + * @return argument of longitude to cache + * @since 12.1 + */ + private double initializeCachedL(final double l, final PositionAngleType positionAngleType) { + if (positionAngleType == cachedPositionAngleType) { + return l; + + } else { + switch (cachedPositionAngleType) { + + case ECCENTRIC: + if (positionAngleType == PositionAngleType.MEAN) { + return EquinoctialLongitudeArgumentUtility.meanToEccentric(ex, ey, l); + } else { + return EquinoctialLongitudeArgumentUtility.trueToEccentric(ex, ey, l); + } + + case MEAN: + if (positionAngleType == PositionAngleType.TRUE) { + return EquinoctialLongitudeArgumentUtility.trueToMean(ex, ey, l); + } else { + return EquinoctialLongitudeArgumentUtility.eccentricToMean(ex, ey, l); + } + + case TRUE: + if (positionAngleType == PositionAngleType.MEAN) { + return EquinoctialLongitudeArgumentUtility.meanToTrue(ex, ey, l); + } else { + return EquinoctialLongitudeArgumentUtility.eccentricToTrue(ex, ey, l); + } + + default: + throw new OrekitInternalError(null); + } + } + } + /** Compute non-Keplerian part of the acceleration from first time derivatives. *

                * This method should be called only when {@link #hasDerivatives()} returns true. @@ -688,7 +906,8 @@ public EquinoctialOrbit shiftedBy(final double dt) { // use Keplerian-only motion final EquinoctialOrbit keplerianShifted = new EquinoctialOrbit(a, ex, ey, hx, hy, getLM() + getKeplerianMeanMotion() * dt, - PositionAngleType.MEAN, getFrame(), + PositionAngleType.MEAN, cachedPositionAngleType, + getFrame(), getDate().shiftedBy(dt), getMu()); if (hasDerivatives()) { @@ -841,9 +1060,9 @@ protected double[][] computeJacobianTrueWrtCartesian() { final double[][] jacobian = computeJacobianEccentricWrtCartesian(); // Differentiating the eccentric longitude equation - // tan((lV - lE)/2) = [ex sin lE - ey cos lE] / [sqrt(1-ex^2-ey^2) + 1 - ex cos lE - ey sin lE] + // tan((lv - lE)/2) = [ex sin lE - ey cos lE] / [sqrt(1-ex^2-ey^2) + 1 - ex cos lE - ey sin lE] // leads to - // cT (dlV - dlE) = cE dlE + cX dex + cY dey + // cT (dlv - dlE) = cE dlE + cX dex + cY dey // with // cT = [d^2 + (ex sin lE - ey cos lE)^2] / 2 // d = 1 + sqrt(1-ex^2-ey^2) - ex cos lE - ey sin lE @@ -851,7 +1070,7 @@ protected double[][] computeJacobianTrueWrtCartesian() { // cX = sin lE (sqrt(1-ex^2-ey^2) + 1) - ey + ex (ex sin lE - ey cos lE) / sqrt(1-ex^2-ey^2) // cY = -cos lE (sqrt(1-ex^2-ey^2) + 1) + ex + ey (ex sin lE - ey cos lE) / sqrt(1-ex^2-ey^2) // which can be solved to find the differential of the true longitude - // dlV = (cT + cE) / cT dlE + cX / cT deX + cY / cT deX + // dlv = (cT + cE) / cT dlE + cX / cT deX + cY / cT deX final SinCos scLe = FastMath.sinCos(getLE()); final double cosLe = scLe.cos(); final double sinLe = scLe.sin(); @@ -887,7 +1106,7 @@ public void addKeplerContribution(final PositionAngleType type, final double gm, final double oMe2; final double ksi; final double n = FastMath.sqrt(gm / a) / a; - final SinCos sc = FastMath.sinCos(lv); + final SinCos sc = FastMath.sinCos(getLv()); switch (type) { case MEAN : pDot[5] += n; @@ -915,14 +1134,14 @@ public String toString() { append("a: ").append(a). append("; ex: ").append(ex).append("; ey: ").append(ey). append("; hx: ").append(hx).append("; hy: ").append(hy). - append("; lv: ").append(FastMath.toDegrees(lv)). + append("; lv: ").append(FastMath.toDegrees(getLv())). append(";}").toString(); } /** {@inheritDoc} */ @Override public PositionAngleType getCachedPositionAngleType() { - return PositionAngleType.TRUE; + return cachedPositionAngleType; } /** {@inheritDoc} */ @@ -952,20 +1171,24 @@ private Object writeReplace() { private static class DTO implements Serializable { /** Serializable UID. */ - private static final long serialVersionUID = 20170414L; + private static final long serialVersionUID = 20231217L; /** Double values. */ - private double[] d; + private final double[] d; /** Frame in which are defined the orbital parameters. */ private final Frame frame; + /** Cached type of position angle. */ + private final PositionAngleType positionAngleType; + /** Simple constructor. * @param orbit instance to serialize */ private DTO(final EquinoctialOrbit orbit) { final TimeStampedPVCoordinates pv = orbit.getPVCoordinates(); + positionAngleType = orbit.cachedPositionAngleType; // decompose date final AbsoluteDate j2000Epoch = @@ -978,16 +1201,16 @@ private DTO(final EquinoctialOrbit orbit) { this.d = new double[] { epoch, offset, orbit.getMu(), orbit.a, orbit.ex, orbit.ey, - orbit.hx, orbit.hy, orbit.lv, + orbit.hx, orbit.hy, orbit.cachedL, orbit.aDot, orbit.exDot, orbit.eyDot, - orbit.hxDot, orbit.hyDot, orbit.lvDot + orbit.hxDot, orbit.hyDot, orbit.cachedLDot }; } else { // we don't have derivatives this.d = new double[] { epoch, offset, orbit.getMu(), orbit.a, orbit.ex, orbit.ey, - orbit.hx, orbit.hy, orbit.lv + orbit.hx, orbit.hy, orbit.cachedL }; } @@ -1005,12 +1228,12 @@ private Object readResolve() { // we have derivatives return new EquinoctialOrbit(d[ 3], d[ 4], d[ 5], d[ 6], d[ 7], d[ 8], d[ 9], d[10], d[11], d[12], d[13], d[14], - PositionAngleType.TRUE, + positionAngleType, frame, j2000Epoch.shiftedBy(d[0]).shiftedBy(d[1]), d[2]); } else { // we don't have derivatives - return new EquinoctialOrbit(d[ 3], d[ 4], d[ 5], d[ 6], d[ 7], d[ 8], PositionAngleType.TRUE, + return new EquinoctialOrbit(d[ 3], d[ 4], d[ 5], d[ 6], d[ 7], d[ 8], positionAngleType, frame, j2000Epoch.shiftedBy(d[0]).shiftedBy(d[1]), d[2]); } diff --git a/src/main/java/org/orekit/orbits/FieldCircularOrbit.java b/src/main/java/org/orekit/orbits/FieldCircularOrbit.java index 29157388d8..6b740c13f9 100644 --- a/src/main/java/org/orekit/orbits/FieldCircularOrbit.java +++ b/src/main/java/org/orekit/orbits/FieldCircularOrbit.java @@ -1292,17 +1292,19 @@ public FieldCircularOrbit removeRates() { /** {@inheritDoc} */ @Override public CircularOrbit toOrbit() { + final PositionAngleType cachedPositionAngleType = getCachedPositionAngleType(); + final double cachedPositionAngle = getAlpha(cachedPositionAngleType).getReal(); if (hasDerivatives()) { return new CircularOrbit(a.getReal(), ex.getReal(), ey.getReal(), - i.getReal(), raan.getReal(), alphaV.getReal(), + i.getReal(), raan.getReal(), cachedPositionAngle, aDot.getReal(), exDot.getReal(), eyDot.getReal(), - iDot.getReal(), raanDot.getReal(), alphaVDot.getReal(), - PositionAngleType.TRUE, getFrame(), + iDot.getReal(), raanDot.getReal(), getAlphaDot(cachedPositionAngleType).getReal(), + cachedPositionAngleType, cachedPositionAngleType, getFrame(), getDate().toAbsoluteDate(), getMu().getReal()); } else { return new CircularOrbit(a.getReal(), ex.getReal(), ey.getReal(), - i.getReal(), raan.getReal(), alphaV.getReal(), - PositionAngleType.TRUE, getFrame(), + i.getReal(), raan.getReal(), cachedPositionAngle, + cachedPositionAngleType, cachedPositionAngleType, getFrame(), getDate().toAbsoluteDate(), getMu().getReal()); } } diff --git a/src/main/java/org/orekit/orbits/FieldEquinoctialOrbit.java b/src/main/java/org/orekit/orbits/FieldEquinoctialOrbit.java index 5c78a238d7..97acabbd36 100644 --- a/src/main/java/org/orekit/orbits/FieldEquinoctialOrbit.java +++ b/src/main/java/org/orekit/orbits/FieldEquinoctialOrbit.java @@ -1046,17 +1046,19 @@ public FieldEquinoctialOrbit removeRates() { /** {@inheritDoc} */ @Override public EquinoctialOrbit toOrbit() { + final PositionAngleType cachedPositionAngleType = getCachedPositionAngleType(); + final double cachedPositionAngle = getL(cachedPositionAngleType).getReal(); if (hasDerivatives()) { return new EquinoctialOrbit(a.getReal(), ex.getReal(), ey.getReal(), - hx.getReal(), hy.getReal(), lv.getReal(), + hx.getReal(), hy.getReal(), cachedPositionAngle, aDot.getReal(), exDot.getReal(), eyDot.getReal(), - hxDot.getReal(), hyDot.getReal(), lvDot.getReal(), - PositionAngleType.TRUE, getFrame(), + hxDot.getReal(), hyDot.getReal(), getLDot(cachedPositionAngleType).getReal(), + cachedPositionAngleType, cachedPositionAngleType, getFrame(), getDate().toAbsoluteDate(), getMu().getReal()); } else { return new EquinoctialOrbit(a.getReal(), ex.getReal(), ey.getReal(), - hx.getReal(), hy.getReal(), lv.getReal(), - PositionAngleType.TRUE, getFrame(), + hx.getReal(), hy.getReal(), cachedPositionAngle, + cachedPositionAngleType, cachedPositionAngleType, getFrame(), getDate().toAbsoluteDate(), getMu().getReal()); } } diff --git a/src/main/java/org/orekit/orbits/FieldKeplerianOrbit.java b/src/main/java/org/orekit/orbits/FieldKeplerianOrbit.java index fbb1f214ed..ad77ff4b21 100644 --- a/src/main/java/org/orekit/orbits/FieldKeplerianOrbit.java +++ b/src/main/java/org/orekit/orbits/FieldKeplerianOrbit.java @@ -1485,17 +1485,20 @@ private void checkParameterRangeInclusive(final String parameterName, final doub /** {@inheritDoc} */ @Override public KeplerianOrbit toOrbit() { + final PositionAngleType cachedPositionAngleType = getCachedPositionAngleType(); + final double cachedPositionAngle = getAnomaly(cachedPositionAngleType).getReal(); if (hasDerivatives()) { return new KeplerianOrbit(a.getReal(), e.getReal(), i.getReal(), - pa.getReal(), raan.getReal(), v.getReal(), + pa.getReal(), raan.getReal(), cachedPositionAngle, aDot.getReal(), eDot.getReal(), iDot.getReal(), - paDot.getReal(), raanDot.getReal(), vDot.getReal(), - PositionAngleType.TRUE, + paDot.getReal(), raanDot.getReal(), + getAnomalyDot(getCachedPositionAngleType()).getReal(), + cachedPositionAngleType, cachedPositionAngleType, getFrame(), getDate().toAbsoluteDate(), getMu().getReal()); } else { return new KeplerianOrbit(a.getReal(), e.getReal(), i.getReal(), - pa.getReal(), raan.getReal(), v.getReal(), - PositionAngleType.TRUE, + pa.getReal(), raan.getReal(), cachedPositionAngle, + cachedPositionAngleType, cachedPositionAngleType, getFrame(), getDate().toAbsoluteDate(), getMu().getReal()); } } diff --git a/src/main/java/org/orekit/orbits/OrbitType.java b/src/main/java/org/orekit/orbits/OrbitType.java index 58775d5010..fcc5443ec5 100644 --- a/src/main/java/org/orekit/orbits/OrbitType.java +++ b/src/main/java/org/orekit/orbits/OrbitType.java @@ -345,7 +345,7 @@ public CircularOrbit normalize(final Orbit orbit, final Orbit reference) { // convert input to proper type final CircularOrbit cO = convertType(orbit); final CircularOrbit cR = convertType(reference); - final PositionAngleType cachedPositionAngle = cR.getCachedPositionAngleType(); + final PositionAngleType cachedPositionAngleType = cR.getCachedPositionAngleType(); // perform normalization if (cO.hasDerivatives()) { @@ -355,15 +355,15 @@ public CircularOrbit normalize(final Orbit orbit, final Orbit reference) { cO.getI(), MathUtils.normalizeAngle(cO.getRightAscensionOfAscendingNode(), cR.getRightAscensionOfAscendingNode()), - MathUtils.normalizeAngle(cO.getAlpha(cachedPositionAngle), - cR.getAlpha(cachedPositionAngle)), + MathUtils.normalizeAngle(cO.getAlpha(cachedPositionAngleType), + cR.getAlpha(cachedPositionAngleType)), cO.getADot(), cO.getCircularExDot(), cO.getCircularEyDot(), cO.getIDot(), cO.getRightAscensionOfAscendingNodeDot(), - cO.getAlphaDot(cachedPositionAngle), - cachedPositionAngle, + cO.getAlphaDot(cachedPositionAngleType), + cachedPositionAngleType, cO.getFrame(), cO.getDate(), cO.getMu()); @@ -374,9 +374,9 @@ public CircularOrbit normalize(final Orbit orbit, final Orbit reference) { cO.getI(), MathUtils.normalizeAngle(cO.getRightAscensionOfAscendingNode(), cR.getRightAscensionOfAscendingNode()), - MathUtils.normalizeAngle(cO.getAlpha(cachedPositionAngle), - cR.getAlpha(cachedPositionAngle)), - cachedPositionAngle, + MathUtils.normalizeAngle(cO.getAlpha(cachedPositionAngleType), + cR.getAlpha(cachedPositionAngleType)), + cachedPositionAngleType, cO.getFrame(), cO.getDate(), cO.getMu()); @@ -584,6 +584,7 @@ public EquinoctialOrbit normalize(final Orbit orbit, final Orbit reference) { // convert input to proper type final EquinoctialOrbit eO = convertType(orbit); final EquinoctialOrbit eR = convertType(reference); + final PositionAngleType cachedPositionAngleType = eR.getCachedPositionAngleType(); // perform normalization if (eO.hasDerivatives()) { @@ -592,14 +593,15 @@ public EquinoctialOrbit normalize(final Orbit orbit, final Orbit reference) { eO.getEquinoctialEy(), eO.getHx(), eO.getHy(), - MathUtils.normalizeAngle(eO.getLv(), eR.getLv()), + MathUtils.normalizeAngle(eO.getL(cachedPositionAngleType), + eR.getL(cachedPositionAngleType)), eO.getADot(), eO.getEquinoctialExDot(), eO.getEquinoctialEyDot(), eO.getHxDot(), eO.getHyDot(), - eO.getLvDot(), - PositionAngleType.TRUE, + eO.getLDot(cachedPositionAngleType), + cachedPositionAngleType, eO.getFrame(), eO.getDate(), eO.getMu()); diff --git a/src/main/java/org/orekit/propagation/semianalytical/dsst/DSSTPropagator.java b/src/main/java/org/orekit/propagation/semianalytical/dsst/DSSTPropagator.java index f0c6842c9f..8b73139dc6 100644 --- a/src/main/java/org/orekit/propagation/semianalytical/dsst/DSSTPropagator.java +++ b/src/main/java/org/orekit/propagation/semianalytical/dsst/DSSTPropagator.java @@ -866,7 +866,7 @@ private static Orbit computeMeanOrbit(final SpacecraftState osculating, final double deltaEy = osculating.getEquinoctialEy() - rebuilt.getEquinoctialEy(); final double deltaHx = osculating.getHx() - rebuilt.getHx(); final double deltaHy = osculating.getHy() - rebuilt.getHy(); - final double deltaLv = MathUtils.normalizeAngle(osculating.getLv() - rebuilt.getLv(), 0.0); + final double deltaLM = MathUtils.normalizeAngle(osculating.getLM() - rebuilt.getLM(), 0.0); // check convergence if (FastMath.abs(deltaA) < thresholdA && @@ -874,7 +874,7 @@ private static Orbit computeMeanOrbit(final SpacecraftState osculating, FastMath.abs(deltaEy) < thresholdE && FastMath.abs(deltaHx) < thresholdI && FastMath.abs(deltaHy) < thresholdI && - FastMath.abs(deltaLv) < thresholdL) { + FastMath.abs(deltaLM) < thresholdL) { return meanOrbit; } @@ -884,8 +884,8 @@ private static Orbit computeMeanOrbit(final SpacecraftState osculating, meanOrbit.getEquinoctialEy() + deltaEy, meanOrbit.getHx() + deltaHx, meanOrbit.getHy() + deltaHy, - meanOrbit.getLv() + deltaLv, - PositionAngleType.TRUE, meanOrbit.getFrame(), + meanOrbit.getLM() + deltaLM, + PositionAngleType.MEAN, meanOrbit.getFrame(), meanOrbit.getDate(), meanOrbit.getMu()); } diff --git a/src/test/java/org/orekit/estimation/leastsquares/DSSTBatchLSEstimatorTest.java b/src/test/java/org/orekit/estimation/leastsquares/DSSTBatchLSEstimatorTest.java index 9cc6039b3a..8c7f3ca45d 100644 --- a/src/test/java/org/orekit/estimation/leastsquares/DSSTBatchLSEstimatorTest.java +++ b/src/test/java/org/orekit/estimation/leastsquares/DSSTBatchLSEstimatorTest.java @@ -216,8 +216,8 @@ public void evaluationPerformed(int iterationsCount, int evaluationscount, DSSTEstimationTestUtils.checkFit(context, estimator, 2, 3, 0.0, 3.1e-6, 0.0, 5.7e-6, - 0.0, 1.3e-6, - 0.0, 5.2e-10); + 0.0, 1.5e-6, + 0.0, 6.1e-10); // after the call to estimate, the parameters lacking a user-specified reference date // got a default one @@ -483,10 +483,10 @@ public void testKeplerRangeAndRangeRate() { // we have low correlation between the two types of measurement. We can expect a good estimate. DSSTEstimationTestUtils.checkFit(context, estimator, 1, 3, - 0.0, 4.9e-7, + 0.0, 5.1e-7, 0.0, 1.6e-6, 0.0, 4.4e-8, - 0.0, 2.0e-11); + 0.0, 2.2e-11); } @Test diff --git a/src/test/java/org/orekit/models/earth/troposphere/FieldNiellMappingFunctionModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/FieldNiellMappingFunctionModelTest.java index c12948e8c1..804c4b06b1 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/FieldNiellMappingFunctionModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/FieldNiellMappingFunctionModelTest.java @@ -256,7 +256,7 @@ public void testMFStateDerivatives() { } // Tolerances - final double epsMFH = 6.506e-12; + final double epsMFH = 6.539e-12; final double epsMFW = 1.557e-11; for (int i = 0; i < 6; i++) { Assertions.assertEquals(0., FastMath.abs(compMFH[i + 1] - refMF[0][i]), epsMFH); diff --git a/src/test/java/org/orekit/orbits/CircularOrbitTest.java b/src/test/java/org/orekit/orbits/CircularOrbitTest.java index d6e072f883..b306bc857f 100644 --- a/src/test/java/org/orekit/orbits/CircularOrbitTest.java +++ b/src/test/java/org/orekit/orbits/CircularOrbitTest.java @@ -765,8 +765,7 @@ void testSerialization() ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(orbit); - Assertions.assertTrue(bos.size() > 350); - Assertions.assertTrue(bos.size() < 400); + Assertions.assertEquals(bos.size(), 527); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); @@ -806,8 +805,7 @@ void testSerializationWithDerivatives() ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(orbit); - Assertions.assertTrue(bos.size() > 400); - Assertions.assertTrue(bos.size() < 450); + Assertions.assertEquals(bos.size(), 575); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); @@ -858,8 +856,7 @@ void testSerializationNoPVWithDerivatives() ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(orbit); - Assertions.assertTrue(bos.size() > 330); - Assertions.assertTrue(bos.size() < 380); + Assertions.assertEquals(bos.size(), 503); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); @@ -1221,6 +1218,7 @@ void testCoverageCachedPositionAngleTypeWithRates() { } } } + @BeforeEach public void setUp() { diff --git a/src/test/java/org/orekit/orbits/EquinoctialOrbitTest.java b/src/test/java/org/orekit/orbits/EquinoctialOrbitTest.java index d77ae300c3..1ad29b80ce 100644 --- a/src/test/java/org/orekit/orbits/EquinoctialOrbitTest.java +++ b/src/test/java/org/orekit/orbits/EquinoctialOrbitTest.java @@ -761,8 +761,7 @@ void testSerialization() ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(orbit); - Assertions.assertTrue(bos.size() > 280); - Assertions.assertTrue(bos.size() < 330); + Assertions.assertEquals(bos.size(), 458); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); @@ -802,8 +801,7 @@ void testSerializationWithDerivatives() ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(orbit); - Assertions.assertTrue(bos.size() > 330); - Assertions.assertTrue(bos.size() < 380); + Assertions.assertEquals(bos.size(), 506); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); @@ -1126,6 +1124,129 @@ void positionAngleNonRegressionOnDeprecated() { actualTrueToEccentric); } + @Test + void testCoverageCachedPositionAngleTypeWithRates() { + // GIVEN + final double semiMajorAxis = 1e4; + final double ex = 0.; + final double ey = 0.; + final double expectedL = 0.; + final double expectedLDot = 0.; + // WHEN & THEN + for (final PositionAngleType inputPositionAngleType: PositionAngleType.values()) { + for (final PositionAngleType cachedPositionAngleType: PositionAngleType.values()) { + final EquinoctialOrbit equinoctialOrbit = new EquinoctialOrbit(semiMajorAxis, ex, ey, 0., 0., + expectedL, 0., 0., 0., 0., 0., expectedLDot, + inputPositionAngleType, cachedPositionAngleType, FramesFactory.getGCRF(), date, mu); + Assertions.assertEquals(expectedL, equinoctialOrbit.getLv()); + Assertions.assertEquals(expectedL, equinoctialOrbit.getLM()); + Assertions.assertEquals(expectedL, equinoctialOrbit.getLE()); + Assertions.assertEquals(expectedLDot, equinoctialOrbit.getLvDot()); + Assertions.assertEquals(expectedLDot, equinoctialOrbit.getLMDot()); + Assertions.assertEquals(expectedLDot, equinoctialOrbit.getLEDot()); + } + } + } + + @Test + void testCachedPositionAngleTypeTrue() { + // GIVEN + final double semiMajorAxis = 1e4; + final double ex = 1e-2; + final double ey = -1e-3; + final double expectedLv = 2.; + final PositionAngleType inputPositionAngleType = PositionAngleType.TRUE; + // WHEN & THEN + for (final PositionAngleType cachedPositionAngleType: PositionAngleType.values()) { + final EquinoctialOrbit equinoctialOrbit = new EquinoctialOrbit(semiMajorAxis, ex, ey, 0., 0., + expectedLv, inputPositionAngleType, cachedPositionAngleType, FramesFactory.getGCRF(), date, mu); + Assertions.assertEquals(expectedLv, equinoctialOrbit.getLv(), 1e-15); + final double actualL = equinoctialOrbit.getL(cachedPositionAngleType); + switch (cachedPositionAngleType) { + + case MEAN: + Assertions.assertEquals(EquinoctialLongitudeArgumentUtility.trueToMean(ex, ey, expectedLv), + actualL); + break; + + case ECCENTRIC: + Assertions.assertEquals(EquinoctialLongitudeArgumentUtility.trueToEccentric(ex, ey, expectedLv), + actualL); + break; + + case TRUE: + Assertions.assertEquals(expectedLv, actualL); + break; + } + } + } + + @Test + void testCachedPositionAngleTypeMean() { + // GIVEN + final double semiMajorAxis = 1e4; + final double ex = 1e-2; + final double ey = -1e-3; + final double expectedLM = 2.; + final PositionAngleType inputPositionAngleType = PositionAngleType.MEAN; + // WHEN & THEN + for (final PositionAngleType cachedPositionAngleType: PositionAngleType.values()) { + final EquinoctialOrbit equinoctialOrbit = new EquinoctialOrbit(semiMajorAxis, ex, ey, 0., 0., + expectedLM, inputPositionAngleType, cachedPositionAngleType, FramesFactory.getGCRF(), date, mu); + Assertions.assertEquals(expectedLM, equinoctialOrbit.getLM(), 1e-15); + final double actualL = equinoctialOrbit.getL(cachedPositionAngleType); + switch (cachedPositionAngleType) { + + case TRUE: + Assertions.assertEquals(EquinoctialLongitudeArgumentUtility.meanToTrue(ex, ey, expectedLM), + actualL); + break; + + case ECCENTRIC: + Assertions.assertEquals(EquinoctialLongitudeArgumentUtility.meanToEccentric(ex, ey, expectedLM), + actualL); + break; + + case MEAN: + Assertions.assertEquals(expectedLM, actualL); + break; + } + } + } + + @Test + void testCachedPositionAngleTypeEccentric() { + // GIVEN + final double semiMajorAxis = 1e4; + final double ex = 1e-2; + final double ey = -1e-3; + final double expectedLE = 2.; + final PositionAngleType inputPositionAngleType = PositionAngleType.ECCENTRIC; + // WHEN & THEN + for (final PositionAngleType cachedPositionAngleType: PositionAngleType.values()) { + final EquinoctialOrbit equinoctialOrbit = new EquinoctialOrbit(semiMajorAxis, ex, ey, 0., 0., + expectedLE, inputPositionAngleType, cachedPositionAngleType, FramesFactory.getGCRF(), date, mu); + Assertions.assertEquals(expectedLE, equinoctialOrbit.getLE(), 1e-15); + final double actualL = equinoctialOrbit.getL(cachedPositionAngleType); + switch (cachedPositionAngleType) { + + case TRUE: + Assertions.assertEquals(EquinoctialLongitudeArgumentUtility.eccentricToTrue(ex, ey, expectedLE), + actualL); + break; + + case MEAN: + Assertions.assertEquals(EquinoctialLongitudeArgumentUtility.eccentricToMean(ex, ey, expectedLE), + actualL); + break; + + case ECCENTRIC: + Assertions.assertEquals(expectedLE, actualL); + break; + } + } + } + @BeforeEach public void setUp() { diff --git a/src/test/java/org/orekit/orbits/KeplerianOrbitTest.java b/src/test/java/org/orekit/orbits/KeplerianOrbitTest.java index d902719113..b9d2cd4a3b 100644 --- a/src/test/java/org/orekit/orbits/KeplerianOrbitTest.java +++ b/src/test/java/org/orekit/orbits/KeplerianOrbitTest.java @@ -1292,8 +1292,7 @@ public void testSerialization() ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(orbit); - Assertions.assertTrue(bos.size() > 280); - Assertions.assertTrue(bos.size() < 330); + Assertions.assertEquals(bos.size(), 461); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); @@ -1333,8 +1332,7 @@ public void testSerializationWithDerivatives() ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(orbit); - Assertions.assertTrue(bos.size() > 330); - Assertions.assertTrue(bos.size() < 380); + Assertions.assertEquals(bos.size(), 509); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); diff --git a/src/test/java/org/orekit/utils/FieldifierTest.java b/src/test/java/org/orekit/utils/FieldifierTest.java index b4f99ffcfd..0ee70c32e3 100644 --- a/src/test/java/org/orekit/utils/FieldifierTest.java +++ b/src/test/java/org/orekit/utils/FieldifierTest.java @@ -69,7 +69,7 @@ void testCircularOrbitFieldification() { Assertions.assertEquals(initialOrbit.getCircularEyDot(), fieldOrbit.getCircularEyDot().getReal()); Assertions.assertEquals(initialOrbit.getIDot(), fieldOrbit.getIDot().getReal()); Assertions.assertEquals(initialOrbit.getRightAscensionOfAscendingNodeDot(), fieldOrbit.getRightAscensionOfAscendingNodeDot().getReal()); - Assertions.assertEquals(initialOrbit.getAlphaMDot(), fieldOrbit.getAlphaMDot().getReal()); + Assertions.assertEquals(initialOrbit.getAlphaMDot(), fieldOrbit.getAlphaMDot().getReal(), 1e-10); } @Test @@ -145,7 +145,7 @@ void testKeplerianOrbitFieldification() { Assertions.assertEquals(initialOrbit.getIDot(), fieldOrbit.getIDot().getReal()); Assertions.assertEquals(initialOrbit.getPerigeeArgumentDot(), fieldOrbit.getPerigeeArgumentDot().getReal()); Assertions.assertEquals(initialOrbit.getRightAscensionOfAscendingNodeDot(), fieldOrbit.getRightAscensionOfAscendingNodeDot().getReal()); - Assertions.assertEquals(initialOrbit.getMeanAnomalyDot(), fieldOrbit.getMeanAnomalyDot().getReal()); + Assertions.assertEquals(initialOrbit.getMeanAnomalyDot(), fieldOrbit.getMeanAnomalyDot().getReal(), 1e-10); } @Test From 80afb2b3303236c35650bb9ac4107005ee5a3601 Mon Sep 17 00:00:00 2001 From: Serrof Date: Tue, 6 Feb 2024 23:58:50 +0100 Subject: [PATCH 123/359] Fixed tolerances in failing tests --- src/changes/changes.xml | 3 ++ .../leastsquares/BatchLSEstimatorTest.java | 6 ++-- .../BrouwerLyddaneBatchLSEstimatorTest.java | 32 +++++++++---------- ...nalyticalUnscentedKalmanEstimatorTest.java | 4 +-- 4 files changed, 24 insertions(+), 21 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 6a8052fb98..902a6c383c 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -21,6 +21,9 @@ + + Added cache for position angle in Orbit when applicable. + Fixed forbidden SBAS System Time in SP3 files. diff --git a/src/test/java/org/orekit/estimation/leastsquares/BatchLSEstimatorTest.java b/src/test/java/org/orekit/estimation/leastsquares/BatchLSEstimatorTest.java index 4839fd9cf9..fc01d7067f 100644 --- a/src/test/java/org/orekit/estimation/leastsquares/BatchLSEstimatorTest.java +++ b/src/test/java/org/orekit/estimation/leastsquares/BatchLSEstimatorTest.java @@ -734,8 +734,8 @@ public void evaluationPerformed(int iterationsCount, int evaluationscount, before.getPosition()), 1.0e-3); Assertions.assertEquals(0.0010514, Vector3D.distance(closeOrbit.getPVCoordinates().getVelocity(), before.getPVCoordinates().getVelocity()), 1.0e-6); - EstimationTestUtils.checkFit(context, estimator, 4, 5, - 0.0, 4.7e-06, + EstimationTestUtils.checkFit(context, estimator, 4, 6, + 0.0, 5.3e-06, 0.0, 1.4e-05, 0.0, 8.8e-07, 0.0, 3.6e-10); @@ -751,7 +751,7 @@ public void evaluationPerformed(int iterationsCount, int evaluationscount, closeOrbit.getDate(), closeOrbit.getMu()); Assertions.assertEquals(0.0, Vector3D.distance(closeOrbit.getPosition(), - determined.getPosition()), 2.7e-6); + determined.getPosition()), 5.3e-6); Assertions.assertEquals(0.0, Vector3D.distance(closeOrbit.getPVCoordinates().getVelocity(), determined.getPVCoordinates().getVelocity()), 2.9e-9); diff --git a/src/test/java/org/orekit/estimation/leastsquares/BrouwerLyddaneBatchLSEstimatorTest.java b/src/test/java/org/orekit/estimation/leastsquares/BrouwerLyddaneBatchLSEstimatorTest.java index 2edac4037b..c818b30926 100644 --- a/src/test/java/org/orekit/estimation/leastsquares/BrouwerLyddaneBatchLSEstimatorTest.java +++ b/src/test/java/org/orekit/estimation/leastsquares/BrouwerLyddaneBatchLSEstimatorTest.java @@ -144,7 +144,7 @@ public void testKeplerRange() { BrouwerLyddaneContext context = BrouwerLyddaneEstimationTestUtils.eccentricContext("regular-data:potential:tides"); final BrouwerLyddanePropagatorBuilder propagatorBuilder = - context.createBuilder(PositionAngleType.MEAN, true, 1.0); + context.createBuilder(PositionAngleType.TRUE, true, 1.0); // create perfect range measurements final Propagator propagator = BrouwerLyddaneEstimationTestUtils.createPropagator(context.initialOrbit, @@ -165,10 +165,10 @@ public void testKeplerRange() { estimator.setMaxEvaluations(20); BrouwerLyddaneEstimationTestUtils.checkFit(context, estimator, 1, 2, - 0.0, 1.1e-4, - 0.0, 1.8e-4, - 0.0, 1.4e-5, - 0.0, 1.3e-8); + 0.0, 3.2e-2, + 0.0, 5.8e-2, + 0.0, 5e-3, + 0.0, 2.8e-6); } @@ -210,11 +210,11 @@ public void testKeplerRangeWithOnBoardAntennaOffset() { estimator.setMaxIterations(10); estimator.setMaxEvaluations(20); - BrouwerLyddaneEstimationTestUtils.checkFit(context, estimator, 1, 2, - 0.0, 1.2e-4, - 0.0, 2.6e-4, - 0.0, 1.4e-5, - 0.0, 1.3e-8); + BrouwerLyddaneEstimationTestUtils.checkFit(context, estimator, 3, 4, + 0.0, 2.94e-2, + 0.0, 5.3e-2, + 0.0, 4.6e-3, + 0.0, 6.3e-6); } @@ -251,15 +251,15 @@ public void testKeplerRangeRate() { for (final ObservedMeasurement rangerate : measurements) { estimator.addMeasurement(rangerate); } - estimator.setParametersConvergenceThreshold(1.0e-3); + estimator.setParametersConvergenceThreshold(1.0e-2); estimator.setMaxIterations(10); estimator.setMaxEvaluations(20); - BrouwerLyddaneEstimationTestUtils.checkFit(context, estimator, 1, 2, - 0.0, 7.9e-8, - 0.0, 1.1e-7, - 0.0, 1.5e-5, - 0.0, 1.4e-8); + BrouwerLyddaneEstimationTestUtils.checkFit(context, estimator, 3,8, + 0.0, 4.9e-5, + 0.0, 1.2e-4, + 0.0, 3.2e-2, + 0.0, 4.4e-5); } @Test diff --git a/src/test/java/org/orekit/estimation/sequential/SemiAnalyticalUnscentedKalmanEstimatorTest.java b/src/test/java/org/orekit/estimation/sequential/SemiAnalyticalUnscentedKalmanEstimatorTest.java index 1c0fac9534..5c64bdbb27 100644 --- a/src/test/java/org/orekit/estimation/sequential/SemiAnalyticalUnscentedKalmanEstimatorTest.java +++ b/src/test/java/org/orekit/estimation/sequential/SemiAnalyticalUnscentedKalmanEstimatorTest.java @@ -344,9 +344,9 @@ public void testRangeWithTesseral() { // Filter the measurements and check the results final double expectedDeltaPos = 0.; - final double posEps = 4.2e-9; + final double posEps = 4.2e-7; final double expectedDeltaVel = 0.; - final double velEps = 1.7e-12; + final double velEps = 3.8e-11; DSSTEstimationTestUtils.checkKalmanFit(context, kalman, measurements, refOrbit, positionAngleType, expectedDeltaPos, posEps, From 25ec222edd89d471803a028e8f4b28a8d2d9b314 Mon Sep 17 00:00:00 2001 From: Alberto Ferrero Date: Wed, 14 Feb 2024 18:47:55 +0000 Subject: [PATCH 124/359] Closes #1215 Adding Latitude and Longitude Range Crossing detectors --- src/changes/changes.xml | 6 +- .../FieldLatitudeRangeCrossingDetector.java | 191 +++++++++++++++ .../FieldLongitudeCrossingDetector.java | 2 +- .../FieldLongitudeRangeCrossingDetector.java | 219 ++++++++++++++++++ .../events/LatitudeRangeCrossingDetector.java | 152 ++++++++++++ .../LongitudeRangeCrossingDetector.java | 170 ++++++++++++++ .../propagation/events/package-info.java | 6 + ...ieldLatitudeRangeCrossingDetectorTest.java | 178 ++++++++++++++ ...eldLongitudeRangeCrossingDetectorTest.java | 179 ++++++++++++++ .../LatitudeRangeCrossingDetectorTest.java | 159 +++++++++++++ .../LongitudeRangeCrossingDetectorTest.java | 162 +++++++++++++ 11 files changed, 1422 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/orekit/propagation/events/FieldLatitudeRangeCrossingDetector.java create mode 100644 src/main/java/org/orekit/propagation/events/FieldLongitudeRangeCrossingDetector.java create mode 100644 src/main/java/org/orekit/propagation/events/LatitudeRangeCrossingDetector.java create mode 100644 src/main/java/org/orekit/propagation/events/LongitudeRangeCrossingDetector.java create mode 100644 src/test/java/org/orekit/propagation/events/FieldLatitudeRangeCrossingDetectorTest.java create mode 100644 src/test/java/org/orekit/propagation/events/FieldLongitudeRangeCrossingDetectorTest.java create mode 100644 src/test/java/org/orekit/propagation/events/LatitudeRangeCrossingDetectorTest.java create mode 100644 src/test/java/org/orekit/propagation/events/LongitudeRangeCrossingDetectorTest.java diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 902a6c383c..28fe63a887 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -21,6 +21,9 @@ + + Create two new EventDetector: LatitudeRangeCrossingDetector and LongitudeRangeCrossingDetector. + Added cache for position angle in Orbit when applicable. @@ -209,7 +212,8 @@ Adding {Field}LongitudeCrossingDetector. - + + Added support for CCSDS/SANA geodetic orbital elements. diff --git a/src/main/java/org/orekit/propagation/events/FieldLatitudeRangeCrossingDetector.java b/src/main/java/org/orekit/propagation/events/FieldLatitudeRangeCrossingDetector.java new file mode 100644 index 0000000000..76ab7a01d4 --- /dev/null +++ b/src/main/java/org/orekit/propagation/events/FieldLatitudeRangeCrossingDetector.java @@ -0,0 +1,191 @@ +/* Copyright 2023-2024 Alberto Ferrero + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Alberto Ferrero licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.propagation.events; + +import org.hipparchus.CalculusFieldElement; +import org.hipparchus.Field; +import org.hipparchus.util.FastMath; +import org.orekit.bodies.FieldGeodeticPoint; +import org.orekit.bodies.OneAxisEllipsoid; +import org.orekit.propagation.FieldSpacecraftState; +import org.orekit.propagation.events.handlers.FieldEventHandler; +import org.orekit.propagation.events.handlers.FieldStopOnIncreasing; + + +/** Detector for geographic latitude crossing. + *

                This detector identifies when a spacecraft crosses a fixed + * latitude range with respect to a central body.

                + * @author Alberto Ferrero + * @since 12.0 + * @param type of the field elements + */ +public class FieldLatitudeRangeCrossingDetector > + extends FieldAbstractDetector, T> { + + /** + * Body on which the latitude is defined. + */ + private final OneAxisEllipsoid body; + + /** + * Fixed latitude to be crossed, lower boundary in radians. + */ + private final double fromLatitude; + + /** + * Fixed latitude to be crossed, upper boundary in radians. + */ + private final double toLatitude; + + /** + * Sign, to get reversed inclusion latitude range (lower > upper). + */ + private final double sign; + + /** + * Build a new detector. + *

                The new instance uses default values for maximal checking interval + * ({@link #DEFAULT_MAXCHECK}) and convergence threshold ({@link + * #DEFAULT_THRESHOLD}).

                + * @param field the type of numbers to use. + * @param body body on which the latitude is defined + * @param fromLatitude latitude to be crossed, lower range boundary + * @param toLatitude latitude to be crossed, upper range boundary + */ + public FieldLatitudeRangeCrossingDetector(final Field field, + final OneAxisEllipsoid body, + final double fromLatitude, + final double toLatitude) { + this(s -> DEFAULT_MAXCHECK, + field.getZero().add(DEFAULT_THRESHOLD), + DEFAULT_MAX_ITER, + new FieldStopOnIncreasing<>(), + body, + fromLatitude, + toLatitude); + } + + /** + * Build a detector. + * + * @param maxCheck maximal checking interval (s) + * @param threshold convergence threshold (s) + * @param body body on which the latitude is defined + * @param fromLatitude latitude to be crossed, lower range boundary + * @param toLatitude latitude to be crossed, upper range boundary + */ + public FieldLatitudeRangeCrossingDetector(final T maxCheck, final T threshold, + final OneAxisEllipsoid body, final double fromLatitude, final double toLatitude) { + this(s -> maxCheck.getReal(), threshold, DEFAULT_MAX_ITER, new FieldStopOnIncreasing<>(), + body, fromLatitude, toLatitude); + } + + /** + * Private constructor with full parameters. + *

                + * This constructor is private as users are expected to use the builder + * API with the various {@code withXxx()} methods to set up the instance + * in a readable manner without using a huge amount of parameters. + *

                + * + * @param maxCheck maximum checking interval (s) + * @param threshold convergence threshold (s) + * @param maxIter maximum number of iterations in the event time search + * @param handler event handler to call at event occurrences + * @param body body on which the latitude is defined + * @param fromLatitude latitude to be crossed, lower range boundary + * @param toLatitude latitude to be crossed, upper range boundary + */ + protected FieldLatitudeRangeCrossingDetector(final FieldAdaptableInterval maxCheck, + final T threshold, + final int maxIter, + final FieldEventHandler handler, + final OneAxisEllipsoid body, + final double fromLatitude, + final double toLatitude) { + super(maxCheck, threshold, maxIter, handler); + this.body = body; + this.fromLatitude = fromLatitude; + this.toLatitude = toLatitude; + this.sign = FastMath.signum(toLatitude - fromLatitude); + } + + /** + * {@inheritDoc} + */ + @Override + protected FieldLatitudeRangeCrossingDetector create(final FieldAdaptableInterval newMaxCheck, + final T newThreshold, + final int newMaxIter, + final FieldEventHandler newHandler) { + return new FieldLatitudeRangeCrossingDetector<>(newMaxCheck, newThreshold, newMaxIter, newHandler, + body, fromLatitude, toLatitude); + } + + /** + * Get the body on which the geographic zone is defined. + * + * @return body on which the geographic zone is defined + */ + public OneAxisEllipsoid getBody() { + return body; + } + + /** + * Get the fixed latitude range to be crossed (radians), lower boundary. + * + * @return fixed lower boundary latitude range to be crossed (radians) + */ + public double getFromLatitude() { + return fromLatitude; + } + + /** + * Get the fixed latitude range to be crossed (radians), upper boundary. + * + * @return fixed lower boundary latitude range to be crossed (radians) + */ + public double getToLatitude() { + return toLatitude; + } + + /** + * Compute the value of the detection function. + *

                + * The value is positive if the spacecraft latitude is inside the latitude range. + * It is positive if the spacecraft is northward to lower boundary range and southward to upper boundary range, + * with respect to the fixed latitude range. + *

                + * + * @param s the current state information: date, kinematics, attitude + * @return positive if spacecraft inside the range + */ + public T g(final FieldSpacecraftState s) { + + // convert state to geodetic coordinates + final FieldGeodeticPoint gp = body.transform(s.getPVCoordinates().getPosition(), + s.getFrame(), s.getDate()); + + // point latitude + final T latitude = gp.getLatitude(); + + // inside or outside latitude range + return latitude.subtract(fromLatitude).multiply(latitude.negate().add(toLatitude)).multiply(sign); + + } + +} diff --git a/src/main/java/org/orekit/propagation/events/FieldLongitudeCrossingDetector.java b/src/main/java/org/orekit/propagation/events/FieldLongitudeCrossingDetector.java index 7f34f1ab86..bace9ad2d2 100644 --- a/src/main/java/org/orekit/propagation/events/FieldLongitudeCrossingDetector.java +++ b/src/main/java/org/orekit/propagation/events/FieldLongitudeCrossingDetector.java @@ -1,4 +1,4 @@ -/* Copyright 2002-2024 Alberto Ferrero +/* Copyright 2023-2024 Alberto Ferrero * Licensed to CS GROUP (CS) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. diff --git a/src/main/java/org/orekit/propagation/events/FieldLongitudeRangeCrossingDetector.java b/src/main/java/org/orekit/propagation/events/FieldLongitudeRangeCrossingDetector.java new file mode 100644 index 0000000000..dbf170e7f1 --- /dev/null +++ b/src/main/java/org/orekit/propagation/events/FieldLongitudeRangeCrossingDetector.java @@ -0,0 +1,219 @@ +/* Copyright 2023-2024 Alberto Ferrero + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Alberto Ferrero licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.propagation.events; + +import org.hipparchus.CalculusFieldElement; +import org.hipparchus.Field; +import org.hipparchus.util.FastMath; +import org.orekit.bodies.FieldGeodeticPoint; +import org.orekit.bodies.OneAxisEllipsoid; +import org.orekit.propagation.FieldSpacecraftState; +import org.orekit.propagation.events.handlers.FieldEventHandler; +import org.orekit.propagation.events.handlers.FieldStopOnIncreasing; + + +/** Detector for geographic longitude crossing. + *

                This detector identifies when a spacecraft crosses a fixed + * longitude range with respect to a central body.

                + * @author Alberto Ferrero + * @since 12.0 + * @param type of the field elements + */ +public class FieldLongitudeRangeCrossingDetector > + extends FieldAbstractDetector, T> { + + /** + * Body on which the longitude is defined. + */ + private final OneAxisEllipsoid body; + + /** + * Fixed longitude to be crossed, lower boundary in radians. + */ + private final double fromLongitude; + + /** + * Fixed longitude to be crossed, upper boundary in radians. + */ + private final double toLongitude; + + /** + * Sign, to get reversed inclusion longitude range (lower > upper). + */ + private final double sign; + + /** + * Build a new detector. + *

                The new instance uses default values for maximal checking interval + * ({@link #DEFAULT_MAXCHECK}) and convergence threshold ({@link + * #DEFAULT_THRESHOLD}).

                + * @param field the type of numbers to use. + * @param body body on which the longitude is defined + * @param fromLongitude longitude to be crossed, lower range boundary + * @param toLongitude longitude to be crossed, upper range boundary + */ + public FieldLongitudeRangeCrossingDetector(final Field field, final OneAxisEllipsoid body, final double fromLongitude, final double toLongitude) { + this(s -> DEFAULT_MAXCHECK, + field.getZero().add(DEFAULT_THRESHOLD), + DEFAULT_MAX_ITER, + new FieldStopOnIncreasing<>(), + body, + fromLongitude, + toLongitude); + } + + /** + * Build a detector. + * + * @param maxCheck maximal checking interval (s) + * @param threshold convergence threshold (s) + * @param body body on which the longitude is defined + * @param fromLongitude longitude to be crossed, lower range boundary + * @param toLongitude longitude to be crossed, upper range boundary + */ + public FieldLongitudeRangeCrossingDetector(final T maxCheck, final T threshold, + final OneAxisEllipsoid body, final double fromLongitude, final double toLongitude) { + this(s -> maxCheck.getReal(), + threshold, + DEFAULT_MAX_ITER, + new FieldStopOnIncreasing<>(), + body, + fromLongitude, + toLongitude); + } + + /** + * Private constructor with full parameters. + *

                + * This constructor is private as users are expected to use the builder + * API with the various {@code withXxx()} methods to set up the instance + * in a readable manner without using a huge amount of parameters. + *

                + * + * @param maxCheck maximum checking interval (s) + * @param threshold convergence threshold (s) + * @param maxIter maximum number of iterations in the event time search + * @param handler event handler to call at event occurrences + * @param body body on which the longitude is defined + * @param fromLongitude longitude to be crossed, lower range boundary + * @param toLongitude longitude to be crossed, upper range boundary + */ + protected FieldLongitudeRangeCrossingDetector(final FieldAdaptableInterval maxCheck, + final T threshold, + final int maxIter, + final FieldEventHandler handler, + final OneAxisEllipsoid body, + final double fromLongitude, + final double toLongitude) { + super(maxCheck, threshold, maxIter, handler); + this.body = body; + this.fromLongitude = ensureLongitudePositiveContinuity(fromLongitude); + this.toLongitude = ensureLongitudePositiveContinuity(toLongitude); + this.sign = FastMath.signum(this.toLongitude - this.fromLongitude); + } + + /** + * {@inheritDoc} + */ + @Override + protected FieldLongitudeRangeCrossingDetector create(final FieldAdaptableInterval newMaxCheck, + final T newThreshold, + final int newMaxIter, + final FieldEventHandler newHandler) { + return new FieldLongitudeRangeCrossingDetector(newMaxCheck, newThreshold, newMaxIter, newHandler, + body, fromLongitude, toLongitude); + } + + /** + * Get the body on which the geographic zone is defined. + * + * @return body on which the geographic zone is defined + */ + public OneAxisEllipsoid getBody() { + return body; + } + + /** Get the fixed longitude range to be crossed (radians), lower boundary. + * @return fixed lower boundary longitude range to be crossed (radians) + */ + public double getFromLongitude() { + return getLongitudeOverOriginalRange(fromLongitude); + } + + /** Get the fixed longitude range to be crossed (radians), upper boundary. + * @return fixed upper boundary longitude range to be crossed (radians) + */ + public double getToLongitude() { + return getLongitudeOverOriginalRange(toLongitude); + } + + /** + * Ensure continuity for negative angles, as longitude defined as [-PI, PI], transform negative to positive. + * New longitude angle definition from [0, 2 PI]. + * + * @param longitude original longitude value + * @return positive range longitude + */ + private T ensureFieldLongitudePositiveContinuity(final T longitude) { + return longitude.getReal() < 0 ? longitude.add(2 * FastMath.PI) : longitude; + } + + /** + * Ensure continuity for negative angles, as longitude defined as [-PI, PI], transform negative to positive. + * New longitude angle definition from [0, 2 PI]. + * + * @param longitude original longitude value + * @return positive range longitude + */ + private double ensureLongitudePositiveContinuity(final double longitude) { + return longitude < 0 ? longitude + 2 * FastMath.PI : longitude; + } + + /** + * Get longitude shifted over the original range [-PI, PI]. + * @param longitude longitude value to convert + * @return original range longitude + */ + private double getLongitudeOverOriginalRange(final double longitude) { + return longitude > FastMath.PI ? longitude - 2 * FastMath.PI : longitude; + } + + /** + * Compute the value of the detection function. + *

                + * The value is positive if the spacecraft longitude is inside the longitude range. + * The longitude value is reflected from [-PI, +PI] to [0, 2 PI] to ensure continuity. + *

                + * + * @param s the current state information: date, kinematics, attitude + * @return positive if spacecraft inside the range + */ + public T g(final FieldSpacecraftState s) { + + // convert state to geodetic coordinates + final FieldGeodeticPoint gp = body.transform(s.getPVCoordinates().getPosition(), + s.getFrame(), s.getDate()); + + // point longitude + final T longitude = ensureFieldLongitudePositiveContinuity(gp.getLongitude()); + + // inside or outside latitude range + return longitude.subtract(fromLongitude).multiply(longitude.negate().add(toLongitude)).multiply(sign); + + } + +} diff --git a/src/main/java/org/orekit/propagation/events/LatitudeRangeCrossingDetector.java b/src/main/java/org/orekit/propagation/events/LatitudeRangeCrossingDetector.java new file mode 100644 index 0000000000..ab1144b41d --- /dev/null +++ b/src/main/java/org/orekit/propagation/events/LatitudeRangeCrossingDetector.java @@ -0,0 +1,152 @@ +/* Copyright 2023-2024 Alberto Ferrero + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Alberto Ferrero licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.propagation.events; + +import org.hipparchus.util.FastMath; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.bodies.OneAxisEllipsoid; +import org.orekit.propagation.SpacecraftState; +import org.orekit.propagation.events.handlers.EventHandler; +import org.orekit.propagation.events.handlers.StopOnDecreasing; + + +/** Detector for geographic latitude crossing. + *

                This detector identifies when a spacecraft crosses a fixed + * latitude range with respect to a central body.

                + * @author Alberto Ferrero + * @since 12.0 + */ +public class LatitudeRangeCrossingDetector extends AbstractDetector { + + /** Body on which the latitude is defined. */ + private final OneAxisEllipsoid body; + + /** Fixed latitude to be crossed, lower boundary in radians. */ + private final double fromLatitude; + + /** Fixed latitude to be crossed, upper boundary in radians. */ + private final double toLatitude; + + /** + * Sign, to get reversed inclusion latitude range (lower > upper). + */ + private final double sign; + + /** Build a new detector. + *

                The new instance uses default values for maximal checking interval + * ({@link #DEFAULT_MAXCHECK}) and convergence threshold ({@link + * #DEFAULT_THRESHOLD}).

                + * @param body body on which the latitude is defined + * @param fromLatitude latitude to be crossed, lower range boundary + * @param toLatitude latitude to be crossed, upper range boundary + */ + public LatitudeRangeCrossingDetector(final OneAxisEllipsoid body, final double fromLatitude, final double toLatitude) { + this(DEFAULT_MAXCHECK, DEFAULT_THRESHOLD, body, fromLatitude, toLatitude); + } + + /** Build a detector. + * @param maxCheck maximal checking interval (s) + * @param threshold convergence threshold (s) + * @param body body on which the latitude is defined + * @param fromLatitude latitude to be crossed, lower range boundary + * @param toLatitude latitude to be crossed, upper range boundary + */ + public LatitudeRangeCrossingDetector(final double maxCheck, final double threshold, + final OneAxisEllipsoid body, final double fromLatitude, final double toLatitude) { + this(s -> maxCheck, threshold, DEFAULT_MAX_ITER, new StopOnDecreasing(), + body, fromLatitude, toLatitude); + } + + /** Private constructor with full parameters. + *

                + * This constructor is private as users are expected to use the builder + * API with the various {@code withXxx()} methods to set up the instance + * in a readable manner without using a huge amount of parameters. + *

                + * @param maxCheck maximum checking interval (s) + * @param threshold convergence threshold (s) + * @param maxIter maximum number of iterations in the event time search + * @param handler event handler to call at event occurrences + * @param body body on which the latitude is defined + * @param fromLatitude latitude to be crossed, lower range boundary + * @param toLatitude latitude to be crossed, upper range boundary + */ + protected LatitudeRangeCrossingDetector(final AdaptableInterval maxCheck, final double threshold, final int maxIter, + final EventHandler handler, + final OneAxisEllipsoid body, final double fromLatitude, final double toLatitude) { + super(maxCheck, threshold, maxIter, handler); + this.body = body; + this.fromLatitude = fromLatitude; + this.toLatitude = toLatitude; + this.sign = FastMath.signum(toLatitude - fromLatitude); + } + + /** {@inheritDoc} */ + @Override + protected LatitudeRangeCrossingDetector create(final AdaptableInterval newMaxCheck, + final double newThreshold, + final int newMaxIter, + final EventHandler newHandler) { + return new LatitudeRangeCrossingDetector(newMaxCheck, newThreshold, newMaxIter, newHandler, + body, fromLatitude, toLatitude); + } + + /** Get the body on which the geographic zone is defined. + * @return body on which the geographic zone is defined + */ + public OneAxisEllipsoid getBody() { + return body; + } + + /** Get the fixed latitude range to be crossed (radians), lower boundary. + * @return fixed lower boundary latitude range to be crossed (radians) + */ + public double getFromLatitude() { + return fromLatitude; + } + + /** Get the fixed latitude range to be crossed (radians), upper boundary. + * @return fixed lower boundary latitude range to be crossed (radians) + */ + public double getToLatitude() { + return toLatitude; + } + + /** Compute the value of the detection function. + *

                + * The value is positive if the spacecraft latitude is inside the latitude range. + * It is positive if the spacecraft is northward to lower boundary range and southward to upper boundary range, + * with respect to the fixed latitude range. + *

                + * @param s the current state information: date, kinematics, attitude + * @return positive if spacecraft inside the range + */ + public double g(final SpacecraftState s) { + + // convert state to geodetic coordinates + final GeodeticPoint gp = body.transform(s.getPVCoordinates().getPosition(), + s.getFrame(), s.getDate()); + + // point latitude + final double latitude = gp.getLatitude(); + + // inside or outside latitude range + return sign * (latitude - fromLatitude) * (toLatitude - latitude); + + } + +} diff --git a/src/main/java/org/orekit/propagation/events/LongitudeRangeCrossingDetector.java b/src/main/java/org/orekit/propagation/events/LongitudeRangeCrossingDetector.java new file mode 100644 index 0000000000..c91960a747 --- /dev/null +++ b/src/main/java/org/orekit/propagation/events/LongitudeRangeCrossingDetector.java @@ -0,0 +1,170 @@ +/* Copyright 2023-2024 Alberto Ferrero + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Alberto Ferrero licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.propagation.events; + +import org.hipparchus.util.FastMath; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.bodies.OneAxisEllipsoid; +import org.orekit.propagation.SpacecraftState; +import org.orekit.propagation.events.handlers.EventHandler; +import org.orekit.propagation.events.handlers.StopOnDecreasing; + + +/** Detector for geographic longitude crossing. + *

                This detector identifies when a spacecraft crosses a fixed + * longitude range with respect to a central body.

                + * @author Alberto Ferrero + * @since 12.0 + */ +public class LongitudeRangeCrossingDetector extends AbstractDetector { + + /** Body on which the longitude is defined. */ + private final OneAxisEllipsoid body; + + /** Fixed longitude to be crossed, lower boundary in radians. */ + private final double fromLongitude; + + /** Fixed longitude to be crossed, upper boundary in radians. */ + private final double toLongitude; + + /** + * Sign, to get reversed inclusion longitude range (lower > upper). + */ + private final double sign; + + /** Build a new detector. + *

                The new instance uses default values for maximal checking interval + * ({@link #DEFAULT_MAXCHECK}) and convergence threshold ({@link + * #DEFAULT_THRESHOLD}).

                + * @param body body on which the longitude is defined + * @param fromLongitude longitude to be crossed, lower range boundary + * @param toLongitude longitude to be crossed, upper range boundary + */ + public LongitudeRangeCrossingDetector(final OneAxisEllipsoid body, final double fromLongitude, final double toLongitude) { + this(DEFAULT_MAXCHECK, DEFAULT_THRESHOLD, body, fromLongitude, toLongitude); + } + + /** Build a detector. + * @param maxCheck maximal checking interval (s) + * @param threshold convergence threshold (s) + * @param body body on which the longitude is defined + * @param fromLongitude longitude to be crossed, lower range boundary + * @param toLongitude longitude to be crossed, upper range boundary + */ + public LongitudeRangeCrossingDetector(final double maxCheck, final double threshold, + final OneAxisEllipsoid body, final double fromLongitude, final double toLongitude) { + this(s -> maxCheck, threshold, DEFAULT_MAX_ITER, new StopOnDecreasing(), + body, fromLongitude, toLongitude); + } + + /** Private constructor with full parameters. + *

                + * This constructor is private as users are expected to use the builder + * API with the various {@code withXxx()} methods to set up the instance + * in a readable manner without using a huge amount of parameters. + *

                + * @param maxCheck maximum checking interval (s) + * @param threshold convergence threshold (s) + * @param maxIter maximum number of iterations in the event time search + * @param handler event handler to call at event occurrences + * @param body body on which the longitude is defined + * @param fromLongitude longitude to be crossed, lower range boundary + * @param toLongitude longitude to be crossed, upper range boundary + */ + protected LongitudeRangeCrossingDetector(final AdaptableInterval maxCheck, final double threshold, final int maxIter, + final EventHandler handler, + final OneAxisEllipsoid body, final double fromLongitude, final double toLongitude) { + super(maxCheck, threshold, maxIter, handler); + this.body = body; + this.fromLongitude = ensureLongitudePositiveContinuity(fromLongitude); + this.toLongitude = ensureLongitudePositiveContinuity(toLongitude); + this.sign = FastMath.signum(this.toLongitude - this.fromLongitude); + } + + /** {@inheritDoc} */ + @Override + protected LongitudeRangeCrossingDetector create(final AdaptableInterval newMaxCheck, + final double newThreshold, + final int newMaxIter, + final EventHandler newHandler) { + return new LongitudeRangeCrossingDetector(newMaxCheck, newThreshold, newMaxIter, newHandler, + body, fromLongitude, toLongitude); + } + + /** Get the body on which the geographic zone is defined. + * @return body on which the geographic zone is defined + */ + public OneAxisEllipsoid getBody() { + return body; + } + + /** Get the fixed longitude range to be crossed (radians), lower boundary. + * @return fixed lower boundary longitude range to be crossed (radians) + */ + public double getFromLongitude() { + return getLongitudeOverOriginalRange(fromLongitude); + } + + /** Get the fixed longitude range to be crossed (radians), upper boundary. + * @return fixed upper boundary longitude range to be crossed (radians) + */ + public double getToLongitude() { + return getLongitudeOverOriginalRange(toLongitude); + } + + /** + * Ensure continuity for negative angles, as longitude defined as [-PI, PI], transform negative to positive. + * New longitude angle definition from [0, 2 PI]. + * @param longitude original longitude value + * @return positive range longitude + */ + private double ensureLongitudePositiveContinuity(final double longitude) { + return longitude < 0 ? longitude + 2 * FastMath.PI : longitude; + } + + /** + * Get longitude shifted over the original range [-PI, PI]. + * @param longitude longitude value to convert + * @return original range longitude + */ + private double getLongitudeOverOriginalRange(final double longitude) { + return longitude > FastMath.PI ? longitude - 2 * FastMath.PI : longitude; + } + + /** Compute the value of the detection function. + *

                + * The value is positive if the spacecraft longitude is inside the longitude range. + * The longitude value is reflected from [-PI, +PI] to [0, 2 PI] to ensure continuity. + *

                + * @param s the current state information: date, kinematics, attitude + * @return positive if spacecraft inside the range + */ + public double g(final SpacecraftState s) { + + // convert state to geodetic coordinates + final GeodeticPoint gp = body.transform(s.getPVCoordinates().getPosition(), + s.getFrame(), s.getDate()); + + // point longitude + final double longitude = ensureLongitudePositiveContinuity(gp.getLongitude()); + + // inside or outside longitude range + return sign * (longitude - fromLongitude) * (toLongitude - longitude); + + } + +} diff --git a/src/main/java/org/orekit/propagation/events/package-info.java b/src/main/java/org/orekit/propagation/events/package-info.java index 38a8567f71..bc58ea0d07 100644 --- a/src/main/java/org/orekit/propagation/events/package-info.java +++ b/src/main/java/org/orekit/propagation/events/package-info.java @@ -78,12 +78,18 @@ *
              • {@link org.orekit.propagation.events.LatitudeCrossingDetector LatitudeCrossingDetector} * detects satellite crossing a parallel (and by default stop at northward crossing) *
              • + *
              • {@link org.orekit.propagation.events.LatitudeRangeCrossingDetector LatitudeRangeCrossingDetector} + * detects satellite crossing a parallel range (and by default stop exiting range) + *
              • *
              • {@link org.orekit.propagation.events.LatitudeExtremumDetector LatitudeExtremumDetector} * detects satellite maximum/minimum latitude (and by default stop at minimum) *
              • *
              • {@link org.orekit.propagation.events.LongitudeCrossingDetector LongitudeCrossingDetector} * detects satellite crossing a meridian (the increasing/decreasing flag is irrelevant for this detector) *
              • + *
              • {@link org.orekit.propagation.events.LongitudeRangeCrossingDetector LongitudeRangeCrossingDetector} + * detects satellite crossing a meridian range (and by default stop exiting range) + *
              • *
              • {@link org.orekit.propagation.events.LongitudeExtremumDetector LongitudeExtremumDetector} * detects satellite maximum/minimum longitude (and by default stop at minimum) *
              • diff --git a/src/test/java/org/orekit/propagation/events/FieldLatitudeRangeCrossingDetectorTest.java b/src/test/java/org/orekit/propagation/events/FieldLatitudeRangeCrossingDetectorTest.java new file mode 100644 index 0000000000..f1b5a5f8a9 --- /dev/null +++ b/src/test/java/org/orekit/propagation/events/FieldLatitudeRangeCrossingDetectorTest.java @@ -0,0 +1,178 @@ +/* Copyright 2023-2024 Alberto Ferrero + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Alberto Ferrero licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.propagation.events; + +import org.hipparchus.geometry.euclidean.threed.Vector3D; +import org.hipparchus.util.Binary64; +import org.hipparchus.util.Binary64Field; +import org.hipparchus.util.FastMath; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.orekit.Utils; +import org.orekit.bodies.OneAxisEllipsoid; +import org.orekit.frames.FramesFactory; +import org.orekit.orbits.FieldEquinoctialOrbit; +import org.orekit.orbits.FieldOrbit; +import org.orekit.propagation.FieldPropagator; +import org.orekit.propagation.FieldSpacecraftState; +import org.orekit.propagation.analytical.FieldEcksteinHechlerPropagator; +import org.orekit.propagation.events.FieldEventsLogger.FieldLoggedEvent; +import org.orekit.propagation.events.handlers.FieldContinueOnEvent; +import org.orekit.time.FieldAbsoluteDate; +import org.orekit.time.TimeScale; +import org.orekit.time.TimeScalesFactory; +import org.orekit.utils.Constants; +import org.orekit.utils.FieldPVCoordinates; +import org.orekit.utils.IERSConventions; +import org.orekit.utils.PVCoordinates; + +/** Unit tests for {@link FieldLatitudeRangeCrossingDetector}. */ +public class FieldLatitudeRangeCrossingDetectorTest { + + /** Arbitrary Field. */ + private static final Binary64Field field = Binary64Field.getInstance(); + + @Test + public void testRegularCrossing() { + + final OneAxisEllipsoid earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS, + Constants.WGS84_EARTH_FLATTENING, + FramesFactory.getITRF(IERSConventions.IERS_2010, true)); + + FieldLatitudeRangeCrossingDetector d = + new FieldLatitudeRangeCrossingDetector<>(v(60.0), v(1.e-6), + earth, FastMath.toRadians(50.0), FastMath.toRadians(60.0)). + withHandler(new FieldContinueOnEvent<>()); + + Assertions.assertEquals(60.0, d.getMaxCheckInterval().currentInterval(null), 1.0e-15); + Assertions.assertEquals(1.0e-6, d.getThreshold().getReal(), 1.0e-15); + Assertions.assertEquals(50.0, FastMath.toDegrees(d.getFromLatitude()), 1.0e-14); + Assertions.assertEquals(60.0, FastMath.toDegrees(d.getToLatitude()), 1.0e-14); + Assertions.assertEquals(AbstractDetector.DEFAULT_MAX_ITER, d.getMaxIterationCount()); + + final TimeScale utc = TimeScalesFactory.getUTC(); + final Vector3D position = new Vector3D(-6142438.668, 3492467.56, -25767.257); + final Vector3D velocity = new Vector3D(505.848, 942.781, 7435.922); + final FieldAbsoluteDate date = new FieldAbsoluteDate<>(field, 2003, 9, 16, utc); + final FieldOrbit orbit = new FieldEquinoctialOrbit<>( + new FieldPVCoordinates<>(v(1), new PVCoordinates(position, velocity)), + FramesFactory.getEME2000(), date, + v(Constants.EIGEN5C_EARTH_MU)); + + FieldPropagator propagator = + new FieldEcksteinHechlerPropagator<>(orbit, + Constants.EIGEN5C_EARTH_EQUATORIAL_RADIUS, + v(Constants.EIGEN5C_EARTH_MU), + Constants.EIGEN5C_EARTH_C20, + Constants.EIGEN5C_EARTH_C30, + Constants.EIGEN5C_EARTH_C40, + Constants.EIGEN5C_EARTH_C50, + Constants.EIGEN5C_EARTH_C60); + + FieldEventsLogger logger = new FieldEventsLogger<>(); + propagator.addEventDetector(logger.monitorDetector(d)); + + propagator.propagate(date.shiftedBy(Constants.JULIAN_DAY)); + for (FieldLoggedEvent e : logger.getLoggedEvents()) { + FieldSpacecraftState state = e.getState(); + double latitude = earth.transform(state.getPosition(earth.getBodyFrame()), + earth.getBodyFrame(), date).getLatitude().getReal(); + if (e.isIncreasing()) { + if (state.getPVCoordinates().getVelocity().getZ().getReal() < 0) { + // entering northward + Assertions.assertEquals(60.0, FastMath.toDegrees(latitude), FastMath.toRadians(1e-4)); + } else { + // entering southward + Assertions.assertEquals(50.0, FastMath.toDegrees(latitude), FastMath.toRadians(1e-4)); + } + } else { + if (state.getPVCoordinates().getVelocity().getZ().getReal() < 0) { + // exiting southward + Assertions.assertEquals(50.0, FastMath.toDegrees(latitude), FastMath.toRadians(1e-4)); + } else { + // exiting northward + Assertions.assertEquals(60.0, FastMath.toDegrees(latitude), FastMath.toRadians(1e-4)); + } + } + } + Assertions.assertEquals(30 * 2, logger.getLoggedEvents().size()); + + } + + @Test + public void testNoCrossing() { + + final OneAxisEllipsoid earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS, + Constants.WGS84_EARTH_FLATTENING, + FramesFactory.getITRF(IERSConventions.IERS_2010, true)); + + FieldLatitudeRangeCrossingDetector d = + new FieldLatitudeRangeCrossingDetector<>(v(10.0), v(1.e-6), + earth, FastMath.toRadians(82.0), FastMath.toRadians(87.0)). + withHandler(new FieldContinueOnEvent<>()); + + Assertions.assertEquals(10.0, d.getMaxCheckInterval().currentInterval(null), 1.0e-15); + Assertions.assertEquals(1.0e-6, d.getThreshold().getReal(), 1.0e-15); + Assertions.assertEquals(82.0, FastMath.toDegrees(d.getFromLatitude()), 1.0e-14); + Assertions.assertEquals(87.0, FastMath.toDegrees(d.getToLatitude()), 1.0e-14); + Assertions.assertEquals(AbstractDetector.DEFAULT_MAX_ITER, d.getMaxIterationCount()); + + final TimeScale utc = TimeScalesFactory.getUTC(); + final Vector3D position = new Vector3D(-6142438.668, 3492467.56, -25767.257); + final Vector3D velocity = new Vector3D(505.848, 942.781, 7435.922); + final FieldAbsoluteDate date = new FieldAbsoluteDate<>(field, 2003, 9, 16, utc); + final FieldOrbit orbit = new FieldEquinoctialOrbit<>( + new FieldPVCoordinates<>(v(1), new PVCoordinates(position, velocity)), + FramesFactory.getEME2000(), date, + v(Constants.EIGEN5C_EARTH_MU)); + + FieldPropagator propagator = + new FieldEcksteinHechlerPropagator<>(orbit, + Constants.EIGEN5C_EARTH_EQUATORIAL_RADIUS, + v(Constants.EIGEN5C_EARTH_MU), + Constants.EIGEN5C_EARTH_C20, + Constants.EIGEN5C_EARTH_C30, + Constants.EIGEN5C_EARTH_C40, + Constants.EIGEN5C_EARTH_C50, + Constants.EIGEN5C_EARTH_C60); + + FieldEventsLogger logger = new FieldEventsLogger(); + propagator.addEventDetector(logger.monitorDetector(d)); + + propagator.propagate(date.shiftedBy(Constants.JULIAN_DAY)); + Assertions.assertEquals(0, logger.getLoggedEvents().size()); + + } + + /** + * Convert double to field value. + * + * @param value to box. + * @return boxed value. + */ + private static Binary64 v(double value) { + return new Binary64(value); + } + + @BeforeEach + public void setUp() { + Utils.setDataRoot("regular-data"); + } + +} + diff --git a/src/test/java/org/orekit/propagation/events/FieldLongitudeRangeCrossingDetectorTest.java b/src/test/java/org/orekit/propagation/events/FieldLongitudeRangeCrossingDetectorTest.java new file mode 100644 index 0000000000..ee7fea5556 --- /dev/null +++ b/src/test/java/org/orekit/propagation/events/FieldLongitudeRangeCrossingDetectorTest.java @@ -0,0 +1,179 @@ +/* Copyright 2023-2024 Alberto Ferrero + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Alberto Ferrero licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.propagation.events; + +import static org.orekit.orbits.PositionAngleType.MEAN; + +import org.hipparchus.geometry.euclidean.threed.Vector3D; +import org.hipparchus.util.Binary64; +import org.hipparchus.util.Binary64Field; +import org.hipparchus.util.FastMath; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.orekit.Utils; +import org.orekit.bodies.FieldGeodeticPoint; +import org.orekit.bodies.OneAxisEllipsoid; +import org.orekit.frames.FramesFactory; +import org.orekit.orbits.FieldEquinoctialOrbit; +import org.orekit.orbits.FieldKeplerianOrbit; +import org.orekit.orbits.FieldOrbit; +import org.orekit.propagation.FieldPropagator; +import org.orekit.propagation.FieldSpacecraftState; +import org.orekit.propagation.analytical.FieldEcksteinHechlerPropagator; +import org.orekit.propagation.analytical.FieldKeplerianPropagator; +import org.orekit.propagation.events.handlers.FieldContinueOnEvent; +import org.orekit.time.FieldAbsoluteDate; +import org.orekit.time.TimeScale; +import org.orekit.time.TimeScalesFactory; +import org.orekit.utils.Constants; +import org.orekit.utils.FieldPVCoordinates; +import org.orekit.utils.IERSConventions; +import org.orekit.utils.PVCoordinates; + +/** Unit tests for {@link FieldLongitudeRangeCrossingDetector}. */ +public class FieldLongitudeRangeCrossingDetectorTest { + + /** + * Arbitrary Field. + */ + private static final Binary64Field field = Binary64Field.getInstance(); + + + @Test + public void testRegularCrossing() { + + final OneAxisEllipsoid earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS, + Constants.WGS84_EARTH_FLATTENING, + FramesFactory.getITRF(IERSConventions.IERS_2010, true)); + + FieldLongitudeRangeCrossingDetector d = + new FieldLongitudeRangeCrossingDetector<>(v(60.0), v(1.e-6), earth, + FastMath.toRadians(10.0), + FastMath.toRadians(18.0)). + withHandler(new FieldContinueOnEvent<>()); + + Assertions.assertEquals(60.0, d.getMaxCheckInterval().currentInterval(null), 1.0e-15); + Assertions.assertEquals(1.0e-6, d.getThreshold().getReal(), 1.0e-15); + Assertions.assertEquals(10.0, FastMath.toDegrees(d.getFromLongitude()), 1.0e-14); + Assertions.assertEquals(18.0, FastMath.toDegrees(d.getToLongitude()), 1.0e-14); + Assertions.assertEquals(AbstractDetector.DEFAULT_MAX_ITER, d.getMaxIterationCount()); + Assertions.assertSame(earth, d.getBody()); + + final TimeScale utc = TimeScalesFactory.getUTC(); + final Vector3D position = new Vector3D(-6142438.668, 3492467.56, -25767.257); + final Vector3D velocity = new Vector3D(505.848, 942.781, 7435.922); + final FieldAbsoluteDate date = new FieldAbsoluteDate<>(field, 2003, 9, 16, utc); + final FieldOrbit orbit = new FieldEquinoctialOrbit<>( + new FieldPVCoordinates<>(v(1), new PVCoordinates(position, velocity)), + FramesFactory.getEME2000(), date, + v(Constants.EIGEN5C_EARTH_MU)); + + FieldPropagator propagator = + new FieldEcksteinHechlerPropagator<>(orbit, + Constants.EIGEN5C_EARTH_EQUATORIAL_RADIUS, + v(Constants.EIGEN5C_EARTH_MU), + Constants.EIGEN5C_EARTH_C20, + Constants.EIGEN5C_EARTH_C30, + Constants.EIGEN5C_EARTH_C40, + Constants.EIGEN5C_EARTH_C50, + Constants.EIGEN5C_EARTH_C60); + + FieldEventsLogger logger = new FieldEventsLogger<>(); + propagator.addEventDetector(logger.monitorDetector(d)); + + propagator.propagate(date.shiftedBy(Constants.JULIAN_DAY)); + for (FieldEventsLogger.FieldLoggedEvent e : logger.getLoggedEvents()) { + FieldSpacecraftState state = e.getState(); + double longitude = earth.transform(state.getPVCoordinates(earth.getBodyFrame()).getPosition(), + earth.getBodyFrame(), date).getLongitude().getReal(); + if (e.isIncreasing()) { + // retrograde orbit, enter + Assertions.assertEquals(18.0, FastMath.toDegrees(longitude), 3.5e-7); + } else { + // retrograde orbit, exit + Assertions.assertEquals(10.0, FastMath.toDegrees(longitude), 3.5e-7); + } + Assertions.assertEquals(28, logger.getLoggedEvents().size()); + } + } + + @Test + public void testZigZag() { + + final OneAxisEllipsoid earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS, + Constants.WGS84_EARTH_FLATTENING, + FramesFactory.getITRF(IERSConventions.IERS_2010, true)); + + FieldLongitudeRangeCrossingDetector d = + new FieldLongitudeRangeCrossingDetector<>(v(600.0), v(1.e-6), earth, + FastMath.toRadians(-120.0), + FastMath.toRadians(-100.0)). + withHandler(new FieldContinueOnEvent<>()); + + Assertions.assertEquals(600.0, d.getMaxCheckInterval().currentInterval(null), 1.0e-15); + Assertions.assertEquals(1.0e-6, d.getThreshold().getReal(), 1.0e-15); + Assertions.assertEquals(-120.0, FastMath.toDegrees(d.getFromLongitude()), 1.0e-8); + Assertions.assertEquals(-100.0, FastMath.toDegrees(d.getToLongitude()), 1.0e-8); + Assertions.assertEquals(AbstractDetector.DEFAULT_MAX_ITER, d.getMaxIterationCount()); + + FieldAbsoluteDate date = FieldAbsoluteDate.getJ2000Epoch(field); + final FieldOrbit orbit = + new FieldKeplerianOrbit<>(v(26464560.0), v(0.8311), v(0.122138), v(3.10686), v(1.00681), + v(0.048363), MEAN, + FramesFactory.getEME2000(), + date, + v(Constants.EIGEN5C_EARTH_MU)); + + + FieldPropagator propagator = new FieldKeplerianPropagator<>(orbit); + + FieldEventsLogger logger = new FieldEventsLogger<>(); + propagator.addEventDetector(logger.monitorDetector(d)); + + propagator.propagate(orbit.getDate().shiftedBy(1 * Constants.JULIAN_DAY)); + Assertions.assertEquals(4, logger.getLoggedEvents().size()); + + // eccentric orbit, at apogee Earth rotation makes as reversed effect + double[] expectedLongitude = new double[]{d.getFromLongitude(), d.getToLongitude(), + d.getToLongitude(), d.getFromLongitude()}; + for (int i = 0; i < 4; ++i) { + FieldSpacecraftState state = logger.getLoggedEvents().get(i).getState(); + FieldGeodeticPoint gp = earth.transform(state.getPVCoordinates(earth.getBodyFrame()).getPosition(), + earth.getBodyFrame(), date); + Assertions.assertEquals(expectedLongitude[i], gp.getLongitude().getReal(), 1.2e-9); + } + + } + + /** + * Convert double to field value. + * + * @param value to box. + * @return boxed value. + */ + private static Binary64 v(double value) { + return new Binary64(value); + } + + @BeforeEach + public void setUp() { + Utils.setDataRoot("regular-data"); + } + +} + diff --git a/src/test/java/org/orekit/propagation/events/LatitudeRangeCrossingDetectorTest.java b/src/test/java/org/orekit/propagation/events/LatitudeRangeCrossingDetectorTest.java new file mode 100644 index 0000000000..e9e400b142 --- /dev/null +++ b/src/test/java/org/orekit/propagation/events/LatitudeRangeCrossingDetectorTest.java @@ -0,0 +1,159 @@ +/* Copyright 2023-2024 Alberto Ferrero + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Alberto Ferrero licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.propagation.events; + +import org.hipparchus.geometry.euclidean.threed.Vector3D; +import org.hipparchus.util.FastMath; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.orekit.Utils; +import org.orekit.bodies.OneAxisEllipsoid; +import org.orekit.frames.FramesFactory; +import org.orekit.orbits.EquinoctialOrbit; +import org.orekit.orbits.Orbit; +import org.orekit.propagation.Propagator; +import org.orekit.propagation.SpacecraftState; +import org.orekit.propagation.analytical.EcksteinHechlerPropagator; +import org.orekit.propagation.events.EventsLogger.LoggedEvent; +import org.orekit.propagation.events.handlers.ContinueOnEvent; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.TimeScale; +import org.orekit.time.TimeScalesFactory; +import org.orekit.utils.Constants; +import org.orekit.utils.IERSConventions; +import org.orekit.utils.PVCoordinates; + +public class LatitudeRangeCrossingDetectorTest { + + @Test + public void testRegularCrossing() { + + final OneAxisEllipsoid earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS, + Constants.WGS84_EARTH_FLATTENING, + FramesFactory.getITRF(IERSConventions.IERS_2010, true)); + + LatitudeRangeCrossingDetector d = + new LatitudeRangeCrossingDetector(60.0, 1.e-6, earth, + FastMath.toRadians(50.0), FastMath.toRadians(60.0)). + withHandler(new ContinueOnEvent()); + + Assertions.assertEquals(60.0, d.getMaxCheckInterval().currentInterval(null), 1.0e-15); + Assertions.assertEquals(1.0e-6, d.getThreshold(), 1.0e-15); + Assertions.assertEquals(50.0, FastMath.toDegrees(d.getFromLatitude()), 1.0e-14); + Assertions.assertEquals(60.0, FastMath.toDegrees(d.getToLatitude()), 1.0e-14); + Assertions.assertEquals(AbstractDetector.DEFAULT_MAX_ITER, d.getMaxIterationCount()); + + final TimeScale utc = TimeScalesFactory.getUTC(); + final Vector3D position = new Vector3D(-6142438.668, 3492467.56, -25767.257); + final Vector3D velocity = new Vector3D(505.848, 942.781, 7435.922); + final AbsoluteDate date = new AbsoluteDate(2003, 9, 16, utc); + final Orbit orbit = new EquinoctialOrbit(new PVCoordinates(position, velocity), + FramesFactory.getEME2000(), date, + Constants.EIGEN5C_EARTH_MU); + + Propagator propagator = + new EcksteinHechlerPropagator(orbit, + Constants.EIGEN5C_EARTH_EQUATORIAL_RADIUS, + Constants.EIGEN5C_EARTH_MU, + Constants.EIGEN5C_EARTH_C20, + Constants.EIGEN5C_EARTH_C30, + Constants.EIGEN5C_EARTH_C40, + Constants.EIGEN5C_EARTH_C50, + Constants.EIGEN5C_EARTH_C60); + + EventsLogger logger = new EventsLogger(); + propagator.addEventDetector(logger.monitorDetector(d)); + + propagator.propagate(date.shiftedBy(Constants.JULIAN_DAY)); + for (LoggedEvent e : logger.getLoggedEvents()) { + SpacecraftState state = e.getState(); + double latitude = earth.transform(state.getPVCoordinates(earth.getBodyFrame()).getPosition(), + earth.getBodyFrame(), null).getLatitude(); + if (e.isIncreasing()) { + if (state.getPVCoordinates().getVelocity().getZ() < 0) { + // entering northward + Assertions.assertEquals(60.0, FastMath.toDegrees(latitude), FastMath.toRadians(1e-4)); + } else { + // entering southward + Assertions.assertEquals(50.0, FastMath.toDegrees(latitude), FastMath.toRadians(1e-4)); + } + } else { + if (state.getPVCoordinates().getVelocity().getZ() < 0) { + // exiting southward + Assertions.assertEquals(50.0, FastMath.toDegrees(latitude), FastMath.toRadians(1e-4)); + } else { + // exiting northward + Assertions.assertEquals(60.0, FastMath.toDegrees(latitude), FastMath.toRadians(1e-4)); + } + } + } + Assertions.assertEquals(30 * 2, logger.getLoggedEvents().size()); + + } + + @Test + public void testNoCrossing() { + + final OneAxisEllipsoid earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS, + Constants.WGS84_EARTH_FLATTENING, + FramesFactory.getITRF(IERSConventions.IERS_2010, true)); + + LatitudeRangeCrossingDetector d = + new LatitudeRangeCrossingDetector(10.0, 1.e-6, earth, + FastMath.toRadians(82.0), FastMath.toRadians(87.0)). + withHandler(new ContinueOnEvent()); + + Assertions.assertEquals(10.0, d.getMaxCheckInterval().currentInterval(null), 1.0e-15); + Assertions.assertEquals(1.0e-6, d.getThreshold(), 1.0e-15); + Assertions.assertEquals(82.0, FastMath.toDegrees(d.getFromLatitude()), 1.0e-14); + Assertions.assertEquals(87.0, FastMath.toDegrees(d.getToLatitude()), 1.0e-14); + Assertions.assertEquals(AbstractDetector.DEFAULT_MAX_ITER, d.getMaxIterationCount()); + + final TimeScale utc = TimeScalesFactory.getUTC(); + final Vector3D position = new Vector3D(-6142438.668, 3492467.56, -25767.257); + final Vector3D velocity = new Vector3D(505.848, 942.781, 7435.922); + final AbsoluteDate date = new AbsoluteDate(2003, 9, 16, utc); + final Orbit orbit = new EquinoctialOrbit(new PVCoordinates(position, velocity), + FramesFactory.getEME2000(), date, + Constants.EIGEN5C_EARTH_MU); + + Propagator propagator = + new EcksteinHechlerPropagator(orbit, + Constants.EIGEN5C_EARTH_EQUATORIAL_RADIUS, + Constants.EIGEN5C_EARTH_MU, + Constants.EIGEN5C_EARTH_C20, + Constants.EIGEN5C_EARTH_C30, + Constants.EIGEN5C_EARTH_C40, + Constants.EIGEN5C_EARTH_C50, + Constants.EIGEN5C_EARTH_C60); + + EventsLogger logger = new EventsLogger(); + propagator.addEventDetector(logger.monitorDetector(d)); + + propagator.propagate(date.shiftedBy(Constants.JULIAN_DAY)); + Assertions.assertEquals(0, logger.getLoggedEvents().size()); + + } + + @BeforeEach + public void setUp() { + Utils.setDataRoot("regular-data"); + } + +} + diff --git a/src/test/java/org/orekit/propagation/events/LongitudeRangeCrossingDetectorTest.java b/src/test/java/org/orekit/propagation/events/LongitudeRangeCrossingDetectorTest.java new file mode 100644 index 0000000000..c2d7070cb3 --- /dev/null +++ b/src/test/java/org/orekit/propagation/events/LongitudeRangeCrossingDetectorTest.java @@ -0,0 +1,162 @@ +/* Copyright 2023-2024 Alberto Ferrero + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * Alberto Ferrero licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.propagation.events; + +import static org.orekit.orbits.PositionAngleType.MEAN; + +import java.util.List; +import org.hipparchus.geometry.euclidean.threed.Vector3D; +import org.hipparchus.util.FastMath; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.orekit.Utils; +import org.orekit.bodies.GeodeticPoint; +import org.orekit.bodies.OneAxisEllipsoid; +import org.orekit.frames.FramesFactory; +import org.orekit.orbits.EquinoctialOrbit; +import org.orekit.orbits.KeplerianOrbit; +import org.orekit.orbits.Orbit; +import org.orekit.propagation.Propagator; +import org.orekit.propagation.SpacecraftState; +import org.orekit.propagation.analytical.EcksteinHechlerPropagator; +import org.orekit.propagation.analytical.KeplerianPropagator; +import org.orekit.propagation.events.EventsLogger.LoggedEvent; +import org.orekit.propagation.events.handlers.ContinueOnEvent; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.TimeScale; +import org.orekit.time.TimeScalesFactory; +import org.orekit.utils.Constants; +import org.orekit.utils.IERSConventions; +import org.orekit.utils.PVCoordinates; + +public class LongitudeRangeCrossingDetectorTest { + + @Test + public void testRegularCrossing() { + + final OneAxisEllipsoid earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS, + Constants.WGS84_EARTH_FLATTENING, + FramesFactory.getITRF(IERSConventions.IERS_2010, true)); + + LongitudeRangeCrossingDetector d = + new LongitudeRangeCrossingDetector(earth, + FastMath.toRadians(10.0), + FastMath.toRadians(18.0)). + withMaxCheck(60). + withThreshold(1.e-6). + withHandler(new ContinueOnEvent()); + + Assertions.assertEquals(60.0, d.getMaxCheckInterval().currentInterval(null), 1.0e-15); + Assertions.assertEquals(1.0e-6, d.getThreshold(), 1.0e-15); + Assertions.assertEquals(10.0, FastMath.toDegrees(d.getFromLongitude()), 1.0e-14); + Assertions.assertEquals(18.0, FastMath.toDegrees(d.getToLongitude()), 1.0e-14); + Assertions.assertEquals(AbstractDetector.DEFAULT_MAX_ITER, d.getMaxIterationCount()); + Assertions.assertSame(earth, d.getBody()); + + final TimeScale utc = TimeScalesFactory.getUTC(); + final Vector3D position = new Vector3D(-6142438.668, 3492467.56, -25767.257); + final Vector3D velocity = new Vector3D(505.848, 942.781, 7435.922); + final AbsoluteDate date = new AbsoluteDate(2003, 9, 16, utc); + final Orbit orbit = new EquinoctialOrbit(new PVCoordinates(position, velocity), + FramesFactory.getEME2000(), date, + Constants.EIGEN5C_EARTH_MU); + + Propagator propagator = + new EcksteinHechlerPropagator(orbit, + Constants.EIGEN5C_EARTH_EQUATORIAL_RADIUS, + Constants.EIGEN5C_EARTH_MU, + Constants.EIGEN5C_EARTH_C20, + Constants.EIGEN5C_EARTH_C30, + Constants.EIGEN5C_EARTH_C40, + Constants.EIGEN5C_EARTH_C50, + Constants.EIGEN5C_EARTH_C60); + + EventsLogger logger = new EventsLogger(); + propagator.addEventDetector(logger.monitorDetector(d)); + + propagator.propagate(date.shiftedBy(Constants.JULIAN_DAY)); + for (LoggedEvent e : logger.getLoggedEvents()) { + SpacecraftState state = e.getState(); + double longitude = earth.transform(state.getPVCoordinates(earth.getBodyFrame()).getPosition(), + earth.getBodyFrame(), date).getLongitude(); + if (e.isIncreasing()) { + // retrograde orbit, enter + Assertions.assertEquals(18.0, FastMath.toDegrees(longitude), 3.5e-7); + } else { + // retrograde orbit, exit + Assertions.assertEquals(10.0, FastMath.toDegrees(longitude), 3.5e-7); + } + Assertions.assertEquals(28, logger.getLoggedEvents().size()); + } + } + + @Test + public void testZigZag() { + + final OneAxisEllipsoid earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS, + Constants.WGS84_EARTH_FLATTENING, + FramesFactory.getITRF(IERSConventions.IERS_2010, true)); + + LongitudeRangeCrossingDetector d = + new LongitudeRangeCrossingDetector(600.0, 1.e-6, earth, + FastMath.toRadians(-120.0), + FastMath.toRadians(-100.0)). + withHandler(new ContinueOnEvent()); + + Assertions.assertEquals(600.0, d.getMaxCheckInterval().currentInterval(null), 1.0e-15); + Assertions.assertEquals(1.0e-6, d.getThreshold(), 1.0e-15); + Assertions.assertEquals(-120.0, FastMath.toDegrees(d.getFromLongitude()), 1.0e-8); + Assertions.assertEquals(-100.0, FastMath.toDegrees(d.getToLongitude()), 1.0e-8); + Assertions.assertEquals(AbstractDetector.DEFAULT_MAX_ITER, d.getMaxIterationCount()); + + AbsoluteDate date = AbsoluteDate.J2000_EPOCH; + KeplerianOrbit orbit = + new KeplerianOrbit(26464560.0, 0.8311, 0.122138, 3.10686, 1.00681, + 0.048363, MEAN, + FramesFactory.getEME2000(), + date, + Constants.EIGEN5C_EARTH_MU); + + + Propagator propagator = new KeplerianPropagator(orbit); + + EventsLogger logger = new EventsLogger(); + propagator.addEventDetector(logger.monitorDetector(d)); + + propagator.propagate(orbit.getDate().shiftedBy(1 * Constants.JULIAN_DAY)); + Assertions.assertEquals(4, logger.getLoggedEvents().size()); + + // eccentric orbit, at apogee Earth rotation makes as reversed effect + double[] expectedLongitude = new double[]{d.getFromLongitude(), d.getToLongitude(), + d.getToLongitude(), d.getFromLongitude()}; + for (int i = 0; i < 4; ++i) { + SpacecraftState state = logger.getLoggedEvents().get(i).getState(); + GeodeticPoint gp = earth.transform(state.getPVCoordinates(earth.getBodyFrame()).getPosition(), + earth.getBodyFrame(), date); + Assertions.assertEquals(expectedLongitude[i], gp.getLongitude(), 1.2e-9); + } + + } + + @BeforeEach + public void setUp() { + Utils.setDataRoot("regular-data"); + } + +} + From af6f5b7cac3a5e78d08f16b1d6f908e19f1753bc Mon Sep 17 00:00:00 2001 From: Serrof Date: Thu, 15 Feb 2024 23:13:55 +0100 Subject: [PATCH 125/359] Fixed changelog --- src/changes/changes.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 28fe63a887..1382ec2087 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -212,8 +212,7 @@ Adding {Field}LongitudeCrossingDetector. - - + Added support for CCSDS/SANA geodetic orbital elements. From 0288b93725db2856e6d23f5ba1dba222f27a0b90 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Fri, 16 Feb 2024 17:17:34 +0100 Subject: [PATCH 126/359] Updated test threshold after merging changes from develop. --- .../FieldNiellMappingFunctionModelTest.java | 178 +----------------- 1 file changed, 2 insertions(+), 176 deletions(-) diff --git a/src/test/java/org/orekit/models/earth/troposphere/FieldNiellMappingFunctionModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/FieldNiellMappingFunctionModelTest.java index f9c29fed6c..de53f39df9 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/FieldNiellMappingFunctionModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/FieldNiellMappingFunctionModelTest.java @@ -19,7 +19,7 @@ import org.hipparchus.util.Binary64Field; import org.junit.jupiter.api.Test; -public class FieldNiellMappingFunctionModelTest { +public class FieldNiellMappingFunctionModelTest extends AbstractFieldMappingFunctionTest { protected TroposphereMappingFunction buildMappingFunction() { return new NiellMappingFunctionModel(); @@ -32,181 +32,7 @@ public void testMappingFactors() { @Test public void testMFStateDerivatives() { - doTestMFStateDerivatives(6.506e-12, 1.557e-11); - - // Geodetic point - final double latitude = FastMath.toRadians(45.0); - final double longitude = FastMath.toRadians(45.0); - final double height = 0.0; - final GeodeticPoint point = new GeodeticPoint(latitude, longitude, height); - // Body: earth - final OneAxisEllipsoid earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS, - Constants.WGS84_EARTH_FLATTENING, - FramesFactory.getITRF(IERSConventions.IERS_2010, true)); - // Topocentric frame - final TopocentricFrame baseFrame = new TopocentricFrame(earth, point, "topo"); - - // Station - final GroundStation station = new GroundStation(baseFrame); - - // Mapping Function model - final MappingFunction model = new NiellMappingFunctionModel(); - - // Derivative Structure - final DSFactory factory = new DSFactory(6, 1); - final DerivativeStructure a0 = factory.variable(0, 24464560.0); - final DerivativeStructure e0 = factory.variable(1, 0.05); - final DerivativeStructure i0 = factory.variable(2, 0.122138); - final DerivativeStructure pa0 = factory.variable(3, 3.10686); - final DerivativeStructure raan0 = factory.variable(4, 1.00681); - final DerivativeStructure anomaly0 = factory.variable(5, 0.048363); - final Field field = a0.getField(); - final DerivativeStructure zero = field.getZero(); - - // Field Date - final FieldAbsoluteDate dsDate = new FieldAbsoluteDate<>(field); - // Field Orbit - final Frame frame = FramesFactory.getEME2000(); - final FieldOrbit dsOrbit = new FieldKeplerianOrbit<>(a0, e0, i0, pa0, raan0, anomaly0, - PositionAngleType.MEAN, frame, - dsDate, zero.add(3.9860047e14)); - // Field State - final FieldSpacecraftState dsState = new FieldSpacecraftState<>(dsOrbit); - - // Initial satellite elevation - final FieldVector3D position = dsState.getPosition(); - final DerivativeStructure dsElevation = baseFrame.getTrackingCoordinates(position, frame, dsDate).getElevation(); - - // Compute mapping factors with state derivatives - final FieldGeodeticPoint dsPoint = new FieldGeodeticPoint<>(zero.add(latitude), zero.add(longitude), zero.add(height)); - final DerivativeStructure[] factors = model.mappingFactors(dsElevation, dsPoint, dsDate); - - final double[] compMFH = factors[0].getAllDerivatives(); - final double[] compMFW = factors[1].getAllDerivatives(); - - // Field -> non-field - final Orbit orbit = dsOrbit.toOrbit(); - final SpacecraftState state = dsState.toSpacecraftState(); - - // Finite differences for reference values - final double[][] refMF = new double[2][6]; - final OrbitType orbitType = OrbitType.KEPLERIAN; - final PositionAngleType angleType = PositionAngleType.MEAN; - double dP = 0.001; - double[] steps = NumericalPropagator.tolerances(1000000 * dP, orbit, orbitType)[0]; - for (int i = 0; i < 6; i++) { - SpacecraftState stateM4 = shiftState(state, orbitType, angleType, -4 * steps[i], i); - final Vector3D positionM4 = stateM4.getPosition(); - final double elevationM4 = station.getBaseFrame(). - getTrackingCoordinates(positionM4, stateM4.getFrame(), stateM4.getDate()). - getElevation(); - double[] delayM4 = model.mappingFactors(elevationM4, point, stateM4.getDate()); - - SpacecraftState stateM3 = shiftState(state, orbitType, angleType, -3 * steps[i], i); - final Vector3D positionM3 = stateM3.getPosition(); - final double elevationM3 = station.getBaseFrame(). - getTrackingCoordinates(positionM3, stateM3.getFrame(), stateM3.getDate()). - getElevation(); - double[] delayM3 = model.mappingFactors(elevationM3, point, stateM3.getDate()); - - SpacecraftState stateM2 = shiftState(state, orbitType, angleType, -2 * steps[i], i); - final Vector3D positionM2 = stateM2.getPosition(); - final double elevationM2 = station.getBaseFrame(). - getTrackingCoordinates(positionM2, stateM2.getFrame(), stateM2.getDate()). - getElevation(); - double[] delayM2 = model.mappingFactors(elevationM2, point, stateM2.getDate()); - - SpacecraftState stateM1 = shiftState(state, orbitType, angleType, -1 * steps[i], i); - final Vector3D positionM1 = stateM1.getPosition(); - final double elevationM1 = station.getBaseFrame(). - getTrackingCoordinates(positionM1, stateM1.getFrame(), stateM1.getDate()). - getElevation(); - double[] delayM1 = model.mappingFactors(elevationM1, point, stateM1.getDate()); - - SpacecraftState stateP1 = shiftState(state, orbitType, angleType, 1 * steps[i], i); - final Vector3D positionP1 = stateP1.getPosition(); - final double elevationP1 = station.getBaseFrame(). - getTrackingCoordinates(positionP1, stateP1.getFrame(), stateP1.getDate()). - getElevation(); - double[] delayP1 = model.mappingFactors(elevationP1, point, stateP1.getDate()); - - SpacecraftState stateP2 = shiftState(state, orbitType, angleType, 2 * steps[i], i); - final Vector3D positionP2 = stateP2.getPosition(); - final double elevationP2 = station.getBaseFrame(). - getTrackingCoordinates(positionP2, stateP2.getFrame(), stateP2.getDate()). - getElevation(); - double[] delayP2 = model.mappingFactors(elevationP2, point, stateP2.getDate()); - - SpacecraftState stateP3 = shiftState(state, orbitType, angleType, 3 * steps[i], i); - final Vector3D positionP3 = stateP3.getPosition(); - final double elevationP3 = station.getBaseFrame(). - getTrackingCoordinates(positionP3, stateP3.getFrame(), stateP3.getDate()). - getElevation(); - double[] delayP3 = model.mappingFactors(elevationP3, point, stateP3.getDate()); - - SpacecraftState stateP4 = shiftState(state, orbitType, angleType, 4 * steps[i], i); - final Vector3D positionP4 = stateP4.getPosition(); - final double elevationP4 = station.getBaseFrame(). - getTrackingCoordinates(positionP4, stateP4.getFrame(), stateP4.getDate()). - getElevation(); - double[] delayP4 = model.mappingFactors(elevationP4, point, stateP4.getDate()); - - fillJacobianColumn(refMF, i, orbitType, angleType, steps[i], - delayM4, delayM3, delayM2, delayM1, - delayP1, delayP2, delayP3, delayP4); - } - - // Tolerances - final double epsMFH = 6.539e-12; - final double epsMFW = 1.557e-11; - for (int i = 0; i < 6; i++) { - Assertions.assertEquals(0., FastMath.abs(compMFH[i + 1] - refMF[0][i]), epsMFH); - Assertions.assertEquals(0., FastMath.abs(compMFW[i + 1] - refMF[1][i]), epsMFW); - } - } - - private void fillJacobianColumn(double[][] jacobian, int column, - OrbitType orbitType, PositionAngleType angleType, double h, - double[] sM4h, double[] sM3h, - double[] sM2h, double[] sM1h, - double[] sP1h, double[] sP2h, - double[] sP3h, double[] sP4h) { - for (int i = 0; i < jacobian.length; ++i) { - jacobian[i][column] = ( -3 * (sP4h[i] - sM4h[i]) + - 32 * (sP3h[i] - sM3h[i]) - - 168 * (sP2h[i] - sM2h[i]) + - 672 * (sP1h[i] - sM1h[i])) / (840 * h); - } - } - - private SpacecraftState shiftState(SpacecraftState state, OrbitType orbitType, PositionAngleType angleType, - double delta, int column) { - - double[][] array = stateToArray(state, orbitType, angleType, true); - array[0][column] += delta; - - return arrayToState(array, orbitType, angleType, state.getFrame(), state.getDate(), - state.getMu(), state.getAttitude()); - - } - - private double[][] stateToArray(SpacecraftState state, OrbitType orbitType, PositionAngleType angleType, - boolean withMass) { - double[][] array = new double[2][withMass ? 7 : 6]; - orbitType.mapOrbitToArray(state.getOrbit(), angleType, array[0], array[1]); - if (withMass) { - array[0][6] = state.getMass(); - } - return array; - } - - private SpacecraftState arrayToState(double[][] array, OrbitType orbitType, PositionAngleType angleType, - Frame frame, AbsoluteDate date, double mu, - Attitude attitude) { - Orbit orbit = orbitType.mapArrayToOrbit(array[0], array[1], angleType, date, mu, frame); - return (array.length > 6) ? - new SpacecraftState(orbit, attitude) : - new SpacecraftState(orbit, attitude, array[0][6]); + doTestMFStateDerivatives(6.539e-12, 1.557e-11); } } From 8b98a9114ccb2448060f881510a09bb8cfc11290 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Fri, 16 Feb 2024 17:05:09 +0100 Subject: [PATCH 127/359] Allow direction-dependent phase centers in inter-satellites measurements. Fixes #1325 --- src/changes/changes.xml | 3 + ...rdAntennaInterSatellitesPhaseModifier.java | 74 +++------- ...rdAntennaInterSatellitesRangeModifier.java | 139 +++--------------- ...OnBoardAntennaOneWayGNSSPhaseModifier.java | 96 ++++-------- ...OnBoardAntennaOneWayGNSSRangeModifier.java | 94 ++++-------- ...aseCentersInterSatellitesBaseModifier.java | 108 ++++++++++++++ .../PhaseCentersOneWayGNSSBaseModifier.java | 86 +++++++++++ .../modifiers/PhaseCentersPhaseModifier.java | 11 +- .../modifiers/PhaseCentersRangeModifier.java | 34 +---- 9 files changed, 310 insertions(+), 335 deletions(-) create mode 100644 src/main/java/org/orekit/estimation/measurements/modifiers/PhaseCentersInterSatellitesBaseModifier.java create mode 100644 src/main/java/org/orekit/estimation/measurements/modifiers/PhaseCentersOneWayGNSSBaseModifier.java diff --git a/src/changes/changes.xml b/src/changes/changes.xml index dc4da52b31..983a67ca8e 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -21,6 +21,9 @@ + + Allow direction-dependent phase centers in inter-satellites measurements. + Fixed forbidden SBAS System Time in SP3 files. diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/OnBoardAntennaInterSatellitesPhaseModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/OnBoardAntennaInterSatellitesPhaseModifier.java index 600c9e0696..c88057853a 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/OnBoardAntennaInterSatellitesPhaseModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/OnBoardAntennaInterSatellitesPhaseModifier.java @@ -23,35 +23,35 @@ import org.orekit.estimation.measurements.EstimatedMeasurementBase; import org.orekit.estimation.measurements.EstimationModifier; import org.orekit.estimation.measurements.gnss.InterSatellitesPhase; -import org.orekit.frames.StaticTransform; -import org.orekit.propagation.SpacecraftState; -import org.orekit.time.AbsoluteDate; +import org.orekit.gnss.antenna.FrequencyPattern; import org.orekit.utils.ParameterDriver; -import org.orekit.utils.TimeStampedPVCoordinates; /** On-board antenna offset effect on inter-satellites phase measurements. * @author Bryan Cazabonne * @since 10.3 */ -public class OnBoardAntennaInterSatellitesPhaseModifier implements EstimationModifier { +public class OnBoardAntennaInterSatellitesPhaseModifier + extends PhaseCentersInterSatellitesBaseModifier + implements EstimationModifier { - /** Position of the Antenna Phase Center in satellite 1 frame. */ - private final Vector3D antennaPhaseCenter1; - - /** Position of the Antenna Phase Center in satellite 2 frame. */ - private final Vector3D antennaPhaseCenter2; + /** Simple constructor. + * @param receiverPhaseCenter position of the Antenna Phase Center in receiver satellite frame + * @param emitterPhaseCenter position of the Antenna Phase Center in emitter satellite frame + */ + public OnBoardAntennaInterSatellitesPhaseModifier(final Vector3D receiverPhaseCenter, + final Vector3D emitterPhaseCenter) { + this(new FrequencyPattern(receiverPhaseCenter, null), + new FrequencyPattern(emitterPhaseCenter, null)); + } /** Simple constructor. - * @param antennaPhaseCenter1 position of the Antenna Phase Center in satellite 1 frame - * (i.e. the satellite which receives the signal and performs the measurement) - * @param antennaPhaseCenter2 position of the Antenna Phase Center in satellite 2 frame - * (i.e. the satellite which simply emits the signal in the one-way - * case, or reflects the signal in the two-way case) + * @param receiverPattern pattern for receiver satellite + * @param emitterPattern pattern for emitter satellite + * @since 12.1 */ - public OnBoardAntennaInterSatellitesPhaseModifier(final Vector3D antennaPhaseCenter1, - final Vector3D antennaPhaseCenter2) { - this.antennaPhaseCenter1 = antennaPhaseCenter1; - this.antennaPhaseCenter2 = antennaPhaseCenter2; + public OnBoardAntennaInterSatellitesPhaseModifier(final FrequencyPattern receiverPattern, + final FrequencyPattern emitterPattern) { + super(receiverPattern, emitterPattern); } /** {@inheritDoc} */ @@ -62,39 +62,9 @@ public List getParametersDrivers() { @Override public void modifyWithoutDerivatives(final EstimatedMeasurementBase estimated) { - - // The participants are satellite 2 at emission, satellite 1 at reception - final TimeStampedPVCoordinates[] participants = estimated.getParticipants(); - final AbsoluteDate emissionDate = participants[0].getDate(); - final AbsoluteDate receptionDate = participants[1].getDate(); - - // transforms from spacecraft to inertial frame at emission/reception dates - final SpacecraftState localState = estimated.getStates()[0]; - final SpacecraftState receptionState = localState.shiftedBy(receptionDate.durationFrom(localState.getDate())); - final StaticTransform receptionSpacecraftToInert = receptionState.toStaticTransform().getInverse(); - final SpacecraftState remoteState = estimated.getStates()[1]; - final SpacecraftState emissionState = remoteState.shiftedBy(emissionDate.durationFrom(remoteState.getDate())); - final StaticTransform emissionSpacecraftToInert = emissionState.toStaticTransform().getInverse(); - - // Compute the geometrical value of the inter-satellites range directly from participants positions. - final Vector3D pSpacecraftReception = receptionSpacecraftToInert.transformPosition(Vector3D.ZERO); - final Vector3D pSpacecraftEmission = emissionSpacecraftToInert.transformPosition(Vector3D.ZERO); - final double interSatellitesRangeUsingSpacecraftCenter = Vector3D.distance(pSpacecraftEmission, pSpacecraftReception); - - // Compute the geometrical value of the range replacing - // The spacecraft positions with antenna phase center positions - final Vector3D pAPCReception = receptionSpacecraftToInert.transformPosition(antennaPhaseCenter1); - final Vector3D pAPCEmission = emissionSpacecraftToInert.transformPosition(antennaPhaseCenter2); - final double interSatellitesRangeUsingAntennaPhaseCenter = Vector3D.distance(pAPCEmission, pAPCReception); - - // Get the estimated value before this modifier is applied - final double[] value = estimated.getEstimatedValue(); - - // Modify the phase value by applying measurement wavelength - final double wavelength = estimated.getObservedMeasurement().getWavelength(); - value[0] += (interSatellitesRangeUsingAntennaPhaseCenter - interSatellitesRangeUsingSpacecraftCenter) / wavelength; - estimated.setEstimatedValue(value); - + estimated.setEstimatedValue(estimated.getEstimatedValue()[0] + + oneWayDistanceModification(estimated) / + estimated.getObservedMeasurement().getWavelength()); } } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/OnBoardAntennaInterSatellitesRangeModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/OnBoardAntennaInterSatellitesRangeModifier.java index e39c8c9fae..ce4685b5c6 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/OnBoardAntennaInterSatellitesRangeModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/OnBoardAntennaInterSatellitesRangeModifier.java @@ -23,35 +23,35 @@ import org.orekit.estimation.measurements.EstimatedMeasurementBase; import org.orekit.estimation.measurements.EstimationModifier; import org.orekit.estimation.measurements.InterSatellitesRange; -import org.orekit.frames.StaticTransform; -import org.orekit.propagation.SpacecraftState; -import org.orekit.time.AbsoluteDate; +import org.orekit.gnss.antenna.FrequencyPattern; import org.orekit.utils.ParameterDriver; -import org.orekit.utils.TimeStampedPVCoordinates; /** On-board antenna offset effect on inter-satellites range measurements. * @author Luc Maisonobe * @since 9.0 */ -public class OnBoardAntennaInterSatellitesRangeModifier implements EstimationModifier { +public class OnBoardAntennaInterSatellitesRangeModifier + extends PhaseCentersInterSatellitesBaseModifier + implements EstimationModifier { - /** Position of the Antenna Phase Center in satellite 1 frame. */ - private final Vector3D antennaPhaseCenter1; - - /** Position of the Antenna Phase Center in satellite 2 frame. */ - private final Vector3D antennaPhaseCenter2; + /** Simple constructor. + * @param receiverPhaseCenter position of the Antenna Phase Center in emitter satellite frame + * @param emitterPhaseCenter position of the Antenna Phase Center in receiver satellite frame + */ + public OnBoardAntennaInterSatellitesRangeModifier(final Vector3D receiverPhaseCenter, + final Vector3D emitterPhaseCenter) { + this(new FrequencyPattern(receiverPhaseCenter, null), + new FrequencyPattern(emitterPhaseCenter, null)); + } /** Simple constructor. - * @param antennaPhaseCenter1 position of the Antenna Phase Center in satellite 1 frame - * (i.e. the satellite which receives the signal and performs the measurement) - * @param antennaPhaseCenter2 position of the Antenna Phase Center in satellite 2 frame - * (i.e. the satellite which simply emits the signal in the one-way - * case, or reflects the signal in the two-way case) + * @param receiverPattern pattern for receiver satellite + * @param emitterPattern pattern for emitter satellite + * @since 12.1 */ - public OnBoardAntennaInterSatellitesRangeModifier(final Vector3D antennaPhaseCenter1, - final Vector3D antennaPhaseCenter2) { - this.antennaPhaseCenter1 = antennaPhaseCenter1; - this.antennaPhaseCenter2 = antennaPhaseCenter2; + public OnBoardAntennaInterSatellitesRangeModifier(final FrequencyPattern receiverPattern, + final FrequencyPattern emitterPattern) { + super(receiverPattern, emitterPattern); } /** {@inheritDoc} */ @@ -63,103 +63,10 @@ public List getParametersDrivers() { /** {@inheritDoc} */ @Override public void modifyWithoutDerivatives(final EstimatedMeasurementBase estimated) { - if (estimated.getParticipants().length < 3) { - modifyOneWay(estimated); - } else { - modifyTwoWay(estimated); - } - } - - /** Apply a modifier to an estimated measurement in the one-way case. - * @param estimated estimated measurement to modify - */ - private void modifyOneWay(final EstimatedMeasurementBase estimated) { - - // the participants are satellite 2 at emission, satellite 1 at reception - final TimeStampedPVCoordinates[] participants = estimated.getParticipants(); - final AbsoluteDate emissionDate = participants[0].getDate(); - final AbsoluteDate receptionDate = participants[1].getDate(); - - // transforms from spacecraft to inertial frame at emission/reception dates - final SpacecraftState refState1 = estimated.getStates()[0]; - final SpacecraftState receptionState = refState1.shiftedBy(receptionDate.durationFrom(refState1.getDate())); - final StaticTransform receptionSpacecraftToInert = receptionState.toStaticTransform().getInverse(); - final SpacecraftState refState2 = estimated.getStates()[1]; - final SpacecraftState emissionState = refState2.shiftedBy(emissionDate.durationFrom(refState2.getDate())); - final StaticTransform emissionSpacecraftToInert = emissionState.toStaticTransform().getInverse(); - - // compute the geometrical value of the inter-satellites range directly from participants positions. - // Note that this may be different from the value returned by estimated.getEstimatedValue(), - // because other modifiers may already have been taken into account - final Vector3D pSpacecraftReception = receptionSpacecraftToInert.transformPosition(Vector3D.ZERO); - final Vector3D pSpacecraftEmission = emissionSpacecraftToInert.transformPosition(Vector3D.ZERO); - final double interSatellitesRangeUsingSpacecraftCenter = - Vector3D.distance(pSpacecraftEmission, pSpacecraftReception); - - // compute the geometrical value of the range replacing - // the spacecraft positions with antenna phase center positions - final Vector3D pAPCReception = receptionSpacecraftToInert.transformPosition(antennaPhaseCenter1); - final Vector3D pAPCEmission = emissionSpacecraftToInert.transformPosition(antennaPhaseCenter2); - final double interSatellitesRangeUsingAntennaPhaseCenter = - Vector3D.distance(pAPCEmission, pAPCReception); - - // get the estimated value before this modifier is applied - final double[] value = estimated.getEstimatedValue(); - - // modify the value - value[0] += interSatellitesRangeUsingAntennaPhaseCenter - interSatellitesRangeUsingSpacecraftCenter; - estimated.setEstimatedValue(value); - - } - - /** Apply a modifier to an estimated measurement in the two-way case. - * @param estimated estimated measurement to modify - */ - private void modifyTwoWay(final EstimatedMeasurementBase estimated) { - - // the participants are satellite 1 at emission, satellite 2 at transit, satellite 1 at reception - final TimeStampedPVCoordinates[] participants = estimated.getParticipants(); - final AbsoluteDate emissionDate = participants[0].getDate(); - final AbsoluteDate transitDate = participants[1].getDate(); - final AbsoluteDate receptionDate = participants[2].getDate(); - - // transforms from spacecraft to inertial frame at emission/reception dates - final SpacecraftState refState1 = estimated.getStates()[0]; - final SpacecraftState receptionState = refState1.shiftedBy(receptionDate.durationFrom(refState1.getDate())); - final StaticTransform receptionSpacecraftToInert = receptionState.toStaticTransform().getInverse(); - final SpacecraftState refState2 = estimated.getStates()[1]; - final SpacecraftState transitState = refState2.shiftedBy(transitDate.durationFrom(refState2.getDate())); - final StaticTransform transitSpacecraftToInert = transitState.toStaticTransform().getInverse(); - final SpacecraftState emissionState = refState1.shiftedBy(emissionDate.durationFrom(refState1.getDate())); - final StaticTransform emissionSpacecraftToInert = emissionState.toStaticTransform().getInverse(); - - // compute the geometrical value of the inter-satellites range directly from participants positions. - // Note that this may be different from the value returned by estimated.getEstimatedValue(), - // because other modifiers may already have been taken into account - final Vector3D pSpacecraftReception = receptionSpacecraftToInert.transformPosition(Vector3D.ZERO); - final Vector3D pSpacecraftTransit = transitSpacecraftToInert.transformPosition(Vector3D.ZERO); - final Vector3D pSpacecraftEmission = emissionSpacecraftToInert.transformPosition(Vector3D.ZERO); - final double interSatellitesRangeUsingSpacecraftCenter = - 0.5 * (Vector3D.distance(pSpacecraftEmission, pSpacecraftTransit) + - Vector3D.distance(pSpacecraftTransit, pSpacecraftReception)); - - // compute the geometrical value of the range replacing - // the spacecraft positions with antenna phase center positions - final Vector3D pAPCReception = receptionSpacecraftToInert.transformPosition(antennaPhaseCenter1); - final Vector3D pAPCTransit = transitSpacecraftToInert.transformPosition(antennaPhaseCenter2); - final Vector3D pAPCEmission = emissionSpacecraftToInert.transformPosition(antennaPhaseCenter1); - final double interSatellitesRangeUsingAntennaPhaseCenter = - 0.5 * (Vector3D.distance(pAPCEmission, pAPCTransit) + - Vector3D.distance(pAPCTransit, pAPCReception)); - - - // get the estimated value before this modifier is applied - final double[] value = estimated.getEstimatedValue(); - - // modify the value - value[0] += interSatellitesRangeUsingAntennaPhaseCenter - interSatellitesRangeUsingSpacecraftCenter; - estimated.setEstimatedValue(value); - + final double delta = estimated.getParticipants().length < 3 ? + oneWayDistanceModification(estimated) : + twoWayDistanceModification(estimated); + estimated.setEstimatedValue(estimated.getEstimatedValue()[0] + delta); } } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/OnBoardAntennaOneWayGNSSPhaseModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/OnBoardAntennaOneWayGNSSPhaseModifier.java index b77c2973fd..76b7c41505 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/OnBoardAntennaOneWayGNSSPhaseModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/OnBoardAntennaOneWayGNSSPhaseModifier.java @@ -24,42 +24,42 @@ import org.orekit.estimation.measurements.EstimatedMeasurementBase; import org.orekit.estimation.measurements.EstimationModifier; import org.orekit.estimation.measurements.gnss.OneWayGNSSPhase; -import org.orekit.frames.StaticTransform; -import org.orekit.orbits.CartesianOrbit; -import org.orekit.orbits.Orbit; -import org.orekit.propagation.SpacecraftState; -import org.orekit.time.AbsoluteDate; +import org.orekit.gnss.antenna.FrequencyPattern; import org.orekit.utils.ParameterDriver; -import org.orekit.utils.TimeStampedPVCoordinates; /** On-board antenna offset effect on one-way GNSS phase measurements. * @author Bryan Cazabonne * @since 10.3 */ -public class OnBoardAntennaOneWayGNSSPhaseModifier implements EstimationModifier { - - /** Position of the Antenna Phase Center in satellite 1 frame. */ - private final Vector3D antennaPhaseCenter1; - - /** Position of the Antenna Phase Center in satellite 2 frame. */ - private final Vector3D antennaPhaseCenter2; - - /** Attitude provider of the emitting satellite. */ - private final AttitudeProvider attitude; +public class OnBoardAntennaOneWayGNSSPhaseModifier + extends PhaseCentersOneWayGNSSBaseModifier + implements EstimationModifier { /** Simple constructor. - * @param antennaPhaseCenter1 position of the Antenna Phase Center in satellite 1 frame + * @param receiverPhaseCenter position of the Antenna Phase Center in satellite 1 frame * (i.e. the satellite which receives the signal and performs the measurement) - * @param antennaPhaseCenter2 position of the Antenna Phase Center in satellite 2 frame + * @param emitterPhaseCenter position of the Antenna Phase Center in satellite 2 frame * (i.e. the satellite which simply emits the signal) - * @param attitude attitude provider of the emitting satellite + * @param attitudeProvider attitude provider of the emitting satellite + */ + public OnBoardAntennaOneWayGNSSPhaseModifier(final Vector3D receiverPhaseCenter, + final Vector3D emitterPhaseCenter, + final AttitudeProvider attitudeProvider) { + this(new FrequencyPattern(receiverPhaseCenter, null), + new FrequencyPattern(emitterPhaseCenter, null), + attitudeProvider); + } + + /** Simple constructor. + * @param receiverPattern pattern for receiver satellite + * @param emitterPattern pattern for emitter satellite + * @param attitudeProvider attitude provider of the emitting satellite + * @since 12.1 */ - public OnBoardAntennaOneWayGNSSPhaseModifier(final Vector3D antennaPhaseCenter1, - final Vector3D antennaPhaseCenter2, - final AttitudeProvider attitude) { - this.antennaPhaseCenter1 = antennaPhaseCenter1; - this.antennaPhaseCenter2 = antennaPhaseCenter2; - this.attitude = attitude; + public OnBoardAntennaOneWayGNSSPhaseModifier(final FrequencyPattern receiverPattern, + final FrequencyPattern emitterPattern, + final AttitudeProvider attitudeProvider) { + super(receiverPattern, emitterPattern, attitudeProvider); } /** {@inheritDoc} */ @@ -71,49 +71,9 @@ public List getParametersDrivers() { /** {@inheritDoc} */ @Override public void modifyWithoutDerivatives(final EstimatedMeasurementBase estimated) { - - // The participants are remote satellite at emission, local satellite at reception - final TimeStampedPVCoordinates[] phaseParticipants = estimated.getParticipants(); - final AbsoluteDate phaseEmissionDate = phaseParticipants[0].getDate(); - final AbsoluteDate phaseReceptionDate = phaseParticipants[1].getDate(); - - // Transforms from spacecraft to inertial frame at reception date - final SpacecraftState refStateLocal = estimated.getStates()[0]; - final SpacecraftState receptionState = refStateLocal.shiftedBy(phaseReceptionDate.durationFrom(refStateLocal.getDate())); - final StaticTransform receptionSpacecraftToInert = receptionState.toStaticTransform().getInverse(); - - // Orbit of the remote satellite - final Orbit orbitRemote = new CartesianOrbit(phaseParticipants[0], refStateLocal.getFrame(), receptionState.getMu()); - - // Transforms from spacecraft to inertial frame at emission date - final SpacecraftState refStateRemote = new SpacecraftState(orbitRemote, - attitude.getAttitude(orbitRemote, - orbitRemote.getDate(), - orbitRemote.getFrame())); - final SpacecraftState emissionState = refStateRemote.shiftedBy(phaseEmissionDate.durationFrom(refStateRemote.getDate())); - final StaticTransform emissionSpacecraftToInert = emissionState.toStaticTransform().getInverse(); - - // Compute the geometrical value of the one-way GNSS phase directly from participants positions. - // Note that this may be different from the value returned by estimated.getEstimatedValue(), - // because other modifiers may already have been taken into account - final Vector3D pSpacecraftReception = receptionSpacecraftToInert.transformPosition(Vector3D.ZERO); - final Vector3D pSpacecraftEmission = emissionSpacecraftToInert.transformPosition(Vector3D.ZERO); - final double oneWayGNSSPhaseUsingSpacecraftCenter = Vector3D.distance(pSpacecraftEmission, pSpacecraftReception); - - // Compute the geometrical value of the phase replacing - // the spacecraft positions with antenna phase center positions - final Vector3D pAPCReception = receptionSpacecraftToInert.transformPosition(antennaPhaseCenter1); - final Vector3D pAPCEmission = emissionSpacecraftToInert.transformPosition(antennaPhaseCenter2); - final double oneWayGNSSPhaseUsingAntennaPhaseCenter = Vector3D.distance(pAPCEmission, pAPCReception); - - // Get the estimated value before this modifier is applied - final double[] value = estimated.getEstimatedValue(); - - // Modify the value - final double wavelength = estimated.getObservedMeasurement().getWavelength(); - value[0] += (oneWayGNSSPhaseUsingAntennaPhaseCenter - oneWayGNSSPhaseUsingSpacecraftCenter) / wavelength; - estimated.setEstimatedValue(value); - + estimated.setEstimatedValue(estimated.getEstimatedValue()[0] + + oneWayDistanceModification(estimated) / + estimated.getObservedMeasurement().getWavelength()); } } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/OnBoardAntennaOneWayGNSSRangeModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/OnBoardAntennaOneWayGNSSRangeModifier.java index 8c388af8ea..fbc431a521 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/OnBoardAntennaOneWayGNSSRangeModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/OnBoardAntennaOneWayGNSSRangeModifier.java @@ -24,42 +24,42 @@ import org.orekit.estimation.measurements.EstimatedMeasurementBase; import org.orekit.estimation.measurements.EstimationModifier; import org.orekit.estimation.measurements.gnss.OneWayGNSSRange; -import org.orekit.frames.StaticTransform; -import org.orekit.orbits.CartesianOrbit; -import org.orekit.orbits.Orbit; -import org.orekit.propagation.SpacecraftState; -import org.orekit.time.AbsoluteDate; +import org.orekit.gnss.antenna.FrequencyPattern; import org.orekit.utils.ParameterDriver; -import org.orekit.utils.TimeStampedPVCoordinates; /** On-board antenna offset effect on one-way GNSS range measurements. * @author Bryan Cazabonne * @since 10.3 */ -public class OnBoardAntennaOneWayGNSSRangeModifier implements EstimationModifier { - - /** Position of the Antenna Phase Center in satellite 1 frame. */ - private final Vector3D antennaPhaseCenter1; - - /** Position of the Antenna Phase Center in satellite 2 frame. */ - private final Vector3D antennaPhaseCenter2; - - /** Attitude provider of the emitting satellite. */ - private final AttitudeProvider attitude; +public class OnBoardAntennaOneWayGNSSRangeModifier + extends PhaseCentersOneWayGNSSBaseModifier + implements EstimationModifier { /** Simple constructor. - * @param antennaPhaseCenter1 position of the Antenna Phase Center in satellite 1 frame + * @param receiverPhaseCenter position of the Antenna Phase Center in satellite 1 frame * (i.e. the satellite which receives the signal and performs the measurement) - * @param antennaPhaseCenter2 position of the Antenna Phase Center in satellite 2 frame + * @param emitterPhaseCenter position of the Antenna Phase Center in satellite 2 frame * (i.e. the satellite which simply emits the signal) - * @param attitude attitude provider of the emitting satellite + * @param attitudeProvider attitude provider of the emitting satellite + */ + public OnBoardAntennaOneWayGNSSRangeModifier(final Vector3D receiverPhaseCenter, + final Vector3D emitterPhaseCenter, + final AttitudeProvider attitudeProvider) { + this(new FrequencyPattern(receiverPhaseCenter, null), + new FrequencyPattern(emitterPhaseCenter, null), + attitudeProvider); + } + + /** Simple constructor. + * @param receiverPattern pattern for receiver satellite + * @param emitterPattern pattern for emitter satellite + * @param attitudeProvider attitude provider of the emitting satellite + * @since 12.1 */ - public OnBoardAntennaOneWayGNSSRangeModifier(final Vector3D antennaPhaseCenter1, - final Vector3D antennaPhaseCenter2, - final AttitudeProvider attitude) { - this.antennaPhaseCenter1 = antennaPhaseCenter1; - this.antennaPhaseCenter2 = antennaPhaseCenter2; - this.attitude = attitude; + public OnBoardAntennaOneWayGNSSRangeModifier(final FrequencyPattern receiverPattern, + final FrequencyPattern emitterPattern, + final AttitudeProvider attitudeProvider) { + super(receiverPattern, emitterPattern, attitudeProvider); } /** {@inheritDoc} */ @@ -71,48 +71,8 @@ public List getParametersDrivers() { /** {@inheritDoc} */ @Override public void modifyWithoutDerivatives(final EstimatedMeasurementBase estimated) { - - // The participants are remote satellite at emission, local satellite at reception - final TimeStampedPVCoordinates[] participants = estimated.getParticipants(); - final AbsoluteDate emissionDate = participants[0].getDate(); - final AbsoluteDate receptionDate = participants[1].getDate(); - - // Transforms from spacecraft to inertial frame at reception date - final SpacecraftState refStateLocal = estimated.getStates()[0]; - final SpacecraftState receptionState = refStateLocal.shiftedBy(receptionDate.durationFrom(refStateLocal.getDate())); - final StaticTransform receptionSpacecraftToInert = receptionState.toStaticTransform().getInverse(); - - // Orbit of the remote satellite - final Orbit orbitRemote = new CartesianOrbit(participants[0], refStateLocal.getFrame(), receptionState.getMu()); - - // Transforms from spacecraft to inertial frame at emission date - final SpacecraftState refStateRemote = new SpacecraftState(orbitRemote, - attitude.getAttitude(orbitRemote, - orbitRemote.getDate(), - orbitRemote.getFrame())); - final SpacecraftState emissionState = refStateRemote.shiftedBy(emissionDate.durationFrom(refStateRemote.getDate())); - final StaticTransform emissionSpacecraftToInert = emissionState.toStaticTransform().getInverse(); - - // Compute the geometrical value of the one-way GNSS range directly from participants positions. - // Note that this may be different from the value returned by estimated.getEstimatedValue(), - // because other modifiers may already have been taken into account - final Vector3D pSpacecraftReception = receptionSpacecraftToInert.transformPosition(Vector3D.ZERO); - final Vector3D pSpacecraftEmission = emissionSpacecraftToInert.transformPosition(Vector3D.ZERO); - final double oneWayGNSSRangeUsingSpacecraftCenter = Vector3D.distance(pSpacecraftEmission, pSpacecraftReception); - - // Compute the geometrical value of the range replacing - // the spacecraft positions with antenna phase center positions - final Vector3D pAPCReception = receptionSpacecraftToInert.transformPosition(antennaPhaseCenter1); - final Vector3D pAPCEmission = emissionSpacecraftToInert.transformPosition(antennaPhaseCenter2); - final double oneWayGNSSRangeUsingAntennaPhaseCenter = Vector3D.distance(pAPCEmission, pAPCReception); - - // Get the estimated value before this modifier is applied - final double[] value = estimated.getEstimatedValue(); - - // Modify the value - value[0] += oneWayGNSSRangeUsingAntennaPhaseCenter - oneWayGNSSRangeUsingSpacecraftCenter; - estimated.setEstimatedValue(value); - + estimated.setEstimatedValue(estimated.getEstimatedValue()[0] + + oneWayDistanceModification(estimated)); } } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseCentersInterSatellitesBaseModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseCentersInterSatellitesBaseModifier.java new file mode 100644 index 0000000000..a2bf47aaef --- /dev/null +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseCentersInterSatellitesBaseModifier.java @@ -0,0 +1,108 @@ +/* Copyright 2002-2024 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.estimation.measurements.modifiers; + +import org.orekit.estimation.measurements.AbstractMeasurement; +import org.orekit.estimation.measurements.EstimatedMeasurementBase; +import org.orekit.estimation.measurements.InterSatellitesRange; +import org.orekit.frames.StaticTransform; +import org.orekit.gnss.antenna.FrequencyPattern; +import org.orekit.propagation.SpacecraftState; +import org.orekit.time.AbsoluteDate; +import org.orekit.utils.TimeStampedPVCoordinates; + +/** On-board antenna offset effect on inter-satellites phase measurements. + * @param type of the measurement + * @author Luc Maisonobe + * @since 12.1 + */ +public class PhaseCentersInterSatellitesBaseModifier> { + + /** Uplink offset model. */ + private final PhaseCentersOffsetComputer uplink; + + /** Downlink offset model. */ + private final PhaseCentersOffsetComputer downlink; + + /** Simple constructor. + * @param pattern1 pattern for satellite 1 + * (i.e. the satellite which receives the signal and performs the measurement) + * @param pattern2 pattern for satellite 2 + * (i.e. the satellite which simply emits the signal in the one-way + * case, or reflects the signal in the two-way case) + */ + public PhaseCentersInterSatellitesBaseModifier(final FrequencyPattern pattern1, + final FrequencyPattern pattern2) { + this.uplink = new PhaseCentersOffsetComputer(pattern1, pattern2); + this.downlink = new PhaseCentersOffsetComputer(pattern2, pattern1); + } + + /** Compute distance modification for one way measurement. + * @param estimated estimated measurement to modify + * @return distance modification to add to raw measurement + */ + public double oneWayDistanceModification(final EstimatedMeasurementBase estimated) { + + // The participants are satellite 2 at emission, satellite 1 at reception + final TimeStampedPVCoordinates[] participants = estimated.getParticipants(); + final AbsoluteDate emissionDate = participants[0].getDate(); + final AbsoluteDate receptionDate = participants[1].getDate(); + + // transforms from spacecraft to inertial frame at emission/reception dates + final SpacecraftState localState = estimated.getStates()[0]; + final SpacecraftState receptionState = localState.shiftedBy(receptionDate.durationFrom(localState.getDate())); + final StaticTransform receptionSpacecraftToInert = receptionState.toStaticTransform().getInverse(); + final SpacecraftState remoteState = estimated.getStates()[1]; + final SpacecraftState emissionState = remoteState.shiftedBy(emissionDate.durationFrom(remoteState.getDate())); + final StaticTransform emissionSpacecraftToInert = emissionState.toStaticTransform().getInverse(); + + // compute offset due to phase centers + return downlink.offset(emissionSpacecraftToInert, receptionSpacecraftToInert); + + } + + /** Compute distance modification for two way measurement. + * @param estimated estimated measurement to modify + * @return distance modification to add to raw measurement + */ + public double twoWayDistanceModification(final EstimatedMeasurementBase estimated) { + + // the participants are satellite 1 at emission, satellite 2 at transit, satellite 1 at reception + final TimeStampedPVCoordinates[] participants = estimated.getParticipants(); + final AbsoluteDate emissionDate = participants[0].getDate(); + final AbsoluteDate transitDate = participants[1].getDate(); + final AbsoluteDate receptionDate = participants[2].getDate(); + + // transforms from spacecraft to inertial frame at emission/reception dates + final SpacecraftState refState1 = estimated.getStates()[0]; + final SpacecraftState receptionState = refState1.shiftedBy(receptionDate.durationFrom(refState1.getDate())); + final StaticTransform receptionSpacecraftToInert = receptionState.toStaticTransform().getInverse(); + final SpacecraftState refState2 = estimated.getStates()[1]; + final SpacecraftState transitState = refState2.shiftedBy(transitDate.durationFrom(refState2.getDate())); + final StaticTransform transitSpacecraftToInert = transitState.toStaticTransform().getInverse(); + final SpacecraftState emissionState = refState1.shiftedBy(emissionDate.durationFrom(refState1.getDate())); + final StaticTransform emissionSpacecraftToInert = emissionState.toStaticTransform().getInverse(); + + // compute offsets due to phase centers + final double uplinkOffset = uplink.offset(emissionSpacecraftToInert, transitSpacecraftToInert); + final double downlinkOffset = downlink.offset(transitSpacecraftToInert, receptionSpacecraftToInert); + + return 0.5 * (uplinkOffset + downlinkOffset); + + } + +} diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseCentersOneWayGNSSBaseModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseCentersOneWayGNSSBaseModifier.java new file mode 100644 index 0000000000..4fac240068 --- /dev/null +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseCentersOneWayGNSSBaseModifier.java @@ -0,0 +1,86 @@ +/* Copyright 2002-2024 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.estimation.measurements.modifiers; + +import org.orekit.attitudes.AttitudeProvider; +import org.orekit.estimation.measurements.AbstractMeasurement; +import org.orekit.estimation.measurements.EstimatedMeasurementBase; +import org.orekit.frames.StaticTransform; +import org.orekit.gnss.antenna.FrequencyPattern; +import org.orekit.orbits.CartesianOrbit; +import org.orekit.orbits.Orbit; +import org.orekit.propagation.SpacecraftState; +import org.orekit.time.AbsoluteDate; +import org.orekit.utils.TimeStampedPVCoordinates; + +/** On-board antenna offset effect on inter-satellites phase measurements. + * @param type of the measurement + * @author Luc Maisonobe + * @since 12.1 + */ +public class PhaseCentersOneWayGNSSBaseModifier> { + + /** Link offset model. */ + private final PhaseCentersOffsetComputer link; + + /** Attitude provider of the emitting satellite. */ + private final AttitudeProvider attitudeProvider; + + /** Simple constructor. + * @param receiverPattern pattern for receiver satellite + * @param emitterPattern pattern for emitter satellite + * @param attitudeProvider attitude provider of the emitting satellite + */ + public PhaseCentersOneWayGNSSBaseModifier(final FrequencyPattern receiverPattern, + final FrequencyPattern emitterPattern, + final AttitudeProvider attitudeProvider) { + this.link = new PhaseCentersOffsetComputer(emitterPattern, receiverPattern); + this.attitudeProvider = attitudeProvider; + } + + /** Compute distance modification for one way measurement. + * @param estimated estimated measurement to modify + * @return distance modification to add to raw measurement + */ + public double oneWayDistanceModification(final EstimatedMeasurementBase estimated) { + + // The participants are remote satellite at emission, local satellite at reception + final TimeStampedPVCoordinates[] phaseParticipants = estimated.getParticipants(); + final AbsoluteDate phaseEmissionDate = phaseParticipants[0].getDate(); + final AbsoluteDate phaseReceptionDate = phaseParticipants[1].getDate(); + + // Transforms from spacecraft to inertial frame at reception date + final SpacecraftState refStateLocal = estimated.getStates()[0]; + final SpacecraftState receptionState = refStateLocal.shiftedBy(phaseReceptionDate.durationFrom(refStateLocal.getDate())); + final StaticTransform receptionSpacecraftToInert = receptionState.toStaticTransform().getInverse(); + + // Orbit of the remote satellite + final Orbit orbitRemote = new CartesianOrbit(phaseParticipants[0], refStateLocal.getFrame(), receptionState.getMu()); + + // Transforms from spacecraft to inertial frame at emission date + final SpacecraftState refStateRemote = new SpacecraftState(orbitRemote, + attitudeProvider.getAttitude(orbitRemote, + orbitRemote.getDate(), + orbitRemote.getFrame())); + final SpacecraftState emissionState = refStateRemote.shiftedBy(phaseEmissionDate.durationFrom(refStateRemote.getDate())); + final StaticTransform emissionSpacecraftToInert = emissionState.toStaticTransform().getInverse(); + + // compute offset due to phase centers + return link.offset(emissionSpacecraftToInert, receptionSpacecraftToInert); + } + +} diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseCentersPhaseModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseCentersPhaseModifier.java index b43577fa3c..93ba00462e 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseCentersPhaseModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseCentersPhaseModifier.java @@ -29,10 +29,9 @@ * @author Luc Maisonobe * @since 12.0 */ -public class PhaseCentersPhaseModifier implements EstimationModifier { - - /** Raw modifier. */ - private final PhaseCentersGroundReceiverBaseModifier modifier; +public class PhaseCentersPhaseModifier + extends PhaseCentersGroundReceiverBaseModifier + implements EstimationModifier { /** Simple constructor. * @param stationPattern station pattern @@ -40,7 +39,7 @@ public class PhaseCentersPhaseModifier implements EstimationModifier { */ public PhaseCentersPhaseModifier(final FrequencyPattern stationPattern, final FrequencyPattern satellitePattern) { - this.modifier = new PhaseCentersGroundReceiverBaseModifier<>(stationPattern, satellitePattern); + super(stationPattern, satellitePattern); } /** {@inheritDoc} */ @@ -53,7 +52,7 @@ public List getParametersDrivers() { @Override public void modifyWithoutDerivatives(final EstimatedMeasurementBase estimated) { estimated.setEstimatedValue(estimated.getEstimatedValue()[0] + - modifier.oneWayDistanceModification(estimated) / + oneWayDistanceModification(estimated) / estimated.getObservedMeasurement().getWavelength()); } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseCentersRangeModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseCentersRangeModifier.java index 29b5d71ddd..5f9240fc76 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseCentersRangeModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseCentersRangeModifier.java @@ -29,10 +29,9 @@ * @author Luc Maisonobe * @since 12.0 */ -public class PhaseCentersRangeModifier implements EstimationModifier { - - /** Raw modifier. */ - private final PhaseCentersGroundReceiverBaseModifier modifier; +public class PhaseCentersRangeModifier + extends PhaseCentersGroundReceiverBaseModifier + implements EstimationModifier { /** Simple constructor. * @param stationPattern station pattern @@ -40,7 +39,7 @@ public class PhaseCentersRangeModifier implements EstimationModifier { */ public PhaseCentersRangeModifier(final FrequencyPattern stationPattern, final FrequencyPattern satellitePattern) { - this.modifier = new PhaseCentersGroundReceiverBaseModifier<>(stationPattern, satellitePattern); + super(stationPattern, satellitePattern); } /** {@inheritDoc} */ @@ -52,27 +51,10 @@ public List getParametersDrivers() { /** {@inheritDoc} */ @Override public void modifyWithoutDerivatives(final EstimatedMeasurementBase estimated) { - if (estimated.getObservedMeasurement().isTwoWay()) { - modifyTwoWay(estimated); - } else { - modifyOneWay(estimated); - } - } - - /** Apply a modifier to a one-way range measurement. - * @param estimated estimated measurement to modify - */ - private void modifyOneWay(final EstimatedMeasurementBase estimated) { - estimated.setEstimatedValue(estimated.getEstimatedValue()[0] + - modifier.oneWayDistanceModification(estimated)); - } - - /** Apply a modifier to a two-way range measurement. - * @param estimated estimated measurement to modify - */ - private void modifyTwoWay(final EstimatedMeasurementBase estimated) { - estimated.setEstimatedValue(estimated.getEstimatedValue()[0] + - modifier.twoWayDistanceModification(estimated)); + final double delta = estimated.getObservedMeasurement().isTwoWay() ? + twoWayDistanceModification(estimated) : + oneWayDistanceModification(estimated); + estimated.setEstimatedValue(estimated.getEstimatedValue()[0] + delta); } } From 3d7d721742810a5f95a9dd79a0832dddf454266b Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Tue, 20 Feb 2024 16:45:54 +0100 Subject: [PATCH 128/359] Fixed javadoc errors. --- .../troposphere/CanonicalSaastamoinenModel.java | 8 ++++---- .../models/earth/troposphere/MariniMurray.java | 5 +++-- .../earth/troposphere/MariniMurrayModel.java | 13 ++----------- .../earth/troposphere/MendesPavlisModel.java | 14 ++++++++------ .../earth/troposphere/ModifiedHopfieldModel.java | 2 -- .../troposphere/ModifiedSaastamoinenModel.java | 10 +++++----- .../troposphere/RevisedChaoMappingFunction.java | 8 +++++--- .../earth/troposphere/TimeSpanEstimatedModel.java | 8 ++++---- .../TroposphereMappingFunctionAdapter.java | 2 +- .../troposphere/TroposphericModelAdapter.java | 2 +- .../earth/weather/GlobalPressureTemperature.java | 2 +- 11 files changed, 34 insertions(+), 40 deletions(-) diff --git a/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java b/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java index b5bbcc445f..f8cac97acb 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/CanonicalSaastamoinenModel.java @@ -198,8 +198,8 @@ public List getParametersDrivers() { /** Get the low elevation threshold value for path delay computation. * @return low elevation threshold, in rad. - * @see #pathDelay(double, GeodeticPoint, double[], AbsoluteDate) - * @see #pathDelay(CalculusFieldElement, FieldGeodeticPoint, CalculusFieldElement[], FieldAbsoluteDate) + * @see #pathDelay(TrackingCoordinates, GeodeticPoint, PressureTemperatureHumidity, double[], AbsoluteDate) + * @see #pathDelay(FieldTrackingCoordinates, FieldGeodeticPoint, FieldPressureTemperatureHumidity, CalculusFieldElement[], FieldAbsoluteDate) */ public double getLowElevationThreshold() { return lowElevationThreshold; @@ -207,8 +207,8 @@ public double getLowElevationThreshold() { /** Set the low elevation threshold value for path delay computation. * @param lowElevationThreshold The new value for the threshold [rad] - * @see #pathDelay(double, GeodeticPoint, double[], AbsoluteDate) - * @see #pathDelay(CalculusFieldElement, FieldGeodeticPoint, CalculusFieldElement[], FieldAbsoluteDate) + * @see #pathDelay(TrackingCoordinates, GeodeticPoint, PressureTemperatureHumidity, double[], AbsoluteDate) + * @see #pathDelay(FieldTrackingCoordinates, FieldGeodeticPoint, FieldPressureTemperatureHumidity, CalculusFieldElement[], FieldAbsoluteDate) */ public void setLowElevationThreshold(final double lowElevationThreshold) { this.lowElevationThreshold = lowElevationThreshold; diff --git a/src/main/java/org/orekit/models/earth/troposphere/MariniMurray.java b/src/main/java/org/orekit/models/earth/troposphere/MariniMurray.java index ce08784364..db4f401d97 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/MariniMurray.java +++ b/src/main/java/org/orekit/models/earth/troposphere/MariniMurray.java @@ -45,12 +45,13 @@ public class MariniMurray implements TroposphericModel { /** Laser frequency parameter. */ - private double fLambda; + private final double fLambda; /** Create a new Marini-Murray model for the troposphere. * @param lambda laser wavelength * @param lambdaUnits units in which {@code lambda} is given - * @see TropoUnit + * @see TroposphericModelUtils#MICRO_M + * @see TroposphericModelUtils#NANO_M * @since 12.1 * */ public MariniMurray(final double lambda, final Unit lambdaUnits) { diff --git a/src/main/java/org/orekit/models/earth/troposphere/MariniMurrayModel.java b/src/main/java/org/orekit/models/earth/troposphere/MariniMurrayModel.java index afd1e616d5..c6f41ad04e 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/MariniMurrayModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/MariniMurrayModel.java @@ -26,7 +26,6 @@ import org.orekit.time.FieldAbsoluteDate; import org.orekit.utils.FieldTrackingCoordinates; import org.orekit.utils.TrackingCoordinates; -import org.orekit.utils.units.Unit; /** The Marini-Murray tropospheric delay model for laser ranging. * @@ -39,12 +38,8 @@ @Deprecated public class MariniMurrayModel extends MariniMurray implements DiscreteTroposphericModel { - /** Constant pressure, temperature and humidity. - * @deprecated as of 12.1 provided when calling {@link #pathDelay(TrackingCoordinates, - * GeodeticPoint, PressureTemperatureHumidity, double[], AbsoluteDate)} - */ - @Deprecated - private PressureTemperatureHumidity pth; + /** Constant pressure, temperature and humidity. */ + private final PressureTemperatureHumidity pth; /** Create a new Marini-Murray model for the troposphere using the given * environmental conditions. @@ -77,9 +72,7 @@ public MariniMurrayModel(final double t0, final double p0, final double rh, fina * @param lambda laser wavelength (c/f), nm * * @return a Marini-Murray model with standard environmental values - * @deprecated since 12.1, replaced by {@link #getStandardModel(double, Unit)} */ - @Deprecated public static MariniMurrayModel getStandardModel(final double lambda) { final double p = TroposphericModelUtils.HECTO_PASCAL.toSI(1013.25); final double t = 273.15 + 20; @@ -89,7 +82,6 @@ public static MariniMurrayModel getStandardModel(final double lambda) { /** {@inheritDoc} */ @Override - @Deprecated public double pathDelay(final double elevation, final GeodeticPoint point, final double[] parameters, final AbsoluteDate date) { return pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), point, @@ -99,7 +91,6 @@ public double pathDelay(final double elevation, final GeodeticPoint point, /** {@inheritDoc} */ @Override - @Deprecated public > T pathDelay(final T elevation, final FieldGeodeticPoint point, final T[] parameters, diff --git a/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java b/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java index e6fedc78a1..1131516808 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/MendesPavlisModel.java @@ -74,13 +74,13 @@ public class MendesPavlisModel private static final double C02 = 0.99995995; /** Dispersion equation for the hydrostatic component. */ - private double fLambdaH; + private final double fLambdaH; /** Dispersion equation for the non-hydrostatic component. */ - private double fLambdaNH; + private final double fLambdaNH; /** Provider for pressure, temperature and humidity. */ - private PressureTemperatureHumidityProvider pthProvider; + private final PressureTemperatureHumidityProvider pthProvider; /** Create a new Mendes-Pavlis model for the troposphere. * This initialization will compute the water vapor pressure @@ -89,7 +89,7 @@ public class MendesPavlisModel * @param p0 the atmospheric pressure at the station, hPa * @param rh the humidity at the station, as a ratio (50% → 0.5) * @param lambda laser wavelength, µm - * @deprecated as of 12.1, replaced by {@link #MendesPavlisModel(PressureTemperatureHumidity, double, Unit)} + * @deprecated as of 12.1, replaced by {@link #MendesPavlisModel(PressureTemperatureHumidityProvider, double, Unit)} */ @Deprecated public MendesPavlisModel(final double t0, final double p0, @@ -109,7 +109,8 @@ public MendesPavlisModel(final double t0, final double p0, * @param pthProvider provider for atmospheric pressure, temperature and humidity at the station * @param lambda laser wavelength * @param lambdaUnits units in which {@code lambda} is given - * @see TropoUnit + * @see TroposphericModelUtils#MICRO_M + * @see TroposphericModelUtils#NANO_M * @since 12.1 * */ public MendesPavlisModel(final PressureTemperatureHumidityProvider pthProvider, @@ -169,7 +170,8 @@ public static MendesPavlisModel getStandardModel(final double lambda) { * @param lambda laser wavelength, µm * @param lambdaUnits units in which {@code lambda} is given * @return a Mendes-Pavlis model with standard environmental values - * @see TropoUnit + * @see TroposphericModelUtils#MICRO_M + * @see TroposphericModelUtils#NANO_M * @since 12.1 */ public static MendesPavlisModel getStandardModel(final double lambda, final Unit lambdaUnits) { diff --git a/src/main/java/org/orekit/models/earth/troposphere/ModifiedHopfieldModel.java b/src/main/java/org/orekit/models/earth/troposphere/ModifiedHopfieldModel.java index f0b072534d..306e199f6d 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/ModifiedHopfieldModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/ModifiedHopfieldModel.java @@ -112,8 +112,6 @@ public TroposphericDelay pathDelay(final TrackingCoordinates trackingCoordinates * elevations lower than a threshold will use the value obtained * for the threshold itself. *

                - * @see #getLowElevationThreshold() - * @see #setLowElevationThreshold(double) */ @Override public > FieldTroposphericDelay pathDelay(final FieldTrackingCoordinates trackingCoordinates, diff --git a/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java b/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java index 5971280d6c..64f5139a56 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/ModifiedSaastamoinenModel.java @@ -118,7 +118,7 @@ public class ModifiedSaastamoinenModel implements TroposphericModel { private final PressureTemperatureHumidityProvider pth0Provider; /** Height dependent converter for pressure, temperature and humidity. */ - private HeightDependentPressureTemperatureHumidityConverter converter; + private final HeightDependentPressureTemperatureHumidityConverter converter; /** Lowest acceptable elevation angle [rad]. */ private double lowElevationThreshold; @@ -434,8 +434,8 @@ public List getParametersDrivers() { /** Get the low elevation threshold value for path delay computation. * @return low elevation threshold, in rad. - * @see #pathDelay(double, GeodeticPoint, double[], AbsoluteDate) - * @see #pathDelay(CalculusFieldElement, FieldGeodeticPoint, CalculusFieldElement[], FieldAbsoluteDate) + * @see #pathDelay(TrackingCoordinates, GeodeticPoint, PressureTemperatureHumidity, double[], AbsoluteDate) + * @see #pathDelay(FieldTrackingCoordinates, FieldGeodeticPoint, FieldPressureTemperatureHumidity, CalculusFieldElement[], FieldAbsoluteDate) * @since 10.2 */ public double getLowElevationThreshold() { @@ -444,8 +444,8 @@ public double getLowElevationThreshold() { /** Set the low elevation threshold value for path delay computation. * @param lowElevationThreshold The new value for the threshold [rad] - * @see #pathDelay(double, GeodeticPoint, double[], AbsoluteDate) - * @see #pathDelay(CalculusFieldElement, FieldGeodeticPoint, CalculusFieldElement[], FieldAbsoluteDate) + * @see #pathDelay(TrackingCoordinates, GeodeticPoint, PressureTemperatureHumidity, double[], AbsoluteDate) + * @see #pathDelay(FieldTrackingCoordinates, FieldGeodeticPoint, FieldPressureTemperatureHumidity, CalculusFieldElement[], FieldAbsoluteDate) * @since 10.2 */ public void setLowElevationThreshold(final double lowElevationThreshold) { diff --git a/src/main/java/org/orekit/models/earth/troposphere/RevisedChaoMappingFunction.java b/src/main/java/org/orekit/models/earth/troposphere/RevisedChaoMappingFunction.java index 5333fe015f..1f9c7c25b1 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/RevisedChaoMappingFunction.java +++ b/src/main/java/org/orekit/models/earth/troposphere/RevisedChaoMappingFunction.java @@ -17,9 +17,11 @@ package org.orekit.models.earth.troposphere; /** Chao mapping function for radio wavelengths. - * - * @see "J. A. Estefan, O. J. Sovers, A Comparative Survey of Current and Proposed Tropospheric - * Refraction-Delay Models for DSN Radio Metric Data Calibration", 1994 + *

                + * The mapping function is described in A. Estefan, O. J. Sovers 1994 paper + * "A Comparative Survey of Current and Proposed Tropospheric Refraction-Delay + * Models for DSN Radio Metric Data Calibration" + *

                * @author Luc Maisonobe * @since 12.1 */ diff --git a/src/main/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModel.java b/src/main/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModel.java index 4eded1dcb3..38748d8d5a 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModel.java +++ b/src/main/java/org/orekit/models/earth/troposphere/TimeSpanEstimatedModel.java @@ -136,7 +136,7 @@ public void addTroposphericModelValidAfter(final EstimatedModel model, final Abs earliestValidityDate, false); } - /** Get the {@link EstimatedTroposphericModel} model valid at a date. + /** Get the {@link EstimatedModel} model valid at a date. * @param date the date of validity * @return the EstimatedTroposphericModel model valid at date */ @@ -153,7 +153,7 @@ public Span getFirstSpan() { } /** Extract the proper parameter drivers' values from the array in input of the - * {@link #pathDelay(double, GeodeticPoint, double[], AbsoluteDate) pathDelay} method. + * {@link #pathDelay(TrackingCoordinates, GeodeticPoint, PressureTemperatureHumidity, double[], AbsoluteDate) pathDelay} method. * Parameters are filtered given an input date. * @param parameters the input parameters array * @param date the date @@ -180,7 +180,7 @@ public double[] extractParameters(final double[] parameters, final AbsoluteDate } /** Extract the proper parameter drivers' values from the array in input of the - * {@link #pathDelay(double, GeodeticPoint, double[], AbsoluteDate) pathDelay} method. + * {@link #pathDelay(TrackingCoordinates, GeodeticPoint, PressureTemperatureHumidity, double[], AbsoluteDate) pathDelay} method. * Parameters are filtered given an input date. * @param parameters the input parameters array * @param date the date @@ -248,7 +248,7 @@ private boolean findByName(final List driversList, final String return false; } - /** Change the parameter drivers names of a {@link EstimatedTroposphericModel} model, if needed. + /** Change the parameter drivers names of a {@link EstimatedModel} model, if needed. *

                * This is done to avoid that several parameter drivers have the same name.
                * It is done only if the user hasn't modify the EstimatedTroposphericModel parameter drivers default names. diff --git a/src/main/java/org/orekit/models/earth/troposphere/TroposphereMappingFunctionAdapter.java b/src/main/java/org/orekit/models/earth/troposphere/TroposphereMappingFunctionAdapter.java index d35d978db6..adff2a7188 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/TroposphereMappingFunctionAdapter.java +++ b/src/main/java/org/orekit/models/earth/troposphere/TroposphereMappingFunctionAdapter.java @@ -30,7 +30,7 @@ *

                * This class is a temporary adapter, it will be removed when * {@link MappingFunction} is removed. - *

                + *

                * @author Luc Maisonobe * @since 12.1 * @deprecated temporary adapter to be removed when {@link MappingFunction} is removed diff --git a/src/main/java/org/orekit/models/earth/troposphere/TroposphericModelAdapter.java b/src/main/java/org/orekit/models/earth/troposphere/TroposphericModelAdapter.java index 77e98239e1..7ad22cfa5c 100644 --- a/src/main/java/org/orekit/models/earth/troposphere/TroposphericModelAdapter.java +++ b/src/main/java/org/orekit/models/earth/troposphere/TroposphericModelAdapter.java @@ -34,7 +34,7 @@ *

                * This class is a temporary adapter, it will be removed when * {@link DiscreteTroposphericModel} is removed. - *

                + *

                * @author Luc Maisonobe * @since 12.1 * @deprecated temporary adapter to be removed when {@link DiscreteTroposphericModel} is removed diff --git a/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature.java b/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature.java index f722a81b7a..dc57c6a4a4 100644 --- a/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature.java +++ b/src/main/java/org/orekit/models/earth/weather/GlobalPressureTemperature.java @@ -68,7 +68,7 @@ public class GlobalPressureTemperature { *

                This method uses the {@link DataContext#getDefault() default data context}. * * @param geoid level surface of the gravity potential of a body - * @see #GlobalPressureTemperatureModel(Geoid, DataContext) + * @see #GlobalPressureTemperature(Geoid, TimeScale) */ @DefaultDataContext public GlobalPressureTemperature(final Geoid geoid) { From 8c19061394d3a7fb4eb4ef79e9d77bb67194e4f7 Mon Sep 17 00:00:00 2001 From: Mark Rutten Date: Wed, 21 Feb 2024 21:42:48 +1030 Subject: [PATCH 129/359] Modify parsing ligic. --- .../java/org/orekit/files/sp3/SP3Writer.java | 22 +- .../org/orekit/files/sp3/SP3WriterTest.java | 5 + src/test/resources/sp3/issue1327-136-sats.sp3 | 577 ++++++++++++++++++ 3 files changed, 592 insertions(+), 12 deletions(-) create mode 100644 src/test/resources/sp3/issue1327-136-sats.sp3 diff --git a/src/main/java/org/orekit/files/sp3/SP3Writer.java b/src/main/java/org/orekit/files/sp3/SP3Writer.java index 10a5442868..b560a50f11 100644 --- a/src/main/java/org/orekit/files/sp3/SP3Writer.java +++ b/src/main/java/org/orekit/files/sp3/SP3Writer.java @@ -332,15 +332,14 @@ private void writeHeader(final SP3Header header) output.append(String.format(Locale.US, "%3s", satId)); --remaining; column += 3; - if (column >= 60) { + if (column >= 60 && remaining > 0) { // finish line output.append(EOL); ++lines; - if (remaining > 0) { - // start new line - output.append("+ "); - column = 9; - } + + // start new line + output.append("+ "); + column = 9; } } while (column < 60) { @@ -368,15 +367,14 @@ private void writeHeader(final SP3Header header) output.append(String.format(Locale.US, THREE_DIGITS_INTEGER, accuracyExp)); --remaining; column += 3; - if (column >= 60) { + if (column >= 60 && remaining > 0) { // finish line output.append(EOL); ++lines; - if (remaining > 0) { - // start new line - output.append(ACCURACY_LINE_PREFIX); - column = 9; - } + + // start new line + output.append(ACCURACY_LINE_PREFIX); + column = 9; } } while (column < 60) { diff --git a/src/test/java/org/orekit/files/sp3/SP3WriterTest.java b/src/test/java/org/orekit/files/sp3/SP3WriterTest.java index 90fc7dd49b..02d2558782 100644 --- a/src/test/java/org/orekit/files/sp3/SP3WriterTest.java +++ b/src/test/java/org/orekit/files/sp3/SP3WriterTest.java @@ -136,6 +136,11 @@ public void testRoundtripLageos() { doTestRoundtrip("/sp3/truncated-nsgf.orb.lageos2.160305.v35.sp3"); } + @Test + public void testRoundtripIssue1327FullLine() { + doTestRoundtrip("/sp3/issue1327-136-sats.sp3"); + } + private void doTestRoundtrip(final String name) { try { DataSource source1 = new DataSource(name, () -> getClass().getResourceAsStream(name)); diff --git a/src/test/resources/sp3/issue1327-136-sats.sp3 b/src/test/resources/sp3/issue1327-136-sats.sp3 new file mode 100644 index 0000000000..c189857a37 --- /dev/null +++ b/src/test/resources/sp3/issue1327-136-sats.sp3 @@ -0,0 +1,577 @@ +#dP2024 2 20 0 0 0.00000000 4 u+U IGS20 FIT MGX +## 0 0.00000000 300.00000000 0 0.0000000000000 ++ 136 J02J03J04J07G02G03G04G05G06G07G08G09G10G11G12G13G14 ++ G15G16G17G18G19G20G21G22G23G24G25G26G27G28G29G30G31 ++ G32R01R02R03R04R05R07R08R09R11R12R14R15R16R17R18R19 ++ R20R21R22R24E02E03E04E05E07E08E09E10E11E12E13E14E15 ++ E18E19E21E24E25E26E27E30E31E33E34E36C01C03C04C07C08 ++ C09C10C11C12C13C14C16C19C20C21C22C23C24C25C26C27C28 ++ C29C30C32C33C34C35C36C37C38C39C40C41C42C43C44C45C46 ++ L05L06L07L09L11L13L15L16L17L18L19L20L21L22L23L24L26 +++ 4 4 4 9 10 10 11 9 10 9 10 10 10 10 9 10 10 +++ 9 10 10 10 10 10 10 9 10 10 10 10 10 10 9 10 9 +++ 10 12 13 12 11 12 11 11 11 10 11 11 11 11 11 11 12 +++ 12 11 10 11 9 9 9 9 9 9 9 9 9 9 9 10 9 +++ 11 9 9 9 9 9 9 9 9 9 9 9 10 10 10 9 9 +++ 10 9 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 +++ 10 10 10 10 10 10 10 10 10 10 10 9 9 10 10 10 10 +++ 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 +%c M cc GPS ccc cccc cccc cccc cccc ccccc ccccc ccccc ccccc +%c cc cc ccc ccc cccc cccc cccc cccc ccccc ccccc ccccc ccccc +%f 1.2500000 1.025000000 0.00000000000 0.000000000000000 +%f 0.0000000 0.000000000 0.00000000000 0.000000000000000 +%i 0 0 0 0 0 0 0 0 0 +%i 0 0 0 0 0 0 0 0 0 +/* +/* +/* +/* +* 2024 2 20 0 0 0.00000000 +PJ02 -30637.964795 25249.134782 19304.283632 0.000000 P +PJ03 -27692.297412 16316.830900 -22661.869605 0.000000 P +PJ04 -22769.168876 35126.667455 37.313274 0.000000 P +PJ07 -25355.503898 33680.881277 44.988384 0.000000 P +PG02 22307.757148 14415.835190 -2224.601124 -482.782474 P +PG03 12029.642526 13227.439477 19540.216157 203.993445 P +PG04 19082.493046 5132.445576 17825.226577 295.908001 P +PG05 -6962.835128 -23130.695138 -11107.093272 -162.446777 P +PG06 6503.721178 -13214.331251 22164.237575 400.331141 P +PG07 21846.161848 2152.308563 -14786.041236 -66.006538 P +PG08 11995.253091 10740.895985 -21280.201630 -167.864346 P +PG09 24583.970685 -6400.659017 7773.671856 97.899175 P +PG10 -10675.829119 19763.718503 -13706.479081 1.039522 P +PG11 -5297.188932 -19233.076646 17583.279377 -581.526289 P +PG12 -11209.840254 -14510.763672 18952.636172 -479.652606 P +PG13 -1605.317351 -15195.469186 -21909.275867 627.100187 P +PG14 13335.423261 -16252.007279 -16095.700257 330.224702 P +PG15 -13106.780196 -10102.571692 -21294.256121 129.478627 P +PG16 396.794220 25576.678375 -6526.540038 -358.894895 P +PG17 22445.038620 -13345.197329 5703.293267 716.439094 P +PG18 -20862.616631 -1089.998130 -16494.161736 -559.289996 P +PG19 16397.571079 -15599.092274 13412.739860 443.052842 P +PG20 -891.633837 -26529.215247 2429.362739 386.861670 P +PG21 19842.276712 16770.548411 -7122.297150 134.313212 P +PG22 10367.333153 -22612.459950 -9281.628667 28.442578 P +PG23 -14438.001265 7734.888683 -20843.471658 159.844119 P +PG24 -20885.801667 -16031.949058 -5312.633801 -434.481122 P +PG25 -15121.855453 -2587.292055 21351.584994 489.098968 P +PG26 -4099.900839 25414.215245 5546.380293 188.390782 P +PG27 -1362.629189 16714.216575 -20771.105400 -5.507671 P +PG28 -9120.536687 12182.766907 21746.445424 -136.844041 P +PG29 -24781.424157 2942.543401 9188.958622 -606.624967 P +PG30 14948.822585 -7959.226446 -20386.187987 -430.334852 P +PG31 110.809676 17332.346858 19800.903108 -227.819024 P +PG32 -19597.860033 15925.691015 8081.067509 -612.507799 P +PR01 12445.621685 1719.273624 22203.351586 77.622838 P +PR02 19015.054425 -12634.469577 11497.160175 -22.512020 P +PR03 14613.873948 -20118.536800 -5774.400277 94.834166 P +PR04 2635.986463 -16165.143074 -19527.014265 224.165816 P +PR05 -10905.030922 -3731.786713 -22736.743052 127.171381 P +PR07 -14042.714190 20161.622003 6802.914174 76.191837 P +PR08 -2143.614408 16097.521541 19722.751922 -74.478737 P +PR09 -10942.526639 3070.009638 22848.030265 170.936285 P +PR11 6759.053466 24440.397821 2848.389893 33.764804 P +PR12 12929.789044 15547.596249 -15521.015830 36.929492 P +PR14 2402.544763 -18843.539991 -17010.245839 26.075340 P +PR15 -7302.079521 -24403.752227 -1300.463969 82.042183 P +PR16 -12895.922639 -15725.740783 15377.755489 23.404950 P +PR17 8982.624516 -8441.191873 22336.583908 62.651645 P +PR18 -8659.832017 -11730.884517 20930.849050 128.250114 P +PR19 -20931.010387 -10331.874684 10285.084852 -266.457430 P +PR20 -23108.080607 -1306.106128 -10658.296736 -108.545618 P +PR21 -8829.110093 8361.565001 -22423.115421 -78.337232 P +PR22 9426.180924 12363.062381 -20200.545025 108.935891 P +PR24 22967.248413 -182.609933 11107.071595 -44.617515 P +PE02 16654.477438 -9186.341345 -22698.078473 104.815906 P +PE03 27581.059494 -10233.931277 3227.433045 -94.959702 P +PE04 -16848.106263 19239.581211 14914.251703 -331.290033 P +PE05 22055.760211 4604.170544 19202.055470 4721.679144 P +PE07 -3156.734279 -17013.948710 -24007.488188 -104.670686 P +PE08 17493.429811 -19030.063169 -14412.601634 -226.566957 P +PE09 2956.323667 16945.061643 24094.321348 -342.238141 P +PE10 3543.688581 19656.177401 -21847.799358 -603.258133 P +PE11 13752.894033 21571.440985 -14912.536027 3236.190627 P +PE12 -6161.560339 15167.474285 -24660.505291 -913.760687 P +PE13 -13175.817249 -21502.747395 15495.216566 -20.232878 P +PE14 21129.982431 -10742.737566 2194.726382 44.290164 P +PE15 6695.996831 -14749.538560 24783.717176 -86.765176 P +PE18 -24317.299562 18840.731417 -10169.715399 346.267304 P +PE19 -27807.469835 8614.541941 -5340.457251 -582.042421 P +PE21 -14455.106556 -12540.119198 22574.558155 -579.891111 P +PE24 3445.764373 28000.342236 -8941.166291 -607.733987 P +PE25 14322.893553 12942.984476 -22440.175976 1.123596 P +PE26 -25182.033997 -15194.134725 -3303.743188 373.768822 P +PE27 -3738.333835 -27870.528442 9257.575819 -279.014779 P +PE30 9295.786773 -26443.982677 -9556.856333 -14.715077 P +PE31 -9049.031027 26581.590061 9351.255631 -16.388451 P +PE33 -22619.340691 -1018.225109 -19056.954260 7.863394 P +PE34 22340.750539 495.300456 19412.294983 -95.584429 P +PE36 25034.060543 15578.503362 2709.802173 -188.317685 P +PC01 -34336.250096 24437.220998 -798.282953 885.127995 P +PC03 -14761.455958 39519.648423 -238.447784 -14.895609 P +PC04 -39619.870159 14326.294100 -1026.375761 832.081284 P +PC07 -17291.958050 36014.596451 -13700.124771 -829.228365 P +PC08 -2602.665379 37960.360347 -17924.344630 24.986613 P +PC09 3206.253685 26957.150447 32847.619520 -513.510749 P +PC10 -11025.411775 36125.554011 -18947.723778 77.975534 P +PC11 19382.573971 -10216.712410 17350.127996 419.488931 P +PC12 27880.271380 1126.785930 639.807601 765.851238 P +PC13 3194.307387 40680.091021 -9838.459990 418.805807 P +PC14 17366.172693 -21143.333801 5346.636932 228.701140 P +PC16 -8910.030990 22508.373852 34789.676961 -349.872617 P +PC19 -12198.761389 24793.047121 4031.350599 -925.315674 P +PC20 -19550.259192 15638.113323 -12347.200563 -179.556882 P +PC21 15658.709023 3991.987078 22766.766708 -961.894742 P +PC22 2547.620664 20254.399943 19041.016460 -103.484125 P +PC23 -10547.965845 -25552.340626 -3846.558736 -780.082093 P +PC24 16370.294084 -3631.684242 -22325.201786 900.259544 P +PC25 3193.082034 -20938.558529 -18194.157661 330.298507 P +PC26 19522.420144 14586.924675 -13586.204053 -251.662551 P +PC27 -25953.707831 -6548.325514 7848.145294 273.587220 P +PC28 -13107.549243 -14485.093272 19932.436088 208.207002 P +PC29 -10033.675964 14961.521345 -21315.261484 244.059625 P +PC30 -25886.709358 5951.164945 -8521.767325 -27.361138 P +PC32 -15661.923021 -3915.083361 -22744.943257 -570.262831 P +PC33 12112.558516 -24826.180398 -3886.153327 -950.181066 P +PC34 25191.982005 -6882.543866 9860.133725 373.041082 P +PC35 13563.188098 14090.488786 -19933.509602 429.607927 P +PC36 -4075.197858 20527.063275 18468.504376 -8.905962 P +PC37 -19129.749919 -15463.529001 13205.532633 -937.539740 P +PC38 -7845.494805 33802.439095 -23798.126120 137.853691 P +PC39 -15572.618277 19822.475260 33821.000449 -7.235812 P +PC40 -25017.448647 31604.064930 -12833.527388 -57.281046 P +PC41 -1960.361980 -20744.764348 -18498.158015 -893.310811 P +PC42 19723.340174 -14202.724382 13732.624131 -452.925683 P +PC43 11095.959803 -14807.449616 20886.997015 61.071491 P +PC44 26135.572361 5725.214397 -8008.910533 389.639965 P +PC45 10643.795396 25522.132476 3643.488482 -71.214303 P +PC46 -15864.316420 4445.183553 22513.829462 -125.274993 P +PL05 13257.591116 -20361.568467 -7872.639156 0.000000 P +PL06 -25162.266944 -3130.193017 -3023.164529 0.000000 P +PL07 -26594.037506 2428.813137 -12764.489938 0.000000 P +PL09 20538.518720 20133.914832 -6996.415556 0.000000 P +PL11 -16713.380173 8556.400633 22872.639347 0.000000 P +PL13 11517.403073 -176.128434 -22779.232459 0.000000 P +PL15 20125.682234 33567.991444 -15832.119657 0.000000 P +PL16 4926.037114 41833.715174 2663.935910 0.000000 P +PL17 -14931.757195 39465.708581 2053.202381 0.000000 P +PL18 -15019.776633 39243.184078 -2235.127276 0.000000 P +PL19 35668.954737 22491.080563 2102.776074 0.000000 P +PL20 20168.629538 32219.277809 18173.445081 0.000000 P +PL21 -26807.934340 32497.152495 559.614982 0.000000 P +PL22 1964.656981 8043.446238 9027.672167 0.000000 P +PL23 2826.442426 -11699.628288 -2665.517842 0.000000 P +PL24 755.603925 12249.577289 -227.770962 0.000000 P +PL26 -25287.808680 33735.316429 40.434925 0.000000 P +* 2024 2 20 0 5 0.00000000 +PJ02 -30433.506439 25242.147504 19748.046745 0.000000 P +PJ03 -28003.972669 16258.965661 -22376.349359 0.000000 P +PJ04 -22593.857301 35153.958153 -503.426665 0.000000 P +PJ07 -25355.664679 33680.635811 45.285340 0.000000 P +PG02 22167.705020 14421.052580 -3169.507326 -482.780690 P +PG03 11949.791155 13965.608098 19076.941958 204.000605 P +PG04 18474.277931 5453.943342 18358.932489 295.910804 P +PG05 -6888.452444 -23529.556916 -10268.510288 -162.447194 P +PG06 7197.886715 -12744.266063 22228.202932 400.326599 P +PG07 22284.735298 2523.673708 -14093.634827 -66.009256 P +PG08 11289.276808 11130.207492 -21453.789214 -167.864905 P +PG09 24341.202575 -6183.319244 8652.785387 97.903009 P +PG10 -10697.498858 19211.449509 -14452.973317 1.039736 P +PG11 -4725.293319 -18866.248097 18134.410867 -581.530081 P +PG12 -11069.703688 -15228.683412 18474.881290 -479.653720 P +PG13 -824.906178 -15438.974710 -21774.210590 627.101223 P +PG14 13345.227754 -15618.743217 -16707.750069 330.227688 P +PG15 -12472.379182 -10561.142075 -21449.764914 129.479811 P +PG16 274.393859 25781.613906 -5602.054843 -358.892375 P +PG17 22639.507529 -13353.281717 4774.680949 716.438726 P +PG18 -21341.105431 -1477.033041 -15845.006600 -559.292457 P +PG19 16899.676274 -15709.161650 12639.066518 443.054432 P +PG20 -792.559303 -26431.728427 3364.482304 386.861243 P +PG21 19551.335425 16677.753794 -7998.725572 134.312795 P +PG22 10378.330488 -22220.545213 -10128.996481 28.440730 P +PG23 -14432.016820 6933.547927 -21132.772916 159.846567 P +PG24 -20663.293178 -16018.462199 -6205.376086 -434.482944 P +PG25 -15076.197474 -3422.935508 21275.402448 489.099308 P +PG26 -4220.677726 25178.064732 6447.699824 188.389550 P +PG27 -2065.274581 17029.773024 -20437.165456 -5.508644 P +PG28 -9821.878194 11741.195572 21683.705805 -136.847923 P +PG29 -24464.522745 2746.348068 10050.595386 -606.624723 P +PG30 15579.863036 -7498.360224 -20096.236669 -430.333344 P +PG31 -551.079508 16919.119831 20156.083661 -227.819055 P +PG32 -19888.847375 15980.371373 7184.533163 -612.508374 P +PR01 11846.630372 2413.858178 22465.238669 77.623184 P +PR02 18649.956055 -12306.617403 12416.080148 -22.512050 P +PR03 14718.607207 -20316.840963 -4730.525009 94.834398 P +PR04 3143.561262 -16774.920244 -18929.920975 224.166311 P +PR05 -10265.507391 -4420.339310 -22910.924590 127.171575 P +PR07 -14175.328001 20387.178773 5768.992921 76.192097 P +PR08 -2650.209698 16710.030542 19140.376701 -74.478722 P +PR09 -11266.326160 2192.119344 22789.424934 170.936914 P +PR11 6759.743272 24293.537828 3907.530552 33.764418 P +PR12 13161.295933 16126.126868 -14715.754826 36.929628 P +PR14 2612.852601 -18161.422109 -17707.174527 26.075358 P +PR15 -7318.639189 -24318.139993 -2365.510951 82.042079 P +PR16 -13133.515075 -16294.746550 14561.699484 23.405012 P +PR17 9878.232441 -8270.831239 22018.913916 62.652590 P +PR18 -7817.519464 -11513.074195 21380.402520 128.250707 P +PR19 -20518.322410 -10157.495044 11245.749608 -266.457881 P +PR20 -23531.183047 -1345.771566 -9682.808141 -108.545783 P +PR21 -9728.126694 8184.040082 -22115.036000 -78.338136 P +PR22 8615.685849 12133.233384 -20694.574585 108.936454 P +PR24 23403.480852 -137.567988 10154.495362 -44.617999 P +PE02 16585.916269 -8502.766777 -23012.130427 104.816839 P +PE03 27474.033772 -10201.482342 4119.604812 -94.960454 P +PE04 -17237.535830 19439.449007 14192.162242 -331.292704 P +PE05 21522.313074 4845.957757 19740.466828 4721.680227 P +PE07 -2506.836140 -17325.163461 -23860.992142 -104.671289 P +PE08 17867.561355 -19227.755185 -13672.129221 -226.568747 P +PE09 2305.356711 17258.585566 23942.666562 -342.242244 P +PE10 3009.650590 19258.778369 -22277.504994 -603.259012 P +PE11 13397.397928 21276.525878 -15641.688588 3236.183183 P +PE12 -6770.650643 14738.408077 -24760.140529 -913.765562 P +PE13 -12805.819078 -21197.664702 16209.974712 -20.232918 P +PE14 21415.336572 -10518.444122 1203.537450 44.293401 P +PE15 7308.833861 -14320.787236 24862.249539 -86.765819 P +PE18 -24451.150020 18970.746095 -9483.558239 346.280287 P +PE19 -27640.618078 8559.851205 -6220.546072 -582.020548 P +PE21 -14406.328751 -13212.897736 22219.496402 -579.891694 P +PE24 3441.392751 28256.648677 -8093.608247 -607.740301 P +PE25 14274.720169 13610.927123 -22072.390051 1.123744 P +PE26 -25279.126909 -15205.092235 -2387.261337 373.772130 P +PE27 -3736.260423 -28137.379124 8413.703792 -279.017637 P +PE30 9250.829181 -26147.567036 -10381.595697 -14.726749 P +PE31 -9004.262300 26290.291190 10181.120415 -16.388717 P +PE33 -23104.605786 -1311.378000 -18447.345052 7.863564 P +PE34 22834.707179 794.286677 18818.538214 -95.585065 P +PE36 25119.801878 15573.279491 1787.396553 -188.319270 P +PC01 -34336.396050 24436.704036 -818.589105 885.128343 P +PC03 -14759.906612 39519.261223 -264.221568 -14.886110 P +PC04 -39620.366443 14325.250947 -1038.011582 832.070104 P +PC07 -17166.590816 36310.509198 -13069.179398 -829.246817 P +PC08 -2248.449683 37644.197983 -18627.968415 24.977807 P +PC09 2931.122374 26698.287356 33077.937043 -513.526323 P +PC10 -10955.817518 36445.495617 -18385.480894 77.970856 P +PC11 19960.626839 -10172.890442 16705.852743 419.494832 P +PC12 27883.885676 1144.807746 -303.750415 765.848558 P +PC13 3574.999199 40454.482203 -10599.136228 418.806786 P +PC14 17286.642469 -20959.498608 6255.464742 228.726650 P +PC16 -9275.070510 22377.100784 34773.866271 -349.879347 P +PC19 -12281.320063 24884.653070 3103.457725 -925.314665 P +PC20 -19340.329626 15254.624166 -13130.808518 -179.568027 P +PC21 15256.077028 4661.534054 22913.239891 -961.894586 P +PC22 2201.690996 20796.034493 18493.104370 -103.479931 P +PC23 -10430.731678 -25448.704643 -4748.495553 -780.081394 P +PC24 16729.075046 -2959.265229 -22157.012677 900.270024 P +PC25 3537.179224 -20406.950075 -18726.589606 330.301288 P +PC26 19712.786052 15000.115646 -12838.812998 -251.664177 P +PC27 -25668.000913 -6576.970453 8714.347873 273.588837 P +PC28 -12416.710195 -14483.390211 20371.350152 208.208295 P +PC29 -10758.425191 14953.228899 -20964.487947 244.061154 P +PC30 -26164.328873 5914.739112 -7653.724467 -27.362579 P +PC32 -15263.636050 -4589.075610 -22888.732243 -570.264588 P +PC33 12194.637334 -24914.067925 -2957.349407 -950.182015 P +PC34 25516.231501 -6846.616072 9017.064946 373.043567 P +PC35 12873.458501 14115.515756 -20367.554827 429.605256 P +PC36 -4411.415805 19979.252995 18985.427120 -8.901913 P +PC37 -19305.013354 -15869.231511 12448.058994 -937.540592 P +PC38 -7611.913376 33446.881002 -24369.978338 137.854395 P +PC39 -15966.452400 19799.311048 33646.902286 -7.235864 P +PC40 -24879.146183 31994.264443 -12119.117732 -57.281553 P +PC41 -1622.596917 -21273.495707 -17922.863072 -893.312445 P +PC42 19492.925823 -13779.536970 14475.970865 -452.924691 P +PC43 11806.323239 -14795.536614 20503.349027 61.071933 P +PC44 25847.320831 5769.031596 -8867.371588 389.643395 P +PC45 10533.372013 25421.781866 4551.112693 -71.215005 P +PC46 -16227.920287 3765.468407 22379.413176 -125.275927 P +PL05 13422.948605 -20620.332591 -6860.400521 0.000000 P +PL06 -25274.983615 -3083.065458 -1952.619439 0.000000 P +PL07 -26227.938206 2277.622175 -13527.150404 0.000000 P +PL09 20379.445168 19969.486746 -7876.448396 0.000000 P +PL11 -16645.197625 7866.434823 23168.247075 0.000000 P +PL13 11833.166594 699.021513 -22606.392402 0.000000 P +PL15 20178.516235 33673.259982 -15541.813471 0.000000 P +PL16 4927.464167 41837.470854 2623.203478 0.000000 P +PL17 -14823.937016 39481.512343 2478.187496 0.000000 P +PL18 -14889.852438 39262.514214 -2713.023552 0.000000 P +PL19 35667.426781 22488.196929 2129.454399 0.000000 P +PL20 20166.006122 32333.118970 17968.977086 0.000000 P +PL21 -26806.597354 32496.978166 627.272531 0.000000 P +PL22 2664.066615 6642.744639 9931.783811 0.000000 P +PL23 3632.286890 -11705.696651 -1348.654204 0.000000 P +PL24 438.768054 12188.364734 1376.477399 0.000000 P +PL26 -25287.844552 33735.049900 39.230665 0.000000 P +* 2024 2 20 0 10 0.00000000 +PJ02 -30231.432633 25227.856676 20183.603111 0.000000 P +PJ03 -28314.849546 16212.938180 -22077.665530 0.000000 P +PJ04 -22417.237826 35173.094192 -1043.919272 0.000000 P +PJ07 -25355.830837 33680.389937 45.560273 0.000000 P +PG02 21996.099624 14412.607451 -4108.394589 -482.778906 P +PG03 11884.530006 14686.688975 18576.859146 204.007765 P +PG04 17854.221345 5794.542520 18857.688370 295.913606 P +PG05 -6820.992187 -23897.833684 -9410.311335 -162.447610 P +PG06 7902.100209 -12286.648987 22249.876740 400.322058 P +PG07 22706.715635 2872.546851 -13374.022246 -66.011973 P +PG08 10584.739688 11534.676257 -21586.838912 -167.865465 P +PG09 24073.440475 -5945.932851 9515.336314 97.906843 P +PG10 -10727.994550 18631.690242 -15171.010836 1.039950 P +PG11 -4130.560875 -18497.983854 18650.948209 -581.533873 P +PG12 -10944.280363 -15929.937764 17961.017525 -479.654833 P +PG13 -54.260249 -15694.729158 -21598.137691 627.102258 P +PG14 13363.831045 -14963.400454 -17287.520937 330.230674 P +PG15 -11841.494519 -11033.133162 -21566.039803 129.480995 P +PG16 159.838484 25953.713150 -4666.627789 -358.889855 P +PG17 22802.091141 -13350.439779 3837.083895 716.438358 P +PG18 -21805.668338 -1841.332374 -15165.723353 -559.294917 P +PG19 17371.803648 -15817.115191 11840.491913 443.056022 P +PG20 -687.375659 -26301.295313 4293.229332 386.860815 P +PG21 19229.508510 16575.656892 -8860.433851 134.312378 P +PG22 10392.203110 -21797.136944 -10956.911871 28.438882 P +PG23 -14440.449823 6122.235443 -21381.404458 159.849016 P +PG24 -20411.621740 -15993.396707 -7086.644523 -434.484766 P +PG25 -15044.519754 -4255.160118 21157.268591 489.099648 P +PG26 -4346.214897 24909.872074 7336.347790 188.388319 P +PG27 -2751.060459 17351.703298 -20064.637293 -5.509617 P +PG28 -10528.099953 11313.519794 21579.374742 -136.851805 P +PG29 -24121.634793 2531.790767 10893.053799 -606.624479 P +PG30 16208.168843 -7054.201459 -19767.597788 -430.331836 P +PG31 -1230.140435 16510.051979 20471.620094 -227.819087 P +PG32 -20148.884444 16023.967840 6274.156950 -612.508949 P +PR01 11258.595595 3130.355961 22678.602779 77.623530 P +PR02 18268.881875 -11941.897668 13308.333821 -22.512079 P +PR03 14790.633799 -20484.931221 -3676.449937 94.834631 P +PR04 3619.295764 -17377.900545 -18291.819304 224.166806 P +PR05 -9639.246043 -5129.132427 -23035.504196 127.171770 P +PR07 -14274.798133 20583.418480 4722.577708 76.192356 P +PR08 -3125.709722 17316.073381 18516.821169 -74.478706 P +PR09 -11609.374373 1325.136619 22681.623685 170.937544 P +PR11 6741.760058 24106.225142 4958.233484 33.764031 P +PR12 13395.098691 16667.272642 -13878.626238 36.929765 P +PR14 2849.063150 -17458.474218 -18365.794241 26.075376 P +PR15 -7318.225792 -24191.227887 -3425.442699 82.041976 P +PR16 -13373.036668 -16825.842978 13714.125856 23.405073 P +PR17 10764.136370 -8125.542272 21653.680117 62.653535 P +PR18 -6952.921684 -11313.248722 21783.766931 128.251301 P +PR19 -20063.512131 -9985.000729 12182.105261 -266.458332 P +PR20 -23915.820548 -1365.489356 -8686.322920 -108.545948 P +PR21 -10617.992446 8031.888812 -21759.171111 -78.339040 P +PR22 7780.937073 11918.931379 -21143.784683 108.937018 P +PR24 23801.925291 -110.557550 9179.979549 -44.618483 P +PE02 16532.522419 -7808.848434 -23294.396789 104.817773 P +PE03 27343.864596 -10154.605779 5006.074879 -94.961205 P +PE04 -17602.658612 19638.251431 13450.449978 -331.295374 P +PE05 20980.406950 5106.891878 20251.583736 4721.681310 P +PE07 -1868.560495 -17648.876809 -23681.473531 -104.671892 P +PE08 18216.899199 -19423.867513 -12912.734774 -226.570537 P +PE09 1666.301930 17584.734697 23757.912053 -342.246346 P +PE10 2455.640209 18867.768631 -22676.402587 -603.259891 P +PE11 13016.828888 20978.500708 -16349.229652 3236.175739 P +PE12 -7392.095059 14322.933808 -24825.529213 -913.770436 P +PE13 -12410.829249 -20890.138605 16902.307592 -20.232957 P +PE14 21664.646116 -10283.202254 209.176930 44.296638 P +PE15 7933.521312 -13906.175853 24906.424091 -86.766462 P +PE18 -24565.264759 19095.194075 -8787.368091 346.293269 P +PE19 -27451.476888 8489.622394 -7092.026826 -581.998676 P +PE21 -14373.725662 -13875.494430 21833.684755 -579.892278 P +PE24 3444.560548 28487.389063 -7234.846665 -607.746615 P +PE25 14242.633917 14268.315441 -21674.077950 1.123893 P +PE26 -25353.427962 -15198.532475 -1467.475695 373.775438 P +PE27 -3741.927730 -28378.711809 7558.198574 -279.020494 P +PE30 9211.049097 -25825.693908 -11191.995220 -14.738420 P +PE31 -8964.649644 25973.342896 10996.894834 -16.388983 P +PE33 -23581.293805 -1582.295899 -17812.205547 7.863733 P +PE34 23320.606912 1071.114969 18198.752964 -95.585701 P +PE36 25182.239385 15550.742346 862.520702 -188.320854 P +PC01 -34336.550543 24436.183463 -838.503493 885.128691 P +PC03 -14758.386336 39518.836164 -289.869391 -14.876611 P +PC04 -39620.879709 14324.219721 -1049.150211 832.058924 P +PC07 -17028.441321 36600.745554 -12432.011558 -829.265270 P +PC08 -1908.396922 37312.712496 -19322.611502 24.969001 P +PC09 2644.984364 26452.101624 33292.915369 -513.541896 P +PC10 -10872.331148 36762.212475 -17814.501834 77.966177 P +PC11 20517.059316 -10142.039502 16034.120309 419.500733 P +PC12 27855.594749 1162.027642 -1246.806856 765.845878 P +PC13 3945.429066 40212.171919 -11354.670005 418.807764 P +PC14 17195.430518 -20747.256082 7153.935879 228.752159 P +PC16 -9645.566344 22262.083989 34741.666018 -349.886078 P +PC19 -12346.075446 24950.383517 2170.450458 -925.313657 P +PC20 -19125.130413 14843.971700 -13892.757835 -179.579172 P +PC21 14865.162131 5342.991484 23021.949350 -961.894430 P +PC22 1876.675130 21328.011781 17914.699920 -103.475736 P +PC23 -10296.209600 -25320.760489 -5642.596412 -780.080695 P +PC24 17097.445314 -2299.295577 -21952.309387 900.280505 P +PC25 3900.586954 -19866.960674 -19228.163487 330.304068 P +PC26 19897.540240 15387.499940 -12070.214559 -251.665803 P +PC27 -25353.516740 -6611.022104 9566.144222 273.590454 P +PC28 -11711.548138 -14495.265077 20776.651562 208.209589 P +PC29 -11470.627666 14958.856572 -20579.118204 244.062682 P +PC30 -26412.718017 5882.876831 -6773.031289 -27.364020 P +PC32 -14877.173236 -5274.847801 -22994.684286 -570.266346 P +PC33 12259.121009 -24975.906992 -2023.657291 -950.182964 P +PC34 25812.060184 -6816.240433 8159.124924 373.046053 P +PC35 12170.085245 14154.527386 -20768.050227 429.602585 P +PC36 -4766.620793 19423.174524 19471.031572 -8.897864 P +PC37 -19474.872455 -16248.816176 11670.064313 -937.541443 P +PC38 -7394.087357 33081.347791 -24930.095642 137.855099 P +PC39 -16360.931171 19793.405574 33456.718704 -7.235916 P +PC40 -24724.022301 32378.193115 -11398.964717 -57.282060 P +PC41 -1305.819312 -21791.455508 -17317.850323 -893.314079 P +PC42 19258.796331 -13330.061722 15195.451469 -452.923698 P +PC43 12503.074563 -14797.067548 20085.854531 61.072375 P +PC44 25530.929437 5819.337740 -9711.228505 389.646826 P +PC45 10405.641255 25296.771810 5451.211389 -71.215708 P +PC46 -16601.973546 3097.475491 22208.031807 -125.276860 P +PL05 13555.122725 -20851.083356 -5833.392274 0.000000 P +PL06 -25343.083321 -3026.814914 -877.867795 0.000000 P +PL07 -25845.123690 2107.984198 -14271.096091 0.000000 P +PL09 20194.504590 19794.515523 -8745.584666 0.000000 P +PL11 -16592.347435 7166.696877 23431.785888 0.000000 P +PL13 12167.035891 1558.784827 -22384.803777 0.000000 P +PL15 20235.943980 33776.180673 -15244.098952 0.000000 P +PL16 4929.062520 41841.222183 2581.219282 0.000000 P +PL17 -14715.567361 39492.694161 2901.993045 0.000000 P +PL18 -14759.166266 39276.026799 -3189.613709 0.000000 P +PL19 35665.840542 22485.422374 2155.117610 0.000000 P +PL20 20168.340532 32446.929034 17755.888513 0.000000 P +PL21 -26805.239904 32496.707925 694.628805 0.000000 P +PL22 3248.107273 5087.568133 10642.028518 0.000000 P +PL23 4374.190959 -11527.425039 -5.988302 0.000000 P +PL24 106.227985 11910.942464 2954.026415 0.000000 P +PL26 -25287.889169 33734.780737 38.007284 0.000000 P +* 2024 2 20 0 15 0.00000000 +PJ02 -30032.089494 25206.408767 20610.800078 0.000000 P +PJ03 -28624.420265 16178.732662 -21766.028124 0.000000 P +PJ04 -22239.617762 35183.938833 -1583.896325 0.000000 P +PJ07 -25356.002303 33680.143792 45.813050 0.000000 P +PG02 21792.528940 14391.844390 -5039.463861 -482.777122 P +PG03 11833.182994 15389.028517 18040.953213 204.014925 P +PG04 17224.033526 6154.235505 19320.535089 295.916409 P +PG05 -6759.184490 -24234.688913 -8534.122401 -162.448027 P +PG06 8614.795375 -11842.544221 22229.230600 400.317516 P +PG07 23110.614237 3199.193132 -12628.652915 -66.014691 P +PG08 9883.262190 11953.609470 -21679.055007 -167.866024 P +PG09 23781.945596 -5687.770460 10359.667105 97.910677 P +PG10 -10768.445440 18025.714987 -15859.177326 1.040163 P +PG11 -3513.811309 -18129.790125 19131.904536 -581.537665 P +PG12 -10833.006758 -16612.884384 17412.076429 -479.655947 P +PG13 705.020414 -15961.888926 -21381.358479 627.103293 P +PG14 13392.151737 -14287.347134 -17833.904956 330.233660 P +PG15 -11215.540987 -11517.716679 -21642.856405 129.482179 P +PG16 51.845353 26092.324571 -3722.071205 -358.887335 P +PG17 22933.001603 -13335.244447 2892.254965 716.437990 P +PG18 -22254.668159 -2183.024332 -14457.614684 -559.297378 P +PG19 17813.376162 -15921.469384 11018.590848 443.057613 P +PG20 -574.800980 -26138.404396 5213.846041 386.860388 P +PG21 18876.759245 16465.664038 -9705.790790 134.311961 P +PG22 10410.256415 -21342.920866 -11763.745130 28.437034 P +PG23 -14463.697962 5302.769584 -21588.907506 159.851464 P +PG24 -20130.700318 -15958.100426 -7954.825249 -434.486588 P +PG25 -15026.706698 -5082.121614 20997.454435 489.099988 P +PG26 -4477.712333 24610.259458 8210.574524 188.387087 P +PG27 -3418.761086 17678.739213 -19654.166710 -5.510590 P +PG28 -11237.559786 10900.532696 21433.652041 -136.855688 P +PG29 -23754.057664 2298.067987 11714.720049 -606.624235 P +PG30 16832.115989 -6627.249144 -19400.936770 -430.330328 P +PG31 -1925.152646 16106.501994 20746.922983 -227.819118 P +PG32 -20378.074055 16055.035519 5351.681209 -612.509525 P +PR01 10683.428351 3867.041368 22842.985435 77.623876 P +PR02 17874.086392 -11540.272201 14172.007976 -22.512109 P +PR03 14831.200431 -20621.133778 -2614.449915 94.834863 P +PR04 4062.738314 -17971.667592 -17614.096277 224.167302 P +PR05 -9028.150348 -5856.349502 -23110.215475 127.171965 P +PR07 -14342.270360 20748.573225 3665.932091 76.192616 P +PR08 -3569.652522 17913.254994 17853.415769 -74.478691 P +PR09 -11970.561767 471.335445 22524.847355 170.938174 P +PR11 6703.389794 23879.630381 5998.230114 33.763644 P +PR12 13629.146436 17170.065902 -13011.443584 36.929902 P +PR14 3111.639219 -16737.025853 -18984.681696 26.075394 P +PR15 -7299.053662 -24024.008706 -4477.966853 82.041872 P +PR16 -13612.401897 -17318.093019 12836.866733 23.405135 P +PR17 11637.751970 -8005.086039 21241.665959 62.654481 P +PR18 -6068.310361 -11132.674444 22140.080093 128.251894 P +PR19 -19567.475030 -9816.506360 13092.128549 -266.458784 P +PR20 -24260.506128 -1366.941873 -7671.001587 -108.546113 P +PR21 -11496.105514 7904.910561 -21356.291805 -78.339945 P +PR22 6924.050877 11721.530538 -21547.198127 108.937581 P +PR24 24161.152886 -99.939173 8185.627590 -44.618966 P +PE02 16494.767757 -7105.886511 -23544.486963 104.818707 P +PE03 27191.322169 -10092.348200 5885.616288 -94.961956 P +PE04 -17943.217722 19834.738633 12690.139842 -331.298045 P +PE05 20431.372449 5387.078163 20734.699968 4721.682393 P +PE07 -1243.014042 -17984.262523 -23469.180338 -104.672496 P +PE08 18541.223587 -19617.132478 -12135.469026 -226.572328 P +PE09 1040.271089 17922.669092 23540.313840 -342.250449 P +PE10 1882.464538 18484.358184 -23043.940539 -603.260770 P +PE11 12611.424126 20678.726384 -17034.181448 3236.168294 P +PE12 -8024.716670 13921.941178 -24856.579158 -913.775311 P +PE13 -11991.128949 -20581.536205 17571.258503 -20.232997 P +PE14 21878.528363 -10036.266844 -785.732660 44.299875 P +PE15 8568.857438 -13506.571836 24916.180821 -86.767104 P +PE18 -24659.753872 19213.072686 -8081.849668 346.306252 P +PE19 -27240.916129 8402.962493 -7953.693291 -581.976804 P +PE21 -14356.853190 -14526.611635 21417.657663 -579.892861 P +PE24 3454.134385 28692.045792 -6366.069415 -607.752928 P +PE25 14226.173194 14913.860429 -21245.789694 1.124042 P +PE26 -25404.126640 -15175.477071 -545.659271 373.778746 P +PE27 -3754.202476 -28593.995322 6692.243301 -279.023352 P +PE30 9177.585075 -25478.906816 -11986.936180 -14.750092 P +PE31 -8931.339648 25631.283120 11797.450003 -16.389250 P +PE33 -24048.003817 -1831.139500 -17152.414876 7.863903 P +PE34 23797.043176 1325.918239 17553.796253 -95.586337 P +PE36 25220.581413 15511.948939 -63.547155 -188.322439 P +PC01 -34336.713970 24435.659854 -858.016585 885.129039 P +PC03 -14756.896400 39518.373537 -315.378994 -14.867111 P +PC04 -39621.409956 14323.201376 -1059.786321 832.047744 P +PC07 -16877.770931 36884.755352 -11788.925568 -829.283722 P +PC08 -1583.164978 36966.540827 -20007.939816 24.960195 P +PC09 2348.399833 26219.054826 33492.449568 -513.557469 P +PC10 -10775.109473 37075.111337 -17235.062833 77.961498 P +PC11 21050.669462 -10123.219866 15336.029568 419.506633 P +PC12 27795.420142 1179.820859 -2187.804972 765.843198 P +PC13 4304.873548 39953.623817 -12104.693934 418.808743 P +PC14 17093.895272 -20506.378203 8040.564008 228.777668 P +PC16 -10020.803655 22163.542580 34693.086411 -349.892808 P +PC19 -12394.100415 24989.401946 1233.865946 -925.312648 P +PC20 -18906.093554 14406.435562 -14631.789874 -179.590317 P +PC21 14486.915393 6035.029454 23092.718667 -961.894274 P +PC22 1572.497342 21848.797022 17306.757888 -103.471542 P +PC23 -10143.514080 -25169.434715 -6527.386043 -780.079996 P +PC24 17474.401491 -1652.944434 -21711.426364 900.290986 P +PC25 4283.214773 -19320.064631 -19698.052676 330.306849 P +PC26 20075.328824 15748.895277 -11281.676000 -251.667428 P +PC27 -25010.885971 -6651.685524 10402.125578 273.592070 P +PC28 -10993.496449 -14521.299931 21147.672363 208.210882 P +PC29 -12168.852115 14977.816744 -20159.787282 244.064211 P +PC30 -26631.410654 5854.325735 -5881.142906 -27.365461 P +PC32 -14503.473556 -5971.056154 -23062.622685 -570.268104 P +PC33 12307.091991 -25010.879523 -1086.620250 -950.183913 P +PC34 26078.907819 -6790.197200 7287.729376 373.048538 P +PC35 11454.512368 14208.042073 -21134.333950 429.599914 P +PC36 -5140.726697 18860.309828 19924.518483 -8.893815 P +PC37 -19637.982282 -16602.105304 10872.831494 -937.542295 P +PC38 -7192.438671 32706.539647 -25478.208621 137.855802 P +PC39 -16755.297748 19804.768536 33250.537315 -7.235967 P +PC40 -24552.367382 32755.124040 -10673.410020 -57.282567 P +PC41 -1009.898323 -22297.120839 -16684.125754 -893.315712 P +PC42 19022.373144 -12854.697183 15889.884359 -452.922706 P +PC43 13184.823708 -14811.416083 19635.204793 61.072817 P +PC44 25187.077877 5877.290753 -10539.091805 389.650256 P +PC45 10259.694010 25148.025703 6342.296058 -71.216411 P +PC46 -16985.500459 2442.424912 21999.972115 -125.277793 P +PL05 13655.163882 -21052.015066 -4793.828111 0.000000 P +PL06 -25366.105296 -2963.499053 198.774719 0.000000 P +PL07 -25446.760149 1919.346830 -14995.297982 0.000000 P +PL09 19983.430783 19610.296748 -9602.621756 0.000000 P +PL11 -16555.276642 6458.501347 23662.891461 0.000000 P +PL13 12517.728060 2400.954589 -22114.942336 0.000000 P +PL15 20297.859301 33876.556333 -14939.118616 0.000000 P +PL16 4930.832070 41844.963552 2538.003462 0.000000 P +PL17 -14606.850407 39499.233858 3324.417312 0.000000 P +PL18 -14627.973687 39283.694056 -3664.668255 0.000000 P +PL19 35664.198971 22482.758228 2179.753345 0.000000 P +PL20 20175.625400 32560.489151 17534.280527 0.000000 P +PL21 -26803.866194 32496.340966 761.651490 0.000000 P +PL22 3699.570780 3412.779629 11144.220369 0.000000 P +PL23 5046.362610 -11165.162401 1336.789362 0.000000 P +PL24 -245.061667 11423.250772 4474.264170 0.000000 P +PL26 -25287.942478 33734.509116 36.765368 0.000000 P +EOF From 1cd029a9c30ad7b6eea30cb1d4467229b71925ca Mon Sep 17 00:00:00 2001 From: Mark Rutten Date: Wed, 21 Feb 2024 17:19:43 +0000 Subject: [PATCH 130/359] Fix issue-1309: Incorrect transmitter location in BistaticRange measurement --- .../measurements/BistaticRange.java | 166 ++----- .../measurements/BistaticRangeRate.java | 356 ++++----------- .../orekit/estimation/measurements/FDOA.java | 412 +++++------------- .../orekit/estimation/measurements/TDOA.java | 282 ++++++------ .../measurements/BistaticRangeRateTest.java | 8 +- .../estimation/measurements/FDOATest.java | 8 +- .../estimation/measurements/TDOATest.java | 6 +- 7 files changed, 370 insertions(+), 868 deletions(-) diff --git a/src/main/java/org/orekit/estimation/measurements/BistaticRange.java b/src/main/java/org/orekit/estimation/measurements/BistaticRange.java index d2cf916f78..2aa57c841b 100644 --- a/src/main/java/org/orekit/estimation/measurements/BistaticRange.java +++ b/src/main/java/org/orekit/estimation/measurements/BistaticRange.java @@ -17,11 +17,8 @@ package org.orekit.estimation.measurements; import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; import org.hipparchus.analysis.differentiation.Gradient; -import org.hipparchus.analysis.differentiation.GradientField; import org.hipparchus.geometry.euclidean.threed.FieldVector3D; import org.hipparchus.geometry.euclidean.threed.Vector3D; import org.orekit.frames.FieldTransform; @@ -117,74 +114,38 @@ protected EstimatedMeasurementBase theoreticalEvaluationWithoutDe final int evaluation, final SpacecraftState[] states) { - final SpacecraftState state = states[0]; - - // Coordinates of the spacecraft - final TimeStampedPVCoordinates pva = state.getPVCoordinates(); - - // transform between station and inertial frame, expressed as a gradient - // The components of station's position in offset frame are the 3 last derivative parameters - final Transform offsetToInertialRx = getReceiverStation().getOffsetToInertial(state.getFrame(), getDate(), false); - final AbsoluteDate downlinkDate = offsetToInertialRx.getDate(); - - // Station position in inertial frame at end of the downlink leg - final TimeStampedPVCoordinates stationReceiver = - offsetToInertialRx.transformPVCoordinates(new TimeStampedPVCoordinates(downlinkDate, - Vector3D.ZERO, Vector3D.ZERO, Vector3D.ZERO)); - - // Compute propagation times - // (if state has already been set up to pre-compensate propagation delay, - // we will have delta == tauD and transitState will be the same as state) - - // Downlink delay - final double tauD = signalTimeOfFlight(pva, stationReceiver.getPosition(), downlinkDate); + final GroundReceiverCommonParametersWithoutDerivatives common = computeCommonParametersWithout(states[0]); + final TimeStampedPVCoordinates transitPV = common.getTransitPV(); + final AbsoluteDate transitDate = transitPV.getDate(); - // Transit state & Transit state (re)computed with gradients - final double delta = downlinkDate.durationFrom(state.getDate()); - final double deltaMTauD = delta - tauD; - final SpacecraftState transitState = state.shiftedBy(deltaMTauD); - final TimeStampedPVCoordinates transitStateDS = pva.shiftedBy(deltaMTauD); + // Approximate emitter location at transit time + final Transform emitterToInertial = + getEmitterStation().getOffsetToInertial(common.getState().getFrame(), transitDate, true); + final TimeStampedPVCoordinates emitterApprox = + emitterToInertial.transformPVCoordinates(new TimeStampedPVCoordinates(transitDate, + Vector3D.ZERO, Vector3D.ZERO, Vector3D.ZERO)); - // transform between secondary station topocentric frame (east-north-zenith) and inertial frame expressed as gradients - // The components of secondary station's position in offset frame are the 3 last derivative parameters - final AbsoluteDate transitDate = downlinkDate.shiftedBy(-tauD); - final Transform offsetToInertialTxApprox = getEmitterStation().getOffsetToInertial(state.getFrame(), transitDate, true); - - // Secondary station PV in inertial frame at transit time - final TimeStampedPVCoordinates transmitApprox = - offsetToInertialTxApprox.transformPVCoordinates(new TimeStampedPVCoordinates(transitDate, - Vector3D.ZERO, Vector3D.ZERO, Vector3D.ZERO)); - - // Uplink time of flight from secondary station to transit state of leg2 - final double tauU = signalTimeOfFlight(transmitApprox, transitStateDS.getPosition(), transitStateDS.getDate()); - - // Total time of flight - final double tauTotal = tauU - deltaMTauD; - - // Absolute date of transmission - final AbsoluteDate transmitDate = downlinkDate.shiftedBy(tauTotal); - final Transform transmitToInert = emitter.getOffsetToInertial(state.getFrame(), transmitDate, true); + // Uplink time of flight from emitter station to transit state + final double tauU = signalTimeOfFlight(emitterApprox, transitPV.getPosition(), transitDate); // Secondary station PV in inertial frame at rebound date on secondary station - final TimeStampedPVCoordinates stationTransmitter = - transmitToInert.transformPVCoordinates(new TimeStampedPVCoordinates(transmitDate, - Vector3D.ZERO, Vector3D.ZERO, Vector3D.ZERO)); + final TimeStampedPVCoordinates emitterPV = emitterApprox.shiftedBy(-tauU); // Prepare the evaluation final EstimatedMeasurementBase estimated = new EstimatedMeasurementBase<>(this, iteration, evaluation, new SpacecraftState[] { - transitState + common.getTransitState() }, new TimeStampedPVCoordinates[] { - stationReceiver, - transitStateDS, - stationTransmitter + common.getStationDownlink(), + transitPV, + emitterPV }); // Range value - final double tau = tauD + tauU; + final double tau = common.getTauD() + tauU; final double range = tau * Constants.SPEED_OF_LIGHT; estimated.setEstimatedValue(range); @@ -199,10 +160,9 @@ protected EstimatedMeasurementBase theoreticalEvaluationWithoutDe protected EstimatedMeasurement theoreticalEvaluation(final int iteration, final int evaluation, final SpacecraftState[] states) { - final SpacecraftState state = states[0]; - // Range derivatives are computed with respect to spacecraft state in inertial frame + // Bistatic range derivatives are computed with respect to spacecraft state in inertial frame // and station parameters // ---------------------- // @@ -210,87 +170,39 @@ protected EstimatedMeasurement theoreticalEvaluation(final int it // - 0..2 - Position of the spacecraft in inertial frame // - 3..5 - Velocity of the spacecraft in inertial frame // - 6..n - measurements parameters (clock offset, station offsets, pole, prime meridian, sat clock offset...) - int nbParams = 6; - final Map indices = new HashMap<>(); - for (ParameterDriver driver : getParametersDrivers()) { - if (driver.isSelected()) { - for (Span span = driver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) { - if (!indices.containsKey(span.getData())) { - indices.put(span.getData(), nbParams++); - } - } - } - } - final FieldVector3D zero = FieldVector3D.getZero(GradientField.getField(nbParams)); - - // Coordinates of the spacecraft expressed as a gradient - final TimeStampedFieldPVCoordinates pvaDS = getCoordinates(state, 0, nbParams); - - // transform between station and inertial frame, expressed as a gradient - // The components of station's position in offset frame are the 3 last derivative parameters - final FieldTransform offsetToInertialRx = - getReceiverStation().getOffsetToInertial(state.getFrame(), getDate(), nbParams, indices); - final FieldAbsoluteDate downlinkDateDS = offsetToInertialRx.getFieldDate(); - - // Station position in inertial frame at end of the downlink leg - final TimeStampedFieldPVCoordinates stationReceiver = - offsetToInertialRx.transformPVCoordinates(new TimeStampedFieldPVCoordinates<>(downlinkDateDS, - zero, zero, zero)); - - // Compute propagation times - // (if state has already been set up to pre-compensate propagation delay, - // we will have delta == tauD and transitState will be the same as state) + final GroundReceiverCommonParametersWithDerivatives common = computeCommonParametersWithDerivatives(state); + final int nbParams = common.getTauD().getFreeParameters(); + final TimeStampedFieldPVCoordinates transitPV = common.getTransitPV(); + final FieldAbsoluteDate transitDate = transitPV.getDate(); - // Downlink delay - final Gradient tauD = signalTimeOfFlight(pvaDS, stationReceiver.getPosition(), downlinkDateDS); + // Approximate emitter location (at transit time) + final FieldVector3D zero = FieldVector3D.getZero(common.getTauD().getField()); + final FieldTransform emitterToInertial = + getEmitterStation().getOffsetToInertial(state.getFrame(), transitDate, nbParams, common.getIndices()); + final TimeStampedFieldPVCoordinates emitterApprox = + emitterToInertial.transformPVCoordinates(new TimeStampedFieldPVCoordinates<>(transitDate, + zero, zero, zero)); - // Transit state & Transit state (re)computed with gradients - final Gradient delta = downlinkDateDS.durationFrom(state.getDate()); - final Gradient deltaMTauD = tauD.negate().add(delta); - final SpacecraftState transitState = state.shiftedBy(deltaMTauD.getValue()); - final TimeStampedFieldPVCoordinates transitStateDS = pvaDS.shiftedBy(deltaMTauD); + // Uplink time of flight from emiiter to transit state + final Gradient tauU = signalTimeOfFlight(emitterApprox, transitPV.getPosition(), transitPV.getDate()); - // transform between secondary station topocentric frame (east-north-zenith) and inertial frame expressed as gradients - // The components of secondary station's position in offset frame are the 3 last derivative parameters - final FieldAbsoluteDate transitDate = downlinkDateDS.shiftedBy(tauD.negate()); - final FieldTransform offsetToInertialTxApprox = - getEmitterStation().getOffsetToInertial(state.getFrame(), transitDate, nbParams, indices); - - // Secondary station PV in inertial frame at transit time - final TimeStampedFieldPVCoordinates transmitApprox = - offsetToInertialTxApprox.transformPVCoordinates(new TimeStampedFieldPVCoordinates<>(transitDate, - zero, zero, zero)); - - // Uplink time of flight from secondary station to transit state of leg2 - final Gradient tauU = signalTimeOfFlight(transmitApprox, transitStateDS.getPosition(), transitStateDS.getDate()); - - // Total time of flight - final Gradient tauTotal = deltaMTauD.negate().add(tauU); - - // Absolute date of transmission - final FieldAbsoluteDate transmitDateDS = downlinkDateDS.shiftedBy(tauTotal); - final FieldTransform transmitToInert = - emitter.getOffsetToInertial(state.getFrame(), transmitDateDS, nbParams, indices); - - // Secondary station PV in inertial frame at rebound date on secondary station - final TimeStampedFieldPVCoordinates stationTransmitter = - transmitToInert.transformPVCoordinates(new TimeStampedFieldPVCoordinates<>(transmitDateDS, - zero, zero, zero)); + // Emitter coordinates at transmit time + final TimeStampedFieldPVCoordinates emitterPV = emitterApprox.shiftedBy(tauU.negate()); // Prepare the evaluation final EstimatedMeasurement estimated = new EstimatedMeasurement<>(this, iteration, evaluation, new SpacecraftState[] { - transitState + common.getTransitState() }, new TimeStampedPVCoordinates[] { - stationReceiver.toTimeStampedPVCoordinates(), - transitStateDS.toTimeStampedPVCoordinates(), - stationTransmitter.toTimeStampedPVCoordinates() + common.getStationDownlink().toTimeStampedPVCoordinates(), + common.getTransitPV().toTimeStampedPVCoordinates(), + emitterPV.toTimeStampedPVCoordinates() }); // Range value - final Gradient tau = tauD.add(tauU); + final Gradient tau = common.getTauD().add(tauU); final Gradient range = tau.multiply(Constants.SPEED_OF_LIGHT); estimated.setEstimatedValue(range.getValue()); @@ -303,7 +215,7 @@ protected EstimatedMeasurement theoreticalEvaluation(final int it // (beware element at index 0 is the value, not a derivative) for (final ParameterDriver driver : getParametersDrivers()) { for (Span span = driver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) { - final Integer index = indices.get(span.getData()); + final Integer index = common.getIndices().get(span.getData()); if (index != null) { estimated.setParameterDerivatives(driver, span.getStart(), derivatives[index]); } diff --git a/src/main/java/org/orekit/estimation/measurements/BistaticRangeRate.java b/src/main/java/org/orekit/estimation/measurements/BistaticRangeRate.java index 7d3d21f73e..54365a86cf 100644 --- a/src/main/java/org/orekit/estimation/measurements/BistaticRangeRate.java +++ b/src/main/java/org/orekit/estimation/measurements/BistaticRangeRate.java @@ -17,11 +17,8 @@ package org.orekit.estimation.measurements; import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; import org.hipparchus.analysis.differentiation.Gradient; -import org.hipparchus.analysis.differentiation.GradientField; import org.hipparchus.geometry.euclidean.threed.FieldVector3D; import org.hipparchus.geometry.euclidean.threed.Vector3D; import org.orekit.frames.FieldTransform; @@ -112,72 +109,51 @@ public GroundStation getReceiverStation() { protected EstimatedMeasurementBase theoreticalEvaluationWithoutDerivatives(final int iteration, final int evaluation, final SpacecraftState[] states) { + final GroundReceiverCommonParametersWithoutDerivatives common = computeCommonParametersWithout(states[0]); + final TimeStampedPVCoordinates transitPV = common.getTransitPV(); + final AbsoluteDate transitDate = transitPV.getDate(); - final SpacecraftState state = states[0]; - - // coordinates of the spacecraft - final TimeStampedPVCoordinates pva = state.getPVCoordinates(); - - // transform between receiver station frame and inertial frame - // at the real date of measurement, i.e. taking station clock offset into account - final Transform receiverToInertial = getReceiverStation().getOffsetToInertial(state.getFrame(), getDate(), false); - final AbsoluteDate measurementDate = receiverToInertial.getDate(); - - // Receiver PV in inertial frame at the end of the downlink leg - final TimeStampedPVCoordinates receiverPV = - receiverToInertial.transformPVCoordinates(new TimeStampedPVCoordinates(measurementDate, - Vector3D.ZERO, Vector3D.ZERO, Vector3D.ZERO)); - - // Compute propagation times - // (if state has already been set up to pre-compensate propagation delay, - // we will have delta == tauD and transitState will be the same as state) - - // Downlink delay - final double tauD = signalTimeOfFlight(pva, receiverPV.getPosition(), measurementDate); - final double delta = measurementDate.durationFrom(state.getDate()); - final double deltaMTauD = delta - tauD; - - // Transit state - final SpacecraftState transitState = state.shiftedBy(deltaMTauD); + // Approximate emitter location at transit time + final Transform emitterToInertial = + getEmitterStation().getOffsetToInertial(common.getState().getFrame(), transitDate, true); + final TimeStampedPVCoordinates emitterApprox = + emitterToInertial.transformPVCoordinates(new TimeStampedPVCoordinates(transitDate, + Vector3D.ZERO, Vector3D.ZERO, Vector3D.ZERO)); - // Transit PV - final TimeStampedPVCoordinates transitPV = pva.shiftedBy(deltaMTauD); + // Uplink time of flight from emitter station to transit state + final double tauU = signalTimeOfFlight(emitterApprox, transitPV.getPosition(), transitDate); - // Downlink range-rate - final EstimatedMeasurementBase evalDownlink = - oneWayTheoreticalEvaluation(iteration, evaluation, true, - receiverPV, transitPV, transitState); + // Secondary station PV in inertial frame at rebound date on secondary station + final TimeStampedPVCoordinates emitterPV = emitterApprox.shiftedBy(-tauU); - // transform between emitter station frame and inertial frame at the transit date - // clock offset from receiver is already compensated - final Transform emitterToInertial = getEmitterStation().getOffsetToInertial(state.getFrame(), transitPV.getDate(), true); - - // emitter PV in inertial frame at the end of the uplink leg - final TimeStampedPVCoordinates emitterPV = - emitterToInertial.transformPVCoordinates(new TimeStampedPVCoordinates(transitPV.getDate(), - Vector3D.ZERO, Vector3D.ZERO, Vector3D.ZERO)); - - // Uplink delay - final double tauU = signalTimeOfFlight(emitterPV, transitPV.getPosition(), transitPV.getDate()); - - // emitter position in inertial frame at the end of the uplink leg - final TimeStampedPVCoordinates emitterUplink = emitterPV.shiftedBy(-tauU); - - // Uplink range-rate - final EstimatedMeasurementBase evalUplink = - oneWayTheoreticalEvaluation(iteration, evaluation, false, - emitterUplink, transitPV, transitState); - - // combine uplink and downlink values + // Prepare the evaluation final EstimatedMeasurementBase estimated = - new EstimatedMeasurementBase<>(this, iteration, evaluation, - evalDownlink.getStates(), - new TimeStampedPVCoordinates[] { - evalUplink.getParticipants()[0], - evalDownlink.getParticipants()[0], - evalDownlink.getParticipants()[1] - }); - estimated.setEstimatedValue(evalDownlink.getEstimatedValue()[0] + evalUplink.getEstimatedValue()[0]); + new EstimatedMeasurementBase<>(this, + iteration, evaluation, + new SpacecraftState[] { + common.getTransitState() + }, + new TimeStampedPVCoordinates[] { + common.getStationDownlink(), + transitPV, + emitterPV + }); + + // Range-rate components + final Vector3D receiverDirection = common.getStationDownlink().getPosition() + .subtract(transitPV.getPosition()).normalize(); + final Vector3D emitterDirection = emitterPV.getPosition() + .subtract(transitPV.getPosition()).normalize(); + + final Vector3D receiverVelocity = common.getStationDownlink().getVelocity() + .subtract(transitPV.getVelocity()); + final Vector3D emitterVelocity = emitterPV.getVelocity() + .subtract(transitPV.getVelocity()); + + // range rate + final double rangeRate = Vector3D.dotProduct(receiverDirection, receiverVelocity) + + Vector3D.dotProduct(emitterDirection, emitterVelocity); + estimated.setEstimatedValue(rangeRate); return estimated; @@ -191,220 +167,70 @@ protected EstimatedMeasurement theoreticalEvaluation(final in final SpacecraftState state = states[0]; - // Bistatic range rate derivatives are computed with respect to: - // - Spacecraft state in inertial frame - // - Emitter station parameters - // - Receiver station parameters - // -------------------------- + // Bistatic range-rate derivatives are computed with respect to spacecraft state in inertial frame + // and station parameters + // ---------------------- + // + // Parameters: // - 0..2 - Position of the spacecraft in inertial frame // - 3..5 - Velocity of the spacecraft in inertial frame - // - 6..n - stations' parameters (stations' offsets, pole, prime meridian...) - int nbParams = 6; - final Map indices = new HashMap(); - for (ParameterDriver driver : getParametersDrivers()) { - // we have to check for duplicate keys because emitter and receiver stations share - // pole and prime meridian parameters names that must be considered - // as one set only (they are combined together by the estimation engine) - if (driver.isSelected()) { - for (Span span = driver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) { - - if (!indices.containsKey(span.getData())) { - indices.put(span.getData(), nbParams++); - } - } - } - } - final FieldVector3D zero = FieldVector3D.getZero(GradientField.getField(nbParams)); - - // coordinates of the spacecraft as a gradient - final TimeStampedFieldPVCoordinates pvaG = getCoordinates(state, 0, nbParams); - - // transform between receiver station frame and inertial frame - // at the real date of measurement, i.e. taking station clock offset into account - final FieldTransform receiverToInertial = - getReceiverStation().getOffsetToInertial(state.getFrame(), getDate(), nbParams, indices); - final FieldAbsoluteDate measurementDateG = receiverToInertial.getFieldDate(); - - // Receiver PV in inertial frame at the end of the downlink leg - final TimeStampedFieldPVCoordinates receiverPV = - receiverToInertial.transformPVCoordinates(new TimeStampedFieldPVCoordinates<>(measurementDateG, - zero, zero, zero)); - - // Compute propagation times - // (if state has already been set up to pre-compensate propagation delay, - // we will have delta == tauD and transitState will be the same as state) - - // Downlink delay - final Gradient tauD = signalTimeOfFlight(pvaG, receiverPV.getPosition(), measurementDateG); - final Gradient delta = measurementDateG.durationFrom(state.getDate()); - final Gradient deltaMTauD = delta.subtract(tauD); - - // Transit state - final SpacecraftState transitState = state.shiftedBy(deltaMTauD.getValue()); - - // Transit PV - final TimeStampedFieldPVCoordinates transitPV = pvaG.shiftedBy(deltaMTauD); - - // Downlink range-rate - final EstimatedMeasurement evalDownlink = - oneWayTheoreticalEvaluation(iteration, evaluation, true, - receiverPV, transitPV, transitState, indices); - - // transform between emitter station frame and inertial frame at the transit date - // clock offset from receiver is already compensated + // - 6..n - measurements parameters (clock offset, station offsets, pole, prime meridian, sat clock offset...) + final GroundReceiverCommonParametersWithDerivatives common = computeCommonParametersWithDerivatives(state); + final int nbParams = common.getTauD().getFreeParameters(); + final TimeStampedFieldPVCoordinates transitPV = common.getTransitPV(); + final FieldAbsoluteDate transitDate = transitPV.getDate(); + + // Approximate emitter location (at transit time) + final FieldVector3D zero = FieldVector3D.getZero(common.getTauD().getField()); final FieldTransform emitterToInertial = - getEmitterStation().getOffsetToInertial(state.getFrame(), transitPV.getDate(), nbParams, indices); - - // emitter PV in inertial frame at the end of the uplink leg - final TimeStampedFieldPVCoordinates emitterPV = - emitterToInertial.transformPVCoordinates(new TimeStampedFieldPVCoordinates<>(transitPV.getDate(), - zero, zero, zero)); - - // Uplink delay - final Gradient tauU = signalTimeOfFlight(emitterPV, transitPV.getPosition(), transitPV.getDate()); - - // emitter position in inertial frame at the end of the uplink leg - final TimeStampedFieldPVCoordinates emitterUplink = emitterPV.shiftedBy(tauU.negate()); - - // Uplink range-rate - final EstimatedMeasurement evalUplink = - oneWayTheoreticalEvaluation(iteration, evaluation, false, - emitterUplink, transitPV, transitState, indices); - - // combine uplink and downlink values - final EstimatedMeasurement estimated = - new EstimatedMeasurement<>(this, iteration, evaluation, - evalDownlink.getStates(), - new TimeStampedPVCoordinates[] { - evalUplink.getParticipants()[0], - evalDownlink.getParticipants()[0], - evalDownlink.getParticipants()[1] - }); - estimated.setEstimatedValue(evalDownlink.getEstimatedValue()[0] + evalUplink.getEstimatedValue()[0]); - - // combine uplink and downlink partial derivatives with respect to state - final double[][] sd1 = evalDownlink.getStateDerivatives(0); - final double[][] sd2 = evalUplink.getStateDerivatives(0); - final double[][] sd = new double[sd1.length][sd1[0].length]; - for (int i = 0; i < sd.length; ++i) { - for (int j = 0; j < sd[0].length; ++j) { - sd[i][j] = sd1[i][j] + sd2[i][j]; - } - } - estimated.setStateDerivatives(0, sd); - - // combine uplink and downlink partial derivatives with respect to parameters - evalDownlink.getDerivativesDrivers().forEach(driver -> { - for (Span span = driver.getValueSpanMap().getFirstSpan(); span != null; span = span.next()) { - - final double[] pd1 = evalDownlink.getParameterDerivatives(driver, span.getStart()); - final double[] pd2 = evalUplink.getParameterDerivatives(driver, span.getStart()); - final double[] pd = new double[pd1.length]; - for (int i = 0; i < pd.length; ++i) { - pd[i] = pd1[i] + pd2[i]; - } - estimated.setParameterDerivatives(driver, span.getStart(), pd); - } - }); - - return estimated; - - } - - /** Evaluate range rate measurement in one-way without derivatives. - * @param iteration iteration number - * @param evaluation evaluations counter - * @param downlink indicator for downlink leg - * @param stationPV station coordinates when signal is at station - * @param transitPV spacecraft coordinates at onboard signal transit - * @param transitState orbital state at onboard signal transit - * @return theoretical value for the current leg - * @since 12.0 - */ - private EstimatedMeasurementBase oneWayTheoreticalEvaluation(final int iteration, final int evaluation, - final boolean downlink, - final TimeStampedPVCoordinates stationPV, - final TimeStampedPVCoordinates transitPV, - final SpacecraftState transitState) { - - // prepare the evaluation - final EstimatedMeasurementBase estimated = - new EstimatedMeasurementBase<>(this, iteration, evaluation, - new SpacecraftState[] { - transitState - }, new TimeStampedPVCoordinates[] { - downlink ? transitPV : stationPV, - downlink ? stationPV : transitPV - }); - - // range rate value - final Vector3D stationPosition = stationPV.getPosition(); - final Vector3D relativePosition = stationPosition.subtract(transitPV.getPosition()); - - final Vector3D stationVelocity = stationPV.getVelocity(); - final Vector3D relativeVelocity = stationVelocity.subtract(transitPV.getVelocity()); - - // radial direction - final Vector3D lineOfSight = relativePosition.normalize(); + getEmitterStation().getOffsetToInertial(state.getFrame(), transitDate, nbParams, common.getIndices()); + final TimeStampedFieldPVCoordinates emitterApprox = + emitterToInertial.transformPVCoordinates(new TimeStampedFieldPVCoordinates<>(transitDate, + zero, zero, zero)); + + // Uplink time of flight from emiiter to transit state + final Gradient tauU = signalTimeOfFlight(emitterApprox, transitPV.getPosition(), transitPV.getDate()); + + // Emitter coordinates at transmit time + final TimeStampedFieldPVCoordinates emitterPV = emitterApprox.shiftedBy(tauU.negate()); + + // Prepare the evaluation + final EstimatedMeasurement estimated = new EstimatedMeasurement<>(this, + iteration, evaluation, + new SpacecraftState[] { + common.getTransitState() + }, + new TimeStampedPVCoordinates[] { + common.getStationDownlink().toTimeStampedPVCoordinates(), + common.getTransitPV().toTimeStampedPVCoordinates(), + emitterPV.toTimeStampedPVCoordinates() + }); + + // Range-rate components + final FieldVector3D receiverDirection = common.getStationDownlink().getPosition() + .subtract(transitPV.getPosition()).normalize(); + final FieldVector3D emitterDirection = emitterPV.getPosition() + .subtract(transitPV.getPosition()).normalize(); + + final FieldVector3D receiverVelocity = common.getStationDownlink().getVelocity() + .subtract(transitPV.getVelocity()); + final FieldVector3D emitterVelocity = emitterPV.getVelocity() + .subtract(transitPV.getVelocity()); // range rate - final double rangeRate = Vector3D.dotProduct(relativeVelocity, lineOfSight); - - estimated.setEstimatedValue(rangeRate); - - return estimated; - - } - - /** Evaluate range rate measurement in one-way. - * @param iteration iteration number - * @param evaluation evaluations counter - * @param downlink indicator for downlink leg - * @param stationPV station coordinates when signal is at station - * @param transitPV spacecraft coordinates at onboard signal transit - * @param transitState orbital state at onboard signal transit - * @param indices indices of the estimated parameters in derivatives computations - * @return theoretical value for the current leg - */ - private EstimatedMeasurement oneWayTheoreticalEvaluation(final int iteration, final int evaluation, final boolean downlink, - final TimeStampedFieldPVCoordinates stationPV, - final TimeStampedFieldPVCoordinates transitPV, - final SpacecraftState transitState, - final Map indices) { - - // prepare the evaluation - final EstimatedMeasurement estimated = - new EstimatedMeasurement(this, iteration, evaluation, - new SpacecraftState[] { - transitState - }, new TimeStampedPVCoordinates[] { - (downlink ? transitPV : stationPV).toTimeStampedPVCoordinates(), - (downlink ? stationPV : transitPV).toTimeStampedPVCoordinates() - }); - - // range rate value - final FieldVector3D stationPosition = stationPV.getPosition(); - final FieldVector3D relativePosition = stationPosition.subtract(transitPV.getPosition()); - - final FieldVector3D stationVelocity = stationPV.getVelocity(); - final FieldVector3D relativeVelocity = stationVelocity.subtract(transitPV.getVelocity()); - - // radial direction - final FieldVector3D lineOfSight = relativePosition.normalize(); - - // range rate - final Gradient rangeRate = FieldVector3D.dotProduct(relativeVelocity, lineOfSight); - + final Gradient rangeRate = FieldVector3D.dotProduct(receiverDirection, receiverVelocity) + .add(FieldVector3D.dotProduct(emitterDirection, emitterVelocity)); estimated.setEstimatedValue(rangeRate.getValue()); - // compute partial derivatives of (rr) with respect to spacecraft state Cartesian coordinates + // Range partial derivatives with respect to state final double[] derivatives = rangeRate.getGradient(); estimated.setStateDerivatives(0, Arrays.copyOfRange(derivatives, 0, 6)); // set partial derivatives with respect to parameters + // (beware element at index 0 is the value, not a derivative) for (final ParameterDriver driver : getParametersDrivers()) { for (Span span = driver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) { - final Integer index = indices.get(span.getData()); + final Integer index = common.getIndices().get(span.getData()); if (index != null) { estimated.setParameterDerivatives(driver, span.getStart(), derivatives[index]); } diff --git a/src/main/java/org/orekit/estimation/measurements/FDOA.java b/src/main/java/org/orekit/estimation/measurements/FDOA.java index 69160d26ce..2729755b6a 100644 --- a/src/main/java/org/orekit/estimation/measurements/FDOA.java +++ b/src/main/java/org/orekit/estimation/measurements/FDOA.java @@ -17,14 +17,10 @@ package org.orekit.estimation.measurements; import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; import org.hipparchus.analysis.differentiation.Gradient; -import org.hipparchus.analysis.differentiation.GradientField; import org.hipparchus.geometry.euclidean.threed.FieldVector3D; import org.hipparchus.geometry.euclidean.threed.Vector3D; -import org.hipparchus.util.FastMath; import org.orekit.frames.FieldTransform; import org.orekit.frames.Transform; import org.orekit.propagation.SpacecraftState; @@ -113,88 +109,61 @@ public GroundStation getSecondStation() { protected EstimatedMeasurementBase theoreticalEvaluationWithoutDerivatives(final int iteration, final int evaluation, final SpacecraftState[] states) { - final SpacecraftState state = states[0]; + final GroundReceiverCommonParametersWithoutDerivatives common = computeCommonParametersWithout(states[0]); + final TimeStampedPVCoordinates emitterPV = common.getTransitPV(); + final AbsoluteDate emitterDate = emitterPV.getDate(); - // coordinates of the spacecraft - final TimeStampedPVCoordinates pva = state.getPVCoordinates(); - - // transform between prime station frame and inertial frame - // at the real date of measurement, i.e. taking station clock offset into account - final Transform primeToInert = getStation().getOffsetToInertial(state.getFrame(), getDate(), false); - final AbsoluteDate measurementDate = primeToInert.getDate(); - - // prime station PV in inertial frame at the real date of the measurement - final TimeStampedPVCoordinates primePV = - primeToInert.transformPVCoordinates(new TimeStampedPVCoordinates(measurementDate, - Vector3D.ZERO, Vector3D.ZERO, Vector3D.ZERO)); - - // compute downlink delay from emitter to prime receiver - final double tau1 = signalTimeOfFlight(pva, primePV.getPosition(), measurementDate); - - // elapsed time between state date and signal arrival to the prime receiver - final double dtMtau1 = measurementDate.durationFrom(state.getDate()) - tau1; - - // satellite state at signal emission - final SpacecraftState emitterState = state.shiftedBy(dtMtau1); - - // satellite pv at signal emission (re)computed with gradient - final TimeStampedPVCoordinates emitterPV = pva.shiftedBy(dtMtau1); - - // second station PV in inertial frame at real date of signal reception - TimeStampedPVCoordinates secondPV; - // initialize search loop of the reception date by second station - double tau2 = tau1; - double delta; - int count = 0; - do { - final double previous = tau2; - // date of signal arrival on second receiver - final AbsoluteDate dateAt2 = emitterState.getDate().shiftedBy(previous); - // transform between second station frame and inertial frame - // at the date of signal arrival, taking clock offset into account - final Transform secondToInert = secondStation.getOffsetToInertial(state.getFrame(), dateAt2, false); - // second receiver position in inertial frame at the real date of signal reception - secondPV = secondToInert.transformPVCoordinates(new TimeStampedPVCoordinates(secondToInert.getDate(), - Vector3D.ZERO, Vector3D.ZERO, Vector3D.ZERO)); - // downlink delay from emitter to second receiver - tau2 = linkDelay(emitterPV.getPosition(), secondPV.getPosition()); - - // Change in the computed downlink delay - delta = FastMath.abs(tau2 - previous); - } while (count++ < 10 && delta >= 2 * FastMath.ulp(tau2)); + // Approximate second location at transit time + final Transform secondToInertial = + getSecondStation().getOffsetToInertial(common.getState().getFrame(), emitterDate, true); + final TimeStampedPVCoordinates secondApprox = + secondToInertial.transformPVCoordinates(new TimeStampedPVCoordinates(emitterDate, + Vector3D.ZERO, Vector3D.ZERO, Vector3D.ZERO)); - // The measured TDOA is (tau1 + clockOffset1) - (tau2 + clockOffset2) - final double offset1 = getStation().getClockOffsetDriver().getValue(emitterState.getDate()); - final double offset2 = secondStation.getClockOffsetDriver().getValue(emitterState.getDate()); - final double tdoa = (tau1 + offset1) - (tau2 + offset2); + // Time of flight from emitter to second station + final double tau2 = TDOA.forwardSignalTimeOfFlight(secondApprox, emitterPV.getPosition(), emitterDate); - // Range-rate sat->primary station - final EstimatedMeasurementBase evalPrimary = oneWayTheoreticalEvaluation(iteration, evaluation, true, - primePV, emitterPV, emitterState); + // Secondary station PV in inertial frame at receive at second station + final TimeStampedPVCoordinates secondPV = secondApprox.shiftedBy(tau2); - // Range-rate sat->secondary station - final EstimatedMeasurementBase evalSecondary = oneWayTheoreticalEvaluation(iteration, evaluation, true, - secondPV, emitterPV, emitterState); + // The measured TDOA is (tau1 + clockOffset1) - (tau2 + clockOffset2) + final double offset1 = getPrimeStation().getClockOffsetDriver().getValue(emitterDate); + final double offset2 = getSecondStation().getClockOffsetDriver().getValue(emitterDate); + final double tdoa = (common.getTauD() + offset1) - (tau2 + offset2); - // Evaluate the FDOA value and derivatives + // Evaluate the FDOA value // ------------------------------------------- - final EstimatedMeasurementBase estimated = - new EstimatedMeasurementBase<>(this, iteration, evaluation, - new SpacecraftState[] { - emitterState - }, - new TimeStampedPVCoordinates[] { - emitterPV, - tdoa > 0 ? secondPV : primePV, - tdoa > 0 ? primePV : secondPV - }); + final EstimatedMeasurement estimated = + new EstimatedMeasurement<>(this, iteration, evaluation, + new SpacecraftState[] { + common.getTransitState() + }, + new TimeStampedPVCoordinates[] { + emitterPV, + tdoa > 0.0 ? secondPV : common.getStationDownlink(), + tdoa > 0.0 ? common.getStationDownlink() : secondPV + }); + + // Range-rate components + final Vector3D primeDirection = common.getStationDownlink().getPosition() + .subtract(emitterPV.getPosition()).normalize(); + final Vector3D secondDirection = secondPV.getPosition() + .subtract(emitterPV.getPosition()).normalize(); + + final Vector3D primeVelocity = common.getStationDownlink().getVelocity() + .subtract(emitterPV.getVelocity()); + final Vector3D secondVelocity = secondPV.getVelocity() + .subtract(emitterPV.getVelocity()); + + // range rate difference + final double rangeRateDifference = Vector3D.dotProduct(primeDirection, primeVelocity) - + Vector3D.dotProduct(secondDirection, secondVelocity); // set FDOA value final double rangeRateToHz = -centreFrequency / Constants.SPEED_OF_LIGHT; - estimated.setEstimatedValue((evalPrimary.getEstimatedValue()[0] - evalSecondary.getEstimatedValue()[0]) * rangeRateToHz); + estimated.setEstimatedValue(rangeRateDifference * rangeRateToHz); return estimated; - } /** {@inheritDoc} */ @@ -204,255 +173,85 @@ protected EstimatedMeasurement theoreticalEvaluation(final int iteration, final SpacecraftState state = states[0]; - // TDOA derivatives are computed with respect to: - // - Spacecraft state in inertial frame - // - Prime station parameters - // - Second station parameters - // -------------------------- + // FDOA derivatives are computed with respect to spacecraft state in inertial frame + // and station parameters + // ---------------------- + // + // Parameters: // - 0..2 - Position of the spacecraft in inertial frame // - 3..5 - Velocity of the spacecraft in inertial frame - // - 6..n - stations' parameters (clock offset, station offsets, pole, prime meridian...) - int nbParams = 6; - final Map indices = new HashMap<>(); - for (ParameterDriver driver : getParametersDrivers()) { - // we have to check for duplicate keys because primary and secondary station share - // pole and prime meridian parameters names that must be considered - // as one set only (they are combined together by the estimation engine) - if (driver.isSelected()) { - for (Span span = driver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) { - - if (!indices.containsKey(span.getData())) { - indices.put(span.getData(), nbParams++); - } - } - } - } - final FieldVector3D zero = FieldVector3D.getZero(GradientField.getField(nbParams)); - - // coordinates of the spacecraft as a gradient - final TimeStampedFieldPVCoordinates pvaG = getCoordinates(state, 0, nbParams); - - // transform between prime station frame and inertial frame - // at the real date of measurement, i.e. taking station clock offset into account - final FieldTransform primeToInert = - getStation().getOffsetToInertial(state.getFrame(), getDate(), nbParams, indices); - final FieldAbsoluteDate measurementDateG = primeToInert.getFieldDate(); - - // prime station PV in inertial frame at the real date of the measurement - final TimeStampedFieldPVCoordinates primePV = - primeToInert.transformPVCoordinates(new TimeStampedFieldPVCoordinates<>(measurementDateG, - zero, zero, zero)); - - // compute downlink delay from emitter to prime receiver - final Gradient tau1 = signalTimeOfFlight(pvaG, primePV.getPosition(), measurementDateG); - - // elapsed time between state date and signal arrival to the prime receiver - final Gradient dtMtau1 = measurementDateG.durationFrom(state.getDate()).subtract(tau1); - - // satellite state at signal emission - final SpacecraftState emitterState = state.shiftedBy(dtMtau1.getValue()); - - // satellite pv at signal emission (re)computed with gradient - final TimeStampedFieldPVCoordinates emitterPV = pvaG.shiftedBy(dtMtau1); - - // second station PV in inertial frame at real date of signal reception - TimeStampedFieldPVCoordinates secondPV; - // initialize search loop of the reception date by second station - Gradient tau2 = tau1; - double delta; - int count = 0; - do { - final double previous = tau2.getValue(); - // date of signal arrival on second receiver - final AbsoluteDate dateAt2 = emitterState.getDate().shiftedBy(previous); - // transform between second station frame and inertial frame - // at the date of signal arrival, taking clock offset into account - final FieldTransform secondToInert = - secondStation.getOffsetToInertial(state.getFrame(), dateAt2, - nbParams, indices); - // second receiver position in inertial frame at the real date of signal reception - secondPV = secondToInert.transformPVCoordinates(new TimeStampedFieldPVCoordinates<>(secondToInert.getFieldDate(), - zero, zero, zero)); - // downlink delay from emitter to second receiver - tau2 = linkDelay(emitterPV.getPosition(), secondPV.getPosition()); - - // Change in the computed downlink delay - delta = FastMath.abs(tau2.getValue() - previous); - } while (count++ < 10 && delta >= 2 * FastMath.ulp(tau2.getValue())); + // - 6..n - measurements parameters (clock offset, station offsets, pole, prime meridian, sat clock offset...) + final GroundReceiverCommonParametersWithDerivatives common = computeCommonParametersWithDerivatives(state); + final int nbParams = common.getTauD().getFreeParameters(); + final TimeStampedFieldPVCoordinates emitterPV = common.getTransitPV(); + final FieldAbsoluteDate emitterDate = emitterPV.getDate(); + + // Approximate secondary location (at emission time) + final FieldVector3D zero = FieldVector3D.getZero(common.getTauD().getField()); + final FieldTransform secondToInertial = + getSecondStation().getOffsetToInertial(state.getFrame(), emitterDate, nbParams, common.getIndices()); + final TimeStampedFieldPVCoordinates secondApprox = + secondToInertial.transformPVCoordinates(new TimeStampedFieldPVCoordinates<>(emitterDate, + zero, zero, zero)); + + // Time of flight from emitter to second station + final Gradient tau2 = TDOA.forwardSignalTimeOfFlight(secondApprox, emitterPV.getPosition(), emitterDate); + + // Second station coordinates at receive time + final TimeStampedFieldPVCoordinates secondPV = secondApprox.shiftedBy(tau2); // The measured TDOA is (tau1 + clockOffset1) - (tau2 + clockOffset2) - final Gradient offset1 = getStation().getClockOffsetDriver().getValue(nbParams, indices, emitterState.getDate()); - final Gradient offset2 = secondStation.getClockOffsetDriver().getValue(nbParams, indices, emitterState.getDate()); - final Gradient tdoaG = tau1.add(offset1).subtract(tau2.add(offset2)); + final Gradient offset1 = getPrimeStation().getClockOffsetDriver() + .getValue(nbParams, common.getIndices(), emitterDate.toAbsoluteDate()); + final Gradient offset2 = getSecondStation().getClockOffsetDriver() + .getValue(nbParams, common.getIndices(), emitterDate.toAbsoluteDate()); + final Gradient tdoaG = common.getTauD().add(offset1).subtract(tau2.add(offset2)); final double tdoa = tdoaG.getValue(); - // Range-rate sat->primary station - final EstimatedMeasurement evalPrimary = oneWayTheoreticalEvaluation(iteration, evaluation, true, - primePV, emitterPV, emitterState, indices); - - // Range-rate sat->secondary station - final EstimatedMeasurement evalSecondary = oneWayTheoreticalEvaluation(iteration, evaluation, true, - secondPV, emitterPV, emitterState, indices); - - // Evaluate the FDOA value and derivatives + // Evaluate the TDOA value and derivatives // ------------------------------------------- - final TimeStampedPVCoordinates pv1 = primePV.toTimeStampedPVCoordinates(); + final TimeStampedPVCoordinates pv1 = common.getStationDownlink().toTimeStampedPVCoordinates(); final TimeStampedPVCoordinates pv2 = secondPV.toTimeStampedPVCoordinates(); final EstimatedMeasurement estimated = - new EstimatedMeasurement<>(this, iteration, evaluation, - new SpacecraftState[] { - emitterState - }, - new TimeStampedPVCoordinates[] { - emitterPV.toTimeStampedPVCoordinates(), - tdoa > 0 ? pv2 : pv1, - tdoa > 0 ? pv1 : pv2 - }); + new EstimatedMeasurement<>(this, iteration, evaluation, + new SpacecraftState[] { + common.getTransitState() + }, + new TimeStampedPVCoordinates[] { + emitterPV.toTimeStampedPVCoordinates(), + tdoa > 0 ? pv2 : pv1, + tdoa > 0 ? pv1 : pv2 + }); + + // Range-rate components + final FieldVector3D primeDirection = common.getStationDownlink().getPosition() + .subtract(emitterPV.getPosition()).normalize(); + final FieldVector3D secondDirection = secondPV.getPosition() + .subtract(emitterPV.getPosition()).normalize(); + + final FieldVector3D primeVelocity = common.getStationDownlink().getVelocity() + .subtract(emitterPV.getVelocity()); + final FieldVector3D secondVelocity = secondPV.getVelocity() + .subtract(emitterPV.getVelocity()); + + // range rate difference + final Gradient rangeRateDifference = FieldVector3D.dotProduct(primeDirection, primeVelocity) + .subtract(FieldVector3D.dotProduct(secondDirection, secondVelocity)); // set FDOA value final double rangeRateToHz = -centreFrequency / Constants.SPEED_OF_LIGHT; - estimated.setEstimatedValue((evalPrimary.getEstimatedValue()[0] - evalSecondary.getEstimatedValue()[0]) * rangeRateToHz); - - // combine primary and secondary partial derivatives with respect to state - final double[][] sd1 = evalPrimary.getStateDerivatives(0); - final double[][] sd2 = evalSecondary.getStateDerivatives(0); - final double[][] sd = new double[sd1.length][sd1[0].length]; - for (int i = 0; i < sd.length; ++i) { - for (int j = 0; j < sd[0].length; ++j) { - sd[i][j] = (sd1[i][j] - sd2[i][j]) * rangeRateToHz; - } - } - estimated.setStateDerivatives(0, sd); + final Gradient fdoa = rangeRateDifference.multiply(rangeRateToHz); + estimated.setEstimatedValue(fdoa.getValue()); - // combine primary and secondary partial derivatives with respect to parameters - evalPrimary.getDerivativesDrivers().forEach(driver -> { - for (Span span = driver.getValueSpanMap().getFirstSpan(); span != null; span = span.next()) { - - final double[] pd1 = evalPrimary.getParameterDerivatives(driver, span.getStart()); - final double[] pd2 = evalSecondary.getParameterDerivatives(driver, span.getStart()); - final double[] pd = new double[pd1.length]; - for (int i = 0; i < pd.length; ++i) { - pd[i] = (pd1[i] - pd2[i]) * rangeRateToHz; - } - estimated.setParameterDerivatives(driver, span.getStart(), pd); - } - }); - - return estimated; - - } - - /** Compute propagation delay on a link. - * @param emitter the position of the emitter - * @param receiver the position of the receiver (same frame as emitter) - * @return the propagation delay - */ - private double linkDelay(final Vector3D emitter, - final Vector3D receiver) { - return receiver.distance(emitter) / Constants.SPEED_OF_LIGHT; - } - - /** Compute propagation delay on a link. - * @param emitter the position of the emitter - * @param receiver the position of the receiver (same frame as emitter) - * @return the propagation delay - */ - private Gradient linkDelay(final FieldVector3D emitter, - final FieldVector3D receiver) { - return receiver.distance(emitter).divide(Constants.SPEED_OF_LIGHT); - } - - /** Evaluate range rate measurement in one-way. - * @param iteration iteration number - * @param evaluation evaluations counter - * @param downlink indicator for downlink leg - * @param stationPV station coordinates when signal is at station - * @param transitPV spacecraft coordinates at onboard signal transit - * @param transitState orbital state at onboard signal transit - * @return theoretical value for the current leg - */ - private EstimatedMeasurementBase oneWayTheoreticalEvaluation(final int iteration, final int evaluation, final boolean downlink, - final TimeStampedPVCoordinates stationPV, - final TimeStampedPVCoordinates transitPV, - final SpacecraftState transitState) { - - // prepare the evaluation - final EstimatedMeasurementBase estimated = - new EstimatedMeasurementBase<>(this, iteration, evaluation, - new SpacecraftState[] { - transitState - }, new TimeStampedPVCoordinates[] { - downlink ? transitPV : stationPV, - downlink ? stationPV : transitPV - }); - - // range rate value - final Vector3D stationPosition = stationPV.getPosition(); - final Vector3D relativePosition = stationPosition.subtract(transitPV.getPosition()); - - final Vector3D stationVelocity = stationPV.getVelocity(); - final Vector3D relativeVelocity = stationVelocity.subtract(transitPV.getVelocity()); - - // radial direction - final Vector3D lineOfSight = relativePosition.normalize(); - - // range rate - final double rangeRate = Vector3D.dotProduct(relativeVelocity, lineOfSight); - - estimated.setEstimatedValue(rangeRate); - - return estimated; - - } - /** Evaluate range rate measurement in one-way. - * @param iteration iteration number - * @param evaluation evaluations counter - * @param downlink indicator for downlink leg - * @param stationPV station coordinates when signal is at station - * @param transitPV spacecraft coordinates at onboard signal transit - * @param transitState orbital state at onboard signal transit - * @param indices indices of the estimated parameters in derivatives computations - * @return theoretical value for the current leg - */ - private EstimatedMeasurement oneWayTheoreticalEvaluation(final int iteration, final int evaluation, final boolean downlink, - final TimeStampedFieldPVCoordinates stationPV, - final TimeStampedFieldPVCoordinates transitPV, - final SpacecraftState transitState, - final Map indices) { - - // prepare the evaluation - final EstimatedMeasurement estimated = - new EstimatedMeasurement<>(this, iteration, evaluation, - new SpacecraftState[] { - transitState - }, new TimeStampedPVCoordinates[] { - (downlink ? transitPV : stationPV).toTimeStampedPVCoordinates(), - (downlink ? stationPV : transitPV).toTimeStampedPVCoordinates() - }); - - // range rate value - final FieldVector3D stationPosition = stationPV.getPosition(); - final FieldVector3D relativePosition = stationPosition.subtract(transitPV.getPosition()); - - final FieldVector3D stationVelocity = stationPV.getVelocity(); - final FieldVector3D relativeVelocity = stationVelocity.subtract(transitPV.getVelocity()); - - // radial direction - final FieldVector3D lineOfSight = relativePosition.normalize(); - - // range rate - final Gradient rangeRate = FieldVector3D.dotProduct(relativeVelocity, lineOfSight); - - estimated.setEstimatedValue(rangeRate.getValue()); - - // compute partial derivatives of (rr) with respect to spacecraft state Cartesian coordinates - final double[] derivatives = rangeRate.getGradient(); + // Range partial derivatives with respect to state + final double[] derivatives = fdoa.getGradient(); estimated.setStateDerivatives(0, Arrays.copyOfRange(derivatives, 0, 6)); // set partial derivatives with respect to parameters + // (beware element at index 0 is the value, not a derivative) for (final ParameterDriver driver : getParametersDrivers()) { for (Span span = driver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) { - final Integer index = indices.get(span.getData()); + final Integer index = common.getIndices().get(span.getData()); if (index != null) { estimated.setParameterDerivatives(driver, span.getStart(), derivatives[index]); } @@ -460,7 +259,6 @@ private EstimatedMeasurement oneWayTheoreticalEvaluation(final int iterati } return estimated; - } } diff --git a/src/main/java/org/orekit/estimation/measurements/TDOA.java b/src/main/java/org/orekit/estimation/measurements/TDOA.java index de2e95e8a1..04aa22b6f2 100644 --- a/src/main/java/org/orekit/estimation/measurements/TDOA.java +++ b/src/main/java/org/orekit/estimation/measurements/TDOA.java @@ -17,11 +17,9 @@ package org.orekit.estimation.measurements; import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; +import org.hipparchus.CalculusFieldElement; import org.hipparchus.analysis.differentiation.Gradient; -import org.hipparchus.analysis.differentiation.GradientField; import org.hipparchus.geometry.euclidean.threed.FieldVector3D; import org.hipparchus.geometry.euclidean.threed.Vector3D; import org.hipparchus.util.FastMath; @@ -104,84 +102,50 @@ public GroundStation getSecondStation() { } /** {@inheritDoc} */ + @SuppressWarnings("checkstyle:WhitespaceAround") @Override protected EstimatedMeasurementBase theoreticalEvaluationWithoutDerivatives(final int iteration, final int evaluation, final SpacecraftState[] states) { - final SpacecraftState state = states[0]; - - // coordinates of the spacecraft - final TimeStampedPVCoordinates pva = state.getPVCoordinates(); - - // transform between prime station frame and inertial frame - // at the real date of measurement, i.e. taking station clock offset into account - final Transform primeToInert = getStation().getOffsetToInertial(state.getFrame(), getDate(), false); - final AbsoluteDate measurementDate = primeToInert.getDate(); + final GroundReceiverCommonParametersWithoutDerivatives common = computeCommonParametersWithout(states[0]); + final TimeStampedPVCoordinates emitterPV = common.getTransitPV(); + final AbsoluteDate emitterDate = emitterPV.getDate(); - // prime station PV in inertial frame at the real date of the measurement - final TimeStampedPVCoordinates primePV = - primeToInert.transformPVCoordinates(new TimeStampedPVCoordinates(measurementDate, - Vector3D.ZERO, Vector3D.ZERO, Vector3D.ZERO)); + // Approximate second location at transit time + final Transform secondToInertial = + getSecondStation().getOffsetToInertial(common.getState().getFrame(), emitterDate, true); + final TimeStampedPVCoordinates secondApprox = + secondToInertial.transformPVCoordinates(new TimeStampedPVCoordinates(emitterDate, + Vector3D.ZERO, Vector3D.ZERO, Vector3D.ZERO)); - // compute downlink delay from emitter to prime receiver - final double tau1 = signalTimeOfFlight(pva, primePV.getPosition(), measurementDate); + // Time of flight from emitter to second station + final double tau2 = forwardSignalTimeOfFlight(secondApprox, emitterPV.getPosition(), emitterDate); - // elapsed time between state date and signal arrival to the prime receiver - final double dtMtau1 = measurementDate.durationFrom(state.getDate()) - tau1; - - // satellite state at signal emission - final SpacecraftState emitterState = state.shiftedBy(dtMtau1); - - // satellite pv at signal emission (re)computed with gradient - final TimeStampedPVCoordinates emitterPV = pva.shiftedBy(dtMtau1); - - // second station PV in inertial frame at real date of signal reception - TimeStampedPVCoordinates secondPV; - // initialize search loop of the reception date by second station - double tau2 = tau1; - double delta; - int count = 0; - do { - final double previous = tau2; - // date of signal arrival on second receiver - final AbsoluteDate dateAt2 = emitterState.getDate().shiftedBy(previous); - // transform between second station frame and inertial frame - // at the date of signal arrival, taking clock offset into account - final Transform secondToInert = - secondStation.getOffsetToInertial(state.getFrame(), dateAt2, true); - // second receiver position in inertial frame at the real date of signal reception - secondPV = secondToInert.transformPVCoordinates(new TimeStampedPVCoordinates(secondToInert.getDate(), - Vector3D.ZERO, Vector3D.ZERO, Vector3D.ZERO)); - // downlink delay from emitter to second receiver - tau2 = linkDelay(emitterPV.getPosition(), secondPV.getPosition()); - - // Change in the computed downlink delay - delta = FastMath.abs(tau2 - previous); - } while (count++ < 10 && delta >= 2 * FastMath.ulp(tau2)); + // Secondary station PV in inertial frame at receive at second station + final TimeStampedPVCoordinates secondPV = secondApprox.shiftedBy(tau2); // The measured TDOA is (tau1 + clockOffset1) - (tau2 + clockOffset2) - final double offset1 = getStation().getClockOffsetDriver().getValue(emitterState.getDate()); - final double offset2 = secondStation.getClockOffsetDriver().getValue(emitterState.getDate()); - final double tdoa = (tau1 + offset1) - (tau2 + offset2); + final double offset1 = getPrimeStation().getClockOffsetDriver().getValue(emitterDate); + final double offset2 = getSecondStation().getClockOffsetDriver().getValue(emitterDate); + final double tdoa = (common.getTauD() + offset1) - (tau2 + offset2); - // Evaluate the TDOA value and derivatives + // Evaluate the TDOA value // ------------------------------------------- final EstimatedMeasurement estimated = - new EstimatedMeasurement<>(this, iteration, evaluation, - new SpacecraftState[] { - emitterState - }, - new TimeStampedPVCoordinates[] { - emitterPV, - tdoa > 0 ? secondPV : primePV, - tdoa > 0 ? primePV : secondPV - }); + new EstimatedMeasurement<>(this, iteration, evaluation, + new SpacecraftState[] { + common.getTransitState() + }, + new TimeStampedPVCoordinates[] { + emitterPV, + tdoa > 0.0 ? secondPV : common.getStationDownlink(), + tdoa > 0.0 ? common.getStationDownlink() : secondPV + }); // set TDOA value estimated.setEstimatedValue(tdoa); return estimated; - } /** {@inheritDoc} */ @@ -191,96 +155,49 @@ protected EstimatedMeasurement theoreticalEvaluation(final int iteration, final SpacecraftState state = states[0]; - // TDOA derivatives are computed with respect to: - // - Spacecraft state in inertial frame - // - Prime station parameters - // - Second station parameters - // -------------------------- + // TDOA derivatives are computed with respect to spacecraft state in inertial frame + // and station parameters + // ---------------------- + // + // Parameters: // - 0..2 - Position of the spacecraft in inertial frame // - 3..5 - Velocity of the spacecraft in inertial frame - // - 6..n - stations' parameters (clock offset, station offsets, pole, prime meridian...) - int nbParams = 6; - final Map indices = new HashMap<>(); - for (ParameterDriver driver : getParametersDrivers()) { - // we have to check for duplicate keys because primary and secondary station share - // pole and prime meridian parameters names that must be considered - // as one set only (they are combined together by the estimation engine) - if (driver.isSelected()) { - for (Span span = driver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) { - - if (!indices.containsKey(span.getData())) { - indices.put(span.getData(), nbParams++); - } - } - } - } - final FieldVector3D zero = FieldVector3D.getZero(GradientField.getField(nbParams)); - - // coordinates of the spacecraft as a gradient - final TimeStampedFieldPVCoordinates pvaG = getCoordinates(state, 0, nbParams); - - // transform between prime station frame and inertial frame - // at the real date of measurement, i.e. taking station clock offset into account - final FieldTransform primeToInert = - getStation().getOffsetToInertial(state.getFrame(), getDate(), nbParams, indices); - final FieldAbsoluteDate measurementDateG = primeToInert.getFieldDate(); - - // prime station PV in inertial frame at the real date of the measurement - final TimeStampedFieldPVCoordinates primePV = - primeToInert.transformPVCoordinates(new TimeStampedFieldPVCoordinates<>(measurementDateG, - zero, zero, zero)); - - // compute downlink delay from emitter to prime receiver - final Gradient tau1 = signalTimeOfFlight(pvaG, primePV.getPosition(), measurementDateG); - - // elapsed time between state date and signal arrival to the prime receiver - final Gradient dtMtau1 = measurementDateG.durationFrom(state.getDate()).subtract(tau1); - - // satellite state at signal emission - final SpacecraftState emitterState = state.shiftedBy(dtMtau1.getValue()); - - // satellite pv at signal emission (re)computed with gradient - final TimeStampedFieldPVCoordinates emitterPV = pvaG.shiftedBy(dtMtau1); - - // second station PV in inertial frame at real date of signal reception - TimeStampedFieldPVCoordinates secondPV; - // initialize search loop of the reception date by second station - Gradient tau2 = tau1; - double delta; - int count = 0; - do { - final double previous = tau2.getValue(); - // date of signal arrival on second receiver - final AbsoluteDate dateAt2 = emitterState.getDate().shiftedBy(previous); - // transform between second station frame and inertial frame - // at the date of signal arrival, taking clock offset into account - final FieldTransform secondToInert = - secondStation.getOffsetToInertial(state.getFrame(), dateAt2, - nbParams, indices); - // second receiver position in inertial frame at the real date of signal reception - secondPV = secondToInert.transformPVCoordinates(new TimeStampedFieldPVCoordinates<>(secondToInert.getFieldDate(), - zero, zero, zero)); - // downlink delay from emitter to second receiver - tau2 = linkDelay(emitterPV.getPosition(), secondPV.getPosition()); - - // Change in the computed downlink delay - delta = FastMath.abs(tau2.getValue() - previous); - } while (count++ < 10 && delta >= 2 * FastMath.ulp(tau2.getValue())); + // - 6..n - measurements parameters (clock offset, station offsets, pole, prime meridian, sat clock offset...) + final GroundReceiverCommonParametersWithDerivatives common = computeCommonParametersWithDerivatives(state); + final int nbParams = common.getTauD().getFreeParameters(); + final TimeStampedFieldPVCoordinates emitterPV = common.getTransitPV(); + final FieldAbsoluteDate emitterDate = emitterPV.getDate(); + + // Approximate secondary location (at emission time) + final FieldVector3D zero = FieldVector3D.getZero(common.getTauD().getField()); + final FieldTransform secondToInertial = + getSecondStation().getOffsetToInertial(state.getFrame(), emitterDate, nbParams, common.getIndices()); + final TimeStampedFieldPVCoordinates secondApprox = + secondToInertial.transformPVCoordinates(new TimeStampedFieldPVCoordinates<>(emitterDate, + zero, zero, zero)); + + // Time of flight from emitter to second station + final Gradient tau2 = forwardSignalTimeOfFlight(secondApprox, emitterPV.getPosition(), emitterDate); + + // Second station coordinates at receive time + final TimeStampedFieldPVCoordinates secondPV = secondApprox.shiftedBy(tau2); // The measured TDOA is (tau1 + clockOffset1) - (tau2 + clockOffset2) - final Gradient offset1 = getStation().getClockOffsetDriver().getValue(nbParams, indices, emitterState.getDate()); - final Gradient offset2 = secondStation.getClockOffsetDriver().getValue(nbParams, indices, emitterState.getDate()); - final Gradient tdoaG = tau1.add(offset1).subtract(tau2.add(offset2)); + final Gradient offset1 = getPrimeStation().getClockOffsetDriver() + .getValue(nbParams, common.getIndices(), emitterDate.toAbsoluteDate()); + final Gradient offset2 = getSecondStation().getClockOffsetDriver() + .getValue(nbParams, common.getIndices(), emitterDate.toAbsoluteDate()); + final Gradient tdoaG = common.getTauD().add(offset1).subtract(tau2.add(offset2)); final double tdoa = tdoaG.getValue(); // Evaluate the TDOA value and derivatives // ------------------------------------------- - final TimeStampedPVCoordinates pv1 = primePV.toTimeStampedPVCoordinates(); + final TimeStampedPVCoordinates pv1 = common.getStationDownlink().toTimeStampedPVCoordinates(); final TimeStampedPVCoordinates pv2 = secondPV.toTimeStampedPVCoordinates(); final EstimatedMeasurement estimated = new EstimatedMeasurement<>(this, iteration, evaluation, new SpacecraftState[] { - emitterState + common.getTransitState() }, new TimeStampedPVCoordinates[] { emitterPV.toTimeStampedPVCoordinates(), @@ -298,7 +215,7 @@ protected EstimatedMeasurement theoreticalEvaluation(final int iteration, // set partial derivatives with respect to parameters for (final ParameterDriver driver : getParametersDrivers()) { for (Span span = driver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) { - final Integer index = indices.get(span.getData()); + final Integer index = common.getIndices().get(span.getData()); if (index != null) { estimated.setParameterDerivatives(driver, span.getStart(), derivatives[index]); } @@ -306,28 +223,75 @@ protected EstimatedMeasurement theoreticalEvaluation(final int iteration, } return estimated; - } - /** Compute propagation delay on a link. - * @param emitter the position of the emitter - * @param receiver the position of the receiver (same frame as emitter) - * @return the propagation delay - * @since 12.0 + + /** Compute propagation delay on a link leg (typically downlink or uplink). This differs from signalTimeOfFlight + * through advancing rather than delaying the emitter. + * + * @param adjustableEmitterPV position/velocity of emitter that may be adjusted + * @param receiverPosition fixed position of receiver at {@code signalArrivalDate}, + * in the same frame as {@code adjustableEmitterPV} + * @param signalArrivalDate date at which the signal arrives to receiver + * @return positive delay between signal emission and signal reception dates */ - private double linkDelay(final Vector3D emitter, - final Vector3D receiver) { - return receiver.distance(emitter) / Constants.SPEED_OF_LIGHT; + public static double forwardSignalTimeOfFlight(final TimeStampedPVCoordinates adjustableEmitterPV, + final Vector3D receiverPosition, + final AbsoluteDate signalArrivalDate) { + + // initialize emission date search loop assuming the state is already correct + // this will be true for all but the first orbit determination iteration, + // and even for the first iteration the loop will converge very fast + final double offset = signalArrivalDate.durationFrom(adjustableEmitterPV.getDate()); + double delay = offset; + + // search signal transit date, computing the signal travel in inertial frame + final double cReciprocal = 1.0 / Constants.SPEED_OF_LIGHT; + double delta; + int count = 0; + do { + final double previous = delay; + final Vector3D transitP = adjustableEmitterPV.shiftedBy(delay - offset).getPosition(); + delay = receiverPosition.distance(transitP) * cReciprocal; + delta = FastMath.abs(delay - previous); + } while (count++ < 10 && delta >= 2 * FastMath.ulp(delay)); + + return delay; + } - /** Compute propagation delay on a link. - * @param emitter the position of the emitter - * @param receiver the position of the receiver (same frame as emitter) - * @return the propagation delay + /** Compute propagation delay on a link leg (typically downlink or uplink).This differs from signalTimeOfFlight + * through advancing rather than delaying the emitter. + * + * @param adjustableEmitterPV position/velocity of emitter that may be adjusted + * @param receiverPosition fixed position of receiver at {@code signalArrivalDate}, + * in the same frame as {@code adjustableEmitterPV} + * @param signalArrivalDate date at which the signal arrives to receiver + * @return positive delay between signal emission and signal reception dates + * @param the type of the components */ - private Gradient linkDelay(final FieldVector3D emitter, - final FieldVector3D receiver) { - return receiver.distance(emitter).divide(Constants.SPEED_OF_LIGHT); + public static > T forwardSignalTimeOfFlight(final TimeStampedFieldPVCoordinates adjustableEmitterPV, + final FieldVector3D receiverPosition, + final FieldAbsoluteDate signalArrivalDate) { + + // Initialize emission date search loop assuming the emitter PV is almost correct + // this will be true for all but the first orbit determination iteration, + // and even for the first iteration the loop will converge extremely fast + final T offset = signalArrivalDate.durationFrom(adjustableEmitterPV.getDate()); + T delay = offset; + + // search signal transit date, computing the signal travel in the frame shared by emitter and receiver + final double cReciprocal = 1.0 / Constants.SPEED_OF_LIGHT; + double delta; + int count = 0; + do { + final double previous = delay.getReal(); + final FieldVector3D transitP = adjustableEmitterPV.shiftedBy(delay.subtract(offset)).getPosition(); + delay = receiverPosition.distance(transitP).multiply(cReciprocal); + delta = FastMath.abs(delay.getReal() - previous); + } while (count++ < 10 && delta >= 2 * FastMath.ulp(delay.getReal())); + + return delay; } } diff --git a/src/test/java/org/orekit/estimation/measurements/BistaticRangeRateTest.java b/src/test/java/org/orekit/estimation/measurements/BistaticRangeRateTest.java index 3a574d1f35..bcba7855b6 100644 --- a/src/test/java/org/orekit/estimation/measurements/BistaticRangeRateTest.java +++ b/src/test/java/org/orekit/estimation/measurements/BistaticRangeRateTest.java @@ -138,7 +138,7 @@ public double[] value(final SpacecraftState state) { } } - Assertions.assertEquals(0, maxRelativeError, 1.4e-7); + Assertions.assertEquals(0, maxRelativeError, 3.7e-6); } @@ -203,7 +203,7 @@ public double[] value(final SpacecraftState state) { } } - Assertions.assertEquals(0, maxRelativeError, 2.1e-8); + Assertions.assertEquals(0, maxRelativeError, 3.7e-6); } @@ -284,7 +284,7 @@ public double value(final ParameterDriver parameterDriver, AbsoluteDate date) { } } - Assertions.assertEquals(0, maxRelativeError, 9.2e-8); + Assertions.assertEquals(0, maxRelativeError, 9.3e-8); } @@ -373,7 +373,7 @@ public double value(final ParameterDriver parameterDriver, AbsoluteDate date) { } } - Assertions.assertEquals(0, maxRelativeError, 5.3e-6); + Assertions.assertEquals(0, maxRelativeError, 2.0e-5); } diff --git a/src/test/java/org/orekit/estimation/measurements/FDOATest.java b/src/test/java/org/orekit/estimation/measurements/FDOATest.java index 00de3b235d..65acded1ab 100644 --- a/src/test/java/org/orekit/estimation/measurements/FDOATest.java +++ b/src/test/java/org/orekit/estimation/measurements/FDOATest.java @@ -135,7 +135,7 @@ public double[] value(final SpacecraftState state) { } } - Assertions.assertEquals(0, maxRelativeError, 2e-5); + Assertions.assertEquals(0, maxRelativeError, 5.4e-6); } @@ -212,11 +212,13 @@ public double value(final ParameterDriver parameterDriver, AbsoluteDate date) { } }, 3, 20.0 * drivers[i].getScale()); final double ref = dMkdP.value(drivers[i], date); - maxRelativeError = FastMath.max(maxRelativeError, FastMath.abs((ref - gradient[0]) / ref)); + if (ref != 0.0) { + maxRelativeError = FastMath.max(maxRelativeError, FastMath.abs((ref - gradient[0]) / ref)); + } } } - Assertions.assertEquals(0, maxRelativeError, 1e-4); + Assertions.assertEquals(0, maxRelativeError, 3.4e-8); } diff --git a/src/test/java/org/orekit/estimation/measurements/TDOATest.java b/src/test/java/org/orekit/estimation/measurements/TDOATest.java index 04c0cdc921..44da89611c 100644 --- a/src/test/java/org/orekit/estimation/measurements/TDOATest.java +++ b/src/test/java/org/orekit/estimation/measurements/TDOATest.java @@ -78,8 +78,8 @@ public void testValues() { } // Mean and std errors check - Assertions.assertEquals(0.0, diffStat.getMean(), 1.e-16); - Assertions.assertEquals(0.0, diffStat.getStandardDeviation(), 1.e-16); + Assertions.assertEquals(0.0, diffStat.getMean(), 1.4e-16); + Assertions.assertEquals(0.0, diffStat.getStandardDeviation(), 2.0e-16); // Test measurement type Assertions.assertEquals(TDOA.MEASUREMENT_TYPE, measurements.get(0).getMeasurementType()); @@ -206,7 +206,7 @@ public double[] value(final SpacecraftState state) { } - Assertions.assertEquals(0, maxRelativeError, 9.0e-4); + Assertions.assertEquals(0, maxRelativeError, 3.2e-3); } From 32f94b9d827eb611d7314ebe26b6c564769aa3d3 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Thu, 22 Feb 2024 16:49:54 +0100 Subject: [PATCH 131/359] Avoid copying ephemeris data. --- .../general/EphemerisSegmentPropagator.java | 37 ++- .../orekit/utils/FieldSortedListTrimmer.java | 167 +++++++++++++ .../orekit/utils/FieldTimeStampedCache.java | 28 ++- .../utils/ImmutableFieldTimeStampedCache.java | 129 ++-------- .../utils/ImmutableTimeStampedCache.java | 101 +------- .../org/orekit/utils/SortedListTrimmer.java | 157 ++++++++++++ .../IntelsatElevenElementsPropagatorTest.java | 4 +- .../utils/FieldSortedListTrimmerTest.java | 207 ++++++++++++++++ .../ImmutableFieldTimeStampedCacheTest.java | 8 +- .../orekit/utils/SortedListTrimmerTest.java | 232 ++++++++++++++++++ 10 files changed, 837 insertions(+), 233 deletions(-) create mode 100644 src/main/java/org/orekit/utils/FieldSortedListTrimmer.java create mode 100644 src/main/java/org/orekit/utils/SortedListTrimmer.java create mode 100644 src/test/java/org/orekit/utils/FieldSortedListTrimmerTest.java create mode 100644 src/test/java/org/orekit/utils/SortedListTrimmerTest.java diff --git a/src/main/java/org/orekit/files/general/EphemerisSegmentPropagator.java b/src/main/java/org/orekit/files/general/EphemerisSegmentPropagator.java index 1bd278ad8f..91021fc9a2 100644 --- a/src/main/java/org/orekit/files/general/EphemerisSegmentPropagator.java +++ b/src/main/java/org/orekit/files/general/EphemerisSegmentPropagator.java @@ -16,9 +16,8 @@ */ package org.orekit.files.general; +import java.util.ArrayList; import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.Stream; import org.hipparchus.geometry.euclidean.threed.Vector3D; import org.orekit.attitudes.AttitudeProvider; @@ -34,7 +33,7 @@ import org.orekit.propagation.analytical.AbstractAnalyticalPropagator; import org.orekit.time.AbsoluteDate; import org.orekit.time.TimeInterpolator; -import org.orekit.utils.ImmutableTimeStampedCache; +import org.orekit.utils.SortedListTrimmer; import org.orekit.utils.TimeStampedPVCoordinates; import org.orekit.utils.TimeStampedPVCoordinatesHermiteInterpolator; @@ -52,14 +51,10 @@ class EphemerisSegmentPropagator extends AbstractAnalyticalPropagator implements BoundedPropagator { - /** - * Sorted cache of state vectors. A duplication of the information in {@link - * #ephemeris} that could be avoided by duplicating the logic of {@link - * ImmutableTimeStampedCache#getNeighbors(AbsoluteDate)} for a general {@link List}. - */ - private final ImmutableTimeStampedCache cache; /** Tabular data from which this propagator is built. */ private final EphemerisSegment ephemeris; + /** Number of sample points to use. */ + private final int nbPoints; /** Inertial frame used for creating orbits. */ private final Frame inertialFrame; /** Frame of the ephemeris data. */ @@ -74,14 +69,12 @@ class EphemerisSegmentPropagator extends Abs EphemerisSegmentPropagator(final EphemerisSegment ephemeris, final AttitudeProvider attitudeProvider) { super(attitudeProvider); - this.cache = new ImmutableTimeStampedCache<>( - ephemeris.getInterpolationSamples(), - ephemeris.getCoordinates()); - this.ephemeris = ephemeris; + this.ephemeris = ephemeris; + this.nbPoints = ephemeris.getInterpolationSamples(); this.ephemerisFrame = ephemeris.getFrame(); - this.inertialFrame = ephemeris.getInertialFrame(); + this.inertialFrame = ephemeris.getInertialFrame(); // set the initial state so getFrame() works - final TimeStampedPVCoordinates ic = cache.getEarliest(); + final TimeStampedPVCoordinates ic = ephemeris.getCoordinates().get(0); final TimeStampedPVCoordinates icInertial = ephemerisFrame .getTransformTo(inertialFrame, ic.getDate()) .transformPVCoordinates(ic); @@ -156,19 +149,19 @@ public void resetInitialState(final SpacecraftState state) { * @return interpolated position-velocity vector */ private TimeStampedPVCoordinates interpolate(final AbsoluteDate date) { - final Stream neighbors = this.cache.getNeighbors(date); + final List neighbors = new SortedListTrimmer(nbPoints). + getNeighborsSubList(date, ephemeris.getCoordinates()); // cast stream to super type - final Stream castedNeighbors = neighbors.map(neighbor -> (TimeStampedPVCoordinates) neighbor); - - // convert to list - final List castedNeighborsList = castedNeighbors.collect(Collectors.toList()); + final List castedNeighbors = new ArrayList<>(neighbors.size()); + castedNeighbors.addAll(neighbors); // create interpolator final TimeInterpolator interpolator = - new TimeStampedPVCoordinatesHermiteInterpolator(castedNeighborsList.size(), ephemeris.getAvailableDerivatives()); + new TimeStampedPVCoordinatesHermiteInterpolator(nbPoints, + ephemeris.getAvailableDerivatives()); - return interpolator.interpolate(date, castedNeighborsList); + return interpolator.interpolate(date, castedNeighbors); } } diff --git a/src/main/java/org/orekit/utils/FieldSortedListTrimmer.java b/src/main/java/org/orekit/utils/FieldSortedListTrimmer.java new file mode 100644 index 0000000000..ae88c45900 --- /dev/null +++ b/src/main/java/org/orekit/utils/FieldSortedListTrimmer.java @@ -0,0 +1,167 @@ +/* Copyright 2002-2024 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.utils; + +import org.hipparchus.CalculusFieldElement; +import org.hipparchus.exception.LocalizedCoreFormats; +import org.hipparchus.util.FastMath; +import org.orekit.errors.OrekitException; +import org.orekit.errors.OrekitIllegalArgumentException; +import org.orekit.errors.OrekitMessages; +import org.orekit.errors.TimeStampedCacheException; +import org.orekit.time.FieldAbsoluteDate; +import org.orekit.time.FieldTimeStamped; + +import java.util.List; + +/** A trimmer for externally stored chronologically sorted lists. + * @author Evan Ward + * @author Vincent Cucchietti + * @since 12.1 + */ +public class FieldSortedListTrimmer { + + /** Size list to return from {@link #getNeighborsSubList(FieldAbsoluteDate, List)}. */ + private final int neighborsSize; + + /** + * Create a new cache with the given neighbors size and data. + * + * @param neighborsSize size of the list returned from {@link #getNeighborsSubList(FieldAbsoluteDate, List)}. + */ + public FieldSortedListTrimmer(final int neighborsSize) { + if (neighborsSize < 1) { + throw new OrekitIllegalArgumentException(LocalizedCoreFormats.NUMBER_TOO_SMALL, + neighborsSize, 1); + } + // assign instance variables + this.neighborsSize = neighborsSize; + } + + /** Get size of the list returned from {@link #getNeighborsSubList(FieldAbsoluteDate, List)}. + * @return size of the list returned from {@link #getNeighborsSubList(FieldAbsoluteDate, List)} + */ + public int getNeighborsSize() { + return neighborsSize; + } + + /** Get the entries surrounding a central date. + *

                + * If the central date is well within covered range, the returned array will + * be balanced with half the points before central date and half the points + * after it (depending on n parity, of course). If the central date is near + * the boundary, then the returned array will be unbalanced and will contain + * only the n earliest (or latest) entries. A typical example of the later + * case is leap seconds cache, since the number of leap seconds cannot be + * arbitrarily increased. + *

                + * @param the type of data + * @param the type of the field elements + * @param central central date + * @param data complete list of entries (must be chronologically sorted) + * @return entries surrounding the specified date (sublist of {@code data}) + */ + public , K extends CalculusFieldElement> + List getNeighborsSubList(final FieldAbsoluteDate central, final List data) { + + if (neighborsSize > data.size()) { + throw new OrekitException(OrekitMessages.NOT_ENOUGH_DATA, data.size()); + } + + // Find central index + final int i = findIndex(central, data); + + // Check index in the range of the data + if (i < 0) { + final FieldAbsoluteDate earliest = data.get(0).getDate(); + throw new TimeStampedCacheException(OrekitMessages.UNABLE_TO_GENERATE_NEW_DATA_BEFORE, + earliest, central, earliest.durationFrom(central).getReal()); + } + else if (i >= data.size()) { + final FieldAbsoluteDate latest = data.get(data.size() - 1).getDate(); + throw new TimeStampedCacheException(OrekitMessages.UNABLE_TO_GENERATE_NEW_DATA_AFTER, + latest, central, central.durationFrom(latest).getReal()); + } + + // Force unbalanced range if necessary + int start = FastMath.max(0, i - (neighborsSize - 1) / 2); + final int end = FastMath.min(data.size(), start + neighborsSize); + start = end - neighborsSize; + + // Return list without copying + return data.subList(start, end); + } + + /** + * Find the index, i, to {@code data} such that {@code data[i] <= t} and + * {@code data[i+1] > t} if {@code data[i+1]} exists. + * + * @param the type of data + * @param the type of the field elements + * @param t the time + * @param data complete list of entries (must be chronologically sorted) + * + * @return the index of the data at or just before {@code t}, {@code -1} if {@code t} is before the first entry, or + * {@code data.size()} if {@code t} is after the last entry. + */ + private , K extends CalculusFieldElement> + int findIndex(final FieldAbsoluteDate t, final List data) { + // left bracket of search algorithm + int iInf = 0; + K dtInf = t.durationFrom(data.get(0)); + if (dtInf.getReal() < 0) { + // before first entry + return -1; + } + + // right bracket of search algorithm + int iSup = data.size() - 1; + K dtSup = t.durationFrom(data.get(data.size() - 1)); + if (dtSup.getReal() > 0) { + // after last entry + return data.size(); + } + + // search entries, using linear interpolation + // this should take only 2 iterations for near linear entries (most frequent use case) + // regardless of the number of entries + // this is much faster than binary search for large number of entries + while (iSup - iInf > 1) { + final int iInterp = (int) FastMath.rint(dtSup.multiply(iInf).subtract(dtInf.multiply(iSup)).divide(dtSup.subtract(dtInf)).getReal()); + final int iMed = FastMath.max(iInf + 1, FastMath.min(iInterp, iSup - 1)); + final K dtMed = t.durationFrom(data.get(iMed).getDate()); + if (dtMed.getReal() < 0) { + iSup = iMed; + dtSup = dtMed; + } else { + iInf = iMed; + dtInf = dtMed; + } + } + + // at this point data[iInf] <= t <= data[iSup], but the javadoc for this method + // says the upper bound is exclusive, so check for equality to make a half open + // interval. + if (dtSup.getReal() == 0.0) { + return iSup; + } + + return iInf; + + } + +} diff --git a/src/main/java/org/orekit/utils/FieldTimeStampedCache.java b/src/main/java/org/orekit/utils/FieldTimeStampedCache.java index f51f8266d6..dd88d47cc9 100644 --- a/src/main/java/org/orekit/utils/FieldTimeStampedCache.java +++ b/src/main/java/org/orekit/utils/FieldTimeStampedCache.java @@ -50,16 +50,38 @@ public interface FieldTimeStampedCache, KK extend * @param central central date * * @return list of cached entries surrounding the specified date. The size of the list is guaranteed to be - * {@link #getNeighborsSize()}. + * {@link #getMaxNeighborsSize()}. */ - Stream getNeighbors(FieldAbsoluteDate central); + default Stream getNeighbors(FieldAbsoluteDate central) { + return getNeighbors(central, getMaxNeighborsSize()); + } + + /** + * Get the entries surrounding a central date. + *

                + * If the central date is well within covered range, the returned array will be balanced with half the points before + * central date and half the points after it (depending on n parity, of course). If the central date is near the + * boundary, then the returned array will be unbalanced and will contain only the n earliest (or latest) entries. A + * typical example of the later case is leap seconds cache, since the number of leap seconds cannot be arbitrarily + * increased. + *

                + * This method is safe for multiple threads to execute concurrently. + * + * @param central central date + * @param n number of neighbors (cannot exceed {@link #getMaxNeighborsSize()}) + * + * @return list of cached entries surrounding the specified date. The size of the list is guaranteed to be + * {@link #getMaxNeighborsSize()}. + * @since 12.1 + */ + Stream getNeighbors(FieldAbsoluteDate central, int n); /** * Get the fixed size of the lists returned by {@link #getNeighbors(FieldAbsoluteDate)}. * * @return size of the list */ - int getNeighborsSize(); + int getMaxNeighborsSize(); /** * Get the earliest entry in this cache. diff --git a/src/main/java/org/orekit/utils/ImmutableFieldTimeStampedCache.java b/src/main/java/org/orekit/utils/ImmutableFieldTimeStampedCache.java index 532163ff4c..c831923358 100644 --- a/src/main/java/org/orekit/utils/ImmutableFieldTimeStampedCache.java +++ b/src/main/java/org/orekit/utils/ImmutableFieldTimeStampedCache.java @@ -25,11 +25,7 @@ import org.hipparchus.CalculusFieldElement; import org.hipparchus.Field; import org.hipparchus.exception.LocalizedCoreFormats; -import org.hipparchus.util.FastMath; -import org.orekit.errors.OrekitIllegalArgumentException; -import org.orekit.errors.OrekitIllegalStateException; -import org.orekit.errors.OrekitMessages; -import org.orekit.errors.TimeStampedCacheException; +import org.orekit.errors.*; import org.orekit.time.FieldAbsoluteDate; import org.orekit.time.FieldChronologicalComparator; import org.orekit.time.FieldTimeStamped; @@ -55,62 +51,47 @@ public class ImmutableFieldTimeStampedCache, KK e */ private final List data; - /** the size list to return from {@link #getNeighbors(FieldAbsoluteDate)}. */ - private final int neighborsSize; - - /** Earliest date. - * @since 12.0 - */ - private final FieldAbsoluteDate earliestDate; - - /** Latest date. - * @since 12.0 - */ - private final FieldAbsoluteDate latestDate; + /** the maximum size list to return from {@link #getNeighbors(FieldAbsoluteDate)}. */ + private final int maxNeighborsSize; /** * Create a new cache with the given neighbors size and data. * - * @param neighborsSize the size of the list returned from {@link #getNeighbors(FieldAbsoluteDate)}. Must be less than or + * @param maxNeighborsSize the maximum size of the list returned from {@link #getNeighbors(FieldAbsoluteDate)}. Must be less than or * equal to {@code data.size()}. * @param data the backing data for this cache. The list will be copied to ensure immutability. To guarantee immutability - * the entries in {@code data} must be immutable themselves. There must be more data than {@code neighborsSize}. + * the entries in {@code data} must be immutable themselves. There must be more data than {@code maxNeighborsSize}. * - * @throws IllegalArgumentException if {@code neighborsSize > data.size()} or if {@code neighborsSize} is negative + * @throws IllegalArgumentException if {@code maxNeighborsSize > data.size()} or if {@code maxNeighborsSize} is negative */ - public ImmutableFieldTimeStampedCache(final int neighborsSize, + public ImmutableFieldTimeStampedCache(final int maxNeighborsSize, final Collection data) { // Parameter check - if (neighborsSize > data.size()) { + if (maxNeighborsSize > data.size()) { throw new OrekitIllegalArgumentException(OrekitMessages.NOT_ENOUGH_CACHED_NEIGHBORS, - data.size(), neighborsSize); + data.size(), maxNeighborsSize); } - if (neighborsSize < 1) { + if (maxNeighborsSize < 1) { throw new OrekitIllegalArgumentException(LocalizedCoreFormats.NUMBER_TOO_SMALL, - neighborsSize, 0); + maxNeighborsSize, 1); } // Assign instance variables - this.neighborsSize = neighborsSize; + this.maxNeighborsSize = maxNeighborsSize; // Sort and copy data first this.data = new ArrayList<>(data); Collections.sort(this.data, new FieldChronologicalComparator<>()); - this.earliestDate = this.data.get(0).getDate(); - this.latestDate = this.data.get(this.data.size() - 1).getDate(); - } /** - * private constructor for {@link #EMPTY_CACHE}. + * private constructor for {@link #emptyCache(Field)}. * @param field field to which the elements belong */ private ImmutableFieldTimeStampedCache(final Field field) { - this.data = null; - this.neighborsSize = 0; - this.earliestDate = FieldAbsoluteDate.getArbitraryEpoch(field); - this.latestDate = FieldAbsoluteDate.getArbitraryEpoch(field); + this.data = null; + this.maxNeighborsSize = 0; } /** @@ -127,36 +108,16 @@ ImmutableFieldTimeStampedCache emptyCache(final Field field) { } /** {@inheritDoc} */ - public Stream getNeighbors(final FieldAbsoluteDate central) { - - // Find central index - final int i = findIndex(central); - - // Check index in the range of the data - if (i < 0) { - final FieldAbsoluteDate earliest = this.getEarliest().getDate(); - throw new TimeStampedCacheException(OrekitMessages.UNABLE_TO_GENERATE_NEW_DATA_BEFORE, - earliest, central, earliest.durationFrom(central).getReal()); - } - else if (i >= this.data.size()) { - final FieldAbsoluteDate latest = this.getLatest().getDate(); - throw new TimeStampedCacheException(OrekitMessages.UNABLE_TO_GENERATE_NEW_DATA_AFTER, - latest, central, central.durationFrom(latest).getReal()); + public Stream getNeighbors(final FieldAbsoluteDate central, final int n) { + if (n > maxNeighborsSize) { + throw new OrekitException(OrekitMessages.NOT_ENOUGH_DATA, maxNeighborsSize); } - - // Force unbalanced range if necessary - int start = FastMath.max(0, i - (this.neighborsSize - 1) / 2); - final int end = FastMath.min(this.data.size(), start + - this.neighborsSize); - start = end - this.neighborsSize; - - // Return list without copying - return this.data.subList(start, end).stream(); + return new FieldSortedListTrimmer(n).getNeighborsSubList(central, data).stream(); } /** {@inheritDoc} */ - public int getNeighborsSize() { - return this.neighborsSize; + public int getMaxNeighborsSize() { + return this.maxNeighborsSize; } /** {@inheritDoc} */ @@ -185,52 +146,6 @@ public String toString() { return "Immutable cache with " + this.data.size() + " entries"; } - /** - * Find the index, i, to {@link #data} such that {@code data[i] <= t} and {@code data[i+1] > t} if {@code data[i+1]} - * exists. - * - * @param t the time - * - * @return the index of the data at or just before {@code t}, {@code -1} if {@code t} is before the first entry, or - * {@code data.size()} if {@code t} is after the last entry. - */ - private int findIndex(final FieldAbsoluteDate t) { - // left bracket of search algorithm - int iInf = 0; - KK dtInf = t.durationFrom(earliestDate); - if (dtInf.getReal() < 0) { - // before first entry - return -1; - } - - // right bracket of search algorithm - int iSup = data.size() - 1; - KK dtSup = t.durationFrom(latestDate); - if (dtSup.getReal() > 0) { - // after last entry - return data.size(); - } - - // search entries, using linear interpolation - // this should take only 2 iterations for near linear entries (most frequent use case) - // regardless of the number of entries - // this is much faster than binary search for large number of entries - while (iSup - iInf > 1) { - final int iInterp = (int) FastMath.rint(dtSup.multiply(iInf).subtract(dtInf.multiply(iSup)).divide(dtSup.subtract(dtInf)).getReal()); - final int iMed = FastMath.max(iInf + 1, FastMath.min(iInterp, iSup - 1)); - final KK dtMed = t.durationFrom(data.get(iMed).getDate()); - if (dtMed.getReal() < 0) { - iSup = iMed; - dtSup = dtMed; - } else { - iInf = iMed; - dtInf = dtMed; - } - } - - return iInf; - } - /** An empty immutable cache that always throws an exception on attempted access. */ private static class EmptyFieldTimeStampedCache, KK extends CalculusFieldElement> extends ImmutableFieldTimeStampedCache { @@ -250,7 +165,7 @@ public Stream getNeighbors(final FieldAbsoluteDate central) { /** {@inheritDoc} */ @Override - public int getNeighborsSize() { + public int getMaxNeighborsSize() { return 0; } diff --git a/src/main/java/org/orekit/utils/ImmutableTimeStampedCache.java b/src/main/java/org/orekit/utils/ImmutableTimeStampedCache.java index 95febb133b..10b3dc2690 100644 --- a/src/main/java/org/orekit/utils/ImmutableTimeStampedCache.java +++ b/src/main/java/org/orekit/utils/ImmutableTimeStampedCache.java @@ -23,7 +23,6 @@ import java.util.stream.Stream; import org.hipparchus.exception.LocalizedCoreFormats; -import org.hipparchus.util.FastMath; import org.orekit.errors.OrekitException; import org.orekit.errors.OrekitIllegalArgumentException; import org.orekit.errors.OrekitIllegalStateException; @@ -51,7 +50,7 @@ public class ImmutableTimeStampedCache */ @SuppressWarnings("rawtypes") private static final ImmutableTimeStampedCache EMPTY_CACHE = - new EmptyTimeStampedCache(); + new EmptyTimeStampedCache<>(); /** * the cached data. Be careful not to modify it after the constructor, or @@ -65,16 +64,6 @@ public class ImmutableTimeStampedCache */ private final int maxNeighborsSize; - /** Earliest date. - * @since 12.0 - */ - private final AbsoluteDate earliestDate; - - /** Latest date. - * @since 12.0 - */ - private final AbsoluteDate latestDate; - /** * Create a new cache with the given neighbors size and data. * @@ -97,17 +86,14 @@ public ImmutableTimeStampedCache(final int maxNeighborsSize, } if (maxNeighborsSize < 1) { throw new OrekitIllegalArgumentException(LocalizedCoreFormats.NUMBER_TOO_SMALL, - maxNeighborsSize, 0); + maxNeighborsSize, 1); } // assign instance variables this.maxNeighborsSize = maxNeighborsSize; // sort and copy data first this.data = new ArrayList<>(data); - Collections.sort(this.data, new ChronologicalComparator()); - - this.earliestDate = this.data.get(0).getDate(); - this.latestDate = this.data.get(this.data.size() - 1).getDate(); + this.data.sort(new ChronologicalComparator()); } @@ -117,91 +103,14 @@ public ImmutableTimeStampedCache(final int maxNeighborsSize, private ImmutableTimeStampedCache() { this.data = null; this.maxNeighborsSize = 0; - this.earliestDate = AbsoluteDate.ARBITRARY_EPOCH; - this.latestDate = AbsoluteDate.ARBITRARY_EPOCH; } /** {@inheritDoc} */ public Stream getNeighbors(final AbsoluteDate central, final int n) { - if (n > maxNeighborsSize) { throw new OrekitException(OrekitMessages.NOT_ENOUGH_DATA, maxNeighborsSize); } - - // find central index - final int i = findIndex(central); - - // check index in in the range of the data - if (i < 0) { - final AbsoluteDate earliest = this.getEarliest().getDate(); - throw new TimeStampedCacheException(OrekitMessages.UNABLE_TO_GENERATE_NEW_DATA_BEFORE, - earliest, central, earliest.durationFrom(central)); - } else if (i >= this.data.size()) { - final AbsoluteDate latest = this.getLatest().getDate(); - throw new TimeStampedCacheException(OrekitMessages.UNABLE_TO_GENERATE_NEW_DATA_AFTER, - latest, central, central.durationFrom(latest)); - } - - // force unbalanced range if necessary - int start = FastMath.max(0, i - (n - 1) / 2); - final int end = FastMath.min(this.data.size(), start + n); - start = end - n; - - // return list without copying - return this.data.subList(start, end).stream(); - } - - /** - * Find the index, i, to {@link #data} such that {@code data[i] <= t} and - * {@code data[i+1] > t} if {@code data[i+1]} exists. - * - * @param t the time - * @return the index of the data at or just before {@code t}, {@code -1} if - * {@code t} is before the first entry, or {@code data.size()} if - * {@code t} is after the last entry. - */ - private int findIndex(final AbsoluteDate t) { - - // left bracket of search algorithm - int iInf = 0; - double dtInf = t.durationFrom(earliestDate); - if (dtInf < 0) { - // before first entry - return -1; - } - - // right bracket of search algorithm - int iSup = data.size() - 1; - double dtSup = t.durationFrom(latestDate); - if (dtSup > 0) { - // after last entry - return data.size(); - } - - // search entries, using linear interpolation - // this should take only 2 iterations for near linear entries (most frequent use case) - // regardless of the number of entries - // this is much faster than binary search for large number of entries - while (iSup - iInf > 1) { - final int iInterp = (int) FastMath.rint((iInf * dtSup - iSup * dtInf) / (dtSup - dtInf)); - final int iMed = FastMath.max(iInf + 1, FastMath.min(iInterp, iSup - 1)); - final double dtMed = t.durationFrom(data.get(iMed).getDate()); - if (dtMed < 0) { - iSup = iMed; - dtSup = dtMed; - } else { - iInf = iMed; - dtInf = dtMed; - } - } - - // at this point data[iInf] <= t <= data[iSup], but the javadoc for this method - // says the upper bound is exclusive, so check for equality to make a half open - // interval. - if (dtSup == 0.0) { - return iSup; - } - return iInf; + return new SortedListTrimmer(n).getNeighborsSubList(central, data).stream(); } /** {@inheritDoc} */ @@ -285,7 +194,7 @@ public String toString() { * @return an empty {@link ImmutableTimeStampedCache}. */ @SuppressWarnings("unchecked") - public static final ImmutableTimeStampedCache emptyCache() { + public static ImmutableTimeStampedCache emptyCache() { return (ImmutableTimeStampedCache) EMPTY_CACHE; } diff --git a/src/main/java/org/orekit/utils/SortedListTrimmer.java b/src/main/java/org/orekit/utils/SortedListTrimmer.java new file mode 100644 index 0000000000..1d8ecfe305 --- /dev/null +++ b/src/main/java/org/orekit/utils/SortedListTrimmer.java @@ -0,0 +1,157 @@ +/* Contributed in the public domain. + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.utils; + +import org.hipparchus.exception.LocalizedCoreFormats; +import org.hipparchus.util.FastMath; +import org.orekit.errors.*; +import org.orekit.time.*; + +import java.util.List; + +/** A trimmer for externally stored chronologically sorted lists. + * + * @author Evan Ward + * @since 12.1 + */ +public class SortedListTrimmer { + + /** Size of the list to return from {@link #getNeighborsSubList(AbsoluteDate, List)}. */ + private final int neighborsSize; + + /** Create a new trimmer with the given neighbors size. + * @param neighborsSize size of the list returned from {@link #getNeighborsSubList(AbsoluteDate, List)} + */ + public SortedListTrimmer(final int neighborsSize) { + if (neighborsSize < 1) { + throw new OrekitIllegalArgumentException(LocalizedCoreFormats.NUMBER_TOO_SMALL, + neighborsSize, 1); + } + // assign instance variables + this.neighborsSize = neighborsSize; + } + + /** Get size of the list returned from {@link #getNeighborsSubList(AbsoluteDate, List)}. + * @return size of the list returned from {@link #getNeighborsSubList(AbsoluteDate, List)} + */ + public int getNeighborsSize() { + return neighborsSize; + } + + /** Get the entries surrounding a central date. + *

                + * If the central date is well within covered range, the returned array will + * be balanced with half the points before central date and half the points + * after it (depending on n parity, of course). If the central date is near + * the boundary, then the returned array will be unbalanced and will contain + * only the n earliest (or latest) entries. A typical example of the later + * case is leap seconds cache, since the number of leap seconds cannot be + * arbitrarily increased. + *

                + * @param the type of data + * @param central central date + * @param data complete list of entries (must be chronologically sorted) + * @return entries surrounding the specified date (sublist of {@code data}) + */ + public List getNeighborsSubList(final AbsoluteDate central, final List data) { + + if (neighborsSize > data.size()) { + throw new OrekitException(OrekitMessages.NOT_ENOUGH_DATA, data.size()); + } + + // find central index + final int i = findIndex(central, data); + + // check index in in the range of the data + if (i < 0) { + final AbsoluteDate earliest = data.get(0).getDate(); + throw new TimeStampedCacheException(OrekitMessages.UNABLE_TO_GENERATE_NEW_DATA_BEFORE, + earliest, central, earliest.durationFrom(central)); + } else if (i >= data.size()) { + final AbsoluteDate latest = data.get(data.size() - 1).getDate(); + throw new TimeStampedCacheException(OrekitMessages.UNABLE_TO_GENERATE_NEW_DATA_AFTER, + latest, central, central.durationFrom(latest)); + } + + // force unbalanced range if necessary + int start = FastMath.max(0, i - (neighborsSize - 1) / 2); + final int end = FastMath.min(data.size(), start + neighborsSize); + start = end - neighborsSize; + + // return list without copying + return data.subList(start, end); + + } + + /** + * Find the index, i, to {@code data} such that {@code data[i] <= t} and + * {@code data[i+1] > t} if {@code data[i+1]} exists. + * + * @param the type of data + * @param t the time + * @param data complete list of entries (must be chronologically sorted) + * @return the index of the data at or just before {@code t}, {@code -1} if + * {@code t} is before the first entry, or {@code data.size()} if + * {@code t} is after the last entry. + */ + private int findIndex(final AbsoluteDate t, final List data) { + + // left bracket of search algorithm + int iInf = 0; + double dtInf = t.durationFrom(data.get(0)); + if (dtInf < 0) { + // before first entry + return -1; + } + + // right bracket of search algorithm + int iSup = data.size() - 1; + double dtSup = t.durationFrom(data.get(data.size() - 1)); + if (dtSup > 0) { + // after last entry + return data.size(); + } + + // search entries, using linear interpolation + // this should take only 2 iterations for near linear entries (most frequent use case) + // regardless of the number of entries + // this is much faster than binary search for large number of entries + while (iSup - iInf > 1) { + final int iInterp = (int) FastMath.rint((iInf * dtSup - iSup * dtInf) / (dtSup - dtInf)); + final int iMed = FastMath.max(iInf + 1, FastMath.min(iInterp, iSup - 1)); + final double dtMed = t.durationFrom(data.get(iMed).getDate()); + if (dtMed < 0) { + iSup = iMed; + dtSup = dtMed; + } else { + iInf = iMed; + dtInf = dtMed; + } + } + + // at this point data[iInf] <= t <= data[iSup], but the javadoc for this method + // says the upper bound is exclusive, so check for equality to make a half open + // interval. + if (dtSup == 0.0) { + return iSup; + } + + return iInf; + + } + +} diff --git a/src/test/java/org/orekit/propagation/analytical/intelsat/IntelsatElevenElementsPropagatorTest.java b/src/test/java/org/orekit/propagation/analytical/intelsat/IntelsatElevenElementsPropagatorTest.java index 95e8e4702f..a4eb7f7539 100644 --- a/src/test/java/org/orekit/propagation/analytical/intelsat/IntelsatElevenElementsPropagatorTest.java +++ b/src/test/java/org/orekit/propagation/analytical/intelsat/IntelsatElevenElementsPropagatorTest.java @@ -21,6 +21,7 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import org.orekit.Utils; import org.orekit.errors.OrekitException; import org.orekit.errors.OrekitMessages; import org.orekit.frames.FramesFactory; @@ -92,8 +93,9 @@ public void testOrbitElementsAtT0() { @BeforeAll public static void initialize() { + Utils.setDataRoot("regular-data"); // Reference elements from Intelsat website (spacecraft 4521) ELEMENTS = new IntelsatElevenElements(new AbsoluteDate("2023-12-04T00:00:00.000", TimeScalesFactory.getUTC()), 302.0058, -0.0096, -0.000629, 0.0297, -0.0004, -0.0194, 0.0007, 0.0378, -0.0018, -0.0011, 0.0015); } -} \ No newline at end of file +} diff --git a/src/test/java/org/orekit/utils/FieldSortedListTrimmerTest.java b/src/test/java/org/orekit/utils/FieldSortedListTrimmerTest.java new file mode 100644 index 0000000000..140b8e4259 --- /dev/null +++ b/src/test/java/org/orekit/utils/FieldSortedListTrimmerTest.java @@ -0,0 +1,207 @@ +/* Contributed in the public domain. + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.utils; + +import org.hipparchus.Field; +import org.hipparchus.util.Binary64; +import org.hipparchus.util.Binary64Field; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.orekit.Utils; +import org.orekit.errors.OrekitException; +import org.orekit.errors.OrekitMessages; +import org.orekit.errors.TimeStampedCacheException; +import org.orekit.time.FieldAbsoluteDate; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * Unit tests for {@link FieldSortedListTrimmer}. + * + * @author Evan Ward + */ +public class FieldSortedListTrimmerTest { + + /** + * Binary64 field. + */ + private static final Field field = Binary64Field.getInstance(); + + /** + * arbitrary date + */ + private static final FieldAbsoluteDate date = FieldAbsoluteDate.getCCSDSEpoch(field); + + /** + * data provided to {@link #trimmer} + */ + private List> data; + + /** + * subject under test + */ + private FieldSortedListTrimmer trimmer; + + /** + * set Orekit data for useful debugging messages from dates. + */ + @BeforeAll + public static void setUpBefore() { + Utils.setDataRoot("regular-data"); + } + + /** + * create {@link #trimmer} and {@link #data} with neighborsSize = 3 + */ + @BeforeEach + public void setUp() { + data = Arrays.asList(date, date.shiftedBy(1), date.shiftedBy(2), + date.shiftedBy(3), date.shiftedBy(4), + date.shiftedBy(5)); + trimmer = new FieldSortedListTrimmer(3); + } + + /** + * check {@link FieldSortedListTrimmer#getNeighborsSubList(FieldAbsoluteDate, List)} + */ + @Test + public void testGetNeighborsSubList() { + // exception for neighborsSize > data.size() + try { + new FieldSortedListTrimmer(data.size() + 1).getNeighborsSubList(date, data); + Assertions.fail("Expected Exception"); + } catch (OrekitException e) { + Assertions.assertEquals(OrekitMessages.NOT_ENOUGH_DATA, e.getSpecifier()); + } + + // exception for non-positive neighborsSize + try { + new FieldSortedListTrimmer(0); + Assertions.fail("Expected Exception"); + } catch (IllegalArgumentException e) { + // expected + } + + // exception for null data + try { + new FieldSortedListTrimmer(1).getNeighborsSubList(date, null); + Assertions.fail("Expected Exception"); + } catch (NullPointerException e) { + // expected + } + + // exception for zero data + try { + new FieldSortedListTrimmer(1).getNeighborsSubList(date, Collections.emptyList()); + Assertions.fail("Expected Exception"); + } catch (OrekitException e) { + Assertions.assertEquals(OrekitMessages.NOT_ENOUGH_DATA, e.getSpecifier()); + } + } + + /** + * check {@link FieldSortedListTrimmer#getNeighborsSubList(FieldAbsoluteDate, List)} + * at a series of different dates designed to test all logic paths. + */ + @Test + public void testgetNeighborsSubList() { + // setup + int size = data.size(); + + // actions + verify + + // before fist data + try { + trimmer.getNeighborsSubList(data.get(0).shiftedBy(-1), data); + Assertions.fail("Expected Exception"); + } + catch (TimeStampedCacheException e) { + // expected + Assertions.assertEquals(OrekitMessages.UNABLE_TO_GENERATE_NEW_DATA_BEFORE, e.getSpecifier()); + } + + // on fist date + Assertions.assertArrayEquals(trimmer.getNeighborsSubList(data.get(0), data).toArray(), + data.subList(0, 3).toArray()); + // between fist and second date + Assertions.assertArrayEquals(trimmer.getNeighborsSubList(data.get(0).shiftedBy(0.5), data).toArray(), + data.subList(0, 3).toArray()); + // in the middle on a date + Assertions.assertArrayEquals(trimmer.getNeighborsSubList(data.get(2), data).toArray(), + data.subList(1, 4).toArray()); + // in the middle between dates + Assertions.assertArrayEquals(trimmer.getNeighborsSubList(data.get(2).shiftedBy(0.5), data).toArray(), + data.subList(1, 4).toArray()); + // just before last date + Assertions.assertArrayEquals(trimmer.getNeighborsSubList(data.get(size - 1).shiftedBy(-0.5), data).toArray(), + data.subList(size - 3, size).toArray()); + // on last date + Assertions.assertArrayEquals(trimmer.getNeighborsSubList(data.get(size - 1), data).toArray(), + data.subList(size - 3, size).toArray()); + + // after last date + FieldAbsoluteDate central = data.get(size - 1).shiftedBy(1); + try { + trimmer.getNeighborsSubList(central, data); + Assertions.fail("Expected Exception"); + } + catch (TimeStampedCacheException e) { + // expected + Assertions.assertEquals(OrekitMessages.UNABLE_TO_GENERATE_NEW_DATA_AFTER, e.getSpecifier()); + } + } + + /** + * check {@link FieldSortedListTrimmer#getNeighborsSize()} + */ + @Test + public void testGetNeighborsSize() { + Assertions.assertEquals(trimmer.getNeighborsSize(), 3); + } + + @Test + public void testNonLinear() { + final List> nonLinearCache = Arrays.asList(date.shiftedBy(10), + date.shiftedBy(14), + date.shiftedBy(18), + date.shiftedBy(23), + date.shiftedBy(30), + date.shiftedBy(36), + date.shiftedBy(45), + date.shiftedBy(55), + date.shiftedBy(67), + date.shiftedBy(90), + date.shiftedBy(118)); + for (double dt = 10; dt < 118; dt += 0.01) { + checkNeighbors(new FieldSortedListTrimmer(2), nonLinearCache, dt); + } + } + + private void checkNeighbors(final FieldSortedListTrimmer nonLinearTrimmer, + final List> nonLinearCache, + final double offset) { + List> s = nonLinearTrimmer.getNeighborsSubList(date.shiftedBy(offset), nonLinearCache); + Assertions.assertEquals(2, s.size()); + Assertions.assertTrue(s.get(0).durationFrom(date).getReal() <= offset); + Assertions.assertTrue(s.get(1).durationFrom(date).getReal() > offset); + } + +} diff --git a/src/test/java/org/orekit/utils/ImmutableFieldTimeStampedCacheTest.java b/src/test/java/org/orekit/utils/ImmutableFieldTimeStampedCacheTest.java index 8e62cf2ebd..d67f817bad 100644 --- a/src/test/java/org/orekit/utils/ImmutableFieldTimeStampedCacheTest.java +++ b/src/test/java/org/orekit/utils/ImmutableFieldTimeStampedCacheTest.java @@ -177,11 +177,11 @@ public void testGetNeighbors() { } /** - * check {@link ImmutableFieldTimeStampedCache#getNeighborsSize()} + * check {@link ImmutableFieldTimeStampedCache#getMaxNeighborsSize()} */ @Test public void testGetNeighborsSize() { - Assertions.assertEquals(cache.getNeighborsSize(), 3); + Assertions.assertEquals(cache.getMaxNeighborsSize(), 3); } /** @@ -239,7 +239,7 @@ public void testImmutable() { } /** - * check {@link ImmutableFieldTimeStampedCache#emptyCache()}. + * check {@link ImmutableFieldTimeStampedCache#emptyCache(Field)}. */ @Test public void testEmptyCache() { @@ -269,7 +269,7 @@ public void testEmptyCache() { // expected } Assertions.assertEquals(cache.getAll().size(), 0); - Assertions.assertEquals(cache.getNeighborsSize(), 0); + Assertions.assertEquals(cache.getMaxNeighborsSize(), 0); } @Test diff --git a/src/test/java/org/orekit/utils/SortedListTrimmerTest.java b/src/test/java/org/orekit/utils/SortedListTrimmerTest.java new file mode 100644 index 0000000000..5375697c32 --- /dev/null +++ b/src/test/java/org/orekit/utils/SortedListTrimmerTest.java @@ -0,0 +1,232 @@ +/* Contributed in the public domain. + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.utils; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.orekit.Utils; +import org.orekit.errors.OrekitException; +import org.orekit.errors.OrekitMessages; +import org.orekit.errors.TimeStampedCacheException; +import org.orekit.time.AbsoluteDate; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * Unit tests for {@link SortedListTrimmer}. + * + * @author Evan Ward + */ +public class SortedListTrimmerTest { + + /** + * arbitrary date + */ + private static final AbsoluteDate date = AbsoluteDate.CCSDS_EPOCH; + + /** + * set Orekit data for useful debugging messages from dates. + */ + @BeforeAll + public static void setUpBefore() { + Utils.setDataRoot("regular-data"); + } + + /** + * data provided to {@link #trimmer} + */ + private List data; + + /** + * subject under test + */ + private SortedListTrimmer trimmer; + + /** + * create {@link #trimmer} and {@link #data} with neighborsSize = 3 + */ + @BeforeEach + public void setUp() { + data = Arrays.asList(date, date.shiftedBy(1), date.shiftedBy(2), + date.shiftedBy(3), date.shiftedBy(4), + date.shiftedBy(5)); + trimmer = new SortedListTrimmer(3); + } + + /** + * check + * {@link SortedListTrimmer#getNeighborsSubList(AbsoluteDate, List)} + */ + @Test + public void testGetNeighborsSubList() { + // exception for neighborsSize > data.size() + try { + new SortedListTrimmer(data.size() + 1).getNeighborsSubList(date, data); + Assertions.fail("Expected Exception"); + } catch (OrekitException e) { + Assertions.assertEquals(OrekitMessages.NOT_ENOUGH_DATA, e.getSpecifier()); + } + + // exception for non-positive neighborsSize + try { + new SortedListTrimmer(0); + Assertions.fail("Expected Exception"); + } catch (IllegalArgumentException e) { + // expected + } + + // exception for null data + try { + new SortedListTrimmer(1).getNeighborsSubList(date, null); + Assertions.fail("Expected Exception"); + } catch (NullPointerException e) { + // expected + } + + // exception for zero data + try { + new SortedListTrimmer(1).getNeighborsSubList(date, Collections.emptyList()); + Assertions.fail("Expected Exception"); + } catch (OrekitException e) { + Assertions.assertEquals(OrekitMessages.NOT_ENOUGH_DATA, e.getSpecifier()); + } + } + + /** + * check {@link SortedListTrimmer#getNeighborsSubList(AbsoluteDate, List)} at a + * series of different dates designed to test all logic paths. + */ + @Test + public void testGetNeighbors() { + // setup + int size = data.size(); + + // actions + verify + + // before fist data + try { + trimmer.getNeighborsSubList(data.get(0).shiftedBy(-1), data); + Assertions.fail("Expected Exception"); + } catch (TimeStampedCacheException e) { + // expected + Assertions.assertEquals(OrekitMessages.UNABLE_TO_GENERATE_NEW_DATA_BEFORE, e.getSpecifier()); + } + + // on fist date + Assertions.assertArrayEquals(trimmer.getNeighborsSubList(data.get(0), data).toArray(), + data.subList(0, 3).toArray()); + // between fist and second date + Assertions.assertArrayEquals(trimmer.getNeighborsSubList(data.get(0).shiftedBy(0.5), data).toArray(), + data.subList(0, 3).toArray()); + // in the middle on a date + Assertions.assertArrayEquals(trimmer.getNeighborsSubList(data.get(2), data).toArray(), + data.subList(1, 4).toArray()); + // in the middle between dates + Assertions.assertArrayEquals(trimmer.getNeighborsSubList(data.get(2).shiftedBy(0.5), data).toArray(), + data.subList(1, 4).toArray()); + // just before last date + Assertions.assertArrayEquals(trimmer.getNeighborsSubList(data.get(size - 1).shiftedBy(-0.5), data).toArray(), + data.subList(size - 3, size).toArray()); + // on last date + Assertions.assertArrayEquals(trimmer.getNeighborsSubList(data.get(size - 1), data).toArray(), + data.subList(size - 3, size).toArray()); + + // after last date + AbsoluteDate central = data.get(size - 1).shiftedBy(1); + try { + trimmer.getNeighborsSubList(central, data); + Assertions.fail("Expected Exception"); + } catch (TimeStampedCacheException e) { + // expected + Assertions.assertEquals(OrekitMessages.UNABLE_TO_GENERATE_NEW_DATA_AFTER, e.getSpecifier()); + } + } + + /** Check findIndex(...) returns results on a half closed interval. */ + @Test + public void testGetNeighborsSingle() { + // setup + trimmer = new SortedListTrimmer(1); + int size = data.size(); + + // actions + verify + // on fist date + Assertions.assertArrayEquals( + trimmer.getNeighborsSubList(data.get(0), data).toArray(), + data.subList(0, 1).toArray()); + // between fist and second date + Assertions.assertArrayEquals( + trimmer.getNeighborsSubList(data.get(0).shiftedBy(0.5), data).toArray(), + data.subList(0, 1).toArray()); + // in the middle on a date + Assertions.assertArrayEquals( + trimmer.getNeighborsSubList(data.get(2), data).toArray(), + data.subList(2, 3).toArray()); + // in the middle between dates + Assertions.assertArrayEquals( + trimmer.getNeighborsSubList(data.get(2).shiftedBy(0.1), data).toArray(), + data.subList(2, 3).toArray()); + // just before last date + Assertions.assertArrayEquals( + trimmer.getNeighborsSubList(data.get(size - 1).shiftedBy(-0.1), data).toArray(), + data.subList(size - 2, size - 1).toArray()); + // on last date + Assertions.assertArrayEquals( + trimmer.getNeighborsSubList(data.get(size - 1), data).toArray(), + data.subList(size - 1, size).toArray()); + } + + /** + * check {@link ImmutableTimeStampedCache#getMaxNeighborsSize()} + */ + @Test + public void testGetNeighborsSize() { + Assertions.assertEquals(trimmer.getNeighborsSize(), 3); + } + + @Test + public void testNonLinear() { + final List nonLinearCache = Arrays.asList(date.shiftedBy(10), + date.shiftedBy(14), + date.shiftedBy(18), + date.shiftedBy(23), + date.shiftedBy(30), + date.shiftedBy(36), + date.shiftedBy(45), + date.shiftedBy(55), + date.shiftedBy(67), + date.shiftedBy(90), + date.shiftedBy(118)); + for (double dt = 10; dt < 118; dt += 0.01) { + checkNeighbors(new SortedListTrimmer(2), nonLinearCache, dt); + } + } + + private void checkNeighbors(final SortedListTrimmer nonLinearTrimmer, + final List nonLinearCache, + final double offset) { + List s = nonLinearTrimmer.getNeighborsSubList(date.shiftedBy(offset), nonLinearCache); + Assertions.assertEquals(2, s.size()); + Assertions.assertTrue(s.get(0).durationFrom(date) <= offset); + Assertions.assertTrue(s.get(1).durationFrom(date) > offset); + } + +} From 75d037f05e96a4428cb1f3017866424a6d5f6c71 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Thu, 22 Feb 2024 17:36:19 +0100 Subject: [PATCH 132/359] Avoid copying ephemeris data. --- .../org/orekit/utils/ImmutableFieldTimeStampedCache.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/orekit/utils/ImmutableFieldTimeStampedCache.java b/src/main/java/org/orekit/utils/ImmutableFieldTimeStampedCache.java index c831923358..c3e3ca5f32 100644 --- a/src/main/java/org/orekit/utils/ImmutableFieldTimeStampedCache.java +++ b/src/main/java/org/orekit/utils/ImmutableFieldTimeStampedCache.java @@ -81,15 +81,15 @@ public ImmutableFieldTimeStampedCache(final int maxNeighborsSize, // Sort and copy data first this.data = new ArrayList<>(data); - Collections.sort(this.data, new FieldChronologicalComparator<>()); + this.data.sort(new FieldChronologicalComparator<>()); } /** * private constructor for {@link #emptyCache(Field)}. - * @param field field to which the elements belong + * @param ignored field to which the elements belong (ignored since 12.1) */ - private ImmutableFieldTimeStampedCache(final Field field) { + private ImmutableFieldTimeStampedCache(final Field ignored) { this.data = null; this.maxNeighborsSize = 0; } @@ -151,7 +151,6 @@ private static class EmptyFieldTimeStampedCache, extends ImmutableFieldTimeStampedCache { /** Simple constructor. - * @param field field to which elements belong */ EmptyFieldTimeStampedCache(final Field field) { super(field); From dcc46f4f78786e561ffd77a1a230e83534108563 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Thu, 22 Feb 2024 18:10:33 +0100 Subject: [PATCH 133/359] Avoid copying ephemeris data. --- .../orekit/files/general/EphemerisFile.java | 4 ++- .../general/EphemerisSegmentPropagator.java | 26 ++++++++----------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/main/java/org/orekit/files/general/EphemerisFile.java b/src/main/java/org/orekit/files/general/EphemerisFile.java index 1c0572686d..7c313ddaaa 100644 --- a/src/main/java/org/orekit/files/general/EphemerisFile.java +++ b/src/main/java/org/orekit/files/general/EphemerisFile.java @@ -30,6 +30,7 @@ import org.orekit.time.AbsoluteDate; import org.orekit.utils.CartesianDerivativesFilter; import org.orekit.utils.TimeStampedPVCoordinates; +import org.orekit.utils.TimeStampedPVCoordinatesHermiteInterpolator; /** * An interface for accessing the data stored in an ephemeris file and using the data to @@ -301,7 +302,8 @@ default Frame getInertialFrame() { * @return a propagator for this ephemeris segment. */ default BoundedPropagator getPropagator() { - return new EphemerisSegmentPropagator<>(this, new FrameAlignedProvider(getInertialFrame())); + return new EphemerisSegmentPropagator<>(this, + new FrameAlignedProvider(getInertialFrame())); } /** diff --git a/src/main/java/org/orekit/files/general/EphemerisSegmentPropagator.java b/src/main/java/org/orekit/files/general/EphemerisSegmentPropagator.java index 91021fc9a2..f6e4950d7a 100644 --- a/src/main/java/org/orekit/files/general/EphemerisSegmentPropagator.java +++ b/src/main/java/org/orekit/files/general/EphemerisSegmentPropagator.java @@ -16,9 +16,6 @@ */ package org.orekit.files.general; -import java.util.ArrayList; -import java.util.List; - import org.hipparchus.geometry.euclidean.threed.Vector3D; import org.orekit.attitudes.AttitudeProvider; import org.orekit.errors.OrekitException; @@ -32,11 +29,13 @@ import org.orekit.propagation.SpacecraftState; import org.orekit.propagation.analytical.AbstractAnalyticalPropagator; import org.orekit.time.AbsoluteDate; -import org.orekit.time.TimeInterpolator; import org.orekit.utils.SortedListTrimmer; import org.orekit.utils.TimeStampedPVCoordinates; import org.orekit.utils.TimeStampedPVCoordinatesHermiteInterpolator; +import java.util.ArrayList; +import java.util.List; + /** * A {@link Propagator} based on a {@link EphemerisSegment}. * @@ -53,8 +52,10 @@ class EphemerisSegmentPropagator extends Abs /** Tabular data from which this propagator is built. */ private final EphemerisSegment ephemeris; - /** Number of sample points to use. */ - private final int nbPoints; + /** Interpolator to use. + * @since 12.2 + */ + private final TimeStampedPVCoordinatesHermiteInterpolator interpolator; /** Inertial frame used for creating orbits. */ private final Frame inertialFrame; /** Frame of the ephemeris data. */ @@ -70,7 +71,8 @@ class EphemerisSegmentPropagator extends Abs final AttitudeProvider attitudeProvider) { super(attitudeProvider); this.ephemeris = ephemeris; - this.nbPoints = ephemeris.getInterpolationSamples(); + this.interpolator = new TimeStampedPVCoordinatesHermiteInterpolator(ephemeris.getInterpolationSamples(), + ephemeris.getAvailableDerivatives()); this.ephemerisFrame = ephemeris.getFrame(); this.inertialFrame = ephemeris.getInertialFrame(); // set the initial state so getFrame() works @@ -95,14 +97,12 @@ class EphemerisSegmentPropagator extends Abs @Override public TimeStampedPVCoordinates getPVCoordinates(final AbsoluteDate date, final Frame frame) { final TimeStampedPVCoordinates interpolatedPVCoordinates = interpolate(date); - return ephemerisFrame.getTransformTo(frame, date).transformPVCoordinates(interpolatedPVCoordinates); } @Override public Vector3D getPosition(final AbsoluteDate date, final Frame frame) { final Vector3D interpolatedPosition = interpolate(date).getPosition(); - return ephemerisFrame.getStaticTransformTo(frame, date).transformPosition(interpolatedPosition); } @@ -149,18 +149,14 @@ public void resetInitialState(final SpacecraftState state) { * @return interpolated position-velocity vector */ private TimeStampedPVCoordinates interpolate(final AbsoluteDate date) { - final List neighbors = new SortedListTrimmer(nbPoints). + final List neighbors = new SortedListTrimmer(interpolator.getNbInterpolationPoints()). getNeighborsSubList(date, ephemeris.getCoordinates()); // cast stream to super type final List castedNeighbors = new ArrayList<>(neighbors.size()); - castedNeighbors.addAll(neighbors); + neighbors.forEach(neighbor -> castedNeighbors.add(neighbor)); // create interpolator - final TimeInterpolator interpolator = - new TimeStampedPVCoordinatesHermiteInterpolator(nbPoints, - ephemeris.getAvailableDerivatives()); - return interpolator.interpolate(date, castedNeighbors); } From 07800f5557bf903b362a6a113b58a66ddbfe4b24 Mon Sep 17 00:00:00 2001 From: Serrof Date: Thu, 15 Feb 2024 23:54:12 +0100 Subject: [PATCH 134/359] Implemented choice of cache in FieldEquinoctialOrbit --- .../org/orekit/orbits/EquinoctialOrbit.java | 30 +- .../orekit/orbits/FieldEquinoctialOrbit.java | 432 ++++++++++++++---- .../orbits/FieldEquinoctialOrbitTest.java | 174 +++++-- .../events/FieldApsideDetectorTest.java | 4 +- 4 files changed, 516 insertions(+), 124 deletions(-) diff --git a/src/main/java/org/orekit/orbits/EquinoctialOrbit.java b/src/main/java/org/orekit/orbits/EquinoctialOrbit.java index 17aaa8f471..fe2939342d 100644 --- a/src/main/java/org/orekit/orbits/EquinoctialOrbit.java +++ b/src/main/java/org/orekit/orbits/EquinoctialOrbit.java @@ -57,7 +57,7 @@ * parameters are still unambiguously defined whereas some Keplerian elements * (more precisely ω and Ω) become ambiguous. For this reason, equinoctial * parameters are the recommended way to represent orbits. Note however than - * * the present implementation does not handle non-elliptical cases. + * the present implementation does not handle non-elliptical cases. *

                *

                * The instance EquinoctialOrbit is guaranteed to be immutable. @@ -403,61 +403,73 @@ public EquinoctialOrbit(final Orbit op) { } /** {@inheritDoc} */ + @Override public OrbitType getType() { return OrbitType.EQUINOCTIAL; } /** {@inheritDoc} */ + @Override public double getA() { return a; } /** {@inheritDoc} */ + @Override public double getADot() { return aDot; } /** {@inheritDoc} */ + @Override public double getEquinoctialEx() { return ex; } /** {@inheritDoc} */ + @Override public double getEquinoctialExDot() { return exDot; } /** {@inheritDoc} */ + @Override public double getEquinoctialEy() { return ey; } /** {@inheritDoc} */ + @Override public double getEquinoctialEyDot() { return eyDot; } /** {@inheritDoc} */ + @Override public double getHx() { return hx; } /** {@inheritDoc} */ + @Override public double getHxDot() { return hxDot; } /** {@inheritDoc} */ + @Override public double getHy() { return hy; } /** {@inheritDoc} */ + @Override public double getHyDot() { return hyDot; } /** {@inheritDoc} */ + @Override public double getLv() { switch (cachedPositionAngleType) { case TRUE: @@ -475,6 +487,7 @@ public double getLv() { } /** {@inheritDoc} */ + @Override public double getLvDot() { switch (cachedPositionAngleType) { case ECCENTRIC: @@ -502,6 +515,7 @@ public double getLvDot() { } /** {@inheritDoc} */ + @Override public double getLE() { switch (cachedPositionAngleType) { case TRUE: @@ -519,6 +533,7 @@ public double getLE() { } /** {@inheritDoc} */ + @Override public double getLEDot() { switch (cachedPositionAngleType) { case TRUE: @@ -546,6 +561,7 @@ public double getLEDot() { } /** {@inheritDoc} */ + @Override public double getLM() { switch (cachedPositionAngleType) { case TRUE: @@ -563,6 +579,7 @@ public double getLM() { } /** {@inheritDoc} */ + @Override public double getLMDot() { switch (cachedPositionAngleType) { case TRUE: @@ -653,21 +670,25 @@ public static double eccentricToMean(final double lE, final double ex, final dou } /** {@inheritDoc} */ + @Override public double getE() { return FastMath.sqrt(ex * ex + ey * ey); } /** {@inheritDoc} */ + @Override public double getEDot() { return (ex * exDot + ey * eyDot) / FastMath.sqrt(ex * ex + ey * ey); } /** {@inheritDoc} */ + @Override public double getI() { return 2 * FastMath.atan(FastMath.sqrt(hx * hx + hy * hy)); } /** {@inheritDoc} */ + @Override public double getIDot() { final double h2 = hx * hx + hy * hy; final double h = FastMath.sqrt(h2); @@ -843,6 +864,7 @@ private Vector3D nonKeplerianAcceleration() { } /** {@inheritDoc} */ + @Override protected Vector3D initPosition() { // get equinoctial parameters @@ -884,6 +906,7 @@ protected Vector3D initPosition() { } /** {@inheritDoc} */ + @Override protected TimeStampedPVCoordinates initPVCoordinates() { // position and velocity @@ -901,6 +924,7 @@ protected TimeStampedPVCoordinates initPVCoordinates() { } /** {@inheritDoc} */ + @Override public EquinoctialOrbit shiftedBy(final double dt) { // use Keplerian-only motion @@ -939,6 +963,7 @@ public EquinoctialOrbit shiftedBy(final double dt) { } /** {@inheritDoc} */ + @Override protected double[][] computeJacobianMeanWrtCartesian() { final double[][] jacobian = new double[6][6]; @@ -1027,6 +1052,7 @@ protected double[][] computeJacobianMeanWrtCartesian() { } /** {@inheritDoc} */ + @Override protected double[][] computeJacobianEccentricWrtCartesian() { // start by computing the Jacobian with mean angle @@ -1054,6 +1080,7 @@ protected double[][] computeJacobianEccentricWrtCartesian() { } /** {@inheritDoc} */ + @Override protected double[][] computeJacobianTrueWrtCartesian() { // start by computing the Jacobian with eccentric angle @@ -1101,6 +1128,7 @@ protected double[][] computeJacobianTrueWrtCartesian() { } /** {@inheritDoc} */ + @Override public void addKeplerContribution(final PositionAngleType type, final double gm, final double[] pDot) { final double oMe2; diff --git a/src/main/java/org/orekit/orbits/FieldEquinoctialOrbit.java b/src/main/java/org/orekit/orbits/FieldEquinoctialOrbit.java index 97acabbd36..82fea2ae40 100644 --- a/src/main/java/org/orekit/orbits/FieldEquinoctialOrbit.java +++ b/src/main/java/org/orekit/orbits/FieldEquinoctialOrbit.java @@ -90,8 +90,11 @@ public class FieldEquinoctialOrbit> extends Fi /** Second component of the inclination vector. */ private final T hy; - /** True longitude argument (rad). */ - private final T lv; + /** Cached longitude argument (rad). */ + private final T cachedL; + + /** Cache type of position angle (longitude argument). */ + private final PositionAngleType cachedPositionAngleType; /** Semi-major axis derivative (m/s). */ private final T aDot; @@ -108,8 +111,8 @@ public class FieldEquinoctialOrbit> extends Fi /** Second component of the inclination vector derivative. */ private final T hyDot; - /** True longitude argument derivative (rad/s). */ - private final T lvDot; + /** Derivative of cached longitude argument (rad/s). */ + private final T cachedLDot; /** Partial Cartesian coordinates (position and velocity are valid, acceleration may be missing). */ private FieldPVCoordinates partialPV; @@ -122,21 +125,48 @@ public class FieldEquinoctialOrbit> extends Fi * @param hy tan(i/2) sin(Ω), second component of inclination vector * @param l (M or E or v) + ω + Ω, mean, eccentric or true longitude argument (rad) * @param type type of longitude argument + * @param cachedPositionAngleType type of cached longitude argument * @param frame the frame in which the parameters are defined * (must be a {@link Frame#isPseudoInertial pseudo-inertial frame}) * @param date date of the orbital parameters * @param mu central attraction coefficient (m³/s²) * @exception IllegalArgumentException if eccentricity is equal to 1 or larger or * if frame is not a {@link Frame#isPseudoInertial pseudo-inertial frame} + * @since 12.1 */ public FieldEquinoctialOrbit(final T a, final T ex, final T ey, final T hx, final T hy, final T l, - final PositionAngleType type, + final PositionAngleType type, final PositionAngleType cachedPositionAngleType, final Frame frame, final FieldAbsoluteDate date, final T mu) throws IllegalArgumentException { this(a, ex, ey, hx, hy, l, null, null, null, null, null, null, - type, frame, date, mu); + type, cachedPositionAngleType, frame, date, mu); + } + + /** Creates a new instance. + * @param a semi-major axis (m) + * @param ex e cos(ω + Ω), first component of eccentricity vector + * @param ey e sin(ω + Ω), second component of eccentricity vector + * @param hx tan(i/2) cos(Ω), first component of inclination vector + * @param hy tan(i/2) sin(Ω), second component of inclination vector + * @param l (M or E or v) + ω + Ω, mean, eccentric or true longitude argument (rad) + * @param type type of longitude argument + * @param frame the frame in which the parameters are defined + * (must be a {@link Frame#isPseudoInertial pseudo-inertial frame}) + * @param date date of the orbital parameters + * @param mu central attraction coefficient (m³/s²) + * @exception IllegalArgumentException if eccentricity is equal to 1 or larger or + * if frame is not a {@link Frame#isPseudoInertial pseudo-inertial frame} + */ + public FieldEquinoctialOrbit(final T a, final T ex, final T ey, + final T hx, final T hy, final T l, + final PositionAngleType type, + final Frame frame, final FieldAbsoluteDate date, final T mu) + throws IllegalArgumentException { + this(a, ex, ey, hx, hy, l, + null, null, null, null, null, null, + type, type, frame, date, mu); } /** Creates a new instance. @@ -153,18 +183,20 @@ public FieldEquinoctialOrbit(final T a, final T ex, final T ey, * @param hyDot d(tan(i/2) sin(Ω))/dt, second component of inclination vector derivative * @param lDot d(M or E or v) + ω + Ω)/dr, mean, eccentric or true longitude argument derivative (rad/s) * @param type type of longitude argument + * @param cachedPositionAngleType of cached longitude argument * @param frame the frame in which the parameters are defined * (must be a {@link Frame#isPseudoInertial pseudo-inertial frame}) * @param date date of the orbital parameters * @param mu central attraction coefficient (m³/s²) * @exception IllegalArgumentException if eccentricity is equal to 1 or larger or * if frame is not a {@link Frame#isPseudoInertial pseudo-inertial frame} + * @since 12.1 */ public FieldEquinoctialOrbit(final T a, final T ex, final T ey, final T hx, final T hy, final T l, final T aDot, final T exDot, final T eyDot, final T hxDot, final T hyDot, final T lDot, - final PositionAngleType type, + final PositionAngleType type, final PositionAngleType cachedPositionAngleType, final Frame frame, final FieldAbsoluteDate date, final T mu) throws IllegalArgumentException { super(frame, date, mu); @@ -173,7 +205,7 @@ public FieldEquinoctialOrbit(final T a, final T ex, final T ey, throw new OrekitIllegalArgumentException(OrekitMessages.HYPERBOLIC_ORBIT_NOT_HANDLED_AS, getClass().getName()); } - + this.cachedPositionAngleType = cachedPositionAngleType; this.a = a; this.aDot = aDot; this.ex = ex; @@ -186,46 +218,50 @@ public FieldEquinoctialOrbit(final T a, final T ex, final T ey, this.hyDot = hyDot; if (hasDerivatives()) { - final FieldUnivariateDerivative1 exUD = new FieldUnivariateDerivative1<>(ex, exDot); - final FieldUnivariateDerivative1 eyUD = new FieldUnivariateDerivative1<>(ey, eyDot); - final FieldUnivariateDerivative1 lUD = new FieldUnivariateDerivative1<>(l, lDot); - final FieldUnivariateDerivative1 lvUD; - switch (type) { - case MEAN : - lvUD = FieldEquinoctialLongitudeArgumentUtility.meanToTrue(exUD, eyUD, lUD); - break; - case ECCENTRIC : - lvUD = FieldEquinoctialLongitudeArgumentUtility.eccentricToTrue(exUD, eyUD, lUD); - break; - case TRUE : - lvUD = lUD; - break; - default : // this should never happen - throw new OrekitInternalError(null); - } - this.lv = lvUD.getValue(); - this.lvDot = lvUD.getDerivative(1); + final FieldUnivariateDerivative1 alphaUD = initializeCachedL(l, lDot, type); + this.cachedL = alphaUD.getValue(); + this.cachedLDot = alphaUD.getFirstDerivative(); } else { - switch (type) { - case MEAN : - this.lv = FieldEquinoctialLongitudeArgumentUtility.meanToTrue(ex, ey, l); - break; - case ECCENTRIC : - this.lv = FieldEquinoctialLongitudeArgumentUtility.eccentricToTrue(ex, ey, l); - break; - case TRUE : - this.lv = l; - break; - default : - throw new OrekitInternalError(null); - } - this.lvDot = null; + this.cachedL = initializeCachedL(l, type); + this.cachedLDot = null; } this.partialPV = null; } + /** Creates a new instance. + * @param a semi-major axis (m) + * @param ex e cos(ω + Ω), first component of eccentricity vector + * @param ey e sin(ω + Ω), second component of eccentricity vector + * @param hx tan(i/2) cos(Ω), first component of inclination vector + * @param hy tan(i/2) sin(Ω), second component of inclination vector + * @param l (M or E or v) + ω + Ω, mean, eccentric or true longitude argument (rad) + * @param aDot semi-major axis derivative (m/s) + * @param exDot d(e cos(ω + Ω))/dt, first component of eccentricity vector derivative + * @param eyDot d(e sin(ω + Ω))/dt, second component of eccentricity vector derivative + * @param hxDot d(tan(i/2) cos(Ω))/dt, first component of inclination vector derivative + * @param hyDot d(tan(i/2) sin(Ω))/dt, second component of inclination vector derivative + * @param lDot d(M or E or v) + ω + Ω)/dr, mean, eccentric or true longitude argument derivative (rad/s) + * @param type type of longitude argument + * @param frame the frame in which the parameters are defined + * (must be a {@link Frame#isPseudoInertial pseudo-inertial frame}) + * @param date date of the orbital parameters + * @param mu central attraction coefficient (m³/s²) + * @exception IllegalArgumentException if eccentricity is equal to 1 or larger or + * if frame is not a {@link Frame#isPseudoInertial pseudo-inertial frame} + * @since 12.1 + */ + public FieldEquinoctialOrbit(final T a, final T ex, final T ey, + final T hx, final T hy, final T l, + final T aDot, final T exDot, final T eyDot, + final T hxDot, final T hyDot, final T lDot, + final PositionAngleType type, + final Frame frame, final FieldAbsoluteDate date, final T mu) + throws IllegalArgumentException { + this(a, ex, ey, hx, hy, l, aDot, exDot, eyDot, hxDot, hyDot, lDot, type, type, frame, date, mu); + } + /** Constructor from Cartesian parameters. * *

                The acceleration provided in {@code pvCoordinates} is accessible using @@ -269,14 +305,15 @@ public FieldEquinoctialOrbit(final TimeStampedFieldPVCoordinates pvCoordinate hy = d.multiply(w.getX()); // compute true longitude argument + cachedPositionAngleType = PositionAngleType.TRUE; final T cLv = (pvP.getX().subtract(d.multiply(pvP.getZ()).multiply(w.getX()))).divide(r); final T sLv = (pvP.getY().subtract(d.multiply(pvP.getZ()).multiply(w.getY()))).divide(r); - lv = sLv.atan2(cLv); + cachedL = sLv.atan2(cLv); // compute eccentricity vector final T eSE = FieldVector3D.dotProduct(pvP, pvV).divide(a.multiply(mu).sqrt()); final T eCE = rV2OnMu.subtract(1); - final T e2 = eCE.multiply(eCE).add(eSE.multiply(eSE)); + final T e2 = eCE.square().add(eSE.square()); final T f = eCE.subtract(e2); final T g = e2.negate().add(1).sqrt().multiply(eSE); ex = a.multiply(f.multiply(cLv).add( g.multiply(sLv))).divide(r); @@ -301,15 +338,15 @@ public FieldEquinoctialOrbit(final TimeStampedFieldPVCoordinates pvCoordinate hxDot = jacobian[3][3].multiply(aX).add(jacobian[3][4].multiply(aY)).add(jacobian[3][5].multiply(aZ)); hyDot = jacobian[4][3].multiply(aX).add(jacobian[4][4].multiply(aY)).add(jacobian[4][5].multiply(aZ)); - // in order to compute true anomaly derivative, we must compute - // mean anomaly derivative including Keplerian motion and convert to true anomaly + // in order to compute true longitude argument derivative, we must compute + // mean longitude argument derivative including Keplerian motion and convert to true anomaly final T lMDot = getKeplerianMeanMotion(). add(jacobian[5][3].multiply(aX)).add(jacobian[5][4].multiply(aY)).add(jacobian[5][5].multiply(aZ)); final FieldUnivariateDerivative1 exUD = new FieldUnivariateDerivative1<>(ex, exDot); final FieldUnivariateDerivative1 eyUD = new FieldUnivariateDerivative1<>(ey, eyDot); final FieldUnivariateDerivative1 lMUD = new FieldUnivariateDerivative1<>(getLM(), lMDot); final FieldUnivariateDerivative1 lvUD = FieldEquinoctialLongitudeArgumentUtility.meanToTrue(exUD, eyUD, lMUD); - lvDot = lvUD.getDerivative(1); + cachedLDot = lvUD.getFirstDerivative(); } else { // acceleration is either almost zero or NaN, @@ -320,7 +357,7 @@ public FieldEquinoctialOrbit(final TimeStampedFieldPVCoordinates pvCoordinate eyDot = null; hxDot = null; hyDot = null; - lvDot = null; + cachedLDot = null; } } @@ -357,14 +394,15 @@ public FieldEquinoctialOrbit(final FieldOrbit op) { ey = op.getEquinoctialEy(); hx = op.getHx(); hy = op.getHy(); - lv = op.getLv(); + cachedPositionAngleType = PositionAngleType.TRUE; + cachedL = op.getLv(); aDot = op.getADot(); exDot = op.getEquinoctialExDot(); eyDot = op.getEquinoctialEyDot(); hxDot = op.getHxDot(); hyDot = op.getHyDot(); - lvDot = op.getLvDot(); + cachedLDot = op.getLvDot(); } /** Constructor from Field and EquinoctialOrbit. @@ -381,7 +419,8 @@ public FieldEquinoctialOrbit(final Field field, final EquinoctialOrbit op) { ey = getZero().newInstance(op.getEquinoctialEy()); hx = getZero().newInstance(op.getHx()); hy = getZero().newInstance(op.getHy()); - lv = getZero().newInstance(op.getLv()); + cachedPositionAngleType = op.getCachedPositionAngleType(); + cachedL = getZero().newInstance(op.getL(cachedPositionAngleType)); if (op.hasDerivatives()) { aDot = getZero().newInstance(op.getADot()); @@ -389,14 +428,14 @@ public FieldEquinoctialOrbit(final Field field, final EquinoctialOrbit op) { eyDot = getZero().newInstance(op.getEquinoctialEyDot()); hxDot = getZero().newInstance(op.getHxDot()); hyDot = getZero().newInstance(op.getHyDot()); - lvDot = getZero().newInstance(op.getLvDot()); + cachedLDot = getZero().newInstance(op.getLDot(cachedPositionAngleType)); } else { aDot = null; exDot = null; eyDot = null; hxDot = null; hyDot = null; - lvDot = null; + cachedLDot = null; } } @@ -412,108 +451,218 @@ public FieldEquinoctialOrbit(final Field field, final Orbit op) { } /** {@inheritDoc} */ + @Override public OrbitType getType() { return OrbitType.EQUINOCTIAL; } /** {@inheritDoc} */ + @Override public T getA() { return a; } /** {@inheritDoc} */ + @Override public T getADot() { return aDot; } /** {@inheritDoc} */ + @Override public T getEquinoctialEx() { return ex; } /** {@inheritDoc} */ + @Override public T getEquinoctialExDot() { return exDot; } /** {@inheritDoc} */ + @Override public T getEquinoctialEy() { return ey; } /** {@inheritDoc} */ + @Override public T getEquinoctialEyDot() { return eyDot; } /** {@inheritDoc} */ + @Override public T getHx() { return hx; } /** {@inheritDoc} */ + @Override public T getHxDot() { return hxDot; } /** {@inheritDoc} */ + @Override public T getHy() { return hy; } /** {@inheritDoc} */ + @Override public T getHyDot() { return hyDot; } /** {@inheritDoc} */ + @Override public T getLv() { - return lv; + switch (cachedPositionAngleType) { + case TRUE: + return cachedL; + + case ECCENTRIC: + return FieldEquinoctialLongitudeArgumentUtility.eccentricToTrue(ex, ey, cachedL); + + case MEAN: + return FieldEquinoctialLongitudeArgumentUtility.meanToTrue(ex, ey, cachedL); + + default: + throw new OrekitInternalError(null); + } } /** {@inheritDoc} */ + @Override public T getLvDot() { - return lvDot; + + if (!hasDerivatives()) { + return null; + } + switch (cachedPositionAngleType) { + case ECCENTRIC: + final FieldUnivariateDerivative1 lEUD = new FieldUnivariateDerivative1<>(cachedL, cachedLDot); + final FieldUnivariateDerivative1 exUD = new FieldUnivariateDerivative1<>(ex, exDot); + final FieldUnivariateDerivative1 eyUD = new FieldUnivariateDerivative1<>(ey, eyDot); + final FieldUnivariateDerivative1 lvUD = FieldEquinoctialLongitudeArgumentUtility.eccentricToTrue(exUD, eyUD, + lEUD); + return lvUD.getFirstDerivative(); + + case TRUE: + return cachedLDot; + + case MEAN: + final FieldUnivariateDerivative1 lMUD = new FieldUnivariateDerivative1<>(cachedL, cachedLDot); + final FieldUnivariateDerivative1 exUD2 = new FieldUnivariateDerivative1<>(ex, exDot); + final FieldUnivariateDerivative1 eyUD2 = new FieldUnivariateDerivative1<>(ey, eyDot); + final FieldUnivariateDerivative1 lvUD2 = FieldEquinoctialLongitudeArgumentUtility.meanToTrue(exUD2, + eyUD2, lMUD); + return lvUD2.getFirstDerivative(); + + default: + throw new OrekitInternalError(null); + } } /** {@inheritDoc} */ + @Override public T getLE() { - return FieldEquinoctialLongitudeArgumentUtility.trueToEccentric(ex, ey, lv); + switch (cachedPositionAngleType) { + case TRUE: + return FieldEquinoctialLongitudeArgumentUtility.trueToEccentric(ex, ey, cachedL); + + case ECCENTRIC: + return cachedL; + + case MEAN: + return FieldEquinoctialLongitudeArgumentUtility.meanToEccentric(ex, ey, cachedL); + + default: + throw new OrekitInternalError(null); + } } /** {@inheritDoc} */ + @Override public T getLEDot() { if (!hasDerivatives()) { return null; } - - final FieldUnivariateDerivative1 lVUD = new FieldUnivariateDerivative1<>(lv, lvDot); - final FieldUnivariateDerivative1 exUD = new FieldUnivariateDerivative1<>(ex, exDot); - final FieldUnivariateDerivative1 eyUD = new FieldUnivariateDerivative1<>(ey, eyDot); - final FieldUnivariateDerivative1 lEUD = FieldEquinoctialLongitudeArgumentUtility.trueToEccentric(exUD, eyUD, lVUD); - return lEUD.getDerivative(1); - + switch (cachedPositionAngleType) { + case TRUE: + final FieldUnivariateDerivative1 lvUD = new FieldUnivariateDerivative1<>(cachedL, cachedLDot); + final FieldUnivariateDerivative1 exUD = new FieldUnivariateDerivative1<>(ex, exDot); + final FieldUnivariateDerivative1 eyUD = new FieldUnivariateDerivative1<>(ey, eyDot); + final FieldUnivariateDerivative1 lEUD = FieldEquinoctialLongitudeArgumentUtility.trueToEccentric(exUD, eyUD, + lvUD); + return lEUD.getFirstDerivative(); + + case ECCENTRIC: + return cachedLDot; + + case MEAN: + final FieldUnivariateDerivative1 lMUD = new FieldUnivariateDerivative1<>(cachedL, cachedLDot); + final FieldUnivariateDerivative1 exUD2 = new FieldUnivariateDerivative1<>(ex, exDot); + final FieldUnivariateDerivative1 eyUD2 = new FieldUnivariateDerivative1<>(ey, eyDot); + final FieldUnivariateDerivative1 lEUD2 = FieldEquinoctialLongitudeArgumentUtility.meanToEccentric(exUD2, + eyUD2, lMUD); + return lEUD2.getFirstDerivative(); + + default: + throw new OrekitInternalError(null); + } } /** {@inheritDoc} */ + @Override public T getLM() { - return FieldEquinoctialLongitudeArgumentUtility.trueToMean(ex, ey, lv); + switch (cachedPositionAngleType) { + case TRUE: + return FieldEquinoctialLongitudeArgumentUtility.trueToMean(ex, ey, cachedL); + + case MEAN: + return cachedL; + + case ECCENTRIC: + return FieldEquinoctialLongitudeArgumentUtility.eccentricToMean(ex, ey, cachedL); + + default: + throw new OrekitInternalError(null); + } } /** {@inheritDoc} */ + @Override public T getLMDot() { if (!hasDerivatives()) { return null; } - - final FieldUnivariateDerivative1 lVUD = new FieldUnivariateDerivative1<>(lv, lvDot); - final FieldUnivariateDerivative1 exUD = new FieldUnivariateDerivative1<>(ex, exDot); - final FieldUnivariateDerivative1 eyUD = new FieldUnivariateDerivative1<>(ey, eyDot); - final FieldUnivariateDerivative1 lMUD = FieldEquinoctialLongitudeArgumentUtility.trueToMean(exUD, eyUD, lVUD); - return lMUD.getDerivative(1); - + switch (cachedPositionAngleType) { + case TRUE: + final FieldUnivariateDerivative1 lvUD = new FieldUnivariateDerivative1<>(cachedL, cachedLDot); + final FieldUnivariateDerivative1 exUD = new FieldUnivariateDerivative1<>(ex, exDot); + final FieldUnivariateDerivative1 eyUD = new FieldUnivariateDerivative1<>(ey, eyDot); + final FieldUnivariateDerivative1 lMUD = FieldEquinoctialLongitudeArgumentUtility.trueToMean(exUD, eyUD, lvUD); + return lMUD.getFirstDerivative(); + + case MEAN: + return cachedLDot; + + case ECCENTRIC: + final FieldUnivariateDerivative1 lEUD = new FieldUnivariateDerivative1<>(cachedL, cachedLDot); + final FieldUnivariateDerivative1 exUD2 = new FieldUnivariateDerivative1<>(ex, exDot); + final FieldUnivariateDerivative1 eyUD2 = new FieldUnivariateDerivative1<>(ey, eyDot); + final FieldUnivariateDerivative1 lMUD2 = FieldEquinoctialLongitudeArgumentUtility.eccentricToMean(exUD2, + eyUD2, lEUD); + return lMUD2.getFirstDerivative(); + + default: + throw new OrekitInternalError(null); + } } /** Get the longitude argument. @@ -591,27 +740,31 @@ public static > T eccentricToMean(final T lE, } /** {@inheritDoc} */ + @Override public T getE() { - return ex.multiply(ex).add(ey.multiply(ey)).sqrt(); + return ex.square().add(ey.square()).sqrt(); } /** {@inheritDoc} */ + @Override public T getEDot() { if (!hasDerivatives()) { return null; } - return ex.multiply(exDot).add(ey.multiply(eyDot)).divide(ex.multiply(ex).add(ey.multiply(ey)).sqrt()); + return ex.multiply(exDot).add(ey.multiply(eyDot)).divide(ex.square().add(ey.square()).sqrt()); } /** {@inheritDoc} */ + @Override public T getI() { - return hx.multiply(hx).add(hy.multiply(hy)).sqrt().atan().multiply(2); + return hx.square().add(hy.square()).sqrt().atan().multiply(2); } /** {@inheritDoc} */ + @Override public T getIDot() { if (!hasDerivatives()) { @@ -638,7 +791,7 @@ private void computePVWithoutA() { // inclination-related intermediate parameters final T hx2 = hx.square(); - final T hy2 = hy.multiply(hy); + final T hy2 = hy.square(); final T factH = getOne().divide(hx2.add(1.0).add(hy2)); // reference axes defining the orbital plane @@ -683,6 +836,95 @@ private void computePVWithoutA() { } + /** Initialize cached argument of longitude with rate. + * @param l input argument of longitude + * @param lDot rate of input argument of longitude + * @param inputType position angle type passed as input + * @return argument of longitude to cache with rate + * @since 12.1 + */ + private FieldUnivariateDerivative1 initializeCachedL(final T l, final T lDot, + final PositionAngleType inputType) { + if (cachedPositionAngleType == inputType) { + return new FieldUnivariateDerivative1<>(l, lDot); + + } else { + final FieldUnivariateDerivative1 exUD = new FieldUnivariateDerivative1<>(ex, exDot); + final FieldUnivariateDerivative1 eyUD = new FieldUnivariateDerivative1<>(ey, eyDot); + final FieldUnivariateDerivative1 lUD = new FieldUnivariateDerivative1<>(l, lDot); + + switch (cachedPositionAngleType) { + + case ECCENTRIC: + if (inputType == PositionAngleType.MEAN) { + return FieldEquinoctialLongitudeArgumentUtility.meanToEccentric(exUD, eyUD, lUD); + } else { + return FieldEquinoctialLongitudeArgumentUtility.trueToEccentric(exUD, eyUD, lUD); + } + + case TRUE: + if (inputType == PositionAngleType.MEAN) { + return FieldEquinoctialLongitudeArgumentUtility.meanToTrue(exUD, eyUD, lUD); + } else { + return FieldEquinoctialLongitudeArgumentUtility.eccentricToTrue(exUD, eyUD, lUD); + } + + case MEAN: + if (inputType == PositionAngleType.TRUE) { + return FieldEquinoctialLongitudeArgumentUtility.trueToMean(exUD, eyUD, lUD); + } else { + return FieldEquinoctialLongitudeArgumentUtility.eccentricToMean(exUD, eyUD, lUD); + } + + default: + throw new OrekitInternalError(null); + + } + + } + + } + + /** Initialize cached argument of longitude. + * @param l input argument of longitude + * @param positionAngleType position angle type passed as input + * @return argument of longitude to cache + * @since 12.1 + */ + private T initializeCachedL(final T l, final PositionAngleType positionAngleType) { + if (positionAngleType == cachedPositionAngleType) { + return l; + + } else { + switch (cachedPositionAngleType) { + + case ECCENTRIC: + if (positionAngleType == PositionAngleType.MEAN) { + return FieldEquinoctialLongitudeArgumentUtility.meanToEccentric(ex, ey, l); + } else { + return FieldEquinoctialLongitudeArgumentUtility.trueToEccentric(ex, ey, l); + } + + case MEAN: + if (positionAngleType == PositionAngleType.TRUE) { + return FieldEquinoctialLongitudeArgumentUtility.trueToMean(ex, ey, l); + } else { + return FieldEquinoctialLongitudeArgumentUtility.eccentricToMean(ex, ey, l); + } + + case TRUE: + if (positionAngleType == PositionAngleType.MEAN) { + return FieldEquinoctialLongitudeArgumentUtility.meanToTrue(ex, ey, l); + } else { + return FieldEquinoctialLongitudeArgumentUtility.eccentricToTrue(ex, ey, l); + } + + default: + throw new OrekitInternalError(null); + } + } + } + /** Compute non-Keplerian part of the acceleration from first time derivatives. *

                * This method should be called only when {@link #hasDerivatives()} returns true. @@ -719,6 +961,7 @@ private FieldVector3D nonKeplerianAcceleration() { } /** {@inheritDoc} */ + @Override protected FieldVector3D initPosition() { // get equinoctial parameters @@ -739,9 +982,9 @@ protected FieldVector3D initPosition() { final T vz = hx.multiply(factH).multiply(2); // eccentricity-related intermediate parameters - final T ex2 = ex.multiply(ex); + final T ex2 = ex.square(); final T exey = ex.multiply(ey); - final T ey2 = ey.multiply(ey); + final T ey2 = ey.square(); final T e2 = ex2.add(ey2); final T eta = getOne().subtract(e2).sqrt().add(1); final T beta = getOne().divide(eta); @@ -762,6 +1005,7 @@ protected FieldVector3D initPosition() { } /** {@inheritDoc} */ + @Override protected TimeStampedFieldPVCoordinates initPVCoordinates() { // position and velocity @@ -780,17 +1024,19 @@ protected TimeStampedFieldPVCoordinates initPVCoordinates() { } /** {@inheritDoc} */ + @Override public FieldEquinoctialOrbit shiftedBy(final double dt) { return shiftedBy(getZero().newInstance(dt)); } /** {@inheritDoc} */ + @Override public FieldEquinoctialOrbit shiftedBy(final T dt) { // use Keplerian-only motion final FieldEquinoctialOrbit keplerianShifted = new FieldEquinoctialOrbit<>(a, ex, ey, hx, hy, getLM().add(getKeplerianMeanMotion().multiply(dt)), - PositionAngleType.MEAN, getFrame(), + PositionAngleType.MEAN, cachedPositionAngleType, getFrame(), getDate().shiftedBy(dt), getMu()); if (hasDerivatives()) { @@ -823,6 +1069,7 @@ PositionAngleType.MEAN, getFrame(), } /** {@inheritDoc} */ + @Override protected T[][] computeJacobianMeanWrtCartesian() { final T[][] jacobian = MathArrays.buildArray(getField(), 6, 6); @@ -839,14 +1086,14 @@ protected T[][] computeJacobianMeanWrtCartesian() { final T sqrtMuA = a.multiply(mu).sqrt(); final T a2 = a.square(); - final T e2 = ex.multiply(ex).add(ey.multiply(ey)); + final T e2 = ex.square().add(ey.square()); final T oMe2 = getOne().subtract(e2); final T epsilon = oMe2.sqrt(); final T beta = getOne().divide(epsilon.add(1)); final T ratio = epsilon.multiply(beta); - final T hx2 = hx.multiply(hx); - final T hy2 = hy.multiply(hy); + final T hx2 = hx.square(); + final T hy2 = hy.square(); final T hxhy = hx.multiply(hy); // precomputing equinoctial frame unit vectors (f, g, w) @@ -912,6 +1159,7 @@ protected T[][] computeJacobianMeanWrtCartesian() { } /** {@inheritDoc} */ + @Override protected T[][] computeJacobianEccentricWrtCartesian() { // start by computing the Jacobian with mean angle @@ -939,6 +1187,7 @@ protected T[][] computeJacobianEccentricWrtCartesian() { } /** {@inheritDoc} */ + @Override protected T[][] computeJacobianTrueWrtCartesian() { // start by computing the Jacobian with eccentric angle @@ -961,7 +1210,7 @@ protected T[][] computeJacobianTrueWrtCartesian() { final T sinLe = scLe.sin(); final T eSinE = ex.multiply(sinLe).subtract(ey.multiply(cosLe)); final T ecosE = ex.multiply(cosLe).add(ey.multiply(sinLe)); - final T e2 = ex.multiply(ex).add(ey.multiply(ey)); + final T e2 = ex.square().add(ey.square()); final T epsilon = getOne().subtract(e2).sqrt(); final T onePeps = epsilon.add(1); final T d = onePeps.subtract(ecosE); @@ -986,12 +1235,13 @@ protected T[][] computeJacobianTrueWrtCartesian() { } /** {@inheritDoc} */ + @Override public void addKeplerContribution(final PositionAngleType type, final T gm, final T[] pDot) { final T oMe2; final T ksi; final T n = gm.divide(a).sqrt().divide(a); - final FieldSinCos sc = FastMath.sinCos(lv); + final FieldSinCos sc = FastMath.sinCos(getLv()); switch (type) { case MEAN : pDot[5] = pDot[5].add(n); @@ -1002,7 +1252,7 @@ public void addKeplerContribution(final PositionAngleType type, final T gm, pDot[5] = pDot[5].add(n.multiply(ksi).divide(oMe2)); break; case TRUE : - oMe2 = getOne().subtract(ex.multiply(ex)).subtract(ey.multiply(ey)); + oMe2 = getOne().subtract(ex.square()).subtract(ey.square()); ksi = ex.multiply(sc.cos()).add(1).add(ey.multiply(sc.sin())); pDot[5] = pDot[5].add(n.multiply(ksi).multiply(ksi).divide(oMe2.multiply(oMe2.sqrt()))); break; @@ -1019,14 +1269,14 @@ public String toString() { append("a: ").append(a.getReal()). append("; ex: ").append(ex.getReal()).append("; ey: ").append(ey.getReal()). append("; hx: ").append(hx.getReal()).append("; hy: ").append(hy.getReal()). - append("; lv: ").append(FastMath.toDegrees(lv.getReal())). + append("; lv: ").append(FastMath.toDegrees(getLv().getReal())). append(";}").toString(); } /** {@inheritDoc} */ @Override public PositionAngleType getCachedPositionAngleType() { - return PositionAngleType.TRUE; + return cachedPositionAngleType; } /** {@inheritDoc} */ @@ -1038,27 +1288,25 @@ public boolean hasRates() { /** {@inheritDoc} */ @Override public FieldEquinoctialOrbit removeRates() { - final PositionAngleType positionAngleType = getCachedPositionAngleType(); return new FieldEquinoctialOrbit<>(getA(), getEquinoctialEx(), getEquinoctialEy(), getHx(), getHy(), - getL(positionAngleType), positionAngleType, getFrame(), getDate(), getMu()); + cachedL, cachedPositionAngleType, getFrame(), getDate(), getMu()); } /** {@inheritDoc} */ @Override public EquinoctialOrbit toOrbit() { - final PositionAngleType cachedPositionAngleType = getCachedPositionAngleType(); - final double cachedPositionAngle = getL(cachedPositionAngleType).getReal(); + final double cachedPositionAngle = cachedL.getReal(); if (hasDerivatives()) { return new EquinoctialOrbit(a.getReal(), ex.getReal(), ey.getReal(), hx.getReal(), hy.getReal(), cachedPositionAngle, aDot.getReal(), exDot.getReal(), eyDot.getReal(), - hxDot.getReal(), hyDot.getReal(), getLDot(cachedPositionAngleType).getReal(), - cachedPositionAngleType, cachedPositionAngleType, getFrame(), + hxDot.getReal(), hyDot.getReal(), cachedLDot.getReal(), + cachedPositionAngleType, getFrame(), getDate().toAbsoluteDate(), getMu().getReal()); } else { return new EquinoctialOrbit(a.getReal(), ex.getReal(), ey.getReal(), hx.getReal(), hy.getReal(), cachedPositionAngle, - cachedPositionAngleType, cachedPositionAngleType, getFrame(), + cachedPositionAngleType, getFrame(), getDate().toAbsoluteDate(), getMu().getReal()); } } diff --git a/src/test/java/org/orekit/orbits/FieldEquinoctialOrbitTest.java b/src/test/java/org/orekit/orbits/FieldEquinoctialOrbitTest.java index 1a91ad70e7..c83bad9d85 100644 --- a/src/test/java/org/orekit/orbits/FieldEquinoctialOrbitTest.java +++ b/src/test/java/org/orekit/orbits/FieldEquinoctialOrbitTest.java @@ -28,10 +28,7 @@ import org.hipparchus.geometry.euclidean.threed.FieldVector3D; import org.hipparchus.linear.FieldMatrixPreservingVisitor; import org.hipparchus.linear.MatrixUtils; -import org.hipparchus.util.Binary64Field; -import org.hipparchus.util.FastMath; -import org.hipparchus.util.MathArrays; -import org.hipparchus.util.MathUtils; +import org.hipparchus.util.*; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -52,7 +49,7 @@ import static org.orekit.OrekitMatchers.relativelyCloseTo; -public class FieldEquinoctialOrbitTest { +class FieldEquinoctialOrbitTest { // Body mu private double mu; @@ -67,121 +64,121 @@ public void setUp() { } @Test - public void testEquinoctialToEquinoctialEll() { + void testEquinoctialToEquinoctialEll() { doTestEquinoctialToEquinoctialEll(Binary64Field.getInstance()); } @Test - public void testEquinoctialToEquinoctialCirc() { + void testEquinoctialToEquinoctialCirc() { doTestEquinoctialToEquinoctialCirc(Binary64Field.getInstance()); } @Test - public void testEquinoctialToCartesian() { + void testEquinoctialToCartesian() { doTestEquinoctialToCartesian(Binary64Field.getInstance()); } @Test - public void testEquinoctialToKeplerian() { + void testEquinoctialToKeplerian() { doTestEquinoctialToKeplerian(Binary64Field.getInstance()); } @Test - public void testNumericalIssue25() { + void testNumericalIssue25() { doTestNumericalIssue25(Binary64Field.getInstance()); } @Test - public void testAnomaly() { + void testAnomaly() { doTestAnomaly(Binary64Field.getInstance()); } @Test - public void testPositionVelocityNorms() { + void testPositionVelocityNorms() { doTestPositionVelocityNorms(Binary64Field.getInstance()); } @Test - public void testGeometry() { + void testGeometry() { doTestGeometry(Binary64Field.getInstance()); } @Test - public void testRadiusOfCurvature() { + void testRadiusOfCurvature() { doTestRadiusOfCurvature(Binary64Field.getInstance()); } @Test - public void testSymmetry() { + void testSymmetry() { doTestSymmetry(Binary64Field.getInstance()); } @Test - public void testJacobianReference() { + void testJacobianReference() { doTestJacobianReference(Binary64Field.getInstance()); } @Test - public void testJacobianFinitedifferences() { + void testJacobianFinitedifferences() { doTestJacobianFinitedifferences(Binary64Field.getInstance()); } @Test - public void testHyperbolic() { + void testHyperbolic() { Assertions.assertThrows(IllegalArgumentException.class, () -> { doTestHyperbolic(Binary64Field.getInstance()); }); } @Test - public void testToOrbitWithoutDerivatives() { + void testToOrbitWithoutDerivatives() { doTestToOrbitWithoutDerivatives(Binary64Field.getInstance()); } @Test - public void testToOrbitWithDerivatives() { + void testToOrbitWithDerivatives() { doTestToOrbitWithDerivatives(Binary64Field.getInstance()); } @Test - public void testDerivativesConversionSymmetry() { + void testDerivativesConversionSymmetry() { doTestDerivativesConversionSymmetry(Binary64Field.getInstance()); } @Test - public void testToString() { + void testToString() { doTestToString(Binary64Field.getInstance()); } @Test - public void testNonInertialFrame() { + void testNonInertialFrame() { Assertions.assertThrows(IllegalArgumentException.class, () -> { doTestNonInertialFrame(Binary64Field.getInstance()); }); } @Test - public void testNonKeplerianDerivatives() { + void testNonKeplerianDerivatives() { doTestNonKeplerianDerivatives(Binary64Field.getInstance()); } @Test - public void testPositionAngleDerivatives() { + void testPositionAngleDerivatives() { doTestPositionAngleDerivatives(Binary64Field.getInstance()); } @Test - public void testEquatorialRetrograde() { + void testEquatorialRetrograde() { doTestEquatorialRetrograde(Binary64Field.getInstance()); } @Test - public void testCopyNonKeplerianAcceleration() { + void testCopyNonKeplerianAcceleration() { doTestCopyNonKeplerianAcceleration(Binary64Field.getInstance()); } @Test - public void testNormalize() { + void testNormalize() { doTestNormalize(Binary64Field.getInstance()); } @@ -243,6 +240,36 @@ private EquinoctialOrbit createOrbitTestFromEquinoctialOrbit(final boolean withD } } + @Test + void testCoverageCachedPositionAngleTypeWithRates() { + // GIVEN + final double semiMajorAxis = 1e4; + final double ex = 0.; + final double ey = 0.; + final double expectedL = 0.; + final double expectedLDot = 0.; + final AbsoluteDate date = AbsoluteDate.ARBITRARY_EPOCH; + final Binary64Field field = Binary64Field.getInstance(); + final Binary64 zero = field.getZero(); + // WHEN & THEN + for (final PositionAngleType inputPositionAngleType: PositionAngleType.values()) { + for (final PositionAngleType cachedPositionAngleType: PositionAngleType.values()) { + final FieldEquinoctialOrbit fieldOrbit = new FieldEquinoctialOrbit<>( + zero.newInstance(semiMajorAxis), zero.newInstance(ex), zero.newInstance(ey), zero, zero, + zero.newInstance(expectedL), zero, zero, zero, zero, zero, zero.newInstance(expectedLDot), + inputPositionAngleType, cachedPositionAngleType, + FramesFactory.getGCRF(), new FieldAbsoluteDate<>(field, date), zero.newInstance(mu)); + Assertions.assertEquals(cachedPositionAngleType, fieldOrbit.getCachedPositionAngleType()); + Assertions.assertEquals(expectedL, fieldOrbit.getLv().getReal()); + Assertions.assertEquals(expectedL, fieldOrbit.getLM().getReal()); + Assertions.assertEquals(expectedL, fieldOrbit.getLE().getReal()); + Assertions.assertEquals(expectedLDot, fieldOrbit.getLvDot().getReal()); + Assertions.assertEquals(expectedLDot, fieldOrbit.getLMDot().getReal()); + Assertions.assertEquals(expectedLDot, fieldOrbit.getLEDot().getReal()); + } + } + } + private > void compareFieldOrbitToOrbit(final FieldEquinoctialOrbit fieldOrbit, final EquinoctialOrbit orbit) { Assertions.assertEquals(orbit.getFrame(), fieldOrbit.getFrame()); @@ -272,6 +299,95 @@ private > void compareFieldOrbitToOrbit(final } } + @Test + @Deprecated + void testTrueToEccentric() { + // GIVEN + final ComplexField field = ComplexField.getInstance(); + final Complex zero = field.getZero(); + final Complex ex = zero.newInstance(1e-2); + final Complex ey = zero.newInstance(1.e-3); + final Complex inputAnomaly = zero.newInstance(1.); + // WHEN + final Complex actualL = FieldEquinoctialOrbit.trueToEccentric(inputAnomaly, ex, ey); + // THEN + final Complex expectedL = FieldEquinoctialLongitudeArgumentUtility.trueToEccentric(ex, ey, inputAnomaly); + Assertions.assertEquals(expectedL.getReal(), actualL.getReal()); + } + + @Test + @Deprecated + void testEccentricToTrue() { + // GIVEN + final ComplexField field = ComplexField.getInstance(); + final Complex zero = field.getZero(); + final Complex ex = zero.newInstance(1e-2); + final Complex ey = zero.newInstance(1.e-3); + final Complex inputAnomaly = zero.newInstance(1.); + // WHEN + final Complex actualL = FieldEquinoctialOrbit.eccentricToTrue(inputAnomaly, ex, ey); + // THEN + final Complex expectedL = FieldEquinoctialLongitudeArgumentUtility.eccentricToTrue(ex, ey, inputAnomaly); + Assertions.assertEquals(expectedL.getReal(), actualL.getReal()); + } + + @Test + @Deprecated + void testMeanToEccentric() { + // GIVEN + final ComplexField field = ComplexField.getInstance(); + final Complex zero = field.getZero(); + final Complex ex = zero.newInstance(1e-2); + final Complex ey = zero.newInstance(1.e-3); + final Complex inputAnomaly = zero.newInstance(1.); + // WHEN + final Complex actualL = FieldEquinoctialOrbit.meanToEccentric(inputAnomaly, ex, ey); + // THEN + final Complex expectedL = FieldEquinoctialLongitudeArgumentUtility.meanToEccentric(ex, ey, inputAnomaly); + Assertions.assertEquals(expectedL.getReal(), actualL.getReal()); + } + + @Test + @Deprecated + void testEccentricToMean() { + // GIVEN + final ComplexField field = ComplexField.getInstance(); + final Complex zero = field.getZero(); + final Complex ex = zero.newInstance(1e-2); + final Complex ey = zero.newInstance(1.e-3); + final Complex inputAnomaly = zero.newInstance(1.); + // WHEN + final Complex actualL = FieldEquinoctialOrbit.eccentricToMean(inputAnomaly, ex, ey); + // THEN + final Complex expectedL = FieldEquinoctialLongitudeArgumentUtility.eccentricToMean(ex, ey, inputAnomaly); + Assertions.assertEquals(expectedL.getReal(), actualL.getReal()); + } + + @Test + void testGetLVersusDouble() { + // GIVEN + final double semiMajorAxis = 1e7; + final double ex = 1e-2; + final double ey = 1e-3; + final double expectedL = 2; + final AbsoluteDate date = AbsoluteDate.ARBITRARY_EPOCH; + final Binary64Field field = Binary64Field.getInstance(); + final Binary64 zero = field.getZero(); + // WHEN & THEN + for (final PositionAngleType inputPositionAngleType: PositionAngleType.values()) { + for (final PositionAngleType cachedPositionAngleType: PositionAngleType.values()) { + final FieldEquinoctialOrbit fieldOrbit = new FieldEquinoctialOrbit<>( + zero.newInstance(semiMajorAxis), zero.newInstance(ex), zero.newInstance(ey), zero, zero, + zero.newInstance(expectedL), inputPositionAngleType, cachedPositionAngleType, + FramesFactory.getGCRF(), new FieldAbsoluteDate<>(field, date), zero.newInstance(mu)); + final EquinoctialOrbit equinoctialOrbit = fieldOrbit.toOrbit(); + Assertions.assertEquals(equinoctialOrbit.getLE(), fieldOrbit.getLE().getReal()); + Assertions.assertEquals(equinoctialOrbit.getLv(), fieldOrbit.getLv().getReal()); + Assertions.assertEquals(equinoctialOrbit.getLM(), fieldOrbit.getLM().getReal()); + } + } + } + private > void doTestEquinoctialToEquinoctialEll(Field field) { T zero = field.getZero(); FieldAbsoluteDate date = new FieldAbsoluteDate<>(field); @@ -1314,7 +1430,7 @@ private > void doTestNormalize(Field field) Assertions.assertNull(normalized1.getEquinoctialEyDot()); Assertions.assertNull(normalized1.getHxDot()); Assertions.assertNull(normalized1.getHyDot()); - Assertions.assertNull(normalized1.getLvDot()); + Assertions.assertNull(normalized1.getLDot(normalized1.getCachedPositionAngleType())); T[] p = MathArrays.buildArray(field, 6); T[] pDot = MathArrays.buildArray(field, 6); diff --git a/src/test/java/org/orekit/propagation/events/FieldApsideDetectorTest.java b/src/test/java/org/orekit/propagation/events/FieldApsideDetectorTest.java index 3b5c66e859..7e7f925338 100644 --- a/src/test/java/org/orekit/propagation/events/FieldApsideDetectorTest.java +++ b/src/test/java/org/orekit/propagation/events/FieldApsideDetectorTest.java @@ -79,7 +79,7 @@ private > void doTestSimple(Field field) { @Test public void testFixedMaxCheck() { - doTestMaxcheck(Binary64Field.getInstance(), s -> 20.0, 4682); + doTestMaxcheck(Binary64Field.getInstance(), s -> 20.0, 4687); } @Test @@ -96,7 +96,7 @@ public void testAnomalyAwareMaxCheck() { final double timeToClosestApside = FastMath.min(timeSincePreviousPerigee, FastMath.min(timeToApogee, timeToNextPerigee)); return (timeToClosestApside < 2 * baseMaxCheck) ? baseMaxCheck : timeToClosestApside - 0.5 * baseMaxCheck; - }, 671); + }, 677); } private > void doTestMaxcheck(final Field field, From 67b977b03e879322f88190c45d67f0d34e809d38 Mon Sep 17 00:00:00 2001 From: Serrof Date: Fri, 16 Feb 2024 23:49:03 +0100 Subject: [PATCH 135/359] Implemented choice of cache in FieldCircularOrbit --- .../java/org/orekit/orbits/CircularOrbit.java | 28 ++ .../org/orekit/orbits/FieldCircularOrbit.java | 410 ++++++++++++++---- .../java/org/orekit/orbits/OrbitType.java | 38 +- .../orekit/orbits/FieldCircularOrbitTest.java | 181 ++++++-- 4 files changed, 527 insertions(+), 130 deletions(-) diff --git a/src/main/java/org/orekit/orbits/CircularOrbit.java b/src/main/java/org/orekit/orbits/CircularOrbit.java index 647da74315..28461354d0 100644 --- a/src/main/java/org/orekit/orbits/CircularOrbit.java +++ b/src/main/java/org/orekit/orbits/CircularOrbit.java @@ -495,39 +495,46 @@ public CircularOrbit(final Orbit op) { } /** {@inheritDoc} */ + @Override public OrbitType getType() { return OrbitType.CIRCULAR; } /** {@inheritDoc} */ + @Override public double getA() { return a; } /** {@inheritDoc} */ + @Override public double getADot() { return aDot; } /** {@inheritDoc} */ + @Override public double getEquinoctialEx() { final SinCos sc = FastMath.sinCos(raan); return ex * sc.cos() - ey * sc.sin(); } /** {@inheritDoc} */ + @Override public double getEquinoctialExDot() { final SinCos sc = FastMath.sinCos(raan); return (exDot - ey * raanDot) * sc.cos() - (eyDot + ex * raanDot) * sc.sin(); } /** {@inheritDoc} */ + @Override public double getEquinoctialEy() { final SinCos sc = FastMath.sinCos(raan); return ey * sc.cos() + ex * sc.sin(); } /** {@inheritDoc} */ + @Override public double getEquinoctialEyDot() { final SinCos sc = FastMath.sinCos(raan); return (eyDot + ex * raanDot) * sc.cos() + (exDot - ey * raanDot) * sc.sin(); @@ -563,6 +570,7 @@ public double getCircularEyDot() { } /** {@inheritDoc} */ + @Override public double getHx() { // Check for equatorial retrograde orbit if (FastMath.abs(i - FastMath.PI) < 1.0e-10) { @@ -572,6 +580,7 @@ public double getHx() { } /** {@inheritDoc} */ + @Override public double getHxDot() { // Check for equatorial retrograde orbit if (FastMath.abs(i - FastMath.PI) < 1.0e-10) { @@ -583,6 +592,7 @@ public double getHxDot() { } /** {@inheritDoc} */ + @Override public double getHy() { // Check for equatorial retrograde orbit if (FastMath.abs(i - FastMath.PI) < 1.0e-10) { @@ -592,6 +602,7 @@ public double getHy() { } /** {@inheritDoc} */ + @Override public double getHyDot() { // Check for equatorial retrograde orbit if (FastMath.abs(i - FastMath.PI) < 1.0e-10) { @@ -827,21 +838,25 @@ public static double eccentricToMean(final double alphaE, final double ex, final } /** {@inheritDoc} */ + @Override public double getE() { return FastMath.sqrt(ex * ex + ey * ey); } /** {@inheritDoc} */ + @Override public double getEDot() { return (ex * exDot + ey * eyDot) / getE(); } /** {@inheritDoc} */ + @Override public double getI() { return i; } /** {@inheritDoc} */ + @Override public double getIDot() { return iDot; } @@ -865,31 +880,37 @@ public double getRightAscensionOfAscendingNodeDot() { } /** {@inheritDoc} */ + @Override public double getLv() { return getAlphaV() + raan; } /** {@inheritDoc} */ + @Override public double getLvDot() { return getAlphaVDot() + raanDot; } /** {@inheritDoc} */ + @Override public double getLE() { return getAlphaE() + raan; } /** {@inheritDoc} */ + @Override public double getLEDot() { return getAlphaEDot() + raanDot; } /** {@inheritDoc} */ + @Override public double getLM() { return getAlphaM() + raan; } /** {@inheritDoc} */ + @Override public double getLMDot() { return getAlphaMDot() + raanDot; } @@ -1068,6 +1089,7 @@ private Vector3D nonKeplerianAcceleration() { } /** {@inheritDoc} */ + @Override protected Vector3D initPosition() { // get equinoctial parameters @@ -1113,6 +1135,7 @@ protected Vector3D initPosition() { } /** {@inheritDoc} */ + @Override protected TimeStampedPVCoordinates initPVCoordinates() { // position and velocity @@ -1130,6 +1153,7 @@ protected TimeStampedPVCoordinates initPVCoordinates() { } /** {@inheritDoc} */ + @Override public CircularOrbit shiftedBy(final double dt) { // use Keplerian-only motion @@ -1167,6 +1191,7 @@ public CircularOrbit shiftedBy(final double dt) { } /** {@inheritDoc} */ + @Override protected double[][] computeJacobianMeanWrtCartesian() { @@ -1296,6 +1321,7 @@ protected double[][] computeJacobianMeanWrtCartesian() { } /** {@inheritDoc} */ + @Override protected double[][] computeJacobianEccentricWrtCartesian() { // start by computing the Jacobian with mean angle @@ -1324,6 +1350,7 @@ protected double[][] computeJacobianEccentricWrtCartesian() { } /** {@inheritDoc} */ + @Override protected double[][] computeJacobianTrueWrtCartesian() { // start by computing the Jacobian with eccentric angle @@ -1372,6 +1399,7 @@ protected double[][] computeJacobianTrueWrtCartesian() { } /** {@inheritDoc} */ + @Override public void addKeplerContribution(final PositionAngleType type, final double gm, final double[] pDot) { final double oMe2; diff --git a/src/main/java/org/orekit/orbits/FieldCircularOrbit.java b/src/main/java/org/orekit/orbits/FieldCircularOrbit.java index 6b740c13f9..4b400ae4c6 100644 --- a/src/main/java/org/orekit/orbits/FieldCircularOrbit.java +++ b/src/main/java/org/orekit/orbits/FieldCircularOrbit.java @@ -89,8 +89,11 @@ public class FieldCircularOrbit> extends Field /** Right Ascension of Ascending Node (rad). */ private final T raan; - /** True latitude argument (rad). */ - private final T alphaV; + /** Cached latitude argument (rad). */ + private final T cachedAlpha; + + /** Type of cached position angle (latitude argument). */ + private final PositionAngleType cachedPositionAngleType; /** Semi-major axis derivative (m/s). */ private final T aDot; @@ -108,7 +111,7 @@ public class FieldCircularOrbit> extends Field private final T raanDot; /** True latitude argument derivative (rad/s). */ - private final T alphaVDot; + private final T cachedAlphaDot; /** Partial Cartesian coordinates (position and velocity are valid, acceleration may be missing). */ private FieldPVCoordinates partialPV; @@ -121,21 +124,75 @@ public class FieldCircularOrbit> extends Field * @param raan right ascension of ascending node (Ω, rad) * @param alpha an + ω, mean, eccentric or true latitude argument (rad) * @param type type of latitude argument + * @param cachedPositionAngleType type of cached latitude argument * @param frame the frame in which are defined the parameters * (must be a {@link Frame#isPseudoInertial pseudo-inertial frame}) * @param date date of the orbital parameters * @param mu central attraction coefficient (m³/s²) * @exception IllegalArgumentException if eccentricity is equal to 1 or larger or * if frame is not a {@link Frame#isPseudoInertial pseudo-inertial frame} + * @since 12.1 */ - public FieldCircularOrbit(final T a, final T ex, final T ey, - final T i, final T raan, + public FieldCircularOrbit(final T a, final T ex, final T ey, final T i, final T raan, final T alpha, final PositionAngleType type, + final PositionAngleType cachedPositionAngleType, final Frame frame, final FieldAbsoluteDate date, final T mu) throws IllegalArgumentException { this(a, ex, ey, i, raan, alpha, null, null, null, null, null, null, - type, frame, date, mu); + type, cachedPositionAngleType, frame, date, mu); + } + + /** Creates a new instance without derivatives and with cached position angle same as value inputted. + * @param a semi-major axis (m) + * @param ex e cos(ω), first component of circular eccentricity vector + * @param ey e sin(ω), second component of circular eccentricity vector + * @param i inclination (rad) + * @param raan right ascension of ascending node (Ω, rad) + * @param alpha an + ω, mean, eccentric or true latitude argument (rad) + * @param type type of latitude argument + * @param frame the frame in which are defined the parameters + * (must be a {@link Frame#isPseudoInertial pseudo-inertial frame}) + * @param date date of the orbital parameters + * @param mu central attraction coefficient (m³/s²) + * @exception IllegalArgumentException if eccentricity is equal to 1 or larger or + * if frame is not a {@link Frame#isPseudoInertial pseudo-inertial frame} + */ + public FieldCircularOrbit(final T a, final T ex, final T ey, final T i, final T raan, + final T alpha, final PositionAngleType type, + final Frame frame, final FieldAbsoluteDate date, final T mu) + throws IllegalArgumentException { + this(a, ex, ey, i, raan, alpha, type, type, frame, date, mu); + } + + /** Creates a new instance. + * @param a semi-major axis (m) + * @param ex e cos(ω), first component of circular eccentricity vector + * @param ey e sin(ω), second component of circular eccentricity vector + * @param i inclination (rad) + * @param raan right ascension of ascending node (Ω, rad) + * @param alpha an + ω, mean, eccentric or true latitude argument (rad) + * @param aDot semi-major axis derivative (m/s) + * @param exDot d(e cos(ω))/dt, first component of circular eccentricity vector derivative + * @param eyDot d(e sin(ω))/dt, second component of circular eccentricity vector derivative + * @param iDot inclination derivative(rad/s) + * @param raanDot right ascension of ascending node derivative (rad/s) + * @param alphaDot d(an + ω), mean, eccentric or true latitude argument derivative (rad/s) + * @param type type of latitude argument + * @param frame the frame in which are defined the parameters + * (must be a {@link Frame#isPseudoInertial pseudo-inertial frame}) + * @param date date of the orbital parameters + * @param mu central attraction coefficient (m³/s²) + * @exception IllegalArgumentException if eccentricity is equal to 1 or larger or + * if frame is not a {@link Frame#isPseudoInertial pseudo-inertial frame} + */ + public FieldCircularOrbit(final T a, final T ex, final T ey, + final T i, final T raan, final T alpha, + final T aDot, final T exDot, final T eyDot, + final T iDot, final T raanDot, final T alphaDot, final PositionAngleType type, + final Frame frame, final FieldAbsoluteDate date, final T mu) + throws IllegalArgumentException { + this(a, ex, ey, i, raan, alpha, aDot, exDot, eyDot, iDot, raanDot, alphaDot, type, type, frame, date, mu); } /** Creates a new instance. @@ -152,18 +209,20 @@ public FieldCircularOrbit(final T a, final T ex, final T ey, * @param raanDot right ascension of ascending node derivative (rad/s) * @param alphaDot d(an + ω), mean, eccentric or true latitude argument derivative (rad/s) * @param type type of latitude argument + * @param cachedPositionAngleType type of cached latitude argument * @param frame the frame in which are defined the parameters * (must be a {@link Frame#isPseudoInertial pseudo-inertial frame}) * @param date date of the orbital parameters * @param mu central attraction coefficient (m³/s²) * @exception IllegalArgumentException if eccentricity is equal to 1 or larger or * if frame is not a {@link Frame#isPseudoInertial pseudo-inertial frame} + * @since 12.1 */ public FieldCircularOrbit(final T a, final T ex, final T ey, final T i, final T raan, final T alpha, final T aDot, final T exDot, final T eyDot, final T iDot, final T raanDot, final T alphaDot, - final PositionAngleType type, + final PositionAngleType type, final PositionAngleType cachedPositionAngleType, final Frame frame, final FieldAbsoluteDate date, final T mu) throws IllegalArgumentException { super(frame, date, mu); @@ -182,45 +241,18 @@ public FieldCircularOrbit(final T a, final T ex, final T ey, this.iDot = iDot; this.raan = raan; this.raanDot = raanDot; + this.cachedPositionAngleType = cachedPositionAngleType; if (hasDerivatives()) { - final FieldUnivariateDerivative1 exUD = new FieldUnivariateDerivative1<>(ex, exDot); - final FieldUnivariateDerivative1 eyUD = new FieldUnivariateDerivative1<>(ey, eyDot); - final FieldUnivariateDerivative1 alphaUD = new FieldUnivariateDerivative1<>(alpha, alphaDot); - final FieldUnivariateDerivative1 alphavUD; - switch (type) { - case MEAN : - alphavUD = FieldCircularLatitudeArgumentUtility.meanToTrue(exUD, eyUD, alphaUD); - break; - case ECCENTRIC : - alphavUD = FieldCircularLatitudeArgumentUtility.eccentricToTrue(exUD, eyUD, alphaUD); - break; - case TRUE : - alphavUD = alphaUD; - break; - default : - throw new OrekitInternalError(null); - } - this.alphaV = alphavUD.getValue(); - this.alphaVDot = alphavUD.getDerivative(1); + final FieldUnivariateDerivative1 alphaUD = initializeCachedAlpha(alpha, alphaDot, type); + this.cachedAlpha = alphaUD.getValue(); + this.cachedAlphaDot = alphaUD.getFirstDerivative(); } else { - switch (type) { - case MEAN : - this.alphaV = FieldCircularLatitudeArgumentUtility.meanToTrue(ex, ey, alpha); - break; - case ECCENTRIC : - this.alphaV = FieldCircularLatitudeArgumentUtility.eccentricToTrue(ex, ey, alpha); - break; - case TRUE : - this.alphaV = alpha; - break; - default : - throw new OrekitInternalError(null); - } - this.alphaVDot = null; + this.cachedAlpha = initializeCachedAlpha(alpha, type); + this.cachedAlphaDot = null; } - this.partialPV = null; + partialPV = null; } @@ -242,6 +274,7 @@ public FieldCircularOrbit(final TimeStampedFieldPVCoordinates pvCoordinates, final Frame frame, final T mu) throws IllegalArgumentException { super(pvCoordinates, frame, mu); + this.cachedPositionAngleType = PositionAngleType.TRUE; // compute semi-major axis final FieldVector3D pvP = pvCoordinates.getPosition(); @@ -290,7 +323,7 @@ public FieldCircularOrbit(final TimeStampedFieldPVCoordinates pvCoordinates, // compute latitude argument final T beta = (ex.multiply(ex).add(ey.multiply(ey)).negate().add(1)).sqrt().add(1).reciprocal(); - alphaV = FieldCircularLatitudeArgumentUtility.eccentricToTrue(ex, ey, y2.add(ey).add(eSE.multiply(beta).multiply(ex)).atan2(x2.add(ex).subtract(eSE.multiply(beta).multiply(ey))) + cachedAlpha = FieldCircularLatitudeArgumentUtility.eccentricToTrue(ex, ey, y2.add(ey).add(eSE.multiply(beta).multiply(ex)).atan2(x2.add(ex).subtract(eSE.multiply(beta).multiply(ey))) ); partialPV = pvCoordinates; @@ -320,7 +353,7 @@ public FieldCircularOrbit(final TimeStampedFieldPVCoordinates pvCoordinates, final FieldUnivariateDerivative1 eyUD = new FieldUnivariateDerivative1<>(ey, eyDot); final FieldUnivariateDerivative1 alphaMUD = new FieldUnivariateDerivative1<>(getAlphaM(), alphaMDot); final FieldUnivariateDerivative1 alphavUD = FieldCircularLatitudeArgumentUtility.meanToTrue(exUD, eyUD, alphaMUD); - alphaVDot = alphavUD.getDerivative(1); + cachedAlphaDot = alphavUD.getFirstDerivative(); } else { // acceleration is either almost zero or NaN, @@ -331,7 +364,7 @@ public FieldCircularOrbit(final TimeStampedFieldPVCoordinates pvCoordinates, eyDot = null; iDot = null; raanDot = null; - alphaVDot = null; + cachedAlphaDot = null; } } @@ -376,7 +409,8 @@ public FieldCircularOrbit(final FieldOrbit op) { final T equiEy = op.getEquinoctialEy(); ex = equiEx.multiply(cosRaan).add(equiEy.multiply(sinRaan)); ey = equiEy.multiply(cosRaan).subtract(equiEx.multiply(sinRaan)); - alphaV = op.getLv().subtract(raan); + cachedPositionAngleType = PositionAngleType.TRUE; + cachedAlpha = op.getLv().subtract(raan); if (op.hasDerivatives()) { aDot = op.getADot(); @@ -390,14 +424,14 @@ public FieldCircularOrbit(final FieldOrbit op) { add(equiEyDot.subtract(equiEx.multiply(raanDot)).multiply(sinRaan)); eyDot = equiEyDot.subtract(equiEx.multiply(raanDot)).multiply(cosRaan). subtract(equiExDot.add(equiEy.multiply(raanDot)).multiply(sinRaan)); - alphaVDot = op.getLvDot().subtract(raanDot); + cachedAlphaDot = op.getLvDot().subtract(raanDot); } else { aDot = null; exDot = null; eyDot = null; iDot = null; raanDot = null; - alphaVDot = null; + cachedAlphaDot = null; } partialPV = null; @@ -418,7 +452,8 @@ public FieldCircularOrbit(final Field field, final CircularOrbit op) { raan = getZero().newInstance(op.getRightAscensionOfAscendingNode()); ex = getZero().newInstance(op.getCircularEx()); ey = getZero().newInstance(op.getCircularEy()); - alphaV = getZero().newInstance(op.getAlphaV()); + cachedPositionAngleType = op.getCachedPositionAngleType(); + cachedAlpha = getZero().newInstance(op.getAlpha(cachedPositionAngleType)); if (op.hasDerivatives()) { aDot = getZero().newInstance(op.getADot()); @@ -426,14 +461,14 @@ public FieldCircularOrbit(final Field field, final CircularOrbit op) { raanDot = getZero().newInstance(op.getRightAscensionOfAscendingNodeDot()); exDot = getZero().newInstance(op.getCircularExDot()); eyDot = getZero().newInstance(op.getCircularEyDot()); - alphaVDot = getZero().newInstance(op.getAlphaVDot()); + cachedAlphaDot = getZero().newInstance(op.getAlphaDot(cachedPositionAngleType)); } else { aDot = null; exDot = null; eyDot = null; iDot = null; raanDot = null; - alphaVDot = null; + cachedAlphaDot = null; } partialPV = null; @@ -451,27 +486,32 @@ public FieldCircularOrbit(final Field field, final Orbit op) { } /** {@inheritDoc} */ + @Override public OrbitType getType() { return OrbitType.CIRCULAR; } /** {@inheritDoc} */ + @Override public T getA() { return a; } /** {@inheritDoc} */ + @Override public T getADot() { return aDot; } /** {@inheritDoc} */ + @Override public T getEquinoctialEx() { final FieldSinCos sc = FastMath.sinCos(raan); return ex.multiply(sc.cos()).subtract(ey.multiply(sc.sin())); } /** {@inheritDoc} */ + @Override public T getEquinoctialExDot() { if (!hasDerivatives()) { @@ -485,12 +525,14 @@ public T getEquinoctialExDot() { } /** {@inheritDoc} */ + @Override public T getEquinoctialEy() { final FieldSinCos sc = FastMath.sinCos(raan); return ey.multiply(sc.cos()).add(ex.multiply(sc.sin())); } /** {@inheritDoc} */ + @Override public T getEquinoctialEyDot() { if (!hasDerivatives()) { @@ -532,6 +574,7 @@ public T getCircularEyDot() { } /** {@inheritDoc} */ + @Override public T getHx() { // Check for equatorial retrograde orbit if (FastMath.abs(i.subtract(i.getPi()).getReal()) < 1.0e-10) { @@ -541,6 +584,7 @@ public T getHx() { } /** {@inheritDoc} */ + @Override public T getHxDot() { if (!hasDerivatives()) { @@ -560,6 +604,7 @@ public T getHxDot() { } /** {@inheritDoc} */ + @Override public T getHy() { // Check for equatorial retrograde orbit if (FastMath.abs(i.subtract(i.getPi()).getReal()) < 1.0e-10) { @@ -569,6 +614,7 @@ public T getHy() { } /** {@inheritDoc} */ + @Override public T getHyDot() { if (!hasDerivatives()) { @@ -591,21 +637,71 @@ public T getHyDot() { * @return v + ω true latitude argument (rad) */ public T getAlphaV() { - return alphaV; + switch (cachedPositionAngleType) { + case TRUE: + return cachedAlpha; + + case ECCENTRIC: + return FieldCircularLatitudeArgumentUtility.eccentricToTrue(ex, ey, cachedAlpha); + + case MEAN: + return FieldCircularLatitudeArgumentUtility.meanToTrue(ex, ey, cachedAlpha); + + default: + throw new OrekitInternalError(null); + } } /** Get the true latitude argument derivative. * @return d(v + ω)/dt true latitude argument derivative (rad/s) */ public T getAlphaVDot() { - return alphaVDot; + + if (!hasDerivatives()) { + return null; + } + switch (cachedPositionAngleType) { + case ECCENTRIC: + final FieldUnivariateDerivative1 alphaEUD = new FieldUnivariateDerivative1<>(cachedAlpha, cachedAlphaDot); + final FieldUnivariateDerivative1 exUD = new FieldUnivariateDerivative1<>(ex, exDot); + final FieldUnivariateDerivative1 eyUD = new FieldUnivariateDerivative1<>(ey, eyDot); + final FieldUnivariateDerivative1 alphaVUD = FieldCircularLatitudeArgumentUtility.eccentricToTrue(exUD, eyUD, + alphaEUD); + return alphaVUD.getFirstDerivative(); + + case TRUE: + return cachedAlphaDot; + + case MEAN: + final FieldUnivariateDerivative1 alphaMUD = new FieldUnivariateDerivative1<>(cachedAlpha, cachedAlphaDot); + final FieldUnivariateDerivative1 exUD2 = new FieldUnivariateDerivative1<>(ex, exDot); + final FieldUnivariateDerivative1 eyUD2 = new FieldUnivariateDerivative1<>(ey, eyDot); + final FieldUnivariateDerivative1 alphaVUD2 = FieldCircularLatitudeArgumentUtility.meanToTrue(exUD2, + eyUD2, alphaMUD); + return alphaVUD2.getFirstDerivative(); + + default: + throw new OrekitInternalError(null); + } } /** Get the eccentric latitude argument. * @return E + ω eccentric latitude argument (rad) */ public T getAlphaE() { - return trueToEccentric(alphaV, ex, ey); + switch (cachedPositionAngleType) { + case TRUE: + return FieldCircularLatitudeArgumentUtility.trueToEccentric(ex, ey, cachedAlpha); + + case ECCENTRIC: + return cachedAlpha; + + case MEAN: + return FieldCircularLatitudeArgumentUtility.meanToEccentric(ex, ey, cachedAlpha); + + default: + throw new OrekitInternalError(null); + } } /** Get the eccentric latitude argument derivative. @@ -616,12 +712,29 @@ public T getAlphaEDot() { if (!hasDerivatives()) { return null; } - - final FieldUnivariateDerivative1 alphaVUD = new FieldUnivariateDerivative1<>(alphaV, alphaVDot); - final FieldUnivariateDerivative1 exUD = new FieldUnivariateDerivative1<>(ex, exDot); - final FieldUnivariateDerivative1 eyUD = new FieldUnivariateDerivative1<>(ey, eyDot); - final FieldUnivariateDerivative1 alphaEUD = trueToEccentric(alphaVUD, exUD, eyUD); - return alphaEUD.getDerivative(1); + switch (cachedPositionAngleType) { + case TRUE: + final FieldUnivariateDerivative1 alphaVUD = new FieldUnivariateDerivative1<>(cachedAlpha, cachedAlphaDot); + final FieldUnivariateDerivative1 exUD = new FieldUnivariateDerivative1<>(ex, exDot); + final FieldUnivariateDerivative1 eyUD = new FieldUnivariateDerivative1<>(ey, eyDot); + final FieldUnivariateDerivative1 alphaEUD = FieldCircularLatitudeArgumentUtility.trueToEccentric(exUD, eyUD, + alphaVUD); + return alphaEUD.getFirstDerivative(); + + case ECCENTRIC: + return cachedAlphaDot; + + case MEAN: + final FieldUnivariateDerivative1 alphaMUD = new FieldUnivariateDerivative1<>(cachedAlpha, cachedAlphaDot); + final FieldUnivariateDerivative1 exUD2 = new FieldUnivariateDerivative1<>(ex, exDot); + final FieldUnivariateDerivative1 eyUD2 = new FieldUnivariateDerivative1<>(ey, eyDot); + final FieldUnivariateDerivative1 alphaVUD2 = FieldCircularLatitudeArgumentUtility.meanToEccentric(exUD2, + eyUD2, alphaMUD); + return alphaVUD2.getFirstDerivative(); + + default: + throw new OrekitInternalError(null); + } } @@ -629,7 +742,19 @@ public T getAlphaEDot() { * @return M + ω mean latitude argument (rad) */ public T getAlphaM() { - return FieldCircularLatitudeArgumentUtility.trueToMean(ex, ey, alphaV); + switch (cachedPositionAngleType) { + case TRUE: + return FieldCircularLatitudeArgumentUtility.trueToMean(ex, ey, cachedAlpha); + + case MEAN: + return cachedAlpha; + + case ECCENTRIC: + return FieldCircularLatitudeArgumentUtility.eccentricToMean(ex, ey, cachedAlpha); + + default: + throw new OrekitInternalError(null); + } } /** Get the mean latitude argument derivative. @@ -640,14 +765,29 @@ public T getAlphaMDot() { if (!hasDerivatives()) { return null; } - - final FieldUnivariateDerivative1 alphaVUD = new FieldUnivariateDerivative1<>(alphaV, alphaVDot); - final FieldUnivariateDerivative1 exUD = new FieldUnivariateDerivative1<>(ex, exDot); - final FieldUnivariateDerivative1 eyUD = new FieldUnivariateDerivative1<>(ey, eyDot); - final FieldUnivariateDerivative1 alphaMUD = FieldCircularLatitudeArgumentUtility.trueToMean(exUD, eyUD, alphaVUD - ); - return alphaMUD.getDerivative(1); - + switch (cachedPositionAngleType) { + case TRUE: + final FieldUnivariateDerivative1 alphaVUD = new FieldUnivariateDerivative1<>(cachedAlpha, cachedAlphaDot); + final FieldUnivariateDerivative1 exUD = new FieldUnivariateDerivative1<>(ex, exDot); + final FieldUnivariateDerivative1 eyUD = new FieldUnivariateDerivative1<>(ey, eyDot); + final FieldUnivariateDerivative1 alphaMUD = FieldCircularLatitudeArgumentUtility.trueToMean(exUD, eyUD, + alphaVUD); + return alphaMUD.getFirstDerivative(); + + case MEAN: + return cachedAlphaDot; + + case ECCENTRIC: + final FieldUnivariateDerivative1 alphaEUD = new FieldUnivariateDerivative1<>(cachedAlpha, cachedAlphaDot); + final FieldUnivariateDerivative1 exUD2 = new FieldUnivariateDerivative1<>(ex, exDot); + final FieldUnivariateDerivative1 eyUD2 = new FieldUnivariateDerivative1<>(ey, eyDot); + final FieldUnivariateDerivative1 alphaMUD2 = FieldCircularLatitudeArgumentUtility.eccentricToMean(exUD2, + eyUD2, alphaEUD); + return alphaMUD2.getFirstDerivative(); + + default: + throw new OrekitInternalError(null); + } } /** Get the latitude argument. @@ -719,11 +859,13 @@ public static > T eccentricToMean(final T alph } /** {@inheritDoc} */ + @Override public T getE() { return ex.multiply(ex).add(ey.multiply(ey)).sqrt(); } /** {@inheritDoc} */ + @Override public T getEDot() { if (!hasDerivatives()) { @@ -735,11 +877,13 @@ public T getEDot() { } /** {@inheritDoc} */ + @Override public T getI() { return i; } /** {@inheritDoc} */ + @Override public T getIDot() { return iDot; } @@ -759,31 +903,37 @@ public T getRightAscensionOfAscendingNodeDot() { } /** {@inheritDoc} */ + @Override public T getLv() { - return alphaV.add(raan); + return getAlphaV().add(raan); } /** {@inheritDoc} */ + @Override public T getLvDot() { - return hasDerivatives() ? alphaVDot.add(raanDot) : null; + return hasDerivatives() ? getAlphaVDot().add(raanDot) : null; } /** {@inheritDoc} */ + @Override public T getLE() { return getAlphaE().add(raan); } /** {@inheritDoc} */ + @Override public T getLEDot() { return hasDerivatives() ? getAlphaEDot().add(raanDot) : null; } /** {@inheritDoc} */ + @Override public T getLM() { return getAlphaM().add(raan); } /** {@inheritDoc} */ + @Override public T getLMDot() { return hasDerivatives() ? getAlphaMDot().add(raanDot) : null; } @@ -855,6 +1005,96 @@ private void computePVWithoutA() { } + + /** Initialize cached alpha with rate. + * @param alpha input alpha + * @param alphaDot rate of input alpha + * @param inputType position angle type passed as input + * @return alpha to cache with rate + * @since 12.1 + */ + private FieldUnivariateDerivative1 initializeCachedAlpha(final T alpha, final T alphaDot, + final PositionAngleType inputType) { + if (cachedPositionAngleType == inputType) { + return new FieldUnivariateDerivative1<>(alpha, alphaDot); + + } else { + final FieldUnivariateDerivative1 exUD = new FieldUnivariateDerivative1<>(ex, exDot); + final FieldUnivariateDerivative1 eyUD = new FieldUnivariateDerivative1<>(ey, eyDot); + final FieldUnivariateDerivative1 alphaUD = new FieldUnivariateDerivative1<>(alpha, alphaDot); + + switch (cachedPositionAngleType) { + + case ECCENTRIC: + if (inputType == PositionAngleType.MEAN) { + return FieldCircularLatitudeArgumentUtility.meanToEccentric(exUD, eyUD, alphaUD); + } else { + return FieldCircularLatitudeArgumentUtility.trueToEccentric(exUD, eyUD, alphaUD); + } + + case TRUE: + if (inputType == PositionAngleType.MEAN) { + return FieldCircularLatitudeArgumentUtility.meanToTrue(exUD, eyUD, alphaUD); + } else { + return FieldCircularLatitudeArgumentUtility.eccentricToTrue(exUD, eyUD, alphaUD); + } + + case MEAN: + if (inputType == PositionAngleType.TRUE) { + return FieldCircularLatitudeArgumentUtility.trueToMean(exUD, eyUD, alphaUD); + } else { + return FieldCircularLatitudeArgumentUtility.eccentricToMean(exUD, eyUD, alphaUD); + } + + default: + throw new OrekitInternalError(null); + + } + + } + + } + + /** Initialize cached alpha. + * @param alpha input alpha + * @param positionAngleType position angle type passed as input + * @return alpha to cache + * @since 12.1 + */ + private T initializeCachedAlpha(final T alpha, final PositionAngleType positionAngleType) { + if (positionAngleType == cachedPositionAngleType) { + return alpha; + + } else { + switch (cachedPositionAngleType) { + + case ECCENTRIC: + if (positionAngleType == PositionAngleType.MEAN) { + return FieldCircularLatitudeArgumentUtility.meanToEccentric(ex, ey, alpha); + } else { + return FieldCircularLatitudeArgumentUtility.trueToEccentric(ex, ey, alpha); + } + + case MEAN: + if (positionAngleType == PositionAngleType.TRUE) { + return FieldCircularLatitudeArgumentUtility.trueToMean(ex, ey, alpha); + } else { + return FieldCircularLatitudeArgumentUtility.eccentricToMean(ex, ey, alpha); + } + + case TRUE: + if (positionAngleType == PositionAngleType.MEAN) { + return FieldCircularLatitudeArgumentUtility.meanToTrue(ex, ey, alpha); + } else { + return FieldCircularLatitudeArgumentUtility.eccentricToTrue(ex, ey, alpha); + } + + default: + throw new OrekitInternalError(null); + } + } + } + /** Compute non-Keplerian part of the acceleration from first time derivatives. *

                * This method should be called only when {@link #hasDerivatives()} returns true. @@ -891,6 +1131,7 @@ private FieldVector3D nonKeplerianAcceleration() { } /** {@inheritDoc} */ + @Override protected FieldVector3D initPosition() { // get equinoctial parameters final T equEx = getEquinoctialEx(); @@ -936,6 +1177,7 @@ protected FieldVector3D initPosition() { } /** {@inheritDoc} */ + @Override protected TimeStampedFieldPVCoordinates initPVCoordinates() { // position and velocity @@ -954,17 +1196,19 @@ protected TimeStampedFieldPVCoordinates initPVCoordinates() { } /** {@inheritDoc} */ + @Override public FieldCircularOrbit shiftedBy(final double dt) { return shiftedBy(getZero().newInstance(dt)); } /** {@inheritDoc} */ + @Override public FieldCircularOrbit shiftedBy(final T dt) { // use Keplerian-only motion final FieldCircularOrbit keplerianShifted = new FieldCircularOrbit<>(a, ex, ey, i, raan, getAlphaM().add(getKeplerianMeanMotion().multiply(dt)), - PositionAngleType.MEAN, getFrame(), + PositionAngleType.MEAN, cachedPositionAngleType, getFrame(), getDate().shiftedBy(dt), getMu()); if (hasDerivatives()) { @@ -997,6 +1241,7 @@ PositionAngleType.MEAN, getFrame(), } /** {@inheritDoc} */ + @Override protected T[][] computeJacobianMeanWrtCartesian() { final T[][] jacobian = MathArrays.buildArray(getOne().getField(), 6, 6); @@ -1156,6 +1401,7 @@ protected T[][] computeJacobianMeanWrtCartesian() { } /** {@inheritDoc} */ + @Override protected T[][] computeJacobianEccentricWrtCartesian() { // start by computing the Jacobian with mean angle @@ -1184,6 +1430,7 @@ protected T[][] computeJacobianEccentricWrtCartesian() { } /** {@inheritDoc} */ + @Override protected T[][] computeJacobianTrueWrtCartesian() { // start by computing the Jacobian with eccentric angle @@ -1230,12 +1477,13 @@ protected T[][] computeJacobianTrueWrtCartesian() { } /** {@inheritDoc} */ + @Override public void addKeplerContribution(final PositionAngleType type, final T gm, final T[] pDot) { final T oMe2; final T ksi; final T n = a.reciprocal().multiply(gm).sqrt().divide(a); - final FieldSinCos sc = FastMath.sinCos(alphaV); + final FieldSinCos sc = FastMath.sinCos(getAlphaV()); switch (type) { case MEAN : pDot[5] = pDot[5].add(n); @@ -1264,14 +1512,14 @@ public String toString() { append(", ex: ").append(ex.getReal()).append(", ey: ").append(ey.getReal()). append(", i: ").append(FastMath.toDegrees(i.getReal())). append(", raan: ").append(FastMath.toDegrees(raan.getReal())). - append(", alphaV: ").append(FastMath.toDegrees(alphaV.getReal())). + append(", alphaV: ").append(FastMath.toDegrees(getAlphaV().getReal())). append(";}").toString(); } /** {@inheritDoc} */ @Override public PositionAngleType getCachedPositionAngleType() { - return PositionAngleType.TRUE; + return cachedPositionAngleType; } /** {@inheritDoc} */ @@ -1283,28 +1531,26 @@ public boolean hasRates() { /** {@inheritDoc} */ @Override public FieldCircularOrbit removeRates() { - final PositionAngleType positionAngleType = getCachedPositionAngleType(); return new FieldCircularOrbit<>(getA(), getCircularEx(), getCircularEy(), - getI(), getRightAscensionOfAscendingNode(), getAlpha(positionAngleType), - positionAngleType, getFrame(), getDate(), getMu()); + getI(), getRightAscensionOfAscendingNode(), cachedAlpha, + cachedPositionAngleType, getFrame(), getDate(), getMu()); } /** {@inheritDoc} */ @Override public CircularOrbit toOrbit() { - final PositionAngleType cachedPositionAngleType = getCachedPositionAngleType(); - final double cachedPositionAngle = getAlpha(cachedPositionAngleType).getReal(); + final double cachedPositionAngle = cachedAlpha.getReal(); if (hasDerivatives()) { return new CircularOrbit(a.getReal(), ex.getReal(), ey.getReal(), i.getReal(), raan.getReal(), cachedPositionAngle, aDot.getReal(), exDot.getReal(), eyDot.getReal(), - iDot.getReal(), raanDot.getReal(), getAlphaDot(cachedPositionAngleType).getReal(), - cachedPositionAngleType, cachedPositionAngleType, getFrame(), + iDot.getReal(), raanDot.getReal(), cachedAlphaDot.getReal(), + cachedPositionAngleType, getFrame(), getDate().toAbsoluteDate(), getMu().getReal()); } else { return new CircularOrbit(a.getReal(), ex.getReal(), ey.getReal(), i.getReal(), raan.getReal(), cachedPositionAngle, - cachedPositionAngleType, cachedPositionAngleType, getFrame(), + cachedPositionAngleType, getFrame(), getDate().toAbsoluteDate(), getMu().getReal()); } } diff --git a/src/main/java/org/orekit/orbits/OrbitType.java b/src/main/java/org/orekit/orbits/OrbitType.java index fcc5443ec5..d3dbf3d927 100644 --- a/src/main/java/org/orekit/orbits/OrbitType.java +++ b/src/main/java/org/orekit/orbits/OrbitType.java @@ -345,7 +345,7 @@ public CircularOrbit normalize(final Orbit orbit, final Orbit reference) { // convert input to proper type final CircularOrbit cO = convertType(orbit); final CircularOrbit cR = convertType(reference); - final PositionAngleType cachedPositionAngleType = cR.getCachedPositionAngleType(); + final PositionAngleType cachedPositionAngleType = cO.getCachedPositionAngleType(); // perform normalization if (cO.hasDerivatives()) { @@ -391,6 +391,7 @@ public > FieldCircularOrbit normalize(final // convert input to proper type final FieldCircularOrbit cO = convertType(orbit); final FieldCircularOrbit cR = convertType(reference); + final PositionAngleType positionAngleType = cO.getCachedPositionAngleType(); // perform normalization if (cO.hasDerivatives()) { @@ -398,15 +399,17 @@ public > FieldCircularOrbit normalize(final cO.getCircularEx(), cO.getCircularEy(), cO.getI(), - MathUtils.normalizeAngle(cO.getRightAscensionOfAscendingNode(), cR.getRightAscensionOfAscendingNode()), - MathUtils.normalizeAngle(cO.getAlphaV(), cR.getAlphaV()), + MathUtils.normalizeAngle(cO.getRightAscensionOfAscendingNode(), + cR.getRightAscensionOfAscendingNode()), + MathUtils.normalizeAngle(cO.getAlpha(positionAngleType), + cR.getAlpha(positionAngleType)), cO.getADot(), cO.getCircularExDot(), cO.getCircularEyDot(), cO.getIDot(), cO.getRightAscensionOfAscendingNodeDot(), - cO.getAlphaVDot(), - PositionAngleType.TRUE, + cO.getAlphaDot(positionAngleType), + positionAngleType, cO.getFrame(), cO.getDate(), cO.getMu()); @@ -415,9 +418,11 @@ public > FieldCircularOrbit normalize(final cO.getCircularEx(), cO.getCircularEy(), cO.getI(), - MathUtils.normalizeAngle(cO.getRightAscensionOfAscendingNode(), cR.getRightAscensionOfAscendingNode()), - MathUtils.normalizeAngle(cO.getAlphaV(), cR.getAlphaV()), - PositionAngleType.TRUE, + MathUtils.normalizeAngle(cO.getRightAscensionOfAscendingNode(), + cR.getRightAscensionOfAscendingNode()), + MathUtils.normalizeAngle(cO.getAlpha(positionAngleType), + cR.getAlpha(positionAngleType)), + positionAngleType, cO.getFrame(), cO.getDate(), cO.getMu()); @@ -584,7 +589,7 @@ public EquinoctialOrbit normalize(final Orbit orbit, final Orbit reference) { // convert input to proper type final EquinoctialOrbit eO = convertType(orbit); final EquinoctialOrbit eR = convertType(reference); - final PositionAngleType cachedPositionAngleType = eR.getCachedPositionAngleType(); + final PositionAngleType cachedPositionAngleType = eO.getCachedPositionAngleType(); // perform normalization if (eO.hasDerivatives()) { @@ -627,6 +632,7 @@ public > FieldEquinoctialOrbit normalize(fi // convert input to proper type final FieldEquinoctialOrbit eO = convertType(orbit); final FieldEquinoctialOrbit eR = convertType(reference); + final PositionAngleType positionAngleType = eO.getCachedPositionAngleType(); // perform normalization if (eO.hasDerivatives()) { @@ -635,14 +641,15 @@ public > FieldEquinoctialOrbit normalize(fi eO.getEquinoctialEy(), eO.getHx(), eO.getHy(), - MathUtils.normalizeAngle(eO.getLv(), eR.getLv()), + MathUtils.normalizeAngle(eO.getL(positionAngleType), + eR.getL(positionAngleType)), eO.getADot(), eO.getEquinoctialExDot(), eO.getEquinoctialEyDot(), eO.getHxDot(), eO.getHyDot(), - eO.getLvDot(), - PositionAngleType.TRUE, + eO.getLDot(positionAngleType), + positionAngleType, eO.getFrame(), eO.getDate(), eO.getMu()); @@ -652,8 +659,9 @@ public > FieldEquinoctialOrbit normalize(fi eO.getEquinoctialEy(), eO.getHx(), eO.getHy(), - MathUtils.normalizeAngle(eO.getLv(), eR.getLv()), - PositionAngleType.TRUE, + MathUtils.normalizeAngle(eO.getL(positionAngleType), + eR.getL(positionAngleType)), + positionAngleType, eO.getFrame(), eO.getDate(), eO.getMu()); @@ -819,7 +827,7 @@ public KeplerianOrbit normalize(final Orbit orbit, final Orbit reference) { // convert input to proper type final KeplerianOrbit kO = convertType(orbit); final KeplerianOrbit kR = convertType(reference); - final PositionAngleType cachedPositionAngleType = kR.getCachedPositionAngleType(); + final PositionAngleType cachedPositionAngleType = kO.getCachedPositionAngleType(); // perform normalization if (kO.hasDerivatives()) { diff --git a/src/test/java/org/orekit/orbits/FieldCircularOrbitTest.java b/src/test/java/org/orekit/orbits/FieldCircularOrbitTest.java index c284134c3f..ffdd891372 100644 --- a/src/test/java/org/orekit/orbits/FieldCircularOrbitTest.java +++ b/src/test/java/org/orekit/orbits/FieldCircularOrbitTest.java @@ -29,10 +29,7 @@ import org.hipparchus.geometry.euclidean.threed.Vector3D; import org.hipparchus.linear.FieldMatrixPreservingVisitor; import org.hipparchus.linear.MatrixUtils; -import org.hipparchus.util.Binary64Field; -import org.hipparchus.util.FastMath; -import org.hipparchus.util.MathArrays; -import org.hipparchus.util.MathUtils; +import org.hipparchus.util.*; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -55,7 +52,7 @@ import static org.orekit.OrekitMatchers.relativelyCloseTo; -public class FieldCircularOrbitTest { +class FieldCircularOrbitTest { // Body mu private double mu; @@ -71,144 +68,144 @@ public void setUp() { } @Test - public void testCircularToEquinoc() { + void testCircularToEquinoc() { doTestCircularToEquinoctialEll(Binary64Field.getInstance()); } @Test - public void testCircToEquinoc() { + void testCircToEquinoc() { doTestCircularToEquinoctialCirc(Binary64Field.getInstance()); } @Test - public void testAnomalyCirc() { + void testAnomalyCirc() { doTestAnomalyCirc(Binary64Field.getInstance()); } @Test - public void testAnomalyEll() { + void testAnomalyEll() { doTestAnomalyEll(Binary64Field.getInstance()); } @Test - public void testCircToCart() { + void testCircToCart() { doTestCircularToCartesian(Binary64Field.getInstance()); } @Test - public void testCircToKepl() { + void testCircToKepl() { doTestCircularToKeplerian(Binary64Field.getInstance()); } @Test - public void testGeometryCirc() { + void testGeometryCirc() { doTestGeometryCirc(Binary64Field.getInstance()); } @Test - public void testGeometryEll() { + void testGeometryEll() { doTestGeometryEll(Binary64Field.getInstance()); } @Test - public void testJacobianFinited() { + void testJacobianFinited() { doTestJacobianFinitedifferences(Binary64Field.getInstance()); } @Test - public void testJacoabianReference() { + void testJacoabianReference() { doTestJacobianReference(Binary64Field.getInstance()); } @Test - public void testNumericalIssue25() { + void testNumericalIssue25() { doTestNumericalIssue25(Binary64Field.getInstance()); } @Test - public void testPerfectlyEquatorial() { + void testPerfectlyEquatorial() { doTestPerfectlyEquatorial(Binary64Field.getInstance()); } @Test - public void testPositionVelocityNormsCirc() { + void testPositionVelocityNormsCirc() { doTestPositionVelocityNormsCirc(Binary64Field.getInstance()); } @Test - public void testPositionVelocity() { + void testPositionVelocity() { doTestPositionVelocityNormsEll(Binary64Field.getInstance()); } @Test - public void testSymmetryCir() { + void testSymmetryCir() { doTestSymmetryCir(Binary64Field.getInstance()); } @Test - public void testSymmetryEll() { + void testSymmetryEll() { doTestSymmetryEll(Binary64Field.getInstance()); } @Test - public void testErrors() { + void testErrors() { Assertions.assertThrows(IllegalArgumentException.class, () -> { doTestNonInertialFrame(Binary64Field.getInstance()); }); } @Test - public void testHyperbolic1() { + void testHyperbolic1() { doTestHyperbolic1(Binary64Field.getInstance()); } @Test - public void testHyperbolic2() { + void testHyperbolic2() { doTestHyperbolic2(Binary64Field.getInstance()); } @Test - public void testToOrbitWithoutDerivatives() { + void testToOrbitWithoutDerivatives() { doTestToOrbitWithoutDerivatives(Binary64Field.getInstance()); } @Test - public void testToOrbitWithDerivatives() { + void testToOrbitWithDerivatives() { doTestToOrbitWithDerivatives(Binary64Field.getInstance()); } @Test - public void testDerivativesConversionSymmetry() { + void testDerivativesConversionSymmetry() { doTestDerivativesConversionSymmetry(Binary64Field.getInstance()); } @Test - public void testToString() { + void testToString() { doTestToString(Binary64Field.getInstance()); } @Test - public void testNonKeplerianDerivatives() { + void testNonKeplerianDerivatives() { doTestNonKeplerianDerivatives(Binary64Field.getInstance()); } @Test - public void testPositionAngleDerivatives() { + void testPositionAngleDerivatives() { doTestPositionAngleDerivatives(Binary64Field.getInstance()); } @Test - public void testEquatorialRetrograde() { + void testEquatorialRetrograde() { doTestEquatorialRetrograde(Binary64Field.getInstance()); } @Test - public void testCopyNonKeplerianAcceleration() { + void testCopyNonKeplerianAcceleration() { doTestCopyNonKeplerianAcceleration(Binary64Field.getInstance()); } @Test - public void testNormalize() { + void testNormalize() { doTestNormalize(Binary64Field.getInstance()); } @@ -301,6 +298,124 @@ private > void compareFieldOrbitToOrbit(final } } + @Test + void testCoverageCachedPositionAngleTypeWithRates() { + // GIVEN + final double semiMajorAxis = 1e4; + final double eccentricity = 0.; + final double expectedAlpha = 0.; + final double expectedAlphaDot = 0.; + final AbsoluteDate date = AbsoluteDate.ARBITRARY_EPOCH; + final Binary64Field field = Binary64Field.getInstance(); + final Binary64 zero = field.getZero(); + // WHEN & THEN + for (final PositionAngleType inputPositionAngleType: PositionAngleType.values()) { + for (final PositionAngleType cachedPositionAngleType: PositionAngleType.values()) { + final FieldCircularOrbit fieldOrbit = new FieldCircularOrbit<>( + zero.newInstance(semiMajorAxis), zero.newInstance(eccentricity), zero, zero, zero, + zero.newInstance(expectedAlpha), zero, zero, zero, zero, zero, + zero.newInstance(expectedAlphaDot), inputPositionAngleType, cachedPositionAngleType, + FramesFactory.getGCRF(), new FieldAbsoluteDate<>(field, date), zero.newInstance(mu)); + Assertions.assertEquals(cachedPositionAngleType, fieldOrbit.getCachedPositionAngleType()); + Assertions.assertEquals(expectedAlpha, fieldOrbit.getAlphaV().getReal()); + Assertions.assertEquals(expectedAlpha, fieldOrbit.getAlphaM().getReal()); + Assertions.assertEquals(expectedAlpha, fieldOrbit.getAlphaE().getReal()); + Assertions.assertEquals(expectedAlphaDot, fieldOrbit.getAlphaVDot().getReal()); + Assertions.assertEquals(expectedAlphaDot, fieldOrbit.getAlphaMDot().getReal()); + Assertions.assertEquals(expectedAlphaDot, fieldOrbit.getAlphaEDot().getReal()); + } + } + } + + @Test + void testGetAlphaVersusDouble() { + // GIVEN + final double semiMajorAxis = 1e7; + final double eccentricity = 1e-2; + final double expectedAlpha = 4.; + final AbsoluteDate date = AbsoluteDate.ARBITRARY_EPOCH; + final Binary64Field field = Binary64Field.getInstance(); + final Binary64 zero = field.getZero(); + // WHEN & THEN + for (final PositionAngleType inputPositionAngleType: PositionAngleType.values()) { + for (final PositionAngleType cachedPositionAngleType: PositionAngleType.values()) { + final FieldCircularOrbit fieldOrbit = new FieldCircularOrbit<>( + zero.newInstance(semiMajorAxis), zero.newInstance(eccentricity), zero, zero, zero, + zero.newInstance(expectedAlpha), inputPositionAngleType, cachedPositionAngleType, + FramesFactory.getGCRF(), new FieldAbsoluteDate<>(field, date), zero.newInstance(mu)); + final CircularOrbit circularOrbit = fieldOrbit.toOrbit(); + Assertions.assertEquals(circularOrbit.getAlphaV(), fieldOrbit.getAlphaV().getReal()); + Assertions.assertEquals(circularOrbit.getAlphaM(), fieldOrbit.getAlphaM().getReal()); + Assertions.assertEquals(circularOrbit.getAlphaE(), fieldOrbit.getAlphaE().getReal()); + } + } + } + + + @Test + @Deprecated + void testTrueToEccentric() { + // GIVEN + final ComplexField field = ComplexField.getInstance(); + final Complex zero = field.getZero(); + final Complex ex = zero.newInstance(1e-2); + final Complex ey = zero.newInstance(1.e-3); + final Complex inputAnomaly = zero.newInstance(1.); + // WHEN + final Complex actualL = FieldCircularOrbit.trueToEccentric(inputAnomaly, ex, ey); + // THEN + final Complex expectedL = FieldCircularLatitudeArgumentUtility.trueToEccentric(ex, ey, inputAnomaly); + Assertions.assertEquals(expectedL.getReal(), actualL.getReal()); + } + + @Test + @Deprecated + void testEccentricToTrue() { + // GIVEN + final ComplexField field = ComplexField.getInstance(); + final Complex zero = field.getZero(); + final Complex ex = zero.newInstance(1e-2); + final Complex ey = zero.newInstance(1.e-3); + final Complex inputAnomaly = zero.newInstance(1.); + // WHEN + final Complex actualL = FieldCircularOrbit.eccentricToTrue(inputAnomaly, ex, ey); + // THEN + final Complex expectedL = FieldCircularLatitudeArgumentUtility.eccentricToTrue(ex, ey, inputAnomaly); + Assertions.assertEquals(expectedL.getReal(), actualL.getReal()); + } + + @Test + @Deprecated + void testMeanToEccentric() { + // GIVEN + final ComplexField field = ComplexField.getInstance(); + final Complex zero = field.getZero(); + final Complex ex = zero.newInstance(1e-2); + final Complex ey = zero.newInstance(1.e-3); + final Complex inputAnomaly = zero.newInstance(1.); + // WHEN + final Complex actualL = FieldCircularOrbit.meanToEccentric(inputAnomaly, ex, ey); + // THEN + final Complex expectedL = FieldCircularLatitudeArgumentUtility.meanToEccentric(ex, ey, inputAnomaly); + Assertions.assertEquals(expectedL.getReal(), actualL.getReal()); + } + + @Test + @Deprecated + void testEccentricToMean() { + // GIVEN + final ComplexField field = ComplexField.getInstance(); + final Complex zero = field.getZero(); + final Complex ex = zero.newInstance(1e-2); + final Complex ey = zero.newInstance(1.e-3); + final Complex inputAnomaly = zero.newInstance(1.); + // WHEN + final Complex actualL = FieldCircularOrbit.eccentricToMean(inputAnomaly, ex, ey); + // THEN + final Complex expectedL = FieldCircularLatitudeArgumentUtility.eccentricToMean(ex, ey, inputAnomaly); + Assertions.assertEquals(expectedL.getReal(), actualL.getReal()); + } + private > void doTestCircularToEquinoctialEll(Field field) { T zero = field.getZero(); From e8dc8f18de2ed155d97b87c3d9aa17e03806b25c Mon Sep 17 00:00:00 2001 From: Serrof Date: Sat, 17 Feb 2024 00:33:39 +0100 Subject: [PATCH 136/359] Implemented choice of cache for FieldKeplerianOrbit --- src/changes/changes.xml | 77 +-- .../radiation/KnockeRediffusedForceModel.java | 12 +- .../orekit/orbits/FieldKeplerianOrbit.java | 544 ++++++++++++++---- .../org/orekit/orbits/KeplerianOrbit.java | 30 +- .../java/org/orekit/orbits/OrbitType.java | 27 +- .../analytical/BrouwerLyddanePropagator.java | 2 +- .../FieldBrouwerLyddanePropagator.java | 2 +- .../KnockeRediffusedForceModelTest.java | 20 +- .../FieldNiellMappingFunctionModelTest.java | 4 +- .../orbits/FieldKeplerianOrbitTest.java | 176 ++++-- .../org/orekit/orbits/OrbitBlenderTest.java | 2 +- .../StateCovarianceBlenderTest.java | 2 +- 12 files changed, 630 insertions(+), 268 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 2ab98bba98..cfb216eff3 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -21,6 +21,9 @@ + + Added cache for position angle in FieldOrbit when applicable. + Allow direction-dependent phase centers in inter-satellites measurements. @@ -64,79 +67,7 @@ Reduce code duplication in (Field)Propagator inheritors. - Fix regression in Ephemeris with interpolationPoints=1. - - - Take azimuthal asymmetry into account in Vienna tropospheric models. - - - Added GlobalPressureTemperature3 model. - - - Added GlobalPressureTemperature2w (i.e. wet) model. - - - Allow to use any GPT grid file (GPT2, GPT2w, GPT3) in GlobalPressureTemperature2 model. - - - Added providers for horizontal gradient. - - - Added Askne-Nordius tropospheric model. - - - Replaced Vienna{One|Three}Model by Vienna{One|Three}. - - - Added ConstantTroposphericModel. - - - Added ChaoMappingFunction for tropospheric mapping function. - - - Added ModifiedHopfieldModel for tropospheric delay. - - - Added CanonicalSaastamoinenModel for tropospheric delay. - - - Replaced SaastamoinenModel by ModifiedSaastamoinenModel for tropospheric delay. - - - Added NBS/NRC steam table model for water vapor pressure. - - - Added Wang1988 model for water vapor pressure. - - - Added CIPM2007 model for water vapor pressure. - - - Added WaterVaporPressureProvider interface. - - - Added HeightDependentPressureTemperatureHumidityConverter for converting weather parameters. - - - Replaced WeatherModel by {Field}PressureTemperatureHumidityProvider. - - - Added {Field}PressureTemperature and {Field}PressureTemperatureHumidity containers. - - - Replaced GlobalPressureTemperature2Model by GlobalPressureTemperature2. - - - Replaced GlobalPressureTemperatureModel by GlobalPressureTemperature. - - - Replaced MappingFunction by TroposphereMappingFunction. - - - Replaced EstimatedTroposphericModel by EstimatedModel. - - - Replaced DiscreteTroposphericModel by TroposphericModel. + Fix regression in Ephemeris with interpolationPoints=1. Added support for Intelsat's 11 elements propagation. diff --git a/src/main/java/org/orekit/forces/radiation/KnockeRediffusedForceModel.java b/src/main/java/org/orekit/forces/radiation/KnockeRediffusedForceModel.java index f02b94e279..ed96eadaa9 100644 --- a/src/main/java/org/orekit/forces/radiation/KnockeRediffusedForceModel.java +++ b/src/main/java/org/orekit/forces/radiation/KnockeRediffusedForceModel.java @@ -34,9 +34,9 @@ import org.orekit.bodies.OneAxisEllipsoid; import org.orekit.data.DataContext; import org.orekit.forces.ForceModel; -import org.orekit.frames.FieldTransform; +import org.orekit.frames.FieldStaticTransform; import org.orekit.frames.Frame; -import org.orekit.frames.Transform; +import org.orekit.frames.StaticTransform; import org.orekit.propagation.FieldSpacecraftState; import org.orekit.propagation.SpacecraftState; import org.orekit.time.AbsoluteDate; @@ -198,7 +198,7 @@ public Vector3D acceleration(final SpacecraftState s, eastAxisOffset = eastAxisOffset + angularResolution) { // Build rotation transformations to get first crown elementary sector center - final Transform eastRotation = new Transform(date, + final StaticTransform eastRotation = StaticTransform.of(date, new Rotation(east, eastAxisOffset, RotationConvention.VECTOR_OPERATOR)); // Get first elementary crown sector center @@ -210,7 +210,7 @@ public Vector3D acceleration(final SpacecraftState s, radialAxisOffset = radialAxisOffset + angularResolution) { // Build rotation transformations to get elementary area center - final Transform radialRotation = new Transform(date, + final StaticTransform radialRotation = StaticTransform.of(date, new Rotation(projectedToGround, radialAxisOffset, RotationConvention.VECTOR_OPERATOR)); // Get current elementary crown sector center @@ -269,7 +269,7 @@ public > FieldVector3D acceleration(final F eastAxisOffset = eastAxisOffset + angularResolution) { // Build rotation transformations to get first crown elementary sector center - final FieldTransform eastRotation = new FieldTransform<>(date, + final FieldStaticTransform eastRotation = FieldStaticTransform.of(date, new FieldRotation<>(east, zero.add(eastAxisOffset), RotationConvention.VECTOR_OPERATOR)); @@ -283,7 +283,7 @@ public > FieldVector3D acceleration(final F radialAxisOffset = radialAxisOffset + angularResolution) { // Build rotation transformations to get elementary area center - final FieldTransform radialRotation = new FieldTransform<>(date, + final FieldStaticTransform radialRotation = FieldStaticTransform.of(date, new FieldRotation<>(projectedToGround, zero.add(radialAxisOffset), RotationConvention.VECTOR_OPERATOR)); diff --git a/src/main/java/org/orekit/orbits/FieldKeplerianOrbit.java b/src/main/java/org/orekit/orbits/FieldKeplerianOrbit.java index ad77ff4b21..011ef93c14 100644 --- a/src/main/java/org/orekit/orbits/FieldKeplerianOrbit.java +++ b/src/main/java/org/orekit/orbits/FieldKeplerianOrbit.java @@ -98,8 +98,8 @@ public class FieldKeplerianOrbit> extends Fiel /** Right Ascension of Ascending Node (rad). */ private final T raan; - /** True anomaly (rad). */ - private final T v; + /** Cached anomaly (rad). */ + private final T cachedAnomaly; /** Semi-major axis derivative (m/s). */ private final T aDot; @@ -116,8 +116,11 @@ public class FieldKeplerianOrbit> extends Fiel /** Right Ascension of Ascending Node derivative (rad/s). */ private final T raanDot; - /** True anomaly derivative (rad/s). */ - private final T vDot; + /** Derivative of cached anomaly (rad/s). */ + private final T cachedAnomalyDot; + + /** Cached type of position angle. */ + private final PositionAngleType cachedPositionAngleType; /** Partial Cartesian coordinates (position and velocity are valid, acceleration may be missing). */ private FieldPVCoordinates partialPV; @@ -133,6 +136,7 @@ public class FieldKeplerianOrbit> extends Fiel * @param raan right ascension of ascending node (Ω, rad) * @param anomaly mean, eccentric or true anomaly (rad) * @param type type of anomaly + * @param cachedPositionAngleType type of cached anomaly * @param frame the frame in which the parameters are defined * (must be a {@link Frame#isPseudoInertial pseudo-inertial frame}) * @param date date of the orbital parameters @@ -140,15 +144,42 @@ public class FieldKeplerianOrbit> extends Fiel * @exception IllegalArgumentException if frame is not a {@link * Frame#isPseudoInertial pseudo-inertial frame} or a and e don't match for hyperbolic orbits, * or v is out of range for hyperbolic orbits + * @since 12.1 */ public FieldKeplerianOrbit(final T a, final T e, final T i, final T pa, final T raan, final T anomaly, final PositionAngleType type, + final PositionAngleType cachedPositionAngleType, final Frame frame, final FieldAbsoluteDate date, final T mu) throws IllegalArgumentException { this(a, e, i, pa, raan, anomaly, null, null, null, null, null, null, - type, frame, date, mu); + type, cachedPositionAngleType, frame, date, mu); + } + + /** Creates a new instance. + * @param a semi-major axis (m), negative for hyperbolic orbits + * @param e eccentricity (positive or equal to 0) + * @param i inclination (rad) + * @param pa perigee argument (ω, rad) + * @param raan right ascension of ascending node (Ω, rad) + * @param anomaly mean, eccentric or true anomaly (rad) + * @param type type of anomaly + * @param frame the frame in which the parameters are defined + * (must be a {@link Frame#isPseudoInertial pseudo-inertial frame}) + * @param date date of the orbital parameters + * @param mu central attraction coefficient (m³/s²) + * @exception IllegalArgumentException if frame is not a {@link + * Frame#isPseudoInertial pseudo-inertial frame} or a and e don't match for hyperbolic orbits, + * or v is out of range for hyperbolic orbits + * @since 12.1 + */ + public FieldKeplerianOrbit(final T a, final T e, final T i, + final T pa, final T raan, + final T anomaly, final PositionAngleType type, + final Frame frame, final FieldAbsoluteDate date, final T mu) + throws IllegalArgumentException { + this(a, e, i, pa, raan, anomaly, type, type, frame, date, mu); } /** Creates a new instance. @@ -165,6 +196,7 @@ public FieldKeplerianOrbit(final T a, final T e, final T i, * @param raanDot right ascension of ascending node derivative, null if unknown (rad/s) * @param anomalyDot mean, eccentric or true anomaly derivative, null if unknown (rad/s) * @param type type of anomaly + * @param cachedPositionAngleType type of cached anomaly * @param frame the frame in which the parameters are defined * (must be a {@link Frame#isPseudoInertial pseudo-inertial frame}) * @param date date of the orbital parameters @@ -172,15 +204,18 @@ public FieldKeplerianOrbit(final T a, final T e, final T i, * @exception IllegalArgumentException if frame is not a {@link * Frame#isPseudoInertial pseudo-inertial frame} or a and e don't match for hyperbolic orbits, * or v is out of range for hyperbolic orbits + * @since 12.1 */ public FieldKeplerianOrbit(final T a, final T e, final T i, final T pa, final T raan, final T anomaly, final T aDot, final T eDot, final T iDot, final T paDot, final T raanDot, final T anomalyDot, - final PositionAngleType type, + final PositionAngleType type, final PositionAngleType cachedPositionAngleType, final Frame frame, final FieldAbsoluteDate date, final T mu) throws IllegalArgumentException { super(frame, date, mu); + this.cachedPositionAngleType = cachedPositionAngleType; + if (a.multiply(e.negate().add(1)).getReal() < 0) { throw new OrekitIllegalArgumentException(OrekitMessages.ORBIT_A_E_MISMATCH_WITH_CONIC_TYPE, a.getReal(), e.getReal()); } @@ -202,63 +237,61 @@ public FieldKeplerianOrbit(final T a, final T e, final T i, this.PLUS_K = FieldVector3D.getPlusK(a.getField()); // third canonical vector if (hasDerivatives()) { - final FieldUnivariateDerivative1 eUD = new FieldUnivariateDerivative1<>(e, eDot); - final FieldUnivariateDerivative1 anomalyUD = new FieldUnivariateDerivative1<>(anomaly, anomalyDot); - final FieldUnivariateDerivative1 vUD; - switch (type) { - case MEAN : - vUD = (a.getReal() < 0) ? - FieldKeplerianAnomalyUtility.hyperbolicMeanToTrue(eUD, anomalyUD) : - FieldKeplerianAnomalyUtility.ellipticMeanToTrue(eUD, anomalyUD); - break; - case ECCENTRIC : - vUD = (a.getReal() < 0) ? - FieldKeplerianAnomalyUtility.hyperbolicEccentricToTrue(eUD, anomalyUD) : - FieldKeplerianAnomalyUtility.ellipticEccentricToTrue(eUD, anomalyUD); - break; - case TRUE : - vUD = anomalyUD; - break; - default : // this should never happen - throw new OrekitInternalError(null); - } - this.v = vUD.getValue(); - this.vDot = vUD.getDerivative(1); + final FieldUnivariateDerivative1 cachedAnomalyUD = initializeCachedAnomaly(anomaly, anomalyDot, type); + this.cachedAnomaly = cachedAnomalyUD.getValue(); + this.cachedAnomalyDot = cachedAnomalyUD.getFirstDerivative(); } else { - switch (type) { - case MEAN : - - this.v = (a.getReal() < 0) ? - FieldKeplerianAnomalyUtility.hyperbolicMeanToTrue(e, anomaly) : - FieldKeplerianAnomalyUtility.ellipticMeanToTrue(e, anomaly); - - break; - case ECCENTRIC : - this.v = (a.getReal() < 0) ? - FieldKeplerianAnomalyUtility.hyperbolicEccentricToTrue(e, anomaly) : - FieldKeplerianAnomalyUtility.ellipticEccentricToTrue(e, anomaly); - - break; - case TRUE : - this.v = anomaly; - break; - default : // this should never happen - throw new OrekitInternalError(null); - } - this.vDot = null; + this.cachedAnomaly = initializeCachedAnomaly(anomaly, type); + this.cachedAnomalyDot = null; } // check true anomaly range - if (e.multiply(v.cos()).add(1).getReal() <= 0) { - final double vMax = e.reciprocal().negate().acos().getReal(); - throw new OrekitIllegalArgumentException(OrekitMessages.ORBIT_ANOMALY_OUT_OF_HYPERBOLIC_RANGE, - v.getReal(), e.getReal(), -vMax, vMax); + if (!isElliptical()) { + final T trueAnomaly = getTrueAnomaly(); + if (e.multiply(trueAnomaly.cos()).add(1).getReal() <= 0) { + final double vMax = e.reciprocal().negate().acos().getReal(); + throw new OrekitIllegalArgumentException(OrekitMessages.ORBIT_ANOMALY_OUT_OF_HYPERBOLIC_RANGE, + trueAnomaly.getReal(), e.getReal(), -vMax, vMax); + } } this.partialPV = null; } + /** Creates a new instance. + * @param a semi-major axis (m), negative for hyperbolic orbits + * @param e eccentricity (positive or equal to 0) + * @param i inclination (rad) + * @param pa perigee argument (ω, rad) + * @param raan right ascension of ascending node (Ω, rad) + * @param anomaly mean, eccentric or true anomaly (rad) + * @param aDot semi-major axis derivative, null if unknown (m/s) + * @param eDot eccentricity derivative, null if unknown + * @param iDot inclination derivative, null if unknown (rad/s) + * @param paDot perigee argument derivative, null if unknown (rad/s) + * @param raanDot right ascension of ascending node derivative, null if unknown (rad/s) + * @param anomalyDot mean, eccentric or true anomaly derivative, null if unknown (rad/s) + * @param type type of anomaly + * @param frame the frame in which the parameters are defined + * (must be a {@link Frame#isPseudoInertial pseudo-inertial frame}) + * @param date date of the orbital parameters + * @param mu central attraction coefficient (m³/s²) + * @exception IllegalArgumentException if frame is not a {@link + * Frame#isPseudoInertial pseudo-inertial frame} or a and e don't match for hyperbolic orbits, + * or v is out of range for hyperbolic orbits + */ + public FieldKeplerianOrbit(final T a, final T e, final T i, + final T pa, final T raan, final T anomaly, + final T aDot, final T eDot, final T iDot, + final T paDot, final T raanDot, final T anomalyDot, + final PositionAngleType type, + final Frame frame, final FieldAbsoluteDate date, final T mu) + throws IllegalArgumentException { + this(a, e, i, pa, raan, anomaly, aDot, eDot, iDot, paDot, raanDot, anomalyDot, + type, type, frame, date, mu); + } + /** Constructor from Cartesian parameters. * *

                The acceleration provided in {@code FieldPVCoordinates} is accessible using @@ -331,13 +364,15 @@ private FieldKeplerianOrbit(final TimeStampedFieldPVCoordinates pvCoordinates final T eSE = FieldVector3D.dotProduct(pvP, pvV).divide(muA.sqrt()); final T eCE = rV2OnMu.subtract(1); e = (eSE.multiply(eSE).add(eCE.multiply(eCE))).sqrt(); - v = FieldKeplerianAnomalyUtility.ellipticEccentricToTrue(e, eSE.atan2(eCE)); + this.cachedPositionAngleType = PositionAngleType.ECCENTRIC; + cachedAnomaly = eSE.atan2(eCE); } else { // hyperbolic orbit final T eSH = FieldVector3D.dotProduct(pvP, pvV).divide(muA.negate().sqrt()); final T eCH = rV2OnMu.subtract(1); e = (m2.negate().divide(muA).add(1)).sqrt(); - v = FieldKeplerianAnomalyUtility.hyperbolicEccentricToTrue(e, (eCH.add(eSH)).divide(eCH.subtract(eSH)).log().divide(2)); + this.cachedPositionAngleType = PositionAngleType.TRUE; + cachedAnomaly = FieldKeplerianAnomalyUtility.hyperbolicEccentricToTrue(e, (eCH.add(eSH)).divide(eCH.subtract(eSH)).log().divide(2)); } // Checking eccentricity range @@ -347,7 +382,7 @@ private FieldKeplerianOrbit(final TimeStampedFieldPVCoordinates pvCoordinates final FieldVector3D node = new FieldVector3D<>(raan, getZero()); final T px = FieldVector3D.dotProduct(pvP, node); final T py = FieldVector3D.dotProduct(pvP, FieldVector3D.crossProduct(momentum, node)).divide(m2.sqrt()); - pa = py.atan2(px).subtract(v); + pa = py.atan2(px).subtract(getTrueAnomaly()); partialPV = pvCoordinates; @@ -374,10 +409,17 @@ private FieldKeplerianOrbit(final TimeStampedFieldPVCoordinates pvCoordinates add(jacobian[5][3].multiply(aX)).add(jacobian[5][4].multiply(aY)).add(jacobian[5][5].multiply(aZ)); final FieldUnivariateDerivative1 eUD = new FieldUnivariateDerivative1<>(e, eDot); final FieldUnivariateDerivative1 MUD = new FieldUnivariateDerivative1<>(getMeanAnomaly(), MDot); - final FieldUnivariateDerivative1 vUD = (a.getReal() < 0) ? - FieldKeplerianAnomalyUtility.hyperbolicMeanToTrue(eUD, MUD) : - FieldKeplerianAnomalyUtility.ellipticMeanToTrue(eUD, MUD); - vDot = vUD.getDerivative(1); + if (cachedPositionAngleType == PositionAngleType.ECCENTRIC) { + final FieldUnivariateDerivative1 EUD = (a.getReal() < 0) ? + FieldKeplerianAnomalyUtility.hyperbolicMeanToEccentric(eUD, MUD) : + FieldKeplerianAnomalyUtility.ellipticMeanToEccentric(eUD, MUD); + cachedAnomalyDot = EUD.getFirstDerivative(); + } else { // TRUE + final FieldUnivariateDerivative1 vUD = (a.getReal() < 0) ? + FieldKeplerianAnomalyUtility.hyperbolicMeanToTrue(eUD, MUD) : + FieldKeplerianAnomalyUtility.ellipticMeanToTrue(eUD, MUD); + cachedAnomalyDot = vUD.getFirstDerivative(); + } } else { // acceleration is either almost zero or NaN, @@ -388,7 +430,7 @@ private FieldKeplerianOrbit(final TimeStampedFieldPVCoordinates pvCoordinates iDot = null; paDot = null; raanDot = null; - vDot = null; + cachedAnomalyDot = null; } } @@ -430,14 +472,15 @@ public FieldKeplerianOrbit(final FieldOrbit op) { public FieldKeplerianOrbit(final Field field, final KeplerianOrbit op) { this(field.getZero().newInstance(op.getA()), field.getZero().newInstance(op.getE()), field.getZero().newInstance(op.getI()), field.getZero().newInstance(op.getPerigeeArgument()), field.getZero().newInstance(op.getRightAscensionOfAscendingNode()), - field.getZero().newInstance(op.getTrueAnomaly()), + field.getZero().newInstance(op.getAnomaly(op.getCachedPositionAngleType())), (op.hasDerivatives()) ? field.getZero().newInstance(op.getADot()) : null, (op.hasDerivatives()) ? field.getZero().newInstance(op.getEDot()) : null, (op.hasDerivatives()) ? field.getZero().newInstance(op.getIDot()) : null, (op.hasDerivatives()) ? field.getZero().newInstance(op.getPerigeeArgumentDot()) : null, (op.hasDerivatives()) ? field.getZero().newInstance(op.getRightAscensionOfAscendingNodeDot()) : null, - (op.hasDerivatives()) ? field.getZero().newInstance(op.getTrueAnomalyDot()) : null, PositionAngleType.TRUE, - op.getFrame(), new FieldAbsoluteDate<>(field, op.getDate()), field.getZero().newInstance(op.getMu())); + (op.hasDerivatives()) ? field.getZero().newInstance(op.getAnomalyDot(op.getCachedPositionAngleType())) : null, + op.getCachedPositionAngleType(), op.getFrame(), + new FieldAbsoluteDate<>(field, op.getDate()), field.getZero().newInstance(op.getMu())); } /** Constructor from Field and Orbit. @@ -451,36 +494,43 @@ public FieldKeplerianOrbit(final Field field, final Orbit op) { } /** {@inheritDoc} */ + @Override public OrbitType getType() { return OrbitType.KEPLERIAN; } /** {@inheritDoc} */ + @Override public T getA() { return a; } /** {@inheritDoc} */ + @Override public T getADot() { return aDot; } /** {@inheritDoc} */ + @Override public T getE() { return e; } /** {@inheritDoc} */ + @Override public T getEDot() { return eDot; } /** {@inheritDoc} */ + @Override public T getI() { return i; } /** {@inheritDoc} */ + @Override public T getIDot() { return iDot; } @@ -523,7 +573,17 @@ public T getRightAscensionOfAscendingNodeDot() { * @return true anomaly (rad) */ public T getTrueAnomaly() { - return v; + switch (cachedPositionAngleType) { + case MEAN: return (a.getReal() < 0) ? FieldKeplerianAnomalyUtility.hyperbolicMeanToTrue(e, cachedAnomaly) : + FieldKeplerianAnomalyUtility.ellipticMeanToTrue(e, cachedAnomaly); + + case TRUE: return cachedAnomaly; + + case ECCENTRIC: return (a.getReal() < 0) ? FieldKeplerianAnomalyUtility.hyperbolicEccentricToTrue(e, cachedAnomaly) : + FieldKeplerianAnomalyUtility.ellipticEccentricToTrue(e, cachedAnomaly); + + default: throw new OrekitInternalError(null); + } } /** Get the true anomaly derivative. @@ -533,16 +593,54 @@ public T getTrueAnomaly() { * @return true anomaly derivative (rad/s) */ public T getTrueAnomalyDot() { - return vDot; + if (hasDerivatives()) { + switch (cachedPositionAngleType) { + case MEAN: + final FieldUnivariateDerivative1 eUD = new FieldUnivariateDerivative1<>(e, eDot); + final FieldUnivariateDerivative1 MUD = new FieldUnivariateDerivative1<>(cachedAnomaly, cachedAnomalyDot); + final FieldUnivariateDerivative1 vUD = (a.getReal() < 0) ? + FieldKeplerianAnomalyUtility.hyperbolicMeanToTrue(eUD, MUD) : + FieldKeplerianAnomalyUtility.ellipticMeanToTrue(eUD, MUD); + return vUD.getFirstDerivative(); + + case TRUE: + return cachedAnomalyDot; + + case ECCENTRIC: + final FieldUnivariateDerivative1 eUD2 = new FieldUnivariateDerivative1<>(e, eDot); + final FieldUnivariateDerivative1 EUD = new FieldUnivariateDerivative1<>(cachedAnomaly, cachedAnomalyDot); + final FieldUnivariateDerivative1 vUD2 = (a.getReal() < 0) ? + FieldKeplerianAnomalyUtility.hyperbolicEccentricToTrue(eUD2, EUD) : + FieldKeplerianAnomalyUtility.ellipticEccentricToTrue(eUD2, EUD); + return vUD2.getFirstDerivative(); + + default: + throw new OrekitInternalError(null); + } + } else { + return null; + } } /** Get the eccentric anomaly. * @return eccentric anomaly (rad) */ public T getEccentricAnomaly() { - return (a.getReal() < 0) ? - FieldKeplerianAnomalyUtility.hyperbolicTrueToEccentric(e, v) : - FieldKeplerianAnomalyUtility.ellipticTrueToEccentric(e, v); + switch (cachedPositionAngleType) { + case MEAN: + return (a.getReal() < 0) ? FieldKeplerianAnomalyUtility.hyperbolicMeanToEccentric(e, cachedAnomaly) : + FieldKeplerianAnomalyUtility.ellipticMeanToEccentric(e, cachedAnomaly); + + case ECCENTRIC: + return cachedAnomaly; + + case TRUE: + return (a.getReal() < 0) ? FieldKeplerianAnomalyUtility.hyperbolicTrueToEccentric(e, cachedAnomaly) : + FieldKeplerianAnomalyUtility.ellipticTrueToEccentric(e, cachedAnomaly); + + default: + throw new OrekitInternalError(null); + } } /** Get the eccentric anomaly derivative. @@ -552,27 +650,50 @@ public T getEccentricAnomaly() { * @return eccentric anomaly derivative (rad/s) */ public T getEccentricAnomalyDot() { - - if (!hasDerivatives()) { + if (hasDerivatives()) { + switch (cachedPositionAngleType) { + case ECCENTRIC: + return cachedAnomalyDot; + + case TRUE: + final FieldUnivariateDerivative1 eUD = new FieldUnivariateDerivative1<>(e, eDot); + final FieldUnivariateDerivative1 vUD = new FieldUnivariateDerivative1<>(cachedAnomaly, cachedAnomalyDot); + final FieldUnivariateDerivative1 EUD = (a.getReal() < 0) ? + FieldKeplerianAnomalyUtility.hyperbolicTrueToEccentric(eUD, vUD) : + FieldKeplerianAnomalyUtility.ellipticTrueToEccentric(eUD, vUD); + return EUD.getFirstDerivative(); + + case MEAN: + final FieldUnivariateDerivative1 eUD2 = new FieldUnivariateDerivative1<>(e, eDot); + final FieldUnivariateDerivative1 MUD = new FieldUnivariateDerivative1<>(cachedAnomaly, cachedAnomalyDot); + final FieldUnivariateDerivative1 EUD2 = (a.getReal() < 0) ? + FieldKeplerianAnomalyUtility.hyperbolicMeanToEccentric(eUD2, MUD) : + FieldKeplerianAnomalyUtility.ellipticMeanToEccentric(eUD2, MUD); + return EUD2.getFirstDerivative(); + + default: + throw new OrekitInternalError(null); + } + } else { return null; } - - final FieldUnivariateDerivative1 eUD = new FieldUnivariateDerivative1<>(e, eDot); - final FieldUnivariateDerivative1 vUD = new FieldUnivariateDerivative1<>(v, vDot); - final FieldUnivariateDerivative1 EUD = (a.getReal() < 0) ? - FieldKeplerianAnomalyUtility.hyperbolicTrueToEccentric(eUD, vUD) : - FieldKeplerianAnomalyUtility.ellipticTrueToEccentric(eUD, vUD); - return EUD.getDerivative(1); - } /** Get the mean anomaly. * @return mean anomaly (rad) */ public T getMeanAnomaly() { - return (a.getReal() < 0) ? - FieldKeplerianAnomalyUtility.hyperbolicTrueToMean(e, v) : - FieldKeplerianAnomalyUtility.ellipticTrueToMean(e, v); + switch (cachedPositionAngleType) { + case ECCENTRIC: return (a.getReal() < 0) ? FieldKeplerianAnomalyUtility.hyperbolicEccentricToMean(e, cachedAnomaly) : + FieldKeplerianAnomalyUtility.ellipticEccentricToMean(e, cachedAnomaly); + + case MEAN: return cachedAnomaly; + + case TRUE: return (a.getReal() < 0) ? FieldKeplerianAnomalyUtility.hyperbolicTrueToMean(e, cachedAnomaly) : + FieldKeplerianAnomalyUtility.ellipticTrueToMean(e, cachedAnomaly); + + default: throw new OrekitInternalError(null); + } } /** Get the mean anomaly derivative. @@ -582,18 +703,33 @@ public T getMeanAnomaly() { * @return mean anomaly derivative (rad/s) */ public T getMeanAnomalyDot() { - - if (!hasDerivatives()) { + if (hasDerivatives()) { + switch (cachedPositionAngleType) { + case MEAN: + return cachedAnomalyDot; + + case ECCENTRIC: + final FieldUnivariateDerivative1 eUD = new FieldUnivariateDerivative1<>(e, eDot); + final FieldUnivariateDerivative1 EUD = new FieldUnivariateDerivative1<>(cachedAnomaly, cachedAnomalyDot); + final FieldUnivariateDerivative1 MUD = (a.getReal() < 0) ? + FieldKeplerianAnomalyUtility.hyperbolicEccentricToMean(eUD, EUD) : + FieldKeplerianAnomalyUtility.ellipticEccentricToMean(eUD, EUD); + return MUD.getFirstDerivative(); + + case TRUE: + final FieldUnivariateDerivative1 eUD2 = new FieldUnivariateDerivative1<>(e, eDot); + final FieldUnivariateDerivative1 vUD = new FieldUnivariateDerivative1<>(cachedAnomaly, cachedAnomalyDot); + final FieldUnivariateDerivative1 MUD2 = (a.getReal() < 0) ? + FieldKeplerianAnomalyUtility.hyperbolicTrueToMean(eUD2, vUD) : + FieldKeplerianAnomalyUtility.ellipticTrueToMean(eUD2, vUD); + return MUD2.getFirstDerivative(); + + default: + throw new OrekitInternalError(null); + } + } else { return null; } - - final FieldUnivariateDerivative1 eUD = new FieldUnivariateDerivative1<>(e, eDot); - final FieldUnivariateDerivative1 vUD = new FieldUnivariateDerivative1<>(v, vDot); - final FieldUnivariateDerivative1 MUD = (a.getReal() < 0) ? - FieldKeplerianAnomalyUtility.hyperbolicTrueToMean(eUD, vUD) : - FieldKeplerianAnomalyUtility.ellipticTrueToMean(eUD, vUD); - return MUD.getDerivative(1); - } /** Get the anomaly. @@ -626,11 +762,13 @@ public boolean hasDerivatives() { } /** {@inheritDoc} */ + @Override public T getEquinoctialEx() { return e.multiply(pa.add(raan).cos()); } /** {@inheritDoc} */ + @Override public T getEquinoctialExDot() { if (!hasDerivatives()) { @@ -640,16 +778,18 @@ public T getEquinoctialExDot() { final FieldUnivariateDerivative1 eUD = new FieldUnivariateDerivative1<>(e, eDot); final FieldUnivariateDerivative1 paUD = new FieldUnivariateDerivative1<>(pa, paDot); final FieldUnivariateDerivative1 raanUD = new FieldUnivariateDerivative1<>(raan, raanDot); - return eUD.multiply(paUD.add(raanUD).cos()).getDerivative(1); + return eUD.multiply(paUD.add(raanUD).cos()).getFirstDerivative(); } /** {@inheritDoc} */ + @Override public T getEquinoctialEy() { - return e.multiply((pa.add(raan)).sin()); + return e.multiply((pa.add(raan)).sin()); } /** {@inheritDoc} */ + @Override public T getEquinoctialEyDot() { if (!hasDerivatives()) { @@ -659,20 +799,22 @@ public T getEquinoctialEyDot() { final FieldUnivariateDerivative1 eUD = new FieldUnivariateDerivative1<>(e, eDot); final FieldUnivariateDerivative1 paUD = new FieldUnivariateDerivative1<>(pa, paDot); final FieldUnivariateDerivative1 raanUD = new FieldUnivariateDerivative1<>(raan, raanDot); - return eUD.multiply(paUD.add(raanUD).sin()).getDerivative(1); + return eUD.multiply(paUD.add(raanUD).sin()).getFirstDerivative(); } /** {@inheritDoc} */ + @Override public T getHx() { // Check for equatorial retrograde orbit if (FastMath.abs(i.subtract(i.getPi()).getReal()) < 1.0e-10) { return getZero().add(Double.NaN); } - return raan.cos().multiply(i.divide(2).tan()); + return raan.cos().multiply(i.divide(2).tan()); } /** {@inheritDoc} */ + @Override public T getHxDot() { if (!hasDerivatives()) { @@ -686,20 +828,22 @@ public T getHxDot() { final FieldUnivariateDerivative1 iUD = new FieldUnivariateDerivative1<>(i, iDot); final FieldUnivariateDerivative1 raanUD = new FieldUnivariateDerivative1<>(raan, raanDot); - return raanUD.cos().multiply(iUD.multiply(0.5).tan()).getDerivative(1); + return raanUD.cos().multiply(iUD.multiply(0.5).tan()).getFirstDerivative(); } /** {@inheritDoc} */ + @Override public T getHy() { // Check for equatorial retrograde orbit if (FastMath.abs(i.subtract(i.getPi()).getReal()) < 1.0e-10) { return getZero().add(Double.NaN); } - return raan.sin().multiply(i.divide(2).tan()); + return raan.sin().multiply(i.divide(2).tan()); } /** {@inheritDoc} */ + @Override public T getHyDot() { if (!hasDerivatives()) { @@ -713,28 +857,32 @@ public T getHyDot() { final FieldUnivariateDerivative1 iUD = new FieldUnivariateDerivative1<>(i, iDot); final FieldUnivariateDerivative1 raanUD = new FieldUnivariateDerivative1<>(raan, raanDot); - return raanUD.sin().multiply(iUD.multiply(0.5).tan()).getDerivative(1); + return raanUD.sin().multiply(iUD.multiply(0.5).tan()).getFirstDerivative(); } /** {@inheritDoc} */ + @Override public T getLv() { - return pa.add(raan).add(v); + return pa.add(raan).add(getTrueAnomaly()); } /** {@inheritDoc} */ + @Override public T getLvDot() { return hasDerivatives() ? - paDot.add(raanDot).add(vDot) : + paDot.add(raanDot).add(getTrueAnomalyDot()) : null; } /** {@inheritDoc} */ + @Override public T getLE() { return pa.add(raan).add(getEccentricAnomaly()); } /** {@inheritDoc} */ + @Override public T getLEDot() { return hasDerivatives() ? paDot.add(raanDot).add(getEccentricAnomalyDot()) : @@ -742,17 +890,164 @@ public T getLEDot() { } /** {@inheritDoc} */ + @Override public T getLM() { return pa.add(raan).add(getMeanAnomaly()); } /** {@inheritDoc} */ + @Override public T getLMDot() { return hasDerivatives() ? paDot.add(raanDot).add(getMeanAnomalyDot()) : null; } + /** Initialize cached anomaly with rate. + * @param anomaly input anomaly + * @param anomalyDot rate of input anomaly + * @param inputType position angle type passed as input + * @return anomaly to cache with rate + * @since 12.1 + */ + private FieldUnivariateDerivative1 initializeCachedAnomaly(final T anomaly, final T anomalyDot, + final PositionAngleType inputType) { + if (cachedPositionAngleType == inputType) { + return new FieldUnivariateDerivative1<>(anomaly, anomalyDot); + + } else { + final FieldUnivariateDerivative1 eUD = new FieldUnivariateDerivative1<>(e, eDot); + final FieldUnivariateDerivative1 anomalyUD = new FieldUnivariateDerivative1<>(anomaly, anomalyDot); + + if (a.getReal() < 0) { + switch (cachedPositionAngleType) { + case MEAN: + if (inputType == PositionAngleType.ECCENTRIC) { + return FieldKeplerianAnomalyUtility.hyperbolicEccentricToMean(eUD, anomalyUD); + } else { + return FieldKeplerianAnomalyUtility.hyperbolicTrueToMean(eUD, anomalyUD); + } + + case ECCENTRIC: + if (inputType == PositionAngleType.MEAN) { + return FieldKeplerianAnomalyUtility.hyperbolicMeanToEccentric(eUD, anomalyUD); + } else { + return FieldKeplerianAnomalyUtility.hyperbolicTrueToEccentric(eUD, anomalyUD); + } + + case TRUE: + if (inputType == PositionAngleType.MEAN) { + return FieldKeplerianAnomalyUtility.hyperbolicMeanToTrue(eUD, anomalyUD); + } else { + return FieldKeplerianAnomalyUtility.hyperbolicEccentricToTrue(eUD, anomalyUD); + } + + default: + break; + } + + } else { + switch (cachedPositionAngleType) { + case MEAN: + if (inputType == PositionAngleType.ECCENTRIC) { + return FieldKeplerianAnomalyUtility.ellipticEccentricToMean(eUD, anomalyUD); + } else { + return FieldKeplerianAnomalyUtility.ellipticTrueToMean(eUD, anomalyUD); + } + + case ECCENTRIC: + if (inputType == PositionAngleType.MEAN) { + return FieldKeplerianAnomalyUtility.ellipticMeanToEccentric(eUD, anomalyUD); + } else { + return FieldKeplerianAnomalyUtility.ellipticTrueToEccentric(eUD, anomalyUD); + } + + case TRUE: + if (inputType == PositionAngleType.MEAN) { + return FieldKeplerianAnomalyUtility.ellipticMeanToTrue(eUD, anomalyUD); + } else { + return FieldKeplerianAnomalyUtility.ellipticEccentricToTrue(eUD, anomalyUD); + } + + default: + break; + } + + } + throw new OrekitInternalError(null); + } + + } + + /** Initialize cached anomaly. + * @param anomaly input anomaly + * @param inputType position angle type passed as input + * @return anomaly to cache + * @since 12.1 + */ + private T initializeCachedAnomaly(final T anomaly, final PositionAngleType inputType) { + if (inputType == cachedPositionAngleType) { + return anomaly; + + } else { + if (a.getReal() < 0) { + switch (cachedPositionAngleType) { + case MEAN: + if (inputType == PositionAngleType.ECCENTRIC) { + return FieldKeplerianAnomalyUtility.hyperbolicEccentricToMean(e, anomaly); + } else { + return FieldKeplerianAnomalyUtility.hyperbolicTrueToMean(e, anomaly); + } + + case ECCENTRIC: + if (inputType == PositionAngleType.MEAN) { + return FieldKeplerianAnomalyUtility.hyperbolicMeanToEccentric(e, anomaly); + } else { + return FieldKeplerianAnomalyUtility.hyperbolicTrueToEccentric(e, anomaly); + } + + case TRUE: + if (inputType == PositionAngleType.ECCENTRIC) { + return FieldKeplerianAnomalyUtility.hyperbolicEccentricToTrue(e, anomaly); + } else { + return FieldKeplerianAnomalyUtility.hyperbolicMeanToTrue(e, anomaly); + } + + default: + break; + } + + } else { + switch (cachedPositionAngleType) { + case MEAN: + if (inputType == PositionAngleType.ECCENTRIC) { + return FieldKeplerianAnomalyUtility.ellipticEccentricToMean(e, anomaly); + } else { + return FieldKeplerianAnomalyUtility.ellipticTrueToMean(e, anomaly); + } + + case ECCENTRIC: + if (inputType == PositionAngleType.MEAN) { + return FieldKeplerianAnomalyUtility.ellipticMeanToEccentric(e, anomaly); + } else { + return FieldKeplerianAnomalyUtility.ellipticTrueToEccentric(e, anomaly); + } + + case TRUE: + if (inputType == PositionAngleType.ECCENTRIC) { + return FieldKeplerianAnomalyUtility.ellipticEccentricToTrue(e, anomaly); + } else { + return FieldKeplerianAnomalyUtility.ellipticMeanToTrue(e, anomaly); + } + + default: + break; + } + } + throw new OrekitInternalError(null); + } + } + /** Compute reference axes. * @return referecne axes * @since 12.0 @@ -822,10 +1117,10 @@ private void computePVWithoutA() { // hyperbolic case // compute position and velocity factors - final FieldSinCos scV = FastMath.sinCos(v); + final FieldSinCos scV = FastMath.sinCos(getTrueAnomaly()); final T sinV = scV.sin(); final T cosV = scV.cos(); - final T f = a.multiply(e.multiply(e).negate().add(1)); + final T f = a.multiply(e.square().negate().add(1)); final T posFactor = f.divide(e.multiply(cosV).add(1)); final T velFactor = FastMath.sqrt(getMu().divide(f)); @@ -873,6 +1168,7 @@ private FieldVector3D nonKeplerianAcceleration() { } /** {@inheritDoc} */ + @Override protected FieldVector3D initPosition() { final FieldVector3D[] axes = referenceAxes(); @@ -894,10 +1190,10 @@ protected FieldVector3D initPosition() { // hyperbolic case // compute position and velocity factors - final FieldSinCos scV = FastMath.sinCos(v); + final FieldSinCos scV = FastMath.sinCos(getTrueAnomaly()); final T sinV = scV.sin(); final T cosV = scV.cos(); - final T f = a.multiply(e.multiply(e).negate().add(1)); + final T f = a.multiply(e.square().negate().add(1)); final T posFactor = f.divide(e.multiply(cosV).add(1)); return new FieldVector3D<>(posFactor.multiply(cosV), axes[0], posFactor.multiply(sinV), axes[1]); @@ -907,6 +1203,7 @@ protected FieldVector3D initPosition() { } /** {@inheritDoc} */ + @Override protected TimeStampedFieldPVCoordinates initPVCoordinates() { // position and velocity @@ -925,17 +1222,19 @@ protected TimeStampedFieldPVCoordinates initPVCoordinates() { } /** {@inheritDoc} */ + @Override public FieldKeplerianOrbit shiftedBy(final double dt) { return shiftedBy(getZero().newInstance(dt)); } /** {@inheritDoc} */ + @Override public FieldKeplerianOrbit shiftedBy(final T dt) { // use Keplerian-only motion final FieldKeplerianOrbit keplerianShifted = new FieldKeplerianOrbit<>(a, e, i, pa, raan, getKeplerianMeanMotion().multiply(dt).add(getMeanAnomaly()), - PositionAngleType.MEAN, getFrame(), getDate().shiftedBy(dt), getMu()); + PositionAngleType.MEAN, cachedPositionAngleType, getFrame(), getDate().shiftedBy(dt), getMu()); if (hasDerivatives()) { @@ -967,6 +1266,7 @@ public FieldKeplerianOrbit shiftedBy(final T dt) { } /** {@inheritDoc} */ + @Override protected T[][] computeJacobianMeanWrtCartesian() { if (isElliptical()) { return computeJacobianMeanWrtCartesianElliptical(); @@ -1014,7 +1314,7 @@ private T[][] computeJacobianMeanWrtCartesianElliptical() { final T twoA = a.multiply(2); final T rOnA = r.divide(a); - final T oMe2 = e.multiply(e).negate().add(1); + final T oMe2 = e.square().negate().add(1); final T epsilon = oMe2.sqrt(); final T sqrtRec = epsilon.reciprocal(); @@ -1208,7 +1508,7 @@ private T[][] computeJacobianMeanWrtCartesianHyperbolic() { final FieldVector3D dpoP = new FieldVector3D<>(cP6, dacP, cP7, this.PLUS_K); final FieldVector3D dpoV = new FieldVector3D<>(cP6, dacV); - final T re2 = r2.multiply(e).multiply(e); + final T re2 = r2.multiply(e.square()); final T recOre2 = p.subtract(r).divide(re2); final T resOre2 = pv.multiply(mOMu).divide(re2); final FieldVector3D dreP = new FieldVector3D<>(mOMu, velocity, pv.divide(mu), dCP); @@ -1219,7 +1519,7 @@ private T[][] computeJacobianMeanWrtCartesianHyperbolic() { fillHalfRow(getOne(), dpoV, getOne().negate(), davV, jacobian[3], 3); // dRAAN - final T cO0 = cI1.multiply(cI1); + final T cO0 = cI1.square(); final T cO1 = mx.multiply(cO0); final T cO2 = my.negate().multiply(cO0); fillHalfRow(cO1, dcYP, cO2, dcXP, jacobian[4], 0); @@ -1243,6 +1543,7 @@ private T[][] computeJacobianMeanWrtCartesianHyperbolic() { } /** {@inheritDoc} */ + @Override protected T[][] computeJacobianEccentricWrtCartesian() { if (isElliptical()) { return computeJacobianEccentricWrtCartesianElliptical(); @@ -1317,6 +1618,7 @@ private T[][] computeJacobianEccentricWrtCartesianHyperbolic() { } /** {@inheritDoc} */ + @Override protected T[][] computeJacobianTrueWrtCartesian() { if (isElliptical()) { return computeJacobianTrueWrtCartesianElliptical(); @@ -1342,7 +1644,7 @@ private T[][] computeJacobianTrueWrtCartesianElliptical() { // dE = [sqrt (1 - e^2) / (1 + e cos v)] dv - [sin E / (1 - e^2)] de // which is inverted and rewritten as: // dv = sqrt (1 - e^2) a/r dE + [sin E / sqrt (1 - e^2)] a/r de - final T e2 = e.multiply(e); + final T e2 = e.square(); final T oMe2 = e2.negate().add(1); final T epsilon = oMe2.sqrt(); final FieldSinCos scE = FastMath.sinCos(getEccentricAnomaly()); @@ -1378,7 +1680,7 @@ private T[][] computeJacobianTrueWrtCartesianHyperbolic() { // dH = [sqrt (e^2 - 1) / (1 + e cos v)] dv + [sinh H / (e^2 - 1)] de // which is inverted and rewritten as: // dv = sqrt (1 - e^2) a/r dH - [sinh H / sqrt (e^2 - 1)] a/r de - final T e2 = e.multiply(e); + final T e2 = e.square(); final T e2Mo = e2.subtract(1); final T epsilon = e2Mo.sqrt(); final T H = getEccentricAnomaly(); @@ -1386,7 +1688,7 @@ private T[][] computeJacobianTrueWrtCartesianHyperbolic() { final T sinhH = H.sinh(); final T aOr = e.multiply(coshH).subtract(1).reciprocal(); final T aFactor = epsilon.multiply(aOr); - final T eFactor = sinhH .multiply(aOr).divide(epsilon); + final T eFactor = sinhH.multiply(aOr).divide(epsilon); // update anomaly row final T[] eRow = jacobian[1]; @@ -1400,6 +1702,7 @@ private T[][] computeJacobianTrueWrtCartesianHyperbolic() { } /** {@inheritDoc} */ + @Override public void addKeplerContribution(final PositionAngleType type, final T gm, final T[] pDot) { final T oMe2; @@ -1412,12 +1715,12 @@ public void addKeplerContribution(final PositionAngleType type, final T gm, break; case ECCENTRIC : oMe2 = e.square().negate().add(1).abs(); - ksi = e.multiply(v.cos()).add(1); + ksi = e.multiply(getTrueAnomaly().cos()).add(1); pDot[5] = pDot[5].add( n.multiply(ksi).divide(oMe2)); break; case TRUE : oMe2 = e.square().negate().add(1).abs(); - ksi = e.multiply(v.cos()).add(1); + ksi = e.multiply(getTrueAnomaly().cos()).add(1); pDot[5] = pDot[5].add(n.multiply(ksi).multiply(ksi).divide(oMe2.multiply(oMe2.sqrt()))); break; default : @@ -1435,14 +1738,14 @@ public String toString() { append("; i: ").append(FastMath.toDegrees(i.getReal())). append("; pa: ").append(FastMath.toDegrees(pa.getReal())). append("; raan: ").append(FastMath.toDegrees(raan.getReal())). - append("; v: ").append(FastMath.toDegrees(v.getReal())). + append("; v: ").append(FastMath.toDegrees(getTrueAnomaly().getReal())). append(";}").toString(); } /** {@inheritDoc} */ @Override public PositionAngleType getCachedPositionAngleType() { - return PositionAngleType.TRUE; + return cachedPositionAngleType; } /** {@inheritDoc} */ @@ -1454,12 +1757,10 @@ public boolean hasRates() { /** {@inheritDoc} */ @Override public FieldKeplerianOrbit removeRates() { - final PositionAngleType positionAngleType = getCachedPositionAngleType(); return new FieldKeplerianOrbit<>(getA(), getE(), getI(), getPerigeeArgument(), getRightAscensionOfAscendingNode(), - getAnomaly(positionAngleType), positionAngleType, getFrame(), getDate(), getMu()); + cachedAnomaly, cachedPositionAngleType, getFrame(), getDate(), getMu()); } - /** Check if the given parameter is within an acceptable range. * The bounds are inclusive: an exception is raised when either of those conditions are met: *

                  @@ -1485,14 +1786,13 @@ private void checkParameterRangeInclusive(final String parameterName, final doub /** {@inheritDoc} */ @Override public KeplerianOrbit toOrbit() { - final PositionAngleType cachedPositionAngleType = getCachedPositionAngleType(); - final double cachedPositionAngle = getAnomaly(cachedPositionAngleType).getReal(); + final double cachedPositionAngle = cachedAnomaly.getReal(); if (hasDerivatives()) { return new KeplerianOrbit(a.getReal(), e.getReal(), i.getReal(), pa.getReal(), raan.getReal(), cachedPositionAngle, aDot.getReal(), eDot.getReal(), iDot.getReal(), paDot.getReal(), raanDot.getReal(), - getAnomalyDot(getCachedPositionAngleType()).getReal(), + cachedAnomalyDot.getReal(), cachedPositionAngleType, cachedPositionAngleType, getFrame(), getDate().toAbsoluteDate(), getMu().getReal()); } else { diff --git a/src/main/java/org/orekit/orbits/KeplerianOrbit.java b/src/main/java/org/orekit/orbits/KeplerianOrbit.java index 80e74457bf..f3cb4a06d6 100644 --- a/src/main/java/org/orekit/orbits/KeplerianOrbit.java +++ b/src/main/java/org/orekit/orbits/KeplerianOrbit.java @@ -452,36 +452,43 @@ public KeplerianOrbit(final Orbit op) { } /** {@inheritDoc} */ + @Override public OrbitType getType() { return OrbitType.KEPLERIAN; } /** {@inheritDoc} */ + @Override public double getA() { return a; } /** {@inheritDoc} */ + @Override public double getADot() { return aDot; } /** {@inheritDoc} */ + @Override public double getE() { return e; } /** {@inheritDoc} */ + @Override public double getEDot() { return eDot; } /** {@inheritDoc} */ + @Override public double getI() { return i; } /** {@inheritDoc} */ + @Override public double getIDot() { return iDot; } @@ -700,11 +707,13 @@ public double getAnomalyDot(final PositionAngleType type) { } /** {@inheritDoc} */ + @Override public double getEquinoctialEx() { return e * FastMath.cos(pa + raan); } /** {@inheritDoc} */ + @Override public double getEquinoctialExDot() { final double paPraan = pa + raan; final SinCos sc = FastMath.sinCos(paPraan); @@ -712,11 +721,13 @@ public double getEquinoctialExDot() { } /** {@inheritDoc} */ + @Override public double getEquinoctialEy() { return e * FastMath.sin(pa + raan); } /** {@inheritDoc} */ + @Override public double getEquinoctialEyDot() { final double paPraan = pa + raan; final SinCos sc = FastMath.sinCos(paPraan); @@ -724,6 +735,7 @@ public double getEquinoctialEyDot() { } /** {@inheritDoc} */ + @Override public double getHx() { // Check for equatorial retrograde orbit if (FastMath.abs(i - FastMath.PI) < 1.0e-10) { @@ -733,6 +745,7 @@ public double getHx() { } /** {@inheritDoc} */ + @Override public double getHxDot() { // Check for equatorial retrograde orbit if (FastMath.abs(i - FastMath.PI) < 1.0e-10) { @@ -744,15 +757,17 @@ public double getHxDot() { } /** {@inheritDoc} */ + @Override public double getHy() { // Check for equatorial retrograde orbit if (FastMath.abs(i - FastMath.PI) < 1.0e-10) { return Double.NaN; } - return FastMath.sin(raan) * FastMath.tan(0.5 * i); + return FastMath.sin(raan) * FastMath.tan(0.5 * i); } /** {@inheritDoc} */ + @Override public double getHyDot() { // Check for equatorial retrograde orbit if (FastMath.abs(i - FastMath.PI) < 1.0e-10) { @@ -764,31 +779,37 @@ public double getHyDot() { } /** {@inheritDoc} */ + @Override public double getLv() { return pa + raan + getTrueAnomaly(); } /** {@inheritDoc} */ + @Override public double getLvDot() { return paDot + raanDot + getTrueAnomalyDot(); } /** {@inheritDoc} */ + @Override public double getLE() { return pa + raan + getEccentricAnomaly(); } /** {@inheritDoc} */ + @Override public double getLEDot() { return paDot + raanDot + getEccentricAnomalyDot(); } /** {@inheritDoc} */ + @Override public double getLM() { return pa + raan + getMeanAnomaly(); } /** {@inheritDoc} */ + @Override public double getLMDot() { return paDot + raanDot + getMeanAnomalyDot(); } @@ -1049,6 +1070,7 @@ private Vector3D nonKeplerianAcceleration() { } /** {@inheritDoc} */ + @Override protected Vector3D initPosition() { final Vector3D[] axes = referenceAxes(); @@ -1084,6 +1106,7 @@ protected Vector3D initPosition() { } /** {@inheritDoc} */ + @Override protected TimeStampedPVCoordinates initPVCoordinates() { // position and velocity @@ -1101,6 +1124,7 @@ protected TimeStampedPVCoordinates initPVCoordinates() { } /** {@inheritDoc} */ + @Override public KeplerianOrbit shiftedBy(final double dt) { // use Keplerian-only motion @@ -1137,6 +1161,7 @@ public KeplerianOrbit shiftedBy(final double dt) { } /** {@inheritDoc} */ + @Override protected double[][] computeJacobianMeanWrtCartesian() { if (isElliptical()) { return computeJacobianMeanWrtCartesianElliptical(); @@ -1412,6 +1437,7 @@ private double[][] computeJacobianMeanWrtCartesianHyperbolic() { } /** {@inheritDoc} */ + @Override protected double[][] computeJacobianEccentricWrtCartesian() { if (isElliptical()) { return computeJacobianEccentricWrtCartesianElliptical(); @@ -1485,6 +1511,7 @@ private double[][] computeJacobianEccentricWrtCartesianHyperbolic() { } /** {@inheritDoc} */ + @Override protected double[][] computeJacobianTrueWrtCartesian() { if (isElliptical()) { return computeJacobianTrueWrtCartesianElliptical(); @@ -1570,6 +1597,7 @@ private double[][] computeJacobianTrueWrtCartesianHyperbolic() { } /** {@inheritDoc} */ + @Override public void addKeplerContribution(final PositionAngleType type, final double gm, final double[] pDot) { final double oMe2; diff --git a/src/main/java/org/orekit/orbits/OrbitType.java b/src/main/java/org/orekit/orbits/OrbitType.java index d3dbf3d927..a8a592fa05 100644 --- a/src/main/java/org/orekit/orbits/OrbitType.java +++ b/src/main/java/org/orekit/orbits/OrbitType.java @@ -616,8 +616,9 @@ public EquinoctialOrbit normalize(final Orbit orbit, final Orbit reference) { eO.getEquinoctialEy(), eO.getHx(), eO.getHy(), - MathUtils.normalizeAngle(eO.getLv(), eR.getLv()), - PositionAngleType.TRUE, + MathUtils.normalizeAngle(eO.getL(cachedPositionAngleType), + eR.getL(cachedPositionAngleType)), + cachedPositionAngleType, eO.getFrame(), eO.getDate(), eO.getMu()); @@ -835,7 +836,8 @@ public KeplerianOrbit normalize(final Orbit orbit, final Orbit reference) { kO.getE(), kO.getI(), MathUtils.normalizeAngle(kO.getPerigeeArgument(), kR.getPerigeeArgument()), - MathUtils.normalizeAngle(kO.getRightAscensionOfAscendingNode(), kR.getRightAscensionOfAscendingNode()), + MathUtils.normalizeAngle(kO.getRightAscensionOfAscendingNode(), + kR.getRightAscensionOfAscendingNode()), MathUtils.normalizeAngle(kO.getAnomaly(cachedPositionAngleType), kR.getAnomaly(cachedPositionAngleType)), kO.getADot(), @@ -871,6 +873,7 @@ public > FieldKeplerianOrbit normalize(fina // convert input to proper type final FieldKeplerianOrbit kO = convertType(orbit); final FieldKeplerianOrbit kR = convertType(reference); + final PositionAngleType positionAngleType = kO.getCachedPositionAngleType(); // perform normalization if (kO.hasDerivatives()) { @@ -878,15 +881,17 @@ public > FieldKeplerianOrbit normalize(fina kO.getE(), kO.getI(), MathUtils.normalizeAngle(kO.getPerigeeArgument(), kR.getPerigeeArgument()), - MathUtils.normalizeAngle(kO.getRightAscensionOfAscendingNode(), kR.getRightAscensionOfAscendingNode()), - MathUtils.normalizeAngle(kO.getTrueAnomaly(), kR.getTrueAnomaly()), + MathUtils.normalizeAngle(kO.getRightAscensionOfAscendingNode(), + kR.getRightAscensionOfAscendingNode()), + MathUtils.normalizeAngle(kO.getAnomaly(positionAngleType), + kR.getAnomaly(positionAngleType)), kO.getADot(), kO.getEDot(), kO.getIDot(), kO.getPerigeeArgumentDot(), kO.getRightAscensionOfAscendingNodeDot(), - kO.getTrueAnomalyDot(), - PositionAngleType.TRUE, + kO.getAnomalyDot(positionAngleType), + positionAngleType, kO.getFrame(), kO.getDate(), kO.getMu()); @@ -895,9 +900,11 @@ public > FieldKeplerianOrbit normalize(fina kO.getE(), kO.getI(), MathUtils.normalizeAngle(kO.getPerigeeArgument(), kR.getPerigeeArgument()), - MathUtils.normalizeAngle(kO.getRightAscensionOfAscendingNode(), kR.getRightAscensionOfAscendingNode()), - MathUtils.normalizeAngle(kO.getTrueAnomaly(), kR.getTrueAnomaly()), - PositionAngleType.TRUE, + MathUtils.normalizeAngle(kO.getRightAscensionOfAscendingNode(), + kR.getRightAscensionOfAscendingNode()), + MathUtils.normalizeAngle(kO.getAnomaly(positionAngleType), + kR.getAnomaly(positionAngleType)), + positionAngleType, kO.getFrame(), kO.getDate(), kO.getMu()); diff --git a/src/main/java/org/orekit/propagation/analytical/BrouwerLyddanePropagator.java b/src/main/java/org/orekit/propagation/analytical/BrouwerLyddanePropagator.java index ee247aea4d..3dec70f92f 100644 --- a/src/main/java/org/orekit/propagation/analytical/BrouwerLyddanePropagator.java +++ b/src/main/java/org/orekit/propagation/analytical/BrouwerLyddanePropagator.java @@ -1435,7 +1435,7 @@ public KeplerianOrbit propagateParameters(final AbsoluteDate date) { g.getValue(), h.getValue(), l.getValue(), a.getFirstDerivative(), e.getFirstDerivative(), i.getFirstDerivative(), g.getFirstDerivative(), h.getFirstDerivative(), l.getFirstDerivative(), - PositionAngleType.MEAN, PositionAngleType.TRUE, mean.getFrame(), date, mu); + PositionAngleType.MEAN, mean.getFrame(), date, mu); } diff --git a/src/main/java/org/orekit/propagation/analytical/FieldBrouwerLyddanePropagator.java b/src/main/java/org/orekit/propagation/analytical/FieldBrouwerLyddanePropagator.java index 91a313d9df..fd72e34388 100644 --- a/src/main/java/org/orekit/propagation/analytical/FieldBrouwerLyddanePropagator.java +++ b/src/main/java/org/orekit/propagation/analytical/FieldBrouwerLyddanePropagator.java @@ -755,7 +755,7 @@ private FieldBLModel computeMeanParameters(final FieldKeplerianOrbit oscul current.mean.getPerigeeArgument() .add(deltaOmega), current.mean.getRightAscensionOfAscendingNode().add(deltaRAAN), current.mean.getMeanAnomaly() .add(deltaAnom), - PositionAngleType.MEAN, + PositionAngleType.MEAN, PositionAngleType.TRUE, current.mean.getFrame(), current.mean.getDate(), mu), mass, referenceRadius, mu, ck0); diff --git a/src/test/java/org/orekit/forces/radiation/KnockeRediffusedForceModelTest.java b/src/test/java/org/orekit/forces/radiation/KnockeRediffusedForceModelTest.java index bc649f9729..1e1c6333a0 100644 --- a/src/test/java/org/orekit/forces/radiation/KnockeRediffusedForceModelTest.java +++ b/src/test/java/org/orekit/forces/radiation/KnockeRediffusedForceModelTest.java @@ -62,7 +62,7 @@ * However, the complete reproduction of the LAGEOS-1 test case is much too long for it to be implemented in test class. * Then, only */ -public class KnockeRediffusedForceModelTest extends AbstractForceModelTest{ +class KnockeRediffusedForceModelTest extends AbstractForceModelTest{ @BeforeEach public void setUp() { @@ -71,7 +71,7 @@ public void setUp() { @Test - public void testJacobianVsFiniteDifferences() { + void testJacobianVsFiniteDifferences() { // initialization AbsoluteDate date = new AbsoluteDate(new DateComponents(2003, 03, 01), @@ -103,7 +103,7 @@ public void testJacobianVsFiniteDifferences() { } @Test - public void testParameterIsotropicSingle() { + void testParameterIsotropicSingle() { final Vector3D pos = new Vector3D(6.46885878304673824e+06, -1.88050918456274318e+06, -1.32931592294715829e+04); final Vector3D vel = new Vector3D(2.14718074509906819e+03, 7.38239351251748485e+03, -1.14097953925384523e+01); @@ -130,7 +130,7 @@ public void testParameterIsotropicSingle() { } @Test - public void testGlobalStateJacobianIsotropicSingle() + void testGlobalStateJacobianIsotropicSingle() { // initialization @@ -171,7 +171,7 @@ public void testGlobalStateJacobianIsotropicSingle() } @Test - public void testRealField() { + void testRealField() { // Initial field Keplerian orbit // The variables are the six orbital parameters @@ -236,13 +236,13 @@ public void testRealField() { // Do the test checkRealFieldPropagation(FKO, PositionAngleType.MEAN, 300., NP, FNP, - 1.0e-30, 1.3e-8, 6.7e-11, 1.4e-10, + 1.0e-15, 1.3e-8, 6.7e-11, 1.4e-10, 1, false); } @Test - public void testRealFieldGradient() { + void testRealFieldGradient() { // Initial field Keplerian orbit // The variables are the six orbital parameters @@ -306,17 +306,17 @@ public void testRealFieldGradient() { // Do the test checkRealFieldPropagationGradient(FKO, PositionAngleType.MEAN, 300., NP, FNP, - 1.0e-30, 1.3e-2, 9.6e-5, 1.4e-4, + 1.0e-15, 1.3e-2, 9.6e-5, 1.4e-4, 1, false); } - /** Roughtly compare Knocke model accelerations against results from "EARTH RADIATION PRESSURE EFFECTS ON SATELLITES", + /** Roughly compare Knocke model accelerations against results from "EARTH RADIATION PRESSURE EFFECTS ON SATELLITES", * 1988, by P. C. Knocke, J. C. Ries, and B. D. Tapley. * The case is as close as possible from what it might be in the paper. Orbit and date have been artifically set so that the angle between * the orbital plan and Earth-Sun direction is almost equal to zero. */ @Test - public void testRoughtAcceleration() { + void testRoughAcceleration() { // LAGEOS-1 final double mass = 406.9; diff --git a/src/test/java/org/orekit/models/earth/troposphere/FieldNiellMappingFunctionModelTest.java b/src/test/java/org/orekit/models/earth/troposphere/FieldNiellMappingFunctionModelTest.java index de53f39df9..f6884e8396 100644 --- a/src/test/java/org/orekit/models/earth/troposphere/FieldNiellMappingFunctionModelTest.java +++ b/src/test/java/org/orekit/models/earth/troposphere/FieldNiellMappingFunctionModelTest.java @@ -19,7 +19,7 @@ import org.hipparchus.util.Binary64Field; import org.junit.jupiter.api.Test; -public class FieldNiellMappingFunctionModelTest extends AbstractFieldMappingFunctionTest { +class FieldNiellMappingFunctionModelTest extends AbstractFieldMappingFunctionTest { protected TroposphereMappingFunction buildMappingFunction() { return new NiellMappingFunctionModel(); @@ -32,7 +32,7 @@ public void testMappingFactors() { @Test public void testMFStateDerivatives() { - doTestMFStateDerivatives(6.539e-12, 1.557e-11); + doTestMFStateDerivatives(6.542e-12, 1.557e-11); } } diff --git a/src/test/java/org/orekit/orbits/FieldKeplerianOrbitTest.java b/src/test/java/org/orekit/orbits/FieldKeplerianOrbitTest.java index 6b55252670..9a781d4871 100644 --- a/src/test/java/org/orekit/orbits/FieldKeplerianOrbitTest.java +++ b/src/test/java/org/orekit/orbits/FieldKeplerianOrbitTest.java @@ -28,10 +28,7 @@ import org.hipparchus.geometry.euclidean.threed.FieldVector3D; import org.hipparchus.linear.FieldMatrixPreservingVisitor; import org.hipparchus.linear.MatrixUtils; -import org.hipparchus.util.Binary64Field; -import org.hipparchus.util.FastMath; -import org.hipparchus.util.MathArrays; -import org.hipparchus.util.MathUtils; +import org.hipparchus.util.*; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -70,186 +67,186 @@ public void setUp() { } @Test - public void testKepToKep() { + void testKepToKep() { doTestKeplerianToKeplerian(Binary64Field.getInstance()); } @Test - public void testKepToCart() { + void testKepToCart() { doTestKeplerianToCartesian(Binary64Field.getInstance()); } @Test - public void testKepToEquin() { + void testKepToEquin() { doTestKeplerianToEquinoctial(Binary64Field.getInstance()); } @Test - public void testAnomaly() { + void testAnomaly() { doTestAnomaly(Binary64Field.getInstance()); } @Test - public void testPositionVelocityNorms() { + void testPositionVelocityNorms() { doTestPositionVelocityNorms(Binary64Field.getInstance()); } @Test - public void testGeometry() { + void testGeometry() { doTestGeometry(Binary64Field.getInstance()); } @Test - public void testSymmetry() { + void testSymmetry() { doTestSymmetry(Binary64Field.getInstance()); } @Test - public void testNonInertialFrame() { + void testNonInertialFrame() { Assertions.assertThrows(IllegalArgumentException.class, () -> { doTestNonInertialFrame(Binary64Field.getInstance()); }); } @Test - public void testPeriod() { + void testPeriod() { doTestPeriod(Binary64Field.getInstance()); } @Test - public void testHyperbola1() { + void testHyperbola1() { doTestHyperbola1(Binary64Field.getInstance()); } @Test - public void testHyperbola2() { + void testHyperbola2() { doTestHyperbola2(Binary64Field.getInstance()); } @Test - public void testToOrbitWithoutDerivatives() { + void testToOrbitWithoutDerivatives() { doTestToOrbitWithoutDerivatives(Binary64Field.getInstance()); } @Test - public void testToOrbitWithDerivatives() { + void testToOrbitWithDerivatives() { doTestToOrbitWithDerivatives(Binary64Field.getInstance()); } @Test - public void testDerivativesConversionSymmetry() { + void testDerivativesConversionSymmetry() { doTestDerivativesConversionSymmetry(Binary64Field.getInstance()); } @Test - public void testDerivativesConversionSymmetryHyperbolic() { + void testDerivativesConversionSymmetryHyperbolic() { doTestDerivativesConversionSymmetryHyperbolic(Binary64Field.getInstance()); } @Test - public void testToString() { + void testToString() { doTestToString(Binary64Field.getInstance()); } @Test - public void testInconsistentHyperbola() { + void testInconsistentHyperbola() { doTestInconsistentHyperbola(Binary64Field.getInstance()); } @Test - public void testVeryLargeEccentricity() { + void testVeryLargeEccentricity() { doTestVeryLargeEccentricity(Binary64Field.getInstance()); } @Test - public void testKeplerEquation() { + void testKeplerEquation() { doTestKeplerEquation(Binary64Field.getInstance()); } @Test - public void testNumericalIssue() { + void testNumericalIssue() { doTestNumericalIssue25(Binary64Field.getInstance()); } @Test - public void testPerfectlyEquatorial() { + void testPerfectlyEquatorial() { doTestPerfectlyEquatorial(Binary64Field.getInstance()); } @Test - public void testJacobianReferenceEllipse() { + void testJacobianReferenceEllipse() { doTestJacobianReferenceEllipse(Binary64Field.getInstance()); } @Test - public void testJacobianFinitedDiff() { + void testJacobianFinitedDiff() { doTestJacobianFinitedifferencesEllipse(Binary64Field.getInstance()); } @Test - public void testJacobianReferenceHyperbola() { + void testJacobianReferenceHyperbola() { doTestJacobianReferenceHyperbola(Binary64Field.getInstance()); } @Test - public void testJacobianFinitDiffHyperbola() { + void testJacobianFinitDiffHyperbola() { doTestJacobianFinitedifferencesHyperbola(Binary64Field.getInstance()); } @Test - public void testKeplerianDerivatives() { + void testKeplerianDerivatives() { doTestKeplerianDerivatives(Binary64Field.getInstance()); } @Test - public void testNonKeplerianEllipticDerivatives() { + void testNonKeplerianEllipticDerivatives() { doTestNonKeplerianEllipticDerivatives(Binary64Field.getInstance()); } @Test - public void testNonKeplerianHyperbolicDerivatives() { + void testNonKeplerianHyperbolicDerivatives() { doTestNonKeplerianHyperbolicDerivatives(Binary64Field.getInstance()); } @Test - public void testPositionAngleDerivatives() { + void testPositionAngleDerivatives() { doTestPositionAngleDerivatives(Binary64Field.getInstance()); } @Test - public void testPositionAngleHyperbolicDerivatives() { + void testPositionAngleHyperbolicDerivatives() { doTestPositionAngleHyperbolicDerivatives(Binary64Field.getInstance()); } @Test - public void testEquatorialRetrograde() { + void testEquatorialRetrograde() { doTestEquatorialRetrograde(Binary64Field.getInstance()); } @Test - public void testOutOfRangeV() { + void testOutOfRangeV() { Assertions.assertThrows(IllegalArgumentException.class, () -> { doTestOutOfRangeV(Binary64Field.getInstance()); }); } @Test - public void testPerfectlyEquatorialConversion() { + void testPerfectlyEquatorialConversion() { doTestPerfectlyEquatorialConversion(Binary64Field.getInstance()); } @Test - public void testCopyNonKeplerianAcceleration() { + void testCopyNonKeplerianAcceleration() { doTestCopyNonKeplerianAcceleration(Binary64Field.getInstance()); } @Test - public void testIssue674() { + void testIssue674() { doTestIssue674(Binary64Field.getInstance()); } @Test - public void testNormalize() { + void testNormalize() { doTestNormalize(Binary64Field.getInstance()); } @@ -343,6 +340,105 @@ private > void compareFieldOrbitToOrbit(final } } + @Test + void testCoverageCachedPositionAngleTypeWithRates() { + // GIVEN + final double semiMajorAxis = 1e4; + final double eccentricity = 0.; + final double expectedAnomaly = 0.; + final double expectedAnomalyDot = 0.; + final AbsoluteDate date = AbsoluteDate.ARBITRARY_EPOCH; + final Binary64Field field = Binary64Field.getInstance(); + final Binary64 zero = field.getZero(); + // WHEN & THEN + for (final PositionAngleType inputPositionAngleType: PositionAngleType.values()) { + for (final PositionAngleType cachedPositionAngleType: PositionAngleType.values()) { + final FieldKeplerianOrbit fieldOrbit = new FieldKeplerianOrbit<>( + zero.newInstance(semiMajorAxis), zero.newInstance(eccentricity), zero, zero, zero, + zero.newInstance(expectedAnomaly), zero, zero, zero, zero, zero, + zero.newInstance(expectedAnomalyDot), inputPositionAngleType, cachedPositionAngleType, + FramesFactory.getGCRF(), new FieldAbsoluteDate<>(field, date), zero.newInstance(mu)); + Assertions.assertEquals(cachedPositionAngleType, fieldOrbit.getCachedPositionAngleType()); + Assertions.assertEquals(expectedAnomaly, fieldOrbit.getTrueAnomaly().getReal()); + Assertions.assertEquals(expectedAnomaly, fieldOrbit.getEccentricAnomaly().getReal()); + Assertions.assertEquals(expectedAnomaly, fieldOrbit.getMeanAnomaly().getReal()); + Assertions.assertEquals(expectedAnomalyDot, fieldOrbit.getTrueAnomalyDot().getReal()); + Assertions.assertEquals(expectedAnomalyDot, fieldOrbit.getEccentricAnomalyDot().getReal()); + Assertions.assertEquals(expectedAnomalyDot, fieldOrbit.getMeanAnomalyDot().getReal()); + } + } + } + + @Test + void testGetAnomalyVersusDouble() { + // GIVEN + final double semiMajorAxis = 1e6; + final double eccentricity = 1e-2; + final double expectedAnomaly = 3.; + // WHE & THEN + compareAnomalies(semiMajorAxis, eccentricity, expectedAnomaly); + } + + @Test + void testGetAnomalyVersusDoubleHyperbolic() { + // GIVEN + final double semiMajorAxis = -1e6; + final double eccentricity = 1.5; + final double expectedAnomaly = 1.; + // WHEN & THEN + compareAnomalies(semiMajorAxis, eccentricity, expectedAnomaly); + } + + private void compareAnomalies(final double semiMajorAxis, final double eccentricity, final double anomaly) { + final AbsoluteDate date = AbsoluteDate.ARBITRARY_EPOCH; + final Binary64Field field = Binary64Field.getInstance(); + final Binary64 zero = field.getZero(); + final double tolerance = 1e-10; + for (final PositionAngleType inputPositionAngleType: PositionAngleType.values()) { + for (final PositionAngleType cachedPositionAngleType: PositionAngleType.values()) { + final FieldKeplerianOrbit fieldOrbit = new FieldKeplerianOrbit<>( + zero.newInstance(semiMajorAxis), zero.newInstance(eccentricity), zero, zero, zero, + zero.newInstance(anomaly), inputPositionAngleType, cachedPositionAngleType, + FramesFactory.getGCRF(), new FieldAbsoluteDate<>(field, date), zero.newInstance(mu)); + final KeplerianOrbit keplerianOrbit = fieldOrbit.toOrbit(); + Assertions.assertEquals(keplerianOrbit.getTrueAnomaly(), fieldOrbit.getTrueAnomaly().getReal(), + tolerance); + Assertions.assertEquals(keplerianOrbit.getEccentricAnomaly(), fieldOrbit.getEccentricAnomaly().getReal(), + tolerance); + Assertions.assertEquals(keplerianOrbit.getMeanAnomaly(), fieldOrbit.getMeanAnomaly().getReal(), + tolerance); + } + } + } + + @Test + void testGetAnomalyDotVersusDoubleHyperbolic() { + final double semiMajorAxis = -1e6; + final double eccentricity = 1.5; + final double anomaly = 1.; + final double anomalyDot = 0.1; + final AbsoluteDate date = AbsoluteDate.ARBITRARY_EPOCH; + final Binary64Field field = Binary64Field.getInstance(); + final Binary64 zero = field.getZero(); + final double tolerance = 1e-10; + for (final PositionAngleType inputPositionAngleType: PositionAngleType.values()) { + for (final PositionAngleType cachedPositionAngleType: PositionAngleType.values()) { + final FieldKeplerianOrbit fieldOrbit = new FieldKeplerianOrbit<>( + zero.newInstance(semiMajorAxis), zero.newInstance(eccentricity), zero, zero, zero, + zero.newInstance(anomaly), zero, zero, zero, zero, zero, zero.newInstance(anomalyDot), + inputPositionAngleType, cachedPositionAngleType, + FramesFactory.getGCRF(), new FieldAbsoluteDate<>(field, date), zero.newInstance(mu)); + final KeplerianOrbit keplerianOrbit = fieldOrbit.toOrbit(); + Assertions.assertEquals(keplerianOrbit.getTrueAnomaly(), fieldOrbit.getTrueAnomaly().getReal(), + tolerance); + Assertions.assertEquals(keplerianOrbit.getEccentricAnomaly(), fieldOrbit.getEccentricAnomaly().getReal(), + tolerance); + Assertions.assertEquals(keplerianOrbit.getMeanAnomaly(), fieldOrbit.getMeanAnomaly().getReal(), + tolerance); + } + } + } + private > void doTestKeplerianToKeplerian(final Field field) { FieldAbsoluteDate date = new FieldAbsoluteDate<>(field); diff --git a/src/test/java/org/orekit/orbits/OrbitBlenderTest.java b/src/test/java/org/orekit/orbits/OrbitBlenderTest.java index fe6c5a02c8..394bb5dd6a 100644 --- a/src/test/java/org/orekit/orbits/OrbitBlenderTest.java +++ b/src/test/java/org/orekit/orbits/OrbitBlenderTest.java @@ -268,7 +268,7 @@ void testBrouwerLyddaneQuadraticBlendingOnSergeiCase() { 0.03654640625064279, 0.09412869297314610, 0.06642996306635666, - 1e-17, false); + 1e-13, false); } @Test diff --git a/src/test/java/org/orekit/propagation/StateCovarianceBlenderTest.java b/src/test/java/org/orekit/propagation/StateCovarianceBlenderTest.java index b2a19a9e7b..5064859b16 100644 --- a/src/test/java/org/orekit/propagation/StateCovarianceBlenderTest.java +++ b/src/test/java/org/orekit/propagation/StateCovarianceBlenderTest.java @@ -180,7 +180,7 @@ void testKeplerianQuadraticBlending() { void testBrouwerLyddaneQuadraticBlending() { // Given final boolean showResults = false; // Show results? - final double tolerance = 1.e-16; + final double tolerance = 1.e-12; // Create state covariance interpolator final SmoothStepFactory.SmoothStepFunction blendingFunction = SmoothStepFactory.getQuadratic(); From 4cb902f40b3494e6bcffe1544918dad4ab79b993 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Fri, 23 Feb 2024 09:36:23 +0100 Subject: [PATCH 137/359] Removed deprecated field parameter in empty cache. --- .../utils/ImmutableFieldTimeStampedCache.java | 41 +++++++++++++------ .../ImmutableFieldTimeStampedCacheTest.java | 39 +++++++++++++++++- 2 files changed, 65 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/orekit/utils/ImmutableFieldTimeStampedCache.java b/src/main/java/org/orekit/utils/ImmutableFieldTimeStampedCache.java index c3e3ca5f32..a2bc7f3e6e 100644 --- a/src/main/java/org/orekit/utils/ImmutableFieldTimeStampedCache.java +++ b/src/main/java/org/orekit/utils/ImmutableFieldTimeStampedCache.java @@ -45,6 +45,13 @@ public class ImmutableFieldTimeStampedCache, KK extends CalculusFieldElement> implements FieldTimeStampedCache { + /** An empty immutable cache that always throws an exception on attempted access. + * @since 12.1 + */ + @SuppressWarnings("rawtypes") + private static final ImmutableFieldTimeStampedCache EMPTY_CACHE = + new EmptyFieldTimeStampedCache(); + /** * the cached data. Be careful not to modify it after the constructor, or return a reference that allows mutating this * list. @@ -85,11 +92,9 @@ public ImmutableFieldTimeStampedCache(final int maxNeighborsSize, } - /** - * private constructor for {@link #emptyCache(Field)}. - * @param ignored field to which the elements belong (ignored since 12.1) + /** Private constructor for {@link #EMPTY_CACHE}. */ - private ImmutableFieldTimeStampedCache(final Field ignored) { + private ImmutableFieldTimeStampedCache() { this.data = null; this.maxNeighborsSize = 0; } @@ -99,12 +104,28 @@ private ImmutableFieldTimeStampedCache(final Field ignored) { * * @param the type of data * @param the type of the calculus field element - * @param field field to which the elements belong + * @param ignored field to which the elements belong + * @return an empty {@link ImmutableTimeStampedCache}. + * @deprecated as of 12.1, replaced by {@link #emptyCache()} + */ + @Deprecated + public static , CFE extends CalculusFieldElement> + ImmutableFieldTimeStampedCache emptyCache(final Field ignored) { + return emptyCache(); + } + + /** + * Get an empty immutable cache. + * + * @param the type of data + * @param the type of the calculus field element * @return an empty {@link ImmutableTimeStampedCache}. + * @since 12.1 */ + @SuppressWarnings("unchecked") public static , CFE extends CalculusFieldElement> - ImmutableFieldTimeStampedCache emptyCache(final Field field) { - return new EmptyFieldTimeStampedCache<>(field); + ImmutableFieldTimeStampedCache emptyCache() { + return (ImmutableFieldTimeStampedCache) EMPTY_CACHE; } /** {@inheritDoc} */ @@ -150,12 +171,6 @@ public String toString() { private static class EmptyFieldTimeStampedCache, KK extends CalculusFieldElement> extends ImmutableFieldTimeStampedCache { - /** Simple constructor. - */ - EmptyFieldTimeStampedCache(final Field field) { - super(field); - } - /** {@inheritDoc} */ @Override public Stream getNeighbors(final FieldAbsoluteDate central) { diff --git a/src/test/java/org/orekit/utils/ImmutableFieldTimeStampedCacheTest.java b/src/test/java/org/orekit/utils/ImmutableFieldTimeStampedCacheTest.java index d67f817bad..5ebbf94cbd 100644 --- a/src/test/java/org/orekit/utils/ImmutableFieldTimeStampedCacheTest.java +++ b/src/test/java/org/orekit/utils/ImmutableFieldTimeStampedCacheTest.java @@ -239,10 +239,11 @@ public void testImmutable() { } /** - * check {@link ImmutableFieldTimeStampedCache#emptyCache(Field)}. + * check {@link ImmutableFieldTimeStampedCache#emptyCache()}. */ + @Deprecated @Test - public void testEmptyCache() { + public void testEmptyCacheDeprecated() { // setup cache = ImmutableFieldTimeStampedCache.emptyCache(Binary64Field.getInstance()); @@ -272,6 +273,40 @@ public void testEmptyCache() { Assertions.assertEquals(cache.getMaxNeighborsSize(), 0); } + /** + * check {@link ImmutableFieldTimeStampedCache#emptyCache()}. + */ + @Test + public void testEmptyCache() { + // setup + cache = ImmutableFieldTimeStampedCache.emptyCache(); + + // actions + verify + try { + cache.getNeighbors(date); + Assertions.fail("Expected Exception"); + } + catch (TimeStampedCacheException e) { + // expected + } + try { + cache.getEarliest(); + Assertions.fail("Expected Exception"); + } + catch (IllegalStateException e) { + // expected + } + try { + cache.getLatest(); + Assertions.fail("Expected Exception"); + } + catch (IllegalStateException e) { + // expected + } + Assertions.assertEquals(cache.getAll().size(), 0); + Assertions.assertEquals(cache.getMaxNeighborsSize(), 0); + } + @Test public void testNonLinear() { final ImmutableFieldTimeStampedCache, Binary64> nonLinearCache = new ImmutableFieldTimeStampedCache<>(2, From 9d7efe378e01cef3aa6f6afdf5f5af7f9fdc29b0 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Fri, 23 Feb 2024 10:50:57 +0100 Subject: [PATCH 138/359] Added missing headers. --- .../org/orekit/bodies/PosVelChebyshevTest.java | 17 +++++++++++++++++ .../estimation/BrouwerLyddaneContext.java | 17 +++++++++++++++++ .../org/orekit/estimation/KeplerianContext.java | 17 +++++++++++++++++ .../orekit/estimation/StationDataProvider.java | 17 +++++++++++++++++ .../UnscentedEstimationTestUtils.java | 17 +++++++++++++++++ .../filtering/PseudoRangeFilteringTest.java | 17 +++++++++++++++++ .../ExtendedSemiAnalyticalKalmanFilterTest.java | 17 +++++++++++++++++ .../SemiAnalyticalKalmanModelTest.java | 17 +++++++++++++++++ ...iAnalyticalUnscentedKalmanEstimatorTest.java | 17 +++++++++++++++++ .../files/stk/STKEphemerisFileParserTest.java | 17 +++++++++++++++++ .../orekit/frames/FieldStaticTransformTest.java | 17 +++++++++++++++++ .../orekit/frames/KinematicTransformTest.java | 17 +++++++++++++++++ .../org/orekit/frames/StaticTransformTest.java | 17 +++++++++++++++++ ...BrouwerLyddaneParametersDerivativesTest.java | 17 +++++++++++++++++ .../BrouwerLyddanePropagatorTest.java | 17 +++++++++++++++++ ...BrouwerLyddaneStateTransitionMatrixTest.java | 17 +++++++++++++++++ ...cksteinHechlerStateTransitionMatrixTest.java | 17 +++++++++++++++++ .../FieldBrouwerLyddanePropagatorTest.java | 17 +++++++++++++++++ .../KeplerianStateTransitionMatrixTest.java | 17 +++++++++++++++++ .../tle/TLEParametersDerivativesTest.java | 17 +++++++++++++++++ .../tle/TLEStateTransitionMatrixTest.java | 17 +++++++++++++++++ ...ularSeparationFromSatelliteDetectorTest.java | 17 +++++++++++++++++ .../FieldLongitudeCrossingDetectorTest.java | 17 +++++++++++++++++ .../FieldStepHandlerMultiplexerTest.java | 17 +++++++++++++++++ .../orekit/time/LazyLoadedTimeScalesTest.java | 17 +++++++++++++++++ ...imeStampedDoubleHermiteInterpolatorTest.java | 17 +++++++++++++++++ ...utePVCoordinatesHermiteInterpolatorTest.java | 17 +++++++++++++++++ .../java/org/orekit/utils/FieldifierTest.java | 17 +++++++++++++++++ ...gularCoordinatesHermiteInterpolatorTest.java | 17 +++++++++++++++++ ...gularCoordinatesHermiteInterpolatorTest.java | 17 +++++++++++++++++ ...eldPVCoordinatesHermiteInterpolatorTest.java | 17 +++++++++++++++++ ...pedPVCoordinatesHermiteInterpolatorTest.java | 17 +++++++++++++++++ 32 files changed, 544 insertions(+) diff --git a/src/test/java/org/orekit/bodies/PosVelChebyshevTest.java b/src/test/java/org/orekit/bodies/PosVelChebyshevTest.java index 97d941e5c6..dc0257f27a 100644 --- a/src/test/java/org/orekit/bodies/PosVelChebyshevTest.java +++ b/src/test/java/org/orekit/bodies/PosVelChebyshevTest.java @@ -1,3 +1,20 @@ +/* Copyright 2002-2024 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.orekit.bodies; import org.hipparchus.analysis.differentiation.Gradient; diff --git a/src/test/java/org/orekit/estimation/BrouwerLyddaneContext.java b/src/test/java/org/orekit/estimation/BrouwerLyddaneContext.java index 199314015f..17fc70f59f 100644 --- a/src/test/java/org/orekit/estimation/BrouwerLyddaneContext.java +++ b/src/test/java/org/orekit/estimation/BrouwerLyddaneContext.java @@ -1,3 +1,20 @@ +/* Copyright 2002-2024 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.orekit.estimation; import org.hipparchus.geometry.euclidean.threed.Vector3D; diff --git a/src/test/java/org/orekit/estimation/KeplerianContext.java b/src/test/java/org/orekit/estimation/KeplerianContext.java index b334388e1f..466a4a663e 100644 --- a/src/test/java/org/orekit/estimation/KeplerianContext.java +++ b/src/test/java/org/orekit/estimation/KeplerianContext.java @@ -1,3 +1,20 @@ +/* Copyright 2002-2024 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.orekit.estimation; import org.hipparchus.geometry.euclidean.threed.Vector3D; diff --git a/src/test/java/org/orekit/estimation/StationDataProvider.java b/src/test/java/org/orekit/estimation/StationDataProvider.java index 39edb1af94..c741051ce7 100644 --- a/src/test/java/org/orekit/estimation/StationDataProvider.java +++ b/src/test/java/org/orekit/estimation/StationDataProvider.java @@ -1,3 +1,20 @@ +/* Copyright 2002-2024 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.orekit.estimation; import org.orekit.estimation.measurements.GroundStation; diff --git a/src/test/java/org/orekit/estimation/UnscentedEstimationTestUtils.java b/src/test/java/org/orekit/estimation/UnscentedEstimationTestUtils.java index 0017401bf5..b2721c5e33 100644 --- a/src/test/java/org/orekit/estimation/UnscentedEstimationTestUtils.java +++ b/src/test/java/org/orekit/estimation/UnscentedEstimationTestUtils.java @@ -1,3 +1,20 @@ +/* Copyright 2002-2024 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.orekit.estimation; import java.util.Arrays; diff --git a/src/test/java/org/orekit/estimation/measurements/filtering/PseudoRangeFilteringTest.java b/src/test/java/org/orekit/estimation/measurements/filtering/PseudoRangeFilteringTest.java index 5c32026df4..24597f3e47 100644 --- a/src/test/java/org/orekit/estimation/measurements/filtering/PseudoRangeFilteringTest.java +++ b/src/test/java/org/orekit/estimation/measurements/filtering/PseudoRangeFilteringTest.java @@ -1,3 +1,20 @@ +/* Copyright 2002-2024 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.orekit.estimation.measurements.filtering; import java.io.BufferedReader; diff --git a/src/test/java/org/orekit/estimation/sequential/ExtendedSemiAnalyticalKalmanFilterTest.java b/src/test/java/org/orekit/estimation/sequential/ExtendedSemiAnalyticalKalmanFilterTest.java index 25a25ba951..d3ce2d1ffe 100644 --- a/src/test/java/org/orekit/estimation/sequential/ExtendedSemiAnalyticalKalmanFilterTest.java +++ b/src/test/java/org/orekit/estimation/sequential/ExtendedSemiAnalyticalKalmanFilterTest.java @@ -1,3 +1,20 @@ +/* Copyright 2002-2024 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.orekit.estimation.sequential; import java.io.File; diff --git a/src/test/java/org/orekit/estimation/sequential/SemiAnalyticalKalmanModelTest.java b/src/test/java/org/orekit/estimation/sequential/SemiAnalyticalKalmanModelTest.java index 4a4d2227e5..fa4c4a743f 100644 --- a/src/test/java/org/orekit/estimation/sequential/SemiAnalyticalKalmanModelTest.java +++ b/src/test/java/org/orekit/estimation/sequential/SemiAnalyticalKalmanModelTest.java @@ -1,3 +1,20 @@ +/* Copyright 2002-2024 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.orekit.estimation.sequential; import org.hipparchus.linear.MatrixUtils; diff --git a/src/test/java/org/orekit/estimation/sequential/SemiAnalyticalUnscentedKalmanEstimatorTest.java b/src/test/java/org/orekit/estimation/sequential/SemiAnalyticalUnscentedKalmanEstimatorTest.java index 5c64bdbb27..b04e99d288 100644 --- a/src/test/java/org/orekit/estimation/sequential/SemiAnalyticalUnscentedKalmanEstimatorTest.java +++ b/src/test/java/org/orekit/estimation/sequential/SemiAnalyticalUnscentedKalmanEstimatorTest.java @@ -1,3 +1,20 @@ +/* Copyright 2002-2024 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.orekit.estimation.sequential; import java.util.List; diff --git a/src/test/java/org/orekit/files/stk/STKEphemerisFileParserTest.java b/src/test/java/org/orekit/files/stk/STKEphemerisFileParserTest.java index b9e6711284..bb6fc08502 100644 --- a/src/test/java/org/orekit/files/stk/STKEphemerisFileParserTest.java +++ b/src/test/java/org/orekit/files/stk/STKEphemerisFileParserTest.java @@ -1,3 +1,20 @@ +/* Copyright 2002-2024 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.orekit.files.stk; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/src/test/java/org/orekit/frames/FieldStaticTransformTest.java b/src/test/java/org/orekit/frames/FieldStaticTransformTest.java index 65fd3b81dc..7538c6b4e0 100644 --- a/src/test/java/org/orekit/frames/FieldStaticTransformTest.java +++ b/src/test/java/org/orekit/frames/FieldStaticTransformTest.java @@ -1,3 +1,20 @@ +/* Copyright 2002-2024 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.orekit.frames; import org.hamcrest.CoreMatchers; diff --git a/src/test/java/org/orekit/frames/KinematicTransformTest.java b/src/test/java/org/orekit/frames/KinematicTransformTest.java index a5516b63f7..e01fe85279 100644 --- a/src/test/java/org/orekit/frames/KinematicTransformTest.java +++ b/src/test/java/org/orekit/frames/KinematicTransformTest.java @@ -1,3 +1,20 @@ +/* Copyright 2002-2024 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.orekit.frames; import org.hipparchus.geometry.euclidean.threed.Rotation; diff --git a/src/test/java/org/orekit/frames/StaticTransformTest.java b/src/test/java/org/orekit/frames/StaticTransformTest.java index 957863e596..fa135bd195 100644 --- a/src/test/java/org/orekit/frames/StaticTransformTest.java +++ b/src/test/java/org/orekit/frames/StaticTransformTest.java @@ -1,3 +1,20 @@ +/* Copyright 2002-2024 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.orekit.frames; import org.hamcrest.CoreMatchers; diff --git a/src/test/java/org/orekit/propagation/analytical/BrouwerLyddaneParametersDerivativesTest.java b/src/test/java/org/orekit/propagation/analytical/BrouwerLyddaneParametersDerivativesTest.java index 910ae19126..182ca56b7e 100644 --- a/src/test/java/org/orekit/propagation/analytical/BrouwerLyddaneParametersDerivativesTest.java +++ b/src/test/java/org/orekit/propagation/analytical/BrouwerLyddaneParametersDerivativesTest.java @@ -1,3 +1,20 @@ +/* Copyright 2002-2024 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.orekit.propagation.analytical; import org.hipparchus.geometry.euclidean.threed.Vector3D; diff --git a/src/test/java/org/orekit/propagation/analytical/BrouwerLyddanePropagatorTest.java b/src/test/java/org/orekit/propagation/analytical/BrouwerLyddanePropagatorTest.java index 91674c8d47..f7c0b8189f 100644 --- a/src/test/java/org/orekit/propagation/analytical/BrouwerLyddanePropagatorTest.java +++ b/src/test/java/org/orekit/propagation/analytical/BrouwerLyddanePropagatorTest.java @@ -1,3 +1,20 @@ +/* Copyright 2002-2024 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.orekit.propagation.analytical; import org.hipparchus.geometry.euclidean.threed.Vector3D; diff --git a/src/test/java/org/orekit/propagation/analytical/BrouwerLyddaneStateTransitionMatrixTest.java b/src/test/java/org/orekit/propagation/analytical/BrouwerLyddaneStateTransitionMatrixTest.java index 3a71b73633..3a518c8fc7 100644 --- a/src/test/java/org/orekit/propagation/analytical/BrouwerLyddaneStateTransitionMatrixTest.java +++ b/src/test/java/org/orekit/propagation/analytical/BrouwerLyddaneStateTransitionMatrixTest.java @@ -1,3 +1,20 @@ +/* Copyright 2002-2024 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.orekit.propagation.analytical; import org.hipparchus.geometry.euclidean.threed.Vector3D; diff --git a/src/test/java/org/orekit/propagation/analytical/EcksteinHechlerStateTransitionMatrixTest.java b/src/test/java/org/orekit/propagation/analytical/EcksteinHechlerStateTransitionMatrixTest.java index adfe989db3..6bff1026b1 100644 --- a/src/test/java/org/orekit/propagation/analytical/EcksteinHechlerStateTransitionMatrixTest.java +++ b/src/test/java/org/orekit/propagation/analytical/EcksteinHechlerStateTransitionMatrixTest.java @@ -1,3 +1,20 @@ +/* Copyright 2002-2024 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.orekit.propagation.analytical; import org.hipparchus.geometry.euclidean.threed.Vector3D; diff --git a/src/test/java/org/orekit/propagation/analytical/FieldBrouwerLyddanePropagatorTest.java b/src/test/java/org/orekit/propagation/analytical/FieldBrouwerLyddanePropagatorTest.java index 6bc4a7251c..67966e9fcc 100644 --- a/src/test/java/org/orekit/propagation/analytical/FieldBrouwerLyddanePropagatorTest.java +++ b/src/test/java/org/orekit/propagation/analytical/FieldBrouwerLyddanePropagatorTest.java @@ -1,3 +1,20 @@ +/* Copyright 2002-2024 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.orekit.propagation.analytical; import java.io.IOException; diff --git a/src/test/java/org/orekit/propagation/analytical/KeplerianStateTransitionMatrixTest.java b/src/test/java/org/orekit/propagation/analytical/KeplerianStateTransitionMatrixTest.java index 81769b2324..eb5886a27f 100644 --- a/src/test/java/org/orekit/propagation/analytical/KeplerianStateTransitionMatrixTest.java +++ b/src/test/java/org/orekit/propagation/analytical/KeplerianStateTransitionMatrixTest.java @@ -1,3 +1,20 @@ +/* Copyright 2002-2024 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.orekit.propagation.analytical; import org.hipparchus.geometry.euclidean.threed.Vector3D; diff --git a/src/test/java/org/orekit/propagation/analytical/tle/TLEParametersDerivativesTest.java b/src/test/java/org/orekit/propagation/analytical/tle/TLEParametersDerivativesTest.java index 67c0b2747e..8affcce50f 100644 --- a/src/test/java/org/orekit/propagation/analytical/tle/TLEParametersDerivativesTest.java +++ b/src/test/java/org/orekit/propagation/analytical/tle/TLEParametersDerivativesTest.java @@ -1,3 +1,20 @@ +/* Copyright 2002-2024 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.orekit.propagation.analytical.tle; import org.hipparchus.linear.RealMatrix; diff --git a/src/test/java/org/orekit/propagation/analytical/tle/TLEStateTransitionMatrixTest.java b/src/test/java/org/orekit/propagation/analytical/tle/TLEStateTransitionMatrixTest.java index 32415802ab..a52b260fe7 100644 --- a/src/test/java/org/orekit/propagation/analytical/tle/TLEStateTransitionMatrixTest.java +++ b/src/test/java/org/orekit/propagation/analytical/tle/TLEStateTransitionMatrixTest.java @@ -1,3 +1,20 @@ +/* Copyright 2002-2024 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.orekit.propagation.analytical.tle; import org.hipparchus.linear.RealMatrix; diff --git a/src/test/java/org/orekit/propagation/events/AngularSeparationFromSatelliteDetectorTest.java b/src/test/java/org/orekit/propagation/events/AngularSeparationFromSatelliteDetectorTest.java index 528f4c6d00..bb04e03d1d 100644 --- a/src/test/java/org/orekit/propagation/events/AngularSeparationFromSatelliteDetectorTest.java +++ b/src/test/java/org/orekit/propagation/events/AngularSeparationFromSatelliteDetectorTest.java @@ -1,3 +1,20 @@ +/* Copyright 2002-2024 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.orekit.propagation.events; import org.hipparchus.geometry.euclidean.threed.Vector3D; diff --git a/src/test/java/org/orekit/propagation/events/FieldLongitudeCrossingDetectorTest.java b/src/test/java/org/orekit/propagation/events/FieldLongitudeCrossingDetectorTest.java index dececccca1..c5a9e6c7b0 100644 --- a/src/test/java/org/orekit/propagation/events/FieldLongitudeCrossingDetectorTest.java +++ b/src/test/java/org/orekit/propagation/events/FieldLongitudeCrossingDetectorTest.java @@ -1,3 +1,20 @@ +/* Copyright 2002-2024 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.orekit.propagation.events; import static org.orekit.orbits.PositionAngleType.MEAN; diff --git a/src/test/java/org/orekit/propagation/sampling/FieldStepHandlerMultiplexerTest.java b/src/test/java/org/orekit/propagation/sampling/FieldStepHandlerMultiplexerTest.java index 41cd0de8b3..5ee14136d9 100644 --- a/src/test/java/org/orekit/propagation/sampling/FieldStepHandlerMultiplexerTest.java +++ b/src/test/java/org/orekit/propagation/sampling/FieldStepHandlerMultiplexerTest.java @@ -1,3 +1,20 @@ +/* Copyright 2002-2024 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.orekit.propagation.sampling; import org.hipparchus.Field; diff --git a/src/test/java/org/orekit/time/LazyLoadedTimeScalesTest.java b/src/test/java/org/orekit/time/LazyLoadedTimeScalesTest.java index 393bebe6ef..a24b5c78e0 100644 --- a/src/test/java/org/orekit/time/LazyLoadedTimeScalesTest.java +++ b/src/test/java/org/orekit/time/LazyLoadedTimeScalesTest.java @@ -1,3 +1,20 @@ +/* Copyright 2002-2024 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.orekit.time; import org.junit.jupiter.api.Assertions; diff --git a/src/test/java/org/orekit/time/TimeStampedDoubleHermiteInterpolatorTest.java b/src/test/java/org/orekit/time/TimeStampedDoubleHermiteInterpolatorTest.java index 0cd89665fc..0069efecb8 100644 --- a/src/test/java/org/orekit/time/TimeStampedDoubleHermiteInterpolatorTest.java +++ b/src/test/java/org/orekit/time/TimeStampedDoubleHermiteInterpolatorTest.java @@ -1,3 +1,20 @@ +/* Copyright 2002-2024 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.orekit.time; import org.junit.jupiter.api.Assertions; diff --git a/src/test/java/org/orekit/utils/FieldAbsolutePVCoordinatesHermiteInterpolatorTest.java b/src/test/java/org/orekit/utils/FieldAbsolutePVCoordinatesHermiteInterpolatorTest.java index 0a35645f54..31eb93bcdf 100644 --- a/src/test/java/org/orekit/utils/FieldAbsolutePVCoordinatesHermiteInterpolatorTest.java +++ b/src/test/java/org/orekit/utils/FieldAbsolutePVCoordinatesHermiteInterpolatorTest.java @@ -1,3 +1,20 @@ +/* Copyright 2002-2024 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.orekit.utils; import org.hipparchus.Field; diff --git a/src/test/java/org/orekit/utils/FieldifierTest.java b/src/test/java/org/orekit/utils/FieldifierTest.java index 0ee70c32e3..262b8be9fd 100644 --- a/src/test/java/org/orekit/utils/FieldifierTest.java +++ b/src/test/java/org/orekit/utils/FieldifierTest.java @@ -1,3 +1,20 @@ +/* Copyright 2002-2024 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.orekit.utils; import org.hipparchus.Field; diff --git a/src/test/java/org/orekit/utils/TimeStampedAngularCoordinatesHermiteInterpolatorTest.java b/src/test/java/org/orekit/utils/TimeStampedAngularCoordinatesHermiteInterpolatorTest.java index 60be21f480..6aaa5a13a9 100644 --- a/src/test/java/org/orekit/utils/TimeStampedAngularCoordinatesHermiteInterpolatorTest.java +++ b/src/test/java/org/orekit/utils/TimeStampedAngularCoordinatesHermiteInterpolatorTest.java @@ -1,3 +1,20 @@ +/* Copyright 2002-2024 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.orekit.utils; import org.hamcrest.MatcherAssert; diff --git a/src/test/java/org/orekit/utils/TimeStampedFieldAngularCoordinatesHermiteInterpolatorTest.java b/src/test/java/org/orekit/utils/TimeStampedFieldAngularCoordinatesHermiteInterpolatorTest.java index 17b5b4282a..556d899361 100644 --- a/src/test/java/org/orekit/utils/TimeStampedFieldAngularCoordinatesHermiteInterpolatorTest.java +++ b/src/test/java/org/orekit/utils/TimeStampedFieldAngularCoordinatesHermiteInterpolatorTest.java @@ -1,3 +1,20 @@ +/* Copyright 2002-2024 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.orekit.utils; import org.hamcrest.MatcherAssert; diff --git a/src/test/java/org/orekit/utils/TimeStampedFieldPVCoordinatesHermiteInterpolatorTest.java b/src/test/java/org/orekit/utils/TimeStampedFieldPVCoordinatesHermiteInterpolatorTest.java index 1f51b7d3ba..16d8c9f3ec 100644 --- a/src/test/java/org/orekit/utils/TimeStampedFieldPVCoordinatesHermiteInterpolatorTest.java +++ b/src/test/java/org/orekit/utils/TimeStampedFieldPVCoordinatesHermiteInterpolatorTest.java @@ -1,3 +1,20 @@ +/* Copyright 2002-2024 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.orekit.utils; import org.hipparchus.Field; diff --git a/src/test/java/org/orekit/utils/TimeStampedPVCoordinatesHermiteInterpolatorTest.java b/src/test/java/org/orekit/utils/TimeStampedPVCoordinatesHermiteInterpolatorTest.java index 7851a9e466..3a9501b755 100644 --- a/src/test/java/org/orekit/utils/TimeStampedPVCoordinatesHermiteInterpolatorTest.java +++ b/src/test/java/org/orekit/utils/TimeStampedPVCoordinatesHermiteInterpolatorTest.java @@ -1,3 +1,20 @@ +/* Copyright 2002-2024 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.orekit.utils; import org.hipparchus.analysis.polynomials.PolynomialFunction; From 742c1f9ae3b2d75abdfc77e5bb729dd4b4e84e92 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Fri, 23 Feb 2024 11:40:22 +0100 Subject: [PATCH 139/359] Added TimeStampedDoubleAndDerivative and interpolator. --- src/changes/changes.xml | 3 + .../time/TimeStampedDoubleAndDerivative.java | 50 +++++++ ...oubleAndDerivativeHermiteInterpolator.java | 94 +++++++++++++ ...eAndDerivativeHermiteInterpolatorTest.java | 130 ++++++++++++++++++ 4 files changed, 277 insertions(+) create mode 100644 src/main/java/org/orekit/time/TimeStampedDoubleAndDerivative.java create mode 100644 src/main/java/org/orekit/time/TimeStampedDoubleAndDerivativeHermiteInterpolator.java create mode 100644 src/test/java/org/orekit/time/TimeStampedDoubleAndDerivativeHermiteInterpolatorTest.java diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 2ab98bba98..38110a455c 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -21,6 +21,9 @@ + + Added TimeStampedDoubleAndDerivative and associated interpolator. + Allow direction-dependent phase centers in inter-satellites measurements. diff --git a/src/main/java/org/orekit/time/TimeStampedDoubleAndDerivative.java b/src/main/java/org/orekit/time/TimeStampedDoubleAndDerivative.java new file mode 100644 index 0000000000..33c5bb5f1a --- /dev/null +++ b/src/main/java/org/orekit/time/TimeStampedDoubleAndDerivative.java @@ -0,0 +1,50 @@ +/* Copyright 2002-2024 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.time; + +/** + * Class that associates a double, its time derivative with a date. + * + * @author Luc Maisonobe + * @since 12.1 + */ +public class TimeStampedDoubleAndDerivative extends TimeStampedDouble { + + /** Time derivative. */ + private final double derivative; + + /** + * Constructor. + * + * @param value value + * @param derivative time derivative + * @param date date associated to value + */ + public TimeStampedDoubleAndDerivative(final double value, final double derivative, + final AbsoluteDate date) { + super(value, date); + this.derivative = derivative; + } + + /** Get time derivative. + * @return time derivztive + */ + public double getDerivative() { + return derivative; + } + +} diff --git a/src/main/java/org/orekit/time/TimeStampedDoubleAndDerivativeHermiteInterpolator.java b/src/main/java/org/orekit/time/TimeStampedDoubleAndDerivativeHermiteInterpolator.java new file mode 100644 index 0000000000..8a0772627b --- /dev/null +++ b/src/main/java/org/orekit/time/TimeStampedDoubleAndDerivativeHermiteInterpolator.java @@ -0,0 +1,94 @@ +/* Copyright 2002-2024 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.time; + +import org.hipparchus.analysis.interpolation.HermiteInterpolator; + +import java.util.List; + +/** + * Hermite interpolator of time stamped double value. + * + * @author Vincent Cucchietti + * @author Luc Maisonobe + * @see HermiteInterpolator + * @see TimeInterpolator + */ +public class TimeStampedDoubleAndDerivativeHermiteInterpolator + extends AbstractTimeInterpolator { + + /** + * Constructor with : + *
                    + *
                  • Default number of interpolation points of {@code DEFAULT_INTERPOLATION_POINTS}
                  • + *
                  • Default extrapolation threshold value ({@code DEFAULT_EXTRAPOLATION_THRESHOLD_SEC} s)
                  • + *
                  + * As this implementation of interpolation is polynomial, it should be used only with small number of interpolation + * points (about 10-20 points) in order to avoid Runge's + * phenomenon and numerical problems (including NaN appearing). + */ + public TimeStampedDoubleAndDerivativeHermiteInterpolator() { + this(DEFAULT_INTERPOLATION_POINTS); + } + + /** + * Constructor with default extrapolation threshold value ({@code DEFAULT_EXTRAPOLATION_THRESHOLD_SEC} s). + *

                  + * As this implementation of interpolation is polynomial, it should be used only with small number of interpolation + * points (about 10-20 points) in order to avoid Runge's + * phenomenon and numerical problems (including NaN appearing). + * + * @param interpolationPoints number of interpolation points + */ + public TimeStampedDoubleAndDerivativeHermiteInterpolator(final int interpolationPoints) { + this(interpolationPoints, DEFAULT_EXTRAPOLATION_THRESHOLD_SEC); + } + + /** + * Constructor. + *

                  + * As this implementation of interpolation is polynomial, it should be used only with small number of interpolation + * points (about 10-20 points) in order to avoid Runge's + * phenomenon and numerical problems (including NaN appearing). + * + * @param interpolationPoints number of interpolation points + * @param extrapolationThreshold extrapolation threshold beyond which the propagation will fail + */ + public TimeStampedDoubleAndDerivativeHermiteInterpolator(final int interpolationPoints, final double extrapolationThreshold) { + super(interpolationPoints, extrapolationThreshold); + } + + /** {@inheritDoc} */ + @Override + protected TimeStampedDoubleAndDerivative interpolate(final InterpolationData interpolationData) { + final HermiteInterpolator interpolator = new HermiteInterpolator(); + + // Fill interpolator with sample + final AbsoluteDate interpolationDate = interpolationData.getInterpolationDate(); + final List neighborList = interpolationData.getNeighborList(); + for (TimeStampedDoubleAndDerivative value : neighborList) { + final double deltaT = value.getDate().durationFrom(interpolationDate); + interpolator.addSamplePoint(deltaT, + new double[] { value.getValue() }, + new double[] { value.getDerivative() }); + } + + final double[][] y = interpolator.derivatives(0, 1); + return new TimeStampedDoubleAndDerivative(y[0][0], y[1][0], interpolationDate); + } + +} diff --git a/src/test/java/org/orekit/time/TimeStampedDoubleAndDerivativeHermiteInterpolatorTest.java b/src/test/java/org/orekit/time/TimeStampedDoubleAndDerivativeHermiteInterpolatorTest.java new file mode 100644 index 0000000000..4137b72be6 --- /dev/null +++ b/src/test/java/org/orekit/time/TimeStampedDoubleAndDerivativeHermiteInterpolatorTest.java @@ -0,0 +1,130 @@ +/* Copyright 2002-2024 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.orekit.time; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.RepeatedTest; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.DoubleAccumulator; + +class TimeStampedDoubleAndDerivativeAndDerivativeHermiteInterpolatorTest { + + @Test + @DisplayName("Test default constructor") + void testDefaultConstructor() { + // When + final TimeStampedDoubleAndDerivativeHermiteInterpolator interpolator = new TimeStampedDoubleAndDerivativeHermiteInterpolator(); + + // Then + Assertions.assertEquals(AbstractTimeInterpolator.DEFAULT_INTERPOLATION_POINTS, + interpolator.getNbInterpolationPoints()); + Assertions.assertEquals(AbstractTimeInterpolator.DEFAULT_EXTRAPOLATION_THRESHOLD_SEC, + interpolator.getExtrapolationThreshold()); + } + + @RepeatedTest(10) + @DisplayName("test interpolator in multi-threaded environment") + void testIssue1164() throws InterruptedException { + // GIVEN + // Create interpolator + final TimeInterpolator interpolator = new TimeStampedDoubleAndDerivativeHermiteInterpolator(); + + // Create sample and interpolation dates + final int sampleSize = 100; + final AbsoluteDate initialDate = new AbsoluteDate(); + final List sample = new ArrayList<>(); + final List dates = new ArrayList<>(); + for (int i = 1; i < sampleSize + 1; i++) { + sample.add(new TimeStampedDoubleAndDerivative(i * i, i / 30.0, + initialDate.shiftedBy(i * 60))); + dates.add(initialDate.shiftedBy(i * 60)); + } + + // Create multithreading environment + ExecutorService service = Executors.newFixedThreadPool(sampleSize); + + final DoubleAccumulator sum0 = new DoubleAccumulator(Double::sum, 0.0); + final DoubleAccumulator sum1 = new DoubleAccumulator(Double::sum, 0.0); + final List> tasks = new ArrayList<>(); + for (final AbsoluteDate date : dates) { + tasks.add(new ParallelTask(interpolator, sum0, sum1, sample, date)); + } + + // WHEN + service.invokeAll(tasks); + + // THEN + // Sum of 1*1 + 2*2 + 3*3 + ... + // Sum of 1 / 30 + 2 / 30 + ... + final double expectedSum0 = sampleSize * (sampleSize + 1) * (2 * sampleSize + 1) / 6.0; + final double expectedSum1 = sampleSize * (sampleSize + 1) / 60.0; + try { + // wait for proper ending + service.shutdown(); + Assertions.assertTrue(service.awaitTermination(5, TimeUnit.SECONDS)); + } catch (InterruptedException ie) { + // Restore interrupted state... + Thread.currentThread().interrupt(); + } + Assertions.assertEquals(expectedSum0, sum0.get(), 1.0e-12); + Assertions.assertEquals(expectedSum1, sum1.get(), 1.0e-12); + } + + /** Custom class for multi threading testing purpose */ + private static class ParallelTask implements Callable { + + private final TimeInterpolator interpolator; + + private final List sample; + + private final DoubleAccumulator sum0; + + private final DoubleAccumulator sum1; + + private final AbsoluteDate interpolationDate; + + private ParallelTask(final TimeInterpolator interpolator, + final DoubleAccumulator sum0, final DoubleAccumulator sum1, + final List sample, + final AbsoluteDate interpolationDate) { + // Store interpolator + this.interpolator = interpolator; + this.sum0 = sum0; + this.sum1 = sum1; + this.interpolationDate = interpolationDate; + this.sample = sample; + } + + @Override + public Integer call() { + // Add result to sums + final TimeStampedDoubleAndDerivative interpolated = interpolator.interpolate(interpolationDate, sample); + sum0.accumulate(interpolated.getValue()); + sum1.accumulate(interpolated.getDerivative()); + return 1; + } + } +} From 47c6352ecba2e4821bdac6d75462bac69a8e2df5 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Fri, 23 Feb 2024 14:59:11 +0100 Subject: [PATCH 140/359] Manage clock offset as an additional state in propagators built from SP3 files. Fiwes #1329 --- src/changes/changes.xml | 3 + .../java/org/orekit/files/sp3/SP3Parser.java | 34 +++++- .../java/org/orekit/files/sp3/SP3Segment.java | 109 +++++++++++++++++- .../java/org/orekit/files/sp3/SP3Utils.java | 5 + .../org/orekit/files/sp3/SP3ParserTest.java | 37 +++++- 5 files changed, 175 insertions(+), 13 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 38110a455c..8a8a8e7d8f 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -21,6 +21,9 @@ + + Manage clock offset as an additional state in propagators built from SP3 files. + Added TimeStampedDoubleAndDerivative and associated interpolator. diff --git a/src/main/java/org/orekit/files/sp3/SP3Parser.java b/src/main/java/org/orekit/files/sp3/SP3Parser.java index 0bad1d5fdb..d7d237a10d 100644 --- a/src/main/java/org/orekit/files/sp3/SP3Parser.java +++ b/src/main/java/org/orekit/files/sp3/SP3Parser.java @@ -26,6 +26,7 @@ import java.util.Locale; import java.util.Scanner; import java.util.function.Function; +import java.util.regex.Matcher; import java.util.regex.Pattern; import org.hipparchus.exception.LocalizedCoreFormats; @@ -39,6 +40,8 @@ import org.orekit.errors.OrekitMessages; import org.orekit.files.general.EphemerisFileParser; import org.orekit.frames.Frame; +import org.orekit.frames.ITRFVersion; +import org.orekit.frames.LazyLoadedFrames; import org.orekit.gnss.TimeSystem; import org.orekit.time.AbsoluteDate; import org.orekit.time.DateComponents; @@ -67,6 +70,9 @@ public class SP3Parser implements EphemerisFileParser { /** String representation of the center of ephemeris coordinate system. **/ public static final String SP3_FRAME_CENTER_STRING = "EARTH"; + /** Pattern for frame names with year. */ + private static final Pattern FRAME_WITH_YEAR = Pattern.compile("(?:(?:ITR)|(?:IGS)|(?:SLR))([0-9]{2})"); + /** Spaces delimiters. */ private static final String SPACES = "\\s+"; @@ -143,16 +149,34 @@ public SP3Parser(final double mu, /** * Default string to {@link Frame} conversion for {@link #SP3Parser()}. * - *

                  This method uses the {@link DataContext#getDefault() default data context}. + *

                  + * This method uses the {@link DataContext#getDefault() default data context}. + * If the frame names has a form like IGS##, or ITR##, or SLR##, where ## + * is a two digits number, then this number will be used to build the + * appropriate {@link ITRFVersion}. Otherwise (for example if name is + * UNDEF or WGS84), then a default {@link + * org.orekit.frames.Frames#getITRF(IERSConventions, boolean) ITRF} + * will be created. + *

                  * * @param name of the frame. * @return ITRF based on 2010 conventions, - * with tidal effects considered during EOP interpolation. + * with tidal effects considered during EOP interpolation */ @DefaultDataContext - private static Frame guessFrame(final String name) { - return DataContext.getDefault().getFrames() - .getITRF(IERSConventions.IERS_2010, false); + public static Frame guessFrame(final String name) { + final LazyLoadedFrames frames = DataContext.getDefault().getFrames(); + final Matcher matcher = FRAME_WITH_YEAR.matcher(name); + if (matcher.matches()) { + // this is a frame of the form IGS14, or ITR20, or SLR08, or similar + final int yy = Integer.parseInt(matcher.group(1)); + return frames.getITRF(ITRFVersion.getITRFVersion(yy), + IERSConventions.IERS_2010, false); + } else { + // unkonwn frame 'maybe UNDEF or WGS84 + // we use a default ITRF + return frames.getITRF(IERSConventions.IERS_2010, false); + } } @Override diff --git a/src/main/java/org/orekit/files/sp3/SP3Segment.java b/src/main/java/org/orekit/files/sp3/SP3Segment.java index cfd73070e8..d463314762 100644 --- a/src/main/java/org/orekit/files/sp3/SP3Segment.java +++ b/src/main/java/org/orekit/files/sp3/SP3Segment.java @@ -19,13 +19,19 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.orekit.attitudes.AttitudeProvider; import org.orekit.files.general.EphemerisFile; import org.orekit.frames.Frame; +import org.orekit.propagation.AdditionalStateProvider; import org.orekit.propagation.BoundedPropagator; -import org.orekit.time.AbsoluteDate; +import org.orekit.propagation.SpacecraftState; +import org.orekit.time.*; +import org.orekit.time.AbstractTimeInterpolator.InterpolationData; import org.orekit.utils.CartesianDerivativesFilter; +import org.orekit.utils.SortedListTrimmer; /** One segment of an {@link SP3Ephemeris}. * @author Thomas Neidhart @@ -118,13 +124,110 @@ public void addCoordinate(final SP3Coordinate coord) { /** {@inheritDoc} */ @Override public BoundedPropagator getPropagator() { - return EphemerisFile.EphemerisSegment.super.getPropagator(); + return addClockManagement(EphemerisFile.EphemerisSegment.super.getPropagator()); } /** {@inheritDoc} */ @Override public BoundedPropagator getPropagator(final AttitudeProvider attitudeProvider) { - return EphemerisFile.EphemerisSegment.super.getPropagator(attitudeProvider); + return addClockManagement(EphemerisFile.EphemerisSegment.super.getPropagator(attitudeProvider)); + } + + /** Add clock management to a propagator. + * @return propagator raw propagator + * @return propagator with managed clock + * @since 12.1 + */ + private BoundedPropagator addClockManagement(final BoundedPropagator propagator) { + final AdditionalStateProvider provider = null; + propagator.addAdditionalStateProvider(filter.getMaxOrder() > 0 ? + new ClockProviderOrder1() : + new ClockProviderOrder0()); + return propagator; + } + + /** Additional provider for clock without derivatives. + * @since 12.1 + */ + private class ClockProviderOrder0 implements AdditionalStateProvider { + + /** Interpolator for clock. */ + private final TimeStampedDoubleHermiteInterpolator interpolator; + + /** Trimmer for coordinates list. */ + private final SortedListTrimmer trimmer; + + /** Simple constructor. + */ + ClockProviderOrder0() { + // we don't use SP3CoordinateHermiteInterpolator + // because the underlying propagator already has interpolated position + // we only interpolate the additional state here + interpolator = new TimeStampedDoubleHermiteInterpolator(getInterpolationSamples()); + trimmer = new SortedListTrimmer(getInterpolationSamples()); + } + + /** {@inheritDoc} */ + @Override + public String getName() { + return SP3Utils.CLOCK_ADDITIONAL_STATE; + } + + /** {@inheritDoc} */ + @Override + public double[] getAdditionalState(final SpacecraftState state) { + final Stream sample = + trimmer. + getNeighborsSubList(state.getDate(), coordinates). + stream(). + map(c -> new TimeStampedDouble(c.getClockCorrection(), c.getDate())); + final TimeStampedDouble interpolated = + interpolator.interpolate(state.getDate(), sample); + return new double[] { interpolated.getValue() }; + } + } + + /** Additional provider for clock with derivatives. + * @since 12.1 + */ + private class ClockProviderOrder1 implements AdditionalStateProvider { + + /** Interpolator for clock. */ + private final TimeStampedDoubleAndDerivativeHermiteInterpolator interpolator; + + /** Trimmer for coordinates list. */ + private final SortedListTrimmer trimmer; + + /** Simple constructor. + */ + ClockProviderOrder1() { + // we don't use SP3CoordinateHermiteInterpolator + // because the underlying propagator already has interpolated position + // we only interpolate the additional state here + interpolator = new TimeStampedDoubleAndDerivativeHermiteInterpolator(getInterpolationSamples()); + trimmer = new SortedListTrimmer(getInterpolationSamples()); + } + + /** {@inheritDoc} */ + @Override + public String getName() { + return SP3Utils.CLOCK_ADDITIONAL_STATE; + } + + /** {@inheritDoc} */ + @Override + public double[] getAdditionalState(final SpacecraftState state) { + final Stream sample = + trimmer. + getNeighborsSubList(state.getDate(), coordinates). + stream(). + map(c -> new TimeStampedDoubleAndDerivative(c.getClockCorrection(), + c.getClockRateChange(), + c.getDate())); + final TimeStampedDoubleAndDerivative interpolated = + interpolator.interpolate(state.getDate(), sample); + return new double[] { interpolated.getValue() }; + } } } diff --git a/src/main/java/org/orekit/files/sp3/SP3Utils.java b/src/main/java/org/orekit/files/sp3/SP3Utils.java index f77d735824..608c4c6969 100644 --- a/src/main/java/org/orekit/files/sp3/SP3Utils.java +++ b/src/main/java/org/orekit/files/sp3/SP3Utils.java @@ -46,6 +46,11 @@ public class SP3Utils { /** Velocity accuracy unit. */ public static final Unit VELOCITY_ACCURACY_UNIT = Unit.parse("mm/s").scale("10⁻⁴mm/s", 1.0e-4); + /** Additional state name for clock. + * @since 12.1 + */ + public static final String CLOCK_ADDITIONAL_STATE = "clock"; + /** Clock unit. */ public static final Unit CLOCK_UNIT = Unit.parse("µs"); diff --git a/src/test/java/org/orekit/files/sp3/SP3ParserTest.java b/src/test/java/org/orekit/files/sp3/SP3ParserTest.java index 16c24cf650..690675706c 100644 --- a/src/test/java/org/orekit/files/sp3/SP3ParserTest.java +++ b/src/test/java/org/orekit/files/sp3/SP3ParserTest.java @@ -38,6 +38,7 @@ import org.orekit.frames.Predefined; import org.orekit.gnss.TimeSystem; import org.orekit.propagation.BoundedPropagator; +import org.orekit.propagation.SpacecraftState; import org.orekit.time.AbsoluteDate; import org.orekit.time.TimeScale; import org.orekit.time.TimeScalesFactory; @@ -227,9 +228,10 @@ public void testParseSP3d1() throws IOException { @Test public void testParseSP3d2() throws IOException { // simple test for version sp3-c, contains p/v entries and correlations - final String ex = "/sp3/example-d-2.sp3"; + final String ex = "/sp3/example-d-2.sp3"; final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex)); - final SP3 file = new SP3Parser().parse(source); + final SP3 file = new SP3Parser(Constants.EIGEN5C_EARTH_MU, 1, SP3Parser::guessFrame). + parse(source); Assertions.assertEquals('d', file.getHeader().getVersion()); Assertions.assertEquals(SP3OrbitType.HLM, file.getHeader().getOrbitType()); @@ -273,6 +275,19 @@ public void testParseSP3d2() throws IOException { Assertions.assertFalse(coords2.get(0).hasOrbitManeuverEvent()); Assertions.assertTrue(coords2.get(0).hasOrbitPrediction()); + final BoundedPropagator propagator = file.getEphemeris("G01").getPropagator(); + final SpacecraftState s = propagator.propagate(coord.getDate()); + final Frame frame = file.getSatellites().get("G01").getFrame(); + Assertions.assertEquals(0.0, + Vector3D.distance(coord.getPosition(), s.getPVCoordinates(frame).getPosition()), + 2.4e-8); + Assertions.assertEquals(0.0, + Vector3D.distance(coord.getVelocity(), s.getPVCoordinates(frame).getVelocity()), + 2.1e-12); + Assertions.assertEquals(coord.getClockCorrection(), + s.getAdditionalState(SP3Utils.CLOCK_ADDITIONAL_STATE)[0], + 1.0e-18); + } @Test @@ -323,20 +338,32 @@ public void testSP3Propagator() throws Exception { Assertions.assertEquals(propagator.getMinDate(), new AbsoluteDate(2015, 5, 5, gps)); Assertions.assertEquals(propagator.getMaxDate(), new AbsoluteDate(2015, 5, 5, 23, 55, 0, gps)); SP3Coordinate expected = ephemeris.getSegments().get(0).getCoordinates().get(0); + SpacecraftState s = propagator.propagate(propagator.getMinDate()); Assertions.assertEquals(0.0, - Vector3D.distance(propagator.getPVCoordinates(propagator.getMinDate(), frame).getPosition(), + Vector3D.distance(s.getPVCoordinates(frame).getPosition(), expected.getPosition()), 3.0e-8); + Assertions.assertEquals(expected.getClockCorrection(), + s.getAdditionalState(SP3Utils.CLOCK_ADDITIONAL_STATE)[0], + 1.0e-15); expected = ephemeris.getSegments().get(0).getCoordinates().get(1); + s = propagator.propagate(expected.getDate()); Assertions.assertEquals(0.0, - Vector3D.distance(propagator.getPVCoordinates(expected.getDate(), frame).getPosition(), + Vector3D.distance(s.getPVCoordinates(frame).getPosition(), expected.getPosition()), 3.0e-8); + Assertions.assertEquals(expected.getClockCorrection(), + s.getAdditionalState(SP3Utils.CLOCK_ADDITIONAL_STATE)[0], + 1.0e-15); expected = ephemeris.getSegments().get(0).getCoordinates().get(ephemeris.getSegments().get(0).getCoordinates().size() - 1); + s = propagator.propagate(propagator.getMaxDate()); Assertions.assertEquals(0.0, - Vector3D.distance(propagator.getPVCoordinates(propagator.getMaxDate(), frame).getPosition(), + Vector3D.distance(s.getPVCoordinates(frame).getPosition(), expected.getPosition()), 3.0e-8); + Assertions.assertEquals(expected.getClockCorrection(), + s.getAdditionalState(SP3Utils.CLOCK_ADDITIONAL_STATE)[0], + 1.0e-15); ephemeris = file.getSatellites().get("E19"); propagator = ephemeris.getPropagator(new FrameAlignedProvider(ephemeris.getFrame())); From e20cb38f36a0d30982f784d2bc40488c0ecd9c0a Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Fri, 23 Feb 2024 15:07:26 +0100 Subject: [PATCH 141/359] Manage clock offset as an additional state in propagators built from SP3 files. Fixes #1329 --- .../java/org/orekit/files/sp3/SP3Parser.java | 32 ++++++++-------- .../java/org/orekit/files/sp3/SP3Segment.java | 13 ++++--- .../org/orekit/files/sp3/SP3ParserTest.java | 38 +++++++++---------- 3 files changed, 42 insertions(+), 41 deletions(-) diff --git a/src/main/java/org/orekit/files/sp3/SP3Parser.java b/src/main/java/org/orekit/files/sp3/SP3Parser.java index d7d237a10d..bea105c44e 100644 --- a/src/main/java/org/orekit/files/sp3/SP3Parser.java +++ b/src/main/java/org/orekit/files/sp3/SP3Parser.java @@ -71,7 +71,7 @@ public class SP3Parser implements EphemerisFileParser { public static final String SP3_FRAME_CENTER_STRING = "EARTH"; /** Pattern for frame names with year. */ - private static final Pattern FRAME_WITH_YEAR = Pattern.compile("(?:(?:ITR)|(?:IGS)|(?:SLR))([0-9]{2})"); + private static final Pattern FRAME_WITH_YEAR = Pattern.compile("(?:ITR|IGS|SLR)([0-9]{2})"); /** Spaces delimiters. */ private static final String SPACES = "\\s+"; @@ -245,7 +245,7 @@ private class ParseInfo { private final TimeScales timeScales; /** The corresponding SP3File object. */ - private SP3 file; + private final SP3 file; /** The latest epoch as read from the SP3 file. */ private AbsoluteDate latestEpoch; @@ -429,7 +429,7 @@ public void parse(final String line, final ParseInfo pi) { int startIdx = 9; while (count++ < pi.maxSatellites && (startIdx + 3) <= lineLength) { final String satId = line.substring(startIdx, startIdx + 3).trim(); - if (satId.length() > 0) { + if (!satId.isEmpty()) { pi.file.addSatellite(satId); } startIdx += 3; @@ -454,7 +454,7 @@ public void parse(final String line, final ParseInfo pi) { int startIdx = 9; while (pi.nbAccuracies < pi.maxSatellites && (startIdx + 3) <= lineLength) { final String sub = line.substring(startIdx, startIdx + 3).trim(); - if (sub.length() > 0) { + if (!sub.isEmpty()) { final int exponent = Integer.parseInt(sub); // the accuracy is calculated as 2**exp (in mm) pi.file.getHeader().setAccuracy(pi.nbAccuracies++, @@ -730,9 +730,9 @@ public void parse(final String line, final ParseInfo pi) { if (pi.latestPosition.getNorm() > 0) { if (line.length() < 69 || - line.substring(61, 63).trim().length() == 0 || - line.substring(64, 66).trim().length() == 0 || - line.substring(67, 69).trim().length() == 0) { + line.substring(61, 63).trim().isEmpty() || + line.substring(64, 66).trim().isEmpty() || + line.substring(67, 69).trim().isEmpty()) { pi.latestPositionAccuracy = null; } else { pi.latestPositionAccuracy = new Vector3D(SP3Utils.siAccuracy(SP3Utils.POSITION_ACCURACY_UNIT, @@ -746,7 +746,7 @@ public void parse(final String line, final ParseInfo pi) { Integer.parseInt(line.substring(67, 69).trim()))); } - if (line.length() < 73 || line.substring(70, 73).trim().length() == 0) { + if (line.length() < 73 || line.substring(70, 73).trim().isEmpty()) { pi.latestClockAccuracy = Double.NaN; } else { pi.latestClockAccuracy = SP3Utils.siAccuracy(SP3Utils.CLOCK_ACCURACY_UNIT, @@ -754,10 +754,10 @@ public void parse(final String line, final ParseInfo pi) { Integer.parseInt(line.substring(70, 73).trim())); } - pi.latestClockEvent = line.length() < 75 ? false : line.substring(74, 75).equals("E"); - pi.latestClockPrediction = line.length() < 76 ? false : line.substring(75, 76).equals("P"); - pi.latestOrbitManeuverEvent = line.length() < 79 ? false : line.substring(78, 79).equals("M"); - pi.latestOrbitPrediction = line.length() < 80 ? false : line.substring(79, 80).equals("P"); + pi.latestClockEvent = line.length() >= 75 && line.charAt(74) == 'E'; + pi.latestClockPrediction = line.length() >= 76 && line.charAt(75) == 'P'; + pi.latestOrbitManeuverEvent = line.length() >= 79 && line.charAt(78) == 'M'; + pi.latestOrbitPrediction = line.length() >= 80 && line.charAt(79) == 'P'; if (!pi.hasVelocityEntries) { final SP3Coordinate coord = @@ -823,9 +823,9 @@ public void parse(final String line, final ParseInfo pi) { final Vector3D velocityAccuracy; if (line.length() < 69 || - line.substring(61, 63).trim().length() == 0 || - line.substring(64, 66).trim().length() == 0 || - line.substring(67, 69).trim().length() == 0) { + line.substring(61, 63).trim().isEmpty() || + line.substring(64, 66).trim().isEmpty() || + line.substring(67, 69).trim().isEmpty()) { velocityAccuracy = null; } else { velocityAccuracy = new Vector3D(SP3Utils.siAccuracy(SP3Utils.VELOCITY_ACCURACY_UNIT, @@ -840,7 +840,7 @@ public void parse(final String line, final ParseInfo pi) { } final double clockRateAccuracy; - if (line.length() < 73 || line.substring(70, 73).trim().length() == 0) { + if (line.length() < 73 || line.substring(70, 73).trim().isEmpty()) { clockRateAccuracy = Double.NaN; } else { clockRateAccuracy = SP3Utils.siAccuracy(SP3Utils.CLOCK_RATE_ACCURACY_UNIT, diff --git a/src/main/java/org/orekit/files/sp3/SP3Segment.java b/src/main/java/org/orekit/files/sp3/SP3Segment.java index d463314762..4549f1e2e0 100644 --- a/src/main/java/org/orekit/files/sp3/SP3Segment.java +++ b/src/main/java/org/orekit/files/sp3/SP3Segment.java @@ -19,7 +19,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.stream.Collectors; import java.util.stream.Stream; import org.orekit.attitudes.AttitudeProvider; @@ -28,8 +27,11 @@ import org.orekit.propagation.AdditionalStateProvider; import org.orekit.propagation.BoundedPropagator; import org.orekit.propagation.SpacecraftState; -import org.orekit.time.*; -import org.orekit.time.AbstractTimeInterpolator.InterpolationData; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.TimeStampedDouble; +import org.orekit.time.TimeStampedDoubleAndDerivative; +import org.orekit.time.TimeStampedDoubleAndDerivativeHermiteInterpolator; +import org.orekit.time.TimeStampedDoubleHermiteInterpolator; import org.orekit.utils.CartesianDerivativesFilter; import org.orekit.utils.SortedListTrimmer; @@ -134,12 +136,10 @@ public BoundedPropagator getPropagator(final AttitudeProvider attitudeProvider) } /** Add clock management to a propagator. - * @return propagator raw propagator * @return propagator with managed clock * @since 12.1 */ private BoundedPropagator addClockManagement(final BoundedPropagator propagator) { - final AdditionalStateProvider provider = null; propagator.addAdditionalStateProvider(filter.getMaxOrder() > 0 ? new ClockProviderOrder1() : new ClockProviderOrder0()); @@ -193,7 +193,8 @@ public double[] getAdditionalState(final SpacecraftState state) { private class ClockProviderOrder1 implements AdditionalStateProvider { /** Interpolator for clock. */ - private final TimeStampedDoubleAndDerivativeHermiteInterpolator interpolator; + private final TimeStampedDoubleAndDerivativeHermiteInterpolator + interpolator; /** Trimmer for coordinates list. */ private final SortedListTrimmer trimmer; diff --git a/src/test/java/org/orekit/files/sp3/SP3ParserTest.java b/src/test/java/org/orekit/files/sp3/SP3ParserTest.java index 690675706c..75f7993709 100644 --- a/src/test/java/org/orekit/files/sp3/SP3ParserTest.java +++ b/src/test/java/org/orekit/files/sp3/SP3ParserTest.java @@ -50,7 +50,7 @@ public class SP3ParserTest { @Test - public void testParseSP3a1() throws IOException, URISyntaxException { + public void testParseSP3a1() { // simple test for version sp3-a, only contains position entries final String ex = "/sp3/example-a-1.sp3"; final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex)); @@ -95,7 +95,7 @@ public void testParseSP3a1() throws IOException, URISyntaxException { } @Test - public void testParseSP3a2() throws IOException { + public void testParseSP3a2() { // simple test for version sp3-a, contains p/v entries final String ex = "/sp3/example-a-2.sp3"; final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex)); @@ -127,7 +127,7 @@ public void testParseSP3a2() throws IOException { } @Test - public void testParseSP3c1() throws IOException { + public void testParseSP3c1() { // simple test for version sp3-c, contains p entries final String ex = "/sp3/example-c-1.sp3"; final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex)); @@ -157,7 +157,7 @@ public void testParseSP3c1() throws IOException { } @Test - public void testParseSP3c2() throws IOException { + public void testParseSP3c2() { // simple test for version sp3-c, contains p/v entries and correlations final String ex = "/sp3/example-c-2.sp3"; final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex)); @@ -189,7 +189,7 @@ public void testParseSP3c2() throws IOException { } @Test - public void testParseSP3d1() throws IOException { + public void testParseSP3d1() { // simple test for version sp3-d, contains p entries final String ex = "/sp3/example-d-1.sp3"; final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex)); @@ -226,7 +226,7 @@ public void testParseSP3d1() throws IOException { } @Test - public void testParseSP3d2() throws IOException { + public void testParseSP3d2() { // simple test for version sp3-c, contains p/v entries and correlations final String ex = "/sp3/example-d-2.sp3"; final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex)); @@ -291,7 +291,7 @@ public void testParseSP3d2() throws IOException { } @Test - public void testSP3GFZ() throws IOException { + public void testSP3GFZ() { // simple test for version sp3-c, contains more than 85 satellites final String ex = "/sp3/gbm19500_truncated.sp3"; final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex)); @@ -319,7 +319,7 @@ public void testSP3GFZ() throws IOException { } @Test - public void testSP3Propagator() throws Exception { + public void testSP3Propagator() { // setup final String ex = "/sp3/gbm18432.sp3.Z"; final DataSource compressed = new DataSource(ex, () -> getClass().getResourceAsStream(ex)); @@ -387,7 +387,7 @@ public void testSP3Propagator() throws Exception { } @Test - public void testSP3Compressed() throws IOException { + public void testSP3Compressed() { final String ex = "/sp3/gbm18432.sp3.Z"; final SP3Parser parser = new SP3Parser(); @@ -438,7 +438,7 @@ private void checkPVEntry(final PVCoordinates expected, final PVCoordinates actu } @Test - public void testTruncatedLine() throws IOException { + public void testTruncatedLine() { try { final String ex = "/sp3/truncated-line.sp3"; final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex)); @@ -455,7 +455,7 @@ public void testTruncatedLine() throws IOException { } @Test - public void testMissingEOF() throws IOException { + public void testMissingEOF() { final String ex = "/sp3/missing-eof.sp3"; try { final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex)); @@ -473,7 +473,7 @@ public void testMissingEOF() throws IOException { } @Test - public void testMissingStandardDeviation() throws IOException { + public void testMissingStandardDeviation() { final String ex = "/sp3/missing-standard-deviation.sp3"; final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex)); final Frame frame = FramesFactory.getITRF(IERSConventions.IERS_2003, true); @@ -496,7 +496,7 @@ public void testMissingStandardDeviation() throws IOException { } @Test - public void testWrongLineIdentifier() throws IOException { + public void testWrongLineIdentifier() { try { final String ex = "/sp3/wrong-line-identifier.sp3"; final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex)); @@ -513,7 +513,7 @@ public void testWrongLineIdentifier() throws IOException { } @Test - public void testBHN() throws IOException { + public void testBHN() { final Frame frame = FramesFactory.getITRF(IERSConventions.IERS_2003, true); final SP3Parser parser = new SP3Parser(Constants.EIGEN5C_EARTH_MU, 3, s -> frame); final String ex = "/sp3/esaBHN.sp3.Z"; @@ -525,7 +525,7 @@ public void testBHN() throws IOException { } @Test - public void testPRO() throws IOException { + public void testPRO() { final Frame frame = FramesFactory.getITRF(IERSConventions.IERS_2003, true); final SP3Parser parser = new SP3Parser(Constants.EIGEN5C_EARTH_MU, 3, s -> frame); final String ex = "/sp3/esaPRO.sp3.Z"; @@ -537,7 +537,7 @@ public void testPRO() throws IOException { } @Test - public void testUnknownType() throws IOException { + public void testUnknownType() { final Frame frame = FramesFactory.getITRF(IERSConventions.IERS_2003, true); final SP3Parser parser = new SP3Parser(Constants.EIGEN5C_EARTH_MU, 3, s -> frame); final String ex = "/sp3/unknownType.sp3.Z"; @@ -549,7 +549,7 @@ public void testUnknownType() throws IOException { } @Test - public void testUnsupportedVersion() throws IOException { + public void testUnsupportedVersion() { try { final String ex = "/sp3/unsupported-version.sp3"; final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex)); @@ -566,7 +566,7 @@ public void testUnsupportedVersion() throws IOException { } @Test - public void testWrongNumberOfEpochs() throws IOException { + public void testWrongNumberOfEpochs() { try { final String ex = "/sp3/wrong-number-of-epochs.sp3"; final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex)); @@ -584,7 +584,7 @@ public void testWrongNumberOfEpochs() throws IOException { } @Test - public void testInconsistentSamplingDates() throws IOException { + public void testInconsistentSamplingDates() { try { final String ex = "/sp3/inconsistent-sampling-dates.sp3"; final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex)); From 2fc20fc180884951d5845b672a02e2bfafc519c6 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Fri, 23 Feb 2024 15:07:43 +0100 Subject: [PATCH 142/359] Manage clock offset as an additional state in propagators built from SP3 files. Fixes #1329 --- src/test/java/org/orekit/files/sp3/SP3ParserTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/test/java/org/orekit/files/sp3/SP3ParserTest.java b/src/test/java/org/orekit/files/sp3/SP3ParserTest.java index 75f7993709..23fc903086 100644 --- a/src/test/java/org/orekit/files/sp3/SP3ParserTest.java +++ b/src/test/java/org/orekit/files/sp3/SP3ParserTest.java @@ -16,8 +16,6 @@ */ package org.orekit.files.sp3; -import java.io.IOException; -import java.net.URISyntaxException; import java.util.Arrays; import java.util.List; From ec7e06b699aec8819c481d229380638e2c68b0cb Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Fri, 23 Feb 2024 15:54:08 +0100 Subject: [PATCH 143/359] Removed star imports. --- .../utils/ImmutableFieldTimeStampedCache.java | 6 ++- .../org/orekit/utils/SortedListTrimmer.java | 8 ++- .../attitudes/AttitudesSequenceTest.java | 16 +++++- .../orekit/attitudes/GroundPointingTest.java | 15 ++++-- .../attitudes/LofOffsetPointingTest.java | 9 +++- .../org/orekit/attitudes/LofOffsetTest.java | 6 ++- .../org/orekit/data/AuthenticatorDialog.java | 10 +++- .../measurements/AngularRaDecTest.java | 23 ++++++--- .../modifiers/AberrationModifierTest.java | 6 ++- .../HarmonicAccelerationModelTest.java | 9 ++-- ...HolmesFeatherstoneAttractionModelTest.java | 6 ++- .../maneuvers/FieldImpulseManeuverTest.java | 51 +++++++++++++++---- .../org/orekit/frames/TIRFProviderTest.java | 7 ++- .../orekit/frames/TransformProviderTest.java | 8 ++- .../AggregateBoundedPropagatorTest.java | 11 ++-- .../AbstractGradientConverterTest.java | 10 ++-- .../FieldNumericalPropagatorTest.java | 40 +++++++++++---- 17 files changed, 186 insertions(+), 55 deletions(-) diff --git a/src/main/java/org/orekit/utils/ImmutableFieldTimeStampedCache.java b/src/main/java/org/orekit/utils/ImmutableFieldTimeStampedCache.java index a2bc7f3e6e..ef045f08f5 100644 --- a/src/main/java/org/orekit/utils/ImmutableFieldTimeStampedCache.java +++ b/src/main/java/org/orekit/utils/ImmutableFieldTimeStampedCache.java @@ -25,7 +25,11 @@ import org.hipparchus.CalculusFieldElement; import org.hipparchus.Field; import org.hipparchus.exception.LocalizedCoreFormats; -import org.orekit.errors.*; +import org.orekit.errors.OrekitException; +import org.orekit.errors.OrekitIllegalArgumentException; +import org.orekit.errors.OrekitIllegalStateException; +import org.orekit.errors.OrekitMessages; +import org.orekit.errors.TimeStampedCacheException; import org.orekit.time.FieldAbsoluteDate; import org.orekit.time.FieldChronologicalComparator; import org.orekit.time.FieldTimeStamped; diff --git a/src/main/java/org/orekit/utils/SortedListTrimmer.java b/src/main/java/org/orekit/utils/SortedListTrimmer.java index 1d8ecfe305..0e1f401f48 100644 --- a/src/main/java/org/orekit/utils/SortedListTrimmer.java +++ b/src/main/java/org/orekit/utils/SortedListTrimmer.java @@ -18,8 +18,12 @@ import org.hipparchus.exception.LocalizedCoreFormats; import org.hipparchus.util.FastMath; -import org.orekit.errors.*; -import org.orekit.time.*; +import org.orekit.errors.OrekitException; +import org.orekit.errors.OrekitIllegalArgumentException; +import org.orekit.errors.OrekitMessages; +import org.orekit.errors.TimeStampedCacheException; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.TimeStamped; import java.util.List; diff --git a/src/test/java/org/orekit/attitudes/AttitudesSequenceTest.java b/src/test/java/org/orekit/attitudes/AttitudesSequenceTest.java index d245e93488..ebfb706d57 100644 --- a/src/test/java/org/orekit/attitudes/AttitudesSequenceTest.java +++ b/src/test/java/org/orekit/attitudes/AttitudesSequenceTest.java @@ -23,7 +23,11 @@ import org.hipparchus.Field; import org.hipparchus.analysis.differentiation.Gradient; import org.hipparchus.analysis.differentiation.GradientField; -import org.hipparchus.geometry.euclidean.threed.*; +import org.hipparchus.geometry.euclidean.threed.FieldRotation; +import org.hipparchus.geometry.euclidean.threed.FieldVector3D; +import org.hipparchus.geometry.euclidean.threed.Rotation; +import org.hipparchus.geometry.euclidean.threed.RotationOrder; +import org.hipparchus.geometry.euclidean.threed.Vector3D; import org.hipparchus.ode.events.Action; import org.hipparchus.ode.nonstiff.AdaptiveStepsizeIntegrator; import org.hipparchus.ode.nonstiff.DormandPrince853Integrator; @@ -69,7 +73,15 @@ import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; import org.orekit.time.TimeScalesFactory; -import org.orekit.utils.*; +import org.orekit.utils.AngularCoordinates; +import org.orekit.utils.AngularDerivativesFilter; +import org.orekit.utils.Constants; +import org.orekit.utils.ExtendedPVCoordinatesProvider; +import org.orekit.utils.FieldPVCoordinates; +import org.orekit.utils.FieldPVCoordinatesProvider; +import org.orekit.utils.IERSConventions; +import org.orekit.utils.PVCoordinates; +import org.orekit.utils.PVCoordinatesProvider; public class AttitudesSequenceTest { diff --git a/src/test/java/org/orekit/attitudes/GroundPointingTest.java b/src/test/java/org/orekit/attitudes/GroundPointingTest.java index 6912a5577c..efe32e3903 100644 --- a/src/test/java/org/orekit/attitudes/GroundPointingTest.java +++ b/src/test/java/org/orekit/attitudes/GroundPointingTest.java @@ -38,8 +38,14 @@ import org.orekit.orbits.PositionAngleType; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; -import org.orekit.utils.*; - +import org.orekit.utils.Constants; +import org.orekit.utils.FieldPVCoordinates; +import org.orekit.utils.FieldPVCoordinatesProvider; +import org.orekit.utils.IERSConventions; +import org.orekit.utils.PVCoordinates; +import org.orekit.utils.PVCoordinatesProvider; +import org.orekit.utils.TimeStampedFieldPVCoordinates; +import org.orekit.utils.TimeStampedPVCoordinates; class GroundPointingTest { @@ -72,7 +78,8 @@ public TimeStampedPVCoordinates getTargetPV(PVCoordinatesProvider pvProv, Absolu } @Override - public > TimeStampedFieldPVCoordinates getTargetPV(FieldPVCoordinatesProvider pvProv, FieldAbsoluteDate date, Frame frame) { + public > TimeStampedFieldPVCoordinates + getTargetPV(FieldPVCoordinatesProvider pvProv, FieldAbsoluteDate date, Frame frame) { return new TimeStampedFieldPVCoordinates(date, FieldPVCoordinates.getZero(date.getField())); } @@ -202,4 +209,4 @@ private > FieldEquinoctialOrbit convertToFi positionAngleType, orbit.getFrame(), fieldDate, zero.add(orbit.getMu())); } -} \ No newline at end of file +} diff --git a/src/test/java/org/orekit/attitudes/LofOffsetPointingTest.java b/src/test/java/org/orekit/attitudes/LofOffsetPointingTest.java index a91096b0fc..64ce3af818 100644 --- a/src/test/java/org/orekit/attitudes/LofOffsetPointingTest.java +++ b/src/test/java/org/orekit/attitudes/LofOffsetPointingTest.java @@ -18,7 +18,11 @@ import org.hipparchus.CalculusFieldElement; import org.hipparchus.Field; -import org.hipparchus.geometry.euclidean.threed.*; +import org.hipparchus.geometry.euclidean.threed.FieldRotation; +import org.hipparchus.geometry.euclidean.threed.Rotation; +import org.hipparchus.geometry.euclidean.threed.RotationConvention; +import org.hipparchus.geometry.euclidean.threed.RotationOrder; +import org.hipparchus.geometry.euclidean.threed.Vector3D; import org.hipparchus.util.Binary64Field; import org.hipparchus.util.FastMath; import org.junit.jupiter.api.AfterEach; @@ -81,7 +85,8 @@ public void testLof() { //************************ final LofOffset lofLaw = new LofOffset(circ.getFrame(), LOFType.LVLH_CCSDS); final LofOffsetPointing lofPointing = new LofOffsetPointing(circ.getFrame(), earthSpheric, lofLaw, Vector3D.PLUS_K); - final Rotation lofRot = lofPointing.getAttitude(circ, date, circ.getFrame()).getRotation(); + final Rotation + lofRot = lofPointing.getAttitude(circ, date, circ.getFrame()).getRotation(); // Compare to body center pointing law //************************************* diff --git a/src/test/java/org/orekit/attitudes/LofOffsetTest.java b/src/test/java/org/orekit/attitudes/LofOffsetTest.java index 339b0353a8..b212ac5091 100644 --- a/src/test/java/org/orekit/attitudes/LofOffsetTest.java +++ b/src/test/java/org/orekit/attitudes/LofOffsetTest.java @@ -20,7 +20,11 @@ import org.hipparchus.Field; import org.hipparchus.analysis.differentiation.GradientField; import org.hipparchus.complex.ComplexField; -import org.hipparchus.geometry.euclidean.threed.*; +import org.hipparchus.geometry.euclidean.threed.FieldRotation; +import org.hipparchus.geometry.euclidean.threed.Rotation; +import org.hipparchus.geometry.euclidean.threed.RotationConvention; +import org.hipparchus.geometry.euclidean.threed.RotationOrder; +import org.hipparchus.geometry.euclidean.threed.Vector3D; import org.hipparchus.util.Binary64Field; import org.hipparchus.util.FastMath; import org.junit.jupiter.api.AfterEach; diff --git a/src/test/java/org/orekit/data/AuthenticatorDialog.java b/src/test/java/org/orekit/data/AuthenticatorDialog.java index 03ccc06583..223baaa92b 100644 --- a/src/test/java/org/orekit/data/AuthenticatorDialog.java +++ b/src/test/java/org/orekit/data/AuthenticatorDialog.java @@ -16,8 +16,14 @@ */ package org.orekit.data; -import javax.swing.*; -import java.awt.*; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JPasswordField; +import javax.swing.JTextField; +import javax.swing.Spring; +import javax.swing.SpringLayout; +import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.net.Authenticator; diff --git a/src/test/java/org/orekit/estimation/measurements/AngularRaDecTest.java b/src/test/java/org/orekit/estimation/measurements/AngularRaDecTest.java index 515c2f0969..f68a8674e3 100644 --- a/src/test/java/org/orekit/estimation/measurements/AngularRaDecTest.java +++ b/src/test/java/org/orekit/estimation/measurements/AngularRaDecTest.java @@ -31,7 +31,11 @@ import org.orekit.estimation.Context; import org.orekit.estimation.EstimationTestUtils; import org.orekit.estimation.measurements.generation.AngularRaDecBuilder; -import org.orekit.frames.*; +import org.orekit.frames.Frame; +import org.orekit.frames.FramesFactory; +import org.orekit.frames.ITRFVersion; +import org.orekit.frames.StaticTransform; +import org.orekit.frames.TopocentricFrame; import org.orekit.models.earth.troposphere.TroposphericModelUtils; import org.orekit.orbits.CartesianOrbit; import org.orekit.orbits.OrbitType; @@ -43,7 +47,13 @@ import org.orekit.time.AbsoluteDate; import org.orekit.time.DateComponents; import org.orekit.time.TimeScalesFactory; -import org.orekit.utils.*; +import org.orekit.utils.Constants; +import org.orekit.utils.Differentiation; +import org.orekit.utils.IERSConventions; +import org.orekit.utils.PVCoordinates; +import org.orekit.utils.ParameterDriver; +import org.orekit.utils.ParameterFunction; +import org.orekit.utils.StateFunction; public class AngularRaDecTest { @@ -160,7 +170,7 @@ public double[] value(final SpacecraftState state) { getEstimatedValue(); } }, measurement.getDimension(), propagator.getAttitudeProvider(), OrbitType.CARTESIAN, - PositionAngleType.TRUE, 250.0, 4).value(state); + PositionAngleType.TRUE, 250.0, 4).value(state); Assertions.assertEquals(finiteDifferencesJacobian.length, jacobian.length); Assertions.assertEquals(finiteDifferencesJacobian[0].length, jacobian[0].length); @@ -291,14 +301,13 @@ public void testIssue1026() { //Context context = EstimationTestUtils.eccentricContext("regular-data/de431-ephemerides"); Utils.setDataRoot("regular-data"); - final double[] pos = {Constants.EGM96_EARTH_EQUATORIAL_RADIUS + 5e5, 1000., 0.}; + final double[] pos = { Constants.EGM96_EARTH_EQUATORIAL_RADIUS + 5e5, 1000., 0.}; final double[] vel = {0., 10., 0.}; final PVCoordinates pvCoordinates = new PVCoordinates(new Vector3D(pos[0], pos[1], pos[2]), - new Vector3D(vel[0], vel[1], vel[2])); + new Vector3D(vel[0], vel[1], vel[2])); final AbsoluteDate epoch = new AbsoluteDate(new DateComponents(2000, 1, 1), TimeScalesFactory.getUTC()); final Frame gcrf = FramesFactory.getGCRF(); - final CartesianOrbit orbit = new CartesianOrbit(pvCoordinates, gcrf, - epoch, Constants.EGM96_EARTH_MU); + final CartesianOrbit orbit = new CartesianOrbit(pvCoordinates, gcrf, epoch, Constants.EGM96_EARTH_MU); final SpacecraftState spacecraftState = new SpacecraftState(orbit); final OrekitStepInterpolator fakeInterpolator = new OrekitStepInterpolator() { public OrekitStepInterpolator restrictStep(SpacecraftState newPreviousState, SpacecraftState newCurrentState) { return null; } diff --git a/src/test/java/org/orekit/estimation/measurements/modifiers/AberrationModifierTest.java b/src/test/java/org/orekit/estimation/measurements/modifiers/AberrationModifierTest.java index 635f2c3dd6..d14edc0f75 100644 --- a/src/test/java/org/orekit/estimation/measurements/modifiers/AberrationModifierTest.java +++ b/src/test/java/org/orekit/estimation/measurements/modifiers/AberrationModifierTest.java @@ -18,7 +18,11 @@ import org.hipparchus.Field; import org.hipparchus.analysis.UnivariateFunction; -import org.hipparchus.analysis.differentiation.*; +import org.hipparchus.analysis.differentiation.DSFactory; +import org.hipparchus.analysis.differentiation.DerivativeStructure; +import org.hipparchus.analysis.differentiation.FiniteDifferencesDifferentiator; +import org.hipparchus.analysis.differentiation.Gradient; +import org.hipparchus.analysis.differentiation.GradientField; import org.hipparchus.geometry.euclidean.threed.Vector3D; import org.hipparchus.util.FastMath; import org.junit.jupiter.api.Assertions; diff --git a/src/test/java/org/orekit/forces/empirical/HarmonicAccelerationModelTest.java b/src/test/java/org/orekit/forces/empirical/HarmonicAccelerationModelTest.java index b0d2a43a2e..3178418d2c 100644 --- a/src/test/java/org/orekit/forces/empirical/HarmonicAccelerationModelTest.java +++ b/src/test/java/org/orekit/forces/empirical/HarmonicAccelerationModelTest.java @@ -32,7 +32,11 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.orekit.Utils; -import org.orekit.attitudes.*; +import org.orekit.attitudes.Attitude; +import org.orekit.attitudes.AttitudeProvider; +import org.orekit.attitudes.CelestialBodyPointed; +import org.orekit.attitudes.FrameAlignedProvider; +import org.orekit.attitudes.LofOffset; import org.orekit.bodies.CelestialBodyFactory; import org.orekit.errors.OrekitException; import org.orekit.estimation.leastsquares.BatchLSEstimator; @@ -144,8 +148,7 @@ private void doTestEquivalentManeuver(final double mass, final ConstantThrustManeuver maneuver, final AttitudeProvider accelerationLaw, final ParametricAcceleration parametricAcceleration, - final double positionTolerance) - { + final double positionTolerance) { SpacecraftState initialState = new SpacecraftState(initialOrbit, maneuverLaw.getAttitude(initialOrbit, diff --git a/src/test/java/org/orekit/forces/gravity/HolmesFeatherstoneAttractionModelTest.java b/src/test/java/org/orekit/forces/gravity/HolmesFeatherstoneAttractionModelTest.java index a25164e1bf..be2c4ef0b1 100644 --- a/src/test/java/org/orekit/forces/gravity/HolmesFeatherstoneAttractionModelTest.java +++ b/src/test/java/org/orekit/forces/gravity/HolmesFeatherstoneAttractionModelTest.java @@ -38,7 +38,11 @@ import org.hipparchus.ode.nonstiff.DormandPrince853FieldIntegrator; import org.hipparchus.ode.nonstiff.DormandPrince853Integrator; import org.hipparchus.util.FastMath; -import org.junit.jupiter.api.*; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; import org.mockito.Mockito; import org.orekit.Utils; import org.orekit.attitudes.Attitude; diff --git a/src/test/java/org/orekit/forces/maneuvers/FieldImpulseManeuverTest.java b/src/test/java/org/orekit/forces/maneuvers/FieldImpulseManeuverTest.java index f37464e2ba..c9df4f8f78 100644 --- a/src/test/java/org/orekit/forces/maneuvers/FieldImpulseManeuverTest.java +++ b/src/test/java/org/orekit/forces/maneuvers/FieldImpulseManeuverTest.java @@ -18,7 +18,13 @@ import org.hipparchus.CalculusFieldElement; import org.hipparchus.Field; -import org.hipparchus.analysis.differentiation.*; +import org.hipparchus.analysis.differentiation.DSFactory; +import org.hipparchus.analysis.differentiation.Gradient; +import org.hipparchus.analysis.differentiation.GradientField; +import org.hipparchus.analysis.differentiation.UnivariateDerivative1; +import org.hipparchus.analysis.differentiation.UnivariateDerivative1Field; +import org.hipparchus.analysis.differentiation.UnivariateDerivative2; +import org.hipparchus.analysis.differentiation.UnivariateDerivative2Field; import org.hipparchus.complex.Complex; import org.hipparchus.complex.ComplexField; import org.hipparchus.geometry.euclidean.threed.FieldVector3D; @@ -43,10 +49,31 @@ import org.orekit.frames.Frame; import org.orekit.frames.FramesFactory; import org.orekit.frames.LOFType; -import org.orekit.orbits.*; -import org.orekit.propagation.*; -import org.orekit.propagation.events.*; -import org.orekit.propagation.events.handlers.*; +import org.orekit.orbits.CartesianOrbit; +import org.orekit.orbits.FieldCartesianOrbit; +import org.orekit.orbits.FieldOrbit; +import org.orekit.orbits.Orbit; +import org.orekit.orbits.OrbitType; +import org.orekit.orbits.PositionAngleType; +import org.orekit.propagation.AbstractPropagator; +import org.orekit.propagation.FieldSpacecraftState; +import org.orekit.propagation.MatricesHarvester; +import org.orekit.propagation.SpacecraftState; +import org.orekit.propagation.events.AbstractDetector; +import org.orekit.propagation.events.DateDetector; +import org.orekit.propagation.events.EclipseDetector; +import org.orekit.propagation.events.EventDetector; +import org.orekit.propagation.events.FieldAbstractDetector; +import org.orekit.propagation.events.FieldAdaptableInterval; +import org.orekit.propagation.events.FieldDateDetector; +import org.orekit.propagation.events.FieldEclipseDetector; +import org.orekit.propagation.events.FieldEventDetector; +import org.orekit.propagation.events.FieldLatitudeCrossingDetector; +import org.orekit.propagation.events.LatitudeCrossingDetector; +import org.orekit.propagation.events.handlers.FieldContinueOnEvent; +import org.orekit.propagation.events.handlers.FieldEventHandler; +import org.orekit.propagation.events.handlers.FieldStopOnEvent; +import org.orekit.propagation.events.handlers.StopOnEvent; import org.orekit.propagation.integration.FieldAdditionalDerivativesProvider; import org.orekit.propagation.integration.FieldCombinedDerivatives; import org.orekit.propagation.numerical.FieldNumericalPropagator; @@ -209,7 +236,8 @@ private > FieldImpulseManeuver fieldDeltaVSat = new FieldVector3D<>(field, impulseManeuver.getDeltaVSat()); final EventDetector detector = impulseManeuver.getTrigger(); final int maxIter = detector.getMaxIterationCount(); - final FieldAdaptableInterval fieldMaxCheck = s -> detector.getMaxCheckInterval().currentInterval(s.toSpacecraftState()); + final FieldAdaptableInterval + fieldMaxCheck = s -> detector.getMaxCheckInterval().currentInterval(s.toSpacecraftState()); final T fieldThreshold = field.getZero().add(detector.getThreshold()); FieldAbstractDetector fieldDetector; if (detector instanceof DateDetector) { @@ -219,11 +247,11 @@ private > FieldImpulseManeuver(field, - ((LatitudeCrossingDetector) detector).getBody(), - ((LatitudeCrossingDetector) detector).getLatitude()); + ((LatitudeCrossingDetector) detector).getBody(), + ((LatitudeCrossingDetector) detector).getLatitude()); } else if (detector instanceof EclipseDetector) { fieldDetector = new FieldEclipseDetector<>(field, - ((EclipseDetector) detector).getOccultationEngine()); + ((EclipseDetector) detector).getOccultationEngine()); } else { throw new OrekitInternalError(null); } @@ -251,7 +279,8 @@ private > void templateDetector(final Field propagator.addEventDetector(impulseManeuver); fieldPropagator.addEventDetector(convertManeuver(field, impulseManeuver, new FieldStopOnEvent<>())); // When - final SpacecraftState terminalState = propagator.propagate(endOfPropagationDate); + final SpacecraftState + terminalState = propagator.propagate(endOfPropagationDate); final FieldSpacecraftState fieldTerminalState = fieldPropagator.propagate(new FieldAbsoluteDate<>(field, endOfPropagationDate)); // Then compareStateToConstantOfFieldState(terminalState, fieldTerminalState); @@ -342,7 +371,7 @@ private > FieldCartesianOrbit createConstan final FieldPVCoordinates fieldPVCoordinates = new FieldPVCoordinates<>(fieldPosition, fieldVelocity); return new FieldCartesianOrbit<>(fieldPVCoordinates, inertialFrame, - new FieldAbsoluteDate<>(field, orbit.getDate()), field.getZero().add(mu)); + new FieldAbsoluteDate<>(field, orbit.getDate()), field.getZero().add(mu)); } @Test diff --git a/src/test/java/org/orekit/frames/TIRFProviderTest.java b/src/test/java/org/orekit/frames/TIRFProviderTest.java index 96ec735084..716968c029 100644 --- a/src/test/java/org/orekit/frames/TIRFProviderTest.java +++ b/src/test/java/org/orekit/frames/TIRFProviderTest.java @@ -29,7 +29,12 @@ import org.orekit.OrekitMatchers; import org.orekit.Utils; import org.orekit.data.DataContext; -import org.orekit.time.*; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.DateComponents; +import org.orekit.time.FieldAbsoluteDate; +import org.orekit.time.TimeComponents; +import org.orekit.time.TimeScale; +import org.orekit.time.TimeScalesFactory; import org.orekit.utils.AngularCoordinates; import org.orekit.utils.IERSConventions; import org.orekit.utils.PVCoordinates; diff --git a/src/test/java/org/orekit/frames/TransformProviderTest.java b/src/test/java/org/orekit/frames/TransformProviderTest.java index 831069c87d..adca39c8dd 100644 --- a/src/test/java/org/orekit/frames/TransformProviderTest.java +++ b/src/test/java/org/orekit/frames/TransformProviderTest.java @@ -20,7 +20,11 @@ import org.hipparchus.Field; import org.hipparchus.complex.Complex; import org.hipparchus.complex.ComplexField; -import org.hipparchus.geometry.euclidean.threed.*; +import org.hipparchus.geometry.euclidean.threed.FieldRotation; +import org.hipparchus.geometry.euclidean.threed.FieldVector3D; +import org.hipparchus.geometry.euclidean.threed.Rotation; +import org.hipparchus.geometry.euclidean.threed.RotationConvention; +import org.hipparchus.geometry.euclidean.threed.Vector3D; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.orekit.time.AbsoluteDate; @@ -113,4 +117,4 @@ public > FieldTransform getTransform(FieldA } } -} \ No newline at end of file +} diff --git a/src/test/java/org/orekit/propagation/analytical/AggregateBoundedPropagatorTest.java b/src/test/java/org/orekit/propagation/analytical/AggregateBoundedPropagatorTest.java index 03794ae003..dcfb89d56b 100644 --- a/src/test/java/org/orekit/propagation/analytical/AggregateBoundedPropagatorTest.java +++ b/src/test/java/org/orekit/propagation/analytical/AggregateBoundedPropagatorTest.java @@ -16,8 +16,6 @@ */ package org.orekit.propagation.analytical; -import java.util.*; - import org.hamcrest.CoreMatchers; import org.hamcrest.MatcherAssert; import org.hipparchus.geometry.euclidean.threed.Vector3D; @@ -35,11 +33,18 @@ import org.orekit.orbits.PositionAngleType; import org.orekit.propagation.BoundedPropagator; import org.orekit.propagation.EphemerisGenerator; -import org.orekit.propagation.Propagator; import org.orekit.propagation.SpacecraftState; import org.orekit.time.AbsoluteDate; import org.orekit.utils.Constants; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.NavigableMap; +import java.util.TreeMap; + /** * Tests for {@link AggregateBoundedPropagator}. * diff --git a/src/test/java/org/orekit/propagation/integration/AbstractGradientConverterTest.java b/src/test/java/org/orekit/propagation/integration/AbstractGradientConverterTest.java index 32f0318965..58c7052433 100644 --- a/src/test/java/org/orekit/propagation/integration/AbstractGradientConverterTest.java +++ b/src/test/java/org/orekit/propagation/integration/AbstractGradientConverterTest.java @@ -27,7 +27,11 @@ import org.orekit.propagation.FieldSpacecraftState; import org.orekit.propagation.SpacecraftState; import org.orekit.time.AbsoluteDate; -import org.orekit.utils.*; +import org.orekit.utils.Constants; +import org.orekit.utils.PVCoordinates; +import org.orekit.utils.ParameterDriver; +import org.orekit.utils.ParameterDriversProvider; +import org.orekit.utils.TimeStampedPVCoordinates; import java.util.ArrayList; import java.util.List; @@ -101,7 +105,7 @@ private SpacecraftState mockState(final boolean isOrbitDefined, final Frame fram final SpacecraftState state = Mockito.mock(SpacecraftState.class); Mockito.when(state.getDate()).thenReturn(AbsoluteDate.ARBITRARY_EPOCH); final TimeStampedPVCoordinates pvCoordinates = new TimeStampedPVCoordinates(state.getDate(), - new PVCoordinates()); + new PVCoordinates()); Mockito.when(state.getPVCoordinates()).thenReturn(pvCoordinates); Mockito.when(state.getPosition()).thenReturn(pvCoordinates.getPosition()); Mockito.when(state.isOrbitDefined()).thenReturn(isOrbitDefined); @@ -141,4 +145,4 @@ protected TestGradientConverter(int freeStateParameters) { } -} \ No newline at end of file +} diff --git a/src/test/java/org/orekit/propagation/numerical/FieldNumericalPropagatorTest.java b/src/test/java/org/orekit/propagation/numerical/FieldNumericalPropagatorTest.java index bce48b0f74..719d31f347 100644 --- a/src/test/java/org/orekit/propagation/numerical/FieldNumericalPropagatorTest.java +++ b/src/test/java/org/orekit/propagation/numerical/FieldNumericalPropagatorTest.java @@ -40,7 +40,10 @@ import org.hipparchus.util.Binary64Field; import org.hipparchus.util.FastMath; import org.hipparchus.util.MathArrays; -import org.junit.jupiter.api.*; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; import org.mockito.Mockito; import org.orekit.OrekitMatchers; import org.orekit.Utils; @@ -69,19 +72,39 @@ import org.orekit.orbits.FieldOrbit; import org.orekit.orbits.OrbitType; import org.orekit.orbits.PositionAngleType; -import org.orekit.propagation.*; -import org.orekit.propagation.events.*; +import org.orekit.propagation.FieldAdditionalStateProvider; +import org.orekit.propagation.FieldBoundedPropagator; +import org.orekit.propagation.FieldEphemerisGenerator; +import org.orekit.propagation.PropagationType; +import org.orekit.propagation.FieldSpacecraftState; +import org.orekit.propagation.SpacecraftState; +import org.orekit.propagation.events.DateDetector; +import org.orekit.propagation.events.EventDetector; +import org.orekit.propagation.events.FieldAbstractDetector; +import org.orekit.propagation.events.FieldAdaptableInterval; +import org.orekit.propagation.events.FieldApsideDetector; +import org.orekit.propagation.events.FieldDateDetector; import org.orekit.propagation.events.handlers.FieldContinueOnEvent; import org.orekit.propagation.events.handlers.FieldEventHandler; import org.orekit.propagation.events.handlers.FieldStopOnEvent; +import org.orekit.propagation.events.FieldEventDetector; import org.orekit.propagation.integration.FieldAbstractIntegratedPropagator; import org.orekit.propagation.integration.FieldAdditionalDerivativesProvider; import org.orekit.propagation.integration.FieldCombinedDerivatives; import org.orekit.propagation.sampling.FieldOrekitStepHandler; import org.orekit.propagation.sampling.FieldOrekitStepInterpolator; -import org.orekit.time.*; -import org.orekit.utils.*; - +import org.orekit.time.AbsoluteDate; +import org.orekit.time.DateComponents; +import org.orekit.time.FieldAbsoluteDate; +import org.orekit.time.FieldTimeStamped; +import org.orekit.time.TimeComponents; +import org.orekit.time.TimeScale; +import org.orekit.time.TimeScalesFactory; +import org.orekit.utils.Constants; +import org.orekit.utils.FieldPVCoordinates; +import org.orekit.utils.IERSConventions; +import org.orekit.utils.ParameterDriver; +import org.orekit.utils.TimeStampedFieldPVCoordinates; public class FieldNumericalPropagatorTest { @@ -106,7 +129,7 @@ void testNotInitialised1() { private > void doTestNotInitialised1(Field field) { // setup - final FieldAbsoluteDate initDate = FieldAbsoluteDate.getJ2000Epoch(field); + final FieldAbsoluteDate initDate = FieldAbsoluteDate.getJ2000Epoch(field); final FieldAbstractIntegratedPropagator notInitialised = new FieldNumericalPropagator<>(field, new ClassicalRungeKuttaFieldIntegrator<>(field, field.getZero().add(10.0))); @@ -203,8 +226,7 @@ static class CountingHandler , T extends Calculu implements FieldEventHandler { /** - * number of calls to {@link #eventOccurred(FieldSpacecraftState, - * FieldEventDetector, boolean)}. + * number of calls to eventOccurred. */ private int eventCount = 0; From 59fd175aa7300147bbc83bbabbf8cb1ff4b635d9 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Fri, 23 Feb 2024 16:09:59 +0100 Subject: [PATCH 144/359] Fixed IDE warnings. --- .../attitudes/AttitudesSequenceTest.java | 126 +++++++++--------- .../orekit/attitudes/GroundPointingTest.java | 4 +- .../attitudes/LofOffsetPointingTest.java | 6 +- .../org/orekit/attitudes/LofOffsetTest.java | 16 +-- .../org/orekit/data/AuthenticatorDialog.java | 27 ++-- .../measurements/AngularRaDecTest.java | 13 +- .../HarmonicAccelerationModelTest.java | 2 +- ...HolmesFeatherstoneAttractionModelTest.java | 33 ++--- .../maneuvers/FieldImpulseManeuverTest.java | 5 +- .../org/orekit/frames/TIRFProviderTest.java | 28 ++-- .../orekit/frames/TransformProviderTest.java | 2 +- .../AggregateBoundedPropagatorTest.java | 14 +- .../FieldNumericalPropagatorTest.java | 58 ++++---- 13 files changed, 151 insertions(+), 183 deletions(-) diff --git a/src/test/java/org/orekit/attitudes/AttitudesSequenceTest.java b/src/test/java/org/orekit/attitudes/AttitudesSequenceTest.java index ebfb706d57..85766d44d7 100644 --- a/src/test/java/org/orekit/attitudes/AttitudesSequenceTest.java +++ b/src/test/java/org/orekit/attitudes/AttitudesSequenceTest.java @@ -68,8 +68,6 @@ import org.orekit.propagation.events.EventsLogger; import org.orekit.propagation.events.handlers.ContinueOnEvent; import org.orekit.propagation.numerical.NumericalPropagator; -import org.orekit.propagation.sampling.FieldOrekitFixedStepHandler; -import org.orekit.propagation.sampling.OrekitFixedStepHandler; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; import org.orekit.time.TimeScalesFactory; @@ -91,7 +89,7 @@ public class AttitudesSequenceTest { @Test public void testDayNightSwitch() { // Initial state definition : date, orbit - final AbsoluteDate initialDate = new AbsoluteDate(2004, 01, 01, 23, 30, 00.000, TimeScalesFactory.getUTC()); + final AbsoluteDate initialDate = new AbsoluteDate(2004, 1, 1, 23, 30, 00.000, TimeScalesFactory.getUTC()); final Vector3D position = new Vector3D(-6142438.668, 3492467.560, -25767.25680); final Vector3D velocity = new Vector3D(505.8479685, 942.7809215, 7435.922231); final Orbit initialOrbit = new KeplerianOrbit(new PVCoordinates(position, velocity), @@ -149,30 +147,28 @@ public Action eventOccurred(final SpacecraftState s, final EventDetector d, fina // Register the switching events to the propagator attitudesSequence.registerSwitchEvents(propagator); - propagator.setStepHandler(60.0, new OrekitFixedStepHandler() { - public void handleStep(SpacecraftState currentState) { - // the Earth position in spacecraft frame should be along spacecraft Z axis - // during night time and away from it during day time due to roll and pitch offsets - final Vector3D earth = currentState.toTransform().transformPosition(Vector3D.ZERO); - final double pointingOffset = Vector3D.angle(earth, Vector3D.PLUS_K); - - // the g function is the eclipse indicator, its an angle between Sun and Earth limb, - // positive when Sun is outside of Earth limb, negative when Sun is hidden by Earth limb - final double eclipseAngle = ed.g(currentState); - - if (currentState.getDate().durationFrom(lastChange) > 300) { - if (inEclipse) { - Assertions.assertTrue(eclipseAngle <= 0); - Assertions.assertEquals(0.0, pointingOffset, 1.0e-6); - } else { - Assertions.assertTrue(eclipseAngle >= 0); - Assertions.assertEquals(0.767215, pointingOffset, 1.0e-6); - } + propagator.setStepHandler(60.0, currentState -> { + // the Earth position in spacecraft frame should be along spacecraft Z axis + // during night time and away from it during day time due to roll and pitch offsets + final Vector3D earth = currentState.toTransform().transformPosition(Vector3D.ZERO); + final double pointingOffset = Vector3D.angle(earth, Vector3D.PLUS_K); + + // the g function is the eclipse indicator, its an angle between Sun and Earth limb, + // positive when Sun is outside of Earth limb, negative when Sun is hidden by Earth limb + final double eclipseAngle = ed.g(currentState); + + if (currentState.getDate().durationFrom(lastChange) > 300) { + if (inEclipse) { + Assertions.assertTrue(eclipseAngle <= 0); + Assertions.assertEquals(0.0, pointingOffset, 1.0e-6); } else { - // we are in transition - Assertions.assertTrue(pointingOffset <= 0.7672155, - pointingOffset + " " + (0.767215 - pointingOffset)); + Assertions.assertTrue(eclipseAngle >= 0); + Assertions.assertEquals(0.767215, pointingOffset, 1.0e-6); } + } else { + // we are in transition + Assertions.assertTrue(pointingOffset <= 0.7672155, + pointingOffset + " " + (0.767215 - pointingOffset)); } }); @@ -199,7 +195,7 @@ private > void doTestDayNightSwitchField(final { // Initial state definition : date, orbit - final FieldAbsoluteDate initialDate = new FieldAbsoluteDate<>(field, 2004, 01, 01, 23, 30, 00.000, TimeScalesFactory.getUTC()); + final FieldAbsoluteDate initialDate = new FieldAbsoluteDate<>(field, 2004, 1, 1, 23, 30, 00.000, TimeScalesFactory.getUTC()); final FieldVector3D position = new FieldVector3D<>(field, new Vector3D(-6142438.668, 3492467.560, -25767.25680)); final FieldVector3D velocity = new FieldVector3D<>(field, @@ -262,40 +258,38 @@ public Action eventOccurred(final SpacecraftState s, } // Propagator : consider the analytical Eckstein-Hechler model - final FieldPropagator propagator = new FieldEcksteinHechlerPropagator(initialOrbit, attitudesSequence, - Constants.EIGEN5C_EARTH_EQUATORIAL_RADIUS, - field.getZero().add(Constants.EIGEN5C_EARTH_MU), - Constants.EIGEN5C_EARTH_C20, - Constants.EIGEN5C_EARTH_C30, Constants.EIGEN5C_EARTH_C40, - Constants.EIGEN5C_EARTH_C50, Constants.EIGEN5C_EARTH_C60); + final FieldPropagator propagator = new FieldEcksteinHechlerPropagator<>(initialOrbit, attitudesSequence, + Constants.EIGEN5C_EARTH_EQUATORIAL_RADIUS, + field.getZero().add(Constants.EIGEN5C_EARTH_MU), + Constants.EIGEN5C_EARTH_C20, + Constants.EIGEN5C_EARTH_C30, Constants.EIGEN5C_EARTH_C40, + Constants.EIGEN5C_EARTH_C50, Constants.EIGEN5C_EARTH_C60); // Register the switching events to the propagator attitudesSequence.registerSwitchEvents(field, propagator); - propagator.setStepHandler(field.getZero().add(60.0), new FieldOrekitFixedStepHandler() { - public void handleStep(FieldSpacecraftState currentState) { - // the Earth position in spacecraft frame should be along spacecraft Z axis - // during night time and away from it during day time due to roll and pitch offsets - final FieldVector3D earth = currentState.toTransform().transformPosition(Vector3D.ZERO); - final T pointingOffset = FieldVector3D.angle(earth, Vector3D.PLUS_K); - - // the g function is the eclipse indicator, its an angle between Sun and Earth limb, - // positive when Sun is outside of Earth limb, negative when Sun is hidden by Earth limb - final double eclipseAngle = ed.g(currentState.toSpacecraftState()); - - if (currentState.getDate().durationFrom(lastChange).getReal() > 300) { - if (inEclipse) { - Assertions.assertTrue(eclipseAngle <= 0); - Assertions.assertEquals(0.0, pointingOffset.getReal(), 1.0e-6); - } else { - Assertions.assertTrue(eclipseAngle >= 0); - Assertions.assertEquals(0.767215, pointingOffset.getReal(), 1.0e-6); - } + propagator.setStepHandler(field.getZero().add(60.0), currentState -> { + // the Earth position in spacecraft frame should be along spacecraft Z axis + // during night time and away from it during day time due to roll and pitch offsets + final FieldVector3D earth = currentState.toTransform().transformPosition(Vector3D.ZERO); + final T pointingOffset = FieldVector3D.angle(earth, Vector3D.PLUS_K); + + // the g function is the eclipse indicator, its an angle between Sun and Earth limb, + // positive when Sun is outside of Earth limb, negative when Sun is hidden by Earth limb + final double eclipseAngle = ed.g(currentState.toSpacecraftState()); + + if (currentState.getDate().durationFrom(lastChange).getReal() > 300) { + if (inEclipse) { + Assertions.assertTrue(eclipseAngle <= 0); + Assertions.assertEquals(0.0, pointingOffset.getReal(), 1.0e-6); } else { - // we are in transition - Assertions.assertTrue(pointingOffset.getReal() <= 0.7672155, - pointingOffset.getReal() + " " + (0.767215 - pointingOffset.getReal())); + Assertions.assertTrue(eclipseAngle >= 0); + Assertions.assertEquals(0.767215, pointingOffset.getReal(), 1.0e-6); } + } else { + // we are in transition + Assertions.assertTrue(pointingOffset.getReal() <= 0.7672155, + pointingOffset.getReal() + " " + (0.767215 - pointingOffset.getReal())); } }); @@ -317,7 +311,7 @@ public void handleStep(FieldSpacecraftState currentState) { public void testBackwardPropagation() { // Initial state definition : date, orbit - final AbsoluteDate initialDate = new AbsoluteDate(2004, 01, 01, 23, 30, 00.000, TimeScalesFactory.getUTC()); + final AbsoluteDate initialDate = new AbsoluteDate(2004, 1, 1, 23, 30, 00.000, TimeScalesFactory.getUTC()); final Vector3D position = new Vector3D(-6142438.668, 3492467.560, -25767.25680); final Vector3D velocity = new Vector3D(505.8479685, 942.7809215, 7435.922231); final Orbit initialOrbit = new KeplerianOrbit(new PVCoordinates(position, velocity), @@ -373,15 +367,15 @@ public void testTooShortTransition() { Assertions.fail("an exception should have been thrown"); } catch (OrekitException oe) { Assertions.assertEquals(OrekitMessages.TOO_SHORT_TRANSITION_TIME_FOR_ATTITUDES_SWITCH, oe.getSpecifier()); - Assertions.assertEquals(transitionTime, ((Double) oe.getParts()[0]).doubleValue(), 1.0e-10); - Assertions.assertEquals(threshold, ((Double) oe.getParts()[1]).doubleValue(), 1.0e-10); + Assertions.assertEquals(transitionTime, (Double) oe.getParts()[0], 1.0e-10); + Assertions.assertEquals(threshold, (Double) oe.getParts()[1], 1.0e-10); } } @Test public void testOutOfSyncCalls() { // Initial state definition : date, orbit - final AbsoluteDate initialDate = new AbsoluteDate(2004, 01, 01, 23, 30, 00.000, TimeScalesFactory.getUTC()); + final AbsoluteDate initialDate = new AbsoluteDate(2004, 1, 1, 23, 30, 00.000, TimeScalesFactory.getUTC()); final Vector3D position = new Vector3D(-6142438.668, 3492467.560, -25767.25680); final Vector3D velocity = new Vector3D(505.8479685, 942.7809215, 7435.922231); final Orbit initialOrbit = new KeplerianOrbit(new PVCoordinates(position, velocity), @@ -457,7 +451,7 @@ public void testOutOfSyncCalls() { @Test public void testResetDuringTransitionForward() { // Initial state definition : date, orbit - final AbsoluteDate initialDate = new AbsoluteDate(2004, 01, 01, 23, 30, 00.000, TimeScalesFactory.getUTC()); + final AbsoluteDate initialDate = new AbsoluteDate(2004, 1, 1, 23, 30, 00.000, TimeScalesFactory.getUTC()); final Vector3D position = new Vector3D(-6142438.668, 3492467.560, -25767.25680); final Vector3D velocity = new Vector3D(505.8479685, 942.7809215, 7435.922231); final Orbit initialOrbit = new KeplerianOrbit(new PVCoordinates(position, velocity), @@ -525,7 +519,7 @@ public void testResetDuringTransitionForward() { @Test public void testResetDuringTransitionBackward() { // Initial state definition : date, orbit - final AbsoluteDate initialDate = new AbsoluteDate(2004, 01, 01, 23, 30, 00.000, TimeScalesFactory.getUTC()); + final AbsoluteDate initialDate = new AbsoluteDate(2004, 1, 1, 23, 30, 00.000, TimeScalesFactory.getUTC()); final Vector3D position = new Vector3D(-6142438.668, 3492467.560, -25767.25680); final Vector3D velocity = new Vector3D(505.8479685, 942.7809215, 7435.922231); final Orbit initialOrbit = new KeplerianOrbit(new PVCoordinates(position, velocity), @@ -707,21 +701,21 @@ public > FieldAttitude getAttitude(FieldPVC private static class Handler implements AttitudesSequence.SwitchHandler { - private AttitudeProvider expectedPrevious; - private AttitudeProvider expectedNext; - private List dates; + private final AttitudeProvider expectedPrevious; + private final AttitudeProvider expectedNext; + private final List dates; public Handler(final AttitudeProvider expectedPrevious, final AttitudeProvider expectedNext) { this.expectedPrevious = expectedPrevious; this.expectedNext = expectedNext; - this.dates = new ArrayList(); + this.dates = new ArrayList<>(); } @Override public void switchOccurred(AttitudeProvider previous, AttitudeProvider next, SpacecraftState state) { - Assertions.assertTrue(previous == expectedPrevious); - Assertions.assertTrue(next == expectedNext); + Assertions.assertSame(previous, expectedPrevious); + Assertions.assertSame(next, expectedNext); dates.add(state.getDate()); } diff --git a/src/test/java/org/orekit/attitudes/GroundPointingTest.java b/src/test/java/org/orekit/attitudes/GroundPointingTest.java index efe32e3903..24cc2b0b2c 100644 --- a/src/test/java/org/orekit/attitudes/GroundPointingTest.java +++ b/src/test/java/org/orekit/attitudes/GroundPointingTest.java @@ -80,7 +80,7 @@ public TimeStampedPVCoordinates getTargetPV(PVCoordinatesProvider pvProv, Absolu @Override public > TimeStampedFieldPVCoordinates getTargetPV(FieldPVCoordinatesProvider pvProv, FieldAbsoluteDate date, Frame frame) { - return new TimeStampedFieldPVCoordinates(date, FieldPVCoordinates.getZero(date.getField())); + return new TimeStampedFieldPVCoordinates<>(date, FieldPVCoordinates.getZero(date.getField())); } } @@ -202,7 +202,7 @@ private > FieldEquinoctialOrbit convertToFi final EquinoctialOrbit orbit) { final T zero = field.getZero(); final T fieldSemiMajorAxis = zero.add(orbit.getA()); - final FieldAbsoluteDate fieldDate = new FieldAbsoluteDate(field, orbit.getDate()); + final FieldAbsoluteDate fieldDate = new FieldAbsoluteDate<>(field, orbit.getDate()); final PositionAngleType positionAngleType = PositionAngleType.MEAN; final T fieldAngle = zero.add(orbit.getL(positionAngleType)); return new FieldEquinoctialOrbit<>(fieldSemiMajorAxis, zero, zero, zero, zero, fieldAngle, diff --git a/src/test/java/org/orekit/attitudes/LofOffsetPointingTest.java b/src/test/java/org/orekit/attitudes/LofOffsetPointingTest.java index 64ce3af818..e5426825ff 100644 --- a/src/test/java/org/orekit/attitudes/LofOffsetPointingTest.java +++ b/src/test/java/org/orekit/attitudes/LofOffsetPointingTest.java @@ -123,7 +123,7 @@ public void testMiss() { @Test public void testSpin() { - AbsoluteDate date = new AbsoluteDate(new DateComponents(1970, 01, 01), + AbsoluteDate date = new AbsoluteDate(new DateComponents(1970, 1, 1), new TimeComponents(3, 25, 45.6789), TimeScalesFactory.getUTC()); KeplerianOrbit orbit = @@ -167,7 +167,7 @@ public void testSpin() { @Test public void testTypesField() { - AbsoluteDate date = new AbsoluteDate(new DateComponents(1970, 01, 01), + AbsoluteDate date = new AbsoluteDate(new DateComponents(1970, 1, 1), new TimeComponents(3, 25, 45.6789), TimeScalesFactory.getUTC()); KeplerianOrbit orbit = @@ -260,7 +260,7 @@ public void setUp() { Utils.setDataRoot("regular-data"); // Computation date - date = new AbsoluteDate(new DateComponents(2008, 04, 07), + date = new AbsoluteDate(new DateComponents(2008, 4, 7), TimeComponents.H00, TimeScalesFactory.getUTC()); diff --git a/src/test/java/org/orekit/attitudes/LofOffsetTest.java b/src/test/java/org/orekit/attitudes/LofOffsetTest.java index b212ac5091..dad0214c04 100644 --- a/src/test/java/org/orekit/attitudes/LofOffsetTest.java +++ b/src/test/java/org/orekit/attitudes/LofOffsetTest.java @@ -176,7 +176,7 @@ public void testSpin() { final AttitudeProvider law = new LofOffset(orbit.getFrame(), LOFType.LVLH_CCSDS, RotationOrder.XYX, 0.1, 0.2, 0.3); - AbsoluteDate date = new AbsoluteDate(new DateComponents(1970, 01, 01), + AbsoluteDate date = new AbsoluteDate(new DateComponents(1970, 1, 1), new TimeComponents(3, 25, 45.6789), TimeScalesFactory.getUTC()); KeplerianOrbit orbit = @@ -215,7 +215,7 @@ public void testSpin() { @Test public void testAnglesSign() { - AbsoluteDate date = new AbsoluteDate(new DateComponents(1970, 01, 01), + AbsoluteDate date = new AbsoluteDate(new DateComponents(1970, 1, 1), new TimeComponents(3, 25, 45.6789), TimeScalesFactory.getUTC()); KeplerianOrbit orbit = @@ -250,7 +250,7 @@ public void testAnglesSign() { @Test public void testRetrieveAngles() { - AbsoluteDate date = new AbsoluteDate(new DateComponents(1970, 01, 01), + AbsoluteDate date = new AbsoluteDate(new DateComponents(1970, 1, 1), new TimeComponents(3, 25, 45.6789), TimeScalesFactory.getUTC()); KeplerianOrbit orbit = @@ -279,7 +279,7 @@ public void testRetrieveAngles() { @Test public void testTypesField() { - AbsoluteDate date = new AbsoluteDate(new DateComponents(1970, 01, 01), + AbsoluteDate date = new AbsoluteDate(new DateComponents(1970, 1, 1), new TimeComponents(3, 25, 45.6789), TimeScalesFactory.getUTC()); KeplerianOrbit orbit = @@ -306,9 +306,9 @@ private void checkSatVector(Orbit o, Attitude a, Vector3D satVector, Vector3D xLof = Vector3D.crossProduct(yLof, zLof); Assertions.assertTrue(Vector3D.dotProduct(xLof, o.getPVCoordinates().getVelocity()) > 0); Vector3D v = a.getRotation().applyInverseTo(satVector); - Assertions.assertEquals(expectedX, Vector3D.dotProduct(v, xLof), 1.0e-8); - Assertions.assertEquals(expectedY, Vector3D.dotProduct(v, yLof), 1.0e-8); - Assertions.assertEquals(expectedZ, Vector3D.dotProduct(v, zLof), 1.0e-8); + Assertions.assertEquals(expectedX, Vector3D.dotProduct(v, xLof), threshold); + Assertions.assertEquals(expectedY, Vector3D.dotProduct(v, yLof), threshold); + Assertions.assertEquals(expectedZ, Vector3D.dotProduct(v, zLof), threshold); } private > void checkField(final Field field, final AttitudeProvider provider, @@ -367,7 +367,7 @@ public void setUp() { Utils.setDataRoot("regular-data"); // Computation date - date = new AbsoluteDate(new DateComponents(2008, 04, 07), + date = new AbsoluteDate(new DateComponents(2008, 4, 7), TimeComponents.H00, TimeScalesFactory.getUTC()); diff --git a/src/test/java/org/orekit/data/AuthenticatorDialog.java b/src/test/java/org/orekit/data/AuthenticatorDialog.java index 223baaa92b..c1f0de4888 100644 --- a/src/test/java/org/orekit/data/AuthenticatorDialog.java +++ b/src/test/java/org/orekit/data/AuthenticatorDialog.java @@ -24,7 +24,6 @@ import javax.swing.Spring; import javax.swing.SpringLayout; import java.awt.Component; -import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.net.Authenticator; import java.net.PasswordAuthentication; @@ -50,7 +49,7 @@ public class AuthenticatorDialog extends Authenticator { /** Simple constructor. */ public AuthenticatorDialog() { - userName = new String(); + userName = ""; password = new char[0]; } @@ -129,19 +128,17 @@ protected PasswordAuthentication getPasswordAuthentication() { SpringLayout.EAST, passwordField); dialog.pack(); - ActionListener al = new ActionListener() { - public void actionPerformed(ActionEvent e) { - if (e.getSource() == cancelButton) { - userName = new String(); - password = new char[0]; - } else { - userName = userNameField.getText(); - password = passwordField.getPassword(); - } - userNameField.setText(null); - passwordField.setText(null); - dialog.setVisible(false); + ActionListener al = e -> { + if (e.getSource() == cancelButton) { + userName = ""; + password = new char[0]; + } else { + userName = userNameField.getText(); + password = passwordField.getPassword(); } + userNameField.setText(null); + passwordField.setText(null); + dialog.setVisible(false); }; passwordField.addActionListener(al); okButton.addActionListener(al); @@ -153,7 +150,7 @@ public void actionPerformed(ActionEvent e) { // to prevent credentials lying around in memory PasswordAuthentication authentication = new PasswordAuthentication(userName, password); - userName = new String(); + userName = ""; password = new char[0]; return authentication; diff --git a/src/test/java/org/orekit/estimation/measurements/AngularRaDecTest.java b/src/test/java/org/orekit/estimation/measurements/AngularRaDecTest.java index f68a8674e3..d70b685abb 100644 --- a/src/test/java/org/orekit/estimation/measurements/AngularRaDecTest.java +++ b/src/test/java/org/orekit/estimation/measurements/AngularRaDecTest.java @@ -53,7 +53,6 @@ import org.orekit.utils.PVCoordinates; import org.orekit.utils.ParameterDriver; import org.orekit.utils.ParameterFunction; -import org.orekit.utils.StateFunction; public class AngularRaDecTest { @@ -163,13 +162,11 @@ public void testStateDerivatives() { // compute a reference value using finite differences final double[][] finiteDifferencesJacobian = - Differentiation.differentiate(new StateFunction() { - public double[] value(final SpacecraftState state) { - return measurement. - estimateWithoutDerivatives(0, 0, new SpacecraftState[] { state }). - getEstimatedValue(); - } - }, measurement.getDimension(), propagator.getAttitudeProvider(), OrbitType.CARTESIAN, + Differentiation.differentiate(state1 -> measurement. + estimateWithoutDerivatives(0, 0, new SpacecraftState[] { + state1 + }). + getEstimatedValue(), measurement.getDimension(), propagator.getAttitudeProvider(), OrbitType.CARTESIAN, PositionAngleType.TRUE, 250.0, 4).value(state); Assertions.assertEquals(finiteDifferencesJacobian.length, jacobian.length); diff --git a/src/test/java/org/orekit/forces/empirical/HarmonicAccelerationModelTest.java b/src/test/java/org/orekit/forces/empirical/HarmonicAccelerationModelTest.java index 3178418d2c..f10eb4efde 100644 --- a/src/test/java/org/orekit/forces/empirical/HarmonicAccelerationModelTest.java +++ b/src/test/java/org/orekit/forces/empirical/HarmonicAccelerationModelTest.java @@ -483,7 +483,7 @@ public void setUp() { final double OMEGA = FastMath.toRadians(261); final double lv = 0; - final AbsoluteDate initDate = new AbsoluteDate(new DateComponents(2004, 01, 01), + final AbsoluteDate initDate = new AbsoluteDate(new DateComponents(2004, 1, 1), new TimeComponents(23, 30, 00.000), TimeScalesFactory.getUTC()); initialOrbit = diff --git a/src/test/java/org/orekit/forces/gravity/HolmesFeatherstoneAttractionModelTest.java b/src/test/java/org/orekit/forces/gravity/HolmesFeatherstoneAttractionModelTest.java index be2c4ef0b1..7a5bcf2a8e 100644 --- a/src/test/java/org/orekit/forces/gravity/HolmesFeatherstoneAttractionModelTest.java +++ b/src/test/java/org/orekit/forces/gravity/HolmesFeatherstoneAttractionModelTest.java @@ -259,8 +259,8 @@ private GradientHessian gradientHessian(final HolmesFeatherstoneAttractionModel for (int m = degree; m >= 0; --m) { // compute tesseral terms - index = ((Integer) computeTesseralMethod.invoke(hfModel, m, degree, index, t, u, tOu, - pnm0Plus2, pnm0Plus1, pnm1Plus1, pnm0, pnm1, pnm2)).intValue(); + index = (Integer) computeTesseralMethod.invoke(hfModel, m, degree, index, t, u, tOu, + pnm0Plus2, pnm0Plus1, pnm1Plus1, pnm0, pnm1, pnm2); if (m <= order) { // compute contribution of current order to field (equation 5 of the paper) @@ -803,7 +803,7 @@ public void testHelioSynchronous() { // initialization - AbsoluteDate date = new AbsoluteDate(new DateComponents(1970, 07, 01), + AbsoluteDate date = new AbsoluteDate(new DateComponents(1970, 7, 1), new TimeComponents(13, 59, 27.816), TimeScalesFactory.getUTC()); Transform itrfToEME2000 = itrf.getTransformTo(FramesFactory.getEME2000(), date); @@ -827,7 +827,7 @@ public void testHelioSynchronous() c, s))); // let the step handler perform the test - propagator.setStepHandler(Constants.JULIAN_DAY, new SpotStepHandler(date, mu)); + propagator.setStepHandler(Constants.JULIAN_DAY, new SpotStepHandler()); propagator.setInitialState(new SpacecraftState(orbit)); propagator.propagate(date.shiftedBy(7 * Constants.JULIAN_DAY)); Assertions.assertTrue(propagator.getCalls() < 9200); @@ -836,13 +836,14 @@ public void testHelioSynchronous() private static class SpotStepHandler implements OrekitFixedStepHandler { - public SpotStepHandler(AbsoluteDate date, double mu) { + private final PVCoordinatesProvider sun; + private double previous; + + public SpotStepHandler() { sun = CelestialBodyFactory.getSun(); previous = Double.NaN; } - private PVCoordinatesProvider sun; - private double previous; public void handleStep(SpacecraftState currentState) { @@ -903,15 +904,15 @@ private static class EckStepHandler implements OrekitFixedStepHandler { /** Body mu */ private static final double mu = 3.986004415e+14; + private final EcksteinHechlerPropagator referencePropagator; + private EckStepHandler(Orbit initialOrbit, double ae, - double c20, double c30, double c40, double c50, double c60) - { + double c20, double c30, double c40, double c50, double c60) { referencePropagator = new EcksteinHechlerPropagator(initialOrbit, ae, mu, c20, c30, c40, c50, c60); } - private EcksteinHechlerPropagator referencePropagator; public void handleStep(SpacecraftState currentState) { SpacecraftState EHPOrbit = referencePropagator.propagate(currentState.getDate()); @@ -1053,7 +1054,7 @@ public void testStateJacobian() GravityFieldFactory.addPotentialCoefficientsReader(new GRGSFormatReader("grim4s4_gr", true)); // initialization - AbsoluteDate date = new AbsoluteDate(new DateComponents(2000, 07, 01), + AbsoluteDate date = new AbsoluteDate(new DateComponents(2000, 7, 1), new TimeComponents(13, 59, 27.816), TimeScalesFactory.getUTC()); double i = FastMath.toRadians(98.7); @@ -1086,7 +1087,7 @@ public void testStateJacobianVs80Implementation() GravityFieldFactory.addPotentialCoefficientsReader(new GRGSFormatReader("grim4s4_gr", true)); // initialization - AbsoluteDate date = new AbsoluteDate(new DateComponents(2000, 07, 01), + AbsoluteDate date = new AbsoluteDate(new DateComponents(2000, 7, 1), new TimeComponents(13, 59, 27.816), TimeScalesFactory.getUTC()); double i = FastMath.toRadians(98.7); @@ -1114,7 +1115,7 @@ public void testStateJacobianVs80ImplementationGradient() GravityFieldFactory.addPotentialCoefficientsReader(new GRGSFormatReader("grim4s4_gr", true)); // initialization - AbsoluteDate date = new AbsoluteDate(new DateComponents(2000, 07, 01), + AbsoluteDate date = new AbsoluteDate(new DateComponents(2000, 7, 1), new TimeComponents(13, 59, 27.816), TimeScalesFactory.getUTC()); double i = FastMath.toRadians(98.7); @@ -1142,7 +1143,7 @@ public void testStateJacobianVsFiniteDifferences() GravityFieldFactory.addPotentialCoefficientsReader(new GRGSFormatReader("grim4s4_gr", true)); // initialization - AbsoluteDate date = new AbsoluteDate(new DateComponents(2000, 07, 01), + AbsoluteDate date = new AbsoluteDate(new DateComponents(2000, 7, 1), new TimeComponents(13, 59, 27.816), TimeScalesFactory.getUTC()); double i = FastMath.toRadians(98.7); @@ -1169,7 +1170,7 @@ public void testStateJacobianVsFiniteDifferencesGradient() GravityFieldFactory.addPotentialCoefficientsReader(new GRGSFormatReader("grim4s4_gr", true)); // initialization - AbsoluteDate date = new AbsoluteDate(new DateComponents(2000, 07, 01), + AbsoluteDate date = new AbsoluteDate(new DateComponents(2000, 7, 1), new TimeComponents(13, 59, 27.816), TimeScalesFactory.getUTC()); double i = FastMath.toRadians(98.7); @@ -1195,7 +1196,7 @@ public void testIssue996() { GravityFieldFactory.addPotentialCoefficientsReader(new GRGSFormatReader("grim4s4_gr", true)); // initialization - AbsoluteDate date = new AbsoluteDate(new DateComponents(2000, 07, 01), + AbsoluteDate date = new AbsoluteDate(new DateComponents(2000, 7, 1), new TimeComponents(13, 59, 27.816), TimeScalesFactory.getUTC()); double i = FastMath.toRadians(98.7); diff --git a/src/test/java/org/orekit/forces/maneuvers/FieldImpulseManeuverTest.java b/src/test/java/org/orekit/forces/maneuvers/FieldImpulseManeuverTest.java index c9df4f8f78..6286d6b359 100644 --- a/src/test/java/org/orekit/forces/maneuvers/FieldImpulseManeuverTest.java +++ b/src/test/java/org/orekit/forces/maneuvers/FieldImpulseManeuverTest.java @@ -382,15 +382,14 @@ public void testAdditionalStatePropagation() { univariateDerivative1Field); FieldSpacecraftState initialState = fieldPropagator.getInitialState(); final String name = "dummy"; - final UnivariateDerivative1 expectedValue = zero; - initialState = initialState.addAdditionalState(name, expectedValue); + initialState = initialState.addAdditionalState(name, zero); fieldPropagator.resetInitialState(initialState); // When final FieldAbsoluteDate targetDate = initialState.getDate().shiftedBy(zero.add(10000.)); final FieldSpacecraftState terminalState = fieldPropagator.propagate(targetDate); // Then final UnivariateDerivative1 actualValue = terminalState.getAdditionalState(name)[0]; - Assertions.assertEquals(expectedValue, actualValue); + Assertions.assertEquals(zero, actualValue); } @Test diff --git a/src/test/java/org/orekit/frames/TIRFProviderTest.java b/src/test/java/org/orekit/frames/TIRFProviderTest.java index 716968c029..727ca17e24 100644 --- a/src/test/java/org/orekit/frames/TIRFProviderTest.java +++ b/src/test/java/org/orekit/frames/TIRFProviderTest.java @@ -77,8 +77,8 @@ public void testAASReferenceLEO() { { 53104, -0.4399619, 0.0015563, -0.140682, 0.333309, Double.NaN, Double.NaN, -0.000199, -0.000252 }, { 53105, -0.4399619, 0.0015563, -0.140682, 0.333309, Double.NaN, Double.NaN, -0.000199, -0.000252 } })); - AbsoluteDate t0 = new AbsoluteDate(new DateComponents(2004, 04, 06), - new TimeComponents(07, 51, 28.386009), + AbsoluteDate t0 = new AbsoluteDate(new DateComponents(2004, 4, 6), + new TimeComponents(7, 51, 28.386009), TimeScalesFactory.getUTC()); // Positions LEO @@ -131,7 +131,7 @@ public void testAASReferenceGEO() { { 53160, -0.4709050, 0.0000000, -0.083853, 0.467217, Double.NaN, Double.NaN, -0.000199, -0.000252 } })); - AbsoluteDate t0 = new AbsoluteDate(new DateComponents(2004, 06, 01), + AbsoluteDate t0 = new AbsoluteDate(new DateComponents(2004, 6, 1), TimeComponents.H00, TimeScalesFactory.getUTC()); @@ -244,7 +244,7 @@ public void testConcurrentGetTransform() // tolerance of comparisons final double absTol = Precision.EPSILON; // the expected result - final List expecteds = new ArrayList(); + final List expecteds = new ArrayList<>(); for (int j = 0; j < nPerJob; j++) { final AbsoluteDate date = start.shiftedBy(timeStep * j); // action @@ -254,19 +254,17 @@ public void testConcurrentGetTransform() } // build jobs for concurrent execution - final List> jobs = new ArrayList>(); + final List> jobs = new ArrayList<>(); for (int i = 0; i < nJobs; i++) { - jobs.add(new Callable() { - public Boolean call() throws Exception { - for (int j = 0; j < nPerJob; j++) { - final AbsoluteDate date = start.shiftedBy(timeStep * j); - // action - final Transform actual = tirf.getTransform(date); - // verify - assertTransformEquals(expecteds.get(j), actual, absTol); - } - return true; + jobs.add(() -> { + for (int j = 0; j < nPerJob; j++) { + final AbsoluteDate date = start.shiftedBy(timeStep * j); + // action + final Transform actual = tirf.getTransform(date); + // verify + assertTransformEquals(expecteds.get(j), actual, absTol); } + return true; }); } diff --git a/src/test/java/org/orekit/frames/TransformProviderTest.java b/src/test/java/org/orekit/frames/TransformProviderTest.java index adca39c8dd..e6af072cc1 100644 --- a/src/test/java/org/orekit/frames/TransformProviderTest.java +++ b/src/test/java/org/orekit/frames/TransformProviderTest.java @@ -113,7 +113,7 @@ public > FieldTransform getTransform(FieldA final Field field = date.getField(); final FieldRotation fieldRotation = new FieldRotation<>(field, transform.getRotation()); final FieldVector3D fieldRotationRate = new FieldVector3D<>(field, transform.getRotationRate()); - return new FieldTransform(date, fieldRotation, fieldRotationRate); + return new FieldTransform<>(date, fieldRotation, fieldRotationRate); } } diff --git a/src/test/java/org/orekit/propagation/analytical/AggregateBoundedPropagatorTest.java b/src/test/java/org/orekit/propagation/analytical/AggregateBoundedPropagatorTest.java index dcfb89d56b..d6976e0d1a 100644 --- a/src/test/java/org/orekit/propagation/analytical/AggregateBoundedPropagatorTest.java +++ b/src/test/java/org/orekit/propagation/analytical/AggregateBoundedPropagatorTest.java @@ -63,11 +63,9 @@ public void setUp() { /** * Check {@link AggregateBoundedPropagator#propagateOrbit(AbsoluteDate)} when the * constituent propagators are exactly adjacent. - * - * @throws Exception on error. */ @Test - public void testAdjacent() throws Exception { + public void testAdjacent() { // setup AbsoluteDate date = AbsoluteDate.CCSDS_EPOCH; BoundedPropagator p1 = createPropagator(date, date.shiftedBy(10), 0); @@ -107,11 +105,9 @@ public void testAdjacent() throws Exception { /** * Check {@link AggregateBoundedPropagator#propagateOrbit(AbsoluteDate)} when the * constituent propagators overlap. - * - * @throws Exception on error. */ @Test - public void testOverlap() throws Exception { + public void testOverlap() { // setup AbsoluteDate date = AbsoluteDate.CCSDS_EPOCH; BoundedPropagator p1 = createPropagator(date, date.shiftedBy(25), 0); @@ -145,11 +141,9 @@ public void testOverlap() throws Exception { /** * Check {@link AggregateBoundedPropagator#propagateOrbit(AbsoluteDate)} with a gap * between the constituent propagators. - * - * @throws Exception on error. */ @Test - public void testGap() throws Exception { + public void testGap() { // setup AbsoluteDate date = AbsoluteDate.CCSDS_EPOCH; BoundedPropagator p1 = createPropagator(date, date.shiftedBy(1), 0); @@ -186,7 +180,7 @@ public void testGap() throws Exception { } @Test - public void testOutsideBounds() throws Exception { + public void testOutsideBounds() { // setup AbsoluteDate date = AbsoluteDate.CCSDS_EPOCH; BoundedPropagator p1 = createPropagator(date, date.shiftedBy(10), 0); diff --git a/src/test/java/org/orekit/propagation/numerical/FieldNumericalPropagatorTest.java b/src/test/java/org/orekit/propagation/numerical/FieldNumericalPropagatorTest.java index 719d31f347..2d9ae353ef 100644 --- a/src/test/java/org/orekit/propagation/numerical/FieldNumericalPropagatorTest.java +++ b/src/test/java/org/orekit/propagation/numerical/FieldNumericalPropagatorTest.java @@ -122,9 +122,7 @@ private > void doTestIssue1032(Field field) @Test void testNotInitialised1() { - Assertions.assertThrows(OrekitException.class, () -> { - doTestNotInitialised1(Binary64Field.getInstance()); - }); + Assertions.assertThrows(OrekitException.class, () -> doTestNotInitialised1(Binary64Field.getInstance())); } private > void doTestNotInitialised1(Field field) { @@ -138,9 +136,7 @@ private > void doTestNotInitialised1(Field @Test void testNotInitialised2() { - Assertions.assertThrows(OrekitException.class, () -> { - doTestNotInitialised2(Binary64Field.getInstance()); - }); + Assertions.assertThrows(OrekitException.class, () -> doTestNotInitialised2(Binary64Field.getInstance())); } private > void doTestNotInitialised2(Field field) { @@ -156,7 +152,7 @@ void testEventAtEndOfEphemeris() { doTestEventAtEndOfEphemeris(Binary64Field.getInstance()); } - private , D extends FieldEventDetector> void doTestEventAtEndOfEphemeris(Field field) { + private > void doTestEventAtEndOfEphemeris(Field field) { T zero = field.getZero(); FieldNumericalPropagator propagator = createPropagator(field); @@ -168,7 +164,7 @@ private , D extends FieldEventDetector> voi final FieldEphemerisGenerator generator = propagator.getEphemerisGenerator(); propagator.propagate(end); FieldBoundedPropagator ephemeris = generator.getGeneratedEphemeris(); - CountingHandler handler = new CountingHandler(); + CountingHandler handler = new CountingHandler<>(); FieldDateDetector detector = new FieldDateDetector<>(field, toArray(end)). withMaxCheck(10). withThreshold(zero.newInstance(1e-9)). @@ -190,7 +186,7 @@ void testEventAtBeginningOfEphemeris() { doTestEventAtBeginningOfEphemeris(Binary64Field.getInstance()); } - private , D extends FieldEventDetector> void doTestEventAtBeginningOfEphemeris(Field field) { + private > void doTestEventAtBeginningOfEphemeris(Field field) { T zero = field.getZero(); FieldNumericalPropagator propagator = createPropagator(field); @@ -203,7 +199,7 @@ private , D extends FieldEventDetector> voi final FieldEphemerisGenerator generator = propagator.getEphemerisGenerator(); propagator.propagate(end); FieldBoundedPropagator ephemeris = generator.getGeneratedEphemeris(); - CountingHandler handler = new CountingHandler(); + CountingHandler handler = new CountingHandler<>(); // events directly on propagation start date are not triggered, // so move the event date slightly after FieldAbsoluteDate eventDate = initDate.shiftedBy(FastMath.ulp(100.0) / 10.0); @@ -222,7 +218,7 @@ private , D extends FieldEventDetector> voi Assertions.assertEquals(2, handler.eventCount); } - static class CountingHandler , T extends CalculusFieldElement> + static class CountingHandler > implements FieldEventHandler { /** @@ -262,11 +258,11 @@ private > void doTestCloseEventDates(Field FieldDateDetector d1 = new FieldDateDetector<>(field, toArray(initDate.shiftedBy(15))). withMaxCheck(10). withThreshold(zero.newInstance(1)). - withHandler(new FieldContinueOnEvent()); + withHandler(new FieldContinueOnEvent<>()); FieldDateDetector d2 = new FieldDateDetector<>(field, toArray(initDate.shiftedBy(15.5))). withMaxCheck(10). withThreshold(zero.newInstance(1)). - withHandler(new FieldContinueOnEvent()); + withHandler(new FieldContinueOnEvent<>()); propagator.addEventDetector(d1); propagator.addEventDetector(d2); @@ -676,9 +672,7 @@ private > FieldPVCoordinates propagateInTyp @Test void testException() { - Assertions.assertThrows(OrekitException.class, () -> { - doTestException(Binary64Field.getInstance()); - }); + Assertions.assertThrows(OrekitException.class, () -> doTestException(Binary64Field.getInstance())); } private > void doTestException(Field field) { @@ -704,11 +698,7 @@ private > void doTestException(Field field) propagator.setStepHandler(new FieldOrekitStepHandler() { private int countDown = 3; - private FieldAbsoluteDate previousCall = null; public void handleStep(FieldOrekitStepInterpolator interpolator) { - if (previousCall != null) { - System.out.println(interpolator.getCurrentState().getDate().compareTo(previousCall) < 0); - } if (--countDown == 0) { throw new OrekitException(LocalizedCoreFormats.SIMPLE_MESSAGE, "dummy error"); } @@ -745,7 +735,7 @@ private > void doTestStopEvent(Field field) propagator.setInitialState(initialState); final FieldAbsoluteDate stopDate = initDate.shiftedBy(1000); - CheckingHandler checking = new CheckingHandler(Action.STOP); + CheckingHandler checking = new CheckingHandler<>(Action.STOP); @SuppressWarnings("unchecked") FieldDateDetector detector = new FieldDateDetector<>(field, stopDate).withHandler(checking); propagator.addEventDetector(detector); @@ -825,7 +815,7 @@ private > void doTestResetDerivativesEvent(Fie propagator.setOrbitType(type); propagator.setInitialState(initialState); final FieldAbsoluteDate resetDate = initDate.shiftedBy(1000); - CheckingHandler checking = new CheckingHandler(Action.RESET_DERIVATIVES); + CheckingHandler checking = new CheckingHandler<>(Action.RESET_DERIVATIVES); @SuppressWarnings("unchecked") FieldDateDetector detector = new FieldDateDetector<>(field, resetDate).withHandler(checking); propagator.addEventDetector(detector); @@ -876,7 +866,7 @@ private > void doTestContinueEvent(Field f final FieldAbsoluteDate resetDate = initDate.shiftedBy(1000); - CheckingHandler checking = new CheckingHandler(Action.CONTINUE); + CheckingHandler checking = new CheckingHandler<>(Action.CONTINUE); @SuppressWarnings("unchecked") FieldDateDetector detector = new FieldDateDetector<>(field, resetDate).withHandler(checking); propagator.addEventDetector(detector); @@ -991,8 +981,8 @@ public T[] getAdditionalState(FieldSpacecraftState state) { Assertions.assertEquals(2, propagator.getManagedAdditionalStates().length); propagator.setInitialState(propagator.getInitialState().addAdditionalState("linear", zero.add(1.5))); - CheckingHandler checking = new CheckingHandler(Action.STOP); - propagator.addEventDetector(new AdditionalStateLinearDetector(zero.add(10.0), zero.add(1.0e-8)).withHandler(checking)); + CheckingHandler checking = new CheckingHandler<>(Action.STOP); + propagator.addEventDetector(new AdditionalStateLinearDetector<>(zero.add(10.0), zero.add(1.0e-8)).withHandler(checking)); final double dt = 3200; checking.assertEvent(false); @@ -1008,7 +998,7 @@ private static class AdditionalStateLinearDetector, T> { public AdditionalStateLinearDetector(T maxCheck, T threshold) { - this(s -> maxCheck.getReal(), threshold, DEFAULT_MAX_ITER, new FieldStopOnEvent()); + this(s -> maxCheck.getReal(), threshold, DEFAULT_MAX_ITER, new FieldStopOnEvent<>()); } private AdditionalStateLinearDetector(FieldAdaptableInterval maxCheck, T threshold, int maxIter, @@ -1019,7 +1009,7 @@ private AdditionalStateLinearDetector(FieldAdaptableInterval maxCheck, T thre protected AdditionalStateLinearDetector create(final FieldAdaptableInterval newMaxCheck, final T newThreshold, final int newMaxIter, final FieldEventHandler newHandler) { - return new AdditionalStateLinearDetector(newMaxCheck, newThreshold, newMaxIter, newHandler); + return new AdditionalStateLinearDetector<>(newMaxCheck, newThreshold, newMaxIter, newHandler); } public T g(FieldSpacecraftState s) { @@ -1064,8 +1054,8 @@ public FieldSpacecraftState resetState(FieldEventDetector detector, FieldS } }; - propagator.addEventDetector(new AdditionalStateLinearDetector(field.getZero().add(10.0), - field.getZero().add(1.0e-8)).withHandler(checking)); + propagator.addEventDetector(new AdditionalStateLinearDetector<>(field.getZero().add(10.0), + field.getZero().add(1.0e-8)).withHandler(checking)); final double dt = 3200; checking.assertEvent(false); @@ -1087,8 +1077,6 @@ private > void doTestEventDetectionBug(final T zero = field.getZero(); TimeScale utc = TimeScalesFactory.getUTC(); FieldAbsoluteDate initialDate = new FieldAbsoluteDate<>(field, 2005, 1, 1, 0, 0, 0.0, utc); - T duration = zero.add(100000.0); - FieldAbsoluteDate endDate = new FieldAbsoluteDate<>(initialDate, duration); // Initialization of the frame EME2000 Frame EME2000 = FramesFactory.getEME2000(); @@ -1104,8 +1092,8 @@ private > void doTestEventDetectionBug(final EME2000, initialDate, zero.add(mu)); - duration = geo.getKeplerianPeriod(); - endDate = new FieldAbsoluteDate<>(initialDate, duration); + T duration = geo.getKeplerianPeriod(); + FieldAbsoluteDate endDate = new FieldAbsoluteDate<>(initialDate, duration); // Numerical Integration final double minStep = 0.001; @@ -1780,7 +1768,7 @@ private > void doTestInfinitePropagation(Fiel // Stop condition T convergenceThreshold = field.getZero().add(1e-9); - propagator.addEventDetector(new FieldDateDetector(field, propagator.getInitialState().getDate().shiftedBy(60)). + propagator.addEventDetector(new FieldDateDetector<>(field, propagator.getInitialState().getDate().shiftedBy(60)). withMaxCheck(1e10).withThreshold(convergenceThreshold)); // Propagate until the stop condition is reached @@ -1835,7 +1823,7 @@ private static > void doTestShift(final FieldC dates[3] = reference.shiftedBy(300.0); dates[4] = reference.shiftedBy(600.0); dates[5] = reference.shiftedBy(900.0); - np.addEventDetector(new FieldDateDetector(field, (FieldTimeStamped[]) dates). + np.addEventDetector(new FieldDateDetector<>(field, (FieldTimeStamped[]) dates). withMaxCheck(30). withThreshold(zero.newInstance(1.0e-9)). withHandler(checker)); From 7d4529ef5234b0b2066ccb30ac865ee75793362b Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Fri, 23 Feb 2024 16:27:35 +0100 Subject: [PATCH 145/359] Removed star imports. --- .../java/org/orekit/orbits/FieldCircularOrbitTest.java | 10 ++++++++-- .../org/orekit/orbits/FieldEquinoctialOrbitTest.java | 8 ++++++-- .../org/orekit/orbits/FieldKeplerianOrbitTest.java | 6 +++++- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/test/java/org/orekit/orbits/FieldCircularOrbitTest.java b/src/test/java/org/orekit/orbits/FieldCircularOrbitTest.java index ffdd891372..047b2de7b0 100644 --- a/src/test/java/org/orekit/orbits/FieldCircularOrbitTest.java +++ b/src/test/java/org/orekit/orbits/FieldCircularOrbitTest.java @@ -29,7 +29,11 @@ import org.hipparchus.geometry.euclidean.threed.Vector3D; import org.hipparchus.linear.FieldMatrixPreservingVisitor; import org.hipparchus.linear.MatrixUtils; -import org.hipparchus.util.*; +import org.hipparchus.util.Binary64; +import org.hipparchus.util.Binary64Field; +import org.hipparchus.util.FastMath; +import org.hipparchus.util.MathArrays; +import org.hipparchus.util.MathUtils; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -449,7 +453,9 @@ private > void doTestCircularToEquinoctialEll( Assertions.assertEquals(param.getHy().getReal(), circ.getHy().getReal(), Utils.epsilonAngle * FastMath.abs(circ.getI().getReal())); - Assertions.assertEquals(MathUtils.normalizeAngle(param.getLv().getReal(), circ.getLv().getReal()), circ.getLv().getReal(), Utils.epsilonAngle * FastMath.abs(circ.getLv().getReal())); + Assertions.assertEquals(MathUtils.normalizeAngle(param.getLv().getReal(), circ.getLv().getReal()), + circ.getLv().getReal(), + Utils.epsilonAngle * FastMath.abs(circ.getLv().getReal())); Assertions.assertFalse(circ.hasDerivatives()); Assertions.assertNull(circ.getADot()); diff --git a/src/test/java/org/orekit/orbits/FieldEquinoctialOrbitTest.java b/src/test/java/org/orekit/orbits/FieldEquinoctialOrbitTest.java index c83bad9d85..e9c3fe8131 100644 --- a/src/test/java/org/orekit/orbits/FieldEquinoctialOrbitTest.java +++ b/src/test/java/org/orekit/orbits/FieldEquinoctialOrbitTest.java @@ -28,7 +28,11 @@ import org.hipparchus.geometry.euclidean.threed.FieldVector3D; import org.hipparchus.linear.FieldMatrixPreservingVisitor; import org.hipparchus.linear.MatrixUtils; -import org.hipparchus.util.*; +import org.hipparchus.util.Binary64; +import org.hipparchus.util.Binary64Field; +import org.hipparchus.util.FastMath; +import org.hipparchus.util.MathArrays; +import org.hipparchus.util.MathUtils; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -419,7 +423,7 @@ private > void doTestEquinoctialToEquinoctialE Assertions.assertEquals(param.getHy().getReal(), equi.getHy().getReal(), Utils.epsilonAngle * FastMath.abs(equi.getI().getReal())); Assertions.assertEquals(MathUtils.normalizeAngle(param.getLv().getReal(), equi.getLv().getReal()), equi.getLv().getReal(), - Utils.epsilonAngle * FastMath.abs(equi.getLv().getReal())); + Utils.epsilonAngle * FastMath.abs(equi.getLv().getReal())); } diff --git a/src/test/java/org/orekit/orbits/FieldKeplerianOrbitTest.java b/src/test/java/org/orekit/orbits/FieldKeplerianOrbitTest.java index 9a781d4871..7097ea48c3 100644 --- a/src/test/java/org/orekit/orbits/FieldKeplerianOrbitTest.java +++ b/src/test/java/org/orekit/orbits/FieldKeplerianOrbitTest.java @@ -28,7 +28,11 @@ import org.hipparchus.geometry.euclidean.threed.FieldVector3D; import org.hipparchus.linear.FieldMatrixPreservingVisitor; import org.hipparchus.linear.MatrixUtils; -import org.hipparchus.util.*; +import org.hipparchus.util.Binary64; +import org.hipparchus.util.Binary64Field; +import org.hipparchus.util.FastMath; +import org.hipparchus.util.MathArrays; +import org.hipparchus.util.MathUtils; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; From 38d1bd10ea2d0c93464ddbffb27719cdc92addbd Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Fri, 23 Feb 2024 16:27:35 +0100 Subject: [PATCH 146/359] Removed star imports. --- .../orekit/files/general/EphemerisFile.java | 1 - .../general/EphemerisSegmentPropagator.java | 8 +- .../java/org/orekit/files/sp3/SP3Segment.java | 125 ++++++------------ .../org/orekit/files/sp3/SP3ParserTest.java | 6 + .../orekit/orbits/FieldCircularOrbitTest.java | 10 +- .../orbits/FieldEquinoctialOrbitTest.java | 8 +- .../orbits/FieldKeplerianOrbitTest.java | 6 +- 7 files changed, 67 insertions(+), 97 deletions(-) diff --git a/src/main/java/org/orekit/files/general/EphemerisFile.java b/src/main/java/org/orekit/files/general/EphemerisFile.java index 7c313ddaaa..3767919170 100644 --- a/src/main/java/org/orekit/files/general/EphemerisFile.java +++ b/src/main/java/org/orekit/files/general/EphemerisFile.java @@ -30,7 +30,6 @@ import org.orekit.time.AbsoluteDate; import org.orekit.utils.CartesianDerivativesFilter; import org.orekit.utils.TimeStampedPVCoordinates; -import org.orekit.utils.TimeStampedPVCoordinatesHermiteInterpolator; /** * An interface for accessing the data stored in an ephemeris file and using the data to diff --git a/src/main/java/org/orekit/files/general/EphemerisSegmentPropagator.java b/src/main/java/org/orekit/files/general/EphemerisSegmentPropagator.java index f6e4950d7a..c26cad85bf 100644 --- a/src/main/java/org/orekit/files/general/EphemerisSegmentPropagator.java +++ b/src/main/java/org/orekit/files/general/EphemerisSegmentPropagator.java @@ -47,7 +47,7 @@ * * @author Evan Ward */ -class EphemerisSegmentPropagator extends AbstractAnalyticalPropagator +public class EphemerisSegmentPropagator extends AbstractAnalyticalPropagator implements BoundedPropagator { /** Tabular data from which this propagator is built. */ @@ -67,8 +67,8 @@ class EphemerisSegmentPropagator extends Abs * @param ephemeris segment containing the data for this propagator. * @param attitudeProvider provider for attitude computation */ - EphemerisSegmentPropagator(final EphemerisSegment ephemeris, - final AttitudeProvider attitudeProvider) { + public EphemerisSegmentPropagator(final EphemerisSegment ephemeris, + final AttitudeProvider attitudeProvider) { super(attitudeProvider); this.ephemeris = ephemeris; this.interpolator = new TimeStampedPVCoordinatesHermiteInterpolator(ephemeris.getInterpolationSamples(), @@ -154,7 +154,7 @@ private TimeStampedPVCoordinates interpolate(final AbsoluteDate date) { // cast stream to super type final List castedNeighbors = new ArrayList<>(neighbors.size()); - neighbors.forEach(neighbor -> castedNeighbors.add(neighbor)); + castedNeighbors.addAll(neighbors); // create interpolator return interpolator.interpolate(date, castedNeighbors); diff --git a/src/main/java/org/orekit/files/sp3/SP3Segment.java b/src/main/java/org/orekit/files/sp3/SP3Segment.java index 4549f1e2e0..c276967c7c 100644 --- a/src/main/java/org/orekit/files/sp3/SP3Segment.java +++ b/src/main/java/org/orekit/files/sp3/SP3Segment.java @@ -19,19 +19,16 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.stream.Stream; +import org.hipparchus.analysis.interpolation.HermiteInterpolator; import org.orekit.attitudes.AttitudeProvider; +import org.orekit.attitudes.FrameAlignedProvider; import org.orekit.files.general.EphemerisFile; +import org.orekit.files.general.EphemerisSegmentPropagator; import org.orekit.frames.Frame; -import org.orekit.propagation.AdditionalStateProvider; import org.orekit.propagation.BoundedPropagator; import org.orekit.propagation.SpacecraftState; import org.orekit.time.AbsoluteDate; -import org.orekit.time.TimeStampedDouble; -import org.orekit.time.TimeStampedDoubleAndDerivative; -import org.orekit.time.TimeStampedDoubleAndDerivativeHermiteInterpolator; -import org.orekit.time.TimeStampedDoubleHermiteInterpolator; import org.orekit.utils.CartesianDerivativesFilter; import org.orekit.utils.SortedListTrimmer; @@ -126,109 +123,63 @@ public void addCoordinate(final SP3Coordinate coord) { /** {@inheritDoc} */ @Override public BoundedPropagator getPropagator() { - return addClockManagement(EphemerisFile.EphemerisSegment.super.getPropagator()); + return new PropagatorWithClock(new FrameAlignedProvider(getInertialFrame())); } /** {@inheritDoc} */ @Override public BoundedPropagator getPropagator(final AttitudeProvider attitudeProvider) { - return addClockManagement(EphemerisFile.EphemerisSegment.super.getPropagator(attitudeProvider)); + return new PropagatorWithClock(attitudeProvider); } - /** Add clock management to a propagator. - * @return propagator with managed clock + /** Propagator including clock. * @since 12.1 */ - private BoundedPropagator addClockManagement(final BoundedPropagator propagator) { - propagator.addAdditionalStateProvider(filter.getMaxOrder() > 0 ? - new ClockProviderOrder1() : - new ClockProviderOrder0()); - return propagator; - } - - /** Additional provider for clock without derivatives. - * @since 12.1 - */ - private class ClockProviderOrder0 implements AdditionalStateProvider { - - /** Interpolator for clock. */ - private final TimeStampedDoubleHermiteInterpolator interpolator; + private class PropagatorWithClock extends EphemerisSegmentPropagator { /** Trimmer for coordinates list. */ private final SortedListTrimmer trimmer; /** Simple constructor. */ - ClockProviderOrder0() { - // we don't use SP3CoordinateHermiteInterpolator - // because the underlying propagator already has interpolated position - // we only interpolate the additional state here - interpolator = new TimeStampedDoubleHermiteInterpolator(getInterpolationSamples()); - trimmer = new SortedListTrimmer(getInterpolationSamples()); + PropagatorWithClock(final AttitudeProvider attitudeProvider) { + super(SP3Segment.this, attitudeProvider); + this.trimmer = new SortedListTrimmer(getInterpolationSamples()); } /** {@inheritDoc} */ @Override - public String getName() { - return SP3Utils.CLOCK_ADDITIONAL_STATE; - } + protected SpacecraftState updateAdditionalStates(final SpacecraftState original) { + + final HermiteInterpolator interpolator = new HermiteInterpolator(); + + // Fill interpolator with sample + trimmer. + getNeighborsSubList(original.getDate(), coordinates). + forEach(c -> { + final double deltaT = c.getDate().durationFrom(original.getDate()); + if (filter.getMaxOrder() < 1) { + // we use only clock offset + interpolator.addSamplePoint(deltaT, + new double[] { c.getClockCorrection() }); + } else { + // we use both clock offset and clock rate + interpolator.addSamplePoint(deltaT, + new double[] { c.getClockCorrection() }, + new double[] { c.getClockRateChange() }); + } + }); + + // perform interpolation (we get derivatives even if we used only clock offset) + final double[][] derivatives = interpolator.derivatives(0.0, 1); + + // add the clock offset and its first derivative + return super.updateAdditionalStates(original). + addAdditionalState(SP3Utils.CLOCK_ADDITIONAL_STATE, derivatives[0]). + addAdditionalStateDerivative(SP3Utils.CLOCK_ADDITIONAL_STATE, derivatives[1]); - /** {@inheritDoc} */ - @Override - public double[] getAdditionalState(final SpacecraftState state) { - final Stream sample = - trimmer. - getNeighborsSubList(state.getDate(), coordinates). - stream(). - map(c -> new TimeStampedDouble(c.getClockCorrection(), c.getDate())); - final TimeStampedDouble interpolated = - interpolator.interpolate(state.getDate(), sample); - return new double[] { interpolated.getValue() }; } - } - /** Additional provider for clock with derivatives. - * @since 12.1 - */ - private class ClockProviderOrder1 implements AdditionalStateProvider { - - /** Interpolator for clock. */ - private final TimeStampedDoubleAndDerivativeHermiteInterpolator - interpolator; - - /** Trimmer for coordinates list. */ - private final SortedListTrimmer trimmer; - - /** Simple constructor. - */ - ClockProviderOrder1() { - // we don't use SP3CoordinateHermiteInterpolator - // because the underlying propagator already has interpolated position - // we only interpolate the additional state here - interpolator = new TimeStampedDoubleAndDerivativeHermiteInterpolator(getInterpolationSamples()); - trimmer = new SortedListTrimmer(getInterpolationSamples()); - } - - /** {@inheritDoc} */ - @Override - public String getName() { - return SP3Utils.CLOCK_ADDITIONAL_STATE; - } - - /** {@inheritDoc} */ - @Override - public double[] getAdditionalState(final SpacecraftState state) { - final Stream sample = - trimmer. - getNeighborsSubList(state.getDate(), coordinates). - stream(). - map(c -> new TimeStampedDoubleAndDerivative(c.getClockCorrection(), - c.getClockRateChange(), - c.getDate())); - final TimeStampedDoubleAndDerivative interpolated = - interpolator.interpolate(state.getDate(), sample); - return new double[] { interpolated.getValue() }; - } } } diff --git a/src/test/java/org/orekit/files/sp3/SP3ParserTest.java b/src/test/java/org/orekit/files/sp3/SP3ParserTest.java index 23fc903086..2574235d30 100644 --- a/src/test/java/org/orekit/files/sp3/SP3ParserTest.java +++ b/src/test/java/org/orekit/files/sp3/SP3ParserTest.java @@ -362,6 +362,12 @@ public void testSP3Propagator() { Assertions.assertEquals(expected.getClockCorrection(), s.getAdditionalState(SP3Utils.CLOCK_ADDITIONAL_STATE)[0], 1.0e-15); + SP3Coordinate previous = ephemeris.getSegments().get(0).getCoordinates().get(ephemeris.getSegments().get(0).getCoordinates().size() - 2); + final double deltaClock = expected.getClockCorrection() - previous.getClockCorrection(); + final double deltaT = expected.getDate().durationFrom(previous.getDate()); + Assertions.assertEquals(deltaClock / deltaT, + s.getAdditionalStateDerivative(SP3Utils.CLOCK_ADDITIONAL_STATE)[0], + 1.0e-26); ephemeris = file.getSatellites().get("E19"); propagator = ephemeris.getPropagator(new FrameAlignedProvider(ephemeris.getFrame())); diff --git a/src/test/java/org/orekit/orbits/FieldCircularOrbitTest.java b/src/test/java/org/orekit/orbits/FieldCircularOrbitTest.java index ffdd891372..047b2de7b0 100644 --- a/src/test/java/org/orekit/orbits/FieldCircularOrbitTest.java +++ b/src/test/java/org/orekit/orbits/FieldCircularOrbitTest.java @@ -29,7 +29,11 @@ import org.hipparchus.geometry.euclidean.threed.Vector3D; import org.hipparchus.linear.FieldMatrixPreservingVisitor; import org.hipparchus.linear.MatrixUtils; -import org.hipparchus.util.*; +import org.hipparchus.util.Binary64; +import org.hipparchus.util.Binary64Field; +import org.hipparchus.util.FastMath; +import org.hipparchus.util.MathArrays; +import org.hipparchus.util.MathUtils; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -449,7 +453,9 @@ private > void doTestCircularToEquinoctialEll( Assertions.assertEquals(param.getHy().getReal(), circ.getHy().getReal(), Utils.epsilonAngle * FastMath.abs(circ.getI().getReal())); - Assertions.assertEquals(MathUtils.normalizeAngle(param.getLv().getReal(), circ.getLv().getReal()), circ.getLv().getReal(), Utils.epsilonAngle * FastMath.abs(circ.getLv().getReal())); + Assertions.assertEquals(MathUtils.normalizeAngle(param.getLv().getReal(), circ.getLv().getReal()), + circ.getLv().getReal(), + Utils.epsilonAngle * FastMath.abs(circ.getLv().getReal())); Assertions.assertFalse(circ.hasDerivatives()); Assertions.assertNull(circ.getADot()); diff --git a/src/test/java/org/orekit/orbits/FieldEquinoctialOrbitTest.java b/src/test/java/org/orekit/orbits/FieldEquinoctialOrbitTest.java index c83bad9d85..e9c3fe8131 100644 --- a/src/test/java/org/orekit/orbits/FieldEquinoctialOrbitTest.java +++ b/src/test/java/org/orekit/orbits/FieldEquinoctialOrbitTest.java @@ -28,7 +28,11 @@ import org.hipparchus.geometry.euclidean.threed.FieldVector3D; import org.hipparchus.linear.FieldMatrixPreservingVisitor; import org.hipparchus.linear.MatrixUtils; -import org.hipparchus.util.*; +import org.hipparchus.util.Binary64; +import org.hipparchus.util.Binary64Field; +import org.hipparchus.util.FastMath; +import org.hipparchus.util.MathArrays; +import org.hipparchus.util.MathUtils; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -419,7 +423,7 @@ private > void doTestEquinoctialToEquinoctialE Assertions.assertEquals(param.getHy().getReal(), equi.getHy().getReal(), Utils.epsilonAngle * FastMath.abs(equi.getI().getReal())); Assertions.assertEquals(MathUtils.normalizeAngle(param.getLv().getReal(), equi.getLv().getReal()), equi.getLv().getReal(), - Utils.epsilonAngle * FastMath.abs(equi.getLv().getReal())); + Utils.epsilonAngle * FastMath.abs(equi.getLv().getReal())); } diff --git a/src/test/java/org/orekit/orbits/FieldKeplerianOrbitTest.java b/src/test/java/org/orekit/orbits/FieldKeplerianOrbitTest.java index 9a781d4871..7097ea48c3 100644 --- a/src/test/java/org/orekit/orbits/FieldKeplerianOrbitTest.java +++ b/src/test/java/org/orekit/orbits/FieldKeplerianOrbitTest.java @@ -28,7 +28,11 @@ import org.hipparchus.geometry.euclidean.threed.FieldVector3D; import org.hipparchus.linear.FieldMatrixPreservingVisitor; import org.hipparchus.linear.MatrixUtils; -import org.hipparchus.util.*; +import org.hipparchus.util.Binary64; +import org.hipparchus.util.Binary64Field; +import org.hipparchus.util.FastMath; +import org.hipparchus.util.MathArrays; +import org.hipparchus.util.MathUtils; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; From f1b55e06ce83d81b27f901652638db9fe1c9e9cd Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Fri, 23 Feb 2024 22:40:26 +0100 Subject: [PATCH 147/359] Fixed checkstyle errors. --- src/main/java/org/orekit/files/sp3/SP3Segment.java | 1 + .../java/org/orekit/utils/ImmutableFieldTimeStampedCache.java | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/orekit/files/sp3/SP3Segment.java b/src/main/java/org/orekit/files/sp3/SP3Segment.java index c276967c7c..9cf4ef615a 100644 --- a/src/main/java/org/orekit/files/sp3/SP3Segment.java +++ b/src/main/java/org/orekit/files/sp3/SP3Segment.java @@ -141,6 +141,7 @@ private class PropagatorWithClock extends EphemerisSegmentPropagator, CFE extends CalculusFieldElement> - ImmutableFieldTimeStampedCache emptyCache(final Field ignored) { + ImmutableFieldTimeStampedCache emptyCache(final Field ignored) { return emptyCache(); } @@ -128,7 +128,7 @@ ImmutableFieldTimeStampedCache emptyCache(final Field ignored) { */ @SuppressWarnings("unchecked") public static , CFE extends CalculusFieldElement> - ImmutableFieldTimeStampedCache emptyCache() { + ImmutableFieldTimeStampedCache emptyCache() { return (ImmutableFieldTimeStampedCache) EMPTY_CACHE; } From 9d46d7a49d3199baa247501dc88d51496fc2b9c0 Mon Sep 17 00:00:00 2001 From: Serrof Date: Fri, 23 Feb 2024 23:02:28 +0100 Subject: [PATCH 148/359] coverage in orbits --- .../org/orekit/orbits/CircularOrbitTest.java | 24 ++++- .../org/orekit/orbits/KeplerianOrbitTest.java | 99 ++++++++++++------- 2 files changed, 84 insertions(+), 39 deletions(-) diff --git a/src/test/java/org/orekit/orbits/CircularOrbitTest.java b/src/test/java/org/orekit/orbits/CircularOrbitTest.java index b306bc857f..1a0c14b9b2 100644 --- a/src/test/java/org/orekit/orbits/CircularOrbitTest.java +++ b/src/test/java/org/orekit/orbits/CircularOrbitTest.java @@ -52,7 +52,7 @@ import static org.orekit.OrekitMatchers.relativelyCloseTo; -public class CircularOrbitTest { +class CircularOrbitTest { // Computation date private AbsoluteDate date; @@ -1219,6 +1219,28 @@ void testCoverageCachedPositionAngleTypeWithRates() { } } + @Test + void testCoverageCachedPositionAngleTypeWithoutRates() { + // GIVEN + final double semiMajorAxis = 1e5; + final double eccentricity = 0.; + final double expectedAlpha = 0.; + // WHEN & THEN + for (final PositionAngleType inputPositionAngleType: PositionAngleType.values()) { + for (final PositionAngleType cachedPositionAngleType: PositionAngleType.values()) { + final CircularOrbit circularOrbit = new CircularOrbit(semiMajorAxis, eccentricity, 0., 0., 0., + expectedAlpha, inputPositionAngleType, cachedPositionAngleType, + FramesFactory.getGCRF(), date, mu); + Assertions.assertEquals(expectedAlpha, circularOrbit.getAlphaV()); + Assertions.assertEquals(expectedAlpha, circularOrbit.getAlphaM()); + Assertions.assertEquals(expectedAlpha, circularOrbit.getAlphaE()); + Assertions.assertEquals(Double.NaN, circularOrbit.getAlphaVDot()); + Assertions.assertEquals(Double.NaN, circularOrbit.getAlphaMDot()); + Assertions.assertEquals(Double.NaN, circularOrbit.getAlphaEDot()); + } + } + } + @BeforeEach public void setUp() { diff --git a/src/test/java/org/orekit/orbits/KeplerianOrbitTest.java b/src/test/java/org/orekit/orbits/KeplerianOrbitTest.java index b9d2cd4a3b..f9b473337a 100644 --- a/src/test/java/org/orekit/orbits/KeplerianOrbitTest.java +++ b/src/test/java/org/orekit/orbits/KeplerianOrbitTest.java @@ -52,7 +52,7 @@ import static org.orekit.OrekitMatchers.relativelyCloseTo; -public class KeplerianOrbitTest { +class KeplerianOrbitTest { // Computation date private AbsoluteDate date; @@ -61,7 +61,7 @@ public class KeplerianOrbitTest { private double mu; @Test - public void testKeplerianToKeplerian() { + void testKeplerianToKeplerian() { // elliptic orbit KeplerianOrbit kep = @@ -120,7 +120,7 @@ public void testKeplerianToKeplerian() { } @Test - public void testKeplerianToCartesian() { + void testKeplerianToCartesian() { KeplerianOrbit kep = new KeplerianOrbit(24464560.0, 0.7311, 0.122138, 3.10686, 1.00681, @@ -139,7 +139,7 @@ public void testKeplerianToCartesian() { } @Test - public void testKeplerianToEquinoctial() { + void testKeplerianToEquinoctial() { KeplerianOrbit kep = new KeplerianOrbit(24464560.0, 0.7311, 0.122138, 3.10686, 1.00681, @@ -155,7 +155,7 @@ public void testKeplerianToEquinoctial() { } @Test - public void testAnomaly() { + void testAnomaly() { Vector3D position = new Vector3D(7.0e6, 1.0e6, 4.0e6); Vector3D velocity = new Vector3D(-500.0, 8000.0, 1000.0); @@ -237,7 +237,7 @@ public void testAnomaly() { } @Test - public void testPositionVelocityNorms() { + void testPositionVelocityNorms() { double mu = 3.9860047e14; // elliptic and non equatorial orbit @@ -293,7 +293,7 @@ public void testPositionVelocityNorms() { } @Test - public void testGeometry() { + void testGeometry() { double mu = 3.9860047e14; // elliptic and non equatorial orbit @@ -397,7 +397,7 @@ public void testGeometry() { } @Test - public void testSymmetry() { + void testSymmetry() { // elliptic and non equatorial orbit Vector3D position = new Vector3D(-4947831., -3765382., -3708221.); @@ -428,7 +428,7 @@ public void testSymmetry() { } @Test - public void testNonInertialFrame() throws IllegalArgumentException { + void testNonInertialFrame() throws IllegalArgumentException { Assertions.assertThrows(IllegalArgumentException.class, () -> { Vector3D position = new Vector3D(-4947831., -3765382., -3708221.); Vector3D velocity = new Vector3D(-2079., 5291., -7842.); @@ -440,7 +440,7 @@ public void testNonInertialFrame() throws IllegalArgumentException { } @Test - public void testPeriod() { + void testPeriod() { KeplerianOrbit orbit = new KeplerianOrbit(7654321.0, 0.1, 0.2, 0, 0, 0, PositionAngleType.TRUE, FramesFactory.getEME2000(), AbsoluteDate.J2000_EPOCH, @@ -450,7 +450,7 @@ public void testPeriod() { } @Test - public void testHyperbola1() { + void testHyperbola1() { KeplerianOrbit orbit = new KeplerianOrbit(-10000000.0, 2.5, 0.3, 0, 0, 0.0, PositionAngleType.TRUE, FramesFactory.getEME2000(), AbsoluteDate.J2000_EPOCH, @@ -472,7 +472,7 @@ public void testHyperbola1() { } @Test - public void testHyperbola2() { + void testHyperbola2() { KeplerianOrbit orbit = new KeplerianOrbit(-10000000.0, 1.2, 0.3, 0, 0, -1.75, PositionAngleType.MEAN, FramesFactory.getEME2000(), AbsoluteDate.J2000_EPOCH, @@ -497,7 +497,7 @@ public void testHyperbola2() { } @Test - public void testInconsistentHyperbola() { + void testInconsistentHyperbola() { try { new KeplerianOrbit(+10000000.0, 2.5, 0.3, 0, 0, 0.0, PositionAngleType.TRUE, @@ -512,7 +512,7 @@ public void testInconsistentHyperbola() { } @Test - public void testVeryLargeEccentricity() { + void testVeryLargeEccentricity() { final Frame eme2000 = FramesFactory.getEME2000(); final double meanAnomaly = 1.; @@ -543,7 +543,7 @@ public void testVeryLargeEccentricity() { } @Test - public void testKeplerEquation() { + void testKeplerEquation() { for (double M = -6 * FastMath.PI; M < 6 * FastMath.PI; M += 0.01) { KeplerianOrbit pElliptic = @@ -568,7 +568,7 @@ public void testKeplerEquation() { } @Test - public void testOutOfRangeV() { + void testOutOfRangeV() { Assertions.assertThrows(IllegalArgumentException.class, () -> { new KeplerianOrbit(-7000434.460140012, 1.1999785407363386, 1.3962787004479158, 1.3962320168955138, 0.3490728321331678, -2.55593407037698, @@ -579,7 +579,7 @@ public void testOutOfRangeV() { } @Test - public void testNumericalIssue25() { + void testNumericalIssue25() { Vector3D position = new Vector3D(3782116.14107698, 416663.11924914, 5875541.62103057); Vector3D velocity = new Vector3D(-6349.7848910501, 288.4061811651, 4066.9366759691); KeplerianOrbit orbit = new KeplerianOrbit(new PVCoordinates(position, velocity), @@ -591,7 +591,7 @@ public void testNumericalIssue25() { } @Test - public void testPerfectlyEquatorial() { + void testPerfectlyEquatorial() { Vector3D position = new Vector3D(6957904.3624652653594, 766529.11411558074507, 0); Vector3D velocity = new Vector3D(-7538.2817012412102845, 342.38751001881413381, 0.); KeplerianOrbit orbit = new KeplerianOrbit(new PVCoordinates(position, velocity), @@ -604,7 +604,7 @@ public void testPerfectlyEquatorial() { } @Test - public void testJacobianReferenceEllipse() { + void testJacobianReferenceEllipse() { AbsoluteDate dateTca = new AbsoluteDate(2000, 04, 01, 0, 0, 0.000, TimeScalesFactory.getUTC()); double mu = 3.986004415e+14; @@ -685,7 +685,7 @@ public void testJacobianReferenceEllipse() { } @Test - public void testJacobianFinitedifferencesEllipse() { + void testJacobianFinitedifferencesEllipse() { AbsoluteDate dateTca = new AbsoluteDate(2000, 04, 01, 0, 0, 0.000, TimeScalesFactory.getUTC()); double mu = 3.986004415e+14; @@ -730,7 +730,7 @@ public double end() { } @Test - public void testJacobianReferenceHyperbola() { + void testJacobianReferenceHyperbola() { AbsoluteDate dateTca = new AbsoluteDate(2000, 04, 01, 0, 0, 0.000, TimeScalesFactory.getUTC()); double mu = 3.986004415e+14; @@ -815,7 +815,7 @@ public void testJacobianReferenceHyperbola() { } @Test - public void testJacobianFinitedifferencesHyperbola() { + void testJacobianFinitedifferencesHyperbola() { AbsoluteDate dateTca = new AbsoluteDate(2000, 04, 01, 0, 0, 0.000, TimeScalesFactory.getUTC()); double mu = 3.986004415e+14; @@ -950,7 +950,7 @@ private void fillColumn(PositionAngleType type, int i, KeplerianOrbit orbit, dou } @Test - public void testPerfectlyEquatorialConversion() { + void testPerfectlyEquatorialConversion() { KeplerianOrbit initial = new KeplerianOrbit(13378000.0, 0.05, 0.0, 0.0, FastMath.PI, 0.0, PositionAngleType.MEAN, FramesFactory.getEME2000(), date, @@ -964,7 +964,7 @@ public void testPerfectlyEquatorialConversion() { } @Test - public void testKeplerianDerivatives() { + void testKeplerianDerivatives() { final KeplerianOrbit orbit = new KeplerianOrbit(new PVCoordinates(new Vector3D(-4947831., -3765382., -3708221.), new Vector3D(-2079., 5291., -7842.)), @@ -1046,7 +1046,7 @@ public double value(double dt) { } @Test - public void testNonKeplerianEllipticDerivatives() { + void testNonKeplerianEllipticDerivatives() { final AbsoluteDate date = new AbsoluteDate("2003-05-01T00:00:20.000", TimeScalesFactory.getUTC()); final Vector3D position = new Vector3D(6896874.444705, 1956581.072644, -147476.245054); final Vector3D velocity = new Vector3D(166.816407662, -1106.783301861, -7372.745712770); @@ -1114,7 +1114,7 @@ public void testNonKeplerianEllipticDerivatives() { } @Test - public void testNonKeplerianHyperbolicDerivatives() { + void testNonKeplerianHyperbolicDerivatives() { final AbsoluteDate date = new AbsoluteDate("2003-05-01T00:00:20.000", TimeScalesFactory.getUTC()); final Vector3D position = new Vector3D(224267911.905821, 290251613.109399, 45534292.777492); final Vector3D velocity = new Vector3D(-1494.068165293, 1124.771027677, 526.915286134); @@ -1194,7 +1194,7 @@ public double value(double dt) { } @Test - public void testPositionAngleDerivatives() { + void testPositionAngleDerivatives() { final AbsoluteDate date = new AbsoluteDate("2003-05-01T00:00:20.000", TimeScalesFactory.getUTC()); final Vector3D position = new Vector3D(6896874.444705, 1956581.072644, -147476.245054); final Vector3D velocity = new Vector3D(166.816407662, -1106.783301861, -7372.745712770); @@ -1237,7 +1237,7 @@ public void testPositionAngleDerivatives() { } @Test - public void testPositionAngleHyperbolicDerivatives() { + void testPositionAngleHyperbolicDerivatives() { final AbsoluteDate date = new AbsoluteDate("2003-05-01T00:00:20.000", TimeScalesFactory.getUTC()); final Vector3D position = new Vector3D(224267911.905821, 290251613.109399, 45534292.777492); final Vector3D velocity = new Vector3D(-1494.068165293, 1124.771027677, 526.915286134); @@ -1280,7 +1280,7 @@ public void testPositionAngleHyperbolicDerivatives() { } @Test - public void testSerialization() + void testSerialization() throws IOException, ClassNotFoundException { Vector3D position = new Vector3D(-29536113.0, 30329259.0, -100125.0); Vector3D velocity = new Vector3D(-2194.0, -2141.0, -8.0); @@ -1316,7 +1316,7 @@ public void testSerialization() } @Test - public void testSerializationWithDerivatives() + void testSerializationWithDerivatives() throws IOException, ClassNotFoundException { Vector3D position = new Vector3D(-29536113.0, 30329259.0, -100125.0); Vector3D velocity = new Vector3D(-2194.0, -2141.0, -8.0); @@ -1356,7 +1356,7 @@ public void testSerializationWithDerivatives() } @Test - public void testEquatorialRetrograde() { + void testEquatorialRetrograde() { Vector3D position = new Vector3D(10000000.0, 0.0, 0.0); Vector3D velocity = new Vector3D(0.0, -6500.0, 1.0e-10); double r2 = position.getNormSq(); @@ -1378,7 +1378,7 @@ public void testEquatorialRetrograde() { } @Test - public void testDerivativesConversionSymmetry() { + void testDerivativesConversionSymmetry() { final AbsoluteDate date = new AbsoluteDate("2003-05-01T00:01:20.000", TimeScalesFactory.getUTC()); Vector3D position = new Vector3D(6893443.400234382, 1886406.1073757345, -589265.1150359757); Vector3D velocity = new Vector3D(-281.1261461082365, -1231.6165642450928, -7348.756363469432); @@ -1408,7 +1408,7 @@ public void testDerivativesConversionSymmetry() { } @Test - public void testDerivativesConversionSymmetryHyperbolic() { + void testDerivativesConversionSymmetryHyperbolic() { final AbsoluteDate date = new AbsoluteDate("2003-05-01T00:00:20.000", TimeScalesFactory.getUTC()); final Vector3D position = new Vector3D(224267911.905821, 290251613.109399, 45534292.777492); final Vector3D velocity = new Vector3D(-1494.068165293, 1124.771027677, 526.915286134); @@ -1437,7 +1437,7 @@ public void testDerivativesConversionSymmetryHyperbolic() { } @Test - public void testToString() { + void testToString() { Vector3D position = new Vector3D(-29536113.0, 30329259.0, -100125.0); Vector3D velocity = new Vector3D(-2194.0, -2141.0, -8.0); PVCoordinates pvCoordinates = new PVCoordinates(position, velocity); @@ -1471,7 +1471,7 @@ void testRemoveRates() { } @Test - public void testCopyNonKeplerianAcceleration() { + void testCopyNonKeplerianAcceleration() { final Frame eme2000 = FramesFactory.getEME2000(); @@ -1502,7 +1502,7 @@ public void testCopyNonKeplerianAcceleration() { } @Test - public void testIssue674() { + void testIssue674() { try { new KeplerianOrbit(24464560.0, -0.7311, 0.122138, 3.10686, 1.00681, 0.048363, PositionAngleType.MEAN, @@ -1518,7 +1518,7 @@ public void testIssue674() { } @Test - public void testNormalize() { + void testNormalize() { KeplerianOrbit withoutDerivatives = new KeplerianOrbit(42166712.0, 0.005, 1.6, -0.3, 1.25, 0.4, PositionAngleType.MEAN, @@ -1569,7 +1569,7 @@ public void testNormalize() { } @Test - public void testKeplerianToPvToKeplerian() { + void testKeplerianToPvToKeplerian() { // setup Frame eci = FramesFactory.getGCRF(); AbsoluteDate date = AbsoluteDate.ARBITRARY_EPOCH; @@ -1641,6 +1641,29 @@ void testCoverageCachedPositionAngleTypeWithRates() { } } + @Test + void testCoverageCachedPositionAngleTypeWithRatesHyperbolic() { + // GIVEN + final double semiMajorAxis = -1e4; + final double eccentricity = 2.; + final double expectedAnomaly = 0.; + final double expectedAnomalyDot = 0.; + // WHEN & THEN + for (final PositionAngleType inputPositionAngleType: PositionAngleType.values()) { + for (final PositionAngleType cachedPositionAngleType: PositionAngleType.values()) { + final KeplerianOrbit keplerianOrbit = new KeplerianOrbit(semiMajorAxis, eccentricity, 0., 0., 0., + expectedAnomaly, 0., 0., 0., 0., 0., expectedAnomalyDot, + inputPositionAngleType, cachedPositionAngleType, FramesFactory.getGCRF(), date, mu); + Assertions.assertEquals(expectedAnomaly, keplerianOrbit.getTrueAnomaly()); + Assertions.assertEquals(expectedAnomaly, keplerianOrbit.getEccentricAnomaly()); + Assertions.assertEquals(expectedAnomaly, keplerianOrbit.getMeanAnomaly()); + Assertions.assertEquals(expectedAnomalyDot, keplerianOrbit.getTrueAnomalyDot()); + Assertions.assertEquals(expectedAnomalyDot, keplerianOrbit.getEccentricAnomalyDot()); + Assertions.assertEquals(expectedAnomalyDot, keplerianOrbit.getMeanAnomalyDot()); + } + } + } + @BeforeEach public void setUp() { From 2214b86fa637395115a95d95441f421d4aea41d3 Mon Sep 17 00:00:00 2001 From: Serrof Date: Sat, 24 Feb 2024 00:02:45 +0100 Subject: [PATCH 149/359] Removed unnecessary calls to (Field)Transform in (Field)ShortTermEncounter2DDefinition. --- src/changes/changes.xml | 3 +++ .../FieldShortTermEncounter2DDefinition.java | 18 +++++++++--------- .../twod/ShortTermEncounter2DDefinition.java | 19 +++++++++---------- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index f2d7d3b021..b399e336c0 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -21,6 +21,9 @@ + + Removed unnecessary calls to (Field)Transform in (Field)ShortTermEncounter2DDefinition. + Added cache for position angle in FieldOrbit when applicable. diff --git a/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/FieldShortTermEncounter2DDefinition.java b/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/FieldShortTermEncounter2DDefinition.java index 521d58f04a..b44a08e2ac 100644 --- a/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/FieldShortTermEncounter2DDefinition.java +++ b/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/FieldShortTermEncounter2DDefinition.java @@ -30,6 +30,7 @@ import org.hipparchus.util.MathUtils; import org.orekit.errors.OrekitException; import org.orekit.errors.OrekitMessages; +import org.orekit.frames.FieldStaticTransform; import org.orekit.frames.FieldTransform; import org.orekit.frames.Frame; import org.orekit.frames.LOF; @@ -300,8 +301,8 @@ public FieldPVCoordinates computeOtherRelativeToReferencePVInReferenceInertia public FieldMatrix computeReferenceInertialToCollisionPlaneProjectionMatrix() { // Create transform from reference inertial frame to encounter local orbital frame - final FieldTransform referenceInertialToEncounterFrameTransform = - new FieldTransform<>(tca, + final FieldStaticTransform referenceInertialToEncounterFrameTransform = + FieldStaticTransform.compose(tca, computeReferenceInertialToReferenceTNWTransform(), computeReferenceTNWToEncounterFrameTransform()); @@ -381,18 +382,17 @@ public FieldStateCovariance computeCombinedCovarianceInEncounterFrame() { public FieldVector2D computeOtherPositionInCollisionPlane() { // Express other in reference inertial - final FieldPVCoordinates otherInReferenceInertial = otherAtTCA.getPVCoordinates(referenceAtTCA.getFrame()); + final FieldVector3D otherInReferenceInertial = otherAtTCA.getPosition(referenceAtTCA.getFrame()); // Express other in reference TNW local orbital frame - final FieldPVCoordinates otherPVInReferenceTNW = - computeReferenceInertialToReferenceTNWTransform().transformPVCoordinates(otherInReferenceInertial); + final FieldVector3D otherPositionInReferenceTNW = + computeReferenceInertialToReferenceTNWTransform().transformPosition(otherInReferenceInertial); // Express other in encounter local orbital frame - final FieldPVCoordinates otherPVInEncounterFrame = - computeReferenceTNWToEncounterFrameTransform().transformPVCoordinates( - otherPVInReferenceTNW); + final FieldVector3D otherPositionInEncounterFrame = + computeReferenceTNWToEncounterFrameTransform().transformPosition(otherPositionInReferenceTNW); - return encounterFrame.projectOntoCollisionPlane(otherPVInEncounterFrame.getPosition()); + return encounterFrame.projectOntoCollisionPlane(otherPositionInEncounterFrame); } diff --git a/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/ShortTermEncounter2DDefinition.java b/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/ShortTermEncounter2DDefinition.java index 6b79bdcc24..6b456e6997 100644 --- a/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/ShortTermEncounter2DDefinition.java +++ b/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/ShortTermEncounter2DDefinition.java @@ -29,6 +29,7 @@ import org.orekit.frames.Frame; import org.orekit.frames.LOF; import org.orekit.frames.LOFType; +import org.orekit.frames.StaticTransform; import org.orekit.frames.Transform; import org.orekit.frames.encounter.EncounterLOF; import org.orekit.frames.encounter.EncounterLOFType; @@ -271,9 +272,8 @@ public PVCoordinates computeOtherRelativeToReferencePVInReferenceInertial() { public RealMatrix computeReferenceInertialToCollisionPlaneProjectionMatrix() { // Create transform from reference inertial frame to encounter local orbital frame - final Transform referenceInertialToEncounterFrameTransform = - new Transform(tca, - computeReferenceInertialToReferenceTNWTransform(), + final StaticTransform referenceInertialToEncounterFrameTransform = + StaticTransform.compose(tca, computeReferenceInertialToReferenceTNWTransform(), computeReferenceTNWToEncounterFrameTransform()); // Create rotation matrix from reference inertial frame to encounter local orbital frame @@ -333,18 +333,17 @@ public StateCovariance computeCombinedCovarianceInEncounterFrame() { public Vector2D computeOtherPositionInCollisionPlane() { // Express other in reference inertial - final PVCoordinates otherInReferenceInertial = otherAtTCA.getPVCoordinates(referenceAtTCA.getFrame()); + final Vector3D otherInReferenceInertial = otherAtTCA.getPosition(referenceAtTCA.getFrame()); // Express other in reference TNW local orbital frame - final PVCoordinates otherPVInReferenceTNW = - computeReferenceInertialToReferenceTNWTransform().transformPVCoordinates(otherInReferenceInertial); + final Vector3D otherPositionInReferenceTNW = + computeReferenceInertialToReferenceTNWTransform().transformPosition(otherInReferenceInertial); // Express other in encounter local orbital frame - final PVCoordinates otherPVInEncounterFrame = - computeReferenceTNWToEncounterFrameTransform().transformPVCoordinates( - otherPVInReferenceTNW); + final Vector3D otherPositionInEncounterFrame = + computeReferenceTNWToEncounterFrameTransform().transformPosition(otherPositionInReferenceTNW); - return encounterFrame.projectOntoCollisionPlane(otherPVInEncounterFrame.getPosition()); + return encounterFrame.projectOntoCollisionPlane(otherPositionInEncounterFrame); } From 399d66ef167e80455174e9ab9cc7bde397955ceb Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Sun, 25 Feb 2024 10:09:10 +0100 Subject: [PATCH 150/359] Split common parameters container. --- .../CommonParametersWithDerivatives.java | 100 ++++++++++++++++++ .../CommonParametersWithoutDerivatives.java | 84 +++++++++++++++ ...ceiverCommonParametersWithDerivatives.java | 58 +--------- ...verCommonParametersWithoutDerivatives.java | 47 +------- 4 files changed, 188 insertions(+), 101 deletions(-) create mode 100644 src/main/java/org/orekit/estimation/measurements/CommonParametersWithDerivatives.java create mode 100644 src/main/java/org/orekit/estimation/measurements/CommonParametersWithoutDerivatives.java diff --git a/src/main/java/org/orekit/estimation/measurements/CommonParametersWithDerivatives.java b/src/main/java/org/orekit/estimation/measurements/CommonParametersWithDerivatives.java new file mode 100644 index 0000000000..eef46e361a --- /dev/null +++ b/src/main/java/org/orekit/estimation/measurements/CommonParametersWithDerivatives.java @@ -0,0 +1,100 @@ +/* Copyright 2002-2024 Luc Maisonobe + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.estimation.measurements; + +import org.hipparchus.analysis.differentiation.Gradient; +import org.orekit.propagation.SpacecraftState; +import org.orekit.utils.TimeStampedFieldPVCoordinates; + +import java.util.Map; + +/** Common intermediate parameters used to estimate measurements where receiver is a ground station. + * @author Luc Maisonobe + * @since 12.1 + */ +public class CommonParametersWithDerivatives { + + /** Spacecraft state. */ + private final SpacecraftState state; + + /** Derivatives indices map. */ + private final Map indices; + + /** Downlink delay. */ + private final Gradient tauD; + + /** Transit state. */ + private final SpacecraftState transitState; + + /** Transit state. */ + private final TimeStampedFieldPVCoordinates transitPV; + + /** Simple constructor. + * @param state spacecraft state + * @param indices derivatives indices map + * @param tauD downlink delay + * @param transitState transit state + * @param transitPV transit position/velocity as a gradient + */ + public CommonParametersWithDerivatives(final SpacecraftState state, + final Map indices, + final Gradient tauD, + final SpacecraftState transitState, + final TimeStampedFieldPVCoordinates transitPV) { + this.state = state; + this.indices = indices; + this.tauD = tauD; + this.transitState = transitState; + this.transitPV = transitPV; + } + + /** Get spacecraft state. + * @return spacecraft state + */ + public SpacecraftState getState() { + return state; + } + + /** Get derivatives indices map. + * @return derivatives indices map + */ + public Map getIndices() { + return indices; + } + + /** Get downlink delay. + * @return ownlink delay + */ + public Gradient getTauD() { + return tauD; + } + + /** Get transit state. + * @return transit state + */ + public SpacecraftState getTransitState() { + return transitState; + } + + /** Get transit position/velocity. + * @return transit position/velocity + */ + public TimeStampedFieldPVCoordinates getTransitPV() { + return transitPV; + } + +} diff --git a/src/main/java/org/orekit/estimation/measurements/CommonParametersWithoutDerivatives.java b/src/main/java/org/orekit/estimation/measurements/CommonParametersWithoutDerivatives.java new file mode 100644 index 0000000000..f8d2720dbe --- /dev/null +++ b/src/main/java/org/orekit/estimation/measurements/CommonParametersWithoutDerivatives.java @@ -0,0 +1,84 @@ +/* Copyright 2002-2024 Luc Maisonobe + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.estimation.measurements; + +import org.orekit.propagation.SpacecraftState; +import org.orekit.utils.TimeStampedPVCoordinates; + +/** Common intermediate parameters used to estimate measurements. + * @author Luc Maisonobe + * @since 12.1 + */ +public class CommonParametersWithoutDerivatives { + + /** Spacecraft state. */ + private final SpacecraftState state; + + /** Downlink delay. */ + private final double tauD; + + /** Transit state. */ + private final SpacecraftState transitState; + + /** Transit position/velocity. */ + private final TimeStampedPVCoordinates transitPV; + + /** Simple constructor. + * @param state spacecraft state + * @param tauD downlink delay + * @param transitState transit state + * @param transitPV transit position/velocity + */ + public CommonParametersWithoutDerivatives(final SpacecraftState state, + final double tauD, + final SpacecraftState transitState, + final TimeStampedPVCoordinates transitPV) { + this.state = state; + this.tauD = tauD; + this.transitState = transitState; + this.transitPV = transitPV; + } + + /** Get spacecraft state. + * @return spacecraft state + */ + public SpacecraftState getState() { + return state; + } + + /** Get downlink delay. + * @return ownlink delay + */ + public double getTauD() { + return tauD; + } + + /** Get transit state. + * @return transit state + */ + public SpacecraftState getTransitState() { + return transitState; + } + + /** Get transit position/velocity. + * @return transit position/velocity + */ + public TimeStampedPVCoordinates getTransitPV() { + return transitPV; + } + +} diff --git a/src/main/java/org/orekit/estimation/measurements/GroundReceiverCommonParametersWithDerivatives.java b/src/main/java/org/orekit/estimation/measurements/GroundReceiverCommonParametersWithDerivatives.java index 6f4eac4c41..84d9f84773 100644 --- a/src/main/java/org/orekit/estimation/measurements/GroundReceiverCommonParametersWithDerivatives.java +++ b/src/main/java/org/orekit/estimation/measurements/GroundReceiverCommonParametersWithDerivatives.java @@ -27,13 +27,7 @@ * @author Luc Maisonobe * @since 12.0 */ -public class GroundReceiverCommonParametersWithDerivatives { - - /** Spacecraft state. */ - private final SpacecraftState state; - - /** Derivatives indices map. */ - private final Map indices; +public class GroundReceiverCommonParametersWithDerivatives extends CommonParametersWithDerivatives { /** Transform between station and inertial frame. */ private final FieldTransform offsetToInertialDownlink; @@ -41,15 +35,6 @@ public class GroundReceiverCommonParametersWithDerivatives { /** Station position in inertial frame at end of the downlink leg. */ private final TimeStampedFieldPVCoordinates stationDownlink; - /** Downlink delay. */ - private final Gradient tauD; - - /** Transit state. */ - private final SpacecraftState transitState; - - /** Transit state. */ - private final TimeStampedFieldPVCoordinates transitPV; - /** Simple constructor. * @param state spacecraft state * @param indices derivatives indices map @@ -66,27 +51,9 @@ public GroundReceiverCommonParametersWithDerivatives(final SpacecraftState state final Gradient tauD, final SpacecraftState transitState, final TimeStampedFieldPVCoordinates transitPV) { - this.state = state; - this.indices = indices; + super(state, indices, tauD, transitState, transitPV); this.offsetToInertialDownlink = offsetToInertialDownlink; this.stationDownlink = stationDownlink; - this.tauD = tauD; - this.transitState = transitState; - this.transitPV = transitPV; - } - - /** Get spacecraft state. - * @return spacecraft state - */ - public SpacecraftState getState() { - return state; - } - - /** Get derivatives indices map. - * @return derivatives indices map - */ - public Map getIndices() { - return indices; } /** Get transform between station and inertial frame. @@ -103,25 +70,4 @@ public TimeStampedFieldPVCoordinates getStationDownlink() { return stationDownlink; } - /** Get downlink delay. - * @return ownlink delay - */ - public Gradient getTauD() { - return tauD; - } - - /** Get transit state. - * @return transit state - */ - public SpacecraftState getTransitState() { - return transitState; - } - - /** Get transit position/velocity. - * @return transit position/velocity - */ - public TimeStampedFieldPVCoordinates getTransitPV() { - return transitPV; - } - } diff --git a/src/main/java/org/orekit/estimation/measurements/GroundReceiverCommonParametersWithoutDerivatives.java b/src/main/java/org/orekit/estimation/measurements/GroundReceiverCommonParametersWithoutDerivatives.java index db5a612df8..0ea224e21d 100644 --- a/src/main/java/org/orekit/estimation/measurements/GroundReceiverCommonParametersWithoutDerivatives.java +++ b/src/main/java/org/orekit/estimation/measurements/GroundReceiverCommonParametersWithoutDerivatives.java @@ -24,10 +24,7 @@ * @author Luc Maisonobe * @since 12.0 */ -public class GroundReceiverCommonParametersWithoutDerivatives { - - /** Spacecraft state. */ - private final SpacecraftState state; +public class GroundReceiverCommonParametersWithoutDerivatives extends CommonParametersWithoutDerivatives { /** Transform between station and inertial frame. */ private final Transform offsetToInertialDownlink; @@ -35,15 +32,6 @@ public class GroundReceiverCommonParametersWithoutDerivatives { /** Station position in inertial frame at end of the downlink leg. */ private final TimeStampedPVCoordinates stationDownlink; - /** Downlink delay. */ - private final double tauD; - - /** Transit state. */ - private final SpacecraftState transitState; - - /** Transit position/velocity. */ - private final TimeStampedPVCoordinates transitPV; - /** Simple constructor. * @param state spacecraft state * @param offsetToInertialDownlink transform between station and inertial frame @@ -58,19 +46,9 @@ public GroundReceiverCommonParametersWithoutDerivatives(final SpacecraftState st final double tauD, final SpacecraftState transitState, final TimeStampedPVCoordinates transitPV) { - this.state = state; + super(state, tauD, transitState, transitPV); this.offsetToInertialDownlink = offsetToInertialDownlink; this.stationDownlink = stationDownlink; - this.tauD = tauD; - this.transitState = transitState; - this.transitPV = transitPV; - } - - /** Get spacecraft state. - * @return spacecraft state - */ - public SpacecraftState getState() { - return state; } /** Get transform between station and inertial frame. @@ -87,25 +65,4 @@ public TimeStampedPVCoordinates getStationDownlink() { return stationDownlink; } - /** Get downlink delay. - * @return ownlink delay - */ - public double getTauD() { - return tauD; - } - - /** Get transit state. - * @return transit state - */ - public SpacecraftState getTransitState() { - return transitState; - } - - /** Get transit position/velocity. - * @return transit position/velocity - */ - public TimeStampedPVCoordinates getTransitPV() { - return transitPV; - } - } From 2b7f95a538a204942b4308b140dc34125008aaad Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Sun, 25 Feb 2024 12:28:40 +0100 Subject: [PATCH 151/359] Whitespace. --- .../estimation/measurements/EstimatedMeasurementBase.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/orekit/estimation/measurements/EstimatedMeasurementBase.java b/src/main/java/org/orekit/estimation/measurements/EstimatedMeasurementBase.java index 1e9d65314c..6f301f60f8 100644 --- a/src/main/java/org/orekit/estimation/measurements/EstimatedMeasurementBase.java +++ b/src/main/java/org/orekit/estimation/measurements/EstimatedMeasurementBase.java @@ -57,9 +57,9 @@ public class EstimatedMeasurementBase> implemen * in inertial frame */ public EstimatedMeasurementBase(final T observedMeasurement, - final int iteration, final int count, - final SpacecraftState[] states, - final TimeStampedPVCoordinates[] participants) { + final int iteration, final int count, + final SpacecraftState[] states, + final TimeStampedPVCoordinates[] participants) { this.observedMeasurement = observedMeasurement; this.iteration = iteration; this.count = count; From fd7c1f763a2b8bb2f389773cacf24b921cc17927 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Sun, 25 Feb 2024 12:29:03 +0100 Subject: [PATCH 152/359] Javadoc. --- src/main/java/org/orekit/estimation/measurements/RangeRate.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/org/orekit/estimation/measurements/RangeRate.java b/src/main/java/org/orekit/estimation/measurements/RangeRate.java index 7e4d29d065..0c45344067 100644 --- a/src/main/java/org/orekit/estimation/measurements/RangeRate.java +++ b/src/main/java/org/orekit/estimation/measurements/RangeRate.java @@ -222,7 +222,6 @@ protected EstimatedMeasurement theoreticalEvaluation(final int iterat * @param transitPV spacecraft coordinates at onboard signal transit * @param transitState orbital state at onboard signal transit * @return theoretical value - * @see #evaluate(SpacecraftStatet) * @since 12.0 */ private EstimatedMeasurementBase oneWayTheoreticalEvaluation(final int iteration, final int evaluation, final boolean downlink, @@ -283,7 +282,6 @@ private EstimatedMeasurementBase oneWayTheoreticalEvaluation(final in * @param indices indices of the estimated parameters in derivatives computations * @param nbParams the number of estimated parameters in derivative computations * @return theoretical value - * @see #evaluate(SpacecraftStatet) */ private EstimatedMeasurement oneWayTheoreticalEvaluation(final int iteration, final int evaluation, final boolean downlink, final TimeStampedFieldPVCoordinates stationPV, From 005d6347f3c5f2127d937364ce4d2a7d3542fac8 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Sun, 25 Feb 2024 12:29:32 +0100 Subject: [PATCH 153/359] Fixed wrong states and PV dates. --- .../measurements/gnss/OneWayGNSSPhase.java | 32 +++++++------------ .../measurements/gnss/OneWayGNSSRange.java | 30 +++++++---------- .../gnss/OneWayGNSSRangeTest.java | 3 +- 3 files changed, 26 insertions(+), 39 deletions(-) diff --git a/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSPhase.java b/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSPhase.java index 36b4f14265..d2487a0cb4 100644 --- a/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSPhase.java +++ b/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSPhase.java @@ -136,22 +136,18 @@ protected EstimatedMeasurementBase theoreticalEvaluationWithout final double dtLocal = getSatellites().get(0).getClockOffsetDriver().getValue(localState.getDate()); final AbsoluteDate arrivalDate = getDate().shiftedBy(-dtLocal); - final TimeStampedPVCoordinates s1Downlink = - pvaLocal.shiftedBy(arrivalDate.durationFrom(pvaLocal.getDate())); - final double tauD = signalTimeOfFlight(pvaRemote, s1Downlink.getPosition(), arrivalDate); - - // Transit state - final double delta = getDate().durationFrom(pvaRemote.getDate()); - final double deltaMTauD = delta - tauD; + final SpacecraftState sDownlink = localState.shiftedBy(arrivalDate.durationFrom(localState.getDate())); + final TimeStampedPVCoordinates pvaDownlink = pvaLocal.shiftedBy(arrivalDate.durationFrom(pvaLocal.getDate())); + final double tauD = signalTimeOfFlight(pvaRemote, pvaDownlink.getPosition(), arrivalDate); // prepare the evaluation final EstimatedMeasurementBase estimatedPhase = new EstimatedMeasurementBase<>(this, iteration, evaluation, new SpacecraftState[] { - localState.shiftedBy(deltaMTauD) + sDownlink }, new TimeStampedPVCoordinates[] { - pvaRemote.shiftedBy(delta - tauD), - localState.shiftedBy(delta).getPVCoordinates() + pvaRemote.shiftedBy(-(dtLocal + tauD)), + sDownlink.getPVCoordinates() }); // Phase value @@ -197,23 +193,19 @@ protected EstimatedMeasurement theoreticalEvaluation(final int final Gradient dtLocal = getSatellites().get(0).getClockOffsetDriver().getValue(nbEstimatedParamsPhase, parameterIndicesPhase, localState.getDate()); final FieldAbsoluteDate arrivalDate = new FieldAbsoluteDate<>(getDate(), dtLocal.negate()); - final TimeStampedFieldPVCoordinates s1Downlink = - pvaLocal.shiftedBy(arrivalDate.durationFrom(pvaLocal.getDate())); + final SpacecraftState sDownlink = localState.shiftedBy(arrivalDate.toAbsoluteDate().durationFrom(localState.getDate())); + final TimeStampedFieldPVCoordinates pvaDownlink = pvaLocal.shiftedBy(arrivalDate.durationFrom(pvaLocal.getDate())); final Gradient tauD = signalTimeOfFlight(new TimeStampedFieldPVCoordinates<>(pvaRemote.getDate(), dtLocal.getField().getOne(), pvaRemote), - s1Downlink.getPosition(), arrivalDate); - - // Transit state - final double delta = getDate().durationFrom(pvaRemote.getDate()); - final Gradient deltaMTauD = tauD.negate().add(delta); + pvaDownlink.getPosition(), arrivalDate); // prepare the evaluation final EstimatedMeasurement estimatedPhase = new EstimatedMeasurement<>(this, iteration, evaluation, new SpacecraftState[] { - localState.shiftedBy(deltaMTauD.getValue()) + sDownlink }, new TimeStampedPVCoordinates[] { - pvaRemote.shiftedBy(delta - tauD.getValue()), - localState.shiftedBy(delta).getPVCoordinates() + pvaRemote.shiftedBy(-(dtLocal.getValue() + tauD.getValue())), + sDownlink.getPVCoordinates() }); // Phase value diff --git a/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRange.java b/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRange.java index 6f6a141fb6..917b98ac69 100644 --- a/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRange.java +++ b/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRange.java @@ -105,21 +105,18 @@ protected EstimatedMeasurementBase theoreticalEvaluationWithout final double dtLocal = getSatellites().get(0).getClockOffsetDriver().getValue(localState.getDate()); final AbsoluteDate arrivalDate = getDate().shiftedBy(-dtLocal); - final TimeStampedPVCoordinates s1Downlink = pvaLocal.shiftedBy(arrivalDate.durationFrom(pvaLocal.getDate())); - final double tauD = signalTimeOfFlight(pvaRemote, s1Downlink.getPosition(), arrivalDate); - - // Transit state - final double delta = getDate().durationFrom(pvaRemote.getDate()); - final double deltaMTauD = delta - tauD; + final SpacecraftState sDownlink = localState.shiftedBy(arrivalDate.durationFrom(localState.getDate())); + final TimeStampedPVCoordinates pvaDownlink = pvaLocal.shiftedBy(arrivalDate.durationFrom(pvaLocal.getDate())); + final double tauD = signalTimeOfFlight(pvaRemote, pvaDownlink.getPosition(), arrivalDate); // Estimated measurement final EstimatedMeasurementBase estimatedRange = new EstimatedMeasurementBase<>(this, iteration, evaluation, new SpacecraftState[] { - localState.shiftedBy(deltaMTauD) + sDownlink }, new TimeStampedPVCoordinates[] { - pvaRemote.shiftedBy(delta - tauD), - localState.shiftedBy(delta).getPVCoordinates() + pvaRemote.shiftedBy(-(dtLocal + tauD)), + sDownlink.getPVCoordinates() }); // Range value @@ -163,22 +160,19 @@ protected EstimatedMeasurement theoreticalEvaluation(final int final Gradient dtLocal = getSatellites().get(0).getClockOffsetDriver().getValue(nbEstimatedParams, parameterIndices, localState.getDate()); final FieldAbsoluteDate arrivalDate = new FieldAbsoluteDate<>(getDate(), dtLocal.negate()); - final TimeStampedFieldPVCoordinates s1Downlink = pvaLocal.shiftedBy(arrivalDate.durationFrom(pvaLocal.getDate())); + final SpacecraftState sDownlink = localState.shiftedBy(arrivalDate.toAbsoluteDate().durationFrom(localState.getDate())); + final TimeStampedFieldPVCoordinates pvaDownlink = pvaLocal.shiftedBy(arrivalDate.durationFrom(pvaLocal.getDate())); final Gradient tauD = signalTimeOfFlight(new TimeStampedFieldPVCoordinates<>(pvaRemote.getDate(), dtLocal.getField().getOne(), pvaRemote), - s1Downlink.getPosition(), arrivalDate); - - // Transit state - final double delta = getDate().durationFrom(pvaRemote.getDate()); - final Gradient deltaMTauD = tauD.negate().add(delta); + pvaDownlink.getPosition(), arrivalDate); // Estimated measurement final EstimatedMeasurement estimatedRange = new EstimatedMeasurement<>(this, iteration, evaluation, new SpacecraftState[] { - localState.shiftedBy(deltaMTauD.getValue()) + sDownlink }, new TimeStampedPVCoordinates[] { - pvaRemote.shiftedBy(delta - tauD.getValue()), - localState.shiftedBy(delta).getPVCoordinates() + pvaRemote.shiftedBy(-(dtLocal.getValue() + tauD.getValue())), + sDownlink.getPVCoordinates() }); // Range value diff --git a/src/test/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRangeTest.java b/src/test/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRangeTest.java index d1e4bb4a82..c286894fa2 100644 --- a/src/test/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRangeTest.java +++ b/src/test/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRangeTest.java @@ -31,6 +31,7 @@ import org.junit.jupiter.api.Test; import org.orekit.estimation.Context; import org.orekit.estimation.EstimationTestUtils; +import org.orekit.estimation.measurements.EstimatedMeasurement; import org.orekit.estimation.measurements.EstimatedMeasurementBase; import org.orekit.estimation.measurements.ObservedMeasurement; import org.orekit.orbits.CartesianOrbit; @@ -236,7 +237,7 @@ void genericTestValues(final boolean printResults) { } Assertions.assertEquals(0.0, absErrorsMedian, 1.3e-7); - Assertions.assertEquals(0.0, absErrorsMin, 6.5e-6); + Assertions.assertEquals(0.0, absErrorsMin, 6.5e-7); Assertions.assertEquals(0.0, absErrorsMax, 1.7e-7); Assertions.assertEquals(0.0, relErrorsMedian, 5.3e-12); Assertions.assertEquals(0.0, relErrorsMax, 7.6e-11); From 095b42d65ccb761606404af5229f4d72cd882ab6 Mon Sep 17 00:00:00 2001 From: Serrof Date: Sat, 24 Feb 2024 14:11:01 +0100 Subject: [PATCH 154/359] changed default PositionAngleType in (Field)NumericalPropagator to ECCENTRIC (#1201) --- src/changes/changes.xml | 3 ++ .../java/org/orekit/orbits/CircularOrbit.java | 9 ++-- .../org/orekit/orbits/EquinoctialOrbit.java | 9 ++-- .../org/orekit/orbits/FieldCircularOrbit.java | 9 ++-- .../orekit/orbits/FieldEquinoctialOrbit.java | 9 ++-- .../numerical/FieldNumericalPropagator.java | 24 +++++---- .../numerical/NumericalPropagator.java | 22 ++++++--- .../forces/drag/TimeSpanDragForceTest.java | 4 +- .../HarmonicAccelerationModelTest.java | 16 ++++-- .../PolynomialAccelerationModelTest.java | 13 +++-- ...HolmesFeatherstoneAttractionModelTest.java | 6 ++- .../maneuvers/ConstantThrustManeuverTest.java | 30 ++++++------ .../maneuvers/FieldImpulseManeuverTest.java | 34 +++++++------ .../SmallManeuverAnalyticalModelTest.java | 11 +++-- .../ProfileThrustPropulsionModelTest.java | 13 +++-- .../radiation/SolarRadiationPressureTest.java | 49 ++++++++++--------- .../BrouwerLyddanePropagatorTest.java | 1 + .../EcksteinHechlerPropagatorTest.java | 1 + .../FieldBrouwerLyddanePropagatorTest.java | 1 + .../FieldEcksteinHechlerPropagatorTest.java | 1 + .../events/EclipseDetectorTest.java | 18 +++---- ...{PickupHandler.java => PickUpHandler.java} | 0 22 files changed, 166 insertions(+), 117 deletions(-) rename src/test/java/org/orekit/propagation/numerical/{PickupHandler.java => PickUpHandler.java} (100%) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index b399e336c0..5c01fe2f38 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -21,6 +21,9 @@ + + Changed default PositionAngleType in (Field)NumericalPropagator to ECCENTRIC. + Removed unnecessary calls to (Field)Transform in (Field)ShortTermEncounter2DDefinition. diff --git a/src/main/java/org/orekit/orbits/CircularOrbit.java b/src/main/java/org/orekit/orbits/CircularOrbit.java index 28461354d0..2405d81bf2 100644 --- a/src/main/java/org/orekit/orbits/CircularOrbit.java +++ b/src/main/java/org/orekit/orbits/CircularOrbit.java @@ -1405,17 +1405,18 @@ public void addKeplerContribution(final PositionAngleType type, final double gm, final double oMe2; final double ksi; final double n = FastMath.sqrt(gm / a) / a; - final SinCos sc = FastMath.sinCos(getAlphaV()); + final SinCos sc; switch (type) { case MEAN : pDot[5] += n; break; case ECCENTRIC : - oMe2 = 1 - ex * ex - ey * ey; - ksi = 1 + ex * sc.cos() + ey * sc.sin(); - pDot[5] += n * ksi / oMe2; + sc = FastMath.sinCos(getAlphaE()); + ksi = 1. / (1 - ex * sc.cos() - ey * sc.sin()); + pDot[5] += n * ksi; break; case TRUE : + sc = FastMath.sinCos(getAlphaV()); oMe2 = 1 - ex * ex - ey * ey; ksi = 1 + ex * sc.cos() + ey * sc.sin(); pDot[5] += n * ksi * ksi / (oMe2 * FastMath.sqrt(oMe2)); diff --git a/src/main/java/org/orekit/orbits/EquinoctialOrbit.java b/src/main/java/org/orekit/orbits/EquinoctialOrbit.java index fe2939342d..7b7fb0feac 100644 --- a/src/main/java/org/orekit/orbits/EquinoctialOrbit.java +++ b/src/main/java/org/orekit/orbits/EquinoctialOrbit.java @@ -1134,17 +1134,18 @@ public void addKeplerContribution(final PositionAngleType type, final double gm, final double oMe2; final double ksi; final double n = FastMath.sqrt(gm / a) / a; - final SinCos sc = FastMath.sinCos(getLv()); + final SinCos sc; switch (type) { case MEAN : pDot[5] += n; break; case ECCENTRIC : - oMe2 = 1 - ex * ex - ey * ey; - ksi = 1 + ex * sc.cos() + ey * sc.sin(); - pDot[5] += n * ksi / oMe2; + sc = FastMath.sinCos(getLE()); + ksi = 1. / (1 - ex * sc.cos() - ey * sc.sin()); + pDot[5] += n * ksi; break; case TRUE : + sc = FastMath.sinCos(getLv()); oMe2 = 1 - ex * ex - ey * ey; ksi = 1 + ex * sc.cos() + ey * sc.sin(); pDot[5] += n * ksi * ksi / (oMe2 * FastMath.sqrt(oMe2)); diff --git a/src/main/java/org/orekit/orbits/FieldCircularOrbit.java b/src/main/java/org/orekit/orbits/FieldCircularOrbit.java index 4b400ae4c6..f82e8aa824 100644 --- a/src/main/java/org/orekit/orbits/FieldCircularOrbit.java +++ b/src/main/java/org/orekit/orbits/FieldCircularOrbit.java @@ -1483,17 +1483,18 @@ public void addKeplerContribution(final PositionAngleType type, final T gm, final T oMe2; final T ksi; final T n = a.reciprocal().multiply(gm).sqrt().divide(a); - final FieldSinCos sc = FastMath.sinCos(getAlphaV()); + final FieldSinCos sc; switch (type) { case MEAN : pDot[5] = pDot[5].add(n); break; case ECCENTRIC : - oMe2 = getOne().subtract(ex.multiply(ex)).subtract(ey.multiply(ey)); - ksi = getOne().add(ex.multiply(sc.cos())).add(ey.multiply(sc.sin())); - pDot[5] = pDot[5].add(n.multiply(ksi).divide(oMe2)); + sc = FastMath.sinCos(getAlphaE()); + ksi = ((ex.multiply(sc.cos())).add(ey.multiply(sc.sin()))).negate().add(1).reciprocal(); + pDot[5] = pDot[5].add(n.multiply(ksi)); break; case TRUE : + sc = FastMath.sinCos(getAlphaV()); oMe2 = getOne().subtract(ex.multiply(ex)).subtract(ey.multiply(ey)); ksi = getOne().add(ex.multiply(sc.cos())).add(ey.multiply(sc.sin())); pDot[5] = pDot[5].add(n.multiply(ksi).multiply(ksi).divide(oMe2.multiply(oMe2.sqrt()))); diff --git a/src/main/java/org/orekit/orbits/FieldEquinoctialOrbit.java b/src/main/java/org/orekit/orbits/FieldEquinoctialOrbit.java index 82fea2ae40..7915f59df2 100644 --- a/src/main/java/org/orekit/orbits/FieldEquinoctialOrbit.java +++ b/src/main/java/org/orekit/orbits/FieldEquinoctialOrbit.java @@ -1241,17 +1241,18 @@ public void addKeplerContribution(final PositionAngleType type, final T gm, final T oMe2; final T ksi; final T n = gm.divide(a).sqrt().divide(a); - final FieldSinCos sc = FastMath.sinCos(getLv()); + final FieldSinCos sc; switch (type) { case MEAN : pDot[5] = pDot[5].add(n); break; case ECCENTRIC : - oMe2 = getOne().subtract(ex.square()).subtract(ey.square()); - ksi = ex.multiply(sc.cos()).add(1).add(ey.multiply(sc.sin())); - pDot[5] = pDot[5].add(n.multiply(ksi).divide(oMe2)); + sc = FastMath.sinCos(getLE()); + ksi = ((ex.multiply(sc.cos())).add(ey.multiply(sc.sin()))).negate().add(1).reciprocal(); + pDot[5] = pDot[5].add(n.multiply(ksi)); break; case TRUE : + sc = FastMath.sinCos(getLv()); oMe2 = getOne().subtract(ex.square()).subtract(ey.square()); ksi = ex.multiply(sc.cos()).add(1).add(ey.multiply(sc.sin())); pDot[5] = pDot[5].add(n.multiply(ksi).multiply(ksi).divide(oMe2.multiply(oMe2.sqrt()))); diff --git a/src/main/java/org/orekit/propagation/numerical/FieldNumericalPropagator.java b/src/main/java/org/orekit/propagation/numerical/FieldNumericalPropagator.java index 356dd839a9..b6e7c67e5c 100644 --- a/src/main/java/org/orekit/propagation/numerical/FieldNumericalPropagator.java +++ b/src/main/java/org/orekit/propagation/numerical/FieldNumericalPropagator.java @@ -126,7 +126,7 @@ * *

                  By default, at the end of the propagation, the propagator resets the initial state to the final state, * thus allowing a new propagation to be started from there without recomputing the part already performed. - * This behaviour can be chenged by calling {@link #setResetAtEnd(boolean)}. + * This behaviour can be changed by calling {@link #setResetAtEnd(boolean)}. *

                  *

                  Beware the same instance cannot be used simultaneously by different threads, the class is not * thread-safe.

                  @@ -196,13 +196,13 @@ public FieldNumericalPropagator(final Field field, final AttitudeProvider attitudeProvider) { super(field, integrator, PropagationType.OSCULATING); this.field = field; - forceModels = new ArrayList(); + forceModels = new ArrayList<>(); initMapper(field); setAttitudeProvider(attitudeProvider); setMu(field.getZero().add(Double.NaN)); clearStepHandlers(); setOrbitType(OrbitType.EQUINOCTIAL); - setPositionAngleType(PositionAngleType.TRUE); + setPositionAngleType(PositionAngleType.ECCENTRIC); } /** Set the flag to ignore or not the creation of a {@link NewtonianAttraction}. @@ -213,16 +213,17 @@ public void setIgnoreCentralAttraction(final boolean ignoreCentralAttraction) { this.ignoreCentralAttraction = ignoreCentralAttraction; } - /** Set the central attraction coefficient μ. - *

                  - * Setting the central attraction coefficient is - * equivalent to {@link #addForceModel(ForceModel) add} - * a {@link NewtonianAttraction} force model. - *

                  + /** Set the central attraction coefficient μ. + *

                  + * Setting the central attraction coefficient is + * equivalent to {@link #addForceModel(ForceModel) add} + * a {@link NewtonianAttraction} force model. + *

                  * @param mu central attraction coefficient (m³/s²) * @see #addForceModel(ForceModel) * @see #getAllForceModels() */ + @Override public void setMu(final T mu) { if (ignoreCentralAttraction) { superSetMu(mu); @@ -327,6 +328,7 @@ public List getAllForceModels() { /** Set propagation orbit type. * @param orbitType orbit type to use for propagation */ + @Override public void setOrbitType(final OrbitType orbitType) { super.setOrbitType(orbitType); } @@ -334,6 +336,7 @@ public void setOrbitType(final OrbitType orbitType) { /** Get propagation parameter type. * @return orbit type used for propagation */ + @Override public OrbitType getOrbitType() { return superGetOrbitType(); } @@ -354,6 +357,7 @@ private OrbitType superGetOrbitType() { *

                  * @param positionAngleType angle type to use for propagation */ + @Override public void setPositionAngleType(final PositionAngleType positionAngleType) { super.setPositionAngleType(positionAngleType); } @@ -361,6 +365,7 @@ public void setPositionAngleType(final PositionAngleType positionAngleType) { /** Get propagation parameter type. * @return angle type to use for propagation */ + @Override public PositionAngleType getPositionAngleType() { return super.getPositionAngleType(); } @@ -373,6 +378,7 @@ public void setInitialState(final FieldSpacecraftState initialState) { } /** {@inheritDoc} */ + @Override public void resetInitialState(final FieldSpacecraftState state) { super.resetInitialState(state); if (!hasNewtonianAttraction()) { diff --git a/src/main/java/org/orekit/propagation/numerical/NumericalPropagator.java b/src/main/java/org/orekit/propagation/numerical/NumericalPropagator.java index 7585958d66..f6b90af9bd 100644 --- a/src/main/java/org/orekit/propagation/numerical/NumericalPropagator.java +++ b/src/main/java/org/orekit/propagation/numerical/NumericalPropagator.java @@ -146,7 +146,7 @@ * *

                  By default, at the end of the propagation, the propagator resets the initial state to the final state, * thus allowing a new propagation to be started from there without recomputing the part already performed. - * This behaviour can be chenged by calling {@link #setResetAtEnd(boolean)}. + * This behaviour can be changed by calling {@link #setResetAtEnd(boolean)}. *

                  *

                  Beware the same instance cannot be used simultaneously by different threads, the class is not * thread-safe.

                  @@ -218,13 +218,13 @@ public NumericalPropagator(final ODEIntegrator integrator) { public NumericalPropagator(final ODEIntegrator integrator, final AttitudeProvider attitudeProvider) { super(integrator, PropagationType.OSCULATING); - forceModels = new ArrayList(); + forceModels = new ArrayList<>(); ignoreCentralAttraction = false; initMapper(); setAttitudeProvider(attitudeProvider); clearStepHandlers(); setOrbitType(OrbitType.EQUINOCTIAL); - setPositionAngleType(PositionAngleType.TRUE); + setPositionAngleType(PositionAngleType.ECCENTRIC); } /** Set the flag to ignore or not the creation of a {@link NewtonianAttraction}. @@ -240,11 +240,12 @@ public void setIgnoreCentralAttraction(final boolean ignoreCentralAttraction) { * Setting the central attraction coefficient is * equivalent to {@link #addForceModel(ForceModel) add} * a {@link NewtonianAttraction} force model. - *

                  - * @param mu central attraction coefficient (m³/s²) - * @see #addForceModel(ForceModel) - * @see #getAllForceModels() - */ + * *

                  + * @param mu central attraction coefficient (m³/s²) + * @see #addForceModel(ForceModel) + * @see #getAllForceModels() + */ + @Override public void setMu(final double mu) { if (ignoreCentralAttraction) { superSetMu(mu); @@ -357,6 +358,7 @@ public List getAllForceModels() { * @param orbitType orbit type to use for propagation, null for * propagating using {@link org.orekit.utils.AbsolutePVCoordinates} rather than {@link Orbit} */ + @Override public void setOrbitType(final OrbitType orbitType) { super.setOrbitType(orbitType); } @@ -365,6 +367,7 @@ public void setOrbitType(final OrbitType orbitType) { * @return orbit type used for propagation, null for * propagating using {@link org.orekit.utils.AbsolutePVCoordinates} rather than {@link Orbit} */ + @Override public OrbitType getOrbitType() { return super.getOrbitType(); } @@ -378,6 +381,7 @@ public OrbitType getOrbitType() { *

                  * @param positionAngleType angle type to use for propagation */ + @Override public void setPositionAngleType(final PositionAngleType positionAngleType) { super.setPositionAngleType(positionAngleType); } @@ -385,6 +389,7 @@ public void setPositionAngleType(final PositionAngleType positionAngleType) { /** Get propagation parameter type. * @return angle type to use for propagation */ + @Override public PositionAngleType getPositionAngleType() { return super.getPositionAngleType(); } @@ -397,6 +402,7 @@ public void setInitialState(final SpacecraftState initialState) { } /** {@inheritDoc} */ + @Override public void resetInitialState(final SpacecraftState state) { super.resetInitialState(state); if (!hasNewtonianAttraction()) { diff --git a/src/test/java/org/orekit/forces/drag/TimeSpanDragForceTest.java b/src/test/java/org/orekit/forces/drag/TimeSpanDragForceTest.java index c83b900d1c..4706124011 100644 --- a/src/test/java/org/orekit/forces/drag/TimeSpanDragForceTest.java +++ b/src/test/java/org/orekit/forces/drag/TimeSpanDragForceTest.java @@ -1381,9 +1381,11 @@ public void RealFieldGradientTest() { FieldNumericalPropagator FNP = new FieldNumericalPropagator<>(field, integrator); FNP.setOrbitType(type); FNP.setInitialState(initialState); + FNP.setPositionAngleType(PositionAngleType.TRUE); NumericalPropagator NP = new NumericalPropagator(RIntegrator); - NP.setOrbitType(type); + NP.setOrbitType(FNP.getOrbitType()); + NP.setPositionAngleType(FNP.getPositionAngleType()); NP.setInitialState(iSR); diff --git a/src/test/java/org/orekit/forces/empirical/HarmonicAccelerationModelTest.java b/src/test/java/org/orekit/forces/empirical/HarmonicAccelerationModelTest.java index f10eb4efde..b3d759cf40 100644 --- a/src/test/java/org/orekit/forces/empirical/HarmonicAccelerationModelTest.java +++ b/src/test/java/org/orekit/forces/empirical/HarmonicAccelerationModelTest.java @@ -48,11 +48,7 @@ import org.orekit.frames.Frame; import org.orekit.frames.FramesFactory; import org.orekit.frames.LOFType; -import org.orekit.orbits.CartesianOrbit; -import org.orekit.orbits.CircularOrbit; -import org.orekit.orbits.KeplerianOrbit; -import org.orekit.orbits.Orbit; -import org.orekit.orbits.PositionAngleType; +import org.orekit.orbits.*; import org.orekit.propagation.FieldBoundedPropagator; import org.orekit.propagation.FieldEphemerisGenerator; import org.orekit.propagation.FieldSpacecraftState; @@ -164,6 +160,8 @@ private void doTestEquivalentManeuver(final double mass, new DormandPrince853Integrator(0.001, 100, tolerance[0], tolerance[1]); integrator0.setInitialStepSize(60); final NumericalPropagator propagator0 = new NumericalPropagator(integrator0); + propagator0.setOrbitType(OrbitType.EQUINOCTIAL); + propagator0.setPositionAngleType(PositionAngleType.TRUE); propagator0.setInitialState(initialState); propagator0.setAttitudeProvider(maneuverLaw); propagator0.addForceModel(maneuver); @@ -173,6 +171,8 @@ private void doTestEquivalentManeuver(final double mass, new DormandPrince853Integrator(0.001, 100, tolerance[0], tolerance[1]); integrator1.setInitialStepSize(60); final NumericalPropagator propagator1 = new NumericalPropagator(integrator1); + propagator1.setOrbitType(propagator0.getOrbitType()); + propagator1.setPositionAngleType(propagator0.getPositionAngleType()); propagator1.setInitialState(initialState); propagator1.setAttitudeProvider(accelerationLaw); propagator1.addForceModel(parametricAcceleration); @@ -279,6 +279,8 @@ private > void doTestEquivalentManeuver(final new DormandPrince853FieldIntegrator<>(field, 0.001, 100, tolerance[0], tolerance[1]); integrator0.setInitialStepSize(60); final FieldNumericalPropagator propagator0 = new FieldNumericalPropagator<>(field, integrator0); + propagator0.setOrbitType(OrbitType.EQUINOCTIAL); + propagator0.setPositionAngleType(PositionAngleType.TRUE); propagator0.setInitialState(initialState); propagator0.setAttitudeProvider(maneuverLaw); propagator0.addForceModel(maneuver); @@ -291,6 +293,8 @@ private > void doTestEquivalentManeuver(final new DormandPrince853FieldIntegrator<>(field, 0.001, 100, tolerance[0], tolerance[1]); integrator1.setInitialStepSize(60); final FieldNumericalPropagator propagator1 = new FieldNumericalPropagator<>(field, integrator1); + propagator1.setOrbitType(propagator0.getOrbitType()); + propagator1.setPositionAngleType(propagator0.getPositionAngleType()); propagator1.setInitialState(initialState); propagator1.setAttitudeProvider(accelerationLaw); propagator1.addForceModel(parametricAcceleration); @@ -377,6 +381,8 @@ public void testCoefficientsDetermination() { new DormandPrince853Integrator(minStep, maxStep, tolerance[0], tolerance[1]); integrator0.setInitialStepSize(60); final NumericalPropagator propagator0 = new NumericalPropagator(integrator0); + propagator0.setOrbitType(OrbitType.EQUINOCTIAL); + propagator0.setPositionAngleType(PositionAngleType.TRUE); propagator0.setInitialState(initialState); propagator0.setAttitudeProvider(maneuverLaw); final ParametricAcceleration hpaRefX1 = new ParametricAcceleration(Vector3D.PLUS_I, true, diff --git a/src/test/java/org/orekit/forces/empirical/PolynomialAccelerationModelTest.java b/src/test/java/org/orekit/forces/empirical/PolynomialAccelerationModelTest.java index 91dad542a5..0bd617571c 100644 --- a/src/test/java/org/orekit/forces/empirical/PolynomialAccelerationModelTest.java +++ b/src/test/java/org/orekit/forces/empirical/PolynomialAccelerationModelTest.java @@ -41,10 +41,7 @@ import org.orekit.forces.maneuvers.ConstantThrustManeuver; import org.orekit.frames.FramesFactory; import org.orekit.frames.LOFType; -import org.orekit.orbits.CartesianOrbit; -import org.orekit.orbits.KeplerianOrbit; -import org.orekit.orbits.Orbit; -import org.orekit.orbits.PositionAngleType; +import org.orekit.orbits.*; import org.orekit.propagation.FieldBoundedPropagator; import org.orekit.propagation.FieldEphemerisGenerator; import org.orekit.propagation.FieldSpacecraftState; @@ -146,6 +143,8 @@ private void doTestEquivalentManeuver(final double mass, new DormandPrince853Integrator(0.001, 100, tolerance[0], tolerance[1]); integrator0.setInitialStepSize(60); final NumericalPropagator propagator0 = new NumericalPropagator(integrator0); + propagator0.setOrbitType(OrbitType.EQUINOCTIAL); + propagator0.setPositionAngleType(PositionAngleType.TRUE); propagator0.setInitialState(initialState); propagator0.setAttitudeProvider(maneuverLaw); propagator0.addForceModel(maneuver); @@ -155,6 +154,8 @@ private void doTestEquivalentManeuver(final double mass, new DormandPrince853Integrator(0.001, 100, tolerance[0], tolerance[1]); integrator1.setInitialStepSize(60); final NumericalPropagator propagator1 = new NumericalPropagator(integrator1); + propagator1.setOrbitType(propagator0.getOrbitType()); + propagator1.setPositionAngleType(propagator0.getPositionAngleType()); propagator1.setInitialState(initialState); propagator1.setAttitudeProvider(accelerationLaw); propagator1.addForceModel(parametricAcceleration); @@ -255,6 +256,8 @@ private > void doTestEquivalentManeuver(final new DormandPrince853FieldIntegrator<>(field, 0.001, 100, tolerance[0], tolerance[1]); integrator0.setInitialStepSize(60); final FieldNumericalPropagator propagator0 = new FieldNumericalPropagator<>(field, integrator0); + propagator0.setOrbitType(OrbitType.EQUINOCTIAL); + propagator0.setPositionAngleType(PositionAngleType.TRUE); propagator0.setInitialState(initialState); propagator0.setAttitudeProvider(maneuverLaw); propagator0.addForceModel(maneuver); @@ -267,6 +270,8 @@ private > void doTestEquivalentManeuver(final new DormandPrince853FieldIntegrator<>(field, 0.001, 100, tolerance[0], tolerance[1]); integrator1.setInitialStepSize(60); final FieldNumericalPropagator propagator1 = new FieldNumericalPropagator<>(field, integrator1); + propagator1.setOrbitType(propagator0.getOrbitType()); + propagator1.setPositionAngleType(propagator0.getPositionAngleType()); propagator1.setInitialState(initialState); propagator1.setAttitudeProvider(accelerationLaw); propagator1.addForceModel(parametricAcceleration); diff --git a/src/test/java/org/orekit/forces/gravity/HolmesFeatherstoneAttractionModelTest.java b/src/test/java/org/orekit/forces/gravity/HolmesFeatherstoneAttractionModelTest.java index 7a5bcf2a8e..a45d7758f0 100644 --- a/src/test/java/org/orekit/forces/gravity/HolmesFeatherstoneAttractionModelTest.java +++ b/src/test/java/org/orekit/forces/gravity/HolmesFeatherstoneAttractionModelTest.java @@ -507,10 +507,12 @@ public void RealFieldTest() { FieldNumericalPropagator FNP = new FieldNumericalPropagator<>(field, integrator); FNP.setOrbitType(type); + FNP.setPositionAngleType(PositionAngleType.TRUE); FNP.setInitialState(initialState); NumericalPropagator NP = new NumericalPropagator(RIntegrator); - NP.setOrbitType(type); + NP.setOrbitType(FNP.getOrbitType()); + NP.setPositionAngleType(FNP.getPositionAngleType()); NP.setInitialState(iSR); double[][] c = new double[3][1]; @@ -891,6 +893,8 @@ public void testEcksteinHechlerReference() { // let the step handler perform the test propagator.setInitialState(new SpacecraftState(initialOrbit)); + propagator.setOrbitType(OrbitType.EQUINOCTIAL); + propagator.setPositionAngleType(PositionAngleType.TRUE); propagator.setStepHandler(20, new EckStepHandler(initialOrbit, ae, unnormalizedC20, unnormalizedC30, unnormalizedC40, unnormalizedC50, unnormalizedC60)); diff --git a/src/test/java/org/orekit/forces/maneuvers/ConstantThrustManeuverTest.java b/src/test/java/org/orekit/forces/maneuvers/ConstantThrustManeuverTest.java index b9e1968eb2..9f5cd760ea 100644 --- a/src/test/java/org/orekit/forces/maneuvers/ConstantThrustManeuverTest.java +++ b/src/test/java/org/orekit/forces/maneuvers/ConstantThrustManeuverTest.java @@ -69,7 +69,7 @@ import org.orekit.utils.ParameterDriver; import org.orekit.utils.TimeStampedPVCoordinates; -public class ConstantThrustManeuverTest extends AbstractLegacyForceModelTest { +class ConstantThrustManeuverTest extends AbstractLegacyForceModelTest { // Body mu private double mu; @@ -126,7 +126,7 @@ private CircularOrbit dummyOrbit(AbsoluteDate date) { } @Test - public void testJacobianVs80Implementation() { + void testJacobianVs80Implementation() { final double isp = 318; final double mass = 2500; final double a = 24396159; @@ -168,7 +168,7 @@ public void testJacobianVs80Implementation() { } @Test - public void testJacobianVs80ImplementationGradient() { + void testJacobianVs80ImplementationGradient() { final double isp = 318; final double mass = 2500; final double a = 24396159; @@ -210,7 +210,7 @@ public void testJacobianVs80ImplementationGradient() { } @Test - public void testPositiveDuration() { + void testPositiveDuration() { AbsoluteDate date = new AbsoluteDate(new DateComponents(2004, 01, 01), new TimeComponents(23, 30, 00.000), TimeScalesFactory.getUTC()); @@ -240,7 +240,7 @@ public void testPositiveDuration() { } @Test - public void testNegativeDuration() { + void testNegativeDuration() { AbsoluteDate date = new AbsoluteDate(new DateComponents(2004, 01, 01), new TimeComponents(23, 30, 00.000), TimeScalesFactory.getUTC()); @@ -264,7 +264,7 @@ public void testNegativeDuration() { } @Test - public void testRoughBehaviour() { + void testRoughBehaviour() { final double isp = 318; final double mass = 2500; final double a = 24396159; @@ -327,7 +327,7 @@ public void testRoughBehaviour() { * propagation X with the FieldPropagation and then applying the taylor * expansion of dX to the result.*/ @Test - public void testRealField() { + void testRealField() { DSFactory factory = new DSFactory(6, 5); DerivativeStructure a_0 = factory.variable(0, 7e7); DerivativeStructure e_0 = factory.variable(1, 0.4); @@ -389,7 +389,7 @@ public void testRealField() { * propagation X with the FieldPropagation and then applying the taylor * expansion of dX to the result.*/ @Test - public void testRealFieldGradient() { + void testRealFieldGradient() { int freeParameters = 6; Gradient a_0 = Gradient.variable(freeParameters, 0, 7e7); Gradient e_0 = Gradient.variable(freeParameters, 1, 0.4); @@ -511,7 +511,7 @@ public void RealFieldExpectErrorTest() { } @Test - public void testForwardAndBackward() { + void testForwardAndBackward() { final double isp = 318; final double mass = 2500; final double a = 24396159; @@ -552,6 +552,7 @@ public void testForwardAndBackward() { integrator1.setInitialStepSize(60); final NumericalPropagator propagator1 = new NumericalPropagator(integrator1); propagator1.setOrbitType(orbitType); + propagator1.setPositionAngleType(PositionAngleType.TRUE); propagator1.setInitialState(initialState); propagator1.setAttitudeProvider(law); propagator1.addForceModel(maneuver); @@ -567,6 +568,7 @@ public void testForwardAndBackward() { integrator2.setInitialStepSize(60); final NumericalPropagator propagator2 = new NumericalPropagator(integrator2); propagator2.setOrbitType(orbitType); + propagator2.setPositionAngleType(propagator1.getPositionAngleType()); propagator2.setInitialState(finalState); propagator2.setAttitudeProvider(law); propagator2.addForceModel(maneuver); @@ -584,7 +586,7 @@ public void testForwardAndBackward() { } @Test - public void testParameterDerivative() { + void testParameterDerivative() { // pos-vel (from a ZOOM ephemeris reference) final Vector3D pos = new Vector3D(6.46885878304673824e+06, -1.88050918456274318e+06, -1.32931592294715829e+04); @@ -606,7 +608,7 @@ public void testParameterDerivative() { } @Test - public void testParameterDerivativeGradient() { + void testParameterDerivativeGradient() { // pos-vel (from a ZOOM ephemeris reference) final Vector3D pos = new Vector3D(6.46885878304673824e+06, -1.88050918456274318e+06, -1.32931592294715829e+04); @@ -628,7 +630,7 @@ public void testParameterDerivativeGradient() { } @Test - public void testInertialManeuver() { + void testInertialManeuver() { final double isp = 318; final double mass = 2500; final double a = 24396159; @@ -722,7 +724,7 @@ public void testInertialManeuver() { } @Test - public void testStopInMiddle() { + void testStopInMiddle() { final double isp = 318; final double mass = 2500; final double a = 24396159; @@ -795,7 +797,7 @@ public void testStopInMiddle() { } @Test - public void testNullDuration() { + void testNullDuration() { // Defining initial state final Frame eme2000 = FramesFactory.getEME2000(); diff --git a/src/test/java/org/orekit/forces/maneuvers/FieldImpulseManeuverTest.java b/src/test/java/org/orekit/forces/maneuvers/FieldImpulseManeuverTest.java index 6286d6b359..0b58c35fc7 100644 --- a/src/test/java/org/orekit/forces/maneuvers/FieldImpulseManeuverTest.java +++ b/src/test/java/org/orekit/forces/maneuvers/FieldImpulseManeuverTest.java @@ -84,7 +84,7 @@ import org.orekit.utils.FieldPVCoordinates; import org.orekit.utils.PVCoordinates; -public class FieldImpulseManeuverTest { +class FieldImpulseManeuverTest { private final double mu = Constants.WGS84_EARTH_MU; private final Frame inertialFrame = FramesFactory.getGCRF(); @@ -97,6 +97,7 @@ public class FieldImpulseManeuverTest { private final Vector3D deltaV = new Vector3D(0.1, -0.5, 0.2); private final double timeOfFlight = 10000.; private final OrbitType orbitType = OrbitType.EQUINOCTIAL; + private final PositionAngleType positionAngleType = PositionAngleType.ECCENTRIC; private final LofOffset attitudeOverride = new LofOffset(inertialFrame, LOFType.QSW); private final GradientField gradientField = GradientField.getField(2); private final UnivariateDerivative1Field univariateDerivative1Field = new UnivariateDerivative1(0., 0.).getField(); @@ -140,7 +141,7 @@ public void setUp() { } @Test - public void testComplexConstructors() { + void testComplexConstructors() { // Given final Complex zero = complexField.getZero(); final Complex isp = zero.add(200.); @@ -165,7 +166,7 @@ public void testComplexConstructors() { } @Test - public void testDeltaVNorm() { + void testDeltaVNorm() { // Given final Complex isp = complexField.getOne().add(200.); final FieldVector3D deltaV = new FieldVector3D<>(complexField, Vector3D.PLUS_I); @@ -189,43 +190,43 @@ public void testDeltaVNorm() { } @Test - public void testEclipseDetectorDerivativeStructure() { + void testEclipseDetectorDerivativeStructure() { templateDetector(new DSFactory(1, 1).getDerivativeField(), DetectorType.ECLIPSE_DETECTOR, Control3DVectorCostType.TWO_NORM); } @Test - public void testEclipseDetectorGradient() { + void testEclipseDetectorGradient() { templateDetector(gradientField, DetectorType.ECLIPSE_DETECTOR, Control3DVectorCostType.TWO_NORM); } @Test - public void testEclipseDetectorGradientNormInf() { + void testEclipseDetectorGradientNormInf() { templateDetector(gradientField, DetectorType.ECLIPSE_DETECTOR, Control3DVectorCostType.INF_NORM); } @Test - public void testDateDetectorComplex() { + void testDateDetectorComplex() { templateDetector(complexField, DetectorType.DATE_DETECTOR, Control3DVectorCostType.TWO_NORM); } @Test - public void testDateDetectorUnivariateDerivative2() { + void testDateDetectorUnivariateDerivative2() { templateDetector(univariateDerivative2Field, DetectorType.DATE_DETECTOR, Control3DVectorCostType.TWO_NORM); } @Test - public void testDateDetectorGradientNorm1() { + void testDateDetectorGradientNorm1() { templateDetector(gradientField, DetectorType.DATE_DETECTOR, Control3DVectorCostType.ONE_NORM); } @Test - public void testLatitudeCrossingDetectorUnivariateDerivative1() { + void testLatitudeCrossingDetectorUnivariateDerivative1() { templateDetector(univariateDerivative1Field, DetectorType.LATITUDE_CROSSING_DETECTOR, Control3DVectorCostType.TWO_NORM); } @Test - public void testLatitudeCrossingDetectorDerivativeStructure() { + void testLatitudeCrossingDetectorDerivativeStructure() { templateDetector(new DSFactory(1, 1).getDerivativeField(), DetectorType.LATITUDE_CROSSING_DETECTOR, Control3DVectorCostType.TWO_NORM); } @@ -321,6 +322,7 @@ private NumericalPropagator createUnperturbedPropagator(final Orbit initialOrbit final NumericalPropagator propagator = new NumericalPropagator(integrator); propagator.setInitialState(new SpacecraftState(initialOrbit, initialMass)); propagator.setOrbitType(orbitType); + propagator.setPositionAngleType(positionAngleType); return propagator; } @@ -335,6 +337,7 @@ private > FieldNumericalPropagator createUn final T fieldInitialMass = field.getZero().add(initialMass); fieldPropagator.setInitialState(new FieldSpacecraftState<>(fieldInitialOrbit, fieldInitialMass)); fieldPropagator.setOrbitType(orbitType); + fieldPropagator.setPositionAngleType(positionAngleType); return fieldPropagator; } @@ -375,7 +378,7 @@ private > FieldCartesianOrbit createConstan } @Test - public void testAdditionalStatePropagation() { + void testAdditionalStatePropagation() { // Given final UnivariateDerivative1 zero = univariateDerivative1Field.getZero(); final FieldNumericalPropagator fieldPropagator = createFieldPropagatorForAdditionalStatesAndDerivatives( @@ -393,7 +396,7 @@ public void testAdditionalStatePropagation() { } @Test - public void testAdditionalStateDerivativesPropagation() { + void testAdditionalStateDerivativesPropagation() { // Given final Gradient zero = gradientField.getZero(); final FieldNumericalPropagator fieldPropagator = createFieldPropagatorForAdditionalStatesAndDerivatives( @@ -426,7 +429,7 @@ private > FieldNumericalPropagator createFi } @Test - public void testBackAndForthPropagation() { + void testBackAndForthPropagation() { // Given final Orbit initialOrbit = createOrbit(); final NumericalPropagator propagator = createUnperturbedPropagator(initialOrbit, initialMass); @@ -435,7 +438,6 @@ public void testBackAndForthPropagation() { final UnivariateDerivative1 zero = univariateDerivative1Field.getZero(); final FieldNumericalPropagator fieldPropagator = createUnperturbedFieldPropagator(univariateDerivative1Field, initialOrbit, initialMass); - fieldPropagator.setOrbitType(propagator.getOrbitType()); fieldPropagator.setAttitudeProvider(propagator.getAttitudeProvider()); fieldPropagator.setResetAtEnd(true); fieldPropagator.addEventDetector(convertManeuver(univariateDerivative1Field, impulseManeuver, new FieldContinueOnEvent<>())); @@ -450,7 +452,7 @@ public void testBackAndForthPropagation() { } @Test - public void testVersusCartesianStateTransitionMatrix() { + void testVersusCartesianStateTransitionMatrix() { // Given final int freeParameters = 3; final GradientField field = GradientField.getField(freeParameters); diff --git a/src/test/java/org/orekit/forces/maneuvers/SmallManeuverAnalyticalModelTest.java b/src/test/java/org/orekit/forces/maneuvers/SmallManeuverAnalyticalModelTest.java index d8209f3b89..c16978a0dc 100644 --- a/src/test/java/org/orekit/forces/maneuvers/SmallManeuverAnalyticalModelTest.java +++ b/src/test/java/org/orekit/forces/maneuvers/SmallManeuverAnalyticalModelTest.java @@ -45,10 +45,10 @@ import org.orekit.utils.Constants; import org.orekit.utils.PVCoordinates; -public class SmallManeuverAnalyticalModelTest { +class SmallManeuverAnalyticalModelTest { @Test - public void testLowEarthOrbit1() { + void testLowEarthOrbit1() { Orbit leo = new CircularOrbit(7200000.0, -1.0e-5, 2.0e-4, FastMath.toRadians(98.0), @@ -95,7 +95,7 @@ public void testLowEarthOrbit1() { } @Test - public void testLowEarthOrbit2() { + void testLowEarthOrbit2() { Orbit leo = new CircularOrbit(7200000.0, -1.0e-5, 2.0e-4, FastMath.toRadians(98.0), @@ -142,7 +142,7 @@ public void testLowEarthOrbit2() { } @Test - public void testEccentricOrbit() { + void testEccentricOrbit() { Orbit heo = new KeplerianOrbit(90000000.0, 0.92, FastMath.toRadians(98.0), FastMath.toRadians(12.3456), @@ -193,7 +193,7 @@ public void testEccentricOrbit() { } @Test - public void testJacobian() { + void testJacobian() { Frame eme2000 = FramesFactory.getEME2000(); Orbit leo = new CircularOrbit(7200000.0, -1.0e-2, 2.0e-3, @@ -295,6 +295,7 @@ private BoundedPropagator getEphemeris(final Orbit orbit, final double mass, integrator.setInitialStepSize(orbit.getKeplerianPeriod() / 100.0); final NumericalPropagator propagator = new NumericalPropagator(integrator); propagator.setOrbitType(orbit.getType()); + propagator.setPositionAngleType(PositionAngleType.TRUE); propagator.setInitialState(initialState); propagator.setAttitudeProvider(law); diff --git a/src/test/java/org/orekit/forces/maneuvers/propulsion/ProfileThrustPropulsionModelTest.java b/src/test/java/org/orekit/forces/maneuvers/propulsion/ProfileThrustPropulsionModelTest.java index ad00d66557..a1f2017ccb 100644 --- a/src/test/java/org/orekit/forces/maneuvers/propulsion/ProfileThrustPropulsionModelTest.java +++ b/src/test/java/org/orekit/forces/maneuvers/propulsion/ProfileThrustPropulsionModelTest.java @@ -54,17 +54,17 @@ import org.orekit.utils.Constants; import org.orekit.utils.TimeSpanMap; -public class ProfileThrustPropulsionModelTest { +class ProfileThrustPropulsionModelTest { @Test - public void testRoughBehaviour() { + void testRoughBehaviour() { doRoughBehaviour( 1.0, 2008.017, 28968115.974); doRoughBehaviour( 10.0, 2009.229, 28950587.132); doRoughBehaviour(100.0, 2021.350, 28777772.266); } @Test - public void testRoughBehaviourField() { + void testRoughBehaviourField() { doRoughBehaviourField(Binary64Field.getInstance(), 1.0, 2008.017, 28968115.974); doRoughBehaviourField(Binary64Field.getInstance(), 10.0, 2009.229, 28950587.132); doRoughBehaviourField(Binary64Field.getInstance(), 100.0, 2021.350, 28777772.266); @@ -90,8 +90,9 @@ private void doRoughBehaviour(final double rampDuration, final double expectedM, final AbsoluteDate initDate = new AbsoluteDate(new DateComponents(2004, 01, 01), new TimeComponents(23, 30, 00.000), TimeScalesFactory.getUTC()); + final PositionAngleType positionAngleType = PositionAngleType.TRUE; final Orbit initOrbit = - new KeplerianOrbit(a, e, i, omega, OMEGA, lv, PositionAngleType.TRUE, + new KeplerianOrbit(a, e, i, omega, OMEGA, lv, positionAngleType, FramesFactory.getEME2000(), initDate, Constants.EIGEN5C_EARTH_MU); final SpacecraftState initialState = new SpacecraftState(initOrbit, law.getAttitude(initOrbit, initOrbit.getDate(), initOrbit.getFrame()), mass); @@ -178,8 +179,9 @@ private > void doRoughBehaviourField(final Fie new DateComponents(2004, 01, 01), new TimeComponents(23, 30, 00.000), TimeScalesFactory.getUTC()); + final PositionAngleType positionAngleType = PositionAngleType.TRUE; final FieldOrbit initOrbit = - new FieldKeplerianOrbit<>(a, e, i, omega, OMEGA, lv, PositionAngleType.TRUE, + new FieldKeplerianOrbit<>(a, e, i, omega, OMEGA, lv, positionAngleType, FramesFactory.getEME2000(), initDate, zero.newInstance(Constants.EIGEN5C_EARTH_MU)); final FieldSpacecraftState initialState = @@ -236,6 +238,7 @@ private > void doRoughBehaviourField(final Fie integrator.setInitialStepSize(0.1); final FieldNumericalPropagator propagator = new FieldNumericalPropagator<>(field, integrator); propagator.setOrbitType(initOrbit.getType()); + propagator.setPositionAngleType(positionAngleType); propagator.setInitialState(initialState); propagator.setAttitudeProvider(law); propagator.addForceModel(maneuver); diff --git a/src/test/java/org/orekit/forces/radiation/SolarRadiationPressureTest.java b/src/test/java/org/orekit/forces/radiation/SolarRadiationPressureTest.java index dd71691a53..60657f5b5a 100644 --- a/src/test/java/org/orekit/forces/radiation/SolarRadiationPressureTest.java +++ b/src/test/java/org/orekit/forces/radiation/SolarRadiationPressureTest.java @@ -157,7 +157,7 @@ protected FieldVector3D accelerationDerivativesGradient(final ForceMod } @Test - public void testLightingInterplanetary() throws ParseException { + void testLightingInterplanetary() throws ParseException { // Initialization AbsoluteDate date = new AbsoluteDate(new DateComponents(1970, 3, 21), new TimeComponents(13, 59, 27.816), @@ -184,7 +184,7 @@ public void testLightingInterplanetary() throws ParseException { } @Test - public void testLighting() throws ParseException { + void testLighting() throws ParseException { // Given AbsoluteDate date = new AbsoluteDate(new DateComponents(1970, 3, 21), @@ -233,7 +233,7 @@ public void testLighting() throws ParseException { } @Test - public void testGlobalStateJacobianIsotropicSingle() { + void testGlobalStateJacobianIsotropicSingle() { // initialization AbsoluteDate date = new AbsoluteDate(new DateComponents(2003, 03, 01), @@ -267,7 +267,7 @@ public void testGlobalStateJacobianIsotropicSingle() { } @Test - public void testLocalJacobianIsotropicClassicalVs80Implementation() { + void testLocalJacobianIsotropicClassicalVs80Implementation() { // initialization AbsoluteDate date = new AbsoluteDate(new DateComponents(2003, 03, 01), @@ -293,7 +293,7 @@ public void testLocalJacobianIsotropicClassicalVs80Implementation() { } @Test - public void testLocalJacobianIsotropicClassicalVs80ImplementationGradient() { + void testLocalJacobianIsotropicClassicalVs80ImplementationGradient() { // initialization AbsoluteDate date = new AbsoluteDate(new DateComponents(2003, 03, 01), @@ -319,39 +319,39 @@ public void testLocalJacobianIsotropicClassicalVs80ImplementationGradient() { } @Test - public void testLocalJacobianIsotropicClassicalVsFiniteDifferencesFullLight() { + void testLocalJacobianIsotropicClassicalVsFiniteDifferencesFullLight() { // here, lighting ratio is exactly 1 for all points used for finite differences doTestLocalJacobianIsotropicClassicalVsFiniteDifferences(250.0, 1000.0, 3.0e-8, false); } @Test - public void testLocalJacobianIsotropicClassicalVsFiniteDifferencesGradientFullLight() { + void testLocalJacobianIsotropicClassicalVsFiniteDifferencesGradientFullLight() { // here, lighting ratio is exactly 1 for all points used for finite differences doTestLocalJacobianIsotropicClassicalVsFiniteDifferencesGradient(250.0, 1000.0, 3.0e-8, false); } @Test - public void testLocalJacobianIsotropicClassicalVsFiniteDifferencesPenumbra() { + void testLocalJacobianIsotropicClassicalVsFiniteDifferencesPenumbra() { // here, lighting ratio is about 0.57, // and remains strictly between 0 and 1 for all points used for finite differences doTestLocalJacobianIsotropicClassicalVsFiniteDifferences(275.5, 100.0, 8.0e-7, false); } @Test - public void testLocalJacobianIsotropicClassicalVsFiniteDifferencesGradientPenumbra() { + void testLocalJacobianIsotropicClassicalVsFiniteDifferencesGradientPenumbra() { // here, lighting ratio is about 0.57, // and remains strictly between 0 and 1 for all points used for finite differences doTestLocalJacobianIsotropicClassicalVsFiniteDifferencesGradient(275.5, 100.0, 8.0e-7, false); } @Test - public void testLocalJacobianIsotropicClassicalVsFiniteDifferencesEclipse() { + void testLocalJacobianIsotropicClassicalVsFiniteDifferencesEclipse() { // here, lighting ratio is exactly 0 for all points used for finite differences doTestLocalJacobianIsotropicClassicalVsFiniteDifferences(300.0, 1000.0, 1.0e-50, false); } @Test - public void testLocalJacobianIsotropicClassicalVsFiniteDifferencesGradientEclipse() { + void testLocalJacobianIsotropicClassicalVsFiniteDifferencesGradientEclipse() { // here, lighting ratio is exactly 0 for all points used for finite differences doTestLocalJacobianIsotropicClassicalVsFiniteDifferencesGradient(300.0, 1000.0, 1.0e-50, false); } @@ -409,7 +409,7 @@ private void doTestLocalJacobianIsotropicClassicalVsFiniteDifferencesGradient(do } @Test - public void testGlobalStateJacobianIsotropicClassical() { + void testGlobalStateJacobianIsotropicClassical() { // initialization AbsoluteDate date = new AbsoluteDate(new DateComponents(2003, 03, 01), @@ -443,7 +443,7 @@ public void testGlobalStateJacobianIsotropicClassical() { } @Test - public void testGlobalStateJacobianIsotropicCnes() { + void testGlobalStateJacobianIsotropicCnes() { // initialization AbsoluteDate date = new AbsoluteDate(new DateComponents(2003, 03, 01), @@ -477,7 +477,7 @@ public void testGlobalStateJacobianIsotropicCnes() { } @Test - public void testParameterDerivativeBox() { + void testParameterDerivativeBox() { final Vector3D pos = new Vector3D(6.46885878304673824e+06, -1.88050918456274318e+06, -1.32931592294715829e+04); final Vector3D vel = new Vector3D(2.14718074509906819e+03, 7.38239351251748485e+03, -1.14097953925384523e+01); @@ -500,7 +500,7 @@ public void testParameterDerivativeBox() { } @Test - public void testParameterDerivativeGradientBox() { + void testParameterDerivativeGradientBox() { final Vector3D pos = new Vector3D(6.46885878304673824e+06, -1.88050918456274318e+06, -1.32931592294715829e+04); final Vector3D vel = new Vector3D(2.14718074509906819e+03, 7.38239351251748485e+03, -1.14097953925384523e+01); @@ -523,7 +523,7 @@ public void testParameterDerivativeGradientBox() { } @Test - public void testGlobalStateJacobianBox() { + void testGlobalStateJacobianBox() { // initialization AbsoluteDate date = new AbsoluteDate(new DateComponents(2003, 03, 01), @@ -558,7 +558,7 @@ public void testGlobalStateJacobianBox() { } @Test - public void testRoughOrbitalModifs() { + void testRoughOrbitalModifs() { // initialization AbsoluteDate date = new AbsoluteDate(new DateComponents(1970, 7, 1), @@ -767,7 +767,7 @@ public void RealFieldExpectErrorTest() { } @Test - public void testFlatteningLEO() { + void testFlatteningLEO() { GravityFieldFactory.addPotentialCoefficientsReader(new ICGEMFormatReader("eigen-6s-truncated", false)); NormalizedSphericalHarmonicsProvider gravityField = GravityFieldFactory.getNormalizedProvider(20, 20); @@ -808,6 +808,7 @@ private NumericalPropagator createLeoPropagator(final CelestialBody sun, final C final NumericalPropagator propagator = new NumericalPropagator(new DormandPrince853Integrator(1.0e-9, 60.0, tol[0], tol[1])); propagator.setOrbitType(OrbitType.CIRCULAR); + propagator.setPositionAngleType(PositionAngleType.TRUE); propagator.addForceModel(new HolmesFeatherstoneAttractionModel(earth.getBodyFrame(), gravityField)); propagator.addForceModel(new ThirdBodyAttraction(sun)); propagator.addForceModel(new ThirdBodyAttraction(moon)); @@ -859,7 +860,7 @@ public void finish(final List finalStates) { * Modifications of the step handler and time span able to print lighting ratios other a year and get a reference like graph. */ @Test - public void testMoonPenumbra() { + void testMoonPenumbra() { final AbsoluteDate date = new AbsoluteDate(2007, 1, 19, 5, 0, 0, TimeScalesFactory.getGPS()); final Vector3D p = new Vector3D(12538484.957505366, 15515522.98001655, -17884023.51839292); final Vector3D v = new Vector3D(-3366.9009055533616, 769.5389825219049, -1679.3840677789601); @@ -869,7 +870,7 @@ public void testMoonPenumbra() { } @Test - public void testEarthPenumbraOnly() { + void testEarthPenumbraOnly() { final AbsoluteDate date = new AbsoluteDate(2007, 3, 13, 17, 14, 0, TimeScalesFactory.getGPS()); final Vector3D p = new Vector3D(-26168647.4977583, -1516554.3304749255, -3206794.210706205); final Vector3D v = new Vector3D(-213.65557094060222, -2377.3633988328584, 3079.4740070013495); @@ -879,7 +880,7 @@ public void testEarthPenumbraOnly() { } @Test - public void testEarthPenumbraAndUmbra() { + void testEarthPenumbraAndUmbra() { final AbsoluteDate date = new AbsoluteDate(2007, 3, 14, 5, 8, 0, TimeScalesFactory.getGPS()); final Vector3D p = new Vector3D(-26101379.998276696, -947280.678355501, -3940992.754483608); final Vector3D v = new Vector3D(-348.8911736753223, -2383.738528546711, 3060.9815784341567); @@ -1042,7 +1043,7 @@ else if (isInMoonPenumbra || isInEarthPenumbra) { * Modifications of the step handler and time span able to print lighting ratios other a year and get a reference like graph. */ @Test - public void testFieldMoonPenumbra() { + void testFieldMoonPenumbra() { Field field = Binary64Field.getInstance(); final FieldAbsoluteDate date = new FieldAbsoluteDate<>(field, 2007, 1, 19, 5, 0, 0, TimeScalesFactory.getGPS()); final FieldVector3D p = new FieldVector3D<>(field, new Vector3D(12538484.957505366, 15515522.98001655, -17884023.51839292)); @@ -1055,7 +1056,7 @@ public void testFieldMoonPenumbra() { } @Test - public void testFieldEarthPenumbraOnly() { + void testFieldEarthPenumbraOnly() { Field field = Binary64Field.getInstance(); final FieldAbsoluteDate date = new FieldAbsoluteDate<>(field, 2007, 3, 13, 17, 14, 0, TimeScalesFactory.getGPS()); final FieldVector3D p = new FieldVector3D<>(field, new Vector3D(-26168647.4977583, -1516554.3304749255, -3206794.210706205)); @@ -1068,7 +1069,7 @@ public void testFieldEarthPenumbraOnly() { } @Test - public void testFieldEarthPenumbraAndUmbra() { + void testFieldEarthPenumbraAndUmbra() { Field field = Binary64Field.getInstance(); final FieldAbsoluteDate date = new FieldAbsoluteDate<>(field, 2007, 3, 14, 5, 8, 0, TimeScalesFactory.getGPS()); final FieldVector3D p = new FieldVector3D<>(field, new Vector3D(-26101379.998276696, -947280.678355501, -3940992.754483608)); diff --git a/src/test/java/org/orekit/propagation/analytical/BrouwerLyddanePropagatorTest.java b/src/test/java/org/orekit/propagation/analytical/BrouwerLyddanePropagatorTest.java index f7c0b8189f..8055be71c7 100644 --- a/src/test/java/org/orekit/propagation/analytical/BrouwerLyddanePropagatorTest.java +++ b/src/test/java/org/orekit/propagation/analytical/BrouwerLyddanePropagatorTest.java @@ -708,6 +708,7 @@ public void testMeanOrbit() { num.addForceModel(new HolmesFeatherstoneAttractionModel(itrf, provider)); num.setInitialState(new SpacecraftState(initialOsculating)); num.setOrbitType(OrbitType.KEPLERIAN); + num.setPositionAngleType(initialOsculating.getCachedPositionAngleType()); final StorelessUnivariateStatistic oscMin = new Min(); final StorelessUnivariateStatistic oscMax = new Max(); final StorelessUnivariateStatistic meanMin = new Min(); diff --git a/src/test/java/org/orekit/propagation/analytical/EcksteinHechlerPropagatorTest.java b/src/test/java/org/orekit/propagation/analytical/EcksteinHechlerPropagatorTest.java index 0f638613c7..e18f465cbd 100644 --- a/src/test/java/org/orekit/propagation/analytical/EcksteinHechlerPropagatorTest.java +++ b/src/test/java/org/orekit/propagation/analytical/EcksteinHechlerPropagatorTest.java @@ -881,6 +881,7 @@ public void testMeanOrbit() { num.addForceModel(new HolmesFeatherstoneAttractionModel(itrf, GravityFieldFactory.getNormalizedProvider(provider))); num.setInitialState(new SpacecraftState(initialOsculating)); num.setOrbitType(OrbitType.CIRCULAR); + num.setPositionAngleType(initialOsculating.getCachedPositionAngleType()); final StorelessUnivariateStatistic oscMin = new Min(); final StorelessUnivariateStatistic oscMax = new Max(); final StorelessUnivariateStatistic meanMin = new Min(); diff --git a/src/test/java/org/orekit/propagation/analytical/FieldBrouwerLyddanePropagatorTest.java b/src/test/java/org/orekit/propagation/analytical/FieldBrouwerLyddanePropagatorTest.java index 67966e9fcc..68bc4e870a 100644 --- a/src/test/java/org/orekit/propagation/analytical/FieldBrouwerLyddanePropagatorTest.java +++ b/src/test/java/org/orekit/propagation/analytical/FieldBrouwerLyddanePropagatorTest.java @@ -897,6 +897,7 @@ private > void doTestMeanOrbit(Field field) num.addForceModel(new HolmesFeatherstoneAttractionModel(itrf, provider)); num.setInitialState(new FieldSpacecraftState<>(initialOsculating)); num.setOrbitType(OrbitType.KEPLERIAN); + num.setPositionAngleType(initialOsculating.getCachedPositionAngleType()); final StorelessUnivariateStatistic oscMin = new Min(); final StorelessUnivariateStatistic oscMax = new Max(); final StorelessUnivariateStatistic meanMin = new Min(); diff --git a/src/test/java/org/orekit/propagation/analytical/FieldEcksteinHechlerPropagatorTest.java b/src/test/java/org/orekit/propagation/analytical/FieldEcksteinHechlerPropagatorTest.java index ef1fb11ef3..fd569310db 100644 --- a/src/test/java/org/orekit/propagation/analytical/FieldEcksteinHechlerPropagatorTest.java +++ b/src/test/java/org/orekit/propagation/analytical/FieldEcksteinHechlerPropagatorTest.java @@ -1002,6 +1002,7 @@ private > void doTestMeanOrbit(Field field) num.addForceModel(new HolmesFeatherstoneAttractionModel(itrf, GravityFieldFactory.getNormalizedProvider(provider))); num.setInitialState(new FieldSpacecraftState<>(initialOsculating)); num.setOrbitType(OrbitType.CIRCULAR); + num.setPositionAngleType(initialOsculating.getCachedPositionAngleType()); final StorelessUnivariateStatistic oscMin = new Min(); final StorelessUnivariateStatistic oscMax = new Max(); final StorelessUnivariateStatistic meanMin = new Min(); diff --git a/src/test/java/org/orekit/propagation/events/EclipseDetectorTest.java b/src/test/java/org/orekit/propagation/events/EclipseDetectorTest.java index 4b408cd1b4..abc8c24027 100644 --- a/src/test/java/org/orekit/propagation/events/EclipseDetectorTest.java +++ b/src/test/java/org/orekit/propagation/events/EclipseDetectorTest.java @@ -53,7 +53,7 @@ import java.util.List; -public class EclipseDetectorTest { +class EclipseDetectorTest { private double mu; private AbsoluteDate iniDate; @@ -65,7 +65,7 @@ public class EclipseDetectorTest { private double sunRadius; @Test - public void testPolar() { + void testPolar() { final KeplerianOrbit original = (KeplerianOrbit) OrbitType.KEPLERIAN.convertType(initialState.getOrbit()); final KeplerianOrbit polar = new KeplerianOrbit(original.getA(), original.getE(), 0.5 * FastMath.PI, original.getPerigeeArgument(), @@ -108,7 +108,7 @@ public void testPolar() { Assertions.assertEquals( 2280.427, events.get(1).getState().getDate().durationFrom(iniDate), 1.0e-3); Assertions.assertTrue(events.get(2).getEventDetector() == withFlattening); Assertions.assertTrue(events.get(2).isIncreasing()); - Assertions.assertEquals( 4310.742, events.get(2).getState().getDate().durationFrom(iniDate), 1.0e-3); + Assertions.assertEquals( 4310.741, events.get(2).getState().getDate().durationFrom(iniDate), 1.0e-3); Assertions.assertTrue(events.get(3).getEventDetector() == withoutFlattening); Assertions.assertTrue(events.get(3).isIncreasing()); Assertions.assertEquals( 4317.155, events.get(3).getState().getDate().durationFrom(iniDate), 1.6e-3); @@ -134,7 +134,7 @@ public void testPolar() { } @Test - public void testEclipse() { + void testEclipse() { EclipseDetector e = new EclipseDetector(sun, sunRadius, earth). withMaxCheck(60.0). withThreshold(1.0e-3). @@ -151,7 +151,7 @@ public void testEclipse() { } @Test - public void testPenumbra() { + void testPenumbra() { EclipseDetector e = new EclipseDetector(sun, sunRadius, earth). withMaxCheck(60.0). withThreshold(1.0e-3). @@ -163,7 +163,7 @@ public void testPenumbra() { } @Test - public void testWithMethods() { + void testWithMethods() { EclipseDetector e = new EclipseDetector(sun, sunRadius, earth). withHandler(new StopOnDecreasing()). withMaxCheck(120.0). @@ -180,7 +180,7 @@ public void testWithMethods() { } @Test - public void testInsideOcculting() { + void testInsideOcculting() { EclipseDetector e = new EclipseDetector(sun, sunRadius, earth); SpacecraftState s = new SpacecraftState(new CartesianOrbit(new TimeStampedPVCoordinates(AbsoluteDate.J2000_EPOCH, new Vector3D(1e6, 2e6, 3e6), @@ -196,7 +196,7 @@ public void testInsideOcculting() { } @Test - public void testInsideOcculted() { + void testInsideOcculted() { EclipseDetector e = new EclipseDetector(sun, sunRadius, earth); Vector3D p = sun.getPosition(AbsoluteDate.J2000_EPOCH, FramesFactory.getGCRF()); SpacecraftState s = new SpacecraftState(new CartesianOrbit(new TimeStampedPVCoordinates(AbsoluteDate.J2000_EPOCH, @@ -208,7 +208,7 @@ public void testInsideOcculted() { } @Test - public void testTooSmallMaxIterationCount() { + void testTooSmallMaxIterationCount() { int n = 5; EclipseDetector e = new EclipseDetector(sun, sunRadius, earth). withHandler(new StopOnDecreasing()). diff --git a/src/test/java/org/orekit/propagation/numerical/PickupHandler.java b/src/test/java/org/orekit/propagation/numerical/PickUpHandler.java similarity index 100% rename from src/test/java/org/orekit/propagation/numerical/PickupHandler.java rename to src/test/java/org/orekit/propagation/numerical/PickUpHandler.java From 5b65fa9efe915c00a626a0bc52687ea50071f67f Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Sun, 25 Feb 2024 15:38:03 +0100 Subject: [PATCH 155/359] Added {Field}ShiftingPVCoordinatesProvider. --- .../FieldShiftingPVCoordinatesProvider.java | 56 +++++++++++++++++++ .../utils/ShiftingPVCoordinatesProvider.java | 53 ++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 src/main/java/org/orekit/utils/FieldShiftingPVCoordinatesProvider.java create mode 100644 src/main/java/org/orekit/utils/ShiftingPVCoordinatesProvider.java diff --git a/src/main/java/org/orekit/utils/FieldShiftingPVCoordinatesProvider.java b/src/main/java/org/orekit/utils/FieldShiftingPVCoordinatesProvider.java new file mode 100644 index 0000000000..6bdd1e9b31 --- /dev/null +++ b/src/main/java/org/orekit/utils/FieldShiftingPVCoordinatesProvider.java @@ -0,0 +1,56 @@ +/* Copyright 2002-2024 Luc Maisonobe + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.orekit.utils; + +import org.hipparchus.CalculusFieldElement; +import org.orekit.frames.Frame; +import org.orekit.time.FieldAbsoluteDate; + +/** Provider using simple {@link FieldPVCoordinates#shiftedBy(CalculusFieldElement)} shiftedBy} and frame transforms for evolution. + * @param the type of the field elements + * @author Luc Maisonobe + * @since 12.1 + */ +public class FieldShiftingPVCoordinatesProvider> + implements FieldPVCoordinatesProvider { + + /** Reference coordinates. */ + private final TimeStampedFieldPVCoordinates referencePV; + + /** Frame in which {@link #referencePV} is defined. */ + private final Frame referenceFrame; + + /** Simple constructor. + * @param referencePV reference coordinates + * @param referenceFrame frame in which {@code reference} is defined + */ + public FieldShiftingPVCoordinatesProvider(final TimeStampedFieldPVCoordinates referencePV, + final Frame referenceFrame) { + this.referencePV = referencePV; + this.referenceFrame = referenceFrame; + } + + /** {@inheritDoc} */ + @Override + public TimeStampedFieldPVCoordinates getPVCoordinates(final FieldAbsoluteDate date, + final Frame frame) { + final TimeStampedFieldPVCoordinates shifted = referencePV.shiftedBy(date.durationFrom(referencePV)); + return referenceFrame.getTransformTo(frame, date).transformPVCoordinates(shifted); + } + +} diff --git a/src/main/java/org/orekit/utils/ShiftingPVCoordinatesProvider.java b/src/main/java/org/orekit/utils/ShiftingPVCoordinatesProvider.java new file mode 100644 index 0000000000..ba8e214e5d --- /dev/null +++ b/src/main/java/org/orekit/utils/ShiftingPVCoordinatesProvider.java @@ -0,0 +1,53 @@ +/* Copyright 2002-2024 Luc Maisonobe + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.orekit.utils; + +import org.orekit.frames.Frame; +import org.orekit.time.AbsoluteDate; + +/** Provider using simple {@link PVCoordinates#shiftedBy(double)} shiftedBy} and frame transforms for evolution. + * @author Luc Maisonobe + * @since 12.1 + */ +public class ShiftingPVCoordinatesProvider implements PVCoordinatesProvider { + + /** Reference coordinates. */ + private final TimeStampedPVCoordinates referencePV; + + /** Frame in which {@link #referencePV} is defined. */ + private final Frame referenceFrame; + + /** Simple constructor. + * @param referencePV reference coordinates + * @param referenceFrame frame in which {@code reference} is defined + */ + public ShiftingPVCoordinatesProvider(final TimeStampedPVCoordinates referencePV, + final Frame referenceFrame) { + this.referencePV = referencePV; + this.referenceFrame = referenceFrame; + } + + /** {@inheritDoc} */ + @Override + public TimeStampedPVCoordinates getPVCoordinates(final AbsoluteDate date, + final Frame frame) { + final TimeStampedPVCoordinates shifted = referencePV.shiftedBy(date.durationFrom(referencePV)); + return referenceFrame.getTransformTo(frame, date).transformPVCoordinates(shifted); + } + +} From 3c4f40c060dc241dc8a40fef4a243140691065c0 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Sun, 25 Feb 2024 15:48:29 +0100 Subject: [PATCH 156/359] Allo using {Field}PVCoordinatesProvider in signal time of flight. --- .../measurements/AbstractMeasurement.java | 105 +++++++++++++++++- .../measurements/BistaticRange.java | 6 +- .../measurements/BistaticRangeRate.java | 6 +- .../EstimatedMeasurementBase.java | 2 +- .../GroundReceiverMeasurement.java | 5 +- .../measurements/InterSatellitesRange.java | 11 +- .../orekit/estimation/measurements/Range.java | 6 +- .../estimation/measurements/RangeRate.java | 20 ++-- .../measurements/TurnAroundRange.java | 26 +++-- .../gnss/InterSatellitesPhase.java | 5 +- .../measurements/gnss/OneWayGNSSPhase.java | 4 +- .../measurements/gnss/OneWayGNSSRange.java | 12 +- .../orekit/utils/PVCoordinatesProvider.java | 2 +- .../measurements/AngularAzElTest.java | 6 +- .../measurements/AngularRaDecTest.java | 6 +- .../measurements/RangeAnalytic.java | 16 ++- .../estimation/measurements/RangeTest.java | 11 ++ .../measurements/TurnAroundRangeAnalytic.java | 36 +++--- .../TurnAroundRangeMeasurementCreator.java | 2 +- .../gnss/OneWayGNSSRangeTest.java | 29 +++-- 20 files changed, 230 insertions(+), 86 deletions(-) diff --git a/src/main/java/org/orekit/estimation/measurements/AbstractMeasurement.java b/src/main/java/org/orekit/estimation/measurements/AbstractMeasurement.java index 650f5242f6..2179b597dd 100644 --- a/src/main/java/org/orekit/estimation/measurements/AbstractMeasurement.java +++ b/src/main/java/org/orekit/estimation/measurements/AbstractMeasurement.java @@ -25,11 +25,18 @@ import org.hipparchus.geometry.euclidean.threed.FieldVector3D; import org.hipparchus.geometry.euclidean.threed.Vector3D; import org.hipparchus.util.FastMath; +import org.orekit.annotation.DefaultDataContext; +import org.orekit.frames.Frame; +import org.orekit.frames.FramesFactory; import org.orekit.propagation.SpacecraftState; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; import org.orekit.utils.Constants; +import org.orekit.utils.FieldPVCoordinatesProvider; +import org.orekit.utils.PVCoordinatesProvider; import org.orekit.utils.ParameterDriver; +import org.orekit.utils.FieldShiftingPVCoordinatesProvider; +import org.orekit.utils.ShiftingPVCoordinatesProvider; import org.orekit.utils.TimeStampedFieldPVCoordinates; import org.orekit.utils.TimeStampedPVCoordinates; @@ -272,15 +279,58 @@ public List> getModifiers() { * in the same frame as {@code adjustableEmitterPV} * @param signalArrivalDate date at which the signal arrives to receiver * @return positive delay between signal emission and signal reception dates + * @deprecated as of 12.1, replaced by either {@link #signalTimeOfFlight(TimeStampedPVCoordinates, + * Vector3D, AbsoluteDate, Frame)} or {@link #signalTimeOfFlight(PVCoordinatesProvider, AbsoluteDate, + * Vector3D, AbsoluteDate, Frame)} */ + @Deprecated + @DefaultDataContext public static double signalTimeOfFlight(final TimeStampedPVCoordinates adjustableEmitterPV, final Vector3D receiverPosition, final AbsoluteDate signalArrivalDate) { + return signalTimeOfFlight(adjustableEmitterPV, receiverPosition, signalArrivalDate, + FramesFactory.getGCRF()); + } + + /** Compute propagation delay on a link leg (typically downlink or uplink). + * @param adjustableEmitterPV position/velocity of emitter that may be adjusted + * @param receiverPosition fixed position of receiver at {@code signalArrivalDate} + * @param receiverFrame frame in which both {@code adjustableEmitterPV} and + * {@code receiver receiverPosition} are defined + * @param signalArrivalDate date at which the signal arrives to receiver + * @return positive delay between signal emission and signal reception dates + * @since 12.1 + */ + public static double signalTimeOfFlight(final TimeStampedPVCoordinates adjustableEmitterPV, + final Vector3D receiverPosition, + final AbsoluteDate signalArrivalDate, + final Frame receiverFrame) { + return signalTimeOfFlight(new ShiftingPVCoordinatesProvider(adjustableEmitterPV, + receiverFrame), + adjustableEmitterPV.getDate(), + receiverPosition, signalArrivalDate, + receiverFrame); + } + + /** Compute propagation delay on a link leg (typically downlink or uplink). + * @param adjustableEmitter position/velocity provider of emitter + * @param approxEmissionDate approximate emission date + * @param receiverPosition fixed position of receiver at {@code signalArrivalDate} + * @param signalArrivalDate date at which the signal arrives to receiver + * @param receiverFrame frame in which receiver is defined + * @return positive delay between signal emission and signal reception dates + * @since 12.1 + */ + public static double signalTimeOfFlight(final PVCoordinatesProvider adjustableEmitter, + final AbsoluteDate approxEmissionDate, + final Vector3D receiverPosition, + final AbsoluteDate signalArrivalDate, + final Frame receiverFrame) { // initialize emission date search loop assuming the state is already correct // this will be true for all but the first orbit determination iteration, // and even for the first iteration the loop will converge very fast - final double offset = signalArrivalDate.durationFrom(adjustableEmitterPV.getDate()); + final double offset = signalArrivalDate.durationFrom(approxEmissionDate); double delay = offset; // search signal transit date, computing the signal travel in inertial frame @@ -289,7 +339,8 @@ public static double signalTimeOfFlight(final TimeStampedPVCoordinates adjustabl int count = 0; do { final double previous = delay; - final Vector3D transitP = adjustableEmitterPV.shiftedBy(offset - delay).getPosition(); + final Vector3D transitP = adjustableEmitter.getPosition(approxEmissionDate.shiftedBy(offset - delay), + receiverFrame); delay = receiverPosition.distance(transitP) * cReciprocal; delta = FastMath.abs(delay - previous); } while (count++ < 10 && delta >= 2 * FastMath.ulp(delay)); @@ -305,15 +356,60 @@ public static double signalTimeOfFlight(final TimeStampedPVCoordinates adjustabl * @param signalArrivalDate date at which the signal arrives to receiver * @return positive delay between signal emission and signal reception dates * @param the type of the components + * @deprecated as of 12.1, replaced by either {@link #signalTimeOfFlight(TimeStampedFieldPVCoordinates, + * FieldVector3D, FieldAbsoluteDate, Frame)} or {@link #signalTimeOfFlight(FieldPVCoordinatesProvider, + * FieldAbsoluteDate, FieldVector3D, FieldAbsoluteDate, Frame)} */ + @Deprecated public static > T signalTimeOfFlight(final TimeStampedFieldPVCoordinates adjustableEmitterPV, final FieldVector3D receiverPosition, final FieldAbsoluteDate signalArrivalDate) { + return signalTimeOfFlight(adjustableEmitterPV, receiverPosition, signalArrivalDate, + FramesFactory.getGCRF()); + } + + /** Compute propagation delay on a link leg (typically downlink or uplink). + * @param adjustableEmitterPV position/velocity of emitter that may be adjusted + * @param receiverPosition fixed position of receiver at {@code signalArrivalDate}, + * in the same frame as {@code adjustableEmitterPV} + * @param signalArrivalDate date at which the signal arrives to receiver + * @return positive delay between signal emission and signal reception dates + * @param receiverFrame frame in which receiver is defined + * @param the type of the components + * @since 12.1 + */ + public static > T signalTimeOfFlight(final TimeStampedFieldPVCoordinates adjustableEmitterPV, + final FieldVector3D receiverPosition, + final FieldAbsoluteDate signalArrivalDate, + final Frame receiverFrame) { + return signalTimeOfFlight(new FieldShiftingPVCoordinatesProvider<>(adjustableEmitterPV, + receiverFrame), + adjustableEmitterPV.getDate(), + receiverPosition, signalArrivalDate, + receiverFrame); + } + + /** Compute propagation delay on a link leg (typically downlink or uplink). + * @param adjustableEmitter position/velocity provider of emitter + * @param approxEmissionDate approximate emission date + * @param receiverPosition fixed position of receiver at {@code signalArrivalDate}, + * in the same frame as {@code adjustableEmitterPV} + * @param signalArrivalDate date at which the signal arrives to receiver + * @param receiverFrame frame in which receiver is defined + * @return positive delay between signal emission and signal reception dates + * @param the type of the components + * @since 12.1 + */ + public static > T signalTimeOfFlight(final FieldPVCoordinatesProvider adjustableEmitter, + final FieldAbsoluteDate approxEmissionDate, + final FieldVector3D receiverPosition, + final FieldAbsoluteDate signalArrivalDate, + final Frame receiverFrame) { // Initialize emission date search loop assuming the emitter PV is almost correct // this will be true for all but the first orbit determination iteration, // and even for the first iteration the loop will converge extremely fast - final T offset = signalArrivalDate.durationFrom(adjustableEmitterPV.getDate()); + final T offset = signalArrivalDate.durationFrom(approxEmissionDate); T delay = offset; // search signal transit date, computing the signal travel in the frame shared by emitter and receiver @@ -322,7 +418,8 @@ public static > T signalTimeOfFlight(final Tim int count = 0; do { final double previous = delay.getReal(); - final FieldVector3D transitP = adjustableEmitterPV.shiftedBy(delay.negate().add(offset)).getPosition(); + final FieldVector3D transitP = adjustableEmitter.getPosition(approxEmissionDate.shiftedBy(offset.subtract(delay)), + receiverFrame); delay = receiverPosition.distance(transitP).multiply(cReciprocal); delta = FastMath.abs(delay.getReal() - previous); } while (count++ < 10 && delta >= 2 * FastMath.ulp(delay.getReal())); diff --git a/src/main/java/org/orekit/estimation/measurements/BistaticRange.java b/src/main/java/org/orekit/estimation/measurements/BistaticRange.java index 2aa57c841b..506e1bcda8 100644 --- a/src/main/java/org/orekit/estimation/measurements/BistaticRange.java +++ b/src/main/java/org/orekit/estimation/measurements/BistaticRange.java @@ -126,7 +126,8 @@ protected EstimatedMeasurementBase theoreticalEvaluationWithoutDe Vector3D.ZERO, Vector3D.ZERO, Vector3D.ZERO)); // Uplink time of flight from emitter station to transit state - final double tauU = signalTimeOfFlight(emitterApprox, transitPV.getPosition(), transitDate); + final double tauU = signalTimeOfFlight(emitterApprox, transitPV.getPosition(), transitDate, + common.getState().getFrame()); // Secondary station PV in inertial frame at rebound date on secondary station final TimeStampedPVCoordinates emitterPV = emitterApprox.shiftedBy(-tauU); @@ -184,7 +185,8 @@ protected EstimatedMeasurement theoreticalEvaluation(final int it zero, zero, zero)); // Uplink time of flight from emiiter to transit state - final Gradient tauU = signalTimeOfFlight(emitterApprox, transitPV.getPosition(), transitPV.getDate()); + final Gradient tauU = signalTimeOfFlight(emitterApprox, transitPV.getPosition(), + transitPV.getDate(), state.getFrame()); // Emitter coordinates at transmit time final TimeStampedFieldPVCoordinates emitterPV = emitterApprox.shiftedBy(tauU.negate()); diff --git a/src/main/java/org/orekit/estimation/measurements/BistaticRangeRate.java b/src/main/java/org/orekit/estimation/measurements/BistaticRangeRate.java index 54365a86cf..91c0002357 100644 --- a/src/main/java/org/orekit/estimation/measurements/BistaticRangeRate.java +++ b/src/main/java/org/orekit/estimation/measurements/BistaticRangeRate.java @@ -121,7 +121,8 @@ protected EstimatedMeasurementBase theoreticalEvaluationWitho Vector3D.ZERO, Vector3D.ZERO, Vector3D.ZERO)); // Uplink time of flight from emitter station to transit state - final double tauU = signalTimeOfFlight(emitterApprox, transitPV.getPosition(), transitDate); + final double tauU = signalTimeOfFlight(emitterApprox, transitPV.getPosition(), transitDate, + common.getState().getFrame()); // Secondary station PV in inertial frame at rebound date on secondary station final TimeStampedPVCoordinates emitterPV = emitterApprox.shiftedBy(-tauU); @@ -189,7 +190,8 @@ protected EstimatedMeasurement theoreticalEvaluation(final in zero, zero, zero)); // Uplink time of flight from emiiter to transit state - final Gradient tauU = signalTimeOfFlight(emitterApprox, transitPV.getPosition(), transitPV.getDate()); + final Gradient tauU = signalTimeOfFlight(emitterApprox, transitPV.getPosition(), transitPV.getDate(), + state.getFrame()); // Emitter coordinates at transmit time final TimeStampedFieldPVCoordinates emitterPV = emitterApprox.shiftedBy(tauU.negate()); diff --git a/src/main/java/org/orekit/estimation/measurements/EstimatedMeasurementBase.java b/src/main/java/org/orekit/estimation/measurements/EstimatedMeasurementBase.java index 6f301f60f8..4cae69655a 100644 --- a/src/main/java/org/orekit/estimation/measurements/EstimatedMeasurementBase.java +++ b/src/main/java/org/orekit/estimation/measurements/EstimatedMeasurementBase.java @@ -171,7 +171,7 @@ public enum Status { PROCESSED, /** Status for rejected measurements. */ - REJECTED; + REJECTED } diff --git a/src/main/java/org/orekit/estimation/measurements/GroundReceiverMeasurement.java b/src/main/java/org/orekit/estimation/measurements/GroundReceiverMeasurement.java index 5eea446ff4..1c0f3c5ccc 100644 --- a/src/main/java/org/orekit/estimation/measurements/GroundReceiverMeasurement.java +++ b/src/main/java/org/orekit/estimation/measurements/GroundReceiverMeasurement.java @@ -155,7 +155,7 @@ protected GroundReceiverCommonParametersWithoutDerivatives computeCommonParamete // we will have delta == tauD and transitState will be the same as state) // Downlink delay - final double tauD = signalTimeOfFlight(pva, stationDownlink.getPosition(), downlinkDate); + final double tauD = signalTimeOfFlight(pva, stationDownlink.getPosition(), downlinkDate, state.getFrame()); // Transit state & Transit state (re)computed with gradients final double delta = downlinkDate.durationFrom(state.getDate()); @@ -206,7 +206,8 @@ protected GroundReceiverCommonParametersWithDerivatives computeCommonParametersW // we will have delta == tauD and transitState will be the same as state) // Downlink delay - final Gradient tauD = signalTimeOfFlight(pva, stationDownlink.getPosition(), downlinkDate); + final Gradient tauD = signalTimeOfFlight(pva, stationDownlink.getPosition(), + downlinkDate, state.getFrame()); // Transit state & Transit state (re)computed with gradients final Gradient delta = downlinkDate.durationFrom(state.getDate()); diff --git a/src/main/java/org/orekit/estimation/measurements/InterSatellitesRange.java b/src/main/java/org/orekit/estimation/measurements/InterSatellitesRange.java index 203e46aa9e..de147826d5 100644 --- a/src/main/java/org/orekit/estimation/measurements/InterSatellitesRange.java +++ b/src/main/java/org/orekit/estimation/measurements/InterSatellitesRange.java @@ -130,7 +130,7 @@ protected EstimatedMeasurementBase theoreticalEvaluationWi final TimeStampedPVCoordinates s1Downlink = pvaL.shiftedBy(arrivalDate.durationFrom(pvaL.getDate())); - final double tauD = signalTimeOfFlight(pvaR, s1Downlink.getPosition(), arrivalDate); + final double tauD = signalTimeOfFlight(pvaR, s1Downlink.getPosition(), arrivalDate, local.getFrame()); // Transit state final double delta = getDate().durationFrom(remote.getDate()); @@ -147,7 +147,8 @@ protected EstimatedMeasurementBase theoreticalEvaluationWi // uplink delay final double tauU = signalTimeOfFlight(pvaL, transitState.getPosition(), - transitState.getDate()); + transitState.getDate(), + local.getFrame()); estimated = new EstimatedMeasurementBase<>(this, iteration, evaluation, new SpacecraftState[] { local.shiftedBy(deltaMTauD), @@ -230,7 +231,8 @@ protected EstimatedMeasurement theoreticalEvaluation(final final TimeStampedFieldPVCoordinates s1Downlink = pvaL.shiftedBy(arrivalDate.durationFrom(pvaL.getDate())); - final Gradient tauD = signalTimeOfFlight(pvaR, s1Downlink.getPosition(), arrivalDate); + final Gradient tauD = signalTimeOfFlight(pvaR, s1Downlink.getPosition(), + arrivalDate, local.getFrame()); // Transit state final double delta = getDate().durationFrom(remote.getDate()); @@ -247,7 +249,8 @@ protected EstimatedMeasurement theoreticalEvaluation(final // uplink delay final Gradient tauU = signalTimeOfFlight(pvaL, transitStateDS.getPosition(), - transitStateDS.getDate()); + transitStateDS.getDate(), + local.getFrame()); estimated = new EstimatedMeasurement<>(this, iteration, evaluation, new SpacecraftState[] { local.shiftedBy(deltaMTauD.getValue()), diff --git a/src/main/java/org/orekit/estimation/measurements/Range.java b/src/main/java/org/orekit/estimation/measurements/Range.java index f9f9d5fb0c..dba9684923 100644 --- a/src/main/java/org/orekit/estimation/measurements/Range.java +++ b/src/main/java/org/orekit/estimation/measurements/Range.java @@ -107,7 +107,8 @@ protected EstimatedMeasurementBase theoreticalEvaluationWithoutDerivative // Station at transit state date (derivatives of tauD taken into account) final TimeStampedPVCoordinates stationAtTransitDate = common.getStationDownlink().shiftedBy(-common.getTauD()); // Uplink delay - final double tauU = signalTimeOfFlight(stationAtTransitDate, transitPV.getPosition(), transitPV.getDate()); + final double tauU = signalTimeOfFlight(stationAtTransitDate, transitPV.getPosition(), + transitPV.getDate(), common.getState().getFrame()); final TimeStampedPVCoordinates stationUplink = common.getStationDownlink().shiftedBy(-common.getTauD() - tauU); // Prepare the evaluation @@ -182,7 +183,8 @@ protected EstimatedMeasurement theoreticalEvaluation(final int iteration, common.getStationDownlink().shiftedBy(common.getTauD().negate()); // Uplink delay final Gradient tauU = - signalTimeOfFlight(stationAtTransitDate, transitPV.getPosition(), transitPV.getDate()); + signalTimeOfFlight(stationAtTransitDate, transitPV.getPosition(), transitPV.getDate(), + state.getFrame()); final TimeStampedFieldPVCoordinates stationUplink = common.getStationDownlink().shiftedBy(-common.getTauD().getValue() - tauU.getValue()); diff --git a/src/main/java/org/orekit/estimation/measurements/RangeRate.java b/src/main/java/org/orekit/estimation/measurements/RangeRate.java index 0c45344067..6075bf56b9 100644 --- a/src/main/java/org/orekit/estimation/measurements/RangeRate.java +++ b/src/main/java/org/orekit/estimation/measurements/RangeRate.java @@ -96,7 +96,8 @@ protected EstimatedMeasurementBase theoreticalEvaluationWithoutDeriva offsetToInertialApproxUplink.transformPVCoordinates(new TimeStampedPVCoordinates(approxUplinkDate, Vector3D.ZERO, Vector3D.ZERO, Vector3D.ZERO)); - final double tauU = signalTimeOfFlight(stationApproxUplink, transitPV.getPosition(), transitPV.getDate()); + final double tauU = signalTimeOfFlight(stationApproxUplink, transitPV.getPosition(), + transitPV.getDate(), common.getState().getFrame()); final TimeStampedPVCoordinates stationUplink = stationApproxUplink.shiftedBy(transitPV.getDate().durationFrom(approxUplinkDate) - tauU); @@ -162,7 +163,8 @@ protected EstimatedMeasurement theoreticalEvaluation(final int iterat offsetToInertialApproxUplink.transformPVCoordinates(new TimeStampedFieldPVCoordinates<>(approxUplinkDateDS, zero, zero, zero)); - final Gradient tauU = signalTimeOfFlight(stationApproxUplink, transitPV.getPosition(), transitPV.getDate()); + final Gradient tauU = signalTimeOfFlight(stationApproxUplink, transitPV.getPosition(), transitPV.getDate(), + state.getFrame()); final TimeStampedFieldPVCoordinates stationUplink = stationApproxUplink.shiftedBy(transitPV.getDate().durationFrom(approxUplinkDateDS).subtract(tauU)); @@ -292,13 +294,13 @@ private EstimatedMeasurement oneWayTheoreticalEvaluation(final int it // prepare the evaluation final EstimatedMeasurement estimated = - new EstimatedMeasurement(this, iteration, evaluation, - new SpacecraftState[] { - transitState - }, new TimeStampedPVCoordinates[] { - (downlink ? transitPV : stationPV).toTimeStampedPVCoordinates(), - (downlink ? stationPV : transitPV).toTimeStampedPVCoordinates() - }); + new EstimatedMeasurement<>(this, iteration, evaluation, + new SpacecraftState[] { + transitState + }, new TimeStampedPVCoordinates[] { + (downlink ? transitPV : stationPV).toTimeStampedPVCoordinates(), + (downlink ? stationPV : transitPV).toTimeStampedPVCoordinates() + }); // range rate value final FieldVector3D stationPosition = stationPV.getPosition(); diff --git a/src/main/java/org/orekit/estimation/measurements/TurnAroundRange.java b/src/main/java/org/orekit/estimation/measurements/TurnAroundRange.java index 096260272f..c342b49054 100644 --- a/src/main/java/org/orekit/estimation/measurements/TurnAroundRange.java +++ b/src/main/java/org/orekit/estimation/measurements/TurnAroundRange.java @@ -156,7 +156,8 @@ protected EstimatedMeasurementBase theoreticalEvaluationWithout Vector3D.ZERO, Vector3D.ZERO, Vector3D.ZERO)); // Compute propagation times - final double primaryTauD = signalTimeOfFlight(pva, primaryArrival.getPosition(), measurementDate); + final double primaryTauD = signalTimeOfFlight(pva, primaryArrival.getPosition(), measurementDate, + state.getFrame()); // Elapsed time between state date t' and signal arrival to the transit state of the 2nd leg final double dtLeg2 = delta - primaryTauD; @@ -180,8 +181,9 @@ protected EstimatedMeasurementBase theoreticalEvaluationWithout // Uplink time of flight from secondary station to transit state of leg2 final double secondaryTauU = signalTimeOfFlight(QSecondaryApprox, - transitStateLeg2PV.getPosition(), - transitStateLeg2PV.getDate()); + transitStateLeg2PV.getPosition(), + transitStateLeg2PV.getDate(), + state.getFrame()); // Total time of flight for leg 2 final double tauLeg2 = primaryTauD + secondaryTauU; @@ -201,7 +203,8 @@ protected EstimatedMeasurementBase theoreticalEvaluationWithout // Downlink time of flight from transitStateLeg1 to secondary station at rebound date final double secondaryTauD = signalTimeOfFlight(transitStateLeg2PV, secondaryRebound.getPosition(), - reboundDate); + reboundDate, + state.getFrame()); // Elapsed time between state date t' and signal arrival to the transit state of the 1st leg @@ -222,7 +225,8 @@ protected EstimatedMeasurementBase theoreticalEvaluationWithout // Uplink time of flight from primary station to transit state of leg1 final double primaryTauU = signalTimeOfFlight(QPrimaryApprox, transitStateLeg1PV.getPosition(), - transitStateLeg1PV.getDate()); + transitStateLeg1PV.getDate(), + state.getFrame()); // Primary station PV in inertial frame at exact emission date final AbsoluteDate emissionDate = transitStateLeg1PV.getDate().shiftedBy(-primaryTauU); @@ -340,7 +344,8 @@ protected EstimatedMeasurement theoreticalEvaluation(final int zero, zero, zero)); // Compute propagation times - final Gradient primaryTauD = signalTimeOfFlight(pvaDS, primaryArrival.getPosition(), measurementDateDS); + final Gradient primaryTauD = signalTimeOfFlight(pvaDS, primaryArrival.getPosition(), + measurementDateDS, state.getFrame()); // Elapsed time between state date t' and signal arrival to the transit state of the 2nd leg final Gradient dtLeg2 = primaryTauD.negate().add(delta); @@ -365,7 +370,8 @@ protected EstimatedMeasurement theoreticalEvaluation(final int // Uplink time of flight from secondary station to transit state of leg2 final Gradient secondaryTauU = signalTimeOfFlight(QSecondaryApprox, transitStateLeg2PV.getPosition(), - transitStateLeg2PV.getDate()); + transitStateLeg2PV.getDate(), + state.getFrame()); // Total time of flight for leg 2 final Gradient tauLeg2 = primaryTauD.add(secondaryTauU); @@ -386,7 +392,8 @@ protected EstimatedMeasurement theoreticalEvaluation(final int // Downlink time of flight from transitStateLeg1 to secondary station at rebound date final Gradient secondaryTauD = signalTimeOfFlight(transitStateLeg2PV, secondaryRebound.getPosition(), - reboundDateDS); + reboundDateDS, + state.getFrame()); // Elapsed time between state date t' and signal arrival to the transit state of the 1st leg @@ -410,7 +417,8 @@ protected EstimatedMeasurement theoreticalEvaluation(final int // Uplink time of flight from primary station to transit state of leg1 final Gradient primaryTauU = signalTimeOfFlight(QPrimaryApprox, transitStateLeg1PV.getPosition(), - transitStateLeg1PV.getDate()); + transitStateLeg1PV.getDate(), + state.getFrame()); // Primary station PV in inertial frame at exact emission date final AbsoluteDate emissionDate = transitStateLeg1PV.getDate().toAbsoluteDate().shiftedBy(-primaryTauU.getValue()); diff --git a/src/main/java/org/orekit/estimation/measurements/gnss/InterSatellitesPhase.java b/src/main/java/org/orekit/estimation/measurements/gnss/InterSatellitesPhase.java index ecbf8dd2c1..27962cd159 100644 --- a/src/main/java/org/orekit/estimation/measurements/gnss/InterSatellitesPhase.java +++ b/src/main/java/org/orekit/estimation/measurements/gnss/InterSatellitesPhase.java @@ -122,7 +122,7 @@ protected EstimatedMeasurementBase theoreticalEvaluationWi final AbsoluteDate arrivalDate = getDate().shiftedBy(-dtl); final TimeStampedPVCoordinates s1Downlink = pvaL.shiftedBy(arrivalDate.durationFrom(pvaL.getDate())); - final double tauD = signalTimeOfFlight(pvaR, s1Downlink.getPosition(), arrivalDate); + final double tauD = signalTimeOfFlight(pvaR, s1Downlink.getPosition(), arrivalDate, local.getFrame()); // Transit state final double delta = getDate().durationFrom(remote.getDate()); @@ -193,7 +193,8 @@ protected EstimatedMeasurement theoreticalEvaluation(final final TimeStampedFieldPVCoordinates s1Downlink = pvaL.shiftedBy(arrivalDate.durationFrom(pvaL.getDate())); - final Gradient tauD = signalTimeOfFlight(pvaR, s1Downlink.getPosition(), arrivalDate); + final Gradient tauD = signalTimeOfFlight(pvaR, s1Downlink.getPosition(), + arrivalDate, local.getFrame()); // Transit state final double delta = getDate().durationFrom(remote.getDate()); diff --git a/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSPhase.java b/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSPhase.java index d2487a0cb4..3b05d45336 100644 --- a/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSPhase.java +++ b/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSPhase.java @@ -138,7 +138,7 @@ protected EstimatedMeasurementBase theoreticalEvaluationWithout final SpacecraftState sDownlink = localState.shiftedBy(arrivalDate.durationFrom(localState.getDate())); final TimeStampedPVCoordinates pvaDownlink = pvaLocal.shiftedBy(arrivalDate.durationFrom(pvaLocal.getDate())); - final double tauD = signalTimeOfFlight(pvaRemote, pvaDownlink.getPosition(), arrivalDate); + final double tauD = signalTimeOfFlight(pvaRemote, pvaDownlink.getPosition(), arrivalDate, localState.getFrame()); // prepare the evaluation final EstimatedMeasurementBase estimatedPhase = @@ -196,7 +196,7 @@ protected EstimatedMeasurement theoreticalEvaluation(final int final SpacecraftState sDownlink = localState.shiftedBy(arrivalDate.toAbsoluteDate().durationFrom(localState.getDate())); final TimeStampedFieldPVCoordinates pvaDownlink = pvaLocal.shiftedBy(arrivalDate.durationFrom(pvaLocal.getDate())); final Gradient tauD = signalTimeOfFlight(new TimeStampedFieldPVCoordinates<>(pvaRemote.getDate(), dtLocal.getField().getOne(), pvaRemote), - pvaDownlink.getPosition(), arrivalDate); + pvaDownlink.getPosition(), arrivalDate, localState.getFrame()); // prepare the evaluation final EstimatedMeasurement estimatedPhase = diff --git a/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRange.java b/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRange.java index 917b98ac69..a43ecd10a2 100644 --- a/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRange.java +++ b/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRange.java @@ -105,9 +105,9 @@ protected EstimatedMeasurementBase theoreticalEvaluationWithout final double dtLocal = getSatellites().get(0).getClockOffsetDriver().getValue(localState.getDate()); final AbsoluteDate arrivalDate = getDate().shiftedBy(-dtLocal); - final SpacecraftState sDownlink = localState.shiftedBy(arrivalDate.durationFrom(localState.getDate())); - final TimeStampedPVCoordinates pvaDownlink = pvaLocal.shiftedBy(arrivalDate.durationFrom(pvaLocal.getDate())); - final double tauD = signalTimeOfFlight(pvaRemote, pvaDownlink.getPosition(), arrivalDate); + final SpacecraftState sDownlink = localState.shiftedBy(arrivalDate.durationFrom(localState)); + final TimeStampedPVCoordinates pvaDownlink = pvaLocal.shiftedBy(arrivalDate.durationFrom(pvaLocal)); + final double tauD = signalTimeOfFlight(pvaRemote, pvaDownlink.getPosition(), arrivalDate, localState.getFrame()); // Estimated measurement final EstimatedMeasurementBase estimatedRange = @@ -160,10 +160,10 @@ protected EstimatedMeasurement theoreticalEvaluation(final int final Gradient dtLocal = getSatellites().get(0).getClockOffsetDriver().getValue(nbEstimatedParams, parameterIndices, localState.getDate()); final FieldAbsoluteDate arrivalDate = new FieldAbsoluteDate<>(getDate(), dtLocal.negate()); - final SpacecraftState sDownlink = localState.shiftedBy(arrivalDate.toAbsoluteDate().durationFrom(localState.getDate())); - final TimeStampedFieldPVCoordinates pvaDownlink = pvaLocal.shiftedBy(arrivalDate.durationFrom(pvaLocal.getDate())); + final SpacecraftState sDownlink = localState.shiftedBy(arrivalDate.toAbsoluteDate().durationFrom(localState)); + final TimeStampedFieldPVCoordinates pvaDownlink = pvaLocal.shiftedBy(arrivalDate.durationFrom(pvaLocal)); final Gradient tauD = signalTimeOfFlight(new TimeStampedFieldPVCoordinates<>(pvaRemote.getDate(), dtLocal.getField().getOne(), pvaRemote), - pvaDownlink.getPosition(), arrivalDate); + pvaDownlink.getPosition(), arrivalDate, localState.getFrame()); // Estimated measurement final EstimatedMeasurement estimatedRange = diff --git a/src/main/java/org/orekit/utils/PVCoordinatesProvider.java b/src/main/java/org/orekit/utils/PVCoordinatesProvider.java index 38ce1670c5..95e419cd8f 100644 --- a/src/main/java/org/orekit/utils/PVCoordinatesProvider.java +++ b/src/main/java/org/orekit/utils/PVCoordinatesProvider.java @@ -22,7 +22,7 @@ import org.orekit.time.AbsoluteDate; /** -** Interface for PV coordinates providers. + * Interface for PV coordinates providers. * @author Veronique Pommier *

                  The PV coordinates provider interface can be used by any class used for position/velocity * computation, for example celestial bodies or spacecraft position/velocity propagators, diff --git a/src/test/java/org/orekit/estimation/measurements/AngularAzElTest.java b/src/test/java/org/orekit/estimation/measurements/AngularAzElTest.java index f45aeae569..29b1f5a6ef 100644 --- a/src/test/java/org/orekit/estimation/measurements/AngularAzElTest.java +++ b/src/test/java/org/orekit/estimation/measurements/AngularAzElTest.java @@ -136,7 +136,8 @@ public void testStateDerivatives() { final AbsoluteDate datemeas = measurement.getDate(); SpacecraftState state = propagator.propagate(datemeas); final Vector3D stationP = stationParameter.getOffsetToInertial(state.getFrame(), datemeas, false).transformPosition(Vector3D.ZERO); - final double meanDelay = AbstractMeasurement.signalTimeOfFlight(state.getPVCoordinates(), stationP, datemeas); + final double meanDelay = AbstractMeasurement.signalTimeOfFlight(state.getPVCoordinates(), stationP, + datemeas, state.getFrame()); final AbsoluteDate date = measurement.getDate().shiftedBy(-0.75 * meanDelay); state = propagator.propagate(date); @@ -237,7 +238,8 @@ public void testParameterDerivatives() { final AbsoluteDate datemeas = measurement.getDate(); final SpacecraftState stateini = propagator.propagate(datemeas); final Vector3D stationP = stationParameter.getOffsetToInertial(stateini.getFrame(), datemeas, false).transformPosition(Vector3D.ZERO); - final double meanDelay = AbstractMeasurement.signalTimeOfFlight(stateini.getPVCoordinates(), stationP, datemeas); + final double meanDelay = AbstractMeasurement.signalTimeOfFlight(stateini.getPVCoordinates(), stationP, + datemeas, stateini.getFrame()); final AbsoluteDate date = measurement.getDate().shiftedBy(-0.75 * meanDelay); final SpacecraftState state = propagator.propagate(date); diff --git a/src/test/java/org/orekit/estimation/measurements/AngularRaDecTest.java b/src/test/java/org/orekit/estimation/measurements/AngularRaDecTest.java index d70b685abb..65271acd88 100644 --- a/src/test/java/org/orekit/estimation/measurements/AngularRaDecTest.java +++ b/src/test/java/org/orekit/estimation/measurements/AngularRaDecTest.java @@ -152,7 +152,8 @@ public void testStateDerivatives() { final AbsoluteDate datemeas = measurement.getDate(); SpacecraftState state = propagator.propagate(datemeas); final Vector3D stationP = stationParameter.getOffsetToInertial(state.getFrame(), datemeas, false).transformPosition(Vector3D.ZERO); - final double meanDelay = AbstractMeasurement.signalTimeOfFlight(state.getPVCoordinates(), stationP, datemeas); + final double meanDelay = AbstractMeasurement.signalTimeOfFlight(state.getPVCoordinates(), stationP, + datemeas, state.getFrame()); final AbsoluteDate date = measurement.getDate().shiftedBy(-0.75 * meanDelay); state = propagator.propagate(date); @@ -254,7 +255,8 @@ public void testParameterDerivatives() { final AbsoluteDate datemeas = measurement.getDate(); final SpacecraftState stateini = propagator.propagate(datemeas); final Vector3D stationP = stationParameter.getOffsetToInertial(stateini.getFrame(), datemeas, false).transformPosition(Vector3D.ZERO); - final double meanDelay = AbstractMeasurement.signalTimeOfFlight(stateini.getPVCoordinates(), stationP, datemeas); + final double meanDelay = AbstractMeasurement.signalTimeOfFlight(stateini.getPVCoordinates(), stationP, + datemeas, stateini.getFrame()); final AbsoluteDate date = measurement.getDate().shiftedBy(-0.75 * meanDelay); final SpacecraftState state = propagator.propagate(date); diff --git a/src/test/java/org/orekit/estimation/measurements/RangeAnalytic.java b/src/test/java/org/orekit/estimation/measurements/RangeAnalytic.java index ab5287a766..71522d29f8 100644 --- a/src/test/java/org/orekit/estimation/measurements/RangeAnalytic.java +++ b/src/test/java/org/orekit/estimation/measurements/RangeAnalytic.java @@ -104,7 +104,8 @@ protected EstimatedMeasurement theoreticalEvaluationAnalytic(final int it // Downlink time of flight final double tauD = signalTimeOfFlight(state.getPVCoordinates(), stationDownlink.getPosition(), - downlinkDate); + downlinkDate, + state.getFrame()); final double delta = downlinkDate.durationFrom(state.getDate()); final double dt = delta - tauD; @@ -120,7 +121,7 @@ protected EstimatedMeasurement theoreticalEvaluationAnalytic(final int it transformPVCoordinates(new TimeStampedPVCoordinates(transitDate, PVCoordinates.ZERO)); // Uplink time of flight - final double tauU = signalTimeOfFlight(stationAtTransitDate, transitP, transitDate); + final double tauU = signalTimeOfFlight(stationAtTransitDate, transitP, transitDate, state.getFrame()); final double tau = tauD + tauU; // Real date and position of station at signal departure @@ -309,7 +310,8 @@ protected EstimatedMeasurement theoreticalEvaluationValidation(final int // the same as state) // Downlink delay - final Gradient tauD = signalTimeOfFlight(pvaDS, stationDownlink.getPosition(), downlinkDateDS); + final Gradient tauD = signalTimeOfFlight(pvaDS, stationDownlink.getPosition(), + downlinkDateDS, state.getFrame()); // Transit state final double delta = downlinkDate.durationFrom(state.getDate()); @@ -324,7 +326,8 @@ protected EstimatedMeasurement theoreticalEvaluationValidation(final int stationDownlink.shiftedBy(tauD.negate()); // Uplink delay final Gradient tauU = - signalTimeOfFlight(stationAtTransitDate, transitStateDS.getPosition(), transitStateDS.getDate()); + signalTimeOfFlight(stationAtTransitDate, transitStateDS.getPosition(), + transitStateDS.getDate(), state.getFrame()); // Prepare the evaluation final EstimatedMeasurement estimated = @@ -371,7 +374,8 @@ protected EstimatedMeasurement theoreticalEvaluationValidation(final int transformPVCoordinates(PVCoordinates.ZERO); // Downlink time of flight from spacecraft to station - final double td = signalTimeOfFlight(state.getPVCoordinates(), QDownlink.getPosition(), downlinkDate); + final double td = signalTimeOfFlight(state.getPVCoordinates(), QDownlink.getPosition(), downlinkDate, + state.getFrame()); final double dt = delta - td; // Transit state position @@ -394,7 +398,7 @@ protected EstimatedMeasurement theoreticalEvaluationValidation(final int transformPVCoordinates(new TimeStampedPVCoordinates(transitT, PVCoordinates.ZERO)); // Uplink time of flight - final double tu = signalTimeOfFlight(QAtTransitDate, transitP, transitT); + final double tu = signalTimeOfFlight(QAtTransitDate, transitP, transitT, state.getFrame()); // Total time of flight final double t = td + tu; diff --git a/src/test/java/org/orekit/estimation/measurements/RangeTest.java b/src/test/java/org/orekit/estimation/measurements/RangeTest.java index 1de519abfc..415954d28b 100644 --- a/src/test/java/org/orekit/estimation/measurements/RangeTest.java +++ b/src/test/java/org/orekit/estimation/measurements/RangeTest.java @@ -251,6 +251,17 @@ void genericTestValues(final boolean printResults) { absoluteErrors.add(absoluteError); relativeErrors.add(FastMath.abs(absoluteError)/FastMath.abs(RangeObserved)); + // test deprecated method (just for test coverage) + // here, the frame is not the same in both calls, but results should be the same as both are inertial frames + Assertions.assertEquals(AbstractMeasurement.signalTimeOfFlight(estimated.getParticipants()[0], + estimated.getParticipants()[1].getPosition(), + estimated.getParticipants()[1].getDate()), + AbstractMeasurement.signalTimeOfFlight(estimated.getParticipants()[0], + estimated.getParticipants()[1].getPosition(), + estimated.getParticipants()[1].getDate(), + state.getFrame()), + 1.0e-6); + // Print results on console ? if (printResults) { final AbsoluteDate measurementDate = measurement.getDate(); diff --git a/src/test/java/org/orekit/estimation/measurements/TurnAroundRangeAnalytic.java b/src/test/java/org/orekit/estimation/measurements/TurnAroundRangeAnalytic.java index c956af17d3..72ac2a1d06 100644 --- a/src/test/java/org/orekit/estimation/measurements/TurnAroundRangeAnalytic.java +++ b/src/test/java/org/orekit/estimation/measurements/TurnAroundRangeAnalytic.java @@ -127,7 +127,8 @@ protected EstimatedMeasurement theoreticalEvaluationAnalytic(fi PVCoordinates.ZERO)); // Downlink time of flight from primary station at t to spacecraft at t' - final double tMd = signalTimeOfFlight(state.getPVCoordinates(), primaryArrival.getPosition(), measurementDate); + final double tMd = signalTimeOfFlight(state.getPVCoordinates(), primaryArrival.getPosition(), + measurementDate, state.getFrame()); // Time difference between t (date of the measurement) and t' (date tagged in spacecraft state) // (if state has already been set up to pre-compensate propagation delay, delta = primaryTauD + secondaryTauU) @@ -146,7 +147,8 @@ protected EstimatedMeasurement theoreticalEvaluationAnalytic(fi // Uplink time of flight from secondary station to transit state leg2 final double tSu = signalTimeOfFlight(QsecondaryTransitLeg2PV, transitStateLeg2.getPosition(), - transitDateLeg2); + transitDateLeg2, + state.getFrame()); // Total time of flight for leg 2 final double t2 = tMd + tSu; @@ -166,7 +168,8 @@ protected EstimatedMeasurement theoreticalEvaluationAnalytic(fi PVCoordinates.ZERO)); // Dowlink time of flight from transitStateLeg1 to secondary station at secondaryStationArrivalDate - final double tSd = signalTimeOfFlight(transitStateLeg2.getPVCoordinates(), secondaryRebound.getPosition(), secondaryStationArrivalDate); + final double tSd = signalTimeOfFlight(transitStateLeg2.getPVCoordinates(), secondaryRebound.getPosition(), + secondaryStationArrivalDate, state.getFrame()); // Transit state from which the satellite reflected the signal from primary to secondary station final SpacecraftState transitStateLeg1 = state.shiftedBy(delta -tMd -tSu -tSd); @@ -181,7 +184,8 @@ protected EstimatedMeasurement theoreticalEvaluationAnalytic(fi // Uplink time of flight from primary station to transit state leg1 final double tMu = signalTimeOfFlight(QPrimaryTransitLeg1PV, transitStateLeg1.getPosition(), - transitDateLeg1); + transitDateLeg1, + state.getFrame()); final AbsoluteDate emissionDate = transitDateLeg1.shiftedBy(-tMu); final TimeStampedPVCoordinates primaryDeparture = primaryTopoToInertTransitLeg1.shiftedBy(emissionDate.durationFrom(primaryTopoToInertTransitLeg1.getDate())). @@ -603,7 +607,7 @@ protected EstimatedMeasurement theoreticalEvaluationValidation( final FieldVector3D QPrimary = primaryToInert.transformPosition(zero); // Compute propagation times - final Gradient primaryTauD = signalTimeOfFlight(pvaDS, QPrimary, measurementDateDS); + final Gradient primaryTauD = signalTimeOfFlight(pvaDS, QPrimary, measurementDateDS, state.getFrame()); // Elapsed time between state date t' and signal arrival to the transit state of the 2nd leg final Gradient dtLeg2 = primaryTauD.negate().add(delta); @@ -629,7 +633,8 @@ protected EstimatedMeasurement theoreticalEvaluationValidation( final Gradient secondaryTauU = signalTimeOfFlight(QsecondaryApprox, transitStateLeg2PV.getPosition(), - transitStateLeg2PV.getDate()); + transitStateLeg2PV.getDate(), + state.getFrame()); // Total time of flight for leg 2 final Gradient tauLeg2 = primaryTauD.add(secondaryTauU); @@ -646,7 +651,8 @@ protected EstimatedMeasurement theoreticalEvaluationValidation( final FieldVector3D Qsecondary = secondaryToInert.transformPosition(zero); // Downlink time of flight from transitStateLeg1 to secondary station at rebound date - final Gradient secondaryTauD = signalTimeOfFlight(transitStateLeg2PV, Qsecondary, reboundDateDS); + final Gradient secondaryTauD = signalTimeOfFlight(transitStateLeg2PV, Qsecondary, + reboundDateDS, state.getFrame()); // Elapsed time between state date t' and signal arrival to the transit state of the 1st leg @@ -669,8 +675,9 @@ protected EstimatedMeasurement theoreticalEvaluationValidation( // Uplink time of flight from primary station to transit state of leg1 final Gradient primaryTauU = signalTimeOfFlight(QPrimaryApprox, - transitStateLeg1PV.getPosition(), - transitStateLeg1PV.getDate()); + transitStateLeg1PV.getPosition(), + transitStateLeg1PV.getDate(), + state.getFrame()); // Total time of flight for leg 1 final Gradient tauLeg1 = secondaryTauD.add(primaryTauU); @@ -738,7 +745,8 @@ protected EstimatedMeasurement theoreticalEvaluationValidation( transformPVCoordinates(new TimeStampedPVCoordinates(measurementDate, PVCoordinates.ZERO)); // Downlink time of flight from primary station at t to spacecraft at t' - final double tMd = signalTimeOfFlight(state.getPVCoordinates(), QMt.getPosition(), measurementDate); + final double tMd = signalTimeOfFlight(state.getPVCoordinates(), QMt.getPosition(), + measurementDate, state.getFrame()); // Transit state from which the satellite reflected the signal from secondary to primary station final SpacecraftState state2 = state.shiftedBy(delta - tMd); @@ -753,7 +761,8 @@ protected EstimatedMeasurement theoreticalEvaluationValidation( // Uplink time of flight from secondary station to transit state leg2 final double tSu = signalTimeOfFlight(QSdate2PV, state2.getPosition(), - transitDateLeg2); + transitDateLeg2, + state.getFrame()); // Total time of flight for leg 2 final double t2 = tMd + tSu; @@ -771,7 +780,7 @@ protected EstimatedMeasurement theoreticalEvaluationValidation( final Vector3D QSA = secondaryTopoToInertArrivalDate.transformPosition(Vector3D.ZERO); // Dowlink time of flight from transitStateLeg1 to secondary station at secondaryStationArrivalDate - final double tSd = signalTimeOfFlight(state2.getPVCoordinates(), QSA, tQSA); + final double tSd = signalTimeOfFlight(state2.getPVCoordinates(), QSA, tQSA, state2.getFrame()); // Transit state from which the satellite reflected the signal from primary to secondary station @@ -787,7 +796,8 @@ protected EstimatedMeasurement theoreticalEvaluationValidation( // Uplink time of flight from primary station to transit state leg1 final double tMu = signalTimeOfFlight(QMdate1PV, state1.getPosition(), - transitDateLeg1); + transitDateLeg1, + state1.getFrame()); // Total time of flight for leg 1 final double t1 = tSd + tMu; diff --git a/src/test/java/org/orekit/estimation/measurements/TurnAroundRangeMeasurementCreator.java b/src/test/java/org/orekit/estimation/measurements/TurnAroundRangeMeasurementCreator.java index b92db9ee07..6e7660ce5e 100644 --- a/src/test/java/org/orekit/estimation/measurements/TurnAroundRangeMeasurementCreator.java +++ b/src/test/java/org/orekit/estimation/measurements/TurnAroundRangeMeasurementCreator.java @@ -182,7 +182,7 @@ public double value(final double x) { // Primary station uplink delay - from primary station to P1 // Here the state date is known. Thus we can use the function "signalTimeOfFlight" // of the AbstractMeasurement class - final double primaryTauU = AbstractMeasurement.signalTimeOfFlight(primaryStationAtReception, P1, T1); + final double primaryTauU = AbstractMeasurement.signalTimeOfFlight(primaryStationAtReception, P1, T1, inertial); final AbsoluteDate primaryEmissionDate = T1.shiftedBy(-primaryTauU); diff --git a/src/test/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRangeTest.java b/src/test/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRangeTest.java index c286894fa2..e6f620b326 100644 --- a/src/test/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRangeTest.java +++ b/src/test/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRangeTest.java @@ -31,7 +31,6 @@ import org.junit.jupiter.api.Test; import org.orekit.estimation.Context; import org.orekit.estimation.EstimationTestUtils; -import org.orekit.estimation.measurements.EstimatedMeasurement; import org.orekit.estimation.measurements.EstimatedMeasurementBase; import org.orekit.estimation.measurements.ObservedMeasurement; import org.orekit.orbits.CartesianOrbit; @@ -149,8 +148,8 @@ void genericTestValues(final boolean printResults) { // Lists for results' storage - Used only for derivatives with respect to state // "final" value to be seen by "handleStep" function of the propagator - final List absoluteErrors = new ArrayList(); - final List relativeErrors = new ArrayList(); + final List absoluteErrors = new ArrayList<>(); + final List relativeErrors = new ArrayList<>(); // Use a lambda function to implement "handleStep" function propagator.setStepHandler(interpolator -> { @@ -280,8 +279,8 @@ void genericTestStateDerivatives(final boolean printResults, final int index, // Lists for results' storage - Used only for derivatives with respect to state // "final" value to be seen by "handleStep" function of the propagator - final List errorsP = new ArrayList(); - final List errorsV = new ArrayList(); + final List errorsP = new ArrayList<>(); + final List errorsV = new ArrayList<>(); // Use a lambda function to implement "handleStep" function propagator.setStepHandler(interpolator -> { @@ -310,14 +309,12 @@ void genericTestStateDerivatives(final boolean printResults, final int index, final double[][] jacobianRef; // Compute a reference value using finite differences - jacobianRef = Differentiation.differentiate(new StateFunction() { - public double[] value(final SpacecraftState state) { - final SpacecraftState[] s = states.clone(); - s[index] = state; - return measurement.estimateWithoutDerivatives(0, 0, s).getEstimatedValue(); - } + jacobianRef = Differentiation.differentiate(state -> { + final SpacecraftState[] s = states.clone(); + s[index] = state; + return measurement.estimateWithoutDerivatives(0, 0, s).getEstimatedValue(); }, measurement.getDimension(), propagator.getAttitudeProvider(), - OrbitType.CARTESIAN, PositionAngleType.TRUE, 2.0, 3).value(states[index]); + OrbitType.CARTESIAN, PositionAngleType.TRUE, 2.0, 3).value(states[index]); Assertions.assertEquals(jacobianRef.length, jacobian.length); Assertions.assertEquals(jacobianRef[0].length, jacobian[0].length); @@ -374,8 +371,8 @@ public double[] value(final SpacecraftState state) { propagator.propagate(measurements.get(measurements.size()-1).getDate()); // Convert lists to double[] and evaluate some statistics - final double relErrorsP[] = errorsP.stream().mapToDouble(Double::doubleValue).toArray(); - final double relErrorsV[] = errorsV.stream().mapToDouble(Double::doubleValue).toArray(); + final double[] relErrorsP = errorsP.stream().mapToDouble(Double::doubleValue).toArray(); + final double[] relErrorsV = errorsV.stream().mapToDouble(Double::doubleValue).toArray(); final double errorsPMedian = new Median().evaluate(relErrorsP); final double errorsPMean = new Mean().evaluate(relErrorsP); @@ -434,7 +431,7 @@ void genericTestParameterDerivatives(final boolean printResults, EstimationTestUtils.createMeasurements(propagator, creator, 1.0, 3.0, 300.0); // List to store the results - final List relErrorList = new ArrayList(); + final List relErrorList = new ArrayList<>(); // Use a lambda function to implement "handleStep" function propagator.setStepHandler(interpolator -> { @@ -520,7 +517,7 @@ public double value(final ParameterDriver parameterDriver, final AbsoluteDate da propagator.propagate(measurements.get(measurements.size()-1).getDate()); // Convert error list to double[] - final double relErrors[] = relErrorList.stream().mapToDouble(Double::doubleValue).toArray(); + final double[] relErrors = relErrorList.stream().mapToDouble(Double::doubleValue).toArray(); // Compute statistics final double relErrorsMedian = new Median().evaluate(relErrors); From 2d2296849f2701ca21cc6f59248ba1cefd91a8cf Mon Sep 17 00:00:00 2001 From: Serrof Date: Sun, 25 Feb 2024 15:21:47 +0100 Subject: [PATCH 157/359] Removed computation of Jacobian w.r.t. Cartesian in full-numerical Keplerian propagation --- .../numerical/FieldNumericalPropagator.java | 22 +++++++++++++++---- .../numerical/NumericalPropagator.java | 22 +++++++++++++++---- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/orekit/propagation/numerical/FieldNumericalPropagator.java b/src/main/java/org/orekit/propagation/numerical/FieldNumericalPropagator.java index b6e7c67e5c..d37875943c 100644 --- a/src/main/java/org/orekit/propagation/numerical/FieldNumericalPropagator.java +++ b/src/main/java/org/orekit/propagation/numerical/FieldNumericalPropagator.java @@ -489,6 +489,9 @@ private class Main implements MainStateEquations, FieldTimeDerivativesEquatio /** Jacobian of the orbital parameters with respect to the Cartesian parameters. */ private T[][] jacobian; + /** Flag keeping track whether Jacobian matrix needs to be recomputed or not. */ + private boolean recomputingJacobian; + /** Simple constructor. * @param integrator numerical integrator to use for propagation. */ @@ -500,8 +503,7 @@ private class Main implements MainStateEquations, FieldTimeDerivativesEquatio forceModel.getFieldEventDetectors(getField()).forEach(detector -> setUpEventDetector(integrator, detector)); } - if (superGetOrbitType() == null) { - // propagation uses absolute position-velocity-acceleration + if (!recomputingJacobian) { // we can set Jacobian once and for all for (int i = 0; i < jacobian.length; ++i) { Arrays.fill(jacobian[i], getField().getZero()); @@ -515,6 +517,18 @@ private class Main implements MainStateEquations, FieldTimeDerivativesEquatio @Override public void init(final FieldSpacecraftState initialState, final FieldAbsoluteDate target) { forceModels.forEach(fm -> fm.init(initialState, target)); + + final int numberOfForces = forceModels.size(); + final OrbitType orbitType = superGetOrbitType(); + if (orbitType != null && orbitType != OrbitType.CARTESIAN && numberOfForces > 0) { + if (numberOfForces > 1) { + recomputingJacobian = true; + } else { + recomputingJacobian = !(forceModels.get(0) instanceof NewtonianAttraction); + } + } else { + recomputingJacobian = false; + } } /** {@inheritDoc} */ @@ -523,8 +537,8 @@ public T[] computeDerivatives(final FieldSpacecraftState state) { final T zero = state.getA().getField().getZero(); currentState = state; Arrays.fill(yDot, zero); - if (superGetOrbitType() != null) { - // propagation uses regular orbits + if (recomputingJacobian) { + // propagation uses Jacobian matrix of orbital parameters w.r.t. Cartesian ones currentState.getOrbit().getJacobianWrtCartesian(getPositionAngleType(), jacobian); } diff --git a/src/main/java/org/orekit/propagation/numerical/NumericalPropagator.java b/src/main/java/org/orekit/propagation/numerical/NumericalPropagator.java index f6b90af9bd..28283cd527 100644 --- a/src/main/java/org/orekit/propagation/numerical/NumericalPropagator.java +++ b/src/main/java/org/orekit/propagation/numerical/NumericalPropagator.java @@ -902,6 +902,9 @@ private class Main implements MainStateEquations, TimeDerivativesEquations { /** Jacobian of the orbital parameters with respect to the Cartesian parameters. */ private double[][] jacobian; + /** Flag keeping track whether Jacobian matrix needs to be recomputed or not. */ + private boolean recomputingJacobian; + /** Simple constructor. * @param integrator numerical integrator to use for propagation. */ @@ -914,8 +917,7 @@ private class Main implements MainStateEquations, TimeDerivativesEquations { forceModel.getEventDetectors().forEach(detector -> setUpEventDetector(integrator, detector)); } - if (getOrbitType() == null) { - // propagation uses absolute position-velocity-acceleration + if (!recomputingJacobian) { // we can set Jacobian once and for all for (int i = 0; i < jacobian.length; ++i) { Arrays.fill(jacobian[i], 0.0); @@ -929,6 +931,18 @@ private class Main implements MainStateEquations, TimeDerivativesEquations { @Override public void init(final SpacecraftState initialState, final AbsoluteDate target) { forceModels.forEach(fm -> fm.init(initialState, target)); + + final int numberOfForces = forceModels.size(); + final OrbitType orbitType = getOrbitType(); + if (orbitType != null && orbitType != OrbitType.CARTESIAN && numberOfForces > 0) { + if (numberOfForces > 1) { + recomputingJacobian = true; + } else { + recomputingJacobian = !(forceModels.get(0) instanceof NewtonianAttraction); + } + } else { + recomputingJacobian = false; + } } /** {@inheritDoc} */ @@ -937,8 +951,8 @@ public double[] computeDerivatives(final SpacecraftState state) { currentState = state; Arrays.fill(yDot, 0.0); - if (getOrbitType() != null) { - // propagation uses regular orbits + if (recomputingJacobian) { + // propagation uses Jacobian matrix of orbital parameters w.r.t. Cartesian ones currentState.getOrbit().getJacobianWrtCartesian(getPositionAngleType(), jacobian); } From e26b40bd8a469bbc07e4ffdaf849a7b1652203ff Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Sun, 25 Feb 2024 18:20:57 +0100 Subject: [PATCH 158/359] Factor common code for on-board measurements. --- ...nBoardCommonParametersWithDerivatives.java | 84 +++++++++ ...ardCommonParametersWithoutDerivatives.java | 79 ++++++++ .../measurements/gnss/OnBoardMeasurement.java | 173 ++++++++++++++++++ .../measurements/gnss/OneWayGNSSPhase.java | 81 +++----- .../measurements/gnss/OneWayGNSSRange.java | 70 ++----- .../gnss/OneWayGNSSPhaseTest.java | 67 +++---- .../gnss/OneWayGNSSRangeTest.java | 42 +++-- 7 files changed, 434 insertions(+), 162 deletions(-) create mode 100644 src/main/java/org/orekit/estimation/measurements/gnss/OnBoardCommonParametersWithDerivatives.java create mode 100644 src/main/java/org/orekit/estimation/measurements/gnss/OnBoardCommonParametersWithoutDerivatives.java create mode 100644 src/main/java/org/orekit/estimation/measurements/gnss/OnBoardMeasurement.java diff --git a/src/main/java/org/orekit/estimation/measurements/gnss/OnBoardCommonParametersWithDerivatives.java b/src/main/java/org/orekit/estimation/measurements/gnss/OnBoardCommonParametersWithDerivatives.java new file mode 100644 index 0000000000..c9c9f2fd4d --- /dev/null +++ b/src/main/java/org/orekit/estimation/measurements/gnss/OnBoardCommonParametersWithDerivatives.java @@ -0,0 +1,84 @@ +/* Copyright 2002-2024 Luc Maisonobe + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.estimation.measurements.gnss; + +import org.hipparchus.analysis.differentiation.Gradient; +import org.orekit.estimation.measurements.CommonParametersWithDerivatives; +import org.orekit.propagation.SpacecraftState; +import org.orekit.utils.TimeStampedFieldPVCoordinates; + +import java.util.Map; + +/** Common intermediate parameters used to estimate measurements where receiver is a satellite. + * @author Luc Maisonobe + * @since 12.1 + */ +public class OnBoardCommonParametersWithDerivatives + extends CommonParametersWithDerivatives { + + /** Local clock offset. */ + final Gradient dtLocal; + + /** Remote clock offset. */ + final Gradient dtRemote; + + /** Remote satellite position/velocity. */ + private final TimeStampedFieldPVCoordinates remotePV; + + /** Simple constructor. + * @param localState local spacecraft state + * @param indices derivatives indices map + * @param dtLocal local clock offset + * @param dtRemote remote clock offset + * @param tauD downlink delay + * @param localPV local satellite position/velocity + * @param remotePV remote satellite position/velocity + */ + public OnBoardCommonParametersWithDerivatives(final SpacecraftState localState, + final Map indices, + final Gradient dtLocal, final Gradient dtRemote, + final Gradient tauD, + final TimeStampedFieldPVCoordinates localPV, + final TimeStampedFieldPVCoordinates remotePV) { + super(localState, indices, tauD, localState, localPV); + this.dtLocal = dtLocal; + this.dtRemote = dtRemote; + this.remotePV = remotePV; + } + + /** Get local clock offset. + * @return local clock offset + */ + public Gradient getDtLocal() { + return dtLocal; + } + + /** Get remote clock offset. + * @return remotr clock offset + */ + public Gradient getDtRemote() { + return dtRemote; + } + + /** Get remote satellite position/velocity. + * @return remote satellite position/velocity + */ + public TimeStampedFieldPVCoordinates getRemotePV() { + return remotePV; + } + +} diff --git a/src/main/java/org/orekit/estimation/measurements/gnss/OnBoardCommonParametersWithoutDerivatives.java b/src/main/java/org/orekit/estimation/measurements/gnss/OnBoardCommonParametersWithoutDerivatives.java new file mode 100644 index 0000000000..2eca5490ab --- /dev/null +++ b/src/main/java/org/orekit/estimation/measurements/gnss/OnBoardCommonParametersWithoutDerivatives.java @@ -0,0 +1,79 @@ +/* Copyright 2002-2024 Luc Maisonobe + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.estimation.measurements.gnss; + +import org.orekit.estimation.measurements.CommonParametersWithoutDerivatives; +import org.orekit.propagation.SpacecraftState; +import org.orekit.utils.TimeStampedPVCoordinates; + +/** Common intermediate parameters used to estimate measurements where receiver is a satellite. + * @author Luc Maisonobe + * @since 12.1 + */ +public class OnBoardCommonParametersWithoutDerivatives + extends CommonParametersWithoutDerivatives { + + /** Local clock offset. */ + final double dtLocal; + + /** Remote clock offset. */ + final double dtRemote; + + /** Remote satellite position/velocity. */ + private final TimeStampedPVCoordinates remotePV; + + /** Simple constructor. + * @param localState local spacecraft state + * @param dtLocal local clock offset + * @param dtRemote remote clock offset + * @param tauD downlink delay + * @param localPV local satellite position/velocity + * @param remotePV remote satellite position/velocity + */ + public OnBoardCommonParametersWithoutDerivatives(final SpacecraftState localState, + final double dtLocal, final double dtRemote, + final double tauD, + final TimeStampedPVCoordinates localPV, + final TimeStampedPVCoordinates remotePV) { + super(localState, tauD, localState, localPV); + this.dtLocal = dtLocal; + this.dtRemote = dtRemote; + this.remotePV = remotePV; + } + + /** Get local clock offset. + * @return local clock offset + */ + public double getDtLocal() { + return dtLocal; + } + + /** Get remote clock offset. + * @return remotr clock offset + */ + public double getDtRemote() { + return dtRemote; + } + + /** Get remote satellite position/velocity. + * @return remote satellite position/velocity + */ + public TimeStampedPVCoordinates getRemotePV() { + return remotePV; + } + +} diff --git a/src/main/java/org/orekit/estimation/measurements/gnss/OnBoardMeasurement.java b/src/main/java/org/orekit/estimation/measurements/gnss/OnBoardMeasurement.java new file mode 100644 index 0000000000..a93d843222 --- /dev/null +++ b/src/main/java/org/orekit/estimation/measurements/gnss/OnBoardMeasurement.java @@ -0,0 +1,173 @@ +/* Copyright 2002-2024 Luc Maisonobe + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.estimation.measurements.gnss; + +import org.hipparchus.analysis.differentiation.Gradient; +import org.orekit.estimation.measurements.AbstractMeasurement; +import org.orekit.estimation.measurements.ObservableSatellite; +import org.orekit.estimation.measurements.ObservedMeasurement; +import org.orekit.propagation.SpacecraftState; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; +import org.orekit.utils.FieldPVCoordinatesProvider; +import org.orekit.utils.PVCoordinatesProvider; +import org.orekit.utils.ParameterDriver; +import org.orekit.utils.TimeSpanMap.Span; +import org.orekit.utils.TimeStampedFieldPVCoordinates; +import org.orekit.utils.TimeStampedPVCoordinates; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** Base class modeling a measurement where receiver is a satellite. + * @param type of the measurement + * @author Luc Maisonobe + * @since 12.1 + */ +public abstract class OnBoardMeasurement> extends AbstractMeasurement { + + /** Constructor. + * @param date date of the measurement + * @param observed observed value + * @param sigma theoretical standard deviation + * @param baseWeight base weight + * @param satellites satellites related to this measurement + */ + public OnBoardMeasurement(final AbsoluteDate date, final double observed, + final double sigma, final double baseWeight, + final List satellites) { + // Call to super constructor + super(date, observed, sigma, baseWeight, satellites); + + // Add parameter drivers + satellites.forEach(s -> addParameterDriver(s.getClockDriftDriver())); + + } + + /** Compute common estimation parameters. + * @param local orbital state of local satellite at measurement date + * @param remote emitting satellite + * @param dtRemote remote clock offset + * @param clockOffsetAlreadyApplied if true, the specified {@code date} is as read + * by the receiver clock (i.e. clock offset not compensated), if false, + * the specified {@code date} was already compensated and is a physical absolute date + * @return common parameters + */ + protected OnBoardCommonParametersWithoutDerivatives computeCommonParametersWithout(final SpacecraftState local, + final PVCoordinatesProvider remote, + final double dtRemote, + final boolean clockOffsetAlreadyApplied) { + + // Coordinates of both satellites + final TimeStampedPVCoordinates pvaLocal = local.getPVCoordinates(); + + // take clock offset into account + final ParameterDriver localClockDriver = getSatellites().get(0).getClockOffsetDriver(); + final double dtLocal = localClockDriver.getValue(getDate()); + final AbsoluteDate arrivalDate = clockOffsetAlreadyApplied ? + getDate() : + getDate().shiftedBy(-dtLocal); + + // Downlink delay + final double deltaT = arrivalDate.durationFrom(local); + final TimeStampedPVCoordinates pvaDownlink = pvaLocal.shiftedBy(deltaT); + final double tauD = signalTimeOfFlight(remote, arrivalDate, pvaDownlink.getPosition(), + arrivalDate, local.getFrame()); + + // Remote satellite at signal emission + return new OnBoardCommonParametersWithoutDerivatives(local, dtLocal, dtRemote, tauD, + pvaDownlink, + remote.getPVCoordinates(arrivalDate.shiftedBy(-tauD), + local.getFrame())); + + } + + /** Compute common estimation parameters. + * ^param nbSat number of satellites involved in the measurement + * @param local orbital state of local satellite at measurement date + * @param remote emitting satellite + * @param dtRemote remote clock offset + * @param clockOffsetAlreadyApplied if true, the specified {@code date} is as read + * by the receiver clock (i.e. clock offset not compensated), if false, + * the specified {@code date} was already compensated and is a physical absolute date + * @return common parameters + */ + protected OnBoardCommonParametersWithDerivatives computeCommonParametersWith(final int nbSat, + final SpacecraftState local, + final PVCoordinatesProvider remote, + final double dtRemote, + final boolean clockOffsetAlreadyApplied) { + + // Range derivatives are computed with respect to spacecraft state in inertial frame + // Parameters: + // - 6k..6k+2 - Position of spacecraft k (counting from 0) in inertial frame + // - 6k+3..6k+5 - Velocity of spacecraft k (counting from 0) in inertial frame + // - 6k+6..n - measurements parameters (clock offset, etc) + int nbEstimatedParams = 6 * nbSat; + final Map parameterIndices = new HashMap<>(); + for (ParameterDriver measurementDriver : getParametersDrivers()) { + if (measurementDriver.isSelected()) { + for (Span span = measurementDriver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) { + parameterIndices.put(span.getData(), nbEstimatedParams++); + } + } + } + + // convert the PVCoordinatesProvider to a FieldPVCoordinatesProvider + final FieldPVCoordinatesProvider gRemote = (date, frame) -> { + + // apply the raw (no derivatives) remote provider + final AbsoluteDate dateBase = date.toAbsoluteDate(); + final TimeStampedPVCoordinates pvBase = remote.getPVCoordinates(dateBase, frame); + final TimeStampedFieldPVCoordinates pvWithoutDerivatives = + new TimeStampedFieldPVCoordinates<>(date.getField(), pvBase); + + // add derivatives, using a trick: we shift the date by 0, with derivatives + final Gradient zeroWithDerivatives = date.durationFrom(dateBase); + return pvWithoutDerivatives.shiftedBy(zeroWithDerivatives); + + }; + + // Coordinates of both satellites + final TimeStampedFieldPVCoordinates + pvaLocal = getCoordinates(local, 0, nbEstimatedParams); + + // take clock offset into account + final ParameterDriver localClockDriver = getSatellites().get(0).getClockOffsetDriver(); + final Gradient dtLocal = localClockDriver.getValue(nbEstimatedParams, parameterIndices, getDate()); + final FieldAbsoluteDate arrivalDate = clockOffsetAlreadyApplied ? + new FieldAbsoluteDate<>(dtLocal.getField(), getDate()) : + new FieldAbsoluteDate<>(getDate(), dtLocal.negate()); + + // Downlink delay + final Gradient deltaT = arrivalDate.durationFrom(local.getDate()); + final TimeStampedFieldPVCoordinates pvaDownlink = pvaLocal.shiftedBy(deltaT); + final Gradient tauD = signalTimeOfFlight(gRemote, arrivalDate, + pvaDownlink.getPosition(), arrivalDate, + local.getFrame()); + + // Remote satellite at signal emission + return new OnBoardCommonParametersWithDerivatives(local, parameterIndices, + dtLocal, dtLocal.newInstance(dtRemote), tauD, + pvaDownlink, + gRemote.getPVCoordinates(arrivalDate.shiftedBy(tauD.negate()), + local.getFrame())); + + } + +} diff --git a/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSPhase.java b/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSPhase.java index 3b05d45336..0673746946 100644 --- a/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSPhase.java +++ b/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSPhase.java @@ -18,22 +18,17 @@ import java.util.Arrays; import java.util.Collections; -import java.util.HashMap; -import java.util.Map; import org.hipparchus.analysis.differentiation.Gradient; -import org.orekit.estimation.measurements.AbstractMeasurement; import org.orekit.estimation.measurements.EstimatedMeasurement; import org.orekit.estimation.measurements.EstimatedMeasurementBase; import org.orekit.estimation.measurements.ObservableSatellite; import org.orekit.propagation.SpacecraftState; import org.orekit.time.AbsoluteDate; -import org.orekit.time.FieldAbsoluteDate; import org.orekit.utils.Constants; import org.orekit.utils.PVCoordinatesProvider; import org.orekit.utils.ParameterDriver; import org.orekit.utils.TimeSpanMap.Span; -import org.orekit.utils.TimeStampedFieldPVCoordinates; import org.orekit.utils.TimeStampedPVCoordinates; /** One-way GNSS phase measurement. @@ -55,7 +50,7 @@ * @author Bryan Cazabonne * @since 10.3 */ -public class OneWayGNSSPhase extends AbstractMeasurement { +public class OneWayGNSSPhase extends OnBoardMeasurement { /** Type of the measurement. */ public static final String MEASUREMENT_TYPE = "OneWayGNSSPhase"; @@ -127,33 +122,24 @@ protected EstimatedMeasurementBase theoreticalEvaluationWithout final int evaluation, final SpacecraftState[] states) { - // Coordinates of both satellites - final SpacecraftState localState = states[0]; - final TimeStampedPVCoordinates pvaLocal = localState.getPVCoordinates(); - final TimeStampedPVCoordinates pvaRemote = remote.getPVCoordinates(getDate(), localState.getFrame()); - - // Downlink delay - final double dtLocal = getSatellites().get(0).getClockOffsetDriver().getValue(localState.getDate()); - final AbsoluteDate arrivalDate = getDate().shiftedBy(-dtLocal); - - final SpacecraftState sDownlink = localState.shiftedBy(arrivalDate.durationFrom(localState.getDate())); - final TimeStampedPVCoordinates pvaDownlink = pvaLocal.shiftedBy(arrivalDate.durationFrom(pvaLocal.getDate())); - final double tauD = signalTimeOfFlight(pvaRemote, pvaDownlink.getPosition(), arrivalDate, localState.getFrame()); + final OnBoardCommonParametersWithoutDerivatives common = + computeCommonParametersWithout(states[0], remote, dtRemote, false); // prepare the evaluation final EstimatedMeasurementBase estimatedPhase = new EstimatedMeasurementBase<>(this, iteration, evaluation, new SpacecraftState[] { - sDownlink + common.getState() }, new TimeStampedPVCoordinates[] { - pvaRemote.shiftedBy(-(dtLocal + tauD)), - sDownlink.getPVCoordinates() + common.getRemotePV(), + common.getTransitPV() }); // Phase value - final double cOverLambda = Constants.SPEED_OF_LIGHT / wavelength; - final double ambiguity = ambiguityDriver.getValue(localState.getDate()); - final double phase = (tauD + dtLocal - dtRemote) * cOverLambda + ambiguity; + final double cOverLambda = Constants.SPEED_OF_LIGHT / wavelength; + final double ambiguity = ambiguityDriver.getValue(common.getState().getDate()); + final double phase = (common.getTauD() + common.getDtLocal() - common.getDtRemote()) * cOverLambda + + ambiguity; // Set value of the estimated measurement estimatedPhase.setEstimatedValue(phase); @@ -169,49 +155,26 @@ protected EstimatedMeasurement theoreticalEvaluation(final int final int evaluation, final SpacecraftState[] states) { - // Phase derivatives are computed with respect to spacecrafts states in inertial frame - // Parameters: - // - 0..2 - Position of the receiver satellite in inertial frame - // - 3..5 - Velocity of the receiver satellite in inertial frame - // - 6..n - Measurement parameters: ambiguity and clock offset - int nbEstimatedParamsPhase = 6; - final Map parameterIndicesPhase = new HashMap<>(); - for (ParameterDriver phaseMeasurementDriver : getParametersDrivers()) { - if (phaseMeasurementDriver.isSelected()) { - for (Span span = phaseMeasurementDriver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) { - parameterIndicesPhase.put(span.getData(), nbEstimatedParamsPhase++); - } - } - } - - // Coordinates of both satellites - final SpacecraftState localState = states[0]; - final TimeStampedFieldPVCoordinates pvaLocal = getCoordinates(localState, 0, nbEstimatedParamsPhase); - final TimeStampedPVCoordinates pvaRemote = remote.getPVCoordinates(getDate(), localState.getFrame()); - - // Downlink delay - final Gradient dtLocal = getSatellites().get(0).getClockOffsetDriver().getValue(nbEstimatedParamsPhase, parameterIndicesPhase, localState.getDate()); - final FieldAbsoluteDate arrivalDate = new FieldAbsoluteDate<>(getDate(), dtLocal.negate()); + final OnBoardCommonParametersWithDerivatives common = + computeCommonParametersWith(1, states[0], remote, dtRemote, false); - final SpacecraftState sDownlink = localState.shiftedBy(arrivalDate.toAbsoluteDate().durationFrom(localState.getDate())); - final TimeStampedFieldPVCoordinates pvaDownlink = pvaLocal.shiftedBy(arrivalDate.durationFrom(pvaLocal.getDate())); - final Gradient tauD = signalTimeOfFlight(new TimeStampedFieldPVCoordinates<>(pvaRemote.getDate(), dtLocal.getField().getOne(), pvaRemote), - pvaDownlink.getPosition(), arrivalDate, localState.getFrame()); - - // prepare the evaluation + // prepare the evaluation final EstimatedMeasurement estimatedPhase = new EstimatedMeasurement<>(this, iteration, evaluation, new SpacecraftState[] { - sDownlink + common.getState() }, new TimeStampedPVCoordinates[] { - pvaRemote.shiftedBy(-(dtLocal.getValue() + tauD.getValue())), - sDownlink.getPVCoordinates() + common.getRemotePV().toTimeStampedPVCoordinates(), + common.getTransitPV().toTimeStampedPVCoordinates() }); // Phase value final double cOverLambda = Constants.SPEED_OF_LIGHT / wavelength; - final Gradient ambiguity = ambiguityDriver.getValue(nbEstimatedParamsPhase, parameterIndicesPhase, localState.getDate()); - final Gradient phase = tauD.add(dtLocal).subtract(dtRemote).multiply(cOverLambda).add(ambiguity); + final Gradient ambiguity = ambiguityDriver.getValue(common.getTauD().getFreeParameters(), common.getIndices(), + common.getState().getDate()); + final Gradient phase = common.getTauD().add(common.getDtLocal()).subtract(common.getDtRemote()). + multiply(cOverLambda). + add(ambiguity); final double[] phaseDerivatives = phase.getGradient(); // Set value and state derivatives of the estimated measurement @@ -222,7 +185,7 @@ protected EstimatedMeasurement theoreticalEvaluation(final int for (final ParameterDriver phaseMeasurementDriver : getParametersDrivers()) { for (Span span = phaseMeasurementDriver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) { - final Integer index = parameterIndicesPhase.get(span.getData()); + final Integer index = common.getIndices().get(span.getData()); if (index != null) { estimatedPhase.setParameterDerivatives(phaseMeasurementDriver, span.getStart(), phaseDerivatives[index]); } diff --git a/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRange.java b/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRange.java index a43ecd10a2..3eb2b4dc5a 100644 --- a/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRange.java +++ b/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRange.java @@ -18,23 +18,18 @@ import java.util.Arrays; import java.util.Collections; -import java.util.HashMap; -import java.util.Map; import org.hipparchus.analysis.differentiation.Gradient; -import org.orekit.estimation.measurements.AbstractMeasurement; import org.orekit.estimation.measurements.EstimatedMeasurement; import org.orekit.estimation.measurements.EstimatedMeasurementBase; import org.orekit.estimation.measurements.InterSatellitesRange; import org.orekit.estimation.measurements.ObservableSatellite; import org.orekit.propagation.SpacecraftState; import org.orekit.time.AbsoluteDate; -import org.orekit.time.FieldAbsoluteDate; import org.orekit.utils.Constants; import org.orekit.utils.PVCoordinatesProvider; import org.orekit.utils.ParameterDriver; import org.orekit.utils.TimeSpanMap.Span; -import org.orekit.utils.TimeStampedFieldPVCoordinates; import org.orekit.utils.TimeStampedPVCoordinates; /** One-way GNSS range measurement. @@ -56,7 +51,7 @@ * @author Bryan Cazabonne * @since 10.3 */ -public class OneWayGNSSRange extends AbstractMeasurement { +public class OneWayGNSSRange extends OnBoardMeasurement { /** Type of the measurement. */ public static final String MEASUREMENT_TYPE = "OneWayGNSSRange"; @@ -96,31 +91,23 @@ protected EstimatedMeasurementBase theoreticalEvaluationWithout final int evaluation, final SpacecraftState[] states) { - // Coordinates of both satellites in local satellite frame - final SpacecraftState localState = states[0]; - final TimeStampedPVCoordinates pvaLocal = localState.getPVCoordinates(); - final TimeStampedPVCoordinates pvaRemote = remote.getPVCoordinates(getDate(), localState.getFrame()); - // Downlink delay - final double dtLocal = getSatellites().get(0).getClockOffsetDriver().getValue(localState.getDate()); - final AbsoluteDate arrivalDate = getDate().shiftedBy(-dtLocal); - - final SpacecraftState sDownlink = localState.shiftedBy(arrivalDate.durationFrom(localState)); - final TimeStampedPVCoordinates pvaDownlink = pvaLocal.shiftedBy(arrivalDate.durationFrom(pvaLocal)); - final double tauD = signalTimeOfFlight(pvaRemote, pvaDownlink.getPosition(), arrivalDate, localState.getFrame()); + final OnBoardCommonParametersWithoutDerivatives common = + computeCommonParametersWithout(states[0], remote, dtRemote, false); // Estimated measurement final EstimatedMeasurementBase estimatedRange = new EstimatedMeasurementBase<>(this, iteration, evaluation, new SpacecraftState[] { - sDownlink + common.getState() }, new TimeStampedPVCoordinates[] { - pvaRemote.shiftedBy(-(dtLocal + tauD)), - sDownlink.getPVCoordinates() + common.getRemotePV(), + common.getTransitPV() }); // Range value - final double range = (tauD + dtLocal - dtRemote) * Constants.SPEED_OF_LIGHT; + final double range = (common.getTauD() + common.getDtLocal() - common.getDtRemote()) * + Constants.SPEED_OF_LIGHT; // Set value of the estimated measurement estimatedRange.setEstimatedValue(range); @@ -136,47 +123,22 @@ protected EstimatedMeasurement theoreticalEvaluation(final int final int evaluation, final SpacecraftState[] states) { - // Range derivatives are computed with respect to spacecraft state in inertial frame - // Parameters: - // - 0..2 - Position of the spacecraft in inertial frame - // - 3..5 - Velocity of the spacecraft in inertial frame - // - 6..n - measurements parameters (clock offset, etc) - int nbEstimatedParams = 6; - final Map parameterIndices = new HashMap<>(); - for (ParameterDriver measurementDriver : getParametersDrivers()) { - if (measurementDriver.isSelected()) { - for (Span span = measurementDriver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) { - parameterIndices.put(span.getData(), nbEstimatedParams++); - } - } - } - - // Coordinates of both satellites in local satellite frame - final SpacecraftState localState = states[0]; - final TimeStampedFieldPVCoordinates pvaLocal = getCoordinates(localState, 0, nbEstimatedParams); - final TimeStampedPVCoordinates pvaRemote = remote.getPVCoordinates(getDate(), localState.getFrame()); - - // Downlink delay - final Gradient dtLocal = getSatellites().get(0).getClockOffsetDriver().getValue(nbEstimatedParams, parameterIndices, localState.getDate()); - final FieldAbsoluteDate arrivalDate = new FieldAbsoluteDate<>(getDate(), dtLocal.negate()); - - final SpacecraftState sDownlink = localState.shiftedBy(arrivalDate.toAbsoluteDate().durationFrom(localState)); - final TimeStampedFieldPVCoordinates pvaDownlink = pvaLocal.shiftedBy(arrivalDate.durationFrom(pvaLocal)); - final Gradient tauD = signalTimeOfFlight(new TimeStampedFieldPVCoordinates<>(pvaRemote.getDate(), dtLocal.getField().getOne(), pvaRemote), - pvaDownlink.getPosition(), arrivalDate, localState.getFrame()); + final OnBoardCommonParametersWithDerivatives common = + computeCommonParametersWith(1, states[0], remote, dtRemote, false); // Estimated measurement final EstimatedMeasurement estimatedRange = new EstimatedMeasurement<>(this, iteration, evaluation, new SpacecraftState[] { - sDownlink + common.getState() }, new TimeStampedPVCoordinates[] { - pvaRemote.shiftedBy(-(dtLocal.getValue() + tauD.getValue())), - sDownlink.getPVCoordinates() + common.getRemotePV().toTimeStampedPVCoordinates(), + common.getTransitPV().toTimeStampedPVCoordinates() }); // Range value - final Gradient range = tauD.add(dtLocal).subtract(dtRemote).multiply(Constants.SPEED_OF_LIGHT); + final Gradient range = common.getTauD().add(common.getDtLocal()).subtract(common.getDtRemote()). + multiply(Constants.SPEED_OF_LIGHT); final double[] rangeDerivatives = range.getGradient(); // Set value and state derivatives of the estimated measurement @@ -187,7 +149,7 @@ protected EstimatedMeasurement theoreticalEvaluation(final int for (final ParameterDriver measurementDriver : getParametersDrivers()) { for (Span span = measurementDriver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) { - final Integer index = parameterIndices.get(span.getData()); + final Integer index = common.getIndices().get(span.getData()); if (index != null) { estimatedRange.setParameterDerivatives(measurementDriver, span.getStart(), rangeDerivatives[index]); } diff --git a/src/test/java/org/orekit/estimation/measurements/gnss/OneWayGNSSPhaseTest.java b/src/test/java/org/orekit/estimation/measurements/gnss/OneWayGNSSPhaseTest.java index ca77900cbe..6395d84a93 100644 --- a/src/test/java/org/orekit/estimation/measurements/gnss/OneWayGNSSPhaseTest.java +++ b/src/test/java/org/orekit/estimation/measurements/gnss/OneWayGNSSPhaseTest.java @@ -84,12 +84,19 @@ public void testStateDerivatives() { System.out.println("\nTest One-way GNSS phase State Derivatives - Finite Differences Comparison\n"); } // Run test - double refErrorsPMedian = 1.9e-10; - double refErrorsPMean = 5.3e-10; - double refErrorsPMax = 3.7e-08; - double refErrorsVMedian = 4.7e-04; - double refErrorsVMean = 1.6e-03; - double refErrorsVMax = 1.1e-01; + // the following relative tolerances for derivatives with respect to velocity + // may seem high, but they have been validated. The partial derivative of + // signal flight time with respect to velocity ∂τ/∂{vx, vy, vz} is about 10⁻¹³ + // when the signal flight time τ is about 10⁻⁴, so finite differences lose + // about 9 significant figures, so it is expected that partial derivatives + // computed with finite differences will only have a few digits corrects and + // that there will be outliers + double refErrorsPMedian = 5.6e-09; + double refErrorsPMean = 2.1e-08; + double refErrorsPMax = 1.1e-06; + double refErrorsVMedian = 1.7e-04; + double refErrorsVMean = 5.1e-04; + double refErrorsVMax = 4.2e-02; this.genericTestStateDerivatives(printResults, 0, refErrorsPMedian, refErrorsPMean, refErrorsPMax, refErrorsVMedian, refErrorsVMean, refErrorsVMax); @@ -109,9 +116,9 @@ public void testParameterDerivatives() { System.out.println("\nTest One-way GNSS phase Derivatives - Finite Differences Comparison\n"); } // Run test - double refErrorsMedian = 1.0e-15; - double refErrorsMean = 1.0e-15; - double refErrorsMax = 1.0e-15; + double refErrorsMedian = 5.8e-15; + double refErrorsMean = 8.5e-15; + double refErrorsMax = 3.2e-14; this.genericTestParameterDerivatives(printResults, refErrorsMedian, refErrorsMean, refErrorsMax); @@ -154,8 +161,8 @@ void genericTestValues(final boolean printResults) { // Lists for results' storage - Used only for derivatives with respect to state // "final" value to be seen by "handleStep" function of the propagator - final List absoluteErrors = new ArrayList(); - final List relativeErrors = new ArrayList(); + final List absoluteErrors = new ArrayList<>(); + final List relativeErrors = new ArrayList<>(); // Use a lambda function to implement "handleStep" function propagator.setStepHandler(interpolator -> { @@ -241,11 +248,11 @@ void genericTestValues(final boolean printResults) { System.out.println("Relative errors max : " + relErrorsMax); } - Assertions.assertEquals(0.0, absErrorsMedian, 6.5e-7); - Assertions.assertEquals(0.0, absErrorsMin, 3.1e-6); - Assertions.assertEquals(0.0, absErrorsMax, 9.0e-7); - Assertions.assertEquals(0.0, relErrorsMedian, 5.9e-12); - Assertions.assertEquals(0.0, relErrorsMax, 1.4e-10); + Assertions.assertEquals(0.0, absErrorsMedian, 6.7e-7); + Assertions.assertEquals(0.0, absErrorsMin, 3.2e-6); + Assertions.assertEquals(0.0, absErrorsMax, 5.7e-7); + Assertions.assertEquals(0.0, relErrorsMedian, 5.4e-12); + Assertions.assertEquals(0.0, relErrorsMax, 1.6e-10); // Test measurement type Assertions.assertEquals(OneWayGNSSPhase.MEASUREMENT_TYPE, measurements.get(0).getMeasurementType()); @@ -286,8 +293,8 @@ void genericTestStateDerivatives(final boolean printResults, final int index, // Lists for results' storage - Used only for derivatives with respect to state // "final" value to be seen by "handleStep" function of the propagator - final List errorsP = new ArrayList(); - final List errorsV = new ArrayList(); + final List errorsP = new ArrayList<>(); + final List errorsV = new ArrayList<>(); // Use a lambda function to implement "handleStep" function propagator.setStepHandler(interpolator -> { @@ -316,14 +323,12 @@ void genericTestStateDerivatives(final boolean printResults, final int index, final double[][] jacobianRef; // Compute a reference value using finite differences - jacobianRef = Differentiation.differentiate(new StateFunction() { - public double[] value(final SpacecraftState state) { - final SpacecraftState[] s = states.clone(); - s[index] = state; - return measurement.estimateWithoutDerivatives(0, 0, s).getEstimatedValue(); - } + jacobianRef = Differentiation.differentiate(state -> { + final SpacecraftState[] s = states.clone(); + s[index] = state; + return measurement.estimateWithoutDerivatives(0, 0, s).getEstimatedValue(); }, measurement.getDimension(), propagator.getAttitudeProvider(), - OrbitType.CARTESIAN, PositionAngleType.TRUE, 2.0, 3).value(states[index]); + OrbitType.CARTESIAN, PositionAngleType.TRUE, 8.0, 5).value(states[index]); Assertions.assertEquals(jacobianRef.length, jacobian.length); Assertions.assertEquals(jacobianRef[0].length, jacobian[0].length); @@ -380,8 +385,8 @@ public double[] value(final SpacecraftState state) { propagator.propagate(measurements.get(measurements.size()-1).getDate()); // Convert lists to double[] and evaluate some statistics - final double relErrorsP[] = errorsP.stream().mapToDouble(Double::doubleValue).toArray(); - final double relErrorsV[] = errorsV.stream().mapToDouble(Double::doubleValue).toArray(); + final double[] relErrorsP = errorsP.stream().mapToDouble(Double::doubleValue).toArray(); + final double[] relErrorsV = errorsV.stream().mapToDouble(Double::doubleValue).toArray(); final double errorsPMedian = new Median().evaluate(relErrorsP); final double errorsPMean = new Mean().evaluate(relErrorsP); @@ -441,7 +446,7 @@ void genericTestParameterDerivatives(final boolean printResults, EstimationTestUtils.createMeasurements(propagator, creator, 1.0, 3.0, 300.0); // List to store the results - final List relErrorList = new ArrayList(); + final List relErrorList = new ArrayList<>(); // Use a lambda function to implement "handleStep" function propagator.setStepHandler(interpolator -> { @@ -485,7 +490,7 @@ public double value(final ParameterDriver parameterDriver, final AbsoluteDate da estimateWithoutDerivatives(0, 0, states). getEstimatedValue()[0]; } - }, 3, 20.0 * drivers[i].getScale()); + }, 5, 10.0 * drivers[i].getScale()); final double ref = dMkdP.value(drivers[i], date); if (printResults) { @@ -526,7 +531,7 @@ public double value(final ParameterDriver parameterDriver, final AbsoluteDate da propagator.propagate(measurements.get(measurements.size()-1).getDate()); // Convert error list to double[] - final double relErrors[] = relErrorList.stream().mapToDouble(Double::doubleValue).toArray(); + final double[] relErrors = relErrorList.stream().mapToDouble(Double::doubleValue).toArray(); // Compute statistics final double relErrorsMedian = new Median().evaluate(relErrors); @@ -568,7 +573,7 @@ public void testIssue734() { Assertions.assertTrue(phase.getAmbiguityDriver().isSelected()); for (ParameterDriver driver : phase.getParametersDrivers()) { // Verify if the current driver corresponds to the phase ambiguity - if (driver.getName() == Phase.AMBIGUITY_NAME) { + if (driver.getName().equals(Phase.AMBIGUITY_NAME)) { Assertions.assertEquals(1234.0, phase.getAmbiguityDriver().getValue(), Double.MIN_VALUE); Assertions.assertTrue(phase.getAmbiguityDriver().isSelected()); } diff --git a/src/test/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRangeTest.java b/src/test/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRangeTest.java index e6f620b326..96206f40a9 100644 --- a/src/test/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRangeTest.java +++ b/src/test/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRangeTest.java @@ -47,7 +47,6 @@ import org.orekit.utils.Differentiation; import org.orekit.utils.ParameterDriver; import org.orekit.utils.ParameterFunction; -import org.orekit.utils.StateFunction; import org.orekit.utils.TimeSpanMap.Span; import org.orekit.utils.TimeStampedPVCoordinates; @@ -79,12 +78,19 @@ public void testStateDerivatives() { System.out.println("\nTest One-way GNSS range State Derivatives - Finite Differences Comparison\n"); } // Run test - double refErrorsPMedian = 1.8e-10; - double refErrorsPMean = 5.1e-10; - double refErrorsPMax = 3.3e-08; - double refErrorsVMedian = 2.3e-03; - double refErrorsVMean = 6.7e-03; - double refErrorsVMax = 2.3e-01; + // the following relative tolerances for derivatives with respect to velocity + // may seem high, but they have been validated. The partial derivative of + // signal flight time with respect to velocity ∂τ/∂{vx, vy, vz} is about 10⁻¹³ + // when the signal flight time τ is about 10⁻⁴, so finite differences lose + // about 9 significant figures, so it is expected that partial derivatives + // computed with finite differences will only have a few digits corrects and + // that there will be outliers + double refErrorsPMedian = 5.6e-09; + double refErrorsPMean = 2.1e-08; + double refErrorsPMax = 1.1e-06; + double refErrorsVMedian = 6.4e-04; + double refErrorsVMean = 2.1e-03; + double refErrorsVMax = 6.8e-02; this.genericTestStateDerivatives(printResults, 0, refErrorsPMedian, refErrorsPMean, refErrorsPMax, refErrorsVMedian, refErrorsVMean, refErrorsVMax); @@ -104,9 +110,9 @@ public void testParameterDerivatives() { System.out.println("\nTest One-way GNSS range Derivatives - Finite Differences Comparison\n"); } // Run test - double refErrorsMedian = 1.0e-15; - double refErrorsMean = 1.0e-15; - double refErrorsMax = 1.0e-15; + double refErrorsMedian = 5.8e-15; + double refErrorsMean = 8.4e-15; + double refErrorsMax = 3.3e-14; this.genericTestParameterDerivatives(printResults, refErrorsMedian, refErrorsMean, refErrorsMax); @@ -235,11 +241,11 @@ void genericTestValues(final boolean printResults) { System.out.println("Relative errors max : " + relErrorsMax); } - Assertions.assertEquals(0.0, absErrorsMedian, 1.3e-7); - Assertions.assertEquals(0.0, absErrorsMin, 6.5e-7); - Assertions.assertEquals(0.0, absErrorsMax, 1.7e-7); - Assertions.assertEquals(0.0, relErrorsMedian, 5.3e-12); - Assertions.assertEquals(0.0, relErrorsMax, 7.6e-11); + Assertions.assertEquals(0.0, absErrorsMedian, 1.4e-7); + Assertions.assertEquals(0.0, absErrorsMin, 6.6e-7); + Assertions.assertEquals(0.0, absErrorsMax, 1.5e-7); + Assertions.assertEquals(0.0, relErrorsMedian, 5.7e-12); + Assertions.assertEquals(0.0, relErrorsMax, 7.2e-11); // Test measurement type Assertions.assertEquals(OneWayGNSSRange.MEASUREMENT_TYPE, measurements.get(0).getMeasurementType()); @@ -298,7 +304,7 @@ void genericTestStateDerivatives(final boolean printResults, final int index, // in order to validate the partial derivatives with respect // to velocity. final double meanDelay = measurement.getObservedValue()[0] / Constants.SPEED_OF_LIGHT; - final AbsoluteDate date = measurement.getDate().shiftedBy(-0.75 * meanDelay); + final AbsoluteDate date = measurement.getDate().shiftedBy(-0.9 * meanDelay); final SpacecraftState[] states = { interpolator.getInterpolatedState(date), ephemeris.propagate(date) @@ -314,7 +320,7 @@ void genericTestStateDerivatives(final boolean printResults, final int index, s[index] = state; return measurement.estimateWithoutDerivatives(0, 0, s).getEstimatedValue(); }, measurement.getDimension(), propagator.getAttitudeProvider(), - OrbitType.CARTESIAN, PositionAngleType.TRUE, 2.0, 3).value(states[index]); + OrbitType.CARTESIAN, PositionAngleType.TRUE, 8.0, 5).value(states[index]); Assertions.assertEquals(jacobianRef.length, jacobian.length); Assertions.assertEquals(jacobianRef[0].length, jacobian[0].length); @@ -476,7 +482,7 @@ public double value(final ParameterDriver parameterDriver, final AbsoluteDate da estimateWithoutDerivatives(0, 0, states). getEstimatedValue()[0]; } - }, 3, 20.0 * drivers[i].getScale()); + }, 5, 10.0 * drivers[i].getScale()); final double ref = dMkdP.value(drivers[i], date); if (printResults) { From 61ae7e52cbbd9ad1eebe41a57d495734e3467785 Mon Sep 17 00:00:00 2001 From: Serrof Date: Sun, 25 Feb 2024 23:31:19 +0100 Subject: [PATCH 159/359] Removed redundant code to create FieldOrbit from Orbit --- src/changes/changes.xml | 3 + .../org/orekit/orbits/FieldCircularOrbit.java | 2 +- .../orekit/orbits/FieldEquinoctialOrbit.java | 2 +- .../orekit/orbits/FieldKeplerianOrbit.java | 2 +- .../propagation/FieldSpacecraftState.java | 26 +---- ...rtTermEncounter1DNumerical2DPOCMethod.java | 14 +-- ...AbstractShortTermEncounter2DPOCMethod.java | 22 ++--- .../java/org/orekit/utils/Fieldifier.java | 98 +------------------ .../java/org/orekit/utils/FieldifierTest.java | 4 + 9 files changed, 32 insertions(+), 141 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 5c01fe2f38..12cf121491 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -21,6 +21,9 @@ + + Removed redundant code to create FieldOrbit from Orbit. + Changed default PositionAngleType in (Field)NumericalPropagator to ECCENTRIC. diff --git a/src/main/java/org/orekit/orbits/FieldCircularOrbit.java b/src/main/java/org/orekit/orbits/FieldCircularOrbit.java index f82e8aa824..2d123e407c 100644 --- a/src/main/java/org/orekit/orbits/FieldCircularOrbit.java +++ b/src/main/java/org/orekit/orbits/FieldCircularOrbit.java @@ -482,7 +482,7 @@ public FieldCircularOrbit(final Field field, final CircularOrbit op) { * @since 12.0 */ public FieldCircularOrbit(final Field field, final Orbit op) { - this(field, new CircularOrbit(op)); + this(field, (CircularOrbit) OrbitType.CIRCULAR.convertType(op)); } /** {@inheritDoc} */ diff --git a/src/main/java/org/orekit/orbits/FieldEquinoctialOrbit.java b/src/main/java/org/orekit/orbits/FieldEquinoctialOrbit.java index 7915f59df2..539d57d44a 100644 --- a/src/main/java/org/orekit/orbits/FieldEquinoctialOrbit.java +++ b/src/main/java/org/orekit/orbits/FieldEquinoctialOrbit.java @@ -447,7 +447,7 @@ public FieldEquinoctialOrbit(final Field field, final EquinoctialOrbit op) { * @since 12.0 */ public FieldEquinoctialOrbit(final Field field, final Orbit op) { - this(field, new EquinoctialOrbit(op)); + this(field, (EquinoctialOrbit) OrbitType.EQUINOCTIAL.convertType(op)); } /** {@inheritDoc} */ diff --git a/src/main/java/org/orekit/orbits/FieldKeplerianOrbit.java b/src/main/java/org/orekit/orbits/FieldKeplerianOrbit.java index 011ef93c14..c4c2113a5a 100644 --- a/src/main/java/org/orekit/orbits/FieldKeplerianOrbit.java +++ b/src/main/java/org/orekit/orbits/FieldKeplerianOrbit.java @@ -490,7 +490,7 @@ public FieldKeplerianOrbit(final Field field, final KeplerianOrbit op) { * @since 12.0 */ public FieldKeplerianOrbit(final Field field, final Orbit op) { - this(field, new KeplerianOrbit(op)); + this(field, (KeplerianOrbit) OrbitType.KEPLERIAN.convertType(op)); } /** {@inheritDoc} */ diff --git a/src/main/java/org/orekit/propagation/FieldSpacecraftState.java b/src/main/java/org/orekit/propagation/FieldSpacecraftState.java index fe04bd86f7..820b526f07 100644 --- a/src/main/java/org/orekit/propagation/FieldSpacecraftState.java +++ b/src/main/java/org/orekit/propagation/FieldSpacecraftState.java @@ -24,7 +24,6 @@ import org.hipparchus.exception.MathIllegalStateException; import org.hipparchus.geometry.euclidean.threed.FieldVector3D; import org.hipparchus.util.FastMath; -import org.hipparchus.util.MathArrays; import org.orekit.attitudes.FieldAttitude; import org.orekit.errors.OrekitException; import org.orekit.errors.OrekitIllegalArgumentException; @@ -34,7 +33,7 @@ import org.orekit.frames.FieldTransform; import org.orekit.frames.Frame; import org.orekit.orbits.FieldOrbit; -import org.orekit.orbits.PositionAngleType; +import org.orekit.orbits.Orbit; import org.orekit.time.FieldAbsoluteDate; import org.orekit.time.FieldTimeShiftable; import org.orekit.time.FieldTimeStamped; @@ -244,28 +243,9 @@ public FieldSpacecraftState(final FieldOrbit orbit, final FieldAttitude at public FieldSpacecraftState(final Field field, final SpacecraftState state) { if (state.isOrbitDefined()) { - final double[] stateD = new double[6]; - final double[] stateDotD = state.getOrbit().hasDerivatives() ? new double[6] : null; - final PositionAngleType positionAngleType = PositionAngleType.TRUE; - state.getOrbit().getType().mapOrbitToArray(state.getOrbit(), positionAngleType, stateD, stateDotD); - final T[] stateF = MathArrays.buildArray(field, 6); - for (int i = 0; i < stateD.length; ++i) { - stateF[i] = field.getZero().newInstance(stateD[i]); - } - final T[] stateDotF; - if (stateDotD == null) { - stateDotF = null; - } else { - stateDotF = MathArrays.buildArray(field, 6); - for (int i = 0; i < stateDotD.length; ++i) { - stateDotF[i] = field.getZero().newInstance(stateDotD[i]); - } - } - - final FieldAbsoluteDate dateF = new FieldAbsoluteDate<>(field, state.getDate()); - this.orbit = state.getOrbit().getType().mapArrayToOrbit(stateF, stateDotF, positionAngleType, dateF, - field.getZero().newInstance(state.getMu()), state.getFrame()); + final Orbit nonFieldOrbit = state.getOrbit(); + this.orbit = nonFieldOrbit.getType().convertToFieldOrbit(field, nonFieldOrbit); this.absPva = null; } else { diff --git a/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/AbstractShortTermEncounter1DNumerical2DPOCMethod.java b/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/AbstractShortTermEncounter1DNumerical2DPOCMethod.java index 1825ba93a6..20e8a29a5e 100644 --- a/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/AbstractShortTermEncounter1DNumerical2DPOCMethod.java +++ b/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/AbstractShortTermEncounter1DNumerical2DPOCMethod.java @@ -138,16 +138,18 @@ public > FieldProbabilityOfCollision comput final DataContext cdmDataContext = cdm.getDataContext(); // Extract primary data - final FieldOrbit primaryOrbit = - Fieldifier.fieldify(field, getObjectOrbitFromCdm(cdmRelativeMetadata, primaryData, - primaryMetadata, cdmDataContext)); + final Orbit primaryOrbitFromCdm = getObjectOrbitFromCdm(cdmRelativeMetadata, primaryData, + primaryMetadata, cdmDataContext); + final FieldOrbit primaryOrbit = primaryOrbitFromCdm.getType().convertToFieldOrbit(field, + primaryOrbitFromCdm); final FieldStateCovariance primaryCovariance = Fieldifier.fieldify(field, getObjectStateCovarianceFromCdm(cdmRelativeMetadata, primaryData)); // Extract secondary data - final FieldOrbit secondaryOrbit = - Fieldifier.fieldify(field, getObjectOrbitFromCdm(cdmRelativeMetadata, secondaryData, - secondaryMetadata, cdmDataContext)); + final Orbit secondaryOrbitFromCdm = getObjectOrbitFromCdm(cdmRelativeMetadata, secondaryData, + secondaryMetadata, cdmDataContext); + final FieldOrbit secondaryOrbit = secondaryOrbitFromCdm.getType().convertToFieldOrbit(field, + secondaryOrbitFromCdm); final FieldStateCovariance secondaryCovariance = Fieldifier.fieldify(field, getObjectStateCovarianceFromCdm(cdmRelativeMetadata, secondaryData)); diff --git a/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/AbstractShortTermEncounter2DPOCMethod.java b/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/AbstractShortTermEncounter2DPOCMethod.java index d21eb5f9ce..85f2ac1e9c 100644 --- a/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/AbstractShortTermEncounter2DPOCMethod.java +++ b/src/main/java/org/orekit/ssa/collision/shorttermencounter/probability/twod/AbstractShortTermEncounter2DPOCMethod.java @@ -119,16 +119,18 @@ public > FieldProbabilityOfCollision comput final DataContext cdmDataContext = cdm.getDataContext(); // Extract primary data - final FieldOrbit primaryOrbit = - Fieldifier.fieldify(field, getObjectOrbitFromCdm(cdmRelativeMetadata, primaryData, - primaryMetadata, cdmDataContext)); + final Orbit primaryOrbitFromCdm = getObjectOrbitFromCdm(cdmRelativeMetadata, primaryData, + primaryMetadata, cdmDataContext); + final FieldOrbit primaryOrbit = primaryOrbitFromCdm.getType().convertToFieldOrbit(field, + primaryOrbitFromCdm); final FieldStateCovariance primaryCovariance = Fieldifier.fieldify(field, getObjectStateCovarianceFromCdm(cdmRelativeMetadata, primaryData)); // Extract secondary data - final FieldOrbit secondaryOrbit = - Fieldifier.fieldify(field, getObjectOrbitFromCdm(cdmRelativeMetadata, secondaryData, - secondaryMetadata, cdmDataContext)); + final Orbit secondaryOrbitFromCdm = getObjectOrbitFromCdm(cdmRelativeMetadata, secondaryData, + secondaryMetadata, cdmDataContext); + final FieldOrbit secondaryOrbit = secondaryOrbitFromCdm.getType().convertToFieldOrbit(field, + secondaryOrbitFromCdm); final FieldStateCovariance secondaryCovariance = Fieldifier.fieldify(field, getObjectStateCovarianceFromCdm(cdmRelativeMetadata, secondaryData)); @@ -198,14 +200,6 @@ public > FieldProbabilityOfCollision comput encounter.getCombinedRadius()); } - /** {@inheritDoc} */ - public abstract ProbabilityOfCollision compute(double xm, double ym, double sigmaX, double sigmaY, double radius); - - /** {@inheritDoc} */ - public abstract > FieldProbabilityOfCollision compute(T xm, T ym, - T sigmaX, T sigmaY, - T radius); - /** {@inheritDoc} */ @Override public String getName() { diff --git a/src/main/java/org/orekit/utils/Fieldifier.java b/src/main/java/org/orekit/utils/Fieldifier.java index 5f235230ed..d216a7cff9 100644 --- a/src/main/java/org/orekit/utils/Fieldifier.java +++ b/src/main/java/org/orekit/utils/Fieldifier.java @@ -21,19 +21,8 @@ import org.hipparchus.linear.FieldMatrix; import org.hipparchus.linear.MatrixUtils; import org.hipparchus.linear.RealMatrix; -import org.orekit.errors.OrekitInternalError; -import org.orekit.frames.Frame; -import org.orekit.orbits.CircularOrbit; -import org.orekit.orbits.EquinoctialOrbit; -import org.orekit.orbits.FieldCartesianOrbit; -import org.orekit.orbits.FieldCircularOrbit; -import org.orekit.orbits.FieldEquinoctialOrbit; -import org.orekit.orbits.FieldKeplerianOrbit; import org.orekit.orbits.FieldOrbit; -import org.orekit.orbits.KeplerianOrbit; import org.orekit.orbits.Orbit; -import org.orekit.orbits.OrbitType; -import org.orekit.orbits.PositionAngleType; import org.orekit.propagation.FieldStateCovariance; import org.orekit.propagation.StateCovariance; import org.orekit.time.FieldAbsoluteDate; @@ -60,93 +49,12 @@ private Fieldifier() { * @param type of the elements * * @return fielded orbit + * @deprecated */ + @Deprecated public static > FieldOrbit fieldify(final Field field, final Orbit orbit) { - final T one = field.getOne(); - final FieldAbsoluteDate fieldDate = new FieldAbsoluteDate<>(field, orbit.getDate()); - final T fieldMu = one.newInstance(orbit.getMu()); - final Frame frame = orbit.getFrame(); - - switch (orbit.getType()) { - case CIRCULAR: { - final CircularOrbit circOrbit = (CircularOrbit) OrbitType.CIRCULAR.convertType(orbit); - - // Get orbital elements - final T a = one.newInstance(circOrbit.getA()); - final T ex = one.newInstance(circOrbit.getCircularEx()); - final T ey = one.newInstance(circOrbit.getCircularEy()); - final T i = one.newInstance(circOrbit.getI()); - final T raan = one.newInstance(circOrbit.getRightAscensionOfAscendingNode()); - final T alphaM = one.newInstance(circOrbit.getAlphaM()); - - // Get derivatives - final T aDot = one.newInstance(circOrbit.getADot()); - final T exDot = one.newInstance(circOrbit.getCircularExDot()); - final T eyDot = one.newInstance(circOrbit.getCircularEyDot()); - final T iDot = one.newInstance(circOrbit.getIDot()); - final T raanDot = one.newInstance(circOrbit.getRightAscensionOfAscendingNodeDot()); - final T alphaMDot = one.newInstance(circOrbit.getAlphaMDot()); - - return new FieldCircularOrbit<>(a, ex, ey, i, raan, alphaM, aDot, exDot, eyDot, iDot, raanDot, alphaMDot, - PositionAngleType.MEAN, frame, fieldDate, fieldMu); - } - - case CARTESIAN: { - final FieldPVCoordinates orbitPV = new FieldPVCoordinates<>(field, orbit.getPVCoordinates()); - - return new FieldCartesianOrbit<>(orbitPV, orbit.getFrame(), fieldDate, fieldMu); - } - - case KEPLERIAN: { - final KeplerianOrbit kepOrbit = (KeplerianOrbit) OrbitType.KEPLERIAN.convertType(orbit); - - // Get orbital elements - final T a = one.newInstance(kepOrbit.getA()); - final T e = one.newInstance(kepOrbit.getE()); - final T i = one.newInstance(kepOrbit.getI()); - final T raan = one.newInstance(kepOrbit.getRightAscensionOfAscendingNode()); - final T pa = one.newInstance(kepOrbit.getPerigeeArgument()); - final T meanAnomaly = one.newInstance(kepOrbit.getMeanAnomaly()); - - // Get derivatives - final T aDot = one.newInstance(kepOrbit.getADot()); - final T eDot = one.newInstance(kepOrbit.getEDot()); - final T iDot = one.newInstance(kepOrbit.getIDot()); - final T raanDot = one.newInstance(kepOrbit.getRightAscensionOfAscendingNodeDot()); - final T paDot = one.newInstance(kepOrbit.getPerigeeArgumentDot()); - final T meanAnomalyDot = one.newInstance(kepOrbit.getMeanAnomalyDot()); - - return new FieldKeplerianOrbit<>(a, e, i, pa, raan, meanAnomaly, aDot, eDot, iDot, paDot, raanDot, - meanAnomalyDot, PositionAngleType.MEAN, frame, fieldDate, fieldMu); - } - case EQUINOCTIAL: { - final EquinoctialOrbit equiOrbit = (EquinoctialOrbit) OrbitType.EQUINOCTIAL.convertType(orbit); - - // Get orbital elements - final T a = one.newInstance(equiOrbit.getA()); - final T ex = one.newInstance(equiOrbit.getEquinoctialEx()); - final T ey = one.newInstance(equiOrbit.getEquinoctialEy()); - final T hx = one.newInstance(equiOrbit.getHx()); - final T hy = one.newInstance(equiOrbit.getHy()); - final T lm = one.newInstance(equiOrbit.getLM()); - - // Get derivatives - final T aDot = one.newInstance(equiOrbit.getADot()); - final T exDot = one.newInstance(equiOrbit.getEquinoctialExDot()); - final T eyDot = one.newInstance(equiOrbit.getEquinoctialEyDot()); - final T hxDot = one.newInstance(equiOrbit.getHxDot()); - final T hyDot = one.newInstance(equiOrbit.getHyDot()); - final T lmDot = one.newInstance(equiOrbit.getLMDot()); - - return new FieldEquinoctialOrbit<>(a, ex, ey, hx, hy, lm, aDot, exDot, eyDot, hxDot, hyDot, - lmDot, PositionAngleType.MEAN, frame, fieldDate, fieldMu); - } - default: - // Should never happen - throw new OrekitInternalError(null); - } - + return orbit.getType().convertToFieldOrbit(field, orbit); } /** diff --git a/src/test/java/org/orekit/utils/FieldifierTest.java b/src/test/java/org/orekit/utils/FieldifierTest.java index 262b8be9fd..909726fd8c 100644 --- a/src/test/java/org/orekit/utils/FieldifierTest.java +++ b/src/test/java/org/orekit/utils/FieldifierTest.java @@ -51,6 +51,7 @@ static void setUp() { } @Test + @Deprecated void testCircularOrbitFieldification() { // GIVEN // Create fake orbit with derivatives @@ -90,6 +91,7 @@ void testCircularOrbitFieldification() { } @Test + @Deprecated void testCartesianOrbitFieldification() { // GIVEN // Create fake orbit with derivatives @@ -127,6 +129,7 @@ void testCartesianOrbitFieldification() { } @Test + @Deprecated void testKeplerianOrbitFieldification() { // GIVEN // Create fake orbit with derivatives @@ -166,6 +169,7 @@ void testKeplerianOrbitFieldification() { } @Test + @Deprecated void testEquinoctialOrbitFieldification() { // GIVEN // Create fake orbit with derivatives From 8aadc363bc537c741e5a83abeb59ffbd37d1e3ef Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Tue, 27 Feb 2024 15:33:45 +0100 Subject: [PATCH 160/359] Added constant and quadratic clock models for GNSS measurements. --- src/changes/changes.xml | 3 + src/main/java/org/orekit/gnss/ClockModel.java | 41 ++++++++ .../org/orekit/gnss/ConstantClockModel.java | 51 ++++++++++ .../orekit/gnss/ConstantFieldClockModel.java | 53 ++++++++++ .../java/org/orekit/gnss/FieldClockModel.java | 44 +++++++++ .../org/orekit/gnss/QuadraticClockModel.java | 97 ++++++++++++++++++ .../orekit/gnss/QuadraticFieldClockModel.java | 99 +++++++++++++++++++ .../orekit/gnss/ConstantClockModelTest.java | 57 +++++++++++ .../gnss/ConstantFieldClockModelTest.java | 56 +++++++++++ .../orekit/gnss/QuadraticClockModelTest.java | 69 +++++++++++++ .../gnss/QuadraticFieldClockModelTest.java | 83 ++++++++++++++++ 11 files changed, 653 insertions(+) create mode 100644 src/main/java/org/orekit/gnss/ClockModel.java create mode 100644 src/main/java/org/orekit/gnss/ConstantClockModel.java create mode 100644 src/main/java/org/orekit/gnss/ConstantFieldClockModel.java create mode 100644 src/main/java/org/orekit/gnss/FieldClockModel.java create mode 100644 src/main/java/org/orekit/gnss/QuadraticClockModel.java create mode 100644 src/main/java/org/orekit/gnss/QuadraticFieldClockModel.java create mode 100644 src/test/java/org/orekit/gnss/ConstantClockModelTest.java create mode 100644 src/test/java/org/orekit/gnss/ConstantFieldClockModelTest.java create mode 100644 src/test/java/org/orekit/gnss/QuadraticClockModelTest.java create mode 100644 src/test/java/org/orekit/gnss/QuadraticFieldClockModelTest.java diff --git a/src/changes/changes.xml b/src/changes/changes.xml index f2d7d3b021..b3c48d67b1 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -21,6 +21,9 @@ + + Added constant and quadratic clock models for GNSS measurements. + Added cache for position angle in FieldOrbit when applicable. diff --git a/src/main/java/org/orekit/gnss/ClockModel.java b/src/main/java/org/orekit/gnss/ClockModel.java new file mode 100644 index 0000000000..0dabe78d54 --- /dev/null +++ b/src/main/java/org/orekit/gnss/ClockModel.java @@ -0,0 +1,41 @@ +/* Copyright 2002-2024 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.gnss; + +import org.orekit.time.AbsoluteDate; + +/** Interface for deterministic smooth clock model. + * + * @author Luc Maisonobe + * @since 12.1 + * + */ +public interface ClockModel { + + /** Get the clock offset at date + * @param date date at which offset is requested + * @return clock offset at specified date + */ + public double getOffset(AbsoluteDate date); + + /** Get the clock rate at date + * @param date date at which offset is requested + * @return clock rate at specified date + */ + public double getRate(AbsoluteDate date); + +} diff --git a/src/main/java/org/orekit/gnss/ConstantClockModel.java b/src/main/java/org/orekit/gnss/ConstantClockModel.java new file mode 100644 index 0000000000..43b363df04 --- /dev/null +++ b/src/main/java/org/orekit/gnss/ConstantClockModel.java @@ -0,0 +1,51 @@ +/* Copyright 2002-2024 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.gnss; + +import org.orekit.time.AbsoluteDate; + +/** Constant clock model. + * + * @author Luc Maisonobe + * @since 12.1 + * + */ +public class ConstantClockModel implements ClockModel { + + /** Constant offset. */ + private final double offset; + + /** Simple constructor. + * @param offset constant offset + */ + public ConstantClockModel(final double offset) { + this.offset = offset; + } + + /** {@inheritDoc} */ + @Override + public double getOffset(final AbsoluteDate date) { + return offset; + } + + /** {@inheritDoc} */ + @Override + public double getRate(final AbsoluteDate date) { + return 0.0; + } + +} diff --git a/src/main/java/org/orekit/gnss/ConstantFieldClockModel.java b/src/main/java/org/orekit/gnss/ConstantFieldClockModel.java new file mode 100644 index 0000000000..ab02066e78 --- /dev/null +++ b/src/main/java/org/orekit/gnss/ConstantFieldClockModel.java @@ -0,0 +1,53 @@ +/* Copyright 2002-2024 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.gnss; + +import org.hipparchus.CalculusFieldElement; +import org.orekit.time.FieldAbsoluteDate; + +/** Constant clock model. + * + * @param type of the field elements + * @author Luc Maisonobe + * @since 12.1 + * + */ +public class ConstantFieldClockModel> implements FieldClockModel { + + /** Constant offset. */ + private final T offset; + + /** Simple constructor. + * @param offset constant offset + */ + public ConstantFieldClockModel(final T offset) { + this.offset = offset; + } + + /** {@inheritDoc} */ + @Override + public T getOffset(final FieldAbsoluteDate date) { + return offset; + } + + /** {@inheritDoc} */ + @Override + public T getRate(final FieldAbsoluteDate date) { + return offset .getField().getZero(); + } + +} diff --git a/src/main/java/org/orekit/gnss/FieldClockModel.java b/src/main/java/org/orekit/gnss/FieldClockModel.java new file mode 100644 index 0000000000..33801b0d29 --- /dev/null +++ b/src/main/java/org/orekit/gnss/FieldClockModel.java @@ -0,0 +1,44 @@ +/* Copyright 2002-2024 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.gnss; + +import org.hipparchus.CalculusFieldElement; +import org.orekit.time.FieldAbsoluteDate; + +/** Interface for deterministic smooth clock model. + * + * @param type of the field elements + * @author Luc Maisonobe + * @since 12.1 + * + */ +public interface FieldClockModel> { + + /** Get the clock offset at date + * @param date date at which offset is requested + * @return clock offset at specified date + */ + public T getOffset(FieldAbsoluteDate date); + + /** Get the clock rate at date + * @param type of the field elements + * @param date date at which offset is requested + * @return clock rate at specified date + */ + public T getRate(FieldAbsoluteDate date); + +} diff --git a/src/main/java/org/orekit/gnss/QuadraticClockModel.java b/src/main/java/org/orekit/gnss/QuadraticClockModel.java new file mode 100644 index 0000000000..c73a0764f3 --- /dev/null +++ b/src/main/java/org/orekit/gnss/QuadraticClockModel.java @@ -0,0 +1,97 @@ +/* Copyright 2002-2024 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.gnss; + +import org.orekit.time.AbsoluteDate; + +/** Quadratic clock model. + * + * @author Luc Maisonobe + * @since 12.1 + * + */ +public class QuadraticClockModel implements ClockModel { + + /** Clock model reference date. */ + private final AbsoluteDate referenceDate; + + /** Constant term. */ + private final double a0; + + /** Linear term. */ + private final double a1; + + /** Quadratic term. */ + private final double a2; + + /** Simple constructor. + * @param referenceDate reference date + * @param a0 constant term + * @param a1 linear term + * @param a2 quadratic term + */ + public QuadraticClockModel(final AbsoluteDate referenceDate, + final double a0, final double a1, final double a2) { + this.referenceDate = referenceDate; + this.a0 = a0; + this.a1 = a1; + this.a2 = a2; + } + + /** Get reference date. + * @return reference date + */ + public AbsoluteDate getReferenceDate() { + return referenceDate; + } + + /** Get constant term. + * @return constant term + */ + public double getA0() { + return a0; + } + + /** Get linear term. + * @return linear term + */ + public double getA1() { + return a1; + } + + /** Get quadratic term. + * @return quadratic term + */ + public double getA2() { + return a2; + } + + /** {@inheritDoc} */ + @Override + public double getOffset(final AbsoluteDate date) { + final double dt = date.durationFrom(referenceDate); + return (a2 * dt + a1) * dt + a0; + } + + /** {@inheritDoc} */ + @Override + public double getRate(final AbsoluteDate date) { + final double dt = date.durationFrom(referenceDate); + return 2 * a2 * dt + a1; + } + +} diff --git a/src/main/java/org/orekit/gnss/QuadraticFieldClockModel.java b/src/main/java/org/orekit/gnss/QuadraticFieldClockModel.java new file mode 100644 index 0000000000..14de025dc8 --- /dev/null +++ b/src/main/java/org/orekit/gnss/QuadraticFieldClockModel.java @@ -0,0 +1,99 @@ +/* Copyright 2002-2024 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.gnss; + +import org.hipparchus.CalculusFieldElement; +import org.orekit.time.FieldAbsoluteDate; + +/** Quadratic clock model. + * + * @param type of the field elements + * @author Luc Maisonobe + * @since 12.1 + * + */ +public class QuadraticFieldClockModel> implements FieldClockModel { + + /** Clock model reference date. */ + private final FieldAbsoluteDate referenceDate; + + /** Constant term. */ + private final T a0; + + /** Linear term. */ + private final T a1; + + /** Quadratic term. */ + private final T a2; + + /** Simple constructor. + * @param referenceDate reference date + * @param a0 constant term + * @param a1 linear term + * @param a2 quadratic term + */ + public QuadraticFieldClockModel(final FieldAbsoluteDate referenceDate, + final T a0, final T a1, final T a2) { + this.referenceDate = referenceDate; + this.a0 = a0; + this.a1 = a1; + this.a2 = a2; + } + + /** Get reference date. + * @return reference date + */ + public FieldAbsoluteDate getReferenceDate() { + return referenceDate; + } + + /** Get constant term. + * @return constant term + */ + public T getA0() { + return a0; + } + + /** Get linear term. + * @return linear term + */ + public T getA1() { + return a1; + } + + /** Get quadratic term. + * @return quadratic term + */ + public T getA2() { + return a2; + } + + /** {@inheritDoc} */ + @Override + public T getOffset(final FieldAbsoluteDate date) { + final T dt = date.durationFrom(referenceDate); + return a2.multiply(dt).add(a1).multiply(dt).add(a0); + } + + /** {@inheritDoc} */ + @Override + public T getRate(final FieldAbsoluteDate date) { + final T dt = date.durationFrom(referenceDate); + return a2.multiply(dt).multiply(2).add(a1); + } + +} diff --git a/src/test/java/org/orekit/gnss/ConstantClockModelTest.java b/src/test/java/org/orekit/gnss/ConstantClockModelTest.java new file mode 100644 index 0000000000..a0c5c51cb7 --- /dev/null +++ b/src/test/java/org/orekit/gnss/ConstantClockModelTest.java @@ -0,0 +1,57 @@ +/* Copyright 2002-2024 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.gnss; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.orekit.time.AbsoluteDate; + + +public class ConstantClockModelTest { + + @Test + public void testValue() { + Assertions.assertEquals(1.25, clock.getOffset(t0), 1.0e-15); + Assertions.assertEquals(1.25, clock.getOffset(t0.shiftedBy(1.0)), 1.0e-15); + Assertions.assertEquals(1.25, clock.getOffset(t0.shiftedBy(2.0)), 1.0e-15); + } + + @Test + public void testRate() { + Assertions.assertEquals(0.0, clock.getRate(t0), 1.0e-15); + Assertions.assertEquals(0.0, clock.getRate(t0.shiftedBy(1.0)), 1.0e-15); + Assertions.assertEquals(0.0, clock.getRate(t0.shiftedBy(2.0)), 1.0e-15); + } + + @BeforeEach + public void setUp() { + t0 = AbsoluteDate.GALILEO_EPOCH; + clock = new ConstantClockModel(1.25); + } + + @AfterEach + public void tearDown() { + t0 = null; + clock = null; + } + + private AbsoluteDate t0; + private ClockModel clock; + +} diff --git a/src/test/java/org/orekit/gnss/ConstantFieldClockModelTest.java b/src/test/java/org/orekit/gnss/ConstantFieldClockModelTest.java new file mode 100644 index 0000000000..f1efa02272 --- /dev/null +++ b/src/test/java/org/orekit/gnss/ConstantFieldClockModelTest.java @@ -0,0 +1,56 @@ +/* Copyright 2002-2024 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.gnss; + +import org.hipparchus.CalculusFieldElement; +import org.hipparchus.Field; +import org.hipparchus.util.Binary64Field; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; + + +public class ConstantFieldClockModelTest { + + @Test + public void testValueField() { + doTestValueField(Binary64Field.getInstance()); + } + + @Test + public void testRateField() { + doTestRateField(Binary64Field.getInstance()); + } + + private > void doTestValueField(final Field field) { + final FieldClockModel clock = new ConstantFieldClockModel<>(field.getZero().newInstance(1.25)); + final FieldAbsoluteDate t0 = new FieldAbsoluteDate(field, AbsoluteDate.GALILEO_EPOCH); + Assertions.assertEquals(1.25, clock.getOffset(t0).getReal(), 1.0e-15); + Assertions.assertEquals(1.25, clock.getOffset(t0.shiftedBy(1.0)).getReal(), 1.0e-15); + Assertions.assertEquals(1.25, clock.getOffset(t0.shiftedBy(2.0)).getReal(), 1.0e-15); + } + + private > void doTestRateField(final Field field) { + final FieldClockModel clock = new ConstantFieldClockModel<>(field.getZero().newInstance(1.25)); + final FieldAbsoluteDate t0 = new FieldAbsoluteDate(field, AbsoluteDate.GALILEO_EPOCH); + Assertions.assertEquals(0.0, clock.getRate(t0).getReal(), 1.0e-15); + Assertions.assertEquals(0.0, clock.getRate(t0.shiftedBy(1.0)).getReal(), 1.0e-15); + Assertions.assertEquals(0.0, clock.getRate(t0.shiftedBy(1.0)).getReal(), 1.0e-15); + } + +} diff --git a/src/test/java/org/orekit/gnss/QuadraticClockModelTest.java b/src/test/java/org/orekit/gnss/QuadraticClockModelTest.java new file mode 100644 index 0000000000..73c5efa77d --- /dev/null +++ b/src/test/java/org/orekit/gnss/QuadraticClockModelTest.java @@ -0,0 +1,69 @@ +/* Copyright 2002-2024 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.gnss; + +import org.hipparchus.util.FastMath; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.orekit.time.AbsoluteDate; + + +public class QuadraticClockModelTest { + + @Test + public void testValue() { + Assertions.assertEquals(1.00 / 256.0, clock.getOffset(t0), 1.0e-15); + Assertions.assertEquals(1.75 / 256.0, clock.getOffset(t0.shiftedBy(1.0)), 1.0e-15); + Assertions.assertEquals(3.00 / 256.0, clock.getOffset(t0.shiftedBy(2.0)), 1.0e-15); + } + + @Test + public void testRate() { + Assertions.assertEquals(1.00 / 512, clock.getRate(t0), 1.0e-15); + Assertions.assertEquals(2.00 / 512, clock.getRate(t0.shiftedBy(1.0)), 1.0e-15); + Assertions.assertEquals(3.00 / 512, clock.getRate(t0.shiftedBy(2.0)), 1.0e-15); + } + + @Test + public void testGetters() { + Assertions.assertEquals(0.0, clock.getReferenceDate().durationFrom(AbsoluteDate.GALILEO_EPOCH), 1.0e-15); + Assertions.assertEquals(1.00 / 256, clock.getA0(), 1.0e-15); + Assertions.assertEquals(1.00 / 512, clock.getA1(), 1.0e-15); + Assertions.assertEquals(1.00 / 1024, clock.getA2(), 1.0e-15); + } + + @BeforeEach + public void setUp() { + t0 = AbsoluteDate.GALILEO_EPOCH; + clock = new QuadraticClockModel(t0, + FastMath.scalb(1.0, -8), + FastMath.scalb(1.0, -9), + FastMath.scalb(1.0, -10)); + } + + @AfterEach + public void tearDown() { + t0 = null; + clock = null; + } + + private AbsoluteDate t0; + private QuadraticClockModel clock; + +} diff --git a/src/test/java/org/orekit/gnss/QuadraticFieldClockModelTest.java b/src/test/java/org/orekit/gnss/QuadraticFieldClockModelTest.java new file mode 100644 index 0000000000..015454c839 --- /dev/null +++ b/src/test/java/org/orekit/gnss/QuadraticFieldClockModelTest.java @@ -0,0 +1,83 @@ +/* Copyright 2002-2024 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.gnss; + +import org.hipparchus.CalculusFieldElement; +import org.hipparchus.Field; +import org.hipparchus.util.Binary64Field; +import org.hipparchus.util.FastMath; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; + + +public class QuadraticFieldClockModelTest { + + @Test + public void testValueField() { + doTestValueField(Binary64Field.getInstance()); + } + + @Test + public void testRateField() { + doTestRateField(Binary64Field.getInstance()); + } + + @Test + public void testGetters() { + doTestGetters(Binary64Field.getInstance()); + } + + private > void doTestValueField(final Field field) { + final FieldAbsoluteDate t0 = new FieldAbsoluteDate<>(field, AbsoluteDate.GALILEO_EPOCH); + final QuadraticFieldClockModel clock = + new QuadraticFieldClockModel<>(t0, + field.getZero().newInstance(FastMath.scalb(1.0, -8)), + field.getZero().newInstance(FastMath.scalb(1.0, -9)), + field.getZero().newInstance(FastMath.scalb(1.0, -10))); + Assertions.assertEquals(1.00 / 256.0, clock.getOffset(t0).getReal(), 1.0e-15); + Assertions.assertEquals(1.75 / 256.0, clock.getOffset(t0.shiftedBy(1.0)).getReal(), 1.0e-15); + Assertions.assertEquals(3.00 / 256.0, clock.getOffset(t0.shiftedBy(2.0)).getReal(), 1.0e-15); + } + + private > void doTestRateField(final Field field) { + final FieldAbsoluteDate t0 = new FieldAbsoluteDate<>(field, AbsoluteDate.GALILEO_EPOCH); + final QuadraticFieldClockModel clock = + new QuadraticFieldClockModel<>(t0, + field.getZero().newInstance(FastMath.scalb(1.0, -8)), + field.getZero().newInstance(FastMath.scalb(1.0, -9)), + field.getZero().newInstance(FastMath.scalb(1.0, -10))); + Assertions.assertEquals(1.00 / 512, clock.getRate(t0).getReal(), 1.0e-15); + Assertions.assertEquals(2.00 / 512, clock.getRate(t0.shiftedBy(1.0)).getReal(), 1.0e-15); + Assertions.assertEquals(3.00 / 512, clock.getRate(t0.shiftedBy(2.0)).getReal(), 1.0e-15); + } + + private > void doTestGetters(final Field field) { + final FieldAbsoluteDate t0 = new FieldAbsoluteDate<>(field, AbsoluteDate.GALILEO_EPOCH); + final QuadraticFieldClockModel clock = + new QuadraticFieldClockModel<>(t0, + field.getZero().newInstance(FastMath.scalb(1.0, -8)), + field.getZero().newInstance(FastMath.scalb(1.0, -9)), + field.getZero().newInstance(FastMath.scalb(1.0, -10))); + Assertions.assertEquals(0.0, clock.getReferenceDate().durationFrom(AbsoluteDate.GALILEO_EPOCH).getReal(), 1.0e-15); + Assertions.assertEquals(1.00 / 256, clock.getA0().getReal(), 1.0e-15); + Assertions.assertEquals(1.00 / 512, clock.getA1().getReal(), 1.0e-15); + Assertions.assertEquals(1.00 / 1024, clock.getA2().getReal(), 1.0e-15); + } + +} From 7543b00b6337da27194a690e6256862afd803a26 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Tue, 27 Feb 2024 18:16:11 +0100 Subject: [PATCH 161/359] Work In Progress on common code factoring. --- .../GroundReceiverMeasurement.java | 4 + .../measurements/GroundStation.java | 22 +++ .../measurements/InterSatellitesRange.java | 10 +- .../measurements/ObservableSatellite.java | 80 +++++++- .../orekit/estimation/measurements/Range.java | 4 +- .../gnss/AbstractOnBoardMeasurement.java | 184 ++++++++++++++++++ .../gnss/AbstractOneWayGNSSMeasurement.java | 135 +++++++++++++ .../gnss/InterSatellitesMeasurement.java | 114 +++++++++++ .../gnss/InterSatellitesPhase.java | 111 +++-------- .../measurements/gnss/OnBoardMeasurement.java | 173 ---------------- .../measurements/gnss/OneWayGNSSPhase.java | 41 ++-- .../measurements/gnss/OneWayGNSSRange.java | 40 ++-- .../gnss/OneWayGNSSPhaseTest.java | 1 - 13 files changed, 623 insertions(+), 296 deletions(-) create mode 100644 src/main/java/org/orekit/estimation/measurements/gnss/AbstractOnBoardMeasurement.java create mode 100644 src/main/java/org/orekit/estimation/measurements/gnss/AbstractOneWayGNSSMeasurement.java create mode 100644 src/main/java/org/orekit/estimation/measurements/gnss/InterSatellitesMeasurement.java delete mode 100644 src/main/java/org/orekit/estimation/measurements/gnss/OnBoardMeasurement.java diff --git a/src/main/java/org/orekit/estimation/measurements/GroundReceiverMeasurement.java b/src/main/java/org/orekit/estimation/measurements/GroundReceiverMeasurement.java index 1c0f3c5ccc..ba97f2c04c 100644 --- a/src/main/java/org/orekit/estimation/measurements/GroundReceiverMeasurement.java +++ b/src/main/java/org/orekit/estimation/measurements/GroundReceiverMeasurement.java @@ -66,6 +66,7 @@ public GroundReceiverMeasurement(final GroundStation station, final boolean twoW super(date, observed, sigma, baseWeight, Collections.singletonList(satellite)); addParameterDriver(station.getClockOffsetDriver()); addParameterDriver(station.getClockDriftDriver()); + addParameterDriver(station.getClockAccelerationDriver()); addParameterDriver(station.getEastOffsetDriver()); addParameterDriver(station.getNorthOffsetDriver()); addParameterDriver(station.getZenithOffsetDriver()); @@ -79,6 +80,7 @@ public GroundReceiverMeasurement(final GroundStation station, final boolean twoW // for one way measurements, the satellite clock offset affects the measurement addParameterDriver(satellite.getClockOffsetDriver()); addParameterDriver(satellite.getClockDriftDriver()); + addParameterDriver(satellite.getClockAccelerationDriver()); } this.station = station; this.twoway = twoWay; @@ -99,6 +101,7 @@ public GroundReceiverMeasurement(final GroundStation station, final boolean twoW super(date, observed, sigma, baseWeight, Collections.singletonList(satellite)); addParameterDriver(station.getClockOffsetDriver()); addParameterDriver(station.getClockDriftDriver()); + addParameterDriver(station.getClockAccelerationDriver()); addParameterDriver(station.getEastOffsetDriver()); addParameterDriver(station.getNorthOffsetDriver()); addParameterDriver(station.getZenithOffsetDriver()); @@ -112,6 +115,7 @@ public GroundReceiverMeasurement(final GroundStation station, final boolean twoW // for one way measurements, the satellite clock offset affects the measurement addParameterDriver(satellite.getClockOffsetDriver()); addParameterDriver(satellite.getClockDriftDriver()); + addParameterDriver(satellite.getClockAccelerationDriver()); } this.station = station; this.twoway = twoWay; diff --git a/src/main/java/org/orekit/estimation/measurements/GroundStation.java b/src/main/java/org/orekit/estimation/measurements/GroundStation.java index 885be937f1..01946d4c6c 100644 --- a/src/main/java/org/orekit/estimation/measurements/GroundStation.java +++ b/src/main/java/org/orekit/estimation/measurements/GroundStation.java @@ -97,6 +97,11 @@ public class GroundStation { /** Suffix for ground clock drift parameters name. */ public static final String DRIFT_SUFFIX = "-drift-clock"; + /** Suffix for ground clock drift parameters name. + * @since 12.1 + */ + public static final String ACCELERATION_SUFFIX = "-acceleration-clock"; + /** Suffix for ground station intermediate frame name. */ public static final String INTERMEDIATE_SUFFIX = "-intermediate"; @@ -142,6 +147,11 @@ public class GroundStation { /** Driver for clock drift. */ private final ParameterDriver clockDriftDriver; + /** Driver for clock acceleration. + * @since 12.1 + */ + private final ParameterDriver clockAccelerationDriver; + /** Driver for position offset along the East axis. */ private final ParameterDriver eastOffsetDriver; @@ -285,6 +295,10 @@ public GroundStation(final TopocentricFrame baseFrame, 0.0, CLOCK_OFFSET_SCALE, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY); + this.clockAccelerationDriver = new ParameterDriver(baseFrame.getName() + ACCELERATION_SUFFIX, + 0.0, CLOCK_OFFSET_SCALE, + Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY); + this.eastOffsetDriver = new ParameterDriver(baseFrame.getName() + OFFSET_SUFFIX + "-East", 0.0, POSITION_OFFSET_SCALE, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY); @@ -342,6 +356,14 @@ public ParameterDriver getClockDriftDriver() { return clockDriftDriver; } + /** Get a driver allowing to change station clock acceleration (which is related to measurement date). + * @return driver for station clock acceleration + * @since 12.1 + */ + public ParameterDriver getClockAccelerationDriver() { + return clockAccelerationDriver; + } + /** Get a driver allowing to change station position along East axis. * @return driver for station position offset along East axis */ diff --git a/src/main/java/org/orekit/estimation/measurements/InterSatellitesRange.java b/src/main/java/org/orekit/estimation/measurements/InterSatellitesRange.java index de147826d5..cfb56c53e7 100644 --- a/src/main/java/org/orekit/estimation/measurements/InterSatellitesRange.java +++ b/src/main/java/org/orekit/estimation/measurements/InterSatellitesRange.java @@ -53,9 +53,9 @@ * offset is subtracted *

                • as range is evaluated using the total signal time of flight, for one-way * measurements the observed range is the real physical signal time of flight to - * which (Δtl - Δtr) ⨉ c is added, where Δtl (resp. Δtr) is the clock offset for the + * which (Δtl - Δtr) ⨯ c is added, where Δtl (resp. Δtr) is the clock offset for the * local satellite (resp. remote satellite). A similar effect exists in - * two-way measurements but it is computed as (Δtl - Δtl) ⨉ c / 2 as the local satellite + * two-way measurements but it is computed as (Δtl - Δtl) ⨯ c / 2 as the local satellite * clock is used for both initial emission and final reception and therefore it evaluates * to zero.
                • *
                @@ -94,9 +94,13 @@ public InterSatellitesRange(final ObservableSatellite local, super(date, range, sigma, baseWeight, Arrays.asList(local, remote)); // for one way and two ways measurements, the local satellite clock offsets affects the measurement addParameterDriver(local.getClockOffsetDriver()); + addParameterDriver(local.getClockDriftDriver()); + addParameterDriver(local.getClockAccelerationDriver()); if (!twoWay) { // for one way measurements, the remote satellite clock offsets also affects the measurement addParameterDriver(remote.getClockOffsetDriver()); + addParameterDriver(remote.getClockDriftDriver()); + addParameterDriver(remote.getClockAccelerationDriver()); } this.twoway = twoWay; } @@ -192,7 +196,7 @@ protected EstimatedMeasurement theoreticalEvaluation(final final int evaluation, final SpacecraftState[] states) { - // Range derivatives are computed with respect to spacecrafts states in inertial frame + // Range derivatives are computed with respect to spacecraft states in inertial frame // ---------------------- // // Parameters: diff --git a/src/main/java/org/orekit/estimation/measurements/ObservableSatellite.java b/src/main/java/org/orekit/estimation/measurements/ObservableSatellite.java index 41ef013ba4..c83f1adcc8 100644 --- a/src/main/java/org/orekit/estimation/measurements/ObservableSatellite.java +++ b/src/main/java/org/orekit/estimation/measurements/ObservableSatellite.java @@ -16,7 +16,16 @@ */ package org.orekit.estimation.measurements; +import java.util.Map; + +import org.hipparchus.analysis.differentiation.Gradient; import org.hipparchus.util.FastMath; +import org.orekit.errors.OrekitException; +import org.orekit.errors.OrekitMessages; +import org.orekit.gnss.QuadraticClockModel; +import org.orekit.gnss.QuadraticFieldClockModel; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; import org.orekit.utils.ParameterDriver; /** Class modeling a satellite that can be observed. @@ -32,6 +41,11 @@ public class ObservableSatellite { /** Prefix for clock drift parameter driver, the propagator index will be appended to it. */ public static final String CLOCK_DRIFT_PREFIX = "clock-drift-satellite-"; + /** Prefix for clock acceleration parameter driver, the propagator index will be appended to it. + * @since 12.1 + */ + public static final String CLOCK_ACCELERATION_PREFIX = "clock-acceleration-satellite-"; + /** Clock offset scaling factor. *

                * We use a power of 2 to avoid numeric noise introduction @@ -49,6 +63,11 @@ public class ObservableSatellite { /** Parameter driver for satellite clock drift. */ private final ParameterDriver clockDriftDriver; + /** Parameter driver for satellite clock acceleration. + * @since 12.1 + */ + private final ParameterDriver clockAccelerationDriver; + /** Simple constructor. * @param propagatorIndex index of the propagator related to this satellite */ @@ -60,6 +79,9 @@ public ObservableSatellite(final int propagatorIndex) { this.clockDriftDriver = new ParameterDriver(CLOCK_DRIFT_PREFIX + propagatorIndex, 0.0, CLOCK_OFFSET_SCALE, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY); + this.clockAccelerationDriver = new ParameterDriver(CLOCK_ACCELERATION_PREFIX + propagatorIndex, + 0.0, CLOCK_OFFSET_SCALE, + Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY); } /** Get the index of the propagator related to this satellite. @@ -85,13 +107,69 @@ public ParameterDriver getClockOffsetDriver() { *

                * The drift is negative if the satellite clock is slowing down and positive if it is speeding up. *

                - * @return clock offset parameter driver + * @return clock drift parameter driver * @since 10.3 */ public ParameterDriver getClockDriftDriver() { return clockDriftDriver; } + /** Get the clock acceleration parameter driver. + * @return clock acceleration parameter driver + * @since 12.1 + */ + public ParameterDriver getClockAccelerationDriver() { + return clockAccelerationDriver; + } + + /** Get a quadratic clock model valid at some date. + * @param date date at which the quadratic model should be valid + * @return quadratic clock model + * @since 12.1 + */ + public QuadraticClockModel getQuadraticClockModel(final AbsoluteDate date) { + final double a0 = clockOffsetDriver.getValue(date); + final double a1 = clockDriftDriver.getValue(date); + final double a2 = clockAccelerationDriver.getValue(date); + AbsoluteDate referenceDate = clockOffsetDriver.getReferenceDate(); + if (referenceDate == null) { + if (a1 == 0 && a2 == 0) { + // it is OK to not have a reference date is clock offset is constant + referenceDate = date; + } else { + throw new OrekitException(OrekitMessages.NO_REFERENCE_DATE_FOR_PARAMETER, + clockOffsetDriver.getName()); + } + } + return new QuadraticClockModel(referenceDate, a0, a1, a2); + } + + /** Get a quadratic clock model valid at some date. + * @param freeParameters total number of free parameters in the gradient + * @param indices indices of the differentiation parameters in derivatives computations, + * must be span name and not driver name + * @param date date at which the quadratic model should be valid + * @return quadratic clock model + * @since 12.1 + */ + public QuadraticFieldClockModel getQuadraticClockModel(final int freeParameters, final Map indices, + final AbsoluteDate date) { + final Gradient a0 = clockOffsetDriver.getValue(freeParameters, indices, date); + final Gradient a1 = clockDriftDriver.getValue(freeParameters, indices, date); + final Gradient a2 = clockAccelerationDriver.getValue(freeParameters, indices, date); + AbsoluteDate referenceDate = clockOffsetDriver.getReferenceDate(); + if (referenceDate == null) { + if (a1.getReal() == 0 && a2.getReal() == 0) { + // it is OK to not have a reference date is clock offset is constant + referenceDate = date; + } else { + throw new OrekitException(OrekitMessages.NO_REFERENCE_DATE_FOR_PARAMETER, + clockOffsetDriver.getName()); + } + } + return new QuadraticFieldClockModel<>(new FieldAbsoluteDate<>(a0.getField(), referenceDate), a0, a1, a2); + } + /** {@inheritDoc} * @since 12.0 */ diff --git a/src/main/java/org/orekit/estimation/measurements/Range.java b/src/main/java/org/orekit/estimation/measurements/Range.java index dba9684923..3d2d14a222 100644 --- a/src/main/java/org/orekit/estimation/measurements/Range.java +++ b/src/main/java/org/orekit/estimation/measurements/Range.java @@ -57,9 +57,9 @@ * clock offset is subtracted *
              • as range is evaluated using the total signal time of flight, for one-way * measurements the observed range is the real physical signal time of flight to - * which (Δtg - Δts) ⨉ c is added, where Δtg (resp. Δts) is the clock offset for the + * which (Δtg - Δts) ⨯ c is added, where Δtg (resp. Δts) is the clock offset for the * receiving ground station (resp. emitting satellite). A similar effect exists in - * two-way measurements but it is computed as (Δtg - Δtg) ⨉ c / 2 as the same ground + * two-way measurements but it is computed as (Δtg - Δtg) ⨯ c / 2 as the same ground * station clock is used for initial emission and final reception and therefore it evaluates * to zero.
              • *
              diff --git a/src/main/java/org/orekit/estimation/measurements/gnss/AbstractOnBoardMeasurement.java b/src/main/java/org/orekit/estimation/measurements/gnss/AbstractOnBoardMeasurement.java new file mode 100644 index 0000000000..74d6da13a1 --- /dev/null +++ b/src/main/java/org/orekit/estimation/measurements/gnss/AbstractOnBoardMeasurement.java @@ -0,0 +1,184 @@ +/* Copyright 2002-2024 Luc Maisonobe + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.estimation.measurements.gnss; + +import org.hipparchus.analysis.differentiation.Gradient; +import org.orekit.estimation.measurements.AbstractMeasurement; +import org.orekit.estimation.measurements.ObservableSatellite; +import org.orekit.estimation.measurements.ObservedMeasurement; +import org.orekit.propagation.SpacecraftState; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; +import org.orekit.utils.FieldPVCoordinatesProvider; +import org.orekit.utils.PVCoordinatesProvider; +import org.orekit.utils.ParameterDriver; +import org.orekit.utils.TimeSpanMap.Span; +import org.orekit.utils.TimeStampedFieldPVCoordinates; +import org.orekit.utils.TimeStampedPVCoordinates; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.function.ToDoubleFunction; + +/** Base class modeling a measurement where receiver is a satellite. + * @param type of the measurement + * @author Luc Maisonobe + * @since 12.1 + */ +public abstract class AbstractOnBoardMeasurement> extends AbstractMeasurement { + + /** Constructor. + * @param date date of the measurement + * @param observed observed value + * @param sigma theoretical standard deviation + * @param baseWeight base weight + * @param satellites satellites related to this measurement + */ + public AbstractOnBoardMeasurement(final AbsoluteDate date, final double observed, + final double sigma, final double baseWeight, + final List satellites) { + // Call to super constructor + super(date, observed, sigma, baseWeight, satellites); + + // Add parameter drivers + satellites.forEach(s -> { + addParameterDriver(s.getClockOffsetDriver()); + addParameterDriver(s.getClockDriftDriver()); + addParameterDriver(s.getClockAccelerationDriver()); + }); + + } + + /** Get emitting satellite clock provider. + * @return emitting satellite clock provider + */ + protected abstract ToDoubleFunction getDoubleRemoteClock(); + + /** Get emitting satellite position/velocity provider. + * @param states states of all spacecraft involved in the measurement + * @return emitting satellite position/velocity provider + */ + protected abstract PVCoordinatesProvider getDoubleRemotePV(SpacecraftState[] states); + + /** Get emitting satellite position/velocity provider. + * @param states states of all spacecraft involved in the measurement + * @param freeParameters total number of free parameters in the gradient + * @return emitting satellite position/velocity provider + */ + protected abstract FieldPVCoordinatesProvider getGradientRemotePV(SpacecraftState[] states, + int freeParameters); + + /** Get emitting satellite clock provider. + * @param freeParameters total number of free parameters in the gradient + * @param indices indices of the differentiation parameters in derivatives computations, + * must be span name and not driver name + * @return emitting satellite clock provider + */ + protected abstract Function, Gradient> getGradientRemoteClock(int freeParameters, Map indices); + + /** Compute common estimation parameters. + * @param states states of all spacecraft involved in the measurement + * @param clockOffsetAlreadyApplied if true, the specified {@code date} is as read + * by the receiver clock (i.e. clock offset not compensated), if false, + * the specified {@code date} was already compensated and is a physical absolute date + * @return common parameters + */ + protected OnBoardCommonParametersWithoutDerivatives computeCommonParametersWithout(final SpacecraftState[] states, + final boolean clockOffsetAlreadyApplied) { + + // local and remote satellites + final TimeStampedPVCoordinates pvaLocal = states[0].getPVCoordinates(); + final double dtLocal = getSatellites(). + get(0). + getQuadraticClockModel(getDate()). + getOffset(getDate()); + final PVCoordinatesProvider remotePV = getDoubleRemotePV(states); + final ToDoubleFunction remoteClock = getDoubleRemoteClock(); + + // take clock offset into account + final AbsoluteDate arrivalDate = clockOffsetAlreadyApplied ? getDate() : getDate().shiftedBy(-dtLocal); + + // Downlink delay + final double deltaT = arrivalDate.durationFrom(states[0]); + final TimeStampedPVCoordinates pvaDownlink = pvaLocal.shiftedBy(deltaT); + final double tauD = signalTimeOfFlight(remotePV, arrivalDate, pvaDownlink.getPosition(), + arrivalDate, states[0].getFrame()); + + // Remote satellite at signal emission + final AbsoluteDate emissionDate = arrivalDate.shiftedBy(-tauD); + return new OnBoardCommonParametersWithoutDerivatives(states[0], dtLocal, remoteClock.applyAsDouble(emissionDate), + tauD, pvaDownlink, + remotePV.getPVCoordinates(emissionDate, states[0].getFrame())); + + } + + /** Compute common estimation parameters. + * @param states states of all spacecraft involved in the measurement + * @param clockOffsetAlreadyApplied if true, the specified {@code date} is as read + * by the receiver clock (i.e. clock offset not compensated), if false, + * the specified {@code date} was already compensated and is a physical absolute date + * @return common parameters + */ + protected OnBoardCommonParametersWithDerivatives computeCommonParametersWith(final SpacecraftState[] states, + final boolean clockOffsetAlreadyApplied) { + + // measurement derivatives are computed with respect to spacecraft state in inertial frame + // Parameters: + // - 6k..6k+2 - Position of spacecraft k (counting k from 0 to nbSat-1) in inertial frame + // - 6k+3..6k+5 - Velocity of spacecraft k (counting k from 0 to nbSat-1) in inertial frame + // - 6nbSat..n - measurements parameters (clock offset, etc) + int nbEstimatedParams = 6 * states.length; + final Map parameterIndices = new HashMap<>(); + for (ParameterDriver measurementDriver : getParametersDrivers()) { + if (measurementDriver.isSelected()) { + for (Span span = measurementDriver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) { + parameterIndices.put(span.getData(), nbEstimatedParams++); + } + } + } + + // local and remote satellites + final TimeStampedFieldPVCoordinates pvaLocal = getCoordinates(states[0], 0, nbEstimatedParams); + final ParameterDriver localClockDriver = getSatellites().get(0).getClockOffsetDriver(); + final Gradient dtLocal = localClockDriver.getValue(nbEstimatedParams, parameterIndices, getDate()); + final FieldPVCoordinatesProvider remotePV = getGradientRemotePV(states, nbEstimatedParams); + final Function, Gradient> remoteClock = getGradientRemoteClock(nbEstimatedParams, parameterIndices); + + // take clock offset into account + final FieldAbsoluteDate arrivalDate = clockOffsetAlreadyApplied ? + new FieldAbsoluteDate<>(dtLocal.getField(), getDate()) : + new FieldAbsoluteDate<>(getDate(), dtLocal.negate()); + + // Downlink delay + final Gradient deltaT = arrivalDate.durationFrom(states[0].getDate()); + final TimeStampedFieldPVCoordinates pvaDownlink = pvaLocal.shiftedBy(deltaT); + final Gradient tauD = signalTimeOfFlight(remotePV, arrivalDate, + pvaDownlink.getPosition(), arrivalDate, + states[0].getFrame()); + + // Remote satellite at signal emission + final FieldAbsoluteDate emissionDate = arrivalDate.shiftedBy(tauD.negate()); + return new OnBoardCommonParametersWithDerivatives(states[0], parameterIndices, + dtLocal, remoteClock.apply(emissionDate), + tauD, pvaDownlink, + remotePV.getPVCoordinates(emissionDate, states[0].getFrame())); + + } + +} diff --git a/src/main/java/org/orekit/estimation/measurements/gnss/AbstractOneWayGNSSMeasurement.java b/src/main/java/org/orekit/estimation/measurements/gnss/AbstractOneWayGNSSMeasurement.java new file mode 100644 index 0000000000..d18d2aee78 --- /dev/null +++ b/src/main/java/org/orekit/estimation/measurements/gnss/AbstractOneWayGNSSMeasurement.java @@ -0,0 +1,135 @@ +/* Copyright 2002-2024 Luc Maisonobe + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.estimation.measurements.gnss; + +import java.util.Collections; +import java.util.Map; +import java.util.function.Function; +import java.util.function.ToDoubleFunction; + +import org.hipparchus.analysis.differentiation.Gradient; +import org.orekit.estimation.measurements.ObservableSatellite; +import org.orekit.estimation.measurements.ObservedMeasurement; +import org.orekit.gnss.QuadraticClockModel; +import org.orekit.gnss.QuadraticFieldClockModel; +import org.orekit.propagation.SpacecraftState; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; +import org.orekit.utils.FieldPVCoordinatesProvider; +import org.orekit.utils.PVCoordinatesProvider; +import org.orekit.utils.TimeStampedFieldPVCoordinates; +import org.orekit.utils.TimeStampedPVCoordinates; + +/** Base class for one-way GNSS measurement. + *

              + * This class can be used in precise orbit determination applications + * for modeling a range measurement between a GNSS satellite (emitter) + * and a LEO satellite (receiver). + *

              + *

              + * The one-way GNSS range measurement assumes knowledge of the orbit and + * the clock offset of the emitting GNSS satellite. For instance, it is + * possible to use a SP3 file or a GNSS navigation message to recover + * the satellite's orbit and clock. + *

              + *

              + * This class is very similar to {@link InterSatellitesMeasurement} measurement + * class. However, using the one-way GNSS range measurement, the orbit and clock + * of the emitting GNSS satellite are NOT estimated simultaneously with + * LEO satellite coordinates. + *

              + * + * @param type of the measurement + * @author Luc Maisonobe + * @since 12.1 + */ +public abstract class AbstractOneWayGNSSMeasurement> extends AbstractOnBoardMeasurement { + + /** Emitting satellite. */ + private final PVCoordinatesProvider remotePV; + + /** Clock offset of the emitting satellite. */ + private final QuadraticClockModel remoteClock; + + /** Simple constructor. + * @param remotePV provider for GNSS satellite which simply emits the signal + * @param remoteClock clock offset of the GNSS satellite + * @param date date of the measurement + * @param range observed value + * @param sigma theoretical standard deviation + * @param baseWeight base weight + * @param local satellite which receives the signal and perform the measurement + */ + public AbstractOneWayGNSSMeasurement(final PVCoordinatesProvider remotePV, + final QuadraticClockModel remoteClock, + final AbsoluteDate date, + final double range, final double sigma, + final double baseWeight, final ObservableSatellite local) { + // Call super constructor + super(date, range, sigma, baseWeight, Collections.singletonList(local)); + // The local satellite clock offset affects the measurement + addParameterDriver(local.getClockOffsetDriver()); + addParameterDriver(local.getClockDriftDriver()); + addParameterDriver(local.getClockAccelerationDriver()); + // Initialise fields + this.remotePV = remotePV; + this.remoteClock = remoteClock; + } + + /** {@inheritDoc} */ + @Override + protected PVCoordinatesProvider getDoubleRemotePV(final SpacecraftState[] states) { + return remotePV; + } + + /** {@inheritDoc} */ + @Override + protected ToDoubleFunction getDoubleRemoteClock() { + return remoteClock::getOffset; + } + + /** {@inheritDoc} */ + @Override + protected FieldPVCoordinatesProvider getGradientRemotePV(final SpacecraftState[] states, + final int freeParameters) { + // convert the PVCoordinatesProvider to a FieldPVCoordinatesProvider + return (date, frame) -> { + + // apply the raw (no derivatives) remote provider + final AbsoluteDate dateBase = date.toAbsoluteDate(); + final TimeStampedPVCoordinates pvBase = remotePV.getPVCoordinates(dateBase, frame); + final TimeStampedFieldPVCoordinates pvWithoutDerivatives = + new TimeStampedFieldPVCoordinates<>(date.getField(), pvBase); + + // add derivatives, using a trick: we shift the date by 0, with derivatives + final Gradient zeroWithDerivatives = date.durationFrom(dateBase); + return pvWithoutDerivatives.shiftedBy(zeroWithDerivatives); + + }; + } + + /** {@inheritDoc} */ + @Override + protected Function, Gradient> getGradientRemoteClock(final int freeParameters, final Map indices) { + final Gradient a0 = Gradient.constant(freeParameters, remoteClock.getA0()); + final Gradient a1 = Gradient.constant(freeParameters, remoteClock.getA1()); + final Gradient a2 = Gradient.constant(freeParameters, remoteClock.getA2()); + final FieldAbsoluteDate referenceDate = new FieldAbsoluteDate<>(a0.getField(), remoteClock.getReferenceDate()); + return new QuadraticFieldClockModel<>(referenceDate, a0, a1, a2)::getOffset; + } + +} diff --git a/src/main/java/org/orekit/estimation/measurements/gnss/InterSatellitesMeasurement.java b/src/main/java/org/orekit/estimation/measurements/gnss/InterSatellitesMeasurement.java new file mode 100644 index 0000000000..288e8b1d43 --- /dev/null +++ b/src/main/java/org/orekit/estimation/measurements/gnss/InterSatellitesMeasurement.java @@ -0,0 +1,114 @@ +/* Copyright 2002-2024 Luc Maisonobe + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.estimation.measurements.gnss; + +import java.util.Arrays; +import java.util.Map; +import java.util.function.Function; +import java.util.function.ToDoubleFunction; + +import org.hipparchus.analysis.differentiation.Gradient; +import org.orekit.estimation.measurements.ObservableSatellite; +import org.orekit.estimation.measurements.ObservedMeasurement; +import org.orekit.propagation.SpacecraftState; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; +import org.orekit.utils.FieldPVCoordinatesProvider; +import org.orekit.utils.PVCoordinatesProvider; +import org.orekit.utils.ShiftingPVCoordinatesProvider; +import org.orekit.utils.TimeStampedFieldPVCoordinates; + +/** BAse class for measurement between two satellites that are both estimated. + *

              + * The measurement is considered to be a signal emitted from + * a remote satellite and received by a local satellite. + * Its value is the number of cycles between emission and reception. + * The motion of both spacecraft during the signal flight time + * are taken into account. The date of the measurement corresponds to the + * reception on ground of the emitted signal. + *

              + * @param type of the measurement + * @author Luc Maisonobe + * @since 12.1 + */ +public abstract class InterSatellitesMeasurement> extends AbstractOnBoardMeasurement { + + /** Constructor. + * @param date date of the measurement + * @param observed observed value + * @param sigma theoretical standard deviation + * @param baseWeight base weight + * @param local satellite which receives the signal and performs the measurement + * @param remote remote satellite which simply emits the signal + */ + public InterSatellitesMeasurement(final AbsoluteDate date, final double observed, + final double sigma, final double baseWeight, + final ObservableSatellite local, + final ObservableSatellite remote) { + // Call to super constructor + super(date, observed, sigma, baseWeight, Arrays.asList(local, remote)); + + addParameterDriver(local.getClockOffsetDriver()); + addParameterDriver(local.getClockDriftDriver()); + addParameterDriver(local.getClockAccelerationDriver()); + addParameterDriver(remote.getClockOffsetDriver()); + addParameterDriver(remote.getClockDriftDriver()); + addParameterDriver(remote.getClockAccelerationDriver()); + + } + + /** {@inheritDoc} */ + @Override + protected PVCoordinatesProvider getDoubleRemotePV(final SpacecraftState[] states) { + return new ShiftingPVCoordinatesProvider(states[1].getPVCoordinates(), states[1].getFrame()); + } + + /** {@inheritDoc} */ + @Override + protected ToDoubleFunction getDoubleRemoteClock() { + return getSatellites().get(1).getQuadraticClockModel(getDate())::getOffset; + } + + /** {@inheritDoc} */ + @Override + protected FieldPVCoordinatesProvider getGradientRemotePV(final SpacecraftState[] states, + final int freeParameters) { + // convert the SpacecraftState to a FieldPVCoordinatesProvider + return (date, frame) -> { + + // shift the raw (no derivatives) remote state + final AbsoluteDate dateBase = date.toAbsoluteDate(); + final SpacecraftState shifted = states[1].shiftedBy(dateBase.durationFrom(states[1])); + + // set up the derivatives with respect to remote state + final TimeStampedFieldPVCoordinates pv = getCoordinates(shifted, 6, freeParameters); + + // add remaining derivatives, using a trick: we shift the date by 0, with derivatives + final Gradient zeroWithDerivatives = date.durationFrom(dateBase); + return pv.shiftedBy(zeroWithDerivatives); + + }; + } + + /** {@inheritDoc} */ + @Override + protected Function, Gradient> getGradientRemoteClock(final int freeParameters, + final Map indices) { + return getSatellites().get(1).getQuadraticClockModel(freeParameters, indices, getDate())::getOffset; + } + +} diff --git a/src/main/java/org/orekit/estimation/measurements/gnss/InterSatellitesPhase.java b/src/main/java/org/orekit/estimation/measurements/gnss/InterSatellitesPhase.java index 27962cd159..7e0937a75f 100644 --- a/src/main/java/org/orekit/estimation/measurements/gnss/InterSatellitesPhase.java +++ b/src/main/java/org/orekit/estimation/measurements/gnss/InterSatellitesPhase.java @@ -17,21 +17,16 @@ package org.orekit.estimation.measurements.gnss; import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; import org.hipparchus.analysis.differentiation.Gradient; -import org.orekit.estimation.measurements.AbstractMeasurement; import org.orekit.estimation.measurements.EstimatedMeasurement; import org.orekit.estimation.measurements.EstimatedMeasurementBase; import org.orekit.estimation.measurements.ObservableSatellite; import org.orekit.propagation.SpacecraftState; import org.orekit.time.AbsoluteDate; -import org.orekit.time.FieldAbsoluteDate; import org.orekit.utils.Constants; import org.orekit.utils.ParameterDriver; import org.orekit.utils.TimeSpanMap.Span; -import org.orekit.utils.TimeStampedFieldPVCoordinates; import org.orekit.utils.TimeStampedPVCoordinates; /** Phase measurement between two satellites. @@ -39,14 +34,14 @@ * The measurement is considered to be a signal emitted from * a remote satellite and received by a local satellite. * Its value is the number of cycles between emission and reception. - * The motion of both spacecrafts during the signal flight time + * The motion of both spacecraft during the signal flight time * are taken into account. The date of the measurement corresponds to the * reception on ground of the emitted signal. *

              * @author Bryan Cazabonne * @since 10.3 */ -public class InterSatellitesPhase extends AbstractMeasurement { +public class InterSatellitesPhase extends InterSatellitesMeasurement { /** Type of the measurement. */ public static final String MEASUREMENT_TYPE = "InterSatellitesPhase"; @@ -75,7 +70,7 @@ public InterSatellitesPhase(final ObservableSatellite local, final double wavelength, final double sigma, final double baseWeight) { // Call to super constructor - super(date, phase, sigma, baseWeight, Arrays.asList(local, remote)); + super(date, phase, sigma, baseWeight, local, remote); // Initialize phase ambiguity driver ambiguityDriver = new ParameterDriver(AMBIGUITY_NAME, 0.0, 1.0, @@ -84,7 +79,11 @@ public InterSatellitesPhase(final ObservableSatellite local, // Add parameter drivers addParameterDriver(ambiguityDriver); addParameterDriver(local.getClockOffsetDriver()); + addParameterDriver(local.getClockDriftDriver()); + addParameterDriver(local.getClockAccelerationDriver()); addParameterDriver(remote.getClockOffsetDriver()); + addParameterDriver(remote.getClockDriftDriver()); + addParameterDriver(remote.getClockAccelerationDriver()); // Initialize fields this.wavelength = wavelength; @@ -110,42 +109,24 @@ protected EstimatedMeasurementBase theoreticalEvaluationWi final int evaluation, final SpacecraftState[] states) { - // Coordinates of both satellites - final SpacecraftState local = states[0]; - final TimeStampedPVCoordinates pvaL = local.getPVCoordinates(); - final SpacecraftState remote = states[1]; - final TimeStampedPVCoordinates pvaR = remote.getPVCoordinates(); - - // Compute propagation times - // Downlink delay - final double dtl = getSatellites().get(0).getClockOffsetDriver().getValue(AbsoluteDate.ARBITRARY_EPOCH); - final AbsoluteDate arrivalDate = getDate().shiftedBy(-dtl); - - final TimeStampedPVCoordinates s1Downlink = pvaL.shiftedBy(arrivalDate.durationFrom(pvaL.getDate())); - final double tauD = signalTimeOfFlight(pvaR, s1Downlink.getPosition(), arrivalDate, local.getFrame()); - - // Transit state - final double delta = getDate().durationFrom(remote.getDate()); - final double deltaMTauD = delta - tauD; + final OnBoardCommonParametersWithoutDerivatives common = computeCommonParametersWithout(states, false); // prepare the evaluation final EstimatedMeasurementBase estimatedPhase = new EstimatedMeasurementBase<>(this, iteration, evaluation, new SpacecraftState[] { - local.shiftedBy(deltaMTauD), - remote.shiftedBy(deltaMTauD) + common.getState(), + states[1] }, new TimeStampedPVCoordinates[] { - remote.shiftedBy(delta - tauD).getPVCoordinates(), - local.shiftedBy(delta).getPVCoordinates() + common.getRemotePV(), + common.getTransitPV() }); - // Clock offsets - final double dtr = getSatellites().get(1).getClockOffsetDriver().getValue(AbsoluteDate.ARBITRARY_EPOCH); - // Phase value final double cOverLambda = Constants.SPEED_OF_LIGHT / wavelength; - final double ambiguity = ambiguityDriver.getValue(AbsoluteDate.ARBITRARY_EPOCH); - final double phase = (tauD + dtl - dtr) * cOverLambda + ambiguity; + final double ambiguity = ambiguityDriver.getValue(common.getState().getDate()); + final double phase = (common.getTauD() + common.getDtLocal() - common.getDtRemote()) * cOverLambda + + ambiguity; estimatedPhase.setEstimatedValue(phase); @@ -160,64 +141,26 @@ protected EstimatedMeasurement theoreticalEvaluation(final final int evaluation, final SpacecraftState[] states) { - // Phase derivatives are computed with respect to spacecrafts states in inertial frame - // ---------------------- - // - // Parameters: - // - 0..2 - Position of the receiver satellite in inertial frame - // - 3..5 - Velocity of the receiver satellite in inertial frame - // - 6..8 - Position of the remote satellite in inertial frame - // - 9..11 - Velocity of the remote satellite in inertial frame - // - 12.. - Measurement parameters: ambiguity, local clock offset, remote clock offset... - int nbParams = 12; - final Map indices = new HashMap<>(); - for (ParameterDriver phaseMeasurementDriver : getParametersDrivers()) { - if (phaseMeasurementDriver.isSelected()) { - for (Span span = phaseMeasurementDriver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) { - - indices.put(span.getData(), nbParams++); - } - } - } + final OnBoardCommonParametersWithDerivatives common = computeCommonParametersWith(states, false); - // Coordinates of both satellites - final SpacecraftState local = states[0]; - final TimeStampedFieldPVCoordinates pvaL = getCoordinates(local, 0, nbParams); - final SpacecraftState remote = states[1]; - final TimeStampedFieldPVCoordinates pvaR = getCoordinates(remote, 6, nbParams); - - // Compute propagation times - // Downlink delay - final Gradient dtl = getSatellites().get(0).getClockOffsetDriver().getValue(nbParams, indices, AbsoluteDate.ARBITRARY_EPOCH); - final FieldAbsoluteDate arrivalDate = new FieldAbsoluteDate<>(getDate(), dtl.negate()); - - final TimeStampedFieldPVCoordinates s1Downlink = - pvaL.shiftedBy(arrivalDate.durationFrom(pvaL.getDate())); - final Gradient tauD = signalTimeOfFlight(pvaR, s1Downlink.getPosition(), - arrivalDate, local.getFrame()); - - // Transit state - final double delta = getDate().durationFrom(remote.getDate()); - final Gradient deltaMTauD = tauD.negate().add(delta); - - // prepare the evaluation + // prepare the evaluation final EstimatedMeasurement estimatedPhase = new EstimatedMeasurement<>(this, iteration, evaluation, new SpacecraftState[] { - local.shiftedBy(deltaMTauD.getValue()), - remote.shiftedBy(deltaMTauD.getValue()) + common.getState(), + states[1] }, new TimeStampedPVCoordinates[] { - remote.shiftedBy(delta - tauD.getValue()).getPVCoordinates(), - local.shiftedBy(delta).getPVCoordinates() + common.getRemotePV().toTimeStampedPVCoordinates(), + common.getTransitPV().toTimeStampedPVCoordinates() }); - // Clock offsets - final Gradient dtr = getSatellites().get(1).getClockOffsetDriver().getValue(nbParams, indices, AbsoluteDate.ARBITRARY_EPOCH); - // Phase value final double cOverLambda = Constants.SPEED_OF_LIGHT / wavelength; - final Gradient ambiguity = ambiguityDriver.getValue(nbParams, indices, AbsoluteDate.ARBITRARY_EPOCH); - final Gradient phase = tauD.add(dtl).subtract(dtr).multiply(cOverLambda).add(ambiguity); + final Gradient ambiguity = ambiguityDriver.getValue(common.getTauD().getFreeParameters(), common.getIndices(), + common.getState().getDate()); + final Gradient phase = common.getTauD().add(common.getDtLocal()).subtract(common.getDtRemote()). + multiply(cOverLambda). + add(ambiguity); estimatedPhase.setEstimatedValue(phase.getValue()); @@ -230,7 +173,7 @@ protected EstimatedMeasurement theoreticalEvaluation(final for (final ParameterDriver driver : getParametersDrivers()) { for (Span span = driver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) { - final Integer index = indices.get(span.getData()); + final Integer index = common.getIndices().get(span.getData()); if (index != null) { estimatedPhase.setParameterDerivatives(driver, span.getStart(), derivatives[index]); } diff --git a/src/main/java/org/orekit/estimation/measurements/gnss/OnBoardMeasurement.java b/src/main/java/org/orekit/estimation/measurements/gnss/OnBoardMeasurement.java deleted file mode 100644 index a93d843222..0000000000 --- a/src/main/java/org/orekit/estimation/measurements/gnss/OnBoardMeasurement.java +++ /dev/null @@ -1,173 +0,0 @@ -/* Copyright 2002-2024 Luc Maisonobe - * Licensed to CS GROUP (CS) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * CS licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.orekit.estimation.measurements.gnss; - -import org.hipparchus.analysis.differentiation.Gradient; -import org.orekit.estimation.measurements.AbstractMeasurement; -import org.orekit.estimation.measurements.ObservableSatellite; -import org.orekit.estimation.measurements.ObservedMeasurement; -import org.orekit.propagation.SpacecraftState; -import org.orekit.time.AbsoluteDate; -import org.orekit.time.FieldAbsoluteDate; -import org.orekit.utils.FieldPVCoordinatesProvider; -import org.orekit.utils.PVCoordinatesProvider; -import org.orekit.utils.ParameterDriver; -import org.orekit.utils.TimeSpanMap.Span; -import org.orekit.utils.TimeStampedFieldPVCoordinates; -import org.orekit.utils.TimeStampedPVCoordinates; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** Base class modeling a measurement where receiver is a satellite. - * @param type of the measurement - * @author Luc Maisonobe - * @since 12.1 - */ -public abstract class OnBoardMeasurement> extends AbstractMeasurement { - - /** Constructor. - * @param date date of the measurement - * @param observed observed value - * @param sigma theoretical standard deviation - * @param baseWeight base weight - * @param satellites satellites related to this measurement - */ - public OnBoardMeasurement(final AbsoluteDate date, final double observed, - final double sigma, final double baseWeight, - final List satellites) { - // Call to super constructor - super(date, observed, sigma, baseWeight, satellites); - - // Add parameter drivers - satellites.forEach(s -> addParameterDriver(s.getClockDriftDriver())); - - } - - /** Compute common estimation parameters. - * @param local orbital state of local satellite at measurement date - * @param remote emitting satellite - * @param dtRemote remote clock offset - * @param clockOffsetAlreadyApplied if true, the specified {@code date} is as read - * by the receiver clock (i.e. clock offset not compensated), if false, - * the specified {@code date} was already compensated and is a physical absolute date - * @return common parameters - */ - protected OnBoardCommonParametersWithoutDerivatives computeCommonParametersWithout(final SpacecraftState local, - final PVCoordinatesProvider remote, - final double dtRemote, - final boolean clockOffsetAlreadyApplied) { - - // Coordinates of both satellites - final TimeStampedPVCoordinates pvaLocal = local.getPVCoordinates(); - - // take clock offset into account - final ParameterDriver localClockDriver = getSatellites().get(0).getClockOffsetDriver(); - final double dtLocal = localClockDriver.getValue(getDate()); - final AbsoluteDate arrivalDate = clockOffsetAlreadyApplied ? - getDate() : - getDate().shiftedBy(-dtLocal); - - // Downlink delay - final double deltaT = arrivalDate.durationFrom(local); - final TimeStampedPVCoordinates pvaDownlink = pvaLocal.shiftedBy(deltaT); - final double tauD = signalTimeOfFlight(remote, arrivalDate, pvaDownlink.getPosition(), - arrivalDate, local.getFrame()); - - // Remote satellite at signal emission - return new OnBoardCommonParametersWithoutDerivatives(local, dtLocal, dtRemote, tauD, - pvaDownlink, - remote.getPVCoordinates(arrivalDate.shiftedBy(-tauD), - local.getFrame())); - - } - - /** Compute common estimation parameters. - * ^param nbSat number of satellites involved in the measurement - * @param local orbital state of local satellite at measurement date - * @param remote emitting satellite - * @param dtRemote remote clock offset - * @param clockOffsetAlreadyApplied if true, the specified {@code date} is as read - * by the receiver clock (i.e. clock offset not compensated), if false, - * the specified {@code date} was already compensated and is a physical absolute date - * @return common parameters - */ - protected OnBoardCommonParametersWithDerivatives computeCommonParametersWith(final int nbSat, - final SpacecraftState local, - final PVCoordinatesProvider remote, - final double dtRemote, - final boolean clockOffsetAlreadyApplied) { - - // Range derivatives are computed with respect to spacecraft state in inertial frame - // Parameters: - // - 6k..6k+2 - Position of spacecraft k (counting from 0) in inertial frame - // - 6k+3..6k+5 - Velocity of spacecraft k (counting from 0) in inertial frame - // - 6k+6..n - measurements parameters (clock offset, etc) - int nbEstimatedParams = 6 * nbSat; - final Map parameterIndices = new HashMap<>(); - for (ParameterDriver measurementDriver : getParametersDrivers()) { - if (measurementDriver.isSelected()) { - for (Span span = measurementDriver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) { - parameterIndices.put(span.getData(), nbEstimatedParams++); - } - } - } - - // convert the PVCoordinatesProvider to a FieldPVCoordinatesProvider - final FieldPVCoordinatesProvider gRemote = (date, frame) -> { - - // apply the raw (no derivatives) remote provider - final AbsoluteDate dateBase = date.toAbsoluteDate(); - final TimeStampedPVCoordinates pvBase = remote.getPVCoordinates(dateBase, frame); - final TimeStampedFieldPVCoordinates pvWithoutDerivatives = - new TimeStampedFieldPVCoordinates<>(date.getField(), pvBase); - - // add derivatives, using a trick: we shift the date by 0, with derivatives - final Gradient zeroWithDerivatives = date.durationFrom(dateBase); - return pvWithoutDerivatives.shiftedBy(zeroWithDerivatives); - - }; - - // Coordinates of both satellites - final TimeStampedFieldPVCoordinates - pvaLocal = getCoordinates(local, 0, nbEstimatedParams); - - // take clock offset into account - final ParameterDriver localClockDriver = getSatellites().get(0).getClockOffsetDriver(); - final Gradient dtLocal = localClockDriver.getValue(nbEstimatedParams, parameterIndices, getDate()); - final FieldAbsoluteDate arrivalDate = clockOffsetAlreadyApplied ? - new FieldAbsoluteDate<>(dtLocal.getField(), getDate()) : - new FieldAbsoluteDate<>(getDate(), dtLocal.negate()); - - // Downlink delay - final Gradient deltaT = arrivalDate.durationFrom(local.getDate()); - final TimeStampedFieldPVCoordinates pvaDownlink = pvaLocal.shiftedBy(deltaT); - final Gradient tauD = signalTimeOfFlight(gRemote, arrivalDate, - pvaDownlink.getPosition(), arrivalDate, - local.getFrame()); - - // Remote satellite at signal emission - return new OnBoardCommonParametersWithDerivatives(local, parameterIndices, - dtLocal, dtLocal.newInstance(dtRemote), tauD, - pvaDownlink, - gRemote.getPVCoordinates(arrivalDate.shiftedBy(tauD.negate()), - local.getFrame())); - - } - -} diff --git a/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSPhase.java b/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSPhase.java index 0673746946..febf0b2aa2 100644 --- a/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSPhase.java +++ b/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSPhase.java @@ -17,12 +17,12 @@ package org.orekit.estimation.measurements.gnss; import java.util.Arrays; -import java.util.Collections; import org.hipparchus.analysis.differentiation.Gradient; import org.orekit.estimation.measurements.EstimatedMeasurement; import org.orekit.estimation.measurements.EstimatedMeasurementBase; import org.orekit.estimation.measurements.ObservableSatellite; +import org.orekit.gnss.QuadraticClockModel; import org.orekit.propagation.SpacecraftState; import org.orekit.time.AbsoluteDate; import org.orekit.utils.Constants; @@ -50,7 +50,7 @@ * @author Bryan Cazabonne * @since 10.3 */ -public class OneWayGNSSPhase extends OnBoardMeasurement { +public class OneWayGNSSPhase extends AbstractOneWayGNSSMeasurement { /** Type of the measurement. */ public static final String MEASUREMENT_TYPE = "OneWayGNSSPhase"; @@ -61,12 +61,6 @@ public class OneWayGNSSPhase extends OnBoardMeasurement { /** Driver for ambiguity. */ private final ParameterDriver ambiguityDriver; - /** Emitting satellite. */ - private final PVCoordinatesProvider remote; - - /** Clock offset of the emitting satellite. */ - private final double dtRemote; - /** Wavelength of the phase observed value [m]. */ private final double wavelength; @@ -85,8 +79,27 @@ public OneWayGNSSPhase(final PVCoordinatesProvider remote, final AbsoluteDate date, final double phase, final double wavelength, final double sigma, final double baseWeight, final ObservableSatellite local) { + this(remote, new QuadraticClockModel(date, dtRemote, 0.0, 0.0), date, phase, wavelength, sigma, baseWeight, local); + } + + /** Simple constructor. + * @param remote provider for GNSS satellite which simply emits the signal + * @param remoteClock clock offset of the GNSS satellite + * @param date date of the measurement + * @param phase observed value, in cycles + * @param wavelength phase observed value wavelength, in meters + * @param sigma theoretical standard deviation + * @param baseWeight base weight + * @param local satellite which receives the signal and perform the measurement + * @since 12.1 + */ + public OneWayGNSSPhase(final PVCoordinatesProvider remote, + final QuadraticClockModel remoteClock, + final AbsoluteDate date, + final double phase, final double wavelength, final double sigma, + final double baseWeight, final ObservableSatellite local) { // Call super constructor - super(date, phase, sigma, baseWeight, Collections.singletonList(local)); + super(remote, remoteClock, date, phase, sigma, baseWeight, local); // Initialize phase ambiguity driver ambiguityDriver = new ParameterDriver(AMBIGUITY_NAME, 0.0, 1.0, @@ -97,8 +110,6 @@ public OneWayGNSSPhase(final PVCoordinatesProvider remote, addParameterDriver(local.getClockOffsetDriver()); // Initialise fields - this.dtRemote = dtRemote; - this.remote = remote; this.wavelength = wavelength; } @@ -122,8 +133,7 @@ protected EstimatedMeasurementBase theoreticalEvaluationWithout final int evaluation, final SpacecraftState[] states) { - final OnBoardCommonParametersWithoutDerivatives common = - computeCommonParametersWithout(states[0], remote, dtRemote, false); + final OnBoardCommonParametersWithoutDerivatives common = computeCommonParametersWithout(states, false); // prepare the evaluation final EstimatedMeasurementBase estimatedPhase = @@ -155,10 +165,9 @@ protected EstimatedMeasurement theoreticalEvaluation(final int final int evaluation, final SpacecraftState[] states) { - final OnBoardCommonParametersWithDerivatives common = - computeCommonParametersWith(1, states[0], remote, dtRemote, false); + final OnBoardCommonParametersWithDerivatives common = computeCommonParametersWith(states, false); - // prepare the evaluation + // prepare the evaluation final EstimatedMeasurement estimatedPhase = new EstimatedMeasurement<>(this, iteration, evaluation, new SpacecraftState[] { diff --git a/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRange.java b/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRange.java index 3eb2b4dc5a..5ba3f92697 100644 --- a/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRange.java +++ b/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRange.java @@ -17,13 +17,13 @@ package org.orekit.estimation.measurements.gnss; import java.util.Arrays; -import java.util.Collections; import org.hipparchus.analysis.differentiation.Gradient; import org.orekit.estimation.measurements.EstimatedMeasurement; import org.orekit.estimation.measurements.EstimatedMeasurementBase; import org.orekit.estimation.measurements.InterSatellitesRange; import org.orekit.estimation.measurements.ObservableSatellite; +import org.orekit.gnss.QuadraticClockModel; import org.orekit.propagation.SpacecraftState; import org.orekit.time.AbsoluteDate; import org.orekit.utils.Constants; @@ -51,17 +51,11 @@ * @author Bryan Cazabonne * @since 10.3 */ -public class OneWayGNSSRange extends OnBoardMeasurement { +public class OneWayGNSSRange extends AbstractOneWayGNSSMeasurement { /** Type of the measurement. */ public static final String MEASUREMENT_TYPE = "OneWayGNSSRange"; - /** Emitting satellite. */ - private final PVCoordinatesProvider remote; - - /** Clock offset of the emitting satellite. */ - private final double dtRemote; - /** Simple constructor. * @param remote provider for GNSS satellite which simply emits the signal * @param dtRemote clock offset of the GNSS satellite, in seconds @@ -76,13 +70,29 @@ public OneWayGNSSRange(final PVCoordinatesProvider remote, final AbsoluteDate date, final double range, final double sigma, final double baseWeight, final ObservableSatellite local) { + this(remote, new QuadraticClockModel(date, dtRemote, 0.0, 0.0), date, range, sigma, baseWeight, local); + } + + /** Simple constructor. + * @param remote provider for GNSS satellite which simply emits the signal + * @param remoteClock clock offset of the GNSS satellite + * @param date date of the measurement + * @param range observed value + * @param sigma theoretical standard deviation + * @param baseWeight base weight + * @param local satellite which receives the signal and perform the measurement + * @since 12.1 + */ + public OneWayGNSSRange(final PVCoordinatesProvider remote, + final QuadraticClockModel remoteClock, + final AbsoluteDate date, + final double range, final double sigma, + final double baseWeight, final ObservableSatellite local) { // Call super constructor - super(date, range, sigma, baseWeight, Collections.singletonList(local)); + super(remote, remoteClock, date, range, sigma, baseWeight, local); // The local satellite clock offset affects the measurement addParameterDriver(local.getClockOffsetDriver()); - // Initialise fields - this.dtRemote = dtRemote; - this.remote = remote; + } /** {@inheritDoc} */ @@ -92,8 +102,7 @@ protected EstimatedMeasurementBase theoreticalEvaluationWithout final SpacecraftState[] states) { - final OnBoardCommonParametersWithoutDerivatives common = - computeCommonParametersWithout(states[0], remote, dtRemote, false); + final OnBoardCommonParametersWithoutDerivatives common = computeCommonParametersWithout(states, false); // Estimated measurement final EstimatedMeasurementBase estimatedRange = @@ -123,8 +132,7 @@ protected EstimatedMeasurement theoreticalEvaluation(final int final int evaluation, final SpacecraftState[] states) { - final OnBoardCommonParametersWithDerivatives common = - computeCommonParametersWith(1, states[0], remote, dtRemote, false); + final OnBoardCommonParametersWithDerivatives common = computeCommonParametersWith(states, false); // Estimated measurement final EstimatedMeasurement estimatedRange = diff --git a/src/test/java/org/orekit/estimation/measurements/gnss/OneWayGNSSPhaseTest.java b/src/test/java/org/orekit/estimation/measurements/gnss/OneWayGNSSPhaseTest.java index 6395d84a93..2180ee20a7 100644 --- a/src/test/java/org/orekit/estimation/measurements/gnss/OneWayGNSSPhaseTest.java +++ b/src/test/java/org/orekit/estimation/measurements/gnss/OneWayGNSSPhaseTest.java @@ -50,7 +50,6 @@ import org.orekit.utils.Differentiation; import org.orekit.utils.ParameterDriver; import org.orekit.utils.ParameterFunction; -import org.orekit.utils.StateFunction; import org.orekit.utils.TimeSpanMap.Span; import org.orekit.utils.TimeStampedPVCoordinates; From 5477e1954b4860f3b7cd6a2020ae42286341ad1b Mon Sep 17 00:00:00 2001 From: Serrof Date: Tue, 27 Feb 2024 22:59:08 +0100 Subject: [PATCH 162/359] improved sonarqube ratings --- .../numerical/FieldNumericalPropagator.java | 12 +- .../numerical/NumericalPropagator.java | 11 +- .../org/orekit/orbits/CircularOrbitTest.java | 550 ++++++++++-------- 3 files changed, 305 insertions(+), 268 deletions(-) diff --git a/src/main/java/org/orekit/propagation/numerical/FieldNumericalPropagator.java b/src/main/java/org/orekit/propagation/numerical/FieldNumericalPropagator.java index d37875943c..1c073e5628 100644 --- a/src/main/java/org/orekit/propagation/numerical/FieldNumericalPropagator.java +++ b/src/main/java/org/orekit/propagation/numerical/FieldNumericalPropagator.java @@ -499,16 +499,16 @@ private class Main implements MainStateEquations, FieldTimeDerivativesEquatio this.yDot = MathArrays.buildArray(getField(), 7); this.jacobian = MathArrays.buildArray(getField(), 6, 6); + this.recomputingJacobian = true; + for (final ForceModel forceModel : forceModels) { forceModel.getFieldEventDetectors(getField()).forEach(detector -> setUpEventDetector(integrator, detector)); } - if (!recomputingJacobian) { - // we can set Jacobian once and for all - for (int i = 0; i < jacobian.length; ++i) { - Arrays.fill(jacobian[i], getField().getZero()); - jacobian[i][i] = getField().getOne(); - } + // default value for Jacobian is identity + for (int i = 0; i < jacobian.length; ++i) { + Arrays.fill(jacobian[i], getField().getZero()); + jacobian[i][i] = getField().getOne(); } } diff --git a/src/main/java/org/orekit/propagation/numerical/NumericalPropagator.java b/src/main/java/org/orekit/propagation/numerical/NumericalPropagator.java index 28283cd527..cdfc5c4d07 100644 --- a/src/main/java/org/orekit/propagation/numerical/NumericalPropagator.java +++ b/src/main/java/org/orekit/propagation/numerical/NumericalPropagator.java @@ -912,17 +912,16 @@ private class Main implements MainStateEquations, TimeDerivativesEquations { this.yDot = new double[7]; this.jacobian = new double[6][6]; + this.recomputingJacobian = true; for (final ForceModel forceModel : forceModels) { forceModel.getEventDetectors().forEach(detector -> setUpEventDetector(integrator, detector)); } - if (!recomputingJacobian) { - // we can set Jacobian once and for all - for (int i = 0; i < jacobian.length; ++i) { - Arrays.fill(jacobian[i], 0.0); - jacobian[i][i] = 1.0; - } + // default value for Jacobian is identity + for (int i = 0; i < jacobian.length; ++i) { + Arrays.fill(jacobian[i], 0.0); + jacobian[i][i] = 1.0; } } diff --git a/src/test/java/org/orekit/orbits/CircularOrbitTest.java b/src/test/java/org/orekit/orbits/CircularOrbitTest.java index 1a0c14b9b2..e65f3c4434 100644 --- a/src/test/java/org/orekit/orbits/CircularOrbitTest.java +++ b/src/test/java/org/orekit/orbits/CircularOrbitTest.java @@ -70,9 +70,9 @@ void testCircularToEquinoctialEll() { // elliptic orbit CircularOrbit circ = - new CircularOrbit(42166712.0, 0.5, -0.5, i, raan, - 5.300 - raan, PositionAngleType.MEAN, - FramesFactory.getEME2000(), date, mu); + new CircularOrbit(42166712.0, 0.5, -0.5, i, raan, + 5.300 - raan, PositionAngleType.MEAN, + FramesFactory.getEME2000(), date, mu); Vector3D pos = circ.getPosition(); Vector3D vit = circ.getPVCoordinates().getVelocity(); @@ -98,9 +98,9 @@ void testCircularToEquinoctialCirc() { // circular orbit EquinoctialOrbit circCir = - new EquinoctialOrbit(42166712.0, 0.1e-10, -0.1e-10, i, raan, - 5.300 - raan, PositionAngleType.MEAN, - FramesFactory.getEME2000(), date, mu); + new EquinoctialOrbit(42166712.0, 0.1e-10, -0.1e-10, i, raan, + 5.300 - raan, PositionAngleType.MEAN, + FramesFactory.getEME2000(), date, mu); Vector3D posCir = circCir.getPosition(); Vector3D vitCir = circCir.getPVCoordinates().getVelocity(); @@ -131,9 +131,9 @@ void testCircularToCartesian() { double ey = eyTilde * cosRaan - exTilde * sinRaan; CircularOrbit circ= - new CircularOrbit(42166712.0, ex, ey, i, raan, - 5.300 - raan, PositionAngleType.MEAN, - FramesFactory.getEME2000(), date, mu); + new CircularOrbit(42166712.0, ex, ey, i, raan, + 5.300 - raan, PositionAngleType.MEAN, + FramesFactory.getEME2000(), date, mu); Vector3D pos = circ.getPosition(); Vector3D vel = circ.getPVCoordinates().getVelocity(); @@ -167,24 +167,24 @@ void testCircularToKeplerian() { double ey = eyTilde * cosRaan - exTilde * sinRaan; CircularOrbit circ= - new CircularOrbit(42166712.0, ex, ey, i, raan, - 5.300 - raan, PositionAngleType.MEAN, - FramesFactory.getEME2000(), date, mu); + new CircularOrbit(42166712.0, ex, ey, i, raan, + 5.300 - raan, PositionAngleType.MEAN, + FramesFactory.getEME2000(), date, mu); KeplerianOrbit kep = new KeplerianOrbit(circ); Assertions.assertEquals(42166712.000, circ.getA(), Utils.epsilonTest * kep.getA()); Assertions.assertEquals(0.110283316961361e-03, kep.getE(), Utils.epsilonE * FastMath.abs(kep.getE())); Assertions.assertEquals(0.166901168553917e-03, kep.getI(), - Utils.epsilonAngle * FastMath.abs(kep.getI())); + Utils.epsilonAngle * FastMath.abs(kep.getI())); Assertions.assertEquals(MathUtils.normalizeAngle(-3.87224326008837, kep.getPerigeeArgument()), - kep.getPerigeeArgument(), - Utils.epsilonTest * FastMath.abs(kep.getPerigeeArgument())); + kep.getPerigeeArgument(), + Utils.epsilonTest * FastMath.abs(kep.getPerigeeArgument())); Assertions.assertEquals(MathUtils.normalizeAngle(5.51473467358854, kep.getRightAscensionOfAscendingNode()), - kep.getRightAscensionOfAscendingNode(), - Utils.epsilonTest * FastMath.abs(kep.getRightAscensionOfAscendingNode())); + kep.getRightAscensionOfAscendingNode(), + Utils.epsilonTest * FastMath.abs(kep.getRightAscensionOfAscendingNode())); Assertions.assertEquals(MathUtils.normalizeAngle(3.65750858649982, kep.getMeanAnomaly()), - kep.getMeanAnomaly(), - Utils.epsilonTest * FastMath.abs(kep.getMeanAnomaly())); + kep.getMeanAnomaly(), + Utils.epsilonTest * FastMath.abs(kep.getMeanAnomaly())); } @@ -192,7 +192,7 @@ void testCircularToKeplerian() { void testHyperbolic1() { try { new CircularOrbit(42166712.0, 0.9, 0.5, 0.01, -0.02, 5.300, - PositionAngleType.MEAN, FramesFactory.getEME2000(), date, mu); + PositionAngleType.MEAN, FramesFactory.getEME2000(), date, mu); } catch (OrekitIllegalArgumentException oe) { Assertions.assertEquals(OrekitMessages.HYPERBOLIC_ORBIT_NOT_HANDLED_AS, oe.getSpecifier()); } @@ -201,7 +201,7 @@ void testHyperbolic1() { @Test void testHyperbolic2() { Orbit orbit = new KeplerianOrbit(42166712.0, 0.9, 0.5, 0.01, -0.02, 5.300, - PositionAngleType.MEAN, FramesFactory.getEME2000(), date, mu); + PositionAngleType.MEAN, FramesFactory.getEME2000(), date, mu); try { new CircularOrbit(orbit.getPVCoordinates(), orbit.getFrame(), orbit.getMu()); } catch (OrekitIllegalArgumentException oe) { @@ -232,29 +232,29 @@ void testAnomalyEll() { double lM = lE - e * FastMath.sin(lE - paPraan); p = new CircularOrbit(p.getA() , p.getCircularEx(), p.getCircularEy(), - p.getRightAscensionOfAscendingNode(), - p.getAlphaV(), lv - raan, PositionAngleType.TRUE, p.getFrame(), date, mu); + p.getRightAscensionOfAscendingNode(), + p.getAlphaV(), lv - raan, PositionAngleType.TRUE, p.getFrame(), date, mu); Assertions.assertEquals(p.getAlphaV() + raan, lv, Utils.epsilonAngle * FastMath.abs(lv)); Assertions.assertEquals(p.getAlphaE() + raan, lE, Utils.epsilonAngle * FastMath.abs(lE)); Assertions.assertEquals(p.getAlphaM() + raan, lM, Utils.epsilonAngle * FastMath.abs(lM)); p = new CircularOrbit(p.getA() , p.getCircularEx(), p.getCircularEy(), - p.getRightAscensionOfAscendingNode(), - p.getAlphaV(), 0, PositionAngleType.TRUE, p.getFrame(), date, mu); + p.getRightAscensionOfAscendingNode(), + p.getAlphaV(), 0, PositionAngleType.TRUE, p.getFrame(), date, mu); p = new CircularOrbit(p.getA() , p.getCircularEx(), p.getCircularEy(), - p.getRightAscensionOfAscendingNode(), - p.getAlphaV(), lE - raan, PositionAngleType.ECCENTRIC, p.getFrame(), date, mu); + p.getRightAscensionOfAscendingNode(), + p.getAlphaV(), lE - raan, PositionAngleType.ECCENTRIC, p.getFrame(), date, mu); Assertions.assertEquals(p.getAlphaV() + raan, lv, Utils.epsilonAngle * FastMath.abs(lv)); Assertions.assertEquals(p.getAlphaE() + raan, lE, Utils.epsilonAngle * FastMath.abs(lE)); Assertions.assertEquals(p.getAlphaM() + raan, lM, Utils.epsilonAngle * FastMath.abs(lM)); p = new CircularOrbit(p.getA() , p.getCircularEx(), p.getCircularEy(), - p.getRightAscensionOfAscendingNode(), - p.getAlphaV(), 0, PositionAngleType.TRUE, p.getFrame(), date, mu); + p.getRightAscensionOfAscendingNode(), + p.getAlphaV(), 0, PositionAngleType.TRUE, p.getFrame(), date, mu); p = new CircularOrbit(p.getA() , p.getCircularEx(), p.getCircularEy(), - p.getRightAscensionOfAscendingNode(), - p.getAlphaV(), lM - raan, PositionAngleType.MEAN, p.getFrame(), date, mu); + p.getRightAscensionOfAscendingNode(), + p.getAlphaV(), lM - raan, PositionAngleType.MEAN, p.getFrame(), date, mu); Assertions.assertEquals(p.getAlphaV() + raan, lv, Utils.epsilonAngle * FastMath.abs(lv)); Assertions.assertEquals(p.getAlphaE() + raan, lE, Utils.epsilonAngle * FastMath.abs(lE)); Assertions.assertEquals(p.getAlphaM() + raan, lM, Utils.epsilonAngle * FastMath.abs(lM)); @@ -272,36 +272,36 @@ void testAnomalyCirc() { // circular orbit p = new CircularOrbit(p.getA() , 0, 0, p.getRightAscensionOfAscendingNode(), - p.getAlphaV(), p.getAlphaV(), PositionAngleType.TRUE, p.getFrame(), date, mu); + p.getAlphaV(), p.getAlphaV(), PositionAngleType.TRUE, p.getFrame(), date, mu); double lv = 1.1; double lE = lv; double lM = lE; p = new CircularOrbit(p.getA() , p.getCircularEx(), p.getCircularEy(), - p.getRightAscensionOfAscendingNode(), - p.getAlphaV(), lv - raan, PositionAngleType.TRUE, p.getFrame(), date, mu); + p.getRightAscensionOfAscendingNode(), + p.getAlphaV(), lv - raan, PositionAngleType.TRUE, p.getFrame(), date, mu); Assertions.assertEquals(p.getAlphaV() + raan, lv, Utils.epsilonAngle * FastMath.abs(lv)); Assertions.assertEquals(p.getAlphaE() + raan, lE, Utils.epsilonAngle * FastMath.abs(lE)); Assertions.assertEquals(p.getAlphaM() + raan, lM, Utils.epsilonAngle * FastMath.abs(lM)); p = new CircularOrbit(p.getA() , p.getCircularEx(), p.getCircularEy(), - p.getRightAscensionOfAscendingNode(), - p.getAlphaV(), 0, PositionAngleType.TRUE, p.getFrame(), date, mu); + p.getRightAscensionOfAscendingNode(), + p.getAlphaV(), 0, PositionAngleType.TRUE, p.getFrame(), date, mu); p = new CircularOrbit(p.getA() , p.getCircularEx(), p.getCircularEy(), - p.getRightAscensionOfAscendingNode(), - p.getAlphaV(), lE - raan, PositionAngleType.ECCENTRIC, p.getFrame(), date, mu); + p.getRightAscensionOfAscendingNode(), + p.getAlphaV(), lE - raan, PositionAngleType.ECCENTRIC, p.getFrame(), date, mu); Assertions.assertEquals(p.getAlphaV() + raan, lv, Utils.epsilonAngle * FastMath.abs(lv)); Assertions.assertEquals(p.getAlphaE() + raan, lE, Utils.epsilonAngle * FastMath.abs(lE)); Assertions.assertEquals(p.getAlphaM() + raan, lM, Utils.epsilonAngle * FastMath.abs(lM)); p = new CircularOrbit(p.getA() , p.getCircularEx(), p.getCircularEy(), - p.getRightAscensionOfAscendingNode(), - p.getAlphaV(), 0, PositionAngleType.TRUE, p.getFrame(), date, mu); + p.getRightAscensionOfAscendingNode(), + p.getAlphaV(), 0, PositionAngleType.TRUE, p.getFrame(), date, mu); p = new CircularOrbit(p.getA() , p.getCircularEx(), p.getCircularEy(), - p.getRightAscensionOfAscendingNode(), - p.getAlphaV(), lM - raan, PositionAngleType.MEAN, p.getFrame(), date, mu); + p.getRightAscensionOfAscendingNode(), + p.getAlphaV(), lM - raan, PositionAngleType.MEAN, p.getFrame(), date, mu); Assertions.assertEquals(p.getAlphaV() + raan, lv, Utils.epsilonAngle * FastMath.abs(lv)); Assertions.assertEquals(p.getAlphaE() + raan, lE, Utils.epsilonAngle * FastMath.abs(lE)); Assertions.assertEquals(p.getAlphaM() + raan, lM, Utils.epsilonAngle * FastMath.abs(lM)); @@ -317,9 +317,9 @@ void testPositionVelocityNormsEll() { double i = 2 * FastMath.atan(FastMath.sqrt(hx * hx + hy * hy)); double raan = FastMath.atan2(hy, hx); CircularOrbit p = - new CircularOrbit(42166712.0, 0.5, -0.5, i, raan, - 0.67 - raan, PositionAngleType.TRUE, - FramesFactory.getEME2000(), date, mu); + new CircularOrbit(42166712.0, 0.5, -0.5, i, raan, + 0.67 - raan, PositionAngleType.TRUE, + FramesFactory.getEME2000(), date, mu); double ex = p.getEquinoctialEx(); double ey = p.getEquinoctialEy(); @@ -332,11 +332,11 @@ void testPositionVelocityNormsEll() { double na = FastMath.sqrt(mu / a); Assertions.assertEquals(a * epsilon * epsilon / ksi, - p.getPosition().getNorm(), - Utils.epsilonTest * FastMath.abs(p.getPosition().getNorm())); + p.getPosition().getNorm(), + Utils.epsilonTest * FastMath.abs(p.getPosition().getNorm())); Assertions.assertEquals(na * FastMath.sqrt(ksi * ksi + nu * nu) / epsilon, - p.getPVCoordinates().getVelocity().getNorm(), - Utils.epsilonTest * FastMath.abs(p.getPVCoordinates().getVelocity().getNorm())); + p.getPVCoordinates().getVelocity().getNorm(), + Utils.epsilonTest * FastMath.abs(p.getPVCoordinates().getVelocity().getNorm())); } @@ -345,10 +345,10 @@ void testNumericalIssue25() { Vector3D position = new Vector3D(3782116.14107698, 416663.11924914, 5875541.62103057); Vector3D velocity = new Vector3D(-6349.7848910501, 288.4061811651, 4066.9366759691); CircularOrbit orbit = new CircularOrbit(new PVCoordinates(position, velocity), - FramesFactory.getEME2000(), - new AbsoluteDate("2004-01-01T23:00:00.000", - TimeScalesFactory.getUTC()), - 3.986004415E14); + FramesFactory.getEME2000(), + new AbsoluteDate("2004-01-01T23:00:00.000", + TimeScalesFactory.getUTC()), + 3.986004415E14); Assertions.assertEquals(0.0, orbit.getE(), 2.0e-14); } @@ -357,10 +357,10 @@ void testPerfectlyEquatorial() { Vector3D position = new Vector3D(-7293947.695148368, 5122184.668436634, 0.0); Vector3D velocity = new Vector3D(-3890.4029433398, -5369.811285264604, 0.0); CircularOrbit orbit = new CircularOrbit(new PVCoordinates(position, velocity), - FramesFactory.getEME2000(), - new AbsoluteDate("2004-01-01T23:00:00.000", - TimeScalesFactory.getUTC()), - 3.986004415E14); + FramesFactory.getEME2000(), + new AbsoluteDate("2004-01-01T23:00:00.000", + TimeScalesFactory.getUTC()), + 3.986004415E14); Assertions.assertEquals(0.0, orbit.getI(), 2.0e-14); Assertions.assertEquals(0.0, orbit.getRightAscensionOfAscendingNode(), 2.0e-14); } @@ -374,9 +374,9 @@ void testPositionVelocityNormsCirc() { double i = 2 * FastMath.atan(FastMath.sqrt(hx * hx + hy * hy)); double raan = FastMath.atan2(hy, hx); CircularOrbit pCirEqua = - new CircularOrbit(42166712.0, 0.1e-8, 0.1e-8, i, raan, - 0.67 - raan, PositionAngleType.TRUE, - FramesFactory.getEME2000(), date, mu); + new CircularOrbit(42166712.0, 0.1e-8, 0.1e-8, i, raan, + 0.67 - raan, PositionAngleType.TRUE, + FramesFactory.getEME2000(), date, mu); double ex = pCirEqua.getEquinoctialEx(); double ey = pCirEqua.getEquinoctialEy(); @@ -389,11 +389,11 @@ void testPositionVelocityNormsCirc() { double na = FastMath.sqrt(mu / a); Assertions.assertEquals(a * epsilon * epsilon / ksi, - pCirEqua.getPosition().getNorm(), - Utils.epsilonTest * FastMath.abs(pCirEqua.getPosition().getNorm())); + pCirEqua.getPosition().getNorm(), + Utils.epsilonTest * FastMath.abs(pCirEqua.getPosition().getNorm())); Assertions.assertEquals(na * FastMath.sqrt(ksi * ksi + nu * nu) / epsilon, - pCirEqua.getPVCoordinates().getVelocity().getNorm(), - Utils.epsilonTest * FastMath.abs(pCirEqua.getPVCoordinates().getVelocity().getNorm())); + pCirEqua.getPVCoordinates().getVelocity().getNorm(), + Utils.epsilonTest * FastMath.abs(pCirEqua.getPVCoordinates().getVelocity().getNorm())); } @Test @@ -405,9 +405,9 @@ void testGeometryEll() { double i = 2 * FastMath.atan(FastMath.sqrt(hx * hx + hy * hy)); double raan = FastMath.atan2(hy, hx); CircularOrbit p = - new CircularOrbit(42166712.0, 0.5, -0.5, i, raan, - 0.67 - raan, PositionAngleType.TRUE, - FramesFactory.getEME2000(), date, mu); + new CircularOrbit(42166712.0, 0.5, -0.5, i, raan, + 0.67 - raan, PositionAngleType.TRUE, + FramesFactory.getEME2000(), date, mu); Vector3D position = p.getPosition(); Vector3D velocity = p.getPVCoordinates().getVelocity(); @@ -418,8 +418,8 @@ void testGeometryEll() { for (double alphaV = 0; alphaV <= 2 * FastMath.PI; alphaV += 2 * FastMath.PI/100.) { p = new CircularOrbit(p.getA() , p.getCircularEx(), p.getCircularEy(), p.getI(), - p.getRightAscensionOfAscendingNode(), - alphaV, PositionAngleType.TRUE, p.getFrame(), date, mu); + p.getRightAscensionOfAscendingNode(), + alphaV, PositionAngleType.TRUE, p.getFrame(), date, mu); position = p.getPosition(); // test if the norm of the position is in the range [perigee radius, apogee radius] // Warning: these tests are without absolute value by choice @@ -449,9 +449,9 @@ void testGeometryCirc() { double i = 2 * FastMath.atan(FastMath.sqrt(hx * hx + hy * hy)); double raan = FastMath.atan2(hy, hx); CircularOrbit pCirEqua = - new CircularOrbit(42166712.0, 0.1e-8, 0.1e-8, i, raan, - 0.67 - raan, PositionAngleType.TRUE, - FramesFactory.getEME2000(), date, mu); + new CircularOrbit(42166712.0, 0.1e-8, 0.1e-8, i, raan, + 0.67 - raan, PositionAngleType.TRUE, + FramesFactory.getEME2000(), date, mu); Vector3D position = pCirEqua.getPosition(); Vector3D velocity = pCirEqua.getPVCoordinates().getVelocity(); @@ -464,8 +464,8 @@ void testGeometryCirc() { for (double alphaV = 0; alphaV <= 2 * FastMath.PI; alphaV += 2 * FastMath.PI/100.) { pCirEqua = new CircularOrbit(pCirEqua.getA() , pCirEqua.getCircularEx(), pCirEqua.getCircularEy(), pCirEqua.getI(), - pCirEqua.getRightAscensionOfAscendingNode(), - alphaV, PositionAngleType.TRUE, pCirEqua.getFrame(), date, mu); + pCirEqua.getRightAscensionOfAscendingNode(), + alphaV, PositionAngleType.TRUE, pCirEqua.getFrame(), date, mu); position = pCirEqua.getPosition(); // test if the norm pf the position is in the range [perigee radius, apogee radius] @@ -541,8 +541,8 @@ void testJacobianReference() { AbsoluteDate dateTca = new AbsoluteDate(2000, 04, 01, 0, 0, 0.000, TimeScalesFactory.getUTC()); double mu = 3.986004415e+14; CircularOrbit orbCir = new CircularOrbit(7000000.0, 0.01, -0.02, 1.2, 2.1, - 0.7, PositionAngleType.MEAN, - FramesFactory.getEME2000(), dateTca, mu); + 0.7, PositionAngleType.MEAN, + FramesFactory.getEME2000(), dateTca, mu); // the following reference values have been computed using the free software // version 6.2 of the MSLIB fortran library by the following program: @@ -591,12 +591,12 @@ void testJacobianReference() { Vector3D pRef = new Vector3D(-4106905.105389204807580, 3603162.539798960555345, 4439730.167038885876536); Vector3D vRef = new Vector3D(740.132407342422994, -5308.773280141396754, 5250.338353483879473); double[][] jRef = { - { -1.1535467596325562, 1.0120556393573172, 1.2470306024626943, 181.96913090864561, -1305.2162699469984, 1290.8494448855752 }, - { -5.07367368325471104E-008, -1.27870567070456834E-008, 1.31544531338558113E-007, -3.09332106417043592E-005, -9.60781276304445404E-005, 1.91506964883791605E-004 }, - { -6.59428471712402018E-008, 1.24561703203882533E-007, -1.41907027322388158E-008, 7.63442601186485441E-005, -1.77446722746170009E-004, 5.99464401287846734E-005 }, - { 7.55079920652274275E-008, 4.41606835295069131E-008, 3.40079310688458225E-008, 7.89724635377817962E-005, 4.61868720707717372E-005, 3.55682891687782599E-005 }, - { -9.20788748896973282E-008, -5.38521280004949642E-008, -4.14712660805579618E-008, 7.78626692360739821E-005, 4.55378113077967091E-005, 3.50684505810897702E-005 }, - { 1.85082436324531617E-008, 1.20506219457886855E-007, -8.31277842285972640E-008, 1.27364008345789645E-004, -1.54770720974742483E-004, -1.78589436862677754E-004 } + { -1.1535467596325562, 1.0120556393573172, 1.2470306024626943, 181.96913090864561, -1305.2162699469984, 1290.8494448855752 }, + { -5.07367368325471104E-008, -1.27870567070456834E-008, 1.31544531338558113E-007, -3.09332106417043592E-005, -9.60781276304445404E-005, 1.91506964883791605E-004 }, + { -6.59428471712402018E-008, 1.24561703203882533E-007, -1.41907027322388158E-008, 7.63442601186485441E-005, -1.77446722746170009E-004, 5.99464401287846734E-005 }, + { 7.55079920652274275E-008, 4.41606835295069131E-008, 3.40079310688458225E-008, 7.89724635377817962E-005, 4.61868720707717372E-005, 3.55682891687782599E-005 }, + { -9.20788748896973282E-008, -5.38521280004949642E-008, -4.14712660805579618E-008, 7.78626692360739821E-005, 4.55378113077967091E-005, 3.50684505810897702E-005 }, + { 1.85082436324531617E-008, 1.20506219457886855E-007, -8.31277842285972640E-008, 1.27364008345789645E-004, -1.54770720974742483E-004, -1.78589436862677754E-004 } }; PVCoordinates pv = orbCir.getPVCoordinates(); @@ -622,8 +622,8 @@ void testJacobianFinitedifferences() { AbsoluteDate dateTca = new AbsoluteDate(2000, 04, 01, 0, 0, 0.000, TimeScalesFactory.getUTC()); double mu = 3.986004415e+14; CircularOrbit orbCir = new CircularOrbit(7000000.0, 0.01, -0.02, 1.2, 2.1, - 0.7, PositionAngleType.MEAN, - FramesFactory.getEME2000(), dateTca, mu); + 0.7, PositionAngleType.MEAN, + FramesFactory.getEME2000(), dateTca, mu); for (PositionAngleType type : PositionAngleType.values()) { double hP = 2.0; @@ -642,27 +642,27 @@ void testJacobianFinitedifferences() { double[][] invJacobian = new double[6][6]; orbCir.getJacobianWrtParameters(type, invJacobian); MatrixUtils.createRealMatrix(jacobian). - multiply(MatrixUtils.createRealMatrix(invJacobian)). - walkInRowOrder(new RealMatrixPreservingVisitor() { - public void start(int rows, int columns, - int startRow, int endRow, int startColumn, int endColumn) { - } + multiply(MatrixUtils.createRealMatrix(invJacobian)). + walkInRowOrder(new RealMatrixPreservingVisitor() { + public void start(int rows, int columns, + int startRow, int endRow, int startColumn, int endColumn) { + } - public void visit(int row, int column, double value) { - Assertions.assertEquals(row == column ? 1.0 : 0.0, value, 4.0e-9); - } + public void visit(int row, int column, double value) { + Assertions.assertEquals(row == column ? 1.0 : 0.0, value, 4.0e-9); + } - public double end() { - return Double.NaN; - } - }); + public double end() { + return Double.NaN; + } + }); } } private double[][] finiteDifferencesJacobian(PositionAngleType type, CircularOrbit orbit, double hP) - { + { double[][] jacobian = new double[6][6]; for (int i = 0; i < 6; ++i) { fillColumn(type, i, orbit, hP, jacobian); @@ -682,79 +682,79 @@ private void fillColumn(PositionAngleType type, int i, CircularOrbit orbit, doub Vector3D dP = Vector3D.ZERO; Vector3D dV = Vector3D.ZERO; switch (i) { - case 0: - h = hP; - dP = new Vector3D(hP, 0, 0); - break; - case 1: - h = hP; - dP = new Vector3D(0, hP, 0); - break; - case 2: - h = hP; - dP = new Vector3D(0, 0, hP); - break; - case 3: - h = hV; - dV = new Vector3D(hV, 0, 0); - break; - case 4: - h = hV; - dV = new Vector3D(0, hV, 0); - break; - default: - h = hV; - dV = new Vector3D(0, 0, hV); - break; + case 0: + h = hP; + dP = new Vector3D(hP, 0, 0); + break; + case 1: + h = hP; + dP = new Vector3D(0, hP, 0); + break; + case 2: + h = hP; + dP = new Vector3D(0, 0, hP); + break; + case 3: + h = hV; + dV = new Vector3D(hV, 0, 0); + break; + case 4: + h = hV; + dV = new Vector3D(0, hV, 0); + break; + default: + h = hV; + dV = new Vector3D(0, 0, hV); + break; } CircularOrbit oM4h = new CircularOrbit(new PVCoordinates(new Vector3D(1, p, -4, dP), new Vector3D(1, v, -4, dV)), - orbit.getFrame(), orbit.getDate(), orbit.getMu()); + orbit.getFrame(), orbit.getDate(), orbit.getMu()); CircularOrbit oM3h = new CircularOrbit(new PVCoordinates(new Vector3D(1, p, -3, dP), new Vector3D(1, v, -3, dV)), - orbit.getFrame(), orbit.getDate(), orbit.getMu()); + orbit.getFrame(), orbit.getDate(), orbit.getMu()); CircularOrbit oM2h = new CircularOrbit(new PVCoordinates(new Vector3D(1, p, -2, dP), new Vector3D(1, v, -2, dV)), - orbit.getFrame(), orbit.getDate(), orbit.getMu()); + orbit.getFrame(), orbit.getDate(), orbit.getMu()); CircularOrbit oM1h = new CircularOrbit(new PVCoordinates(new Vector3D(1, p, -1, dP), new Vector3D(1, v, -1, dV)), - orbit.getFrame(), orbit.getDate(), orbit.getMu()); + orbit.getFrame(), orbit.getDate(), orbit.getMu()); CircularOrbit oP1h = new CircularOrbit(new PVCoordinates(new Vector3D(1, p, +1, dP), new Vector3D(1, v, +1, dV)), - orbit.getFrame(), orbit.getDate(), orbit.getMu()); + orbit.getFrame(), orbit.getDate(), orbit.getMu()); CircularOrbit oP2h = new CircularOrbit(new PVCoordinates(new Vector3D(1, p, +2, dP), new Vector3D(1, v, +2, dV)), - orbit.getFrame(), orbit.getDate(), orbit.getMu()); + orbit.getFrame(), orbit.getDate(), orbit.getMu()); CircularOrbit oP3h = new CircularOrbit(new PVCoordinates(new Vector3D(1, p, +3, dP), new Vector3D(1, v, +3, dV)), - orbit.getFrame(), orbit.getDate(), orbit.getMu()); + orbit.getFrame(), orbit.getDate(), orbit.getMu()); CircularOrbit oP4h = new CircularOrbit(new PVCoordinates(new Vector3D(1, p, +4, dP), new Vector3D(1, v, +4, dV)), - orbit.getFrame(), orbit.getDate(), orbit.getMu()); + orbit.getFrame(), orbit.getDate(), orbit.getMu()); jacobian[0][i] = (-3 * (oP4h.getA() - oM4h.getA()) + - 32 * (oP3h.getA() - oM3h.getA()) - - 168 * (oP2h.getA() - oM2h.getA()) + - 672 * (oP1h.getA() - oM1h.getA())) / (840 * h); + 32 * (oP3h.getA() - oM3h.getA()) - + 168 * (oP2h.getA() - oM2h.getA()) + + 672 * (oP1h.getA() - oM1h.getA())) / (840 * h); jacobian[1][i] = (-3 * (oP4h.getCircularEx() - oM4h.getCircularEx()) + - 32 * (oP3h.getCircularEx() - oM3h.getCircularEx()) - - 168 * (oP2h.getCircularEx() - oM2h.getCircularEx()) + - 672 * (oP1h.getCircularEx() - oM1h.getCircularEx())) / (840 * h); + 32 * (oP3h.getCircularEx() - oM3h.getCircularEx()) - + 168 * (oP2h.getCircularEx() - oM2h.getCircularEx()) + + 672 * (oP1h.getCircularEx() - oM1h.getCircularEx())) / (840 * h); jacobian[2][i] = (-3 * (oP4h.getCircularEy() - oM4h.getCircularEy()) + - 32 * (oP3h.getCircularEy() - oM3h.getCircularEy()) - - 168 * (oP2h.getCircularEy() - oM2h.getCircularEy()) + - 672 * (oP1h.getCircularEy() - oM1h.getCircularEy())) / (840 * h); + 32 * (oP3h.getCircularEy() - oM3h.getCircularEy()) - + 168 * (oP2h.getCircularEy() - oM2h.getCircularEy()) + + 672 * (oP1h.getCircularEy() - oM1h.getCircularEy())) / (840 * h); jacobian[3][i] = (-3 * (oP4h.getI() - oM4h.getI()) + - 32 * (oP3h.getI() - oM3h.getI()) - - 168 * (oP2h.getI() - oM2h.getI()) + - 672 * (oP1h.getI() - oM1h.getI())) / (840 * h); + 32 * (oP3h.getI() - oM3h.getI()) - + 168 * (oP2h.getI() - oM2h.getI()) + + 672 * (oP1h.getI() - oM1h.getI())) / (840 * h); jacobian[4][i] = (-3 * (oP4h.getRightAscensionOfAscendingNode() - oM4h.getRightAscensionOfAscendingNode()) + - 32 * (oP3h.getRightAscensionOfAscendingNode() - oM3h.getRightAscensionOfAscendingNode()) - - 168 * (oP2h.getRightAscensionOfAscendingNode() - oM2h.getRightAscensionOfAscendingNode()) + - 672 * (oP1h.getRightAscensionOfAscendingNode() - oM1h.getRightAscensionOfAscendingNode())) / (840 * h); + 32 * (oP3h.getRightAscensionOfAscendingNode() - oM3h.getRightAscensionOfAscendingNode()) - + 168 * (oP2h.getRightAscensionOfAscendingNode() - oM2h.getRightAscensionOfAscendingNode()) + + 672 * (oP1h.getRightAscensionOfAscendingNode() - oM1h.getRightAscensionOfAscendingNode())) / (840 * h); jacobian[5][i] = (-3 * (oP4h.getAlpha(type) - oM4h.getAlpha(type)) + - 32 * (oP3h.getAlpha(type) - oM3h.getAlpha(type)) - - 168 * (oP2h.getAlpha(type) - oM2h.getAlpha(type)) + - 672 * (oP1h.getAlpha(type) - oM1h.getAlpha(type))) / (840 * h); + 32 * (oP3h.getAlpha(type) - oM3h.getAlpha(type)) - + 168 * (oP2h.getAlpha(type) - oM2h.getAlpha(type)) + + 672 * (oP1h.getAlpha(type) - oM1h.getAlpha(type))) / (840 * h); } @Test void testSerialization() - throws IOException, ClassNotFoundException { + throws IOException, ClassNotFoundException { Vector3D position = new Vector3D(-29536113.0, 30329259.0, -100125.0); Vector3D velocity = new Vector3D(-2194.0, -2141.0, -8.0); PVCoordinates pvCoordinates = new PVCoordinates( position, velocity); @@ -790,13 +790,13 @@ void testSerialization() @Test void testSerializationWithDerivatives() - throws IOException, ClassNotFoundException { + throws IOException, ClassNotFoundException { Vector3D position = new Vector3D(-29536113.0, 30329259.0, -100125.0); Vector3D velocity = new Vector3D(-2194.0, -2141.0, -8.0); double r2 = position.getNormSq(); double r = FastMath.sqrt(r2); Vector3D acceleration = new Vector3D(-mu / (r * r2), position, - 1, new Vector3D(-0.1, 0.2, 0.3)); + 1, new Vector3D(-0.1, 0.2, 0.3)); PVCoordinates pvCoordinates = new PVCoordinates( position, velocity, acceleration); CircularOrbit orbit = new CircularOrbit(pvCoordinates, FramesFactory.getEME2000(), date, mu); Assertions.assertEquals(42255170.003, orbit.getA(), 1.0e-3); @@ -810,46 +810,46 @@ void testSerializationWithDerivatives() ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); CircularOrbit deserialized = (CircularOrbit) ois.readObject(); - Assertions.assertEquals(orbit.getA(), deserialized.getA(), 1.0e-10); - Assertions.assertEquals(orbit.getCircularEx(), deserialized.getCircularEx(), 1.0e-10); - Assertions.assertEquals(orbit.getCircularEy(), deserialized.getCircularEy(), 1.0e-10); - Assertions.assertEquals(orbit.getI(), deserialized.getI(), 1.0e-10); - Assertions.assertEquals(orbit.getRightAscensionOfAscendingNode(), deserialized.getRightAscensionOfAscendingNode(), 1.0e-10); - Assertions.assertEquals(orbit.getAlphaV(), deserialized.getAlphaV(), 1.0e-10); - Assertions.assertEquals(orbit.getADot(), deserialized.getADot(), 1.0e-10); - Assertions.assertEquals(orbit.getCircularExDot(), deserialized.getCircularExDot(), 1.0e-10); - Assertions.assertEquals(orbit.getCircularEyDot(), deserialized.getCircularEyDot(), 1.0e-10); - Assertions.assertEquals(orbit.getIDot(), deserialized.getIDot(), 1.0e-10); - Assertions.assertEquals(orbit.getRightAscensionOfAscendingNodeDot(), deserialized.getRightAscensionOfAscendingNodeDot(), 1.0e-10); - Assertions.assertEquals(orbit.getAlphaVDot(), deserialized.getAlphaVDot(), 1.0e-10); + Assertions.assertEquals(orbit.getA(), deserialized.getA()); + Assertions.assertEquals(orbit.getCircularEx(), deserialized.getCircularEx()); + Assertions.assertEquals(orbit.getCircularEy(), deserialized.getCircularEy()); + Assertions.assertEquals(orbit.getI(), deserialized.getI()); + Assertions.assertEquals(orbit.getRightAscensionOfAscendingNode(), deserialized.getRightAscensionOfAscendingNode()); + Assertions.assertEquals(orbit.getAlphaV(), deserialized.getAlphaV()); + Assertions.assertEquals(orbit.getADot(), deserialized.getADot()); + Assertions.assertEquals(orbit.getCircularExDot(), deserialized.getCircularExDot()); + Assertions.assertEquals(orbit.getCircularEyDot(), deserialized.getCircularEyDot()); + Assertions.assertEquals(orbit.getIDot(), deserialized.getIDot()); + Assertions.assertEquals(orbit.getRightAscensionOfAscendingNodeDot(), deserialized.getRightAscensionOfAscendingNodeDot()); + Assertions.assertEquals(orbit.getAlphaVDot(), deserialized.getAlphaVDot()); Assertions.assertEquals(orbit.getDate(), deserialized.getDate()); - Assertions.assertEquals(orbit.getMu(), deserialized.getMu(), 1.0e-10); + Assertions.assertEquals(orbit.getMu(), deserialized.getMu()); Assertions.assertEquals(orbit.getFrame().getName(), deserialized.getFrame().getName()); } @Test void testSerializationNoPVWithDerivatives() - throws IOException, ClassNotFoundException { + throws IOException, ClassNotFoundException { Vector3D position = new Vector3D(-29536113.0, 30329259.0, -100125.0); Vector3D velocity = new Vector3D(-2194.0, -2141.0, -8.0); double r2 = position.getNormSq(); double r = FastMath.sqrt(r2); Vector3D acceleration = new Vector3D(-mu / (r * r2), position, - 1, new Vector3D(-0.1, 0.2, 0.3)); + 1, new Vector3D(-0.1, 0.2, 0.3)); PVCoordinates pvCoordinates = new PVCoordinates( position, velocity, acceleration); CircularOrbit original = new CircularOrbit(pvCoordinates, FramesFactory.getEME2000(), date, mu); // rebuild the same orbit, preserving derivatives but removing Cartesian coordinates // (to check one specific path in serialization.deserialization) CircularOrbit orbit = new CircularOrbit(original.getA(), original.getCircularEx(), original.getCircularEy(), - original.getI(), original.getRightAscensionOfAscendingNode(), - original.getAlphaV(), - original.getADot(), original.getCircularExDot(), original.getCircularEyDot(), - original.getIDot(), original.getRightAscensionOfAscendingNodeDot(), - original.getAlphaVDot(), - PositionAngleType.TRUE, original.getFrame(), - original.getDate(), original.getMu()); + original.getI(), original.getRightAscensionOfAscendingNode(), + original.getAlphaV(), + original.getADot(), original.getCircularExDot(), original.getCircularEyDot(), + original.getIDot(), original.getRightAscensionOfAscendingNodeDot(), + original.getAlphaVDot(), + PositionAngleType.TRUE, original.getFrame(), + original.getDate(), original.getMu()); Assertions.assertEquals(42255170.003, orbit.getA(), 1.0e-3); ByteArrayOutputStream bos = new ByteArrayOutputStream(); @@ -861,22 +861,60 @@ void testSerializationNoPVWithDerivatives() ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); CircularOrbit deserialized = (CircularOrbit) ois.readObject(); - Assertions.assertEquals(orbit.getA(), deserialized.getA(), 1.0e-10); - Assertions.assertEquals(orbit.getCircularEx(), deserialized.getCircularEx(), 1.0e-10); - Assertions.assertEquals(orbit.getCircularEy(), deserialized.getCircularEy(), 1.0e-10); - Assertions.assertEquals(orbit.getI(), deserialized.getI(), 1.0e-10); - Assertions.assertEquals(orbit.getRightAscensionOfAscendingNode(), deserialized.getRightAscensionOfAscendingNode(), 1.0e-10); - Assertions.assertEquals(orbit.getAlphaV(), deserialized.getAlphaV(), 1.0e-10); - Assertions.assertEquals(orbit.getADot(), deserialized.getADot(), 1.0e-10); - Assertions.assertEquals(orbit.getCircularExDot(), deserialized.getCircularExDot(), 1.0e-10); - Assertions.assertEquals(orbit.getCircularEyDot(), deserialized.getCircularEyDot(), 1.0e-10); - Assertions.assertEquals(orbit.getIDot(), deserialized.getIDot(), 1.0e-10); - Assertions.assertEquals(orbit.getRightAscensionOfAscendingNodeDot(), deserialized.getRightAscensionOfAscendingNodeDot(), 1.0e-10); - Assertions.assertEquals(orbit.getAlphaVDot(), deserialized.getAlphaVDot(), 1.0e-10); + compareOrbits(orbit, deserialized); + + } + + @Test + void testSerializationNoPVWithoutDerivatives() + throws IOException, ClassNotFoundException { + Vector3D position = new Vector3D(-29536113.0, 30329259.0, -100125.0); + Vector3D velocity = new Vector3D(-2194.0, -2141.0, -8.0); + double r2 = position.getNormSq(); + double r = FastMath.sqrt(r2); + Vector3D acceleration = new Vector3D(-mu / (r * r2), position, + 1, new Vector3D(-0.1, 0.2, 0.3)); + PVCoordinates pvCoordinates = new PVCoordinates( position, velocity, acceleration); + CircularOrbit original = new CircularOrbit(pvCoordinates, FramesFactory.getEME2000(), date, mu); + + // rebuild the same orbit, preserving derivatives but removing Cartesian coordinates + // (to check one specific path in serialization.deserialization) + CircularOrbit orbit = new CircularOrbit(original.getA(), original.getCircularEx(), original.getCircularEy(), + original.getI(), original.getRightAscensionOfAscendingNode(), + original.getAlphaV(), + PositionAngleType.TRUE, original.getFrame(), + original.getDate(), original.getMu()); + Assertions.assertEquals(42255170.003, orbit.getA(), 1.0e-3); + + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(bos); + oos.writeObject(orbit); + + Assertions.assertEquals(bos.size(), 455); + + ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); + ObjectInputStream ois = new ObjectInputStream(bis); + CircularOrbit deserialized = (CircularOrbit) ois.readObject(); + compareOrbits(orbit, deserialized); + + } + + private void compareOrbits(final CircularOrbit orbit, final CircularOrbit deserialized) { + Assertions.assertEquals(orbit.getA(), deserialized.getA()); + Assertions.assertEquals(orbit.getCircularEx(), deserialized.getCircularEx()); + Assertions.assertEquals(orbit.getCircularEy(), deserialized.getCircularEy()); + Assertions.assertEquals(orbit.getI(), deserialized.getI()); + Assertions.assertEquals(orbit.getRightAscensionOfAscendingNode(), deserialized.getRightAscensionOfAscendingNode()); + Assertions.assertEquals(orbit.getAlphaV(), deserialized.getAlphaV()); + Assertions.assertEquals(orbit.getADot(), deserialized.getADot()); + Assertions.assertEquals(orbit.getCircularExDot(), deserialized.getCircularExDot()); + Assertions.assertEquals(orbit.getCircularEyDot(), deserialized.getCircularEyDot()); + Assertions.assertEquals(orbit.getIDot(), deserialized.getIDot()); + Assertions.assertEquals(orbit.getRightAscensionOfAscendingNodeDot(), deserialized.getRightAscensionOfAscendingNodeDot()); + Assertions.assertEquals(orbit.getAlphaVDot(), deserialized.getAlphaVDot()); Assertions.assertEquals(orbit.getDate(), deserialized.getDate()); - Assertions.assertEquals(orbit.getMu(), deserialized.getMu(), 1.0e-10); + Assertions.assertEquals(orbit.getMu(), deserialized.getMu()); Assertions.assertEquals(orbit.getFrame().getName(), deserialized.getFrame().getName()); - } @Test @@ -891,59 +929,59 @@ void testNonKeplerianDerivatives() { final CircularOrbit orbit = new CircularOrbit(pv, frame, mu); Assertions.assertEquals(differentiate(pv, frame, mu, shifted -> shifted.getA()), - orbit.getADot(), - 4.3e-8); + orbit.getADot(), + 4.3e-8); Assertions.assertEquals(differentiate(pv, frame, mu, shifted -> shifted.getEquinoctialEx()), - orbit.getEquinoctialExDot(), - 2.1e-15); + orbit.getEquinoctialExDot(), + 2.1e-15); Assertions.assertEquals(differentiate(pv, frame, mu, shifted -> shifted.getEquinoctialEy()), - orbit.getEquinoctialEyDot(), - 5.4e-16); + orbit.getEquinoctialEyDot(), + 5.4e-16); Assertions.assertEquals(differentiate(pv, frame, mu, shifted -> shifted.getHx()), - orbit.getHxDot(), - 1.6e-15); + orbit.getHxDot(), + 1.6e-15); Assertions.assertEquals(differentiate(pv, frame, mu, shifted -> shifted.getHy()), - orbit.getHyDot(), - 7.3e-17); + orbit.getHyDot(), + 7.3e-17); Assertions.assertEquals(differentiate(pv, frame, mu, shifted -> shifted.getLv()), - orbit.getLvDot(), - 3.4e-16); + orbit.getLvDot(), + 3.4e-16); Assertions.assertEquals(differentiate(pv, frame, mu, shifted -> shifted.getLE()), - orbit.getLEDot(), - 3.5e-15); + orbit.getLEDot(), + 3.5e-15); Assertions.assertEquals(differentiate(pv, frame, mu, shifted -> shifted.getLM()), - orbit.getLMDot(), - 5.3e-15); + orbit.getLMDot(), + 5.3e-15); Assertions.assertEquals(differentiate(pv, frame, mu, shifted -> shifted.getE()), - orbit.getEDot(), - 6.8e-16); + orbit.getEDot(), + 6.8e-16); Assertions.assertEquals(differentiate(pv, frame, mu, shifted -> shifted.getI()), - orbit.getIDot(), - 5.7e-16); + orbit.getIDot(), + 5.7e-16); Assertions.assertEquals(differentiate(pv, frame, mu, shifted -> shifted.getCircularEx()), - orbit.getCircularExDot(), - 2.2e-15); + orbit.getCircularExDot(), + 2.2e-15); Assertions.assertEquals(differentiate(pv, frame, mu, shifted -> shifted.getCircularEy()), - orbit.getCircularEyDot(), - 5.3e-17); + orbit.getCircularEyDot(), + 5.3e-17); Assertions.assertEquals(differentiate(pv, frame, mu, shifted -> shifted.getAlphaV()), - orbit.getAlphaVDot(), - 4.3e-15); + orbit.getAlphaVDot(), + 4.3e-15); Assertions.assertEquals(differentiate(pv, frame, mu, shifted -> shifted.getAlphaE()), - orbit.getAlphaEDot(), - 1.2e-15); + orbit.getAlphaEDot(), + 1.2e-15); Assertions.assertEquals(differentiate(pv, frame, mu, shifted -> shifted.getAlphaM()), - orbit.getAlphaMDot(), - 3.7e-15); + orbit.getAlphaMDot(), + 3.7e-15); Assertions.assertEquals(differentiate(pv, frame, mu, shifted -> shifted.getAlpha(PositionAngleType.TRUE)), - orbit.getAlphaDot(PositionAngleType.TRUE), - 4.3e-15); + orbit.getAlphaDot(PositionAngleType.TRUE), + 4.3e-15); Assertions.assertEquals(differentiate(pv, frame, mu, shifted -> shifted.getAlpha(PositionAngleType.ECCENTRIC)), - orbit.getAlphaDot(PositionAngleType.ECCENTRIC), - 1.2e-15); + orbit.getAlphaDot(PositionAngleType.ECCENTRIC), + 1.2e-15); Assertions.assertEquals(differentiate(pv, frame, mu, shifted -> shifted.getAlpha(PositionAngleType.MEAN)), - orbit.getAlphaDot(PositionAngleType.MEAN), - 3.7e-15); + orbit.getAlphaDot(PositionAngleType.MEAN), + 3.7e-15); } @@ -957,7 +995,7 @@ public double value(double dt) { } }); return diff.value(factory.variable(0, 0.0)).getPartialDerivative(1); - } + } @Test void testPositionAngleDerivatives() { @@ -972,18 +1010,18 @@ void testPositionAngleDerivatives() { for (PositionAngleType type : PositionAngleType.values()) { final CircularOrbit rebuilt = new CircularOrbit(orbit.getA(), - orbit.getCircularEx(), - orbit.getCircularEy(), - orbit.getI(), - orbit.getRightAscensionOfAscendingNode(), - orbit.getAlpha(type), - orbit.getADot(), - orbit.getCircularExDot(), - orbit.getCircularEyDot(), - orbit.getIDot(), - orbit.getRightAscensionOfAscendingNodeDot(), - orbit.getAlphaDot(type), - type, orbit.getFrame(), orbit.getDate(), orbit.getMu()); + orbit.getCircularEx(), + orbit.getCircularEy(), + orbit.getI(), + orbit.getRightAscensionOfAscendingNode(), + orbit.getAlpha(type), + orbit.getADot(), + orbit.getCircularExDot(), + orbit.getCircularEyDot(), + orbit.getIDot(), + orbit.getRightAscensionOfAscendingNodeDot(), + orbit.getAlphaDot(type), + type, orbit.getFrame(), orbit.getDate(), orbit.getMu()); MatcherAssert.assertThat(rebuilt.getA(), relativelyCloseTo(orbit.getA(), 1)); MatcherAssert.assertThat(rebuilt.getCircularEx(), relativelyCloseTo(orbit.getCircularEx(), 1)); MatcherAssert.assertThat(rebuilt.getCircularEy(), relativelyCloseTo(orbit.getCircularEy(), 1)); @@ -1011,7 +1049,7 @@ void testEquatorialRetrograde() { double r2 = position.getNormSq(); double r = FastMath.sqrt(r2); Vector3D acceleration = new Vector3D(-mu / (r * r2), position, - 1, new Vector3D(-0.1, 0.2, 0.3)); + 1, new Vector3D(-0.1, 0.2, 0.3)); PVCoordinates pvCoordinates = new PVCoordinates(position, velocity, acceleration); CircularOrbit orbit = new CircularOrbit(pvCoordinates, FramesFactory.getEME2000(), date, mu); Assertions.assertEquals(10637829.465, orbit.getA(), 1.0e-3); @@ -1034,7 +1072,7 @@ void testDerivativesConversionSymmetry() { Vector3D acceleration = new Vector3D(-7.460341170581685, -2.0415957334584527, 0.6393322823627762); PVCoordinates pvCoordinates = new PVCoordinates( position, velocity, acceleration); CircularOrbit orbit = new CircularOrbit(pvCoordinates, FramesFactory.getEME2000(), - date, Constants.EIGEN5C_EARTH_MU); + date, Constants.EIGEN5C_EARTH_MU); Assertions.assertTrue(orbit.hasDerivatives()); double r2 = position.getNormSq(); double r = FastMath.sqrt(r2); @@ -1063,7 +1101,7 @@ void testToString() { PVCoordinates pvCoordinates = new PVCoordinates(position, velocity); CircularOrbit orbit = new CircularOrbit(pvCoordinates, FramesFactory.getEME2000(), date, mu); Assertions.assertEquals("circular parameters: {a: 4.225517000282565E7, ex: 0.002082917137146049, ey: 5.173980074371024E-4, i: 0.20189257051515358, raan: -87.91788415673473, alphaV: -137.84099636616548;}", - orbit.toString()); + orbit.toString()); } @Test @@ -1099,7 +1137,7 @@ void testCopyNonKeplerianAcceleration() { final Vector3D position = new Vector3D(42164140, 0, 0); // Build PVCoodrinates starting from its position and computing the corresponding circular velocity final PVCoordinates pv = new PVCoordinates(position, - new Vector3D(0, FastMath.sqrt(mu / position.getNorm()), 0)); + new Vector3D(0, FastMath.sqrt(mu / position.getNorm()), 0)); // Build a KeplerianOrbit in eme2000 final Orbit orbit = new CircularOrbit(pv, eme2000, date, mu); @@ -1111,26 +1149,26 @@ void testCopyNonKeplerianAcceleration() { final Orbit shiftedOrbitCopy = orbitCopy.shiftedBy(10); // This does not work Assertions.assertEquals(0.0, - Vector3D.distance(shiftedOrbit.getPosition(), - shiftedOrbitCopy.getPosition()), - 1.0e-10); + Vector3D.distance(shiftedOrbit.getPosition(), + shiftedOrbitCopy.getPosition()), + 1.0e-10); Assertions.assertEquals(0.0, - Vector3D.distance(shiftedOrbit.getPVCoordinates().getVelocity(), - shiftedOrbitCopy.getPVCoordinates().getVelocity()), - 1.0e-10); + Vector3D.distance(shiftedOrbit.getPVCoordinates().getVelocity(), + shiftedOrbitCopy.getPVCoordinates().getVelocity()), + 1.0e-10); } @Test void testNormalize() { CircularOrbit withoutDerivatives = - new CircularOrbit(42166712.0, 0.005, -0.025, 1.6, - 1.25, 0.4, PositionAngleType.MEAN, - FramesFactory.getEME2000(), date, mu); + new CircularOrbit(42166712.0, 0.005, -0.025, 1.6, + 1.25, 0.4, PositionAngleType.MEAN, + FramesFactory.getEME2000(), date, mu); CircularOrbit ref = - new CircularOrbit(24000000.0, -0.012, 0.01, 0.2, - -6.28, 6.28, PositionAngleType.MEAN, - FramesFactory.getEME2000(), date, mu); + new CircularOrbit(24000000.0, -0.012, 0.01, 0.2, + -6.28, 6.28, PositionAngleType.MEAN, + FramesFactory.getEME2000(), date, mu); CircularOrbit normalized1 = (CircularOrbit) OrbitType.CIRCULAR.normalize(withoutDerivatives, ref); Assertions.assertFalse(normalized1.hasDerivatives()); @@ -1150,11 +1188,11 @@ void testNormalize() { double[] p = new double[6]; OrbitType.CIRCULAR.mapOrbitToArray(withoutDerivatives, PositionAngleType.TRUE, p, null); CircularOrbit withDerivatives = (CircularOrbit) OrbitType.CIRCULAR.mapArrayToOrbit(p, - new double[] { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0 }, - PositionAngleType.TRUE, - withoutDerivatives.getDate(), - withoutDerivatives.getMu(), - withoutDerivatives.getFrame()); + new double[] { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0 }, + PositionAngleType.TRUE, + withoutDerivatives.getDate(), + withoutDerivatives.getMu(), + withoutDerivatives.getFrame()); CircularOrbit normalized2 = (CircularOrbit) OrbitType.CIRCULAR.normalize(withDerivatives, ref); Assertions.assertTrue(normalized2.hasDerivatives()); Assertions.assertEquals(0.0, normalized2.getA() - withDerivatives.getA(), 1.0e-6); From 1a64be5558962d737a6a3eeb293cdcace535305a Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Wed, 28 Feb 2024 13:25:34 +0100 Subject: [PATCH 163/359] Improved clock models, with proper derivatives. --- .../measurements/ObservableSatellite.java | 55 +----- .../measurements/QuadraticClockModel.java | 149 +++++++++++++++++ .../QuadraticFieldClockModel.java | 42 +---- .../gnss/AbstractOnBoardMeasurement.java | 5 +- .../gnss/AbstractOneWayGNSSMeasurement.java | 12 +- .../gnss/InterSatellitesMeasurement.java | 7 +- .../measurements/gnss/OneWayGNSSPhase.java | 2 +- .../measurements/gnss/OneWayGNSSRange.java | 2 +- src/main/java/org/orekit/gnss/ClockModel.java | 41 ----- .../org/orekit/gnss/ConstantClockModel.java | 51 ------ .../orekit/gnss/ConstantFieldClockModel.java | 53 ------ .../java/org/orekit/gnss/FieldClockModel.java | 44 ----- .../org/orekit/gnss/QuadraticClockModel.java | 97 ----------- .../measurements/QuadraticClockModelTest.java | 156 ++++++++++++++++++ .../QuadraticFieldClockModelTest.java | 20 +-- .../orekit/gnss/ConstantClockModelTest.java | 57 ------- .../gnss/ConstantFieldClockModelTest.java | 56 ------- .../orekit/gnss/QuadraticClockModelTest.java | 69 -------- 18 files changed, 333 insertions(+), 585 deletions(-) create mode 100644 src/main/java/org/orekit/estimation/measurements/QuadraticClockModel.java rename src/main/java/org/orekit/{gnss => estimation/measurements}/QuadraticFieldClockModel.java (77%) delete mode 100644 src/main/java/org/orekit/gnss/ClockModel.java delete mode 100644 src/main/java/org/orekit/gnss/ConstantClockModel.java delete mode 100644 src/main/java/org/orekit/gnss/ConstantFieldClockModel.java delete mode 100644 src/main/java/org/orekit/gnss/FieldClockModel.java delete mode 100644 src/main/java/org/orekit/gnss/QuadraticClockModel.java create mode 100644 src/test/java/org/orekit/estimation/measurements/QuadraticClockModelTest.java rename src/test/java/org/orekit/{gnss => estimation/measurements}/QuadraticFieldClockModelTest.java (74%) delete mode 100644 src/test/java/org/orekit/gnss/ConstantClockModelTest.java delete mode 100644 src/test/java/org/orekit/gnss/ConstantFieldClockModelTest.java delete mode 100644 src/test/java/org/orekit/gnss/QuadraticClockModelTest.java diff --git a/src/main/java/org/orekit/estimation/measurements/ObservableSatellite.java b/src/main/java/org/orekit/estimation/measurements/ObservableSatellite.java index c83f1adcc8..c24d28a38b 100644 --- a/src/main/java/org/orekit/estimation/measurements/ObservableSatellite.java +++ b/src/main/java/org/orekit/estimation/measurements/ObservableSatellite.java @@ -16,16 +16,7 @@ */ package org.orekit.estimation.measurements; -import java.util.Map; - -import org.hipparchus.analysis.differentiation.Gradient; import org.hipparchus.util.FastMath; -import org.orekit.errors.OrekitException; -import org.orekit.errors.OrekitMessages; -import org.orekit.gnss.QuadraticClockModel; -import org.orekit.gnss.QuadraticFieldClockModel; -import org.orekit.time.AbsoluteDate; -import org.orekit.time.FieldAbsoluteDate; import org.orekit.utils.ParameterDriver; /** Class modeling a satellite that can be observed. @@ -123,51 +114,13 @@ public ParameterDriver getClockAccelerationDriver() { } /** Get a quadratic clock model valid at some date. - * @param date date at which the quadratic model should be valid * @return quadratic clock model * @since 12.1 */ - public QuadraticClockModel getQuadraticClockModel(final AbsoluteDate date) { - final double a0 = clockOffsetDriver.getValue(date); - final double a1 = clockDriftDriver.getValue(date); - final double a2 = clockAccelerationDriver.getValue(date); - AbsoluteDate referenceDate = clockOffsetDriver.getReferenceDate(); - if (referenceDate == null) { - if (a1 == 0 && a2 == 0) { - // it is OK to not have a reference date is clock offset is constant - referenceDate = date; - } else { - throw new OrekitException(OrekitMessages.NO_REFERENCE_DATE_FOR_PARAMETER, - clockOffsetDriver.getName()); - } - } - return new QuadraticClockModel(referenceDate, a0, a1, a2); - } - - /** Get a quadratic clock model valid at some date. - * @param freeParameters total number of free parameters in the gradient - * @param indices indices of the differentiation parameters in derivatives computations, - * must be span name and not driver name - * @param date date at which the quadratic model should be valid - * @return quadratic clock model - * @since 12.1 - */ - public QuadraticFieldClockModel getQuadraticClockModel(final int freeParameters, final Map indices, - final AbsoluteDate date) { - final Gradient a0 = clockOffsetDriver.getValue(freeParameters, indices, date); - final Gradient a1 = clockDriftDriver.getValue(freeParameters, indices, date); - final Gradient a2 = clockAccelerationDriver.getValue(freeParameters, indices, date); - AbsoluteDate referenceDate = clockOffsetDriver.getReferenceDate(); - if (referenceDate == null) { - if (a1.getReal() == 0 && a2.getReal() == 0) { - // it is OK to not have a reference date is clock offset is constant - referenceDate = date; - } else { - throw new OrekitException(OrekitMessages.NO_REFERENCE_DATE_FOR_PARAMETER, - clockOffsetDriver.getName()); - } - } - return new QuadraticFieldClockModel<>(new FieldAbsoluteDate<>(a0.getField(), referenceDate), a0, a1, a2); + public QuadraticClockModel getQuadraticClockModel() { + return new QuadraticClockModel(clockOffsetDriver, + clockDriftDriver, + clockAccelerationDriver); } /** {@inheritDoc} diff --git a/src/main/java/org/orekit/estimation/measurements/QuadraticClockModel.java b/src/main/java/org/orekit/estimation/measurements/QuadraticClockModel.java new file mode 100644 index 0000000000..71f1e6ccb7 --- /dev/null +++ b/src/main/java/org/orekit/estimation/measurements/QuadraticClockModel.java @@ -0,0 +1,149 @@ +/* Copyright 2002-2024 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.estimation.measurements; + +import org.hipparchus.analysis.differentiation.Gradient; +import org.hipparchus.util.FastMath; +import org.orekit.errors.OrekitException; +import org.orekit.errors.OrekitMessages; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; +import org.orekit.utils.ParameterDriver; + +import java.util.Map; + +/** Quadratic clock model. + * + * @author Luc Maisonobe + * @since 12.1 + * + */ +public class QuadraticClockModel { + + /** Clock offset scaling factor. + *

              + * We use a power of 2 to avoid numeric noise introduction + * in the multiplications/divisions sequences. + *

              + */ + private static final double CLOCK_OFFSET_SCALE = FastMath.scalb(1.0, -10); + + /** Constant term. */ + private final ParameterDriver a0; + + /** Linear term. */ + private final ParameterDriver a1; + + /** Quadratic term. */ + private final ParameterDriver a2; + + /** Simple constructor. + * @param referenceDate reference date + * @param a0 constant term + * @param a1 linear term + * @param a2 quadratic term + */ + public QuadraticClockModel(final AbsoluteDate referenceDate, + final double a0, final double a1, final double a2) { + this(new ParameterDriver("a0", + 0.0, CLOCK_OFFSET_SCALE, + Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY), + new ParameterDriver("a1", + 0.0, CLOCK_OFFSET_SCALE, + Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY), + new ParameterDriver("a2", + 0.0, CLOCK_OFFSET_SCALE, + Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY)); + this.a0.setValue(a0); + this.a0.setReferenceDate(referenceDate); + this.a1.setValue(a1); + this.a1.setReferenceDate(referenceDate); + this.a2.setValue(a2); + this.a2.setReferenceDate(referenceDate); + } + + /** Simple constructor. + * @param a0 constant term + * @param a1 linear term + * @param a2 quadratic term + */ + public QuadraticClockModel(final ParameterDriver a0, final ParameterDriver a1, final ParameterDriver a2) { + this.a0 = a0; + this.a1 = a1; + this.a2 = a2; + } + + /** Get the clock offset at date + * @param date date at which offset is requested + * @return clock offset at specified date + */ + public double getOffset(final AbsoluteDate date) { + final double dt = date.durationFrom(getSafeReference(date)); + return (a2.getValue(date) * dt + a1.getValue(date)) * dt + a0.getValue(date); + } + + /** Get the clock rate at date + * @param date date at which offset is requested + * @return clock rate at specified date + */ + public double getRate(final AbsoluteDate date) { + final double dt = date.durationFrom(getSafeReference(date)); + return 2 * a2.getValue(date) * dt + a1.getValue(date); + } + + /** Get a safe reference date. + *

              + * This method deals with parameters drivers for which no reference + * date has been set, which is acceptable if the model is not + * time-dependent. + *

              + * @param date date at which values are requested + * @return safe reference date + */ + private AbsoluteDate getSafeReference(final AbsoluteDate date) { + if (a0.getReferenceDate() == null) { + if (a1.getValue(date) == 0 && a2.getValue(date) == 0) { + // it is OK to not have a reference date is clock offset is constant + return date; + } else { + throw new OrekitException(OrekitMessages.NO_REFERENCE_DATE_FOR_PARAMETER, + a0.getName()); + } + } else { + return a0.getReferenceDate(); + } + } + + /** Convert to gradient model. + * @param freeParameters total number of free parameters in the gradient + * @param indices indices of the differentiation parameters in derivatives computations, + * must be span name and not driver name + * @param date date at which model must be valid + * @return converted clock model + */ + public QuadraticFieldClockModel toGradientModel(final int freeParameters, + final Map indices, + final AbsoluteDate date) { + final Gradient g0 = a0.getValue(freeParameters, indices, date); + final Gradient g1 = a1.getValue(freeParameters, indices, date); + final Gradient g2 = a2.getValue(freeParameters, indices, date); + final FieldAbsoluteDate referenceDate = + new FieldAbsoluteDate<>(g0.getField(), getSafeReference(date)); + return new QuadraticFieldClockModel<>(referenceDate, g0, g1, g2); + } + +} diff --git a/src/main/java/org/orekit/gnss/QuadraticFieldClockModel.java b/src/main/java/org/orekit/estimation/measurements/QuadraticFieldClockModel.java similarity index 77% rename from src/main/java/org/orekit/gnss/QuadraticFieldClockModel.java rename to src/main/java/org/orekit/estimation/measurements/QuadraticFieldClockModel.java index 14de025dc8..b4076240dc 100644 --- a/src/main/java/org/orekit/gnss/QuadraticFieldClockModel.java +++ b/src/main/java/org/orekit/estimation/measurements/QuadraticFieldClockModel.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.orekit.gnss; +package org.orekit.estimation.measurements; import org.hipparchus.CalculusFieldElement; import org.orekit.time.FieldAbsoluteDate; @@ -26,7 +26,7 @@ * @since 12.1 * */ -public class QuadraticFieldClockModel> implements FieldClockModel { +public class QuadraticFieldClockModel> { /** Clock model reference date. */ private final FieldAbsoluteDate referenceDate; @@ -54,43 +54,19 @@ public QuadraticFieldClockModel(final FieldAbsoluteDate referenceDate, this.a2 = a2; } - /** Get reference date. - * @return reference date + /** Get the clock offset at date + * @param date date at which offset is requested + * @return clock offset at specified date */ - public FieldAbsoluteDate getReferenceDate() { - return referenceDate; - } - - /** Get constant term. - * @return constant term - */ - public T getA0() { - return a0; - } - - /** Get linear term. - * @return linear term - */ - public T getA1() { - return a1; - } - - /** Get quadratic term. - * @return quadratic term - */ - public T getA2() { - return a2; - } - - /** {@inheritDoc} */ - @Override public T getOffset(final FieldAbsoluteDate date) { final T dt = date.durationFrom(referenceDate); return a2.multiply(dt).add(a1).multiply(dt).add(a0); } - /** {@inheritDoc} */ - @Override + /** Get the clock rate at date + * @param date date at which offset is requested + * @return clock rate at specified date + */ public T getRate(final FieldAbsoluteDate date) { final T dt = date.durationFrom(referenceDate); return a2.multiply(dt).multiply(2).add(a1); diff --git a/src/main/java/org/orekit/estimation/measurements/gnss/AbstractOnBoardMeasurement.java b/src/main/java/org/orekit/estimation/measurements/gnss/AbstractOnBoardMeasurement.java index 74d6da13a1..b5a517aa92 100644 --- a/src/main/java/org/orekit/estimation/measurements/gnss/AbstractOnBoardMeasurement.java +++ b/src/main/java/org/orekit/estimation/measurements/gnss/AbstractOnBoardMeasurement.java @@ -90,7 +90,8 @@ protected abstract FieldPVCoordinatesProvider getGradientRemotePV(Spac * must be span name and not driver name * @return emitting satellite clock provider */ - protected abstract Function, Gradient> getGradientRemoteClock(int freeParameters, Map indices); + protected abstract Function, Gradient> getGradientRemoteClock(int freeParameters, + Map indices); /** Compute common estimation parameters. * @param states states of all spacecraft involved in the measurement @@ -106,7 +107,7 @@ protected OnBoardCommonParametersWithoutDerivatives computeCommonParametersWitho final TimeStampedPVCoordinates pvaLocal = states[0].getPVCoordinates(); final double dtLocal = getSatellites(). get(0). - getQuadraticClockModel(getDate()). + getQuadraticClockModel(). getOffset(getDate()); final PVCoordinatesProvider remotePV = getDoubleRemotePV(states); final ToDoubleFunction remoteClock = getDoubleRemoteClock(); diff --git a/src/main/java/org/orekit/estimation/measurements/gnss/AbstractOneWayGNSSMeasurement.java b/src/main/java/org/orekit/estimation/measurements/gnss/AbstractOneWayGNSSMeasurement.java index d18d2aee78..328553495f 100644 --- a/src/main/java/org/orekit/estimation/measurements/gnss/AbstractOneWayGNSSMeasurement.java +++ b/src/main/java/org/orekit/estimation/measurements/gnss/AbstractOneWayGNSSMeasurement.java @@ -24,8 +24,7 @@ import org.hipparchus.analysis.differentiation.Gradient; import org.orekit.estimation.measurements.ObservableSatellite; import org.orekit.estimation.measurements.ObservedMeasurement; -import org.orekit.gnss.QuadraticClockModel; -import org.orekit.gnss.QuadraticFieldClockModel; +import org.orekit.estimation.measurements.QuadraticClockModel; import org.orekit.propagation.SpacecraftState; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; @@ -124,12 +123,9 @@ protected FieldPVCoordinatesProvider getGradientRemotePV(final Spacecr /** {@inheritDoc} */ @Override - protected Function, Gradient> getGradientRemoteClock(final int freeParameters, final Map indices) { - final Gradient a0 = Gradient.constant(freeParameters, remoteClock.getA0()); - final Gradient a1 = Gradient.constant(freeParameters, remoteClock.getA1()); - final Gradient a2 = Gradient.constant(freeParameters, remoteClock.getA2()); - final FieldAbsoluteDate referenceDate = new FieldAbsoluteDate<>(a0.getField(), remoteClock.getReferenceDate()); - return new QuadraticFieldClockModel<>(referenceDate, a0, a1, a2)::getOffset; + protected Function, Gradient> getGradientRemoteClock(final int freeParameters, + final Map indices) { + return remoteClock.toGradientModel(freeParameters, indices, getDate())::getOffset; } } diff --git a/src/main/java/org/orekit/estimation/measurements/gnss/InterSatellitesMeasurement.java b/src/main/java/org/orekit/estimation/measurements/gnss/InterSatellitesMeasurement.java index 288e8b1d43..03252ade7b 100644 --- a/src/main/java/org/orekit/estimation/measurements/gnss/InterSatellitesMeasurement.java +++ b/src/main/java/org/orekit/estimation/measurements/gnss/InterSatellitesMeasurement.java @@ -80,7 +80,7 @@ protected PVCoordinatesProvider getDoubleRemotePV(final SpacecraftState[] states /** {@inheritDoc} */ @Override protected ToDoubleFunction getDoubleRemoteClock() { - return getSatellites().get(1).getQuadraticClockModel(getDate())::getOffset; + return getSatellites().get(1).getQuadraticClockModel()::getOffset; } /** {@inheritDoc} */ @@ -108,7 +108,10 @@ protected FieldPVCoordinatesProvider getGradientRemotePV(final Spacecr @Override protected Function, Gradient> getGradientRemoteClock(final int freeParameters, final Map indices) { - return getSatellites().get(1).getQuadraticClockModel(freeParameters, indices, getDate())::getOffset; + return getSatellites(). + get(1). + getQuadraticClockModel(). + toGradientModel(freeParameters, indices, getDate())::getOffset; } } diff --git a/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSPhase.java b/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSPhase.java index febf0b2aa2..274d7bdb2e 100644 --- a/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSPhase.java +++ b/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSPhase.java @@ -22,7 +22,7 @@ import org.orekit.estimation.measurements.EstimatedMeasurement; import org.orekit.estimation.measurements.EstimatedMeasurementBase; import org.orekit.estimation.measurements.ObservableSatellite; -import org.orekit.gnss.QuadraticClockModel; +import org.orekit.estimation.measurements.QuadraticClockModel; import org.orekit.propagation.SpacecraftState; import org.orekit.time.AbsoluteDate; import org.orekit.utils.Constants; diff --git a/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRange.java b/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRange.java index 5ba3f92697..e07162789b 100644 --- a/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRange.java +++ b/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRange.java @@ -23,7 +23,7 @@ import org.orekit.estimation.measurements.EstimatedMeasurementBase; import org.orekit.estimation.measurements.InterSatellitesRange; import org.orekit.estimation.measurements.ObservableSatellite; -import org.orekit.gnss.QuadraticClockModel; +import org.orekit.estimation.measurements.QuadraticClockModel; import org.orekit.propagation.SpacecraftState; import org.orekit.time.AbsoluteDate; import org.orekit.utils.Constants; diff --git a/src/main/java/org/orekit/gnss/ClockModel.java b/src/main/java/org/orekit/gnss/ClockModel.java deleted file mode 100644 index 0dabe78d54..0000000000 --- a/src/main/java/org/orekit/gnss/ClockModel.java +++ /dev/null @@ -1,41 +0,0 @@ -/* Copyright 2002-2024 Thales Alenia Space - * Licensed to CS GROUP (CS) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * CS licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.orekit.gnss; - -import org.orekit.time.AbsoluteDate; - -/** Interface for deterministic smooth clock model. - * - * @author Luc Maisonobe - * @since 12.1 - * - */ -public interface ClockModel { - - /** Get the clock offset at date - * @param date date at which offset is requested - * @return clock offset at specified date - */ - public double getOffset(AbsoluteDate date); - - /** Get the clock rate at date - * @param date date at which offset is requested - * @return clock rate at specified date - */ - public double getRate(AbsoluteDate date); - -} diff --git a/src/main/java/org/orekit/gnss/ConstantClockModel.java b/src/main/java/org/orekit/gnss/ConstantClockModel.java deleted file mode 100644 index 43b363df04..0000000000 --- a/src/main/java/org/orekit/gnss/ConstantClockModel.java +++ /dev/null @@ -1,51 +0,0 @@ -/* Copyright 2002-2024 Thales Alenia Space - * Licensed to CS GROUP (CS) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * CS licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.orekit.gnss; - -import org.orekit.time.AbsoluteDate; - -/** Constant clock model. - * - * @author Luc Maisonobe - * @since 12.1 - * - */ -public class ConstantClockModel implements ClockModel { - - /** Constant offset. */ - private final double offset; - - /** Simple constructor. - * @param offset constant offset - */ - public ConstantClockModel(final double offset) { - this.offset = offset; - } - - /** {@inheritDoc} */ - @Override - public double getOffset(final AbsoluteDate date) { - return offset; - } - - /** {@inheritDoc} */ - @Override - public double getRate(final AbsoluteDate date) { - return 0.0; - } - -} diff --git a/src/main/java/org/orekit/gnss/ConstantFieldClockModel.java b/src/main/java/org/orekit/gnss/ConstantFieldClockModel.java deleted file mode 100644 index ab02066e78..0000000000 --- a/src/main/java/org/orekit/gnss/ConstantFieldClockModel.java +++ /dev/null @@ -1,53 +0,0 @@ -/* Copyright 2002-2024 Thales Alenia Space - * Licensed to CS GROUP (CS) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * CS licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.orekit.gnss; - -import org.hipparchus.CalculusFieldElement; -import org.orekit.time.FieldAbsoluteDate; - -/** Constant clock model. - * - * @param type of the field elements - * @author Luc Maisonobe - * @since 12.1 - * - */ -public class ConstantFieldClockModel> implements FieldClockModel { - - /** Constant offset. */ - private final T offset; - - /** Simple constructor. - * @param offset constant offset - */ - public ConstantFieldClockModel(final T offset) { - this.offset = offset; - } - - /** {@inheritDoc} */ - @Override - public T getOffset(final FieldAbsoluteDate date) { - return offset; - } - - /** {@inheritDoc} */ - @Override - public T getRate(final FieldAbsoluteDate date) { - return offset .getField().getZero(); - } - -} diff --git a/src/main/java/org/orekit/gnss/FieldClockModel.java b/src/main/java/org/orekit/gnss/FieldClockModel.java deleted file mode 100644 index 33801b0d29..0000000000 --- a/src/main/java/org/orekit/gnss/FieldClockModel.java +++ /dev/null @@ -1,44 +0,0 @@ -/* Copyright 2002-2024 Thales Alenia Space - * Licensed to CS GROUP (CS) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * CS licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.orekit.gnss; - -import org.hipparchus.CalculusFieldElement; -import org.orekit.time.FieldAbsoluteDate; - -/** Interface for deterministic smooth clock model. - * - * @param type of the field elements - * @author Luc Maisonobe - * @since 12.1 - * - */ -public interface FieldClockModel> { - - /** Get the clock offset at date - * @param date date at which offset is requested - * @return clock offset at specified date - */ - public T getOffset(FieldAbsoluteDate date); - - /** Get the clock rate at date - * @param type of the field elements - * @param date date at which offset is requested - * @return clock rate at specified date - */ - public T getRate(FieldAbsoluteDate date); - -} diff --git a/src/main/java/org/orekit/gnss/QuadraticClockModel.java b/src/main/java/org/orekit/gnss/QuadraticClockModel.java deleted file mode 100644 index c73a0764f3..0000000000 --- a/src/main/java/org/orekit/gnss/QuadraticClockModel.java +++ /dev/null @@ -1,97 +0,0 @@ -/* Copyright 2002-2024 Thales Alenia Space - * Licensed to CS GROUP (CS) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * CS licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.orekit.gnss; - -import org.orekit.time.AbsoluteDate; - -/** Quadratic clock model. - * - * @author Luc Maisonobe - * @since 12.1 - * - */ -public class QuadraticClockModel implements ClockModel { - - /** Clock model reference date. */ - private final AbsoluteDate referenceDate; - - /** Constant term. */ - private final double a0; - - /** Linear term. */ - private final double a1; - - /** Quadratic term. */ - private final double a2; - - /** Simple constructor. - * @param referenceDate reference date - * @param a0 constant term - * @param a1 linear term - * @param a2 quadratic term - */ - public QuadraticClockModel(final AbsoluteDate referenceDate, - final double a0, final double a1, final double a2) { - this.referenceDate = referenceDate; - this.a0 = a0; - this.a1 = a1; - this.a2 = a2; - } - - /** Get reference date. - * @return reference date - */ - public AbsoluteDate getReferenceDate() { - return referenceDate; - } - - /** Get constant term. - * @return constant term - */ - public double getA0() { - return a0; - } - - /** Get linear term. - * @return linear term - */ - public double getA1() { - return a1; - } - - /** Get quadratic term. - * @return quadratic term - */ - public double getA2() { - return a2; - } - - /** {@inheritDoc} */ - @Override - public double getOffset(final AbsoluteDate date) { - final double dt = date.durationFrom(referenceDate); - return (a2 * dt + a1) * dt + a0; - } - - /** {@inheritDoc} */ - @Override - public double getRate(final AbsoluteDate date) { - final double dt = date.durationFrom(referenceDate); - return 2 * a2 * dt + a1; - } - -} diff --git a/src/test/java/org/orekit/estimation/measurements/QuadraticClockModelTest.java b/src/test/java/org/orekit/estimation/measurements/QuadraticClockModelTest.java new file mode 100644 index 0000000000..c68a43fce0 --- /dev/null +++ b/src/test/java/org/orekit/estimation/measurements/QuadraticClockModelTest.java @@ -0,0 +1,156 @@ +/* Copyright 2002-2024 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.estimation.measurements; + +import org.hipparchus.analysis.differentiation.Gradient; +import org.hipparchus.analysis.differentiation.GradientField; +import org.hipparchus.util.FastMath; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.orekit.errors.OrekitException; +import org.orekit.errors.OrekitMessages; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FieldAbsoluteDate; +import org.orekit.utils.ParameterDriver; +import org.orekit.utils.TimeSpanMap.Span; + +import java.util.HashMap; +import java.util.Map; + +public class QuadraticClockModelTest { + + @Test + public void testValue() { + final AbsoluteDate t0 = AbsoluteDate.GALILEO_EPOCH; + final QuadraticClockModel clock = new QuadraticClockModel(t0, + FastMath.scalb(1.0, -8), + FastMath.scalb(1.0, -9), + FastMath.scalb(1.0, -10)); + Assertions.assertEquals(1.00 / 256.0, clock.getOffset(t0), 1.0e-15); + Assertions.assertEquals(1.75 / 256.0, clock.getOffset(t0.shiftedBy(1.0)), 1.0e-15); + Assertions.assertEquals(3.00 / 256.0, clock.getOffset(t0.shiftedBy(2.0)), 1.0e-15); + } + + @Test + public void testRate() { + final AbsoluteDate t0 = AbsoluteDate.GALILEO_EPOCH; + final QuadraticClockModel clock = new QuadraticClockModel(t0, + FastMath.scalb(1.0, -8), + FastMath.scalb(1.0, -9), + FastMath.scalb(1.0, -10)); + Assertions.assertEquals(1.00 / 512, clock.getRate(t0), 1.0e-15); + Assertions.assertEquals(2.00 / 512, clock.getRate(t0.shiftedBy(1.0)), 1.0e-15); + Assertions.assertEquals(3.00 / 512, clock.getRate(t0.shiftedBy(2.0)), 1.0e-15); + } + + @Test + public void testSafeReferenceDate() { + final ParameterDriver a0 = new ParameterDriver("a0", 0.0, 1.0, + Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY); + final ParameterDriver a1 = new ParameterDriver("a1", 0.0, 1.0, + Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY); + final ParameterDriver a2 = new ParameterDriver("a2", 0.0, 1.0, + Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY); + final QuadraticClockModel clock = new QuadraticClockModel(a0, a1, a2); + + // OK to have no reference date if a1 and a2 are both zero + a0.setValue(0.125); + Assertions.assertEquals(0.125, clock.getOffset(AbsoluteDate.GALILEO_EPOCH)); + + // not OK to have no reference date if a1 is non zero + a1.setValue(1.0); + try { + clock.getOffset(AbsoluteDate.GALILEO_EPOCH); + Assertions.fail("an exception should have been thrown"); + } catch (OrekitException oe) { + Assertions.assertEquals(OrekitMessages.NO_REFERENCE_DATE_FOR_PARAMETER, oe.getSpecifier()); + Assertions.assertEquals(a0.getName(), oe.getParts()[0]); + } + + // not OK to have no reference date if a2 is non zero + a1.setValue(0.0); + a2.setValue(1.0); + try { + clock.getOffset(AbsoluteDate.GALILEO_EPOCH); + Assertions.fail("an exception should have been thrown"); + } catch (OrekitException oe) { + Assertions.assertEquals(OrekitMessages.NO_REFERENCE_DATE_FOR_PARAMETER, oe.getSpecifier()); + Assertions.assertEquals(a0.getName(), oe.getParts()[0]); + } + + // back to OK if we reset drift and acceleration + a2.setValue(0); + Assertions.assertEquals(0.125, clock.getOffset(AbsoluteDate.GALILEO_EPOCH)); + + } + + @Test + public void testGradient() { + final AbsoluteDate t0 = AbsoluteDate.GALILEO_EPOCH; + final ParameterDriver a0 = new ParameterDriver("a0", 0.0, 1.0, + Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY); + final ParameterDriver a1 = new ParameterDriver("a1", 0.0, 1.0, + Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY); + final ParameterDriver a2 = new ParameterDriver("a2", 0.0, 1.0, + Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY); + final QuadraticClockModel clock = new QuadraticClockModel(a0, a1, a2); + + int nbParams = 0; + final Map indices = new HashMap<>(); + a0.setValue(FastMath.scalb(1.0, -8)); + a0.setReferenceDate(t0); + a0.setSelected(true); + for (Span span = a0.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) { + indices.put(span.getData(), nbParams++); + } + a1.setValue(FastMath.scalb(1.0, -9)); + a1.setReferenceDate(t0); + a1.setSelected(true); + for (Span span = a1.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) { + indices.put(span.getData(), nbParams++); + } + a2.setValue(FastMath.scalb(1.0, -10)); + a2.setReferenceDate(t0); + a2.setSelected(true); + for (Span span = a2.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) { + indices.put(span.getData(), nbParams++); + } + + QuadraticFieldClockModel gradientModel = clock.toGradientModel(nbParams, indices, t0); + final FieldAbsoluteDate t0g = new FieldAbsoluteDate<>(GradientField.getField(nbParams), t0); + + final Gradient g0 = gradientModel.getOffset(t0g); + Assertions.assertEquals(1.00 / 256, g0.getValue(), 1.0e-15); + Assertions.assertEquals(1.00, g0.getPartialDerivative(0), 1.0e-15); + Assertions.assertEquals(0.00, g0.getPartialDerivative(1), 1.0e-15); + Assertions.assertEquals(0.00, g0.getPartialDerivative(2), 1.0e-15); + + final Gradient g1 = gradientModel.getOffset(t0g.shiftedBy(1.0)); + Assertions.assertEquals(1.75 / 256, g1.getValue(), 1.0e-15); + Assertions.assertEquals(1.00, g1.getPartialDerivative(0), 1.0e-15); + Assertions.assertEquals(1.00, g1.getPartialDerivative(1), 1.0e-15); + Assertions.assertEquals(1.00, g1.getPartialDerivative(2), 1.0e-15); + + final Gradient g2 = gradientModel.getOffset(t0g.shiftedBy(2.0)); + Assertions.assertEquals(3.00 / 256, g2.getValue(), 1.0e-15); + Assertions.assertEquals(1.00, g2.getPartialDerivative(0), 1.0e-15); + Assertions.assertEquals(2.00, g2.getPartialDerivative(1), 1.0e-15); + Assertions.assertEquals(4.00, g2.getPartialDerivative(2), 1.0e-15); + + } + +} diff --git a/src/test/java/org/orekit/gnss/QuadraticFieldClockModelTest.java b/src/test/java/org/orekit/estimation/measurements/QuadraticFieldClockModelTest.java similarity index 74% rename from src/test/java/org/orekit/gnss/QuadraticFieldClockModelTest.java rename to src/test/java/org/orekit/estimation/measurements/QuadraticFieldClockModelTest.java index 015454c839..3c928cfa7d 100644 --- a/src/test/java/org/orekit/gnss/QuadraticFieldClockModelTest.java +++ b/src/test/java/org/orekit/estimation/measurements/QuadraticFieldClockModelTest.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.orekit.gnss; +package org.orekit.estimation.measurements; import org.hipparchus.CalculusFieldElement; import org.hipparchus.Field; @@ -38,11 +38,6 @@ public void testRateField() { doTestRateField(Binary64Field.getInstance()); } - @Test - public void testGetters() { - doTestGetters(Binary64Field.getInstance()); - } - private > void doTestValueField(final Field field) { final FieldAbsoluteDate t0 = new FieldAbsoluteDate<>(field, AbsoluteDate.GALILEO_EPOCH); final QuadraticFieldClockModel clock = @@ -67,17 +62,4 @@ private > void doTestRateField(final Field Assertions.assertEquals(3.00 / 512, clock.getRate(t0.shiftedBy(2.0)).getReal(), 1.0e-15); } - private > void doTestGetters(final Field field) { - final FieldAbsoluteDate t0 = new FieldAbsoluteDate<>(field, AbsoluteDate.GALILEO_EPOCH); - final QuadraticFieldClockModel clock = - new QuadraticFieldClockModel<>(t0, - field.getZero().newInstance(FastMath.scalb(1.0, -8)), - field.getZero().newInstance(FastMath.scalb(1.0, -9)), - field.getZero().newInstance(FastMath.scalb(1.0, -10))); - Assertions.assertEquals(0.0, clock.getReferenceDate().durationFrom(AbsoluteDate.GALILEO_EPOCH).getReal(), 1.0e-15); - Assertions.assertEquals(1.00 / 256, clock.getA0().getReal(), 1.0e-15); - Assertions.assertEquals(1.00 / 512, clock.getA1().getReal(), 1.0e-15); - Assertions.assertEquals(1.00 / 1024, clock.getA2().getReal(), 1.0e-15); - } - } diff --git a/src/test/java/org/orekit/gnss/ConstantClockModelTest.java b/src/test/java/org/orekit/gnss/ConstantClockModelTest.java deleted file mode 100644 index a0c5c51cb7..0000000000 --- a/src/test/java/org/orekit/gnss/ConstantClockModelTest.java +++ /dev/null @@ -1,57 +0,0 @@ -/* Copyright 2002-2024 Thales Alenia Space - * Licensed to CS GROUP (CS) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * CS licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.orekit.gnss; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.orekit.time.AbsoluteDate; - - -public class ConstantClockModelTest { - - @Test - public void testValue() { - Assertions.assertEquals(1.25, clock.getOffset(t0), 1.0e-15); - Assertions.assertEquals(1.25, clock.getOffset(t0.shiftedBy(1.0)), 1.0e-15); - Assertions.assertEquals(1.25, clock.getOffset(t0.shiftedBy(2.0)), 1.0e-15); - } - - @Test - public void testRate() { - Assertions.assertEquals(0.0, clock.getRate(t0), 1.0e-15); - Assertions.assertEquals(0.0, clock.getRate(t0.shiftedBy(1.0)), 1.0e-15); - Assertions.assertEquals(0.0, clock.getRate(t0.shiftedBy(2.0)), 1.0e-15); - } - - @BeforeEach - public void setUp() { - t0 = AbsoluteDate.GALILEO_EPOCH; - clock = new ConstantClockModel(1.25); - } - - @AfterEach - public void tearDown() { - t0 = null; - clock = null; - } - - private AbsoluteDate t0; - private ClockModel clock; - -} diff --git a/src/test/java/org/orekit/gnss/ConstantFieldClockModelTest.java b/src/test/java/org/orekit/gnss/ConstantFieldClockModelTest.java deleted file mode 100644 index f1efa02272..0000000000 --- a/src/test/java/org/orekit/gnss/ConstantFieldClockModelTest.java +++ /dev/null @@ -1,56 +0,0 @@ -/* Copyright 2002-2024 Thales Alenia Space - * Licensed to CS GROUP (CS) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * CS licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.orekit.gnss; - -import org.hipparchus.CalculusFieldElement; -import org.hipparchus.Field; -import org.hipparchus.util.Binary64Field; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.orekit.time.AbsoluteDate; -import org.orekit.time.FieldAbsoluteDate; - - -public class ConstantFieldClockModelTest { - - @Test - public void testValueField() { - doTestValueField(Binary64Field.getInstance()); - } - - @Test - public void testRateField() { - doTestRateField(Binary64Field.getInstance()); - } - - private > void doTestValueField(final Field field) { - final FieldClockModel clock = new ConstantFieldClockModel<>(field.getZero().newInstance(1.25)); - final FieldAbsoluteDate t0 = new FieldAbsoluteDate(field, AbsoluteDate.GALILEO_EPOCH); - Assertions.assertEquals(1.25, clock.getOffset(t0).getReal(), 1.0e-15); - Assertions.assertEquals(1.25, clock.getOffset(t0.shiftedBy(1.0)).getReal(), 1.0e-15); - Assertions.assertEquals(1.25, clock.getOffset(t0.shiftedBy(2.0)).getReal(), 1.0e-15); - } - - private > void doTestRateField(final Field field) { - final FieldClockModel clock = new ConstantFieldClockModel<>(field.getZero().newInstance(1.25)); - final FieldAbsoluteDate t0 = new FieldAbsoluteDate(field, AbsoluteDate.GALILEO_EPOCH); - Assertions.assertEquals(0.0, clock.getRate(t0).getReal(), 1.0e-15); - Assertions.assertEquals(0.0, clock.getRate(t0.shiftedBy(1.0)).getReal(), 1.0e-15); - Assertions.assertEquals(0.0, clock.getRate(t0.shiftedBy(1.0)).getReal(), 1.0e-15); - } - -} diff --git a/src/test/java/org/orekit/gnss/QuadraticClockModelTest.java b/src/test/java/org/orekit/gnss/QuadraticClockModelTest.java deleted file mode 100644 index 73c5efa77d..0000000000 --- a/src/test/java/org/orekit/gnss/QuadraticClockModelTest.java +++ /dev/null @@ -1,69 +0,0 @@ -/* Copyright 2002-2024 Thales Alenia Space - * Licensed to CS GROUP (CS) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * CS licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.orekit.gnss; - -import org.hipparchus.util.FastMath; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.orekit.time.AbsoluteDate; - - -public class QuadraticClockModelTest { - - @Test - public void testValue() { - Assertions.assertEquals(1.00 / 256.0, clock.getOffset(t0), 1.0e-15); - Assertions.assertEquals(1.75 / 256.0, clock.getOffset(t0.shiftedBy(1.0)), 1.0e-15); - Assertions.assertEquals(3.00 / 256.0, clock.getOffset(t0.shiftedBy(2.0)), 1.0e-15); - } - - @Test - public void testRate() { - Assertions.assertEquals(1.00 / 512, clock.getRate(t0), 1.0e-15); - Assertions.assertEquals(2.00 / 512, clock.getRate(t0.shiftedBy(1.0)), 1.0e-15); - Assertions.assertEquals(3.00 / 512, clock.getRate(t0.shiftedBy(2.0)), 1.0e-15); - } - - @Test - public void testGetters() { - Assertions.assertEquals(0.0, clock.getReferenceDate().durationFrom(AbsoluteDate.GALILEO_EPOCH), 1.0e-15); - Assertions.assertEquals(1.00 / 256, clock.getA0(), 1.0e-15); - Assertions.assertEquals(1.00 / 512, clock.getA1(), 1.0e-15); - Assertions.assertEquals(1.00 / 1024, clock.getA2(), 1.0e-15); - } - - @BeforeEach - public void setUp() { - t0 = AbsoluteDate.GALILEO_EPOCH; - clock = new QuadraticClockModel(t0, - FastMath.scalb(1.0, -8), - FastMath.scalb(1.0, -9), - FastMath.scalb(1.0, -10)); - } - - @AfterEach - public void tearDown() { - t0 = null; - clock = null; - } - - private AbsoluteDate t0; - private QuadraticClockModel clock; - -} From 022c4ec4bfd5040e9ebf34f198894f9b1931a252 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Wed, 28 Feb 2024 14:02:41 +0100 Subject: [PATCH 164/359] Added missing @DefaultDataContext annotation. --- .../org/orekit/estimation/measurements/AbstractMeasurement.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/orekit/estimation/measurements/AbstractMeasurement.java b/src/main/java/org/orekit/estimation/measurements/AbstractMeasurement.java index 2179b597dd..bbacd09a1f 100644 --- a/src/main/java/org/orekit/estimation/measurements/AbstractMeasurement.java +++ b/src/main/java/org/orekit/estimation/measurements/AbstractMeasurement.java @@ -361,6 +361,7 @@ public static double signalTimeOfFlight(final PVCoordinatesProvider adjustableEm * FieldAbsoluteDate, FieldVector3D, FieldAbsoluteDate, Frame)} */ @Deprecated + @DefaultDataContext public static > T signalTimeOfFlight(final TimeStampedFieldPVCoordinates adjustableEmitterPV, final FieldVector3D receiverPosition, final FieldAbsoluteDate signalArrivalDate) { From f34230821ff25a39da3fc6c2b781583d06735ef5 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Fri, 1 Mar 2024 11:37:31 +0100 Subject: [PATCH 165/359] Removed duplicated parameter addition. --- .../measurements/gnss/InterSatellitesPhase.java | 8 +------- .../estimation/measurements/gnss/OneWayGNSSRange.java | 3 --- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/src/main/java/org/orekit/estimation/measurements/gnss/InterSatellitesPhase.java b/src/main/java/org/orekit/estimation/measurements/gnss/InterSatellitesPhase.java index 7e0937a75f..23c4255b0c 100644 --- a/src/main/java/org/orekit/estimation/measurements/gnss/InterSatellitesPhase.java +++ b/src/main/java/org/orekit/estimation/measurements/gnss/InterSatellitesPhase.java @@ -41,7 +41,7 @@ * @author Bryan Cazabonne * @since 10.3 */ -public class InterSatellitesPhase extends InterSatellitesMeasurement { +public class InterSatellitesPhase extends AbstractInterSatellitesMeasurement { /** Type of the measurement. */ public static final String MEASUREMENT_TYPE = "InterSatellitesPhase"; @@ -78,12 +78,6 @@ public InterSatellitesPhase(final ObservableSatellite local, // Add parameter drivers addParameterDriver(ambiguityDriver); - addParameterDriver(local.getClockOffsetDriver()); - addParameterDriver(local.getClockDriftDriver()); - addParameterDriver(local.getClockAccelerationDriver()); - addParameterDriver(remote.getClockOffsetDriver()); - addParameterDriver(remote.getClockDriftDriver()); - addParameterDriver(remote.getClockAccelerationDriver()); // Initialize fields this.wavelength = wavelength; diff --git a/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRange.java b/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRange.java index e07162789b..4db3b1a824 100644 --- a/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRange.java +++ b/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRange.java @@ -90,9 +90,6 @@ public OneWayGNSSRange(final PVCoordinatesProvider remote, final double baseWeight, final ObservableSatellite local) { // Call super constructor super(remote, remoteClock, date, range, sigma, baseWeight, local); - // The local satellite clock offset affects the measurement - addParameterDriver(local.getClockOffsetDriver()); - } /** {@inheritDoc} */ From edd5df47c3abd32bc2e363067aecab2e2ffca2bc Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Fri, 1 Mar 2024 11:38:16 +0100 Subject: [PATCH 166/359] Fixed missing derivative with respect to velocity. --- ...> AbstractInterSatellitesMeasurement.java} | 33 ++++++------------- 1 file changed, 10 insertions(+), 23 deletions(-) rename src/main/java/org/orekit/estimation/measurements/gnss/{InterSatellitesMeasurement.java => AbstractInterSatellitesMeasurement.java} (72%) diff --git a/src/main/java/org/orekit/estimation/measurements/gnss/InterSatellitesMeasurement.java b/src/main/java/org/orekit/estimation/measurements/gnss/AbstractInterSatellitesMeasurement.java similarity index 72% rename from src/main/java/org/orekit/estimation/measurements/gnss/InterSatellitesMeasurement.java rename to src/main/java/org/orekit/estimation/measurements/gnss/AbstractInterSatellitesMeasurement.java index 03252ade7b..6612ee857e 100644 --- a/src/main/java/org/orekit/estimation/measurements/gnss/InterSatellitesMeasurement.java +++ b/src/main/java/org/orekit/estimation/measurements/gnss/AbstractInterSatellitesMeasurement.java @@ -32,7 +32,7 @@ import org.orekit.utils.ShiftingPVCoordinatesProvider; import org.orekit.utils.TimeStampedFieldPVCoordinates; -/** BAse class for measurement between two satellites that are both estimated. +/** Base class for measurement between two satellites that are both estimated. *

              * The measurement is considered to be a signal emitted from * a remote satellite and received by a local satellite. @@ -45,7 +45,7 @@ * @author Luc Maisonobe * @since 12.1 */ -public abstract class InterSatellitesMeasurement> extends AbstractOnBoardMeasurement { +public abstract class AbstractInterSatellitesMeasurement> extends AbstractOnBoardMeasurement { /** Constructor. * @param date date of the measurement @@ -55,20 +55,12 @@ public abstract class InterSatellitesMeasurement getGradientRemotePV(final Spacecr // convert the SpacecraftState to a FieldPVCoordinatesProvider return (date, frame) -> { - // shift the raw (no derivatives) remote state - final AbsoluteDate dateBase = date.toAbsoluteDate(); - final SpacecraftState shifted = states[1].shiftedBy(dateBase.durationFrom(states[1])); - - // set up the derivatives with respect to remote state - final TimeStampedFieldPVCoordinates pv = getCoordinates(shifted, 6, freeParameters); + // set up the derivatives with respect to remote state at its date + final TimeStampedFieldPVCoordinates pv0 = getCoordinates(states[1], 6, freeParameters); - // add remaining derivatives, using a trick: we shift the date by 0, with derivatives - final Gradient zeroWithDerivatives = date.durationFrom(dateBase); - return pv.shiftedBy(zeroWithDerivatives); + // shift to desired date + return pv0.shiftedBy(date.durationFrom(states[1].getDate())); }; } From f2a16f4af283c0a018223902c23c592124ce7909 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Fri, 1 Mar 2024 11:38:47 +0100 Subject: [PATCH 167/359] Streamlined code. --- .../measurements/gnss/InterSatellitesPhaseTest.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/test/java/org/orekit/estimation/measurements/gnss/InterSatellitesPhaseTest.java b/src/test/java/org/orekit/estimation/measurements/gnss/InterSatellitesPhaseTest.java index a259f283b5..fbf4fc824c 100644 --- a/src/test/java/org/orekit/estimation/measurements/gnss/InterSatellitesPhaseTest.java +++ b/src/test/java/org/orekit/estimation/measurements/gnss/InterSatellitesPhaseTest.java @@ -326,9 +326,8 @@ void genericTestStateDerivatives(final boolean printResults, final int index, for (final ObservedMeasurement measurement : measurements) { // Play test if the measurement date is between interpolator previous and current date - if ((measurement.getDate().durationFrom(interpolator.getPreviousState().getDate()) > 0.) && - (measurement.getDate().durationFrom(interpolator.getCurrentState().getDate()) <= 0.) - ) { + if (measurement.getDate().isAfter(interpolator.getPreviousState()) && + measurement.getDate().isBeforeOrEqualTo(interpolator.getCurrentState())) { // We intentionally propagate to a date which is close to the // real spacecraft state but is *not* the accurate date, by @@ -367,8 +366,11 @@ public double[] value(final SpacecraftState state) { dJacobian[i][j] = jacobian[i][j] - jacobianRef[i][j]; dJacobianRelative[i][j] = FastMath.abs(dJacobian[i][j]/jacobianRef[i][j]); - if (j < 3) { errorsP.add(dJacobianRelative[i][j]); - } else { errorsV.add(dJacobianRelative[i][j]); } + if (j < 3) { + errorsP.add(dJacobianRelative[i][j]); + } else { + errorsV.add(dJacobianRelative[i][j]); + } } } // Print values in console ? From b05f4d73bdc43066284d3b02436b83cb8d5d825c Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Fri, 1 Mar 2024 11:38:59 +0100 Subject: [PATCH 168/359] Fixed javadoc. --- .../measurements/gnss/AbstractOneWayGNSSMeasurement.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/orekit/estimation/measurements/gnss/AbstractOneWayGNSSMeasurement.java b/src/main/java/org/orekit/estimation/measurements/gnss/AbstractOneWayGNSSMeasurement.java index 328553495f..46ec1d9ef6 100644 --- a/src/main/java/org/orekit/estimation/measurements/gnss/AbstractOneWayGNSSMeasurement.java +++ b/src/main/java/org/orekit/estimation/measurements/gnss/AbstractOneWayGNSSMeasurement.java @@ -46,7 +46,7 @@ * the satellite's orbit and clock. *

              *

              - * This class is very similar to {@link InterSatellitesMeasurement} measurement + * This class is very similar to {@link AbstractInterSatellitesMeasurement} measurement * class. However, using the one-way GNSS range measurement, the orbit and clock * of the emitting GNSS satellite are NOT estimated simultaneously with * LEO satellite coordinates. From 2ef026e01eae4ee9026f05b28057dd35433858aa Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Fri, 1 Mar 2024 11:41:16 +0100 Subject: [PATCH 169/359] Fixed warnings. --- .../gnss/InterSatellitesPhaseTest.java | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/src/test/java/org/orekit/estimation/measurements/gnss/InterSatellitesPhaseTest.java b/src/test/java/org/orekit/estimation/measurements/gnss/InterSatellitesPhaseTest.java index fbf4fc824c..6dbcc95379 100644 --- a/src/test/java/org/orekit/estimation/measurements/gnss/InterSatellitesPhaseTest.java +++ b/src/test/java/org/orekit/estimation/measurements/gnss/InterSatellitesPhaseTest.java @@ -177,8 +177,8 @@ void genericTestValues(final boolean printResults) { // Lists for results' storage - Used only for derivatives with respect to state // "final" value to be seen by "handleStep" function of the propagator - final List absoluteErrors = new ArrayList(); - final List relativeErrors = new ArrayList(); + final List absoluteErrors = new ArrayList<>(); + final List relativeErrors = new ArrayList<>(); // Use a lambda function to implement "handleStep" function propagator.setStepHandler(interpolator -> { @@ -317,8 +317,8 @@ void genericTestStateDerivatives(final boolean printResults, final int index, // Lists for results' storage - Used only for derivatives with respect to state // "final" value to be seen by "handleStep" function of the propagator - final List errorsP = new ArrayList(); - final List errorsV = new ArrayList(); + final List errorsP = new ArrayList<>(); + final List errorsV = new ArrayList<>(); // Use a lambda function to implement "handleStep" function propagator.setStepHandler(interpolator -> { @@ -346,14 +346,12 @@ void genericTestStateDerivatives(final boolean printResults, final int index, final double[][] jacobianRef; // Compute a reference value using finite differences - jacobianRef = Differentiation.differentiate(new StateFunction() { - public double[] value(final SpacecraftState state) { - final SpacecraftState[] s = states.clone(); - s[index] = state; - return measurement.estimateWithoutDerivatives(0, 0, s).getEstimatedValue(); - } + jacobianRef = Differentiation.differentiate(state -> { + final SpacecraftState[] s = states.clone(); + s[index] = state; + return measurement.estimateWithoutDerivatives(0, 0, s).getEstimatedValue(); }, measurement.getDimension(), propagator.getAttitudeProvider(), - OrbitType.CARTESIAN, PositionAngleType.TRUE, 2.0, 3).value(states[index]); + OrbitType.CARTESIAN, PositionAngleType.TRUE, 2.0, 3).value(states[index]); Assertions.assertEquals(jacobianRef.length, jacobian.length); Assertions.assertEquals(jacobianRef[0].length, jacobian[0].length); @@ -413,8 +411,8 @@ public double[] value(final SpacecraftState state) { propagator.propagate(measurements.get(measurements.size()-1).getDate()); // Convert lists to double[] and evaluate some statistics - final double relErrorsP[] = errorsP.stream().mapToDouble(Double::doubleValue).toArray(); - final double relErrorsV[] = errorsV.stream().mapToDouble(Double::doubleValue).toArray(); + final double[] relErrorsP = errorsP.stream().mapToDouble(Double::doubleValue).toArray(); + final double[] relErrorsV = errorsV.stream().mapToDouble(Double::doubleValue).toArray(); final double errorsPMedian = new Median().evaluate(relErrorsP); final double errorsPMean = new Mean().evaluate(relErrorsP); @@ -476,7 +474,7 @@ void genericTestParameterDerivatives(final boolean printResults, EstimationTestUtils.createMeasurements(propagator, creator, 1.0, 3.0, 300.0); // List to store the results - final List relErrorList = new ArrayList(); + final List relErrorList = new ArrayList<>(); // Use a lambda function to implement "handleStep" function propagator.setStepHandler(interpolator -> { @@ -563,7 +561,7 @@ public double value(final ParameterDriver parameterDriver, final AbsoluteDate da propagator.propagate(measurements.get(measurements.size()-1).getDate()); // Convert error list to double[] - final double relErrors[] = relErrorList.stream().mapToDouble(Double::doubleValue).toArray(); + final double[] relErrors = relErrorList.stream().mapToDouble(Double::doubleValue).toArray(); // Compute statistics final double relErrorsMedian = new Median().evaluate(relErrors); @@ -606,7 +604,7 @@ public void testIssue734() { Assertions.assertTrue(phase.getAmbiguityDriver().isSelected()); for (ParameterDriver driver : phase.getParametersDrivers()) { // Verify if the current driver corresponds to the phase ambiguity - if (driver.getName() == Phase.AMBIGUITY_NAME) { + if (Phase.AMBIGUITY_NAME.equals(driver.getName())) { Assertions.assertEquals(1234.0, phase.getAmbiguityDriver().getValue(), Double.MIN_VALUE); Assertions.assertTrue(phase.getAmbiguityDriver().isSelected()); } From dc5f47037177db6c834f41fa182b9a407c80dade Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Fri, 1 Mar 2024 11:41:33 +0100 Subject: [PATCH 170/359] Fixed warnings. --- .../gnss/InterSatellitesPhaseTest.java | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/test/java/org/orekit/estimation/measurements/gnss/InterSatellitesPhaseTest.java b/src/test/java/org/orekit/estimation/measurements/gnss/InterSatellitesPhaseTest.java index 6dbcc95379..dec431450d 100644 --- a/src/test/java/org/orekit/estimation/measurements/gnss/InterSatellitesPhaseTest.java +++ b/src/test/java/org/orekit/estimation/measurements/gnss/InterSatellitesPhaseTest.java @@ -50,7 +50,6 @@ import org.orekit.utils.Differentiation; import org.orekit.utils.ParameterDriver; import org.orekit.utils.ParameterFunction; -import org.orekit.utils.StateFunction; import org.orekit.utils.TimeSpanMap.Span; import org.orekit.utils.TimeStampedPVCoordinates; @@ -503,12 +502,12 @@ void genericTestParameterDerivatives(final boolean printResults, measurement.getSatellites().get(1).getClockOffsetDriver() }; - for (int i = 0; i < drivers.length; ++i) { - for (Span span = drivers[i].getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) { - final double[] gradient = measurement.estimate(0, 0, states).getParameterDerivatives(drivers[i], span.getStart()); + for (final ParameterDriver driver : drivers) { + for (Span span = driver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) { + final double[] gradient = measurement.estimate(0, 0, states).getParameterDerivatives(driver, span.getStart()); Assertions.assertEquals(1, measurement.getDimension()); Assertions.assertEquals(1, gradient.length); - + // Compute a reference value using finite differences final ParameterFunction dMkdP = Differentiation.differentiate(new ParameterFunction() { @@ -519,13 +518,13 @@ public double value(final ParameterDriver parameterDriver, final AbsoluteDate da estimateWithoutDerivatives(0, 0, states). getEstimatedValue()[0]; } - }, 3, 20.0 * drivers[i].getScale()); - final double ref = dMkdP.value(drivers[i], span.getStart()); - + }, 3, 20.0 * driver.getScale()); + final double ref = dMkdP.value(driver, span.getStart()); + if (printResults) { System.out.format(Locale.US, "%10.3e %10.3e ", gradient[0]-ref, FastMath.abs((gradient[0]-ref)/ref)); } - + final double relError = FastMath.abs((ref-gradient[0])/ref); relErrorList.add(relError); // Assert.assertEquals(ref, gradient[0], 6.1e-5 * FastMath.abs(ref)); From 16b3ded1b2445765d34cb28686283ef2f7b5a6c6 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Fri, 1 Mar 2024 18:31:02 +0100 Subject: [PATCH 171/359] Added InterSatellitesOneWayRangeRate measurements. Fixes #1332 --- src/changes/changes.xml | 3 + ...InterSatellitesOneWayRangeRateBuilder.java | 105 +++ .../AbstractInterSatellitesMeasurement.java | 25 +- .../gnss/AbstractOnBoardMeasurement.java | 66 +- .../gnss/AbstractOneWayGNSSMeasurement.java | 21 +- .../gnss/InterSatellitesOneWayRangeRate.java | 139 ++++ .../gnss/InterSatellitesPhase.java | 4 +- ...nBoardCommonParametersWithDerivatives.java | 51 +- ...ardCommonParametersWithoutDerivatives.java | 51 +- .../measurements/gnss/OneWayGNSSPhase.java | 4 +- .../measurements/gnss/OneWayGNSSRange.java | 4 +- ...rSatellitesOneWayRangeRateBuilderTest.java | 168 +++++ ...itesOneWayRangeRateMeasurementCreator.java | 141 ++++ .../InterSatellitesOneWayRangeRateTest.java | 614 ++++++++++++++++++ 14 files changed, 1302 insertions(+), 94 deletions(-) create mode 100644 src/main/java/org/orekit/estimation/measurements/generation/InterSatellitesOneWayRangeRateBuilder.java create mode 100644 src/main/java/org/orekit/estimation/measurements/gnss/InterSatellitesOneWayRangeRate.java create mode 100644 src/test/java/org/orekit/estimation/measurements/generation/InterSatellitesOneWayRangeRateBuilderTest.java create mode 100644 src/test/java/org/orekit/estimation/measurements/gnss/InterSatellitesOneWayRangeRateMeasurementCreator.java create mode 100644 src/test/java/org/orekit/estimation/measurements/gnss/InterSatellitesOneWayRangeRateTest.java diff --git a/src/changes/changes.xml b/src/changes/changes.xml index b3c48d67b1..ce62e96c47 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -21,6 +21,9 @@ + + Added InterSatellitesOneWayRangeRate measurements. + Added constant and quadratic clock models for GNSS measurements. diff --git a/src/main/java/org/orekit/estimation/measurements/generation/InterSatellitesOneWayRangeRateBuilder.java b/src/main/java/org/orekit/estimation/measurements/generation/InterSatellitesOneWayRangeRateBuilder.java new file mode 100644 index 0000000000..ab0b11a127 --- /dev/null +++ b/src/main/java/org/orekit/estimation/measurements/generation/InterSatellitesOneWayRangeRateBuilder.java @@ -0,0 +1,105 @@ +/* Copyright 2002-2024 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.estimation.measurements.generation; + +import org.hipparchus.random.CorrelatedRandomVectorGenerator; +import org.orekit.estimation.measurements.EstimationModifier; +import org.orekit.estimation.measurements.ObservableSatellite; +import org.orekit.estimation.measurements.gnss.InterSatellitesOneWayRangeRate; +import org.orekit.propagation.SpacecraftState; +import org.orekit.propagation.sampling.OrekitStepInterpolator; +import org.orekit.time.AbsoluteDate; +import org.orekit.utils.ParameterDriver; + +import java.util.Map; + +/** Builder for {@link org.orekit.estimation.measurements.gnss.InterSatellitesOneWayRangeRate} measurements. + * @author Luc Maisonobe + * @since 12.1 + */ +public class InterSatellitesOneWayRangeRateBuilder + extends AbstractMeasurementBuilder { + + /** Satellite which receives the signal and performs the measurement. */ + private final ObservableSatellite local; + + /** Satellite which simply emits the signal. */ + private final ObservableSatellite remote; + + /** Simple constructor. + * @param noiseSource noise source, may be null for generating perfect measurements + * @param local satellite which receives the signal and performs the measurement + * @param remote satellite which simply emits the signal + * @param sigma theoretical standard deviation + * @param baseWeight base weight + */ + public InterSatellitesOneWayRangeRateBuilder(final CorrelatedRandomVectorGenerator noiseSource, + final ObservableSatellite local, final ObservableSatellite remote, + final double sigma, final double baseWeight) { + super(noiseSource, sigma, baseWeight, local, remote); + this.local = local; + this.remote = remote; + } + + /** {@inheritDoc} */ + @Override + public InterSatellitesOneWayRangeRate build(final AbsoluteDate date, + final Map interpolators) { + + final double sigma = getTheoreticalStandardDeviation()[0]; + final double baseWeight = getBaseWeight()[0]; + final SpacecraftState[] relevant = new SpacecraftState[] { + interpolators.get(local).getInterpolatedState(date), + interpolators.get(remote).getInterpolatedState(date) + }; + + // create a dummy measurement + final InterSatellitesOneWayRangeRate dummy = new InterSatellitesOneWayRangeRate(local, remote, relevant[0].getDate(), + Double.NaN, sigma, baseWeight); + for (final EstimationModifier modifier : getModifiers()) { + dummy.addModifier(modifier); + } + + // set a reference date for parameters missing one + for (final ParameterDriver driver : dummy.getParametersDrivers()) { + if (driver.getReferenceDate() == null) { + final AbsoluteDate start = getStart(); + final AbsoluteDate end = getEnd(); + driver.setReferenceDate(start.durationFrom(end) <= 0 ? start : end); + } + } + + // estimate the perfect value of the measurement + double rangeRate = dummy.estimateWithoutDerivatives(0, 0, relevant).getEstimatedValue()[0]; + + // add the noise + final double[] noise = getNoise(); + if (noise != null) { + rangeRate += noise[0]; + } + + // generate measurement + final InterSatellitesOneWayRangeRate measurement = new InterSatellitesOneWayRangeRate(local, remote, relevant[0].getDate(), + rangeRate, sigma, baseWeight); + for (final EstimationModifier modifier : getModifiers()) { + measurement.addModifier(modifier); + } + return measurement; + + } + +} diff --git a/src/main/java/org/orekit/estimation/measurements/gnss/AbstractInterSatellitesMeasurement.java b/src/main/java/org/orekit/estimation/measurements/gnss/AbstractInterSatellitesMeasurement.java index 6612ee857e..b6f433a925 100644 --- a/src/main/java/org/orekit/estimation/measurements/gnss/AbstractInterSatellitesMeasurement.java +++ b/src/main/java/org/orekit/estimation/measurements/gnss/AbstractInterSatellitesMeasurement.java @@ -17,16 +17,13 @@ package org.orekit.estimation.measurements.gnss; import java.util.Arrays; -import java.util.Map; -import java.util.function.Function; -import java.util.function.ToDoubleFunction; import org.hipparchus.analysis.differentiation.Gradient; import org.orekit.estimation.measurements.ObservableSatellite; import org.orekit.estimation.measurements.ObservedMeasurement; +import org.orekit.estimation.measurements.QuadraticClockModel; import org.orekit.propagation.SpacecraftState; import org.orekit.time.AbsoluteDate; -import org.orekit.time.FieldAbsoluteDate; import org.orekit.utils.FieldPVCoordinatesProvider; import org.orekit.utils.PVCoordinatesProvider; import org.orekit.utils.ShiftingPVCoordinatesProvider; @@ -65,20 +62,20 @@ public AbstractInterSatellitesMeasurement(final AbsoluteDate date, final double /** {@inheritDoc} */ @Override - protected PVCoordinatesProvider getDoubleRemotePV(final SpacecraftState[] states) { + protected PVCoordinatesProvider getRemotePV(final SpacecraftState[] states) { return new ShiftingPVCoordinatesProvider(states[1].getPVCoordinates(), states[1].getFrame()); } /** {@inheritDoc} */ @Override - protected ToDoubleFunction getDoubleRemoteClock() { - return getSatellites().get(1).getQuadraticClockModel()::getOffset; + protected QuadraticClockModel getRemoteClock() { + return getSatellites().get(1).getQuadraticClockModel(); } /** {@inheritDoc} */ @Override - protected FieldPVCoordinatesProvider getGradientRemotePV(final SpacecraftState[] states, - final int freeParameters) { + protected FieldPVCoordinatesProvider getRemotePV(final SpacecraftState[] states, + final int freeParameters) { // convert the SpacecraftState to a FieldPVCoordinatesProvider return (date, frame) -> { @@ -91,14 +88,4 @@ protected FieldPVCoordinatesProvider getGradientRemotePV(final Spacecr }; } - /** {@inheritDoc} */ - @Override - protected Function, Gradient> getGradientRemoteClock(final int freeParameters, - final Map indices) { - return getSatellites(). - get(1). - getQuadraticClockModel(). - toGradientModel(freeParameters, indices, getDate())::getOffset; - } - } diff --git a/src/main/java/org/orekit/estimation/measurements/gnss/AbstractOnBoardMeasurement.java b/src/main/java/org/orekit/estimation/measurements/gnss/AbstractOnBoardMeasurement.java index b5a517aa92..e9e5673be7 100644 --- a/src/main/java/org/orekit/estimation/measurements/gnss/AbstractOnBoardMeasurement.java +++ b/src/main/java/org/orekit/estimation/measurements/gnss/AbstractOnBoardMeasurement.java @@ -17,9 +17,12 @@ package org.orekit.estimation.measurements.gnss; import org.hipparchus.analysis.differentiation.Gradient; +import org.hipparchus.analysis.differentiation.GradientField; import org.orekit.estimation.measurements.AbstractMeasurement; import org.orekit.estimation.measurements.ObservableSatellite; import org.orekit.estimation.measurements.ObservedMeasurement; +import org.orekit.estimation.measurements.QuadraticClockModel; +import org.orekit.estimation.measurements.QuadraticFieldClockModel; import org.orekit.propagation.SpacecraftState; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; @@ -33,8 +36,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.function.Function; -import java.util.function.ToDoubleFunction; /** Base class modeling a measurement where receiver is a satellite. * @param type of the measurement @@ -68,21 +69,21 @@ public AbstractOnBoardMeasurement(final AbsoluteDate date, final double observed /** Get emitting satellite clock provider. * @return emitting satellite clock provider */ - protected abstract ToDoubleFunction getDoubleRemoteClock(); + protected abstract QuadraticClockModel getRemoteClock(); /** Get emitting satellite position/velocity provider. * @param states states of all spacecraft involved in the measurement * @return emitting satellite position/velocity provider */ - protected abstract PVCoordinatesProvider getDoubleRemotePV(SpacecraftState[] states); + protected abstract PVCoordinatesProvider getRemotePV(SpacecraftState[] states); /** Get emitting satellite position/velocity provider. * @param states states of all spacecraft involved in the measurement * @param freeParameters total number of free parameters in the gradient * @return emitting satellite position/velocity provider */ - protected abstract FieldPVCoordinatesProvider getGradientRemotePV(SpacecraftState[] states, - int freeParameters); + protected abstract FieldPVCoordinatesProvider getRemotePV(SpacecraftState[] states, + int freeParameters); /** Get emitting satellite clock provider. * @param freeParameters total number of free parameters in the gradient @@ -90,8 +91,10 @@ protected abstract FieldPVCoordinatesProvider getGradientRemotePV(Spac * must be span name and not driver name * @return emitting satellite clock provider */ - protected abstract Function, Gradient> getGradientRemoteClock(int freeParameters, - Map indices); + protected QuadraticFieldClockModel getRemoteClock(final int freeParameters, + final Map indices) { + return getRemoteClock().toGradientModel(freeParameters, indices, getDate()); + } /** Compute common estimation parameters. * @param states states of all spacecraft involved in the measurement @@ -104,16 +107,14 @@ protected OnBoardCommonParametersWithoutDerivatives computeCommonParametersWitho final boolean clockOffsetAlreadyApplied) { // local and remote satellites - final TimeStampedPVCoordinates pvaLocal = states[0].getPVCoordinates(); - final double dtLocal = getSatellites(). - get(0). - getQuadraticClockModel(). - getOffset(getDate()); - final PVCoordinatesProvider remotePV = getDoubleRemotePV(states); - final ToDoubleFunction remoteClock = getDoubleRemoteClock(); + final TimeStampedPVCoordinates pvaLocal = states[0].getPVCoordinates(); + final QuadraticClockModel localClock = getSatellites().get(0).getQuadraticClockModel(); + final double localClockOffset = localClock.getOffset(getDate()); + final double localClockRate = localClock.getRate(getDate()); + final PVCoordinatesProvider remotePV = getRemotePV(states); // take clock offset into account - final AbsoluteDate arrivalDate = clockOffsetAlreadyApplied ? getDate() : getDate().shiftedBy(-dtLocal); + final AbsoluteDate arrivalDate = clockOffsetAlreadyApplied ? getDate() : getDate().shiftedBy(-localClockOffset); // Downlink delay final double deltaT = arrivalDate.durationFrom(states[0]); @@ -122,8 +123,13 @@ protected OnBoardCommonParametersWithoutDerivatives computeCommonParametersWitho arrivalDate, states[0].getFrame()); // Remote satellite at signal emission - final AbsoluteDate emissionDate = arrivalDate.shiftedBy(-tauD); - return new OnBoardCommonParametersWithoutDerivatives(states[0], dtLocal, remoteClock.applyAsDouble(emissionDate), + final AbsoluteDate emissionDate = arrivalDate.shiftedBy(-tauD); + final QuadraticClockModel remoteClock = getRemoteClock(); + final double remoteClockOffset = remoteClock.getOffset(emissionDate); + final double remoteClockRate = remoteClock.getRate(emissionDate); + return new OnBoardCommonParametersWithoutDerivatives(states[0], + localClockOffset, localClockRate, + remoteClockOffset, remoteClockRate, tauD, pvaDownlink, remotePV.getPVCoordinates(emissionDate, states[0].getFrame())); @@ -153,18 +159,20 @@ protected OnBoardCommonParametersWithDerivatives computeCommonParametersWith(fin } } } + final FieldAbsoluteDate gDate = new FieldAbsoluteDate<>(GradientField.getField(nbEstimatedParams), + getDate()); // local and remote satellites - final TimeStampedFieldPVCoordinates pvaLocal = getCoordinates(states[0], 0, nbEstimatedParams); - final ParameterDriver localClockDriver = getSatellites().get(0).getClockOffsetDriver(); - final Gradient dtLocal = localClockDriver.getValue(nbEstimatedParams, parameterIndices, getDate()); - final FieldPVCoordinatesProvider remotePV = getGradientRemotePV(states, nbEstimatedParams); - final Function, Gradient> remoteClock = getGradientRemoteClock(nbEstimatedParams, parameterIndices); + final TimeStampedFieldPVCoordinates pvaLocal = getCoordinates(states[0], 0, nbEstimatedParams); + final QuadraticFieldClockModel localClock = getSatellites().get(0).getQuadraticClockModel(). + toGradientModel(nbEstimatedParams, parameterIndices, getDate()); + final Gradient localClockOffset = localClock.getOffset(gDate); + final Gradient localClockRate = localClock.getRate(gDate); + final FieldPVCoordinatesProvider remotePV = getRemotePV(states, nbEstimatedParams); // take clock offset into account final FieldAbsoluteDate arrivalDate = clockOffsetAlreadyApplied ? - new FieldAbsoluteDate<>(dtLocal.getField(), getDate()) : - new FieldAbsoluteDate<>(getDate(), dtLocal.negate()); + gDate : gDate.shiftedBy(localClockOffset.negate()); // Downlink delay final Gradient deltaT = arrivalDate.durationFrom(states[0].getDate()); @@ -174,9 +182,13 @@ protected OnBoardCommonParametersWithDerivatives computeCommonParametersWith(fin states[0].getFrame()); // Remote satellite at signal emission - final FieldAbsoluteDate emissionDate = arrivalDate.shiftedBy(tauD.negate()); + final FieldAbsoluteDate emissionDate = arrivalDate.shiftedBy(tauD.negate()); + final QuadraticFieldClockModel remoteClock = getRemoteClock(nbEstimatedParams, parameterIndices); + final Gradient remoteClockOffset = remoteClock.getOffset(emissionDate); + final Gradient remoteClockRate = remoteClock.getRate(emissionDate); return new OnBoardCommonParametersWithDerivatives(states[0], parameterIndices, - dtLocal, remoteClock.apply(emissionDate), + localClockOffset, localClockRate, + remoteClockOffset, remoteClockRate, tauD, pvaDownlink, remotePV.getPVCoordinates(emissionDate, states[0].getFrame())); diff --git a/src/main/java/org/orekit/estimation/measurements/gnss/AbstractOneWayGNSSMeasurement.java b/src/main/java/org/orekit/estimation/measurements/gnss/AbstractOneWayGNSSMeasurement.java index 46ec1d9ef6..0e1ed3fdf2 100644 --- a/src/main/java/org/orekit/estimation/measurements/gnss/AbstractOneWayGNSSMeasurement.java +++ b/src/main/java/org/orekit/estimation/measurements/gnss/AbstractOneWayGNSSMeasurement.java @@ -17,9 +17,6 @@ package org.orekit.estimation.measurements.gnss; import java.util.Collections; -import java.util.Map; -import java.util.function.Function; -import java.util.function.ToDoubleFunction; import org.hipparchus.analysis.differentiation.Gradient; import org.orekit.estimation.measurements.ObservableSatellite; @@ -27,7 +24,6 @@ import org.orekit.estimation.measurements.QuadraticClockModel; import org.orekit.propagation.SpacecraftState; import org.orekit.time.AbsoluteDate; -import org.orekit.time.FieldAbsoluteDate; import org.orekit.utils.FieldPVCoordinatesProvider; import org.orekit.utils.PVCoordinatesProvider; import org.orekit.utils.TimeStampedFieldPVCoordinates; @@ -91,20 +87,20 @@ public AbstractOneWayGNSSMeasurement(final PVCoordinatesProvider remotePV, /** {@inheritDoc} */ @Override - protected PVCoordinatesProvider getDoubleRemotePV(final SpacecraftState[] states) { + protected PVCoordinatesProvider getRemotePV(final SpacecraftState[] states) { return remotePV; } /** {@inheritDoc} */ @Override - protected ToDoubleFunction getDoubleRemoteClock() { - return remoteClock::getOffset; + protected QuadraticClockModel getRemoteClock() { + return remoteClock; } /** {@inheritDoc} */ @Override - protected FieldPVCoordinatesProvider getGradientRemotePV(final SpacecraftState[] states, - final int freeParameters) { + protected FieldPVCoordinatesProvider getRemotePV(final SpacecraftState[] states, + final int freeParameters) { // convert the PVCoordinatesProvider to a FieldPVCoordinatesProvider return (date, frame) -> { @@ -121,11 +117,4 @@ protected FieldPVCoordinatesProvider getGradientRemotePV(final Spacecr }; } - /** {@inheritDoc} */ - @Override - protected Function, Gradient> getGradientRemoteClock(final int freeParameters, - final Map indices) { - return remoteClock.toGradientModel(freeParameters, indices, getDate())::getOffset; - } - } diff --git a/src/main/java/org/orekit/estimation/measurements/gnss/InterSatellitesOneWayRangeRate.java b/src/main/java/org/orekit/estimation/measurements/gnss/InterSatellitesOneWayRangeRate.java new file mode 100644 index 0000000000..b4a5988216 --- /dev/null +++ b/src/main/java/org/orekit/estimation/measurements/gnss/InterSatellitesOneWayRangeRate.java @@ -0,0 +1,139 @@ +/* Copyright 2002-2024 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.estimation.measurements.gnss; + +import org.hipparchus.analysis.differentiation.Gradient; +import org.hipparchus.geometry.euclidean.threed.FieldVector3D; +import org.hipparchus.geometry.euclidean.threed.Vector3D; +import org.orekit.estimation.measurements.EstimatedMeasurement; +import org.orekit.estimation.measurements.EstimatedMeasurementBase; +import org.orekit.estimation.measurements.ObservableSatellite; +import org.orekit.propagation.SpacecraftState; +import org.orekit.time.AbsoluteDate; +import org.orekit.utils.Constants; +import org.orekit.utils.FieldPVCoordinates; +import org.orekit.utils.PVCoordinates; +import org.orekit.utils.ParameterDriver; +import org.orekit.utils.TimeSpanMap.Span; +import org.orekit.utils.TimeStampedPVCoordinates; + +import java.util.Arrays; + +/** One way range-rate measurement between two satellites. + * @author Luc Maisonobe + * @since 12.1 + */ +public class InterSatellitesOneWayRangeRate + extends AbstractInterSatellitesMeasurement { + + /** Type of the measurement. */ + public static final String MEASUREMENT_TYPE = "InterSatellitesOneWayRangeRate"; + + /** Constructor. + * @param local satellite which receives the signal and performs the measurement + * @param remote remote satellite which simply emits the signal + * @param date date of the measurement + * @param rangeRate observed value (m/s) + * @param sigma theoretical standard deviation + * @param baseWeight base weight + */ + public InterSatellitesOneWayRangeRate(final ObservableSatellite local, + final ObservableSatellite remote, + final AbsoluteDate date, final double rangeRate, + final double sigma, final double baseWeight) { + // Call to super constructor + super(date, rangeRate, sigma, baseWeight, local, remote); + } + + /** {@inheritDoc} */ + @Override + protected EstimatedMeasurementBase theoreticalEvaluationWithoutDerivatives(final int iteration, + final int evaluation, + final SpacecraftState[] states) { + + final OnBoardCommonParametersWithoutDerivatives common = computeCommonParametersWithout(states, false); + + // prepare the evaluation + final EstimatedMeasurementBase estimatedPhase = + new EstimatedMeasurementBase<>(this, iteration, evaluation, + new SpacecraftState[] { + common.getState(), + states[1] + }, new TimeStampedPVCoordinates[] { + common.getRemotePV(), + common.getTransitPV() + }); + + // Range rate value + final PVCoordinates delta = new PVCoordinates(common.getRemotePV(), common.getTransitPV()); + final double rangeRate = Vector3D.dotProduct(delta.getVelocity(), delta.getPosition().normalize()) + + Constants.SPEED_OF_LIGHT * (common.getLocalRate() - common.getRemoteRate()); + + estimatedPhase.setEstimatedValue(rangeRate); + + // Return the estimated measurement + return estimatedPhase; + + } + + /** {@inheritDoc} */ + @Override + protected EstimatedMeasurement theoreticalEvaluation(final int iteration, + final int evaluation, + final SpacecraftState[] states) { + + final OnBoardCommonParametersWithDerivatives common = computeCommonParametersWith(states, false); + + // prepare the evaluation + final EstimatedMeasurement estimatedPhase = + new EstimatedMeasurement<>(this, iteration, evaluation, + new SpacecraftState[] { + common.getState(), + states[1] + }, new TimeStampedPVCoordinates[] { + common.getRemotePV().toTimeStampedPVCoordinates(), + common.getTransitPV().toTimeStampedPVCoordinates() + }); + + // Range rate value + final FieldPVCoordinates delta = new FieldPVCoordinates<>(common.getRemotePV(), common.getTransitPV()); + final Gradient rangeRate = FieldVector3D.dotProduct(delta.getVelocity(), delta.getPosition().normalize()). + add(common.getLocalRate().subtract(common.getRemoteRate()).multiply(Constants.SPEED_OF_LIGHT)); + + estimatedPhase.setEstimatedValue(rangeRate.getValue()); + + // Range partial derivatives with respect to states + final double[] derivatives = rangeRate.getGradient(); + estimatedPhase.setStateDerivatives(0, Arrays.copyOfRange(derivatives, 0, 6)); + estimatedPhase.setStateDerivatives(1, Arrays.copyOfRange(derivatives, 6, 12)); + + // Set partial derivatives with respect to parameters + for (final ParameterDriver driver : getParametersDrivers()) { + for (Span span = driver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) { + final Integer index = common.getIndices().get(span.getData()); + if (index != null) { + estimatedPhase.setParameterDerivatives(driver, span.getStart(), derivatives[index]); + } + } + } + + // Return the estimated measurement + return estimatedPhase; + + } + +} diff --git a/src/main/java/org/orekit/estimation/measurements/gnss/InterSatellitesPhase.java b/src/main/java/org/orekit/estimation/measurements/gnss/InterSatellitesPhase.java index 23c4255b0c..7d7a4576c0 100644 --- a/src/main/java/org/orekit/estimation/measurements/gnss/InterSatellitesPhase.java +++ b/src/main/java/org/orekit/estimation/measurements/gnss/InterSatellitesPhase.java @@ -119,7 +119,7 @@ protected EstimatedMeasurementBase theoreticalEvaluationWi // Phase value final double cOverLambda = Constants.SPEED_OF_LIGHT / wavelength; final double ambiguity = ambiguityDriver.getValue(common.getState().getDate()); - final double phase = (common.getTauD() + common.getDtLocal() - common.getDtRemote()) * cOverLambda + + final double phase = (common.getTauD() + common.getLocalOffset() - common.getRemoteOffset()) * cOverLambda + ambiguity; estimatedPhase.setEstimatedValue(phase); @@ -152,7 +152,7 @@ protected EstimatedMeasurement theoreticalEvaluation(final final double cOverLambda = Constants.SPEED_OF_LIGHT / wavelength; final Gradient ambiguity = ambiguityDriver.getValue(common.getTauD().getFreeParameters(), common.getIndices(), common.getState().getDate()); - final Gradient phase = common.getTauD().add(common.getDtLocal()).subtract(common.getDtRemote()). + final Gradient phase = common.getTauD().add(common.getLocalOffset()).subtract(common.getRemoteOffset()). multiply(cOverLambda). add(ambiguity); diff --git a/src/main/java/org/orekit/estimation/measurements/gnss/OnBoardCommonParametersWithDerivatives.java b/src/main/java/org/orekit/estimation/measurements/gnss/OnBoardCommonParametersWithDerivatives.java index c9c9f2fd4d..d7fddb0b61 100644 --- a/src/main/java/org/orekit/estimation/measurements/gnss/OnBoardCommonParametersWithDerivatives.java +++ b/src/main/java/org/orekit/estimation/measurements/gnss/OnBoardCommonParametersWithDerivatives.java @@ -31,10 +31,16 @@ public class OnBoardCommonParametersWithDerivatives extends CommonParametersWithDerivatives { /** Local clock offset. */ - final Gradient dtLocal; + final Gradient localOffset; + + /** Local clock rate. */ + final Gradient localRate; /** Remote clock offset. */ - final Gradient dtRemote; + final Gradient remoteOffset; + + /** Remote clock rate. */ + final Gradient remoteRate; /** Remote satellite position/velocity. */ private final TimeStampedFieldPVCoordinates remotePV; @@ -42,36 +48,55 @@ public class OnBoardCommonParametersWithDerivatives /** Simple constructor. * @param localState local spacecraft state * @param indices derivatives indices map - * @param dtLocal local clock offset - * @param dtRemote remote clock offset + * @param localOffset local clock offset + * @param localRate local clock rate + * @param remoteOffset remote clock offset + * @param remoteRate remote clock rate * @param tauD downlink delay * @param localPV local satellite position/velocity * @param remotePV remote satellite position/velocity */ public OnBoardCommonParametersWithDerivatives(final SpacecraftState localState, final Map indices, - final Gradient dtLocal, final Gradient dtRemote, + final Gradient localOffset, final Gradient localRate, + final Gradient remoteOffset, final Gradient remoteRate, final Gradient tauD, final TimeStampedFieldPVCoordinates localPV, final TimeStampedFieldPVCoordinates remotePV) { super(localState, indices, tauD, localState, localPV); - this.dtLocal = dtLocal; - this.dtRemote = dtRemote; - this.remotePV = remotePV; + this.localOffset = localOffset; + this.localRate = localRate; + this.remoteOffset = remoteOffset; + this.remoteRate = remoteRate; + this.remotePV = remotePV; } /** Get local clock offset. * @return local clock offset */ - public Gradient getDtLocal() { - return dtLocal; + public Gradient getLocalOffset() { + return localOffset; + } + + /** Get local clock rate. + * @return local clock rate + */ + public Gradient getLocalRate() { + return localRate; } /** Get remote clock offset. - * @return remotr clock offset + * @return remote clock offset + */ + public Gradient getRemoteOffset() { + return remoteOffset; + } + + /** Get remote clock rate. + * @return remote clock rate */ - public Gradient getDtRemote() { - return dtRemote; + public Gradient getRemoteRate() { + return remoteRate; } /** Get remote satellite position/velocity. diff --git a/src/main/java/org/orekit/estimation/measurements/gnss/OnBoardCommonParametersWithoutDerivatives.java b/src/main/java/org/orekit/estimation/measurements/gnss/OnBoardCommonParametersWithoutDerivatives.java index 2eca5490ab..fcada424d5 100644 --- a/src/main/java/org/orekit/estimation/measurements/gnss/OnBoardCommonParametersWithoutDerivatives.java +++ b/src/main/java/org/orekit/estimation/measurements/gnss/OnBoardCommonParametersWithoutDerivatives.java @@ -28,45 +28,70 @@ public class OnBoardCommonParametersWithoutDerivatives extends CommonParametersWithoutDerivatives { /** Local clock offset. */ - final double dtLocal; + final double localOffset; + + /** Local clock rate. */ + final double localRate; /** Remote clock offset. */ - final double dtRemote; + final double remoteOffset; + + /** Remote clock rate. */ + final double remoteRate; /** Remote satellite position/velocity. */ private final TimeStampedPVCoordinates remotePV; /** Simple constructor. * @param localState local spacecraft state - * @param dtLocal local clock offset - * @param dtRemote remote clock offset + * @param localOffset local clock offset + * @param localRate local clock rate + * @param remoteOffset remote clock offset + * @param remoteRate remote clock rate * @param tauD downlink delay * @param localPV local satellite position/velocity * @param remotePV remote satellite position/velocity */ public OnBoardCommonParametersWithoutDerivatives(final SpacecraftState localState, - final double dtLocal, final double dtRemote, + final double localOffset, final double localRate, + final double remoteOffset, final double remoteRate, final double tauD, final TimeStampedPVCoordinates localPV, final TimeStampedPVCoordinates remotePV) { super(localState, tauD, localState, localPV); - this.dtLocal = dtLocal; - this.dtRemote = dtRemote; - this.remotePV = remotePV; + this.localOffset = localOffset; + this.localRate = localRate; + this.remoteOffset = remoteOffset; + this.remoteRate = remoteRate; + this.remotePV = remotePV; } /** Get local clock offset. * @return local clock offset */ - public double getDtLocal() { - return dtLocal; + public double getLocalOffset() { + return localOffset; + } + + /** Get local clock rate. + * @return local clock rate + */ + public double getLocalRate() { + return localRate; } /** Get remote clock offset. - * @return remotr clock offset + * @return remote clock offset + */ + public double getRemoteOffset() { + return remoteOffset; + } + + /** Get remote clock rate. + * @return remote clock rate */ - public double getDtRemote() { - return dtRemote; + public double getRemoteRate() { + return remoteRate; } /** Get remote satellite position/velocity. diff --git a/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSPhase.java b/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSPhase.java index 274d7bdb2e..f53ad5027d 100644 --- a/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSPhase.java +++ b/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSPhase.java @@ -148,7 +148,7 @@ protected EstimatedMeasurementBase theoreticalEvaluationWithout // Phase value final double cOverLambda = Constants.SPEED_OF_LIGHT / wavelength; final double ambiguity = ambiguityDriver.getValue(common.getState().getDate()); - final double phase = (common.getTauD() + common.getDtLocal() - common.getDtRemote()) * cOverLambda + + final double phase = (common.getTauD() + common.getLocalOffset() - common.getRemoteOffset()) * cOverLambda + ambiguity; // Set value of the estimated measurement @@ -181,7 +181,7 @@ protected EstimatedMeasurement theoreticalEvaluation(final int final double cOverLambda = Constants.SPEED_OF_LIGHT / wavelength; final Gradient ambiguity = ambiguityDriver.getValue(common.getTauD().getFreeParameters(), common.getIndices(), common.getState().getDate()); - final Gradient phase = common.getTauD().add(common.getDtLocal()).subtract(common.getDtRemote()). + final Gradient phase = common.getTauD().add(common.getLocalOffset()).subtract(common.getRemoteOffset()). multiply(cOverLambda). add(ambiguity); final double[] phaseDerivatives = phase.getGradient(); diff --git a/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRange.java b/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRange.java index 4db3b1a824..4db254ed87 100644 --- a/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRange.java +++ b/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRange.java @@ -112,7 +112,7 @@ protected EstimatedMeasurementBase theoreticalEvaluationWithout }); // Range value - final double range = (common.getTauD() + common.getDtLocal() - common.getDtRemote()) * + final double range = (common.getTauD() + common.getLocalOffset() - common.getRemoteOffset()) * Constants.SPEED_OF_LIGHT; // Set value of the estimated measurement @@ -142,7 +142,7 @@ protected EstimatedMeasurement theoreticalEvaluation(final int }); // Range value - final Gradient range = common.getTauD().add(common.getDtLocal()).subtract(common.getDtRemote()). + final Gradient range = common.getTauD().add(common.getLocalOffset()).subtract(common.getRemoteOffset()). multiply(Constants.SPEED_OF_LIGHT); final double[] rangeDerivatives = range.getGradient(); diff --git a/src/test/java/org/orekit/estimation/measurements/generation/InterSatellitesOneWayRangeRateBuilderTest.java b/src/test/java/org/orekit/estimation/measurements/generation/InterSatellitesOneWayRangeRateBuilderTest.java new file mode 100644 index 0000000000..67e8aff59e --- /dev/null +++ b/src/test/java/org/orekit/estimation/measurements/generation/InterSatellitesOneWayRangeRateBuilderTest.java @@ -0,0 +1,168 @@ +/* Copyright 2002-2024 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.estimation.measurements.generation; + +import org.hipparchus.linear.MatrixUtils; +import org.hipparchus.linear.RealMatrix; +import org.hipparchus.random.CorrelatedRandomVectorGenerator; +import org.hipparchus.random.GaussianRandomGenerator; +import org.hipparchus.random.RandomGenerator; +import org.hipparchus.random.Well19937a; +import org.hipparchus.util.FastMath; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.orekit.estimation.Context; +import org.orekit.estimation.EstimationTestUtils; +import org.orekit.estimation.Force; +import org.orekit.estimation.measurements.ObservableSatellite; +import org.orekit.estimation.measurements.ObservedMeasurement; +import org.orekit.estimation.measurements.gnss.InterSatellitesOneWayRangeRate; +import org.orekit.estimation.measurements.modifiers.Bias; +import org.orekit.orbits.KeplerianOrbit; +import org.orekit.orbits.Orbit; +import org.orekit.orbits.OrbitType; +import org.orekit.orbits.PositionAngleType; +import org.orekit.propagation.Propagator; +import org.orekit.propagation.SpacecraftState; +import org.orekit.propagation.analytical.KeplerianPropagator; +import org.orekit.propagation.conversion.NumericalPropagatorBuilder; +import org.orekit.propagation.events.InterSatDirectViewDetector; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FixedStepSelector; +import org.orekit.time.TimeScalesFactory; +import org.orekit.utils.PVCoordinates; + +import java.util.SortedSet; + +public class InterSatellitesOneWayRangeRateBuilderTest { + + private static final double SIGMA = 0.5; + private static final double BIAS = -0.01; + + private MeasurementBuilder getBuilder(final RandomGenerator random, + final ObservableSatellite receiver, + final ObservableSatellite remote) { + final RealMatrix covariance = MatrixUtils.createRealDiagonalMatrix(new double[] { SIGMA * SIGMA }); + MeasurementBuilder isrb = + new InterSatellitesOneWayRangeRateBuilder(random == null ? null : new CorrelatedRandomVectorGenerator(covariance, + 1.0e-10, + new GaussianRandomGenerator(random)), + receiver, remote, SIGMA, 1.0); + isrb.addModifier(new Bias<>(new String[] { "bias" }, + new double[] { BIAS }, + new double[] { 1.0 }, + new double[] { Double.NEGATIVE_INFINITY }, + new double[] { Double.POSITIVE_INFINITY })); + return isrb; + } + + @Test + public void testForward() { + doTest(0xc82a56322345dc25L, 0.0, 1.2, 2.8 * SIGMA); + } + + @Test + public void testBackward() { + doTest(0x95c10149c4891232L, 0.0, -1.0, 2.6 * SIGMA); + } + + private Propagator buildPropagator() { + return EstimationTestUtils.createPropagator(context.initialOrbit, propagatorBuilder); + } + + private void doTest(long seed, double startPeriod, double endPeriod, double tolerance) { + Generator generator = new Generator(); + generator.addPropagator(buildPropagator()); // dummy first propagator + generator.addPropagator(buildPropagator()); // dummy second propagator + ObservableSatellite receiver = generator.addPropagator(buildPropagator()); // useful third propagator + generator.addPropagator(buildPropagator()); // dummy fourth propagator + final Orbit o1 = context.initialOrbit; + // for the second satellite, we simply reverse velocity + final Orbit o2 = new KeplerianOrbit(new PVCoordinates(o1.getPosition(), + o1.getPVCoordinates().getVelocity().negate()), + o1.getFrame(), o1.getDate(), o1.getMu()); + ObservableSatellite remote = generator.addPropagator(new KeplerianPropagator(o2)); // useful sixth propagator + final double step = 60.0; + + // beware that in order to avoid deadlocks, the secondary PV coordinates provider + // in InterSatDirectViewDetector must be *different* from the second propagator + // added to generator above! The reason is the event detector will be bound + // to the first propagator, so it cannot also refer to the second one at the same time + // this is the reason why we create a *new* KeplerianPropagator below + generator.addScheduler(new EventBasedScheduler<>(getBuilder(new Well19937a(seed), receiver, remote), + new FixedStepSelector(step, TimeScalesFactory.getUTC()), + generator.getPropagator(receiver), + new InterSatDirectViewDetector(context.earth, new KeplerianPropagator(o2)), + SignSemantic.FEASIBLE_MEASUREMENT_WHEN_POSITIVE)); + + final GatheringSubscriber gatherer = new GatheringSubscriber(); + generator.addSubscriber(gatherer); + final double period = o1.getKeplerianPeriod(); + AbsoluteDate t0 = o1.getDate().shiftedBy(startPeriod * period); + AbsoluteDate t1 = o1.getDate().shiftedBy(endPeriod * period); + generator.generate(t0, t1); + SortedSet> measurements = gatherer.getGeneratedMeasurements(); + + // and yet another set of propagators for reference + Propagator propagator1 = buildPropagator(); + Propagator propagator2 = new KeplerianPropagator(o2); + + double maxError = 0; + AbsoluteDate previous = null; + AbsoluteDate tInf = t0.isBefore(t1) ? t0 : t1; + AbsoluteDate tSup = t0.isBefore(t1) ? t1 : t0; + for (ObservedMeasurement measurement : measurements) { + AbsoluteDate date = measurement.getDate(); + double[] m = measurement.getObservedValue(); + Assertions.assertTrue(date.compareTo(tInf) >= 0); + Assertions.assertTrue(date.compareTo(tSup) <= 0); + if (previous != null) { + if (t0.isBefore(t1)) { + // measurements are expected to be chronological + Assertions.assertTrue(date.durationFrom(previous) >= 0.999999 * step); + } else { + // measurements are expected to be reverse chronological + Assertions.assertTrue(previous.durationFrom(date) >= 0.999999 * step); + } + } + previous = date; + double[] e = measurement.estimateWithoutDerivatives(0, 0, + new SpacecraftState[] { + propagator1.propagate(date), + propagator2.propagate(date) + }).getEstimatedValue(); + for (int i = 0; i < m.length; ++i) { + maxError = FastMath.max(maxError, FastMath.abs(e[i] - m[i])); + } + } + Assertions.assertEquals(0.0, maxError, tolerance); + } + + @BeforeEach + public void setUp() { + context = EstimationTestUtils.eccentricContext("regular-data:potential:tides"); + + propagatorBuilder = context.createBuilder(OrbitType.KEPLERIAN, PositionAngleType.TRUE, true, + 1.0e-6, 300.0, 0.001, Force.POTENTIAL, + Force.THIRD_BODY_SUN, Force.THIRD_BODY_MOON); + } + + Context context; + NumericalPropagatorBuilder propagatorBuilder; + +} diff --git a/src/test/java/org/orekit/estimation/measurements/gnss/InterSatellitesOneWayRangeRateMeasurementCreator.java b/src/test/java/org/orekit/estimation/measurements/gnss/InterSatellitesOneWayRangeRateMeasurementCreator.java new file mode 100644 index 0000000000..1c22dab892 --- /dev/null +++ b/src/test/java/org/orekit/estimation/measurements/gnss/InterSatellitesOneWayRangeRateMeasurementCreator.java @@ -0,0 +1,141 @@ +/* Copyright 2002-2024 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.estimation.measurements.gnss; + +import org.hipparchus.analysis.UnivariateFunction; +import org.hipparchus.analysis.solvers.BracketingNthOrderBrentSolver; +import org.hipparchus.analysis.solvers.UnivariateSolver; +import org.hipparchus.geometry.euclidean.threed.Vector3D; +import org.orekit.errors.OrekitException; +import org.orekit.estimation.measurements.MeasurementCreator; +import org.orekit.estimation.measurements.ObservableSatellite; +import org.orekit.propagation.BoundedPropagator; +import org.orekit.propagation.SpacecraftState; +import org.orekit.time.AbsoluteDate; +import org.orekit.utils.Constants; +import org.orekit.utils.PVCoordinates; +import org.orekit.utils.ParameterDriver; + +import java.util.Arrays; + +public class InterSatellitesOneWayRangeRateMeasurementCreator + extends MeasurementCreator { + + private final BoundedPropagator ephemeris; + private final Vector3D antennaPhaseCenter1; + private final Vector3D antennaPhaseCenter2; + private final ObservableSatellite local; + private final ObservableSatellite remote; + + public InterSatellitesOneWayRangeRateMeasurementCreator(final BoundedPropagator ephemeris, + final double localClockOffset, + final double localClockRate, + final double localClockAcceleration, + final double remoteClockOffset, + final double remoteClockRate, + final double remoteClockAcceleration) { + this(ephemeris, + localClockOffset, localClockRate, localClockAcceleration, + remoteClockOffset, remoteClockRate, remoteClockAcceleration, + Vector3D.ZERO, Vector3D.ZERO); + } + + public InterSatellitesOneWayRangeRateMeasurementCreator(final BoundedPropagator ephemeris, + final double localClockOffset, + final double localClockRate, + final double localClockAcceleration, + final double remoteClockOffset, + final double remoteClockRate, + final double remoteClockAcceleration, + final Vector3D antennaPhaseCenter1, + final Vector3D antennaPhaseCenter2) { + this.ephemeris = ephemeris; + this.antennaPhaseCenter1 = antennaPhaseCenter1; + this.antennaPhaseCenter2 = antennaPhaseCenter2; + this.local = new ObservableSatellite(0); + this.local.getClockOffsetDriver().setValue(localClockOffset); + this.local.getClockDriftDriver().setValue(localClockRate); + this.local.getClockAccelerationDriver().setValue(localClockAcceleration); + this.remote = new ObservableSatellite(1); + this.remote.getClockOffsetDriver().setValue(remoteClockOffset); + this.remote.getClockDriftDriver().setValue(remoteClockRate); + this.remote.getClockAccelerationDriver().setValue(remoteClockAcceleration); + } + + public ObservableSatellite getLocalSatellite() { + return local; + } + + public ObservableSatellite getRemoteSatellite() { + return remote; + } + + public void init(final SpacecraftState s0, final AbsoluteDate t, final double step) { + for (final ParameterDriver driver : Arrays.asList(local.getClockOffsetDriver(), + local.getClockDriftDriver(), + local.getClockAccelerationDriver(), + remote.getClockOffsetDriver(), + remote.getClockDriftDriver(), + remote.getClockAccelerationDriver())) { + if (driver.getReferenceDate() == null) { + driver.setReferenceDate(s0.getDate()); + } + } + } + + public void handleStep(final SpacecraftState currentState) { + try { + final AbsoluteDate date = currentState.getDate(); + final PVCoordinates pv = currentState.toTransform().getInverse(). + transformPVCoordinates(new PVCoordinates(antennaPhaseCenter1)); + final double localClk = local.getQuadraticClockModel().getOffset(date); + + final UnivariateSolver solver = new BracketingNthOrderBrentSolver(1.0e-12, 5); + + final double downLinkDelay = solver.solve(1000, x -> { + final Vector3D other = ephemeris. + propagate(date.shiftedBy(-x)). + toTransform(). + getInverse(). + transformPosition(antennaPhaseCenter2); + final double d = Vector3D.distance(pv.getPosition(), other); + return d - x * Constants.SPEED_OF_LIGHT; + }, -1.0, 1.0); + final AbsoluteDate transitDate = currentState.getDate().shiftedBy(-downLinkDelay); + final PVCoordinates otherAtTransit = + ephemeris.propagate(transitDate). + toTransform(). + getInverse(). + transformPVCoordinates(new PVCoordinates(antennaPhaseCenter2)); + final PVCoordinates delta = new PVCoordinates(otherAtTransit, pv); + final double rangeRate = Vector3D.dotProduct(delta.getPosition().normalize(), delta.getVelocity()) + + Constants.SPEED_OF_LIGHT * (local.getQuadraticClockModel().getRate(date) - + remote.getQuadraticClockModel().getRate(transitDate)); + + // generate measurement + final InterSatellitesOneWayRangeRate phase = new InterSatellitesOneWayRangeRate(local, remote, + date.shiftedBy(localClk), + rangeRate, + 1.0, 10); + addMeasurement(phase); + + } catch (OrekitException oe) { + throw new OrekitException(oe); + } + } + +} diff --git a/src/test/java/org/orekit/estimation/measurements/gnss/InterSatellitesOneWayRangeRateTest.java b/src/test/java/org/orekit/estimation/measurements/gnss/InterSatellitesOneWayRangeRateTest.java new file mode 100644 index 0000000000..03dad396a7 --- /dev/null +++ b/src/test/java/org/orekit/estimation/measurements/gnss/InterSatellitesOneWayRangeRateTest.java @@ -0,0 +1,614 @@ +/* Copyright 2002-2024 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.estimation.measurements.gnss; + +import org.hipparchus.geometry.euclidean.threed.Vector3D; +import org.hipparchus.stat.descriptive.moment.Mean; +import org.hipparchus.stat.descriptive.rank.Max; +import org.hipparchus.stat.descriptive.rank.Median; +import org.hipparchus.stat.descriptive.rank.Min; +import org.hipparchus.util.FastMath; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.orekit.estimation.Context; +import org.orekit.estimation.EstimationTestUtils; +import org.orekit.estimation.measurements.EstimatedMeasurementBase; +import org.orekit.estimation.measurements.ObservedMeasurement; +import org.orekit.orbits.CartesianOrbit; +import org.orekit.orbits.Orbit; +import org.orekit.orbits.OrbitType; +import org.orekit.orbits.PositionAngleType; +import org.orekit.propagation.BoundedPropagator; +import org.orekit.propagation.EphemerisGenerator; +import org.orekit.propagation.Propagator; +import org.orekit.propagation.SpacecraftState; +import org.orekit.propagation.conversion.NumericalPropagatorBuilder; +import org.orekit.time.AbsoluteDate; +import org.orekit.utils.Constants; +import org.orekit.utils.Differentiation; +import org.orekit.utils.PVCoordinates; +import org.orekit.utils.ParameterDriver; +import org.orekit.utils.ParameterFunction; +import org.orekit.utils.TimeSpanMap.Span; +import org.orekit.utils.TimeStampedPVCoordinates; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Locale; + +public class InterSatellitesOneWayRangeRateTest { + + /** + * Test the values of the range rate comparing the observed values and the estimated values + * Both are calculated with a different algorithm + */ + @Test + public void testValues() { + boolean printResults = false; + if (printResults) { + System.out.println("\nTest inter-satellites Range Rate Values\n"); + } + // Run test + this.genericTestValues(printResults); + } + + /** + * Test the values of the state derivatives using a numerical + * finite differences calculation as a reference + */ + @Test + public void testStateDerivativesEmitter() { + + boolean printResults = false; + if (printResults) { + System.out.println("\nTest inter-satellites Range Rate State Derivatives - Finite Differences Comparison\n"); + } + // Run test + double refErrorsPMedian = 7.1e-10; + double refErrorsPMean = 7.1e-09; + double refErrorsPMax = 1.8e-06; + double refErrorsVMedian = 2.4e-10; + double refErrorsVMean = 5.2e-10; + double refErrorsVMax = 2.5e-08; + this.genericTestStateDerivatives(printResults, 0, + refErrorsPMedian, refErrorsPMean, refErrorsPMax, + refErrorsVMedian, refErrorsVMean, refErrorsVMax); + } + + /** + * Test the values of the state derivatives using a numerical + * finite differences calculation as a reference + */ + @Test + public void testStateDerivativesTransit() { + + boolean printResults = false; + if (printResults) { + System.out.println("\nTest inter-satellites Range Rate State Derivatives - Finite Differences Comparison\n"); + } + // Run test + double refErrorsPMedian = 7.1e-10; + double refErrorsPMean = 7.1e-09; + double refErrorsPMax = 1.8e-06; + double refErrorsVMedian = 2.6e-010; + double refErrorsVMean = 4.9e-10; + double refErrorsVMax = 1.1e-08; + this.genericTestStateDerivatives(printResults, 1, + refErrorsPMedian, refErrorsPMean, refErrorsPMax, + refErrorsVMedian, refErrorsVMean, refErrorsVMax); + } + + /** + * Test the values of the parameters' derivatives using a numerical + * finite differences calculation as a reference + */ + @Test + public void testParameterDerivatives() { + + // Print the results ? + boolean printResults = false; + + if (printResults) { + System.out.println("\nTest Range Rate Parameter Derivatives - Finite Differences Comparison\n"); + } + // Run test + double refErrorsMedian = 2.2e-16; + double refErrorsMean = 1.2e-7; + double refErrorsMax = 2.9e-6; + this.genericTestParameterDerivatives(printResults, + refErrorsMedian, refErrorsMean, refErrorsMax); + + } + + /** + * Generic test function for values of the inter-satellites range rate + * @param printResults Print the results ? + */ + void genericTestValues(final boolean printResults) { + + Context context = EstimationTestUtils.eccentricContext("regular-data:potential:tides"); + + final NumericalPropagatorBuilder propagatorBuilder = + context.createBuilder(OrbitType.KEPLERIAN, PositionAngleType.TRUE, true, + 1.0e-6, 60.0, 0.001); + + // Create perfect inter-satellites range rate measurements + final TimeStampedPVCoordinates original = context.initialOrbit.getPVCoordinates(); + final Orbit closeOrbit = new CartesianOrbit(new TimeStampedPVCoordinates(context.initialOrbit.getDate(), + original.getPosition().add(new Vector3D(1000, 2000, 3000)), + original.getVelocity().add(new Vector3D(-0.03, 0.01, 0.02))), + context.initialOrbit.getFrame(), + context.initialOrbit.getMu()); + final Propagator closePropagator = EstimationTestUtils.createPropagator(closeOrbit, + propagatorBuilder); + final EphemerisGenerator generator = closePropagator.getEphemerisGenerator(); + closePropagator.propagate(context.initialOrbit.getDate().shiftedBy(3.5 * closeOrbit.getKeplerianPeriod())); + final BoundedPropagator ephemeris = generator.getGeneratedEphemeris(); + final Propagator propagator = EstimationTestUtils.createPropagator(context.initialOrbit, + propagatorBuilder); + + final double localClockOffset = 0.14e-06; + final double localClockRate = -0.12e-10; + final double localClockAcceleration = 1.4e-13; + final double remoteClockOffset = 469.0e-06; + final double remoteClockRate = 33.0e-10; + final double remoteClockAcceleration = 0.5e-13; + final List> measurements = + EstimationTestUtils.createMeasurements(propagator, + new InterSatellitesOneWayRangeRateMeasurementCreator(ephemeris, + localClockOffset, localClockRate, localClockAcceleration, + remoteClockOffset, remoteClockRate, remoteClockAcceleration), + 1.0, 3.0, 300.0); + + // Lists for results' storage - Used only for derivatives with respect to state + // "final" value to be seen by "handleStep" function of the propagator + final List absoluteErrors = new ArrayList<>(); + final List relativeErrors = new ArrayList<>(); + + // Use a lambda function to implement "handleStep" function + propagator.setStepHandler(interpolator -> { + + for (final ObservedMeasurement measurement : measurements) { + + // Play test if the measurement date is between interpolator previous and current date + if (measurement.getDate().isAfter(interpolator.getPreviousState()) && + measurement.getDate().isBeforeOrEqualTo(interpolator.getCurrentState())) { + // We intentionally propagate to a date which is close to the + // real spacecraft state but is *not* the accurate date, by + // compensating only part of the downlink delay. This is done + // in order to validate the partial derivatives with respect + // to velocity. + final double meanDelay = measurement.getObservedValue()[0] / Constants.SPEED_OF_LIGHT; + final AbsoluteDate date = measurement.getDate().shiftedBy(-0.75 * meanDelay); + final SpacecraftState state = interpolator.getInterpolatedState(date); + + // Values of the range rate & errors + final double rangeRateObserved = measurement.getObservedValue()[0]; + final EstimatedMeasurementBase estimated = measurement.estimateWithoutDerivatives(0, 0, + new SpacecraftState[] { + state, + ephemeris.propagate(state.getDate()) + }); + + final TimeStampedPVCoordinates[] participants = estimated.getParticipants(); + Assertions.assertEquals(2, participants.length); + final PVCoordinates delta = new PVCoordinates(participants[0], participants[1]); + final double radialVelocity = Vector3D.dotProduct(delta.getVelocity(), delta.getPosition().normalize()); + final AbsoluteDate t0 = measurement.getSatellites().get(0).getClockOffsetDriver().getReferenceDate(); + final double dtLocal = measurement.getDate().durationFrom(t0); + final double localRate = 2 * localClockAcceleration * dtLocal + localClockRate; + final double dtRemote = participants[0].getDate().durationFrom(t0); + final double remoteRate = 2 * remoteClockAcceleration * dtRemote + remoteClockRate; + Assertions.assertEquals(radialVelocity + Constants.SPEED_OF_LIGHT * (localRate - remoteRate), + estimated.getEstimatedValue()[0], + 1.0e-7); + + final double rangeRateEstimated = estimated.getEstimatedValue()[0]; + final double absoluteError = rangeRateEstimated-rangeRateObserved; + absoluteErrors.add(absoluteError); + relativeErrors.add(FastMath.abs(absoluteError)/FastMath.abs(rangeRateObserved)); + + // Print results on console ? + if (printResults) { + final AbsoluteDate measurementDate = measurement.getDate(); + + System.out.format(Locale.US, "%-23s %-23s %19.6f %19.6f %13.6e %13.6e%n", + measurementDate.toStringWithoutUtcOffset(context.utc, 3), + date.toStringWithoutUtcOffset(context.utc, 3), + rangeRateObserved, rangeRateEstimated, + FastMath.abs(rangeRateEstimated-rangeRateObserved), + FastMath.abs((rangeRateEstimated-rangeRateObserved)/rangeRateObserved)); + } + + } // End if measurement date between previous and current interpolator step + } // End for loop on the measurements + }); // End lambda function handlestep + + // Print results on console ? Header + if (printResults) { + System.out.format(Locale.US, "%-23s %-23s %19s %19s %19s %19s%n", + "Measurement Date", "State Date", + "range rate observed [m/s]", "range rate estimated [m/s]", + "Δrange rate [m/s]", "rel Δrange rate"); + } + + // Rewind the propagator to initial date + propagator.propagate(context.initialOrbit.getDate()); + + // Sort measurements chronologically + measurements.sort(Comparator.naturalOrder()); + + // Propagate to final measurement's date + propagator.propagate(measurements.get(measurements.size()-1).getDate()); + + // Convert lists to double array + final double[] absErrors = absoluteErrors.stream().mapToDouble(Double::doubleValue).toArray(); + final double[] relErrors = relativeErrors.stream().mapToDouble(Double::doubleValue).toArray(); + + // Statistics' assertion + final double absErrorsMedian = new Median().evaluate(absErrors); + final double absErrorsMin = new Min().evaluate(absErrors); + final double absErrorsMax = new Max().evaluate(absErrors); + final double relErrorsMedian = new Median().evaluate(relErrors); + final double relErrorsMax = new Max().evaluate(relErrors); + + // Print the results on console ? Final results + if (printResults) { + System.out.println(); + System.out.println("Absolute errors median: " + absErrorsMedian); + System.out.println("Absolute errors min : " + absErrorsMin); + System.out.println("Absolute errors max : " + absErrorsMax); + System.out.println("Relative errors median: " + relErrorsMedian); + System.out.println("Relative errors max : " + relErrorsMax); + } + + Assertions.assertEquals(0.0, absErrorsMedian, 3.7e-09); + Assertions.assertEquals(0.0, absErrorsMin, 2.6e-11); + Assertions.assertEquals(0.0, absErrorsMax, 1.5e-08); + Assertions.assertEquals(0.0, relErrorsMedian, 9.9e-10); + Assertions.assertEquals(0.0, relErrorsMax, 5.7e-8); + + // Test measurement type + Assertions.assertEquals(InterSatellitesOneWayRangeRate.MEASUREMENT_TYPE, measurements.get(0).getMeasurementType()); + } + + void genericTestStateDerivatives(final boolean printResults, final int index, + final double refErrorsPMedian, final double refErrorsPMean, final double refErrorsPMax, + final double refErrorsVMedian, final double refErrorsVMean, final double refErrorsVMax) { + + Context context = EstimationTestUtils.eccentricContext("regular-data:potential:tides"); + + final NumericalPropagatorBuilder propagatorBuilder = + context.createBuilder(OrbitType.KEPLERIAN, PositionAngleType.TRUE, true, + 1.0e-6, 60.0, 0.001); + + // Create perfect inter-satellites range rate measurements + final TimeStampedPVCoordinates original = context.initialOrbit.getPVCoordinates(); + final Orbit closeOrbit = new CartesianOrbit(new TimeStampedPVCoordinates(context.initialOrbit.getDate(), + original.getPosition().add(new Vector3D(1000, 2000, 3000)), + original.getVelocity().add(new Vector3D(-0.03, 0.01, 0.02))), + context.initialOrbit.getFrame(), + context.initialOrbit.getMu()); + final Propagator closePropagator = EstimationTestUtils.createPropagator(closeOrbit, + propagatorBuilder); + final EphemerisGenerator generator = closePropagator.getEphemerisGenerator(); + closePropagator.propagate(context.initialOrbit.getDate().shiftedBy(3.5 * closeOrbit.getKeplerianPeriod())); + final BoundedPropagator ephemeris = generator.getGeneratedEphemeris(); + final Propagator propagator = EstimationTestUtils.createPropagator(context.initialOrbit, + propagatorBuilder); + + final double localClockOffset = 0.14e-06; + final double localClockRate = -0.12e-10; + final double localClockAcceleration = 1.4e-13; + final double remoteClockOffset = 469.0e-06; + final double remoteClockRate = 33.0e-10; + final double remoteClockAcceleration = 0.5e-13; + final List> measurements = + EstimationTestUtils.createMeasurements(propagator, + new InterSatellitesOneWayRangeRateMeasurementCreator(ephemeris, + localClockOffset, localClockRate, localClockAcceleration, + remoteClockOffset, remoteClockRate, remoteClockAcceleration), + 1.0, 3.0, 300.0); + + // Lists for results' storage - Used only for derivatives with respect to state + // "final" value to be seen by "handleStep" function of the propagator + final List errorsP = new ArrayList<>(); + final List errorsV = new ArrayList<>(); + + // Use a lambda function to implement "handleStep" function + propagator.setStepHandler(interpolator -> { + + for (final ObservedMeasurement measurement : measurements) { + + // Play test if the measurement date is between interpolator previous and current date + if (measurement.getDate().isAfter(interpolator.getPreviousState()) && + measurement.getDate().isBeforeOrEqualTo(interpolator.getCurrentState())) { + + // We intentionally propagate to a date which is close to the + // real spacecraft state but is *not* the accurate date, by + // compensating only part of the downlink delay. This is done + // in order to validate the partial derivatives with respect + // to velocity. + final double meanDelay = measurement.getObservedValue()[0] / Constants.SPEED_OF_LIGHT; + final AbsoluteDate date = measurement.getDate().shiftedBy(-0.75 * meanDelay); + final SpacecraftState[] states = { + interpolator.getInterpolatedState(date), + ephemeris.propagate(date) + }; + final double[][] jacobian = measurement.estimate(0, 0, states).getStateDerivatives(index); + + // Jacobian reference value + final double[][] jacobianRef; + + // Compute a reference value using finite differences + jacobianRef = Differentiation.differentiate(state -> { + final SpacecraftState[] s = states.clone(); + s[index] = state; + return measurement.estimateWithoutDerivatives(0, 0, s).getEstimatedValue(); + }, measurement.getDimension(), propagator.getAttitudeProvider(), + OrbitType.CARTESIAN, PositionAngleType.TRUE, 2.0, 3).value(states[index]); + + Assertions.assertEquals(jacobianRef.length, jacobian.length); + Assertions.assertEquals(jacobianRef[0].length, jacobian[0].length); + + // Errors & relative errors on the Jacobian + double [][] dJacobian = new double[jacobian.length][jacobian[0].length]; + double [][] dJacobianRelative = new double[jacobian.length][jacobian[0].length]; + for (int i = 0; i < jacobian.length; ++i) { + for (int j = 0; j < jacobian[i].length; ++j) { + dJacobian[i][j] = jacobian[i][j] - jacobianRef[i][j]; + dJacobianRelative[i][j] = FastMath.abs(dJacobian[i][j]/jacobianRef[i][j]); + + if (j < 3) { + errorsP.add(dJacobianRelative[i][j]); + } else { + errorsV.add(dJacobianRelative[i][j]); + } + } + } + // Print values in console ? + if (printResults) { + System.out.format(Locale.US, "%-23s %-23s " + + "%10.3e %10.3e %10.3e " + + "%10.3e %10.3e %10.3e " + + "%10.3e %10.3e %10.3e " + + "%10.3e %10.3e %10.3e%n", + measurement.getDate().toStringWithoutUtcOffset(context.utc, 3), + date.toStringWithoutUtcOffset(context.utc, 3), + dJacobian[0][0], dJacobian[0][1], dJacobian[0][2], + dJacobian[0][3], dJacobian[0][4], dJacobian[0][5], + dJacobianRelative[0][0], dJacobianRelative[0][1], dJacobianRelative[0][2], + dJacobianRelative[0][3], dJacobianRelative[0][4], dJacobianRelative[0][5]); + } + } // End if measurement date between previous and current interpolator step + } // End for loop on the measurements + }); + + // Print results on console ? + if (printResults) { + System.out.format(Locale.US, "%-23s %-23s " + + "%10s %10s %10s " + + "%10s %10s %10s " + + "%10s %10s %10s " + + "%10s %10s %10s%n", + "Measurement Date", "State Date", + "ΔdPx", "ΔdPy", "ΔdPz", "ΔdVx", "ΔdVy", "ΔdVz", + "rel ΔdPx", "rel ΔdPy", "rel ΔdPz", + "rel ΔdVx", "rel ΔdVy", "rel ΔdVz"); + } + + // Rewind the propagator to initial date + propagator.propagate(context.initialOrbit.getDate()); + + // Sort measurements, primarily chronologically + measurements.sort(Comparator.naturalOrder()); + + // Propagate to final measurement's date + propagator.propagate(measurements.get(measurements.size()-1).getDate()); + + // Convert lists to double[] and evaluate some statistics + final double[] relErrorsP = errorsP.stream().mapToDouble(Double::doubleValue).toArray(); + final double[] relErrorsV = errorsV.stream().mapToDouble(Double::doubleValue).toArray(); + + final double errorsPMedian = new Median().evaluate(relErrorsP); + final double errorsPMean = new Mean().evaluate(relErrorsP); + final double errorsPMax = new Max().evaluate(relErrorsP); + final double errorsVMedian = new Median().evaluate(relErrorsV); + final double errorsVMean = new Mean().evaluate(relErrorsV); + final double errorsVMax = new Max().evaluate(relErrorsV); + + // Print the results on console ? + if (printResults) { + System.out.println(); + System.out.format(Locale.US, "Relative errors dR/dP -> Median: %6.3e / Mean: %6.3e / Max: %6.3e%n", + errorsPMedian, errorsPMean, errorsPMax); + System.out.format(Locale.US, "Relative errors dR/dV -> Median: %6.3e / Mean: %6.3e / Max: %6.3e%n", + errorsVMedian, errorsVMean, errorsVMax); + } + + Assertions.assertEquals(0.0, errorsPMedian, refErrorsPMedian); + Assertions.assertEquals(0.0, errorsPMean, refErrorsPMean); + Assertions.assertEquals(0.0, errorsPMax, refErrorsPMax); + Assertions.assertEquals(0.0, errorsVMedian, refErrorsVMedian); + Assertions.assertEquals(0.0, errorsVMean, refErrorsVMean); + Assertions.assertEquals(0.0, errorsVMax, refErrorsVMax); + } + + void genericTestParameterDerivatives(final boolean printResults, + final double refErrorsMedian, final double refErrorsMean, final double refErrorsMax) { + + Context context = EstimationTestUtils.eccentricContext("regular-data:potential:tides"); + + final NumericalPropagatorBuilder propagatorBuilder = + context.createBuilder(OrbitType.KEPLERIAN, PositionAngleType.TRUE, true, + 1.0e-6, 60.0, 0.001); + + // Create perfect inter-satellites range rate measurements + final TimeStampedPVCoordinates original = context.initialOrbit.getPVCoordinates(); + final Orbit closeOrbit = new CartesianOrbit(new TimeStampedPVCoordinates(context.initialOrbit.getDate(), + original.getPosition().add(new Vector3D(1000, 2000, 3000)), + original.getVelocity().add(new Vector3D(-0.03, 0.01, 0.02))), + context.initialOrbit.getFrame(), + context.initialOrbit.getMu()); + final Propagator closePropagator = EstimationTestUtils.createPropagator(closeOrbit, propagatorBuilder); + final EphemerisGenerator generator = closePropagator.getEphemerisGenerator(); + closePropagator.propagate(context.initialOrbit.getDate().shiftedBy(3.5 * closeOrbit.getKeplerianPeriod())); + final BoundedPropagator ephemeris = generator.getGeneratedEphemeris(); + + // Create perfect range rate measurements + final double localClockOffset = 0.14e-06; + final double localClockRate = -0.12e-10; + final double localClockAcceleration = 1.4e-13; + final double remoteClockOffset = 469.0e-06; + final double remoteClockRate = 33.0e-10; + final double remoteClockAcceleration = 0.5e-13; + final InterSatellitesOneWayRangeRateMeasurementCreator creator = + new InterSatellitesOneWayRangeRateMeasurementCreator(ephemeris, + localClockOffset, localClockRate, localClockAcceleration, + remoteClockOffset, remoteClockRate, remoteClockAcceleration); + creator.getLocalSatellite().getClockOffsetDriver().setSelected(true); + creator.getLocalSatellite().getClockDriftDriver().setSelected(true); + creator.getLocalSatellite().getClockAccelerationDriver().setSelected(true); + creator.getRemoteSatellite().getClockOffsetDriver().setSelected(true); + creator.getRemoteSatellite().getClockDriftDriver().setSelected(true); + creator.getRemoteSatellite().getClockAccelerationDriver().setSelected(true); + + final Propagator propagator = EstimationTestUtils.createPropagator(context.initialOrbit, + propagatorBuilder); + final List> measurements = + EstimationTestUtils.createMeasurements(propagator, creator, 1.0, 3.0, 300.0); + + // List to store the results + final List relErrorList = new ArrayList<>(); + + // Use a lambda function to implement "handleStep" function + propagator.setStepHandler(interpolator -> { + + for (final ObservedMeasurement measurement : measurements) { + + // Play test if the measurement date is between interpolator previous and current date + if (measurement.getDate().isAfter(interpolator.getPreviousState()) && + measurement.getDate().isBeforeOrEqualTo(interpolator.getCurrentState())) { + + // We intentionally propagate to a date which is close to the + // real spacecraft state but is *not* the accurate date, by + // compensating only part of the downlink delay. This is done + // in order to validate the partial derivatives with respect + // to velocity. If we had chosen the proper state date, the + // range rate would have depended only on the current position but + // not on the current velocity. + final double meanDelay = measurement.getObservedValue()[0] / Constants.SPEED_OF_LIGHT; + final AbsoluteDate date = measurement.getDate().shiftedBy(-0.75 * meanDelay); + final SpacecraftState[] states = { + interpolator.getInterpolatedState(date), + ephemeris.propagate(date) + }; + final ParameterDriver[] drivers = new ParameterDriver[] { + measurement.getSatellites().get(0).getClockOffsetDriver(), + measurement.getSatellites().get(0).getClockDriftDriver(), + measurement.getSatellites().get(0).getClockAccelerationDriver(), + measurement.getSatellites().get(1).getClockOffsetDriver(), + measurement.getSatellites().get(1).getClockDriftDriver(), + measurement.getSatellites().get(1).getClockAccelerationDriver() + }; + + for (final ParameterDriver driver : drivers) { + for (Span span = driver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) { + final double[] gradient = measurement.estimate(0, 0, states).getParameterDerivatives(driver, span.getStart()); + Assertions.assertEquals(1, measurement.getDimension()); + Assertions.assertEquals(1, gradient.length); + + // Compute a reference value using finite differences + final ParameterFunction dMkdP = + Differentiation.differentiate(new ParameterFunction() { + /** {@inheritDoc} */ + @Override + public double value(final ParameterDriver parameterDriver, final AbsoluteDate date) { + return measurement. + estimateWithoutDerivatives(0, 0, states). + getEstimatedValue()[0]; + } + }, 3, 20.0 * driver.getScale()); + final double ref = dMkdP.value(driver, span.getStart()); + + final double relError; + if (ref == 0.0) { + // this protection is because range rate is completely independent for remote clock offset + // (it depends only on remote clock rate and acceleration), so ref is exactly 0.0 + // so here we compute an absolute error and not a relative error (anyway, it is 0) + relError = ref - gradient[0]; + } else { + relError = FastMath.abs((ref - gradient[0]) / ref); + } + relErrorList.add(relError); + + if (printResults) { + System.out.format(Locale.US, "%10.3e %10.3e ", gradient[0]-ref, relError); + } + + } + } + if (printResults) { + System.out.format(Locale.US, "%n"); + } + + } // End if measurement date between previous and current interpolator step + } // End for loop on the measurements + }); + + // Rewind the propagator to initial date + propagator.propagate(context.initialOrbit.getDate()); + + // Sort measurements chronologically + measurements.sort(Comparator.naturalOrder()); + + // Print results ? Header + if (printResults) { + System.out.format(Locale.US, "%-22s %-22s %-22s %-22s %-22s %-22s%n" + + "%10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s%n", + "local offset", "local rate", "local acceleration", + "remote offset", "remote rate", "remote acceleration", + "Δoₗ", "rel Δoₗ", "Δrₗ", "rel Δrₗ", "Δaₗ", "rel Δaₗ", + "Δoᵣ", "rel Δoᵣ", "Δrᵣ", "rel Δrᵣ", "Δaᵣ", "rel Δaᵣ"); + } + + // Propagate to final measurement's date + propagator.propagate(measurements.get(measurements.size()-1).getDate()); + + // Convert error list to double[] + final double[] relErrors = relErrorList.stream().mapToDouble(Double::doubleValue).toArray(); + + // Compute statistics + final double relErrorsMedian = new Median().evaluate(relErrors); + final double relErrorsMean = new Mean().evaluate(relErrors); + final double relErrorsMax = new Max().evaluate(relErrors); + + // Print the results on console ? + if (printResults) { + System.out.println(); + System.out.format(Locale.US, "Relative errors dR/dQ -> Median: %6.3e / Mean: %6.3e / Max: %6.3e%n", + relErrorsMedian, relErrorsMean, relErrorsMax); + } + + Assertions.assertEquals(0.0, relErrorsMedian, refErrorsMedian); + Assertions.assertEquals(0.0, relErrorsMean, refErrorsMean); + Assertions.assertEquals(0.0, relErrorsMax, refErrorsMax); + + } + +} From 8231c232c5c54ea0f25caaba3d70dae33f062cb2 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Fri, 1 Mar 2024 20:38:33 +0100 Subject: [PATCH 172/359] Fixed style and javadoc warnings. --- .../estimation/measurements/QuadraticClockModel.java | 4 ++-- .../estimation/measurements/QuadraticFieldClockModel.java | 4 ++-- .../measurements/gnss/AbstractOnBoardMeasurement.java | 6 +++--- .../gnss/OnBoardCommonParametersWithDerivatives.java | 8 ++++---- .../gnss/OnBoardCommonParametersWithoutDerivatives.java | 8 ++++---- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/orekit/estimation/measurements/QuadraticClockModel.java b/src/main/java/org/orekit/estimation/measurements/QuadraticClockModel.java index 71f1e6ccb7..f7b445c7e4 100644 --- a/src/main/java/org/orekit/estimation/measurements/QuadraticClockModel.java +++ b/src/main/java/org/orekit/estimation/measurements/QuadraticClockModel.java @@ -87,7 +87,7 @@ public QuadraticClockModel(final ParameterDriver a0, final ParameterDriver a1, f this.a2 = a2; } - /** Get the clock offset at date + /** Get the clock offset at date. * @param date date at which offset is requested * @return clock offset at specified date */ @@ -96,7 +96,7 @@ public double getOffset(final AbsoluteDate date) { return (a2.getValue(date) * dt + a1.getValue(date)) * dt + a0.getValue(date); } - /** Get the clock rate at date + /** Get the clock rate at date. * @param date date at which offset is requested * @return clock rate at specified date */ diff --git a/src/main/java/org/orekit/estimation/measurements/QuadraticFieldClockModel.java b/src/main/java/org/orekit/estimation/measurements/QuadraticFieldClockModel.java index b4076240dc..06cca191f0 100644 --- a/src/main/java/org/orekit/estimation/measurements/QuadraticFieldClockModel.java +++ b/src/main/java/org/orekit/estimation/measurements/QuadraticFieldClockModel.java @@ -54,7 +54,7 @@ public QuadraticFieldClockModel(final FieldAbsoluteDate referenceDate, this.a2 = a2; } - /** Get the clock offset at date + /** Get the clock offset at date. * @param date date at which offset is requested * @return clock offset at specified date */ @@ -63,7 +63,7 @@ public T getOffset(final FieldAbsoluteDate date) { return a2.multiply(dt).add(a1).multiply(dt).add(a0); } - /** Get the clock rate at date + /** Get the clock rate at date. * @param date date at which offset is requested * @return clock rate at specified date */ diff --git a/src/main/java/org/orekit/estimation/measurements/gnss/AbstractOnBoardMeasurement.java b/src/main/java/org/orekit/estimation/measurements/gnss/AbstractOnBoardMeasurement.java index e9e5673be7..74d092e1c6 100644 --- a/src/main/java/org/orekit/estimation/measurements/gnss/AbstractOnBoardMeasurement.java +++ b/src/main/java/org/orekit/estimation/measurements/gnss/AbstractOnBoardMeasurement.java @@ -59,9 +59,9 @@ public AbstractOnBoardMeasurement(final AbsoluteDate date, final double observed // Add parameter drivers satellites.forEach(s -> { - addParameterDriver(s.getClockOffsetDriver()); - addParameterDriver(s.getClockDriftDriver()); - addParameterDriver(s.getClockAccelerationDriver()); + addParameterDriver(s.getClockOffsetDriver()); + addParameterDriver(s.getClockDriftDriver()); + addParameterDriver(s.getClockAccelerationDriver()); }); } diff --git a/src/main/java/org/orekit/estimation/measurements/gnss/OnBoardCommonParametersWithDerivatives.java b/src/main/java/org/orekit/estimation/measurements/gnss/OnBoardCommonParametersWithDerivatives.java index d7fddb0b61..a37adbb4f6 100644 --- a/src/main/java/org/orekit/estimation/measurements/gnss/OnBoardCommonParametersWithDerivatives.java +++ b/src/main/java/org/orekit/estimation/measurements/gnss/OnBoardCommonParametersWithDerivatives.java @@ -31,16 +31,16 @@ public class OnBoardCommonParametersWithDerivatives extends CommonParametersWithDerivatives { /** Local clock offset. */ - final Gradient localOffset; + private final Gradient localOffset; /** Local clock rate. */ - final Gradient localRate; + private final Gradient localRate; /** Remote clock offset. */ - final Gradient remoteOffset; + private final Gradient remoteOffset; /** Remote clock rate. */ - final Gradient remoteRate; + private final Gradient remoteRate; /** Remote satellite position/velocity. */ private final TimeStampedFieldPVCoordinates remotePV; diff --git a/src/main/java/org/orekit/estimation/measurements/gnss/OnBoardCommonParametersWithoutDerivatives.java b/src/main/java/org/orekit/estimation/measurements/gnss/OnBoardCommonParametersWithoutDerivatives.java index fcada424d5..33d5f30c82 100644 --- a/src/main/java/org/orekit/estimation/measurements/gnss/OnBoardCommonParametersWithoutDerivatives.java +++ b/src/main/java/org/orekit/estimation/measurements/gnss/OnBoardCommonParametersWithoutDerivatives.java @@ -28,16 +28,16 @@ public class OnBoardCommonParametersWithoutDerivatives extends CommonParametersWithoutDerivatives { /** Local clock offset. */ - final double localOffset; + private final double localOffset; /** Local clock rate. */ - final double localRate; + private final double localRate; /** Remote clock offset. */ - final double remoteOffset; + private final double remoteOffset; /** Remote clock rate. */ - final double remoteRate; + private final double remoteRate; /** Remote satellite position/velocity. */ private final TimeStampedPVCoordinates remotePV; From acf2e091e91728e9eef6e6a7e81bfbab37104f69 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Sun, 3 Mar 2024 18:09:43 +0100 Subject: [PATCH 173/359] Added AmbiguityDriver and AmbiguityCache. --- src/changes/changes.xml | 3 + .../modifiers/AmbiguityCache.java | 103 ++++++++++++++++++ .../modifiers/AmbiguityDriver.java | 90 +++++++++++++++ .../modifiers/AmbiguityCacheTest.java | 46 ++++++++ 4 files changed, 242 insertions(+) create mode 100644 src/main/java/org/orekit/estimation/measurements/modifiers/AmbiguityCache.java create mode 100644 src/main/java/org/orekit/estimation/measurements/modifiers/AmbiguityDriver.java create mode 100644 src/test/java/org/orekit/estimation/measurements/modifiers/AmbiguityCacheTest.java diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 58a35adc8b..e219d20eec 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -21,6 +21,9 @@ + + Added AmbiguityDriver and AmbiguityCache. + Added InterSatellitesOneWayRangeRate measurements. diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/AmbiguityCache.java b/src/main/java/org/orekit/estimation/measurements/modifiers/AmbiguityCache.java new file mode 100644 index 0000000000..ee5f5778f5 --- /dev/null +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/AmbiguityCache.java @@ -0,0 +1,103 @@ +/* Copyright 2002-2024 Luc Maisonobe + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.estimation.measurements.modifiers; + +import org.hipparchus.util.Precision; + +import java.util.HashMap; +import java.util.Map; + +/** Cache for {@link AmbiguityDriver}. + * @author Luc Maisonobe + * @since 12.1 + */ +public class AmbiguityCache { + + /** Cache map. */ + private final Map cache; + + /** Simple constructor. + */ + public AmbiguityCache() { + cache = new HashMap<>(); + } + + /** Get a cached driver for ambiguity. + *

              + * A new parameter driver is created and cached the first time an + * emitter/receiver/wavelength triplet is used; after that, the cached + * driver will be returned when the same triplet is passed again + *

              + * @param emitter emitter id + * @param receiver receiver id + * @param wavelength signal wavelength + * @return parameter driver for the emitter/receiver/wavelength triplet + */ + public AmbiguityDriver getAmbiguity(final String emitter, final String receiver, final double wavelength) { + final Key key = new Key(emitter, receiver, wavelength); + AmbiguityDriver driver = cache.get(key); + if (driver == null) { + // we need to create and cache a new parameter driver + driver = new AmbiguityDriver(emitter, receiver, wavelength); + cache.put(key, driver); + } + return driver; + } + + /** Key for the map. */ + private static class Key { + + /** Emitter id. */ + private final String emitter; + + /** Receiver id. */ + private final String receiver; + + /** Wavelength. */ + private final double wavelength; + + /** Simple constructor. + * @param emitter emitter id + * @param receiver receiver id + * @param wavelength signal wavelength + */ + Key(final String emitter, final String receiver, final double wavelength) { + this.emitter = emitter; + this.receiver = receiver; + this.wavelength = wavelength; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + return (emitter.hashCode() ^ receiver.hashCode()) ^ Double.hashCode(wavelength); + } + + /** {@inheritDoc} */ + @Override + public boolean equals(final Object object) { + if (object instanceof Key) { + final Key other = (Key) object; + return emitter.equals(other.emitter) && receiver.equals(other.receiver) && + Precision.equals(wavelength, other.wavelength, 1); + } + return false; + } + + } + +} diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/AmbiguityDriver.java b/src/main/java/org/orekit/estimation/measurements/modifiers/AmbiguityDriver.java new file mode 100644 index 0000000000..5a06e991bc --- /dev/null +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/AmbiguityDriver.java @@ -0,0 +1,90 @@ +/* Copyright 2002-2024 Luc Maisonobe + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.estimation.measurements.modifiers; + +import org.hipparchus.util.FastMath; +import org.orekit.gnss.Frequency; +import org.orekit.utils.Constants; +import org.orekit.utils.ParameterDriver; + +import java.util.Locale; + +/** Specialized {@link ParameterDriver} for ambiguity. + * @author Luc Maisonobe + * @since 12.1 + */ +public class AmbiguityDriver extends ParameterDriver { + + /** Prefix for parameter drivers names. */ + public static final String PREFIX = "ambiguity"; + + /** Ambiguity scale factor. + *

              + * We use a power of 2 to avoid numeric noise introduction + * in the multiplications/divisions sequences. + *

              + */ + private static final double AMBIGUITY_SCALE = FastMath.scalb(1.0, 26); + + /** Emitter id. */ + private final String emitter; + + /** Receiver id. */ + private final String receiver; + + /** Wavelength. */ + private final double wavelength; + + /** Simple constructor. + * @param emitter emitter id + * @param receiver receiver id + * @param wavelength signal wavelength + */ + public AmbiguityDriver(final String emitter, final String receiver, final double wavelength) { + // the name is built from emitter, receiver and the multiplier + // with respect to common frequency F0 (10.23 MHz) + super(String.format(Locale.US, "%s-%s-%s-%.2f", + PREFIX, emitter, receiver, + Constants.SPEED_OF_LIGHT / (wavelength * 1.0e6 * Frequency.F0)), + 0.0, AMBIGUITY_SCALE, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY); + this.emitter = emitter; + this.receiver = receiver; + this.wavelength = wavelength; + } + + /** Get emitter id. + * @return emitter id + */ + public String getEmitter() { + return emitter; + } + + /** Get receiver id. + * @return receiver id + */ + public String getReceiver() { + return receiver; + } + + /** Get signal wavelength. + * @return signal wavelength + */ + public double getWavelength() { + return wavelength; + } + +} diff --git a/src/test/java/org/orekit/estimation/measurements/modifiers/AmbiguityCacheTest.java b/src/test/java/org/orekit/estimation/measurements/modifiers/AmbiguityCacheTest.java new file mode 100644 index 0000000000..3525bcd82d --- /dev/null +++ b/src/test/java/org/orekit/estimation/measurements/modifiers/AmbiguityCacheTest.java @@ -0,0 +1,46 @@ +/* Copyright 2002-2024 Luc Maisonobe + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.estimation.measurements.modifiers; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.orekit.gnss.Frequency; + +public class AmbiguityCacheTest { + + @Test + public void testCache() { + final AmbiguityCache cache = new AmbiguityCache(); + final AmbiguityDriver driver01 = cache.getAmbiguity("E18", "TUKT", Frequency.E01.getWavelength()); + Assertions.assertEquals("E18", driver01.getEmitter()); + Assertions.assertEquals("TUKT", driver01.getReceiver()); + Assertions.assertEquals(Frequency.E01.getWavelength(), driver01.getWavelength(), 1.0e-10); + Assertions.assertEquals("ambiguity-E18-TUKT-154.00", driver01.getName()); + final AmbiguityDriver driver05 = cache.getAmbiguity("E18", "TUKT", Frequency.E05.getWavelength()); + Assertions.assertEquals("E18", driver05.getEmitter()); + Assertions.assertEquals("TUKT", driver05.getReceiver()); + Assertions.assertEquals(Frequency.E05.getWavelength(), driver05.getWavelength(), 1.0e-10); + Assertions.assertEquals("ambiguity-E18-TUKT-115.00", driver05.getName()); + final AmbiguityDriver driverB = cache.getAmbiguity("E19", "AGGO", Frequency.E01.getWavelength()); + Assertions.assertEquals("E19", driverB.getEmitter()); + Assertions.assertEquals("AGGO", driverB.getReceiver()); + Assertions.assertEquals(Frequency.E01.getWavelength(), driverB.getWavelength(), 1.0e-10); + Assertions.assertEquals("ambiguity-E19-AGGO-154.00", driverB.getName()); + Assertions.assertSame(driver01, cache.getAmbiguity("E18", "TUKT", Frequency.E01.getWavelength())); + } + +} From 01128af79ceead8129afdb099f23c0bfdeee65f6 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Mon, 4 Mar 2024 09:56:13 +0100 Subject: [PATCH 174/359] Fixed compilation warnings. --- src/main/java/org/orekit/estimation/measurements/TDOA.java | 1 - .../java/org/orekit/forces/maneuvers/FieldImpulseManeuver.java | 2 ++ .../gnss/InterSatellitesOneWayRangeRateMeasurementCreator.java | 1 - 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/orekit/estimation/measurements/TDOA.java b/src/main/java/org/orekit/estimation/measurements/TDOA.java index 04aa22b6f2..8430c86f8a 100644 --- a/src/main/java/org/orekit/estimation/measurements/TDOA.java +++ b/src/main/java/org/orekit/estimation/measurements/TDOA.java @@ -102,7 +102,6 @@ public GroundStation getSecondStation() { } /** {@inheritDoc} */ - @SuppressWarnings("checkstyle:WhitespaceAround") @Override protected EstimatedMeasurementBase theoreticalEvaluationWithoutDerivatives(final int iteration, final int evaluation, final SpacecraftState[] states) { diff --git a/src/main/java/org/orekit/forces/maneuvers/FieldImpulseManeuver.java b/src/main/java/org/orekit/forces/maneuvers/FieldImpulseManeuver.java index 1a03e59f67..43fa92f129 100644 --- a/src/main/java/org/orekit/forces/maneuvers/FieldImpulseManeuver.java +++ b/src/main/java/org/orekit/forces/maneuvers/FieldImpulseManeuver.java @@ -233,6 +233,7 @@ public Action eventOccurred(final FieldSpacecraftState s, final FieldEventDetector detector, final boolean increasing) { // filter underlying event + @SuppressWarnings("unchecked") final FieldImpulseManeuver im = (FieldImpulseManeuver) detector; final Action underlyingAction = im.trigger.getHandler().eventOccurred(s, im.trigger, increasing); @@ -245,6 +246,7 @@ public Action eventOccurred(final FieldSpacecraftState s, public FieldSpacecraftState resetState(final FieldEventDetector detector, final FieldSpacecraftState oldState) { + @SuppressWarnings("unchecked") final FieldImpulseManeuver im = (FieldImpulseManeuver) detector; final FieldAbsoluteDate date = oldState.getDate(); final FieldRotation rotation; diff --git a/src/test/java/org/orekit/estimation/measurements/gnss/InterSatellitesOneWayRangeRateMeasurementCreator.java b/src/test/java/org/orekit/estimation/measurements/gnss/InterSatellitesOneWayRangeRateMeasurementCreator.java index 1c22dab892..da995f83c5 100644 --- a/src/test/java/org/orekit/estimation/measurements/gnss/InterSatellitesOneWayRangeRateMeasurementCreator.java +++ b/src/test/java/org/orekit/estimation/measurements/gnss/InterSatellitesOneWayRangeRateMeasurementCreator.java @@ -16,7 +16,6 @@ */ package org.orekit.estimation.measurements.gnss; -import org.hipparchus.analysis.UnivariateFunction; import org.hipparchus.analysis.solvers.BracketingNthOrderBrentSolver; import org.hipparchus.analysis.solvers.UnivariateSolver; import org.hipparchus.geometry.euclidean.threed.Vector3D; From 6365d1444a2b2669b0fe621a6cc23cbb42aa490a Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Mon, 4 Mar 2024 09:58:27 +0100 Subject: [PATCH 175/359] Fixed leaked resources in tests. --- .../orekit/bodies/PredefinedIAUPolesTest.java | 85 ++++++++++--------- .../java/org/orekit/bodies/SolarBodyTest.java | 61 ++++++------- 2 files changed, 74 insertions(+), 72 deletions(-) diff --git a/src/test/java/org/orekit/bodies/PredefinedIAUPolesTest.java b/src/test/java/org/orekit/bodies/PredefinedIAUPolesTest.java index 2cbc96aede..092ede0d91 100644 --- a/src/test/java/org/orekit/bodies/PredefinedIAUPolesTest.java +++ b/src/test/java/org/orekit/bodies/PredefinedIAUPolesTest.java @@ -82,50 +82,51 @@ public void testSun() throws UnsupportedEncodingException, IOException { public void testNaif() throws UnsupportedEncodingException, IOException { final TimeScale tdb = TimeScalesFactory.getTDB(); final InputStream inEntry = getClass().getResourceAsStream("/naif/IAU-pole-NAIF.txt"); - BufferedReader reader = new BufferedReader(new InputStreamReader(inEntry, StandardCharsets.UTF_8)); - for (String line = reader.readLine(); line != null; line = reader.readLine()) { - line = line.trim(); - if (!line.isEmpty() && !line.startsWith("#")) { - - // extract reference data from Naif - String[] fields = line.split("\\s+"); - final AbsoluteDate date1 = new AbsoluteDate(fields[0], tdb); - final AbsoluteDate date2 = new AbsoluteDate(AbsoluteDate.J2000_EPOCH, - Double.parseDouble(fields[1]), - tdb); - final EphemerisType type = EphemerisType.valueOf(fields[2]); - final double alphaRef = Double.parseDouble(fields[3]); - final double deltaRef = Double.parseDouble(fields[4]); - final double wRef = Double.parseDouble(fields[5]); - final double[][] m = new double[3][3]; - int index = 6; - for (int i = 0; i < 3; ++i) { - for (int j = 0; j < 3; ++j) { - // we transpose the matrix to get the transform - // from ICRF to body frame - m[j][i] = Double.parseDouble(fields[index++]); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(inEntry, StandardCharsets.UTF_8))) { + for (String line = reader.readLine(); line != null; line = reader.readLine()) { + line = line.trim(); + if (!line.isEmpty() && !line.startsWith("#")) { + + // extract reference data from Naif + String[] fields = line.split("\\s+"); + final AbsoluteDate date1 = new AbsoluteDate(fields[0], tdb); + final AbsoluteDate date2 = new AbsoluteDate(AbsoluteDate.J2000_EPOCH, + Double.parseDouble(fields[1]), + tdb); + final EphemerisType type = EphemerisType.valueOf(fields[2]); + final double alphaRef = Double.parseDouble(fields[3]); + final double deltaRef = Double.parseDouble(fields[4]); + final double wRef = Double.parseDouble(fields[5]); + final double[][] m = new double[3][3]; + int index = 6; + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + // we transpose the matrix to get the transform + // from ICRF to body frame + m[j][i] = Double.parseDouble(fields[index++]); + } } - } - Rotation rRef = new Rotation(m, 1.0e-10); - - // check pole - IAUPole iauPole = PredefinedIAUPoles.getIAUPole(type, timeScales); - Vector3D pole = iauPole.getPole(date2); - double w = iauPole.getPrimeMeridianAngle(date2); - Assertions.assertEquals(0.0, date2.durationFrom(date1), 8.0e-5); - Assertions.assertEquals(alphaRef, MathUtils.normalizeAngle(pole.getAlpha(), alphaRef), 1.8e-15); - Assertions.assertEquals(deltaRef, pole.getDelta(), 2.4e-13); - Assertions.assertEquals(wRef, MathUtils.normalizeAngle(w, wRef), 2.5e-12); - - // check matrix - Vector3D qNode = Vector3D.crossProduct(Vector3D.PLUS_K, pole); - if (qNode.getNormSq() < Precision.SAFE_MIN) { - qNode = Vector3D.PLUS_I; - } - final Rotation rotation = new Rotation(Vector3D.PLUS_K, wRef, RotationConvention.FRAME_TRANSFORM). - applyTo(new Rotation(pole, qNode, Vector3D.PLUS_K, Vector3D.PLUS_I)); - Assertions.assertEquals(0.0, Rotation.distance(rRef, rotation), 1.9e-15); + Rotation rRef = new Rotation(m, 1.0e-10); + + // check pole + IAUPole iauPole = PredefinedIAUPoles.getIAUPole(type, timeScales); + Vector3D pole = iauPole.getPole(date2); + double w = iauPole.getPrimeMeridianAngle(date2); + Assertions.assertEquals(0.0, date2.durationFrom(date1), 8.0e-5); + Assertions.assertEquals(alphaRef, MathUtils.normalizeAngle(pole.getAlpha(), alphaRef), 1.8e-15); + Assertions.assertEquals(deltaRef, pole.getDelta(), 2.4e-13); + Assertions.assertEquals(wRef, MathUtils.normalizeAngle(w, wRef), 2.5e-12); + + // check matrix + Vector3D qNode = Vector3D.crossProduct(Vector3D.PLUS_K, pole); + if (qNode.getNormSq() < Precision.SAFE_MIN) { + qNode = Vector3D.PLUS_I; + } + final Rotation rotation = new Rotation(Vector3D.PLUS_K, wRef, RotationConvention.FRAME_TRANSFORM). + applyTo(new Rotation(pole, qNode, Vector3D.PLUS_K, Vector3D.PLUS_I)); + Assertions.assertEquals(0.0, Rotation.distance(rRef, rotation), 1.9e-15); + } } } } diff --git a/src/test/java/org/orekit/bodies/SolarBodyTest.java b/src/test/java/org/orekit/bodies/SolarBodyTest.java index fa8617dadc..86357a02c4 100644 --- a/src/test/java/org/orekit/bodies/SolarBodyTest.java +++ b/src/test/java/org/orekit/bodies/SolarBodyTest.java @@ -70,37 +70,38 @@ public void testNaif() throws UnsupportedEncodingException, IOException { final Frame refFrame = FramesFactory.getICRF(); final TimeScale tdb = TimeScalesFactory.getTDB(); final InputStream inEntry = getClass().getResourceAsStream("/naif/DE431-ephemeris-NAIF.txt"); - BufferedReader reader = new BufferedReader(new InputStreamReader(inEntry, StandardCharsets.UTF_8)); - for (String line = reader.readLine(); line != null; line = reader.readLine()) { - line = line.trim(); - if (!line.isEmpty() && !line.startsWith("#")) { - - // extract reference data from Naif - String[] fields = line.split("\\s+"); - final AbsoluteDate date1 = new AbsoluteDate(fields[0], tdb); - final AbsoluteDate date2 = new AbsoluteDate(AbsoluteDate.J2000_EPOCH, - Double.parseDouble(fields[1]), - tdb); - String name = fields[2]; - final String barycenter = fields[3]; - final Vector3D pRef = new Vector3D(Double.parseDouble(fields[4]) * 1000.0, - Double.parseDouble(fields[5]) * 1000.0, - Double.parseDouble(fields[6]) * 1000.0); - final Vector3D vRef = new Vector3D(Double.parseDouble(fields[7]) * 1000.0, - Double.parseDouble(fields[8]) * 1000.0, - Double.parseDouble(fields[9]) * 1000.0); - - // check position-velocity - Assertions.assertEquals("BARYCENTER", barycenter); - if (name.equals("EARTH")) { - name = "EARTH-MOON BARYCENTER"; + try (BufferedReader reader = new BufferedReader(new InputStreamReader(inEntry, StandardCharsets.UTF_8))) { + for (String line = reader.readLine(); line != null; line = reader.readLine()) { + line = line.trim(); + if (!line.isEmpty() && !line.startsWith("#")) { + + // extract reference data from Naif + String[] fields = line.split("\\s+"); + final AbsoluteDate date1 = new AbsoluteDate(fields[0], tdb); + final AbsoluteDate date2 = new AbsoluteDate(AbsoluteDate.J2000_EPOCH, + Double.parseDouble(fields[1]), + tdb); + String name = fields[2]; + final String barycenter = fields[3]; + final Vector3D pRef = new Vector3D(Double.parseDouble(fields[4]) * 1000.0, + Double.parseDouble(fields[5]) * 1000.0, + Double.parseDouble(fields[6]) * 1000.0); + final Vector3D vRef = new Vector3D(Double.parseDouble(fields[7]) * 1000.0, + Double.parseDouble(fields[8]) * 1000.0, + Double.parseDouble(fields[9]) * 1000.0); + + // check position-velocity + Assertions.assertEquals("BARYCENTER", barycenter); + if (name.equals("EARTH")) { + name = "EARTH-MOON BARYCENTER"; + } + Assertions.assertEquals(0.0, date2.durationFrom(date1), 8.0e-5); + final PVCoordinates pv = CelestialBodyFactory.getBody(name).getPVCoordinates(date2, + refFrame); + + Assertions.assertEquals(0.0, Vector3D.distance(pRef, pv.getPosition()), 15.0); + Assertions.assertEquals(0.0, Vector3D.distance(vRef, pv.getVelocity()), 1.0e-5); } - Assertions.assertEquals(0.0, date2.durationFrom(date1), 8.0e-5); - final PVCoordinates pv = CelestialBodyFactory.getBody(name).getPVCoordinates(date2, - refFrame); - - Assertions.assertEquals(0.0, Vector3D.distance(pRef, pv.getPosition()), 15.0); - Assertions.assertEquals(0.0, Vector3D.distance(vRef, pv.getVelocity()), 1.0e-5); } } } From dbfc3ef25a58df94aa997debc705236dfaf9ddbd Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Mon, 4 Mar 2024 10:31:22 +0100 Subject: [PATCH 176/359] Fixed compilation warnings in tests. --- .../estimation/measurements/RangeTest.java | 1 + .../maneuvers/FieldImpulseManeuverTest.java | 7 +- .../org/orekit/orbits/OrbitBlenderTest.java | 89 +++++++++ .../FieldSpacecraftStateInterpolatorTest.java | 181 ++++++++++++++++++ .../propagation/FieldSpacecraftStateTest.java | 2 - .../SpacecraftStateInterpolatorTest.java | 50 +++++ .../StateCovarianceBlenderTest.java | 101 ++++++++++ ...ianceKeplerianHermiteInterpolatorTest.java | 6 +- .../FieldEcksteinHechlerPropagatorTest.java | 1 - .../FieldKeplerianPropagatorTest.java | 1 - .../events/FieldDateDetectorTest.java | 7 +- .../events/FieldEventDetectorTest.java | 4 - ...FieldEventEnablingPredicateFilterTest.java | 4 - .../LongitudeRangeCrossingDetectorTest.java | 1 - .../handlers/FieldRecordAndContinueTest.java | 1 - .../FieldIntegratedEphemerisTest.java | 1 - .../FieldNumericalPropagatorTest.java | 4 - .../FieldStepHandlerMultiplexerTest.java | 6 - .../dsst/FieldDSSTPropagatorTest.java | 2 - 19 files changed, 429 insertions(+), 40 deletions(-) diff --git a/src/test/java/org/orekit/estimation/measurements/RangeTest.java b/src/test/java/org/orekit/estimation/measurements/RangeTest.java index 415954d28b..3f764e8545 100644 --- a/src/test/java/org/orekit/estimation/measurements/RangeTest.java +++ b/src/test/java/org/orekit/estimation/measurements/RangeTest.java @@ -184,6 +184,7 @@ public void testParameterDerivativesWithEstimatedModifier() { * Generic test function for values of the range * @param printResults Print the results ? */ + @SuppressWarnings("deprecation") void genericTestValues(final boolean printResults) { Context context = EstimationTestUtils.eccentricContext("regular-data:potential:tides"); diff --git a/src/test/java/org/orekit/forces/maneuvers/FieldImpulseManeuverTest.java b/src/test/java/org/orekit/forces/maneuvers/FieldImpulseManeuverTest.java index 0b58c35fc7..581a8f9186 100644 --- a/src/test/java/org/orekit/forces/maneuvers/FieldImpulseManeuverTest.java +++ b/src/test/java/org/orekit/forces/maneuvers/FieldImpulseManeuverTest.java @@ -148,7 +148,6 @@ void testComplexConstructors() { final FieldVector3D deltaV = new FieldVector3D<>(complexField, Vector3D.PLUS_I); final FieldAbsoluteDate fieldAbsoluteDate = new FieldAbsoluteDate<>(complexField, AbsoluteDate.ARBITRARY_EPOCH); - @SuppressWarnings("unchecked") final FieldDateDetector dateDetector = new FieldDateDetector<>(complexField, fieldAbsoluteDate).withThreshold(zero.add(100.)); // When @@ -172,7 +171,6 @@ void testDeltaVNorm() { final FieldVector3D deltaV = new FieldVector3D<>(complexField, Vector3D.PLUS_I); final FieldAbsoluteDate fieldAbsoluteDate = new FieldAbsoluteDate<>(complexField, AbsoluteDate.ARBITRARY_EPOCH); - @SuppressWarnings("unchecked") final FieldDateDetector dateDetector = new FieldDateDetector<>(complexField, fieldAbsoluteDate); // When @@ -242,7 +240,6 @@ private > FieldImpulseManeuver fieldDetector; if (detector instanceof DateDetector) { - @SuppressWarnings("unchecked") FieldDateDetector dateDetector = new FieldDateDetector<>(field, new FieldAbsoluteDate<>(field, ((DateDetector) detector).getDate())); fieldDetector = dateDetector; @@ -467,10 +464,8 @@ void testVersusCartesianStateTransitionMatrix() { propagator.addEventDetector(dateDetector); propagator.setOrbitType(OrbitType.CARTESIAN); final Gradient zero = field.getZero(); - @SuppressWarnings("unchecked") final FieldDateDetector fieldDateDetector = - new FieldDateDetector<>(field, - new FieldAbsoluteDate<>(field, dateDetector.getDate())); + new FieldDateDetector<>(field, new FieldAbsoluteDate<>(field, dateDetector.getDate())); final FieldVector3D fieldDeltaV = new FieldVector3D<>( Gradient.variable(freeParameters, 0, 0.), Gradient.variable(freeParameters, 1, 0.), diff --git a/src/test/java/org/orekit/orbits/OrbitBlenderTest.java b/src/test/java/org/orekit/orbits/OrbitBlenderTest.java index 394bb5dd6a..9965ef694a 100644 --- a/src/test/java/org/orekit/orbits/OrbitBlenderTest.java +++ b/src/test/java/org/orekit/orbits/OrbitBlenderTest.java @@ -225,6 +225,31 @@ void testKeplerianQuadraticBlendingOnSergeiCase() { final AbstractAnalyticalPropagator propagator = new KeplerianPropagator(sergeiOrbit); final OrbitBlender orbitBlender = new OrbitBlender(quadratic, propagator, sergeiFrame); + final TimeInterpolator stateInterpolator = + new SpacecraftStateInterpolator(2, 1.0e-3, sergeiFrame, orbitBlender, null, null, null, null); + + // When & Then + doTestInterpolation(stateInterpolator, DEFAULT_SERGEI_PROPAGATION_TIME, DEFAUTL_SERGEI_TABULATED_TIMESTEP, + 0.05185755740700528, + 0.08169252246167892, + 0.05262772652596856, + 0.08349987869494085, + 0.10151652739088853, + 0.14827634525717634, + 1e-17, false); + } + + @SuppressWarnings("deprecation") + @Test + @DisplayName("non regression test on Keplerian quadratic orbit blending on full force model test case from : " + + "TANYGIN, Sergei. Efficient covariance interpolation using blending of approximate covariance propagations. " + + "The Journal of the Astronautical Sciences, 2014, vol. 61, no 1, p. 107-132.") + void testKeplerianQuadraticBlendingOnSergeiCaseDeprecated() { + // Given + final SmoothStepFactory.SmoothStepFunction quadratic = SmoothStepFactory.getQuadratic(); + final AbstractAnalyticalPropagator propagator = new KeplerianPropagator(sergeiOrbit); + final OrbitBlender orbitBlender = new OrbitBlender(quadratic, propagator, sergeiFrame); + final TimeInterpolator stateInterpolator = new SpacecraftStateInterpolator(sergeiFrame, orbitBlender, null, null, null, null); @@ -257,6 +282,39 @@ void testBrouwerLyddaneQuadraticBlendingOnSergeiCase() { Constants.EIGEN5C_EARTH_C50, 0); final OrbitBlender orbitBlender = new OrbitBlender(quadratic, propagator, sergeiFrame); + final TimeInterpolator stateInterpolator = + new SpacecraftStateInterpolator(2, 1.0e-3, sergeiFrame, orbitBlender, null, null, null, null); + + // When & Then + doTestInterpolation(stateInterpolator, DEFAULT_SERGEI_PROPAGATION_TIME, DEFAUTL_SERGEI_TABULATED_TIMESTEP, + 0.05106377388516059, + 0.03671310671380644, + 0.05451875412478483, + 0.03654640625064279, + 0.09412869297314610, + 0.06642996306635666, + 1e-13, false); + } + + @SuppressWarnings("deprecation") + @Test + @DisplayName("non regression test on Brouwer-Lyddane quadratic orbit blending on full force model test case from : " + + "TANYGIN, Sergei. Efficient covariance interpolation using blending of approximate covariance propagations. " + + "The Journal of the Astronautical Sciences, 2014, vol. 61, no 1, p. 107-132.") + void testBrouwerLyddaneQuadraticBlendingOnSergeiCaseDeprecated() { + // Given + final SpacecraftState sergeiState = StateCovarianceKeplerianHermiteInterpolatorTest.generateSergeiReferenceState(); + final Frame sergeiFrame = sergeiState.getFrame(); + + final SmoothStepFactory.SmoothStepFunction quadratic = SmoothStepFactory.getQuadratic(); + final AbstractAnalyticalPropagator propagator = + new BrouwerLyddanePropagator(sergeiState.getOrbit(), sergeiState.getMass(), + Constants.EIGEN5C_EARTH_EQUATORIAL_RADIUS, + Constants.EIGEN5C_EARTH_MU, Constants.EIGEN5C_EARTH_C20, + Constants.EIGEN5C_EARTH_C30, Constants.EIGEN5C_EARTH_C40, + Constants.EIGEN5C_EARTH_C50, 0); + final OrbitBlender orbitBlender = new OrbitBlender(quadratic, propagator, sergeiFrame); + final TimeInterpolator stateInterpolator = new SpacecraftStateInterpolator(sergeiFrame, orbitBlender, null, null, null, null); @@ -286,6 +344,37 @@ void testEcksteinHechlerQuadraticBlendingOnSergeiCase() { Constants.EIGEN5C_EARTH_C50, Constants.EIGEN5C_EARTH_C60); final OrbitBlender orbitBlender = new OrbitBlender(quadratic, propagator, sergeiFrame); + final TimeInterpolator stateInterpolator = + new SpacecraftStateInterpolator(2, 1.0e-3, sergeiFrame, orbitBlender, null, null, null, null); + + // When & Then + doTestInterpolation(stateInterpolator, DEFAULT_SERGEI_PROPAGATION_TIME, DEFAUTL_SERGEI_TABULATED_TIMESTEP, + 0.00854503692536256, + 0.01192593187393609, + 0.00895077301610845, + 0.01299681289409554, + 0.01600030634518512, + 0.01743228687362160, + 1e-17, false); + + } + + @SuppressWarnings("deprecation") + @Test + @DisplayName("non regression test on Eckstein-Hechler quadratic orbit blending on full force model test case from : " + + "TANYGIN, Sergei. Efficient covariance interpolation using blending of approximate covariance propagations. " + + "The Journal of the Astronautical Sciences, 2014, vol. 61, no 1, p. 107-132.") + void testEcksteinHechlerQuadraticBlendingOnSergeiCaseDeprecated() { + // Given + final SmoothStepFactory.SmoothStepFunction quadratic = SmoothStepFactory.getQuadratic(); + final AbstractAnalyticalPropagator propagator = + new EcksteinHechlerPropagator(sergeiState.getOrbit(), sergeiState.getMass(), + Constants.EIGEN5C_EARTH_EQUATORIAL_RADIUS, + Constants.EIGEN5C_EARTH_MU, Constants.EIGEN5C_EARTH_C20, + Constants.EIGEN5C_EARTH_C30, Constants.EIGEN5C_EARTH_C40, + Constants.EIGEN5C_EARTH_C50, Constants.EIGEN5C_EARTH_C60); + final OrbitBlender orbitBlender = new OrbitBlender(quadratic, propagator, sergeiFrame); + final TimeInterpolator stateInterpolator = new SpacecraftStateInterpolator(sergeiFrame, orbitBlender, null, null, null, null); diff --git a/src/test/java/org/orekit/propagation/FieldSpacecraftStateInterpolatorTest.java b/src/test/java/org/orekit/propagation/FieldSpacecraftStateInterpolatorTest.java index 5e26c3dc41..f7f2c687fb 100644 --- a/src/test/java/org/orekit/propagation/FieldSpacecraftStateInterpolatorTest.java +++ b/src/test/java/org/orekit/propagation/FieldSpacecraftStateInterpolatorTest.java @@ -188,6 +188,43 @@ public void testErrorThrownWhenOneInterpolatorIsNotConsistentWithSampleSize() { Mockito.when(massInterpolator.getSubInterpolators()).thenReturn(Collections.singletonList(massInterpolator)); Mockito.when(massInterpolator.getNbInterpolationPoints()).thenReturn(2); + final FieldSpacecraftStateInterpolator stateInterpolator = + new FieldSpacecraftStateInterpolator<>(2, 1.0e-3, outputFrame, orbitInterpolator, absPVInterpolator, massInterpolator, + null, null); + + // WHEN & THEN + OrekitIllegalArgumentException thrown = Assertions.assertThrows(OrekitIllegalArgumentException.class, () -> + AbstractFieldTimeInterpolator.checkInterpolatorCompatibilityWithSampleSize(stateInterpolator, 2)); + + Assertions.assertEquals(OrekitMessages.NOT_ENOUGH_DATA, thrown.getSpecifier()); + Assertions.assertEquals(2, ((Integer) thrown.getParts()[0]).intValue()); + + } + + @SuppressWarnings("deprecation") + @Test + public void testErrorThrownWhenOneInterpolatorIsNotConsistentWithSampleSizeDeprecated() { + // GIVEN + final Frame outputFrame = Mockito.mock(Frame.class); + + @SuppressWarnings("unchecked") + final FieldTimeInterpolator, Binary64> orbitInterpolator = + Mockito.mock(FieldTimeInterpolator.class); + Mockito.when(orbitInterpolator.getSubInterpolators()).thenReturn(Collections.singletonList(orbitInterpolator)); + Mockito.when(orbitInterpolator.getNbInterpolationPoints()).thenReturn(2); + + @SuppressWarnings("unchecked") + final FieldTimeInterpolator, Binary64> absPVInterpolator = + Mockito.mock(FieldTimeInterpolator.class); + Mockito.when(absPVInterpolator.getSubInterpolators()).thenReturn(Collections.singletonList(absPVInterpolator)); + Mockito.when(absPVInterpolator.getNbInterpolationPoints()).thenReturn(4); + + @SuppressWarnings("unchecked") + final FieldTimeInterpolator, Binary64> massInterpolator = + Mockito.mock(FieldTimeInterpolator.class); + Mockito.when(massInterpolator.getSubInterpolators()).thenReturn(Collections.singletonList(massInterpolator)); + Mockito.when(massInterpolator.getNbInterpolationPoints()).thenReturn(2); + final FieldSpacecraftStateInterpolator stateInterpolator = new FieldSpacecraftStateInterpolator<>(outputFrame, orbitInterpolator, absPVInterpolator, massInterpolator, null, null); @@ -540,6 +577,59 @@ void testGetNbInterpolationsWithMultipleSubInterpolators() { Mockito.when(attitudeInterpolator.getSubInterpolators()).thenReturn(Collections.singletonList(attitudeInterpolator)); Mockito.when(additionalStateInterpolator.getSubInterpolators()).thenReturn(Collections.singletonList(additionalStateInterpolator)); + final FieldSpacecraftStateInterpolator stateInterpolator = + new FieldSpacecraftStateInterpolator<>(2, 1.0e-3, frame, orbitInterpolator, absPVAInterpolator, massInterpolator, + attitudeInterpolator, additionalStateInterpolator); + + // WHEN + final int returnedNbInterpolationPoints = stateInterpolator.getNbInterpolationPoints(); + + // THEN + Assertions.assertEquals(AdditionalStateNbInterpolationPoints, returnedNbInterpolationPoints); + } + + @SuppressWarnings("deprecation") + @Test + void testGetNbInterpolationsWithMultipleSubInterpolatorsDeprecated() { + // GIVEN + // Create mock interpolators + final Frame frame = Mockito.mock(Frame.class); + + @SuppressWarnings("unchecked") + final FieldTimeInterpolator, Binary64> orbitInterpolator = + Mockito.mock(FieldOrbitHermiteInterpolator.class); + @SuppressWarnings("unchecked") + final FieldTimeInterpolator, Binary64> absPVAInterpolator = + Mockito.mock(FieldAbsolutePVCoordinatesHermiteInterpolator.class); + @SuppressWarnings("unchecked") + final FieldTimeInterpolator, Binary64> massInterpolator = + Mockito.mock(TimeStampedFieldHermiteInterpolator.class); + @SuppressWarnings("unchecked") + final FieldTimeInterpolator, Binary64> attitudeInterpolator = + Mockito.mock(FieldAttitudeInterpolator.class); + @SuppressWarnings("unchecked") + final FieldTimeInterpolator, Binary64> additionalStateInterpolator = + Mockito.mock(TimeStampedFieldHermiteInterpolator.class); + + // Implement mocks behaviours + final int orbitNbInterpolationPoints = 2; + final int absPVANbInterpolationPoints = 3; + final int massNbInterpolationPoints = 4; + final int AttitudeNbInterpolationPoints = 5; + final int AdditionalStateNbInterpolationPoints = 6; + + Mockito.when(orbitInterpolator.getNbInterpolationPoints()).thenReturn(orbitNbInterpolationPoints); + Mockito.when(absPVAInterpolator.getNbInterpolationPoints()).thenReturn(absPVANbInterpolationPoints); + Mockito.when(massInterpolator.getNbInterpolationPoints()).thenReturn(massNbInterpolationPoints); + Mockito.when(attitudeInterpolator.getNbInterpolationPoints()).thenReturn(AttitudeNbInterpolationPoints); + Mockito.when(additionalStateInterpolator.getNbInterpolationPoints()).thenReturn(AdditionalStateNbInterpolationPoints); + + Mockito.when(orbitInterpolator.getSubInterpolators()).thenReturn(Collections.singletonList(orbitInterpolator)); + Mockito.when(absPVAInterpolator.getSubInterpolators()).thenReturn(Collections.singletonList(absPVAInterpolator)); + Mockito.when(massInterpolator.getSubInterpolators()).thenReturn(Collections.singletonList(massInterpolator)); + Mockito.when(attitudeInterpolator.getSubInterpolators()).thenReturn(Collections.singletonList(attitudeInterpolator)); + Mockito.when(additionalStateInterpolator.getSubInterpolators()).thenReturn(Collections.singletonList(additionalStateInterpolator)); + final FieldSpacecraftStateInterpolator stateInterpolator = new FieldSpacecraftStateInterpolator<>(frame, orbitInterpolator, absPVAInterpolator, massInterpolator, attitudeInterpolator, additionalStateInterpolator); @@ -599,6 +689,24 @@ void testErrorThrownWhenGivingNoInterpolatorForState() { final Frame inertialFrameMock = Mockito.mock(Frame.class); Mockito.when(inertialFrameMock.isPseudoInertial()).thenReturn(true); + // When & Then + Exception thrown = Assertions.assertThrows(OrekitIllegalArgumentException.class, + () -> new FieldSpacecraftStateInterpolator<>(2, 1.0e-3, inertialFrameMock, + null, null, null, null, + null)); + + Assertions.assertEquals("creating a spacecraft state interpolator requires at least one orbit interpolator or an " + + "absolute position-velocity-acceleration interpolator", thrown.getMessage()); + } + + @SuppressWarnings("deprecation") + @Test + @DisplayName("test error thrown when using no interpolator for state") + void testErrorThrownWhenGivingNoInterpolatorForStateDeprecated() { + // Given + final Frame inertialFrameMock = Mockito.mock(Frame.class); + Mockito.when(inertialFrameMock.isPseudoInertial()).thenReturn(true); + // When & Then Exception thrown = Assertions.assertThrows(OrekitIllegalArgumentException.class, () -> new FieldSpacecraftStateInterpolator<>(inertialFrameMock, @@ -621,6 +729,36 @@ void testErrorThrownWhenGivingEmptySample() { final List> states = new ArrayList<>(); + // Create interpolator + @SuppressWarnings("unchecked") + final FieldTimeInterpolator, Binary64> orbitInterpolatorMock = + Mockito.mock(FieldTimeInterpolator.class); + + final FieldTimeInterpolator, Binary64> interpolator = + new FieldSpacecraftStateInterpolator<>(2, 1.0e-3, inertialFrame, orbitInterpolatorMock, null, null, null, null); + + // When & Then + OrekitIllegalArgumentException thrown = Assertions.assertThrows(OrekitIllegalArgumentException.class, () -> + interpolator.interpolate(interpolationDate, states)); + + Assertions.assertEquals(OrekitMessages.NOT_ENOUGH_DATA, thrown.getSpecifier()); + Assertions.assertEquals(0, ((Integer) thrown.getParts()[0]).intValue()); + + } + + @SuppressWarnings("deprecation") + @Test + @DisplayName("test error thrown when giving empty sample") + void testErrorThrownWhenGivingEmptySampleDeprecated() { + // Given + + @SuppressWarnings("unchecked") + final FieldAbsoluteDate interpolationDate = Mockito.mock(FieldAbsoluteDate.class); + + final Frame inertialFrame = FramesFactory.getEME2000(); + + final List> states = new ArrayList<>(); + // Create interpolator @SuppressWarnings("unchecked") final FieldTimeInterpolator, Binary64> orbitInterpolatorMock = @@ -644,6 +782,49 @@ void testFieldSpacecraftStateInterpolatorCreation() { final Frame inertialFrameMock = Mockito.mock(Frame.class); Mockito.when(inertialFrameMock.isPseudoInertial()).thenReturn(true); + @SuppressWarnings("unchecked") + final FieldTimeInterpolator, Binary64> orbitInterpolatorMock = + Mockito.mock(FieldTimeInterpolator.class); + + @SuppressWarnings("unchecked") + final FieldTimeInterpolator, Binary64> absPVInterpolatorMock = + Mockito.mock(FieldTimeInterpolator.class); + + @SuppressWarnings("unchecked") + final FieldTimeInterpolator, Binary64> massInterpolatorMock = + Mockito.mock(FieldTimeInterpolator.class); + + @SuppressWarnings("unchecked") + final FieldTimeInterpolator, Binary64> attitudeInterpolatorMock = + Mockito.mock(FieldTimeInterpolator.class); + + @SuppressWarnings("unchecked") + final FieldTimeInterpolator, Binary64> additionalInterpolatorMock = + Mockito.mock(FieldTimeInterpolator.class); + + // When + final FieldSpacecraftStateInterpolator interpolator = + new FieldSpacecraftStateInterpolator<>(2, 1.0e-3, inertialFrameMock, orbitInterpolatorMock, absPVInterpolatorMock, + massInterpolatorMock, attitudeInterpolatorMock, + additionalInterpolatorMock); + + // Then + Assertions.assertEquals(inertialFrameMock, interpolator.getOutputFrame()); + Assertions.assertEquals(orbitInterpolatorMock, interpolator.getOrbitInterpolator().get()); + Assertions.assertEquals(absPVInterpolatorMock, interpolator.getAbsPVAInterpolator().get()); + Assertions.assertEquals(massInterpolatorMock, interpolator.getMassInterpolator().get()); + Assertions.assertEquals(attitudeInterpolatorMock, interpolator.getAttitudeInterpolator().get()); + Assertions.assertEquals(additionalInterpolatorMock, interpolator.getAdditionalStateInterpolator().get()); + + } + + @SuppressWarnings("deprecation") + @Test + void testFieldSpacecraftStateInterpolatorCreationDeprecated() { + // Given + final Frame inertialFrameMock = Mockito.mock(Frame.class); + Mockito.when(inertialFrameMock.isPseudoInertial()).thenReturn(true); + @SuppressWarnings("unchecked") final FieldTimeInterpolator, Binary64> orbitInterpolatorMock = Mockito.mock(FieldTimeInterpolator.class); diff --git a/src/test/java/org/orekit/propagation/FieldSpacecraftStateTest.java b/src/test/java/org/orekit/propagation/FieldSpacecraftStateTest.java index a3d7a21b5a..4ff344a841 100644 --- a/src/test/java/org/orekit/propagation/FieldSpacecraftStateTest.java +++ b/src/test/java/org/orekit/propagation/FieldSpacecraftStateTest.java @@ -1004,7 +1004,6 @@ private > void doTestAdditionalTestResetOnEven // Create date detector and handler FieldAbsoluteDate changeDate = date0.shiftedBy(3); - @SuppressWarnings("unchecked") FieldDateDetector dateDetector = new FieldDateDetector<>(field, changeDate). withHandler(new FieldEventHandler() { @@ -1056,7 +1055,6 @@ private > void doTestAdditionalTestResetOnEven // Create date detector and handler FieldAbsoluteDate changeDate = date0.shiftedBy(3); - @SuppressWarnings("unchecked") FieldDateDetector dateDetector = new FieldDateDetector<>(field, changeDate). withHandler(new FieldEventHandler() { diff --git a/src/test/java/org/orekit/propagation/SpacecraftStateInterpolatorTest.java b/src/test/java/org/orekit/propagation/SpacecraftStateInterpolatorTest.java index 774ea1f334..3a484b1c24 100644 --- a/src/test/java/org/orekit/propagation/SpacecraftStateInterpolatorTest.java +++ b/src/test/java/org/orekit/propagation/SpacecraftStateInterpolatorTest.java @@ -509,6 +509,56 @@ void testGetNbInterpolationsWithMultipleSubInterpolators() { Mockito.when(attitudeInterpolator.getSubInterpolators()).thenReturn(Collections.singletonList(attitudeInterpolator)); Mockito.when(additionalStateInterpolator.getSubInterpolators()).thenReturn(Collections.singletonList(additionalStateInterpolator)); + final SpacecraftStateInterpolator stateInterpolator = + new SpacecraftStateInterpolator(2, 1.0e-3, frame, orbitInterpolator, absPVAInterpolator, massInterpolator, + attitudeInterpolator, additionalStateInterpolator); + + // WHEN + final int returnedNbInterpolationPoints = stateInterpolator.getNbInterpolationPoints(); + + // THEN + Assertions.assertEquals(AdditionalStateNbInterpolationPoints, returnedNbInterpolationPoints); + } + + @SuppressWarnings("deprecation") + @Test + void testGetNbInterpolationsWithMultipleSubInterpolatorsDeprecated() { + // GIVEN + // Create mock interpolators + final Frame frame = Mockito.mock(Frame.class); + + final TimeInterpolator orbitInterpolator = Mockito.mock(OrbitHermiteInterpolator.class); + + final TimeInterpolator absPVAInterpolator = + Mockito.mock(AbsolutePVCoordinatesHermiteInterpolator.class); + + final TimeInterpolator massInterpolator = + Mockito.mock(TimeStampedDoubleHermiteInterpolator.class); + + final TimeInterpolator attitudeInterpolator = Mockito.mock(AttitudeInterpolator.class); + + final TimeInterpolator additionalStateInterpolator = + Mockito.mock(TimeStampedDoubleHermiteInterpolator.class); + + // Implement mocks behaviours + final int orbitNbInterpolationPoints = 2; + final int absPVANbInterpolationPoints = 3; + final int massNbInterpolationPoints = 4; + final int AttitudeNbInterpolationPoints = 5; + final int AdditionalStateNbInterpolationPoints = 6; + + Mockito.when(orbitInterpolator.getNbInterpolationPoints()).thenReturn(orbitNbInterpolationPoints); + Mockito.when(absPVAInterpolator.getNbInterpolationPoints()).thenReturn(absPVANbInterpolationPoints); + Mockito.when(massInterpolator.getNbInterpolationPoints()).thenReturn(massNbInterpolationPoints); + Mockito.when(attitudeInterpolator.getNbInterpolationPoints()).thenReturn(AttitudeNbInterpolationPoints); + Mockito.when(additionalStateInterpolator.getNbInterpolationPoints()).thenReturn(AdditionalStateNbInterpolationPoints); + + Mockito.when(orbitInterpolator.getSubInterpolators()).thenReturn(Collections.singletonList(orbitInterpolator)); + Mockito.when(absPVAInterpolator.getSubInterpolators()).thenReturn(Collections.singletonList(absPVAInterpolator)); + Mockito.when(massInterpolator.getSubInterpolators()).thenReturn(Collections.singletonList(massInterpolator)); + Mockito.when(attitudeInterpolator.getSubInterpolators()).thenReturn(Collections.singletonList(attitudeInterpolator)); + Mockito.when(additionalStateInterpolator.getSubInterpolators()).thenReturn(Collections.singletonList(additionalStateInterpolator)); + final SpacecraftStateInterpolator stateInterpolator = new SpacecraftStateInterpolator(frame, orbitInterpolator, absPVAInterpolator, massInterpolator, attitudeInterpolator, additionalStateInterpolator); diff --git a/src/test/java/org/orekit/propagation/StateCovarianceBlenderTest.java b/src/test/java/org/orekit/propagation/StateCovarianceBlenderTest.java index 5064859b16..2b0aefe7be 100644 --- a/src/test/java/org/orekit/propagation/StateCovarianceBlenderTest.java +++ b/src/test/java/org/orekit/propagation/StateCovarianceBlenderTest.java @@ -95,6 +95,56 @@ private void doTestBlending(final double propagationHorizon, final double tabula sergeiFrame, OrbitType.CARTESIAN, PositionAngleType.MEAN); + // Create state interpolator + final TimeInterpolator stateInterpolator = + new SpacecraftStateInterpolator(2, 1.0e-3, sergeiFrame, orbitInterpolator, null, null, null, null); + + // When + final DescriptiveStatistics[] relativeRMSSigmaError = + StateCovarianceKeplerianHermiteInterpolatorTest.computeStatisticsCovarianceInterpolationOnSergeiCase( + propagationHorizon, tabulatedTimeStep, stateInterpolator, covarianceInterpolator); + + // Then + if (showResults) { + System.out.format(Locale.US, "%35s = %20.16f%n", "relativeRMSSigmaError[0].getMean", relativeRMSSigmaError[0].getMean()); + System.out.format(Locale.US, "%35s = %20.16f%n", "relativeRMSSigmaError[1].getMean", relativeRMSSigmaError[1].getMean()); + System.out.format(Locale.US, "%35s = %20.16f%n", "relativeRMSSigmaError[0].getMedian", relativeRMSSigmaError[0].getPercentile(50)); + System.out.format(Locale.US, "%35s = %20.16f%n", "relativeRMSSigmaError[1].getMedian", relativeRMSSigmaError[1].getPercentile(50)); + System.out.format(Locale.US, "%35s = %20.16f%n", "relativeRMSSigmaError[0].getMax", relativeRMSSigmaError[0].getMax()); + System.out.format(Locale.US, "%35s = %20.16f%n", "relativeRMSSigmaError[1].getMax", relativeRMSSigmaError[1].getMax()); + + } + + // Results obtained when using modified orbit date to use truncated JPL test resource file + Assertions.assertEquals(expectedMeanRMSPositionError, relativeRMSSigmaError[0].getMean(), tolerance); + Assertions.assertEquals(expectedMeanRMSVelocityError, relativeRMSSigmaError[1].getMean(), tolerance); + Assertions.assertEquals(expectedMedianRMSPositionError, relativeRMSSigmaError[0].getPercentile(50), tolerance); + Assertions.assertEquals(expectedMedianRMSVelocityError, relativeRMSSigmaError[1].getPercentile(50), tolerance); + Assertions.assertEquals(expectedMaxRMSPositionError, relativeRMSSigmaError[0].getMax(), tolerance); + Assertions.assertEquals(expectedMaxRMSVelocityError, relativeRMSSigmaError[1].getMax(), tolerance); + } + + @Deprecated + private void doTestBlendingDeprecated(final double propagationHorizon, final double tabulatedTimeStep, + final SmoothStepFactory.SmoothStepFunction blendingFunction, + final AbstractAnalyticalPropagator analyticalPropagator, + final double expectedMeanRMSPositionError, + final double expectedMeanRMSVelocityError, + final double expectedMedianRMSPositionError, + final double expectedMedianRMSVelocityError, + final double expectedMaxRMSPositionError, + final double expectedMaxRMSVelocityError, + final double tolerance, + final boolean showResults) { + final TimeInterpolator orbitInterpolator = new OrbitBlender(blendingFunction, + analyticalPropagator, + sergeiFrame); + + final TimeInterpolator> covarianceInterpolator = + new StateCovarianceBlender(blendingFunction, orbitInterpolator, + sergeiFrame, OrbitType.CARTESIAN, + PositionAngleType.MEAN); + // Create state interpolator final TimeInterpolator stateInterpolator = new SpacecraftStateInterpolator(sergeiFrame, orbitInterpolator, null, null, null, null); @@ -216,6 +266,57 @@ void testBrouwerLyddaneQuadraticBlending() { Assertions.assertEquals(0.32564919981018114, relativeRMSSigmaError[1].getMax(), 1e-16);*/ } + /** + * Test based on the full force model test case from TANYGIN, Sergei. Efficient covariance interpolation using blending + * of approximate covariance propagations. The Journal of the Astronautical Sciences, 2014, vol. 61, no 1, p. 107-132. + *

              + * This instance of the test aims to test the Quadratic Blending method using Brouwer Lyddane propagation. This is a + * non-regression test. + */ + @Deprecated + @Test + @DisplayName("test Brouwer Lyddane quadratic blending interpolation on full force model test case from: " + + "TANYGIN, Sergei. Efficient covariance interpolation using blending of approximate covariance propagations. " + + "The Journal of the Astronautical Sciences, 2014, vol. 61, no 1, p. 107-132.") + void testBrouwerLyddaneQuadraticBlendingDeprecated() { + // Given + final boolean showResults = false; // Show results? + final double tolerance = 1.e-12; + + // Create state covariance interpolator + final SmoothStepFactory.SmoothStepFunction blendingFunction = SmoothStepFactory.getQuadratic(); + + final AbstractAnalyticalPropagator propagator = new BrouwerLyddanePropagator(sergeiOrbit, + sergeiState.getMass(), + Constants.EIGEN5C_EARTH_EQUATORIAL_RADIUS, + Constants.EIGEN5C_EARTH_MU, + Constants.EIGEN5C_EARTH_C20, + Constants.EIGEN5C_EARTH_C30, + Constants.EIGEN5C_EARTH_C40, + Constants.EIGEN5C_EARTH_C50, + 0); + + // When & Then + doTestBlendingDeprecated(DEFAULT_SERGEI_PROPAGATION_TIME, DEFAUTL_SERGEI_TABULATED_TIMESTEP, blendingFunction, + propagator, + 0.0823442943514750, + 0.1976467714037895, + 0.0888590153696339, + 0.2020905044160413, + 0.1446159909426887, + 0.3894610461790040, + tolerance, + showResults); + + // Results obtained when using Sergei reference date + /* Assertions.assertEquals(0.07645785479359624, relativeRMSSigmaError[0].getMean(), 1e-17); + Assertions.assertEquals(0.17941792898602038, relativeRMSSigmaError[1].getMean(), 1e-17); + Assertions.assertEquals(0.08259069655149026, relativeRMSSigmaError[0].getPercentile(50), 1e-17); + Assertions.assertEquals(0.18352413417267063, relativeRMSSigmaError[1].getPercentile(50), 1e-17); + Assertions.assertEquals(0.13164670404592496, relativeRMSSigmaError[0].getMax(), 1e-17); + Assertions.assertEquals(0.32564919981018114, relativeRMSSigmaError[1].getMax(), 1e-16);*/ + } + /** * Test based on the full force model test case from TANYGIN, Sergei. Efficient covariance interpolation using blending * of approximate covariance propagations. The Journal of the Astronautical Sciences, 2014, vol. 61, no 1, p. 107-132. diff --git a/src/test/java/org/orekit/propagation/StateCovarianceKeplerianHermiteInterpolatorTest.java b/src/test/java/org/orekit/propagation/StateCovarianceKeplerianHermiteInterpolatorTest.java index fac52d1645..94a7cd19a6 100644 --- a/src/test/java/org/orekit/propagation/StateCovarianceKeplerianHermiteInterpolatorTest.java +++ b/src/test/java/org/orekit/propagation/StateCovarianceKeplerianHermiteInterpolatorTest.java @@ -605,7 +605,7 @@ void testQuinticKeplerianInterpolation() { // Create state interpolator final TimeInterpolator stateInterpolator = - new SpacecraftStateInterpolator(sergeiFrame, orbitInterpolator, null, null, null, null); + new SpacecraftStateInterpolator(2, 1.0e-3, sergeiFrame, orbitInterpolator, null, null, null, null); // When & Then doTestInterpolation(stateInterpolator, covarianceInterpolator, @@ -664,7 +664,7 @@ void testCubicKeplerianInterpolation() { // Create state interpolator final TimeInterpolator stateInterpolator = - new SpacecraftStateInterpolator(sergeiFrame, orbitInterpolator, null, null, null, null); + new SpacecraftStateInterpolator(2, 1.0e-3, sergeiFrame, orbitInterpolator, null, null, null, null); // When & then doTestInterpolation(stateInterpolator, covarianceInterpolator, @@ -722,7 +722,7 @@ void testLinearKeplerianInterpolation() { // Create state interpolator final TimeInterpolator stateInterpolator = - new SpacecraftStateInterpolator(sergeiFrame, orbitInterpolator, null, null, null, null); + new SpacecraftStateInterpolator(2, 1.0e-3, sergeiFrame, orbitInterpolator, null, null, null, null); // When & Then doTestInterpolation(stateInterpolator, covarianceInterpolator, diff --git a/src/test/java/org/orekit/propagation/analytical/FieldEcksteinHechlerPropagatorTest.java b/src/test/java/org/orekit/propagation/analytical/FieldEcksteinHechlerPropagatorTest.java index fd569310db..3565c035fd 100644 --- a/src/test/java/org/orekit/propagation/analytical/FieldEcksteinHechlerPropagatorTest.java +++ b/src/test/java/org/orekit/propagation/analytical/FieldEcksteinHechlerPropagatorTest.java @@ -817,7 +817,6 @@ private > void doDate(Field field) { FieldEcksteinHechlerPropagator propagator = new FieldEcksteinHechlerPropagator<>(orbit, provider); final FieldAbsoluteDate stopDate = date.shiftedBy(500.0); - @SuppressWarnings("unchecked") FieldDateDetector detector = new FieldDateDetector<>(field, stopDate); propagator.addEventDetector(detector); FieldAbsoluteDate farTarget = date.shiftedBy(10000.0); diff --git a/src/test/java/org/orekit/propagation/analytical/FieldKeplerianPropagatorTest.java b/src/test/java/org/orekit/propagation/analytical/FieldKeplerianPropagatorTest.java index 5b92378bf3..23a2321177 100644 --- a/src/test/java/org/orekit/propagation/analytical/FieldKeplerianPropagatorTest.java +++ b/src/test/java/org/orekit/propagation/analytical/FieldKeplerianPropagatorTest.java @@ -674,7 +674,6 @@ private > void doTestDate(Field field) { FramesFactory.getEME2000(), new FieldAbsoluteDate<>(field), zero.add(3.986004415e14)); FieldKeplerianPropagator propagator = new FieldKeplerianPropagator<>(orbit); final FieldAbsoluteDate stopDate = new FieldAbsoluteDate<>(field).shiftedBy(500.0); - @SuppressWarnings("unchecked") FieldDateDetector detector = new FieldDateDetector<>(field, stopDate); propagator.addEventDetector(detector); FieldAbsoluteDate farTarget = new FieldAbsoluteDate<>(field).shiftedBy(10000.0); diff --git a/src/test/java/org/orekit/propagation/events/FieldDateDetectorTest.java b/src/test/java/org/orekit/propagation/events/FieldDateDetectorTest.java index 26e5dc55f0..90a143b053 100644 --- a/src/test/java/org/orekit/propagation/events/FieldDateDetectorTest.java +++ b/src/test/java/org/orekit/propagation/events/FieldDateDetectorTest.java @@ -334,11 +334,10 @@ private > void doTestIssue935(Field field) // Min gap to seconds int maxCheck = (int) ((end - start) / 2000); - @SuppressWarnings("unchecked") FieldDateDetector dateDetector = new FieldDateDetector<>(field, getAbsoluteDateFromTimestamp(field, start)). - withMinGap(maxCheck). - withThreshold(field.getZero().newInstance(1.0e-6)). - withHandler(new FieldStopOnEvent<>()); + withMinGap(maxCheck). + withThreshold(field.getZero().newInstance(1.0e-6)). + withHandler(new FieldStopOnEvent<>()); dateDetector.addEventDate(getAbsoluteDateFromTimestamp(field, end)); // Add event detectors to orbit diff --git a/src/test/java/org/orekit/propagation/events/FieldEventDetectorTest.java b/src/test/java/org/orekit/propagation/events/FieldEventDetectorTest.java index 60c7583283..98751246d2 100644 --- a/src/test/java/org/orekit/propagation/events/FieldEventDetectorTest.java +++ b/src/test/java/org/orekit/propagation/events/FieldEventDetectorTest.java @@ -108,7 +108,6 @@ public void init(final FieldSpacecraftState initialState, FieldPropagator propagator = new FieldKeplerianPropagator<>(orbit); T stepSize = zero.add(60.0); - @SuppressWarnings("unchecked") final FieldDateDetector detector = new FieldDateDetector<>(field, date.shiftedBy(stepSize.multiply(5.25))).withHandler(handler); propagator.addEventDetector(detector); propagator.propagate(date.shiftedBy(stepSize.multiply(10))); @@ -138,7 +137,6 @@ private > void doTestBasicScheduling(Field FieldPropagator propagator = new FieldKeplerianPropagator<>(orbit); T stepSize = zero.add(60.0); OutOfOrderChecker checker = new OutOfOrderChecker<>(stepSize); - @SuppressWarnings("unchecked") FieldDateDetector detector = new FieldDateDetector<>(field, date.shiftedBy(stepSize.multiply(5.25))).withHandler(checker); propagator.addEventDetector(detector); propagator.setStepHandler(stepSize, checker); @@ -349,7 +347,6 @@ public void testWrappedException() { doTestWrappedException(Binary64Field.getInstance()); } - @SuppressWarnings("unchecked") private > void doTestWrappedException(Field field) { final T zero = field.getZero(); final Throwable dummyCause = new RuntimeException(); @@ -503,7 +500,6 @@ private > void doTestScheduling(final Field }); for (int i = 0; i < 10; ++i) { - @SuppressWarnings("unchecked") FieldDateDetector detector = new FieldDateDetector<>(field, initialDate.shiftedBy(0.0625 * (i + 1))). withHandler((state, d, increasing) -> { checker.callDate(state.getDate()); diff --git a/src/test/java/org/orekit/propagation/events/FieldEventEnablingPredicateFilterTest.java b/src/test/java/org/orekit/propagation/events/FieldEventEnablingPredicateFilterTest.java index b00f42091f..9cd54f07e7 100644 --- a/src/test/java/org/orekit/propagation/events/FieldEventEnablingPredicateFilterTest.java +++ b/src/test/java/org/orekit/propagation/events/FieldEventEnablingPredicateFilterTest.java @@ -173,7 +173,6 @@ public boolean eventIsEnabled(final FieldSpacecraftState state, @Test public void testResetState() { final List> reset = new ArrayList<>(); - @SuppressWarnings("unchecked") FieldDateDetector raw = new FieldDateDetector<>(Binary64Field.getInstance(), orbit.getDate().shiftedBy(3600.0)). withMaxCheck(1000.0). withHandler(new FieldEventHandler() { @@ -222,7 +221,6 @@ public void testExceedHistoryForward() throws IOException { final double period = 900.0; // the raw detector should trigger one event at each 900s period - @SuppressWarnings("unchecked") final FieldDateDetector raw = new FieldDateDetector<>(Binary64Field.getInstance(), orbit.getDate().shiftedBy(-0.5 * period)). withMaxCheck(period / 3). @@ -277,7 +275,6 @@ public void testExceedHistoryBackward() throws IOException { final double period = 900.0; // the raw detector should trigger one event at each 900s period - @SuppressWarnings("unchecked") final FieldDateDetector raw = new FieldDateDetector<>(Binary64Field.getInstance(), orbit.getDate().shiftedBy(+0.5 * period)). withMaxCheck(period / 3). @@ -330,7 +327,6 @@ public boolean eventIsEnabled(FieldSpacecraftState state, @Test public void testGenerics() { // setup - @SuppressWarnings("unchecked") FieldDateDetector detector = new FieldDateDetector<>(orbit.getDate().getField(), orbit.getDate()); FieldEnablingPredicate predicate = (state, eventDetector, g) -> true; diff --git a/src/test/java/org/orekit/propagation/events/LongitudeRangeCrossingDetectorTest.java b/src/test/java/org/orekit/propagation/events/LongitudeRangeCrossingDetectorTest.java index c2d7070cb3..3120685b76 100644 --- a/src/test/java/org/orekit/propagation/events/LongitudeRangeCrossingDetectorTest.java +++ b/src/test/java/org/orekit/propagation/events/LongitudeRangeCrossingDetectorTest.java @@ -18,7 +18,6 @@ import static org.orekit.orbits.PositionAngleType.MEAN; -import java.util.List; import org.hipparchus.geometry.euclidean.threed.Vector3D; import org.hipparchus.util.FastMath; import org.junit.jupiter.api.Assertions; diff --git a/src/test/java/org/orekit/propagation/events/handlers/FieldRecordAndContinueTest.java b/src/test/java/org/orekit/propagation/events/handlers/FieldRecordAndContinueTest.java index 12016abf58..39f21b352a 100644 --- a/src/test/java/org/orekit/propagation/events/handlers/FieldRecordAndContinueTest.java +++ b/src/test/java/org/orekit/propagation/events/handlers/FieldRecordAndContinueTest.java @@ -53,7 +53,6 @@ public void testGetEvents() { FieldAbsoluteDate date = new FieldAbsoluteDate<>(field, AbsoluteDate.J2000_EPOCH); Binary64 zero = date.getField().getZero(); - @SuppressWarnings("unchecked") FieldDateDetector detector = new FieldDateDetector<>(field, date); Frame eci = FramesFactory.getGCRF(); FieldOrbit orbit = new FieldKeplerianOrbit<>( diff --git a/src/test/java/org/orekit/propagation/integration/FieldIntegratedEphemerisTest.java b/src/test/java/org/orekit/propagation/integration/FieldIntegratedEphemerisTest.java index a5ccb5be85..ed3636b4d1 100644 --- a/src/test/java/org/orekit/propagation/integration/FieldIntegratedEphemerisTest.java +++ b/src/test/java/org/orekit/propagation/integration/FieldIntegratedEphemerisTest.java @@ -214,7 +214,6 @@ private > void doTestNoReset(Field field) numericalPropagator.setInitialState(new FieldSpacecraftState<>(initialOrbit)); numericalPropagator.propagate(finalDate); FieldBoundedPropagator ephemeris = generator.getGeneratedEphemeris(); - @SuppressWarnings("unchecked") FieldDateDetector detector = new FieldDateDetector<>(initialOrbit.getDate().getField(), initialOrbit.getDate().shiftedBy(10)). withHandler((s, d, increasing) -> Action.RESET_STATE); diff --git a/src/test/java/org/orekit/propagation/numerical/FieldNumericalPropagatorTest.java b/src/test/java/org/orekit/propagation/numerical/FieldNumericalPropagatorTest.java index 2d9ae353ef..3a95ea45f8 100644 --- a/src/test/java/org/orekit/propagation/numerical/FieldNumericalPropagatorTest.java +++ b/src/test/java/org/orekit/propagation/numerical/FieldNumericalPropagatorTest.java @@ -736,7 +736,6 @@ private > void doTestStopEvent(Field field) final FieldAbsoluteDate stopDate = initDate.shiftedBy(1000); CheckingHandler checking = new CheckingHandler<>(Action.STOP); - @SuppressWarnings("unchecked") FieldDateDetector detector = new FieldDateDetector<>(field, stopDate).withHandler(checking); propagator.addEventDetector(detector); Assertions.assertEquals(1, propagator.getEventsDetectors().size()); @@ -780,7 +779,6 @@ public FieldSpacecraftState resetState(FieldEventDetector detector, FieldS return new FieldSpacecraftState<>(oldState.getOrbit(), oldState.getAttitude(), oldState.getMass().subtract(200.0)); } }; - @SuppressWarnings("unchecked") FieldDateDetector detector = new FieldDateDetector<>(field, resetDate).withHandler(checking); propagator.addEventDetector(detector); checking.assertEvent(false); @@ -816,7 +814,6 @@ private > void doTestResetDerivativesEvent(Fie propagator.setInitialState(initialState); final FieldAbsoluteDate resetDate = initDate.shiftedBy(1000); CheckingHandler checking = new CheckingHandler<>(Action.RESET_DERIVATIVES); - @SuppressWarnings("unchecked") FieldDateDetector detector = new FieldDateDetector<>(field, resetDate).withHandler(checking); propagator.addEventDetector(detector); final double dt = 3200; @@ -867,7 +864,6 @@ private > void doTestContinueEvent(Field f final FieldAbsoluteDate resetDate = initDate.shiftedBy(1000); CheckingHandler checking = new CheckingHandler<>(Action.CONTINUE); - @SuppressWarnings("unchecked") FieldDateDetector detector = new FieldDateDetector<>(field, resetDate).withHandler(checking); propagator.addEventDetector(detector); final double dt = 3200; diff --git a/src/test/java/org/orekit/propagation/sampling/FieldStepHandlerMultiplexerTest.java b/src/test/java/org/orekit/propagation/sampling/FieldStepHandlerMultiplexerTest.java index 5ee14136d9..dcc4e7db48 100644 --- a/src/test/java/org/orekit/propagation/sampling/FieldStepHandlerMultiplexerTest.java +++ b/src/test/java/org/orekit/propagation/sampling/FieldStepHandlerMultiplexerTest.java @@ -255,14 +255,12 @@ public void testOnTheFlyChanges() { double add60 = 3.0; double rem60 = 78.0; FieldFixedCounter counter60 = new FieldFixedCounter(); - @SuppressWarnings("unchecked") FieldDateDetector d1 = new FieldDateDetector<>(field, initDate.shiftedBy(add60)). withHandler((s, d, i) -> { multiplexer.add(zero.newInstance(60.0), counter60); return Action.CONTINUE; }); propagator.addEventDetector(d1); - @SuppressWarnings("unchecked") FieldDateDetector d2 = new FieldDateDetector<>(field, initDate.shiftedBy(rem60)). withHandler((s, d, i) -> { multiplexer.remove(counter60); @@ -273,14 +271,12 @@ public void testOnTheFlyChanges() { double addVar = 5.0; double remVar = 7.0; FieldVariableCounter counterVar = new FieldVariableCounter(); - @SuppressWarnings("unchecked") FieldDateDetector d3 = new FieldDateDetector<>(field, initDate.shiftedBy(addVar)). withHandler((s, d, i) -> { multiplexer.add(counterVar); return Action.CONTINUE; }); propagator.addEventDetector(d3); - @SuppressWarnings("unchecked") FieldDateDetector d4 = new FieldDateDetector<>(field, initDate.shiftedBy(remVar)). withHandler((s, d, i) -> { multiplexer.remove(counterVar); @@ -291,14 +287,12 @@ public void testOnTheFlyChanges() { double add10 = 6.0; double rem10 = 82.0; FieldFixedCounter counter10 = new FieldFixedCounter(); - @SuppressWarnings("unchecked") FieldDateDetector d5 = new FieldDateDetector<>(field, initDate.shiftedBy(add10)). withHandler((s, d, i) -> { multiplexer.add(zero.newInstance(10.0), counter10); return Action.CONTINUE; }); propagator.addEventDetector(d5); - @SuppressWarnings("unchecked") FieldDateDetector d6 = new FieldDateDetector<>(field, initDate.shiftedBy(rem10)). withHandler((s, d, i) -> { multiplexer.clear(); diff --git a/src/test/java/org/orekit/propagation/semianalytical/dsst/FieldDSSTPropagatorTest.java b/src/test/java/org/orekit/propagation/semianalytical/dsst/FieldDSSTPropagatorTest.java index eb95297aff..d0334582a5 100644 --- a/src/test/java/org/orekit/propagation/semianalytical/dsst/FieldDSSTPropagatorTest.java +++ b/src/test/java/org/orekit/propagation/semianalytical/dsst/FieldDSSTPropagatorTest.java @@ -671,7 +671,6 @@ private > void doTestStopEvent(Field field) final FieldAbsoluteDate stopDate = state.getDate().shiftedBy(1000); CheckingHandler, T> checking = new CheckingHandler, T>(Action.STOP); - @SuppressWarnings("unchecked") FieldDateDetector detector = new FieldDateDetector<>(field, stopDate).withHandler(checking); dsstPropagator.addEventDetector(detector); checking.assertEvent(false); @@ -691,7 +690,6 @@ private > void doTestContinueEvent(Field fi final FieldAbsoluteDate resetDate = state.getDate().shiftedBy(1000); CheckingHandler, T> checking = new CheckingHandler, T>(Action.CONTINUE); - @SuppressWarnings("unchecked") FieldDateDetector detector = new FieldDateDetector<>(field, resetDate).withHandler(checking); dsstPropagator.addEventDetector(detector); final double dt = 3200; From 8b6e94d512123942326a76e61ac1ae909c64f1ae Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Tue, 5 Mar 2024 14:49:13 +0100 Subject: [PATCH 177/359] Added OneWayGNSSRangeRate and OneWayGNSSRangeRateBuilder. --- .../OneWayGNSSRangeRateBuilder.java | 107 ++++ .../gnss/OneWayGNSSRangeRate.java | 174 ++++++ ...rSatellitesOneWayRangeRateBuilderTest.java | 4 +- .../OneWayGNSSRangeRateBuilderTest.java | 169 ++++++ .../gnss/OneWayGNSSRangeRateCreator.java | 132 ++++ .../gnss/OneWayGNSSRangeRateTest.java | 564 ++++++++++++++++++ 6 files changed, 1148 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/orekit/estimation/measurements/generation/OneWayGNSSRangeRateBuilder.java create mode 100644 src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRangeRate.java create mode 100644 src/test/java/org/orekit/estimation/measurements/generation/OneWayGNSSRangeRateBuilderTest.java create mode 100644 src/test/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRangeRateCreator.java create mode 100644 src/test/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRangeRateTest.java diff --git a/src/main/java/org/orekit/estimation/measurements/generation/OneWayGNSSRangeRateBuilder.java b/src/main/java/org/orekit/estimation/measurements/generation/OneWayGNSSRangeRateBuilder.java new file mode 100644 index 0000000000..3a54e48a75 --- /dev/null +++ b/src/main/java/org/orekit/estimation/measurements/generation/OneWayGNSSRangeRateBuilder.java @@ -0,0 +1,107 @@ +/* Copyright 2002-2024 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.estimation.measurements.generation; + +import org.hipparchus.random.CorrelatedRandomVectorGenerator; +import org.orekit.estimation.measurements.EstimationModifier; +import org.orekit.estimation.measurements.ObservableSatellite; +import org.orekit.estimation.measurements.gnss.OneWayGNSSRangeRate; +import org.orekit.propagation.SpacecraftState; +import org.orekit.propagation.sampling.OrekitStepInterpolator; +import org.orekit.time.AbsoluteDate; +import org.orekit.utils.ParameterDriver; + +import java.util.Map; + +/** Builder for {@link org.orekit.estimation.measurements.gnss.OneWayGNSSRangeRate} measurements. + * @author Luc Maisonobe + * @since 12.1 + */ +public class OneWayGNSSRangeRateBuilder + extends AbstractMeasurementBuilder { + + /** Satellite which receives the signal and performs the measurement. */ + private final ObservableSatellite local; + + /** Satellite which simply emits the signal. */ + private final ObservableSatellite remote; + + /** Simple constructor. + * @param noiseSource noise source, may be null for generating perfect measurements + * @param local satellite which receives the signal and performs the measurement + * @param remote satellite which simply emits the signal + * @param sigma theoretical standard deviation + * @param baseWeight base weight + */ + public OneWayGNSSRangeRateBuilder(final CorrelatedRandomVectorGenerator noiseSource, + final ObservableSatellite local, final ObservableSatellite remote, + final double sigma, final double baseWeight) { + super(noiseSource, sigma, baseWeight, local, remote); + this.local = local; + this.remote = remote; + } + + /** {@inheritDoc} */ + @Override + public OneWayGNSSRangeRate build(final AbsoluteDate date, + final Map interpolators) { + + final double sigma = getTheoreticalStandardDeviation()[0]; + final double baseWeight = getBaseWeight()[0]; + final SpacecraftState[] relevant = new SpacecraftState[] { + interpolators.get(local).getInterpolatedState(date), + interpolators.get(remote).getInterpolatedState(date) + }; + + // create a dummy measurement + final OneWayGNSSRangeRate dummy = new OneWayGNSSRangeRate(interpolators.get(remote), + remote.getQuadraticClockModel(), relevant[0].getDate(), + Double.NaN, sigma, baseWeight, local); + for (final EstimationModifier modifier : getModifiers()) { + dummy.addModifier(modifier); + } + + // set a reference date for parameters missing one + for (final ParameterDriver driver : dummy.getParametersDrivers()) { + if (driver.getReferenceDate() == null) { + final AbsoluteDate start = getStart(); + final AbsoluteDate end = getEnd(); + driver.setReferenceDate(start.durationFrom(end) <= 0 ? start : end); + } + } + + // estimate the perfect value of the measurement + double rangeRate = dummy.estimateWithoutDerivatives(0, 0, relevant).getEstimatedValue()[0]; + + // add the noise + final double[] noise = getNoise(); + if (noise != null) { + rangeRate += noise[0]; + } + + // generate measurement + final OneWayGNSSRangeRate measurement = new OneWayGNSSRangeRate(interpolators.get(remote), + remote.getQuadraticClockModel(), relevant[0].getDate(), + rangeRate, sigma, baseWeight, local); + for (final EstimationModifier modifier : getModifiers()) { + measurement.addModifier(modifier); + } + return measurement; + + } + +} diff --git a/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRangeRate.java b/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRangeRate.java new file mode 100644 index 0000000000..c8cbd2ac77 --- /dev/null +++ b/src/main/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRangeRate.java @@ -0,0 +1,174 @@ +/* Copyright 2002-2024 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.estimation.measurements.gnss; + +import java.util.Arrays; + +import org.hipparchus.analysis.differentiation.Gradient; +import org.hipparchus.geometry.euclidean.threed.FieldVector3D; +import org.hipparchus.geometry.euclidean.threed.Vector3D; +import org.orekit.estimation.measurements.EstimatedMeasurement; +import org.orekit.estimation.measurements.EstimatedMeasurementBase; +import org.orekit.estimation.measurements.ObservableSatellite; +import org.orekit.estimation.measurements.QuadraticClockModel; +import org.orekit.propagation.SpacecraftState; +import org.orekit.time.AbsoluteDate; +import org.orekit.utils.Constants; +import org.orekit.utils.FieldPVCoordinates; +import org.orekit.utils.PVCoordinates; +import org.orekit.utils.PVCoordinatesProvider; +import org.orekit.utils.ParameterDriver; +import org.orekit.utils.TimeSpanMap.Span; +import org.orekit.utils.TimeStampedPVCoordinates; + +/** One-way GNSS range rate measurement. + *

              + * This class can be used in precise orbit determination applications + * for modeling a range rate measurement between a GNSS satellite (emitter) + * and a LEO satellite (receiver). + *

              + * The one-way GNSS range rate measurement assumes knowledge of the orbit and + * the clock offset of the emitting GNSS satellite. For instance, it is + * possible to use a SP3 file or a GNSS navigation message to recover + * the satellite's orbit and clock. + *

              + * This class is very similar to {@link InterSatellitesOneWayRangeRate} measurement + * class. However, using the one-way GNSS range measurement, the orbit and clock + * of the emitting GNSS satellite are NOT estimated simultaneously with + * LEO satellite coordinates. + * + * @author Luc Maisonobe + * @since 12.1 + */ +public class OneWayGNSSRangeRate extends AbstractOneWayGNSSMeasurement { + + /** Type of the measurement. */ + public static final String MEASUREMENT_TYPE = "OneWayGNSSRangeRate"; + + /** Simple constructor. + * @param remote provider for GNSS satellite which simply emits the signal + * @param dtRemote clock offset of the GNSS satellite, in seconds + * @param date date of the measurement + * @param rangeRate observed value + * @param sigma theoretical standard deviation + * @param baseWeight base weight + * @param local satellite which receives the signal and perform the measurement + */ + public OneWayGNSSRangeRate(final PVCoordinatesProvider remote, + final double dtRemote, + final AbsoluteDate date, + final double rangeRate, final double sigma, + final double baseWeight, final ObservableSatellite local) { + this(remote, new QuadraticClockModel(date, dtRemote, 0.0, 0.0), date, rangeRate, sigma, baseWeight, local); + } + + /** Simple constructor. + * @param remote provider for GNSS satellite which simply emits the signal + * @param remoteClock clock offset of the GNSS satellite + * @param date date of the measurement + * @param rangeRate observed value + * @param sigma theoretical standard deviation + * @param baseWeight base weight + * @param local satellite which receives the signal and perform the measurement + * @since 12.1 + */ + public OneWayGNSSRangeRate(final PVCoordinatesProvider remote, + final QuadraticClockModel remoteClock, + final AbsoluteDate date, + final double rangeRate, final double sigma, + final double baseWeight, final ObservableSatellite local) { + // Call super constructor + super(remote, remoteClock, date, rangeRate, sigma, baseWeight, local); + } + + /** {@inheritDoc} */ + @Override + protected EstimatedMeasurementBase theoreticalEvaluationWithoutDerivatives(final int iteration, + final int evaluation, + final SpacecraftState[] states) { + + + final OnBoardCommonParametersWithoutDerivatives common = computeCommonParametersWithout(states, false); + + // Estimated measurement + final EstimatedMeasurementBase estimatedRangeRate = + new EstimatedMeasurementBase<>(this, iteration, evaluation, + new SpacecraftState[] { + common.getState() + }, new TimeStampedPVCoordinates[] { + common.getRemotePV(), + common.getTransitPV() + }); + + // Range rate value + final PVCoordinates delta = new PVCoordinates(common.getRemotePV(), common.getTransitPV()); + final double rangeRate = Vector3D.dotProduct(delta.getVelocity(), delta.getPosition().normalize()) + + Constants.SPEED_OF_LIGHT * (common.getLocalRate() - common.getRemoteRate()); + + // Set value of the estimated measurement + estimatedRangeRate.setEstimatedValue(rangeRate); + + // Return the estimated measurement + return estimatedRangeRate; + + } + + /** {@inheritDoc} */ + @Override + protected EstimatedMeasurement theoreticalEvaluation(final int iteration, + final int evaluation, + final SpacecraftState[] states) { + + final OnBoardCommonParametersWithDerivatives common = computeCommonParametersWith(states, false); + + // Estimated measurement + final EstimatedMeasurement estimatedRangeRate = + new EstimatedMeasurement<>(this, iteration, evaluation, + new SpacecraftState[] { + common.getState() + }, new TimeStampedPVCoordinates[] { + common.getRemotePV().toTimeStampedPVCoordinates(), + common.getTransitPV().toTimeStampedPVCoordinates() + }); + + // Range rate value + final FieldPVCoordinates delta = new FieldPVCoordinates<>(common.getRemotePV(), common.getTransitPV()); + final Gradient rangeRate = FieldVector3D.dotProduct(delta.getVelocity(), delta.getPosition().normalize()). + add(common.getLocalRate().subtract(common.getRemoteRate()).multiply(Constants.SPEED_OF_LIGHT)); + final double[] rangeRateDerivatives = rangeRate.getGradient(); + + // Set value and state derivatives of the estimated measurement + estimatedRangeRate.setEstimatedValue(rangeRate.getValue()); + estimatedRangeRate.setStateDerivatives(0, Arrays.copyOfRange(rangeRateDerivatives, 0, 6)); + + // Set partial derivatives with respect to parameters + for (final ParameterDriver measurementDriver : getParametersDrivers()) { + for (Span span = measurementDriver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) { + + final Integer index = common.getIndices().get(span.getData()); + if (index != null) { + estimatedRangeRate.setParameterDerivatives(measurementDriver, span.getStart(), rangeRateDerivatives[index]); + } + } + } + + // Return the estimated measurement + return estimatedRangeRate; + + } + +} diff --git a/src/test/java/org/orekit/estimation/measurements/generation/InterSatellitesOneWayRangeRateBuilderTest.java b/src/test/java/org/orekit/estimation/measurements/generation/InterSatellitesOneWayRangeRateBuilderTest.java index 67e8aff59e..5452106f56 100644 --- a/src/test/java/org/orekit/estimation/measurements/generation/InterSatellitesOneWayRangeRateBuilderTest.java +++ b/src/test/java/org/orekit/estimation/measurements/generation/InterSatellitesOneWayRangeRateBuilderTest.java @@ -73,12 +73,12 @@ private MeasurementBuilder getBuilder(final Rand @Test public void testForward() { - doTest(0xc82a56322345dc25L, 0.0, 1.2, 2.8 * SIGMA); + doTest(0x5006ca3f1e03ea93L, 0.0, 1.2, 2.4 * SIGMA); } @Test public void testBackward() { - doTest(0x95c10149c4891232L, 0.0, -1.0, 2.6 * SIGMA); + doTest(0xd7643ffbaff67906L, 0.0, -1.0, 3.0 * SIGMA); } private Propagator buildPropagator() { diff --git a/src/test/java/org/orekit/estimation/measurements/generation/OneWayGNSSRangeRateBuilderTest.java b/src/test/java/org/orekit/estimation/measurements/generation/OneWayGNSSRangeRateBuilderTest.java new file mode 100644 index 0000000000..8dc55684fa --- /dev/null +++ b/src/test/java/org/orekit/estimation/measurements/generation/OneWayGNSSRangeRateBuilderTest.java @@ -0,0 +1,169 @@ +/* Copyright 2002-2024 Luc Maisonobe + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.estimation.measurements.generation; + +import org.hipparchus.linear.MatrixUtils; +import org.hipparchus.linear.RealMatrix; +import org.hipparchus.random.CorrelatedRandomVectorGenerator; +import org.hipparchus.random.GaussianRandomGenerator; +import org.hipparchus.random.RandomGenerator; +import org.hipparchus.random.Well19937a; +import org.hipparchus.util.FastMath; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.orekit.estimation.Context; +import org.orekit.estimation.EstimationTestUtils; +import org.orekit.estimation.Force; +import org.orekit.estimation.measurements.ObservableSatellite; +import org.orekit.estimation.measurements.ObservedMeasurement; +import org.orekit.estimation.measurements.gnss.OneWayGNSSRangeRate; +import org.orekit.estimation.measurements.modifiers.Bias; +import org.orekit.orbits.KeplerianOrbit; +import org.orekit.orbits.Orbit; +import org.orekit.orbits.OrbitType; +import org.orekit.orbits.PositionAngleType; +import org.orekit.propagation.Propagator; +import org.orekit.propagation.SpacecraftState; +import org.orekit.propagation.analytical.KeplerianPropagator; +import org.orekit.propagation.conversion.NumericalPropagatorBuilder; +import org.orekit.propagation.events.InterSatDirectViewDetector; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.FixedStepSelector; +import org.orekit.time.TimeScalesFactory; +import org.orekit.utils.PVCoordinates; + +import java.util.SortedSet; + +public class OneWayGNSSRangeRateBuilderTest { + + private static final double SIGMA = 0.5; + private static final double BIAS = -0.01; + + private MeasurementBuilder getBuilder(final RandomGenerator random, + final ObservableSatellite receiver, + final ObservableSatellite remote) { + final RealMatrix covariance = MatrixUtils.createRealDiagonalMatrix(new double[] { SIGMA * SIGMA }); + MeasurementBuilder b = + new OneWayGNSSRangeRateBuilder(random == null ? null : new CorrelatedRandomVectorGenerator(covariance, + 1.0e-10, + new GaussianRandomGenerator(random)), + receiver, remote, + SIGMA, 1.0); + b.addModifier(new Bias<>(new String[] { "bias" }, + new double[] { BIAS }, + new double[] { 1.0 }, + new double[] { Double.NEGATIVE_INFINITY }, + new double[] { Double.POSITIVE_INFINITY })); + return b; + } + + @Test + public void testForward() { + doTest(0x066acbc9bf1074a3L, 0.0, 1.2, 2.8 * SIGMA); + } + + @Test + public void testBackward() { + doTest(0x58ffc7ad03c2310bL, 0.0, -1.0, 2.5 * SIGMA); + } + + private Propagator buildPropagator() { + return EstimationTestUtils.createPropagator(context.initialOrbit, propagatorBuilder); + } + + private void doTest(long seed, double startPeriod, double endPeriod, double tolerance) { + Generator generator = new Generator(); + generator.addPropagator(buildPropagator()); // dummy first propagator + generator.addPropagator(buildPropagator()); // dummy second propagator + ObservableSatellite receiver = generator.addPropagator(buildPropagator()); // useful third propagator + generator.addPropagator(buildPropagator()); // dummy fourth propagator + final Orbit o1 = context.initialOrbit; + // for the second satellite, we simply reverse velocity + final Orbit o2 = new KeplerianOrbit(new PVCoordinates(o1.getPosition(), + o1.getPVCoordinates().getVelocity().negate()), + o1.getFrame(), o1.getDate(), o1.getMu()); + ObservableSatellite remote = generator.addPropagator(new KeplerianPropagator(o2)); // useful sixth propagator + final double step = 60.0; + + // beware that in order to avoid deadlocks, the secondary PV coordinates provider + // in InterSatDirectViewDetector must be *different* from the second propagator + // added to generator above! The reason is the event detector will be bound + // to the first propagator, so it cannot also refer to the second one at the same time + // this is the reason why we create a *new* KeplerianPropagator below + generator.addScheduler(new EventBasedScheduler<>(getBuilder(new Well19937a(seed), receiver, remote), + new FixedStepSelector(step, TimeScalesFactory.getUTC()), + generator.getPropagator(receiver), + new InterSatDirectViewDetector(context.earth, new KeplerianPropagator(o2)), + SignSemantic.FEASIBLE_MEASUREMENT_WHEN_POSITIVE)); + + final GatheringSubscriber gatherer = new GatheringSubscriber(); + generator.addSubscriber(gatherer); + final double period = o1.getKeplerianPeriod(); + AbsoluteDate t0 = o1.getDate().shiftedBy(startPeriod * period); + AbsoluteDate t1 = o1.getDate().shiftedBy(endPeriod * period); + generator.generate(t0, t1); + SortedSet> measurements = gatherer.getGeneratedMeasurements(); + + // and yet another set of propagators for reference + Propagator propagator1 = buildPropagator(); + Propagator propagator2 = new KeplerianPropagator(o2); + + double maxError = 0; + AbsoluteDate previous = null; + AbsoluteDate tInf = t0.isBefore(t1) ? t0 : t1; + AbsoluteDate tSup = t0.isBefore(t1) ? t1 : t0; + for (ObservedMeasurement measurement : measurements) { + AbsoluteDate date = measurement.getDate(); + double[] m = measurement.getObservedValue(); + Assertions.assertTrue(date.compareTo(tInf) >= 0); + Assertions.assertTrue(date.compareTo(tSup) <= 0); + if (previous != null) { + if (t0.isBefore(t1)) { + // measurements are expected to be chronological + Assertions.assertTrue(date.durationFrom(previous) >= 0.999999 * step); + } else { + // measurements are expected to be reverse chronological + Assertions.assertTrue(previous.durationFrom(date) >= 0.999999 * step); + } + } + previous = date; + double[] e = measurement.estimateWithoutDerivatives(0, 0, + new SpacecraftState[] { + propagator1.propagate(date), + propagator2.propagate(date) + }).getEstimatedValue(); + for (int i = 0; i < m.length; ++i) { + maxError = FastMath.max(maxError, FastMath.abs(e[i] - m[i])); + } + } + Assertions.assertEquals(0.0, maxError, tolerance); + } + + @BeforeEach + public void setUp() { + context = EstimationTestUtils.eccentricContext("regular-data:potential:tides"); + + propagatorBuilder = context.createBuilder(OrbitType.KEPLERIAN, PositionAngleType.TRUE, true, + 1.0e-6, 300.0, 0.001, Force.POTENTIAL, + Force.THIRD_BODY_SUN, Force.THIRD_BODY_MOON); + } + + Context context; + NumericalPropagatorBuilder propagatorBuilder; + +} diff --git a/src/test/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRangeRateCreator.java b/src/test/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRangeRateCreator.java new file mode 100644 index 0000000000..4b3b03686b --- /dev/null +++ b/src/test/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRangeRateCreator.java @@ -0,0 +1,132 @@ +/* Copyright 2002-2024 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.estimation.measurements.gnss; + +import org.hipparchus.analysis.UnivariateFunction; +import org.hipparchus.analysis.solvers.BracketingNthOrderBrentSolver; +import org.hipparchus.analysis.solvers.UnivariateSolver; +import org.hipparchus.geometry.euclidean.threed.Vector3D; +import org.orekit.errors.OrekitException; +import org.orekit.estimation.measurements.MeasurementCreator; +import org.orekit.estimation.measurements.ObservableSatellite; +import org.orekit.estimation.measurements.QuadraticClockModel; +import org.orekit.propagation.BoundedPropagator; +import org.orekit.propagation.SpacecraftState; +import org.orekit.time.AbsoluteDate; +import org.orekit.utils.Constants; +import org.orekit.utils.PVCoordinates; +import org.orekit.utils.ParameterDriver; + +import java.util.Arrays; + +public class OneWayGNSSRangeRateCreator + extends MeasurementCreator { + + private final BoundedPropagator ephemeris; + private final QuadraticClockModel remoteClk; + private final Vector3D antennaPhaseCenter1; + private final Vector3D antennaPhaseCenter2; + private final ObservableSatellite local; + + public OneWayGNSSRangeRateCreator(final BoundedPropagator ephemeris, + final double localClockOffset, + final double localClockRate, + final double localClockAcceleration, + final double remoteClockOffset, + final double remoteClockRate, + final double remoteClockAcceleration) { + this(ephemeris, + localClockOffset, localClockRate, localClockAcceleration, + remoteClockOffset, remoteClockRate, remoteClockAcceleration, + Vector3D.ZERO, Vector3D.ZERO); + } + + public OneWayGNSSRangeRateCreator(final BoundedPropagator ephemeris, + final double localClockOffset, + final double localClockRate, + final double localClockAcceleration, + final double remoteClockOffset, + final double remoteClockRate, + final double remoteClockAcceleration, + final Vector3D antennaPhaseCenter1, + final Vector3D antennaPhaseCenter2) { + this.ephemeris = ephemeris; + this.antennaPhaseCenter1 = antennaPhaseCenter1; + this.antennaPhaseCenter2 = antennaPhaseCenter2; + this.local = new ObservableSatellite(0); + this.local.getClockOffsetDriver().setValue(localClockOffset); + this.local.getClockDriftDriver().setValue(localClockRate); + this.local.getClockAccelerationDriver().setValue(localClockAcceleration); + this.remoteClk = new QuadraticClockModel(ephemeris.getMinDate(), + remoteClockOffset, + remoteClockRate, + remoteClockAcceleration); + } + + public ObservableSatellite getLocalSatellite() { + return local; + } + + public void init(final SpacecraftState s0, final AbsoluteDate t, final double step) { + for (final ParameterDriver driver : Arrays.asList(local.getClockOffsetDriver(), + local.getClockDriftDriver(), + local.getClockAccelerationDriver())) { + if (driver.getReferenceDate() == null) { + driver.setReferenceDate(s0.getDate()); + } + } + } + + public void handleStep(final SpacecraftState currentState) { + try { + final AbsoluteDate date = currentState.getDate(); + final PVCoordinates pv = currentState.toTransform().getInverse(). + transformPVCoordinates(new PVCoordinates(antennaPhaseCenter1)); + final double localClk = local.getQuadraticClockModel().getOffset(date); + + final UnivariateSolver solver = new BracketingNthOrderBrentSolver(1.0e-12, 5); + + final double downLinkDelay = solver.solve(1000, new UnivariateFunction() { + public double value(final double x) { + final Vector3D other = ephemeris. + propagate(date.shiftedBy(-x)). + toTransform(). + getInverse(). + transformPosition(antennaPhaseCenter2); + final double d = Vector3D.distance(pv.getPosition(), other); + return d - x * Constants.SPEED_OF_LIGHT; + } + }, -1.0, 1.0); + final AbsoluteDate transitDate = currentState.getDate().shiftedBy(-downLinkDelay); + final PVCoordinates otherAtTransit = ephemeris.propagate(transitDate). + toTransform(). + getInverse(). + transformPVCoordinates(new PVCoordinates(antennaPhaseCenter2)); + final PVCoordinates delta = new PVCoordinates(otherAtTransit, pv); + final double rangeRate = Vector3D.dotProduct(delta.getPosition().normalize(), delta.getVelocity()) + + Constants.SPEED_OF_LIGHT * (local.getQuadraticClockModel().getRate(date) - + remoteClk.getRate(transitDate)); + + // Generate measurement + addMeasurement(new OneWayGNSSRangeRate(ephemeris, remoteClk, date.shiftedBy(localClk), rangeRate, 1.0, 10, local)); + + } catch (OrekitException oe) { + throw new OrekitException(oe); + } + } + +} diff --git a/src/test/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRangeRateTest.java b/src/test/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRangeRateTest.java new file mode 100644 index 0000000000..6cf6e0b636 --- /dev/null +++ b/src/test/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRangeRateTest.java @@ -0,0 +1,564 @@ +/* Copyright 2002-2024 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.estimation.measurements.gnss; + +import org.hipparchus.geometry.euclidean.threed.Vector3D; +import org.hipparchus.stat.descriptive.moment.Mean; +import org.hipparchus.stat.descriptive.rank.Max; +import org.hipparchus.stat.descriptive.rank.Median; +import org.hipparchus.stat.descriptive.rank.Min; +import org.hipparchus.util.FastMath; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.orekit.estimation.Context; +import org.orekit.estimation.EstimationTestUtils; +import org.orekit.estimation.measurements.EstimatedMeasurementBase; +import org.orekit.estimation.measurements.ObservedMeasurement; +import org.orekit.orbits.CartesianOrbit; +import org.orekit.orbits.Orbit; +import org.orekit.orbits.OrbitType; +import org.orekit.orbits.PositionAngleType; +import org.orekit.propagation.BoundedPropagator; +import org.orekit.propagation.EphemerisGenerator; +import org.orekit.propagation.Propagator; +import org.orekit.propagation.SpacecraftState; +import org.orekit.propagation.conversion.NumericalPropagatorBuilder; +import org.orekit.time.AbsoluteDate; +import org.orekit.utils.Constants; +import org.orekit.utils.Differentiation; +import org.orekit.utils.ParameterDriver; +import org.orekit.utils.ParameterFunction; +import org.orekit.utils.TimeSpanMap.Span; +import org.orekit.utils.TimeStampedPVCoordinates; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Locale; + +public class OneWayGNSSRangeRateTest { + + /** + * Test the values of the range rate comparing the observed values and the estimated values + * Both are calculated with a different algorithm + */ + @Test + public void testValues() { + boolean printResults = false; + if (printResults) { + System.out.println("\nTest One-way GNSS range rate Values\n"); + } + // Run test + this.genericTestValues(printResults); + } + + /** + * Test the values of the state derivatives using a numerical + * finite differences calculation as a reference + */ + @Test + public void testStateDerivatives() { + + boolean printResults = false; + if (printResults) { + System.out.println("\nTest One-way GNSS range rate State Derivatives - Finite Differences Comparison\n"); + } + // Run test + // the following relative tolerances for derivatives with respect to velocity + // may seem high, but they have been validated. The partial derivative of + // signal flight time with respect to velocity ∂τ/∂{vx, vy, vz} is about 10⁻¹³ + // when the signal flight time τ is about 10⁻⁴, so finite differences lose + // about 9 significant figures, so it is expected that partial derivatives + // computed with finite differences will only have a few digits corrects and + // that there will be outliers + double refErrorsPMedian = 5.6e-10; + double refErrorsPMean = 3.4e-09; + double refErrorsPMax = 6.8e-07; + double refErrorsVMedian = 6.6e-11; + double refErrorsVMean = 1.8e-10; + double refErrorsVMax = 7.1e-09; + this.genericTestStateDerivatives(printResults, 0, + refErrorsPMedian, refErrorsPMean, refErrorsPMax, + refErrorsVMedian, refErrorsVMean, refErrorsVMax); + } + + /** + * Test the values of the parameters' derivatives using a numerical + * finite differences calculation as a reference + */ + @Test + public void testParameterDerivatives() { + + // Print the results ? + boolean printResults = false; + + if (printResults) { + System.out.println("\nTest One-way GNSS range rate Derivatives - Finite Differences Comparison\n"); + } + // Run test + double refErrorsMedian = 6.7e-8; + double refErrorsMean = 2.1e-7; + double refErrorsMax = 2.8e-6; + this.genericTestParameterDerivatives(printResults, + refErrorsMedian, refErrorsMean, refErrorsMax); + + } + + /** + * Generic test function for values of the one-way GNSS range + * @param printResults Print the results ? + */ + void genericTestValues(final boolean printResults) { + + Context context = EstimationTestUtils.eccentricContext("regular-data:potential:tides"); + + final NumericalPropagatorBuilder propagatorBuilder = + context.createBuilder(OrbitType.KEPLERIAN, PositionAngleType.TRUE, true, + 1.0e-6, 60.0, 0.001); + + // Create perfect inter-satellites range rate measurements + final TimeStampedPVCoordinates original = context.initialOrbit.getPVCoordinates(); + final Orbit closeOrbit = new CartesianOrbit(new TimeStampedPVCoordinates(context.initialOrbit.getDate(), + original.getPosition().add(new Vector3D(1000, 2000, 3000)), + original.getVelocity().add(new Vector3D(-0.03, 0.01, 0.02))), + context.initialOrbit.getFrame(), + context.initialOrbit.getMu()); + final Propagator closePropagator = EstimationTestUtils.createPropagator(closeOrbit, + propagatorBuilder); + final EphemerisGenerator generator = closePropagator.getEphemerisGenerator(); + closePropagator.propagate(context.initialOrbit.getDate().shiftedBy(3.5 * closeOrbit.getKeplerianPeriod())); + final BoundedPropagator ephemeris = generator.getGeneratedEphemeris(); + final Propagator propagator = EstimationTestUtils.createPropagator(context.initialOrbit, + propagatorBuilder); + + final double localClockOffset = 0.14e-06; + final double localClockRate = -0.12e-10; + final double localClockAcceleration = 1.4e-13; + final double remoteClockOffset = 469.0e-06; + final double remoteClockRate = 33.0e-10; + final double remoteClockAcceleration = 0.5e-13; + final List> measurements = + EstimationTestUtils.createMeasurements(propagator, + new OneWayGNSSRangeRateCreator(ephemeris, + localClockOffset, localClockRate, localClockAcceleration, + remoteClockOffset, remoteClockRate, remoteClockAcceleration), + 1.0, 3.0, 300.0); + + // Lists for results' storage - Used only for derivatives with respect to state + // "final" value to be seen by "handleStep" function of the propagator + final List absoluteErrors = new ArrayList<>(); + final List relativeErrors = new ArrayList<>(); + + // Use a lambda function to implement "handleStep" function + propagator.setStepHandler(interpolator -> { + + for (final ObservedMeasurement measurement : measurements) { + + // Play test if the measurement date is between interpolator previous and current date + if ((measurement.getDate().durationFrom(interpolator.getPreviousState().getDate()) > 0.) && + (measurement.getDate().durationFrom(interpolator.getCurrentState().getDate()) <= 0.) + ) { + // We intentionally propagate to a date which is close to the + // real spacecraft state but is *not* the accurate date, by + // compensating only part of the downlink delay. This is done + // in order to validate the partial derivatives with respect + // to velocity. + final double meanDelay = measurement.getObservedValue()[0] / Constants.SPEED_OF_LIGHT; + final AbsoluteDate date = measurement.getDate().shiftedBy(-0.75 * meanDelay); + final SpacecraftState state = interpolator.getInterpolatedState(date); + + // Values of the range rate & errors + final double rangeObserved = measurement.getObservedValue()[0]; + final EstimatedMeasurementBase estimated = measurement.estimateWithoutDerivatives(0, 0, + new SpacecraftState[] { + state, + ephemeris.propagate(state.getDate()) + }); + + final double rangeEstimated = estimated.getEstimatedValue()[0]; + final double absoluteError = rangeEstimated-rangeObserved; + absoluteErrors.add(absoluteError); + relativeErrors.add(FastMath.abs(absoluteError)/FastMath.abs(rangeObserved)); + + // Print results on console ? + if (printResults) { + final AbsoluteDate measurementDate = measurement.getDate(); + + System.out.format(Locale.US, "%-23s %-23s %19.6f %19.6f %13.6e %13.6e%n", + measurementDate, date, + rangeObserved, rangeEstimated, + FastMath.abs(rangeEstimated-rangeObserved), + FastMath.abs((rangeEstimated-rangeObserved)/rangeObserved)); + } + + } // End if measurement date between previous and current interpolator step + } // End for loop on the measurements + }); // End lambda function handlestep + + // Print results on console ? Header + if (printResults) { + System.out.format(Locale.US, "%-23s %-23s %19s %19s %19s %19s%n", + "Measurement Date", "State Date", + "range rate observed [m/s]", "range rate estimated [m/s]", + "Δrange rate[m/s]", "rel ΔRange rate"); + } + + // Rewind the propagator to initial date + propagator.propagate(context.initialOrbit.getDate()); + + // Sort measurements chronologically + measurements.sort(Comparator.naturalOrder()); + + // Propagate to final measurement's date + propagator.propagate(measurements.get(measurements.size()-1).getDate()); + + // Convert lists to double array + final double[] absErrors = absoluteErrors.stream().mapToDouble(Double::doubleValue).toArray(); + final double[] relErrors = relativeErrors.stream().mapToDouble(Double::doubleValue).toArray(); + + // Statistics' assertion + final double absErrorsMedian = new Median().evaluate(absErrors); + final double absErrorsMin = new Min().evaluate(absErrors); + final double absErrorsMax = new Max().evaluate(absErrors); + final double relErrorsMedian = new Median().evaluate(relErrors); + final double relErrorsMax = new Max().evaluate(relErrors); + + // Print the results on console ? Final results + if (printResults) { + System.out.println(); + System.out.println("Absolute errors median: " + absErrorsMedian); + System.out.println("Absolute errors min : " + absErrorsMin); + System.out.println("Absolute errors max : " + absErrorsMax); + System.out.println("Relative errors median: " + relErrorsMedian); + System.out.println("Relative errors max : " + relErrorsMax); + } + + Assertions.assertEquals(0.0, absErrorsMedian, 3.9e-9); + Assertions.assertEquals(0.0, absErrorsMin, 1.2e-11); + Assertions.assertEquals(0.0, absErrorsMax, 1.6e-8); + Assertions.assertEquals(0.0, relErrorsMedian, 1.1e-9); + Assertions.assertEquals(0.0, relErrorsMax, 1.1e-7); + + // Test measurement type + Assertions.assertEquals(OneWayGNSSRangeRate.MEASUREMENT_TYPE, measurements.get(0).getMeasurementType()); + } + + void genericTestStateDerivatives(final boolean printResults, final int index, + final double refErrorsPMedian, final double refErrorsPMean, final double refErrorsPMax, + final double refErrorsVMedian, final double refErrorsVMean, final double refErrorsVMax) { + + Context context = EstimationTestUtils.eccentricContext("regular-data:potential:tides"); + + final NumericalPropagatorBuilder propagatorBuilder = + context.createBuilder(OrbitType.KEPLERIAN, PositionAngleType.TRUE, true, + 1.0e-6, 60.0, 0.001); + + // Create perfect one-way GNSS range rate measurements + final TimeStampedPVCoordinates original = context.initialOrbit.getPVCoordinates(); + final Orbit closeOrbit = new CartesianOrbit(new TimeStampedPVCoordinates(context.initialOrbit.getDate(), + original.getPosition().add(new Vector3D(1000, 2000, 3000)), + original.getVelocity().add(new Vector3D(-0.03, 0.01, 0.02))), + context.initialOrbit.getFrame(), + context.initialOrbit.getMu()); + final Propagator closePropagator = EstimationTestUtils.createPropagator(closeOrbit, + propagatorBuilder); + final EphemerisGenerator generator = closePropagator.getEphemerisGenerator(); + closePropagator.propagate(context.initialOrbit.getDate().shiftedBy(3.5 * closeOrbit.getKeplerianPeriod())); + final BoundedPropagator ephemeris = generator.getGeneratedEphemeris(); + final Propagator propagator = EstimationTestUtils.createPropagator(context.initialOrbit, + propagatorBuilder); + + final double localClockOffset = 0.14e-06; + final double localClockRate = -0.12e-10; + final double localClockAcceleration = 1.4e-13; + final double remoteClockOffset = 469.0e-06; + final double remoteClockRate = 33.0e-10; + final double remoteClockAcceleration = 0.5e-13; + final List> measurements = + EstimationTestUtils.createMeasurements(propagator, + new OneWayGNSSRangeRateCreator(ephemeris, + localClockOffset, localClockRate, localClockAcceleration, + remoteClockOffset, remoteClockRate, remoteClockAcceleration), + 1.0, 3.0, 300.0); + + // Lists for results' storage - Used only for derivatives with respect to state + // "final" value to be seen by "handleStep" function of the propagator + final List errorsP = new ArrayList<>(); + final List errorsV = new ArrayList<>(); + + // Use a lambda function to implement "handleStep" function + propagator.setStepHandler(interpolator -> { + + for (final ObservedMeasurement measurement : measurements) { + + // Play test if the measurement date is between interpolator previous and current date + if ((measurement.getDate().durationFrom(interpolator.getPreviousState().getDate()) > 0.) && + (measurement.getDate().durationFrom(interpolator.getCurrentState().getDate()) <= 0.) + ) { + + // We intentionally propagate to a date which is close to the + // real spacecraft state but is *not* the accurate date, by + // compensating only part of the downlink delay. This is done + // in order to validate the partial derivatives with respect + // to velocity. + final double meanDelay = measurement.getObservedValue()[0] / Constants.SPEED_OF_LIGHT; + final AbsoluteDate date = measurement.getDate().shiftedBy(-0.9 * meanDelay); + final SpacecraftState[] states = { + interpolator.getInterpolatedState(date), + ephemeris.propagate(date) + }; + final double[][] jacobian = measurement.estimate(0, 0, states).getStateDerivatives(index); + + // Jacobian reference value + final double[][] jacobianRef; + + // Compute a reference value using finite differences + jacobianRef = Differentiation.differentiate(state -> { + final SpacecraftState[] s = states.clone(); + s[index] = state; + return measurement.estimateWithoutDerivatives(0, 0, s).getEstimatedValue(); + }, measurement.getDimension(), propagator.getAttitudeProvider(), + OrbitType.CARTESIAN, PositionAngleType.TRUE, 8.0, 5).value(states[index]); + + Assertions.assertEquals(jacobianRef.length, jacobian.length); + Assertions.assertEquals(jacobianRef[0].length, jacobian[0].length); + + // Errors & relative errors on the Jacobian + double [][] dJacobian = new double[jacobian.length][jacobian[0].length]; + double [][] dJacobianRelative = new double[jacobian.length][jacobian[0].length]; + for (int i = 0; i < jacobian.length; ++i) { + for (int j = 0; j < jacobian[i].length; ++j) { + dJacobian[i][j] = jacobian[i][j] - jacobianRef[i][j]; + dJacobianRelative[i][j] = FastMath.abs(dJacobian[i][j]/jacobianRef[i][j]); + + if (j < 3) { errorsP.add(dJacobianRelative[i][j]); + } else { errorsV.add(dJacobianRelative[i][j]); } + } + } + // Print values in console ? + if (printResults) { + System.out.format(Locale.US, "%-23s %-23s " + + "%10.3e %10.3e %10.3e " + + "%10.3e %10.3e %10.3e " + + "%10.3e %10.3e %10.3e " + + "%10.3e %10.3e %10.3e%n", + measurement.getDate(), date, + dJacobian[0][0], dJacobian[0][1], dJacobian[0][2], + dJacobian[0][3], dJacobian[0][4], dJacobian[0][5], + dJacobianRelative[0][0], dJacobianRelative[0][1], dJacobianRelative[0][2], + dJacobianRelative[0][3], dJacobianRelative[0][4], dJacobianRelative[0][5]); + } + } // End if measurement date between previous and current interpolator step + } // End for loop on the measurements + }); + + // Print results on console ? + if (printResults) { + System.out.format(Locale.US, "%-23s %-23s " + + "%10s %10s %10s " + + "%10s %10s %10s " + + "%10s %10s %10s " + + "%10s %10s %10s%n", + "Measurement Date", "State Date", + "ΔdPx", "ΔdPy", "ΔdPz", "ΔdVx", "ΔdVy", "ΔdVz", + "rel ΔdPx", "rel ΔdPy", "rel ΔdPz", + "rel ΔdVx", "rel ΔdVy", "rel ΔdVz"); + } + + // Rewind the propagator to initial date + propagator.propagate(context.initialOrbit.getDate()); + + // Sort measurements, primarily chronologically + measurements.sort(Comparator.naturalOrder()); + + // Propagate to final measurement's date + propagator.propagate(measurements.get(measurements.size()-1).getDate()); + + // Convert lists to double[] and evaluate some statistics + final double[] relErrorsP = errorsP.stream().mapToDouble(Double::doubleValue).toArray(); + final double[] relErrorsV = errorsV.stream().mapToDouble(Double::doubleValue).toArray(); + + final double errorsPMedian = new Median().evaluate(relErrorsP); + final double errorsPMean = new Mean().evaluate(relErrorsP); + final double errorsPMax = new Max().evaluate(relErrorsP); + final double errorsVMedian = new Median().evaluate(relErrorsV); + final double errorsVMean = new Mean().evaluate(relErrorsV); + final double errorsVMax = new Max().evaluate(relErrorsV); + + // Print the results on console ? + if (printResults) { + System.out.println(); + System.out.format(Locale.US, "Relative errors dR/dP -> Median: %6.3e / Mean: %6.3e / Max: %6.3e%n", + errorsPMedian, errorsPMean, errorsPMax); + System.out.format(Locale.US, "Relative errors dR/dV -> Median: %6.3e / Mean: %6.3e / Max: %6.3e%n", + errorsVMedian, errorsVMean, errorsVMax); + } + + Assertions.assertEquals(0.0, errorsPMedian, refErrorsPMedian); + Assertions.assertEquals(0.0, errorsPMean, refErrorsPMean); + Assertions.assertEquals(0.0, errorsPMax, refErrorsPMax); + Assertions.assertEquals(0.0, errorsVMedian, refErrorsVMedian); + Assertions.assertEquals(0.0, errorsVMean, refErrorsVMean); + Assertions.assertEquals(0.0, errorsVMax, refErrorsVMax); + } + + void genericTestParameterDerivatives(final boolean printResults, + final double refErrorsMedian, final double refErrorsMean, final double refErrorsMax) { + + Context context = EstimationTestUtils.eccentricContext("regular-data:potential:tides"); + + final NumericalPropagatorBuilder propagatorBuilder = + context.createBuilder(OrbitType.KEPLERIAN, PositionAngleType.TRUE, true, + 1.0e-6, 60.0, 0.001); + + // Create perfect one-way GNSS range ratemeasurements + final TimeStampedPVCoordinates original = context.initialOrbit.getPVCoordinates(); + final Orbit closeOrbit = new CartesianOrbit(new TimeStampedPVCoordinates(context.initialOrbit.getDate(), + original.getPosition().add(new Vector3D(1000, 2000, 3000)), + original.getVelocity().add(new Vector3D(-0.03, 0.01, 0.02))), + context.initialOrbit.getFrame(), + context.initialOrbit.getMu()); + final Propagator closePropagator = EstimationTestUtils.createPropagator(closeOrbit, propagatorBuilder); + final EphemerisGenerator generator = closePropagator.getEphemerisGenerator(); + closePropagator.propagate(context.initialOrbit.getDate().shiftedBy(3.5 * closeOrbit.getKeplerianPeriod())); + final BoundedPropagator ephemeris = generator.getGeneratedEphemeris(); + + // Create perfect range ratemeasurements + final double localClockOffset = 0.14e-06; + final double localClockRate = -0.12e-10; + final double localClockAcceleration = 1.4e-13; + final double remoteClockOffset = 469.0e-06; + final double remoteClockRate = 33.0e-10; + final double remoteClockAcceleration = 0.5e-13; + final OneWayGNSSRangeRateCreator creator = new OneWayGNSSRangeRateCreator(ephemeris, + localClockOffset, localClockRate, localClockAcceleration, + remoteClockOffset, remoteClockRate, remoteClockAcceleration); + creator.getLocalSatellite().getClockOffsetDriver().setSelected(true); + + final Propagator propagator = EstimationTestUtils.createPropagator(context.initialOrbit, + propagatorBuilder); + final List> measurements = + EstimationTestUtils.createMeasurements(propagator, creator, 1.0, 3.0, 300.0); + + // List to store the results + final List relErrorList = new ArrayList<>(); + + // Use a lambda function to implement "handleStep" function + propagator.setStepHandler(interpolator -> { + + for (final ObservedMeasurement measurement : measurements) { + + // Play test if the measurement date is between interpolator previous and current date + if ((measurement.getDate().durationFrom(interpolator.getPreviousState().getDate()) > 0.) && + (measurement.getDate().durationFrom(interpolator.getCurrentState().getDate()) <= 0.)) { + + // We intentionally propagate to a date which is close to the + // real spacecraft state but is *not* the accurate date, by + // compensating only part of the downlink delay. This is done + // in order to validate the partial derivatives with respect + // to velocity. If we had chosen the proper state date, the + // range rate would have depended only on the current position but + // not on the current velocity. + final double meanDelay = measurement.getObservedValue()[0] / Constants.SPEED_OF_LIGHT; + final AbsoluteDate date = measurement.getDate().shiftedBy(-0.75 * meanDelay); + final SpacecraftState[] states = { + interpolator.getInterpolatedState(date), + ephemeris.propagate(date) + }; + final ParameterDriver[] drivers = new ParameterDriver[] { + measurement.getSatellites().get(0).getClockOffsetDriver(), + }; + + for (int i = 0; i < drivers.length; ++i) { + for (Span span = drivers[i].getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) { + + final double[] gradient = measurement.estimate(0, 0, states).getParameterDerivatives(drivers[i], span.getStart()); + Assertions.assertEquals(1, measurement.getDimension()); + Assertions.assertEquals(1, gradient.length); + + // Compute a reference value using finite differences + final ParameterFunction dMkdP = + Differentiation.differentiate(new ParameterFunction() { + /** {@inheritDoc} */ + @Override + public double value(final ParameterDriver parameterDriver, final AbsoluteDate date) { + return measurement. + estimateWithoutDerivatives(0, 0, states). + getEstimatedValue()[0]; + } + }, 5, 10.0 * drivers[i].getScale()); + final double ref = dMkdP.value(drivers[i], date); + + if (printResults) { + System.out.format(Locale.US, "%10.3e %10.3e ", gradient[0]-ref, FastMath.abs((gradient[0]-ref)/ref)); + } + + final double relError = FastMath.abs((ref-gradient[0])/ref); + relErrorList.add(relError); + } + } + if (printResults) { + System.out.format(Locale.US, "%n"); + } + + } // End if measurement date between previous and current interpolator step + } // End for loop on the measurements + }); + + // Rewind the propagator to initial date + propagator.propagate(context.initialOrbit.getDate()); + + // Sort measurements chronologically + measurements.sort(Comparator.naturalOrder()); + + // Print results ? Header + if (printResults) { + System.out.format(Locale.US, "%-15s %-23s %-23s " + + "%10s %10s %10s %10s %10s %10s %10s %10s %10s %10s%n", + "Station", "Measurement Date", "State Date", + "Δt", "rel Δt", + "ΔdQx", "rel ΔdQx", + "ΔdQy", "rel ΔdQy", + "ΔdQz", "rel ΔdQz", + "Δtsat", "rel Δtsat"); + } + + // Propagate to final measurement's date + propagator.propagate(measurements.get(measurements.size()-1).getDate()); + + // Convert error list to double[] + final double[] relErrors = relErrorList.stream().mapToDouble(Double::doubleValue).toArray(); + + // Compute statistics + final double relErrorsMedian = new Median().evaluate(relErrors); + final double relErrorsMean = new Mean().evaluate(relErrors); + final double relErrorsMax = new Max().evaluate(relErrors); + + // Print the results on console ? + if (printResults) { + System.out.println(); + System.out.format(Locale.US, "Relative errors dR/dQ -> Median: %6.3e / Mean: %6.3e / Max: %6.3e%n", + relErrorsMedian, relErrorsMean, relErrorsMax); + } + + Assertions.assertEquals(0.0, relErrorsMedian, refErrorsMedian); + Assertions.assertEquals(0.0, relErrorsMean, refErrorsMean); + Assertions.assertEquals(0.0, relErrorsMax, refErrorsMax); + + } + +} From 226bf443b0eeab5db6cdd2f52ba53eae405efd25 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Tue, 5 Mar 2024 16:06:26 +0100 Subject: [PATCH 178/359] Added relativistic corrections for on-board Doppler measurements. --- ...tivisticClockOnBoardRangeRateModifier.java | 90 ++++++++++++++++++ ...nterSatellitesOneWayRangeRateModifier.java | 54 +++++++++++ ...isticClockOneWayGNSSRangeRateModifier.java | 64 +++++++++++++ .../gnss/OneWayGNSSRangeRateCreator.java | 19 ++-- ...SatellitesOneWayRangeRateModifierTest.java | 91 +++++++++++++++++++ ...cClockOneWayGNSSRangeRateModifierTest.java | 91 +++++++++++++++++++ 6 files changed, 398 insertions(+), 11 deletions(-) create mode 100644 src/main/java/org/orekit/estimation/measurements/modifiers/AbstractRelativisticClockOnBoardRangeRateModifier.java create mode 100644 src/main/java/org/orekit/estimation/measurements/modifiers/RelativisticClockInterSatellitesOneWayRangeRateModifier.java create mode 100644 src/main/java/org/orekit/estimation/measurements/modifiers/RelativisticClockOneWayGNSSRangeRateModifier.java create mode 100644 src/test/java/org/orekit/estimation/measurements/modifiers/RelativisticClockInterSatellitesOneWayRangeRateModifierTest.java create mode 100644 src/test/java/org/orekit/estimation/measurements/modifiers/RelativisticClockOneWayGNSSRangeRateModifierTest.java diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/AbstractRelativisticClockOnBoardRangeRateModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/AbstractRelativisticClockOnBoardRangeRateModifier.java new file mode 100644 index 0000000000..f1cb04d3a9 --- /dev/null +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/AbstractRelativisticClockOnBoardRangeRateModifier.java @@ -0,0 +1,90 @@ +/* Copyright 2002-2024 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.estimation.measurements.modifiers; + +import org.orekit.estimation.measurements.EstimatedMeasurementBase; +import org.orekit.estimation.measurements.EstimationModifier; +import org.orekit.estimation.measurements.ObservedMeasurement; +import org.orekit.utils.Constants; +import org.orekit.utils.ParameterDriver; + +import java.util.Collections; +import java.util.List; + +/** Class modifying theoretical range-rate measurement with relativistic frequency deviation. + *

              + * Relativistic clock correction is caused by the motion of the satellite as well as + * the change in the gravitational potential + *

              + * @param type of the measurement + * @author Luc Maisonobe + * @since 12.1 + * + * @see "Teunissen, Peter, and Oliver Montenbruck, eds. Springer handbook of global navigation + * satellite systems. Chapter 19.2. Springer, 2017." + */ +public abstract class AbstractRelativisticClockOnBoardRangeRateModifier> + extends AbstractRelativisticClockModifier implements EstimationModifier { + + /** Gravitational constant. */ + private final double gm; + + /** Simple constructor. + * @param gm gravitational constant for main body in signal path vicinity. + */ + public AbstractRelativisticClockOnBoardRangeRateModifier(final double gm) { + super(); + this.gm = gm; + } + + /** Get gravitational constant for main body in signal path vicinity. + * @return gravitational constant for main body in signal path vicinity + */ + protected double getGm() { + return gm; + } + + /** {@inheritDoc} */ + @Override + public List getParametersDrivers() { + return Collections.emptyList(); + } + + /** Apply relativistic frequency deviation. + * @param estimated estimated measurement to modify + * @param aLocal semi major axis or local (receiver) satellite + * @param rLocal distance of local (receiver) satellite to central body center + * @param aRemote semi major axis or remote (transmitter) satellite + * @param rRemote distance of remote (transmitter) satellite to central body center + */ + protected void modifyWithoutDerivatives(final EstimatedMeasurementBase estimated, + final double aLocal, final double rLocal, + final double aRemote, final double rRemote) { + + // compute relativistic frequency deviation + final double factor = -gm * getScaleFactor(); + final double dfLocal = factor * (1.0 / aLocal - 1.0 / rLocal); + final double dfRemote = factor * (1.0 / aRemote - 1.0 / rRemote); + + // Update estimated value taking into account the relativistic effect. + final double[] newValue = estimated.getEstimatedValue().clone(); + newValue[0] = newValue[0] + (dfLocal - dfRemote) * Constants.SPEED_OF_LIGHT; + estimated.setEstimatedValue(newValue); + + } + +} diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/RelativisticClockInterSatellitesOneWayRangeRateModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/RelativisticClockInterSatellitesOneWayRangeRateModifier.java new file mode 100644 index 0000000000..c71a7fe44c --- /dev/null +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/RelativisticClockInterSatellitesOneWayRangeRateModifier.java @@ -0,0 +1,54 @@ +/* Copyright 2002-2024 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.estimation.measurements.modifiers; + +import org.orekit.estimation.measurements.EstimatedMeasurementBase; +import org.orekit.estimation.measurements.gnss.InterSatellitesOneWayRangeRate; +import org.orekit.propagation.SpacecraftState; + +/** Class modifying theoretical range-rate measurement with relativistic frequency deviation. + *

              + * Relativistic clock correction is caused by the motion of the satellite as well as + * the change in the gravitational potential + *

              + * @author Luc Maisonobe + * @since 12.1 + * + * @see "Teunissen, Peter, and Oliver Montenbruck, eds. Springer handbook of global navigation + * satellite systems. Chapter 19.2. Springer, 2017." + */ +public class RelativisticClockInterSatellitesOneWayRangeRateModifier + extends AbstractRelativisticClockOnBoardRangeRateModifier { + + /** Simple constructor. + * @param gm gravitational constant for main body in signal path vicinity. + */ + public RelativisticClockInterSatellitesOneWayRangeRateModifier(final double gm) { + super(gm); + } + + /** {@inheritDoc} */ + @Override + public void modifyWithoutDerivatives(final EstimatedMeasurementBase estimated) { + final SpacecraftState local = estimated.getStates()[0]; + final SpacecraftState remote = estimated.getStates()[1]; + modifyWithoutDerivatives(estimated, + local.getA(), local.getPosition().getNorm(), + remote.getA(), remote.getPosition().getNorm()); + } + +} diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/RelativisticClockOneWayGNSSRangeRateModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/RelativisticClockOneWayGNSSRangeRateModifier.java new file mode 100644 index 0000000000..759a867b13 --- /dev/null +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/RelativisticClockOneWayGNSSRangeRateModifier.java @@ -0,0 +1,64 @@ +/* Copyright 2002-2024 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.estimation.measurements.modifiers; + +import org.orekit.estimation.measurements.EstimatedMeasurementBase; +import org.orekit.estimation.measurements.gnss.OneWayGNSSRangeRate; +import org.orekit.propagation.SpacecraftState; +import org.orekit.utils.PVCoordinates; + +/** Class modifying theoretical range-rate measurement with relativistic frequency deviation. + *

              + * Relativistic clock correction is caused by the motion of the satellite as well as + * the change in the gravitational potential + *

              + * @author Luc Maisonobe + * @since 12.1 + * + * @see "Teunissen, Peter, and Oliver Montenbruck, eds. Springer handbook of global navigation + * satellite systems. Chapter 19.2. Springer, 2017." + */ +public class RelativisticClockOneWayGNSSRangeRateModifier + extends AbstractRelativisticClockOnBoardRangeRateModifier { + + /** Simple constructor. + * @param gm gravitational constant for main body in signal path vicinity. + */ + public RelativisticClockOneWayGNSSRangeRateModifier(final double gm) { + super(gm); + } + + /** {@inheritDoc} */ + @Override + public void modifyWithoutDerivatives(final EstimatedMeasurementBase estimated) { + + // local satellite + final SpacecraftState local = estimated.getStates()[0]; + + // compute semi major axis of remote (transmitter) satellite + final PVCoordinates remote = estimated.getParticipants()[0]; + final double rRemote = remote.getPosition().getNorm(); + final double vRemote = remote.getVelocity().getNorm(); + final double aRemote = 1.0 / (2 / rRemote - vRemote * vRemote / getGm()); + + modifyWithoutDerivatives(estimated, + local.getA(), local.getPosition().getNorm(), + aRemote, rRemote); + + } + +} diff --git a/src/test/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRangeRateCreator.java b/src/test/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRangeRateCreator.java index 4b3b03686b..cb6085093b 100644 --- a/src/test/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRangeRateCreator.java +++ b/src/test/java/org/orekit/estimation/measurements/gnss/OneWayGNSSRangeRateCreator.java @@ -16,7 +16,6 @@ */ package org.orekit.estimation.measurements.gnss; -import org.hipparchus.analysis.UnivariateFunction; import org.hipparchus.analysis.solvers.BracketingNthOrderBrentSolver; import org.hipparchus.analysis.solvers.UnivariateSolver; import org.hipparchus.geometry.euclidean.threed.Vector3D; @@ -100,16 +99,14 @@ public void handleStep(final SpacecraftState currentState) { final UnivariateSolver solver = new BracketingNthOrderBrentSolver(1.0e-12, 5); - final double downLinkDelay = solver.solve(1000, new UnivariateFunction() { - public double value(final double x) { - final Vector3D other = ephemeris. - propagate(date.shiftedBy(-x)). - toTransform(). - getInverse(). - transformPosition(antennaPhaseCenter2); - final double d = Vector3D.distance(pv.getPosition(), other); - return d - x * Constants.SPEED_OF_LIGHT; - } + final double downLinkDelay = solver.solve(1000, x -> { + final Vector3D other = ephemeris. + propagate(date.shiftedBy(-x)). + toTransform(). + getInverse(). + transformPosition(antennaPhaseCenter2); + final double d = Vector3D.distance(pv.getPosition(), other); + return d - x * Constants.SPEED_OF_LIGHT; }, -1.0, 1.0); final AbsoluteDate transitDate = currentState.getDate().shiftedBy(-downLinkDelay); final PVCoordinates otherAtTransit = ephemeris.propagate(transitDate). diff --git a/src/test/java/org/orekit/estimation/measurements/modifiers/RelativisticClockInterSatellitesOneWayRangeRateModifierTest.java b/src/test/java/org/orekit/estimation/measurements/modifiers/RelativisticClockInterSatellitesOneWayRangeRateModifierTest.java new file mode 100644 index 0000000000..0cb0af9b2b --- /dev/null +++ b/src/test/java/org/orekit/estimation/measurements/modifiers/RelativisticClockInterSatellitesOneWayRangeRateModifierTest.java @@ -0,0 +1,91 @@ +/* Copyright 2002-2024 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.estimation.measurements.modifiers; + +import org.hipparchus.geometry.euclidean.threed.Vector3D; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.orekit.Utils; +import org.orekit.estimation.measurements.EstimatedMeasurement; +import org.orekit.estimation.measurements.EstimatedMeasurementBase; +import org.orekit.estimation.measurements.EstimationModifier; +import org.orekit.estimation.measurements.gnss.InterSatellitesOneWayRangeRate; +import org.orekit.estimation.measurements.ObservableSatellite; +import org.orekit.propagation.SpacecraftState; +import org.orekit.propagation.analytical.tle.TLE; +import org.orekit.propagation.analytical.tle.TLEPropagator; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.TimeScalesFactory; +import org.orekit.utils.Constants; +import org.orekit.utils.PVCoordinates; + +public class RelativisticClockInterSatellitesOneWayRangeRateModifierTest { + + /** Date. */ + private static AbsoluteDate date; + + /** Spacecraft states. */ + private static SpacecraftState[] states; + + @Test + public void testRelativisticClockCorrection() { + + // Measurement + final PVCoordinates delta = new PVCoordinates(states[1].getPVCoordinates(), + states[0].getPVCoordinates()); + final InterSatellitesOneWayRangeRate range = new InterSatellitesOneWayRangeRate(new ObservableSatellite(0), + new ObservableSatellite(1), + date, + Vector3D.dotProduct(delta.getVelocity(), + delta.getPosition().normalize()), + 1.0, 1.0); + + // Inter-satellites range rate before applying the modifier + final EstimatedMeasurementBase estimatedBefore = range.estimateWithoutDerivatives(0, 0, states); + + // Inter-satellites range rate before applying the modifier + final EstimationModifier modifier = + new RelativisticClockInterSatellitesOneWayRangeRateModifier(Constants.EIGEN5C_EARTH_MU); + range.addModifier(modifier); + final EstimatedMeasurement estimatedAfter = range.estimate(0, 0, states); + + // Verify + Assertions.assertEquals(1.63e-3, estimatedBefore.getEstimatedValue()[0] - estimatedAfter.getEstimatedValue()[0], 1.0e-5); + Assertions.assertEquals(0, modifier.getParametersDrivers().size()); + + } + + @BeforeEach + public void setUp() { + // Data root + Utils.setDataRoot("regular-data"); + + // Date + date = new AbsoluteDate("2004-01-13T00:00:00.000", TimeScalesFactory.getUTC()); + + // Spacecraft states + states = new SpacecraftState[2]; + final TLE local = new TLE("1 27642U 03002A 04013.91734903 .00000108 00000-0 12227-4 0 3621", + "2 27642 93.9970 6.8623 0003169 80.1383 280.0205 14.90871424 54508"); + final TLE remote = new TLE("1 20061U 89044A 04013.44391333 .00000095 00000-0 10000-3 0 3242", + "2 20061 53.4233 172.2072 0234017 261.4179 95.8975 2.00577231106949"); + states[0] = TLEPropagator.selectExtrapolator(local).propagate(date); + states[1] = TLEPropagator.selectExtrapolator(remote).propagate(date); + } + +} diff --git a/src/test/java/org/orekit/estimation/measurements/modifiers/RelativisticClockOneWayGNSSRangeRateModifierTest.java b/src/test/java/org/orekit/estimation/measurements/modifiers/RelativisticClockOneWayGNSSRangeRateModifierTest.java new file mode 100644 index 0000000000..a581d458cb --- /dev/null +++ b/src/test/java/org/orekit/estimation/measurements/modifiers/RelativisticClockOneWayGNSSRangeRateModifierTest.java @@ -0,0 +1,91 @@ +/* Copyright 2002-2024 Thales Alenia Space + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.estimation.measurements.modifiers; + +import org.hipparchus.geometry.euclidean.threed.Vector3D; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.orekit.Utils; +import org.orekit.estimation.measurements.EstimatedMeasurement; +import org.orekit.estimation.measurements.EstimatedMeasurementBase; +import org.orekit.estimation.measurements.EstimationModifier; +import org.orekit.estimation.measurements.ObservableSatellite; +import org.orekit.estimation.measurements.gnss.OneWayGNSSRangeRate; +import org.orekit.propagation.SpacecraftState; +import org.orekit.propagation.analytical.tle.TLE; +import org.orekit.propagation.analytical.tle.TLEPropagator; +import org.orekit.time.AbsoluteDate; +import org.orekit.time.TimeScalesFactory; +import org.orekit.utils.Constants; +import org.orekit.utils.PVCoordinates; + +public class RelativisticClockOneWayGNSSRangeRateModifierTest { + + /** Date. */ + private static AbsoluteDate date; + + /** Spacecraft states. */ + private static SpacecraftState[] states; + + @Test + public void testRelativisticClockCorrection() { + + // Measurement + final PVCoordinates delta = new PVCoordinates(states[1].getPVCoordinates(), + states[0].getPVCoordinates()); + final OneWayGNSSRangeRate + range = new OneWayGNSSRangeRate(states[1].getOrbit(), 0.0, + date, + Vector3D.dotProduct(delta.getVelocity(), + delta.getPosition().normalize()), + 1.0, 1.0, new ObservableSatellite(0)); + + // Inter-satellites range rate before applying the modifier + final EstimatedMeasurementBase estimatedBefore = range.estimateWithoutDerivatives(0, 0, states); + + // Inter-satellites range rate before applying the modifier + final EstimationModifier modifier = + new RelativisticClockOneWayGNSSRangeRateModifier(Constants.EIGEN5C_EARTH_MU); + range.addModifier(modifier); + final EstimatedMeasurement estimatedAfter = range.estimate(0, 0, states); + + // Verify + Assertions.assertEquals(1.63e-3, estimatedBefore.getEstimatedValue()[0] - estimatedAfter.getEstimatedValue()[0], 1.0e-5); + Assertions.assertEquals(0, modifier.getParametersDrivers().size()); + + } + + @BeforeEach + public void setUp() { + // Data root + Utils.setDataRoot("regular-data"); + + // Date + date = new AbsoluteDate("2004-01-13T00:00:00.000", TimeScalesFactory.getUTC()); + + // Spacecraft states + states = new SpacecraftState[2]; + final TLE local = new TLE("1 27642U 03002A 04013.91734903 .00000108 00000-0 12227-4 0 3621", + "2 27642 93.9970 6.8623 0003169 80.1383 280.0205 14.90871424 54508"); + final TLE remote = new TLE("1 20061U 89044A 04013.44391333 .00000095 00000-0 10000-3 0 3242", + "2 20061 53.4233 172.2072 0234017 261.4179 95.8975 2.00577231106949"); + states[0] = TLEPropagator.selectExtrapolator(local).propagate(date); + states[1] = TLEPropagator.selectExtrapolator(remote).propagate(date); + } + +} From 4d4bf34f86c33dc1b06c649d103ecc9118a584ea Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Wed, 6 Mar 2024 09:28:38 +0100 Subject: [PATCH 179/359] Documentation. --- src/main/java/org/orekit/overview.html | 4 +++- src/site/markdown/index.md | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/orekit/overview.html b/src/main/java/org/orekit/overview.html index 0eb64ccb18..039fb785ce 100644 --- a/src/main/java/org/orekit/overview.html +++ b/src/main/java/org/orekit/overview.html @@ -1,4 +1,4 @@ - + OREKIT

              1. Purpose

              @@ -306,6 +306,7 @@

              2. Features

            • position-velocity
            • position
            • inter-satellites range (one way and two way)
            • +
            • inter-satellites GNSS one way range rate
            • inter-satellites GNSS phase
            • GNSS code
            • GNSS phase with integer ambiguity resolution and wind-up effect
            • @@ -327,6 +328,7 @@

              2. Features

            • biases
            • delays
            • Antenna Phase Center
            • +
            • Phase ambiguity
            • Shapiro relativistic effect
            • aberration of light in telescope measurements
            diff --git a/src/site/markdown/index.md b/src/site/markdown/index.md index 091d3a0ed7..ed27f5ec14 100644 --- a/src/site/markdown/index.md +++ b/src/site/markdown/index.md @@ -240,6 +240,7 @@ * position-velocity * position * inter-satellites range (one way and two way) + * inter-satellites GNSS one way range rate * inter-satellites GNSS phase * GNSS code * GNSS phase with integer ambiguity resolution and wind-up effect @@ -258,6 +259,7 @@ * biases * delays * Antenna Phase Center + * Phase ambiguity * Shapiro relativistic effect * aberration of light in telescope measurements * possibility to add custom measurement modifiers (even for predefined events) From df08ae6363e8a37ef1d8e06cbd1c4e5f273c74d6 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Wed, 6 Mar 2024 10:00:31 +0100 Subject: [PATCH 180/359] Added getOriginalEstimatedValue() to estimated measurements. --- src/changes/changes.xml | 3 +++ .../measurements/EstimatedMeasurementBase.java | 16 ++++++++++++++++ .../modifiers/TropoModifierTest.java | 3 +++ 3 files changed, 22 insertions(+) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 58a35adc8b..8efbccd443 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -21,6 +21,9 @@ + + Added separate access to original estimation and modifications in estimated measurements. + Added InterSatellitesOneWayRangeRate measurements. diff --git a/src/main/java/org/orekit/estimation/measurements/EstimatedMeasurementBase.java b/src/main/java/org/orekit/estimation/measurements/EstimatedMeasurementBase.java index 4cae69655a..9f61e0f20a 100644 --- a/src/main/java/org/orekit/estimation/measurements/EstimatedMeasurementBase.java +++ b/src/main/java/org/orekit/estimation/measurements/EstimatedMeasurementBase.java @@ -42,6 +42,11 @@ public class EstimatedMeasurementBase> implemen /** Coordinates of the participants in signal travel order. */ private final TimeStampedPVCoordinates[] participants; + /** Original estimated value prior to any modification. + * @since 12.1 + */ + private double[] originalEstimatedValue; + /** Estimated value. */ private double[] estimatedValue; @@ -130,6 +135,14 @@ public double[] getObservedValue() { return observedMeasurement.getObservedValue(); } + /** Get the original estimated value prior to any modification. + * @return original estimated value prior to any modification + * @since 12.1 + */ + public double[] getOriginalEstimatedValue() { + return originalEstimatedValue.clone(); + } + /** Get the estimated value. * @return estimated value */ @@ -141,6 +154,9 @@ public double[] getEstimatedValue() { * @param estimatedValue estimated value */ public void setEstimatedValue(final double... estimatedValue) { + if (originalEstimatedValue == null) { + this.originalEstimatedValue = estimatedValue.clone(); + } this.estimatedValue = estimatedValue.clone(); } diff --git a/src/test/java/org/orekit/estimation/measurements/modifiers/TropoModifierTest.java b/src/test/java/org/orekit/estimation/measurements/modifiers/TropoModifierTest.java index 04693ae1af..1d5ec16270 100644 --- a/src/test/java/org/orekit/estimation/measurements/modifiers/TropoModifierTest.java +++ b/src/test/java/org/orekit/estimation/measurements/modifiers/TropoModifierTest.java @@ -117,6 +117,9 @@ public void testRangeTropoModifier() { final double epsilon = 1e-6; Assertions.assertTrue(Precision.compareTo(diffMeters, 12., epsilon) < 0); Assertions.assertTrue(Precision.compareTo(diffMeters, 0., epsilon) > 0); + Assertions.assertEquals(evalNoMod.getEstimatedValue()[0], + eval.getOriginalEstimatedValue()[0], + 3.0e-14 * evalNoMod.getEstimatedValue()[0]); } } From f114f47ed6ef4701e3816fb30eeb617c8c13058b Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Wed, 6 Mar 2024 11:48:08 +0100 Subject: [PATCH 181/359] Added getAppliedEffects() to estimated measurements. Fixes #1338 --- .../EstimatedMeasurementBase.java | 44 ++++++++++++++++ .../measurements/gnss/AbstractWindUp.java | 6 +-- .../modifiers/AberrationModifier.java | 4 +- .../modifiers/AbstractAmbiguityModifier.java | 18 +++++-- ...tivisticClockOnBoardRangeRateModifier.java | 2 +- .../AbstractShapiroBaseModifier.java | 11 ++-- .../AngularIonosphericDelayModifier.java | 10 ++-- .../AngularRadioRefractionModifier.java | 2 +- .../AngularTroposphericDelayModifier.java | 17 +++--- .../measurements/modifiers/Bias.java | 17 +++--- .../modifiers/BistaticModifierUtil.java | 50 +++++++++++++++++- ...BistaticRangeIonosphericDelayModifier.java | 6 ++- ...aticRangeRateIonosphericDelayModifier.java | 7 ++- ...ticRangeRateTroposphericDelayModifier.java | 6 ++- ...istaticRangeTroposphericDelayModifier.java | 11 ++-- ...InterSatellitesPhaseAmbiguityModifier.java | 4 +- ...rdAntennaInterSatellitesPhaseModifier.java | 7 +-- ...rdAntennaInterSatellitesRangeModifier.java | 2 +- ...OnBoardAntennaOneWayGNSSPhaseModifier.java | 7 +-- ...OnBoardAntennaOneWayGNSSRangeModifier.java | 5 +- ...OnBoardAntennaTurnAroundRangeModifier.java | 2 +- .../OneWayGNSSPhaseAmbiguityModifier.java | 4 +- .../modifiers/ParametricModelEffect.java | 4 +- .../ParametricModelEffectGradient.java | 4 +- .../modifiers/PhaseAmbiguityModifier.java | 4 +- .../modifiers/PhaseCentersPhaseModifier.java | 7 +-- .../modifiers/PhaseCentersRangeModifier.java | 3 +- .../PhaseIonosphericDelayModifier.java | 15 ++---- .../PhaseTroposphericDelayModifier.java | 11 +--- .../RangeIonosphericDelayModifier.java | 12 +++-- .../modifiers/RangeModifierUtil.java | 47 ++++++++++++++++- .../RangeRateIonosphericDelayModifier.java | 12 +++-- .../modifiers/RangeRateModifierUtil.java | 50 +++++++++++++++++- .../RangeRateTroposphericDelayModifier.java | 10 ++-- .../RangeTroposphericDelayModifier.java | 12 +++-- ...sticClockInterSatellitesPhaseModifier.java | 2 +- ...sticClockInterSatellitesRangeModifier.java | 2 +- ...ativisticClockOneWayGNSSPhaseModifier.java | 2 +- ...ativisticClockOneWayGNSSRangeModifier.java | 2 +- .../RelativisticClockPhaseModifier.java | 2 +- .../RelativisticClockRangeModifier.java | 2 +- .../RelativisticClockRangeRateModifier.java | 2 +- ...icJ2ClockInterSatellitesPhaseModifier.java | 2 +- ...icJ2ClockInterSatellitesRangeModifier.java | 2 +- ...ivisticJ2ClockOneWayGNSSPhaseModifier.java | 2 +- ...ivisticJ2ClockOneWayGNSSRangeModifier.java | 2 +- .../RelativisticJ2ClockPhaseModifier.java | 2 +- .../RelativisticJ2ClockRangeModifier.java | 2 +- .../ShapiroInterSatellitePhaseModifier.java | 2 +- .../ShapiroInterSatelliteRangeModifier.java | 2 +- .../ShapiroOneWayGNSSPhaseModifier.java | 2 +- .../ShapiroOneWayGNSSRangeModifier.java | 2 +- .../modifiers/ShapiroPhaseModifier.java | 2 +- .../modifiers/ShapiroRangeModifier.java | 2 +- .../TDOAIonosphericDelayModifier.java | 7 ++- .../modifiers/TDOAModifierUtil.java | 52 ++++++++++++++++++- .../TDOATroposphericDelayModifier.java | 6 ++- ...rnAroundRangeIonosphericDelayModifier.java | 24 ++++----- ...nAroundRangeTroposphericDelayModifier.java | 38 ++++++-------- .../modifiers/TropoModifierTest.java | 15 ++---- 60 files changed, 432 insertions(+), 181 deletions(-) diff --git a/src/main/java/org/orekit/estimation/measurements/EstimatedMeasurementBase.java b/src/main/java/org/orekit/estimation/measurements/EstimatedMeasurementBase.java index 9f61e0f20a..6ad97d7086 100644 --- a/src/main/java/org/orekit/estimation/measurements/EstimatedMeasurementBase.java +++ b/src/main/java/org/orekit/estimation/measurements/EstimatedMeasurementBase.java @@ -20,6 +20,8 @@ import org.orekit.time.AbsoluteDate; import org.orekit.utils.TimeStampedPVCoordinates; +import java.util.IdentityHashMap; + /** Class holding an estimated theoretical value associated to an {@link ObservedMeasurement observed measurement}. * @param the type of the measurement * @author Luc Maisonobe @@ -50,6 +52,11 @@ public class EstimatedMeasurementBase> implemen /** Estimated value. */ private double[] estimatedValue; + /** Applied modifiers effects. + * @since 12.1 + */ + private final IdentityHashMap, double[]> appliedEffects; + /** Measurement status. */ private Status status; @@ -71,6 +78,7 @@ public EstimatedMeasurementBase(final T observedMeasurement, this.states = states.clone(); this.participants = participants.clone(); this.status = Status.PROCESSED; + this.appliedEffects = new IdentityHashMap<>(); } /** Get the associated observed measurement. @@ -143,6 +151,17 @@ public double[] getOriginalEstimatedValue() { return originalEstimatedValue.clone(); } + /** Get the applied effects of modifiers. + *

            + * The effects have already accounted for in {@link #getEstimatedValue()} + *

            + * @return applied modifier effects + * @since 12.1 + */ + public IdentityHashMap, double[]> getAppliedEffects() { + return appliedEffects; + } + /** Get the estimated value. * @return estimated value */ @@ -152,6 +171,7 @@ public double[] getEstimatedValue() { /** Set the estimated value. * @param estimatedValue estimated value + * @see #modifyEstimatedValue(EstimationModifier, double...) */ public void setEstimatedValue(final double... estimatedValue) { if (originalEstimatedValue == null) { @@ -160,6 +180,30 @@ public void setEstimatedValue(final double... estimatedValue) { this.estimatedValue = estimatedValue.clone(); } + /** Modify the estimated value. + * @param modifier modifier that generates this estimated value + * @param newEstimatedValue new estimated value + * @since 12.1 + */ + public void modifyEstimatedValue(final EstimationModifier modifier, final double... newEstimatedValue) { + + if (modifier == null) { + setEstimatedValue(newEstimatedValue); + } else { + final double[] effect = new double[newEstimatedValue.length]; + for (int i = 0; i < effect.length; ++i) { + // compute effect + effect[i] = newEstimatedValue[i] - estimatedValue[i]; + // update value + estimatedValue[i] = newEstimatedValue[i]; + } + + // store effect + appliedEffects.put(modifier, effect); + } + + } + /** Get the status. *

            * The status is set to {@link Status#PROCESSED PROCESSED} at construction, and diff --git a/src/main/java/org/orekit/estimation/measurements/gnss/AbstractWindUp.java b/src/main/java/org/orekit/estimation/measurements/gnss/AbstractWindUp.java index 6d8a4b1b41..9484325ce3 100644 --- a/src/main/java/org/orekit/estimation/measurements/gnss/AbstractWindUp.java +++ b/src/main/java/org/orekit/estimation/measurements/gnss/AbstractWindUp.java @@ -38,10 +38,10 @@ public abstract class AbstractWindUp> implements EstimationModifier { /** Emitter dipole. */ - private Dipole emitter; + private final Dipole emitter; /** Receiver dipole. */ - private Dipole receiver; + private final Dipole receiver; /** Cached angular value of wind-up. */ private double angularWindUp; @@ -110,7 +110,7 @@ public void modifyWithoutDerivatives(final EstimatedMeasurementBase estimated angularWindUp = MathUtils.normalizeAngle(correction, angularWindUp); // update estimate - estimated.setEstimatedValue(estimated.getEstimatedValue()[0] + angularWindUp / MathUtils.TWO_PI); + estimated.modifyEstimatedValue(this, estimated.getEstimatedValue()[0] + angularWindUp / MathUtils.TWO_PI); } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/AberrationModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/AberrationModifier.java index cf05eda927..488f12d8af 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/AberrationModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/AberrationModifier.java @@ -352,7 +352,7 @@ public void modifyWithoutDerivatives(final EstimatedMeasurementBase estimated) { final Gradient rightAscension = baseRightAscension.add(twoPiWrap); // New estimated values - estimated.setEstimatedValue(rightAscension.getValue(), naturalRaDec[1].getValue()); + estimated.modifyEstimatedValue(this, rightAscension.getValue(), naturalRaDec[1].getValue()); // Derivatives (only parameter, no state) final double[] raDerivatives = rightAscension.getGradient(); diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/AbstractAmbiguityModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/AbstractAmbiguityModifier.java index 3cec597178..c198ed75c6 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/AbstractAmbiguityModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/AbstractAmbiguityModifier.java @@ -22,6 +22,8 @@ import org.hipparchus.util.FastMath; import org.orekit.estimation.measurements.EstimatedMeasurement; import org.orekit.estimation.measurements.EstimatedMeasurementBase; +import org.orekit.estimation.measurements.EstimationModifier; +import org.orekit.estimation.measurements.ObservedMeasurement; import org.orekit.utils.ParameterDriver; import org.orekit.utils.TimeSpanMap.Span; @@ -61,21 +63,29 @@ protected List getDrivers() { } /** Modify measurement. + * @param type of the measurements + * @param modifier applied modifier * @param estimated measurement to modify + * @since 12.1 */ - protected void doModifyWithoutDerivatives(final EstimatedMeasurementBase estimated) { + protected > void doModifyWithoutDerivatives(final EstimationModifier modifier, + final EstimatedMeasurementBase estimated) { // Apply the ambiguity to the measurement value for (Span span = ambiguity.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) { final double[] value = estimated.getEstimatedValue(); value[0] += ambiguity.getValue(span.getStart()); - estimated.setEstimatedValue(value); + estimated.modifyEstimatedValue(modifier, value); } } /** Modify measurement. + * @param type of the measurements + * @param modifier applied modifier * @param estimated measurement to modify + * @since 12.1 */ - protected void doModify(final EstimatedMeasurement estimated) { + protected > void doModify(final EstimationModifier modifier, + final EstimatedMeasurement estimated) { // apply the ambiguity to the measurement derivatives for (Span span = ambiguity.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) { @@ -86,7 +96,7 @@ protected void doModify(final EstimatedMeasurement estimated) { } // apply the ambiguity to the measurement value - doModifyWithoutDerivatives(estimated); + doModifyWithoutDerivatives(modifier, estimated); } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/AbstractRelativisticClockOnBoardRangeRateModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/AbstractRelativisticClockOnBoardRangeRateModifier.java index f1cb04d3a9..5c2980c97e 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/AbstractRelativisticClockOnBoardRangeRateModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/AbstractRelativisticClockOnBoardRangeRateModifier.java @@ -83,7 +83,7 @@ protected void modifyWithoutDerivatives(final EstimatedMeasurementBase estima // Update estimated value taking into account the relativistic effect. final double[] newValue = estimated.getEstimatedValue().clone(); newValue[0] = newValue[0] + (dfLocal - dfRemote) * Constants.SPEED_OF_LIGHT; - estimated.setEstimatedValue(newValue); + estimated.modifyEstimatedValue(this, newValue); } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/AbstractShapiroBaseModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/AbstractShapiroBaseModifier.java index 3e8eb0501a..07f6296850 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/AbstractShapiroBaseModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/AbstractShapiroBaseModifier.java @@ -19,6 +19,8 @@ import org.hipparchus.geometry.euclidean.threed.Vector3D; import org.hipparchus.util.FastMath; import org.orekit.estimation.measurements.EstimatedMeasurementBase; +import org.orekit.estimation.measurements.EstimationModifier; +import org.orekit.estimation.measurements.ObservedMeasurement; import org.orekit.utils.Constants; import org.orekit.utils.TimeStampedPVCoordinates; @@ -26,7 +28,6 @@ *

            * Shapiro time delay is a relativistic effect due to gravity. *

            - * * @author Luc Maisonobe * @since 10.0 */ @@ -43,9 +44,13 @@ public AbstractShapiroBaseModifier(final double gm) { } /** Modify measurement. + * @param type of the measurements + * @param modifier applied modifier * @param estimated measurement to modify + * @since 12.1 */ - protected void doModify(final EstimatedMeasurementBase estimated) { + protected > void doModify(final EstimationModifier modifier, + final EstimatedMeasurementBase estimated) { // compute correction, for one way or two way measurements final TimeStampedPVCoordinates[] pv = estimated.getParticipants(); @@ -56,7 +61,7 @@ protected void doModify(final EstimatedMeasurementBase estimated) { // update estimated value taking into account the Shapiro time delay. final double[] newValue = estimated.getEstimatedValue().clone(); newValue[0] = newValue[0] + correction; - estimated.setEstimatedValue(newValue); + estimated.modifyEstimatedValue(modifier, newValue); } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/AngularIonosphericDelayModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/AngularIonosphericDelayModifier.java index 5d22fd1463..685eddd0d1 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/AngularIonosphericDelayModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/AngularIonosphericDelayModifier.java @@ -34,13 +34,16 @@ import org.orekit.utils.TrackingCoordinates; /** Class modifying theoretical angular measurement with ionospheric delay. + *

            * The effect of ionospheric correction on the angular measurement is computed * through the computation of the ionospheric delay. The spacecraft state * is shifted by the computed delay time and elevation and azimuth are computed * again with the new spacecraft state. - * + *

            + *

            * The ionospheric delay depends on the frequency of the signal (GNSS, VLBI, ...). * For optical measurements (e.g. SLR), the ray is not affected by ionosphere charged particles. + *

            *

            * Since 10.0, state derivatives and ionospheric parameters derivates are computed * using automatic differentiation. @@ -77,8 +80,7 @@ private double angularErrorIonosphericModel(final GroundStation station, // Base frame associated with the station final TopocentricFrame baseFrame = station.getBaseFrame(); // delay in meters - final double delay = ionoModel.pathDelay(state, baseFrame, frequency, ionoModel.getParameters(state.getDate())); - return delay; + return ionoModel.pathDelay(state, baseFrame, frequency, ionoModel.getParameters(state.getDate())); } /** {@inheritDoc} */ @@ -112,7 +114,7 @@ public void modifyWithoutDerivatives(final EstimatedMeasurementBase // Update estimated value taking into account the ionospheric delay. // Azimuth - elevation values - estimated.setEstimatedValue(azimuth, tc.getElevation()); + estimated.modifyEstimatedValue(this, azimuth, tc.getElevation()); } } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/AngularRadioRefractionModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/AngularRadioRefractionModifier.java index 88f71efad8..f574ad8ee3 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/AngularRadioRefractionModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/AngularRadioRefractionModifier.java @@ -92,7 +92,7 @@ public void modifyWithoutDerivatives(final EstimatedMeasurementBase // consider only effect on elevation newValue[1] = newValue[1] + correction; - estimated.setEstimatedValue(newValue[0], newValue[1]); + estimated.modifyEstimatedValue(this, newValue[0], newValue[1]); } } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/AngularTroposphericDelayModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/AngularTroposphericDelayModifier.java index a0b118a23c..a7c7644dbe 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/AngularTroposphericDelayModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/AngularTroposphericDelayModifier.java @@ -33,13 +33,16 @@ import org.orekit.utils.TrackingCoordinates; /** Class modifying theoretical angular measurement with tropospheric delay. + *

            * The effect of tropospheric correction on the angular is computed * through the computation of the tropospheric delay.The spacecraft state * is shifted by the computed delay time and elevation and azimuth are computed * again with the new spacecraft state. - * + *

            + *

            * In general, for GNSS, VLBI, ... there is hardly any frequency dependence in the delay. * For SLR techniques however, the frequency dependence is sensitive. + *

            * * @author Thierry Ceolin * @since 8.0 @@ -85,14 +88,12 @@ private double angularErrorTroposphericModel(final GroundStation station, // only consider measures above the horizon if (trackingCoordinates.getElevation() > 0.0) { // delay in meters - final double delay = tropoModel.pathDelay(trackingCoordinates, - station.getOffsetGeodeticPoint(state.getDate()), - station.getPressureTemperatureHumidity(state.getDate()), - tropoModel.getParameters(state.getDate()), state.getDate()). + return tropoModel.pathDelay(trackingCoordinates, + station.getOffsetGeodeticPoint(state.getDate()), + station.getPressureTemperatureHumidity(state.getDate()), + tropoModel.getParameters(state.getDate()), state.getDate()). getDelay(); - // one-way measurement. - return delay; } return 0; @@ -129,7 +130,7 @@ public void modifyWithoutDerivatives(final EstimatedMeasurementBase // Update estimated value taking into account the tropospheric delay. // Azimuth - elevation values - estimated.setEstimatedValue(azimuth, tc.getElevation()); + estimated.modifyEstimatedValue(this, azimuth, tc.getElevation()); } } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/Bias.java b/src/main/java/org/orekit/estimation/measurements/modifiers/Bias.java index cdbd65a0c7..23add1f646 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/Bias.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/Bias.java @@ -83,13 +83,13 @@ public void modifyWithoutDerivatives(final EstimatedMeasurementBase estimated // apply the bias to the measurement value final double[] value = estimated.getEstimatedValue(); int nb = 0; - for (int i = 0; i < drivers.size(); ++i) { - final ParameterDriver driver = drivers.get(i); - for (Span span = driver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) { + for (final ParameterDriver driver : drivers) { + for (Span span = driver.getNamesSpanMap().getFirstSpan(); + span != null; span = span.next()) { value[nb++] += driver.getValue(span.getStart()); } } - estimated.setEstimatedValue(value); + estimated.modifyEstimatedValue(this, value); } @@ -99,12 +99,13 @@ public void modify(final EstimatedMeasurement estimated) { // apply the bias to the measurement value int nb = 0; - for (int i = 0; i < drivers.size(); ++i) { - final ParameterDriver driver = drivers.get(i); - for (Span span = driver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) { + for (final ParameterDriver driver : drivers) { + for (Span span = driver.getNamesSpanMap().getFirstSpan(); + span != null; span = span.next()) { if (driver.isSelected()) { // add the partial derivatives - estimated.setParameterDerivatives(driver, span.getStart(), derivatives[nb++]); + estimated.setParameterDerivatives(driver, span.getStart(), + derivatives[nb++]); } } } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/BistaticModifierUtil.java b/src/main/java/org/orekit/estimation/measurements/modifiers/BistaticModifierUtil.java index f9c64d18bd..7f0f9d6318 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/BistaticModifierUtil.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/BistaticModifierUtil.java @@ -21,6 +21,7 @@ import org.hipparchus.analysis.differentiation.Gradient; import org.orekit.estimation.measurements.EstimatedMeasurement; import org.orekit.estimation.measurements.EstimatedMeasurementBase; +import org.orekit.estimation.measurements.EstimationModifier; import org.orekit.estimation.measurements.GroundStation; import org.orekit.estimation.measurements.ObservedMeasurement; import org.orekit.propagation.FieldSpacecraftState; @@ -48,10 +49,29 @@ private BistaticModifierUtil() { * @param emitter emitter station * @param receiver receiver station * @param modelEffect model effect + * @deprecated as of 12.1, replaced by {@link #modify(EstimatedMeasurementBase, + * GroundStation, GroundStation, ParametricModelEffect, EstimationModifier)} */ + @Deprecated public static > void modify(final EstimatedMeasurementBase estimated, final GroundStation emitter, final GroundStation receiver, final ParametricModelEffect modelEffect) { + modify(estimated, emitter, receiver, modelEffect, null); + } + + /** Apply a modifier to an estimated measurement. + * @param type of the measurement + * @param estimated estimated measurement to modify + * @param emitter emitter station + * @param receiver receiver station + * @param modelEffect model effect + * @param modifier applied modifier + * @since 12.1 + */ + public static > void modify(final EstimatedMeasurementBase estimated, + final GroundStation emitter, final GroundStation receiver, + final ParametricModelEffect modelEffect, + final EstimationModifier modifier) { // update estimated value taking into account the model effect. // The model effect delay is directly added to the measurement. @@ -59,7 +79,7 @@ public static > void modify(final EstimatedMeas final double[] newValue = estimated.getEstimatedValue().clone(); newValue[0] += modelEffect.evaluate(emitter, state); newValue[0] += modelEffect.evaluate(receiver, state); - estimated.setEstimatedValue(newValue); + estimated.modifyEstimatedValue(modifier, newValue); } @@ -72,13 +92,39 @@ public static > void modify(final EstimatedMeas * @param parametricModel parametric modifier model * @param modelEffect model effect * @param modelEffectGradient model effect gradient + * @deprecated as of 12.1, replaced by {@link #modify(EstimatedMeasurement, + * ParameterDriversProvider, AbstractGradientConverter, GroundStation, GroundStation, + * ParametricModelEffect, ParametricModelEffectGradient, EstimationModifier)} */ + @Deprecated public static > void modify(final EstimatedMeasurement estimated, final ParameterDriversProvider parametricModel, final AbstractGradientConverter converter, final GroundStation emitter, final GroundStation receiver, final ParametricModelEffect modelEffect, final ParametricModelEffectGradient modelEffectGradient) { + modify(estimated, parametricModel, converter, emitter, receiver, modelEffect, modelEffectGradient, null); + } + + /** Apply a modifier to an estimated measurement. + * @param type of the measurement + * @param estimated estimated measurement to modify + * @param emitter emitter station + * @param receiver receiver station + * @param converter gradient converter + * @param parametricModel parametric modifier model + * @param modelEffect model effect + * @param modelEffectGradient model effect gradient + * @param modifier applied modifier + * @since 12.1 + */ + public static > void modify(final EstimatedMeasurement estimated, + final ParameterDriversProvider parametricModel, + final AbstractGradientConverter converter, + final GroundStation emitter, final GroundStation receiver, + final ParametricModelEffect modelEffect, + final ParametricModelEffectGradient modelEffectGradient, + final EstimationModifier modifier) { final SpacecraftState state = estimated.getStates()[0]; @@ -148,7 +194,7 @@ public static > void modify(final EstimatedMeas } // modify the value - modify(estimated, emitter, receiver, modelEffect); + modify(estimated, emitter, receiver, modelEffect, modifier); } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/BistaticRangeIonosphericDelayModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/BistaticRangeIonosphericDelayModifier.java index b61d2f52e7..efdda8fd5b 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/BistaticRangeIonosphericDelayModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/BistaticRangeIonosphericDelayModifier.java @@ -63,7 +63,8 @@ public void modifyWithoutDerivatives(final EstimatedMeasurementBase estimated) { new ModifierGradientConverter(state, 6, new FrameAlignedProvider(state.getFrame())), emitter, receiver, this::rangeErrorIonosphericModel, - this::rangeErrorIonosphericModel); + this::rangeErrorIonosphericModel, + this); } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/BistaticRangeRateIonosphericDelayModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/BistaticRangeRateIonosphericDelayModifier.java index 8d25bb17a9..58a5e0567c 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/BistaticRangeRateIonosphericDelayModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/BistaticRangeRateIonosphericDelayModifier.java @@ -54,7 +54,9 @@ public void modifyWithoutDerivatives(final EstimatedMeasurementBase estimated) { new ModifierGradientConverter(state, 6, new FrameAlignedProvider(state.getFrame())), emitter, receiver, this::rangeRateErrorIonosphericModel, - this::rangeRateErrorIonosphericModel); + this::rangeRateErrorIonosphericModel, + this); } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/BistaticRangeRateTroposphericDelayModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/BistaticRangeRateTroposphericDelayModifier.java index f1f61214f4..5c70c08fd2 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/BistaticRangeRateTroposphericDelayModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/BistaticRangeRateTroposphericDelayModifier.java @@ -65,7 +65,8 @@ public void modifyWithoutDerivatives(final EstimatedMeasurementBase estimated) { new ModifierGradientConverter(state, 6, new FrameAlignedProvider(state.getFrame())), emitter, receiver, this::rangeRateErrorTroposphericModel, - this::rangeRateErrorTroposphericModel); + this::rangeRateErrorTroposphericModel, + this); } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/BistaticRangeTroposphericDelayModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/BistaticRangeTroposphericDelayModifier.java index 5fb3354d88..a41ab59d84 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/BistaticRangeTroposphericDelayModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/BistaticRangeTroposphericDelayModifier.java @@ -26,11 +26,14 @@ import org.orekit.propagation.SpacecraftState; /** Class modifying theoretical bistatic range measurement with tropospheric delay. + *

            * The effect of tropospheric correction on the range is directly computed * through the computation of the tropospheric delay. - * + *

            + *

            * In general, for GNSS, VLBI, ... there is hardly any frequency dependence in the delay. * For SLR techniques however, the frequency dependence is sensitive. + *

            * * @author Maxime Journot * @author Joris Olympio @@ -65,7 +68,8 @@ public void modifyWithoutDerivatives(final EstimatedMeasurementBase estimated) { new ModifierGradientConverter(state, 6, new FrameAlignedProvider(state.getFrame())), emitter, receiver, this::rangeErrorTroposphericModel, - this::rangeErrorTroposphericModel); + this::rangeErrorTroposphericModel, + this); } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/InterSatellitesPhaseAmbiguityModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/InterSatellitesPhaseAmbiguityModifier.java index 3cc4d90998..378e9b10e7 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/InterSatellitesPhaseAmbiguityModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/InterSatellitesPhaseAmbiguityModifier.java @@ -54,13 +54,13 @@ public List getParametersDrivers() { /** {@inheritDoc} */ @Override public void modifyWithoutDerivatives(final EstimatedMeasurementBase estimated) { - doModifyWithoutDerivatives(estimated); + doModifyWithoutDerivatives(this, estimated); } /** {@inheritDoc} */ @Override public void modify(final EstimatedMeasurement estimated) { - doModify(estimated); + doModify(this, estimated); } } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/OnBoardAntennaInterSatellitesPhaseModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/OnBoardAntennaInterSatellitesPhaseModifier.java index c88057853a..f409aebf89 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/OnBoardAntennaInterSatellitesPhaseModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/OnBoardAntennaInterSatellitesPhaseModifier.java @@ -62,9 +62,10 @@ public List getParametersDrivers() { @Override public void modifyWithoutDerivatives(final EstimatedMeasurementBase estimated) { - estimated.setEstimatedValue(estimated.getEstimatedValue()[0] + - oneWayDistanceModification(estimated) / - estimated.getObservedMeasurement().getWavelength()); + estimated.modifyEstimatedValue(this, + estimated.getEstimatedValue()[0] + + oneWayDistanceModification(estimated) / + estimated.getObservedMeasurement().getWavelength()); } } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/OnBoardAntennaInterSatellitesRangeModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/OnBoardAntennaInterSatellitesRangeModifier.java index ce4685b5c6..8267be0307 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/OnBoardAntennaInterSatellitesRangeModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/OnBoardAntennaInterSatellitesRangeModifier.java @@ -66,7 +66,7 @@ public void modifyWithoutDerivatives(final EstimatedMeasurementBase getParametersDrivers() { /** {@inheritDoc} */ @Override public void modifyWithoutDerivatives(final EstimatedMeasurementBase estimated) { - estimated.setEstimatedValue(estimated.getEstimatedValue()[0] + - oneWayDistanceModification(estimated) / - estimated.getObservedMeasurement().getWavelength()); + estimated.modifyEstimatedValue(this, + estimated.getEstimatedValue()[0] + + oneWayDistanceModification(estimated) / + estimated.getObservedMeasurement().getWavelength()); } } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/OnBoardAntennaOneWayGNSSRangeModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/OnBoardAntennaOneWayGNSSRangeModifier.java index fbc431a521..243524dbc2 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/OnBoardAntennaOneWayGNSSRangeModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/OnBoardAntennaOneWayGNSSRangeModifier.java @@ -71,8 +71,9 @@ public List getParametersDrivers() { /** {@inheritDoc} */ @Override public void modifyWithoutDerivatives(final EstimatedMeasurementBase estimated) { - estimated.setEstimatedValue(estimated.getEstimatedValue()[0] + - oneWayDistanceModification(estimated)); + estimated.modifyEstimatedValue(this, + estimated.getEstimatedValue()[0] + + oneWayDistanceModification(estimated)); } } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/OnBoardAntennaTurnAroundRangeModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/OnBoardAntennaTurnAroundRangeModifier.java index 4bdded6a42..ccfb0b0e44 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/OnBoardAntennaTurnAroundRangeModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/OnBoardAntennaTurnAroundRangeModifier.java @@ -97,7 +97,7 @@ public void modifyWithoutDerivatives(final EstimatedMeasurementBase getParametersDrivers() { /** {@inheritDoc} */ @Override public void modifyWithoutDerivatives(final EstimatedMeasurementBase estimated) { - doModifyWithoutDerivatives(estimated); + doModifyWithoutDerivatives(this, estimated); } /** {@inheritDoc} */ @Override public void modify(final EstimatedMeasurement estimated) { - doModify(estimated); + doModify(this, estimated); } } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/ParametricModelEffect.java b/src/main/java/org/orekit/estimation/measurements/modifiers/ParametricModelEffect.java index 92d4315f1d..2a98c8de7c 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/ParametricModelEffect.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/ParametricModelEffect.java @@ -19,12 +19,12 @@ import org.orekit.estimation.measurements.GroundStation; import org.orekit.propagation.SpacecraftState; -/** Functional interface for parameteric models. +/** Functional interface for parametric models. * @author Luc Maisonobe * @since 11.2 */ @FunctionalInterface -interface ParametricModelEffect { +public interface ParametricModelEffect { /** Evaluate the parametric model effect. * @param station station diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/ParametricModelEffectGradient.java b/src/main/java/org/orekit/estimation/measurements/modifiers/ParametricModelEffectGradient.java index 3cee3ca169..9439a0c29d 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/ParametricModelEffectGradient.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/ParametricModelEffectGradient.java @@ -20,12 +20,12 @@ import org.orekit.estimation.measurements.GroundStation; import org.orekit.propagation.FieldSpacecraftState; -/** Functional interface for parameteric models. +/** Functional interface for parametric models. * @author Luc Maisonobe * @since 11.2 */ @FunctionalInterface -interface ParametricModelEffectGradient { +public interface ParametricModelEffectGradient { /** Evaluate the parametric model effect. * @param station station diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseAmbiguityModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseAmbiguityModifier.java index 0ca3cce25e..90b3a790f5 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseAmbiguityModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseAmbiguityModifier.java @@ -54,12 +54,12 @@ public List getParametersDrivers() { @Override public void modifyWithoutDerivatives(final EstimatedMeasurementBase estimated) { - doModifyWithoutDerivatives(estimated); + doModifyWithoutDerivatives(this, estimated); } @Override public void modify(final EstimatedMeasurement estimated) { - doModify(estimated); + doModify(this, estimated); } } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseCentersPhaseModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseCentersPhaseModifier.java index 93ba00462e..0c1060f9b5 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseCentersPhaseModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseCentersPhaseModifier.java @@ -51,9 +51,10 @@ public List getParametersDrivers() { /** {@inheritDoc} */ @Override public void modifyWithoutDerivatives(final EstimatedMeasurementBase estimated) { - estimated.setEstimatedValue(estimated.getEstimatedValue()[0] + - oneWayDistanceModification(estimated) / - estimated.getObservedMeasurement().getWavelength()); + estimated.modifyEstimatedValue(this, + estimated.getEstimatedValue()[0] + + oneWayDistanceModification(estimated) / + estimated.getObservedMeasurement().getWavelength()); } } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseCentersRangeModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseCentersRangeModifier.java index 5f9240fc76..95eb51c1cd 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseCentersRangeModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseCentersRangeModifier.java @@ -54,7 +54,8 @@ public void modifyWithoutDerivatives(final EstimatedMeasurementBase estim final double delta = estimated.getObservedMeasurement().isTwoWay() ? twoWayDistanceModification(estimated) : oneWayDistanceModification(estimated); - estimated.setEstimatedValue(estimated.getEstimatedValue()[0] + delta); + estimated.modifyEstimatedValue(this, + estimated.getEstimatedValue()[0] + delta); } } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseIonosphericDelayModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseIonosphericDelayModifier.java index 18b46bb4e6..0428347bab 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseIonosphericDelayModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseIonosphericDelayModifier.java @@ -109,9 +109,7 @@ private > T phaseErrorIonosphericModel(final G */ private double[][] phaseErrorJacobianState(final double[] derivatives, final int freeStateParameters) { final double[][] finiteDifferencesJacobian = new double[1][6]; - for (int i = 0; i < freeStateParameters; i++) { - finiteDifferencesJacobian[0][i] = derivatives[i]; - } + System.arraycopy(derivatives, 0, finiteDifferencesJacobian[0], 0, freeStateParameters); return finiteDifferencesJacobian; } @@ -143,14 +141,7 @@ private double phaseErrorParameterDerivative(final GroundStation station, private double[] phaseErrorParameterDerivative(final double[] derivatives, final int freeStateParameters) { // 0 ... freeStateParameters - 1 -> derivatives of the delay wrt state // freeStateParameters ... n -> derivatives of the delay wrt ionospheric parameters - final int dim = derivatives.length - freeStateParameters; - final double[] phaseError = new double[dim]; - - for (int i = 0; i < dim; i++) { - phaseError[i] = derivatives[freeStateParameters + i]; - } - - return phaseError; + return Arrays.copyOfRange(derivatives, freeStateParameters, derivatives.length); } /** {@inheritDoc} */ @@ -171,7 +162,7 @@ public void modifyWithoutDerivatives(final EstimatedMeasurementBase estim final double[] newValue = estimated.getEstimatedValue(); final double delay = phaseErrorIonosphericModel(station, state); newValue[0] = newValue[0] - delay; - estimated.setEstimatedValue(newValue); + estimated.modifyEstimatedValue(this, newValue); } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseTroposphericDelayModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseTroposphericDelayModifier.java index e9ef2d961a..0fbef7a047 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseTroposphericDelayModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/PhaseTroposphericDelayModifier.java @@ -175,14 +175,7 @@ private double phaseErrorParameterDerivative(final GroundStation station, private double[] phaseErrorParameterDerivative(final double[] derivatives, final int freeStateParameters) { // 0 ... freeStateParameters - 1 -> derivatives of the delay wrt state // freeStateParameters ... n -> derivatives of the delay wrt tropospheric parameters - final int dim = derivatives.length - freeStateParameters; - final double[] rangeError = new double[dim]; - - for (int i = 0; i < dim; i++) { - rangeError[i] = derivatives[freeStateParameters + i]; - } - - return rangeError; + return Arrays.copyOfRange(derivatives, freeStateParameters, derivatives.length); } /** {@inheritDoc} */ @@ -204,7 +197,7 @@ public void modifyWithoutDerivatives(final EstimatedMeasurementBase estim final double[] newValue = estimated.getEstimatedValue(); final double delay = phaseErrorTroposphericModel(station, state, measurement.getWavelength()); newValue[0] = newValue[0] + delay; - estimated.setEstimatedValue(newValue); + estimated.modifyEstimatedValue(this, newValue); } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/RangeIonosphericDelayModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/RangeIonosphericDelayModifier.java index 9a8af72a45..436b133e04 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/RangeIonosphericDelayModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/RangeIonosphericDelayModifier.java @@ -26,11 +26,14 @@ import org.orekit.propagation.SpacecraftState; /** Class modifying theoretical range measurement with ionospheric delay. + *

            * The effect of ionospheric correction on the range is directly computed * through the computation of the ionospheric delay. - * + *

            + *

            * The ionospheric delay depends on the frequency of the signal (GNSS, VLBI, ...). * For optical measurements (e.g. SLR), the ray is not affected by ionosphere charged particles. + *

            *

            * Since 10.0, state derivatives and ionospheric parameters derivates are computed * using automatic differentiation. @@ -58,7 +61,9 @@ public void modifyWithoutDerivatives(final EstimatedMeasurementBase estim final Range measurement = estimated.getObservedMeasurement(); final GroundStation station = measurement.getStation(); - RangeModifierUtil.modifyWithoutDerivatives(estimated, station, this::rangeErrorIonosphericModel); + RangeModifierUtil.modifyWithoutDerivatives(estimated, station, + this::rangeErrorIonosphericModel, + this); } @@ -74,7 +79,8 @@ public void modify(final EstimatedMeasurement estimated) { new ModifierGradientConverter(state, 6, new FrameAlignedProvider(state.getFrame())), station, this::rangeErrorIonosphericModel, - this::rangeErrorIonosphericModel); + this::rangeErrorIonosphericModel, + this); } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/RangeModifierUtil.java b/src/main/java/org/orekit/estimation/measurements/modifiers/RangeModifierUtil.java index ce3804c15f..a264325892 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/RangeModifierUtil.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/RangeModifierUtil.java @@ -21,6 +21,7 @@ import org.hipparchus.analysis.differentiation.Gradient; import org.orekit.estimation.measurements.EstimatedMeasurement; import org.orekit.estimation.measurements.EstimatedMeasurementBase; +import org.orekit.estimation.measurements.EstimationModifier; import org.orekit.estimation.measurements.GroundStation; import org.orekit.estimation.measurements.ObservedMeasurement; import org.orekit.propagation.FieldSpacecraftState; @@ -49,10 +50,28 @@ private RangeModifierUtil() { * @param station ground station * @param modelEffect model effect * @since 12.0 + * @deprecated as of 12.1, replaced by {@link #modifyWithoutDerivatives(EstimatedMeasurementBase, + * GroundStation, ParametricModelEffect, EstimationModifier)} */ + @Deprecated public static > void modifyWithoutDerivatives(final EstimatedMeasurementBase estimated, final GroundStation station, final ParametricModelEffect modelEffect) { + modifyWithoutDerivatives(estimated, station, modelEffect, null); + } + + /** Apply a modifier to an estimated measurement. + * @param type of the measurement + * @param estimated estimated measurement to modify + * @param station ground station + * @param modelEffect model effect + * @param modifier applied modifier + * @since 12.1 + */ + public static > void modifyWithoutDerivatives(final EstimatedMeasurementBase estimated, + final GroundStation station, + final ParametricModelEffect modelEffect, + final EstimationModifier modifier) { final SpacecraftState state = estimated.getStates()[0]; final double[] oldValue = estimated.getEstimatedValue(); @@ -62,7 +81,7 @@ public static > void modifyWithoutDerivatives(f final double[] newValue = oldValue.clone(); final double delay = modelEffect.evaluate(station, state); newValue[0] = newValue[0] + delay; - estimated.setEstimatedValue(newValue); + estimated.modifyEstimatedValue(modifier, newValue); } @@ -74,13 +93,37 @@ public static > void modifyWithoutDerivatives(f * @param parametricModel parametric modifier model * @param modelEffect model effect * @param modelEffectGradient model effect gradient + * @deprecated as of 12.1, replaced by {@link #modify(EstimatedMeasurement, + * ParameterDriversProvider, AbstractGradientConverter, GroundStation, + * ParametricModelEffect, ParametricModelEffectGradient, EstimationModifier)} */ + @Deprecated public static > void modify(final EstimatedMeasurement estimated, final ParameterDriversProvider parametricModel, final AbstractGradientConverter converter, final GroundStation station, final ParametricModelEffect modelEffect, final ParametricModelEffectGradient modelEffectGradient) { + modify(estimated, parametricModel, converter, station, modelEffect, modelEffectGradient, null); + } + + /** Apply a modifier to an estimated measurement. + * @param type of the measurement + * @param estimated estimated measurement to modify + * @param station ground station + * @param converter gradient converter + * @param parametricModel parametric modifier model + * @param modelEffect model effect + * @param modelEffectGradient model effect gradient + * @param modifier applied modifier + */ + public static > void modify(final EstimatedMeasurement estimated, + final ParameterDriversProvider parametricModel, + final AbstractGradientConverter converter, + final GroundStation station, + final ParametricModelEffect modelEffect, + final ParametricModelEffectGradient modelEffectGradient, + final EstimationModifier modifier) { final SpacecraftState state = estimated.getStates()[0]; @@ -126,7 +169,7 @@ public static > void modify(final EstimatedMeas } // update estimated value taking into account the ionospheric delay. - modifyWithoutDerivatives(estimated, station, modelEffect); + modifyWithoutDerivatives(estimated, station, modelEffect, modifier); } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/RangeRateIonosphericDelayModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/RangeRateIonosphericDelayModifier.java index 36df51ef16..af035a5852 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/RangeRateIonosphericDelayModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/RangeRateIonosphericDelayModifier.java @@ -28,12 +28,15 @@ import org.orekit.propagation.SpacecraftState; /** Class modifying theoretical range-rate measurement with ionospheric delay. + *

            * The effect of ionospheric correction on the range-rate is directly computed * through the computation of the ionospheric delay difference with respect to * time. - * + *

            + *

            * The ionospheric delay depends on the frequency of the signal (GNSS, VLBI, ...). * For optical measurements (e.g. SLR), the ray is not affected by ionosphere charged particles. + *

            *

            * Since 10.0, state derivatives and ionospheric parameters derivates are computed * using automatic differentiation. @@ -84,7 +87,9 @@ public void modifyWithoutDerivatives(final EstimatedMeasurementBase e final RangeRate measurement = estimated.getObservedMeasurement(); final GroundStation station = measurement.getStation(); - RangeModifierUtil.modifyWithoutDerivatives(estimated, station, this::rangeRateErrorIonosphericModel); + RangeModifierUtil.modifyWithoutDerivatives(estimated, station, + this::rangeRateErrorIonosphericModel, + this); } @@ -100,7 +105,8 @@ public void modify(final EstimatedMeasurement estimated) { new ModifierGradientConverter(state, 6, new FrameAlignedProvider(state.getFrame())), station, this::rangeRateErrorIonosphericModel, - this::rangeRateErrorIonosphericModel); + this::rangeRateErrorIonosphericModel, + this); } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/RangeRateModifierUtil.java b/src/main/java/org/orekit/estimation/measurements/modifiers/RangeRateModifierUtil.java index c42dd5749a..8b4c03524f 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/RangeRateModifierUtil.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/RangeRateModifierUtil.java @@ -21,6 +21,7 @@ import org.hipparchus.analysis.differentiation.Gradient; import org.orekit.estimation.measurements.EstimatedMeasurement; import org.orekit.estimation.measurements.EstimatedMeasurementBase; +import org.orekit.estimation.measurements.EstimationModifier; import org.orekit.estimation.measurements.GroundStation; import org.orekit.estimation.measurements.ObservedMeasurement; import org.orekit.propagation.FieldSpacecraftState; @@ -47,10 +48,28 @@ private RangeRateModifierUtil() { * @param estimated estimated measurement to modify * @param station ground station * @param modelEffect model effect + * @deprecated as of 12.1, replaced by {@link #modifyWithoutDerivatives(EstimatedMeasurementBase, + * GroundStation, ParametricModelEffect, EstimationModifier)} */ + @Deprecated public static > void modifyWithoutDerivatives(final EstimatedMeasurementBase estimated, final GroundStation station, final ParametricModelEffect modelEffect) { + modifyWithoutDerivatives(estimated, station, modelEffect, null); + } + + /** Apply a modifier to an estimated measurement. + * @param type of the measurement + * @param estimated estimated measurement to modify + * @param station ground station + * @param modelEffect model effect + * @param modifier applied modifier + * @since 12.1 + */ + public static > void modifyWithoutDerivatives(final EstimatedMeasurementBase estimated, + final GroundStation station, + final ParametricModelEffect modelEffect, + final EstimationModifier modifier) { final SpacecraftState state = estimated.getStates()[0]; @@ -59,7 +78,7 @@ public static > void modifyWithoutDerivatives(f final double[] newValue = estimated.getEstimatedValue(); final double delay = modelEffect.evaluate(station, state); newValue[0] = newValue[0] + delay; - estimated.setEstimatedValue(newValue); + estimated.modifyEstimatedValue(modifier, newValue); } @@ -71,13 +90,40 @@ public static > void modifyWithoutDerivatives(f * @param parametricModel parametric modifier model * @param modelEffect model effect * @param modelEffectGradient model effect gradient + * @deprecated as of 12.1, replaced by {@link #modify(EstimatedMeasurement, + * ParameterDriversProvider, AbstractGradientConverter, GroundStation, + * ParametricModelEffect, ParametricModelEffectGradient, EstimationModifier)} */ + @Deprecated public static > void modify(final EstimatedMeasurement estimated, final ParameterDriversProvider parametricModel, final AbstractGradientConverter converter, final GroundStation station, final ParametricModelEffect modelEffect, final ParametricModelEffectGradient modelEffectGradient) { + modify(estimated, parametricModel, converter, station, + modelEffect, modelEffectGradient, null); + + } + + /** Apply a modifier to an estimated measurement. + * @param type of the measurement + * @param estimated estimated measurement to modify + * @param station ground station + * @param converter gradient converter + * @param parametricModel parametric modifier model + * @param modelEffect model effect + * @param modelEffectGradient model effect gradient + * @param modifier applied modifier + * @since 12.1 + */ + public static > void modify(final EstimatedMeasurement estimated, + final ParameterDriversProvider parametricModel, + final AbstractGradientConverter converter, + final GroundStation station, + final ParametricModelEffect modelEffect, + final ParametricModelEffectGradient modelEffectGradient, + final EstimationModifier modifier) { final SpacecraftState state = estimated.getStates()[0]; @@ -126,7 +172,7 @@ public static > void modify(final EstimatedMeas } // update estimated value taking into account the ionospheric delay. - modifyWithoutDerivatives(estimated, station, modelEffect); + modifyWithoutDerivatives(estimated, station, modelEffect, modifier); } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/RangeRateTroposphericDelayModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/RangeRateTroposphericDelayModifier.java index 4c6c9e788c..dd83258ee9 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/RangeRateTroposphericDelayModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/RangeRateTroposphericDelayModifier.java @@ -28,12 +28,15 @@ import org.orekit.propagation.SpacecraftState; /** Class modifying theoretical range-rate measurements with tropospheric delay. + *

            * The effect of tropospheric correction on the range-rate is directly computed * through the computation of the tropospheric delay difference with respect to * time. - * + *

            + *

            * In general, for GNSS, VLBI, ... there is hardly any frequency dependence in the delay. * For SLR techniques however, the frequency dependence is sensitive. + *

            * * @author Joris Olympio * @since 8.0 @@ -108,7 +111,7 @@ public void modifyWithoutDerivatives(final EstimatedMeasurementBase e final RangeRate measurement = estimated.getObservedMeasurement(); final GroundStation station = measurement.getStation(); - RangeRateModifierUtil.modifyWithoutDerivatives(estimated, station, this::rangeRateErrorTroposphericModel); + RangeRateModifierUtil.modifyWithoutDerivatives(estimated, station, this::rangeRateErrorTroposphericModel, this); } @@ -125,7 +128,8 @@ public void modify(final EstimatedMeasurement estimated) { new ModifierGradientConverter(state, 6, new FrameAlignedProvider(state.getFrame())), station, this::rangeRateErrorTroposphericModel, - this::rangeRateErrorTroposphericModel); + this::rangeRateErrorTroposphericModel, + this); } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/RangeTroposphericDelayModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/RangeTroposphericDelayModifier.java index f955a759ae..1d0c156782 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/RangeTroposphericDelayModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/RangeTroposphericDelayModifier.java @@ -26,11 +26,14 @@ import org.orekit.propagation.SpacecraftState; /** Class modifying theoretical range measurement with tropospheric delay. + *

            * The effect of tropospheric correction on the range is directly computed * through the computation of the tropospheric delay. - * + *

            + *

            * In general, for GNSS, VLBI, ... there is hardly any frequency dependence in the delay. * For SLR techniques however, the frequency dependence is sensitive. + *

            * * @author Maxime Journot * @author Joris Olympio @@ -64,7 +67,9 @@ public void modifyWithoutDerivatives(final EstimatedMeasurementBase estim final Range measurement = estimated.getObservedMeasurement(); final GroundStation station = measurement.getStation(); - RangeModifierUtil.modifyWithoutDerivatives(estimated, station, this::rangeErrorTroposphericModel); + RangeModifierUtil.modifyWithoutDerivatives(estimated, station, + this::rangeErrorTroposphericModel, + this); } @@ -81,7 +86,8 @@ public void modify(final EstimatedMeasurement estimated) { new ModifierGradientConverter(state, 6, new FrameAlignedProvider(state.getFrame())), station, this::rangeErrorTroposphericModel, - this::rangeErrorTroposphericModel); + this::rangeErrorTroposphericModel, + this); } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/RelativisticClockInterSatellitesPhaseModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/RelativisticClockInterSatellitesPhaseModifier.java index bc45a32449..e69d589269 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/RelativisticClockInterSatellitesPhaseModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/RelativisticClockInterSatellitesPhaseModifier.java @@ -62,7 +62,7 @@ public void modifyWithoutDerivatives(final EstimatedMeasurementBase estim final double cOverLambda = Constants.SPEED_OF_LIGHT / wavelength; final double[] newValue = estimated.getEstimatedValue().clone(); newValue[0] = newValue[0] - dtRel * cOverLambda; - estimated.setEstimatedValue(newValue); + estimated.modifyEstimatedValue(this, newValue); } } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/RelativisticClockRangeModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/RelativisticClockRangeModifier.java index 824760b186..eed1913a94 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/RelativisticClockRangeModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/RelativisticClockRangeModifier.java @@ -58,7 +58,7 @@ public void modifyWithoutDerivatives(final EstimatedMeasurementBase estim // Update estimated value taking into account the relativistic effect. final double[] newValue = estimated.getEstimatedValue().clone(); newValue[0] = newValue[0] - dtRel * Constants.SPEED_OF_LIGHT; - estimated.setEstimatedValue(newValue); + estimated.modifyEstimatedValue(this, newValue); } } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/RelativisticClockRangeRateModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/RelativisticClockRangeRateModifier.java index 69d3486439..ddf5cd37ff 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/RelativisticClockRangeRateModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/RelativisticClockRangeRateModifier.java @@ -70,7 +70,7 @@ public void modifyWithoutDerivatives(final EstimatedMeasurementBase e // Update estimated value taking into account the relativistic effect. final double[] newValue = estimated.getEstimatedValue().clone(); newValue[0] = newValue[0] + dfRel * Constants.SPEED_OF_LIGHT; - estimated.setEstimatedValue(newValue); + estimated.modifyEstimatedValue(this, newValue); } /** Returns the inverse of the given value. diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/RelativisticJ2ClockInterSatellitesPhaseModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/RelativisticJ2ClockInterSatellitesPhaseModifier.java index c51c2c83df..0a351268bb 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/RelativisticJ2ClockInterSatellitesPhaseModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/RelativisticJ2ClockInterSatellitesPhaseModifier.java @@ -77,7 +77,7 @@ public void modifyWithoutDerivatives(final EstimatedMeasurementBase estim final double cOverLambda = Constants.SPEED_OF_LIGHT / wavelength; final double[] newValue = estimated.getEstimatedValue().clone(); newValue[0] = newValue[0] - dtJ2 * cOverLambda; - estimated.setEstimatedValue(newValue); + estimated.modifyEstimatedValue(this, newValue); } } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/RelativisticJ2ClockRangeModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/RelativisticJ2ClockRangeModifier.java index fb645a893e..68560a84e1 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/RelativisticJ2ClockRangeModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/RelativisticJ2ClockRangeModifier.java @@ -72,7 +72,7 @@ public void modifyWithoutDerivatives(final EstimatedMeasurementBase estim // Update estimated value taking into account the relativistic effect. final double[] newValue = estimated.getEstimatedValue().clone(); newValue[0] = newValue[0] - dtJ2 * Constants.SPEED_OF_LIGHT; - estimated.setEstimatedValue(newValue); + estimated.modifyEstimatedValue(this, newValue); } } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/ShapiroInterSatellitePhaseModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/ShapiroInterSatellitePhaseModifier.java index 5aa8741a0b..bb0e8f5ca3 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/ShapiroInterSatellitePhaseModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/ShapiroInterSatellitePhaseModifier.java @@ -57,7 +57,7 @@ public void modifyWithoutDerivatives(final EstimatedMeasurementBase getParametersDrivers() { /** {@inheritDoc} */ @Override public void modifyWithoutDerivatives(final EstimatedMeasurementBase estimated) { - doModify(estimated); + doModify(this, estimated); } } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/ShapiroOneWayGNSSPhaseModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/ShapiroOneWayGNSSPhaseModifier.java index e03df8a565..7295ea0953 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/ShapiroOneWayGNSSPhaseModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/ShapiroOneWayGNSSPhaseModifier.java @@ -57,7 +57,7 @@ public void modifyWithoutDerivatives(final EstimatedMeasurementBase getParametersDrivers() { /** {@inheritDoc} */ @Override public void modifyWithoutDerivatives(final EstimatedMeasurementBase estimated) { - doModify(estimated); + doModify(this, estimated); } } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/ShapiroPhaseModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/ShapiroPhaseModifier.java index dbce3fbc51..3095226d60 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/ShapiroPhaseModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/ShapiroPhaseModifier.java @@ -62,7 +62,7 @@ public void modifyWithoutDerivatives(final EstimatedMeasurementBase estim // update estimated value taking into account the Shapiro time delay. final double[] newValue = estimated.getEstimatedValue().clone(); newValue[0] = newValue[0] + correction; - estimated.setEstimatedValue(newValue); + estimated.modifyEstimatedValue(this, newValue); } } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/ShapiroRangeModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/ShapiroRangeModifier.java index 66576f028d..5d989f50ef 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/ShapiroRangeModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/ShapiroRangeModifier.java @@ -50,7 +50,7 @@ public List getParametersDrivers() { /** {@inheritDoc} */ @Override public void modifyWithoutDerivatives(final EstimatedMeasurementBase estimated) { - doModify(estimated); + doModify(this, estimated); } } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/TDOAIonosphericDelayModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/TDOAIonosphericDelayModifier.java index 7d8d4f5766..9080d89458 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/TDOAIonosphericDelayModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/TDOAIonosphericDelayModifier.java @@ -107,7 +107,9 @@ public void modifyWithoutDerivatives(final EstimatedMeasurementBase estima final GroundStation primeStation = measurement.getPrimeStation(); final GroundStation secondStation = measurement.getSecondStation(); - TDOAModifierUtil.modifyWithoutDerivatives(estimated, primeStation, secondStation, this::timeErrorIonosphericModel); + TDOAModifierUtil.modifyWithoutDerivatives(estimated, primeStation, secondStation, + this::timeErrorIonosphericModel, + this); } @@ -123,7 +125,8 @@ public void modify(final EstimatedMeasurement estimated) { new ModifierGradientConverter(state, 6, new FrameAlignedProvider(state.getFrame())), primeStation, secondStation, this::timeErrorIonosphericModel, - this::timeErrorIonosphericModel); + this::timeErrorIonosphericModel, + this); } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/TDOAModifierUtil.java b/src/main/java/org/orekit/estimation/measurements/modifiers/TDOAModifierUtil.java index 8c141782f6..b05a7a7a88 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/TDOAModifierUtil.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/TDOAModifierUtil.java @@ -21,6 +21,7 @@ import org.hipparchus.analysis.differentiation.Gradient; import org.orekit.estimation.measurements.EstimatedMeasurement; import org.orekit.estimation.measurements.EstimatedMeasurementBase; +import org.orekit.estimation.measurements.EstimationModifier; import org.orekit.estimation.measurements.GroundStation; import org.orekit.estimation.measurements.ObservedMeasurement; import org.orekit.propagation.FieldSpacecraftState; @@ -48,11 +49,31 @@ private TDOAModifierUtil() { * @param primeStation prime station * @param secondStation second station * @param modelEffect model effect + * @deprecated as of 12.1, replaced by {@link #modifyWithoutDerivatives(EstimatedMeasurementBase, + * GroundStation, GroundStation, ParametricModelEffect, EstimationModifier)} */ + @Deprecated public static > void modifyWithoutDerivatives(final EstimatedMeasurementBase estimated, final GroundStation primeStation, final GroundStation secondStation, final ParametricModelEffect modelEffect) { + modifyWithoutDerivatives(estimated, primeStation, secondStation, modelEffect, null); + } + + /** Apply a modifier to an estimated measurement. + * @param type of the measurement + * @param estimated estimated measurement to modify + * @param primeStation prime station + * @param secondStation second station + * @param modelEffect model effect + * @param modifier applied modifier + * @since 12.1 + */ + public static > void modifyWithoutDerivatives(final EstimatedMeasurementBase estimated, + final GroundStation primeStation, + final GroundStation secondStation, + final ParametricModelEffect modelEffect, + final EstimationModifier modifier) { final SpacecraftState state = estimated.getStates()[0]; final double[] oldValue = estimated.getEstimatedValue(); @@ -64,7 +85,7 @@ public static > void modifyWithoutDerivatives(f final double[] newValue = oldValue.clone(); newValue[0] += primeDelay; newValue[0] -= secondDelay; - estimated.setEstimatedValue(newValue); + estimated.modifyEstimatedValue(modifier, newValue); } /** Apply a modifier to an estimated measurement. @@ -76,13 +97,40 @@ public static > void modifyWithoutDerivatives(f * @param parametricModel parametric modifier model * @param modelEffect model effect * @param modelEffectGradient model effect gradient + * @deprecated as of 12.1, replaced by {@link #modify(EstimatedMeasurement, + * ParameterDriversProvider, AbstractGradientConverter, GroundStation, GroundStation, + * ParametricModelEffect, ParametricModelEffectGradient, EstimationModifier)} */ + @Deprecated public static > void modify(final EstimatedMeasurement estimated, final ParameterDriversProvider parametricModel, final AbstractGradientConverter converter, final GroundStation primeStation, final GroundStation secondStation, final ParametricModelEffect modelEffect, final ParametricModelEffectGradient modelEffectGradient) { + modify(estimated, parametricModel, converter, primeStation, secondStation, + modelEffect, modelEffectGradient, null); + } + + /** Apply a modifier to an estimated measurement. + * @param type of the measurement + * @param estimated estimated measurement to modify + * @param primeStation prime station + * @param secondStation second station + * @param converter gradient converter + * @param parametricModel parametric modifier model + * @param modelEffect model effect + * @param modelEffectGradient model effect gradient + * @param modifier applied modifier + * @since 12.1 + */ + public static > void modify(final EstimatedMeasurement estimated, + final ParameterDriversProvider parametricModel, + final AbstractGradientConverter converter, + final GroundStation primeStation, final GroundStation secondStation, + final ParametricModelEffect modelEffect, + final ParametricModelEffectGradient modelEffectGradient, + final EstimationModifier modifier) { final SpacecraftState state = estimated.getStates()[0]; final double[] oldValue = estimated.getEstimatedValue(); @@ -155,7 +203,7 @@ public static > void modify(final EstimatedMeas final double[] newValue = oldValue.clone(); newValue[0] += primeGDelay.getReal(); newValue[0] -= secondGDelay.getReal(); - estimated.setEstimatedValue(newValue); + estimated.modifyEstimatedValue(modifier, newValue); } } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/TDOATroposphericDelayModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/TDOATroposphericDelayModifier.java index 7876bcfc2b..4dc0fb0542 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/TDOATroposphericDelayModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/TDOATroposphericDelayModifier.java @@ -145,7 +145,8 @@ public void modifyWithoutDerivatives(final EstimatedMeasurementBase estima final GroundStation primeStation = measurement.getPrimeStation(); final GroundStation secondStation = measurement.getSecondStation(); - TDOAModifierUtil.modifyWithoutDerivatives(estimated, primeStation, secondStation, this::timeErrorTroposphericModel); + TDOAModifierUtil.modifyWithoutDerivatives(estimated, primeStation, secondStation, + this::timeErrorTroposphericModel, this); } @@ -162,7 +163,8 @@ public void modify(final EstimatedMeasurement estimated) { new ModifierGradientConverter(state, 6, new FrameAlignedProvider(state.getFrame())), primeStation, secondStation, this::timeErrorTroposphericModel, - this::timeErrorTroposphericModel); + this::timeErrorTroposphericModel, + this); } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/TurnAroundRangeIonosphericDelayModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/TurnAroundRangeIonosphericDelayModifier.java index c599cd858b..a0a3f7607b 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/TurnAroundRangeIonosphericDelayModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/TurnAroundRangeIonosphericDelayModifier.java @@ -38,11 +38,14 @@ import org.orekit.utils.TimeSpanMap.Span; /** Class modifying theoretical TurnAroundRange measurement with ionospheric delay. + *

            * The effect of ionospheric correction on the TurnAroundRange is directly computed * through the computation of the ionospheric delay. - * + *

            + *

            * The ionospheric delay depends on the frequency of the signal (GNSS, VLBI, ...). * For optical measurements (e.g. SLR), the ray is not affected by ionosphere charged particles. + *

            *

            * Since 10.0, state derivatives and ionospheric parameters derivates are computed * using automatic differentiation. @@ -79,8 +82,7 @@ private double rangeErrorIonosphericModel(final GroundStation station, // Base frame associated with the station final TopocentricFrame baseFrame = station.getBaseFrame(); // Delay in meters - final double delay = ionoModel.pathDelay(state, baseFrame, frequency, ionoModel.getParameters(state.getDate())); - return delay; + return ionoModel.pathDelay(state, baseFrame, frequency, ionoModel.getParameters(state.getDate())); } /** Compute the measurement error due to ionosphere. @@ -96,8 +98,7 @@ private > T rangeErrorIonosphericModel(final G // Base frame associated with the station final TopocentricFrame baseFrame = station.getBaseFrame(); // Delay in meters - final T delay = ionoModel.pathDelay(state, baseFrame, frequency, parameters); - return delay; + return ionoModel.pathDelay(state, baseFrame, frequency, parameters); } /** Compute the Jacobian of the delay term wrt state using @@ -150,14 +151,7 @@ public double value(final ParameterDriver parameterDriver, final AbsoluteDate da private double[] rangeErrorParameterDerivative(final double[] derivatives, final int freeStateParameters) { // 0 ... freeStateParameters - 1 -> derivatives of the delay wrt state // freeStateParameters ... n -> derivatives of the delay wrt ionospheric parameters - final int dim = derivatives.length - freeStateParameters; - final double[] rangeError = new double[dim]; - - for (int i = 0; i < dim; i++) { - rangeError[i] = derivatives[freeStateParameters + i]; - } - - return rangeError; + return Arrays.copyOfRange(derivatives, freeStateParameters, derivatives.length); } /** {@inheritDoc} */ @@ -180,7 +174,7 @@ public void modifyWithoutDerivatives(final EstimatedMeasurementBase estimated) { // The ionospheric delay is directly added to the TurnAroundRange. final double[] newValue = estimated.getEstimatedValue(); newValue[0] = newValue[0] + primaryGDelay.getReal() + secondaryGDelay.getReal(); - estimated.setEstimatedValue(newValue); + estimated.modifyEstimatedValue(this, newValue); } } diff --git a/src/main/java/org/orekit/estimation/measurements/modifiers/TurnAroundRangeTroposphericDelayModifier.java b/src/main/java/org/orekit/estimation/measurements/modifiers/TurnAroundRangeTroposphericDelayModifier.java index daeff520ca..74c542b40d 100644 --- a/src/main/java/org/orekit/estimation/measurements/modifiers/TurnAroundRangeTroposphericDelayModifier.java +++ b/src/main/java/org/orekit/estimation/measurements/modifiers/TurnAroundRangeTroposphericDelayModifier.java @@ -42,11 +42,14 @@ import org.orekit.utils.TrackingCoordinates; /** Class modifying theoretical turn-around TurnAroundRange measurement with tropospheric delay. + *

            * The effect of tropospheric correction on the TurnAroundRange is directly computed * through the computation of the tropospheric delay. - * + *

            + *

            * In general, for GNSS, VLBI, ... there is hardly any frequency dependence in the delay. * For SLR techniques however, the frequency dependence is sensitive. + *

            * * @author Maxime Journot * @since 9.0 @@ -91,13 +94,11 @@ private double rangeErrorTroposphericModel(final GroundStation station, final Sp // only consider measures above the horizon if (trackingCoordinates.getElevation() > 0) { // Delay in meters - final double delay = tropoModel.pathDelay(trackingCoordinates, - station.getOffsetGeodeticPoint(state.getDate()), - station.getPressureTemperatureHumidity(state.getDate()), - tropoModel.getParameters(state.getDate()), state.getDate()). + return tropoModel.pathDelay(trackingCoordinates, + station.getOffsetGeodeticPoint(state.getDate()), + station.getPressureTemperatureHumidity(state.getDate()), + tropoModel.getParameters(state.getDate()), state.getDate()). getDelay(); - - return delay; } return 0; @@ -125,13 +126,11 @@ private > T rangeErrorTroposphericModel(final // only consider measures above the horizon if (trackingCoordinates.getElevation().getReal() > 0) { // Delay in meters - final T delay = tropoModel.pathDelay(trackingCoordinates, - station.getOffsetGeodeticPoint(state.getDate()), - station.getPressureTemperatureHumidity(state.getDate()), - parameters, state.getDate()). + return tropoModel.pathDelay(trackingCoordinates, + station.getOffsetGeodeticPoint(state.getDate()), + station.getPressureTemperatureHumidity(state.getDate()), + parameters, state.getDate()). getDelay(); - - return delay; } return zero; @@ -186,14 +185,7 @@ public double value(final ParameterDriver parameterDriver, final AbsoluteDate da private double[] rangeErrorParameterDerivative(final double[] derivatives, final int freeStateParameters) { // 0 ... freeStateParameters - 1 -> derivatives of the delay wrt state // freeStateParameters ... n -> derivatives of the delay wrt tropospheric parameters - final int dim = derivatives.length - freeStateParameters; - final double[] rangeError = new double[dim]; - - for (int i = 0; i < dim; i++) { - rangeError[i] = derivatives[freeStateParameters + i]; - } - - return rangeError; + return Arrays.copyOfRange(derivatives, freeStateParameters, derivatives.length); } /** {@inheritDoc} */ @@ -217,7 +209,7 @@ public void modifyWithoutDerivatives(final EstimatedMeasurementBase estimated) { // The tropospheric delay is directly added to the TurnAroundRange. final double[] newValue = oldValue.clone(); newValue[0] = newValue[0] + primaryGDelay.getReal() + secondaryGDelay.getReal(); - estimated.setEstimatedValue(newValue); + estimated.modifyEstimatedValue(this, newValue); } diff --git a/src/test/java/org/orekit/estimation/measurements/modifiers/TropoModifierTest.java b/src/test/java/org/orekit/estimation/measurements/modifiers/TropoModifierTest.java index 1d5ec16270..d5338be358 100644 --- a/src/test/java/org/orekit/estimation/measurements/modifiers/TropoModifierTest.java +++ b/src/test/java/org/orekit/estimation/measurements/modifiers/TropoModifierTest.java @@ -21,9 +21,7 @@ import org.hipparchus.util.MathUtils; import org.hipparchus.util.Precision; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.orekit.estimation.Context; import org.orekit.estimation.EstimationTestUtils; @@ -63,16 +61,6 @@ public class TropoModifierTest { - @BeforeEach - public void setUp() throws Exception { - - } - - @AfterEach - public void tearDown() { - - } - @Test public void testRangeTropoModifier() { @@ -120,6 +108,9 @@ public void testRangeTropoModifier() { Assertions.assertEquals(evalNoMod.getEstimatedValue()[0], eval.getOriginalEstimatedValue()[0], 3.0e-14 * evalNoMod.getEstimatedValue()[0]); + Assertions.assertEquals(eval.getEstimatedValue()[0] - eval.getOriginalEstimatedValue()[0], + eval.getAppliedEffects().get(modifier)[0], + 1.0e-15); } } From 8a8020defdec891e64c59d135ff8b9f10efe32b7 Mon Sep 17 00:00:00 2001 From: Luc Maisonobe Date: Wed, 6 Mar 2024 14:18:17 +0100 Subject: [PATCH 182/359] Updated semantics of field transforms with dates. Fixes #1328 --- src/changes/changes.xml | 4 ++++ .../measurements/GroundStation.java | 20 ++++++++----------- src/main/java/org/orekit/frames/Frame.java | 11 +++++----- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 8efbccd443..69eb4f82a8 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -21,6 +21,10 @@ + + Field versions of Frame.get{|Static|Kinematic}TransformTo don't allow + null dates (they never did, but the javadoc wrongly stated this was allowed) + Added separate access to original estimation and modifications in estimated measurements. diff --git a/src/main/java/org/orekit/estimation/measurements/GroundStation.java b/src/main/java/org/orekit/estimation/measurements/GroundStation.java index 01946d4c6c..330ab5ae27 100644 --- a/src/main/java/org/orekit/estimation/measurements/GroundStation.java +++ b/src/main/java/org/orekit/estimation/measurements/GroundStation.java @@ -524,21 +524,21 @@ public GeodeticPoint getOffsetGeodeticPoint(final AbsoluteDate date) { final double y = northOffsetDriver.getValue(); final double z = zenithOffsetDriver.getValue(); final BodyShape baseShape = baseFrame.getParentShape(); - final StaticTransform baseToBody = - baseFrame.getStaticTransformTo(baseShape.getBodyFrame(), date); + final StaticTransform baseToBody = baseFrame.getStaticTransformTo(baseShape.getBodyFrame(), date); Vector3D origin = baseToBody.transformPosition(new Vector3D(x, y, z)); if (date != null) { origin = origin.add(computeDisplacement(date, origin)); } - return baseShape.transform(origin, baseShape.getBodyFrame(), null); + return baseShape.transform(origin, baseShape.getBodyFrame(), date); } /** Get the geodetic point at the center of the offset frame. * @param type of the field elements - * @param date current date (may be null if displacements are ignored) + * @param date current date(must be non-null, which is a more stringent condition + * * than in {@link #getOffsetGeodeticPoint(AbsoluteDate)} * @return geodetic point at the center of the offset frame * @since 12.1 */ @@ -549,15 +549,11 @@ public > FieldGeodeticPoint getOffsetGeodet final double y = northOffsetDriver.getValue(); final double z = zenithOffsetDriver.getValue(); final BodyShape baseShape = baseFrame.getParentShape(); - final FieldStaticTransform baseToBody = - baseFrame.getStaticTransformTo(baseShape.getBodyFrame(), date); - FieldVector3D origin = baseToBody.transformPosition(new Vector3D(x, y, z)); - - if (date != null) { - origin = origin.add(computeDisplacement(date.toAbsoluteDate(), origin.toVector3D())); - } + final FieldStaticTransform baseToBody = baseFrame.getStaticTransformTo(baseShape.getBodyFrame(), date); + FieldVector3D origin = baseToBody.transformPosition(new Vector3D(x, y, z)); + origin = origin.add(computeDisplacement(date.toAbsoluteDate(), origin.toVector3D())); - return baseShape.transform(origin, baseShape.getBodyFrame(), null); + return baseShape.transform(origin, baseShape.getBodyFrame(), date); } diff --git a/src/main/java/org/orekit/frames/Frame.java b/src/main/java/org/orekit/frames/Frame.java index 8a3a34873a..8e264f58ce 100644 --- a/src/main/java/org/orekit/frames/Frame.java +++ b/src/main/java/org/orekit/frames/Frame.java @@ -253,7 +253,8 @@ public Transform getTransformTo(final Frame destination, final AbsoluteDate date /** Get the transform from the instance to another frame. * @param destination destination frame to which we want to transform vectors - * @param date the date (can be null if it is sure than no date dependent frame is used) + * @param date the date (must be non-null, which is a more stringent condition + * * than in {@link #getTransformTo(Frame, FieldAbsoluteDate)}) * @param the type of the field elements * @return transform from the instance to the destination frame */ @@ -330,8 +331,8 @@ public StaticTransform getStaticTransformTo(final Frame destination, * @param type of the elements * @param destination destination frame to which we want to transform * vectors - * @param date the date (can be null if it is sure than no date - * dependent frame is used) + * @param date the date (must be non-null, which is a more stringent condition + * than in {@link #getStaticTransformTo(Frame, AbsoluteDate)}) * @return static transform from the instance to the destination frame * @since 12.0 */ @@ -361,8 +362,8 @@ public > FieldStaticTransform getStaticTran * @param Type of transform returned. * @param destination destination frame to which we want to transform * vectors - * @param date the date (can be null if it is sure than no date - * dependent frame is used) + * @param date the date (must be non-null, which is a more stringent condition + * * than in {@link #getKinematicTransformTo(Frame, AbsoluteDate)}) * @return kinematic transform from the instance to the destination frame * @since 12.1 */ From 668a0cc2039cc5455d927eef30bbdeaf424481d2 Mon Sep 17 00:00:00 2001 From: Sebastien Dinot Date: Wed, 6 Mar 2024 15:22:34 +0100 Subject: [PATCH 183/359] SonarQube URL now provided by an env. variable The URL of the SonarQube instance on which the report is to be published is no longer hard-coded in the pom.xml file, but provided by the SONAR_HOST_URL environment variable. Signed-off-by: Sebastien Dinot --- .gitlab-ci.yml | 1 + pom.xml | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index fed0decb12..77b34c5500 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -35,6 +35,7 @@ verify: script: - mvn $MAVEN_CLI_OPTS checkstyle:check verify site - test -z "$SONAR_TOKEN" || mvn $MAVEN_CLI_OPTS sonar:sonar + -Dsonar.host.url=${SONAR_HOST_URL} -Dsonar.login=${SONAR_TOKEN} -Dsonar.branch.name=${CI_COMMIT_REF_NAME} -Dsonar.projectKey="$SONAR_PROJECT_KEY" diff --git a/pom.xml b/pom.xml index 9ef33f2e10..a8841ae7b7 100644 --- a/pom.xml +++ b/pom.xml @@ -60,9 +60,6 @@ 1.8 1.8 ${git.revision}; ${maven.build.timestamp} - - https://sonar.orekit.org/ - ${java.home}/../lib/ ${tools.jar.dir}/tools.jar From 4c5f7891a2581ae910be25f9cf15595f67dc5c92 Mon Sep 17 00:00:00 2001 From: Sebastien Dinot Date: Wed, 6 Mar 2024 15:24:28 +0100 Subject: [PATCH 184/359] Gitlab CI should wait the SonarQube analysis result Signed-off-by: Sebastien Dinot --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 77b34c5500..82a174707d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -40,6 +40,7 @@ verify: -Dsonar.branch.name=${CI_COMMIT_REF_NAME} -Dsonar.projectKey="$SONAR_PROJECT_KEY" -Dsonar.projectName="$SONAR_PROJECT_NAME" + -Dsonar.qualitygate.wait=true artifacts: paths: - target/*.jar From 4ac337890d3a84f26f1ec75bd7d8d3e4b012e8c1 Mon Sep 17 00:00:00 2001 From: Sebastien Dinot Date: Wed, 6 Mar 2024 16:19:48 +0100 Subject: [PATCH 185/359] Update CI/CD build env Update of the compilation environment used by the CI/CD pipeline, to make it compatible with the requirements of the new SonarQube version. Signed-off-by: Sebastien Dinot --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 82a174707d..0251eb520d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -6,7 +6,7 @@ stages: default: # Default image - image: registry.orekit.org/orekit/ci-utils/maven:3.6.2-jdk-8-slim + image: registry.orekit.org/orekit/ci-utils/maven:3.9.6-eclipse-temurin-11 # Cache downloaded dependencies and plugins between builds. # To keep cache across branches add 'key: "$CI_JOB_REF_NAME"' cache: From 61d33344c52a41e20d4599f0c16478ebe42cceb6 Mon Sep 17 00:00:00 2001 From: Sebastien Dinot Date: Wed, 6 Mar 2024 17:02:46 +0100 Subject: [PATCH 186/359] Resolve merge conflict --- src/main/java/org/orekit/overview.html | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/orekit/overview.html b/src/main/java/org/orekit/overview.html index 039fb785ce..a99744bd9d 100644 --- a/src/main/java/org/orekit/overview.html +++ b/src/main/java/org/orekit/overview.html @@ -1,20 +1,24 @@ + -OREKIT + + + OREKIT +

            1. Purpose

            -

            - OREKIT library is a low-level library for space mechanics projects. It is -implemented in the JAVA language. +

            + OREKIT library is a low-level library for space mechanics projects. It is +implemented in the JAVA language.

            OREKIT project was initiated by CS with the following goals in mind: