Skip to content

数据库操作

dimine_python_sdk.lib.io 模块提供对 Dimine 钻孔数据库(.dmd)的原生访问能力,无需启动 Dimine GUI 即可读取和处理数据。

前置条件: - 环境变量 DIMINE_HOME 指向包含 DmPyBindInterface.pyd 的目录 - Python >= 3.12


模块定位

SDK 的数据处理层模块:

模块 用途 典型类
lib.io 钻孔数据库(.dmd)、DMF/DMG/DMT/DMB 文件读写 DmdFile、DmfFile、DmgFile、DmtFile、DmbFile
lib.prospecting 块模型估值与储量估算、钻孔处理封装器 BlockModelEvaluator、create_block_model、DrillFunctionWrapper
models 对外 Pydantic 纯数据模型 Point、Line、Shell

本文档覆盖 lib.io 中的钻孔数据库操作(DmdFile)。DMF 文件处理请参考 IO操作 和 文件格式转换。


一、钻孔数据库操作

dimine_python_sdk.lib.io 提供对 Dimine 钻孔数据库(.dmd)的专用访问能力。钻孔数据库包含四大核心表:孔口表、测斜表、岩性表、样品表,API 统一返回 pandas.DataFrame,列名均为中文标准格式,与 Python 数据科学生态无缝衔接。

列名规范:写入时 DataFrame 的列名必须使用中文标准列名;读取时返回的列名也为中文标准格式。

前置导入:

from dimine_python_sdk.lib.io import DmdFile, dmd_conn, DmdError

1.1 加载与创建

从文件加载

from dimine_python_sdk.lib.io import DmdFile

# 加载钻孔数据库
db = DmdFile("C:/Projects/Mine/钻孔数据.dmd")

# 支持相对路径
db = DmdFile("钻孔数据.dmd", base_path="C:/Projects/Mine")

创建空对象(从 DataFrame 写入)

初始化时不传路径,可以创建一个空白钻孔数据库对象,通过赋值 DataFrame 后再保存:

import pandas as pd
from dimine_python_sdk.lib.io import DmdFile

db = DmdFile()

# 准备 DataFrame(必须使用中文标准列名)
df_collar = pd.DataFrame({
    "工程号": ["ZK001", "ZK002"],
    "横坐标": [100.0, 200.0],
    "纵坐标": [300.0, 400.0],
    "高程": [500.0, 550.0],
    "总深度": [100.0, 120.0],
    "勘探线": ["L1", "L2"],
})

# 赋值到数据库
db.collar = df_collar

# 保存到文件
db.save("C:/Projects/Mine/新钻孔数据.dmd")

显式加载方法

也可以在创建空对象后,通过 load() 方法加载文件:

db = DmdFile()
db.load("C:/Projects/Mine/钻孔数据.dmd")
print(db.collar.head())

使用上下文管理器(推荐)

使用 dmd_conn 可确保资源自动释放,避免内存泄漏。支持传文件路径或创建空对象:

from dimine_python_sdk.lib.io import dmd_conn

# 从文件加载
with dmd_conn("C:/Projects/Mine/钻孔数据.dmd") as db:
    print(db.collar.head())
    # 离开 with 块后自动释放资源

# 创建空对象,赋值后保存
with dmd_conn() as db:
    db.collar = df_collar
    db.save("C:/Projects/Mine/新钻孔数据.dmd")

1.2 访问钻孔数据表

钻孔数据库包含四大核心表,通过属性即可访问,返回类型均为 pandas.DataFrame:

属性 说明 返回类型
db.collar 孔口表(钻孔基本信息:孔号、坐标、深度等) pd.DataFrame
db.survey 测斜表(钻孔轨迹测斜数据) pd.DataFrame
db.lithology 岩性表(钻孔岩性分层信息) pd.DataFrame
db.sample 样品表(化验样品数据) pd.DataFrame
db.extend_tables 扩展表列表(附加自定义数据表) list[NativeExtendTable]
db.table_names 所有表名列表(含扩展表) list[str]
from dimine_python_sdk.lib.io import dmd_conn

with dmd_conn("C:/Projects/Mine/钻孔数据.dmd") as db:
    # 访问四大表(均为 pd.DataFrame)
    collar = db.collar       # 孔口表
    survey = db.survey       # 测斜表
    lithology = db.lithology # 岩性表
    sample = db.sample       # 样品表

    # 也可以使用 dict 风格访问(含扩展表)
    collar = db["collar"]
    survey = db["survey"]
    lithology = db["lithology"]
    sample = db["sample"]
    # 扩展表也支持 dict 风格访问
    # ext_df = db["分层表"]

    # 获取所有表名(含扩展表)
    print(f"表名列表: {db.table_names}")
    print(f"表总数: {len(db)}")

    print(f"孔口表记录数: {len(collar)}")
    print(f"测斜表记录数: {len(survey)}")
    print(f"岩性表记录数: {len(lithology)}")
    print(f"样品表记录数: {len(sample)}")

DataFrame 操作示例

由于返回的是 pd.DataFrame,可直接使用 pandas 原生操作:

with dmd_conn("C:/Projects/Mine/钻孔数据.dmd") as db:
    # 获取所有钻孔孔号(Series)
    hole_ids = db.collar["工程号"]
    print(f"钻孔数量: {len(hole_ids)}")

    # 查看第一条孔口记录(Series)
    row = db.collar.iloc[0]
    print(row["工程号"], row["总深度"])

    # 获取前5条
    print(db.collar.head(5))

    # 字段名列表(均为中文标准列名)
    print(db.collar.columns.tolist())

    # 条件筛选
    deep_holes = db.collar[db.collar["总深度"] > 500]
    print(f"深孔数量: {len(deep_holes)}")

通过 setter 修改数据表

可以将修改后的 DataFrame 赋值回数据库:

with dmd_conn("C:/Projects/Mine/钻孔数据.dmd") as db:
    # 读取
    df = db.collar.copy()

    # 修改(保持中文标准列名)
    df["总深度"] = df["总深度"] * 1.1

    # 写回(仅更新内存缓存)
    db.collar = df

    # 保存(写入 .dmt 子表 + .dmd 引用)
    db.save()

1.3 标准列名映射规范 {: #standard-column-mapping }

DmdFile 对四大表的 DataFrame 列名有严格的格式要求。写入时必须使用中文标准列名;读取时返回中文标准列名。

孔口表(db.collar)

中文列名(输入) 英文列名(存储) 说明 必选
工程号 BHID 钻孔唯一标识 是
横坐标 EAST X 坐标 是
纵坐标 NOTRH Y 坐标 是
高程 ELEVATION Z 高程 是
总深度 TOTALDEPTH 钻孔总深度 是
勘探线 SECTION 所属勘探线 是
工程类型 工程类型 工程类型 否
其他 OTHERFIELDS 其他扩展字段 否
from dimine_python_sdk.lib.native.prospecting import COLLAR_COLUMN_MAP

# 查看完整映射
print(COLLAR_COLUMN_MAP)
# {'工程号': 'BHID', '横坐标': 'EAST', ...}

测斜表(db.survey)

中文列名(输入) 英文列名(存储) 说明
工程号 SURBHID 钻孔编号
测斜深度 SDEPTH 测斜深度
方位角 AZIMUTH 方位角
倾角 DIP 倾角

岩性表(db.lithology)

中文列名(输入) 英文列名(存储) 说明
工程号 LITHBHID 钻孔编号
起始 LITHFROM 起始深度
结束 LITHTO 结束深度
岩性编号 ROCK-TYPE 岩性编号

样品表(db.sample)

中文列名(输入) 英文列名(存储) 说明
工程号 SAMBHID 工程编号
样本编号 SAMPLE-ID 样品编号
起始 SAMFROM 样品起始深度
结束 SAMTO 样品结束深度

样品表除上述必选标准列外,还支持附加任意数量元素品位列(如 CU、TFE、AU、AG 等)。这些非标准列会写入 _sample.dmt 子表文件,但不会出现在 .dmd 引用映射中。

# 通过类属性查看完整映射
from dimine_python_sdk.lib.native.prospecting import SAMPLE_COLUMN_MAP
print(SAMPLE_COLUMN_MAP)
# {'工程号': 'SAMBHID', '样本编号': 'SAMPLE-ID', ...}

列名校验规则

写入时对 DataFrame 列名进行两级校验:

校验层级 规则 不满足时的行为
必选标准列 映射字典中标记为必选的列必须全部存在 抛出 DmdError,提示缺少的列
非标准列 不在映射字典中的额外列(如元素品位 CU、TFE 等)不会被拒绝 记录 debug 日志,列会写入 .dmt 子表但不出现于 .dmd 映射

各表必选标准列:

表 必选列
孔口表 工程号、横坐标、纵坐标、高程、总深度、勘探线
测斜表 工程号、测斜深度、方位角、倾角
岩性表 工程号、起始、结束、岩性编号
样品表 工程号、样本编号、起始、结束
  • 孔口表的 工程类型、其他 为可选标准列,缺失不会报错
  • 读取时,只保留映射字典中定义的列,多余列自动过滤;标准列按定义顺序排列,额外列保留在后
import pandas as pd
from dimine_python_sdk.lib.io import DmdFile

db = DmdFile()

# 正确:包含所有必选标准列 + 非标准列(元素品位)
db.sample = pd.DataFrame({
    "工程号": ["ZK001", "ZK001"],
    "样本编号": ["S001", "S002"],
    "起始": [0.0, 50.0],
    "结束": [50.0, 100.0],
    "CU": [0.35, 0.42],     # 非标准列,写入 .dmt 但不映射到 .dmd
    "AU": [1.2, 0.8],
    "AG": [5.0, 3.2],
})

# 正确:孔口表可选列 '其他' 可以省略
db.collar = pd.DataFrame({
    "工程号": ["ZK001"],
    "横坐标": [100.0],
    "纵坐标": [200.0],
    "高程": [50.0],
    "总深度": [150.0],
    "勘探线": ["L1"],
})

# 错误:缺少必选标准列
db.collar = pd.DataFrame({"工程号": ["ZK001"], "depth": [100.0]})
# DmdError: 孔口表 缺少必选标准列: ['横坐标', '纵坐标', '高程', '总深度', '勘探线']

1.4 保存与重新加载

from dimine_python_sdk.lib.io import DmdFile

db = DmdFile("C:/Projects/Mine/钻孔数据.dmd")

# 修改后保存(覆盖原文件)
db.save()

# 另存为新文件
db.save("C:/Projects/Mine/钻孔数据备份.dmd")

# 重新加载文件(清空缓存)
db.reload()

# 释放资源
db.close()

空对象调用 save() 不指定路径会抛出 DmdError,必须传入 output_path。


1.5 扩展表

扩展表是 DMD 钻孔数据库中的附加数据表,用于存储除四大核心表(孔口表、测斜表、岩性表、样品表)之外的自定义数据。常见用途包括:分层表、化探数据表、地质编录表等,适用于隐式地层建模等高级场景。

读取扩展表

from dimine_python_sdk.lib.io import dmd_conn

with dmd_conn("C:/Projects/Mine/钻孔数据.dmd") as db:
    # 获取所有扩展表
    for ext in db.extend_tables:
        print(f"表名: {ext.table_name}")
        print(f"DMT 文件: {ext.dmt_filename}")
        print(f"钻孔编号列: {ext.hole_id_column}")
        print(f"起始深度列: {ext.from_column}")
        print(f"结束深度列: {ext.to_column}")
        print(f"显示标题: {ext.display_title}")
        print(f"记录数: {len(ext.df)}")
        print(ext.df.head())

    # 通过表名直接访问扩展表数据
    df = db["分层表"]

    # 检查是否包含某扩展表
    if "分层表" in db:
        print("包含分层表")

写入扩展表

使用 NativeExtendTable 对象或 dict 设置扩展表数据:

import pandas as pd
from dimine_python_sdk.lib.io import DmdFile
from dimine_python_sdk.lib.native.models import NativeExtendTable

db = DmdFile()

# 设置四大核心表...
db.collar = collar_df
db.survey = survey_df
db.lithology = lithology_df

# 准备扩展表数据
ext_df = pd.DataFrame({
    "工程号": ["ZK001", "ZK001"],
    "起始": [0.0, 50.0],
    "结束": [50.0, 100.0],
    "分层名称": ["风化层", "基岩"],
})

# 方式一:使用 NativeExtendTable(推荐)
db.extend_tables = [
    NativeExtendTable(
        df=ext_df,
        dmt_filename="分层表.dmt",
        hole_id_column="工程号",
        from_column="起始",
        to_column="结束",
        display_title="分层表",
    ),
]

# 方式二:使用 dict(向后兼容)
db.extend_tables = [
    {
        "df": ext_df,
        "dmt_filename": "分层表.dmt",
        "hole_id_column": "工程号",
        "from_column": "起始",
        "to_column": "结束",
        "display_title": "分层表",
    },
]

# 保存(扩展表会自动写入伴随 .dmt 文件并更新 .dmd 引用)
db.save("C:/Projects/Mine/钻孔数据.dmd")

扩展表数据结构

每个扩展表(NativeExtendTable)包含以下字段:

字段 类型 说明
df pd.DataFrame 扩展表数据(保留 DMT 原始列名)
dmt_filename str 伴随 .dmt 文件名(如 "分层表.dmt")
table_name str 表名(优先 display_title,其次 dmt_filename 去后缀)
field_list str 字段元数据(逗号分隔的 4 个值:孔号列,起始深度列,结束深度列,标题)
hole_id_column str\|None 钻孔编号对应列名
from_column str\|None 起始深度对应列名
to_column str\|None 结束深度对应列名
display_title str\|None 标题名称(Dimine UI 显示用)

元数据自动推导:NativeExtendTable.__post_init__ 会自动完成 field_list ↔ 元数据字段(hole_id_column、from_column、to_column、display_title)的双向推导。设置 field_list 时自动解析出各元数据字段;设置元数据字段时自动构造 field_list。

扩展表在 info 中的展示

with dmd_conn("C:/Projects/Mine/钻孔数据.dmd") as db:
    info = db.info
    print(f"扩展表数量: {info['extend_table_count']}")
    for ext_info in info['extend_tables']:
        print(f"  {ext_info['table_name']}: {ext_info['rows']} 行, "
              f"列: {ext_info['columns']}")

1.6 钻孔数据处理

钻孔数据处理通过 DrillFunctionWrapper 封装器提供,均通过 Pydantic 参数模型传入。

样长组合

将不等长样品按指定长度重新组合:

from dimine_python_sdk.lib.prospecting import DrillFunctionWrapper
from dimine_python_sdk.lib.prospecting.models import SampleLengthCombineParam

params = SampleLengthCombineParam(
    input_file="C:/Projects/Mine/样品数据.dmg",
    combine_length=1.0,      # 组合长度 1m
    combine_percent=0.75,    # 组合百分比 75%(默认值)
    # output_file 可省略,自动生成为 样品数据_combined.dmg
)

result = DrillFunctionWrapper.sample_length_combine(params)
print(f"处理结果: {result}")

参数说明:

参数 类型 默认值 说明
input_file str (必选) 输入样品数据文件路径
combine_length float 1.0 组合长度(m),必须 > 0
combine_percent float 0.75 组合百分比,0-1 之间(传给 C++ 前自动 ×100 取整)
output_file str {input}_combined.dmg 输出文件路径(未设置时自动从输入文件名推导)

台阶组合

按台阶高程对样品数据进行组合:

from dimine_python_sdk.lib.prospecting import DrillFunctionWrapper
from dimine_python_sdk.lib.prospecting.models import StepCombineParam

params = StepCombineParam(
    input_file="C:/Projects/Mine/样品数据.dmg",
    step_height=2.0,       # 台阶高度(默认 2m)
    start_height=0.0,      # 起始高程
    end_height=100.0,      # 结束高程
    # calculate_model 默认 1(长度加权平均)
    # low_dip 默认 0.0
    # output_file 可省略,自动生成为 样品数据_step.dmg
)

result = DrillFunctionWrapper.step_combine(params)
print(f"处理结果: {result}")

参数说明:

参数 类型 默认值 说明
input_file str (必选) 输入 dmg 文件路径
step_height float 2.0 台阶高度
start_height float (必选) 起始高程
end_height float (必选) 结束高程
calculate_model int 1 计算方式:0=算术平均,1=长度加权平均
low_dip float 0.0 忽略的最小倾角,即忽略倾角 ≤ ±该值的钻孔
output_file str {input}_step.dmg 输出文件路径(未设置时自动从输入文件名推导)

特高品位处理

对超过阈值的特高品位样品进行处理:

from dimine_python_sdk.lib.prospecting import DrillFunctionWrapper
from dimine_python_sdk.lib.prospecting.models import HighGradeProcessParam

params = HighGradeProcessParam(
    input_file="C:/Projects/Mine/样品数据.dmg",
    grade_field="Cu",           # 品位字段
    process_mode=0,             # 0:国内标准
    average_multiple=6,         # 平均值倍数
    frequency=0.95,             # 累积频率阈值
    replace_method=2,           # 2:相邻样品平均值
    assign_value=2.5,           # 替换给定值
    result_field="Cu_processed", # 结果字段名
)

result = DrillFunctionWrapper.extra_high_grade_process(params)
print(f"处理结果: {result}")

参数说明:

参数 类型 默认值 说明
input_file str (必选) 输入 dmg 文件路径
grade_field str (必选) 品位字段名(如 Cu、Au)
process_mode int 0 处理模式:0=国内标准,1=国外标准
average_multiple int 6 平均值倍数(仅 6/7/8)
frequency float 0.95 累积频率阈值,0-1 之间
replace_method int 2 替换方式(见下表)
assign_value float 0.0 给定值(replace_method=1 时生效)
adjoin_average float 2 相邻样品平均值
average_method int 1 平均值计算方式:0=算数平均,1=长度加权平均
contain_mode int 0 包含模式:0=包含特高品位,1=不包含
result_field str {grade_field} 结果字段名(未设置时默认为源品位字段名)

replace_method 枚举:

值 说明
0 剔除法
1 给定值
2 相邻样品平均值
3 矿体平均品位法
4 单一工程法
5 截止品位法

1.7 异常处理

from dimine_python_sdk.lib.io import dmd_conn, DmdError, DmdLoadError

# 加载异常
try:
    with dmd_conn("不存在的文件.dmd") as dmd:
        print(dmd.collar.head())
except DmdLoadError as e:
    print(f"加载失败: {e}")

# 处理异常(DrillFunctionWrapper 直接传播原生异常)
try:
    from dimine_python_sdk.lib.prospecting import DrillFunctionWrapper
    from dimine_python_sdk.lib.prospecting.models import SampleLengthCombineParam

    params = SampleLengthCombineParam(
        input_file="无效路径.dmf",
        combine_length=1.0,
        output_file="输出.dmf",
    )
    result = DrillFunctionWrapper.sample_length_combine(params)
except Exception as e:
    print(f"处理失败: {e}")

二、完整示例

示例一:读取并分析已有钻孔数据库

from dimine_python_sdk.lib.io import dmd_conn
from dimine_python_sdk.lib.prospecting import DrillFunctionWrapper
from dimine_python_sdk.lib.prospecting.models import SampleLengthCombineParam


def main():
    file_path = "C:/Projects/Mine/钻孔数据.dmd"

    with dmd_conn(file_path) as dmd:
        # 1. 打印数据库概况
        print("=" * 40)
        print("钻孔数据库概况")
        print("=" * 40)
        print(f"文件路径: {dmd.file_path}")
        print(f"孔口表记录数: {len(dmd.collar)}")

        # 2. 查看孔口表结构
        print("\n" + "=" * 40)
        print("孔口表信息")
        print("=" * 40)
        print(f"字段: {dmd.collar.columns.tolist()}")
        print(f"记录数: {len(dmd.collar)}")

        # 3. 查看前3条孔口记录
        print("\n前3条孔口记录:")
        print(dmd.collar.head(3))

        # 4. 提取所有孔号
        hole_ids = dmd.collar["工程号"]
        print(f"\n所有钻孔: {hole_ids.tolist()}")

        # 5. pandas 分析
        print(f"\npandas DataFrame 形状: {dmd.collar.shape}")
        print(dmd.collar.describe())

        # 6. 样长组合示例
        print("\n" + "=" * 40)
        print("样长组合处理")
        print("=" * 40)
        params = SampleLengthCombineParam(
            input_file="C:/Projects/Mine/样品数据.dmf",
            combine_length=1.0,
            combine_percent=1.0,
            output_file="C:/Projects/Mine/组合后样品.dmf",
        )
        result = DrillFunctionWrapper.sample_length_combine(params)
        print(f"处理结果: {result}")


if __name__ == "__main__":
    main()

示例二:从 DataFrame 创建新的钻孔数据库

import pandas as pd
from dimine_python_sdk.lib.io import DmdFile


def create_drill_db():
    # 1. 创建空对象
    db = DmdFile()

    # 2. 准备孔口表
    df_collar = pd.DataFrame({
        "工程号": ["ZK001", "ZK002", "ZK003"],
        "横坐标": [100.0, 200.0, 300.0],
        "纵坐标": [400.0, 500.0, 600.0],
        "高程": [700.0, 750.0, 800.0],
        "总深度": [150.0, 200.0, 180.0],
        "勘探线": ["L1", "L2", "L3"],
        "其他": ["备注1", "备注2", "备注3"],
    })

    # 3. 准备测斜表
    df_survey = pd.DataFrame({
        "工程号": ["ZK001", "ZK001", "ZK002", "ZK002"],
        "测斜深度": [0.0, 50.0, 0.0, 80.0],
        "方位角": [30.0, 32.0, 45.0, 47.0],
        "倾角": [-60.0, -62.0, -55.0, -58.0],
    })

    # 4. 准备岩性表
    df_lithology = pd.DataFrame({
        "工程号": ["ZK001", "ZK001", "ZK002"],
        "起始": [0.0, 50.0, 0.0],
        "结束": [50.0, 150.0, 200.0],
        "岩性编号": ["花岗岩", "砂岩", "页岩"],
    })

    # 5. 准备样品表(可选;除标准列外可附加元素品位等非标准列)
    df_sample = pd.DataFrame({
        "工程号": ["ZK001", "ZK001", "ZK002"],
        "样本编号": ["S001", "S002", "S003"],
        "起始": [0.0, 50.0, 0.0],
        "结束": [50.0, 100.0, 80.0],
        "CU": [0.35, 0.42, 0.28],   # 非标准列:铜品位
        "AU": [1.2, 0.8, 2.1],      # 非标准列:金品位
    })

    # 6. 赋值到数据库
    db.collar = df_collar
    db.survey = df_survey
    db.lithology = df_lithology
    db.sample = df_sample

    # 7. 保存
    db.save("C:/Projects/Mine/新钻孔数据.dmd")
    print("数据库已保存")


if __name__ == "__main__":
    create_drill_db()

示例三:从 CSV 导入数据并保存为钻孔数据库

从外部系统导出的 CSV 文件,通过列名映射转换为标准格式后,可直接保存为 .dmd 钻孔数据库,在 Dimine 中打开使用。

完整代码见 examples/import_csv_to_drill_db.md,核心步骤如下:

import pandas as pd
from dimine_python_sdk.lib.io import DmdFile

# 1. 读取外部 CSV,映射为中文标准列名
df_collar = pd.read_csv("raw_collar.csv").rename(columns={
    "HoleID": "工程号",
    "X": "横坐标",
    "Y": "纵坐标",
    "Z": "高程",
    "Depth": "总深度",
    "Line": "勘探线",
})

# 2. 同理导入测斜表、岩性表
df_survey = pd.read_csv("raw_survey.csv").rename(columns={
    "HoleID": "工程号",
    "Depth": "测斜深度",
    "Azimuth": "方位角",
    "Dip": "倾角",
})

df_lithology = pd.read_csv("raw_lithology.csv").rename(columns={
    "HoleID": "工程号",
    "From": "起始",
    "To": "结束",
    "Rock": "岩性编号",
})

# 3. 赋值并保存
db = DmdFile()
db.collar = df_collar
db.survey = df_survey
db.lithology = df_lithology

db.save("钻孔数据.dmd")
print("已保存为钻孔数据库,可在 Dimine 中直接打开")

后续步骤:钻孔数据库准备好后,可进入 储量估算 流程—— 样品组合 → 特高品位处理 → 创建块段模型 → 搜索椭球体参数计算 → 估值 → 储量计算。