提示:随着学习会不断加深里面的👩


一、DEM-Engine

DEM-Engine 是一款专门用于离散元法(Discrete Element Method, DEM)的高性能数值模拟引擎,核心是用来模拟颗粒 / 粉体 / 散体物料的运动、碰撞、受力与堆积行为。
代码:https://github.com/projectchrono/DEM-Engine
这里面需要是c++代码,要重新编译,可以把readme喂给豆包,一点一点的安装吧,要用GPU加速才行

二、DEM-Engine可以做什么?

  1. 工业粉体 / 颗粒过程模拟 3D 打印清粉工艺优化:就像你正在做的,模拟 SLM/SLS 打印后,零件内腔、流道里的粉末残留分布、流动和清粉过程(吹气、振动、吹扫),找到死角和清粉难点,优化工艺参数。

  2. 粉体输送与混合:模拟料仓、螺旋输送机、混粉机里的颗粒流动、堵塞、偏析问题,优化设备结构和工艺参数。 破碎 /
    研磨设备设计:模拟矿石、物料在破碎机、球磨机里的破碎、磨损过程,预测设备寿命和生产效率。

  3. 岩土与地质工程:模拟土壤、砂石、尾矿的堆积、滑坡、沉降过程,分析边坡稳定性、地基承载力。模拟盾构机、掘进机刀具与岩土颗粒的相互作用,优化刀具设计和施工参数。

  4. 化工与制药行业模拟流化床、反应器里的颗粒流化、传热传质过程,优化反应效率。模拟药片、胶囊的混合、压片、输送过程,预测粉体流动性和成品质量。

  5. 能源与矿业模拟煤矿、矿石在输送、装卸、筛分过程中的行为,优化矿场设备和流程。模拟储料仓、料斗的卸料过程,分析结拱、堵塞问题。

三、它的核心能力:为什么用它,而不是普通软件?

  • 精准的颗粒物理模型能模拟颗粒间的碰撞、摩擦、粘附、团聚,以及颗粒与设备 零件壁面的相互作用,甚至可以加入热传导、静电、湿颗粒(含液体)等复杂效应,非常贴近真实粉体行为。
  • 大规模并行计算(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 图片选项。

  1. 安装 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/ 汇报都能直接打开。
在这里插入图片描述

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐