JavaError in the propagate method of PropagatorsParallelizer

Hi Everyone,

I am playing with a script about the visibility of 2 Walker constellations from 2 ground stations using PropagatorsParallelizer. I have found the other script about PropagatorsParallelizer very helpful and was able to get my script running on my laptop. However, when I am launching the same script from my new desktop, I am hitting the following JavaError:

Traceback (most recent call last):
File “Test_TTC_Walker.py”, line 166, in
_ = parallelizer.propagate(extrap_date, final_date)
orekit.JavaError: <super: <class ‘JavaError’>, >
Java stacktrace:
java.lang.RuntimeException: TypeError
at org.orekit.propagation.sampling.PythonMultiSatStepHandler.handleStep(Native Method)
at org.orekit.propagation.PropagatorsParallelizer.propagate(PropagatorsParallelizer.java:180)

I did import the same conda env from my laptop to my desktop. Attached please find my code

Thanks!

Wenhao

import orekit
vm = orekit.initVM()

from orekit.pyhelpers import setup_orekit_curdir, absolutedate_to_datetime
setup_orekit_curdir()

from org.orekit.propagation.analytical.tle import TLE, TLEPropagator
from org.orekit.propagation.analytical import KeplerianPropagator
from org.orekit.propagation.events import ElevationDetector, EventsLogger
from org.orekit.propagation.events.handlers import ContinueOnEvent
from org.orekit.propagation import PropagatorsParallelizer, SpacecraftState, PythonAdditionalStateProvider
from org.orekit.propagation.sampling import PythonMultiSatStepHandler
from org.orekit.orbits import CartesianOrbit, KeplerianOrbit, OrbitType, PositionAngle
from org.orekit.frames import FramesFactory, TopocentricFrame
from org.orekit.utils import Constants, IERSConventions
from org.orekit.bodies import OneAxisEllipsoid, GeodeticPoint
from org.orekit.time import TimeScalesFactory, AbsoluteDate
from java.util import Arrays
from orekit import JArray_double

from math import pi, degrees, radians
import numpy as np
import datetime
import pandas as pd

config = pd.DataFrame()

config['constellation'] = [0, 1]
config['name'] = ['OneWeb', 'Galileo']
config['total'] = [588, 24]
config['plane'] = [12, 3]
config['f'] = [1, 1]
config['type'] = ['Star', 'Delta'] 

# https://celestrak.com/NORAD/elements/oneweb.txt: ONEWEB-0012 (LEO). Note that for Walker Star constellation, should use a seed satellite from "plane 1". Not sure if this choice is correct. However, it does not affect the conclusion from this simulation.
# https://celestrak.com/NORAD/elements/galileo.txt: GSAT0101 (MEO)
config['tle_line1_seed'] = ['1 44057U 19010A   21242.77040566  .00019687  00000-0  46314-1 0  9997',
                            '1 37846U 11060A   21242.30456699 -.00000070  00000-0  00000-0 0  9997']
config['tle_line2_seed'] = ['2 44057  87.4890 245.4230 0000321 339.7858  20.3264 13.23573112120926',
                            '2 37846  56.8763  29.2664 0001970  60.7596 299.2674  1.70475360 61250']

dt_utc_now = datetime.datetime.utcnow()
initial_date = AbsoluteDate(dt_utc_now.year,
                           dt_utc_now.month,
                           dt_utc_now.day,
                           dt_utc_now.hour,
                           dt_utc_now.minute,
                           0.0 + dt_utc_now.second,
                           TimeScalesFactory.getUTC())

extrap_date = initial_date
final_date = extrap_date.shiftedBy(3600. * 24 * 2) # 48hours

inertial_frame = FramesFactory.getEME2000()

earth_frame = FramesFactory.getITRF(IERSConventions.IERS_2010, True)
earth = OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
                         Constants.WGS84_EARTH_FLATTENING,
                         earth_frame)
                         
def TLEToKeplerian(prop, frame, date, mu):
    return KeplerianOrbit(OrbitType.KEPLERIAN.convertType(CartesianOrbit(prop.getPVCoordinates(date, frame), inertial_frame, date, mu)))

tle_seed = [TLE(config['tle_line1_seed'][i], config['tle_line2_seed'][i]) for i in range(len(config))]
config['prop_seed']  = [TLEPropagator.selectExtrapolator(tle) for tle in tle_seed]
config['orbit_kep_seed'] = config['prop_seed'].apply(lambda x: TLEToKeplerian(x, inertial_frame, extrap_date, Constants.WGS84_EARTH_MU))

ephemeris = pd.DataFrame(columns=['constellation', 'name', 'shell', 'plane', 'orbit'])

for i in range(len(config)):
    # These parameters are common among all satellites within a Walker constellation
    sma = config['orbit_kep_seed'][i].getA()
    eccentricity = config['orbit_kep_seed'][i].getE()
    inclination = config['orbit_kep_seed'][i].getI()

    pa = config['orbit_kep_seed'][i].getPerigeeArgument()
    
    # This is common among all satellites within a same plane. Offset by 2 * pi / p between planes for Walker Delta, and by pi / p for Walker star
    raan = config['orbit_kep_seed'][i].getRightAscensionOfAscendingNode()
    
    # This is offset by f * 2 * pi / t from west to east between planes, and by p * 2 * pi / t between neighboring satellites within a plane 
    true_anomaly = config['orbit_kep_seed'][i].getTrueAnomaly() # In Walker pattern, true anomaly is equally distributed
    
    is_walker_delta = (config['type'][i].lower() == "delta")
    n_sat_per_plane = int(config['total'][i] / config['plane'][i])
    for p in range(config['plane'][i]):
        if is_walker_delta:
            raan_tmp = float(raan + 2 * pi / config['plane'][i] * p)
        else:
            raan_tmp = float(raan + pi / config['plane'][i] * p)
            
        offset_true_anomaly = config['f'][i] * 2 * pi / config['total'][i] * p # Offset of true anomaly for the current plane w.r.t to the seed plane
        
        
        true_anomaly_tmp = [float(true_anomaly + offset_true_anomaly + j * config['plane'][i] * 2 * pi / config['total'][i]) for j in range(n_sat_per_plane)]
        
        ephemeris_tmp = pd.DataFrame()
       
        ephemeris_tmp['orbit'] = [KeplerianOrbit(sma, eccentricity, inclination, pa, raan_tmp, true_anomaly_tmp[j],
                                                PositionAngle.TRUE, inertial_frame, extrap_date, Constants.WGS84_EARTH_MU) \
                                  for j in range(n_sat_per_plane)]
        
        ephemeris_tmp['constellation'] = config['constellation'][i] 
        ephemeris_tmp['shell'] = i
        ephemeris_tmp['name'] = config['name'][i]
        ephemeris_tmp['plane'] = p
        
        ephemeris = ephemeris.append(ephemeris_tmp, ignore_index=True)
        
ephemeris['spacecraftID'] = range(len(ephemeris))
_ = ephemeris.set_index('spacecraftID')

lat_lon_data = pd.DataFrame()

lat_lon_data['constellation'] = ephemeris['constellation']
lat_lon_data['name'] = ephemeris['name']
lat_lon_data['shell'] = ephemeris['shell']
lat_lon_data['plane'] = ephemeris['plane'].apply(lambda x: float(x))

lat_lon_data['point'] = ephemeris['orbit'].apply(lambda x: earth.transform(x.getPVCoordinates(inertial_frame).getPosition(), inertial_frame, extrap_date)) 
lat_lon_data['latitude'] = lat_lon_data['point'].apply(lambda x: degrees(x.getLatitude()))
lat_lon_data['longitude'] = lat_lon_data['point'].apply(lambda x: degrees(x.getLongitude()))

_ = lat_lon_data.drop('point', axis=1)

config_gs = pd.DataFrame()

lat = [34.252047, 40.957778]
lon = [109.018003, 100.291667]
alt = [418., 1079.]  # https://www.advancedconverter.com/map-tools/find-altitude-by-coordinates
name_gs = ['WeiNan', 'DongFeng']
min_elev = [5, 30] # Min elevation angle in degree

config_gs['station'] = [GeodeticPoint(radians(lat[i]), radians(lon[i]), alt[i]) for i in range(len(lat))]
config_gs['frame'] = config_gs['station'].apply(lambda x: TopocentricFrame(earth, x, 'Esrange'))
config_gs['logger'] = config_gs['station'].apply(lambda x: EventsLogger())
config_gs['detector_elev'] = [config_gs['logger'][i].monitorDetector(ElevationDetector(config_gs['frame'][i]).withConstantElevation(radians(min_elev[i])).withHandler(ContinueOnEvent())) for i in range(len(config_gs))]
config_gs['name'] = name_gs

ephemeris['propagator'] = ephemeris['orbit'].apply(lambda x: KeplerianPropagator(x)) 

def addSpaceCraftID(row):
    row['propagator'].resetInitialState(row['propagator'].getInitialState().addAdditionalState('spacecraftID', [float(row['spacecraftID'])]))
    
_ = ephemeris.apply(addSpaceCraftID, axis = 1)

# Add event detecctor to each individal propagator
for i in range(len(lat)):
    ephemeris['propagator'].apply(lambda x: x.addEventDetector(config_gs['detector_elev'][i]))
    
class SimpleStepHandler(PythonMultiSatStepHandler):
    
    def init(self, s, t):
        pass
    
    def handleStep(self, interpolators, isLast):
        pass
    
step_handler = SimpleStepHandler()

parallelizer = PropagatorsParallelizer(Arrays.asList(ephemeris['propagator']), step_handler)

extrap_date = initial_date
final_date = extrap_date.shiftedBy(3600. * 1) # 1hr propagation takes roughly one minute on my little laptop

_ = parallelizer.propagate(extrap_date, final_date)

Hi @huragok

Welcome to the Orekit forum! :slight_smile:

Unfortunately, the only answer I can give you is the classic one: “It works on my computer.”
I added two prints in order to see if it works properly:

print("done 1")
_ = parallelizer.propagate(extrap_date, final_date)
print("done 2")

And here are the results on the console:

runfile('/home/bryan/Documents/Projets/Orekit/Python/untitled0.py', wdir='/home/bryan/Documents/Projets/Orekit/Python')
done 1
done 2

I think this is an environment issue. I used Spyder with a Python 3.9 version. My Orekit version is 10.3 with openjdk 8.0.265. Also, I used the Anaconda navigator to install the environment and launch Spyder. I installed the environment using the script made by @petrus.hyvonen.

I’m sorry I can’t help you more

Best regards,
Bryan

Thanks @bcazabonne for taking a look at my issue! Guess I will have to play with my environment a little more :cry: Will come back to this thread if I have some new findings.

Best regards,

Wenhao

Hi @huragok,

This is due to a change in the API in orekit v11.

The new API for handlers has a separate method for finishing, instead of the previous isLast parameters as an input to handleStep.

Thus the new code for your example in v11 should be:

class SimpleStepHandler(PythonMultiSatStepHandler):

    def init(self, s, t):
        pass

    def handleStep(self, interpolators):
        pass

    def finish(self, finalStates):
        pass

Best Regards
/Petrus

1 Like