ANYsolver 0.1.0__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.
Files changed (70) hide show
  1. anysolver/__init__.py +631 -0
  2. anysolver/anystructure_fem_mode.py +942 -0
  3. anysolver/arc_length.py +758 -0
  4. anysolver/assembly.py +950 -0
  5. anysolver/baselines.py +303 -0
  6. anysolver/beam_shell_verification.py +4276 -0
  7. anysolver/beam_validity.py +110 -0
  8. anysolver/benchmarks.py +495 -0
  9. anysolver/boundary.py +476 -0
  10. anysolver/buckling.py +442 -0
  11. anysolver/buckling_validity.py +91 -0
  12. anysolver/capacity_workflow.py +350 -0
  13. anysolver/cases.py +173 -0
  14. anysolver/composite_strip_verification.py +297 -0
  15. anysolver/contact.py +3461 -0
  16. anysolver/corotational.py +371 -0
  17. anysolver/cylinder_benchmarks.py +364 -0
  18. anysolver/dynamics.py +723 -0
  19. anysolver/element_qualification.py +432 -0
  20. anysolver/elements.py +2724 -0
  21. anysolver/external_references.py +369 -0
  22. anysolver/fe_core.py +327 -0
  23. anysolver/fracture.py +551 -0
  24. anysolver/imperfections.py +390 -0
  25. anysolver/jit_compiler.py +108 -0
  26. anysolver/kernel_warmup.py +180 -0
  27. anysolver/linalg.py +760 -0
  28. anysolver/mass_properties.py +179 -0
  29. anysolver/material_curves.py +231 -0
  30. anysolver/matrix_assembly.py +558 -0
  31. anysolver/mesh_gen.py +1065 -0
  32. anysolver/mesh_load_bc_verification.py +609 -0
  33. anysolver/modal.py +282 -0
  34. anysolver/nonlinear.py +300 -0
  35. anysolver/nonlinear_performance.py +920 -0
  36. anysolver/nonlinear_performance_batch_b.py +592 -0
  37. anysolver/nonlinear_performance_batch_c.py +506 -0
  38. anysolver/nonlinear_performance_bootstrap.py +120 -0
  39. anysolver/nonlinear_reduced_assembly.py +760 -0
  40. anysolver/nonlinear_static.py +1518 -0
  41. anysolver/plasticity.py +419 -0
  42. anysolver/plasticity_qualification.py +314 -0
  43. anysolver/production_readiness.py +304 -0
  44. anysolver/quality_control.py +1497 -0
  45. anysolver/recovery.py +505 -0
  46. anysolver/recovery_policy.py +205 -0
  47. anysolver/reference_cases.py +425 -0
  48. anysolver/results.py +503 -0
  49. anysolver/runtime.py +9030 -0
  50. anysolver/s4_validity.py +326 -0
  51. anysolver/sesam_fem/__init__.py +55 -0
  52. anysolver/sesam_fem/__main__.py +80 -0
  53. anysolver/sesam_fem/diagnostics.py +65 -0
  54. anysolver/sesam_fem/document.py +814 -0
  55. anysolver/sesam_fem/exporter.py +84 -0
  56. anysolver/sesam_fem/importer.py +365 -0
  57. anysolver/sesam_fem/records.py +257 -0
  58. anysolver/sesam_fem/schema.py +107 -0
  59. anysolver/sesam_fem/sif_importer.py +397 -0
  60. anysolver/sesam_fem/validation.py +62 -0
  61. anysolver/shell_benchmarks.py +367 -0
  62. anysolver/test_cases.py +610 -0
  63. anysolver/validation.py +416 -0
  64. anysolver/vectorized_nonlinear.py +334 -0
  65. anysolver/vectorized_stiffness.py +571 -0
  66. anysolver-0.1.0.dist-info/METADATA +165 -0
  67. anysolver-0.1.0.dist-info/RECORD +70 -0
  68. anysolver-0.1.0.dist-info/WHEEL +5 -0
  69. anysolver-0.1.0.dist-info/licenses/LICENSE +674 -0
  70. anysolver-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,334 @@
1
+ import numpy as np
2
+ from typing import Tuple, Optional, Any, Dict
3
+
4
+ from .jit_compiler import njit
5
+ from .plasticity import plane_stress_return_map
6
+ from .elements import lobatto_layers, plane_stress_elastic_matrix
7
+
8
+
9
+ @njit
10
+ def _jit_batch_integrate_nonlinear_response(
11
+ u_loc_batch: np.ndarray,
12
+ N_res_batch: np.ndarray,
13
+ M_res_batch: np.ndarray,
14
+ C0_batch: np.ndarray,
15
+ C1_batch: np.ndarray,
16
+ C2_batch: np.ndarray,
17
+ B_m_all_batch: np.ndarray,
18
+ B_b_all_batch: np.ndarray,
19
+ B_d_all_batch: np.ndarray,
20
+ Gw_all_batch: np.ndarray,
21
+ detw_all_batch: np.ndarray,
22
+ B_s_all_batch: np.ndarray,
23
+ detw_shear_all_batch: np.ndarray,
24
+ D_shear: np.ndarray,
25
+ drilling_stiffness: float,
26
+ tangent: bool,
27
+ has_plasticity: bool,
28
+ n_dof: int,
29
+ ) -> Tuple[np.ndarray, np.ndarray]:
30
+ n_elem = u_loc_batch.shape[0]
31
+ F_loc_batch = np.zeros((n_elem, n_dof))
32
+ K_loc_batch = np.zeros((n_elem, n_dof, n_dof))
33
+
34
+ n_gp = detw_all_batch.shape[1]
35
+
36
+ for e in range(n_elem):
37
+ u_loc = u_loc_batch[e]
38
+ detw_all = detw_all_batch[e]
39
+ B_m_all = B_m_all_batch[e]
40
+ B_b_all = B_b_all_batch[e]
41
+ B_d_all = B_d_all_batch[e]
42
+ Gw_all = Gw_all_batch[e]
43
+ N_res = N_res_batch[e]
44
+ M_res = M_res_batch[e]
45
+ C0 = C0_batch[e]
46
+ C1 = C1_batch[e]
47
+ C2 = C2_batch[e]
48
+
49
+ for g in range(n_gp):
50
+ detw = detw_all[g]
51
+ B_m = B_m_all[g]
52
+ B_b = B_b_all[g]
53
+ B_d = B_d_all[g]
54
+ Gw = Gw_all[g]
55
+
56
+ theta_0 = 0.0
57
+ theta_1 = 0.0
58
+ for i in range(n_dof):
59
+ theta_0 += Gw[0, i] * u_loc[i]
60
+ theta_1 += Gw[1, i] * u_loc[i]
61
+
62
+ B_eff = np.zeros((3, n_dof))
63
+ for i in range(n_dof):
64
+ B_eff[0, i] = B_m[0, i] + theta_0 * Gw[0, i]
65
+ B_eff[1, i] = B_m[1, i] + theta_1 * Gw[1, i]
66
+ B_eff[2, i] = B_m[2, i] + theta_0 * Gw[1, i] + theta_1 * Gw[0, i]
67
+
68
+ N_g = N_res[g]
69
+ M_g = M_res[g]
70
+ B_eff_T_N = np.zeros(n_dof)
71
+ B_b_T_M = np.zeros(n_dof)
72
+ for i in range(n_dof):
73
+ B_eff_T_N[i] = B_eff[0, i] * N_g[0] + B_eff[1, i] * N_g[1] + B_eff[2, i] * N_g[2]
74
+ B_b_T_M[i] = B_b[0, i] * M_g[0] + B_b[1, i] * M_g[1] + B_b[2, i] * M_g[2]
75
+
76
+ Bd_u = 0.0
77
+ for i in range(n_dof):
78
+ Bd_u += B_d[0, i] * u_loc[i]
79
+
80
+ for i in range(n_dof):
81
+ F_loc_batch[e, i] += (B_eff_T_N[i] + B_b_T_M[i]) * detw
82
+ F_loc_batch[e, i] += B_d[0, i] * (drilling_stiffness * Bd_u) * detw
83
+
84
+ if not tangent:
85
+ continue
86
+
87
+ C0_g = C0[g]
88
+ C2_g = C2[g]
89
+
90
+ C0_B_eff = np.zeros((3, n_dof))
91
+ C2_B_b = np.zeros((3, n_dof))
92
+ for r in range(3):
93
+ for c in range(n_dof):
94
+ val0 = 0.0
95
+ val2 = 0.0
96
+ for k in range(3):
97
+ val0 += C0_g[r, k] * B_eff[k, c]
98
+ val2 += C2_g[r, k] * B_b[k, c]
99
+ C0_B_eff[r, c] = val0
100
+ C2_B_b[r, c] = val2
101
+
102
+ for r in range(n_dof):
103
+ for c in range(n_dof):
104
+ val_eff = 0.0
105
+ val_b = 0.0
106
+ for k in range(3):
107
+ val_eff += B_eff[k, r] * C0_B_eff[k, c]
108
+ val_b += B_b[k, r] * C2_B_b[k, c]
109
+ K_loc_batch[e, r, c] += (val_eff + val_b) * detw
110
+
111
+ if has_plasticity:
112
+ C1_g = C1[g]
113
+ C1_B_b = np.zeros((3, n_dof))
114
+ C1_B_eff = np.zeros((3, n_dof))
115
+ for r in range(3):
116
+ for c in range(n_dof):
117
+ val_b = 0.0
118
+ val_eff = 0.0
119
+ for k in range(3):
120
+ val_b += C1_g[r, k] * B_b[k, c]
121
+ val_eff += C1_g[r, k] * B_eff[k, c]
122
+ C1_B_b[r, c] = val_b
123
+ C1_B_eff[r, c] = val_eff
124
+
125
+ for r in range(n_dof):
126
+ for c in range(n_dof):
127
+ forward = 0.0
128
+ reverse = 0.0
129
+ for k in range(3):
130
+ forward += B_eff[k, r] * C1_B_b[k, c]
131
+ reverse += B_b[k, r] * C1_B_eff[k, c]
132
+ K_loc_batch[e, r, c] += (forward + reverse) * detw
133
+
134
+ N00 = N_g[0]
135
+ N11 = N_g[1]
136
+ N01 = N_g[2]
137
+
138
+ N_Gw_0 = N00 * Gw[0] + N01 * Gw[1]
139
+ N_Gw_1 = N01 * Gw[0] + N11 * Gw[1]
140
+ for r in range(n_dof):
141
+ for c in range(n_dof):
142
+ K_loc_batch[e, r, c] += (Gw[0, r] * N_Gw_0[c] + Gw[1, r] * N_Gw_1[c]) * detw
143
+ K_loc_batch[e, r, c] += B_d[0, r] * (drilling_stiffness * B_d[0, c]) * detw
144
+
145
+ n_shear = detw_shear_all_batch.shape[1]
146
+ detw_shear_all = detw_shear_all_batch[e]
147
+ B_s_all = B_s_all_batch[e]
148
+
149
+ for g in range(n_shear):
150
+ detw_s = detw_shear_all[g]
151
+ B_s = B_s_all[g]
152
+
153
+ Bs_u_0 = 0.0
154
+ Bs_u_1 = 0.0
155
+ for i in range(n_dof):
156
+ Bs_u_0 += B_s[0, i] * u_loc[i]
157
+ Bs_u_1 += B_s[1, i] * u_loc[i]
158
+
159
+ f_s_0 = D_shear[0, 0] * Bs_u_0 + D_shear[0, 1] * Bs_u_1
160
+ f_s_1 = D_shear[1, 0] * Bs_u_0 + D_shear[1, 1] * Bs_u_1
161
+
162
+ for i in range(n_dof):
163
+ F_loc_batch[e, i] += (B_s[0, i] * f_s_0 + B_s[1, i] * f_s_1) * detw_s
164
+
165
+ if not tangent:
166
+ continue
167
+
168
+ C_s = np.zeros((2, n_dof))
169
+ for r in range(2):
170
+ for c in range(n_dof):
171
+ C_s[r, c] = D_shear[r, 0] * B_s[0, c] + D_shear[r, 1] * B_s[1, c]
172
+
173
+ for r in range(n_dof):
174
+ for c in range(n_dof):
175
+ K_loc_batch[e, r, c] += (B_s[0, r] * C_s[0, c] + B_s[1, r] * C_s[1, c]) * detw_s
176
+
177
+ return F_loc_batch, K_loc_batch
178
+
179
+
180
+ def batch_shell_nonlinear_response(
181
+ u_elem_batch: np.ndarray,
182
+ T0_batch: np.ndarray,
183
+ B_m_all_batch: np.ndarray,
184
+ B_b_all_batch: np.ndarray,
185
+ B_d_all_batch: np.ndarray,
186
+ Gw_all_batch: np.ndarray,
187
+ detw_all_batch: np.ndarray,
188
+ B_s_all_batch: np.ndarray,
189
+ detw_shear_all_batch: np.ndarray,
190
+ E: float,
191
+ nu: float,
192
+ G_mod: float,
193
+ h: float,
194
+ drilling_stabilization: float,
195
+ tangent: bool,
196
+ curve: Any,
197
+ plastic_strain_batch: np.ndarray,
198
+ alpha_batch: np.ndarray,
199
+ num_layers: int,
200
+ ) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
201
+ """Computes nonlinear response for a batch of elements."""
202
+ n_elem = u_elem_batch.shape[0]
203
+ n_dof = u_elem_batch.shape[1]
204
+
205
+ u_loc_batch = (T0_batch @ u_elem_batch[:, :, None]).squeeze(-1)
206
+
207
+ C_el = plane_stress_elastic_matrix(E, nu)
208
+ D_shear = G_mod * (5.0 / 6.0) * h * np.eye(2, dtype=float)
209
+ drilling_stiffness = G_mod * h * drilling_stabilization
210
+
211
+ n_gp = detw_all_batch.shape[1]
212
+
213
+ theta_batch = (Gw_all_batch @ u_loc_batch[:, None, :, None]).squeeze(-1)
214
+ memb_strain_batch = (B_m_all_batch @ u_loc_batch[:, None, :, None]).squeeze(-1)
215
+ memb_strain_batch += np.stack([
216
+ 0.5 * theta_batch[..., 0]**2,
217
+ 0.5 * theta_batch[..., 1]**2,
218
+ theta_batch[..., 0] * theta_batch[..., 1]
219
+ ], axis=-1)
220
+
221
+ curvature_batch = (B_b_all_batch @ u_loc_batch[:, None, :, None]).squeeze(-1)
222
+
223
+ z_layers, w_layers = lobatto_layers(num_layers, h)
224
+ layer_strain = (
225
+ memb_strain_batch[:, :, None, :] + z_layers[None, None, :, None] * curvature_batch[:, :, None, :]
226
+ ).reshape(n_elem * n_gp * num_layers, 3)
227
+
228
+ has_plasticity = curve is not None
229
+ if not has_plasticity:
230
+ N_res_batch = memb_strain_batch @ (h * C_el).T
231
+ M_res_batch = curvature_batch @ (h**3 / 12.0 * C_el).T
232
+ C0_batch = np.broadcast_to(h * C_el, (n_elem, n_gp, 3, 3))
233
+ C1_batch = np.zeros((n_elem, n_gp, 3, 3), dtype=float)
234
+ C2_batch = np.broadcast_to(h**3 / 12.0 * C_el, (n_elem, n_gp, 3, 3))
235
+ ep_new = plastic_strain_batch
236
+ alpha_new = alpha_batch
237
+ else:
238
+ sigma, C_tan, ep_new, alpha_new = plane_stress_return_map(
239
+ layer_strain,
240
+ plastic_strain_batch.reshape(n_elem * n_gp * num_layers, 3),
241
+ alpha_batch.reshape(n_elem * n_gp * num_layers),
242
+ E,
243
+ nu,
244
+ curve,
245
+ compute_tangent=tangent,
246
+ )
247
+
248
+ ep_new = ep_new.reshape(n_elem, n_gp * num_layers, 3)
249
+ alpha_new = alpha_new.reshape(n_elem, n_gp * num_layers)
250
+
251
+ sigma = sigma.reshape(n_elem, n_gp, num_layers, 3)
252
+ C_tan = C_tan.reshape(n_elem, n_gp, num_layers, 3, 3)
253
+
254
+ N_res_batch, M_res_batch, C0_batch, C1_batch, C2_batch = _jit_integrate_layers(
255
+ sigma, C_tan, w_layers, z_layers, tangent
256
+ )
257
+
258
+ F_loc_batch, K_loc_batch = _jit_batch_integrate_nonlinear_response(
259
+ u_loc_batch,
260
+ N_res_batch,
261
+ M_res_batch,
262
+ C0_batch,
263
+ C1_batch,
264
+ C2_batch,
265
+ B_m_all_batch,
266
+ B_b_all_batch,
267
+ B_d_all_batch,
268
+ Gw_all_batch,
269
+ detw_all_batch,
270
+ B_s_all_batch,
271
+ detw_shear_all_batch,
272
+ D_shear,
273
+ drilling_stiffness,
274
+ tangent,
275
+ has_plasticity,
276
+ n_dof,
277
+ )
278
+
279
+ F_int_batch = (T0_batch.transpose(0, 2, 1) @ F_loc_batch[:, :, None]).squeeze(-1)
280
+ if tangent:
281
+ K_T_batch = T0_batch.transpose(0, 2, 1) @ K_loc_batch @ T0_batch
282
+ else:
283
+ K_T_batch = np.zeros((n_elem, 0, 0))
284
+
285
+ return F_int_batch, K_T_batch, ep_new, alpha_new, layer_strain
286
+
287
+
288
+ def shell_nonlinear_batch_eligible(element: Any) -> bool:
289
+ """Return whether the vectorized kernel matches the scalar shell response."""
290
+
291
+ return bool(
292
+ getattr(element, "_is_quadrilateral", False)
293
+ and not (
294
+ getattr(element, "_is_8node", False)
295
+ and bool(getattr(element, "reduced_integration", False))
296
+ )
297
+ )
298
+
299
+
300
+ @njit
301
+ def _jit_integrate_layers(
302
+ sigma: np.ndarray,
303
+ C_tan: np.ndarray,
304
+ w_layers: np.ndarray,
305
+ z_layers: np.ndarray,
306
+ tangent: bool,
307
+ ) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
308
+ n_elem, n_gp, num_layers, _ = sigma.shape
309
+ N_res_batch = np.zeros((n_elem, n_gp, 3))
310
+ M_res_batch = np.zeros((n_elem, n_gp, 3))
311
+ C0_batch = np.zeros((n_elem, n_gp, 3, 3))
312
+ C1_batch = np.zeros((n_elem, n_gp, 3, 3))
313
+ C2_batch = np.zeros((n_elem, n_gp, 3, 3))
314
+
315
+ for e in range(n_elem):
316
+ for g in range(n_gp):
317
+ for l in range(num_layers):
318
+ w = w_layers[l]
319
+ z = z_layers[l]
320
+ wz = w * z
321
+ wz2 = wz * z
322
+ for i in range(3):
323
+ N_res_batch[e, g, i] += w * sigma[e, g, l, i]
324
+ M_res_batch[e, g, i] += wz * sigma[e, g, l, i]
325
+
326
+ if tangent:
327
+ for i in range(3):
328
+ for j in range(3):
329
+ val = C_tan[e, g, l, i, j]
330
+ C0_batch[e, g, i, j] += w * val
331
+ C1_batch[e, g, i, j] += wz * val
332
+ C2_batch[e, g, i, j] += wz2 * val
333
+
334
+ return N_res_batch, M_res_batch, C0_batch, C1_batch, C2_batch