Author: He XingChen
Last Updated: 2026-08-14

原生 Fortran 后端(HASH-HP)

CNCHASH 基于 Modern Fortran + OpenMP 后端构建。所有数值计算(网格搜索、 S/P 振幅、不确定性分析、速度模型表)都在 libhashhp 中运行;Python 层负责 API、文件处理和批量调度。如果没有编译原生库,包会给出明确的 构建错误。

架构

HASH_complete/            # 原始 Fortran HASH v1.2(不可变上游,golden reference)
cnchash/                  # Python 包
  ├── backend/
  │   ├── base.py         # HashBackend 接口
  │   └── fortran_backend.py  # libhashhp 的 ctypes 绑定
  ├── driver.py           # run_hash / run_hash_batch
  ├── io.py               # 震相/台站文件处理
  └── utils.py            # 纯 Python 工具
src/hash_hp/              # Modern Fortran 核心
  ├── hash_kinds.f90      # real64/int32 类型定义
  ├── hash_geometry.f90   # TO_CAR/FPCOOR/cross
  ├── hash_rotation.f90   # 旋转网格缓存
  ├── hash_runtime.f90    # 网格缓存 + OpenMP 线程控制
  ├── hash_focalmc.f90    # FOCALMC,旋转方向 OpenMP 并行
  ├── hash_misfit.f90     # GET_GAP/GET_MISF
  ├── hash_uncertainty.f90# MECH_ROT/MECH_AVG/MECH_PROB
  ├── hash_amplitude.f90  # FOCALAMP_MC/GET_MISF_AMP
  ├── hash_velocity.f90   # LAYERTRACE/MK_TABLE/GET_TTS
  ├── hash_batch.f90      # 完整事件流水线 + 事件级并行批处理
  └── hash_c_api.f90      # 稳定的 ISO_C_BINDING ABI(ctypes,无需 f2py)

设计规则

  • 内核无 I/O。 src/hash_hp 只接收数组并返回数组;文件、格式和 异常都由 Python 处理。

  • 热循环零分配。 每个事件的 workspace 复用;旋转网格每个 dang 只构建一次,之后共享只读。

  • 禁止嵌套 OpenMP。 批量模式要么按事件并行、要么按旋转并行,绝不 同时嵌套。

  • 默认确定性。 可接受机制按网格顺序取前 maxout 个 (selection=0)。传入 selection=1 可复现原始 HASH 的随机选择。

  • 默认不开 -ffast-math 科学计算正确性优先;如需开启显式设置 CNCHASH_FAST_MATH=ON

  • HASH_complete/ 保持不动。 它是 golden reference。

构建

cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build

默认为可移植构建。设置 -DCNCHASH_NATIVE_MARCH=ON 可生成仅在当前 机器上运行、约快 2.5 倍的本机优化版本。

后端选择

from cnchash import run_hash, available_backends, get_backend_info

run_hash(az, the, pol, qual, backend="auto")     # 默认(fortran)
run_hash(az, the, pol, qual, backend="fortran")  # 显式指定
print(available_backends())
print(get_backend_info())

环境变量:CNCHASH_BACKENDCNCHASH_NUM_THREADSCNCHASH_HASHHP_LIB(显式指定库路径)。

批量模式

run_hash_batch 一次调用将大量事件送入 Fortran 核心(CSR 风格扁平 数组),大型目录使用事件级 OpenMP 并行:

from cnchash import run_hash_batch

results = run_hash_batch(events, nmc=30, backend="fortran", num_threads=16)

与 HASH v1.2 的有意差异

项目

HASH v1.2

HASH-HP

GET_GAP 空隙

INTEGER(隐式类型截断)

REAL(空隙为连续值)

GET_MISF 断层面向量

弧度被误当作度数(单位 bug)

已修复:向 FPCOOR 传度数

GET_MISF_AMP stdr

振幅台站累计权重

相同

nf > maxout 时的选择

rand(0) 随机

默认确定性

velocity GET_TTS 深度检查

d(nd0)(未初始化)

d(ndep)

velocity 射线缓冲区

固定 10001(可能溢出)

20001 堆分配

所有差异都是 bug 修复。测试保证可接受机制集合和首选解在相同输入下 与原始 HASH v1.2 一致(见 tests/test_accuracy.py),仅剩聚类边界上 单精度与双精度带来的微小差异。