PeriDEM 0.2.0
PeriDEM -- Peridynamics-based high-fidelity model for granular media
Loading...
Searching...
No Matches
util.py
Go to the documentation of this file.
1import os
2import numpy as np
3import sys
4
5def print_const(arg, fmt = '%4.6e', prefix = ""):
6 return prefix + fmt % arg + '\n'
7
8def print_list(arg, fmt = '%4.6e', delim = ', '):
9 a = ''
10 for i in range(len(arg)):
11 a += fmt % arg[i]
12 if i < len(arg) - 1:
13 a += delim
14 return a
15
16def print_bool(arg, prefix = ""):
17 return prefix + 'True\n' if arg == True else 'False\n'
18
19def print_dbl(arg, prefix = ""):
20 return print_const(arg, '%4.6e', prefix)
21
22def print_int(arg, prefix = ""):
23 return print_const(arg, '%d', prefix)
24
25def print_dbl_list(arg, prefix = ""):
26 a = prefix + '[' + print_list(arg, '%4.6e') + ']\n'
27 return a
28
29def print_int_list(arg, prefix = ""):
30 a = prefix + '[' + print_list(arg, '%4.6e') + ']\n'
31 return a
32
33def print_point_gmsh(arg, n):
34 return 'Point(%d) = {' % n + print_list(arg) + '};\n'
35
36def print_cir_gmsh(arg, n):
37 return 'Circle(%d) = {' % n + print_list(arg, '%d') + '};\n'
38
39def print_line_gmsh(arg, n):
40 return 'Line(%d) = {' % n + print_list(arg, '%d') + '};\n'
41
42def print_lineloop_gmsh(arg, n):
43 return 'Line Loop(%d) = {' % n + print_list(arg, '%d') + '};\n'
44
45def gmsh_file_hdr(f):
46 f.write('cl__1 = 1;\n')
47 f.write('Mesh.MshFileVersion = 2.2;\n')
48
49def get_E(K, nu):
50 """
51 Returns Young's modulus given bulk modulus and Poisson's ratio
52
53 Parameters
54 ----------
55 K : float
56 Bulk modulus
57 nu : float
58 Poisson's ratio
59
60 Returns
61 -------
62 float
63 Young's modulus
64 """
65 return 3. * K * (1. - 2. * nu)
66
67def get_G(E, nu):
68 """
69 Returns shear modulus given Young's modulus and Poisson's ratio
70
71 Parameters
72 ----------
73 E: float
74 Young's modulus
75 nu : float
76 Poisson's ratio
77
78 Returns
79 -------
80 float
81 Shear modulus
82 """
83 return E / (2. * (1. + nu))
84
85
86def get_eff_k(k1, k2):
87 """
88 Returns effective bulk modulus
89
90 Parameters
91 ----------
92 k1: float
93 First bulk modulus
94 k2 : float
95 Second bulk modulus
96
97 Returns
98 -------
99 float
100 Effective bulk modulus
101 """
102 return 2. * k1 * k2 / (k1 + k2)
103
104def get_max(l):
105 """
106 Returns maximum value in list
107
108 Parameters
109 ----------
110 l: list
111 List of values
112
113 Returns
114 -------
115 float
116 Maximum value
117 """
118 l = np.array(l)
119 return l.max()
120
121def rotate(p, theta, axis):
122 """
123 Returns rotation of vector about specified axis by specified angle
124
125 Parameters
126 ----------
127 p: list
128 Coordinates of vector
129 theta : float
130 Angle of rotation
131 axis : list
132 Axis of rotation
133
134 Returns
135 -------
136 list
137 Coordinates of rotated vector
138 """
139 p_np, axis_np = np.array(p), np.array(axis)
140 ct, st = np.cos(theta), np.sin(theta)
141 p_dot_n = np.dot(p_np,axis_np)
142 n_cross_p = np.cross(axis_np, p_np)
143
144 return (1. - ct) * p_dot_n * axis_np + ct * p_np + st * n_cross_p
145
146def get_ref_hex_points(center, radius, add_center = False):
147 """
148 Returns size points on reference hexagon
149
150 Reference hexagon:
151
152 v3 v2
153 + +
154
155
156 + o +
157 v4 x v1
158
159 + +
160 v5 v6
161
162 Axis is a vector from x to v1 and radius is distance between x and v1.
163
164 Parameters
165 ----------
166 center: list
167 Coordinates of center of hexagon
168 radius : float
169 Radius of hexagon
170 add_center : bool
171 True if we include the center to the returned list (first point in the returned list will be the center if the flag is true)
172
173 Returns
174 -------
175 list
176 Coordinates of points
177 """
178 axis = [1., 0., 0.]
179 rotate_axis = [0., 0., 1.]
180 points = []
181 if add_center:
182 points.append(center)
183
184 for i in range(6):
185 xi = rotate(axis, i*np.pi/3., rotate_axis)
186 points.append([center[i] + radius * xi[i] for i in range(3)])
187
188 return points
189
190def get_ref_drum_points(center, radius, width, add_center = False):
191 """
192 Returns size points on reference concave polygon (we refer to it as drum)
193
194 Reference concave polygon:
195
196 v3 v2
197 + -------------------------------- +
198 \ /
199 \ /
200 + o +
201 /v4 x v1 \
202 / \
203 + -------------------------------- +
204 v5 v6
205
206 Axis is a vector from x to v1, radius is distance between x and v2, and width of neck is the distance between v2 and v4.
207
208 Parameters
209 ----------
210 center: list
211 Coordinates of center of polygon
212 radius : float
213 Radius of polygon (distance between center x and vertex v2)
214 width : float
215 Width of neck, i.e. distance between vertex v2 and v4
216 add_center : bool
217 True if we include the center to the returned list (first point in the returned list will be the center if the flag is true)
218
219 Returns
220 -------
221 list
222 Coordinates of points
223 """
224 axis = [1., 0., 0.]
225 rotate_axis = [0., 0., 1.]
226
227 x1 = rotate(axis, np.pi/3., rotate_axis)
228 x2 = rotate(axis, -np.pi/3., rotate_axis)
229
230 points = []
231 if add_center:
232 points.append(center)
233
234 # v1
235 points.append([center[i] + width*0.5*axis[i] for i in range(3)])
236 # v2
237 points.append([center[i] + radius*x1[i] for i in range(3)])
238 # v3
239 points.append([center[i] + radius*x1[i] - radius*axis[i] for i in range(3)])
240 # v4
241 points.append([center[i] - width*0.5*axis[i] for i in range(3)])
242 # v5
243 v6 = [center[i] + radius*x2[i] for i in range(3)]
244 points.append([v6[i] - radius*axis[i] for i in range(3)])
245 # v6
246 points.append(v6)
247
248 return points
249
250
251def does_intersect(p, particles, padding):
252 """
253 Returns true if particle p intersects or is near enough to existing particles
254
255 Parameters
256 ----------
257 p : list
258 Coordinates of center and radius of particle [x,y,z,r]
259 particles : list
260 List of center + radius of multiple particles. E.g. particles[0] is a list containing coordinates of center and radius.
261 padding: float
262 Minimum distance between circle boundaries such that if two circles
263
264 Returns
265 -------
266 bool
267 True if particle intersects or is near enough to one of the particle in the list
268 """
269 if len(p) < 4: raise Exception('p = {} must have atleast 4 elements'.format(p))
270 if len(particles) == 0: raise Exception('particles = {} can not be empty'.format(particles))
271 if padding < 0.: raise Exception('padding = {} can not be negative'.format(padding))
272
273 for q in particles:
274 if len(q) < 4: raise Exception('q = {} in particles must have atleast 4 elements'.format(q))
275 pq = np.array([p[i] - q[i] for i in range(3)])
276 if np.linalg.norm(pq) <= p[3] + q[3] + padding:
277 return True
278 return False
279
280def does_intersect_rect(p, particles, padding, rect, is_3d = False):
281 """
282 Returns true if particle p is sufficiently close or outside the rectangle (in 2d) or cuboid (in 3d)
283
284 Parameters
285 ----------
286 p : list
287 Coordinates of center and radius of particle [x,y,z,r]
288 particles : list
289 List of center + radius of multiple particles. E.g. particles[0] is a list containing coordinates of center and radius.
290 padding: float
291 Minimum distance between circle boundaries such that if two circles
292 rect: list
293 Coordinates of left-bottom and right-top corner points of rectangle (2d) or cuboid (3d). E.g. [x1 y1, z1, x2, y2, z2]
294 is_3d: bool
295 True if we are dealing with cuboid
296
297 Returns
298 -------
299 bool
300 True if particle intersects or is near enough to the rectangle
301 """
302 if len(p) < 4: raise Exception('p = {} must have atleast 4 elements'.format(p))
303 if len(particles) == 0: raise Exception('particles = {} can not be empty'.format(particles))
304 if padding < 0.: raise Exception('padding = {} can not be negative'.format(padding))
305 if len(rect) < 6: raise Exception('rect = {} must have 6 elements'.format(rect))
306
307 pr = [p[0] - p[3], p[1] - p[3], p[2], p[0] + p[3], p[1] + p[3], p[2]]
308 if is_3d:
309 pr[2] -= p[3]
310 pr[5] += p[3]
311
312 if pr[0] < rect[0] + padding or pr[1] < rect[1] + padding or pr[3] > rect[3] - padding or pr[4] > rect[4] - padding:
313 if is_3d:
314 if pr[2] < rect[2] + padding or pr[5] > rect[5] - padding:
315 return True
316 else:
317 return True
318 return False
319
320def generate_circle_gmsh_input(filename, center, radius, mesh_size, pp_tag = None):
321 """
322 Creates .geo file for discretization of circle using gmsh
323
324 Parameters
325 ----------
326 filename : str
327 Filename of .geo file to be created
328 center : list
329 Coordinates of center of circle
330 radius: float
331 Radius of circle
332 mesh_size: float
333 Mesh size
334 pp_tag: str, optional
335 Postfix .geo file with this tag
336 """
337 pp_tag_str = '_{}'.format(str(pp_tag)) if pp_tag is not None else ''
338 geof = open(filename + pp_tag_str + '.geo','w')
339 gmsh_file_hdr(geof)
340
341
342 points = []
343 points.append([center[0], center[1], center[2]])
344 points.append([center[0] + radius, center[1], center[2]])
345 points.append([center[0] - radius, center[1], center[2]])
346 points.append([center[0], center[1] + radius, center[2]])
347 points.append([center[0], center[1] - radius, center[2]])
348 for i in range(len(points)):
349 geof.write(print_point_gmsh([points[i][0], points[i][1], points[i][2], mesh_size], i+1))
350
351
352 geof.write(print_cir_gmsh([2,1,4], 1))
353 geof.write(print_cir_gmsh([4,1,3], 2))
354 geof.write(print_cir_gmsh([3,1,5], 3))
355 geof.write(print_cir_gmsh([5,1,2], 4))
356
357
358 geof.write(print_lineloop_gmsh([2, 3, 4, 1], 1))
359
360
361 geof.write("Plane Surface(1) = {1};\n")
362
363
364 geof.write("Point{1} In Surface {1};")
365
366
367 geof.close()
368
369def generate_rectangle_gmsh_input(filename, rectangle, mesh_size, pp_tag = None):
370 """
371 Creates .geo file for discretization of rectangle using gmsh
372
373 Parameters
374 ----------
375 filename : str
376 Filename of .geo file to be created
377 rectangle : list
378 Coordinates of left-bottom and right-top corner points of rectangle
379 mesh_size: float
380 Mesh size
381 pp_tag: str, optional
382 Postfix .geo file with this tag
383 """
384 pp_tag_str = '_{}'.format(str(pp_tag)) if pp_tag is not None else ''
385 geof = open(filename + pp_tag_str + '.geo','w')
386 gmsh_file_hdr(geof)
387
388
389 points = []
390 points.append([rectangle[0], rectangle[1], rectangle[2]])
391 points.append([rectangle[3], rectangle[1], rectangle[2]])
392 points.append([rectangle[3], rectangle[4], rectangle[2]])
393 points.append([rectangle[0], rectangle[4], rectangle[2]])
394 for i in range(len(points)):
395 geof.write(print_point_gmsh([points[i][0], points[i][1], points[i][2], mesh_size], i+1))
396
397
398 for i in range(4):
399 if i < 3:
400 geof.write(print_line_gmsh([i+1,i+2], i+1))
401 else:
402 geof.write(print_line_gmsh([i+1,1], i+1))
403
404
405 geof.write(print_lineloop_gmsh([i+1 for i in range(4)], 1))
406
407
408 geof.write("Plane Surface(1) = {1};\n")
409
410
411 geof.write("Point{1} In Surface {1};")
412
413
414 tag = '"' + "a" + '"'
415 geof.write("Physical Surface(%s) = {1};\n" % (tag))
416
417
418 geof.close()
419
420def generate_hexagon_gmsh_input(filename, center, radius, mesh_size, pp_tag = None):
421 """
422 Creates .geo file for discretization of hexagon using gmsh
423
424 Parameters
425 ----------
426 filename : str
427 Filename of .geo file to be created
428 center : list
429 Coordinates of center of hexagon
430 radius: float
431 Radius
432 mesh_size: float
433 Mesh size
434 pp_tag: str, optional
435 Postfix .geo file with this tag
436 """
437 pp_tag_str = '_{}'.format(str(pp_tag)) if pp_tag is not None else ''
438 geof = open(filename + pp_tag_str + '.geo','w')
439 gmsh_file_hdr(geof)
440
441
442 points = get_ref_hex_points(center, radius, True)
443 for i in range(len(points)):
444 geof.write(print_point_gmsh([points[i][0], points[i][1], points[i][2], mesh_size], i+1))
445
446
447 for i in range(6):
448 if i < 5:
449 geof.write(print_line_gmsh([i+2,i+3], i+1))
450 else:
451 geof.write(print_line_gmsh([i+2,2], i+1))
452
453
454 geof.write(print_lineloop_gmsh([i+1 for i in range(6)], 1))
455
456
457 geof.write("Plane Surface(1) = {1};\n")
458
459
460 geof.write("Point{1} In Surface {1};")
461
462
463 geof.close()
464
465
466def generate_drum_gmsh_input(filename, center, radius, width, mesh_size, pp_tag = None):
467 """
468 Creates .geo file for discretization of drum (concave polygon, see get_ref_drum_points) using gmsh
469
470 Parameters
471 ----------
472 filename : str
473 Filename of .geo file to be created
474 center : list
475 Coordinates of center
476 radius: float
477 Radius
478 width: float
479 Neck width (see get_ref_drum_points())
480 mesh_size: float
481 Mesh size
482 pp_tag: str, optional
483 Postfix .geo file with this tag
484 """
485 pp_tag_str = '_{}'.format(str(pp_tag)) if pp_tag is not None else ''
486 geof = open(filename + pp_tag_str + '.geo','w')
487 gmsh_file_hdr(geof)
488
489
490 points = get_ref_drum_points(center, radius, width, True)
491 for i in range(len(points)):
492 geof.write(print_point_gmsh([points[i][0], points[i][1], points[i][2], mesh_size], i+1))
493
494
495 for i in range(6):
496 if i < 5:
497 geof.write(print_line_gmsh([i+2,i+3], i+1))
498 else:
499 geof.write(print_line_gmsh([i+2,2], i+1))
500
501
502 geof.write(print_lineloop_gmsh([i+1 for i in range(6)], 1))
503
504
505 geof.write("Plane Surface(1) = {1};\n")
506
507
508 geof.write("Point{1} In Surface {1};")
509
510
511 geof.close()