docs: bilingual comments for the validation tools
Also makes the table generators emit the bilingual module docs, so a regenerated table matches the committed one.
This commit is contained in:
parent
1b0d288d73
commit
a2c2f5984a
|
|
@ -6,6 +6,13 @@
|
||||||
//!
|
//!
|
||||||
//! Source: the MHB2000 model, as distributed with the IAU SOFA library
|
//! Source: the MHB2000 model, as distributed with the IAU SOFA library
|
||||||
//! and implemented by ERFA.
|
//! and implemented by ERFA.
|
||||||
|
//!
|
||||||
|
//! 分点方程式的 IAU 2000 补充项。
|
||||||
|
//!
|
||||||
|
//! 该表由 `validation/tools/generate_eect_table.py` 从参考实现生成,
|
||||||
|
//! 原样再现,未经改动。
|
||||||
|
//!
|
||||||
|
//! 出处:MHB2000 模型,随 IAU SOFA 库分发并由 ERFA 实现。
|
||||||
|
|
||||||
use super::ComplementaryTerm;
|
use super::ComplementaryTerm;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,16 @@
|
||||||
//! Source: the MHB2000 model of Mathews, Herring and Buffett, adopted by
|
//! Source: the MHB2000 model of Mathews, Herring and Buffett, adopted by
|
||||||
//! the International Astronomical Union in 2000 and distributed as part
|
//! the International Astronomical Union in 2000 and distributed as part
|
||||||
//! of the IAU SOFA library, as implemented by ERFA.
|
//! of the IAU SOFA library, as implemented by ERFA.
|
||||||
|
//!
|
||||||
|
//! IAU 2000A 章动级数。
|
||||||
|
//!
|
||||||
|
//! 该表由 `validation/tools/generate_nutation_table.py` 从该模型的参考
|
||||||
|
//! 实现生成,原样再现,未经改动。
|
||||||
|
//!
|
||||||
|
//! 字段次序遵循参考实现,它并非论文中列出系数的次序。
|
||||||
|
//!
|
||||||
|
//! 出处:Mathews、Herring 与 Buffett 的 MHB2000 模型,2000 年由国际
|
||||||
|
//! 天文学联合会采纳,随 IAU SOFA 库分发,由 ERFA 实现。
|
||||||
|
|
||||||
use super::{PlanetaryTerm, SeriesTerm};
|
use super::{PlanetaryTerm, SeriesTerm};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,13 @@
|
||||||
//!
|
//!
|
||||||
//! Source: ITU-R Recommendation P.839-4, *Rain height model for prediction
|
//! Source: ITU-R Recommendation P.839-4, *Rain height model for prediction
|
||||||
//! methods*.
|
//! methods*.
|
||||||
|
//!
|
||||||
|
//! ITU-R P.839-4 零度等温线高度表。
|
||||||
|
//!
|
||||||
|
//! 该表由 `validation/tools/generate_p839_table.py` 从随该建议书发布的
|
||||||
|
//! 数据生成,此处以米为单位的整数再现,这正是该建议书发布的分辨率。
|
||||||
|
//!
|
||||||
|
//! 出处:ITU-R 建议书 P.839-4,*Rain height model for prediction methods*。
|
||||||
|
|
||||||
/// The height of the zero degree isotherm, in metres.
|
/// The height of the zero degree isotherm, in metres.
|
||||||
///
|
///
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,20 @@ Usage:
|
||||||
|
|
||||||
Exit status is zero when every quantity agrees within tolerance and one
|
Exit status is zero when every quantity agrees within tolerance and one
|
||||||
otherwise.
|
otherwise.
|
||||||
|
|
||||||
|
用 ERFA 交叉核对 ApsisRS 的 IAU 2000/2006 地球定向。
|
||||||
|
|
||||||
|
读取由 ``cargo run -p apsis-rs --features physics --example dump_iau2000``
|
||||||
|
写出的量,并用 ERFA 逐个重算,后者是国际天文学联合会通过 SOFA 库及其
|
||||||
|
ERFA 衍生物分发的参考实现。
|
||||||
|
|
||||||
|
本脚本不需要网络访问。
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
pixi run python validation/python/time/check_iau2000.py [path]
|
||||||
|
|
||||||
|
每个量都在容差内一致时退出状态为零,否则为一。
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
@ -35,13 +49,27 @@ import erfa
|
||||||
# `gst06a` is built on the non-rotating origin while the Rust value is built
|
# `gst06a` is built on the non-rotating origin while the Rust value is built
|
||||||
# on the equinox. The two formulations agree to about two microarcseconds,
|
# on the equinox. The two formulations agree to about two microarcseconds,
|
||||||
# which is 1e-11 radians, and that is what is allowed here.
|
# which is 1e-11 radians, and that is what is allowed here.
|
||||||
|
#
|
||||||
|
# 容差。
|
||||||
|
#
|
||||||
|
# 章动、黄赤交角与岁差在双精度最后几位的水平上被复现,故它们以 1e-14
|
||||||
|
# 比较。
|
||||||
|
#
|
||||||
|
# 恒星时与各矩阵累积了若干次转动的双精度误差,故容许更大。
|
||||||
|
#
|
||||||
|
# 格林尼治视恒星时有其自己的容差,因为 ERFA 的 `gst06a` 建立在非旋转原点
|
||||||
|
# 之上,而 Rust 值建立在春分点之上。两种表述相符到约两微角秒,即 1e-11
|
||||||
|
# 弧度,此处容许的就是这个。
|
||||||
SCALAR_TOLERANCE = 1e-14
|
SCALAR_TOLERANCE = 1e-14
|
||||||
SIDEREAL_TOLERANCE = 1e-10
|
SIDEREAL_TOLERANCE = 1e-10
|
||||||
MATRIX_TOLERANCE = 1e-9
|
MATRIX_TOLERANCE = 1e-9
|
||||||
|
|
||||||
|
|
||||||
def tolerance_for(quantity: str) -> float:
|
def tolerance_for(quantity: str) -> float:
|
||||||
"""Returns the tolerance that applies to a quantity."""
|
"""Returns the tolerance that applies to a quantity.
|
||||||
|
|
||||||
|
返回适用于某个量的容差。
|
||||||
|
"""
|
||||||
if quantity == "gast":
|
if quantity == "gast":
|
||||||
return SIDEREAL_TOLERANCE
|
return SIDEREAL_TOLERANCE
|
||||||
if quantity in ("bpn", "c2t"):
|
if quantity in ("bpn", "c2t"):
|
||||||
|
|
@ -51,18 +79,25 @@ def tolerance_for(quantity: str) -> float:
|
||||||
DEFAULT_INPUT = Path("validation/data/expected/rust_iau2000.csv")
|
DEFAULT_INPUT = Path("validation/data/expected/rust_iau2000.csv")
|
||||||
|
|
||||||
# The Terrestrial Time offset from UTC, in seconds, matching the Rust side.
|
# The Terrestrial Time offset from UTC, in seconds, matching the Rust side.
|
||||||
|
# 地球时相对 UTC 的偏移,单位为秒,与 Rust 侧一致。
|
||||||
TT_MINUS_UTC_SECONDS = 32.184 + 37.0
|
TT_MINUS_UTC_SECONDS = 32.184 + 37.0
|
||||||
|
|
||||||
|
|
||||||
def read_rows(path: Path) -> list[dict[str, str]]:
|
def read_rows(path: Path) -> list[dict[str, str]]:
|
||||||
"""Reads the CSV rows."""
|
"""Reads the CSV rows.
|
||||||
|
|
||||||
|
读取 CSV 各行。
|
||||||
|
"""
|
||||||
with path.open(newline="") as handle:
|
with path.open(newline="") as handle:
|
||||||
reader = csv.DictReader(handle)
|
reader = csv.DictReader(handle)
|
||||||
return [row for row in reader if row.get("mjd")]
|
return [row for row in reader if row.get("mjd")]
|
||||||
|
|
||||||
|
|
||||||
def tt_julian_date(utc_mjd: float) -> float:
|
def tt_julian_date(utc_mjd: float) -> float:
|
||||||
"""Returns the Terrestrial Time Julian date for a UTC Modified Julian Date."""
|
"""Returns the Terrestrial Time Julian date for a UTC Modified Julian Date.
|
||||||
|
|
||||||
|
返回某 UTC 约化儒略日对应的地球时儒略日。
|
||||||
|
"""
|
||||||
return utc_mjd + 2400000.5 + TT_MINUS_UTC_SECONDS / 86400.0
|
return utc_mjd + 2400000.5 + TT_MINUS_UTC_SECONDS / 86400.0
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -122,6 +157,8 @@ def main(argv: list[str]) -> int:
|
||||||
elif quantity == "c2t":
|
elif quantity == "c2t":
|
||||||
# The equinox based chain: the bias, precession and nutation,
|
# The equinox based chain: the bias, precession and nutation,
|
||||||
# then Greenwich apparent sidereal time, then the polar motion.
|
# then Greenwich apparent sidereal time, then the polar motion.
|
||||||
|
# 基于春分点的链条:先偏差、岁差与章动,再格林尼治视恒星时,
|
||||||
|
# 然后极移。
|
||||||
matrix = erfa.c2t06a(d1, d2, d1, d2, 0.0, 0.0)
|
matrix = erfa.c2t06a(d1, d2, d1, d2, 0.0, 0.0)
|
||||||
reference = matrix[index // 3][index % 3]
|
reference = matrix[index // 3][index % 3]
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,29 @@ Usage:
|
||||||
|
|
||||||
Exit status is zero when every instant agrees within tolerance and one
|
Exit status is zero when every instant agrees within tolerance and one
|
||||||
otherwise.
|
otherwise.
|
||||||
|
|
||||||
|
交叉核对 ApsisRS 的时标换算。
|
||||||
|
|
||||||
|
读取由 ``cargo run -p apsis-rs --features physics --example dump_time`` 写出
|
||||||
|
的样本,并用 astropy 逐个重算瞬时,然后报告最大差异。
|
||||||
|
|
||||||
|
把某 UTC 瞬时写为浮点日有两种约定。本工作区用带阶跃偏移的线性约化儒略日,
|
||||||
|
故偏移 ``TAI - UTC`` 在闰秒处改变,其间恒定。Astropy 经 ERFA 用的是准儒略
|
||||||
|
日,其中含闰秒的一天有 86 401 秒长,故其 ``tai - utc`` 之差在这样一天中
|
||||||
|
斜坡变化。因此把两者作为儒略日之差比较,度量的是约定的差异而非数值误差。
|
||||||
|
|
||||||
|
本检查改为比较 TAI 瞬时。两侧被赋予相同的 UTC 日历瞬时,所得 TAI 约化
|
||||||
|
儒略日按两部分比较:整数日与小数,这避免了单个浮点日在接近 60 000 处会
|
||||||
|
遭受的精度损失。
|
||||||
|
|
||||||
|
本脚本不需要网络访问;它禁用 astropy 对地球定向数据的自动下载,这些换算
|
||||||
|
并不使用该数据。
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
pixi run python validation/python/time/check_time.py [path]
|
||||||
|
|
||||||
|
每个瞬时都在容差内一致时退出状态为零,否则为一。
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
@ -38,25 +61,33 @@ from pathlib import Path
|
||||||
from astropy.time import Time
|
from astropy.time import Time
|
||||||
|
|
||||||
# The TAI instant is compared to one microsecond.
|
# The TAI instant is compared to one microsecond.
|
||||||
|
# TAI 瞬时比较到一微秒。
|
||||||
TOLERANCE_SECONDS = 1e-6
|
TOLERANCE_SECONDS = 1e-6
|
||||||
|
|
||||||
SECONDS_PER_DAY = 86400.0
|
SECONDS_PER_DAY = 86400.0
|
||||||
# The Modified Julian Date scale starts half a day after the Julian Date
|
# The Modified Julian Date scale starts half a day after the Julian Date
|
||||||
# scale, so this is the offset between the two day counts.
|
# scale, so this is the offset between the two day counts.
|
||||||
|
# 约化儒略日的起点比儒略日晚半天,故这是两种日计数之间的偏移。
|
||||||
MJD_OFFSET_FROM_JD = 2400000.5
|
MJD_OFFSET_FROM_JD = 2400000.5
|
||||||
|
|
||||||
DEFAULT_INPUT = Path("validation/data/expected/rust_time.csv")
|
DEFAULT_INPUT = Path("validation/data/expected/rust_time.csv")
|
||||||
|
|
||||||
|
|
||||||
def disable_remote_data() -> None:
|
def disable_remote_data() -> None:
|
||||||
"""Stops astropy from trying to download Earth orientation data."""
|
"""Stops astropy from trying to download Earth orientation data.
|
||||||
|
|
||||||
|
阻止 astropy 尝试下载地球定向数据。
|
||||||
|
"""
|
||||||
from astropy.utils import iers
|
from astropy.utils import iers
|
||||||
|
|
||||||
iers.conf.auto_download = False
|
iers.conf.auto_download = False
|
||||||
|
|
||||||
|
|
||||||
def read_rows(path: Path) -> tuple[list[dict[str, str]], dict[str, str]]:
|
def read_rows(path: Path) -> tuple[list[dict[str, str]], dict[str, str]]:
|
||||||
"""Reads the CSV rows and the trailing comment metadata."""
|
"""Reads the CSV rows and the trailing comment metadata.
|
||||||
|
|
||||||
|
读取 CSV 各行以及末尾的注释元数据。
|
||||||
|
"""
|
||||||
metadata: dict[str, str] = {}
|
metadata: dict[str, str] = {}
|
||||||
data_lines = []
|
data_lines = []
|
||||||
with path.open(newline="") as handle:
|
with path.open(newline="") as handle:
|
||||||
|
|
@ -74,7 +105,10 @@ def read_rows(path: Path) -> tuple[list[dict[str, str]], dict[str, str]]:
|
||||||
|
|
||||||
|
|
||||||
def rust_tai_parts(row: dict[str, str]) -> tuple[int, float]:
|
def rust_tai_parts(row: dict[str, str]) -> tuple[int, float]:
|
||||||
"""Returns the Rust TAI instant as an integer day and a fraction."""
|
"""Returns the Rust TAI instant as an integer day and a fraction.
|
||||||
|
|
||||||
|
把 Rust 的 TAI 瞬时返回为整数日与小数。
|
||||||
|
"""
|
||||||
return int(row["tai_day"]), float(row["tai_frac"])
|
return int(row["tai_day"]), float(row["tai_frac"])
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -83,6 +117,11 @@ def reference_tai_parts(row: dict[str, str]) -> tuple[float, float]:
|
||||||
|
|
||||||
The two part form of an astropy time keeps the day count in ``jd1`` and
|
The two part form of an astropy time keeps the day count in ``jd1`` and
|
||||||
the within-day offset in ``jd2``, so the subtraction below is exact.
|
the within-day offset in ``jd2``, so the subtraction below is exact.
|
||||||
|
|
||||||
|
把 astropy 的 TAI 瞬时返回为整数日与小数。
|
||||||
|
|
||||||
|
astropy 时间的两部分形式把日计数保存在 ``jd1``、把日内偏移保存在
|
||||||
|
``jd2``,故下面的减法精确。
|
||||||
"""
|
"""
|
||||||
iso = (
|
iso = (
|
||||||
f"{int(row['year']):04d}-{int(row['month']):02d}-{int(row['day']):02d}"
|
f"{int(row['year']):04d}-{int(row['month']):02d}-{int(row['day']):02d}"
|
||||||
|
|
@ -137,6 +176,8 @@ def main(argv: list[str]) -> int:
|
||||||
# against the reference only at the points where the reference is
|
# against the reference only at the points where the reference is
|
||||||
# constant in the workspace's sense, which the instant comparison
|
# constant in the workspace's sense, which the instant comparison
|
||||||
# above has already validated.
|
# above has already validated.
|
||||||
|
# 本工作区报告的偏移是阶跃函数。只在参考值于本工作区意义下恒定的点
|
||||||
|
# 处对它作核对,而上面的瞬时比较已验证了这些点。
|
||||||
rust_offset = float(row["tai_minus_utc"])
|
rust_offset = float(row["tai_minus_utc"])
|
||||||
if abs(error) <= TOLERANCE_SECONDS and abs(rust_offset) > worst_offset:
|
if abs(error) <= TOLERANCE_SECONDS and abs(rust_offset) > worst_offset:
|
||||||
worst_offset = rust_offset
|
worst_offset = rust_offset
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,21 @@ Fetch the reference with:
|
||||||
Usage:
|
Usage:
|
||||||
|
|
||||||
python validation/tools/generate_eect_table.py path/to/eect00.c
|
python validation/tools/generate_eect_table.py path/to/eect00.c
|
||||||
|
|
||||||
|
生成 IAU 2000 分点方程式补充项的 Rust 源码。
|
||||||
|
|
||||||
|
补充项是黄经章动不包含的、分点方程式的小周期附加项。它们来自与章动相同的
|
||||||
|
理论,为使分点方程式与章动级数一致所必需。
|
||||||
|
|
||||||
|
参考实现是 ERFA 库,它是 IAU SOFA 库的衍生物。
|
||||||
|
|
||||||
|
获取参考源码:
|
||||||
|
|
||||||
|
curl -O https://raw.githubusercontent.com/liberfa/erfa/master/src/eect00.c
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
python validation/tools/generate_eect_table.py path/to/eect00.c
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
@ -25,7 +40,10 @@ from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
def extract_array(source: str, name: str) -> str:
|
def extract_array(source: str, name: str) -> str:
|
||||||
"""Returns the body of a C array initializer."""
|
"""Returns the body of a C array initializer.
|
||||||
|
|
||||||
|
返回一个 C 数组初始化器的正文。
|
||||||
|
"""
|
||||||
start = source.index(name + "[] = {")
|
start = source.index(name + "[] = {")
|
||||||
brace = source.index("{", start)
|
brace = source.index("{", start)
|
||||||
depth = 0
|
depth = 0
|
||||||
|
|
@ -42,13 +60,19 @@ def extract_array(source: str, name: str) -> str:
|
||||||
|
|
||||||
|
|
||||||
def parse_terms(body: str) -> list[tuple[str, str]]:
|
def parse_terms(body: str) -> list[tuple[str, str]]:
|
||||||
"""Returns the multiplier and coefficient groups of each term."""
|
"""Returns the multiplier and coefficient groups of each term.
|
||||||
|
|
||||||
|
返回每一项的乘数组与系数组。
|
||||||
|
"""
|
||||||
body = re.sub(r"/\*.*?\*/", "", body, flags=re.S)
|
body = re.sub(r"/\*.*?\*/", "", body, flags=re.S)
|
||||||
return re.findall(r"\{\{([^{}]*)\},\s*([^}]*)\}", body)
|
return re.findall(r"\{\{([^{}]*)\},\s*([^}]*)\}", body)
|
||||||
|
|
||||||
|
|
||||||
def emit(name: str, doc: str, terms: list[tuple[str, str]]) -> None:
|
def emit(name: str, doc: str, terms: list[tuple[str, str]]) -> None:
|
||||||
"""Prints one Rust constant."""
|
"""Prints one Rust constant.
|
||||||
|
|
||||||
|
打印一个 Rust 常量。
|
||||||
|
"""
|
||||||
print(doc)
|
print(doc)
|
||||||
print(f"pub static {name}: [ComplementaryTerm; {len(terms)}] = [")
|
print(f"pub static {name}: [ComplementaryTerm; {len(terms)}] = [")
|
||||||
for multipliers, coefficients in terms:
|
for multipliers, coefficients in terms:
|
||||||
|
|
@ -78,17 +102,24 @@ def main(argv: list[str]) -> int:
|
||||||
print("//!")
|
print("//!")
|
||||||
print("//! Source: the MHB2000 model, as distributed with the IAU SOFA library")
|
print("//! Source: the MHB2000 model, as distributed with the IAU SOFA library")
|
||||||
print("//! and implemented by ERFA.")
|
print("//! and implemented by ERFA.")
|
||||||
|
print("//!")
|
||||||
|
print("//! 分点方程式的 IAU 2000 补充项。")
|
||||||
|
print("//!")
|
||||||
|
print("//! 该表由 `validation/tools/generate_eect_table.py` 从参考实现生成,")
|
||||||
|
print("//! 原样再现,未经改动。")
|
||||||
|
print("//!")
|
||||||
|
print("//! 出处:MHB2000 模型,随 IAU SOFA 库分发并由 ERFA 实现。")
|
||||||
print()
|
print()
|
||||||
print("use super::ComplementaryTerm;")
|
print("use super::ComplementaryTerm;")
|
||||||
print()
|
print()
|
||||||
emit(
|
emit(
|
||||||
"CONSTANT_TERMS",
|
"CONSTANT_TERMS",
|
||||||
"/// The terms that do not depend on time.\n///\n/// The eight multipliers apply to the arguments `l`, `l'`, `F`, `D`, `Om`,\n/// the mean longitude of Venus, the mean longitude of the Earth, and the\n/// general accumulated precession, in that order.",
|
"/// The terms that do not depend on time.\n///\n/// The eight multipliers apply to the arguments `l`, `l'`, `F`, `D`, `Om`,\n/// the mean longitude of Venus, the mean longitude of the Earth, and the\n/// general accumulated precession, in that order.\n///\n/// 不依赖时间的各项。\n///\n/// 八个乘数按 `l`、`l'`、`F`、`D`、`Om`、金星的平黄经、地球的平黄经,以及\n/// 一般累积岁差的次序施加于这些参数。",
|
||||||
constant,
|
constant,
|
||||||
)
|
)
|
||||||
emit(
|
emit(
|
||||||
"LINEAR_TERMS",
|
"LINEAR_TERMS",
|
||||||
"/// The terms whose amplitude grows linearly with time.\n///\n/// The arguments are the same as for the constant terms.",
|
"/// The terms whose amplitude grows linearly with time.\n///\n/// The arguments are the same as for the constant terms.\n///\n/// 幅度随时间线性增长的各项。\n///\n/// 参数与常数项相同。",
|
||||||
linear,
|
linear,
|
||||||
)
|
)
|
||||||
return 0
|
return 0
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,31 @@ Fetch the reference with:
|
||||||
Usage:
|
Usage:
|
||||||
|
|
||||||
python validation/tools/generate_nutation_table.py path/to/nut00a.c
|
python validation/tools/generate_nutation_table.py path/to/nut00a.c
|
||||||
|
|
||||||
|
生成 IAU 2000A 章动级数的 Rust 源码。
|
||||||
|
|
||||||
|
该级数即 MHB2000 模型。它有一个日月部分与一个行星部分,二者都是长长的
|
||||||
|
整数辐角乘数与实数系数表,故它们是机械地从参考实现转录而非手写。
|
||||||
|
|
||||||
|
参考实现是 ERFA 库,它是国际天文学联合会维护的 IAU SOFA 库的衍生物。其
|
||||||
|
源码是该级数的权威表述。
|
||||||
|
|
||||||
|
字段次序即参考实现所用者,它并非论文中列出系数的次序:
|
||||||
|
|
||||||
|
日月:乘数 l、l'、F、D、Om;然后 sp、spt、cp、ce、cet、se
|
||||||
|
行星:乘数 l、F、D、Om、Me、Ve、E、Ma、Ju、Sa、Ur、Ne、pa;
|
||||||
|
然后 sp、cp、se、ce
|
||||||
|
|
||||||
|
两个级数使用不同的辐角集合,且对黄赤交角使用不同的系数分组,故生成的
|
||||||
|
Rust 类型将它们分开。
|
||||||
|
|
||||||
|
获取参考源码:
|
||||||
|
|
||||||
|
curl -O https://raw.githubusercontent.com/liberfa/erfa/master/src/nut00a.c
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
python validation/tools/generate_nutation_table.py path/to/nut00a.c
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
@ -37,7 +62,10 @@ from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
def extract_array(source: str, name: str) -> str:
|
def extract_array(source: str, name: str) -> str:
|
||||||
"""Returns the body of a C array initializer."""
|
"""Returns the body of a C array initializer.
|
||||||
|
|
||||||
|
返回一个 C 数组初始化器的正文。
|
||||||
|
"""
|
||||||
start = source.index(name + "[] = {")
|
start = source.index(name + "[] = {")
|
||||||
brace = source.index("{", start)
|
brace = source.index("{", start)
|
||||||
depth = 0
|
depth = 0
|
||||||
|
|
@ -54,7 +82,10 @@ def extract_array(source: str, name: str) -> str:
|
||||||
|
|
||||||
|
|
||||||
def parse_terms(body: str) -> list[list[str]]:
|
def parse_terms(body: str) -> list[list[str]]:
|
||||||
"""Returns the numeric terms of an array of brace groups."""
|
"""Returns the numeric terms of an array of brace groups.
|
||||||
|
|
||||||
|
返回一组花括号组的数组中的数值项。
|
||||||
|
"""
|
||||||
body = re.sub(r"/\*.*?\*/", "", body, flags=re.S)
|
body = re.sub(r"/\*.*?\*/", "", body, flags=re.S)
|
||||||
terms = []
|
terms = []
|
||||||
for group in re.findall(r"\{([^{}]*)\}", body):
|
for group in re.findall(r"\{([^{}]*)\}", body):
|
||||||
|
|
@ -92,6 +123,16 @@ def main(argv: list[str]) -> int:
|
||||||
print("//! Source: the MHB2000 model of Mathews, Herring and Buffett, adopted by")
|
print("//! Source: the MHB2000 model of Mathews, Herring and Buffett, adopted by")
|
||||||
print("//! the International Astronomical Union in 2000 and distributed as part")
|
print("//! the International Astronomical Union in 2000 and distributed as part")
|
||||||
print("//! of the IAU SOFA library, as implemented by ERFA.")
|
print("//! of the IAU SOFA library, as implemented by ERFA.")
|
||||||
|
print("//!")
|
||||||
|
print("//! IAU 2000A 章动级数。")
|
||||||
|
print("//!")
|
||||||
|
print("//! 该表由 `validation/tools/generate_nutation_table.py` 从该模型的参考")
|
||||||
|
print("//! 实现生成,原样再现,未经改动。")
|
||||||
|
print("//!")
|
||||||
|
print("//! 字段次序遵循参考实现,它并非论文中列出系数的次序。")
|
||||||
|
print("//!")
|
||||||
|
print("//! 出处:Mathews、Herring 与 Buffett 的 MHB2000 模型,2000 年由国际")
|
||||||
|
print("//! 天文学联合会采纳,随 IAU SOFA 库分发,由 ERFA 实现。")
|
||||||
print()
|
print()
|
||||||
print("use super::{PlanetaryTerm, SeriesTerm};")
|
print("use super::{PlanetaryTerm, SeriesTerm};")
|
||||||
print()
|
print()
|
||||||
|
|
@ -102,6 +143,12 @@ def main(argv: list[str]) -> int:
|
||||||
print("/// in that order. The coefficients are the longitude sine, its time")
|
print("/// in that order. The coefficients are the longitude sine, its time")
|
||||||
print("/// derivative, the longitude cosine, the obliquity cosine, its time")
|
print("/// derivative, the longitude cosine, the obliquity cosine, its time")
|
||||||
print("/// derivative, and the obliquity sine, in units of 0.1 microarcsecond.")
|
print("/// derivative, and the obliquity sine, in units of 0.1 microarcsecond.")
|
||||||
|
print("///")
|
||||||
|
print("/// 级数中的日月各项。")
|
||||||
|
print("///")
|
||||||
|
print("/// 各乘数按 `l`、`l'`、`F`、`D`、`Om` 的次序施加于这些参数。各系数依次是")
|
||||||
|
print("/// 黄经正弦、其时间导数、黄经余弦、黄赤交角余弦、其时间导数,以及黄赤交角")
|
||||||
|
print("/// 正弦,单位为 0.1 微角秒。")
|
||||||
print(f"pub static LUNI_SOLAR: [SeriesTerm; {len(lunisolar)}] = [")
|
print(f"pub static LUNI_SOLAR: [SeriesTerm; {len(lunisolar)}] = [")
|
||||||
for term in lunisolar:
|
for term in lunisolar:
|
||||||
multipliers = ", ".join(term[:5])
|
multipliers = ", ".join(term[:5])
|
||||||
|
|
@ -124,6 +171,12 @@ def main(argv: list[str]) -> int:
|
||||||
print("/// coefficients are the longitude sine, the longitude cosine, the")
|
print("/// coefficients are the longitude sine, the longitude cosine, the")
|
||||||
print("/// obliquity sine, and the obliquity cosine, in units of 0.1")
|
print("/// obliquity sine, and the obliquity cosine, in units of 0.1")
|
||||||
print("/// microarcsecond.")
|
print("/// microarcsecond.")
|
||||||
|
print("///")
|
||||||
|
print("/// 级数中的行星各项。")
|
||||||
|
print("///")
|
||||||
|
print("/// 各乘数按 `l`、`F`、`D`、`Om`、水星到天王星的平黄经、海王星的平黄经,")
|
||||||
|
print("/// 以及一般累积岁差的次序施加于这些参数。各系数依次是黄经正弦、黄经余弦、")
|
||||||
|
print("/// 黄赤交角正弦与黄赤交角余弦,单位为 0.1 微角秒。")
|
||||||
print(f"pub static PLANETARY: [PlanetaryTerm; {len(planetary)}] = [")
|
print(f"pub static PLANETARY: [PlanetaryTerm; {len(planetary)}] = [")
|
||||||
for term in planetary:
|
for term in planetary:
|
||||||
multipliers = ", ".join(term[:13])
|
multipliers = ", ".join(term[:13])
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,16 @@ publishes.
|
||||||
Usage:
|
Usage:
|
||||||
|
|
||||||
python validation/tools/generate_p839_table.py > /tmp/p839_table.rs
|
python validation/tools/generate_p839_table.py > /tmp/p839_table.rs
|
||||||
|
|
||||||
|
生成 ITU-R P.839-4 雨顶高度表的 Rust 源码。
|
||||||
|
|
||||||
|
该建议书把零度等温线高度给出为 1.5 度分辨率的全球列表网格。本脚本从
|
||||||
|
``itur`` 参考包读取该网格,并输出一个 Rust 模块,把它以十分之一千米的整数
|
||||||
|
嵌入,这正是该建议书发布的分辨率。
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
python validation/tools/generate_p839_table.py > /tmp/p839_table.rs
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
@ -23,6 +33,7 @@ BASE = (
|
||||||
)
|
)
|
||||||
|
|
||||||
# The grid resolution, in degrees.
|
# The grid resolution, in degrees.
|
||||||
|
# 网格分辨率,单位为度。
|
||||||
STEP_DEGREES = 1.5
|
STEP_DEGREES = 1.5
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -36,11 +47,13 @@ def main() -> int:
|
||||||
|
|
||||||
# The grid is regular: latitude runs from 90 down to -90 and longitude
|
# The grid is regular: latitude runs from 90 down to -90 and longitude
|
||||||
# from 0 to 360, both in steps of 1.5 degrees.
|
# from 0 to 360, both in steps of 1.5 degrees.
|
||||||
|
# 该网格是规则的:纬度自 90 降到 -90,经度自 0 到 360,步长均为 1.5 度。
|
||||||
assert np.allclose(latitudes[:, 0], np.linspace(90.0, -90.0, rows)), "latitude grid"
|
assert np.allclose(latitudes[:, 0], np.linspace(90.0, -90.0, rows)), "latitude grid"
|
||||||
assert np.allclose(longitudes[0, :], np.linspace(0.0, 360.0, columns)), "longitude grid"
|
assert np.allclose(longitudes[0, :], np.linspace(0.0, 360.0, columns)), "longitude grid"
|
||||||
|
|
||||||
# The recommendation publishes the height to the nearest metre, so the
|
# The recommendation publishes the height to the nearest metre, so the
|
||||||
# table is stored in metres to avoid losing precision.
|
# table is stored in metres to avoid losing precision.
|
||||||
|
# 该建议书把高度发布到最近一米,故该表以米存储以避免损失精度。
|
||||||
metres = np.round(heights * 1000.0).astype(np.uint16)
|
metres = np.round(heights * 1000.0).astype(np.uint16)
|
||||||
|
|
||||||
print("/// The height of the zero degree isotherm, in metres.")
|
print("/// The height of the zero degree isotherm, in metres.")
|
||||||
|
|
@ -53,6 +66,15 @@ def main() -> int:
|
||||||
print("///")
|
print("///")
|
||||||
print("/// Source: ITU-R Recommendation P.839-4, *Rain height model for prediction")
|
print("/// Source: ITU-R Recommendation P.839-4, *Rain height model for prediction")
|
||||||
print("/// methods*, which tabulates the isotherm height on this grid.")
|
print("/// methods*, which tabulates the isotherm height on this grid.")
|
||||||
|
print("///")
|
||||||
|
print("/// 零度等温线的高度,单位为米。")
|
||||||
|
print("///")
|
||||||
|
print("/// 网格在行方向上自北纬 90 度到南纬 90 度,在列方向上自东经 0 度到")
|
||||||
|
print("/// 360 度,步长均为 1.5 度,故有 121 行 241 列。分数纬度或经度处的值")
|
||||||
|
print("/// 由周围四点之间的双线性插值求得。")
|
||||||
|
print("///")
|
||||||
|
print("/// 出处:ITU-R 建议书 P.839-4,*Rain height model for prediction methods*,")
|
||||||
|
print("/// 它在该网格上列出等温线高度。")
|
||||||
print(f"pub static ZERO_ISOTHERM_HEIGHT_METRES: [[u16; {columns}]; {rows}] = [")
|
print(f"pub static ZERO_ISOTHERM_HEIGHT_METRES: [[u16; {columns}]; {rows}] = [")
|
||||||
for row in range(rows):
|
for row in range(rows):
|
||||||
values = ", ".join(str(int(value)) for value in metres[row])
|
values = ", ".join(str(int(value)) for value in metres[row])
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue