-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfetch_chains.py
More file actions
154 lines (137 loc) · 5.62 KB
/
Copy pathfetch_chains.py
File metadata and controls
154 lines (137 loc) · 5.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
"""Fetch the public posterior chains used by the chain-derived probes.
These chain files are NOT redistributable through this repository for
size and licensing reasons; the user must download them from the
collaborations' public archives. This script automates the download
where the URL is stable + public, and prints clear instructions for
the cases that require institutional credentials or accept-license
clickthrough.
Run: python -m src.fetch_chains [--probe planck|act|kids|des|desi|pr4|all]
After running, the per-probe directories under data/ will contain the
chain files needed by src.load_chains.* (see download_summary.json
for an inventory of what landed and what is still pending).
Important: the chain files vary in size from ~50 MB (DESI Y1 BAO) to
~2 GB (Planck PR4 NPIPE). Download time is dominated by the Planck
products. We do not retry; if the server times out, re-run the
script and only the missing files will be fetched.
"""
from __future__ import annotations
import argparse
import json
import sys
import urllib.request
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
DATA = ROOT / "data"
# --- Stable public URLs -----------------------------------------------------
# Each entry: (target_relative_path, url, expected_min_bytes, notes)
PUBLIC_URLS = {
"planck_pr3": [
# Planck PR3 base ΛCDM TT,TE,EE+lowE chains (cosmomc format,
# 4 walker files + .paramnames + .ranges)
("planck2018_chains/base/plikHM_TTTEEE_lowl_lowE/"
"base_plikHM_TTTEEE_lowl_lowE_1.txt",
"https://irsa.ipac.caltech.edu/data/Planck/release_3/ancillary-data/"
"cosmoparams/COM_CosmoParams_base-plikHM-TTTEEE-lowl-lowE_R3.00.zip",
100_000_000,
"ZIP archive; extract under data/planck2018_chains/ "
"(Planck Legacy Archive)."),
],
"act_dr6": [
("act_dr6_chains/actbase_lcdm_camb/actbase_lcdm_camb/"
"actbase_lcdm_camb.1.txt",
"https://lambda.gsfc.nasa.gov/data/suborbital/ACT/ACT_dr6/"
"likelihood/data/v1.0/MCMCChains/actbase_lcdm_camb.tar.gz",
50_000_000,
"TAR archive; extract under data/act_dr6_chains/ "
"(LAMBDA / NASA ACT DR6 release)."),
],
"kids1000": [
("kids1000/KiDS1000_cosmis_shear_data_release/"
"chains_and_config_files/main_chains_iterative_covariance/"
"cosebis/chain/output_multinest_C.txt",
"https://kids.strw.leidenuniv.nl/cs2018/KiDS1000_cosmis_shear_data_release.tar.gz",
200_000_000,
"TAR archive; extract under data/kids1000/ (KiDS-1000 release)."),
],
"des_y3": [
("des_y3/chain_3x2pt_lcdm_SR_maglim.txt",
"https://desdr-server.ncsa.illinois.edu/despublic/y3a2_files/"
"chains/chain_3x2pt_lcdm_SR_maglim.txt",
5_000_000,
"Direct .txt download; ~30 MB (DES Y3 release)."),
],
"desi_y1": [
# DESI Y1 BAO + BBN baseline chain (placeholder; fill in real URL
# from DESI DR1 public archive as available).
("desi_y1_chains/desi_y1_bao_bbn.txt",
"https://data.desi.lbl.gov/public/dr1/cosmology/chains/"
"desi_y1_bao_bbn.txt",
1_000_000,
"Direct .txt; small (~5 MB)."),
],
"planck_pr4": [
("planck_pr4_chains/hlpTTTEEE_lowT_lowE_1.txt",
"https://portal.nersc.gov/cfs/cmb/planck2020/chains/"
"PR4_NPIPE_TTTEEE_lowT_lowE.tar.gz",
500_000_000,
"TAR; extract under data/planck_pr4_chains/ "
"(NERSC; PR4 NPIPE / Tristram et al. 2024)."),
],
}
def _download(url: str, target: Path) -> bool:
"""Stream a file; return True on success. Skip if already present."""
if target.exists() and target.stat().st_size > 0:
return True
target.parent.mkdir(parents=True, exist_ok=True)
try:
print(f" fetching {url}")
with urllib.request.urlopen(url, timeout=60) as r, open(target, "wb") as f:
while True:
chunk = r.read(1 << 20)
if not chunk:
break
f.write(chunk)
return True
except Exception as e:
print(f" FAIL: {e}")
if target.exists() and target.stat().st_size == 0:
target.unlink()
return False
def fetch_one(probe: str) -> dict:
if probe not in PUBLIC_URLS:
raise KeyError(f"unknown probe '{probe}'")
out = {"probe": probe, "fetched": [], "missing": [], "notes": []}
for rel, url, _, note in PUBLIC_URLS[probe]:
target = DATA / rel
if target.exists() and target.stat().st_size > 0:
out["fetched"].append(rel)
continue
ok = _download(url, target)
(out["fetched"] if ok else out["missing"]).append(rel)
if note and not ok:
out["notes"].append(note)
return out
def main():
p = argparse.ArgumentParser()
p.add_argument("--probe", default="all",
choices=list(PUBLIC_URLS) + ["all"])
args = p.parse_args()
targets = list(PUBLIC_URLS) if args.probe == "all" else [args.probe]
summary = []
for t in targets:
print(f"=== {t} ===")
summary.append(fetch_one(t))
out = DATA / "download_summary.json"
out.write_text(json.dumps(summary, indent=2))
n_ok = sum(len(s["fetched"]) for s in summary)
n_missing = sum(len(s["missing"]) for s in summary)
print(f"\nFetched {n_ok}; missing {n_missing}.")
print(f"Wrote {out}")
if n_missing:
print("\nManual download required for missing files. Notes:")
for s in summary:
for note in s["notes"]:
print(f" [{s['probe']}] {note}")
sys.exit(1)
if __name__ == "__main__":
main()