File: Test4.py

package info (click to toggle)
yade 2026.1.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 34,448 kB
  • sloc: cpp: 97,645; python: 52,173; sh: 677; makefile: 162
file content (168 lines) | stat: -rw-r--r-- 6,250 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
# -*- encoding=utf-8 -*-
# 2023 © Vasileios Angelidakis <vasileios.angelidakis@fau.de>
# 2023 © Bruno Chareyre <bruno.chareyre@grenoble-inp.fr>
# 2023 © Robert Caulk <rob.caulk@gmail.com>

# Benchmarks from Chung and Ooi (2011)
# Test No 4: Oblique impact of a sphere with a rigid plane with a constant resultant velocity but at different incident angles
# Units: SI (m, N, Pa, kg, sec)

# script execution:
# yade Test4.py (with default arguments, else:)
# yade Test4.py [aluminium_oxide|aluminium_alloy] [en] [use_en]
# example: yade Test4.py aluminium_oxide 5 False (equivalent to default)

# ------------------------------------------------------------------------------------------
import math
from yade import plot
import sys

material = str(sys.argv[1]) if len(sys.argv) > 1 else 'aluminium_oxide'  # options are 'aluminium_oxide'|'aluminium_alloy'
angle = float(str(sys.argv[2])) if len(sys.argv) > 2 else 5  # Incident angle (degrees)
use_en = sys.argv[3] if len(sys.argv) > 3 else 'False'  # optional parameter, whether to define en/es or betan/betas
vn_ini = 3.9
en = 0.98

try:
	os.mkdir('outputData')
except:
	pass  # will pass if folder already exists

# ------------------------------------------------------------------------------------------
# Material properties
if material == 'aluminium_oxide':
	spheresMat = O.materials.append(FrictMat(young=3.8e11, poisson=0.23, density=4000, frictionAngle=atan(0.092)))
	wallsMat = O.materials.append(
	        FrictMat(young=3.8e14, poisson=0.23, density=4000, frictionAngle=atan(0.092))
	)  # The wall/facet elements are 1000 stiffer than the sphere
elif material == 'aluminium_alloy':
	spheresMat = O.materials.append(FrictMat(young=7.0e10, poisson=0.33, density=2700, frictionAngle=atan(0.092)))
	wallsMat = O.materials.append(
	        FrictMat(young=7.0e13, poisson=0.33, density=2700, frictionAngle=atan(0.092))
	)  # The wall/facet elements are 1000 stiffer than the sphere
else:
	print('The material should be either aluminium_oxide or aluminium_alloy')

# ------------------------------------------------------------------------------------------
# Create boundary as wall/facet
r = 0.0025
distance = r  # initial distance of sphere from plane

O.bodies.append(sphere([-distance, 0, 0], material=spheresMat, radius=r))
O.bodies.append(wall(position=0, axis=0, material=wallsMat))  # Use walls
#O.bodies.append(facet([[0,-3*r,-3*r],[0,-3*r,3*r],[0,3*r,0]],material=wallsMat,fixed=True,color=[1,0,0])) # Use facets

b0 = O.bodies[0]
b1 = O.bodies[1]

b0.state.vel[0] = vn_ini * cos(
        radians(angle)
)  # X velocity component - horizontal		-> Note: The rigid plane is normal to the X direction (i.e. parallel to the Y-Z plane)
b0.state.vel[1] = vn_ini * sin(radians(angle))  # Y velocity component - vertical

hasHadContact = False  # Whether the two bodies have ever been in contact

if use_en == 'True':  # Here I use 'True' as a string
	ip2 = Ip2_FrictMat_FrictMat_MindlinPhys(en=en, es=en)
else:
	# Option 1: Traditional formula of beta-en
	#	betan=-log(en)/(pi**2+(log(en)**2))**0.5

	# Option 2: Thornton et al (2013) specifically for a Hertzian model with no attractive forces
	h1 = -6.918798
	h2 = -16.41105
	h3 = 146.8049
	h4 = -796.4559
	h5 = 2928.711
	h6 = -7206.864
	h7 = 11494.29
	h8 = -11342.18
	h9 = 6276.757
	h10 = -1489.915

	alpha = en * (h1 + en * (h2 + en * (h3 + en * (h4 + en * (h5 + en * (h6 + en * (h7 + en * (h8 + en * (h9 + en * h10)))))))))
	betan = 0 if en == 1.0 else sqrt(1 / (1 - ((1 + en)**2) * exp(alpha)) - 1)  # This is noted as gamma in Thornton et al (2013)

	betas = betan  # betas=0.0
	ip2 = Ip2_FrictMat_FrictMat_MindlinPhys(betan=betan, betas=betas)

# ------------------------------------------------------------------------------------------
# Calculate elastic contact parameters
Ea = O.materials[0].young
Va = O.materials[0].poisson
Ga = Ea / (2 * (1 + Va))

Eb = O.materials[1].young
Vb = O.materials[1].poisson
Gb = Eb / (2 * (1 + Vb))

E = Ea * Eb / ((1. - Va**2) * Eb + (1. - Vb**2) * Ea)
G = 1.0 / ((2 - Va) / Ga + (2 - Vb) / Gb)

Kno = 4.0 / 3.0 * E * sqrt(r)
Kso = 8.0 * sqrt(r) * G

# ------------------------------------------------------------------------------------------
# Simulation loop
O.engines = [
        ForceResetter(),
        InsertionSortCollider([Bo1_Sphere_Aabb(), Bo1_Facet_Aabb(), Bo1_Wall_Aabb()]),
        InteractionLoop(
                # handle facet+sphere and wall+sphere collisions
                [Ig2_Facet_Sphere_ScGeom(), Ig2_Wall_Sphere_ScGeom()],
                [ip2],
                [Law2_ScGeom_MindlinPhys_Mindlin(preventGranularRatcheting=False)]
        ),
        NewtonIntegrator(gravity=(0, 0, 0), damping=0),
        PyRunner(command='addPlotData()', iterPeriod=1)
]

O.dt = 0.01 * RayleighWaveTimeStep()


# ------------------------------------------------------------------------------------------
# Collect history of data which will be plotted
def addPlotData():
	global hasHadContact
	if O.interactions.countReal() > 0:
		ii = O.interactions.nth(0)
		ii.phys.kno = Kno
		ii.phys.kso = Kso
		hasHadContact = True
	else:
		if hasHadContact == True and b0.state.pos[0] < -distance:
			vn_fin = b0.state.vel[0]

			en = b0.state.vel[0] / (vn_ini * cos(radians(angle)))
			et = b0.state.vel[1] / (vn_ini * sin(radians(angle)))
			theta = degrees(
			        atan((-et * vn_ini * sin(radians(angle)) - r * b0.state.angVel[2]) / (en * vn_ini * cos(radians(angle))))
			)  # Contact-patch rebound angle

			flag = 'w' if angle == 5 else 'a'  # Rewrite file for the first value angle=5 or else append
			name = '_en_es' if use_en == 'True' else '_betan_betas'

			with open('outputData/Test4_' + material + name + '.txt', flag) as myfile:
				myfile.write(str(angle))
				myfile.write(' ')
				myfile.write(str(et))  # Tangential coefficient of restitution
				myfile.write(' ')
				myfile.write(str(b0.state.angVel[2]))  # Post-collision angular velocity
				myfile.write(' ')
				myfile.write(str(theta))  # Rebound angle (degrees)
				myfile.write("\n")
			O.pause()


O.saveTmp()

# ------------------------------------------------------------------------------------------
# Visualisation
try:
	from yade import qt
	v = qt.View()
	v.sceneRadius = 5 * r
except:
	pass

O.run()