Version 13.0 of Orekit introduced some incompatible API changes with respect to versions 12.x. These changes are summarized in the following table. The next paragraphs give hints about how users should change application source code to adapt to this new version.
In the 12.X series, two independent ways to convert an Orbit
into a FieldOrbit
were set up. One was to use a new utility class Fieldifier
and the second one
was to use a convertToFieldOrbit
method from OrbitType
. As this was redundant,
the utility method in Fieldifier
was deprecated and the convertToFieldOrbit
method from OrbitType
was kept. The deprecated method was removed in 13.0
If users called the utility method in Fieldifier
, they should now call the
method from OrbitType
. This means replacing (taking a circular orbit as an
example):
import org.orekit.orbits.FieldCircularOrbit;
import org.orekit.utils.Fieldifier;
final FieldCircularOrbit<T> fieldCircularOrbit = (FieldCircularOrbit<T>) Fieldifier.fieldify(field, circularOrbit);
by
final FieldCircularOrbit<T> fieldCircularOrbit = (FieldCircularOrbit<T>) circularOrbit.getType().convertToFieldOrbit(Field);
In the 12.X series, it was possible to build a SpacecraftStateInterpolator
without
specifying the number of interpolation points or the threshold. In this case, it
used the default values. This could generate exceptions if the associated interpolators
for orbit, mass, attitude… did not use the same default values. The constructor was
deprecated in 12.0 and a new constructor added with settings for number of interpolation
points and threshold. The deprecated constructor was removed in 13.0
If user code called the SpacecraftStateInterpolator
without specifying the number of
interpolation points or the threshold, it should now add these parameters explicitly,
using AbstractTimeInterpolator.DEFAULT_INTERPOLATION_POINTS
and
AbstractTimeInterpolator.DEFAULT_EXTRAPOLATION_THRESHOLD_SEC
.
Propagators had a method getEventsDetectors
, whose naming was inconsistent with similar functions in EventDetectorProvider
and Hipparchus.
Simply replace your calls by getEventDetectors
.
In the 12.X series, it was possible to build an AbsoluteDate
from a
java.time.Instant
, specifying an arbitrary time scale. This was not
compliant with the Instant
API which requires using UTC. A constructor
using only the Instant
was added in 12.1 as well as a constructor with
at time scale that is enforced to be UTC. The constructor with
Instant
and TimeScale
was deprecated. The deprecated constructor
was removed in 13.0.
If the constructor with a Instant
and TimeScale
was used and the
time scale was already UTC, then there is nothing to do. If the time
scale was not UTC, then the semantics must be revised by users, as they
did violate Instant
API, so they probably need to check how the
Instant
is produced, to ensure it is really in UTC.
In the 12.X series, position angles in orbits (anomalies for {Field}KeplerianOrbit
,
latitude arguments for {Field}CircularOrbit
, longitude arguments for
{Field}EquinoctialOrbit
) could be converted between their MEAN
, TRUE
and
ECCENTRIC
flavors using static methods in the orbit classes themselves. These static
have been moved to dedicated utility classes {Field}KeplerianAnomalyUtility
,
{Field}CircularAnomalyUtility
, and {Field}EquinoctialAnomalyUtility
as of version
12.1. The methods in the orbit classes have been deprecated in 12.1 and removed
in 13.0.
As the methods are static ones, just the name of the class providing the
methods should be changed. This means replacing (taking circular orbit
and conversion from ECCENTRIC
to TRUE
as an example):
final double alphaV = CircularOrbit.eccentricToTrue(ex, ey, alphaE);
by
final double alphaV = CircularLatitudeArgumentUtility.eccentricToTrue(ex, ey, alphaE);
In the 12.X series, Fitting of Earth Orientation Parameters was introduced. This was initially configured using a fitting duration as well as an exponential weight with a time constant, starting with small weights at the beginning of the fitting duration and increasing weights afterwards. However, this led to numerical errors in some configurations. A new configuration was then used, starting from the last known EOP and decreasing weights when going towards past. The fitting duration was therefore ignored as the exponential decrease made it useless. The corresponding constructor was deprecated. This deprecated constructor was removed in 13.0.
If users called the SingleParameterFitter
with a fitting duration, they should
just remove this parameter; anyway it was ignored since 12.0.1, so this should
not have any influence.
In the 12.X series, tropospheric models implemented the DiscreteTroposphericModel
interface. This interface used constant temperature pressure and hygrometry but
variable location, which was inconsistent. It did not allow to use models that
are azimuth-dependant (slanted atmosphere layers). It also used inconsistent non-SI
units. The interface was completely rewritten as TroposphericModel
in 12.1, and
the existing models were rewritten to implement the new interfaces. A new
PressureTemperatureHumidityProvider
has been introduced, allowing tropospheric models
to be applied at any time and any location. This provider generates PressureTemperatureHumidity
instances on the fly as needed. The API of GroundStation
, TroposphericModel
and
TroposphereMappingFunction
did however not embrace this change thoroughly. Some parts still
referred to PressureTemperatureHumidity
, some parts mixed use of both
PressureTemperatureHumidityProvider
and PressureTemperatureHumidity
, some parts took an
argument of one type and ignored it, using an internal provider. This was confusing and not user-friendly.
The older tropospheric model interface, and the former models implementations were deprecated. In version 13.0, the deprecated interface, implementations and constructor were all removed.
All the tropospheric models available in Orekit 12.X are still available, sometimes
with different names (for example MariniMurrayModel
is now called MariniMurray
,
SaastamoinenModel
is now ModifiedSaastamoinenModel
, but there is also a
CanonicalSaastamoinenModel
) and different constructors. Some models allow passing
a PressureTemperatureHumidityProvider
to the constructor, which allows to retrieve
time and location-dependent weather parameters. Several new tropospheric models
have been added in the process. AngularTroposphericDelayModifier
was also discovered
to be seriously flawed and has been replaced by AngularRadioRefractionModifier
.
Users should review the models they use and adapt the class names as well as the
new constructor parameters. If they used a simple configuration with fixed weather
parameters, they can use either ConstantPressureTemperatureHumidityProvider
or
TroposphericModelUtils.STANDARD_ATMOSPHERE_PROVIDER
(or
TroposphericModelUtils.STANDARD_ATMOSPHERE
if they need the constant values
and not the provider). For better representativity, it is suggested to use either
a global model like GlobalPressureTemperature3
or to implement
PressureTemperatureHumidityProvider
with a custom class downloading real
measured data.
Many tropospheric models constructors now take a PressureTemperatureHumidityProvider
instance as an argument. As the provider is internally stored, another change is that
there is no need anymore to pass a PressureTemperatureHumidity
argument to the pathDelay
method of TroposphericModel
implementations or to the mappingFactors
method of
TroposphereMappingFunction
implementations, these arguments are simply removed.
The GlobalPressureTemperature2
and GlobalPressureTemperature2w
constructors now
take an additional TimeScales
parameter that allows the class to use custom DataContext
and be independent of the default data context.
In the 12.X series, the ImmutableFieldTimeStampedCache.emptyCache
had a
field argument which was in fact ignored. This method has been deprecated
in 12.1 and a new method without any argument added. The deprecated method
was removed in 13.0
If users called ImmutableFieldTimeStampedCache.emptyCache
with a field
argument, they should just remove the argument at the call site.
In the 12.X series, the AbstractMeasurement
method signalTimeOfFlight
only
used a TimeStampedPVCoordinates
without care about the frame it refered too. An
additional signature was added, using a PVCoordinatesProvider
, which required
specifying the frame. For consistency, the frame was also added in the
TimeStampedPVCoordinates
version and the method without the frame was deprecated.
The deprecated method was removed in 13.0.
If user code called signalTimeOfFlight
without a frame, it should now also
pass the frame in the arguments list.
In the 12.X series, the phase measurements (both ground measurements and inter-satellite
measurements) managed one ambiguity parameter for each measurement, and in addition there
were dedicated modifiers for the same purpose. This was cumbersome and wasted a lot of
resources since numerous parameter drivers where create and should be managed together
as they share the same name. An AmbiguityCache
has been set up to drastically reduce
the number of parameter drivers (allowing to use only one driver for each
emitter/receiver/wavelength triplet) and could be passed to the measurements constructors.
This cache holds AmbiguityDriver
entries that are specialized ParameterDriver
.
The constructor without the ambiguity cache were deprecated and a temporary default cache
was made available and used by these deprecated constructors. As with this change the
phase measurements managed the ambiguity by themselves, the additional modifiers were
also deprecated. All deprecated constructors and classes were removed in 13.0, as well
as the temporary default cache.
In order to build phase measurements, users should set up one instance of an ambiguity
cache on their own (just calling new AmbiguityCache()
) and pass it as an argument
to the phase measurements constructors (or the phase measurements builders constructors
in the measurement generation use case). The cache will be populated automatically as
measurements are created. The ambiguities can be retrieved either from the measurements
themselves (using the getAmbiguityDriver
method) or from the cache, given the emitter,
receiver and wavelength.
In the 12.X series, the RCV CLOCK OFFS APPL
flag in Rinex observation files was
parsed as an integer, despite it really has the semantic of a flag. This was confusing
as a numerical value could lead people to think it was really the offset itself that
was stored there, when in fact the offset is present in the observations. The
integer-based getter and setters were deprecated in 12.1 and new boolean-based getters
and setters were added. The deprecated getters and setters were removed in 13.0.
If users called setClkOffset
or getClkOffset
, they should replace these calls
by the boolean versions setClockOffsetApplied
and getClockOffsetApplied
.
In the 12.X series, the build
method in MeasurementBuilder<T>
interface from
package org.orekit.estimation.measurements.generation
did return an
object of type T
, where T
was the parameterized type in MeasurementBuilder<T>
and extended ObservedMeasurement<T>
.
Returning only the observed value was limiting as users may sometimes need access to the complete states that were used during the generation. These states were in fact computed internally and discarded after the observed measurement was produced. The rationale of this change was to allow retrieving these complete states.
Starting with version 13.0 the return type of the build
method was therefore
changed to EstimatedMeasurementBase<T>
.
If the additional information is relevant to the caller application, then users should change the type of the variable they use to store the estimated measurement and use it. This means replacing
final T built = builder.build(date, interpolators);
by
final EstimatedMeasurementBase<T> built = builder.build(date, interpolators);
If the additional information is not relevant to the caller application, then users can just extract the observed measurement from the estimated measurement. This means replacing
final T built = builder.build(date, interpolators);
by
final T built = builder.build(date, interpolators).getObservedMeasurement();
In the 12.X series, AggregateBoundedPropagator.getPropagators
method rebuilt
the map each time it was called. It was deplrecated and replaced by a
getPropagatorsMap
method that retruend the same map each call. The deprecated
method was removed in 13.0
User code should just adapt the method name at call site.
In 12.X series, the PropagatorBuilder.copy()
method was deprecated and replaced
by the .clone()
method available natively in Java. The deprecated method was removed in 13.0
The change is straightforward. Users only have to replace
import org.orekit.propagation.conversion.AbstractPropagatorBuilder;
final AbstractPropagatorBuilder newBuilder = builder.copy();
by
final AbstractPropagatorBuilder newBuilder = builder.clone();
The method currentInterval
in {Field}AdaptableInterval
now has a second argument called isForward
to indicate the direction of propagation.
This allows to tailor the computation knowing this information and follows a similar change in Hipparchus.
If you only use “constant” intervals, you should use the static method of
to create instance and nothing needs changed. Otherwise, just add the second argument in your signature and use if if applicable.
Computation of spherical regions is based on Binary Space Partitioning trees (BSPTree
), which are provided
by the underlying Hipparchus library.
In some cases, when operating on regions that have almost aligned features (like a sensor swath projected
on ground, with sampled boundary points along a very regulat orbit), some numerical errors occur. A lot
of efforts have been put in improving robustness. As part of these efforts, the API in the partitioning
package from Hipparchus has been changed. Many classes like BSPTree
, BSPTreeVisitor
, Hyperplane
,
SubHyperplane
, Region
, Regionfactory
… that were previously parameterized with the space type
(Euclidean3D
, Euclidean2D
, Euclidean1D
, Sphere2D
, Sphere1D
) are now parameterized with both the
space type, the associated point type (Vector3D
, Vector2D
, Vector1D
, S2Point
, S1Point
), the
associated hyperplane type (Plane
, Line
, OrientedPoint
, Circle
, LimitAngle
), and the associated
subèhyperplane type (SubPlane
, SubLine
, SubOrientedPoint
, SubCircle
, SubLimitAngle
). The point
types themselves also include their own type as a second parameter in addition to the space type.
This improves robustness as it allows stronger typing.
This Hipparchus API change does not affect the Orekit public API at all (the changes are implementation
details at Orekit level), but they may affect users who build SphericalPolygonsSet
objects using Region
and RegionFactory
, which are Hipparchus classes.
The required changes at users level are limited to variables declarations. They should replace Region<Sphere2D>
by Region<Sphere2D, S2Point, Circle, SubCircle>
and RegionFactory<Sphere2D>
by
RegionFactory<Sphere2D, S2Point, Circle, SubCircle>
.
In the 12.X series, frames guessing in IGS products like SP3 or Rinex files
was flawed. It missed several cases and returned a default Earth frame that
could be wrong. A more general utility method IGSUtils.guessFrame
was introduced.
This method complies with more classical denominations used by IGS laboratories
and also allows as an extension to use a few non-rotating frames as used in some
industrial teams. The SP3Parser.guessFrame
method and SP3Parser.SP3_FRAME_CENTER_STRING
constant were deprecated. The deprecated items were removed in 13.0.
If user codes did call SP3Parser.guessFrame
, they should call instead IGSUtils.guessFrame
.
In the 12.X series, numerous classes and methods in the library used the
enumerates Frequency
and ObservationType
from package org.orekit.gnss
directly. These enumerates listed the predefined frequencies and observable
that are used by the existing GNSS systems (GPS, Glonass, Galileo, Beidou,
QZSS, IRNSS, SBAS).
Enumerates are fine when dealing with existing systems supported by Orekit,
but they are not sufficient when designing new navigation systems using new
frequencies or new observables. The rationale of this change was to allow using
custom frequencies and observation types. The naming convention for the first
enumerate was also awkward as the name Frequency
was too generic and therefore
confusing and as the API also provided access to other elements (like wavelength,
common frequency multiplier, and name). A last problem with the enumerates API was
that it used non-SI units (MHz instead of Hz for frequency).
This change was introduced in two steps, one that did not break the API and was introduced in version 12.1 and one that did break the API and was introduced in version 13.0.
Starting with version 12.1, several methods of this enumerate where moved
upward in new interface GnssSignal
and its superinterface RadioWave
.
This had no consequence on users source code. Starting with version 13.0,
the Frequency
enumerate was renamed PredefinedGnssSignal
and numerous
methods that did reference it were changed to reference either RadioWave
,
GnssSignal
, or PredefinedGnssSignal
. The ObservationType
was also
changed to be an interface and a new enumerate PredefinedObservationType
was introduced.
As long as only enumerates were used, relying on the equality operator ==
to compare a predefined signal with a reference was relevant. It is not relevant
anymore when using interfaces implemented by custom user classes. Two
predicate methods, closeTo(other)
and closeTo(other, tolerance)
have
therefore been added to the new RadioWave
interface to check if frequencies
are close enough. The first method uses a default tolerance of 1 mHz, which is
good enough for most purposes.
A few method names have been changed according to their return types,
for example getFrequencies()
in Antenna
has been renamed getRadioWaves()
,
getFrequency()
in ObservationType
has been renamed getSignal()
,
and getSignal()
in BeidouCivilianNavigationMessage
has been renamed
getRadioWave()
.
The Rinex parser and writer API have been extended to allow these new signals and observation types to be used in Rinex files. Note however that as these elements are non-standard, the files produced may be impossible to read with applications that do not rely on Orekit for parsing.
In most cases, as the interfaces are just higher level abstractions of the
same concept that was already implemented by the Frequency
enumerate,
users can just change the types of the objects they use to either
PredefinedGnssSignal
, GnssSignal
or RadioWave
depending on the method.
Sometimes the type appears in a parameterized type, so for example the
ReceiverAntenna
constructor now requires a Map<RadioWave, FrequencyPattern>
instead of a Map<Frequency, FrequencyPattern>
. Such types changes in methods
signatures and field types are sufficient if the only methods used in the
enumerate were getName()
or getRatio()
(which are defined in GnssSignal
)
or if they were getFrequency()
or getWavelength()
(which are defined in
RadioWave
). Note that getMHzFrequency()
has been replaced by getFrequency()
which returns a predefinedGnssSignal in Hz and not in MHz anymore, for consistency with
Orekit convention to use SI units everywhere.
As explained above, if the enumerate was used directly with an equality
operator to check against some predefined value, this check should be
changed to a proximity check by calling one of the closeTo
methods.
The call sites for methods that have changed names must be adapted to use the new names.
The PressureTemperatureHumidityProvider
interface introduced in 12.0
defines two methods with name getWeatherParamerers
, which was a typo.
The error was fixed and the name was changed to getWeatherParameters
in 13.0.
The change is straightforward. Users only have to replace calls to getWeatherParamerers
by calls to getWeatherParameters
.
In the 12.X series, dates were implemented using an epoch as a whole number of seconds from
a reference date and a double offset corresponding to the fractional parts of the seconds.
As the fractional part was between 0.0 and 1.0, its resolution was of the order of magnitude
of a femtosecond near 1.0, and when dates resulted from successive computations (typically
sequences of calls to shiftedBy
), accuracies at picoseconds level could be regularly
achieved. There were however rounding problems when dates were output in textual form depending
on the number of decimal digits used. When using a number of digits ensuring safe
write/read roundtrip operations (like using the Ryū algorithm), this induced writing many digits
thar were not human-friendly. When on the other hand the number of digits was chosen to be
either human-friendly (say milliseconds or microseconds) or compliant with some standard format,
then safe write/read roundtrip operation was not possible anymore and errors crept in, typically
in ephemeris data. Another type of problems occurred when standard java Instant
, Date
or
TimeUnit
were used as they refer to milliseconds, microseconds or nanoseconds which are
decimal-based sub-multiples of the second and not binary-based sub-multiples of primitive double
numbers. A similar problem linked to decimal versus binary representation occurred when TT
(Terrestrial Time) scale was used. The offset between TT and TAI (International Atomic Time) is
by convention exactly 32.184s, and neither 32.184 nor 0.184 can be represented exactly as IEEE754
primitive double numbers. The closest normal numbers that can be represented exactly are
respectively $\frac{0x10178D4FDF3B64}{2^{47}}$ which is about 2.5 femtoseconds smaller than 32.184s,
and $\frac{0x178D4FDF3B645A}{2^{55}}$, which is about 3.11 attoseconds smaller than 0.184s.
There were also several problems with the linear models between UTC and TAI that were used before
year 1972. The offsets were whole numbers of microseconds and slopes were whole numbers of
nanoseconds per seconds. Supporting properly the linear models before 1972 may seem moot but is in
fact really required because many systems use Unix time, so it is widely used in interfaces or
databases. The official Unix time as defined by POSIX explicitly ignores leap seconds, but many
users ignore this specificity and would just use new ApsoluteDate(1970, 1, 1, utc)
, expecting this
to be seamlessly interoperable with standard java Instant
, Date
or TimeUnit
. It is not fully
possible but at least roundtrip conversions between the two representations, with and without leap
seconds, should remain safe. Unfortunately the 1970-01-01 epoch is located within a four years time
range (from 1968 to 1972) during which the offset between UTC and TAI exhibited a 30 ns/s slope. This
induced a 378691200 ns offset as of 1970-01-01 (to be added to the 4213170 µs offset that was active
since 1968-01-01) and the slope continued to be applied for two years later. This complicates safe
roundtrip conversions.
In order to alleviate these problems, dates handling has been thoroughly revamped. The whole number
of seconds since reference epoch is still stored as a signed primitive long like it was before, so the
range of dates that can be represented is still ±292 billions years for AbsoluteDate
(but it is still
±5.88 millions years for DateComponents
and DateTimeComponents
as they use primitive int for the
day offset with respect to J2000.0). The fractional part within the second is what was changed: it is
now also stored as a non-negative primitive long with fixed precision at a resolution of one attosecond
($10^{-18}s$). The choice of attoseconds allows to represent exactly all important offsets (between TT
and TAI, or between UTC and TAI during the linear eras), as well as all times converted from standard
java Instant
, Date
or TimeUnit
classes, and as it is a decimal-based sub-multiple, it is both
human-friendly, standard formats friendly and often avoids the awkward display of series of 999999
decimals that resulted from binary to decimal conversions. This choice also allows simple computation
as adding or subtracting two values in attoseconds that are both smaller than one second never overflows
(a primitive long containing a number of attoseconds could hold any values between ±9.22s, so simple
additions and subtractions of up to 9 such numbers followed by handling a carry to bring the result back
between $0$ and $10^{18}$ and updating the associated seconds number is straightforward). The workhorse
of the new implementation is a new TimeOffset
class that contains a time offset split into seconds and
attoseconds. This new class is therefore much more accurate than the previous one (attoseconds rather
than femtoseconds) and more importantly is more robust, much simpler as it does not have to deal with IEEE-754
and finally it is decimal-friendly. Provisions have been made to properly handle NaN
, and ±∞ (both in
computation, parsing and writing).
Many methods that used primitive double to represent durations or offsets have been rewritten to take
TimeOffset
instances as arguments or to generate them as return values. This affects the API of classes
AbsoluteDate
, TimeComponents
, DateTimeComponents
, GNSSDate
, OffsetModel
UTCTAIOffset
and their
field counterparts for the classes that have one, as well as the TimeScale
and TimeShiftable
interfaces
and all their implementations. In most cases, the methods taking a primitive double as an argument have
been kept, and they delegate to a new method that creates a TimeOffset
instance on the fly from the double.
Methods that returned a primitive double have sometimes been kept (for example durationFrom
in AbsoluteDate
is still there) but a sister method has been created to take advantage of the new implementation with increased
accuracy (so there are now accurateDurationFrom
and accurateOffsetFrom
methods in AbsoluteDate
). Some
methods that returned a primitive double have been changed and now return TimeOffset
instances, this is in
particular the case of all the methods in the TimeScale
interface.
The field version of AbsoluteDate
(FieldAbsoluteDate
) has also been rewritten and is now entirely based
on AbsoluteDate
: each FieldAbsoluteDate
embeds an AbsoluteDate
that represent the same date but without
the Field
features. This means that the toAbsoluteDate
methods is now a simple getter and returns an already
present instance, it is much less costly than before. This improved the consistency between the non-field and
the field versions, reduced duplications a lot and greatly simplified the code.
As these changes were made, it appeared the AggregatedPVCoordinatesProvider
class threw
OrekitIllegalArgumentException
and IllegalStateException
instead of OrekitException
when
an out-of-range date was used, which make them more difficult to catch. This has been changed too.
Despite the change is a revamp of the most widely used class in Orekit (AbsoluteDate
), many
efforts have been put to preserve the public API as much as possible. Many methods using
primitive double or providing primitive double are still there. One big exception to this
is the TimeScale
interface, which now only uses TimeOffset
instances. As most users just
use the time scales as opaque objects when reading/writing dates, they should not be affected
too much. In any case, they can still continue using primitive double by wrapping them in or
out of TimeOffset
instances, replacing calls like timeScale.offsetFromTAI(date)
by
timeScale.offsetFromTAI(date).toDouble()
. On the other hand, if they need to call a method
that needs a TimeOffset
and they only have a primitive double, wrapping is done by replacing
calls like object.someMethod(offset)
by object.someMethod(new TimeOffset(offset))
.
Custom implementations of TimeShiftable
could be updated to take advantage of the new
shiftedBy(TimeOffset)
method, but it is not required as there is a default implementation that
delegates to the original shiftedBy(double)
method.
If some user code breaks due to API changes, though, it is recommended to avoid using the
wrapping between primitive double and TimeOffset
. What is recommended is to take the
opportunity to remove entirely the primitive double and generalize use of TimeOffset
everywhere. This will increase both accuracy of computation and robustness.
Avoiding primitive double also applies to parsing and to literal constants in models or
non-regression test input data. When parsing a text like “3.2184e+01” from a String field
variable, instead of using new TimeOffset(Double.parseDouble(Field))
one should rather
use TimeOffset.parse(Field)
. The rationale is that TimeOffset.parse
preserves decimals
because it will parse the “3” and “2184” parts separately, apply the exponent and split
that into an exact 32 seconds part and an exact 184 milliseconds part, whereas the double
parsing would be slightly off (about 2.5 femtoseconds in this case) as IEEE754 cannot
represent this number exactly. The small parsing error will show up when printing dates in
some times scales. TimeOffset.parse(Field)
also supports parsing special offsets
like NaN
(regardless of case), -∞
and +∞
(for parsing infinity, the sign is mandatory).
When using literal constants in source code (say for example 32.184 as
before, which is the offset between TT and TAI) then rather than using new TimeOffset(32.184)
,
users should use the linear combinations constructors as in
new TimeOffset(32, TimeOffset.SECOND, 184, TimeOffset.MILLISECOND)
. There are such linear
combinations constructors from 1 to 5 terms and the multiplicative factors can be long integers.
The static method TimeComponents.fromSecond
intended to finely tune construction of dates
within a leap second occurrence has been replaced by a public constructor taking a single
TimeOffset
argument instead of its first two arguments.
In the OffsetModel
class, the units for slopes in UTC-TAI linear models used prior to 1972
were changed from seconds per day to nanoseconds per UTC second (despite neither is a SI unit),
as looking at the values shows these slopes were in fact simple numbers (only three different
slopes were used between 1961 and 1972: 15ns/s, 13ns/s and 30ns/s). The offset has also been
changed from double to TimeOffset
to allow representing exactly the microseconds offsets used
in linear models before 1972. As the UTCTAIOffset
and OffsetModel
classes are mainly
intended to implement UTC-TAI loaders and Orekit already provides loaders for the major formats,
this should not affect many users. For those users who did implement custom loaders that take
old slopes and double offsets into account, they should scale the slopes by changing their
parsing code from double slope = Double.parseDouble(Field)
to
int slope = (int) (TimeOffset.parse(Field).getAttoSeconds() / SLOPE_FACTOR)
were SLOPE_FACTOR
is defined as long SLOPE_FACTOR = 86400L * 1000000000L
; and then build the offset by using
this integer slope in nanoseconds per UTC seconds. Using TimeOffset.parse
instead of
Double.parseDouble
avoids numerical noise as parsing is done in decimal.
If users caught OrekitIllegalArgumentException
and IllegalStateException
when using
AggregatedPVCoordinatesProvider
, they must now catch OrekitException
to recover from out-of-range
dates.
As dates resolution is now always exactly one attosecond, when using shitftedBy
to set up a date just
before of after another date (for example to set up a transition in a TimeSpanMap
), the recommended
shift value is either TimeOffset.ATTOSECOND
or TimeOffset.ATTOSECOND.negate()
. Using Double.MIN_VALUE
won't work (anyway, it only worked in previous versions when the date was exactly at a TAI second, i.e.
when the offset was exactly 0.0).
A new createMedian
factory method has also been added to {Field}AbsoluteDate
In 12.X series, the signalTimeOfFlight
method assumed the signal was received at
a known fixed date, but was emitted at an earlier unknown date that is estimated.
In some cases (typically in GNSS where signals are generated by atomic clocks),
it is the emission date that is perfectly known and it is the later arrival time
that should be estimated.
The signalTimeOfFlight
method was therefore renamed signalTimeOfFlightAdjustableEmitter
and new signalTimeOfFlightAdjustableReceiver
methods with various signatures
were added in 13.0.
The change is straightforward. Users only have to replace calls to signalTimeOfFlight
by calls to signalTimeOfFlightAdjustableEmitter
.
In 12.X series, Sinex and Sinex-bias files parsing was not in line with other formats parsers
implementations. It still refers to DataLoader
instead of the new DataSource
paradigm,
hence relying on a regular expression for supported names and Sinex files being contained
in a DataContext
. The SinexLoader
class was a huge and complicated class and was a nightmare
to maintain. It was used both as the parser and as the container for parsed results. It mixed
Sinex and Sinex bias, which despite having a common base are different formats. It did not allow
proper loading of Observable-Specific Signal Biases, it only handled Differential Signal Biases
and probably mixed things up when parsing OSB or IFB files. It also used the older naming convention
of Differential Code Bias despite newer biases can refer to phase and not to code only, so they
are now named Differential Signal Bias. During parsing, it merged the description within the data
despite they are separated in the files. It only used string fields even for parts that had proper
associated classes, like satellite in system or observable types. The loaded biases were claimed
to be in SI units, but in fact phase biases could not really be parsed because the cycles unit
was not aavailable and the code biases despite being in one SI units (converted from nanoseconds
to seconds), this was not really consistent with a pseudo-range measurement in meters.
The Sinex parse also did not load complete phase center positions, it parsed SITE/ECCENTRICITY but this represents only a global Antenna Reference Point (ARP). The real phase centers are offset with respect to the ARP and are frequency dependent. For ground receivers, the phase centers are provided in the SITE/GPS_PHASE_CENTER and SITE/GAL_PHASE_CENTER blocks. For satellites, there is a SATELLITE/PHASE_CENTER block. All these blocks were ignored.
In order to alleviate all these shortcomings, parsing was rewritten from the ground up and split into
several specialized block and line parsers as well as several containers. Support for Observable-Specific
Signal Biases was added (but support for Ionosphere-Free Signal Bias, IFB, is still lacking, it could
however be added easily if required, thanks to the new modular architecture). A new unit, Unit.CYCLE
with name “cyc” was added, it is a dimensionless unit (just like the already existing Unit.NONE
,
Unit.ONE
, and Unit.PERCENT
).
Users that relied on SinexLoader
class configured from a regular expression for supported names
and requiring the Sinex files to be available in a data context should now use either the SinexParser
or the SinexBiasParser
class and pass to their parse
methods the DataSource
instances they want to
parse. This is simpler and more consistent with other existing parsers in Orekit (CCSDS, Rinex, SP3, CRD,
CPF, GPT…). The parse
methods return a container holding the parsed data, Sinex
in the SinexParser
case and SinexBias
in the SinexBiasParser
case.
When using SinexParser
to load Earth Orientation Parameters, users should be aware that since Sinex
files contain only one EOP entry block, they should call the parse
method with several DataSource
instances to have a reasonable time range covered. This was already the case in the previous implementation
and was generally worked around using a regular expression that matched several Sinex files. The resulting
Sinex
container does not implementEopHistoryLoader
by itself, instead it has a getEopLoader
that
returns such an object. The ITRFVersion
that should be used to build the EOP history is now specified
when calling getEopLoader
after parsing and not before parsing as was needed before.
The getters for accessing parsed data have been streamlined. The different levels of maps in SinexBias
have been renamed according to the new naming conventions to use Dsc
instead of Dcb
. The satellites
keys have been changed from String
to SatInSystem
with a specific Pseudo-Random-Number
SatInSystem.ANY_PRN
(which is set to -1) used to represent system-wide biases. The observations keys
have been changed from String
to ObservationType
. The SinexParser
takes a typeBuilder
argument
allowing users to parse custom ObservationType
if needed. This typeBuilder
can safely be set to
PredefinedObservationType::valueOf
when parsing Sinex-bias files containing only predefined observation
types.
The code biases are now in meters SI unit, the Constants.SPEED_OF_LIGHT
conversion factor is already
applied by the parser itself. Users should not apply this factor anymore at their level.
The getAntennaType
getter in the Station
objects provided by Sinex.getStations
has been replaced by
a getAntennaKey
method that returns a container with both the antenna type and the serial number. A new
getPhaseCenters
method that returns a map from GNSS signals to phase centers has also been added. This
method uses the antenna keys and handles cases where for example the SITE/GPS_PHASE_CENTER
block in the
Sinex file uses a catch-all “—–” entry that matches all serial numbers whereas the SITE/ANTENNA
block
uses specific serial numbers for the antennas.
The bottleneck of indirect shooting was the call to propagate
on FieldNumericalPropagator
,
plagued by event detection as well as adaptive step-size when used.
To improve performance, the integration is now done step by step (using the non-Field history),
by direct calls to the Hipparchus integrator (requiring to build ODE equations).
Also for this reason, the ShootingIntegrationSettings
has been revamped, now imposing {Field}ExplicitRungeKuttaIntegratorBuilder
.
The buildFieldPropagator
method in AbstractIndirectShooting
does not exist anymore, but inheritors must now implement buildFieldODE
.
The classes ClassicalRungeKuttaIntegrationSettings
and DormandPrince54IntegrationSettings
have been removed.
Instead, you can use the ShootingIntegrationSettingsFactory
, which offer more built-in choices.
In the 12.X series, SatelliteAntenna
used separate fields and accessors for satellite system
and satellite Pseudo-Random-Number, despite a SatInSystem
container already existed for this.
This was both awkward and dupplicated PRN offsets logic when parsing satellites antenna from Antex
files. PRN numbers in several IGS files (Rinex, Sinex, Antex…) are shifted by a 100 units offset
for SBAS system and shifted by 192 units for QZSS systems.
The change was to generalize use of SatInSystem
and moving the parsing logic from the various
format-specific parsers to SatInSystem
.
The SatelliteAntenna
constructor now takes a SatInSystem
argument instead of separate system
and prn. Users that do not build the instances themselves but simply retrieve them using
AntexLoader
will not be affected by this change, other users should change the call to the
constructor and build a SatInSystem
instance beforehand.
The getSatelliteSystem
and getPrnNumber
have been replaced by a single getSatInSystem
method,
which in turn gives access to the system and PRN.
The classes ImpulseManeuver
and FieldImpulseManeuver
do not inherit anymore from AbstractDetector
and
FieldAbstractDetector
anymore. The rational is that the create
method was unsafe, allowing users to replace the
handler, which should not happen for the logic to work. Nonetheless, a withDetectionSettings
method has been preserved.
On another note, the maneuver is now applied no matter the Action
returned by the event trigger's handler,
whilst before it was only if it was STOP
, which was somewhat arbitrary and was preventing from using RecordAndContinue
.
Replace any calls to create
by withDetectionSettings
when applicable. In case your trigger had a
StopOnIncreasing
or StopOnDecreasing
handler, use an EventPredicateFilter
instead.
The create
method of AbstractDetector
and FieldAbstractDetector
now has only one signature,
involving EventDetectionSettings
and FieldEventDetectionSettings
.
This way, future modifications to the detection system will not impact the signature anymore, as it should be buffered by the data container.
The old, longer signature which was already deprecated has been removed.
Implement create
with the only possible arguments.
Note that if you do not use the with
method, you probably do not need to use {Field}AbstractDetector
and {Field}EventDetector
may well be enough for your need.
The interface AttitudeProvider
now implements EventDetectorsProvider
, with default methods returning empty Stream
.
The rational is that internal events such as discontinuities in attitude are thus fed to propagators internally.
The class AttitudesSequence
leverages this change, so that registerSwitchEvents
does not exist anymore.
Simply delete the calls to registerSwitchEvents
.
The propagator will automatically use the switches if you used setAttitudeProvider
.
The class ExtendedPVCoordinatesProvider
has been deprecated and ExtendedPositionProvider
should be used instead.
The rationale is that the reference to PVCoordinates is confusing as implementations did not necessarily provide with accelerations.
Moreover, ExtendedPositionProvider
only requires a Field
implementation of getPosition
, the other methods are deduced from it using automatic differentiation.
This way, all velocity vectors are the first time derivative of the position vectors by construction, something that was not guaranteed before.
Replace any calls to ExtendedPVCoordinatesProvider
and ExtendedPVCoordinatesProviderAdapter
by ExtendedPositionProvider
and ExtendedPositionProviderAdapter
respectively.
A method toExtendedPVCoordinatesProvider
has been added to ExtendedPositionProvider
to facilitate phasing out.
In the 12.X series, Orbit
and FieldOrbit
would respectively have Nan and null rates for orbital elements if none was passed explicitly.
Now there are default values, which are the Keplerian ones, meaning that most of them are zero (only the position angle varies).
In consequence, the method hasDerivatives
in orbits has been renamed, as well as removeRates
in the interface PositionAngleBased
.
Replace your calls to hasDerivatives
by hasNonKeplerianAcceleration
, removeRates
by withKeplerianRates
and hasRates
by hasNonKeplerianRates
.
Moreover, do not expect NaN or null rates anymore.
The GNSS propagators are specialized analytical propagators that fit the orbit of navigation satellites for short duration (up to a few hours, far less than one orbit). They correspond to the models that are broadcast in navigation signals so end users can compute their own position, knowing the emitting satellites position. In the 12.X series, these propagators could only be built by loading external data (Rinex navigation files, RTCM streams…) but could not be fit by Orekit itself using orbit determination or fitting of precise ephemerides.
The change was to replace the fixed parameters of the analytical models (initial orbital parameters,
drifts and harmonic correction coefficients) by ParameterDriver
, introduce a trio of new classes
GnssHarvester
, GnssGradientConverter
and FieldGnssPropagator
and link them to the GNSSPropagator
class, so it now returns an instance of GnssHarvester
when its setupMatricesComputation
method is
called instead of throwing an UnsupportedOperationException
as it did previously.
In order to make this change, the GNSSOrbitalElements
interface that is at the root of a deep
classes hierarchy containing all GNSS almanacs and navigation messages has been changed from an
interface to a class that holds the various ParameterDriver
instances. This implies that directly
at this root level, the parameters can be changed (by calling ParameterDriver.setValue()
). Some
cleanup have been made so the setDate
method that was available deeper in the hierarchy has
been removed to ensure the date remains always consistent with the getTimeDriver()
parameter when
it is updated, either by calling setValue
at parameter driver level or by calling setTime
directly.
The constructors then require additional parameters (TimeScales
and SatelliteSystem
) to properly
recompute the date on the fly. The methods related to mean motion have been renamed for consistency
with GPS interface specification, adding a suffix 0
to {set|get}MeanMotion
and {set|get}DeltaN
,
moving the rates that should be added to these 0
values up in the class hierarchy, and letting the
callers add the rates. The rates additions are always taken into account in the specialized propagator,
they are non-zero only in navigation messages for some rates in civilian navigation mesages for other rates.
The main change for user code is that now it is possible to call setupMatricesComputation
for
GNSS propagators (this was the goal of the change).
Side effects are that users building directly classes from the hierarchy rooted at GNSSOrbitalElements
now need to provide TimeScales
and SatelliteSystem
arguments to base class constructors for the dates
handling, and they need to remove existing calls to setDate
(which are obsolete as date is always kept
in sync with the GNSS time parameter). If they developed their own classes, these classes should now extend
GNSSOrbitalElements
instead of implementing it as it is now a class.
If users called {set|get}MeanMotion
or {set|get}DeltaN
methods, they should add the 0
suffix and
call {set|get}MeanMotion0
or {set|get}DeltaN0
. Users must be aware that these getters are now restricted
to the fixed value and that the rates (getADot
, getDeltaN0
, getDeltaN0Dot
) must be added explicitly.
These effects should not affect many users as classes in the GNSSOrbitalElements
hierarchy are mainly
built internally (for example by the Rinex parsers) and users generally only get the already built instances
to pass them for example to GNSS propagators. One should be aware that in some strange cases, the
SatelliteSystem
to use at construction is not always the one corresponding to the real constellation.
This happens for example internally when we parse Rinex navigation files, as in these files the week number
for Galileo, IRNSS and QZSS must be aligned with GPS week and not the original system week (but for an unknown
reason, Rinex files specification requires to not change alignment for Beidou satellites and to keep the
Beidou constellation reference).
A getEffectName
has been added in 13.0 to the EstimationModifier
interface, so it is
easier to analyse the various contributors to an estimated measurement. All modifiers
provided by Orekit implement this new method and return a small effect name (troposphere,
ionosphere, wind-up…).
If users implemented their own modifiers, they must implement this method, typically by just returning a literal constant hard-coded in the implementation class or one of its super-classes.
The interfaces AdaptableInterval
and FieldAdaptableInterval
have been moved down to the subpackage intervals
in events
,
where their native inheritors already were. This makes for a cleaner architecture.
Modify the import by adding intervals
.
The EarthITU453AtmosphereRefraction
used up to 12.0 was misleading as the model implemented
was really ITU-R P.834. The class has therefore with renamed with the correct ITU recommendation
number: ITURP834AtmosphericRefraction
; new ITURP834PathDelay
, ITURP834MappingFunction
,
and ITURP834WeatherParametersProvider
models have been added too, with consistent naming.
Users should just change the class name they use.
Different names were in use for the so-called maximum check parameter for event detection.
DEFAULT_MAX_CHECK
has been set as the unique one, in line with DEFAULT_MAX_ITER
.
Simply replace any calls to DEFAULT_MAXCHECK
with DEFAULT_MAX_CHECK
.
The Field
methods in the interface CartesianCost
have been extracted to a FieldCartesianCost
.
The rationale is to give more flexibility for the latter.
As a consequence CartesianAdjointDynamicsProvider
is now an abstract class.
Usual inheritors are available in CartesianAdjointDynamicsProviderFactory
.
For Field
methods of cost functions, use the new classes e.g. FieldUnboundedEnergy
.
Use CartesianAdjointDynamicsProviderFactory
if applicable, otherwise get inspiration from it to create your own implementation of CartesianAdjointDynamicsProvider
.
The interface SwitchHandler
has been extracted from AttitudesSequence
and renamed AttitudeSwitchHandler
for clarity.
It is also used by the new class AttitudesSwitcher
.
Simply replace any calls to AttitudesSequences.SwitchHandler
with AttitudeSwitchHandler
.
The (possible null) attribute attitudeOverride
in Maneuver
is now an instance of a new interface AttitudeRotationModel
, aboveAttitudeProvider
.
It allows users to define ParameterDriver
in order to include their derivatives in the State Transition Matrix computation with {Field}NumericalPropagator
.
You need to cast the output of getAttitudeOverride
as AttitudeProvider
if you intend to use its specific methods
after passing it to the constructor of Maneuver
.
Java generics have been introduced in abstract classes inheriting from {Field}ODEIntegratorBuilder
.
It removes the need for casting on outputs. As part of this change, the two interfaces now only return interfaces,
not abstract classes.
Declare outputs of ODEIntegratorBuilder
as ODEIntegrator
instead of AbstractIntegrator
.
Similarly, declare outputs of FieldODEIntegratorBuilder
as FieldODEIntegrator
instead of AbstractFieldIntegrator
.
The full constructor of {Field}ImpulseManeuver
has changed.
Instead of providing a given {Field}Vector3D
, users have the possibility to build a full logic via the {Field}ImpulseProvider
interface.
This new API also allows using a single detector for maneuvers of different magnitude.
Most of the constructors signatures have been preserved, but the getDeltaVSat
does not exist anymore.
One cannot call getDeltaVSat
anymore. If you need to know what velocity was applied, you can use
a RecordAndContinue
event handler for instance and call the {Field}ImpulseProvider
on the collected states,
for instance with oldState
:
Vector3D deltaVSat = im.getImpulseProvider().getImpulse(oldState, im.forward);
The NeQuick model from Aeronomy and Radiopropagation Laboratory of the Abdus Salam International Centre
for Theoretical Physics Trieste, Italy has been available in Orekit since version 10.1 but only as the
Galileo-specific version. This version differs from the original model recommended by ITU in a number of ways.
It uses a different modified dip latitude grid, it uses a different way to integrate electron density, it has
different clipping constraints at low altitudes…
The ITU recommended implementation has therefore been added as a new NeQuickITU
class alongside the Galileo-pecific
one which has been renamed from NeQuickModel
to NeQuickGalileo
, and moved in a dedicated nequick
package.
The low-level electronDensity
method does not take a modip
parameter anymore, this parameter is
computed internally using different interpolation tables for NeQuickITU
and NeQuickGalileo
.
Users that relied on the Galileo-specific model and that still want to use it have to use the new name of the class,
NeQuickGalileo
and import it from the org.orekit.models.earth.ionosphere.nequick
package. If they called
the low level electronDensity
method, they should remove the modip
parameter.
Users that want to use the ITU-recommended version should use NeQuickITU
from the
org.orekit.models.earth.ionosphere.nequick
package.
The class ProfileThrustPropulsionModel
was using polynomial segments for no particular reasons,
so they have been generalized as ThrustVectorProvider
. The mass is now an argument as well to broaden applications.
The original constructor of ProfileThrustPropulsionModel
has been replaced by an static of
method,
since now a TimeSpanMap
of ThrustVectorProvider
is expected as argument.
The interface ManeuverTriggers
included resetters which are not used in Maneuver
, so
a new dedicated, intermediate interface has been introduced, called ResettableManeuverTriggers
.
If you do use resetters, replace ManeuverTriggers
by ResettableManeuverTriggers
.
If you were not implementing these methods with actual logic, remove them.
All objects that implemented Serializable
and that needed a dedicated so-called data transfer object to do so have had
that code removed, as well as their serializationUID
. The motivations were numerous.
First of all, often that process was based on a default DataContext
and the Field
equivalent classes were usually not Serializable
.
Moreover, it made code maintenance more tedious, especially since Orekit is still in Java 1.8 and does not have the
Record
type which is very convenient for serialization.
Stop using native serialization of Orbit
, PVCoordinates
, etc.
If needed by users, they are encouraged to implement their own mechanism.
{Field}SpacecraftState
wraps getters from the - possibly present - {Field}Orbit
attribute.
This is not safe as it can be NaN
for Orbit
and null
for FieldOrbit
.
These methods e.g. getA
have been removed.
Use getOrbit
before getA
, getOrbit
before getMu
, getOrbit
before getKeplerianPeriod
, etc.
One can check if they are present with isOrbitDefined
.
There was a copy-paste error in the RinexNavigation
class; the addGPSLegacyNavigationMessage
appeared twice, once taking a GPSCivilianNavigationMessage
argument and once taking a
GPSLegacyNavigationMessage
. One of these methods should have been named addGPSCivilianNavigationMessage
.
This was fixed in 13.0
If users called addGPSLegacyNavigationMessage
with a GPSCivilianNavigationMessage
argument, they
should change the method name to addGPSCivilianNavigationMessage
.
Visibility of methods (Field)AbstractPropagator#updateAdditionalStates
and (Field)AbstractAnalyticalPropagator#basicPropagate
and propagateOrbit
were changed from protected
to public
.
Simply change visibility of corresponding methods in classes subclassing (Field)AbstractPropagator
or (Field)AbstractAnalyticalPropagator
.
A new interface AdditionalDataProvider
has been introduced to generalize the mechanism of AdditionalStateProvider
to any object.
Class implementing AdditionalStateProvider
have to replace
public class MyAdditional implements AdditionalStateProvider {
// Some code
public double[] getAdditionalState(SpacecraftState state) {
// Compute additional state
}
// Some code
}
by
public class MyAdditional implements AdditionalDataProvider<double[]> {
// Some code
public double[] getAdditionalData(SpacecraftState state) {
// Compute additional state
}
// Some code
}
In Propagator
, the following methods
void addAdditionalStateProvider(AdditionalStateProvider additionalStateProvider);
List<AdditionalStateProvider> getAdditionalStateProviders();
boolean isAdditionalStateManaged(String name);
String[] getManagedAdditionalStates();
are replaced by
void addAdditionalDataProvider(AdditionalDataProvider additionalStateProvider);
List<AdditionalDataProvider<?>> getAdditionalDataProviders();
boolean isAdditionalDataManaged(String name);
String[] getManagedAdditionalData();
In AbstractPropagator
, the following method
SpacecraftState updateAdditionalStates(SpacecraftState original);
are replaced by
SpacecraftState updateAdditionalData(SpacecraftState original);
In SpacecraftState
, the following methods
SpacecraftState addAdditionalState(final String name, final double... value);
boolean hasAdditionalState(final String name);
public DoubleArrayDictionary getAdditionalStatesValues();
are replaced by
SpacecraftState addAdditionalData(final String name, final Object value);
boolean hasAdditionalData(final String name);
public DataDictionary getAdditionalDataValues();
The double[] getAdditionalState(final String name)
method has been preserved. It uses the generalized mechanism
but safe cast are performed to provide a double[]
. The new method Object getAdditionalData(final String name)
is
also available.
A new interface FieldAdditionalDataProvider
has been introduced to ensure consistency with AdditionalDataProvider
.
It replaces the FieldAdditionalStateProvider
interface.
Class implementing FieldAdditionalStateProvider
have to replace
public class MyFieldAdditional<T extends CalculusFieldElement<T>> implements FieldAdditionalStateProvider<T> {
// Some code
public T[] getAdditionalState(FieldSpacecraftState<T> state) {
// Compute additional state
}
// Some code
}
by
public class MyFieldAdditional<T extends CalculusFieldElement<T>> implements FieldAdditionalDataProvider<T> {
// Some code
public T[] getAdditionalData(FieldSpacecraftState<T> state) {
// Compute additional state
}
// Some code
}
In FieldPropagator
, the following methods
void addAdditionalStateProvider(FieldAdditionalStateProvider<T> additionalStateProvider);
List<FieldAdditionalStateProvider<T>> getAdditionalStateProviders();
boolean isAdditionalStateManaged(String name);
String[] getManagedAdditionalStates();
are replaced by
void addAdditionalStateProvider(FieldAdditionalDataProvider<T> additionalDataProvider);
List<FieldAdditionalDataProvider<T>> getAdditionalDataProviders();
boolean isAdditionalDataManaged(String name);
String[] getManagedAdditionalData();
In FieldAbstractPropagator
, the following method
FieldSpacecraftState<T> updateAdditionalStates(FieldSpacecraftState<T> original);
are replaced by
FieldSpacecraftState<T> updateAdditionalData(FieldSpacecraftState<T> original);
In FieldSpacecraftState
, the following methods
FieldSpacecraftState<T> addAdditionalState(final String name, final T... value);
boolean hasAdditionalState(final String name);
public FieldArrayDictionary getAdditionalStatesValues();
are replaced by
FieldSpacecraftState<T> addAdditionalData(final String name, final T... value);
boolean hasAdditionalData(final String name);
public FieldArrayDictionary getAdditionalDataValues();
(Field)SpacecraftState
now has withXXX
methods to create new instances.
Some constructors have been removed and some only deprecated for convenience.
Use withMass
, withAttitude
, withAdditionalData
and withAdditionalStatesDerivatives
instead of constructors with partial attribute selection.
StartStopFiringEventsTrigger
and IntervalEventTrigger
no longer required (Field)AbstractDetector
, only (Field)EventDetector
.
This is more generic and the only counterpart for custom implementations is to define the FieldEventDetectionSettings
properly in the Field
conversion methods
(convertAndSetUpStartHandler
, convertAndSetUpStopHandler
and convertAndSetUpHandler
), if used.
You may need to change the declaration type of the trigger detectors if you retrieved them
(from (Field)AbstractDetector
to (Field)EventDetector
).
If you had a custom Field
implementation, update the detector conversion routines.
Most built-in FieldEventDetector
in Orekit have a withDetectionSettings
method so changes should be minimal.
EventSlopeFilter
, EventShifter
and EventEnablingPredicateFilter
all have a privately-defined,
specific EventHandler
that should not be discarded for them to properly work.
Therefore, withHandler
has been removed, by removing the inheritance from AbstractDetector
altogether because of the create
method.
If you need to use a specific EventHandler
, you can pass it to the underlying detector,
as the specific handler in the filter/shifter will call it. Note also that any detector can be wrapped via the interface DetectorModifier
,
where one can apply custom overloads.
On the other hand, a consequence of not inheriting from AbstractDetector
is that there is no longer any withThreshold
, withMaxIter
, withMaxCheck
methods.
However, EventSlopeFilter
, EventShifter
and EventEnablingPredicateFilter
all still have withDetectionSettings
whilst (Field)EventDetectionSettings
now has its own builder mechanism.
The latter can also be passed directly in the detector's constructor.
The system formerly known as IRNSS (Indian Regional Navigation Satellite System) has been officially renamed
NavIC (Navigation with Indian Constellation). This denomination has been adopted in latest Rinex standards.
Numerous enumerates, constants and methods referred to this name. Most of them have been renamed; for example
the getIrnssEpoch()
in TimesScales
has been renamed into getNavicEpoch()
, the IRNSS_MU
constant in GNSSConstants
has been renamed into NAVIC_MU
and the IRNSSNavigationMessage
class has been renamed into NavICLegacyNavigationMessage
.
The literal constants that are parsed from files still using the former name have been kept as is, as these
names are mandatory. As an example, in Antex files, the known satellite names are still parsed from the IRNSS-1IGSO
string literal despite the corresponding entry in the SatelliteType
enumerate has been changed to NAVIC_1IGSO
.
Another example occurs in Rinex files, where the identifier for NavIC time is still IRN
.
There have been no structural changes, only renaming has been performed.
Users calling methods that follow camelcase convention should replace IRNSS
by NavIC
in method names.
Users referring constants or enumerates that follow uppercase convention should replace IRNSS
by NAVIC
.
In 12.X series, a PressureTemperatureHumidityProvider
has been introduced, allowing tropospheric models
to be applied at any time and any location. This provider generates PressureTemperatureHumidity
instances
on the fly as needed.
The older API of GroundStation
, TroposphericModel
and TroposphereMappingFunction
did not embrace
this change thoroughly. Some parts still referred to PressureTemperatureHumidity
, some parts mixed
use of both PressureTemperatureHumidityProvider
and PressureTemperatureHumidity
, some parts took an
argument of one type and ignored it, using an internal provider. This was confusing and not user-friendly.
The new design uses PressureTemperatureHumidityProvider
thoroughly and the provider is now only under
the responsibility of the tropospheric models. The GroundStation
class does not reference it anymore.
The main changes for users are the constructors of tropospheric models. Many of them now take a
PressureTemperatureHumidityProvider
instance as an argument.
As the provider is internally stored, another change is that there is no need anymore to pass a
PressureTemperatureHumidity
argument to the pathDelay
method of TroposphericModel
implementations
or to the mappingFactors
method of TroposphereMappingFunction
implementations, these arguments are
simply removed.
In 12.X series, the RtcmMessageType
enumerate used the default data context to build GNSS dates.
This prevented users to have full control of their data context, which is a problem on stream-based
always-on services.
This dependency was removed by simply passing a reference to a user-provided TimeScales
factory, which
could be the default one or could be a custom one. This new parameter is passed by the parser, so
the constructors of RtcmMessagesParser
, IgsSsrMessagesParser
, MessagesParser
and NtripClient
were changed to add this TimeScales
factory. The getParser
method in the ntrip Type
enumerate
also takes this TimeScales
factory as an argument because it build the parser corresponding to the type.
The main changes for users are to add the TimesScales
factory to either the constructors if they
call them directly or to the getParser
method in the ntrip Type
enumerate. The factory can
be the one returned by DataContext.getDefault().getTimeScales()
if the default data context
is suitable for users needs.