Commit ce17e000 authored by Bryan Cazabonne's avatar Bryan Cazabonne
Browse files

Merge branch 'develop' of https://gitlab.orekit.org/orekit/orekit.git

into develop
parents b6af0ac3 f39856b3
Pipeline #797 passed with stages
in 26 minutes and 38 seconds
......@@ -23,6 +23,9 @@
<release version="10.3" date="TBD" description="TBD">
<action dev="bryan" type="update" issue="741">
Updated Hipparchus version to 1.8 and updated code with new functionalities.
</action>
<action dev="bryan" type="add" issue="740">
Added aggregator for bounded attitude providers.
</action>
<action dev="thomas" type="add" issue="8">
Added Knocke's Earth rediffused radiation pressure force model.
......
/* Copyright 2002-2020 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.attitudes;
import java.util.Collection;
import java.util.Map.Entry;
import java.util.NavigableMap;
import java.util.TreeMap;
import org.hipparchus.RealFieldElement;
import org.orekit.errors.OrekitException;
import org.orekit.errors.OrekitMessages;
import org.orekit.frames.Frame;
import org.orekit.time.AbsoluteDate;
import org.orekit.time.FieldAbsoluteDate;
import org.orekit.utils.FieldPVCoordinatesProvider;
import org.orekit.utils.PVCoordinatesProvider;
/**
* A {@link BoundedAttitudeProvider} that covers a larger time span from several constituent
* attitude providers that cover shorter time spans.
*
* @author Bryan Cazabonne
* @since 10.3
*/
public class AggregateBoundedAttitudeProvider implements BoundedAttitudeProvider {
/** Constituent attitude provider. */
private final NavigableMap<AbsoluteDate, BoundedAttitudeProvider> providers;
/**
* Constructor.
* @param providers attitude providers that provide the backing data for this instance.
* There must be at least one attitude provider in the collection.
* If there are gaps between the {@link BoundedAttitudeProvider#getMaxDate()}
* of one attitude provider and the {@link BoundedAttitudeProvider#getMinDate()}
* of the next attitude provider an exception may be thrown by any method of
* this class at any time. If there are overlaps between the the {@link
* BoundedAttitudeProvider#getMaxDate()} of one attitude provider and the {@link
* BoundedAttitudeProvider#getMinDate()} of the next attitude provider then the
* attitude provider with the latest {@link BoundedAttitudeProvider#getMinDate()}
* is used.
*/
public AggregateBoundedAttitudeProvider(final Collection<? extends BoundedAttitudeProvider> providers) {
// Check if the collection is empty
if (providers.isEmpty()) {
throw new OrekitException(OrekitMessages.NOT_ENOUGH_ATTITUDE_PROVIDERS);
}
// Initialize map
this.providers = new TreeMap<>();
// Loop on providers
for (final BoundedAttitudeProvider provider : providers) {
// Fill collection
this.providers.put(provider.getMinDate(), provider);
}
}
/** {@inheritDoc} */
@Override
public Attitude getAttitude(final PVCoordinatesProvider pvProv, final AbsoluteDate date,
final Frame frame) {
// Get the attitude provider for the given date
final BoundedAttitudeProvider provider = getAttitudeProvider(date);
// Build attitude
return provider.getAttitude(pvProv, date, frame);
}
/** {@inheritDoc} */
@Override
public <T extends RealFieldElement<T>> FieldAttitude<T> getAttitude(final FieldPVCoordinatesProvider<T> pvProv,
final FieldAbsoluteDate<T> date, final Frame frame) {
// Get the attitude provider for the given date
final BoundedAttitudeProvider provider = getAttitudeProvider(date.toAbsoluteDate());
// Build attitude
return provider.getAttitude(pvProv, date, frame);
}
/** {@inheritDoc} */
@Override
public AbsoluteDate getMinDate() {
return providers.firstEntry().getValue().getMinDate();
}
/** {@inheritDoc} */
@Override
public AbsoluteDate getMaxDate() {
return providers.lastEntry().getValue().getMaxDate();
}
/**
* Get the attitude provider to use for the given date.
* @param date of query
* @return attitude provider to use on date.
*/
private BoundedAttitudeProvider getAttitudeProvider(final AbsoluteDate date) {
final Entry<AbsoluteDate, BoundedAttitudeProvider> attitudeEntry = providers.floorEntry(date);
if (attitudeEntry != null) {
return attitudeEntry.getValue();
} else {
// Let the first attitude provider throw the exception
return providers.firstEntry().getValue();
}
}
}
/* Copyright 2002-2020 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.attitudes;
import org.orekit.time.AbsoluteDate;
/** This interface is intended for attitude ephemerides valid only during a time range.
*
* <p>This interface provides a mean to retrieve an attitude at
* any time within a given range. It should be implemented by attitude readers
* based on external data files.</p>
*
* @author Bryan Cazabonne
* @since 10.3
*/
public interface BoundedAttitudeProvider extends AttitudeProvider {
/** Get the first date of the range.
* @return the first date of the range
*/
AbsoluteDate getMinDate();
/** Get the last date of the range.
* @return the last date of the range
*/
AbsoluteDate getMaxDate();
}
......@@ -220,6 +220,8 @@ public enum OrekitMessages implements Localizable {
NOT_ENOUGH_GNSS_FOR_DOP("only {0} GNSS orbits are provided while {1} are needed to compute the DOP"),
NOT_ENOUGH_PROPAGATORS(
"Creating an aggregate propagator requires at least one constituent propagator, but none were provided."),
NOT_ENOUGH_ATTITUDE_PROVIDERS(
"Creating an aggregate attitude provider requires at least one constituent attitude provider, but none were provided."),
NULL_ARGUMENT("argument {0} cannot be null"), VALUE_NOT_FOUND("value {0} not found in {1}"),
EPHEMERIS_FILE_NO_MULTI_SUPPORT("Ephemeris file format does not support multiple space objects"),
KLOBUCHAR_ALPHA_BETA_NOT_LOADED("Klobuchar coefficients α or β could not be loaded from {0}"),
......
......@@ -24,8 +24,6 @@ import java.util.Map;
import java.util.Map.Entry;
import org.hipparchus.geometry.euclidean.threed.RotationOrder;
import org.orekit.attitudes.AttitudeProvider;
import org.orekit.attitudes.TabulatedProvider;
import org.orekit.errors.OrekitException;
import org.orekit.errors.OrekitMessages;
import org.orekit.files.general.AttitudeEphemerisFile;
......@@ -313,10 +311,8 @@ public class AEMFile extends ADMFile implements AttitudeEphemerisFile {
}
/**
* Get the reference frame from which attitude is defined.
* @return the reference frame from which attitude is defined
*/
/** {@inheritDoc} */
@Override
public Frame getReferenceFrame() {
return refFrame;
}
......@@ -560,13 +556,6 @@ public class AEMFile extends ADMFile implements AttitudeEphemerisFile {
this.rotationOrder = order;
}
/** {@inheritDoc} */
@Override
public AttitudeProvider getAttitudeProvider() {
return new TabulatedProvider(getReferenceFrame(), getAngularCoordinates(),
getInterpolationSamples(), getAvailableDerivatives());
}
}
......
......@@ -16,11 +16,14 @@
*/
package org.orekit.files.general;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.hipparchus.geometry.euclidean.threed.RotationOrder;
import org.orekit.attitudes.AttitudeProvider;
import org.orekit.attitudes.AggregateBoundedAttitudeProvider;
import org.orekit.attitudes.BoundedAttitudeProvider;
import org.orekit.frames.Frame;
import org.orekit.time.AbsoluteDate;
import org.orekit.time.TimeScale;
import org.orekit.utils.AngularDerivativesFilter;
......@@ -96,6 +99,20 @@ public interface AttitudeEphemerisFile {
*/
AbsoluteDate getStop();
/**
* Get the attitude provider corresponding to this ephemeris, combining data from all {@link
* #getSegments() segments}.
*
* @return an attitude provider for all the data in this attitude ephemeris file.
*/
default BoundedAttitudeProvider getAttitudeProvider() {
final List<BoundedAttitudeProvider> providers = new ArrayList<>();
for (final AttitudeEphemerisSegment attitudeSegment : this.getSegments()) {
providers.add(attitudeSegment.getAttitudeProvider());
}
return new AggregateBoundedAttitudeProvider(providers);
}
}
/**
......@@ -141,6 +158,13 @@ public interface AttitudeEphemerisFile {
*/
String getRefFrameBString();
/**
* Get the reference frame from which attitude is defined.
*
* @return the reference frame from which attitude is defined
*/
Frame getReferenceFrame();
/**
* Get the rotation direction of the attitude.
*
......@@ -225,7 +249,9 @@ public interface AttitudeEphemerisFile {
*
* @return the attitude provider for this attitude ephemeris segment.
*/
AttitudeProvider getAttitudeProvider();
default BoundedAttitudeProvider getAttitudeProvider() {
return new EphemerisSegmentAttitudeProvider(this);
}
}
......
/* Copyright 2002-2020 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.general;
import java.util.List;
import java.util.stream.Collectors;
import org.hipparchus.RealFieldElement;
import org.orekit.attitudes.Attitude;
import org.orekit.attitudes.AttitudeProvider;
import org.orekit.attitudes.BoundedAttitudeProvider;
import org.orekit.attitudes.FieldAttitude;
import org.orekit.files.general.AttitudeEphemerisFile.AttitudeEphemerisSegment;
import org.orekit.frames.Frame;
import org.orekit.time.AbsoluteDate;
import org.orekit.time.FieldAbsoluteDate;
import org.orekit.utils.FieldPVCoordinatesProvider;
import org.orekit.utils.ImmutableTimeStampedCache;
import org.orekit.utils.PVCoordinatesProvider;
import org.orekit.utils.TimeStampedAngularCoordinates;
import org.orekit.utils.TimeStampedFieldAngularCoordinates;
/**
* An {@link AttitudeProvider} based on an {@link AttitudeEphemerisSegment}.
* @author Bryan Cazabonne
* @since 10.3
*/
public class EphemerisSegmentAttitudeProvider implements BoundedAttitudeProvider {
/** Cached attitude table. */
private final transient ImmutableTimeStampedCache<TimeStampedAngularCoordinates> table;
/** Tabular data from which this attitude provider is built. */
private final AttitudeEphemerisSegment segment;
/**
* Constructor.
* @param segment segment containing the attitude data for this provider.
*/
public EphemerisSegmentAttitudeProvider(final AttitudeEphemerisSegment segment) {
this.segment = segment;
this.table = new ImmutableTimeStampedCache<TimeStampedAngularCoordinates>(segment.getInterpolationSamples(),
segment.getAngularCoordinates());
}
/** {@inheritDoc} */
@Override
public Attitude getAttitude(final PVCoordinatesProvider pvProv, final AbsoluteDate date,
final Frame frame) {
// Get attitudes sample on which interpolation will be performed
final List<TimeStampedAngularCoordinates> attitudeSample = table.getNeighbors(date).collect(Collectors.toList());
// Interpolate attitude data
final TimeStampedAngularCoordinates interpolatedAttitude =
TimeStampedAngularCoordinates.interpolate(date, segment.getAvailableDerivatives(), attitudeSample);
// Build the interpolated attitude
return new Attitude(segment.getReferenceFrame(), interpolatedAttitude);
}
/** {@inheritDoc} */
@Override
public <T extends RealFieldElement<T>> FieldAttitude<T> getAttitude(final FieldPVCoordinatesProvider<T> pvProv,
final FieldAbsoluteDate<T> date, final Frame frame) {
// Get attitudes sample on which interpolation will be performed
final List<TimeStampedFieldAngularCoordinates<T>> attitudeSample = table.getNeighbors(date.toAbsoluteDate()).
map(ac -> new TimeStampedFieldAngularCoordinates<>(date.getField(), ac)).
collect(Collectors.toList());
// Interpolate attitude data
final TimeStampedFieldAngularCoordinates<T> interpolatedAttitude =
TimeStampedFieldAngularCoordinates.interpolate(date, segment.getAvailableDerivatives(), attitudeSample);
// Build the interpolated attitude
return new FieldAttitude<>(segment.getReferenceFrame(), interpolatedAttitude);
}
/** {@inheritDoc} */
@Override
public AbsoluteDate getMinDate() {
return segment.getStart();
}
/** {@inheritDoc} */
@Override
public AbsoluteDate getMaxDate() {
return segment.getStop();
}
}
......@@ -24,8 +24,6 @@ import java.util.concurrent.ConcurrentHashMap;
import org.hipparchus.geometry.euclidean.threed.RotationOrder;
import org.orekit.annotation.DefaultDataContext;
import org.orekit.attitudes.AttitudeProvider;
import org.orekit.attitudes.TabulatedProvider;
import org.orekit.bodies.CelestialBody;
import org.orekit.data.DataContext;
import org.orekit.errors.OrekitIllegalArgumentException;
......@@ -518,6 +516,12 @@ public class OrekitAttitudeEphemerisFile implements AttitudeEphemerisFile {
return refFrameBString;
}
/** {@inheritDoc} */
@Override
public Frame getReferenceFrame() {
return referenceFrame;
}
/** {@inheritDoc} */
@Override
public String getAttitudeDirection() {
......@@ -584,13 +588,6 @@ public class OrekitAttitudeEphemerisFile implements AttitudeEphemerisFile {
return angularDerivativesFilter;
}
/** {@inheritDoc} */
@Override
public AttitudeProvider getAttitudeProvider() {
return new TabulatedProvider(referenceFrame, getAngularCoordinates(),
getInterpolationSamples(), getAvailableDerivatives());
}
}
}
......@@ -454,6 +454,9 @@ CCSDS_TIME_SYSTEM_NOT_IMPLEMENTED = brugen af tidssystemet {0} i CCSDS filer kr
# Creating an aggregate propagator requires at least one constituent propagator, but none were provided.
NOT_ENOUGH_PROPAGATORS = Oprettelsen af en aggregeret propagator kræver mindst en propagator-bestanddel, men ingen blev angivet.
# Creating an aggregate attitude provider requires at least one constituent attitude provider, but none were provided.
NOT_ENOUGH_ATTITUDE_PROVIDERS = <MISSING TRANSLATION>
# argument {0} cannot be null
NULL_ARGUMENT = argument {0} kan ikke være null
......
......@@ -454,6 +454,9 @@ CCSDS_TIME_SYSTEM_NOT_IMPLEMENTED = Die Benutzung des Zeitsystems {0} in CCSDS D
# Creating an aggregate propagator requires at least one constituent propagator, but none were provided.
NOT_ENOUGH_PROPAGATORS = Das erstellen von AggregatePropagator benötigt zumindest einen Bestandteil des Propagator. Es wurden keine zur Verfügung gestellt
# Creating an aggregate attitude provider requires at least one constituent attitude provider, but none were provided.
NOT_ENOUGH_ATTITUDE_PROVIDERS = <MISSING TRANSLATION>
# argument {0} cannot be null
NULL_ARGUMENT = Das Argument {0} kann nicht "null" sein
......
......@@ -454,6 +454,9 @@ CCSDS_TIME_SYSTEM_NOT_IMPLEMENTED = <MISSING TRANSLATION>
# Creating an aggregate propagator requires at least one constituent propagator, but none were provided.
NOT_ENOUGH_PROPAGATORS = <MISSING TRANSLATION>
# Creating an aggregate attitude provider requires at least one constituent attitude provider, but none were provided.
NOT_ENOUGH_ATTITUDE_PROVIDERS = <MISSING TRANSLATION>
# argument {0} cannot be null
NULL_ARGUMENT = <MISSING TRANSLATION>
......
......@@ -454,6 +454,9 @@ CCSDS_TIME_SYSTEM_NOT_IMPLEMENTED = use of time system {0} in CCSDS files requir
# Creating an aggregate propagator requires at least one constituent propagator, but none were provided.
NOT_ENOUGH_PROPAGATORS = Creating an aggregate propagator requires at least one constituent propagator, but none were provided.
# Creating an aggregate attitude provider requires at least one constituent attitude provider, but none were provided.
NOT_ENOUGH_ATTITUDE_PROVIDERS = Creating an aggregate attitude provider requires at least one constituent attitude provider, but none were provided.
# argument {0} cannot be null
NULL_ARGUMENT = argument {0} cannot be null
......
......@@ -454,6 +454,9 @@ CCSDS_TIME_SYSTEM_NOT_IMPLEMENTED = para utilizar el sistema temporal {0} en los
# Creating an aggregate propagator requires at least one constituent propagator, but none were provided.
NOT_ENOUGH_PROPAGATORS = para crear un propagador combinado se necesita al menos un propagador, pero no se ha especificado ninguno
# Creating an aggregate attitude provider requires at least one constituent attitude provider, but none were provided.
NOT_ENOUGH_ATTITUDE_PROVIDERS = <MISSING TRANSLATION>
# argument {0} cannot be null
NULL_ARGUMENT = la entrada {0} no puede ser nula
......
......@@ -454,6 +454,9 @@ CCSDS_TIME_SYSTEM_NOT_IMPLEMENTED = l''utilisation du système temporel {0} néc
# Creating an aggregate propagator requires at least one constituent propagator, but none were provided.
NOT_ENOUGH_PROPAGATORS = la création d''un propagateur combiné nécessite au moins un propagateur, mais aucun n''a été fourni
# Creating an aggregate attitude provider requires at least one constituent attitude provider, but none were provided.
NOT_ENOUGH_ATTITUDE_PROVIDERS = la création d''un fournisseur d''attitude combiné nécessite au moins un fournisseur d''attitude, mais aucun n''a été fourni.
# argument {0} cannot be null
NULL_ARGUMENT = l''argument {0} ne devrait pas être nul
......
......@@ -454,6 +454,9 @@ CCSDS_TIME_SYSTEM_NOT_IMPLEMENTED = <MISSING TRANSLATION>
# Creating an aggregate propagator requires at least one constituent propagator, but none were provided.
NOT_ENOUGH_PROPAGATORS = <MISSING TRANSLATION>
# Creating an aggregate attitude provider requires at least one constituent attitude provider, but none were provided.
NOT_ENOUGH_ATTITUDE_PROVIDERS = <MISSING TRANSLATION>
# argument {0} cannot be null
NULL_ARGUMENT = <MISSING TRANSLATION>
......
......@@ -455,6 +455,9 @@ CCSDS_TIME_SYSTEM_NOT_IMPLEMENTED = l''utilizzo del sistema temporale {0} nei fi
# Creating an aggregate propagator requires at least one constituent propagator, but none were provided.
NOT_ENOUGH_PROPAGATORS = la creazione di un propagatore combinato richiede almeno un propagatore, ma non ne è stato fornito alcuno
# Creating an aggregate attitude provider requires at least one constituent attitude provider, but none were provided.
NOT_ENOUGH_ATTITUDE_PROVIDERS = <MISSING TRANSLATION>
# argument {0} cannot be null
NULL_ARGUMENT = l''argomento {0} non può essere nullo
......
......@@ -454,6 +454,9 @@ CCSDS_TIME_SYSTEM_NOT_IMPLEMENTED = Bruk av tidssystemet {0} i CCSDS-filer kreve
# Creating an aggregate propagator requires at least one constituent propagator, but none were provided.
NOT_ENOUGH_PROPAGATORS = En aggregat-propagatør krever minst en bestanddel propagatør, men ingen var spesifisert.
# Creating an aggregate attitude provider requires at least one constituent attitude provider, but none were provided.
NOT_ENOUGH_ATTITUDE_PROVIDERS = <MISSING TRANSLATION>
# argument {0} cannot be null
NULL_ARGUMENT = argumentet {0} kan ikke være null
......
......@@ -454,6 +454,9 @@ CCSDS_TIME_SYSTEM_NOT_IMPLEMENTED = utilizarea sistemului de timp {0} în fișie
# Creating an aggregate propagator requires at least one constituent propagator, but none were provided.
NOT_ENOUGH_PROPAGATORS = Crearea unui propagator combinator necesită cel puțin un propagator, dar nici unul nu a fost definit.
# Creating an aggregate attitude provider requires at least one constituent attitude provider, but none were provided.
NOT_ENOUGH_ATTITUDE_PROVIDERS = <MISSING TRANSLATION>
# argument {0} cannot be null
NULL_ARGUMENT = argumentul {0} nu poate fi nul
......
/* Copyright 2002-2020 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.attitudes;
import java.io.InputStream;
import java.util.Collections;
import org.hipparchus.Field;
import org.hipparchus.RealFieldElement;
import org.hipparchus.geometry.euclidean.threed.FieldRotation;
import org.hipparchus.geometry.euclidean.threed.Rotation;
import org.hipparchus.util.Decimal64Field;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.orekit.Utils;
import org.orekit.bodies.CelestialBodyFactory;
import org.orekit.errors.OrekitException;
import org.orekit.errors.OrekitMessages;
import org.orekit.files.ccsds.AEMFile;
import org.orekit.files.ccsds.AEMFile.AemSatelliteEphemeris;
import org.orekit.files.ccsds.AEMParser;
import org.orekit.time.AbsoluteDate;
import org.orekit.time.FieldAbsoluteDate;
import org.orekit.time.TimeScalesFactory;
import org.orekit.utils.IERSConventions;
public class AggregateBoundedAttitudeProviderTest {
@Before
public void setUp() {
Utils.setDataRoot(