Davout 0.1.1.dev182__py3-none-any.whl → 0.1.1.dev183__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- Davout/CuboidGmsh/aa_tests/solids/notch_mesh.py +250 -0
- Davout/DeepMech/aa_tests/SVD_framework/kinematics_surrogate_model.py +16 -9
- Davout/MultiMech/aa_tests_and_examples/physics_prototypes/compressible_hyperelasticity.py +14 -8
- Davout/MultiMech/aa_tests_and_examples/physics_prototypes/incompressible_hyperelasticity.py +8 -3
- Davout/MultiMech/aa_tests_and_examples/physics_prototypes/infinitesimal_plasticity.py +239 -0
- Davout/MultiMech/constitutive_models/hyperelasticity/infinitesimal_elasticity.py +146 -0
- Davout/MultiMech/constitutive_models/plasticity/isotropic_infinitesimal_plasticity.py +636 -0
- Davout/MultiMech/tool_box/boundary_conditions_tools.py +51 -8
- Davout/MultiMech/tool_box/constitutive_tools.py +42 -14
- Davout/MultiMech/tool_box/functional_tools.py +293 -22
- Davout/MultiMech/tool_box/mesh_handling_tools.py +14 -5
- Davout/MultiMech/tool_box/newton_raphson_tools.py +310 -0
- Davout/MultiMech/tool_box/projection_tools.py +652 -0
- Davout/MultiMech/tool_box/pseudotime_stepping_tools.py +6 -6
- Davout/MultiMech/tool_box/read_write_tools.py +371 -113
- Davout/MultiMech/tool_box/surface_loading_tools.py +10 -4
- Davout/MultiMech/tool_box/variational_tools.py +1 -179
- {davout-0.1.1.dev182.dist-info → davout-0.1.1.dev183.dist-info}/METADATA +1 -1
- {davout-0.1.1.dev182.dist-info → davout-0.1.1.dev183.dist-info}/RECORD +22 -16
- {davout-0.1.1.dev182.dist-info → davout-0.1.1.dev183.dist-info}/WHEEL +0 -0
- {davout-0.1.1.dev182.dist-info → davout-0.1.1.dev183.dist-info}/licenses/LICENSE +0 -0
- {davout-0.1.1.dev182.dist-info → davout-0.1.1.dev183.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
# Routine to generate an interchangeble mesh both for thrird medium
|
|
2
|
+
# contact and for notch-based crack propagation.
|
|
3
|
+
#
|
|
4
|
+
# Mesh made by Bianca Grahl Reyes
|
|
5
|
+
|
|
6
|
+
import h5py
|
|
7
|
+
|
|
8
|
+
import numpy as np
|
|
9
|
+
|
|
10
|
+
from .....Davout.CuboidGmsh.solids import cuboid_prisms as prisms
|
|
11
|
+
|
|
12
|
+
from .....Davout.CuboidGmsh.tool_box import meshing_tools as tools
|
|
13
|
+
|
|
14
|
+
from .....Davout.PythonicUtilities.path_tools import get_parent_path_of_file
|
|
15
|
+
|
|
16
|
+
# Defines a function to generate the mesh from a set of geometrical pa-
|
|
17
|
+
# rametres. L is the length of the box, W is the width of the box, H is
|
|
18
|
+
# the height of the box, theta is the notch opening angle, and
|
|
19
|
+
# half_W_notch is the notch width.
|
|
20
|
+
|
|
21
|
+
def generate_mesh(L, W, H, theta, half_W_notch, L_notch, transfinite_x,
|
|
22
|
+
transfinite_y, transfinite_z, transfinite_radial, mesh_file_name,
|
|
23
|
+
bias_x, bias_y, bias_z, bias_radial, include_drittes_medium=True,
|
|
24
|
+
verbose=True):
|
|
25
|
+
|
|
26
|
+
# Verifies whether the notch opening angle of the notch is between 0
|
|
27
|
+
# and 90 degrees
|
|
28
|
+
|
|
29
|
+
if theta<0.0 or theta>90.0:
|
|
30
|
+
|
|
31
|
+
raise ValueError("The notch opening angle should be between 0 "+
|
|
32
|
+
"and 90 degrees. Currently, 'theta' is "+str(theta))
|
|
33
|
+
|
|
34
|
+
# Converts the theta angle to radians
|
|
35
|
+
|
|
36
|
+
theta = theta*(np.pi/180.0)
|
|
37
|
+
|
|
38
|
+
# Verifies whether the notch width is confined within the box width
|
|
39
|
+
|
|
40
|
+
if (2*half_W_notch*np.sin(theta))>=W:
|
|
41
|
+
|
|
42
|
+
raise ValueError("The notch width, 'half_W_notch', and the not"+
|
|
43
|
+
"ch opening angle, 'theta', should be such that 2*half_W_notch"+
|
|
44
|
+
"*sin(theta) < W. So that the notch fits into the width of the"+
|
|
45
|
+
" box")
|
|
46
|
+
|
|
47
|
+
# Verifies whether the notch length is confined within the box length
|
|
48
|
+
|
|
49
|
+
# Defines the surfaces and volumes regions names for imposition of
|
|
50
|
+
# boundary conditions and integration of constitutive models
|
|
51
|
+
|
|
52
|
+
surfaces_regions_names = ["top", "front_solid", "front_third", "back", "bottom"]
|
|
53
|
+
|
|
54
|
+
volumes_regions_names = ["third medium", "solid"]
|
|
55
|
+
|
|
56
|
+
# Initializes the mesh
|
|
57
|
+
|
|
58
|
+
geometric_data = tools.gmsh_initialization(surface_regionsNames=
|
|
59
|
+
surfaces_regions_names, volume_regionsNames=volumes_regions_names)
|
|
60
|
+
|
|
61
|
+
# Creates the upper half of the notch (filled with third medium)
|
|
62
|
+
|
|
63
|
+
# Sets the corner points
|
|
64
|
+
|
|
65
|
+
corner_points = np.array([[L-L_notch, 0.5*W, 0.0], [L, 0.5*W, 0.0],
|
|
66
|
+
[L, (0.5*W)+(half_W_notch*np.sin(theta)), 0.0], [L-L_notch+(
|
|
67
|
+
half_W_notch*np.cos(theta)), (0.5*W)+(half_W_notch*np.sin(theta)),
|
|
68
|
+
0.0],
|
|
69
|
+
[L-L_notch, 0.5*W, H], [L, 0.5*W, H],
|
|
70
|
+
[L, (0.5*W)+(half_W_notch*np.sin(theta)), H], [L-L_notch+(
|
|
71
|
+
half_W_notch*np.cos(theta)), (0.5*W)+(half_W_notch*np.sin(theta)),
|
|
72
|
+
H]])
|
|
73
|
+
|
|
74
|
+
# Generates this cuboid
|
|
75
|
+
|
|
76
|
+
if include_drittes_medium:
|
|
77
|
+
|
|
78
|
+
geometric_data = prisms.hexahedron_from_corners(corner_points,
|
|
79
|
+
transfinite_directions = [transfinite_y, transfinite_x,
|
|
80
|
+
transfinite_z], geometric_data=geometric_data,
|
|
81
|
+
explicit_volume_physical_group_name = "third medium",
|
|
82
|
+
explicit_surface_physical_group_name = {3: "front_third"},
|
|
83
|
+
bias_directions = {"x": bias_y, "y": bias_x, "z": bias_z})
|
|
84
|
+
|
|
85
|
+
# Creates the upper section of the solid
|
|
86
|
+
|
|
87
|
+
# Sets the corner points
|
|
88
|
+
|
|
89
|
+
corner_points = np.array([[L-L_notch+(half_W_notch*np.cos(theta)),
|
|
90
|
+
(0.5*W)+(half_W_notch*np.sin(theta)), 0.0],
|
|
91
|
+
[L, (0.5*W)+(half_W_notch*np.sin(theta)), 0.0],
|
|
92
|
+
[L, W, 0.0], [0.0, W, 0.0],
|
|
93
|
+
[L-L_notch+(half_W_notch*np.cos(theta)),
|
|
94
|
+
(0.5*W)+(half_W_notch*np.sin(theta)), H],
|
|
95
|
+
[L, (0.5*W)+(half_W_notch*np.sin(theta)), H],
|
|
96
|
+
[L, W, H], [0.0, W, H]])
|
|
97
|
+
|
|
98
|
+
# Generates this cuboid
|
|
99
|
+
|
|
100
|
+
geometric_data = prisms.hexahedron_from_corners(corner_points,
|
|
101
|
+
transfinite_directions = [transfinite_radial, transfinite_x,
|
|
102
|
+
transfinite_z], geometric_data=geometric_data,
|
|
103
|
+
explicit_volume_physical_group_name = "solid",
|
|
104
|
+
explicit_surface_physical_group_name = {3: "front_solid", 4: "top"},
|
|
105
|
+
bias_directions = {"x": bias_radial, "y": bias_x, "z": bias_z})
|
|
106
|
+
|
|
107
|
+
# Creates the upper section of the back of the solid
|
|
108
|
+
|
|
109
|
+
# Sets the corner points
|
|
110
|
+
|
|
111
|
+
corner_points = np.array([[0.0, 0.5*W, 0.0], [L-L_notch, 0.5*W, 0.0],
|
|
112
|
+
[L-L_notch+(half_W_notch*np.cos(theta)), (0.5*W)+(half_W_notch*
|
|
113
|
+
np.sin(theta)), 0.0], [0.0, W, 0.0],
|
|
114
|
+
[0.0, 0.5*W, H], [L-L_notch, 0.5*W, H],
|
|
115
|
+
[L-L_notch+(half_W_notch*np.cos(theta)), (0.5*W)+(half_W_notch*
|
|
116
|
+
np.sin(theta)), H], [0.0, W, H]])
|
|
117
|
+
|
|
118
|
+
# Generates this cuboid
|
|
119
|
+
|
|
120
|
+
geometric_data = prisms.hexahedron_from_corners(corner_points,
|
|
121
|
+
transfinite_directions = [transfinite_y, transfinite_x,
|
|
122
|
+
transfinite_z], geometric_data=geometric_data,
|
|
123
|
+
explicit_volume_physical_group_name = "solid",
|
|
124
|
+
explicit_surface_physical_group_name = {5: "back"},
|
|
125
|
+
bias_directions = {"x": bias_y, "y": bias_radial, "z": bias_z})
|
|
126
|
+
|
|
127
|
+
# Creates the botton section of the back of the solid (6)
|
|
128
|
+
|
|
129
|
+
# Sets the corner points
|
|
130
|
+
|
|
131
|
+
corner_points = np.array([[0.0, 0.0, 0.0], [(L-L_notch)+(
|
|
132
|
+
half_W_notch*np.cos(theta)), 0.5*W-(half_W_notch*np.sin(theta)), 0.0],
|
|
133
|
+
[L-L_notch, 0.5*W, 0.0], [0.0, 0.5*W, 0.0],
|
|
134
|
+
[0.0, 0.0, H], [(L-L_notch)+(half_W_notch*np.cos(theta)),
|
|
135
|
+
0.5*W-(half_W_notch*np.sin(theta)), H],
|
|
136
|
+
[L-L_notch, 0.5*W, H], [0.0, 0.5*W, H]])
|
|
137
|
+
|
|
138
|
+
# Generates this cuboid
|
|
139
|
+
|
|
140
|
+
geometric_data = prisms.hexahedron_from_corners(corner_points,
|
|
141
|
+
transfinite_directions = [transfinite_y, transfinite_radial,
|
|
142
|
+
transfinite_z], geometric_data=geometric_data,
|
|
143
|
+
explicit_volume_physical_group_name = "solid",
|
|
144
|
+
explicit_surface_physical_group_name = {5: "back"},
|
|
145
|
+
bias_directions = {"x": -bias_y, "y": bias_radial, "z": bias_z})
|
|
146
|
+
|
|
147
|
+
# Creates the botton part of the third medium (2)
|
|
148
|
+
|
|
149
|
+
# Sets the corner points
|
|
150
|
+
|
|
151
|
+
corner_points = np.array([[(L-L_notch)+(half_W_notch*np.cos(theta)),
|
|
152
|
+
0.5*W-(half_W_notch*np.sin(theta)), 0.0], [L, 0.5*W-(half_W_notch*
|
|
153
|
+
np.sin(theta)), 0.0], [L, 0.5*W, 0.0], [L-L_notch, 0.5*W, 0.0],
|
|
154
|
+
[(L-L_notch)+(half_W_notch*np.cos(theta)), 0.5*W-(half_W_notch*
|
|
155
|
+
np.sin(theta)), H], [L, 0.5*W-(half_W_notch*np.sin(theta)), H],
|
|
156
|
+
[L, 0.5*W, H], [L-L_notch, 0.5*W, H]])
|
|
157
|
+
|
|
158
|
+
# Generates this cuboid
|
|
159
|
+
|
|
160
|
+
if include_drittes_medium:
|
|
161
|
+
|
|
162
|
+
geometric_data = prisms.hexahedron_from_corners(corner_points,
|
|
163
|
+
transfinite_directions = [transfinite_y, transfinite_x,
|
|
164
|
+
transfinite_z], geometric_data=geometric_data,
|
|
165
|
+
explicit_volume_physical_group_name = "third medium",
|
|
166
|
+
explicit_surface_physical_group_name = {3: "front_third"},
|
|
167
|
+
bias_directions = {"x": -bias_y, "y": bias_x, "z": bias_z})
|
|
168
|
+
|
|
169
|
+
# Creates the botton part of the solid (4)
|
|
170
|
+
|
|
171
|
+
# Sets the corner points
|
|
172
|
+
|
|
173
|
+
corner_points = np.array([[0.0, 0.0, 0.0], [L, 0.0, 0.0],
|
|
174
|
+
[L, (0.5*W)-(half_W_notch*np.sin(theta)), 0.0], [L-L_notch+(
|
|
175
|
+
half_W_notch*np.cos(theta)), (0.5*W)-(half_W_notch*np.sin(theta)), 0.0],
|
|
176
|
+
[0.0, 0.0, H], [L, 0.0, H], [L, (0.5*W)-(half_W_notch*np.sin(theta)),
|
|
177
|
+
H], [L-L_notch+(half_W_notch*np.cos(theta)), (0.5*W)-(half_W_notch*
|
|
178
|
+
np.sin(theta)), H]])
|
|
179
|
+
|
|
180
|
+
# Generates this cuboid
|
|
181
|
+
|
|
182
|
+
geometric_data = prisms.hexahedron_from_corners(corner_points,
|
|
183
|
+
transfinite_directions = [transfinite_y, transfinite_x,
|
|
184
|
+
transfinite_z], geometric_data=geometric_data,
|
|
185
|
+
explicit_volume_physical_group_name = "solid",
|
|
186
|
+
explicit_surface_physical_group_name = {3: "front_solid", 2: "bottom"},
|
|
187
|
+
bias_directions = {"x": -bias_radial, "y": bias_x, "z": bias_z})
|
|
188
|
+
|
|
189
|
+
####################################################################
|
|
190
|
+
# Mesh generation #
|
|
191
|
+
####################################################################
|
|
192
|
+
|
|
193
|
+
tools.gmsh_finalize(geometric_data=geometric_data, file_name=
|
|
194
|
+
mesh_file_name, file_directory="", verbose=verbose)
|
|
195
|
+
|
|
196
|
+
# Testing block
|
|
197
|
+
|
|
198
|
+
if __name__ == "__main__":
|
|
199
|
+
|
|
200
|
+
# Example parameters for the mesh generation
|
|
201
|
+
|
|
202
|
+
L = 10.0
|
|
203
|
+
|
|
204
|
+
W = 5.0
|
|
205
|
+
|
|
206
|
+
H = 3.0
|
|
207
|
+
|
|
208
|
+
theta = 30.0
|
|
209
|
+
|
|
210
|
+
half_W_notch = 1.0
|
|
211
|
+
|
|
212
|
+
L_notch = 8.0
|
|
213
|
+
|
|
214
|
+
# Sets the number of elements of each direction
|
|
215
|
+
|
|
216
|
+
transfinite_x = 10
|
|
217
|
+
|
|
218
|
+
transfinite_y = 4
|
|
219
|
+
|
|
220
|
+
transfinite_z = 5
|
|
221
|
+
|
|
222
|
+
transfinite_radial = 5
|
|
223
|
+
|
|
224
|
+
# Sets the bias factors. When the bias is 1.0, nothing happens and
|
|
225
|
+
# the finite elements are uniformly distributed
|
|
226
|
+
|
|
227
|
+
bias_x = 1.1
|
|
228
|
+
|
|
229
|
+
bias_y = 1.2
|
|
230
|
+
|
|
231
|
+
bias_z = 1.0
|
|
232
|
+
|
|
233
|
+
bias_radial = -1.5
|
|
234
|
+
|
|
235
|
+
# Defines the name of the mesh and appends the whole path to it.
|
|
236
|
+
# Uses a function from Davout to automatically retrieve the path to
|
|
237
|
+
# this file (notch_mesh.py)
|
|
238
|
+
|
|
239
|
+
mesh_file_name = get_parent_path_of_file()+"//notch_mesh"
|
|
240
|
+
|
|
241
|
+
# Sets a flag to add or not the mesh of the third medium
|
|
242
|
+
|
|
243
|
+
include_drittes_medium = True
|
|
244
|
+
|
|
245
|
+
# Calls the mesh generation function
|
|
246
|
+
|
|
247
|
+
generate_mesh(L, W, H, theta, half_W_notch, L_notch, transfinite_x,
|
|
248
|
+
transfinite_y, transfinite_z, transfinite_radial, mesh_file_name,
|
|
249
|
+
bias_x, bias_y, bias_z, bias_radial, include_drittes_medium=
|
|
250
|
+
include_drittes_medium)
|
|
@@ -361,9 +361,13 @@ class RVEKinematicsSurrogateModel:
|
|
|
361
361
|
|
|
362
362
|
if __name__=="__main__":
|
|
363
363
|
|
|
364
|
-
|
|
364
|
+
# Sets the number of transfinite divisions in the RVE mesh
|
|
365
365
|
|
|
366
|
-
n_divisions =
|
|
366
|
+
n_divisions = 10
|
|
367
|
+
|
|
368
|
+
# Sets component to be learnt
|
|
369
|
+
|
|
370
|
+
component_to_be_learnt = "Y"
|
|
367
371
|
|
|
368
372
|
# Sets a dictionary for the number of DOFs in the mesh for each num-
|
|
369
373
|
# ber of divisions
|
|
@@ -372,8 +376,11 @@ if __name__=="__main__":
|
|
|
372
376
|
|
|
373
377
|
# Defines the array with the DOFs to be learnt
|
|
374
378
|
|
|
375
|
-
|
|
376
|
-
|
|
379
|
+
components_dictionary = {"X": 0, "Y": 1, "Z": 2}
|
|
380
|
+
|
|
381
|
+
subdofs_to_learn = np.arange(components_dictionary[
|
|
382
|
+
component_to_be_learnt], dofs_per_number_of_divisions[n_divisions],
|
|
383
|
+
3)
|
|
377
384
|
|
|
378
385
|
# Defines the number of input neurons of the main network. Remember
|
|
379
386
|
# that the data matrix is a tensor [n_samples, n_input_variables].
|
|
@@ -399,7 +406,7 @@ if __name__=="__main__":
|
|
|
399
406
|
1.0}},
|
|
400
407
|
{"quadratic": {"number of neurons": min(n_neurons_per_layer[0],
|
|
401
408
|
n_neurons_per_layer[1]), "a2": 1.0}},
|
|
402
|
-
{"quadratic": {"number of neurons": min(n_neurons_per_layer[1],
|
|
409
|
+
{"quadratic": {"number of neurons": min(n_neurons_per_layer[1],
|
|
403
410
|
n_neurons_per_layer[2])}}]
|
|
404
411
|
|
|
405
412
|
# Sets the modulating function for the weights matrices
|
|
@@ -416,11 +423,11 @@ if __name__=="__main__":
|
|
|
416
423
|
|
|
417
424
|
verbose_delta_iterations = 50
|
|
418
425
|
|
|
419
|
-
n_monte_carlo_realizations =
|
|
426
|
+
n_monte_carlo_realizations = 1000
|
|
420
427
|
|
|
421
|
-
n_best_models =
|
|
428
|
+
n_best_models = 30
|
|
422
429
|
|
|
423
|
-
n_best_samples =
|
|
430
|
+
n_best_samples = 20
|
|
424
431
|
|
|
425
432
|
loss_metric = "MeanSquaredError"
|
|
426
433
|
|
|
@@ -429,7 +436,7 @@ if __name__=="__main__":
|
|
|
429
436
|
|
|
430
437
|
parameters_dtype = "float32"
|
|
431
438
|
|
|
432
|
-
saved_model_file = "
|
|
439
|
+
saved_model_file = "RVE_kinematics_model_"+str(component_to_be_learnt)
|
|
433
440
|
|
|
434
441
|
# Sets the path for the data
|
|
435
442
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Routine to experiment with
|
|
1
|
+
# Routine to experiment with compressible hyperelasticity
|
|
2
2
|
|
|
3
3
|
from dolfin import *
|
|
4
4
|
|
|
@@ -6,7 +6,7 @@ from .....Davout.PythonicUtilities.path_tools import get_parent_path_of_file
|
|
|
6
6
|
|
|
7
7
|
from .....Davout.MultiMech.tool_box.mesh_handling_tools import read_mshMesh
|
|
8
8
|
|
|
9
|
-
from .....Davout.MultiMech.constitutive_models.hyperelasticity.isotropic_hyperelasticity import
|
|
9
|
+
from .....Davout.MultiMech.constitutive_models.hyperelasticity.isotropic_hyperelasticity import NeoHookean
|
|
10
10
|
|
|
11
11
|
from .....Davout.MultiMech.tool_box import functional_tools
|
|
12
12
|
|
|
@@ -31,21 +31,27 @@ E = 1E6
|
|
|
31
31
|
|
|
32
32
|
poisson = 0.3
|
|
33
33
|
|
|
34
|
-
constitutive_models = {"volume 1":
|
|
34
|
+
constitutive_models = {"volume 1": NeoHookean({"E": E, "nu": poisson})}
|
|
35
|
+
|
|
36
|
+
# Checks the constitutive models
|
|
37
|
+
|
|
38
|
+
for constitutive_model in constitutive_models.values():
|
|
39
|
+
|
|
40
|
+
constitutive_model.check_model({})
|
|
35
41
|
|
|
36
42
|
# Sets the function space
|
|
37
43
|
|
|
38
44
|
functional_data_class = functional_tools.construct_monolithicFunctionSpace(
|
|
39
45
|
{"Displacement": {"field type": "vector", "interpolation function": "C"+
|
|
40
|
-
"G", "polynomial degree": 2},
|
|
41
|
-
"terpolation function": "CG", "polynomial degree": 1}}, mesh_data_class)
|
|
46
|
+
"G", "polynomial degree": 2}}, mesh_data_class)
|
|
42
47
|
|
|
43
48
|
# Dirichlet boundary conditions
|
|
44
49
|
|
|
45
|
-
bc, dirichlet_loads, functional_data_class, elements_dictionary,
|
|
50
|
+
(bc, dirichlet_loads, functional_data_class, elements_dictionary,
|
|
51
|
+
variational_form, post_processes, post_processesSubmesh, solution_name) = (
|
|
46
52
|
functional_tools.construct_DirichletBCs({"bottom":
|
|
47
|
-
{"BC case": "FixedSupportDirichletBC",
|
|
48
|
-
|
|
53
|
+
{"BC case": "FixedSupportDirichletBC"}}, functional_data_class,
|
|
54
|
+
mesh_data_class))
|
|
49
55
|
|
|
50
56
|
# Variational form of the exterior work using an uniform referential
|
|
51
57
|
# traction
|
|
@@ -6,7 +6,7 @@ from .....Davout.PythonicUtilities.path_tools import get_parent_path_of_file
|
|
|
6
6
|
|
|
7
7
|
from .....Davout.MultiMech.tool_box.mesh_handling_tools import read_mshMesh
|
|
8
8
|
|
|
9
|
-
from .....Davout.MultiMech.constitutive_models.hyperelasticity.isotropic_hyperelasticity import
|
|
9
|
+
from .....Davout.MultiMech.constitutive_models.hyperelasticity.isotropic_hyperelasticity import NeoHookean
|
|
10
10
|
|
|
11
11
|
from .....Davout.MultiMech.tool_box import functional_tools
|
|
12
12
|
|
|
@@ -31,7 +31,11 @@ E = 1E6
|
|
|
31
31
|
|
|
32
32
|
poisson = 0.3
|
|
33
33
|
|
|
34
|
-
constitutive_model =
|
|
34
|
+
constitutive_model = NeoHookean({"E": E, "nu": poisson})
|
|
35
|
+
|
|
36
|
+
# Checks the constitutive models
|
|
37
|
+
|
|
38
|
+
constitutive_model.check_model({})
|
|
35
39
|
|
|
36
40
|
# Sets the function space
|
|
37
41
|
|
|
@@ -42,7 +46,8 @@ functional_data_class = functional_tools.construct_monolithicFunctionSpace(
|
|
|
42
46
|
|
|
43
47
|
# Dirichlet boundary conditions
|
|
44
48
|
|
|
45
|
-
bc, dirichlet_loads, functional_data_class, elements_dictionary,
|
|
49
|
+
(bc, dirichlet_loads, functional_data_class, elements_dictionary,
|
|
50
|
+
variational_form, post_processes, post_processesSubmesh, solution_name) = (
|
|
46
51
|
functional_tools.construct_DirichletBCs({"bottom":
|
|
47
52
|
{"BC case": "FixedSupportDirichletBC", "sub_fieldsToApplyBC": "Displac"+
|
|
48
53
|
"ement"}}, functional_data_class, mesh_data_class))
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
# Routine to experiment with quadrature elements to allow for implemen-
|
|
2
|
+
# tations concerned with algorithmic procedures in the quadrature points
|
|
3
|
+
|
|
4
|
+
from dolfin import *
|
|
5
|
+
|
|
6
|
+
from .....Davout.PythonicUtilities.path_tools import get_parent_path_of_file
|
|
7
|
+
|
|
8
|
+
from .....Davout.MultiMech.tool_box.mesh_handling_tools import read_mshMesh
|
|
9
|
+
|
|
10
|
+
from .....Davout.MultiMech.constitutive_models.plasticity.isotropic_infinitesimal_plasticity import ExponentialHardeningElastoPlasticWithBackStress
|
|
11
|
+
|
|
12
|
+
from .....Davout.MultiMech.constitutive_models.hyperelasticity.infinitesimal_elasticity import LinearIsotropicElastic
|
|
13
|
+
|
|
14
|
+
from .....Davout.MultiMech.tool_box import functional_tools
|
|
15
|
+
|
|
16
|
+
from .....Davout.MultiMech.tool_box import variational_tools
|
|
17
|
+
|
|
18
|
+
from .....Davout.MultiMech.tool_box.newton_raphson_tools import NewtonRaphson
|
|
19
|
+
|
|
20
|
+
from .....Davout.MultiMech.tool_box.read_write_tools import write_field_to_xdmf
|
|
21
|
+
|
|
22
|
+
# Creates a box mesh using gmsh
|
|
23
|
+
|
|
24
|
+
shape_function_degree = 3
|
|
25
|
+
|
|
26
|
+
quadrature_degree = int(2*(shape_function_degree-1))
|
|
27
|
+
|
|
28
|
+
mesh_data_class = read_mshMesh({"length x": 0.3, "length y": 0.2, "len"+
|
|
29
|
+
"gth z": 3.0, "number of divisions in x": 5, "number of divisions in y":
|
|
30
|
+
5, "number of divisions in z": 40, "verbose": False, "mesh file name":
|
|
31
|
+
"box_mesh", "mesh file directory": get_parent_path_of_file()},
|
|
32
|
+
quadrature_degree=quadrature_degree)
|
|
33
|
+
|
|
34
|
+
# Neumann boundary conditions
|
|
35
|
+
|
|
36
|
+
maximum_load = 1.5E3
|
|
37
|
+
|
|
38
|
+
plastic_material = False
|
|
39
|
+
|
|
40
|
+
# Sets the number of load steps (pseudo-time steps)
|
|
41
|
+
|
|
42
|
+
n_load_steps = 5
|
|
43
|
+
|
|
44
|
+
# Sets the constitutive model
|
|
45
|
+
|
|
46
|
+
E = 1E6
|
|
47
|
+
|
|
48
|
+
poisson = 0.3
|
|
49
|
+
|
|
50
|
+
# Sets the coefficients of the plastic behavior
|
|
51
|
+
|
|
52
|
+
sigma_y = 2E3
|
|
53
|
+
|
|
54
|
+
H_back_stress = 0.0
|
|
55
|
+
|
|
56
|
+
K_1 = E*0.02
|
|
57
|
+
|
|
58
|
+
K_2 = 0.0
|
|
59
|
+
|
|
60
|
+
theta = 0.0
|
|
61
|
+
|
|
62
|
+
constitutive_models = None
|
|
63
|
+
|
|
64
|
+
if plastic_material:
|
|
65
|
+
|
|
66
|
+
constitutive_models = {"volume 1":
|
|
67
|
+
ExponentialHardeningElastoPlasticWithBackStress({"E": E, "nu":
|
|
68
|
+
poisson, "sigma_y": sigma_y, "H": H_back_stress, "K_1": K_1, "K_2":
|
|
69
|
+
K_2, "theta": theta}, newton_raphson_tolerance=1E-4)}
|
|
70
|
+
|
|
71
|
+
else:
|
|
72
|
+
|
|
73
|
+
constitutive_models = {"volume 1": LinearIsotropicElastic({"E": E,
|
|
74
|
+
"nu": poisson})}
|
|
75
|
+
|
|
76
|
+
# Checks the constitutive models and ensures that the supplied param-
|
|
77
|
+
# eters are correct
|
|
78
|
+
|
|
79
|
+
for constitutive_model in constitutive_models.values():
|
|
80
|
+
|
|
81
|
+
constitutive_model.check_model({"mesh_data_class": mesh_data_class})
|
|
82
|
+
|
|
83
|
+
# Sets the function space
|
|
84
|
+
|
|
85
|
+
functional_data_class = functional_tools.construct_monolithicFunctionSpace(
|
|
86
|
+
{"Displacement": {"field type": "vector", "interpolation function": "C"+
|
|
87
|
+
"G", "polynomial degree": shape_function_degree}}, mesh_data_class,
|
|
88
|
+
verbose=True)
|
|
89
|
+
|
|
90
|
+
# Dirichlet boundary conditions
|
|
91
|
+
|
|
92
|
+
(bc, dirichlet_loads, functional_data_class, elements_dictionary,
|
|
93
|
+
variational_form, post_processes, post_processesSubmesh, solution_name) = (
|
|
94
|
+
functional_tools.construct_DirichletBCs({"bottom": {"BC case": "Simple"+
|
|
95
|
+
"SupportDirichletBC", "bc_informationsDict": {"list_of_constrained_dofs":
|
|
96
|
+
[2]}}, "right": {"BC case": "SimpleSupportDirichletBC", "bc_information"+
|
|
97
|
+
"sDict": {"list_of_constrained_dofs": [1]}}, "back": {"BC case": "Simp"+
|
|
98
|
+
"leSupportDirichletBC", "bc_informationsDict": {"list_of_constrained_d"+
|
|
99
|
+
"ofs": [0]}}}, functional_data_class, mesh_data_class))
|
|
100
|
+
|
|
101
|
+
# Variational form of the exterior work using an uniform referential
|
|
102
|
+
# traction
|
|
103
|
+
|
|
104
|
+
external_work, neumann_loads = variational_tools.traction_work({"top": {
|
|
105
|
+
"load case": "UniformReferentialTraction", "amplitude_tractionX":
|
|
106
|
+
0.0, "amplitude_tractionY": 0.0, "amplitude_tractionZ": maximum_load,
|
|
107
|
+
"parametric_load_curve": "linear", "t": 0.0, "t_final": 1.0}},
|
|
108
|
+
"Displacement", functional_data_class, mesh_data_class, [])
|
|
109
|
+
|
|
110
|
+
# Computes the elements necessary to pull-back the Cauchy stress to the
|
|
111
|
+
# first Piola-Kirchhoff stress tensor using Nanson's formula
|
|
112
|
+
|
|
113
|
+
I = Identity(functional_data_class.solution_fields["Displacement"
|
|
114
|
+
].geometric_dimension())
|
|
115
|
+
|
|
116
|
+
F = grad(functional_data_class.solution_fields["Displacement"])+I
|
|
117
|
+
|
|
118
|
+
F_invT = inv(F).T
|
|
119
|
+
|
|
120
|
+
J = det(F)
|
|
121
|
+
|
|
122
|
+
# Gets the variational form of the inner work
|
|
123
|
+
|
|
124
|
+
internal_work = 0.0
|
|
125
|
+
|
|
126
|
+
for physical_group, constitutive_model in constitutive_models.items():
|
|
127
|
+
|
|
128
|
+
print("\nUpdates the constitutive model at '"+str(physical_group)+
|
|
129
|
+
"'")
|
|
130
|
+
|
|
131
|
+
# Updates the internal variables and the tangent modulus. The second
|
|
132
|
+
# argument is false, because this update is not inside a Newton-
|
|
133
|
+
# Raphson iteration
|
|
134
|
+
|
|
135
|
+
if plastic_material:
|
|
136
|
+
|
|
137
|
+
constitutive_model.update_internal_variables(
|
|
138
|
+
functional_data_class.solution_fields["Displacement"],
|
|
139
|
+
flag_newton_raphson_iteration=False)
|
|
140
|
+
|
|
141
|
+
# Gets the Cauchy stress tensor from the linear elastic constitutive
|
|
142
|
+
# relation and pulls it back to the first Piola-Kirchhoff stress
|
|
143
|
+
# tensor. This way, a formulation of large displacements and infini-
|
|
144
|
+
# tesimal strains can be accomplished, since the linearization of
|
|
145
|
+
# the first Piola-Kirchhoff stress tensor will carry the geometric
|
|
146
|
+
# nonlinearities
|
|
147
|
+
|
|
148
|
+
sigma = constitutive_model.cauchy_stress(
|
|
149
|
+
functional_data_class.solution_fields["Displacement"])
|
|
150
|
+
|
|
151
|
+
P = J*sigma*F_invT
|
|
152
|
+
|
|
153
|
+
internal_work += (inner(P, (grad(
|
|
154
|
+
functional_data_class.variation_fields["Displacement"])))*
|
|
155
|
+
mesh_data_class.dx(mesh_data_class.domain_physicalGroupsNameToTag[
|
|
156
|
+
physical_group]))
|
|
157
|
+
|
|
158
|
+
# Defines a function to update the variational form
|
|
159
|
+
|
|
160
|
+
verbose = True
|
|
161
|
+
|
|
162
|
+
def variational_form_update_function(pseudo_time,
|
|
163
|
+
flag_newton_raphson_iteration, verbose=verbose):
|
|
164
|
+
|
|
165
|
+
# Update the load class
|
|
166
|
+
|
|
167
|
+
neumann_loads[0].update_load(pseudo_time, verbose=verbose)
|
|
168
|
+
|
|
169
|
+
if verbose:
|
|
170
|
+
|
|
171
|
+
print("\nUpdates the constitutive model at '"+str(physical_group
|
|
172
|
+
)+"'")
|
|
173
|
+
|
|
174
|
+
# Updates the internal variables and the tangent modulus
|
|
175
|
+
|
|
176
|
+
if plastic_material:
|
|
177
|
+
|
|
178
|
+
constitutive_models["volume 1"].update_internal_variables(
|
|
179
|
+
functional_data_class.solution_fields["Displacement"],
|
|
180
|
+
flag_newton_raphson_iteration=flag_newton_raphson_iteration,
|
|
181
|
+
verbose=verbose)
|
|
182
|
+
|
|
183
|
+
# Defines a class to perform post-processes. In this case, simply sa-
|
|
184
|
+
# ving the output field
|
|
185
|
+
|
|
186
|
+
class PostProcesses:
|
|
187
|
+
|
|
188
|
+
def __init__(self, visualization_copy):
|
|
189
|
+
|
|
190
|
+
self.xdmf_file = None
|
|
191
|
+
|
|
192
|
+
self.visualization_copy_file = None
|
|
193
|
+
|
|
194
|
+
self.visualization_copy = visualization_copy
|
|
195
|
+
|
|
196
|
+
def __call__(self, pseudo_time, time_step):
|
|
197
|
+
|
|
198
|
+
# Saves this pseudo-time step in a xdmf file
|
|
199
|
+
|
|
200
|
+
if self.visualization_copy:
|
|
201
|
+
|
|
202
|
+
self.xdmf_file, self.visualization_copy_file = write_field_to_xdmf(
|
|
203
|
+
functional_data_class, explicit_file_name=
|
|
204
|
+
get_parent_path_of_file()+"//displacement_finite_deformat"+
|
|
205
|
+
"ion_with_infinitesimal_strain.xdmf", file=self.xdmf_file,
|
|
206
|
+
time=pseudo_time, time_step=time_step, visualization_copy=
|
|
207
|
+
self.visualization_copy, visualization_copy_file=
|
|
208
|
+
self.visualization_copy_file,
|
|
209
|
+
flag_read_copy=True, close_file=False)
|
|
210
|
+
|
|
211
|
+
else:
|
|
212
|
+
|
|
213
|
+
self.xdmf_file = write_field_to_xdmf(functional_data_class,
|
|
214
|
+
explicit_file_name=get_parent_path_of_file()+"//displaceme"+
|
|
215
|
+
"nt_finite_deformation_with_infinitesimal_strain.xdmf",
|
|
216
|
+
file=self.xdmf_file, time=pseudo_time, time_step=time_step)
|
|
217
|
+
|
|
218
|
+
post_processes = PostProcesses(True)
|
|
219
|
+
|
|
220
|
+
# Sets the Newton-Raphson solver
|
|
221
|
+
|
|
222
|
+
newton_raphson_class = NewtonRaphson(n_load_steps, variational_form=(
|
|
223
|
+
internal_work-external_work), functional_data_class=
|
|
224
|
+
functional_data_class, boundary_conditions_list=bc,
|
|
225
|
+
variational_form_update_function=variational_form_update_function,
|
|
226
|
+
post_processing_function=post_processes, use_custom_newton=True)
|
|
227
|
+
|
|
228
|
+
# Calls the loading procedure
|
|
229
|
+
|
|
230
|
+
newton_raphson_class()
|
|
231
|
+
|
|
232
|
+
if plastic_material:
|
|
233
|
+
|
|
234
|
+
print("\nEvaluates the internal variables after the full load hist"+
|
|
235
|
+
"ory")
|
|
236
|
+
|
|
237
|
+
constitutive_models["volume 1"].update_internal_variables(
|
|
238
|
+
functional_data_class.solution_fields["Displacement"],
|
|
239
|
+
flag_newton_raphson_iteration=False, verbose=True)
|