PeriDEM 0.2.0
PeriDEM -- Peridynamics-based high-fidelity model for granular media
Loading...
Searching...
No Matches
particle_wall.py
Go to the documentation of this file.
1import os
2import numpy as np
3import sys
4from pathlib import Path
5import subprocess
6import argparse
7
8# import util functions
9from util import *
10
11
12def particle_locations(filename, radius, centers, pp_tag = None):
13 """
14 Creates .csv file containing the center, radius, orientation, and zone id of each particle in two-particle setup
15
16 Parameters
17 ----------
18 filename : str
19 Filename of .csv file to be created
20 radius: list
21 List containing radius of a particle
22 centers: list
23 List containing the centers of a particle
24 pp_tag: str, optional
25 Postfix .geo file with this tag
26 """
27 pp_tag_str = '_{}'.format(str(pp_tag)) if pp_tag is not None else ''
28 inpf = open(filename + pp_tag_str + '.csv','w')
29 inpf.write('i, x, y, z, r, o\n')
30 for i in range(len(radius)):
31 inpf.write('%d, ' % i)
32 inpf.write(print_list(centers[i], '%Lf'))
33 inpf.write(', %Lf' % radius[i])
34 o = 0. if i == 0 else np.pi * 0.5
35 inpf.write(', %Lf\n' % o)
36 inpf.close()
37
38if __name__ == "__main__":
39
40 parser = argparse.ArgumentParser(description='Setup and run PeriDEM simulation')
41 parser.add_argument('--peridem_path',
42 default=None,
43 type=str,
44 help="Path to PeriDEM executable")
45 args = parser.parse_args()
46 if args.peridem_path is None:
47 raise ValueError("Invalid path to PeriDEM executable")
48 if Path(args.peridem_path).is_file() == False:
49 raise ValueError("PeriDEM executable does not exist")
50
51 fpath = './'
52
54 center = [0., 0., 0.]
55
56
57 g = [0., -10., 0.]
58
59
60 R = 0.001
61
62
63 h = R / 8.
64
65
66 horizon = 3. * h
67
68
69 wall_rect = [0., 0., 0., 2.*R, horizon, 0.]
70
71
72 d = 0.001
73 # reduce compute time by reducing the distance between particle and wall and assigning top particle velocity
74 delta = d - horizon
75 v0 = [0, -np.sqrt(2. * np.abs(g[1]) * delta), 0.]
76
77
78 T = 0.1
79 N_steps = 2000000
80 # if dt is large, the simulation could produce garbage results so care is needed
81 dt = T / N_steps
82 # steps per output, i.e., simulation will generate output every 50 steps
83 N_out = N_steps / 100
84
85
87 nu1 = 0.25
88 rho1 = 1200.
89 K1 = 2.16e+7
90 E1 = get_E(K1, nu1) # see util.py
91 G1 = get_G(E1, nu1)
92 Gc1 = 50.
93
94 # for zone 2 (in this case zone 2 consists of wall)
95 nu2 = 0.25
96 rho2 = 1200.
97 K2 = 2.16e+7
98 E2 = get_E(K2, nu2)
99 G2 = get_G(E2, nu2)
100 Gc2 = 50.
101
102
106 R_contact_factor = 0.95
107
108
109 Kn_11 = 18. * get_eff_k(K1, K1) / (np.pi * np.power(horizon, 5))
110 Kn_22 = 18. * get_eff_k(K2, K2) / (np.pi * np.power(horizon, 5))
111 Kn_12 = 18. * get_eff_k(K1, K2) / (np.pi * np.power(horizon, 5))
112
113
114 beta_n_eps = 0.9
115 # factor for damping (Constant C in the PeriDEM paper)
116 beta_n_factor = 5000.
117 damping_active = True
118
119
120 friction_coeff = 0.5
121 friction_active = False # friction is not active
122
123 # create particle_locations.csv file
124 centers = []
125 centers.append([R, wall_rect[4] + (d - delta) + R, 0.])
126 print('top height = %Lf' % (wall_rect[4] + d + 2*R))
127 particle_locations(fpath + 'particle_locations', [R], centers)
128
129
130 generate_circle_gmsh_input(fpath + 'p', center, R, h)
131 generate_rectangle_gmsh_input(fpath + 'w', wall_rect, h)
132
133
134 inpf = open(fpath + 'input.yaml','w')
135
136
137 inpf.write("Model:\n")
138 inpf.write(" Dimension: 2\n")
139 inpf.write(" Discretization_Type:\n")
140 inpf.write(" Spatial: finite_difference\n") # we refer to meshfree discretization by finite_difference
141 inpf.write(" Time: central_difference\n") # you can use either central_difference or velocity_verlet
142 inpf.write(" Final_Time: %4.6e\n" % (T))
143 inpf.write(" Time_Steps: %d\n" % (N_steps))
144
145
146 inpf.write("Policy:\n")
147 inpf.write(" Enable_PostProcessing: true\n")
148
149
153 inpf.write("Container:\n")
154 inpf.write(" Geometry:\n")
155 inpf.write(" Type: rectangle\n")
156 # we define container to be rectangle.
157 # in the code, we need to provide 6 element vector to define a rectangle
158 # first 3 in the vector correspond to coordinate of the left-bottom corner
159 # and remaining correspond to coordinates of the right-top corner
160 contain_params = [0., 0., 0., 2.*R, 4.*R, 0.]
161 inpf.write(" Parameters: " + print_dbl_list(contain_params))
162
163
165 inpf.write("Zone:\n")
166 inpf.write(" Zones: 2\n")
167
168
169 inpf.write(" Zone_1:\n")
170 # specify that this is not a zone containing wall
171 inpf.write(" Is_Wall: false\n")
172
173
174 inpf.write(" Zone_2:\n")
175 inpf.write(" Is_Wall: true\n")
176 inpf.write(" Type: rectangle\n")
177 inpf.write(" Parameters: " + print_dbl_list(wall_rect))
178
179
182 inpf.write("Particle:\n")
183 # specify reference particle details for zone 1 particles (in this case zone 1 has just one particle)
184 inpf.write(" Zone_1:\n")
185 # reference particle is of circular type
186 inpf.write(" Type: circle\n")
187 # in the code, circle is defined using 4 vector array
188 # first element in the vector is radius, and rest are the coordinates of the center
189 # recall that we fixed referene particles at center = [0,0,0]
190 p_geom = [R, center[0], center[1], center[2]]
191 inpf.write(" Parameters: " + print_dbl_list(p_geom))
192
193
194 inpf.write("Wall:\n")
195 inpf.write(" Zone_2:\n")
196 inpf.write(" Type: flexible\n")
197 inpf.write(" All_Dofs_Constrained: true\n")
198 inpf.write(" Mesh: true\n")
199
200
201 inpf.write("Particle_Generation:\n")
202 inpf.write(" From_File: particle_locations.csv\n")
203 inpf.write(" File_Data_Type: loc_rad_orient\n")
204
205
206 inpf.write("Mesh:\n")
207
208 # zone 1
209 inpf.write(" Zone_1:\n")
210 inpf.write(" File: p.msh \n")
211
212 # zone 2
213 inpf.write(" Zone_2:\n")
214 inpf.write(" File: w.msh \n")
215
216
218 inpf.write("Contact:\n")
219
220 # 11
221 # this fixes the contact between two particles in zone 1
222 inpf.write(" Zone_11:\n")
223 inpf.write(" Contact_Radius_Factor: %4.6e\n" % (R_contact_factor))
224
225 if damping_active == False:
226 inpf.write(" Damping_On: false\n")
227 if friction_active == False:
228 inpf.write(" Friction_On: false\n")
229
230 inpf.write(" Kn: %4.6e\n" % (Kn_11))
231 inpf.write(" Epsilon: %4.6e\n" % (beta_n_eps))
232 inpf.write(" Friction_Coeff: %4.6e\n" % (friction_coeff))
233 inpf.write(" Kn_Factor: 1.0\n")
234 inpf.write(" Beta_n_Factor: %4.6e\n" % (beta_n_factor))
235
236 # 12
237 # this fixes the contact between two particles in zone 1 and zone 2
238 inpf.write(" Zone_12:\n")
239 inpf.write(" Contact_Radius_Factor: %4.6e\n" % (R_contact_factor))
240
241 if damping_active == False:
242 inpf.write(" Damping_On: false\n")
243 if friction_active == False:
244 inpf.write(" Friction_On: false\n")
245
246 inpf.write(" Kn: %4.6e\n" % (Kn_12))
247 inpf.write(" Epsilon: %4.6e\n" % (beta_n_eps))
248 inpf.write(" Friction_Coeff: %4.6e\n" % (friction_coeff))
249 inpf.write(" Kn_Factor: 1.0\n")
250 inpf.write(" Beta_n_Factor: %4.6e\n" % (beta_n_factor))
251
252 # 22
253 inpf.write(" Zone_22:\n")
254 inpf.write(" Contact_Radius_Factor: %4.6e\n" % (R_contact_factor))
255
256 if damping_active == False:
257 inpf.write(" Damping_On: false\n")
258 if friction_active == False:
259 inpf.write(" Friction_On: false\n")
260
261 inpf.write(" Kn: %4.6e\n" % (Kn_22))
262 inpf.write(" Epsilon: %4.6e\n" % (beta_n_eps))
263 inpf.write(" Friction_Coeff: %4.6e\n" % (friction_coeff))
264 inpf.write(" Kn_Factor: 1.0\n")
265 inpf.write(" Beta_n_Factor: %4.6e\n" % (beta_n_factor))
266
267
269 inpf.write("Neighbor:\n")
270 inpf.write(" Update_Criteria: simple_all\n")
271 inpf.write(" Search_Factor: 5.0\n")
272
273
275 inpf.write("Material:\n")
276
277 # zone 1
278 inpf.write(" Zone_1:\n")
279 inpf.write(" Type: PDState\n")
280 inpf.write(" Horizon: %4.6e\n" % (horizon))
281 inpf.write(" Density: %4.6e\n" % (rho1))
282 inpf.write(" Compute_From_Classical: true\n")
283 inpf.write(" K: %4.6e\n" % (K1))
284 inpf.write(" G: %4.6e\n" % (G1))
285 inpf.write(" Gc: %4.6e\n" % (Gc1))
286 inpf.write(" Influence_Function:\n")
287 inpf.write(" Type: 1\n")
288
289 # zone 2
290 inpf.write(" Zone_2:\n")
291 inpf.write(" Type: PDState\n")
292 inpf.write(" Horizon: %4.6e\n" % (horizon))
293 inpf.write(" Density: %4.6e\n" % (rho2))
294 inpf.write(" Compute_From_Classical: true\n")
295 inpf.write(" K: %4.6e\n" % (K2))
296 inpf.write(" G: %4.6e\n" % (G2))
297 inpf.write(" Gc: %4.6e\n" % (Gc2))
298 inpf.write(" Influence_Function:\n")
299 inpf.write(" Type: 1\n")
300
301
303 inpf.write("Force_BC:\n")
304 inpf.write(" Gravity: " + print_dbl_list(g))
305
306
307 inpf.write("IC:\n")
308 inpf.write(" Constant_Velocity:\n")
309 inpf.write(" Velocity_Vector: " + print_dbl_list(v0))
310 inpf.write(" Particle_List: [0]\n")
311
312
313 inpf.write("Displacement_BC:\n")
314 inpf.write(" Sets: 2\n")
315 inpf.write(" Set_1:\n")
316 inpf.write(" Wall_List: [0]\n")
317 inpf.write(" Direction: [1,2]\n")
318 inpf.write(" Time_Function:\n")
319 inpf.write(" Type: constant\n")
320 inpf.write(" Parameters:\n")
321 inpf.write(" - 0.0\n")
322 inpf.write(" Spatial_Function:\n")
323 inpf.write(" Type: constant\n")
324 inpf.write(" Zero_Displacement: true\n")
325
326 inpf.write(" Set_2:\n")
327 inpf.write(" Particle_List: [0]\n")
328 inpf.write(" Direction: [1]\n")
329 inpf.write(" Time_Function:\n")
330 inpf.write(" Type: constant\n")
331 inpf.write(" Parameters:\n")
332 inpf.write(" - 0.0\n")
333 inpf.write(" Spatial_Function:\n")
334 inpf.write(" Type: constant\n")
335
336
338 inpf.write("Output:\n")
339 # where to write files
340 inpf.write(" Path: ./\n")
341 inpf.write(" Tags:\n")
342 # list the variable that you want to output in the .vtu file
343 inpf.write(" - Displacement\n")
344 inpf.write(" - Velocity\n")
345 inpf.write(" - Force\n")
346 inpf.write(" - Force_Density\n")
347 inpf.write(" - Damage_Z\n")
348 inpf.write(" - Damage\n")
349 inpf.write(" - Nodal_Volume\n")
350 inpf.write(" - Zone_ID\n")
351 inpf.write(" - Particle_ID\n")
352 inpf.write(" - Fixity\n")
353 inpf.write(" - Force_Fixity\n")
354 inpf.write(" - Contact_Nodes\n")
355 inpf.write(" - No_Fail_Node\n")
356 inpf.write(" - Boundary_Node_Flag\n")
357 inpf.write(" - Theta\n")
358 # how frequent the output should take place
359 inpf.write(" Output_Interval: %d\n" % (N_out))
360 inpf.write(" Compress_Type: zlib\n")
361 inpf.write(" Perform_FE_Out: false\n")
362 inpf.write(" Perform_Out: true\n")
363 # how frequent we dump the test specific outputs
364 inpf.write(" Test_Output_Interval: %d\n" % (N_out))
365 # what is verbosity level (last time I checked, the maximum is 3 so if you have 3 or above it will
366 # produce maximum debug information)
367 inpf.write(" Debug: 3\n")
368 # assign this simulation a tag
369 inpf.write(" Tag_PP: 0\n")
370
371
372 inpf.write("HPX:\n")
373 inpf.write(" Partitions: 1\n")
374
375
377 inpf.close()
378
379
381 print('running gmsh')
382 cmd = "gmsh p.geo -2 &> /dev/null"
383 process = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)
384 output, error = process.communicate()
385
386 cmd = "gmsh w.geo -2 &> /dev/null"
387 process = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)
388 output, error = process.communicate()
389
390
391 print('running peridem')
392 cmd = args.peridem_path + " -i input.yaml -nThreads 8"
393 process = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)
394 output, error = process.communicate()
particle_locations(filename, radius, centers, pp_tag=None)
generate_rectangle_gmsh_input(filename, rectangle, mesh_size, pp_tag=None)
Definition util.py:369
get_eff_k(k1, k2)
Definition util.py:86
get_G(E, nu)
Definition util.py:67
print_dbl_list(arg, prefix="")
Definition util.py:25
print_list(arg, fmt='%4.6e', delim=', ')
Definition util.py:8
generate_circle_gmsh_input(filename, center, radius, mesh_size, pp_tag=None)
Definition util.py:320
get_E(K, nu)
Definition util.py:49