← Back to team overview

yade-users team mailing list archive

Re: [Question #700963]: Pore size distribution

 

Question #700963 on Yade changed:
https://answers.launchpad.net/yade/+question/700963

Jan Stránský posted a new comment:
Generating pores "home-made"
Cheers
Jan

###
import scipy.spatial

# https://www2.mps.mpg.de/homes/daly/CSDS/t4h/tetra.htm
# https://math.stackexchange.com/questions/2820212/circumradius-of-a-tetrahedron
# filter out "degenerate" tetrahedrons
def delaunay2poreTetras(delaunay,limit=0.1):
    vertices = delaunay.points
    tetras = delaunay.simplices
    def quality(tetra):
        vs = v0,v1,v2,v3 = [Vector3(vertices[i]) for i in tetra]
        d1 = v1 - v0
        d2 = v2 - v0
        d3 = v3 - v0
        v = d1.dot(d2.cross(d3)) / 6
        v = abs(v) # volume
        a = d1.norm()
        b = d2.norm()
        c = d3.norm()
        A = (v2-v3).norm()
        B = (v1-v3).norm()
        C = (v1-v2).norm()
        aa,bb,cc = a*A, b*B, c*C
        den = (aa+bb+cc)*(aa+bb-cc)*(aa-bb+cc)*(-aa+bb+cc)
        den = abs(den)
        r = sqrt(den)/(24*v) # radius of circum sphere
        q = (9*sqrt(3)/8*v)**(1/3.)/r # quality in range [0,1]
        return q
    return [t for t in tetras if quality(t) > limit]

# some home-made inefficient (but working :-) iterative approach
def tetra2pore(tetra):
    bodies = [O.bodies[int(i)] for i in tetra]
    vertices = [b.state.pos for b in bodies]
    radii = [b.shape.radius for b in bodies]
    center = 0.25*sum(vertices,Vector3.Zero) # initial guess, center of mass of tetrahedron
    for i in range(100): # TODO stop condition
        ds = d1,d2,d3,d4 = [(center-v).norm()-r for v,r in zip(vertices,radii)] # distances from "touching"
        dMin,dMax = min(ds),max(ds)
        iMin,iMax = ds.index(dMin), ds.index(dMax)
        vMin,vMax = vertices[iMin],vertices[iMax]
        dirMin = (center - vMin).normalized()
        dirMax = (center - vMax).normalized()
        # based on min and max distance "push" the center a bit
        dd = (dMax - dMin) * 0.1
        center += dirMin * dd - dirMax * dd
    radius = (center - vertices[0]).norm() - radii[0]
    return center,radius


# testing packing, colored red
O.bodies.append((
    sphere((1.0,2.0,3.0),1.0,color=(1,0,0),mask=0b001),
    sphere((4.0,2.0,3.0),1.6,color=(1,0,0),mask=0b001),
    sphere((2.5,4.0,3.0),1.2,color=(1,0,0),mask=0b001),
    sphere((2.6,3.0,5.0),1.1,color=(1,0,0),mask=0b001),
    sphere((5.0,4.0,5.0),1.4,color=(1,0,0),mask=0b001),
    sphere((5.0,5.0,2.5),1.3,color=(1,0,0),mask=0b001),
    sphere((6.5,3.0,3.0),1.2,color=(1,0,0),mask=0b001),
    sphere((7.4,4.8,4.0),1.2,color=(1,0,0),mask=0b001),
))

centers = [b.state.pos for b in O.bodies]
delaunay = scipy.spatial.Delaunay(centers) # tetrahedralization
tetras = delaunay2poreTetras(delaunay) # only "good" tetrahedrons
pores = [tetra2pore(t) for t in tetras] # pores out of tetrahedrons

# pores, colored cyan
for c,r in pores:
    O.bodies.append(sphere(c,r,color=(0,1,1),mask=0b010))

# tetrahedrons as facets, for visualization
for ii in tetras:
    vs = [delaunay.points[i] for i in ii]
    v1,v2,v3,v4 = [Vector3(list(v)) for v in vs]
    O.bodies.append((
        facet((v1,v2,v3),mask=0b100),
        facet((v1,v2,v4),mask=0b100),
        facet((v1,v3,v4),mask=0b100),
        facet((v2,v3,v4),mask=0b100),
    ))

# improve sphere display quality
yade.qt.Gl1_Sphere.quality = 2
###

-- 
You received this question notification because your team yade-users is
an answer contact for Yade.