1. Res2DInv 工程数据导入与测线拓扑检查
为什么先做拓扑检查再反演
Res2DInv 的反演网格是按“测线位置—电极间距—排列类型”三者共同建立的。如果导入的数据里电极间距不一致、测点序号跳号,或者某条排列的电极坐标与相邻排列对不上,反演程序不会报错,而是把这些点当作真实的地电异常去拟合,最终在剖面上形成假的“高阻/低阻竖条”。因此导入后的第一件事不是点反演,而是把测线拓扑核对清楚。
本例使用一条 24 电极、电极间距 5 m 的温纳剖面作为教学示例数据(示例数据,非实测),测线沿 x 方向布设,电极编号 1~24,对应桩号 0~115 m。数据文件采用 Res2DInv 通用 DAT 格式:第一行为排列类型与电极数,随后每行是“测点位置序号、电极距系数 n、视电阻率”。
导入前的数据准备与格式约定
Res2DInv 的 DAT 文件对字段位置敏感,导入前先确认三件事:排列类型代码、电极总数、每行的四个字段顺序。温纳排列的通用写法如下(示例数据):
1
24
1 1 0.0 128.4
2 1 5.0 131.7
3 1 10.0 126.9
...
1 2 2.5 142.3
2 2 7.5 139.8
...
字段含义依次为:测点序号、电极距系数 n、测点中心桩号(m)、视电阻率(Ω·m)。注意第三列是“测点中心位置”,温纳排列中它等于当前四电极组的中心桩号,而不是第一个电极的桩号。这一点在检查拓扑连续性时最容易出错。
测线拓扑检查的三个判据
- 电极间距一致性:同一 n 值下,相邻测点中心桩号之差应恒等于电极间距 a(本例 5 m)。若出现 4.8、5.2 之类的偏差,说明野外电极实际位置与记录不符。
- 测点连续性:同一 n 值下的测点序号应连续,缺号意味着该位置数据缺失,需在 DAT 中补占位行或明确标记。
- 排列覆盖范围:n 越大,参与电极跨度越大,可用的测点中心越少。检查每个 n 的测点数量是否符合 (N - 3n) 的预期,本例 N=24,n=1 应有 21 个测点,n=2 应有 18 个,依此类推。
用脚本完成批量核对
手工核对 24 电极、3 个 n 层的数据容易漏项,下面这段 Python 脚本直接读取 DAT 文件,按 n 分组检查间距、序号连续性和测点数量,并输出异常清单。脚本只依赖标准库,可直接运行。
import csv
A = 5.0 # 电极间距 (m)
N_ELECTRODES = 24
def load_dat(path):
rows = []
with open(path, newline='') as f:
lines = [ln.strip() for ln in f if ln.strip()]
# 第 1 行排列类型,第 2 行电极数,之后为数据
for ln in lines[2:]:
parts = ln.split()
if len(parts) < 4:
continue
idx, n, center, rho = int(parts[0]), int(parts[1]), float(parts[2]), parts[3]
rows.append({"idx": idx, "n": n, "center": center, "rho": rho})
return rows
def check_topology(rows):
issues = []
by_n = {}
for r in rows:
by_n.setdefault(r["n"], []).append(r)
for n, pts in sorted(by_n.items()):
pts.sort(key=lambda p: p["idx"])
expected = N_ELECTRODES - 3 * n
if len(pts) != expected:
issues.append(f"n={n}: 测点数 {len(pts)},预期 {expected}")
# 序号连续性
for i in range(1, len(pts)):
if pts[i]["idx"] != pts[i-1]["idx"] + 1:
issues.append(f"n={n}: 序号跳号 {pts[i-1]['idx']} -> {pts[i]['idx']}")
# 间距一致性
for i in range(1, len(pts)):
d = pts[i]["center"] - pts[i-1]["center"]
if abs(d - A) > 1e-6:
issues.append(f"n={n}: 第 {pts[i]['idx']} 点间距 {d:.2f} m,应为 {A} m")
# 空值
for p in pts:
if p["rho"] in ("", "-", "NaN"):
issues.append(f"n={n}: 第 {p['idx']} 点视电阻率缺失")
return issues
if __name__ == "__main__":
data = load_dat("line01.dat")
problems = check_topology(data)
if problems:
print("发现异常:")
for p in problems:
print(" -", p)
else:
print("拓扑检查通过,可进入反演。")
脚本输出的异常清单就是“异常测点记录表”的原始内容。对每条异常,按下面的处理原则决定是修正、补占位还是剔除:
| 异常类型 | 判断依据 | 处理方式 |
|---|---|---|
| 间距偏差 ≤ 0.5 m | 野外电极实际位置与记录不符 | 按实测桩号修正 center 字段,保留数据 |
| 间距偏差 > 0.5 m | 可能电极被移动或记录错误 | 标记为可疑点,反演前剔除或单独复核 |
| 序号跳号 | 该位置无观测 | 补占位行(rho 留空),保持网格对齐 |
| 视电阻率缺失 | 仪器未记录或读数无效 | 补占位行并标记,不参与反演拟合 |
输出可反演的数据文件
修正完成后,把处理结果写回 DAT 文件。注意 Res2DInv 对空值的容忍度有限,缺失点建议用占位行保留位置,而不是直接删行——删行会让后续测点序号整体前移,反演网格随之错位。下面是在同一脚本中追加的写出函数:
def write_dat(path, rows, arr_type=1, n_electrodes=24):
with open(path, "w") as f:
f.write(f"{arr_type}\n{n_electrodes}\n")
for r in sorted(rows, key=lambda x: (x["n"], x["idx"])):
rho = r["rho"] if r["rho"] not in ("", "-", "NaN") else ""
f.write(f"{r['idx']} {r['n']} {r['center']:.1f} {rho}\n")
写出后重新运行 check_topology,确认异常清单为空或只剩已标记的可疑点,即可把该 DAT 文件作为反演输入。同时把异常测点整理成一张记录表,随数据一起归档,便于后续反演结果出现异常时回溯。