Skip to content

装药模板套用与适配

全局配置库里的装药结构模板(explosivemodel.dmt,如 连续装药 / 间隔装药)以某个标定孔深描述炮孔自孔口 → 孔底的分段结构——第 0 段固定是孔口填塞物。 真实炮孔孔深几乎不可能正好等于标定总长,因此需要把模板按「装药模式 × 调整规则」适配到 每根孔:填塞保规范下限、炸药 / 间隔按策略取舍或压缩、富余空间补到孔口填塞或末段间隔, 保证分段总长精确 = 孔深

适用场景:工地有成熟的装药结构经验模板(一段一段怎么装已标定好),希望按模板结构去装药, 而不是让 SDK 用单耗公式凭空生成结构。若没有固定模板、更想「按单耗算药量」,用直算入口 design_charge(见 爆破设计流程 / 装药)。

本模块算法移植自 Dimine CDesignExplosiveOperator(修正版)。数值口径:长度 m、重量 kg、 延时 ms;重量按炸药段逐段 × 线装药密度累加。

from dimine_python_sdk.lib.blasting import (
    ChargeParams, Explosive, Hole, ChargeMode, AdjustRule,
    design_charge_from_template, adapt_charge_template, TemplateAdaptation,
)
from dimine_python_sdk.lib.blasting.charge_design import min_stemming_length

一、底层适配 adapt_charge_template

单孔(几何层,不绑定孔对象)把模板适配到给定孔深:

result: TemplateAdaptation = adapt_charge_template(
    hole_length=16.0,                 # 真实孔深 m
    segments=template_segments,        # 模板分段(ChargeSegment / dict),第 0 段=孔口填塞
    mode=ChargeMode.MIN_STEMMING,      # 装药模式
    adjust=AdjustRule.PROPORTIONAL,    # 调整规则
    min_block_length=4.5,              # 最小填塞规范下限(用 min_stemming_length 算)
    line_density={"2#岩石炸药": 6.0},    # 炸药名 → 线装药密度 kg/m
    # 仅模式1(按单耗)需要:
    # consumption=0.4, hole_space=5.0, row_space=4.0,
    # primary_density_default=6.0,     # 模板炸药名查不到密度时的兜底
)

min_block_length 请用公式装药与模板适配共用的权威口径:

# = max(min_stemming, 0.7·W, 20·直径m, 4.5m)
min_block_length = min_stemming_length(ChargeParams(), burden=4.0, diameter_m=220.0 / 1000.0)

返回 TemplateAdaptation(frozen dataclass):

字段 说明
ok 是否适配成功
fail_code / fail_reason 失败原因 A/B/C(见下)
segments 适配后的分段(自孔口→孔底),总长精确 = 孔深
charge_length / charge_weight 装药总长度 m / 装药总量 kg
stemming_length / spacer_length 填塞长度 m / 间隔总长度 m(间隔器+空气)

三种失败(不抛异常ok=False + fail_code

code 含义
A 孔深 ≤ 最小填塞规范下限
B 孔深 < 按单耗所需装药长度(仅模式1)
C 孔深 < 最小填塞 + 间隔总长(仅模式2)

结构 / 参数本身的错误(模板为空、无有效长度、模式1 缺参数或无炸药段、炸药名既查不到密度又无兜底) 则抛 ValueError

三种装药模式 × 三种调整规则

装药模式 ChargeMode(决定「优先级」):

模式 优先级 行为
MIN_STEMMING 优先最小填塞和炸药 填塞保最小 → 炸药尽量保 → 间隔尽量保 富余全给孔口填塞;空间不足先放弃间隔再压缩炸药
BY_SPECIFIC_CHARGE 优先按单耗 按单耗定药量 → 填塞保最小 目标药量 = consumption × 孔距×排距 × 孔深,按模板炸药段「长度×密度」比例反解各段实装长度,使实装药量恰好等于目标
STEMMING_SPACER 优先填塞和间隔器 间隔全保 → 填塞保最小 → 剩余给炸药 保留模板全部间隔,其余空间给炸药

调整规则 AdjustRule(决定炸药段被压缩 / 有多余时「保哪一侧」):

规则 语义
PROPORTIONAL 按比例 各炸药段按模板长度比例等比缩放
MOUTH_FIRST 优先孔口装药 自孔口段起逐段保证(模板长度),装完即止
BOTTOM_FIRST 优先孔底装药 自孔底段倒序保证;仍有富余则补到孔口侧第一段

直观效果(对同一根 10 m 孔、同一模板,见 test_template_adapt_strategy.py): 模式0 药量 ≥ 模式1 ≥ 模式2;模式2 保留间隔、余量喂炸药;MOUTH_FIRST 保孔口段、 BOTTOM_FIRST 保孔底段。孔深恰好等于模板总长时,任何模式/规则都逐段还原模板。


二、批量入口 design_charge_from_template

对一整批炮孔套模板,直接产出 .dmo 可用的装药结果:

from dimine_python_sdk.lib.blasting import ChargeTemplateDB

# 1) 从模板库取出一个模板(自孔口→孔底;模板不存在 → [])
db = ChargeTemplateDB()
template_segments = db.segments("间隔装药")

# 2) 炸药库(主炸药 = 模板炸药段命中的名字,否则取列表首个;其线密度兼作未知段名的兜底)
explosives = [Explosive(name="2#岩石炸药", line_density=6.0, unit_price=5.0),
              Explosive(name="乳化炸药", line_density=6.0, unit_price=8.0)]

# 3) 逐孔套模板(mode / adjust 由 ChargeParams 决定)
results = design_charge_from_template(
    holes,                       # 布孔结果 list[Hole]
    template_segments,
    explosives,
    burden=4.0,                  # 最小抵抗线 W m
    params=ChargeParams(
        charge_mode=ChargeMode.MIN_STEMMING,   # 或 BY_SPECIFIC_CHARGE / STEMMING_SPACER
        adjust_rule=AdjustRule.PROPORTIONAL,
        specific_charge=0.4,                   # 模式1 使用
    ),
)  # -> list[ChargeResult](每孔一个,顺序同 holes)

每个炮孔内部先算 min_block = min_stemming_length(params, W, 孔径m),再交给 adapt_charge_template失败孔不抛异常:返回 segments == []charge_weight == 0,并把原因写进该孔 warnings (如 "[装药结构适配失败:原因A] 孔深小于最小填塞长度");模板不含炸药段时给黄/红提示且药量为 0。

for r in results:
    if not r.segments:
        print(r.hole_number, "适配失败:", r.warnings)   # 原因 A/B/C,需人工处理(如并入深孔或降台阶)

ChargeResult 各字段与直算口径一致(specific_charge_area 记录每孔负担面积:前排 a×W、 后排 a×b),可直接交给 起爆网络与 DMO 的后续步骤。


三、完整示例(含校验)

from dimine_python_sdk.lib.blasting import (
    BlastRegion, HoleLayoutParams, Hole, ChargeParams, ChargeMode, AdjustRule,
    ChargeTemplateDB, layout_holes, design_charge_from_template, build_network,
)

# 布孔
region = BlastRegion(
    name="M01",
    polygon=[(0, 0), (30, 0), (30, 25), (0, 25)],
    mouth={"mode": "z", "value": 765.0},
    bottom={"mode": "depth", "value": 15.0},
)
holes = layout_holes(region, HoleLayoutParams(hole_spacing=5.0, row_spacing=4.0))

# 取模板 + 装药
template = ChargeTemplateDB().segments("间隔装药")      # 需 DIMINE_HOME
results = design_charge_from_template(
    holes, template,
    [Explosive(name="2#岩石炸药", line_density=6.0)],
    burden=4.0,
    params=ChargeParams(charge_mode=ChargeMode.MIN_STEMMING,
                        adjust_rule=AdjustRule.PROPORTIONAL),
)

# 校验不变式(与公式装药引擎一致)
assert len(results) == len(holes)
for r in results:
    if r.segments:
        assert abs(sum(s.length for s in r.segments) - r.depth) < 1e-6   # 总长=孔深
        assert r.segments[0].fill_type == template[0].fill_type           # 首段=孔口填塞
        assert r.stemming_length >= 4.5                                   # 填塞 ≥ 规范下限
        for s in r.segments:
            assert s.delay >= 0 or s.fill_type in ("填塞物", "间隔器", "空气")  # 惰性段 delay=-1

记忆要点:模板第 0 段固定为孔口填塞物,其长度由算法重算,模板里写多少不影响; 适配后的炸药段雷管延时沿用模板设定(如 350 → 380 → 410 ms),惰性段恒为 -1; 起爆药包 / 空气参与结构与起爆,但 起爆药包 重量计 0。


参考链接