コンテンツにスキップ

Storeにデータを保存する

Storeは、取得した元ファイル・SOPRANが作った中間データ・利用者が採用した解析結果を、1つのルートの下に層を分けて置く仕組みです。 解析の作業場所であるProjectとは分けて持ち、複数のProjectや計算機から同じStoreを使えます。 保存先の決め方は設定、ディレクトリとファイルの詳細はStoreのファイル構造にあります。

store = spn.Store("/path/to/sopran_data")

層ごとに置くもの

層 置くもの 作るもの
raw 配布元から取得した元ファイル。名前とディレクトリ構成は配布元のまま ダウンロード
normalized 機器の標準的な物理量(カウント、エネルギーフラックス、磁場など)をParquetにしたもの Pipeline、write_parquet
features SOPRANが計算した派生量(軌道幾何、ピッチ角スペクトル、データの有無の集計など) キャッシュ、write_parquet
models 校正やモデル当てはめの結果 試作API、write_parquet
databases 利用者や研究テーマごとに採用した表(イベント一覧など) store.database、store.event_catalog
cache 再生成できる一時ファイル 内部処理
registry 検索用の索引 自動

raw/の元ファイルには、取得元URL・チェックサム・取得日時を書いた付属JSON(<ファイル名>.sopran.json)が付きます。

キャッシュで計算をやり直さない

軌道幾何・磁力線の接続・LRSのスペクトル・ピッチ角スペクトルなどは、cache=で計算結果をStoreに残せます。

cache 動作
"use"(既定) 同じ引数の結果があれば読み、無ければ計算して保存する
"refresh" 計算し直して上書きする
"never" 保存せず、その場で計算する

保存先はfeatures層などのデータセットの下に、計算条件ごとのvariants/<variant_id>/として分かれます。 variant_idは引数と入力ファイルの内容から決まるため、条件の違う結果を取り違えることはありません。 入力の元ファイルが一部欠けてmissing="empty"や"warn"で読んだ結果は、不完全なのでキャッシュに保存しません。

データの有無を集計する

各エンドポイントのcoverage()は、日ごとか月ごとに、観測サンプル数と取得済みファイル数を集計した表を返します。

daily = spn.kaguya.esa1.counts.coverage(spn.month("2008-02"), freq="day")

列はsample_count、finite_sample_count、sample_time_count、expected_remote_files、 available_source_filesです。結果はfeatures層に<dataset>.coverageとして保存して再利用します。 これは観測の有無の集計で、解釈を加えたイベントではありません。

Storeの中を探す

store.datasets(refresh=True)                       # 全データセットの一覧(Polars)
store.datasets(layer="features", mission="kaguya")
store.raw_files(refresh=True, mission="kaguya")    # 元ファイルの一覧

lazy = store.scan_dataset("kaguya.esa1.counts", layer="normalized")   # Polars LazyFrame
frame = lazy.filter(...).collect()

store.dataset(dataset_id, layer=...)はデータセットの記録(DatasetRecord)を返します。

操作 呼び出し
完了したシャードを読む record.scan()
シャードの状態を見る record.shards(status="failed")、record.failed_shards()
シャードのチェックサムを確かめる record.verify_checksums()、record.verify_shards()
入力の元ファイルまで含めて確かめる store.verify_dataset(dataset_id, layer=...)
カタログを付属JSONから作り直す record.rebuild_catalog()、store.rebuild()

研究テーマのデータベース

採用した解析結果はdatabases層に、テーマごとの名前空間としてまとめます。

db = store.database("lunar_wake", create=True)
db.register_product(name="event_table", schema=schema, description="hand-curated lunar wake events")
db.adopt_dataset(record, description="aligned context features")   # 既存データセットを移動せずに登録
db.products()
db.product("event_table").scan()

adopt_datasetはfeatures層などにあるデータセットを、場所を変えずにデータベースの一覧へ加えます。

イベントカタログ

人が選んだイベントや検出器の出力は、event_catalogで検証付きの表として保存できます。

catalog = store.event_catalog("lunar_wake", create=True)
catalog.write_events(events, time_coverage=spn.month("2008-02"), overwrite=True)

monthly = catalog.counts(freq="month", by=("instrument",))
rates = catalog.rates(exposure, freq="day", by=("phenomenon",))

eventsはtime_start、time_stop、mission、instrument、phenomenon、confidence、detector、 detector_versionの列を持つ表です。ratesは、検出器が実際に判定できた時間(exposure_seconds)で 件数を割った発生率を返し、イベントが0件の期間も0として残します。 観測できなかった期間を0件と区別するため、exposureには判定できた時間を別に集計して渡します。

別の計算機へ運ぶ

Storeはファイルのままrsyncで運べる形に保っています。手順はStoreを別マシンへ運ぶにあります。