# add uniform fibers to the cylinder-shape specimen

Asked by Hanying Zhang on 2020-06-06

Hi,

This is a yade user working on 'How to add uniform fibers in a cylinder shape specimen of a traix experiment',my problem is how to add uniform fibers, the fibers should be seen as cylinder so should i use "gridconnection" to create grids first then connect them with cylinder/segment? If so, how can i get a uniform distribution of fibers?

and i wanna take a traix experiment with it but i have no idea how to set the wall outside a cylinder specimen.

besides, i am working on this article, trying to simulate the experiment in it. Do you guys have any suggestions to me on modeling or any articles to study on? Thank you so much.

Respectfully,

xxxe

## Question information

Language:
English Edit question
Status:
For:
Assignee:
No assignee Edit question
Last query:
2020-07-02
2020-07-02
 Jan Stránský (honzik) said on 2020-06-12: #1

Hello,

> how to add uniform fibers
> how can i get a uniform distribution of fibers?

what does "uniform" mean? the same sizes? uniformly distributed sizes? uniformly distributed orientations?

> should i use "gridconnection" to create grids first then connect them with cylinder/segment?

sounds like a reasonable approach.
Alternatively you can approximate the cylinder as a clump made of spheres.

cheers
Jan

 Hanying Zhang (xxxe) said on 2020-06-12: #2

Hi Jan,

> what does "uniform" mean? the same sizes? uniformly distributed sizes? uniformly distributed orientations?

"uniform" means that the possibility of the position of fibers occurring in the specimen is equal at every spot. and there are different sizes of fibers, the orientations of the fibers are random, just like a real specimen that you mix fibers with sand well, fibers' position are uniform and the orientations are random.

> Alternatively you can approximate the cylinder as a clump made of spheres.

I want to simulate quartz sand which was reinforced with discrete polypropylene fibers with the average dimensions 12 mm in length, 0.0015 mm in diameter, and with specific density of 0.91, tensile strength of 460 MPa and elastic modulus of 3.5 MPa. The fiber content used in the experiments was 0.15, 0.25, 0.35 and 0.5% by weight of sand.

The specimens were statically compacted in three layers into a 39.1 mm diameter by 80 mm high split mold.

"the average dimensions 12 mm in length, 0.0015 mm in diameter" I think its not working with clumps.

xxxe

 Jan Stránský (honzik) said on 2020-06-12: #3

One approach is a "makeCloud -> compaction", very similar to the problems involving only spheres.
1) using makeCloud, create spheres representing sand
2) using makeCloud, add "fibre-spheres" - spheres with dimensions of the fibers
3) replace "fibre-spheres" with cylinders
4) compact the specimen

> just like a real specimen that you mix fibers with sand well, fibers' position are uniform and the orientations are random.

are they? (a bit philosophical question, depending on definition of "random" :-)

> the orientations of the fibers are random

please be more specific. Random is too random word :-)
Do you want the directions to be random with uniform distribution, or just "some randomness" is ok?

> "the average dimensions 12 mm in length, 0.0015 mm in diameter" I think its not working with clumps.

probably..

cheers
Jan

 Hanying Zhang (xxxe) said on 2020-06-20: #4

Hi Jan,

> Do you want the directions to be random with uniform distribution, or just "some randomness" is ok?

the former, random directions and uniform distribution. although i think the difference between both may be not much.

> I check the links and this code is almost what i want.

#########
def randomOrientation(): # most likely not very well random, but for this example it is ok
from random import random as r
return Quaternion((r(),r(),r()),2*pi*r())

# create loose spherical packing using makeCloud
mi,ma = (0,0,0),(20,20,20)
nCyls,nSphs = 40,30
sp.makeCloud(mi,ma,rMean=2,rRelFuzz=.5,num=nCyls) # makeCloud for cylinders
sp.makeCloud(mi,ma,rMean=1,rRelFuzz=.5,num=nSphs) # makeCloud for spheres
if i < nCyls: # add cylinder
ori = randomOrientation()
O.bodies.append(box(pos,extents,ori))
##########

but there are still questions:
1)i try to increase the number of spheres and change cubic size, while error occurs "Exceeded 1000 tries to insert non-overlapping sphere to packing. Only 15 spheres were added, although you requested 500." and box turns out to be different sizes, i mean two kinds of size with big difference, nothing about relFuzz.

2)it seems that cylinders(box actually) take up the whole cubic space(depending on the longest edge) so that no sphere appears around the cylinder within cubic space, this is not what i want.

i am still working on the "for" part of the code, its a little confusing to me.

thanks a lot.
xxxe

 Hanying Zhang (xxxe) said on 2020-06-20: #5

The fiber content used in the experiments was 0.15, 0.25, 0.35 and 0.5% by weight of sand. How can i get specific fiber content by weight of sand?

thanks a lot
xxxe

 Jan Stránský (honzik) said on 2020-06-20: #6

> random directions and uniform distribution.

I have no experience, you have to search a bit..
my randomOrientation most likely is not uniform, just "some randomness"

> 1)i try to increase the number of spheres and change cubic size, while error occurs "Exceeded 1000 tries to insert non-overlapping sphere to packing. Only 15 spheres were added, although you requested 500." and box turns out to be different sizes, i mean two kinds of size with big difference, nothing about relFuzz.

it seems the number of spheres and the makeCloud "volume" is not "proportional", difficult to say without values.

> 2)it seems that cylinders(box actually) take up the whole cubic space(depending on the longest edge) so that no sphere appears around the cylinder within cubic space, this is not what i want.

cylinders (boxes) replaces spheres, so no sphere is generated within spherical space (not cubic).
This is intended, makeCloud creates a loose packing and you have to compact it anyway before a serious simulation.

> i am still working on the "for" part of the code, its a little confusing to me.

what is ""for" part"?

> How can i get specific fiber content by weight of sand?

there are many ways.
E.g. create more fibres and then delete one-by-one unless the content match your need.

cheers
Jan

 Hanying Zhang (xxxe) said on 2020-06-25: #7

>my randomOrientation most likely is not uniform, just "some randomness"

that works for me too(i didn't figure out way to achieve ‘random directions and uniform distribution’ so…)

>cylinders (boxes) replaces spheres, so no sphere is generated within spherical space (not cubic).

replaces? i don't get it…the code below makes cloud of 40 spheres and 30 spheres first(not adding to simulation),then when i<40, add every box to bodies,(where are those 40 spheres?),then add 30 spheres to bodies? Why not adding all 70 spheres to bodies?

#########
def randomOrientation(): # most likely not very well random, but for this example it is ok
from random import random as r
return Quaternion((r(),r(),r()),2*pi*r())

# create loose spherical packing using makeCloud
mi,ma = (0,0,0),(20,20,20)
nCyls,nSphs = 40,30
sp.makeCloud(mi,ma,rMean=2,rRelFuzz=.5,num=nCyls) # makeCloud for cylinders
sp.makeCloud(mi,ma,rMean=1,rRelFuzz=.5,num=nSphs) # makeCloud for spheres
if i < nCyls: # add cylinder
ori = randomOrientation()
O.bodies.append(box(pos,extents,ori))
##########

1)i need to simulate fiber so i changed a bit then it's not working, cylinders are out of space requested before.
2)i set orientation=Quaternion ((r(),r(),r()),r()) but it turns out cylinders' orientation are not random.

my code is below.

#########

from random import random as r

def randomOrientation(): # most likely not very well random, but for this example it is ok
from random import random as r
return Quaternion((r(),r(),r()),r())

# create loose spherical packing using makeCloud
mi,ma = (0,0,0),(0.08,0.08,0.08)
nCyls,nSphs = 1000,100000
sp.makeCloud(mi,ma,rMean=0.012,rRelFuzz=.003,num=nCyls) # makeCloud for cylinders
sp.makeCloud(mi,ma,rMean=0.0011,rRelFuzz=.0005,num=nSphs) # makeCloud for spheres
if i < nCyls: # add cylinder
#O.bodies.append(sphere())

##########

thank u soooo much
xxxe

 Jan Stránský (honzik) said on 2020-06-25: #8

> ... random directions and uniform distribution
> that ["some randomness"] works for me too

> i didn't figure out way to achieve ‘random directions and uniform distribution’ so…

see e.g.  (UnitRandom function) and following links and source code

> replaces? i don't get it…the code below makes cloud of 40 spheres and 30 spheres first(not adding to simulation),then when i<40, add every box to bodies,(where are those 40 spheres?),then add 30 spheres to bodies? Why not adding all 70 spheres to bodies?

mentioned here (#3) as well as in :
1) create some spheres, meant to be actual spheres in simulation (30 in the mentioned case)
2) create some spheres ("fibre-spheres"), meant just to reserve space for fibres (not added to the simulation). 40 in the mentioned case. Those 40 spheres are not anywhere, they are "replaced" by the fibres.
3) replace "fibre-spheres" by fibres

> 1)i need to simulate fiber so i changed a bit then it's not working, cylinders are out of space requested before.
> O.bodies.append(geom.facetCylinder(center=(r(),r(),r()),...))

here you set random position, no surprise that "cylinders are out of space". Use center=pos instead

> 2)i set orientation=Quaternion ((r(),r(),r()),r()) but it turns out cylinders' orientation are not random.
> O.bodies.append(geom.facetCylinder(...,orientation=Quaternion(),...))

no, you set orientation=Quaternion().
If you really set orientation=Quaternion ((r(),r(),r()),r()), then the orientation is random

> sp.makeCloud(mi,ma,rMean=0.012,rRelFuzz=.003,num=nCyls) # makeCloud for cylinders
...
> O.bodies.append(geom.facetCylinder(...,height=0.012,...)

size (height) of the cylinder should be equal to the sphere size (2*radius). Either do not use rRelFuzz (then the size is fixed) or better use the radius value for facetCylinder creation.

cheers
Jan

 Hanying Zhang (xxxe) said on 2020-06-25: #9

the paper i want to simulate writes"The compacted sand and fiber-reinforced specimens for triaxial tests were prepared by hand-mixing dry sand, water and polypropylene fibers. To prevent floating of the fibers, it is important to add the water before adding the fibers during the mixing process. The specimens were statically compacted in three layers into a 39.1 mm diameter by 80 mm high split mold. "
i think what the specimen needs to achieve is "random directions and uniform distribution", but indeed what it can get is just "some randomness".

>no, you set orientation=Quaternion().
If you really set orientation=Quaternion ((r(),r(),r()),r()), then the orientation is random

i changed code according to your suggestion, they all works except the orientation one. the randomness of cylinders seems like randomness in a small amount of angles off one direction.

>1) create some spheres, meant to be actual spheres in simulation (30 in the mentioned case)
2) create some spheres ("fibre-spheres"), meant just to reserve space for fibres (not added to the simulation). 40 in the mentioned case. Those 40 spheres are not anywhere, they are "replaced" by the fibres.
3) replace "fibre-spheres" by fibres

i still wonder how same codes turn out to be "create some spheres, meant to be actual spheres in simulation" and "create some spheres ("fibre-spheres"), meant just to reserve space for fibres (not added to the simulation)"……and i need to calculate two mass of spheres and cylinders, how can i distinguish them with codes.

#########

from random import random as r

def randomOrientation(): # most likely not very well random, but for this example it is ok
from random import random as r
return Quaternion((r(),r(),r()),r())

# create loose spherical packing using makeCloud
mi,ma = (0,0,0),(0.08,0.08,0.08)
nCyls,nSphs = 1000,100000
sp.makeCloud(mi,ma,rMean=0.006,num=nCyls) # makeCloud for cylinders
sp.makeCloud(mi,ma,rMean=0.0011,rRelFuzz=.0005,num=nSphs) # makeCloud for spheres
if i < nCyls: # add cylinder
#O.bodies.append(sphere())

##########

cyl = pack.inCylinder((0.04,0.04,0),(0.04,0.04,0.08),0.0391) # predicate for a cylinder
#for c,r in sp:
# if cyl(c,r): O.bodies.append(sphere(c,r))
#mass = 0.0
#for b in O.bodies:
# if cyl(b.state.pos): # b is inside cyl1
# mass += b.state.mass

##########

thanks
xxxe

 Jan Stránský (honzik) said on 2020-06-25: #10

Concerning random orientation, you can try the approach from 
###
def randomOrientation():
# from the source code of Quaternion::UnitRandom()
# https://eigen.tuxfamily.org/dox-devel/Quaternion_8h_source.html
from random import random as r
u1 = r()
u2 = r() * pi
u3 = r() * pi
a = sqrt(1 - u1)
b = sqrt(u1)
return Quaternion(a*sin(u2),a*cos(u2),b*sin(u3),b*cos(u3))
# test
O.bodies.append([box((0,0,0),(10,1,.1),orientation=randomOrientation()) for _ in range(50)])
O.step()
###

> i still wonder how same codes turn out to be "create some spheres, meant to be actual spheres in simulation" and "create some spheres ("fibre-spheres"), meant just to reserve space for fibres (not added to the simulation)"

this I did not get..
what is "same code"?

> ……and i need to calculate two mass of spheres and cylinders, how can i distinguish them with codes.

spheres = [b for b in O.bodies if isisntance(b.shape,Sphere)]
massSpheres = sum(b.state.mass for b in spheres)

(facet)cylinders - depends if sum is needed etc..

You can also have the two lists directly from the code:
###
cyls = []
sphs = []
if i < nCyls: # add cylinder
cyl = geom.facetCylinder(...)
O.bodies.append(cyl)
cyls.append(cyl)
O.bodies.append(sph)
sphs.append(sph)
# do whetever with sphs and cyls lists
###

If you need specific masses for spheres and cylinders, you can modify the procedure a bit:
1) create spheres, add them to simulation, compute their mass if needed
2) create "fibre-spheres"
3) replace "fibre-spheres" by fibres one by one (also add them to simulation one by one). If the desired fibre mass matches desired value, stop replacing and adding fibres.

cheers
Jan

 Jan Stránský (honzik) said on 2020-06-29: #11

Concerning randomOrientation, it is now part of Yade as utils.randomOrientation 
cheers
Jan

 Hanying Zhang (xxxe) said on 2020-07-02: #12

hi,

1)Is there a geom module that can be used to simulate fiber? it should be deformable(shear force need be applied on it) and look like a fiber(cylinder would be fine, i used facetcylinder before then i found it cant deform… )
2)the specimen should be cylinder shape. i wonder how specimens can be isotropically consolidated to pressures of 50 kPa, 100 kPa, 200 kPa and 300 kPa. ususlly the pressures are applied by wall and i think that cylinder dont have side ?
3)i need to observe the stress–dilatancy relationship of specimen so the exteral surface should be deformable too,what kind of geom module/material should i use?

my script is below, it's totally a mess…

##########

###############
#cubic generate
###############

def randomOrientation():
# from the source code of Quaternion::UnitRandom()
# https://eigen.tuxfamily.org/dox-devel/Quaternion_8h_source.html
from random import random as r
u1 = r()
u2 = r() * pi
u3 = r() * pi
a = sqrt(1 - u1)
b = sqrt(u1)
return Quaternion(a*sin(u2),a*cos(u2),b*sin(u3),b*cos(u3))

# create loose spherical packing using makeCloud
mi,ma = (0,0,0),(0.2,0.2,0.2)
nCyls,nSphs = 2350,50000
sp.makeCloud(mi,ma,rMean=0.006,num=nCyls) # makeCloud for cylinders
sp.makeCloud(mi,ma,rMean=0.0011,rRelFuzz=.0005,num=nSphs) # makeCloud for spheres
if i < nSphs:
for i in O.bodies:
#if i < nSphs:
i.shape.color=(0,0.5,0.5)
else:

#if i < nCyls: # add cylinder
#for i in O.bodies:
#if i < nSphs:
# i.shape.color=(0,0,1)

##########
#predicate
##########

#pred = pack.inCylinder((0.04,0.04,0),(0.04,0.04,0.08),0.0391) # predicate for a cylinder

################
#certain content
################

#spheres = [b for b in O.bodies if isisntance(b.shape,Sphere)]
#massSpheres = sum(b.state.mass for b in spheres)
#cylinders = [b for b in O.bodies if isisntance(b.shape,Cylinder)]
#massSCylinders = sum(b.state.mass for b in cylinders)

#x = massSCylinders/massSpheres
# if x < 0.35: # 35%

#mass = 0.0
#for b in O.bodies:
# if cyl(b.state.pos): # b is inside cyl1
# mass += b.state.mass

##########
############################
### DEFINING ENGINES ###
############################

O.materials.append(FrictMat(young=15e6,poisson=.4,frictionAngle=0,density=0,label='frictionless'))

walls=aabbWalls(thickness=1e-10,material='frictionless')
wallIds=O.bodies.append(walls)

triax=TriaxialCompressionEngine(
wall_bottom_id=wallIds,
wall_top_id=wallIds,
wall_left_id=wallIds,
wall_right_id=wallIds,
wall_back_id=wallIds,
wall_front_id=wallIds,
internalCompaction=False,
sigmaIsoCompaction=-50e3,
sigmaLateralConfinement=-50e3,
max_vel=10,
strainRate=0.01,
label="triax"
)

O.engines=[
ForceResetter(),
InsertionSortCollider([
Bo1_Sphere_Aabb(),
Bo1_GridConnection_Aabb()]),
InteractionLoop([
Ig2_Sphere_Sphere_ScGeom(),
Ig2_GridNode_GridNode_GridNodeGeom6D(),
Ig2_GridConnection_GridConnection_GridCoGridCoGeom(),
],
[
Ip2_CohFrictMat_CohFrictMat_CohFrictPhys(setCohesionNow=True,setCohesionOnNewContacts=False), # internal cylinder physics
Ip2_FrictMat_FrictMat_FrictPhys() # physics for external interactions, i.e., cylinder-cylinder interaction
],
[ Law2_ScGeom_FrictPhys_CundallStrack(),
Law2_ScGeom6D_CohFrictPhys_CohesionMoment(), # contact law for "internal" cylinder forces
Law2_GridCoGridCoGeom_FrictPhys_CundallStrack() # contact law for cylinder-cylinder interaction
]
),
## We will use the global stiffness of each body to determine an optimal timestep (see https://yade-dem.org/w/images/1/1b/Chareyre&Villard2005_licensed.pdf)
GlobalStiffnessTimeStepper(active=1,timeStepUpdateInterval=100,timestepSafetyCoefficient=0.8),
triax,
#TriaxialStateRecorder(iterPeriod=100,file='WallStresses'),
NewtonIntegrator(damping=.4)
]

Gl1_Sphere.stripes=1

#######################################
### APPLYING CONFINING PRESSURE ###
#######################################

#triax.goal1=triax.goal2=triax.goal3=-10000

#while 1:
# O.run(10, True)
#the global unbalanced force on dynamic bodies, thus excluding boundaries, which are not at equilibrium
#unb=unbalancedForce()
#print 'unbalanced force:',unb,' mean stress: ',triax.meanStress
#if unb<stabilityThreshold and abs(-10000-triax.meanStress)/10000<0.001:
# break

#print "### Isotropic state saved ###"

############

thanks
xxxe

 Jan Stránský (honzik) said on 2020-07-02: #13

> 1)Is there a geom module that can be used to simulate fiber? it should be deformable(shear force need be applied on it) and look like a fiber(cylinder would be fine, i used facetcylinder before then i found it cant deform… )

Have a look at cylinders connected with GridConnections *

> 2)the specimen should be cylinder shape. i wonder how specimens can be isotropically consolidated to pressures of 50 kPa, 100 kPa, 200 kPa and 300 kPa. ususlly the pressures are applied by wall and i think that cylinder dont have side ?

You can discretize the surface with boxes applying appropriate force on them. Boxes are independent, so in a sense it simulates deformable surface.
Or maybe PFacets *

> 3)i need to observe the stress–dilatancy relationship of specimen so the exteral surface should be deformable too,what kind of geom module/material should i use?

just a note, the need of stress-dilatancy IMO does not imply deformable surface.
Have a look at PFacets *
> my script is below, it's totally a mess…

some script is usually better than nothing, but at the same time you cannot expect much from it :-)

* I have no experience with cylinders, grid connections, PFacets.. just to point you to a direction where to search or how to ask further questions

cheers
Jan