File: script-session1.py

package info (click to toggle)
yade 2025.2.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 33,308 kB
  • sloc: cpp: 93,298; python: 50,409; sh: 577; makefile: 162
file content (221 lines) | stat: -rw-r--r-- 10,353 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# -*- encoding=utf-8 -*-
#*************************************************************************
#  Copyright (C) 2010 by Bruno Chareyre                                  *
#  bruno.chareyre_at_grenoble-inp.fr                                     *
#                                                                        *
#  This program is free software; it is licensed under the terms of the  *
#  GNU General Public License v2 or later. See file LICENSE for details. *
#*************************************************************************/

## This script details the simulation of a triaxial test on sphere packings using Yade
## See the associated pdf file for detailed exercises
## the algorithms presented here have been used in published papers, namely:
## * Chareyre et al. 2002 (http://www.geosyntheticssociety.org/Resources/Archive/GI/src/V9I2/GI-V9-N2-Paper1.pdf)
## * Chareyre and Villard 2005 (https://yade-dem.org/w/images/1/1b/Chareyre&Villard2005_licensed.pdf)
## * Scholtès et al. 2009 (http://dx.doi.org/10.1016/j.ijengsci.2008.07.002)
## * Tong et al.2012 (http://dx.doi.org/10.2516/ogst/2012032)
##
## Most of the ideas were actually developped during my PhD.
## If you want to know more on micro-macro relations evaluated by triaxial simulations
## AND if you can read some french, it is here: http://tel.archives-ouvertes.fr/docs/00/48/68/07/PDF/Thesis.pdf

from yade import pack

############################################
###   DEFINING VARIABLES AND MATERIALS   ###
############################################

# The following 5 lines will be used later for batch execution
nRead = readParamsFromTable(
        num_spheres=1000,  # number of spheres
        compFricDegree=30,  # contact friction during the confining phase
        key='_triax_base_',  # put you simulation's name here
        unknownOk=True
)
from yade.params import table

num_spheres = table.num_spheres  # number of spheres
key = table.key
targetPorosity = 0.43  #the porosity we want for the packing
compFricDegree = table.compFricDegree  # initial contact friction during the confining phase (will be decreased during the REFD compaction process)
finalFricDegree = 30  # contact friction during the deviatoric loading
rate = -0.02  # loading rate (strain rate)
damp = 0.2  # damping coefficient
stabilityThreshold = 0.01  # we test unbalancedForce against this value in different loops (see below)
young = 5e6  # contact stiffness
mn, mx = Vector3(0, 0, 0), Vector3(1, 1, 1)  # corners of the initial packing

## create materials for spheres and plates
O.materials.append(FrictMat(young=young, poisson=0.5, frictionAngle=radians(compFricDegree), density=2600, label='spheres'))
O.materials.append(FrictMat(young=young, poisson=0.5, frictionAngle=0, density=0, label='walls'))

## create walls around the packing
walls = aabbWalls([mn, mx], thickness=0, material='walls')
wallIds = O.bodies.append(walls)

## use a SpherePack object to generate a random loose particles packing
sp = pack.SpherePack()

clumps = False  #turn this true for the same example with clumps
if clumps:
	## approximate mean rad of the futur dense packing for latter use
	volume = (mx[0] - mn[0]) * (mx[1] - mn[1]) * (mx[2] - mn[2])
	mean_rad = pow(0.09 * volume / num_spheres, 0.3333)
	## define a unique clump type (we could have many, see clumpCloud documentation)
	c1 = pack.SpherePack([((-0.2 * mean_rad, 0, 0), 0.5 * mean_rad), ((0.2 * mean_rad, 0, 0), 0.5 * mean_rad)])
	## generate positions and input them in the simulation
	sp.makeClumpCloud(mn, mx, [c1], periodic=False)
	sp.toSimulation(material='spheres')
	O.bodies.updateClumpProperties()  #get more accurate clump masses/volumes/inertia
else:
	sp.makeCloud(mn, mx, -1, 0.3333, num_spheres, False, 0.95, seed=1)  #"seed" make the "random" generation always the same
	O.bodies.append([sphere(center, rad, material='spheres') for center, rad in sp])
	#or alternatively (higher level function doing exactly the same):
	#sp.toSimulation(material='spheres')

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

triax = TriaxialStressController(
        ## TriaxialStressController will be used to control stress and strain. It controls particles size and plates positions.
        ## this control of boundary conditions was used for instance in http://dx.doi.org/10.1016/j.ijengsci.2008.07.002
        maxMultiplier=1. + 2e4 / young,  # spheres growing factor (fast growth)
        finalMaxMultiplier=1. + 2e3 / young,  # spheres growing factor (slow growth)
        thickness=0,
        ## switch stress/strain control using a bitmask. What is a bitmask, huh?!
        ## Say x=1 if stess is controlled on x, else x=0. Same for for y and z, which are 1 or 0.
        ## Then an integer uniquely defining the combination of all these tests is: mask = x*1 + y*2 + z*4
        ## to put it differently, the mask is the integer whose binary representation is xyz, i.e.
        ## "100" (1) means "x", "110" (3) means "x and y", "111" (7) means "x and y and z", etc.
        stressMask=7,
        internalCompaction=True,  # If true the confining pressure is generated by growing particles
)

newton = NewtonIntegrator(damping=damp)

O.engines = [
        ForceResetter(),
        InsertionSortCollider([Bo1_Sphere_Aabb(), Bo1_Box_Aabb()]),
        InteractionLoop([Ig2_Sphere_Sphere_ScGeom(), Ig2_Box_Sphere_ScGeom()], [Ip2_FrictMat_FrictMat_FrictPhys()], [Law2_ScGeom_FrictPhys_CundallStrack()]),
        ## 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' + table.key),
        newton
]

if nRead == 0:
	yade.qt.Controller(), yade.qt.View()

## UNCOMMENT THE FOLLOWING SECTIONS ONE BY ONE
## DEPENDING ON YOUR EDITOR, IT COULD BE DONE
## BY SELECTING THE CODE BLOCKS BETWEEN THE SUBTITLES
## AND PRESSING CTRL+SHIFT+D

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

#the value of (isotropic) confining stress defines the target stress to be applied in all three directions
triax.goal1 = triax.goal2 = triax.goal3 = -10000

#while 1:
#O.run(1000, 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

#O.save('confinedState'+key+'.yade.gz')
#print "###      Isotropic state saved      ###"

###################################################
###   REACHING A SPECIFIED POROSITY PRECISELY   ###
###################################################

### We will reach a prescribed value of porosity with the REFD algorithm
### (see http://dx.doi.org/10.2516/ogst/2012032 and
### http://www.geosyntheticssociety.org/Resources/Archive/GI/src/V9I2/GI-V9-N2-Paper1.pdf)

#import sys #this is only for the flush() below
#while triax.porosity>targetPorosity:
## we decrease friction value and apply it to all the bodies and contacts
#compFricDegree = 0.95*compFricDegree
#setContactFriction(radians(compFricDegree))
#print "\r Friction: ",compFricDegree," porosity:",triax.porosity,
#sys.stdout.flush()
## while we run steps, triax will tend to grow particles as the packing
## keeps shrinking as a consequence of decreasing friction. Consequently
## porosity will decrease
#O.run(500,1)

#O.save('compactedState'+key+'.yade.gz')
#print "###    Compacted state saved      ###"

##############################
###   DEVIATORIC LOADING   ###
##############################

##We move to deviatoric loading, let us turn internal compaction off to keep particles sizes constant
#triax.internalCompaction=False

## Change contact friction (remember that decreasing it would generate instantaneous instabilities)
#setContactFriction(radians(finalFricDegree))

##set stress control on x and z, we will impose strain rate on y
#triax.stressMask = 5
##now goal2 is the target strain rate
#triax.goal2=rate
## we define the lateral stresses during the test, here the same 10kPa as for the initial confinement.
#triax.goal1=-10000
#triax.goal3=-10000

##we can change damping here. What is the effect in your opinion?
#newton.damping=0.1

##Save temporary state in live memory. This state will be reloaded from the interface with the "reload" button.
#O.saveTmp()

#####################################################
###    Example of how to record and plot data     ###
#####################################################

#from yade import plot

### a function saving variables
#def history():
#plot.addData(e11=-triax.strain[0], e22=-triax.strain[1], e33=-triax.strain[2],
#ev=-triax.strain[0]-triax.strain[1]-triax.strain[2],
#s11=-triax.stress(triax.wall_right_id)[0],
#s22=-triax.stress(triax.wall_top_id)[1],
#s33=-triax.stress(triax.wall_front_id)[2],
#i=O.iter)

#if 1:
## include a periodic engine calling that function in the simulation loop
#O.engines=O.engines[0:5]+[PyRunner(iterPeriod=20,command='history()',label='recorder')]+O.engines[5:7]
##O.engines.insert(4,PyRunner(iterPeriod=20,command='history()',label='recorder'))
#else:
## With the line above, we are recording some variables twice. We could in fact replace the previous
## TriaxialRecorder
## by our periodic engine. Uncomment the following line:
#O.engines[4]=PyRunner(iterPeriod=20,command='history()',label='recorder')

#O.run(100,True)

### declare what is to plot. "None" is for separating y and y2 axis
#plot.plots={'i':('e11','e22','e33',None,'s11','s22','s33')}
### the traditional triaxial curves would be more like this:
##plot.plots={'e22':('s11','s22','s33',None,'ev')}

## display on the screen (doesn't work on VMware image it seems)
#plot.plot()

#####  PLAY THE SIMULATION HERE WITH "PLAY" BUTTON OR WITH THE COMMAND O.run(N)  #####

## In that case we can still save the data to a text file at the the end of the simulation, with:
#plot.saveDataTxt('results'+key)
##or even generate a script for gnuplot. Open another terminal and type  "gnuplot plotScriptKEY.gnuplot:
#plot.saveGnuplot('plotScript'+key)