【问题标题】:How to parallelize calculations of celestial bodies motion?如何并行计算天体运动?
【发布时间】:2020-04-01 15:18:25
【问题描述】:

我有一段代码使用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 使用包含 Satrec 类的 sgp4。

我想知道是否有某种方法可以并行化这个.apply()。或者也许我根本不应该尝试使用 Skyfield 函数进行并行处理?

【问题讨论】:

  • 正如我所见,线程之间根本不需要交换信息。所以这个任务应该很简单吧?

标签: python parallel-processing dask skyfield sgp4


【解决方案1】:

唉,你用来使计算并行的所有机制都是通过创建另一个进程然后将计算中涉及的所有对象的副本发送到另一个进程来实现的——Satrec 对象被写入在 C++ 中,而不是 Python 中,以使其更快,并且 C++ 对象没有本地方式将自己“序列化”为字节以传输到另一个进程。 (Python 对象内置了这种能力。)

您是否对代码进行了概要分析以了解最昂贵的步骤是什么?我的猜测是,您的大部分费用都花在了太阳计算上,因为要实现其高精度 Skyfield 需要以非常高的精度计算地球的方位,以使太阳在天空中的位置对射电天文学家来说也具有足够高的精度。

但如果您自己不需要那么高的精度,您可以切换到太阳的低精度天空坐标。在get_sun_position() 中使用t 之前,请尝试这样做:

t._nutation_angles = iau2000b(t.tt)

这将使用对地球章动的较低精度估计(打印出此更改前后的值以查看差异有多大,并将其与您的应用程序可以承受的不准确性进行比较),但也希望运行得更快.

【讨论】:

  • 你是对的,最昂贵的操作是太阳位置计算。不幸的是,在t 之前使用t._nutation_angles = iau2000b(t.tt) 并没有加快计算速度。但我抓住了这个想法,并将尝试降低在get_sun_position() 中确定地球坐标的准确性。您能否告诉我是否有机会在不同的内核上运行 get_sun_position() 和 get_sat_position()?
  • 如果你传递一个时间数组,那么许多底层操作发生在 NumPy 而不是 Python 中。您是否探索过您在平台上使用的 NumPy 版本是否使用多个内核进行阵列操作?哦,而且:章动角动作应该会大大加快速度,我想知道为什么它不适合你?如果您可以在问题中提供完整的 Python 脚本,人们可以运行它来重现您的问题,那么我很乐意在我自己的机器上尝试一下,看看为什么加速没有帮助。
  • 当然,here 你可以找到讨论工作的 jupyter notebook。我正在使用 NumPy 1.16.4。
猜你喜欢
  • 2012-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多