#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""MERRA-2 气溶胶沉降下载 v2 (SNICAR雪反照率用, 2026-10-01重写).

v2修正(v1选错了集合, 感谢审阅):
  1. 集合 M2TMNXAER(tavgM_2d_aer_Nx)没有BCPHILIC/BCPHOBIC/OCPHILIC/OCPHOBIC,
     也没有DUEXTTFRH —— 那些是3D混合比或不存在的变量.
  2. SNICAR需要的是沉降通量(kg m-2 s-1), 在 M2TMNXADG(tavgM_2d_adg_Nx):
       BC干沉降 BCDP001/BCDP002, BC湿沉降 BCWT001/BCWT002
       OC干沉降 OCDP001/OCDP002, OC湿沉降 OCWT001/OCWT002
       沙尘干沉降 DUDP001-DUDP005, 沙尘湿沉降 DUWT001-DUWT005
  3. 主机改为 goldsmr4 (MERRA2_MONTHLY 正宿主), 文件流号按年代
     (1980s=100, 1992-1999=200, 2000-2010=300, 2011-=400), 404自动换.
  4. 逐月单文件(不再按年拼接, 月界不丢); 失败不写"假成功"文件,
     打印HTTP状态码+响应前200字符.
  5. 每月整文件nc4约30MB(共228个月约7GB); 服务器端入库脚本会自动裁剪到
     78-103E/28-50N并抽取18个沉降变量, 你只需原样拷回.

用法:
  1. https://urs.earthdata.nasa.gov/ 注册
  2. https://disc.gsfc.nasa.gov/earthdata-login-token-generator 生成token
  3. 粘贴到 TOKEN
  4. py aerosol_standalone_v2.py          # 全部228个月
     py aerosol_standalone_v2.py 2010     # 只下2010年
  5. 完成后把 aerosol_out/ 拷回服务器 传输/ 目录

依赖: py -m pip install requests
"""
import sys
import time
from pathlib import Path

import requests

# ===== 认证(二选一; 优先token, 失败再填账号密码) =====
TOKEN = "eyJ0eXAiOiJKV1QiLCJvcmlnaW4iOiJFYXJ0aGRhdGEgTG9naW4iLCJzaWciOiJlZGxqd3RwdWJrZXlfb3BzIiwiYWxnIjoiUlMyNTYifQ.eyJ0eXBlIjoiVXNlciIsInVpZCI6ImxpbndlaXhpbiIsImV4cCI6MTc5NjA1MTAyMiwiaWF0IjoxNzkwODY3MDIyLCJpc3MiOiJodHRwczovL3Vycy5lYXJ0aGRhdGEubmFzYS5nb3YiLCJpZGVudGl0eV9wcm92aWRlciI6ImVkbF9vcHMiLCJhY3IiOiJlZGwiLCJhc3N1cmFuY2VfbGV2ZWwiOjN9.1l-vAzhDdO00hTFKbZHWOxMe6LbYa-YaGYRi3uwzJubOnnl5bH6rmQ4ZhnMG9Y1jUL7rUfSCjo83Fe0Z2Fe5A_vQ6eoU5yu-8-qMT7TSWRlCyA_ASSosmhspdtBuAL5nXJAPbizzinDm-7HajRW0l7mfo0tLq5998n5oP7PBnPuNE_-UeKnF5kpIPS6tII0ORcW5kYsiAgXn0UTikbbw7qnpcX6oGuygfus9zQuFmMk3C2T5RbuEpAVyK8s3UQC2Djg64RwSkLViu4J16f82dDwnuVFrN-qQs3s0CWguH3OJae70GgiYC_zowxLWl8lVwICpi-C5n-e98TgM5gJ1SA"          # disc.gsfc.nasa.gov → Earthdata Login Token
USERNAME = ""                          # 或: Earthdata用户名(和PASSWORD一起填)
PASSWORD = ""                          # 或: Earthdata密码

TMP = Path("aerosol_out")
TMP.mkdir(exist_ok=True)

# 亚洲高山区(覆盖九流域). MERRA-2 0.625°x0.5°: lon自-180起, lat自-90起
# 78E→(78+180)/0.625=412.8→412; 103E→452.8→452; 28N→236; 50N→280
LON_W, LON_E = 412, 452
LAT_S, LAT_N = 236, 280

VARS = (
    [f"BCDP00{i}" for i in (1, 2)] + [f"BCWT00{i}" for i in (1, 2)] +
    [f"OCDP00{i}" for i in (1, 2)] + [f"OCWT00{i}" for i in (1, 2)] +
    [f"DUDP00{i}" for i in range(1, 6)] + [f"DUWT00{i}" for i in range(1, 6)]
)

HOST = "https://goldsmr4.gesdisc.eosdis.nasa.gov/data/MERRA2_MONTHLY/M2TMNXADG.5.12.4"


def stream_of(yr):
    """MERRA-2文件流号(实测goldsmr4目录): 2000=200, 2001-2010=300, 2011-=400."""
    return 200 if yr == 2000 else (300 if yr <= 2010 else 400)


def download_month(session, yr, mo):
    """直连下载整月nc4(~30MB/月, 含全部变量); 服务器端入库时再裁剪区域.
    (OPeNDAP .ascii服务已410退役, 故改为整文件直下; Bearer token走HTTPS直连.)"""
    out = TMP / f"adg_{yr}{mo:02d}.nc4"
    if out.exists() and out.stat().st_size > 10_000_000:
        return "skip"
    for stream in (stream_of(yr), 300, 400, 200):          # 首选+兜底(2000年在200流!)
        url = (f"{HOST}/{yr}/"
               f"MERRA2_{stream}.tavgM_2d_adg_Nx.{yr}{mo:02d}.nc4")
        try:
            r = session.get(url, timeout=600, stream=True)
            if r.status_code == 404:
                continue                                    # 换流号
            r.raise_for_status()
            n = 0
            with open(out, "wb") as fh:
                for chunk in r.iter_content(1 << 20):
                    fh.write(chunk); n += len(chunk)
            if n < 10_000_000:                              # nc4月文件应~30MB
                out.unlink(missing_ok=True)
                print(f"  {yr}-{mo:02d} stream{stream} 文件过小({n}B), 重试")
                time.sleep(20); continue
            return "ok"
        except Exception as e:
            msg = getattr(e, "response", None)
            extra = f" HTTP{msg.status_code}: {msg.text[:180]!r}" if msg is not None else ""
            print(f"  {yr}-{mo:02d} stream{stream} 异常: {str(e)[:80]}{extra}")
            time.sleep(20)
    return "fail"


def main():
    years = [int(a) for a in sys.argv[1:]] or list(range(2000, 2019))
    s = requests.Session()
    if TOKEN and "粘贴" not in TOKEN:
        s.headers.update({"Authorization": f"Bearer {TOKEN}"})
    elif USERNAME and PASSWORD:
        s.auth = (USERNAME, PASSWORD)
    else:
        sys.exit("请先填 TOKEN 或 USERNAME/PASSWORD")
    ok = skip = fail = 0
    for yr in years:
        for mo in range(1, 13):
            st = download_month(s, yr, mo)
            ok += st == "ok"; skip += st == "skip"; fail += st == "fail"
            print(f"[{yr}-{mo:02d}] {st}  (ok={ok} skip={skip} fail={fail})",
                  flush=True)
    print(f"\n完成: ok={ok} skip={skip} fail={fail}")
    if fail:
        print("失败月可重跑本脚本(已成功的自动跳过). 若401/403: token过期,"
              " 到 disc.gsfc.nasa.gov 重新生成; 若连续404: 网络到goldsmr4不通.")


if __name__ == "__main__":
    main()
