Skip to main content

Satellite Observation Package for Retrieval, Analysis, and Navigation

Project description

SOPRAN

Satellite Observation Package for Retrieval, Analysis, and Navigation.

SOPRAN は、衛星観測データの取得、読み込み、解析、可視化、座標変換を Python から 扱うためのライブラリとして作る予定のリポジトリです。まずは KAGUYA/SELENE や ARTEMIS など、月周辺の衛星データ解析を主対象にします。

目標

  • ミッションごとに異なるデータ形式や測定器を、共通した使い方で扱えるようにする。
  • IDL/SPEDAS で使ってきた解析スクリプトを pure Python + Rust の実装へ移植する。
  • Python から読みやすい API を提供しつつ、重い decode、binning、fit、大量 batch 処理は Rust backend へ分離する。
  • 解析作業で増えた一時コードを、そのまま積み上げず、reader、product、workflow、 analysis primitive として整理する。

初期スコープ

  • KAGUYA/SELENE の public data reader と product builder
  • ARTEMIS の基本 reader と時系列 product
  • SPEDAS/tplot に近い軽量な時系列データモデル
  • dataset root / local cache / metadata の共通 resolver
  • SPICE を使った時刻・座標系補助
  • DEM/SVM などの天体固有 map product、投影、経度表現、region query
  • DEM と太陽位置に基づく shadow / illumination product
  • Rust による重い処理の backend 化

依存関係

SOPRAN は研究・解析環境でそのまま使えることを優先し、KAGUYA/ARTEMIS、SPICE、 SpacePy、MAP/DEM/SVM、Matplotlib/HoloViz 系の runtime backend を標準 dependencies に 含めます。optional-dependencies は用途別の目印と開発環境向けに残しています。

pip install sopran
pip install "sopran[full]"
pip install "sopran[dev]"

optional extras は kaguya, artemis, moon, viz, geospace, full, dev に分けますが、 runtime 系は標準 dependencies にも含めます。

Documentation

公開ドキュメントは MkDocs Material で docs/ からビルドします。GitHub Pages は .github/workflows/docs.ymlmain への push 時に build/deploy する構成です。

pip install mkdocs mkdocs-material "mkdocstrings[python]" pymdown-extensions numpy
set PYTHONPATH=src
mkdocs serve

pip install -e ".[docs]" も定義していますが、通常の runtime dependencies も解決対象になるため、 Windows で MSVC がない環境では aacgmv2 などの build に失敗することがあります。docs だけを 編集する場合は上の軽量 install を使います。

現在動く最小 API

KAGUYA ESA1 については、public PBF file discovery、ローカル raw PBF decode、 xarray/polars 変換、parquet 保存、Pipeline scan/run、最小 PlotStack までの縦切りを 実装し始めています。ARTEMIS FGM は normalized parquet が Store にある場合の load skeleton を 用意しています。

import sopran as spn

store = spn.Store("F:/sopran_data")
kg = spn.Kaguya(store=store, download="never")
time = spn.day("2008-01-01")

kg.esa1.energy_flux.info()
kg.esa1.energy_flux.plan(time)

esa1 = kg.esa1.load(time)
ds = esa1.to_xarray()
counts = esa1.to_polars("counts", reduce_look="sum")
record = esa1.write_parquet(store, variable="counts", reduce_look="sum")

pipe = (
    kg.esa1.pipeline(time)
    .decode()
    .select_variables("counts")
    .quicklook("counts")
    .write("kaguya.esa1.counts", layer="normalized")
)
pipe.run()                 # existing shard があれば失敗
pipe.run(mode="replace")   # 明示置換
pipe.run(mode="append")    # catalog に shard を追加
manifest = store.dataset("kaguya.esa1.counts", layer="normalized").manifest()
manifest["provenance"]["pipeline"]["stages"]

lazy = kg.esa1.pipeline(time).from_normalized().select_variables("counts").scan()
counts_frame = lazy.collect()

stream = (
    kg.esa1.pipeline(time)
    .from_normalized()
    .select_variables("counts")
    .stream(partition="day")
)
for day_frame in stream:
    pass

stack = spn.stack(
    kg.esa1.counts.load(time).spectrogram(y="energy"),
    kg.esa1.quality.load(time).line(),
)
fig = stack.plot(backend="matplotlib")
quicklook = stack.quicklook("esa1_counts", root="reports", backend="matplotlib")

bins = spn.time_bins(time, cadence="10s", partial="keep")
features = spn.align(
    kg.esa1.quality.load(time),
    grid=bins,
    method="nearest",
    tolerance="5s",
).to_polars()

# sza, wave_power, density, and quality_flag are loaded xarray-like products.
ml_features = (
    spn.SampleTable(bins)
    .add(sza, method="nearest", tolerance="5s")
    .add(wave_power, method="max")
    .add(density, method="median")
    .collect(join="inner", quality_mask=quality_flag)
    .to_polars()
)

time x component の vector product は magnetic_field_x のような wide columns に展開します。 観測量ごとに対応づけ方法を変える場合は SampleTable を使います。現在の reducer は nearest, center, mean, max, median, first, last です。 join="outer" は全binを残し、join="inner" は欠損featureを含むbinを落とします。 fill=-1.0 のように指定すると、outer で残した欠損featureを明示値で埋められます。 quality_mask=<1D time series> はbin内でcenterに近いmask値が0/False/欠損のbinを落とします。 partial="keep" はcadenceで割り切れない末尾binを残し、partial="drop" は捨てます。 to_polars(layout="long")time, feature, value 形式のtableを返します。 metadata() はgridやreducer条件を返し、保存時のmanifest材料にできます。 spn.align(...).write_parquet("features.parquet") または spn.SampleTable(...).collect().write_parquet("features.parquet") で feature table を保存できます。

raw file は Store.raw_path("kaguya", "pds3") 以下に public provider path を保って置きます。 たとえば ESA1 の 2008-01-01 は次の配置を探索します。

F:/sopran_data/raw/kaguya/pds3/
  sln-l-pace-3-pbf1-v3.0/20080101/data/IPACE_PBF1_080101_ESA1_V003.dat.gz

保存済み dataset は Store.datasets(refresh=True)registry/datasets.parquet に索引化し、 layer や mission で絞り込めます。

index = store.datasets(refresh=True)
kaguya_features = store.datasets(layer="features", mission="kaguya")

kg.esa1.energy_flux は実データではなく endpoint です。属性アクセスだけでは I/O を起こさず、 実データ取得は .load(time)、計算は .compute(...)、描画は .plot(...) を実行点にします。

解析プロジェクトでは case に時間範囲や既定 frame を持たせます。

prj = spn.Project("projects/lunar_wake")
case = prj.case("wake_20080201")

counts = case.kaguya.esa1.counts.load()
artemis_b_plan = case.artemis.p1.fgm.magnetic_field.plan()
moon_dem_plan = case.moon.dem.plan(source="kaguya.tc.dem")
moon_sza_plan = case.moon.sza.plan()

stack = case.stack(
    counts.spectrogram(y="energy"),
    case.kaguya.esa1.quality.load().line(),
)
stack.plot()

artifact = prj.save(case.kaguya.esa1.quality.load(), "interim/kaguya_esa1_quality_wake")

月面 DEM/SVM/SZA/shadow/illumination は mission ではなく body-first API を主導線にします。

moon = spn.Moon()
region = spn.Region(lon=(120, 160), lat=(-45, -10), body="moon")

dem_plan = moon.dem.plan(source="kaguya.tc.dem", region=region, resolution="512ppd")
sza_plan = moon.sza.plan(time="2008-02-01T12:00:00", region=region)
shadow_plan = moon.shadow.plan(time="2008-02-01T12:00:00", dem=dem_plan)

ユーザー定義の database product は Store 配下に metadata と空 dataset として登録できます。

db = store.database("lunar_wake", create=True)
product = db.register_product(
    name="event_table",
    schema=kg.esa1.schema(),
    description="hand-curated lunar wake events",
)

pipe.write(db.product("event_table", description="event table generated by pipeline"))
events = db.product("event_table").scan()

予定ディレクトリ

src/sopran/
  core/
  missions/
    kaguya/
    artemis/
  bodies/
    moon/
  maps/
  frames/
  analysis/
  plot/
crates/
  sopran-backend/
docs/
tests/

ユーザーの解析 workspace は repository 内部の package とは分けて、projects/lunar_wake/ のように 管理します。

旧リポジトリ

以前の作業リポジトリは F:\idl\lunarsat にあります。そこには KAGUYA 解析、dataset layout、Rust backend の試行錯誤が含まれていますが、このリポジトリでは設計を整理し直して 作り直します。

License

SOPRAN original code and documentation are licensed under Apache-2.0.

SPEDAS/PySPEDAS-derived ports must retain their upstream notices. The current policy is documented in THIRD_PARTY_NOTICES.md: MIT-licensed SPEDAS routines can be ported with attribution, while GPL/NASA-OSA external components should not be copied into the Apache-2.0 core without a separate license review.

開発状況

現在は KAGUYA ESA1 の local PBF decode、xarray/polars 変換、parquet 保存、Pipeline run/scan、 PlotStack、Project/Case、Moon surface skeleton、ARTEMIS FGM normalized store load skeleton を 実装し始めています。 詳細設計は SPEC.md, STORE.md, PIPELINE.md, SURFACE.md, PLOTTING.md に分けます。

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sopran-0.0.0.tar.gz (144.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sopran-0.0.0-py3-none-any.whl (94.8 kB view details)

Uploaded Python 3

File details

Details for the file sopran-0.0.0.tar.gz.

File metadata

  • Download URL: sopran-0.0.0.tar.gz
  • Upload date:
  • Size: 144.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for sopran-0.0.0.tar.gz
Algorithm Hash digest
SHA256 d1335dd31f81ffee138bf4e106a9dda1dfe7408c21c660241773f3a51c84c88a
MD5 b0af187a498c793d93bd2781ffc347b8
BLAKE2b-256 2d8940996b594949a247b0073082ae22670d9022eea27d71e57f64535b8ec496

See more details on using hashes here.

Provenance

The following attestation bundles were made for sopran-0.0.0.tar.gz:

Publisher: publish.yml on Nkzono99/sopran

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file sopran-0.0.0-py3-none-any.whl.

File metadata

  • Download URL: sopran-0.0.0-py3-none-any.whl
  • Upload date:
  • Size: 94.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for sopran-0.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8513fa294b3baed402eaf696626f3a51d3b30db66713b2e833d350edae403771
MD5 7a346698456948aa29ac3d27333c8dba
BLAKE2b-256 8b63b956879dcbea852809ebf0a2dfe2fdd8b96e9a3b85944e448976fd998955

See more details on using hashes here.

Provenance

The following attestation bundles were made for sopran-0.0.0-py3-none-any.whl:

Publisher: publish.yml on Nkzono99/sopran

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page