Inter-Satellite Link Computation

Vincent,

To be clear, when you say “use the satellites TLEs to build your detectors”, you mean the “TLEPropagator” object for the secondary satellites? I do this, and I “allEphemeris.addEventDetector(isl)”, and propagate the “propagators” object? Propagating either “allEphemeris” or “propagators” gives me an inifinite loop, but no recursion warning this time.

I think I follow the logic and it is sound to me. However, I am confused as to why I still have that infinite loop. There is no recursion warning as before, but the code runs infinitely. I attahced my code again, I’ve added the event handler to this script so its more clear.

Thank you, Franco

        // create propagators for each sat, and create ephemeris generators from every propagator
        List<Propagator> propagators = new ArrayList<>();
        List<EphemerisGenerator> ephemerisGenerators = new ArrayList<>();
        List<Propagator> allEphemeris = new ArrayList<>();

        for (TLE tle : TLE_list) {
            TLEPropagator Prop = TLEPropagator.selectExtrapolator(tle);
            Prop.setAttitudeProvider(new NadirPointing(inertialFrame, earth));
            propagators.add(Prop);
            ephemerisGenerators.add(Prop.getEphemerisGenerator());
        }

        // propagate parallelizer to generate all ephemeris for all satellites
        PropagatorsParallelizer propagatorParallelizer1 = new PropagatorsParallelizer(propagators, new DistanceHandler(60));
        propagatorParallelizer1.propagate(begin_date, final_date);

        // retrieve ephemeris data from all generators
        for (EphemerisGenerator ephemerisGenerator : ephemerisGenerators) {
            allEphemeris.add(ephemerisGenerator.getGeneratedEphemeris());
        }

        // create lists containing lists of events for all satellites
        List<List<AbsoluteDate>> startTimes = new ArrayList<>();
        List<List<AbsoluteDate>> endTimes = new ArrayList<>();

        for (int i = 0; i < propagators.size(); i++) {

            allEphemeris.get(i).clearEventsDetectors();

            final double maxcheck = 60;  // Checking every x second
            final double threshold = 0.001; //Convergence to 0.001 seconds

            for (int j = 0; j<TLE_list.size(); j++) {

                if (TLE_list.get(i).getSatelliteNumber() == TLE_list.get(j).getSatelliteNumber()) {
                    continue;
                }

                List<AbsoluteDate> start = new ArrayList<>();
                List<AbsoluteDate> end = new ArrayList<>();

                final InterSatDirectViewDetector isl = new InterSatDirectViewDetector(earth, propagators.get(j));
                isl.withMaxCheck(maxcheck).withThreshold(threshold).withHandler((s, detector, increasing) -> {
                    if (increasing) {
                        start.add(s.getDate());
                    } else {
                        end.add(s.getDate());
                    }
                    return Action.CONTINUE;
                });
                allEphemeris.get(i).addEventDetector(isl);
                startTimes.add(start);
                endTimes.add(end);
           }

        }

        // propagate ephemeris to generate events
        PropagatorsParallelizer propagatorsParallelizer2 = new PropagatorsParallelizer(allEphemeris, new DistanceHandler(60));
        propagatorsParallelizer2.propagate(begin_date, final_date);

Franco,

Exactly

Propagate the ephemeris as this is where you added your detectors

Also, i fixed some of your provided code and added my own comments on part that need further work:

I’m also confused about this, could you pinpoint the location of the infinite loop ? I will take a fresh look at it tomorrow but it should work.

Vincent,

When I propagate the second paralellizer, there are no errors or warnings as before, however the code doesn’t seem to finish running. I am only using two satellites and 3 day simulation time, so I would assume it should be fast. I am attaching the code again below for your convenience.

Thank you, Franco

        // create propagators for each sat, and create ephemeris generators from every propagator
        List<Propagator> propagators = new ArrayList<>();
        List<EphemerisGenerator> ephemerisGenerators = new ArrayList<>();
        List<Propagator> allEphemeris = new ArrayList<>();

        for (TLE tle : TLE_list) {
            TLEPropagator Prop = TLEPropagator.selectExtrapolator(tle);
            Prop.setAttitudeProvider(new NadirPointing(inertialFrame, earth));
            propagators.add(Prop);
            ephemerisGenerators.add(Prop.getEphemerisGenerator());
        }

        AbsoluteDate begin_date = TLE_list.get(1).getDate();
        AbsoluteDate final_date = begin_date.shiftedBy(simTime); // End date of propagation(Orekit)

        // propagate parallelizer to generate all ephemeris for all satellites
        PropagatorsParallelizer propagatorParallelizer1 = new PropagatorsParallelizer(propagators, new DistanceHandler(60));
        propagatorParallelizer1.propagate(begin_date, final_date);

        // retrieve ephemeris data from all generators
        for (EphemerisGenerator ephemerisGenerator : ephemerisGenerators) {
            allEphemeris.add(ephemerisGenerator.getGeneratedEphemeris());
        }

        // create lists containing lists of events for all satellites
        List<List<EventDetector_Constructor.Event_Manager>> ISL_events = new ArrayList<>(); // list of ground station detections

        final double maxcheck = 60;  // Checking every x second
        final double threshold = 0.001; //Convergence to 0.001 seconds

        for (int i = 0; i < propagators.size(); i++) {

            List<EventDetector_Constructor.Event_Manager> ISL_events_current = new ArrayList<>();

            for (int j = i+1; j<TLE_list.size(); j++) {

                if (TLE_list.get(i).getSatelliteNumber() == TLE_list.get(j).getSatelliteNumber()) {
                    continue;
                }

                EventDetector_Constructor.Event_Manager add_event_detector = EventDetector_Constructor.getEvent_ISL(maxcheck, threshold
                        , String.valueOf(TLE_list.get(j).getSatelliteNumber()), propagators.get(j)); // constructs event
                allEphemeris.get(i).addEventDetector(add_event_detector.event_detector); // propagates event
                ISL_events_current.add(add_event_detector); // adds event to list

            }
            ISL_events.add(ISL_events_current);

        }

        // propagate ephemeris to generate events
        PropagatorsParallelizer propagatorsParallelizer2 = new PropagatorsParallelizer(allEphemeris, new DistanceHandler(60));
        propagatorsParallelizer2.propagate(begin_date, final_date);

You seem to reuse the propagators twice.
The first use is when you put them in new PropagatorsParallelizer(propagators, new DistanceHandler(60)) and the second use is when you add them to the detector, calling propagators.get(j). The propagators you put in the propagators parallelizer should not be used anywhere else, they should be built for the parallelizer and are only managed by it.

Here is some additional information that may help you understand what happens.
Propagators are not just functions you call without any side effects. They do maintain some internal state, and they do register some kind of feedback functions (step handlers, events detectors) that are passed to them before they are run. This means that calling propagators in loops, or reusing propagators, or using propagators in multi-threaded environments should be attempted with care.
The propagators parallelizer does register its own specific step handler for all propagators it manages, it uses this to synchronize the propagators together. So once this handler has been added to them, when these propagators are called this step handler is called and the parallelizer as well as all other sibling propagators will have some kind of interaction. So when you reuse propagator.get(j), you get a step handler that you do not want, and it interacts badly with the rest of the code.

The easiest way to have reproducible behaviour is to just build one propagator when you need one, use it, and drop it afterwards. A TLE propagator is just a few hundred of bytes, simple to build, simple to discard. If you need to rerun propagation 1000 times on the same TLE, just build 1000 propagators in row from this single TLE, don’t try to reuse the propagators.

Yet another point on your example.
In the case of analytical propagators (and TLEPropagator is an analytical propagator), building an ephemeris from a propagator is not really useful. In fact, in this case, the ephemeris is just a wrapper around the analytical propagator itself. Building ephemeris is interesting in order to convert a numerical propagator into an analytical one, at the expense of memory usage.

So in your case, I would just go with building and rebuilding TLE propagators and use them directly. You just need to propagate once (i.e. use only one PropagatorParallelizer), but taking care that the event detectors do not use the same propagators the parallelizer uses. So at the end you will have something like parallelizer holds propagators 1, 2 and 3, directly built from TLE A, B and C. Propagator 1 event detectors reference propagators 4 and 5 built also from TLE B and C, propagator 2 event detectors reference propagators 6 and 7 built from TLE A and C, propagator 3 event detectors reference propagators 8 and 9 built from TLE A and B. So at the end you have 3 main propagators and 6 sub-propagators, so 9 propagators in all, built from 3 TLEs. Well in fact you could reduce this to only 3 sub-propagators, but the logic would be more complex and not worth the extra work, just build 6 sub-propagators, it is more straightforward.

Luc,

Thank you for all your help, we have events!! I also tried what you said about the pehemeris and it does indeed work without the need for ephemeris. And also thank you for the explanation about the propagators, I am pretty bad at JAVA so the logic flow is a bit alien to me.

Thank you, Franco

Good job :+1: !

Thanks Luc for your insight ! I suggested ephemeris because i thought that, even though both of them are analytical, an interpolation would still be faster than the computation of the TLE analytical model and also this would make things “clearer” by being different.

UPDATE: My bad, when generating an ephemeris from an analytical propagator, it returns the analytical propagator itself so my idea does not work :sweat_smile:

Cheers,
Vincent