网络统计报告:p21 实际 vs 目标、倾向分布、迹长分布。
只做只读统计,不参与网络生成。数据全部由已有几何对象(裂隙线段端点)
推导:迹长 = 两端点欧氏距离;方向角 = atan2(dy, dx) 折到 [0, 180)。
compute_dip_bins(dips, bin_size=DIP_BIN_DEG, max_deg=180.0)
方向角直方图分箱。返回长度 round(max_deg/bin_size) 的计数列表。
Source code in zdem_dfn/stats.py
31
32
33
34
35
36
37
38
39
40 | def compute_dip_bins(dips: Sequence[float],
bin_size: float = DIP_BIN_DEG,
max_deg: float = 180.0) -> list[int]:
"""方向角直方图分箱。返回长度 round(max_deg/bin_size) 的计数列表。"""
n_bins = max(1, int(round(max_deg / bin_size)))
bins = [0] * n_bins
for dip in dips:
idx = min(int(dip // bin_size), n_bins - 1)
bins[idx] += 1
return bins
|
compute_network_stats(fractures, min_x, max_x, min_y, max_y)
统计裂隙网络。
返回 dict:
- count / total_length / mean_length / min_length / max_length
- p21_actual(总迹长/面积)与 p21_target(各 FRACTURE_SETS 之和,运行时读 config)
- dip_bins:以 10° 分箱的方向角计数(含上界闭合 bin)
- length_bins:10 个等宽迹长区间的计数
- window:统计窗口(面积、X/Y 范围)
Source code in zdem_dfn/stats.py
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 | def compute_network_stats(fractures: Sequence[Segment],
min_x: float, max_x: float,
min_y: float, max_y: float) -> dict[str, Any]:
"""统计裂隙网络。
返回 dict:
- count / total_length / mean_length / min_length / max_length
- p21_actual(总迹长/面积)与 p21_target(各 FRACTURE_SETS 之和,运行时读 config)
- dip_bins:以 10° 分箱的方向角计数(含上界闭合 bin)
- length_bins:10 个等宽迹长区间的计数
- window:统计窗口(面积、X/Y 范围)
"""
area = (max_x - min_x) * (max_y - min_y)
lengths: list[float] = []
dips: list[float] = []
for seg in fractures:
length, dip = _segment_length_and_dip(seg)
lengths.append(length)
dips.append(dip)
p21_target = 0.0
for fset in config.FRACTURE_SETS:
p21_target += float(fset.get("p21", 0.0))
dip_bins = compute_dip_bins(dips)
if lengths:
lo, hi = min(lengths), max(lengths)
width = (hi - lo) / LENGTH_BIN_COUNT if hi > lo else 1.0
length_bins = [0] * LENGTH_BIN_COUNT
for length in lengths:
idx = min(int((length - lo) / width), LENGTH_BIN_COUNT - 1)
length_bins[idx] += 1
length_bin_edges = [lo + i * width for i in range(LENGTH_BIN_COUNT + 1)]
else:
length_bins = [0] * LENGTH_BIN_COUNT
length_bin_edges = [0.0] * (LENGTH_BIN_COUNT + 1)
total_length = sum(lengths)
return {
"count": len(fractures),
"total_length": total_length,
"mean_length": total_length / len(fractures) if fractures else 0.0,
"min_length": min(lengths) if lengths else 0.0,
"max_length": max(lengths) if lengths else 0.0,
"p21_actual": total_length / area if area > 0 else 0.0,
"p21_target": p21_target,
"window_area": area,
"window": (min_x, max_x, min_y, max_y),
"dip_bin_size": DIP_BIN_DEG,
"dip_bins": dip_bins,
"length_bin_edges": length_bin_edges,
"length_bins": length_bins,
}
|
write_stats_report(stats, path, tag_counts=None)
写统计报告。.csv 后缀 → CSV;其余 → Markdown。
tag_counts:可选的颗粒标签计数(如 {"DFN_Matrix": 1503, ...})附在报告尾部。
Source code in zdem_dfn/stats.py
104
105
106
107
108
109
110
111
112
113
114 | def write_stats_report(stats: dict[str, Any], path: str,
tag_counts: dict[str, int] | None = None) -> None:
"""写统计报告。``.csv`` 后缀 → CSV;其余 → Markdown。
tag_counts:可选的颗粒标签计数(如 {"DFN_Matrix": 1503, ...})附在报告尾部。
"""
ext = os.path.splitext(path)[1].lower()
if ext == ".csv":
_write_csv(stats, path)
return
_write_markdown(stats, path, tag_counts)
|