Hi everyone,
I’m developing several EDEM API plugins to study melting of DRI particles in an electric furnace. The model is EDEM-only (no CFD): buoyancy, drag, convection, conduction, shrinkage and removal are implemented via plugins.
Functionally the plugins work, but I hit a multi-threading problem:
- In single-thread runs everything is stable, but slow.
- In multi-thread runs I can insert a handful of particles, but when I spawn a larger bed (e.g., 1000–5000 particles at t = 0 with a static factory) EDEM crashes. Also with less particle but longer simulations EDEM tends to crash.
From debugging, I believe two plugins are not MT-safe and result in a race condition. I’d really appreciate guidance how to make EDEM API plugins MT-safe. I am a novice C++ programmer so this is new for me. After some days of fiddling around I have not succeeded myself. The plugins that give me trouble are:
1. CTemperatureUpdateV2:
I need each particle’s initial mass for my energy balance, but particles shrink, so I can’t reuse particle.mass
. I currently cache the initial mass in a global unordered_map
keyed by particle ID:
This works in single-thread mode but likely races in multi-thread mode when many particles are created/processed simultaneously and my EDEM crashes silently with the following crashdump.
I feel like the main issue is that I declare isThreadSafe but that the script is not multi-thread safe and therefore upon generation of many particles in the first time step immediately crashes.
2. CSurfaceTrackingV2
I have the same problem in this plugin I think.
This plugin identifies surface particles of the feed pile so only those feel convection. A screenshot of how this looks is provided below. The script tags the outside particles.
To realise this, I discretize the domain into voxels (cells). This looks as follows:
Each timestep I:
- compute each particle’s voxel location and add it to
m_currentVoxelSet
- compare
m_currentVoxelSet
to m_previousVoxelSet
to find surface voxels/particles. (looking at empty neighbour cells) - swap/clear the sets for the next step
The relevant code:
Because externalForce()
is run in parallel, the shared m_currentVoxelSet
is written concurrently. That likely explains the crash when many particles are inserted/processed at the same time
Now, I am quite a novice programmer to C++ and I have never had to make anything MT-safe. Also, I can not find any API examples that uses similar logic to my plugins and is MT-safe.
My question
Can anyone explain to me what it would take to preserve the logic of both plugins but make the scripts MT-safe for the usage in EDEM.
- CTemperatureUpdateV2:
What is the correct, simple way to store each particle’s initial mass so it’s safe in multi-thread runs?
(Right now I use one global container and it crashes.)
Please show the small code change I should make. - CSurfaceTrackingV2:
I currently insert voxels into one shared set inside externalForce(int threadID, …)
and swap/clear sets when time
changes inside externalForce
.What is the EDEM-2025 best way to do this MT-safe
Is the correct pattern:
1. in starting(..., numThreads)
: allocate per-thread voxel sets,
2. in externalForce(threadID, …)
: write only to threadID
’s set,
3. in the single-threaded end-of-step callback (please confirm the exact name in EDEM 2025): merge per-thread sets, then swap/clear?
A 10–20 line sketch showing allocate → collect → merge/swap would be perfect.
If someone can share a tiny code sketch (10–20 lines) for both cases, or give me some guidance on how to best preserve the logic of both plugins but make it MT-safe that would be perfect. Right now I dont know where to start after trying several things.
Kind regards,
Jan-Thijn Wijnker
The full code of both plugins: