Discharge and reinsertion

50 views
Skip to first unread message

Yves ROBERT

unread,
Feb 20, 2024, 10:58:23 AM2/20/24
to ProjectChrono
Hello,

I am looking for the most efficient way to discharge spheres and reinsert them within the geometry with DEM-Engine.

My ideal goal would be to take the lowest spheres in a sphere stack one by one and reinsert them (one by one) from the top of the geometry. It can be relaxed in reinserting the spheres from a pipe that can contain a few spheres. My application also requires that I track the number of discharged/reinserted spheres, and to be as fast as possible in solving each iteration. However, I have not been able so far to do it.

My first attempt was to make it as simple as possible, but I sacrificed too many requirements. In that attempt, I make a discharge plane, and spheres that are below the plane have their positions reset at the top of the geometry:

[...]
recirculation_vmax = 100 # "Explosion" safety when colliding -> reset
vel_reinsertion = [0,0,0] # How fast we reinsert the sphere
z_discharge = sphere['equivalent_radius'] # How high we want the spheres to be discharged
pipe_height = world_height - 4*sphere['equivalent_radius'] # How high do we want the pipe in which the sphere is reinserted
pipe_radius = 2*sphere['equivalent_radius'] # How wide the "pipe" that reinserts the spheres is

# Make the position block: for a given sphere, precalculate the x,y,z of the re-insertion when the test is satisfied
# Note: the test is satisfied if the sphere is below the recirculation plane, or if the velocity is too high
pos_block = f'''curandState state;
float Zmin, Zmax, Rmax, x, y, z, radius, radius_squared, angle;
curand_init(1234, ownerID, 0, &state);
float random_number = curand_uniform(&state);
float max_v = max(max(vX, vY), vZ);;
bool need_reset = ((Z > {z_discharge}) || (max_v > {recirculation_vmax}));
if (need_reset)
{{
    Zmin = {world_height - 
pipe_height + sphere['equivalent_radius']};
    Zmax = {world_height - sphere['equivalent_radius']};
    Rmax = {pipe_radius - sphere['equivalent_radius']};

    radius_squared = curand_uniform(&state) * std::pow(Rmax, 2.0f);
    radius = std::pow(radius_squared, 0.5f);
    angle =  curand_uniform(&state) * 3.14 * 2;
    x = radius * sin(angle);
    y = radius * cos(angle);
    z = Zmin + curand_uniform(&state)*(Zmax-Zmin);
}}'''

# Make the velocity block. No calculation is needed, just the same check
vel_block = f'''float max_v = max(max(vX, vY), vZ);;
bool need_reset = ((Z > {z_discharge}) || (max_v > {recirculation_vmax}));'''

# Apply rules to the spheres' family (1)
DEMSim.CorrectFamilyPosition(1, '(need_reset) ? x : X', '(need_reset) ? y : Y', '(need_reset) ? z : Z', pos_block)
DEMSim.CorrectFamilyLinVel(1, f'(need_reset) ? {
vel_reinsertion[0]} : vX', f'(need_reset) ? {vel_reinsertion[1]} : vY', f'(need_reset) ? {vel_reinsertion[2]} : vZ', vel_block)
[...]

A few issues arise here: I cannot control how many spheres are discharged, so there are way too many of these spheres that are trying to be reinserted at the same time, without the possibility of avoiding collisions when sampling the new positions, and the reset condition is not enough.

Another idea would be to play with families. I could use ChangeClumpFamily for a box with the same discharge plane (DEMSim.ChangeClumpFamily(100, Z=[-1e99, z_discharge], orig_fam=1)), but that does not resolve my issue much further. It allows me to change z_discharge dynamically but requires me to extract and sort the elevation of each sphere which seems highly inefficient.

What could be good would be to "force" a discharge rate, but that seems impossible as is. The last idea would be to delete the spheres at the bottom and create new ones at the top. That would still require tracking in some way that I am not aware of, but also would require calling UpdateClumps() regularly (as discussed in one of my previous posts) and would keep increasing memory/time as the calculation goes.

Therefore, my question is: is there a way to select the lowest spheres and re-circulate them from the top at a given rate with collision prevention, while being as efficient as possible?

Thank you!

Ruochun Zhang

unread,
Feb 24, 2024, 10:13:10 PM2/24/24
to ProjectChrono
Hi Yves,

First I'd like to thank you for posting some of our prior discussions here. It might help inspire others.

It seems you are still looking for a "portal" type boundary with tracking numbers ability. While it's on the list of features that I wanted to add, right now I have a few ideas to achieve the same, besides the ones you proposed. If we have the chance, we can talk about them in the follow-up posts.

However, I have a question regarding the first idea you proposed. It is a smart way to utilize CorrectFamilyXXX methods to isolate those elements that need to be reinserted and randomly re-position them, and I think it should work. However, since  CorrectFamilyXXX methods check the conditions every step, unless the physics naturally leads to quick-session reinsertions (like having a huge outlet orifice), there should not be "way too many of these spheres that are trying to be reinserted" at any given time.

Can you explain why the line "bool need_reset = ((Z > {z_discharge}) || (max_v > {recirculation_vmax}));" has Z > {z_discharge}, rather than Z < {z_discharge}? If it is >, wouldn't you have almost all elements in the simulation trying to be reinserted at the same time?

Can you explain this first and then let me know whether you expect the simulation to naturally have quick-session reinsertions by the nature of the governing physics, then we can continue the discussion.

Thank you,
Ruochun
Reply all
Reply to author
Forward
0 new messages