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)