DEM-Engine与ParaView的使用
提示:随着学习会不断加深里面的👩
文章目录
一、DEM-Engine
DEM-Engine 是一款专门用于离散元法(Discrete Element Method, DEM)的高性能数值模拟引擎,核心是用来模拟颗粒 / 粉体 / 散体物料的运动、碰撞、受力与堆积行为。
代码:https://github.com/projectchrono/DEM-Engine
这里面需要是c++代码,要重新编译,可以把readme喂给豆包,一点一点的安装吧,要用GPU加速才行
二、DEM-Engine可以做什么?
-
工业粉体 / 颗粒过程模拟 3D 打印清粉工艺优化:就像你正在做的,模拟 SLM/SLS 打印后,零件内腔、流道里的粉末残留分布、流动和清粉过程(吹气、振动、吹扫),找到死角和清粉难点,优化工艺参数。
-
粉体输送与混合:模拟料仓、螺旋输送机、混粉机里的颗粒流动、堵塞、偏析问题,优化设备结构和工艺参数。 破碎 /
研磨设备设计:模拟矿石、物料在破碎机、球磨机里的破碎、磨损过程,预测设备寿命和生产效率。 -
岩土与地质工程:模拟土壤、砂石、尾矿的堆积、滑坡、沉降过程,分析边坡稳定性、地基承载力。模拟盾构机、掘进机刀具与岩土颗粒的相互作用,优化刀具设计和施工参数。
-
化工与制药行业模拟流化床、反应器里的颗粒流化、传热传质过程,优化反应效率。模拟药片、胶囊的混合、压片、输送过程,预测粉体流动性和成品质量。
-
能源与矿业模拟煤矿、矿石在输送、装卸、筛分过程中的行为,优化矿场设备和流程。模拟储料仓、料斗的卸料过程,分析结拱、堵塞问题。
三、它的核心能力:为什么用它,而不是普通软件?
- 精准的颗粒物理模型能模拟颗粒间的碰撞、摩擦、粘附、团聚,以及颗粒与设备 零件壁面的相互作用,甚至可以加入热传导、静电、湿颗粒(含液体)等复杂效应,非常贴近真实粉体行为。
- 大规模并行计算(GPU/CPU)像你现在处理的百万级颗粒数据,DEM-Engine 通常支持 GPU
加速,能高效处理超大规模颗粒体系,快速得到模拟结果,这也是你需要 ParaView 配合做后处理的原因。与多物理场耦合可以和流体力学(CFD)、有限元(FEM)耦合,比如模拟气固两相流、颗粒对设备的磨损和冲击,实现 “粉体 + 流体 +结构” 的多场协同分析。 - 完整的前处理 - 求解 - 后处理流程支持颗粒生成、零件几何导入、参数设置、求解计算,再输出时间序列点云数据(也就是你现在用
ParaView 打开的 CSV 文件),方便后续做可视化和分析。
代码怎么使用
有两点需要注意:
- DEM-Engine默认的以米为单位,所以你要判断你的模型是以米为单位,还是以毫米为单位,如果以毫米为单位,需要缩小一千倍drum_mesh->Scale(0.01f)
- drum_mesh->SetInitPos(make_float3(0, 0, 0));这里面的三个点,代表了你模型的初始中心点放在了(0,0,0),就是模型的中心点
- 粒子不要太小
- 世界大小,要足够的大一些
- 粒子之间的距离很重要
怎么判断模型是以米为单位,还是以毫米为单位
如果是几十上百,基本上是以毫米为单位,如果0.几基本上就是以米为单位
// Copyright (c) 2021, SBEL GPU Development Team
// Copyright (c) 2021, University of Wisconsin - Madison
//
// SPDX-License-Identifier: BSD-3-Clause
#include <core/ApiVersion.h>
#include <core/utils/ThreadManager.h>
#include <DEM/API.h>
#include <DEM/HostSideHelpers.hpp>
#include <DEM/utils/Samplers.hpp>
#include <cstdio>
#include <chrono>
#include <filesystem>
#include <random>
#include <iostream>
using namespace deme;
using namespace std::filesystem;
int main() {
// ===================== 仿真全局参数(适配金属颗粒) =====================
float drum_rot_vel = 0.05; // 滚筒旋转角速度 rad/s
// 3D打印金属颗粒常见尺寸:0.05-0.15mm(这里放大为便于仿真,单位m)
float particle_rad_min = 0.0001; // 最小金属颗粒半径 50μm
float particle_rad_max = 0.0001; // 最大金属颗粒半径 150μm
float drum_scale = 1.0;
DEMSolver DEMSim;
DEMSim.SetVerbosity("ERROR");
DEMSim.SetOutputFormat("CSV");
DEMSim.SetOutputContent({"ABSV"}); // 增加力和扭矩输出,便于分析金属颗粒受力
DEMSim.SetMeshOutputFormat("VTK");
path out_dir = current_path();
out_dir /= "DemoOutput_RotatingDrum_MetalParticle";
create_directory(out_dir);
DEMSim.SetErrorOutVelocity(100000.0);
DEMSim.SetErrorOutAvgContacts(500);
// ===================== 材料定义(金属颗粒+滚筒特性) =====================
// 滚筒材料:不锈钢(常用3D打印设备滚筒材质)
auto mat_type_drum = DEMSim.LoadMaterial({
{"E", 2e6}, // 降低10000倍!
{"nu", 0.3},
{"CoR", 0.6},
{"mu", 0.4},
{"Crr", 0.02}
});
auto mat_type_metal = DEMSim.LoadMaterial({
{"E", 1e6}, // 降低10000倍!
{"nu", 0.34},
{"CoR", 0.55},
{"mu", 0.45},
{"Crr", 0.02}
});
// ===================== 仿真域 & 时间步 =====================
double world_size = 0.4;
DEMSim.InstructBoxDomainDimension({-world_size/2., world_size/2.},
{-world_size/2., world_size/2.},
{0, 0.5});
DEMSim.InstructBoxDomainBoundingBC("top_open", mat_type_drum);
// 金属颗粒尺寸更小,需匹配更小的时间步保证稳定性
float step_size = 1e-7;
// ===================== 加载 网格滚筒 =====================
auto drum_mesh = DEMSim.AddWavefrontMeshObject((GET_DATA_PATH() / "mesh/drum.obj").string(), mat_type_drum);
if (!drum_mesh) {
std::cerr << "FATAL: 滚筒网格加载失败!" << std::endl;
return -1;
}
std::cout << "滚筒网格三角面数量: " << drum_mesh->GetNumTriangles() << std::endl;
drum_mesh->SetInitPos(make_float3(0, 0, 0));
drum_mesh->Scale(0.001f);
drum_mesh->SetFamily(1);
DEMSim.SetFamilyPrescribedAngVel(1, std::to_string(drum_rot_vel), "0", "0");
// ====================== 生成3D打印金属颗粒 ======================
std::vector<std::shared_ptr<DEMClumpTemplate>> templates_metal;
float rad_step = (particle_rad_max - particle_rad_min) / 3;
for (int i = 0; i < 4; i++) {
float r = particle_rad_min + i * rad_step;
std::cout << "DEBUG: Loading metal particle type " << i << ", r = " << r << " m" << std::endl;
// 金属颗粒密度:Ti6Al4V密度4430 kg/m³(不锈钢7850,铝合金2700)
float density = 4430.0;
float mass = density * (4.0/3.0 * PI * r * r * r);
templates_metal.push_back(
DEMSim.LoadSphereType(mass, r, mat_type_metal)
);
}
std::cout << "DEBUG: All metal particle templates loaded" << std::endl;
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dist(0, templates_metal.size()-1);
// 金属颗粒采样间距(保证不重叠)
PDSampler sampler(2.2*particle_rad_max);
// 适配小颗粒的采样区域(保证颗粒数量合理)
float sample_halfwidth = 0.003; // 总宽度 7cm < 7.4cm
float sample_height=0.003;
float3 sample_center = make_float3(-0.22, 0, 0);
std::cout << "DEBUG: Starting sampling metal particles..." << std::endl;
auto input_xyz = sampler.SampleBox(sample_center, make_float3(sample_halfwidth, sample_halfwidth, sample_height));
std::cout << "DEBUG: Sampling done, got " << input_xyz.size() << " metal particles" << std::endl;
// 关键:限制粒子数量,避免超出内存上限
// 限制到 3000 个,兼顾视觉效果 + 内存 + 不崩溃
if (input_xyz.size() > 300) {
input_xyz.resize(100);
}
std::vector<std::shared_ptr<DEMClumpTemplate>> template_to_use(input_xyz.size());
for (unsigned int i = 0; i < input_xyz.size(); i++) {
template_to_use[i] = templates_metal[dist(gen)];
}
DEMSim.AddClumps(template_to_use, input_xyz);
std::cout << "生成金属颗粒总数: " << input_xyz.size() << std::endl;
// ===================== 仿真全局设置 =====================
DEMSim.SetInitTimeStep(step_size);
DEMSim.SetMaxVelocity(5.0); // 金属颗粒密度大,速度限制更低更稳定
DEMSim.SetGravitationalAcceleration(make_float3(0, 0, -9.81));
std::cout << "DEBUG: Initializing DEM solver..." << std::endl;
DEMSim.Initialize();
std::cout << "DEBUG: DEM solver initialized successfully!" << std::endl;
// ===================== 仿真输出控制 =====================
float sim_time = 3.0; // 适当延长仿真时间,观察金属颗粒运动特性
unsigned int fps = 10;
float frame_time = 1.0 / fps;
unsigned int currframe = 0;
std::cout << "输出帧率: " << fps << " FPS" << std::endl;
for (float t = 0; t < sim_time; t += frame_time) {
std::cout << "当前帧: " << currframe << std::endl;
char filename[100], meshfilename[100];
sprintf(filename, "DEMdemo_metal_particle_%04d.csv", currframe);
sprintf(meshfilename, "DEMdemo_drum_mesh_%04d.vtk", currframe);
DEMSim.WriteSphereFile(out_dir / filename);
DEMSim.WriteMeshFile(out_dir / meshfilename);
currframe++;
std::cout << "执行动力学..." << std::endl;
DEMSim.DoDynamicsThenSync(frame_time);
DEMSim.ShowThreadCollaborationStats();
}
std::cout << "=====================================" << std::endl;
std::cout << "3D打印金属颗粒旋转滚筒仿真完成!" << std::endl;
std::cout << "颗粒类型:Ti6Al4V钛合金(可替换为其他金属)" << std::endl;
std::cout << "颗粒尺寸:50-150μm(3D打印常用范围)" << std::endl;
std::cout << "=====================================" << std::endl;
return 0;
}
粒子生成区域
// 适配小颗粒的采样区域(保证颗粒数量合理)
float sample_halfwidth = 0.05; // 总宽度 7cm < 7.4cm
float sample_height = 0.02; // 薄一点,不堆
float3 sample_center = make_float3(-6, 0, 0);
std::cout << "DEBUG: Starting sampling metal particles..." << std::endl;
auto input_xyz = sampler.SampleBox(sample_center, make_float3(sample_halfwidth, sample_halfwidth, sample_height));
EM 引擎不管模型内部是不是空的,只要粒子初始位置与壁面碰撞体重叠,就会判定为穿透,产生巨大的排斥力,直接导致速度溢出报错,可以先导入第一轮的.csv和模型看看初始位置有没有放错
DSampler 的对称逻辑是:
以采样中心点为中心,左右对称撒点你把中心直接挪到了 -0.22,那它只会在 -0.22 左右小范围对称,不会跑到 +0.22 去生成另一堆。
时间步(time step),就是仿真里「每次更新一次世界状态」所前进的时间长度。
比如你设 step_size = 1e-7,意思是: 仿真每算一次动力学,时间就往前走 0.0000001 秒

DEMSim.SetGravitationalAcceleration(make_float3(0, -9.81, 0));这个代表了设置重力,(x,y,z)
四、ParaView
1.什么是ParaView
ParaView 是一款开源、跨平台的科学数据可视化与分析工具,由美国洛斯阿拉莫斯国家实验室开发,专门用来处理大规模数值模拟数据,
2.怎么安装以及和DEM-Engine关系是什么
在安装DEM-Engine的时候,会把readme喂给豆包,同样你让豆包给出安装流程,一步一步的安装就行,千万要注意,要在本机上安装,不要在远程ssh上进行安装,会出很多错误,
- DEM-Engine(做颗粒模拟) → 导出CSV/点云数据 → ParaView(可视化+分析+导出结果)
- DEM-Engine 负责 “算数据”,告诉你每个颗粒的位置、速度、受力 ParaView 负责“看懂数据”,把枯燥的数字变成能直观看到的 3D 模型和动画,帮你判断清粉工艺哪里有问题。
3.可以做什么
- 点云 / 颗粒数据可视化就是你现在正在做的:把 DEM-Engine 输出的颗粒数据,转换成 3D点云模型,还能调整点大小、颜色、透明度,甚至播放随时间变化的颗粒运动动画。
- 数据后处理与分析你可以直接在 ParaView里对数据做筛选、统计和切片:比如筛选出特定区域的颗粒,计算残留量给颗粒按速度、大小上色,一眼看出分布规律用透明度穿透观察零件内部的粉末死角,解决 3D 打印清粉问题
-
4. 怎么使用
选择file,打开 选中你的csv文件打开

点击apply,会看到下面的情况
看窗口最顶部的菜单栏,点击 Filters → 找到 Alphabetical → 往下翻找到 Table To Points,点击它。
现在你在 TableToPoints1 的属性面板里,按下面的方式操作:
找到 X Column 这一行,它的右边有个下拉箭头 ▼,点一下,在弹出的列表里选择 X(你的 CSV 里的 X 坐标列)。
找到 Y Column 这一行,点下拉箭头,选择 Y。
找到 Z Column 这一行,点下拉箭头,选择 Z。
注意:现在这三个列都是你 CSV 里的 X/Y/Z,不是之前的 Points 了,设置要对应上。
确认这三行都设置好了,再点一次左上角的 Apply 按钮。

小眼睛别忘了点
设置一下最大的帧数,点一下play就可以播放了
4. llinux下怎么导出视频
点击顶部菜单栏 File → Save Animation。
Linux 版 ParaView 里非常常见的情况:导出 MP4 视频的功能需要额外的 FFmpeg 支持,而你的系统里没装 / 没识别到,所以下拉框里只有 PNG 图片选项。
- 安装 FFmpeg
打开终端,根据你的发行版执行命令:
Ubuntu/Debian:
sudo apt update
sudo apt install ffmpeg
安装好后,只有.ogv先导出 .ogv


,再用 FFmpeg 转成 MP4运行
ffmpeg -i 你的视频文件.ogv -c:v libx264 -pix_fmt yuv420p output.mp4
生成的 output.mp4 就是通用格式,Windows/Mac/ 汇报都能直接打开。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)