Как распараллелить расчеты движения небесных тел? - PullRequest
0 голосов
/ 01 апреля 2020

У меня есть фрагмент кода, который вычисляет позиции некоторых спутников и планет, используя Skyfield . Для ясности я использую Pandas DataFrame в качестве контейнера позиций и соответствующих моментов времени. Я хочу сделать расчет параллельно, но всегда получаю одну и ту же ошибку: TypeError: can't pickle Satrec objects. Были протестированы различные параллелизаторы, такие как Dask, pandarallel , swifter и Pool.map ().

Пример куска кода для распараллеливания:

        def get_sun_position(self, row):
            t = self.ts.utc(row["Date"]) # from skyfield
            pos = self.earth.at(t).observe(self.sun).apparent().position.m # from skyfield, error is here
            return pos

        def get_sat_position(self, row):
            t = self.ts.utc(row["Date"]) # from skyfield
            pos = self.sat.at(t).position.m # from skyfield, error is here
            return pos

        def get_positions(self):
            self.df["sat_pos"] = self.df.swifter.apply(self.get_sat_position, axis=1) # all the parallelization goes here
            self.df["sun_pos"] = self.df.swifter.apply(self.get_sun_position, axis=1) # and here

# the same implementation but using dask
#         self.df["sat_pos"] = dd.from_pandas(self.df, npartitions=4*cpu_count())\
#             .map_partitions(lambda df : df.apply(lambda row : self.get_sat_position(row),axis=1))\
#                 .compute(scheduler='processes')
#         self.df["sun_pos"] = dd.from_pandas(self.df, npartitions=4*cpu_count())\
#             .map_partitions(lambda df : df.apply(lambda row : self.get_sun_position(row),axis=1))\
#                 .compute(scheduler='processes')

Для Dask, чтобы избежать Pickle, я попытался вручную установить serializaton , как это serializers=['dask', 'pickle'], но это не так Т помочь.

Как я понимаю, Skyfield использует sgp4 , который содержит класс Satre c.

Мне было бы интересно узнать, есть ли способ распараллелить это .apply(). Или, может быть, мне вообще не стоит использовать функции Skyfield для параллельной обработки?

1 Ответ

0 голосов
/ 02 апреля 2020

Увы, все механизмы, которые вы используете для параллельного вычисления, делают это путем создания другого процесса и последующей отправки копий всех объектов, участвующих в вычислении, другому процессу - и объект Satrec записывается в C ++, а не Python, чтобы сделать это быстрее, и объекты C ++ не имеют собственного способа «сериализации» в байты для передачи другому процессу. (Python объекты имеют эту встроенную способность.)

Профилировали ли вы свой код, чтобы увидеть, какие самые дорогие шаги? Я предполагаю, что большая часть ваших расходов идет на вычисление Солнца, потому что для достижения его высокой точности Skyfield необходимо вычислить ориентацию Земли с очень высокой точностью, чтобы дать положению Солнца в небе достаточно высокую точность даже для радиоастрономов.

Но если вам самим не нужна такая высокая точность, вы можете переключиться на более низкие координаты неба для Солнца. Прежде чем использовать t в get_sun_position(), попробуйте сделать следующее:

t._nutation_angles = iau2000b(t.tt)

Это будет использовать более низкую точность оценки нутации Земли (распечатайте значения до и после этого изменения, чтобы увидеть, насколько велика разница заключается в том, насколько неточность может выдержать ваше приложение), но, надеюсь, будет работать быстрее.

...