Hi @evan.ward thanks a lot for your kind help. I’ve changed the return value of my custom PassCounter
to Action.RESET_EVENTS
from Action.CONTINUE
- is this what you’ve had in mind? Even after the change, I still get different results depending on the order in which I create handlers. The only difference is that now eclipseDetectorWithPassCounter
has to be after eclipseDetectorWithLogger
. I’m not sure if this is an indication of a larger issue?
Also, I see where you’re going with this, thanks for the idea. It didn’t cross my mind to communicate between detectors and handlers like this:
if (increasing) {
durationDetector.stop(s.getDate()); // Let the durationDetector know when eclipse starts/ends so that the duration event can be found by the propagator
} else {
durationDetector.start(s.getDate());
}
return Action.RESET_EVENTS;
}));
I’ve implemented this but with a custom handler (I don’t think Python supports lambda detectors, see this post). Unfortunately, it falls over when I try to attach this ElapsedTimeHandler
to the EclipseDetector
with the following error:
InvalidArgsError: (<class 'org.orekit.propagation.events.EclipseDetector'>, 'withHandler', <ElapsedTimeHandler: java.lang.Object@25f7391e>)
I’m not sure why this is the case because the custom handler is nearly identical to my PassCounter
, which works. Any ideas what might be wrong? I’ve put my changed code here below.
class PassCounter(PythonEventHandler):
""" Counts events. Will stop propagation after first n events."""
def __init__(self, limit):
self.limit = limit
self.passesInc = 0
self.passesDec = 0
super(PassCounter, self).__init__()
def init(self, initialState, target):
# Not used, just to try and port functionality from ElapsedTimeCounter.
self.startEpoch = initialState.getDate() #TODO 'PassCounter' object has no attribute 'startEpoch'?
self.elapsedSec = 0.0 #TODO: 'PassCounter' object has no attribute 'elapsedSec'?
super(PassCounter, self).init() # Doesn't affect the odd attribute errors.
#TODO for whatever reason, init is never called. This is why I had cryptic Java errors in ElapsedTimeCounter - because attributes were undefined!
def eventOccurred(self, s, T, increasing):
if increasing:
self.passesInc = self.passesInc + 1
print(f'Increasing pass at {s.getDate()}, passes = {self.passesInc}')
else:
self.passesDec = self.passesDec + 1
print(f'Decreasing pass at {s.getDate()}, passes = {self.passesDec}')
# Just as an example, stop propagation after some no. events.
if self.passesInc >= self.limit and self.passesDec >= self.limit:
return Action.STOP
else:
return Action.RESET_EVENTS # Check other event detectors, not simply continue.
def resetState(self, detector, oldState):
return oldState
class ElapsedTimeDetector(PythonAbstractDetector):
""" Counts the elapsed time since a decreasing event, and triggers and event
when the elapsed time reaches a predefined limit. Inspired by this:
https://forum.orekit.org/t/eventdetection-based-on-time-in/293
"""
def __init__(self, target, handler=None):
self.target = target
self.startEpoch = None
self.elapsedSec = 0.0
dmax = float(PythonAbstractDetector.DEFAULT_MAXCHECK)
dthresh = float(PythonAbstractDetector.DEFAULT_THRESHOLD)
dmaxiter = PythonAbstractDetector.DEFAULT_MAX_ITER
if handler is None:
handler = ContinueOnEvent().of_(ElapsedTimeDetector)
super(ElapsedTimeDetector, self).__init__(dmax, dthresh, dmaxiter, handler) #super(maxCheck, threshold, maxIter, handler);
def init(self, initialState, target):
pass
def g(self, s):
if self.startEpoch is None:
add = 0.0
else:
add = s.getDate().durationFrom(self.startEpoch)
return self.elapsedSec - self.target + add
def start(self, d):
self.startEpoch = d
def stop(self, d):
self.elapsedSec += d.durationFrom(self.startEpoch)
self.startEpoch = None
class ElapsedTimeHandler(PythonEventHandler):
""" Handler for EclipseDetector that also marks start/stop times in ElapsedTimeDetector. """
def __init__(self):
super(PythonEventHandler, self).__init__()
def init(self, initialState, target):
pass
def setDetector(self, elapsedDetector):
self.elapsedDetector = elapsedDetector
def eventOccurred(self, s, T, increasing):
if increasing:
self.elapsedDetector.start(s.getDate())
print(f'Increasing pass at {self.elapsedDetector.startEpoch}')
else:
self.elapsedDetector.stop(s.getDate())
print(f'Increasing pass at {self.elapsedDetector.startEpoch}, duration = {self.elapsedHandler.elapsedSec}')
return Action.RESET_EVENTS # Check other event detectors, not simply continue.
def resetState(self, detector, oldState):
return oldState
(…)
#%% Configure the propagator events
passCounter = PassCounter(limit=MAX_ECLIPSES)
elapsedTimeDetector = ElapsedTimeDetector(100.0)
elapsedTimeHandler = ElapsedTimeHandler()
elapsedTimeHandler.setDetector(elapsedTimeDetector)
logger = EventsLogger()
propagator.addEventDetector(elapsedTimeDetector)
#TODO eclipseDetectorWithElapsedHandler fails to instantiate due to InvalidArgsError in withHandler???
eclipseDetectorWithElapsedHandler = EclipseDetector(sun, Constants.SUN_RADIUS, earth).withUmbra().withHandler(elapsedTimeHandler)
#TODO eclipseDetectorWithPassCounter has to be here for eclipseDetectorWithLogger to work properly. Otherwise, we get 9 logged events.
eclipseDetectorWithLogger = EclipseDetector(sun, Constants.SUN_RADIUS, earth).withUmbra().withHandler(ContinueOnEvent())
loggedDetector = logger.monitorDetector(eclipseDetectorWithLogger)
propagator.addEventDetector(loggedDetector)
#TODO After changing from Action.CONTINUE to RESET_EVENTS had to move the eclipseDetectorWithPassCounter to the end. Why?
eclipseDetectorWithPassCounter = EclipseDetector(sun, Constants.SUN_RADIUS, earth).withUmbra().withHandler(passCounter)
propagator.addEventDetector(eclipseDetectorWithPassCounter)