[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Orekit Developers] Resetting Additional States in Event Handler



Hi Luc,

The bug report has been created (https://www.orekit.org/forge/issues/483)

Many thanks again for all your support,

Frank

On Mon, Jul 9, 2018 at 4:32 PM, MAISONOBE Luc <luc.maisonobe@c-s.fr> wrote:

Frank Mason <frankmason1992@gmail.com> a écrit :

Hi Luc,

Hi Frank,


Many thanks for your fast and constructive response, I have followed your
approached and it works (see full at the end of the email).

Yes, I will create a bug report for this.

I just have one additional question:

A) I have implemented the AdditionalStatesProvider not storing the event
epoch, but simply changing the value that should be provided. Is this
solution also valid?

It may fail in some cases. During propagation, the propagator handles
several close dates at once: the previous state, the current state
before checking event, the state at several potential occurrences times.
It basically has a sliding window of time. At some point near the end
of the current step handling, the propagator decides what should be the
next thing to do: finishing the step if there are no events, or triggering
the first event if some should occur before step end. Then it calls
event occurred and go forward in time. If only this happened, then your
approach would probably work as we took care to schedule things properly.

However, there are also step handlers. The limitation I mentioned before
is that the step handler for one step is called *after* the event handler
that ends this step. The reason for that is because the event handler could
return Action.STOP and therefore the step handler should be called with
isLast set to true as this will be the final step. So the step handlers
are always "late" with regard to the events handler. This is the part we
cannot change due to the isLast flag. IT is even worse for fixed step
handler because one full variable step can span over several fixed steps.
In your case, the event handlers is called at 00:00:03 but the fixed
step handlers at that time is still at 00:00:01 and so you see the
event, then the step ending at 00:00:02, then the step ending at 00:00:03,
you are already 2 steps late. If you want to output correct additional
states despite eventOccurred has already been called, you should remember
the date and be ready to be called (during the preparation of the call
to the step handler) with a date earlier.

One way to manage this kind of behaviour easily is to store the value
of the additional state using a TimeSpanMap<double[]> in your provider.
Then when eventOccured is called, you will just have to call the
addValidAfter() method of TimeSpanMap to register the fact that after
the specified date, a new double[] is valid. The TimeSpanMap will
remember all the history and get you the appropriate double[] for
any date. It works even if there are several changes.

hope this helps,
Luc



Thanks a lot,
Frank


public static class MyProvider implements AdditionalStateProvider {

private double value = -1;
@Override
public String getName() {
return "A";
}

@Override
public double[] getAdditionalState(SpacecraftState state) throws
OrekitException {
return new double[] {value};
}
public void setValue(double value) {
this.value = value;
}
}
public static class MyHandler implements EventHandler<DateDetector> {
private final MyProvider myProvider;

public MyHandler(MyProvider myProvider) {
this.myProvider = myProvider;
}
@Override
public Action eventOccurred(SpacecraftState s, DateDetector detector,
boolean increasing)
throws OrekitException {
myProvider.setValue(+1);
return Action.CONTINUE;
}
}
public static void main(String[] args) throws OrekitException {

// Load Orekit data
DataProvidersManager.getInstance()
.addProvider(new DirectoryCrawler(new File("OREKIT_DATA_PATH_HERE")));

// Build orbit
AbsoluteDate date0 = new AbsoluteDate(2000, 1, 1,
TimeScalesFactory.getUTC());
Orbit orbit = new KeplerianOrbit(7.1E6, 0, 0, 0, 0, 0, PositionAngle.TRUE,
FramesFactory.getGCRF(), date0,
Constants.WGS84_EARTH_MU);

// Build propagator
ODEIntegrator odeIntegrator = new DormandPrince853Integrator(1E-3, 1E3,
1E-6, 1E-6);
NumericalPropagator propagator = new NumericalPropagator(odeIntegrator);


// Create initial state and add it to the propagator
SpacecraftState initialState = new
SpacecraftState(orbit).addAdditionalState("A", -1);

propagator.setInitialState(initialState);
//Create provider and handler
MyProvider myProvider = new MyProvider();
EventHandler<DateDetector> myHandler = new MyHandler(myProvider);
// Create date detector and handler
DateDetector dateDetector = new
DateDetector(date0.shiftedBy(3)).withHandler(myHandler);

propagator.addEventDetector(dateDetector);
propagator.addAdditionalStateProvider(myProvider);

// Set the propagator mode
propagator.setMasterMode(1, new OrekitFixedStepHandler() {

@Override
public void handleStep(SpacecraftState currentState, boolean isLast) throws
OrekitException {
String line = currentState.getDate().toString();

for (Entry<String, double[]> entry :
currentState.getAdditionalStates().entrySet()) {
line += " " + entry.getKey();

for (double d : entry.getValue()) {
line += " " + d;
}
}
System.out.println(line);
}
});

// Propagate
propagator.propagate(date0, date0.shiftedBy(5));
}




On Mon, Jul 9, 2018 at 3:00 PM, MAISONOBE Luc <luc.maisonobe@c-s.fr> wrote:


Frank Mason <frankmason1992@gmail.com> a écrit :

Hi,


Hi Frank,


I am trying to use an Event Handler to reset an additional state (called
"A"), changing its value from -1 to +1 when the event is detected. The new
state built inside the handler contains the proper value (+1), however,
when the propagator goes on, it seems to ignore it and keeps its original
value of "-1". Console output looks like this:

*2000-01-01T00:00:00.000 A -1.0*
*2000-01-01T00:00:01.000 A -1.0*
*Additional state A set to +1*
*2000-01-01T00:00:02.000 A -1.0*


The value -1 at 00:00:02.000 is normal. The state is really changed
at 00:00:03.000. the fact the print statement from event handler
and the print statement from step handler are out of order is a
know limitation of Orekit which we cannot fix.

*2000-01-01T00:00:03.000 A -1.0*
*2000-01-01T00:00:04.000 A -1.0*


The value -1 at 00:00:03.000 *could* be considered normal, as at that
time the value changes, so both -1 or +1 could be acceptable.

The value -1 at 00:00:04.000 is a bug! It is due to the fact this
additional state as no corresponding provider. I.E. it was set up
un the initial state, but theaddAdditionalStateProvider method from
the Propagator interface was never called. Therefore, the propagator
considers the additional state is fixed and that when creating
complete states throughout the propagation it simply copies the
value from initial state. This is done in the protected method
updateAdditionalStates in the AbstractPropagator class.

Could you file a bug on the forge so we do not forget to fix this?

You may try as a workaround to set up an AdditionalStateProvider and
in the eventOccurred event of your event handler, you could remember
the date of the last switch, and return either -1 or +1 depending on
the state date being before or after the switch date. Beware that
the AdditionalStateProvider.getAdditionalState method *could*
potentially be called out of order, so you really should store
the event date and use it.


* // Instantiate additional states*
* Map<String, double[]> additionalStates = new HashMap<String,
double[]>();*
* additionalStates.put("A", new double[] { -1 });*

* // Create initial state and add it to the propagator*
* SpacecraftState initialState = new SpacecraftState(orbit,
additionalStates);*


Rather than dealing directly with Map, I would suggest that you use
the fluent API of Spacecraftstate and directly use:


SpacecraftState initialState = new SpacecraftState(orbit).addAdditionalState("A",
-1);


* @Override*
* public SpacecraftState resetState(DateDetector detector, SpacecraftState
oldState) {*
* Map<String, double[]> newAdditionalStates = new HashMap<String,
double[]>();*
* newAdditionalStates.put("A", new double[] { +1 });*

* SpacecraftState newSpacecraftState = new
SpacecraftState(oldState.getOrbit(), oldState.getAttitude(),*
* oldState.getMass(), newAdditionalStates);*

* System.out.println("Additional state A set to +1");*
* return newSpacecraftState;*
* }*
* });*


Here, creating the Map by yourself is probably an error. It assumes there
are
no other additional states. If for example another part of the code had
added
another state (for example partial derivative equations in orbit
determination
do add some additional state by themselves), then these would be lost and
only
your "A" state would be present. You should really be

  public SpacecraftState resetState(DateDetector detector, SpacecraftState
oldState) {
      SpacecraftState newSpacecraftState = oldState.addAdditionalState("A",
+1);
      System.out.println("Additional state A set to +1 at " +
oldState.getDate());
      return newSpacecraftState;
  }

best regards,
Luc