Welcome to ask.woodem.org. You may post when you login through your GitHub account.

Generate a random packed bed of spherocylinders in a cylindrical column

0 votes
52 views
asked Jun 24 by coderguruz (120 points)
edited Jun 24 by coderguruz
I want to generate a random packed bed of spherocylinders (capsules) in a cylindrical column.

How could I do this task with WooDEM?

Is it possible to get the particle positions at the end of the simulation in a text file in the form of their A and B coordinates (x,y,z coordinates of the cylinder initial and final points, which completely define the position, instead of using one point and three angles)?

Thanks in advance.

1 Answer

0 votes
answered Jun 24 by eudoxos (44,890 points)

Hi,

you can use a script like this for what you need:

import woo, woo.core, woo.dem, woo.pack
# this returns geometry only via dynamic simulation
packed=woo.pack.randomDensePack2(
    # define the geometyr (cylinder)
    predicate=woo.pack.inCylinder((0,0,0),(0,0,2),1),
    # define what particles go into the cylinder
    generator=woo.dem.PsdCapsuleGenerator(psdPts=[(.15,0),(.25,.8),(.3,1.)],shaftRadiusRatio=(1.,2.)),
)
# create new scene 
S=woo.master.scene=woo.core.Scene(fields=[woo.dem.DemField()])
# add capsules
packed.toDem(S,S.dem,mat=woo.utils.defaultMaterial())
# print endpoint coordinates for all of them
for p in S.dem.par:
    if not isinstance(p.shape,woo.dem.Capsule): continue
    print(p.shape.endPt(0),p.shape.endPt(1))

Note however a few caveats:

  1. You will need the latest version of woo from git (or wait for the package from woo-daily PPA) since I only wrapped Capsule::endPt in python now (the function existed before, by only in c++)
  2. The dynamic simulation in randomDensePack2 is somewhat unreliable depending on what you do, and might involve some hand-tuning. On the top of that, I did some big fixes in the underlying PeriIsoCompressor engine lately... I am not sure what the result will be, as the input variation is too big.
  3. The generated packing is not 100% overlap-free, which is in fact impossible (at least with dynamic methods). If you use the packing later, make sure you take the initial position as equilibrium, to avoid initial explosion.

If you only need loose packing, or want to run gravity deposition yourself, that is another topic, and the solution would be simpler (no secondary simulation involved, just generation and deposition):

import woo.core, woo.dem, woo.utils, math
from minieigen import *
woo.master.usesApi=10103
S=woo.master.scene=woo.core.Scene(
    fields=[woo.dem.DemField(
        gravity=(0,0,-10),
        # add bottom and cylinder walls
        par=[woo.dem.Wall.make(0,axis=2)]+woo.triangulated.cylinder(Vector3(0,0,0),Vector3(0,0,2),radius=1)
    )],
    engines=woo.dem.DemField.minimalEngines()+[woo.dem.CylinderInlet(
        stepPeriod=200,
        radius=1,
        height=2,
        node=woo.core.Node((0,0,0),((0,1,0),-math.pi/2)),
        massRate=0,
        materials=[woo.utils.defaultMaterial()],
        generator=woo.dem.PsdCapsuleGenerator(psdPts=[(.15,0),(.25,.8),(.3,1.)],shaftRadiusRatio=(1.,2.))
    )
])
# run and stop manually when happy

The post-processing to save particle endpoints would be the same as in the former case.

HTH, Vaclav

commented Jul 12 by coderguruz (120 points)
edited Jul 12 by coderguruz

Thank you very much for your help.
The Python script works fine, but I need to add two features:

  • I want monodisperse spherocylinders, not a PSD.
  • I want to save particle positions in a simple text file as six Cartesian coordinates (x, y, z) per row (without using orientation angles): the first three are for point A, while the last three are for point B. In this way any spherocylinder is completely defined, once you know its radius in a monodisperse packing.
commented Jul 12 by eudoxos (44,890 points)

Monodisperse is only a special type of PSD, so you assign step-wise function to the PSD, like psdPts=[(.2,0),(.2,1)] to have all of them .2, and shaftRadioRatio=(2.,2.) to have the elongation identical everywhere. The PSD diameter is volumetrically equivalent diameter (not diameter of the shaft), watch out for that.

As a code guru, writing the positions into file is surely trivial for you (untested, something like this:

with open('coords.txt','w') as out:
   for p in S.dem.par:
      if not isinstance(p.shape,woo.dem.Capsule): continue
      a,b=p.shape.endPt(0),p.shape.endPt(1)
      out.write('%g %g %g %g %g %g\n'%(a[0],a[1],a[2],b[0],b[1],b[2])
      # with python3 arguably more elegant
      # out.write('%g %g %g %g %g %g\n'%(*a,*b))
      # or even save one line with
      # out.write(6*'%g '%(*p.shape.endPt(0),*p.shape.endPt(1))+'\n')
commented Jul 22 by coderguruz (120 points)

Sorry, but I am not a Python expert.
I am still unable to print the position of particles in a text file with your suggestions, probably because the simulation goes on and I have to wait until it stops.
I am not interested in seeing the simulation in a 3D graphical window, but I am interested in the text file with the position of particles.
Is it possible also to directly export the packed bed in VTK format, suitable to be opened in ParaView?

commented Jul 22 by eudoxos (44,890 points)

Alright, guru, here you go. Save this as something, like aa.py. Then run woo aa.py, then wait a bit. It will open Paraview for you, and write coordinates. You can quit by pressing Ctrl-D from woo, or typing exit.

There is no way to export the packed bed in VTK format other than triangulated capsule surfaces; there is not capsule-shaped primitive in VTK.

import woo.core, woo.dem, woo.utils, math, woo.paraviewscript
from minieigen import *
woo.master.usesApi=10103
S=woo.master.scene=woo.core.Scene(
    fields=[woo.dem.DemField(
        gravity=(0,0,-10),
        # add bottom and cylinder walls
        par=[woo.dem.Wall.make(0,axis=2,glAB=((-1,-1),(1,1)))]+woo.triangulated.cylinder(Vector3(0,0,0),Vector3(0,0,2),radius=1)
    )],
    engines=woo.dem.DemField.minimalEngines(damping=.4)+[woo.dem.CylinderInlet(
        stepPeriod=200,
        radius=1,
        height=2,
        node=woo.core.Node((0,0,0),((0,1,0),-math.pi/2)),
        massRate=0,
        materials=[woo.utils.defaultMaterial()],
        generator=woo.dem.PsdCapsuleGenerator(psdPts=[(.15,0),(.25,.8),(.3,1.)],shaftRadiusRatio=(1.,2.))
    ),
    woo.core.PyRunner('ubf=woo.utils.unbalancedForce(S)\nprint(ubf)\nif ubf<.05 and S.step>1000: done(S)',400),
])

def done(S):
    S.stop()
    with open('capsules.txt','w') as out:
       for p in S.dem.par:
          if not isinstance(p.shape,woo.dem.Capsule): continue
          a,b=p.shape.endPt(0),p.shape.endPt(1)
          out.write('%g %g %g %g %g %g\n'%(a[0],a[1],a[2],b[0],b[1],b[2]))
    vtk=woo.dem.VtkExport(out='capsules-')
    vtk(S) # trigger manually writing Paraview data files
    # write paraview script and run it
    woo.paraviewscript.write('capsules.py',**woo.paraviewscript.kwFromVtkExport(vtk))
    woo.paraviewscript.launchPV('capsules.py')

S.run()
commented Jul 27 by coderguruz (120 points)

Thanks for your answer but, if I try to fill a cylindrical column with an height/radius ratio of 4 with mono-disperse spherocylinders, the simulation doesn't stop in a reasonable time and no text file "capsules.txt" is generated.
I have also two questions for you:
1) In case I need to mention your code in a scientific publication, do you have any references (for example papers) related to WooDEM?
2) What is the method on which your code is based? Is it reliable?
Thank you in advance.

...