Skip to content

Stats

zdem_dfn.stats

网络统计报告: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)