Pass over a point prediction using TLE data

I’m trying to predict the passage of a CubeSat over a certain point (lat, long) on ground, I’ve taken some inspiration from orekit tutorial “VisibilityCheck" and some other examples in the forum and written below code.
It gives correct latitude and longitude for the satellite at any point of time captured in the Elevation detector event.
I have verified it for ISS (ZARYA).

 final Frame earthFrame = FramesFactory.getITRF(IERSConventions.IERS_2010, true);

        //define earth as main body
        final OneAxisEllipsoid earth = new OneAxisEllipsoid(equatorialRadius, flattening, earthFrame);
        //the SGP4 documentation says that the frame shall be TEME
        final Frame satelliteFrame = FramesFactory.getTEME();

        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //convert AOI coordinates to Geodetic points.
        final GeodeticPoint reno = new GeodeticPoint(FastMath.toRadians(latitude), FastMath.toRadians(longitude), altitude);
        //define a topocentric frame
        final TopocentricFrame topo = new TopocentricFrame(earth, reno, AOI)

        final AttitudeProvider attitudeProvider = new LofOffset(satelliteFrame, LOFType.VVLH);

        // Event definition
        final double maxcheck  = 60.0;
        final double threshold =  1.e-6;
        final double elevation = FastMath.toRadians(10.0);
        final EventDetector sta1Visi =
                new ElevationDetector(maxcheck, threshold, topo)
                        .withConstantElevation(elevation)
                        .withHandler((s, detector, increasing) -> {
                            PVCoordinates pvCoordinates = s.getPVCoordinates(earthFrame);
                            GeodeticPoint geodeticPoint = earth.transform(pvCoordinates.getPosition(),earthFrame, s.getDate());
                            // lat lon of propagated point
                            double lat = FastMath.toDegrees(geodeticPoint.getLatitude());
                            double lon = FastMath.toDegrees(geodeticPoint.getLongitude());

                            // azimuth and elevation of propagated point
                            final double azimuth = FastMath.toDegrees(topo.getAzimuth(pvCoordinates.getPosition(), earthFrame, s.getDate()));
                            final double ele = FastMath.toDegrees(topo.getElevation(pvCoordinates.getPosition(), earthFrame, s.getDate()));

                            System.out.println("Propagated at " + s.getDate() + ": lat=" + lat + "; lon=" + lon + "; azimuth=" + azimuth + "; elevation=" + ele);

                            System.out.println(" Visibility on " +
                                    detector.getTopocentricFrame().getName() +
                                    (increasing ? " begins at " : " ends at ") +
                                    s.getDate());
                            return Action.CONTINUE;
                        });


        final TLE tle = new TLE(line1, line2);

        //new propagator
        final SGP4 propagator = new SGP4(tle, attitudeProvider, mass, satelliteFrame);

        EventsLogger logger = new EventsLogger();
        propagator.addEventDetector(logger.monitorDetector(sta1Visi));
        try {
            propagator.propagate(new AbsoluteDate(formatter.parse(startTime), TimeScalesFactory.getUTC()), new AbsoluteDate(formatter.parse(endTime), TimeScalesFactory.getUTC()));
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }

This code gives a pair of events for beginning and end of passes for a constant elevation (10 degree here).

Propagated at 2023-08-22T11:17:12.79863974561675Z: lat=27.62489174851167; lon=-115.32453184851641; azimuth=161.19866462895507; elevation=9.999999997707407
 Visibility on Reno begins at 2023-08-22T11:17:12.79863974561675Z
Propagated at 2023-08-22T11:20:45.20479290591206Z: lat=36.953273739554064; lon=-104.24420797397191; azimuth=96.94249600356848; elevation=10.000000000034794
 Visibility on Reno ends at 2023-08-22T11:20:45.20479290591206Z

However, I’m unable to find the maximum elevation for these passes. Is it possible to attach multiple detectors to a propagator?
Also, what the values maxCheck and threshold meant for , if anyone can point me in the right documentation.
Ultimately, I want to predict the passage over an area for remote-sensing. What detector should be used there, or maybe some example for covering an area rather than a single point on the ground.

Hi @shresthdeepgupta

Welcome to the Orekit forum.

Of course! The addEventDetector() merthod can be called multiple times. Please find an example developed by Luc showing how to add both an ElevationDetector and an ElevationExtremumDetector to your propagator (Comparing Access Time Analysis SGP4:STK and OreKit - #6 by luc)

In order to explain what those parameters represent, it is important to know how event detection is based in Orekit. Each event detectors in Orekit are represented by a function. We call it the g function. For instance, for an ElevationDetector, the function is the difference between the satellite elevation and the elevation threshold initialized by the user. An event is detected when the sign of the g function change.
Depending the integrator step, the change of the sign is first detected with a poor accuracy. So, Orekit (and Hipparchus) will improve the event detection epoch with a small dichotomy around the detection epoch. The parameter threshold represents the convergence threshold in the event time search. And the parameter maxCheck represents the time interval for the search.

For this you can use GeographicZoneDetector.

Best regards,
Bryan

@bcazabonne Thanks for this brief explanation. Really gave a good insight.
I’ll try to use GeographicalZoneDetector and get back if I have any doubts.