Data initialization : Différence entre versions

De Wiki
Aller à : navigation, rechercher
(Vehicle)
 
(42 révisions intermédiaires par le même utilisateur non affichées)
Ligne 1 : Ligne 1 :
 +
The main modifications between V11.3 and previous versions are due to the use of original [http://patrius.cnes.fr PATRIUS] classes rather than to use "Custom" classes originally proposed by [http://genopus.cnes.fr GENOPUS]. Anyway, some "Custom" classes still remain as [http://patrius.cnes.fr PATRIUS] classes are not sufficiently consistent.
 +
 +
 
== Orbit ==
 
== Orbit ==
  
Ligne 29 : Ligne 32 :
 
:* '''NOTHING''' (all options set to null)
 
:* '''NOTHING''' (all options set to null)
 
:* '''ONLY_PREC_NUT''' (only precession and nutation)
 
:* '''ONLY_PREC_NUT''' (only precession and nutation)
:* '''FACTORY''' (equivalent to the most complete definition as in the <font color=#FF8C00>GUI</font>)
+
:* '''FACTORY''' (equivalent to the most complete definition as in the <font color=#FF8C00 title="Graphical User Interface">GUI</font>)
 
:* '''IGNORE''' (nothing is define internally by <font color=#556B2F>'''PSIMU'''</font> which will take into account the user parametrization previously done)
 
:* '''IGNORE''' (nothing is define internally by <font color=#556B2F>'''PSIMU'''</font> which will take into account the user parametrization previously done)
  
 
== Vehicle ==
 
== Vehicle ==
  
In fact, we need to pass both an <font color=#4169E1>Assembly</font> and a <font color=#4169E1>MassProvider</font>. It could seem curious but it is due to the fact that, if we have maneuvers, it will be mandatory to initialize them with the same <font color=#4169E1>MassProvider</font> (see example [[#Maneuvers|here]]). To get them, we could use the <font color=#4169E1>AssemblyBuilder</font> given by [[https://logiciels.cnes.fr/en/node/62?type=desc PATRIUS]] or the <font color=#4169E1>CustomVehicle</font> class coming from [[https://logiciels.cnes.fr/en/node/78?type=desc GENOPUS]] waiting for the next <font color=#4169E1>Vehicle</font> class that will appear from [[https://logiciels.cnes.fr/en/node/62?type=desc PATRIUS]] V3.4. In the example below, we will use the <font color=#4169E1>CustomVehicle</font> class initializing mass and aerodynamic properties (here no engines and no tanks):
+
Since V11.3, it is no more necessary to pass an <font color=#4169E1>Assembly</font> object but a <font color=#4169E1>Vehicle one</font>. Anyway, it is allways mandatory to pass a <font color=#4169E1>MassProvider</font> object, issued from the <font color=#4169E1>Vehicle</font> one. It could seem curious but it is due to the fact that, if we have maneuvers, it will be mandatory to initialize them with the same <font color=#4169E1>MassProvider</font> (see example [[#Maneuvers|here]]).
 +
 
 +
In fact, we need to pass both an <font color=#4169E1>Assembly</font> and a <font color=#4169E1>MassProvider</font>. It could seem curious but it is due to the fact that, if we have maneuvers, it will be mandatory to initialize them with the same <font color=#4169E1>MassProvider</font> (see example [[#Maneuvers|here]]). To get them, we will use the <font color=#4169E1>createAssembly()</font> method given by <font color=#4169E1>Vehicle</font> class.
 +
 
 +
<syntaxhighlight lang="java">
 +
final Assembly assembly = vehicle.createAssembly(GCRF);
 +
final MassProvider mm = new MassModel(assembly);
 +
</syntaxhighlight>
 +
 
 +
''<font color=#FF0000>'''Note : for CPU time purpose it is recommanded that the frame (GCRF in the previous example), mandatory in the construction of the vehicle, must be exactly the same that the one used for the propagation.'''</font>''
 +
 
 +
In the example below, we will then use the <font color=#4169E1>Vehicle</font> class initializing mass and aerodynamic properties (here no engines and no tanks):
  
 
<syntaxhighlight lang="java">
 
<syntaxhighlight lang="java">
Ligne 40 : Ligne 54 :
 
final double dryMass = 1000.;
 
final double dryMass = 1000.;
 
final MassProperty dryMassProperty = new MassProperty(dryMass);
 
final MassProperty dryMassProperty = new MassProperty(dryMass);
 +
       
 
// Shape
 
// Shape
final CustomSphere sphere = new CustomSphere(5.0);
+
final double sref = 5.0;
final CustomVehicleSurfaceModel vehicleRefSurface =
+
Sphere sphere = new Sphere(sref);
  new CustomVehicleSurfaceModel(sphere);
+
final RightParallelepiped solarPanels = new RightParallelepiped(10., 0., 0.);
 +
VehicleSurfaceModel vehicleRefSurface = new VehicleSurfaceModel(sphere, solarPanels);
 +
 
 
// Aerodynamic properties
 
// Aerodynamic properties
 
final double cd = 2.0;
 
final double cd = 2.0;
 
final double cl = 0.;
 
final double cl = 0.;
final CustomAerodynamicProperties aerodynamicProperties =
+
final AerodynamicProperties aerodynamicProperties = new AerodynamicProperties(vehicleRefSurface, cd, cl);
  new CustomAerodynamicProperties(vehicleRefSurface, cd, cl);
+
       
 +
final Vehicle vehicle = new Vehicle(vehicleRefSurface, null, dryMassProperty, aerodynamicProperties, null, null, null);
  
final CustomVehicle vehicle =
+
final Assembly assembly = vehicle.createAssembly(GCRF);
  new CustomVehicle(dryMassProperty, aerodynamicProperties, null, null, null);
+
final Assembly assembly = vehicle.getAssembly(GCRF);
+
 
final MassProvider mm = new MassModel(assembly);
 
final MassProvider mm = new MassModel(assembly);
 
</syntaxhighlight>
 
</syntaxhighlight>
  
<font color=#FF0000>''Note : be careful that the frame (GCRF in the previous example), mandatory in the construction of the vehicle must be exactly the same that the one used for the propagation (limitation due to PATRIUS).''</font>
+
''<font color=#FF0000>'''Note : due to a PATRIUS anomaly, if the user needs to define solar panels characteristics, it is mandatory to use the Vehicle constructor with all parameters and the VehiculeSurfaceModel including the panels as above (and not a list of Facet); also, do not use the setters methods.'''</font>''
  
 
== Forces ==
 
== Forces ==
  
To define, which forces will be applied along the trajectory, we use the <font color=#4169E1>CustomForceModels</font> class (waiting for the equivalent [[https://logiciels.cnes.fr/en/node/62?type=desc PATRIUS]] class).
+
Since V11.3, to define, which forces will be applied along the trajectory, we use the [http://patrius.cnes.fr PATRIUS] <font color=#4169E1>ForceModelsData</font> class (no more necessary to use the specific <font color=#4169E1>CustomForceModels</font> class which does not exist anymore).
  
 
=== Potential ===
 
=== Potential ===
Ligne 67 : Ligne 83 :
 
<syntaxhighlight lang="java">
 
<syntaxhighlight lang="java">
 
// Potential
 
// Potential
final ForceModel potential = createPot("grim4s4_gr", 8, 8);
+
final ForceModel potential = EarthGravitationalModelFactory.getDroziner(GravityFieldNames.GRGS, "grim4s4_gr", 8, 8, true);
       
+
final CustomForceModels forces = new CustomForceModels(potential, null, null, null, null, null, null, null, null, null, null);
+
</syntaxhighlight>
+
 
+
Note that the <font color=#4169E1>createPot()</font> <font color=#FF8C00>static</font> method is the following one (waiting for such utility from V3.4.1 of [[https://logiciels.cnes.fr/en/node/62?type=desc PATRIUS]]):
+
 
+
<syntaxhighlight lang="java">
+
public static ForceModel createPot ( String namePot, int nzo, int nte) throws IOException, ParseException, OrekitException {
+
       
+
// Adding « reader » for gravity models
+
GravityFieldFactory.addPotentialCoefficientsReader(
+
    new GRGSFormatReader(namePot, true));
+
 
+
// Getting gravity model from « namePot » model
+
final PotentialCoefficientsProvider provider =
+
    GravityFieldFactory.getPotentialProvider();
+
 
+
// Getting zonal and tesseral terms
+
final int n = nzo; // max zonal degree
+
final int m = nte; // max tesseral order
+
   
+
int ntmp = 1;
+
if ( n != 0 ) ntmp = nzo;
+
   
+
final double[][] C = provider.getC(ntmp, m, false);
+
final double[][] S = provider.getS(ntmp, m, false);
+
  
// Force model creation
+
final ForceModelsData forces = new ForceModelsData(potential, null, null, null, null, null, null, null, null, null, null, null, null,  null, null);
ForceModel pot = new DrozinerAttractionModel(FramesFactory.getITRF(),
+
                    provider.getAe(), provider.getMu(), C, S);
+
   
+
return pot;
+
   
+
}
+
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 
=== Aerodynamic ===
 
=== Aerodynamic ===
  
Then we could add an aerodynamic force model
+
Then we could add an aerodynamic force model. Since V11.3, it is no more necessary to use "Custom" classes.
  
 
<syntaxhighlight lang="java">
 
<syntaxhighlight lang="java">
Ligne 115 : Ligne 99 :
 
   new ExtendedOneAxisEllipsoid(REQ, FLAT, ITRF, "EARTH");
 
   new ExtendedOneAxisEllipsoid(REQ, FLAT, ITRF, "EARTH");
 
      
 
      
final CustomAtmosphere atmosphere = new CustomUS76(EARTH);
+
final Atmosphere atmosphere = new US76(EARTH);
final CustomDragForce dragForce = new CustomDragForce(1., atmosphere, assembly);
+
final DragForce dragForce = new DragForce(1., atmosphere, assembly);
 
        
 
        
 
forces.setDragForce(dragForce);
 
forces.setDragForce(dragForce);
 
</syntaxhighlight>
 
</syntaxhighlight>
  
=== Solar adiative pressure ===
+
=== Solar radiative pressure ===
  
Here are explained how to use both radiative pressure and rediffused radiative pressure force models:
+
Here are explained how to use both radiative pressure and rediffused radiative pressure force models. Again, since V11.3, no more tu use old "Custom" classes.
  
 
<syntaxhighlight lang="java">
 
<syntaxhighlight lang="java">
Ligne 132 : Ligne 116 :
 
   new ExtendedOneAxisEllipsoid(REQ, FLAT, ITRF, "EARTH");
 
   new ExtendedOneAxisEllipsoid(REQ, FLAT, ITRF, "EARTH");
 
          
 
          
final CustomPatriusSolarRadiationPressure radPres =
+
SolarRadiationPressureEllipsoid radPres = new SolarRadiationPressureEllipsoid(dRef, pRef, sunBody, EARTH, assembly, 1.);
  new CustomPatriusSolarRadiationPressure(dRef, pRef, sunBody, EARTH, assembly, 1.);
+
  
 
forces.setSolarRadiationPressure(radPres);
 
forces.setSolarRadiationPressure(radPres);
Ligne 147 : Ligne 130 :
 
final double coefIr = 1.;
 
final double coefIr = 1.;
 
          
 
          
final CustomRediffusedRadiationPressure rediffusedRadiationPressure =
+
RediffusedRadiativeModel rdm = new RediffusedRadiativeModel(inAlbedo, inIr, coefAlbedo, coefIr, assembly);
  new CustomRediffusedRadiationPressure(sunBody, GCRF, inCorona, inMeridian,
+
RediffusedRadiationPressure reDiff =  new RediffusedRadiationPressure(sunBody, GCRF, inCorona, inMeridian, inEmissivityModel, rdm);
                                        inEmissivityModel, inAlbedo, inIr,
+
     
                                        coefAlbedo, coefK0Ir, assembly);
+
forces.setRediffusedRadiationPressure(reDiff);
       
+
</syntaxhighlight>
forces.setRediffusedSolarRadiationPressure(rediffusedRadiationPressure);
+
  
 +
=== Specific forces ===
 +
 +
It is also possible to add specific forces via the <font color=#4169E1>addForceModel()</font> method as below:
 +
 +
<syntaxhighlight lang="java">
 +
final Psimu test = new Psimu(...);
 +
test.addForceModel(myForce);
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Ligne 162 : Ligne 151 :
 
=== Propulsive properties ===
 
=== Propulsive properties ===
  
First, the user will have to define propulsive properties with engine(s) and tank(s):
+
First, the user will have to define propulsive properties with engine(s) and tank(s).
  
 
<syntaxhighlight lang="java">
 
<syntaxhighlight lang="java">
 
// Propulsive properties
 
// Propulsive properties
final CustomEngine engine = new CustomEngine("ENGINE", 320., 400.);
+
final PropulsiveProperty engine = new PropulsiveProperty(400, 320.);
final ArrayList<CustomEngine> listOfEngines = new ArrayList<CustomEngine>();
+
engine.setPartName("ENGINE");
 +
final ArrayList<PropulsiveProperty> listOfEngines = new ArrayList<PropulsiveProperty>();
 
listOfEngines.add(engine);
 
listOfEngines.add(engine);
final CustomFuelTank tank = new CustomFuelTank("TANK", 100.);
+
final TankProperty tank = new TankProperty(200.);
final ArrayList<CustomFuelTank> listOfTanks = new ArrayList<CustomFuelTank>();
+
tank.setPartName("TANK");
 +
final ArrayList<TankProperty> listOfTanks = new ArrayList<TankProperty>();
 +
listOfTanks.add(tank);
 
listOfTanks.add(tank);
 
listOfTanks.add(tank);
 
          
 
          
final CustomVehicle vehicle =
+
final Vehicle vehicle = new Vehicle(vehicleRefSurface, null, dryMassProperty, null, null, listOfEngines, listOfTanks);
  new CustomVehicle(dryMassProperty, null, null, listOfEngines, listOfTanks);
+
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 
=== Sequence ===
 
=== Sequence ===
  
Then, a maneuver sequence will be created thanks to the <font color=#4169E1>CustomManeuverSequence</font> (the [[https://logiciels.cnes.fr/en/node/62?type=desc PATRIUS]] <font color=#4169E1>ManeuverSequence</font> is not directly used as it does not still manage engines and tanks; it will be available with V3.4.1).
+
Then, a maneuver sequence will be created thanks to the <font color=#4169E1>CustomManeuverSequence</font> (the [[https://logiciels.cnes.fr/en/node/62?type=desc PATRIUS]] <font color=#4169E1>ManeuverSequence</font> is not directly used as it does not still manage events.
  
 
=== Impulsive maneuver ===
 
=== Impulsive maneuver ===
  
Here we have an example of a 10m/s impulse maneuver in <font color=#FF8C00>TNW</font>:
+
Here we have an example of a 10m/s impulse maneuver in <font color=#FF8C00>TNW</font> occuring for an <font color=#FF8C00 title="Argument Of Latitude">AOL</font> of 180 degrees:
  
 
<syntaxhighlight lang="java">
 
<syntaxhighlight lang="java">
 
final double aol = FastMath.toRadians(180.);
 
final double aol = FastMath.toRadians(180.);
final CustomAOLDetector eventImp =
+
final CustomAOLDetector aolDetector = new CustomAOLDetector(aol, PositionAngle.TRUE, GCRF, MAXCHECK, THRESHOLD, Action.STOP);
  new CustomAOLDetector(aol, PositionAngle.TRUE, GCRF, 1, maxCheck, threshold,
+
final IntervalOccurrenceDetectorWrapper impEvent = new IntervalOccurrenceDetectorWrapper(aolDetector, 1, 1, 1, Action.STOP);
                        Action.STOP, true);
+
final GenericCodingEventDetector codingEvent =
+
  eventImp.getGenericCodingEventDetector("imp man", "imp man");
+
 
+
 
final Vector3D deltaV = new Vector3D(10., 0., 0.);
 
final Vector3D deltaV = new Vector3D(10., 0., 0.);
 
+
final CustomImpulseManeuver imp = new CustomImpulseManeuver("Impulse maneuver", listOfEngines.get(0), listOfTanks.get(0), LOFType.TNW, impEvent, deltaV, mm);
final CustomImpulseManeuver imp =
+
  new CustomImpulseManeuver("Impulse maneuver", engine, tank, LOFType.TNW, eventImp, deltaV, mm, codingEvent);
+
 
</syntaxhighlight>
 
</syntaxhighlight>
  
<font color=#FF0000>
+
''<font color=#FF0000>
''Note: it is mandatory to define the maneuver with a Coding Event detector to allow to '''PSIMU''' to manage events.''
+
'''Note: it is mandatory to configure the event with a STOP action (needed by [[https://logiciels.cnes.fr/en/node/62?type=desc PATRIUS]]).'''
 
+
</font>''
''Note: it is also mandatory to configure the event with a '''STOP''' action (needed by [[https://logiciels.cnes.fr/en/node/62?type=desc PATRIUS]]) as the Coding event must have a CONTINUE action (automatically done if using the getGenericCodingEventDetector () method).''
+
</font>
+
  
 
At last, the user will create the maneuver sequence to pass to <font color=#556B2F>'''PSIMU'''</font>:
 
At last, the user will create the maneuver sequence to pass to <font color=#556B2F>'''PSIMU'''</font>:
  
 
<syntaxhighlight lang="java">
 
<syntaxhighlight lang="java">
final ArrayList<CustomManeuverInterface> listOfMan =
+
final CustomManeuverSequence manSeq = new CustomManeuverSequence(0., 0.);
  new ArrayList<CustomManeuverInterface>();
+
manSeq.addManeuver(imp);
listOfMan.add(imp);
+
final CustomManeuverSequence manSeq = new CustomManeuverSequence(listOfMan, 0., 0.);
+
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Ligne 221 : Ligne 202 :
 
final double start = iniOrbit.getKeplerianPeriod();
 
final double start = iniOrbit.getKeplerianPeriod();
 
final AbsoluteDate startDate = date.shiftedBy(start);
 
final AbsoluteDate startDate = date.shiftedBy(start);
final CustomDateDetector startEvent =
+
final CustomDateDetector startEvent = new CustomDateDetector(startDate, MAXCHECK, THRESHOLD, Action.STOP);
  new CustomDateDetector(startDate, maxCheck, threshold, Action.STOP);
+
final double dur = 1000.;
final GenericCodingEventDetector startEventCoding =
+
final AbsoluteDate endDate = startDate.shiftedBy(dur);
  startEvent.getGenericCodingEventDetector("start", "start");
+
final CustomDateDetector stopEvent = new CustomDateDetector(endDate, MAXCHECK, THRESHOLD, Action.STOP);
final double thrustDuration = 1000.;
+
 
+
final AbsoluteDate endDate = startDate.shiftedBy(thrustDuration);
+
final CustomDateDetector stopEvent =
+
  new CustomDateDetector(endDate, maxCheck, threshold, Action.STOP);
+
final GenericCodingEventDetector stopEventCoding =
+
  stopEvent.getGenericCodingEventDetector("stop", "stop");
+
 
+
 
final Vector3D direction = new Vector3D(-1., 0., 0.);
 
final Vector3D direction = new Vector3D(-1., 0., 0.);
final CustomConstantManeuver cont =
+
CustomConstantManeuver cont =
  new CustomConstantManeuver("Continuous maneuver", engine, tank, LOFType.TNW,
+
    new CustomConstantManeuver("Continuous maneuver", listOfEngines.get(0), listOfTanks.get(0), LOFType.TNW, startEvent, stopEvent, direction, mm);
                              startEvent, startEventCoding, stopEvent, stopEventCoding,
+
                              direction, mm);
+
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Ligne 243 : Ligne 214 :
  
 
It is mandatory to get at least one attitude law. With the V11.0, it is not possible to have only one law and it is mandatory to use the “switch” possibility by using the [[https://logiciels.cnes.fr/en/node/62?type=desc PATRIUS]] <font color=#4169E1>AttitudesSequence</font> class.
 
It is mandatory to get at least one attitude law. With the V11.0, it is not possible to have only one law and it is mandatory to use the “switch” possibility by using the [[https://logiciels.cnes.fr/en/node/62?type=desc PATRIUS]] <font color=#4169E1>AttitudesSequence</font> class.
 +
 +
This example shows how to define a single law (available since V11.1):
 +
 +
<syntaxhighlight lang="java">
 +
final AttitudeLaw attitudeLaw = new LofOffset(LOFType.TNW);
 +
</syntaxhighlight>
 +
 +
This other example uses a switching possibility:
  
 
<syntaxhighlight lang="java">
 
<syntaxhighlight lang="java">
Ligne 254 : Ligne 233 :
 
</syntaxhighlight>
 
</syntaxhighlight>
  
<font color=#FF0000>''Note : be very careful not to use by default constructors for event detectors as they introduce a STOP event, so your propagation will stop anyway !''</font>
+
''<font color=#FF0000>'''Note : be very careful not to use by default constructors for event detectors as they introduce a STOP event, so your propagation will stop anyway !'''</font>''
  
 
== Integration ==
 
== Integration ==
  
Then integration data have to be defined. Here an example with <font color=#FF8C00>RK4</font> integrator …
+
Then integration data have to be defined. Here an example with <font color=#FF8C00 title="Runge Kutta 4th order">RK4</font> integrator …
  
 
<syntaxhighlight lang="java">
 
<syntaxhighlight lang="java">
 
final double duration = 86400.;
 
final double duration = 86400.;
 
final double hStop = 120.e+3;
 
final double hStop = 120.e+3;
final PsimuPropagationData propagationData =
+
final PsimuPropagationData propagationData = new PsimuPropagationData(duration, GCRF, hStop);
  new PsimuPropagationData(duration, GCRF, hStop);
+
 
final double step = 5.;
 
final double step = 5.;
 
final RK4data integrationData = new RK4data(propagationData, step);
 
final RK4data integrationData = new RK4data(propagationData, step);
<syntaxhighlight>
+
</syntaxhighlight>
  
 
… or with the <font color=#FF8C00>DOP</font> integrator …
 
… or with the <font color=#FF8C00>DOP</font> integrator …
Ligne 289 : Ligne 267 :
  
 
<syntaxhighlight lang="java">
 
<syntaxhighlight lang="java">
final Psimu test =
+
final Psimu test = new Psimu(iniOrbit, EARTH, UserFramesConfsEnum.IGNORE, integrationData, vehicle, mm, forces, manSeq, attitudeLaw);
  new Psimu(iniOrbit, EARTH, ONLY_PREC_NUT , integrationData, assembly, mm, forces, manSeq, seqAtt);
+
 
</syntaxhighlight>
 
</syntaxhighlight>

Version actuelle en date du 14 mai 2020 à 17:34

The main modifications between V11.3 and previous versions are due to the use of original PATRIUS classes rather than to use "Custom" classes originally proposed by GENOPUS. Anyway, some "Custom" classes still remain as PATRIUS classes are not sufficiently consistent.


Orbit

To initialize an orbit, we simply have to build it using [PATRIUS] object. For example:

final TimeScale TUC = TimeScalesFactory.getUTC();
final AbsoluteDate date = new AbsoluteDate("2010-01-01T12:00:00.000", TUC);       
final double sma = Constants.WGS84_EARTH_EQUATORIAL_RADIUS + 250.e3;
final double ecc = 0.;
final double inc = FastMath.toRadians(51.6);
final double raan = FastMath.toRadians(0.);
final double pa  = FastMath.toRadians(0.);
final double ano = FastMath.toRadians(0.);
final Frame GCRF = FramesFactory.getGCRF();
final KeplerianOrbit iniOrbit =
  new KeplerianOrbit(sma, ecc, inc, raan, pa, ano, PositionAngle.MEAN, GCRF, date, MU);

Earth features

Data equivalent to the “Earth features” tab are distributed via two arguments:

1. A ExtendedOneAxisEllipsoid object which will define the shape of the planet
final ExtendedOneAxisEllipsoid EARTH =
   new ExtendedOneAxisEllipsoid(REQ, FLAT, ITRF, "EARTH");
2. A type of enumerates that will propose some pre-defined configurations as:
  • NOTHING (all options set to null)
  • ONLY_PREC_NUT (only precession and nutation)
  • FACTORY (equivalent to the most complete definition as in the GUI)
  • IGNORE (nothing is define internally by PSIMU which will take into account the user parametrization previously done)

Vehicle

Since V11.3, it is no more necessary to pass an Assembly object but a Vehicle one. Anyway, it is allways mandatory to pass a MassProvider object, issued from the Vehicle one. It could seem curious but it is due to the fact that, if we have maneuvers, it will be mandatory to initialize them with the same MassProvider (see example here).

In fact, we need to pass both an Assembly and a MassProvider. It could seem curious but it is due to the fact that, if we have maneuvers, it will be mandatory to initialize them with the same MassProvider (see example here). To get them, we will use the createAssembly() method given by Vehicle class.

final Assembly assembly = vehicle.createAssembly(GCRF);
final MassProvider mm = new MassModel(assembly);

Note : for CPU time purpose it is recommanded that the frame (GCRF in the previous example), mandatory in the construction of the vehicle, must be exactly the same that the one used for the propagation.

In the example below, we will then use the Vehicle class initializing mass and aerodynamic properties (here no engines and no tanks):

// Dry mass
final double dryMass = 1000.;
final MassProperty dryMassProperty = new MassProperty(dryMass);
 
// Shape
final double sref = 5.0;
Sphere sphere = new Sphere(sref);
final RightParallelepiped solarPanels = new RightParallelepiped(10., 0., 0.);
VehicleSurfaceModel vehicleRefSurface = new VehicleSurfaceModel(sphere, solarPanels);
 
// Aerodynamic properties
final double cd = 2.0;
final double cl = 0.;
final AerodynamicProperties aerodynamicProperties = new AerodynamicProperties(vehicleRefSurface, cd, cl);
 
final Vehicle vehicle = new Vehicle(vehicleRefSurface, null, dryMassProperty, aerodynamicProperties, null, null, null);
 
final Assembly assembly = vehicle.createAssembly(GCRF);
final MassProvider mm = new MassModel(assembly);

Note : due to a PATRIUS anomaly, if the user needs to define solar panels characteristics, it is mandatory to use the Vehicle constructor with all parameters and the VehiculeSurfaceModel including the panels as above (and not a list of Facet); also, do not use the setters methods.

Forces

Since V11.3, to define, which forces will be applied along the trajectory, we use the PATRIUS ForceModelsData class (no more necessary to use the specific CustomForceModels class which does not exist anymore).

Potential

In the following example, we will initialize the potential model (mandatory).

// Potential
final ForceModel potential = EarthGravitationalModelFactory.getDroziner(GravityFieldNames.GRGS, "grim4s4_gr", 8, 8, true);
 
final ForceModelsData forces = new ForceModelsData(potential, null, null, null, null, null, null, null, null, null, null, null, null,  null, null);

Aerodynamic

Then we could add an aerodynamic force model. Since V11.3, it is no more necessary to use "Custom" classes.

final double REQ  = Constants.WGS84_EARTH_EQUATORIAL_RADIUS;
final double FLAT = Constants.WGS84_EARTH_FLATTENING;
final Frame ITRF = FramesFactory.getITRF();
final ExtendedOneAxisEllipsoid EARTH =
   new ExtendedOneAxisEllipsoid(REQ, FLAT, ITRF, "EARTH");
 
final Atmosphere atmosphere = new US76(EARTH);
final DragForce dragForce = new DragForce(1., atmosphere, assembly);
 
forces.setDragForce(dragForce);

Solar radiative pressure

Here are explained how to use both radiative pressure and rediffused radiative pressure force models. Again, since V11.3, no more tu use old "Custom" classes.

final CelestialBody sunBody = new MeeusSun();
final double dRef = 1.4959787E11;
final double pRef = 4.5605E-6;
final ExtendedOneAxisEllipsoid EARTH =
   new ExtendedOneAxisEllipsoid(REQ, FLAT, ITRF, "EARTH");
 
SolarRadiationPressureEllipsoid radPres = new SolarRadiationPressureEllipsoid(dRef, pRef, sunBody, EARTH, assembly, 1.);
 
forces.setSolarRadiationPressure(radPres);
 
// By default values used when GUI mode ...
final int inCorona = 1;
final int inMeridian = 10;
final IEmissivityModel inEmissivityModel = new KnockeRiesModel();
// Value accessible via GUI mode
final boolean inAlbedo = false;
final boolean inIr = false;
final double coefAlbedo = 1.;
final double coefIr = 1.;
 
RediffusedRadiativeModel rdm = new RediffusedRadiativeModel(inAlbedo, inIr, coefAlbedo, coefIr, assembly);
RediffusedRadiationPressure reDiff =  new RediffusedRadiationPressure(sunBody, GCRF, inCorona, inMeridian, inEmissivityModel, rdm);
 
forces.setRediffusedRadiationPressure(reDiff);

Specific forces

It is also possible to add specific forces via the addForceModel() method as below:

final Psimu test = new Psimu(...);
test.addForceModel(myForce);

Maneuvers

If the user wants to add some maneuvers, it will have to do it using the [GENOPUS] Custom ManeuverSequence class. Indeed, this class is derivated from the PATRIUS ManeuverSequence but allows taking into account Engines and Tanks notion. From [PATRIUS] V3.4, it will be possible to directly use [PATRIUS] class.

Propulsive properties

First, the user will have to define propulsive properties with engine(s) and tank(s).

// Propulsive properties
final PropulsiveProperty engine = new PropulsiveProperty(400, 320.);
engine.setPartName("ENGINE");
final ArrayList<PropulsiveProperty> listOfEngines = new ArrayList<PropulsiveProperty>();
listOfEngines.add(engine);
final TankProperty tank = new TankProperty(200.);
tank.setPartName("TANK");
final ArrayList<TankProperty> listOfTanks = new ArrayList<TankProperty>();
listOfTanks.add(tank);
listOfTanks.add(tank);
 
final Vehicle vehicle = new Vehicle(vehicleRefSurface, null, dryMassProperty, null, null, listOfEngines, listOfTanks);

Sequence

Then, a maneuver sequence will be created thanks to the CustomManeuverSequence (the [PATRIUS] ManeuverSequence is not directly used as it does not still manage events.

Impulsive maneuver

Here we have an example of a 10m/s impulse maneuver in TNW occuring for an AOL of 180 degrees:

final double aol = FastMath.toRadians(180.);
final CustomAOLDetector aolDetector = new CustomAOLDetector(aol, PositionAngle.TRUE, GCRF, MAXCHECK, THRESHOLD, Action.STOP);
final IntervalOccurrenceDetectorWrapper impEvent = new IntervalOccurrenceDetectorWrapper(aolDetector, 1, 1, 1, Action.STOP);
final Vector3D deltaV = new Vector3D(10., 0., 0.);
final CustomImpulseManeuver imp = new CustomImpulseManeuver("Impulse maneuver", listOfEngines.get(0), listOfTanks.get(0), LOFType.TNW, impEvent, deltaV, mm);

Note: it is mandatory to configure the event with a STOP action (needed by [PATRIUS]).

At last, the user will create the maneuver sequence to pass to PSIMU:

final CustomManeuverSequence manSeq = new CustomManeuverSequence(0., 0.);
manSeq.addManeuver(imp);

Constant thrust maneuver

The next source code shows how to define a constant thrust maneuver …

final double start = iniOrbit.getKeplerianPeriod();
final AbsoluteDate startDate = date.shiftedBy(start);
final CustomDateDetector startEvent = new CustomDateDetector(startDate, MAXCHECK, THRESHOLD, Action.STOP);
final double dur = 1000.;
final AbsoluteDate endDate = startDate.shiftedBy(dur);
final CustomDateDetector stopEvent = new CustomDateDetector(endDate, MAXCHECK, THRESHOLD, Action.STOP);
final Vector3D direction = new Vector3D(-1., 0., 0.);
CustomConstantManeuver cont =
    new CustomConstantManeuver("Continuous maneuver", listOfEngines.get(0), listOfTanks.get(0), LOFType.TNW, startEvent, stopEvent, direction, mm);

Attitude

It is mandatory to get at least one attitude law. With the V11.0, it is not possible to have only one law and it is mandatory to use the “switch” possibility by using the [PATRIUS] AttitudesSequence class.

This example shows how to define a single law (available since V11.1):

final AttitudeLaw attitudeLaw = new LofOffset(LOFType.TNW);

This other example uses a switching possibility:

final AttitudeLaw law = new LofOffset(LOFType.TNW, RotationOrder.ZYX, 0., 0., 0.);
final double maxCheck = AbstractDetector.DEFAULT_MAXCHECK;
final double threshold = AbstractDetector.DEFAULT_THRESHOLD;
final EventDetector event =
   new DateDetector(date, maxCheck, threshold, Action.RESET_STATE);
final AttitudesSequence seqAtt = new AttitudesSequence();
seqAtt.addSwitchingCondition(law, event, true, false, law);

Note : be very careful not to use by default constructors for event detectors as they introduce a STOP event, so your propagation will stop anyway !

Integration

Then integration data have to be defined. Here an example with RK4 integrator …

final double duration = 86400.;
final double hStop = 120.e+3;
final PsimuPropagationData propagationData = new PsimuPropagationData(duration, GCRF, hStop);
final double step = 5.;
final RK4data integrationData = new RK4data(propagationData, step);

… or with the DOP integrator …

final double minStep = 0.1;
final double maxStep = 30.;
final double[] vecAbsoluteTolerance =
   { 1.0E-5, 1.0E-5, 1.0E-5, 1.0E-8, 1.0E-8, 1.0E-8 };
final double[] vecRelativeTolerance =
   { 1.0E-8, 1.0E-8, 1.0E-8, 1.0E-8, 1.0E-8, 1.0E-8 };
final double absMassTolerance = 1.0E-3;
final double relMassTolerance = 1.0E-2;
final double positionError = 0.;
final DopData intData = new DopData(propagationData, minStep, maxStep, vecAbsoluteTolerance, vecRelativeTolerance, absMassTolerance, relMassTolerance);

PSIMU object

As we have all mandatory data to initialize PSIMU, we can build such an object (note that in this example there is a “null” argument for the sequence of maneuvers.

final Psimu test = new Psimu(iniOrbit, EARTH, UserFramesConfsEnum.IGNORE, integrationData, vehicle, mm, forces, manSeq, attitudeLaw);