ANYfeSolver 0.5.0a1__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 (751) hide show
  1. anyfesolver/__init__.py +1075 -0
  2. anyfesolver/_b2_attachment_elimination_dev.py +261 -0
  3. anyfesolver/_b2_f10_f11_point_attachment.py +163 -0
  4. anyfesolver/_b2_loaded_point_trace_dev.py +173 -0
  5. anyfesolver/_b2_physical_flexibility_linear.py +707 -0
  6. anyfesolver/_b2_physical_linear_batch_dev.py +491 -0
  7. anyfesolver/_b2_physical_linear_definition.py +415 -0
  8. anyfesolver/_b2_physical_load_bubbles.py +282 -0
  9. anyfesolver/_compensated_contractions.py +497 -0
  10. anyfesolver/_compensated_native.py +437 -0
  11. anyfesolver/_corotational_batch.py +219 -0
  12. anyfesolver/_director_trace.py +214 -0
  13. anyfesolver/_dyadic_bilinear.py +76 -0
  14. anyfesolver/_dyadic_factor_chain.py +25 -0
  15. anyfesolver/_ge_beam3_adaptive_arc_program.py +286 -0
  16. anyfesolver/_ge_beam3_analysis_combined.py +102 -0
  17. anyfesolver/_ge_beam3_analysis_fibre_translation.py +130 -0
  18. anyfesolver/_ge_beam3_analysis_modal_snapshot.py +27 -0
  19. anyfesolver/_ge_beam3_analysis_nodal_program.py +140 -0
  20. anyfesolver/_ge_beam3_analysis_translation.py +147 -0
  21. anyfesolver/_ge_beam3_analysis_translation_modal.py +84 -0
  22. anyfesolver/_ge_beam3_arc_geometry.py +89 -0
  23. anyfesolver/_ge_beam3_arc_program.py +304 -0
  24. anyfesolver/_ge_beam3_authoritative_cell_seed.py +25 -0
  25. anyfesolver/_ge_beam3_cell_identity.py +52 -0
  26. anyfesolver/_ge_beam3_centered_batched_finite_inertia.py +132 -0
  27. anyfesolver/_ge_beam3_centered_finite_inertia.py +171 -0
  28. anyfesolver/_ge_beam3_centered_mixed.py +104 -0
  29. anyfesolver/_ge_beam3_centered_reference.py +187 -0
  30. anyfesolver/_ge_beam3_centered_so3_strain.py +76 -0
  31. anyfesolver/_ge_beam3_complementary_section.py +122 -0
  32. anyfesolver/_ge_beam3_compliance_snapshot_guard.py +20 -0
  33. anyfesolver/_ge_beam3_connected_dynamic.py +486 -0
  34. anyfesolver/_ge_beam3_connected_trajectory.py +258 -0
  35. anyfesolver/_ge_beam3_conservative_backtrack.py +26 -0
  36. anyfesolver/_ge_beam3_controlled_fibre_modes.py +105 -0
  37. anyfesolver/_ge_beam3_coupled_beam_subdomain.py +128 -0
  38. anyfesolver/_ge_beam3_coupled_modes.py +256 -0
  39. anyfesolver/_ge_beam3_deterministic_reduction.py +264 -0
  40. anyfesolver/_ge_beam3_displacement_program.py +255 -0
  41. anyfesolver/_ge_beam3_durable_coupled.py +251 -0
  42. anyfesolver/_ge_beam3_dynamic_elastic_state.py +461 -0
  43. anyfesolver/_ge_beam3_effective_deadline.py +58 -0
  44. anyfesolver/_ge_beam3_elastic_seed_continuation.py +223 -0
  45. anyfesolver/_ge_beam3_elastic_seed_modal.py +139 -0
  46. anyfesolver/_ge_beam3_equilibrium_line_program.py +98 -0
  47. anyfesolver/_ge_beam3_equilibrium_schur_solver.py +96 -0
  48. anyfesolver/_ge_beam3_factor_chain_modes.py +103 -0
  49. anyfesolver/_ge_beam3_fibre_cell.py +408 -0
  50. anyfesolver/_ge_beam3_fibre_distributed_couples.py +191 -0
  51. anyfesolver/_ge_beam3_fibre_kinematic_cell.py +75 -0
  52. anyfesolver/_ge_beam3_fibre_line_program.py +157 -0
  53. anyfesolver/_ge_beam3_fibre_line_work.py +87 -0
  54. anyfesolver/_ge_beam3_fibre_reference_modal.py +104 -0
  55. anyfesolver/_ge_beam3_fibre_schur_solver.py +134 -0
  56. anyfesolver/_ge_beam3_fibre_section.py +286 -0
  57. anyfesolver/_ge_beam3_fibre_static_boundary.py +113 -0
  58. anyfesolver/_ge_beam3_g1_analysis.py +307 -0
  59. anyfesolver/_ge_beam3_g1_elastic.py +161 -0
  60. anyfesolver/_ge_beam3_g1_element.py +185 -0
  61. anyfesolver/_ge_beam3_g1_operator.py +137 -0
  62. anyfesolver/_ge_beam3_g2_analysis.py +176 -0
  63. anyfesolver/_ge_beam3_g2_constraints.py +162 -0
  64. anyfesolver/_ge_beam3_g3_analysis.py +385 -0
  65. anyfesolver/_ge_beam3_g3_constraints.py +168 -0
  66. anyfesolver/_ge_beam3_g3b_owner.py +296 -0
  67. anyfesolver/_ge_beam3_g3b_q4_reference.py +186 -0
  68. anyfesolver/_ge_beam3_g3b_reference.py +206 -0
  69. anyfesolver/_ge_beam3_g3b_result_schema.py +107 -0
  70. anyfesolver/_ge_beam3_g3b_s3_reference.py +185 -0
  71. anyfesolver/_ge_beam3_g3b_weighted_reference.py +193 -0
  72. anyfesolver/_ge_beam3_g3c_affine_q4_chart.py +58 -0
  73. anyfesolver/_ge_beam3_g3c_affine_q4_increment_chart.py +257 -0
  74. anyfesolver/_ge_beam3_g3c_affine_q4_recovery.py +434 -0
  75. anyfesolver/_ge_beam3_g3c_affine_q4_registry.py +127 -0
  76. anyfesolver/_ge_beam3_g3c_b2_physical.py +153 -0
  77. anyfesolver/_ge_beam3_g3c_b2_physical_adapter.py +160 -0
  78. anyfesolver/_ge_beam3_g3c_definition.py +117 -0
  79. anyfesolver/_ge_beam3_g3c_local_beam.py +188 -0
  80. anyfesolver/_ge_beam3_g3c_local_shell.py +371 -0
  81. anyfesolver/_ge_beam3_g3c_owner.py +400 -0
  82. anyfesolver/_ge_beam3_g3c_physical_authority.py +203 -0
  83. anyfesolver/_ge_beam3_g3c_physical_owner.py +556 -0
  84. anyfesolver/_ge_beam3_g3c_recovery.py +91 -0
  85. anyfesolver/_ge_beam3_g3c_so3_numerics.py +81 -0
  86. anyfesolver/_ge_beam3_g3c_stable/__init__.py +1 -0
  87. anyfesolver/_ge_beam3_g3c_stable/authority.py +152 -0
  88. anyfesolver/_ge_beam3_g3c_stable/beam.py +196 -0
  89. anyfesolver/_ge_beam3_g3c_stable/boundary.py +38 -0
  90. anyfesolver/_ge_beam3_g3c_stable/chart.py +23 -0
  91. anyfesolver/_ge_beam3_g3c_stable/compensated.py +46 -0
  92. anyfesolver/_ge_beam3_g3c_stable/element.py +190 -0
  93. anyfesolver/_ge_beam3_g3c_stable/fit.py +54 -0
  94. anyfesolver/_ge_beam3_g3c_stable/joint.py +255 -0
  95. anyfesolver/_ge_beam3_g3c_stable/line_work.py +92 -0
  96. anyfesolver/_ge_beam3_g3c_stable/operator.py +147 -0
  97. anyfesolver/_ge_beam3_g3c_stable/owner.py +415 -0
  98. anyfesolver/_ge_beam3_g3c_stable/shell.py +358 -0
  99. anyfesolver/_ge_beam3_g4_completion.py +186 -0
  100. anyfesolver/_ge_beam3_g4a_station_transaction.py +385 -0
  101. anyfesolver/_ge_beam3_g5_completion.py +68 -0
  102. anyfesolver/_ge_beam3_g6_domain.py +354 -0
  103. anyfesolver/_ge_beam3_generalized_cell.py +172 -0
  104. anyfesolver/_ge_beam3_generalized_ellipsoid_section.py +215 -0
  105. anyfesolver/_ge_beam3_generalized_static_boundary.py +233 -0
  106. anyfesolver/_ge_beam3_lifted_kinetic_factor.py +26 -0
  107. anyfesolver/_ge_beam3_line_fibre_modes.py +121 -0
  108. anyfesolver/_ge_beam3_load_program.py +275 -0
  109. anyfesolver/_ge_beam3_loaded_modal.py +225 -0
  110. anyfesolver/_ge_beam3_mixed_ad.py +286 -0
  111. anyfesolver/_ge_beam3_native_analysis.py +484 -0
  112. anyfesolver/_ge_beam3_native_arc.py +269 -0
  113. anyfesolver/_ge_beam3_native_arc_adaptive.py +251 -0
  114. anyfesolver/_ge_beam3_native_arc_restart.py +88 -0
  115. anyfesolver/_ge_beam3_native_arc_source.py +62 -0
  116. anyfesolver/_ge_beam3_native_buckling.py +206 -0
  117. anyfesolver/_ge_beam3_native_combined_couples.py +179 -0
  118. anyfesolver/_ge_beam3_native_combined_restart.py +205 -0
  119. anyfesolver/_ge_beam3_native_definition.py +238 -0
  120. anyfesolver/_ge_beam3_native_distributed_element.py +220 -0
  121. anyfesolver/_ge_beam3_native_distributed_loading.py +92 -0
  122. anyfesolver/_ge_beam3_native_distributed_program.py +165 -0
  123. anyfesolver/_ge_beam3_native_distributed_recovery.py +34 -0
  124. anyfesolver/_ge_beam3_native_distributed_restart.py +221 -0
  125. anyfesolver/_ge_beam3_native_dynamic_analysis.py +149 -0
  126. anyfesolver/_ge_beam3_native_dynamic_restart.py +261 -0
  127. anyfesolver/_ge_beam3_native_fibre_current_modal.py +104 -0
  128. anyfesolver/_ge_beam3_native_fibre_recovery.py +34 -0
  129. anyfesolver/_ge_beam3_native_fibre_restart.py +211 -0
  130. anyfesolver/_ge_beam3_native_fibre_static_element.py +193 -0
  131. anyfesolver/_ge_beam3_native_force_adaptation.py +56 -0
  132. anyfesolver/_ge_beam3_native_generalized_combined_couples.py +188 -0
  133. anyfesolver/_ge_beam3_native_generalized_combined_restart.py +207 -0
  134. anyfesolver/_ge_beam3_native_generalized_element.py +222 -0
  135. anyfesolver/_ge_beam3_native_generalized_factor_modal.py +122 -0
  136. anyfesolver/_ge_beam3_native_generalized_loading.py +92 -0
  137. anyfesolver/_ge_beam3_native_generalized_modal.py +274 -0
  138. anyfesolver/_ge_beam3_native_generalized_paired_modal.py +13 -0
  139. anyfesolver/_ge_beam3_native_generalized_parameter.py +89 -0
  140. anyfesolver/_ge_beam3_native_generalized_program.py +196 -0
  141. anyfesolver/_ge_beam3_native_generalized_recovery.py +34 -0
  142. anyfesolver/_ge_beam3_native_generalized_restart.py +243 -0
  143. anyfesolver/_ge_beam3_native_history_profile.py +53 -0
  144. anyfesolver/_ge_beam3_native_line_loading.py +93 -0
  145. anyfesolver/_ge_beam3_native_line_program.py +150 -0
  146. anyfesolver/_ge_beam3_native_line_recovery.py +34 -0
  147. anyfesolver/_ge_beam3_native_line_restart.py +197 -0
  148. anyfesolver/_ge_beam3_native_line_static_element.py +220 -0
  149. anyfesolver/_ge_beam3_native_load_admission.py +37 -0
  150. anyfesolver/_ge_beam3_native_midpoint.py +1004 -0
  151. anyfesolver/_ge_beam3_native_multi_shell_contact.py +539 -0
  152. anyfesolver/_ge_beam3_native_pair_contact.py +236 -0
  153. anyfesolver/_ge_beam3_native_shell_contact.py +357 -0
  154. anyfesolver/_ge_beam3_native_spatial_couples.py +176 -0
  155. anyfesolver/_ge_beam3_native_spatial_restart.py +204 -0
  156. anyfesolver/_ge_beam3_native_transient.py +467 -0
  157. anyfesolver/_ge_beam3_native_translation.py +225 -0
  158. anyfesolver/_ge_beam3_native_translation_restart.py +54 -0
  159. anyfesolver/_ge_beam3_operator_validation_scope.py +53 -0
  160. anyfesolver/_ge_beam3_p5/__init__.py +11 -0
  161. anyfesolver/_ge_beam3_p5/algebra.py +91 -0
  162. anyfesolver/_ge_beam3_p5/arrays.py +29 -0
  163. anyfesolver/_ge_beam3_p5/chart.py +45 -0
  164. anyfesolver/_ge_beam3_p5/codec.py +82 -0
  165. anyfesolver/_ge_beam3_p5/committed_modal.py +191 -0
  166. anyfesolver/_ge_beam3_p5/compensated.py +118 -0
  167. anyfesolver/_ge_beam3_p5/compensated_coordinates.py +44 -0
  168. anyfesolver/_ge_beam3_p5/core.py +159 -0
  169. anyfesolver/_ge_beam3_p5/element.py +207 -0
  170. anyfesolver/_ge_beam3_p5/factors.py +61 -0
  171. anyfesolver/_ge_beam3_p5/inertia.py +120 -0
  172. anyfesolver/_ge_beam3_p5/mass.py +70 -0
  173. anyfesolver/_ge_beam3_p5/mixed.py +256 -0
  174. anyfesolver/_ge_beam3_p5/reference_modal.py +73 -0
  175. anyfesolver/_ge_beam3_p5/section.py +139 -0
  176. anyfesolver/_ge_beam3_p5/typed_schema.py +111 -0
  177. anyfesolver/_ge_beam3_p5_centered/__init__.py +6 -0
  178. anyfesolver/_ge_beam3_p5_centered/codec.py +84 -0
  179. anyfesolver/_ge_beam3_p5_centered/committed_modal.py +192 -0
  180. anyfesolver/_ge_beam3_p5_centered/core.py +171 -0
  181. anyfesolver/_ge_beam3_p5_centered/element.py +216 -0
  182. anyfesolver/_ge_beam3_p5_centered/mass.py +99 -0
  183. anyfesolver/_ge_beam3_p5_centered/positions.py +34 -0
  184. anyfesolver/_ge_beam3_p5_centered/reference_modal.py +73 -0
  185. anyfesolver/_ge_beam3_p5_coordinates/__init__.py +6 -0
  186. anyfesolver/_ge_beam3_p5_coordinates/codec.py +84 -0
  187. anyfesolver/_ge_beam3_p5_coordinates/committed_modal.py +192 -0
  188. anyfesolver/_ge_beam3_p5_coordinates/core.py +163 -0
  189. anyfesolver/_ge_beam3_p5_coordinates/element.py +213 -0
  190. anyfesolver/_ge_beam3_p5_coordinates/positions.py +102 -0
  191. anyfesolver/_ge_beam3_p5_coordinates/reference_modal.py +73 -0
  192. anyfesolver/_ge_beam3_p5_loads/__init__.py +7 -0
  193. anyfesolver/_ge_beam3_p5_loads/codec.py +85 -0
  194. anyfesolver/_ge_beam3_p5_loads/core.py +192 -0
  195. anyfesolver/_ge_beam3_p5_loads/element.py +243 -0
  196. anyfesolver/_ge_beam3_p5_loads/state.py +120 -0
  197. anyfesolver/_ge_beam3_p5_loads/work.py +45 -0
  198. anyfesolver/_ge_beam3_p5_seeded/__init__.py +9 -0
  199. anyfesolver/_ge_beam3_p5_seeded/codec.py +87 -0
  200. anyfesolver/_ge_beam3_p5_seeded/core.py +197 -0
  201. anyfesolver/_ge_beam3_p5_seeded/element.py +245 -0
  202. anyfesolver/_ge_beam3_p5_seeded/state.py +122 -0
  203. anyfesolver/_ge_beam3_p5_seeded/work.py +47 -0
  204. anyfesolver/_ge_beam3_pose_joint.py +268 -0
  205. anyfesolver/_ge_beam3_precise_geometric_work.py +147 -0
  206. anyfesolver/_ge_beam3_reassembled_signed_modes.py +101 -0
  207. anyfesolver/_ge_beam3_reference_identity.py +92 -0
  208. anyfesolver/_ge_beam3_refined_fibre_schur_solver.py +104 -0
  209. anyfesolver/_ge_beam3_refinement_capacity.py +19 -0
  210. anyfesolver/_ge_beam3_relative_virgin_reference_modes.py +60 -0
  211. anyfesolver/_ge_beam3_retained_arc.py +350 -0
  212. anyfesolver/_ge_beam3_retained_arc_geometry.py +66 -0
  213. anyfesolver/_ge_beam3_retained_arc_modal.py +125 -0
  214. anyfesolver/_ge_beam3_retained_elastic.py +134 -0
  215. anyfesolver/_ge_beam3_retained_fibre.py +209 -0
  216. anyfesolver/_ge_beam3_retained_fibre_control.py +270 -0
  217. anyfesolver/_ge_beam3_retained_fibre_element.py +58 -0
  218. anyfesolver/_ge_beam3_retained_fibre_modal.py +155 -0
  219. anyfesolver/_ge_beam3_retained_fibre_modes.py +189 -0
  220. anyfesolver/_ge_beam3_retained_fibre_program.py +68 -0
  221. anyfesolver/_ge_beam3_retained_fibre_state.py +268 -0
  222. anyfesolver/_ge_beam3_retained_force_program.py +72 -0
  223. anyfesolver/_ge_beam3_retained_generalized.py +186 -0
  224. anyfesolver/_ge_beam3_retained_generalized_modal.py +171 -0
  225. anyfesolver/_ge_beam3_retained_generalized_program.py +63 -0
  226. anyfesolver/_ge_beam3_retained_generalized_state.py +281 -0
  227. anyfesolver/_ge_beam3_retained_nodal_loading.py +111 -0
  228. anyfesolver/_ge_beam3_retained_plastic.py +116 -0
  229. anyfesolver/_ge_beam3_retained_plastic_modes.py +144 -0
  230. anyfesolver/_ge_beam3_retained_plastic_program.py +69 -0
  231. anyfesolver/_ge_beam3_retained_plastic_state.py +165 -0
  232. anyfesolver/_ge_beam3_retained_state.py +194 -0
  233. anyfesolver/_ge_beam3_retained_translation_control.py +345 -0
  234. anyfesolver/_ge_beam3_retained_translation_modal.py +137 -0
  235. anyfesolver/_ge_beam3_schur_line_program.py +98 -0
  236. anyfesolver/_ge_beam3_seeded_fibre_control.py +175 -0
  237. anyfesolver/_ge_beam3_seeded_load_program.py +301 -0
  238. anyfesolver/_ge_beam3_seeded_loaded_modal.py +226 -0
  239. anyfesolver/_ge_beam3_seeded_signed_modes.py +150 -0
  240. anyfesolver/_ge_beam3_shared_kinematic_split.py +53 -0
  241. anyfesolver/_ge_beam3_shell_joint_state.py +396 -0
  242. anyfesolver/_ge_beam3_shell_joint_trial.py +217 -0
  243. anyfesolver/_ge_beam3_signed_loaded_modes.py +140 -0
  244. anyfesolver/_ge_beam3_spatial_fibre_program.py +113 -0
  245. anyfesolver/_ge_beam3_spatial_nodal_moments.py +38 -0
  246. anyfesolver/_ge_beam3_station_resultant_cell.py +235 -0
  247. anyfesolver/_ge_beam3_variational_shell.py +211 -0
  248. anyfesolver/_ge_beam3_virgin_reference_modes.py +60 -0
  249. anyfesolver/_impact_coupling.py +162 -0
  250. anyfesolver/_native_authority_dag.py +77 -0
  251. anyfesolver/_native_dyadic_interval_inertia.py +64 -0
  252. anyfesolver/_native_exact_shift_chain_modes.py +140 -0
  253. anyfesolver/_native_exact_shift_inertia.py +86 -0
  254. anyfesolver/_native_factor_chain_modes.py +192 -0
  255. anyfesolver/_native_guard.cpp +828 -0
  256. anyfesolver/_native_guard_dispatch.py +140 -0
  257. anyfesolver/_native_large_factor_chain.py +55 -0
  258. anyfesolver/_native_material_protocol.py +51 -0
  259. anyfesolver/_native_midpoint_controller.py +90 -0
  260. anyfesolver/_native_modal_capacity.py +26 -0
  261. anyfesolver/_native_paired_factor_chain_modes.py +244 -0
  262. anyfesolver/_native_reassembled_factor_modes.py +185 -0
  263. anyfesolver/_native_reference_factor_spectrum.py +102 -0
  264. anyfesolver/_native_reference_modal.py +180 -0
  265. anyfesolver/_native_relative_factor_chain_modes.py +204 -0
  266. anyfesolver/_native_relative_reference_factor_spectrum.py +110 -0
  267. anyfesolver/_native_retained_step.py +15 -0
  268. anyfesolver/_native_rotation_state.py +797 -0
  269. anyfesolver/_native_signed_factor_modes.py +257 -0
  270. anyfesolver/_native_signed_kinetic_factor_modes.py +279 -0
  271. anyfesolver/_native_stationary_spectrum.py +79 -0
  272. anyfesolver/_nonlinear_events.py +150 -0
  273. anyfesolver/_nonlinear_seed.py +80 -0
  274. anyfesolver/_paired_modal_arithmetic.py +71 -0
  275. anyfesolver/_plate_stability_continuation.py +171 -0
  276. anyfesolver/_q4_assumed_strain_plasticity.py +502 -0
  277. anyfesolver/_qualified_authority_epoch.py +561 -0
  278. anyfesolver/_relative_reference_svd.py +44 -0
  279. anyfesolver/_stiffened_shell_affine_endpoint.py +232 -0
  280. anyfesolver/_stiffened_shell_algorithmic_pullback.py +38 -0
  281. anyfesolver/_stiffened_shell_arc_checkpoint.py +422 -0
  282. anyfesolver/_stiffened_shell_arc_control.py +108 -0
  283. anyfesolver/_stiffened_shell_arc_metric.py +222 -0
  284. anyfesolver/_stiffened_shell_arc_publication.py +153 -0
  285. anyfesolver/_stiffened_shell_arc_trial.py +310 -0
  286. anyfesolver/_stiffened_shell_b2_affine_resolution.py +101 -0
  287. anyfesolver/_stiffened_shell_b2_assembly_diagnostics.py +172 -0
  288. anyfesolver/_stiffened_shell_b2_definition_ownership.py +189 -0
  289. anyfesolver/_stiffened_shell_b2_experimental.py +153 -0
  290. anyfesolver/_stiffened_shell_b2_nodal_footprint.py +273 -0
  291. anyfesolver/_stiffened_shell_b2_physical_rigid_footprint.py +237 -0
  292. anyfesolver/_stiffened_shell_b2_q4_panel_experimental.py +2447 -0
  293. anyfesolver/_stiffened_shell_b2_q4_point_experimental.py +251 -0
  294. anyfesolver/_stiffened_shell_b2_reference_buckling.py +413 -0
  295. anyfesolver/_stiffened_shell_b3_chart.py +70 -0
  296. anyfesolver/_stiffened_shell_b3_local_adapter.py +141 -0
  297. anyfesolver/_stiffened_shell_beam_history.py +107 -0
  298. anyfesolver/_stiffened_shell_bl5_local_experimental.py +173 -0
  299. anyfesolver/_stiffened_shell_bl5_native_elastic.py +28 -0
  300. anyfesolver/_stiffened_shell_branch_event_trial.py +58 -0
  301. anyfesolver/_stiffened_shell_consumer_capabilities.py +124 -0
  302. anyfesolver/_stiffened_shell_coordinate_support.py +110 -0
  303. anyfesolver/_stiffened_shell_displacement_adaptive.py +327 -0
  304. anyfesolver/_stiffened_shell_displacement_checkpoint.py +360 -0
  305. anyfesolver/_stiffened_shell_displacement_control.py +326 -0
  306. anyfesolver/_stiffened_shell_displacement_corrector.py +293 -0
  307. anyfesolver/_stiffened_shell_displacement_increment.py +121 -0
  308. anyfesolver/_stiffened_shell_distributing_footprint.py +354 -0
  309. anyfesolver/_stiffened_shell_distributing_pose.py +267 -0
  310. anyfesolver/_stiffened_shell_f06_increment_arithmetic.py +205 -0
  311. anyfesolver/_stiffened_shell_ge_body_load.py +300 -0
  312. anyfesolver/_stiffened_shell_ge_checkpoint_binary.py +472 -0
  313. anyfesolver/_stiffened_shell_ge_distributed_load.py +210 -0
  314. anyfesolver/_stiffened_shell_ge_distributed_programme.py +175 -0
  315. anyfesolver/_stiffened_shell_ge_distributing_finite.py +242 -0
  316. anyfesolver/_stiffened_shell_ge_distributing_reference.py +296 -0
  317. anyfesolver/_stiffened_shell_ge_experimental.py +2454 -0
  318. anyfesolver/_stiffened_shell_ge_finite_experimental.py +2714 -0
  319. anyfesolver/_stiffened_shell_ge_mixed_modal_mass.py +33 -0
  320. anyfesolver/_stiffened_shell_ge_point_buckling.py +723 -0
  321. anyfesolver/_stiffened_shell_ge_pressure_load.py +366 -0
  322. anyfesolver/_stiffened_shell_ge_reference_modal.py +580 -0
  323. anyfesolver/_stiffened_shell_generalized_recovery.py +150 -0
  324. anyfesolver/_stiffened_shell_increment_control.py +217 -0
  325. anyfesolver/_stiffened_shell_l1_assembly_experimental.py +420 -0
  326. anyfesolver/_stiffened_shell_l1_local_experimental.py +284 -0
  327. anyfesolver/_stiffened_shell_l1_supported_work_experimental.py +146 -0
  328. anyfesolver/_stiffened_shell_native_distributed_load.py +120 -0
  329. anyfesolver/_stiffened_shell_native_gravity.py +236 -0
  330. anyfesolver/_stiffened_shell_nodal_footprint.py +255 -0
  331. anyfesolver/_stiffened_shell_physical_q4_mass.py +98 -0
  332. anyfesolver/_stiffened_shell_physical_s3_mass.py +53 -0
  333. anyfesolver/_stiffened_shell_point_recovery.py +49 -0
  334. anyfesolver/_stiffened_shell_q4_algorithmic_pullback.py +88 -0
  335. anyfesolver/_stiffened_shell_q4_material_event.py +114 -0
  336. anyfesolver/_stiffened_shell_q4_reference.py +65 -0
  337. anyfesolver/_stiffened_shell_rotation_charts.py +58 -0
  338. anyfesolver/_stiffened_shell_s3_algorithmic_pullback.py +59 -0
  339. anyfesolver/_stiffened_shell_s3_conservative_buckling.py +28 -0
  340. anyfesolver/_stiffened_shell_s3_dead_work_candidate.py +107 -0
  341. anyfesolver/_stiffened_shell_s3_material_event.py +30 -0
  342. anyfesolver/_stiffened_shell_same_parent_trial.py +224 -0
  343. anyfesolver/_stiffened_shell_selected_recovery.py +113 -0
  344. anyfesolver/_stiffened_shell_staged_load_experimental.py +392 -0
  345. anyfesolver/_stiffened_shell_stress_free_reference.py +204 -0
  346. anyfesolver/_wire_types.py +17 -0
  347. anyfesolver/activity.py +1537 -0
  348. anyfesolver/algebraic_dynamics.py +2864 -0
  349. anyfesolver/analysis_session.py +897 -0
  350. anyfesolver/anystructure_fem_mode.py +1637 -0
  351. anyfesolver/arc_length.py +2587 -0
  352. anyfesolver/assembly.py +1830 -0
  353. anyfesolver/b3_ge.py +179 -0
  354. anyfesolver/baselines.py +303 -0
  355. anyfesolver/beam_sections.py +292 -0
  356. anyfesolver/beam_shell_verification.py +4685 -0
  357. anyfesolver/beam_validity.py +110 -0
  358. anyfesolver/benchmarks.py +495 -0
  359. anyfesolver/boundary.py +1680 -0
  360. anyfesolver/buckling.py +2136 -0
  361. anyfesolver/buckling_validity.py +91 -0
  362. anyfesolver/capacity_workflow.py +431 -0
  363. anyfesolver/capsule_runtime_guard.py +99 -0
  364. anyfesolver/cases.py +173 -0
  365. anyfesolver/composite_strip_verification.py +297 -0
  366. anyfesolver/concentrated_mass.py +84 -0
  367. anyfesolver/constraint_audit.py +553 -0
  368. anyfesolver/contact.py +4785 -0
  369. anyfesolver/contact_performance.py +301 -0
  370. anyfesolver/control.py +206 -0
  371. anyfesolver/corotational.py +1935 -0
  372. anyfesolver/corotational_performance.py +157 -0
  373. anyfesolver/current_state_tangent.py +2780 -0
  374. anyfesolver/cylinder_benchmarks.py +369 -0
  375. anyfesolver/damage_matrix_performance.py +617 -0
  376. anyfesolver/dynamics.py +2833 -0
  377. anyfesolver/e4_pl_element.py +8265 -0
  378. anyfesolver/e4_pl_enriched.py +194 -0
  379. anyfesolver/e4_pl_enriched_nonlinear.py +159 -0
  380. anyfesolver/e4_pl_s3_element.py +9752 -0
  381. anyfesolver/e4_pl_s3_initial_fields.py +101 -0
  382. anyfesolver/e4_pl_s3_state.py +4723 -0
  383. anyfesolver/e4_pl_s3_v2_element.py +1844 -0
  384. anyfesolver/e4_pl_s3_v2b_element.py +1936 -0
  385. anyfesolver/e4_pl_s3_v2c_element.py +2196 -0
  386. anyfesolver/e4_pl_s3_v2d_element.py +2621 -0
  387. anyfesolver/e4_pl_s3_v2d_state.py +376 -0
  388. anyfesolver/element_capabilities.py +159 -0
  389. anyfesolver/element_qualification.py +432 -0
  390. anyfesolver/elements.py +6327 -0
  391. anyfesolver/experimental_csr_assembly.py +238 -0
  392. anyfesolver/external_references.py +1253 -0
  393. anyfesolver/fe_core.py +832 -0
  394. anyfesolver/floating_pressure_regions.py +119 -0
  395. anyfesolver/floating_response.py +486 -0
  396. anyfesolver/floating_transient.py +1281 -0
  397. anyfesolver/fracture.py +621 -0
  398. anyfesolver/ge_beam3_curved_reference.py +725 -0
  399. anyfesolver/ge_beam3_element.py +885 -0
  400. anyfesolver/ge_beam3_mixed_element.py +1216 -0
  401. anyfesolver/ge_beam3_mixed_state.py +814 -0
  402. anyfesolver/ge_beam3_native.py +129 -0
  403. anyfesolver/ge_beam3_native_connected_dynamics.py +24 -0
  404. anyfesolver/ge_beam3_native_dynamics.py +70 -0
  405. anyfesolver/ge_beam3_state.py +672 -0
  406. anyfesolver/general_contact/__init__.py +151 -0
  407. anyfesolver/general_contact/_enriched_multitarget_empty.py +202 -0
  408. anyfesolver/general_contact/_enriched_multitarget_trial.py +183 -0
  409. anyfesolver/general_contact/_results_archive_common.py +65 -0
  410. anyfesolver/general_contact/algebraic_path.py +206 -0
  411. anyfesolver/general_contact/arc_contact.py +237 -0
  412. anyfesolver/general_contact/arc_results_archive.py +158 -0
  413. anyfesolver/general_contact/augmentation.py +157 -0
  414. anyfesolver/general_contact/automatic_domain.py +621 -0
  415. anyfesolver/general_contact/beam_chain_consistent.py +357 -0
  416. anyfesolver/general_contact/beam_chain_end_geometry.py +237 -0
  417. anyfesolver/general_contact/beam_chain_ends.py +220 -0
  418. anyfesolver/general_contact/beam_chain_pair.py +416 -0
  419. anyfesolver/general_contact/beam_curve_end_geometry.py +254 -0
  420. anyfesolver/general_contact/beam_curve_ends.py +237 -0
  421. anyfesolver/general_contact/beam_curve_pair.py +794 -0
  422. anyfesolver/general_contact/beam_curve_pair_static.py +303 -0
  423. anyfesolver/general_contact/beam_end_radial_geometry.py +221 -0
  424. anyfesolver/general_contact/beam_end_topology.py +15 -0
  425. anyfesolver/general_contact/beam_hemisphere_coupled_tool.py +61 -0
  426. anyfesolver/general_contact/beam_hemisphere_cylinder.py +134 -0
  427. anyfesolver/general_contact/beam_hemisphere_cylinder_motion.py +89 -0
  428. anyfesolver/general_contact/beam_hemisphere_cylinder_work.py +216 -0
  429. anyfesolver/general_contact/beam_hemisphere_plane.py +175 -0
  430. anyfesolver/general_contact/beam_hemisphere_s3_support.py +152 -0
  431. anyfesolver/general_contact/beam_hemisphere_sphere.py +135 -0
  432. anyfesolver/general_contact/beam_hemisphere_sphere_work.py +114 -0
  433. anyfesolver/general_contact/beam_hemisphere_support.py +211 -0
  434. anyfesolver/general_contact/beam_pair.py +523 -0
  435. anyfesolver/general_contact/beam_pair_end_geometry.py +269 -0
  436. anyfesolver/general_contact/beam_pair_ends.py +222 -0
  437. anyfesolver/general_contact/beam_plane.py +425 -0
  438. anyfesolver/general_contact/beam_radial.py +500 -0
  439. anyfesolver/general_contact/beam_radial_ends.py +223 -0
  440. anyfesolver/general_contact/beam_s3_directional_rates.py +196 -0
  441. anyfesolver/general_contact/beam_s3_rotational_transient.py +126 -0
  442. anyfesolver/general_contact/beam_s3_transient.py +139 -0
  443. anyfesolver/general_contact/beam_shell.py +648 -0
  444. anyfesolver/general_contact/beam_shell_patch.py +395 -0
  445. anyfesolver/general_contact/beam_temporal_bounds.py +230 -0
  446. anyfesolver/general_contact/capability.py +101 -0
  447. anyfesolver/general_contact/capped_cylinder.py +618 -0
  448. anyfesolver/general_contact/contact_search.py +95 -0
  449. anyfesolver/general_contact/core.py +1769 -0
  450. anyfesolver/general_contact/curved_s3_q4_work.py +238 -0
  451. anyfesolver/general_contact/curved_shell_skin.py +520 -0
  452. anyfesolver/general_contact/d1_interior_profile.py +427 -0
  453. anyfesolver/general_contact/deformable_beam_s3_caps.py +143 -0
  454. anyfesolver/general_contact/deformable_beam_s3_line.py +211 -0
  455. anyfesolver/general_contact/deformable_beam_s3_static.py +152 -0
  456. anyfesolver/general_contact/descriptor_rates.py +61 -0
  457. anyfesolver/general_contact/enriched_cold_predictor.py +161 -0
  458. anyfesolver/general_contact/enriched_moment_batch.py +337 -0
  459. anyfesolver/general_contact/enriched_multitarget.py +308 -0
  460. anyfesolver/general_contact/enriched_multitarget_gap.py +156 -0
  461. anyfesolver/general_contact/enriched_multitarget_moments.py +194 -0
  462. anyfesolver/general_contact/enriched_multitarget_topology.py +171 -0
  463. anyfesolver/general_contact/enriched_nonlinear.py +440 -0
  464. anyfesolver/general_contact/enriched_overlap.py +299 -0
  465. anyfesolver/general_contact/enriched_path.py +253 -0
  466. anyfesolver/general_contact/enriched_small_cut.py +310 -0
  467. anyfesolver/general_contact/enriched_static.py +481 -0
  468. anyfesolver/general_contact/enriched_union.py +320 -0
  469. anyfesolver/general_contact/equilibrated_pressure_pivot.py +140 -0
  470. anyfesolver/general_contact/event_subdivision.py +273 -0
  471. anyfesolver/general_contact/finite_mixed_state.py +133 -0
  472. anyfesolver/general_contact/finite_rigid_patch.py +196 -0
  473. anyfesolver/general_contact/finite_rigid_support.py +129 -0
  474. anyfesolver/general_contact/finite_rigid_sweep.py +53 -0
  475. anyfesolver/general_contact/finite_rotation_predictor.py +171 -0
  476. anyfesolver/general_contact/finite_rotation_skin.py +212 -0
  477. anyfesolver/general_contact/finite_rotation_state.py +106 -0
  478. anyfesolver/general_contact/finite_rotation_sweep.py +161 -0
  479. anyfesolver/general_contact/finite_v2d_state.py +104 -0
  480. anyfesolver/general_contact/fixed_projection_graph.py +205 -0
  481. anyfesolver/general_contact/fixed_projection_s3_events.py +235 -0
  482. anyfesolver/general_contact/free_rigid.py +134 -0
  483. anyfesolver/general_contact/friction_point.py +378 -0
  484. anyfesolver/general_contact/gap_extrema.py +119 -0
  485. anyfesolver/general_contact/guided_pair_transient_geometry.py +138 -0
  486. anyfesolver/general_contact/initial_contact_seed.py +368 -0
  487. anyfesolver/general_contact/linearized_pivot.py +595 -0
  488. anyfesolver/general_contact/material_work_diagnostics.py +159 -0
  489. anyfesolver/general_contact/moment_batch_ad.py +129 -0
  490. anyfesolver/general_contact/moment_batch_points.py +75 -0
  491. anyfesolver/general_contact/moving.py +1031 -0
  492. anyfesolver/general_contact/multiple_beam_rigid.py +248 -0
  493. anyfesolver/general_contact/multiple_beam_s3_caps.py +199 -0
  494. anyfesolver/general_contact/multiple_beam_s3_transient.py +223 -0
  495. anyfesolver/general_contact/multiple_projected_pairs.py +196 -0
  496. anyfesolver/general_contact/multiple_shell_planes.py +226 -0
  497. anyfesolver/general_contact/native_activation_static.py +143 -0
  498. anyfesolver/general_contact/native_checkpoint_results.py +213 -0
  499. anyfesolver/general_contact/native_curve_union.py +268 -0
  500. anyfesolver/general_contact/native_curved_geometry.py +374 -0
  501. anyfesolver/general_contact/native_curved_pair_partition.py +590 -0
  502. anyfesolver/general_contact/native_curved_plane_work.py +864 -0
  503. anyfesolver/general_contact/native_curved_s3_work.py +472 -0
  504. anyfesolver/general_contact/native_event_polynomial.py +164 -0
  505. anyfesolver/general_contact/native_fibre_context.py +173 -0
  506. anyfesolver/general_contact/native_fibre_results.py +74 -0
  507. anyfesolver/general_contact/native_initial_guess.py +122 -0
  508. anyfesolver/general_contact/native_material_activation.py +108 -0
  509. anyfesolver/general_contact/native_material_plane.py +111 -0
  510. anyfesolver/general_contact/native_material_s3.py +209 -0
  511. anyfesolver/general_contact/native_multi_s3_static.py +722 -0
  512. anyfesolver/general_contact/native_normal_angles.py +233 -0
  513. anyfesolver/general_contact/native_pair_error_budget.py +49 -0
  514. anyfesolver/general_contact/native_replay_arithmetic.py +103 -0
  515. anyfesolver/general_contact/native_replay_diagnostics.py +90 -0
  516. anyfesolver/general_contact/native_retained_body_junction.py +99 -0
  517. anyfesolver/general_contact/native_retained_body_pair.py +220 -0
  518. anyfesolver/general_contact/native_retained_body_projection.py +160 -0
  519. anyfesolver/general_contact/native_retained_body_static.py +62 -0
  520. anyfesolver/general_contact/native_retained_cell_pair.py +185 -0
  521. anyfesolver/general_contact/native_retained_curve_cell.py +102 -0
  522. anyfesolver/general_contact/native_retained_line_plane.py +210 -0
  523. anyfesolver/general_contact/native_retained_line_s3.py +440 -0
  524. anyfesolver/general_contact/native_retained_line_s3_work.py +91 -0
  525. anyfesolver/general_contact/native_retained_pair_static.py +845 -0
  526. anyfesolver/general_contact/native_retained_s3_static.py +554 -0
  527. anyfesolver/general_contact/native_retained_static.py +478 -0
  528. anyfesolver/general_contact/native_retained_station.py +222 -0
  529. anyfesolver/general_contact/native_retained_whole_pair.py +2120 -0
  530. anyfesolver/general_contact/native_s3_swept.py +149 -0
  531. anyfesolver/general_contact/native_shell_static_driver.py +144 -0
  532. anyfesolver/general_contact/native_surface_activation.py +391 -0
  533. anyfesolver/general_contact/native_surface_bounds.py +198 -0
  534. anyfesolver/general_contact/native_surface_contributor.py +121 -0
  535. anyfesolver/general_contact/native_surface_crossing.py +81 -0
  536. anyfesolver/general_contact/native_surface_event_sequence.py +320 -0
  537. anyfesolver/general_contact/native_surface_extrema.py +72 -0
  538. anyfesolver/general_contact/native_surface_friction_integral.py +1724 -0
  539. anyfesolver/general_contact/native_surface_front.py +742 -0
  540. anyfesolver/general_contact/native_surface_front_boundary.py +160 -0
  541. anyfesolver/general_contact/native_surface_front_precision.py +78 -0
  542. anyfesolver/general_contact/native_surface_front_work.py +118 -0
  543. anyfesolver/general_contact/native_surface_history.py +334 -0
  544. anyfesolver/general_contact/native_surface_normal.py +324 -0
  545. anyfesolver/general_contact/native_surface_patch.py +213 -0
  546. anyfesolver/general_contact/native_surface_path.py +348 -0
  547. anyfesolver/general_contact/native_surface_quadrature.py +212 -0
  548. anyfesolver/general_contact/native_surface_s3_friction.py +340 -0
  549. anyfesolver/general_contact/native_surface_support.py +776 -0
  550. anyfesolver/general_contact/native_surface_transaction.py +198 -0
  551. anyfesolver/general_contact/native_transient_multi_shell.py +108 -0
  552. anyfesolver/general_contact/native_transient_pair.py +61 -0
  553. anyfesolver/general_contact/native_transient_shell.py +44 -0
  554. anyfesolver/general_contact/normal_s3_skin_path.py +163 -0
  555. anyfesolver/general_contact/overlap.py +443 -0
  556. anyfesolver/general_contact/pair.py +466 -0
  557. anyfesolver/general_contact/patch_broadphase.py +111 -0
  558. anyfesolver/general_contact/patch_mortar.py +593 -0
  559. anyfesolver/general_contact/patch_sliding.py +644 -0
  560. anyfesolver/general_contact/plane_newmark_events.py +278 -0
  561. anyfesolver/general_contact/pointwise_patch.py +288 -0
  562. anyfesolver/general_contact/polynomial_roots.py +312 -0
  563. anyfesolver/general_contact/pressure_basis.py +241 -0
  564. anyfesolver/general_contact/pressure_diagnostics.py +155 -0
  565. anyfesolver/general_contact/pressure_overlay.py +182 -0
  566. anyfesolver/general_contact/pressure_space.py +51 -0
  567. anyfesolver/general_contact/q4_material_checkpoint.py +276 -0
  568. anyfesolver/general_contact/q4_overlap_local_bound.py +1111 -0
  569. anyfesolver/general_contact/q4_q4_overlap_derivatives.py +234 -0
  570. anyfesolver/general_contact/q4_q4_swept_bound.py +58 -0
  571. anyfesolver/general_contact/q4_s3_overlap_derivatives.py +1159 -0
  572. anyfesolver/general_contact/q4_s3_tiny_wedge.py +180 -0
  573. anyfesolver/general_contact/q4_skin_work.py +87 -0
  574. anyfesolver/general_contact/q4_source_mortar_energy.py +181 -0
  575. anyfesolver/general_contact/q4_source_overlap.py +401 -0
  576. anyfesolver/general_contact/q4_target_overlap.py +181 -0
  577. anyfesolver/general_contact/request_identity.py +192 -0
  578. anyfesolver/general_contact/rigid_translation.py +199 -0
  579. anyfesolver/general_contact/runtime.py +27 -0
  580. anyfesolver/general_contact/s3_friction_chart_interval.py +104 -0
  581. anyfesolver/general_contact/s3_friction_coverage.py +165 -0
  582. anyfesolver/general_contact/s3_friction_dyadic_interval.py +39 -0
  583. anyfesolver/general_contact/s3_friction_history_path.py +111 -0
  584. anyfesolver/general_contact/s3_friction_mesh_coverage.py +145 -0
  585. anyfesolver/general_contact/s3_friction_mesh_gap.py +74 -0
  586. anyfesolver/general_contact/s3_friction_mesh_monolithic.py +150 -0
  587. anyfesolver/general_contact/s3_friction_monolithic.py +121 -0
  588. anyfesolver/general_contact/s3_friction_moving_coverage.py +114 -0
  589. anyfesolver/general_contact/s3_friction_pair.py +237 -0
  590. anyfesolver/general_contact/s3_friction_point.py +129 -0
  591. anyfesolver/general_contact/s3_friction_prepared_path.py +254 -0
  592. anyfesolver/general_contact/s3_friction_replay.py +1094 -0
  593. anyfesolver/general_contact/s3_friction_rim_path.py +69 -0
  594. anyfesolver/general_contact/s3_friction_rim_transaction.py +23 -0
  595. anyfesolver/general_contact/s3_friction_static.py +267 -0
  596. anyfesolver/general_contact/s3_friction_swept_gap.py +112 -0
  597. anyfesolver/general_contact/s3_friction_touch.py +94 -0
  598. anyfesolver/general_contact/s3_friction_weak_pressure.py +66 -0
  599. anyfesolver/general_contact/s3_overlap_derivatives.py +220 -0
  600. anyfesolver/general_contact/s3_overlap_hermite_gap.py +180 -0
  601. anyfesolver/general_contact/s3_pair_static.py +343 -0
  602. anyfesolver/general_contact/s3_patch_augmented.py +2056 -0
  603. anyfesolver/general_contact/s3_patch_mortar_energy.py +545 -0
  604. anyfesolver/general_contact/s3_patch_static.py +1725 -0
  605. anyfesolver/general_contact/s3_pressure_hermite_bounds.py +395 -0
  606. anyfesolver/general_contact/s3_pressure_polygon_bounds.py +73 -0
  607. anyfesolver/general_contact/s3_q4_gap_resolution.py +191 -0
  608. anyfesolver/general_contact/s3_q4_overlap_derivatives.py +252 -0
  609. anyfesolver/general_contact/s3_q4_swept.py +56 -0
  610. anyfesolver/general_contact/s3_skin_work.py +101 -0
  611. anyfesolver/general_contact/s3_sliding_friction.py +640 -0
  612. anyfesolver/general_contact/s3_stable_plane_gap.py +43 -0
  613. anyfesolver/general_contact/seed_path_vertex_interval.py +323 -0
  614. anyfesolver/general_contact/semismooth.py +133 -0
  615. anyfesolver/general_contact/semismooth_block.py +147 -0
  616. anyfesolver/general_contact/semismooth_path.py +871 -0
  617. anyfesolver/general_contact/shell_pair_hermite_sweep.py +336 -0
  618. anyfesolver/general_contact/shell_sphere_temporal_bounds.py +305 -0
  619. anyfesolver/general_contact/skin_geometry.py +106 -0
  620. anyfesolver/general_contact/sliding.py +349 -0
  621. anyfesolver/general_contact/sphere.py +691 -0
  622. anyfesolver/general_contact/sphere_temporal_bounds.py +241 -0
  623. anyfesolver/general_contact/static_path.py +2608 -0
  624. anyfesolver/general_contact/static_results_archive.py +140 -0
  625. anyfesolver/general_contact/structural_state_bridge.py +196 -0
  626. anyfesolver/general_contact/supported_schur.py +594 -0
  627. anyfesolver/general_contact/swept_patch_broadphase.py +160 -0
  628. anyfesolver/general_contact/transient.py +2921 -0
  629. anyfesolver/general_contact/transient_results_archive.py +491 -0
  630. anyfesolver/general_contact/triangle_mortar_energy.py +280 -0
  631. anyfesolver/general_contact/triangle_pair_energy.py +211 -0
  632. anyfesolver/general_contact/triangulated_rigid.py +94 -0
  633. anyfesolver/general_contact/triangulated_rigid_static.py +399 -0
  634. anyfesolver/general_contact/warped_q4_plane.py +185 -0
  635. anyfesolver/general_contact/warped_q4_skin.py +302 -0
  636. anyfesolver/general_contact/warped_q4_static.py +331 -0
  637. anyfesolver/impact_performance.py +273 -0
  638. anyfesolver/impact_reduced_assembly.py +294 -0
  639. anyfesolver/imperfections.py +397 -0
  640. anyfesolver/inertia_relief.py +676 -0
  641. anyfesolver/initial_field_state.py +54 -0
  642. anyfesolver/jit_compiler.py +135 -0
  643. anyfesolver/kernel_warmup.py +228 -0
  644. anyfesolver/linalg.py +1002 -0
  645. anyfesolver/marine_contributions.py +634 -0
  646. anyfesolver/marine_coupled_equilibrium.py +292 -0
  647. anyfesolver/marine_equilibrium.py +405 -0
  648. anyfesolver/marine_hydro_coordinates.py +346 -0
  649. anyfesolver/marine_linear.py +549 -0
  650. anyfesolver/marine_link.py +306 -0
  651. anyfesolver/marine_mechanical.py +923 -0
  652. anyfesolver/marine_mooring.py +533 -0
  653. anyfesolver/marine_morison.py +331 -0
  654. anyfesolver/marine_potential_flow.py +403 -0
  655. anyfesolver/marine_rigid.py +397 -0
  656. anyfesolver/marine_seabed.py +122 -0
  657. anyfesolver/mass_properties.py +352 -0
  658. anyfesolver/material_curves.py +52 -0
  659. anyfesolver/materials.py +43 -0
  660. anyfesolver/matrix_assembly.py +7330 -0
  661. anyfesolver/mesh_gen.py +904 -0
  662. anyfesolver/mesh_load_bc_verification.py +612 -0
  663. anyfesolver/modal.py +2494 -0
  664. anyfesolver/nonlinear.py +341 -0
  665. anyfesolver/nonlinear_analysis_diagnostics.py +466 -0
  666. anyfesolver/nonlinear_element_evaluation.py +126 -0
  667. anyfesolver/nonlinear_performance.py +2094 -0
  668. anyfesolver/nonlinear_performance_batch_b.py +1173 -0
  669. anyfesolver/nonlinear_performance_batch_c.py +850 -0
  670. anyfesolver/nonlinear_performance_bootstrap.py +164 -0
  671. anyfesolver/nonlinear_reduced_assembly.py +806 -0
  672. anyfesolver/nonlinear_restart.py +1708 -0
  673. anyfesolver/nonlinear_state.py +2800 -0
  674. anyfesolver/nonlinear_static.py +9407 -0
  675. anyfesolver/outcomes.py +694 -0
  676. anyfesolver/plasticity.py +2087 -0
  677. anyfesolver/plasticity_qualification.py +758 -0
  678. anyfesolver/prepared_static.py +1129 -0
  679. anyfesolver/prepared_static_envelopes.py +389 -0
  680. anyfesolver/prepared_static_loads.py +1180 -0
  681. anyfesolver/prepared_static_measures.py +18 -0
  682. anyfesolver/prepared_static_numeric.py +247 -0
  683. anyfesolver/prepared_static_q4.py +297 -0
  684. anyfesolver/prepared_static_recovery.py +2068 -0
  685. anyfesolver/prepared_static_response.py +1013 -0
  686. anyfesolver/prepared_static_shared.py +226 -0
  687. anyfesolver/prepared_static_snapshot.py +323 -0
  688. anyfesolver/prepared_static_vectorized.py +866 -0
  689. anyfesolver/pressure_regions.py +287 -0
  690. anyfesolver/production_readiness.py +343 -0
  691. anyfesolver/quality_control.py +1487 -0
  692. anyfesolver/quantities.py +1289 -0
  693. anyfesolver/recovery.py +4217 -0
  694. anyfesolver/recovery_batches.py +1985 -0
  695. anyfesolver/recovery_policy.py +205 -0
  696. anyfesolver/recovery_s4.py +289 -0
  697. anyfesolver/recovery_shell_frames.py +102 -0
  698. anyfesolver/reference_cases.py +366 -0
  699. anyfesolver/result_capsule.py +2175 -0
  700. anyfesolver/results.py +752 -0
  701. anyfesolver/runtime.py +9819 -0
  702. anyfesolver/s3_reference_batch.py +1338 -0
  703. anyfesolver/s3_v2c_fast_assembly.py +544 -0
  704. anyfesolver/s3_v2d_fast_assembly.py +447 -0
  705. anyfesolver/s4_validity.py +354 -0
  706. anyfesolver/sections.py +67 -0
  707. anyfesolver/sesam_fem/__init__.py +55 -0
  708. anyfesolver/sesam_fem/__main__.py +80 -0
  709. anyfesolver/sesam_fem/diagnostics.py +5 -0
  710. anyfesolver/sesam_fem/document.py +39 -0
  711. anyfesolver/sesam_fem/exporter.py +9 -0
  712. anyfesolver/sesam_fem/importer.py +228 -0
  713. anyfesolver/sesam_fem/records.py +21 -0
  714. anyfesolver/sesam_fem/schema.py +35 -0
  715. anyfesolver/sesam_fem/sif_importer.py +9 -0
  716. anyfesolver/sesam_fem/validation.py +5 -0
  717. anyfesolver/sestra_deep_diagnostics.py +173 -0
  718. anyfesolver/sestra_mixed_verification.py +146 -0
  719. anyfesolver/sestra_structure_benchmarks.py +270 -0
  720. anyfesolver/sestra_three_case.py +215 -0
  721. anyfesolver/sestra_verification.py +523 -0
  722. anyfesolver/shell_benchmarks.py +367 -0
  723. anyfesolver/shell_formulations/director_field.py +799 -0
  724. anyfesolver/shell_formulations/geometry_provenance.py +921 -0
  725. anyfesolver/shell_formulations/mitc4_plus_d_quality.py +318 -0
  726. anyfesolver/shell_formulations/mitc4_plus_d_reference.py +837 -0
  727. anyfesolver/shell_formulations/mitc4_plus_d_scalar.py +209 -0
  728. anyfesolver/shell_formulations/protocol.py +222 -0
  729. anyfesolver/shell_formulations/q4_common.py +271 -0
  730. anyfesolver/shell_formulations/s4_restricted_policy.py +78 -0
  731. anyfesolver/shell_sections.py +394 -0
  732. anyfesolver/solid_submodel.py +930 -0
  733. anyfesolver/static_batch.py +662 -0
  734. anyfesolver/static_envelopes.py +250 -0
  735. anyfesolver/stiffened_shell.py +388 -0
  736. anyfesolver/submodel_transfer.py +1306 -0
  737. anyfesolver/test_cases.py +610 -0
  738. anyfesolver/threading_policy.py +431 -0
  739. anyfesolver/validation.py +719 -0
  740. anyfesolver/vectorized_beam.py +139 -0
  741. anyfesolver/vectorized_generalized_shell.py +448 -0
  742. anyfesolver/vectorized_hill48.py +956 -0
  743. anyfesolver/vectorized_nonlinear.py +360 -0
  744. anyfesolver/vectorized_stiffness.py +694 -0
  745. anyfesolver-0.5.0a1.dist-info/METADATA +374 -0
  746. anyfesolver-0.5.0a1.dist-info/RECORD +751 -0
  747. anyfesolver-0.5.0a1.dist-info/WHEEL +5 -0
  748. anyfesolver-0.5.0a1.dist-info/licenses/COPYRIGHT +1 -0
  749. anyfesolver-0.5.0a1.dist-info/licenses/LICENSE +373 -0
  750. anyfesolver-0.5.0a1.dist-info/licenses/THIRD_PARTY_NOTICES.md +32 -0
  751. anyfesolver-0.5.0a1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1936 @@
1
+ """Strict flat-linear E4-PL S3 V2B production candidate.
2
+
3
+ This module deliberately implements only the bounded flat-linear V5B surface:
4
+ a flat, small-strain, homogeneous isotropic elastic triangle with CST membrane,
5
+ source-authorized relaxed MIN3 bending/shear, exact three-point Hammer
6
+ integration and the barycentric PL drill completion. Its only mixed-model admission is an exact,
7
+ globally coplanar qualified-Q4/V2B mesh with one positively aligned physical
8
+ director. Every inherited shell capability outside that surface fails closed
9
+ rather than falling back to legacy TRI3 mechanics.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import math
15
+ import threading
16
+ import weakref
17
+ from types import MappingProxyType
18
+ from typing import Any, Dict, Mapping, Optional, Sequence, Tuple
19
+
20
+ import numpy as np
21
+
22
+ from .element_capabilities import ElementCapabilityError
23
+ from .elements import ShellElement
24
+ from .e4_pl_element import (
25
+ FORMULATION_ID as _QUALIFIED_Q4_FORMULATION_ID,
26
+ QualifiedE4PLShellElement,
27
+ )
28
+ from .fe_core import FEMesh, Material, Node
29
+ from .e4_pl_s3_state import require_exact_numpy_runtime_authority
30
+
31
+
32
+ SELECTOR = "e4-pl-s3-v2b"
33
+ FORMULATION_ID = "CANDIDATE_E4_PL_S3_V2B_FLAT_LINEAR_V1"
34
+ IMPLEMENTATION_ID = "E4_PL_S3_V2B_MIN3_RELAXED_UHM_CST_PL_HAMMER3_V1"
35
+ FORMULATION_SCHEMA = "anysolver.e4-pl-s3-v2b-strict-flat-linear-element-v1"
36
+ SOURCE_CONTRACT_SCHEMA = "anysolver.e4-pl-s3-v5b-relaxation-source-selection-v1"
37
+ SOURCE_CONTRACT_SHA256 = (
38
+ "0AE9DAA05B63A43D456423BCDC676E7421AB3583F152EE5DB3D0E36FE60A17A0"
39
+ )
40
+ EQUATION_MAP_SHA256 = (
41
+ "C322711E0B395F578EEBB8DEE8D48DFF955DCBF0EC4A12ED2B975F2B4F87C789"
42
+ )
43
+ PRIMARY_SOURCE_SHA256 = (
44
+ "54A310C93E7BF140684B7B48D7C6416D99758804E648FB62B2C954150E853174"
45
+ )
46
+ RELAXATION_AUTHORITY_SHA256 = (
47
+ "0AE9DAA05B63A43D456423BCDC676E7421AB3583F152EE5DB3D0E36FE60A17A0"
48
+ )
49
+ QUADRATURE_AUTHORITY_ID = "S3_V2B_MIN3_HAMMER3_DEGREE2_EXACT_V1"
50
+ PL_COMPLETION_POLICY_ID = "S3_V2_BARYCENTRIC_EXACT_SCHUR_KD_EQUALS_A66_V1"
51
+ RESULTANT_POLICY_ID = "SHELL_VARIATIONAL_RESULTANTS_V1"
52
+ DIRECTOR_POLICY_ID = "S3_V2_FIXED_PHYSICAL_DIRECTOR_D3_BLOCK_TRANSPORT_V1"
53
+ SECTION_POLICY_ID = "S3_V2_HOMOGENEOUS_ISOTROPIC_UNCOUPLED_ZERO_OFFSET_V1"
54
+ SHEAR_CORRECTION = 5.0 / 6.0
55
+ CBMIN3 = 2.0
56
+ _ROTATIONAL_INDICES = np.frombuffer(
57
+ np.asarray((3, 4, 9, 10, 15, 16), dtype=np.intp).tobytes(),
58
+ dtype=np.intp,
59
+ )
60
+
61
+ _NORMAL_TOLERANCE = 1.0e-10
62
+ _DEGENERACY_FACTOR = 64.0 * np.finfo(np.float64).eps
63
+
64
+
65
+ class StrictFlatLinearCapabilityError(ElementCapabilityError):
66
+ """The requested operation is outside the authorized S3 V2 surface."""
67
+
68
+
69
+ def _immutable_float64_array(value: Any) -> np.ndarray:
70
+ contiguous = np.ascontiguousarray(value, dtype=np.float64)
71
+ return np.frombuffer(
72
+ contiguous.tobytes(order="C"),
73
+ dtype=np.float64,
74
+ ).reshape(contiguous.shape)
75
+
76
+
77
+ # Natural coordinates are (xi, eta), with lambda = 1 - xi - eta. The same
78
+ # three positive physical weights A/3 are used for membrane, bending and shear.
79
+ HAMMER_POINTS = _immutable_float64_array(
80
+ (
81
+ (1.0 / 6.0, 1.0 / 6.0),
82
+ (2.0 / 3.0, 1.0 / 6.0),
83
+ (1.0 / 6.0, 2.0 / 3.0),
84
+ )
85
+ )
86
+ HAMMER_REFERENCE_WEIGHTS = _immutable_float64_array(
87
+ (1.0 / 6.0, 1.0 / 6.0, 1.0 / 6.0)
88
+ )
89
+
90
+ SUPPORTED_OPERATIONS = frozenset(
91
+ {
92
+ "linear_stiffness",
93
+ "linear_internal_force",
94
+ "raw_variational_resultants",
95
+ "dead_transverse_pressure",
96
+ "flat_qualified_q4_v2a_mixed_mesh",
97
+ }
98
+ )
99
+ BLOCKED_OPERATIONS = frozenset(
100
+ {
101
+ "consistent_mass",
102
+ "geometric_stiffness",
103
+ "nonlinear_geometry",
104
+ "material_nonlinearity",
105
+ "unqualified_mixed_element_mesh",
106
+ "nonlinear_state",
107
+ "qualified_recovery",
108
+ "serialization",
109
+ "restart",
110
+ "follower_pressure",
111
+ "distributed_couple",
112
+ "offset_load",
113
+ "generalized_section",
114
+ "curved_shell",
115
+ "nonplanar_mixed_shell_mesh",
116
+ }
117
+ )
118
+ CAPABILITY_MATRIX = MappingProxyType(
119
+ {
120
+ **{name: "SUPPORTED_STRICT_FLAT_LINEAR" for name in SUPPORTED_OPERATIONS},
121
+ **{name: "BLOCKED_OUTSIDE_STAGE1_AUTHORITY" for name in BLOCKED_OPERATIONS},
122
+ }
123
+ )
124
+
125
+
126
+ def _real_scalar(value: Any, label: str) -> float:
127
+ if isinstance(value, (bool, np.bool_)) or not isinstance(
128
+ value,
129
+ (int, float, np.integer, np.floating),
130
+ ):
131
+ raise TypeError(f"strict-flat S3 V2 {label} must be a finite real scalar")
132
+ made = float(value)
133
+ if not math.isfinite(made):
134
+ raise ValueError(f"strict-flat S3 V2 {label} must be finite")
135
+ return made
136
+
137
+
138
+ def _unit_vector(value: Any, label: str) -> np.ndarray:
139
+ if type(value) in {list, tuple} and any(
140
+ isinstance(component, (bool, np.bool_))
141
+ or not isinstance(component, (int, float, np.integer, np.floating))
142
+ for component in value
143
+ ):
144
+ raise ValueError(f"strict-flat S3 V2 {label} must be a finite 3-vector")
145
+ try:
146
+ vector = np.asarray(value, dtype=np.float64).reshape(-1)
147
+ except (TypeError, ValueError) as exc:
148
+ raise ValueError(
149
+ f"strict-flat S3 V2 {label} must be a finite 3-vector"
150
+ ) from exc
151
+ if vector.size != 3 or not np.all(np.isfinite(vector)):
152
+ raise ValueError(f"strict-flat S3 V2 {label} must be a finite 3-vector")
153
+ norm = float(np.linalg.norm(vector))
154
+ if not math.isfinite(norm) or norm <= 0.0:
155
+ raise ValueError(f"strict-flat S3 V2 {label} must be nonzero")
156
+ return _immutable_float64_array(vector / norm)
157
+
158
+
159
+ def _block_permutation(order: Tuple[int, int, int]) -> np.ndarray:
160
+ permutation = np.zeros((18, 18), dtype=np.float64)
161
+ identity = np.eye(6, dtype=np.float64)
162
+ for internal, external in enumerate(order):
163
+ permutation[
164
+ 6 * internal : 6 * internal + 6,
165
+ 6 * external : 6 * external + 6,
166
+ ] = identity
167
+ return permutation
168
+
169
+
170
+ def _local_component_transform(frame: np.ndarray) -> np.ndarray:
171
+ transform = np.zeros((18, 18), dtype=np.float64)
172
+ local_from_global = np.asarray(frame, dtype=np.float64).T
173
+ for node in range(3):
174
+ base = 6 * node
175
+ transform[base : base + 3, base : base + 3] = local_from_global
176
+ transform[base + 3 : base + 6, base + 3 : base + 6] = (
177
+ local_from_global
178
+ )
179
+ return transform
180
+
181
+
182
+ def _plate_embedding() -> np.ndarray:
183
+ """Map local shell q to printed [w,beta_x,beta_y] node blocks."""
184
+
185
+ embedding = np.zeros((9, 18), dtype=np.float64)
186
+ for node in range(3):
187
+ shell = 6 * node
188
+ plate = 3 * node
189
+ embedding[plate, shell + 2] = 1.0
190
+ embedding[plate + 1, shell + 4] = 1.0
191
+ embedding[plate + 2, shell + 3] = -1.0
192
+ return embedding
193
+
194
+
195
+ _PLATE_EMBEDDING = _immutable_float64_array(_plate_embedding())
196
+ _LAYOUT_SENTINEL = object()
197
+ _MIXED_SCOPE_CACHE_SENTINEL = object()
198
+ _MIXED_SCOPE_CACHE_NAME = "_strict_flat_v2b_mixed_scope_cache_v1"
199
+ _COMPONENT_CACHE_SCHEMA = "strict-flat-s3-v2b-exact-component-cache-v1"
200
+ _COMPONENT_CACHE_ENTRY_SCHEMA = (
201
+ "strict-flat-s3-v2b-exact-component-cache-entry-v1"
202
+ )
203
+ _COMPONENT_CACHE_CAPACITY = 512
204
+
205
+
206
+ def _make_exact_component_compute_wrapper() -> Any:
207
+ """Create the sole cache surface with all mutable state closure-owned."""
208
+
209
+ entries: Dict[Tuple[Any, ...], Tuple[Any, ...]] = {}
210
+ missing = object()
211
+ lock = threading.RLock()
212
+ float64 = np.dtype(np.float64)
213
+ float64_name = float64.str
214
+ matrix_names = (
215
+ "membrane",
216
+ "bending",
217
+ "shear",
218
+ "physical",
219
+ "pl",
220
+ "total",
221
+ )
222
+ packed_shapes = {
223
+ **{name: (18, 18) for name in matrix_names},
224
+ "frame": (3, 3),
225
+ "phi": (3,),
226
+ }
227
+ packed_names = (*matrix_names, "frame", "phi")
228
+ output_names = (
229
+ "membrane",
230
+ "bending",
231
+ "shear",
232
+ "physical",
233
+ "pl",
234
+ "numerical",
235
+ "hourglass",
236
+ "total",
237
+ "frame",
238
+ "area",
239
+ "phi",
240
+ "phi_squared",
241
+ "quadrature_authority_id",
242
+ "pl_completion_policy_id",
243
+ "relaxation_authority_sha256",
244
+ )
245
+ zero_matrix_payload = np.zeros((18, 18), dtype=np.float64).tobytes(order="C")
246
+
247
+ def fail(label: str) -> None:
248
+ raise StrictFlatLinearCapabilityError(
249
+ f"strict-flat S3 V2 exact component cache {label}"
250
+ )
251
+
252
+ def array_identity(
253
+ value: Any,
254
+ shape: Tuple[int, ...],
255
+ label: str,
256
+ ) -> Tuple[Any, ...]:
257
+ if (
258
+ type(value) is not np.ndarray
259
+ or value.dtype != float64
260
+ or value.shape != shape
261
+ or not np.all(np.isfinite(value))
262
+ ):
263
+ fail(f"{label} array is malformed")
264
+ return (float64_name, shape, value.tobytes(order="C"))
265
+
266
+ def scalar_identity(value: Any, label: str) -> bytes:
267
+ if type(value) is not float or not math.isfinite(value) or value <= 0.0:
268
+ fail(f"{label} scalar is malformed")
269
+ return np.float64(value).tobytes()
270
+
271
+ def cache_key(
272
+ geometry: Mapping[str, Any],
273
+ constitutive: Mapping[str, Any],
274
+ ) -> Tuple[Any, ...]:
275
+ return (
276
+ _COMPONENT_CACHE_SCHEMA,
277
+ FORMULATION_ID,
278
+ IMPLEMENTATION_ID,
279
+ SOURCE_CONTRACT_SHA256,
280
+ RELAXATION_AUTHORITY_SHA256,
281
+ EQUATION_MAP_SHA256,
282
+ QUADRATURE_AUTHORITY_ID,
283
+ PL_COMPLETION_POLICY_ID,
284
+ array_identity(
285
+ geometry["local_coordinates"], (3, 2), "local-coordinate"
286
+ ),
287
+ array_identity(
288
+ geometry["shape_gradients"], (3, 2), "shape-gradient"
289
+ ),
290
+ scalar_identity(geometry["area"], "area"),
291
+ array_identity(geometry["frame"], (3, 3), "frame"),
292
+ array_identity(
293
+ geometry["local_from_external"],
294
+ (18, 18),
295
+ "external transform",
296
+ ),
297
+ array_identity(constitutive["A"], (3, 3), "membrane constitutive"),
298
+ array_identity(constitutive["D"], (3, 3), "bending constitutive"),
299
+ array_identity(constitutive["H"], (2, 2), "shear constitutive"),
300
+ scalar_identity(constitutive["bending_scalar"], "bending"),
301
+ scalar_identity(constitutive["shear_scalar"], "shear"),
302
+ scalar_identity(constitutive["drill_scale"], "drill"),
303
+ array_identity(HAMMER_POINTS, (3, 2), "Hammer point"),
304
+ array_identity(HAMMER_REFERENCE_WEIGHTS, (3,), "Hammer weight"),
305
+ array_identity(_PLATE_EMBEDDING, (9, 18), "plate embedding"),
306
+ scalar_identity(CBMIN3, "CBMIN3"),
307
+ tuple(int(value) for value in _ROTATIONAL_INDICES),
308
+ )
309
+
310
+ def pack_result(result: Mapping[str, Any]) -> Tuple[Any, ...]:
311
+ if type(result) is not dict or tuple(result) != output_names:
312
+ fail("result schema or order differs")
313
+ packed = tuple(
314
+ (
315
+ name,
316
+ *array_identity(result[name], packed_shapes[name], name),
317
+ )
318
+ for name in packed_names
319
+ )
320
+ pl_payload = packed[packed_names.index("pl")][-1]
321
+ numerical = array_identity(result["numerical"], (18, 18), "numerical")
322
+ hourglass = array_identity(result["hourglass"], (18, 18), "hourglass")
323
+ if numerical[-1] != pl_payload or hourglass[-1] != zero_matrix_payload:
324
+ fail("numerical component identity differs")
325
+ if (
326
+ result["quadrature_authority_id"] != QUADRATURE_AUTHORITY_ID
327
+ or result["pl_completion_policy_id"] != PL_COMPLETION_POLICY_ID
328
+ or result["relaxation_authority_sha256"]
329
+ != RELAXATION_AUTHORITY_SHA256
330
+ ):
331
+ fail("policy identity differs")
332
+ return (
333
+ _COMPONENT_CACHE_ENTRY_SCHEMA,
334
+ packed,
335
+ scalar_identity(result["area"], "result area"),
336
+ scalar_identity(result["phi_squared"], "MIN3 relaxation"),
337
+ )
338
+
339
+ def unpack_result(record: Tuple[Any, ...]) -> Dict[str, Any]:
340
+ if (
341
+ type(record) is not tuple
342
+ or len(record) != 4
343
+ or record[0] != _COMPONENT_CACHE_ENTRY_SCHEMA
344
+ or type(record[1]) is not tuple
345
+ or len(record[1]) != len(packed_names)
346
+ or type(record[2]) is not bytes
347
+ or len(record[2]) != float64.itemsize
348
+ or type(record[3]) is not bytes
349
+ or len(record[3]) != float64.itemsize
350
+ ):
351
+ fail("packed entry schema differs")
352
+ arrays: Dict[str, np.ndarray] = {}
353
+ for expected_name, expected_shape, packed in zip(
354
+ packed_names,
355
+ (packed_shapes[name] for name in packed_names),
356
+ record[1],
357
+ ):
358
+ if (
359
+ type(packed) is not tuple
360
+ or len(packed) != 4
361
+ or packed[0] != expected_name
362
+ or packed[1] != float64_name
363
+ or packed[2] != expected_shape
364
+ or type(packed[3]) is not bytes
365
+ or len(packed[3]) != math.prod(expected_shape) * float64.itemsize
366
+ ):
367
+ fail("packed array schema differs")
368
+ array = np.frombuffer(packed[3], dtype=float64).reshape(expected_shape)
369
+ if not np.all(np.isfinite(array)):
370
+ fail("packed array is nonfinite")
371
+ arrays[expected_name] = array.copy()
372
+ area = float(np.frombuffer(record[2], dtype=float64, count=1)[0])
373
+ if not math.isfinite(area) or area <= 0.0:
374
+ fail("packed area is malformed")
375
+ phi_squared = float(np.frombuffer(record[3], dtype=float64, count=1)[0])
376
+ if not math.isfinite(phi_squared) or not 0.0 < phi_squared <= 1.0:
377
+ fail("packed MIN3 relaxation is malformed")
378
+ pl = arrays["pl"]
379
+ return {
380
+ "membrane": arrays["membrane"],
381
+ "bending": arrays["bending"],
382
+ "shear": arrays["shear"],
383
+ "physical": arrays["physical"],
384
+ "pl": pl,
385
+ "numerical": pl.copy(),
386
+ "hourglass": np.zeros((18, 18), dtype=np.float64),
387
+ "total": arrays["total"],
388
+ "frame": arrays["frame"],
389
+ "area": area,
390
+ "phi": arrays["phi"],
391
+ "phi_squared": phi_squared,
392
+ "quadrature_authority_id": QUADRATURE_AUTHORITY_ID,
393
+ "pl_completion_policy_id": PL_COMPLETION_POLICY_ID,
394
+ "relaxation_authority_sha256": RELAXATION_AUTHORITY_SHA256,
395
+ }
396
+
397
+ def calculate(
398
+ self: Any,
399
+ geometry: Mapping[str, Any],
400
+ constitutive: Mapping[str, Any],
401
+ ) -> Dict[str, Any]:
402
+ operators = self._operators(geometry, constitutive)
403
+ area = float(geometry["area"])
404
+ physical_weight = area / 3.0
405
+ membrane_local = (
406
+ operators["B_m"].T
407
+ @ constitutive["A"]
408
+ @ operators["B_m"]
409
+ * area
410
+ )
411
+ # MIN3 curvature is constant for the linear triangle. Form it once,
412
+ # matching the accepted V5A/V5B source equation and avoiding a
413
+ # numerically different three-way accumulation of identical terms.
414
+ bending_operator = operators["B_b"][0]
415
+ bending_local = (
416
+ bending_operator.T
417
+ @ constitutive["D"]
418
+ @ bending_operator
419
+ * area
420
+ )
421
+ shear_local = np.zeros((18, 18), dtype=np.float64)
422
+ for shear_operator in operators["B_s"]:
423
+ shear_local += (
424
+ shear_operator.T
425
+ @ constitutive["H"]
426
+ @ shear_operator
427
+ * physical_weight
428
+ )
429
+ bending_sum = float(
430
+ sum(bending_local[index, index] for index in _ROTATIONAL_INDICES)
431
+ )
432
+ unrelaxed_shear_sum = float(
433
+ sum(shear_local[index, index] for index in _ROTATIONAL_INDICES)
434
+ )
435
+ if (
436
+ not math.isfinite(bending_sum)
437
+ or not math.isfinite(unrelaxed_shear_sum)
438
+ or bending_sum <= 0.0
439
+ or unrelaxed_shear_sum <= 0.0
440
+ ):
441
+ fail("MIN3 relaxation diagonal sums are invalid")
442
+ psi_hat = bending_sum / unrelaxed_shear_sum
443
+ phi_squared = CBMIN3 * psi_hat / (1.0 + CBMIN3 * psi_hat)
444
+ if not math.isfinite(phi_squared) or not 0.0 < phi_squared <= 1.0:
445
+ fail("MIN3 relaxation factor is invalid")
446
+ shear_local *= phi_squared
447
+ barycentric_mass = (area / 12.0) * np.asarray(
448
+ ((2.0, 1.0, 1.0), (1.0, 2.0, 1.0), (1.0, 1.0, 2.0)),
449
+ dtype=np.float64,
450
+ )
451
+ constraint = operators["C"]
452
+ pl_local = (
453
+ float(constitutive["drill_scale"])
454
+ * constraint.T
455
+ @ barycentric_mass
456
+ @ constraint
457
+ )
458
+ physical_local = membrane_local + bending_local + shear_local
459
+ total_local = physical_local + pl_local
460
+ transform = np.asarray(geometry["local_from_external"], dtype=np.float64)
461
+
462
+ def globalize(matrix: np.ndarray) -> np.ndarray:
463
+ made = transform.T @ matrix @ transform
464
+ return 0.5 * (made + made.T)
465
+
466
+ membrane = globalize(membrane_local)
467
+ bending = globalize(bending_local)
468
+ shear = globalize(shear_local)
469
+ physical = globalize(physical_local)
470
+ pl = globalize(pl_local)
471
+ total = globalize(total_local)
472
+ return {
473
+ "membrane": membrane,
474
+ "bending": bending,
475
+ "shear": shear,
476
+ "physical": physical,
477
+ "pl": pl,
478
+ "numerical": pl.copy(),
479
+ "hourglass": np.zeros((18, 18), dtype=np.float64),
480
+ "total": total,
481
+ "frame": np.asarray(geometry["frame"], dtype=np.float64).copy(),
482
+ "area": area,
483
+ "phi": np.asarray(operators["phi"], dtype=np.float64).copy(),
484
+ "phi_squared": phi_squared,
485
+ "quadrature_authority_id": QUADRATURE_AUTHORITY_ID,
486
+ "pl_completion_policy_id": PL_COMPLETION_POLICY_ID,
487
+ "relaxation_authority_sha256": RELAXATION_AUTHORITY_SHA256,
488
+ }
489
+
490
+ def compute_stiffness_components(
491
+ self: Any,
492
+ mesh: FEMesh,
493
+ material: Material,
494
+ ) -> Mapping[str, Any]:
495
+ # Admission and all live instance/model/material guards deliberately run
496
+ # before any cache observation. Only exact validated numeric inputs
497
+ # enter the closure-owned key.
498
+ geometry = self._geometry(mesh)
499
+ constitutive = self._constitutive(material)
500
+ key = cache_key(geometry, constitutive)
501
+ with lock:
502
+ cached = entries.get(key, missing)
503
+ if cached is not missing:
504
+ return unpack_result(cached)
505
+
506
+ components = calculate(self, geometry, constitutive)
507
+ packed = pack_result(components)
508
+ with lock:
509
+ existing = entries.get(key, missing)
510
+ if existing is not missing:
511
+ if existing != packed:
512
+ fail("concurrent result disagreement")
513
+ else:
514
+ entries[key] = packed
515
+ if len(entries) > _COMPONENT_CACHE_CAPACITY:
516
+ # Retain the lexicographically smallest exact content keys;
517
+ # the final cache set is independent of insertion/thread order.
518
+ del entries[max(entries)]
519
+ return components
520
+
521
+ compute_stiffness_components.__qualname__ = (
522
+ "StrictFlatLinearE4PLS3V2BShellElement.compute_stiffness_components"
523
+ )
524
+ return compute_stiffness_components
525
+
526
+
527
+ def _validate_module_authority(
528
+ _expected_hammer_points: np.ndarray = HAMMER_POINTS,
529
+ _expected_hammer_weights: np.ndarray = HAMMER_REFERENCE_WEIGHTS,
530
+ _expected_plate_embedding: np.ndarray = _PLATE_EMBEDDING,
531
+ _expected_rotational_indices: np.ndarray = _ROTATIONAL_INDICES,
532
+ _expected_supported: frozenset[str] = SUPPORTED_OPERATIONS,
533
+ _expected_blocked: frozenset[str] = BLOCKED_OPERATIONS,
534
+ _expected_capabilities: Mapping[str, str] = CAPABILITY_MATRIX,
535
+ _expected_shear_correction: float = SHEAR_CORRECTION,
536
+ _expected_cbmin3: float = CBMIN3,
537
+ _expected_normal_tolerance: float = _NORMAL_TOLERANCE,
538
+ _expected_degeneracy_factor: float = _DEGENERACY_FACTOR,
539
+ _expected_selector: str = SELECTOR,
540
+ _expected_formulation_id: str = FORMULATION_ID,
541
+ _expected_implementation_id: str = IMPLEMENTATION_ID,
542
+ _expected_formulation_schema: str = FORMULATION_SCHEMA,
543
+ _expected_source_schema: str = SOURCE_CONTRACT_SCHEMA,
544
+ _expected_source_hash: str = SOURCE_CONTRACT_SHA256,
545
+ _expected_equation_hash: str = EQUATION_MAP_SHA256,
546
+ _expected_primary_hash: str = PRIMARY_SOURCE_SHA256,
547
+ _expected_relaxation_hash: str = RELAXATION_AUTHORITY_SHA256,
548
+ _expected_quadrature_id: str = QUADRATURE_AUTHORITY_ID,
549
+ _expected_pl_id: str = PL_COMPLETION_POLICY_ID,
550
+ _expected_resultant_id: str = RESULTANT_POLICY_ID,
551
+ _expected_director_id: str = DIRECTOR_POLICY_ID,
552
+ _expected_section_id: str = SECTION_POLICY_ID,
553
+ _expected_numpy: Any = np,
554
+ _expected_math: Any = math,
555
+ _expected_threading: Any = threading,
556
+ _expected_shell_class: Any = ShellElement,
557
+ _expected_mesh_class: Any = FEMesh,
558
+ _expected_material_class: Any = Material,
559
+ _expected_capability_error: Any = ElementCapabilityError,
560
+ _expected_candidate_error: Any = StrictFlatLinearCapabilityError,
561
+ _expected_real_scalar: Any = _real_scalar,
562
+ _expected_immutable_array: Any = _immutable_float64_array,
563
+ _expected_unit_vector: Any = _unit_vector,
564
+ _expected_block_permutation: Any = _block_permutation,
565
+ _expected_component_transform: Any = _local_component_transform,
566
+ _expected_numpy_guard: Any = require_exact_numpy_runtime_authority,
567
+ _expected_layout_sentinel: Any = _LAYOUT_SENTINEL,
568
+ _expected_mixed_scope_cache_sentinel: Any = _MIXED_SCOPE_CACHE_SENTINEL,
569
+ _expected_mixed_scope_cache_name: str = _MIXED_SCOPE_CACHE_NAME,
570
+ _expected_component_cache_schema: str = _COMPONENT_CACHE_SCHEMA,
571
+ _expected_component_cache_entry_schema: str = _COMPONENT_CACHE_ENTRY_SCHEMA,
572
+ _expected_component_cache_capacity: int = _COMPONENT_CACHE_CAPACITY,
573
+ _expected_qualified_q4_formulation_id: str = _QUALIFIED_Q4_FORMULATION_ID,
574
+ _expected_qualified_q4_class: Any = QualifiedE4PLShellElement,
575
+ _expected_node_class: Any = Node,
576
+ ) -> None:
577
+ """Fail closed if a frozen Stage-1 module binding was rebound at runtime."""
578
+
579
+ identity_bindings = (
580
+ (HAMMER_POINTS, _expected_hammer_points),
581
+ (HAMMER_REFERENCE_WEIGHTS, _expected_hammer_weights),
582
+ (_PLATE_EMBEDDING, _expected_plate_embedding),
583
+ (_ROTATIONAL_INDICES, _expected_rotational_indices),
584
+ (SUPPORTED_OPERATIONS, _expected_supported),
585
+ (BLOCKED_OPERATIONS, _expected_blocked),
586
+ (CAPABILITY_MATRIX, _expected_capabilities),
587
+ (np, _expected_numpy),
588
+ (math, _expected_math),
589
+ (threading, _expected_threading),
590
+ (ShellElement, _expected_shell_class),
591
+ (QualifiedE4PLShellElement, _expected_qualified_q4_class),
592
+ (FEMesh, _expected_mesh_class),
593
+ (Material, _expected_material_class),
594
+ (Node, _expected_node_class),
595
+ (ElementCapabilityError, _expected_capability_error),
596
+ (StrictFlatLinearCapabilityError, _expected_candidate_error),
597
+ (_real_scalar, _expected_real_scalar),
598
+ (_immutable_float64_array, _expected_immutable_array),
599
+ (_unit_vector, _expected_unit_vector),
600
+ (_block_permutation, _expected_block_permutation),
601
+ (_local_component_transform, _expected_component_transform),
602
+ (require_exact_numpy_runtime_authority, _expected_numpy_guard),
603
+ (_LAYOUT_SENTINEL, _expected_layout_sentinel),
604
+ (_MIXED_SCOPE_CACHE_SENTINEL, _expected_mixed_scope_cache_sentinel),
605
+ )
606
+ scalar_bindings = (
607
+ (SHEAR_CORRECTION, _expected_shear_correction),
608
+ (CBMIN3, _expected_cbmin3),
609
+ (_NORMAL_TOLERANCE, _expected_normal_tolerance),
610
+ (_DEGENERACY_FACTOR, _expected_degeneracy_factor),
611
+ (SELECTOR, _expected_selector),
612
+ (FORMULATION_ID, _expected_formulation_id),
613
+ (IMPLEMENTATION_ID, _expected_implementation_id),
614
+ (FORMULATION_SCHEMA, _expected_formulation_schema),
615
+ (SOURCE_CONTRACT_SCHEMA, _expected_source_schema),
616
+ (SOURCE_CONTRACT_SHA256, _expected_source_hash),
617
+ (EQUATION_MAP_SHA256, _expected_equation_hash),
618
+ (PRIMARY_SOURCE_SHA256, _expected_primary_hash),
619
+ (RELAXATION_AUTHORITY_SHA256, _expected_relaxation_hash),
620
+ (QUADRATURE_AUTHORITY_ID, _expected_quadrature_id),
621
+ (PL_COMPLETION_POLICY_ID, _expected_pl_id),
622
+ (RESULTANT_POLICY_ID, _expected_resultant_id),
623
+ (DIRECTOR_POLICY_ID, _expected_director_id),
624
+ (SECTION_POLICY_ID, _expected_section_id),
625
+ (_MIXED_SCOPE_CACHE_NAME, _expected_mixed_scope_cache_name),
626
+ (_COMPONENT_CACHE_SCHEMA, _expected_component_cache_schema),
627
+ (_COMPONENT_CACHE_ENTRY_SCHEMA, _expected_component_cache_entry_schema),
628
+ (_COMPONENT_CACHE_CAPACITY, _expected_component_cache_capacity),
629
+ (
630
+ _QUALIFIED_Q4_FORMULATION_ID,
631
+ _expected_qualified_q4_formulation_id,
632
+ ),
633
+ )
634
+ if any(actual is not expected for actual, expected in identity_bindings) or any(
635
+ type(actual) is not type(expected) or actual != expected
636
+ for actual, expected in scalar_bindings
637
+ ):
638
+ raise StrictFlatLinearCapabilityError(
639
+ "strict-flat S3 V2 frozen module authority was modified"
640
+ )
641
+ _expected_numpy_guard(context="strict-flat S3 V2")
642
+
643
+
644
+ _FROZEN_INSTANCE_STATE = frozenset(
645
+ {
646
+ "_internal_forces",
647
+ "_is_3node",
648
+ "_is_4node",
649
+ "_is_6node",
650
+ "_is_8node",
651
+ "_is_quadrilateral",
652
+ "_is_triangular",
653
+ "_mass_matrix",
654
+ "_stiffness_matrix",
655
+ "_strict_flat_v2_frozen",
656
+ "drilling_stabilization",
657
+ "element_id",
658
+ "hourglass_stabilization",
659
+ "material_angle_deg",
660
+ "material_direction",
661
+ "material_name",
662
+ "node_ids",
663
+ "reduced_integration",
664
+ "reference_normal",
665
+ "shell_section",
666
+ "thickness",
667
+ }
668
+ )
669
+ _MESH_AUTHORITY_STATE = frozenset(
670
+ {"_qualified_direct_state_token", "_qualified_direct_state_tokens"}
671
+ )
672
+
673
+
674
+ def _make_instance_authority_registry() -> Tuple[Any, Any]:
675
+ registry: "weakref.WeakKeyDictionary[Any, Tuple[Any, ...]]" = (
676
+ weakref.WeakKeyDictionary()
677
+ )
678
+
679
+ def register(element: Any, signature: Tuple[Any, ...]) -> None:
680
+ registry[element] = signature
681
+
682
+ def require(element: Any, signature: Tuple[Any, ...]) -> None:
683
+ expected = registry.get(element)
684
+ if expected is None or expected != signature:
685
+ raise StrictFlatLinearCapabilityError(
686
+ "strict-flat S3 V2 construction authority changed"
687
+ )
688
+
689
+ return register, require
690
+
691
+
692
+ (
693
+ _register_instance_authority,
694
+ _require_instance_authority,
695
+ ) = _make_instance_authority_registry()
696
+
697
+
698
+ def _make_final_class_authority() -> Tuple[Any, Any]:
699
+ authority: Optional[Dict[str, Any]] = None
700
+
701
+ def initialize(cls: type) -> None:
702
+ nonlocal authority
703
+ if authority is not None:
704
+ raise RuntimeError("strict-flat S3 V2 class authority already initialized")
705
+ authority = dict(type.__getattribute__(cls, "__dict__"))
706
+
707
+ def require(cls: type) -> None:
708
+ if authority is None:
709
+ raise RuntimeError("strict-flat S3 V2 class authority is not initialized")
710
+ namespace = type.__getattribute__(cls, "__dict__")
711
+ if set(namespace) != set(authority) or any(
712
+ namespace[name] is not expected for name, expected in authority.items()
713
+ ):
714
+ raise StrictFlatLinearCapabilityError(
715
+ "strict-flat S3 V2 candidate class namespace changed"
716
+ )
717
+
718
+ return initialize, require
719
+
720
+
721
+ (
722
+ _initialize_final_class_authority,
723
+ _require_final_class_authority,
724
+ ) = _make_final_class_authority()
725
+
726
+
727
+ class _StrictFlatCandidateMeta(type(ShellElement)):
728
+ """Prevent normal runtime mutation of the reviewed candidate class."""
729
+
730
+ def __setattr__(cls, name: str, value: Any) -> None:
731
+ namespace = type.__getattribute__(cls, "__dict__")
732
+ if namespace.get("_strict_flat_v2_class_frozen") is True:
733
+ raise StrictFlatLinearCapabilityError(
734
+ "strict-flat S3 V2 candidate class authority is frozen"
735
+ )
736
+ super().__setattr__(name, value)
737
+
738
+ def __delattr__(cls, name: str) -> None:
739
+ namespace = type.__getattribute__(cls, "__dict__")
740
+ if namespace.get("_strict_flat_v2_class_frozen") is True:
741
+ raise StrictFlatLinearCapabilityError(
742
+ "strict-flat S3 V2 candidate class authority is frozen"
743
+ )
744
+ super().__delattr__(name)
745
+
746
+
747
+ class StrictFlatLinearE4PLS3V2BShellElement(
748
+ ShellElement, metaclass=_StrictFlatCandidateMeta
749
+ ):
750
+ """Opt-in S3 V2 for the strict flat, linear, isotropic Stage-1 scope."""
751
+
752
+ __slots__ = ("_strict_flat_v2_layout_sentinel",)
753
+
754
+ formulation_id = FORMULATION_ID
755
+ selector = SELECTOR
756
+ supported_operations = SUPPORTED_OPERATIONS
757
+ blocked_operations = BLOCKED_OPERATIONS
758
+ _legacy_shell_dispatch_forbidden = FORMULATION_ID
759
+ _strict_flat_v2_class_frozen = False
760
+ _register_instance_authority = staticmethod(_register_instance_authority)
761
+ _require_instance_authority = staticmethod(_require_instance_authority)
762
+ _module_authority_guard = staticmethod(_validate_module_authority)
763
+
764
+ # Do not inherit the legacy S3 one-point shear rule. Both physical blocks
765
+ # use the published three-point Hammer rule.
766
+ TRI_GAUSS_POINTS_3 = HAMMER_POINTS
767
+ TRI_GAUSS_WEIGHTS_3 = HAMMER_REFERENCE_WEIGHTS
768
+
769
+ def __getattribute__(
770
+ self,
771
+ name: str,
772
+ _frozen_state: frozenset[str] = _FROZEN_INSTANCE_STATE,
773
+ _mesh_state: frozenset[str] = _MESH_AUTHORITY_STATE,
774
+ ) -> Any:
775
+ # The inherited Element hierarchy owns an instance ``__dict__``. A
776
+ # caller could otherwise shadow a frozen operator (for example
777
+ # ``_constitutive``) without touching the reviewed class. Reject such
778
+ # shadows before Python dispatches them; the exact state-set check in
779
+ # ``_validate_configuration`` catches every other injected name.
780
+ if name not in {"__dict__", "__class__"}:
781
+ namespace = object.__getattribute__(self, "__dict__")
782
+ if (
783
+ namespace.get("_strict_flat_v2_frozen") is True
784
+ and name in namespace
785
+ and name not in (_frozen_state | _mesh_state)
786
+ ):
787
+ raise StrictFlatLinearCapabilityError(
788
+ "strict-flat S3 V2 forbids instance operator shadowing"
789
+ )
790
+ return super().__getattribute__(name)
791
+
792
+ def __setattr__(self, name: str, value: Any) -> None:
793
+ namespace = object.__getattribute__(self, "__dict__")
794
+ if namespace.get("_strict_flat_v2_frozen") is True:
795
+ raise StrictFlatLinearCapabilityError(
796
+ "strict-flat S3 V2 candidate state is immutable after construction"
797
+ )
798
+ super().__setattr__(name, value)
799
+
800
+ def __init__(
801
+ self,
802
+ element_id: int,
803
+ node_ids: Sequence[int],
804
+ material_name: str = "default",
805
+ *,
806
+ thickness: float = 0.01,
807
+ reference_normal: Sequence[float],
808
+ ) -> None:
809
+ __class__._module_authority_guard()
810
+ if type(element_id) is not int:
811
+ raise TypeError("strict-flat S3 V2 element_id must be an exact integer")
812
+ if type(material_name) is not str:
813
+ raise TypeError("strict-flat S3 V2 material_name must be a string")
814
+ owned_node_ids = tuple(node_ids)
815
+ if len(owned_node_ids) != 3:
816
+ raise ValueError(
817
+ "StrictFlatLinearE4PLS3V2BShellElement requires exactly three nodes"
818
+ )
819
+ if not all(type(node_id) is int for node_id in owned_node_ids):
820
+ raise TypeError(
821
+ "strict-flat S3 V2 node_ids must contain exact non-boolean integers"
822
+ )
823
+ if len(set(owned_node_ids)) != 3:
824
+ raise ValueError("strict-flat S3 V2 node_ids must be distinct")
825
+ thickness_value = _real_scalar(thickness, "thickness")
826
+ if thickness_value <= 0.0:
827
+ raise ValueError("strict-flat S3 V2 thickness must be strictly positive")
828
+ normal = _unit_vector(reference_normal, "reference_normal")
829
+
830
+ super().__init__(
831
+ element_id,
832
+ owned_node_ids,
833
+ material_name,
834
+ thickness=thickness_value,
835
+ drilling_stabilization=0.0,
836
+ reduced_integration=False,
837
+ hourglass_stabilization=0.0,
838
+ material_direction=None,
839
+ material_angle_deg=0.0,
840
+ shell_section=None,
841
+ )
842
+ self.reference_normal = normal
843
+ object.__setattr__(self, "_strict_flat_v2_layout_sentinel", _LAYOUT_SENTINEL)
844
+ __class__._register_instance_authority(
845
+ self,
846
+ (
847
+ element_id,
848
+ owned_node_ids,
849
+ material_name,
850
+ thickness_value,
851
+ normal.tobytes(order="C"),
852
+ ),
853
+ )
854
+ object.__setattr__(self, "_strict_flat_v2_frozen", True)
855
+
856
+ @property
857
+ def gauss_points(self) -> np.ndarray:
858
+ self._validate_configuration()
859
+ return HAMMER_POINTS
860
+
861
+ @property
862
+ def gauss_weights(self) -> np.ndarray:
863
+ self._validate_configuration()
864
+ return HAMMER_REFERENCE_WEIGHTS
865
+
866
+ @property
867
+ def shear_gauss_points(self) -> np.ndarray:
868
+ self._validate_configuration()
869
+ return HAMMER_POINTS
870
+
871
+ @property
872
+ def shear_gauss_weights(self) -> np.ndarray:
873
+ self._validate_configuration()
874
+ return HAMMER_REFERENCE_WEIGHTS
875
+
876
+ @property
877
+ def physical_reference_director(self) -> np.ndarray:
878
+ self._validate_configuration()
879
+ return np.asarray(self.reference_normal, dtype=np.float64).copy()
880
+
881
+ def capability_matrix(self) -> Dict[str, str]:
882
+ self._validate_configuration()
883
+ return dict(CAPABILITY_MATRIX)
884
+
885
+ @staticmethod
886
+ def _unsupported(operation: str) -> None:
887
+ raise StrictFlatLinearCapabilityError(
888
+ f"strict-flat S3 V2 capability {operation!r} is outside the "
889
+ "authorized Stage-1 flat-linear surface"
890
+ )
891
+
892
+ def _validate_configuration(
893
+ self,
894
+ _module_guard: Any = _validate_module_authority,
895
+ _class_guard: Any = _require_final_class_authority,
896
+ _frozen_state: frozenset[str] = _FROZEN_INSTANCE_STATE,
897
+ _mesh_state: frozenset[str] = _MESH_AUTHORITY_STATE,
898
+ _layout_sentinel: Any = _LAYOUT_SENTINEL,
899
+ ) -> None:
900
+ _module_guard()
901
+ _class_guard(__class__)
902
+ if type(self) is not __class__:
903
+ raise StrictFlatLinearCapabilityError(
904
+ "strict-flat S3 V2 mechanics require the exact production class"
905
+ )
906
+ if (
907
+ __class__.formulation_id != FORMULATION_ID
908
+ or __class__.selector != SELECTOR
909
+ or __class__.supported_operations is not SUPPORTED_OPERATIONS
910
+ or __class__.blocked_operations is not BLOCKED_OPERATIONS
911
+ or __class__._legacy_shell_dispatch_forbidden != FORMULATION_ID
912
+ or __class__.TRI_GAUSS_POINTS_3 is not HAMMER_POINTS
913
+ or __class__.TRI_GAUSS_WEIGHTS_3 is not HAMMER_REFERENCE_WEIGHTS
914
+ ):
915
+ raise StrictFlatLinearCapabilityError(
916
+ "strict-flat S3 V2 frozen class authority was modified"
917
+ )
918
+ namespace = object.__getattribute__(self, "__dict__")
919
+ state_names = set(namespace)
920
+ if state_names != set(_frozen_state) and state_names != set(
921
+ _frozen_state | _mesh_state
922
+ ):
923
+ raise StrictFlatLinearCapabilityError(
924
+ "strict-flat S3 V2 instance authority contains unregistered state"
925
+ )
926
+ if namespace.get("_strict_flat_v2_frozen") is not True:
927
+ raise StrictFlatLinearCapabilityError(
928
+ "strict-flat S3 V2 instance authority is not frozen"
929
+ )
930
+ if (
931
+ object.__getattribute__(self, "_strict_flat_v2_layout_sentinel")
932
+ is not _layout_sentinel
933
+ ):
934
+ raise StrictFlatLinearCapabilityError(
935
+ "strict-flat S3 V2 class-layout authority changed"
936
+ )
937
+ if _mesh_state <= state_names:
938
+ token = namespace["_qualified_direct_state_token"]
939
+ tokens = namespace["_qualified_direct_state_tokens"]
940
+ if (
941
+ not isinstance(token, list)
942
+ or len(token) != 1
943
+ or type(token[0]) is not int
944
+ or type(tokens) is not list
945
+ or not tokens
946
+ or not any(candidate is token for candidate in tokens)
947
+ or any(
948
+ not isinstance(candidate, list)
949
+ or len(candidate) != 1
950
+ or type(candidate[0]) is not int
951
+ for candidate in tokens
952
+ )
953
+ ):
954
+ raise StrictFlatLinearCapabilityError(
955
+ "strict-flat S3 V2 mesh authority token is malformed"
956
+ )
957
+ if type(self.element_id) is not int:
958
+ raise ValueError("strict-flat S3 V2 element_id authority changed")
959
+ if type(self.material_name) is not str:
960
+ raise ValueError("strict-flat S3 V2 material_name authority changed")
961
+ if (
962
+ type(self.node_ids) is not tuple
963
+ or len(self.node_ids) != 3
964
+ or not all(type(node_id) is int for node_id in self.node_ids)
965
+ or len(set(self.node_ids)) != 3
966
+ ):
967
+ raise ValueError("strict-flat S3 V2 connectivity authority changed")
968
+ if (
969
+ type(self.thickness) is not float
970
+ or not math.isfinite(self.thickness)
971
+ or self.thickness <= 0.0
972
+ ):
973
+ raise ValueError("strict-flat S3 V2 thickness authority changed")
974
+ if (
975
+ self.drilling_stabilization != 0.0
976
+ or self.hourglass_stabilization != 0.0
977
+ or type(self.reduced_integration) is not bool
978
+ or self.reduced_integration
979
+ or self.material_direction is not None
980
+ or self.material_angle_deg != 0.0
981
+ or self.shell_section is not None
982
+ ):
983
+ raise StrictFlatLinearCapabilityError(
984
+ "strict-flat S3 V2 forbids legacy integration, stabilization, "
985
+ "orientation and generalized-section controls"
986
+ )
987
+ if (
988
+ self._stiffness_matrix is not None
989
+ or self._mass_matrix is not None
990
+ or self._internal_forces is not None
991
+ or self._is_3node is not True
992
+ or self._is_triangular is not True
993
+ or self._is_4node is not False
994
+ or self._is_6node is not False
995
+ or self._is_8node is not False
996
+ or self._is_quadrilateral is not False
997
+ ):
998
+ raise StrictFlatLinearCapabilityError(
999
+ "strict-flat S3 V2 inherited runtime state changed"
1000
+ )
1001
+ __class__._require_instance_authority(
1002
+ self,
1003
+ (
1004
+ self.element_id,
1005
+ self.node_ids,
1006
+ self.material_name,
1007
+ self.thickness,
1008
+ self.reference_normal.tobytes(order="C"),
1009
+ ),
1010
+ )
1011
+ normal = self.reference_normal
1012
+ if (
1013
+ type(normal) is not np.ndarray
1014
+ or normal.shape != (3,)
1015
+ or normal.dtype != np.dtype(np.float64)
1016
+ or normal.flags.writeable
1017
+ or not np.all(np.isfinite(normal))
1018
+ or not math.isclose(
1019
+ float(np.linalg.norm(normal)),
1020
+ 1.0,
1021
+ rel_tol=0.0,
1022
+ abs_tol=8.0 * np.finfo(np.float64).eps,
1023
+ )
1024
+ ):
1025
+ raise ValueError("strict-flat S3 V2 reference_normal authority changed")
1026
+
1027
+ def _coordinates(self, mesh: FEMesh) -> np.ndarray:
1028
+ if type(mesh) is not FEMesh:
1029
+ raise TypeError("strict-flat S3 V2 requires an exact FEMesh")
1030
+ coordinates = np.empty((3, 3), dtype=np.float64)
1031
+ for index, node_id in enumerate(self.node_ids):
1032
+ node = mesh.get_node(node_id)
1033
+ if node is None:
1034
+ raise ValueError(
1035
+ f"strict-flat S3 V2 references missing node {node_id}"
1036
+ )
1037
+ value = np.asarray(node.coords(), dtype=np.float64)
1038
+ if value.shape != (3,) or not np.all(np.isfinite(value)):
1039
+ raise ValueError(
1040
+ f"strict-flat S3 V2 node {node_id} has invalid coordinates"
1041
+ )
1042
+ coordinates[index] = value
1043
+ return coordinates
1044
+
1045
+ def _validate_model_scope(self, mesh: FEMesh) -> None:
1046
+ """Admit only one exact, coplanar qualified-Q4/V2B model boundary.
1047
+
1048
+ The complete registry is checked once per mesh mutation epoch. A
1049
+ successful check is cached with the mesh's solver-owned direct-state
1050
+ token, mapping identities and topology/geometry revisions. This keeps
1051
+ formal mixed-mesh assembly linear in the element count while any node,
1052
+ element or registry mutation forces a complete revalidation.
1053
+ """
1054
+
1055
+ if type(mesh) is not FEMesh:
1056
+ raise TypeError("strict-flat S3 V2 requires an exact FEMesh")
1057
+
1058
+ mesh_namespace = object.__getattribute__(mesh, "__dict__")
1059
+ elements = dict.get(mesh_namespace, "elements")
1060
+ nodes = dict.get(mesh_namespace, "nodes")
1061
+ token = dict.get(mesh_namespace, "_qualified_direct_state_token")
1062
+ revisions = dict.get(mesh_namespace, "revisions")
1063
+ if (
1064
+ not isinstance(elements, dict)
1065
+ or not isinstance(nodes, dict)
1066
+ or not isinstance(token, list)
1067
+ or len(token) != 1
1068
+ or type(token[0]) is not int
1069
+ or type(revisions) is not dict
1070
+ or type(revisions.get("topology")) is not int
1071
+ or type(revisions.get("geometry")) is not int
1072
+ ):
1073
+ raise StrictFlatLinearCapabilityError(
1074
+ "strict-flat S3 V2 mesh registry authority is malformed"
1075
+ )
1076
+ if not elements:
1077
+ # Standalone element evaluation remains part of the local
1078
+ # formulation gate. A nonempty model registry, however, must own
1079
+ # the exact element instance evaluated below.
1080
+ return
1081
+ if elements.get(self.element_id) is not self:
1082
+ raise StrictFlatLinearCapabilityError(
1083
+ "strict-flat S3 V2 element registry identity must register the "
1084
+ "evaluated V2B instance exactly"
1085
+ )
1086
+
1087
+ q4_class_namespace = type.__getattribute__(
1088
+ QualifiedE4PLShellElement,
1089
+ "__dict__",
1090
+ )
1091
+ if (
1092
+ q4_class_namespace.get("formulation_id")
1093
+ != _QUALIFIED_Q4_FORMULATION_ID
1094
+ ):
1095
+ raise StrictFlatLinearCapabilityError(
1096
+ "strict-flat S3 V2 qualified Q4 formulation identity changed"
1097
+ )
1098
+
1099
+ common_normal = np.asarray(self.reference_normal, dtype=np.float64)
1100
+ cache = dict.get(mesh_namespace, _MIXED_SCOPE_CACHE_NAME)
1101
+ if (
1102
+ type(cache) is tuple
1103
+ and len(cache) == 8
1104
+ and cache[0] is _MIXED_SCOPE_CACHE_SENTINEL
1105
+ and cache[1] is token
1106
+ and cache[2] == token[0]
1107
+ and cache[3] is nodes
1108
+ and cache[4] is elements
1109
+ and cache[5] == revisions["topology"]
1110
+ and cache[6] == revisions["geometry"]
1111
+ and cache[7] == common_normal.tobytes(order="C")
1112
+ ):
1113
+ return
1114
+
1115
+ try:
1116
+ registered_items = list(elements.items())
1117
+ registered_nodes = list(nodes.items())
1118
+ except (AttributeError, RuntimeError, TypeError, ValueError) as exc:
1119
+ raise StrictFlatLinearCapabilityError(
1120
+ "strict-flat S3 V2 mesh registry authority is malformed"
1121
+ ) from exc
1122
+
1123
+ allowed_types = (__class__, QualifiedE4PLShellElement)
1124
+ registered_elements: list[Any] = []
1125
+ for key, element in registered_items:
1126
+ if type(key) is not int or type(element) not in allowed_types:
1127
+ raise StrictFlatLinearCapabilityError(
1128
+ "strict-flat S3 V2 mixed element registry permits only exact "
1129
+ "qualified Q4 and V2B shell elements"
1130
+ )
1131
+ namespace = object.__getattribute__(element, "__dict__")
1132
+ element_id = dict.get(namespace, "element_id")
1133
+ if type(element_id) is not int or key != element_id:
1134
+ raise StrictFlatLinearCapabilityError(
1135
+ "strict-flat S3 V2 element registry identity is malformed"
1136
+ )
1137
+ registered_elements.append(element)
1138
+ if (
1139
+ len({id(element) for element in registered_elements})
1140
+ != len(registered_elements)
1141
+ or len(
1142
+ {
1143
+ dict.get(object.__getattribute__(element, "__dict__"), "element_id")
1144
+ for element in registered_elements
1145
+ }
1146
+ )
1147
+ != len(registered_elements)
1148
+ ):
1149
+ raise StrictFlatLinearCapabilityError(
1150
+ "strict-flat S3 V2 element registry contains duplicate identities"
1151
+ )
1152
+
1153
+ node_coordinates: dict[int, np.ndarray] = {}
1154
+ observed_nodes: list[Node] = []
1155
+ for key, node in registered_nodes:
1156
+ if type(key) is not int or type(node) is not Node:
1157
+ raise StrictFlatLinearCapabilityError(
1158
+ "strict-flat S3 V2 node registry identity is malformed"
1159
+ )
1160
+ namespace = object.__getattribute__(node, "__dict__")
1161
+ if type(dict.get(namespace, "id")) is not int or namespace["id"] != key:
1162
+ raise StrictFlatLinearCapabilityError(
1163
+ "strict-flat S3 V2 node registry identity is malformed"
1164
+ )
1165
+ try:
1166
+ coordinate = np.asarray(
1167
+ (
1168
+ _real_scalar(dict.get(namespace, "x"), f"node {key} x"),
1169
+ _real_scalar(dict.get(namespace, "y"), f"node {key} y"),
1170
+ _real_scalar(dict.get(namespace, "z"), f"node {key} z"),
1171
+ ),
1172
+ dtype=np.float64,
1173
+ )
1174
+ except (TypeError, ValueError) as exc:
1175
+ raise StrictFlatLinearCapabilityError(
1176
+ f"strict-flat S3 V2 node {key} coordinates are invalid"
1177
+ ) from exc
1178
+ node_coordinates[key] = coordinate
1179
+ observed_nodes.append(node)
1180
+ if len({id(node) for node in observed_nodes}) != len(observed_nodes):
1181
+ raise StrictFlatLinearCapabilityError(
1182
+ "strict-flat S3 V2 node registry contains duplicate identities"
1183
+ )
1184
+
1185
+ for element in registered_elements:
1186
+ if type(element) is __class__:
1187
+ element._validate_configuration()
1188
+ director = np.asarray(element.reference_normal, dtype=np.float64)
1189
+ element_coordinates = element._coordinates(mesh)
1190
+ else:
1191
+ namespace = object.__getattribute__(element, "__dict__")
1192
+ if "formulation_id" in namespace:
1193
+ raise StrictFlatLinearCapabilityError(
1194
+ "strict-flat S3 V2 qualified Q4 formulation identity is "
1195
+ "shadowed"
1196
+ )
1197
+ # This accessor runs the independently frozen Q4 runtime and
1198
+ # instance guards before returning any coordinate observation.
1199
+ element_coordinates = np.asarray(
1200
+ element.get_node_coordinates(mesh),
1201
+ dtype=np.float64,
1202
+ )
1203
+ reference_normal = dict.get(namespace, "reference_normal")
1204
+ polarity = dict.get(namespace, "director_polarity")
1205
+ if reference_normal is None:
1206
+ raise StrictFlatLinearCapabilityError(
1207
+ "strict-flat S3 V2 mixed qualified Q4 requires an "
1208
+ "authoritative reference_normal"
1209
+ )
1210
+ if type(polarity) is not int or polarity not in {-1, 1}:
1211
+ raise StrictFlatLinearCapabilityError(
1212
+ "strict-flat S3 V2 qualified Q4 physical-director "
1213
+ "authority is malformed"
1214
+ )
1215
+ director = float(polarity) * np.asarray(
1216
+ reference_normal,
1217
+ dtype=np.float64,
1218
+ )
1219
+ if (
1220
+ director.shape != (3,)
1221
+ or not np.all(np.isfinite(director))
1222
+ or not math.isclose(
1223
+ float(np.linalg.norm(director)),
1224
+ 1.0,
1225
+ rel_tol=0.0,
1226
+ abs_tol=8.0 * np.finfo(np.float64).eps,
1227
+ )
1228
+ or float(director @ common_normal)
1229
+ < 1.0 - _NORMAL_TOLERANCE
1230
+ ):
1231
+ raise StrictFlatLinearCapabilityError(
1232
+ "strict-flat S3 V2 mixed shell physical directors are not "
1233
+ "positively aligned"
1234
+ )
1235
+ if (
1236
+ element_coordinates.shape != (len(element.node_ids), 3)
1237
+ or not np.all(np.isfinite(element_coordinates))
1238
+ or any(node_id not in node_coordinates for node_id in element.node_ids)
1239
+ ):
1240
+ raise StrictFlatLinearCapabilityError(
1241
+ "strict-flat S3 V2 mixed shell connectivity is malformed"
1242
+ )
1243
+
1244
+ if not node_coordinates:
1245
+ raise StrictFlatLinearCapabilityError(
1246
+ "strict-flat S3 V2 nonempty element registry has no nodes"
1247
+ )
1248
+ all_coordinates = np.asarray(
1249
+ [node_coordinates[key] for key in sorted(node_coordinates)],
1250
+ dtype=np.float64,
1251
+ )
1252
+ common_origin = all_coordinates[0]
1253
+ relative = all_coordinates - common_origin
1254
+ scale = max(1.0, float(np.max(np.linalg.norm(relative, axis=1))))
1255
+ offsets = relative @ common_normal
1256
+ if float(np.max(np.abs(offsets))) > _NORMAL_TOLERANCE * scale:
1257
+ raise StrictFlatLinearCapabilityError(
1258
+ "strict-flat S3 V2 shell nodes are not globally coplanar"
1259
+ )
1260
+
1261
+ object.__setattr__(
1262
+ mesh,
1263
+ _MIXED_SCOPE_CACHE_NAME,
1264
+ (
1265
+ _MIXED_SCOPE_CACHE_SENTINEL,
1266
+ token,
1267
+ token[0],
1268
+ nodes,
1269
+ elements,
1270
+ revisions["topology"],
1271
+ revisions["geometry"],
1272
+ common_normal.tobytes(order="C"),
1273
+ ),
1274
+ )
1275
+
1276
+ def _geometry(self, mesh: FEMesh) -> Dict[str, Any]:
1277
+ self._validate_configuration()
1278
+ self._validate_model_scope(mesh)
1279
+ external = self._coordinates(mesh)
1280
+ normal = np.asarray(self.reference_normal, dtype=np.float64)
1281
+ edge_12 = external[1] - external[0]
1282
+ edge_13 = external[2] - external[0]
1283
+ edge_scale = max(
1284
+ float(edge_12 @ edge_12),
1285
+ float(edge_13 @ edge_13),
1286
+ float((external[2] - external[1]) @ (external[2] - external[1])),
1287
+ np.finfo(np.float64).tiny,
1288
+ )
1289
+ cross = np.cross(edge_12, edge_13)
1290
+ doubled_area = float(np.linalg.norm(cross))
1291
+ if (
1292
+ not math.isfinite(doubled_area)
1293
+ or doubled_area <= _DEGENERACY_FACTOR * edge_scale
1294
+ ):
1295
+ raise ValueError(
1296
+ "strict-flat S3 V2 requires a numerically nondegenerate triangle"
1297
+ )
1298
+ tangency = max(abs(float(edge_12 @ normal)), abs(float(edge_13 @ normal)))
1299
+ if tangency > _NORMAL_TOLERANCE * math.sqrt(edge_scale):
1300
+ raise StrictFlatLinearCapabilityError(
1301
+ "strict-flat S3 V2 reference_normal is not normal to the flat facet"
1302
+ )
1303
+ signed = float(cross @ normal)
1304
+ if abs(signed) < (1.0 - _NORMAL_TOLERANCE) * doubled_area:
1305
+ raise StrictFlatLinearCapabilityError(
1306
+ "strict-flat S3 V2 reference_normal is incompatible with the facet"
1307
+ )
1308
+ order: Tuple[int, int, int] = (0, 1, 2) if signed > 0.0 else (0, 2, 1)
1309
+ coordinates = external[np.asarray(order, dtype=np.intp)]
1310
+
1311
+ x_axis = coordinates[1] - coordinates[0]
1312
+ x_axis /= float(np.linalg.norm(x_axis))
1313
+ y_axis = np.cross(normal, x_axis)
1314
+ y_axis /= float(np.linalg.norm(y_axis))
1315
+ frame = np.column_stack((x_axis, y_axis, normal))
1316
+ relative = coordinates - coordinates[0]
1317
+ local = np.column_stack((relative @ x_axis, relative @ y_axis))
1318
+ jacobian = np.array(
1319
+ (
1320
+ (local[1, 0] - local[0, 0], local[2, 0] - local[0, 0]),
1321
+ (local[1, 1] - local[0, 1], local[2, 1] - local[0, 1]),
1322
+ ),
1323
+ dtype=np.float64,
1324
+ )
1325
+ determinant = float(np.linalg.det(jacobian))
1326
+ if not math.isfinite(determinant) or determinant <= 0.0:
1327
+ raise RuntimeError(
1328
+ "strict-flat S3 V2 failed to construct a positive element chart"
1329
+ )
1330
+ natural_gradients = np.asarray(
1331
+ ((-1.0, -1.0), (1.0, 0.0), (0.0, 1.0)),
1332
+ dtype=np.float64,
1333
+ )
1334
+ gradients = natural_gradients @ np.linalg.inv(jacobian)
1335
+ permutation = _block_permutation(order)
1336
+ local_from_external = _local_component_transform(frame) @ permutation
1337
+ return {
1338
+ "external_coordinates": external,
1339
+ "internal_order": order,
1340
+ "local_coordinates": local,
1341
+ "shape_gradients": gradients,
1342
+ "area": 0.5 * determinant,
1343
+ "frame": frame,
1344
+ "local_from_external": local_from_external,
1345
+ }
1346
+
1347
+ def _constitutive(self, material: Material) -> Dict[str, Any]:
1348
+ if type(material) is not Material:
1349
+ raise StrictFlatLinearCapabilityError(
1350
+ "strict-flat S3 V2 requires the exact homogeneous isotropic Material"
1351
+ )
1352
+ if getattr(material, "hardening_curve", None) is not None:
1353
+ raise StrictFlatLinearCapabilityError(
1354
+ "strict-flat S3 V2 material nonlinearity is outside Stage-1 authority"
1355
+ )
1356
+ yield_stress = getattr(material, "yield_stress", 0.0)
1357
+ if yield_stress is not None and _real_scalar(yield_stress, "yield_stress") != 0.0:
1358
+ raise StrictFlatLinearCapabilityError(
1359
+ "strict-flat S3 V2 requires a purely elastic material descriptor"
1360
+ )
1361
+ elastic_modulus = _real_scalar(
1362
+ getattr(material, "elastic_modulus", None),
1363
+ "elastic_modulus",
1364
+ )
1365
+ poisson_ratio = _real_scalar(
1366
+ getattr(material, "poisson_ratio", None),
1367
+ "poisson_ratio",
1368
+ )
1369
+ if elastic_modulus <= 0.0:
1370
+ raise ValueError("strict-flat S3 V2 elastic_modulus must be positive")
1371
+ if not -1.0 < poisson_ratio < 0.5:
1372
+ raise ValueError(
1373
+ "strict-flat S3 V2 poisson_ratio must satisfy -1 < nu < 0.5"
1374
+ )
1375
+ membrane_scale = (
1376
+ elastic_modulus * self.thickness / (1.0 - poisson_ratio**2)
1377
+ )
1378
+ bending_scale = (
1379
+ elastic_modulus
1380
+ * self.thickness**3
1381
+ / (12.0 * (1.0 - poisson_ratio**2))
1382
+ )
1383
+ isotropic = np.asarray(
1384
+ (
1385
+ (1.0, poisson_ratio, 0.0),
1386
+ (poisson_ratio, 1.0, 0.0),
1387
+ (0.0, 0.0, 0.5 * (1.0 - poisson_ratio)),
1388
+ ),
1389
+ dtype=np.float64,
1390
+ )
1391
+ membrane = membrane_scale * isotropic
1392
+ bending = bending_scale * isotropic
1393
+ # Preserve the accepted source-equation operation order. These are
1394
+ # binary64 calculations, so the algebraically equivalent staged shear
1395
+ # modulus expression is not byte-identical to the V5B authority.
1396
+ shear_scalar = (
1397
+ SHEAR_CORRECTION
1398
+ * elastic_modulus
1399
+ * self.thickness
1400
+ / (2.0 * (1.0 + poisson_ratio))
1401
+ )
1402
+ drill_scale = (
1403
+ self.thickness
1404
+ * elastic_modulus
1405
+ / (2.0 * (1.0 + poisson_ratio))
1406
+ )
1407
+ shear = shear_scalar * np.eye(2, dtype=np.float64)
1408
+ if not all(
1409
+ np.all(np.isfinite(matrix)) for matrix in (membrane, bending, shear)
1410
+ ) or shear_scalar <= 0.0:
1411
+ raise ValueError("strict-flat S3 V2 constitutive data are invalid")
1412
+ return {
1413
+ "A": membrane,
1414
+ "D": bending,
1415
+ "H": shear,
1416
+ "bending_scalar": bending_scale,
1417
+ "shear_scalar": shear_scalar,
1418
+ "drill_scale": drill_scale,
1419
+ }
1420
+
1421
+ @staticmethod
1422
+ def _membrane_operator(gradients: np.ndarray) -> np.ndarray:
1423
+ operator = np.zeros((3, 18), dtype=np.float64)
1424
+ for node, (derivative_x, derivative_y) in enumerate(gradients):
1425
+ base = 6 * node
1426
+ operator[0, base] = derivative_x
1427
+ operator[1, base + 1] = derivative_y
1428
+ operator[2, base] = derivative_y
1429
+ operator[2, base + 1] = derivative_x
1430
+ return operator
1431
+
1432
+ @staticmethod
1433
+ def _pl_constraint(gradients: np.ndarray) -> np.ndarray:
1434
+ constraint = np.zeros((3, 18), dtype=np.float64)
1435
+ for row in range(3):
1436
+ for node, (derivative_x, derivative_y) in enumerate(gradients):
1437
+ base = 6 * node
1438
+ constraint[row, base] = 0.5 * derivative_y
1439
+ constraint[row, base + 1] = -0.5 * derivative_x
1440
+ constraint[row, 6 * row + 5] = 1.0
1441
+ return constraint
1442
+
1443
+ @staticmethod
1444
+ def _edge_data(local: np.ndarray) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
1445
+ directed = ((0, 1), (1, 2), (2, 0))
1446
+ cosine = np.empty(3, dtype=np.float64)
1447
+ sine = np.empty(3, dtype=np.float64)
1448
+ length = np.empty(3, dtype=np.float64)
1449
+ for edge, (first, second) in enumerate(directed):
1450
+ delta = local[second] - local[first]
1451
+ edge_length = float(np.linalg.norm(delta))
1452
+ if not math.isfinite(edge_length) or edge_length <= 0.0:
1453
+ raise ValueError("strict-flat S3 V2 has an invalid directed edge")
1454
+ length[edge] = edge_length
1455
+ cosine[edge] = delta[0] / edge_length
1456
+ sine[edge] = delta[1] / edge_length
1457
+ return cosine, sine, length
1458
+
1459
+ @staticmethod
1460
+ def _side_kinematics(
1461
+ cosine: np.ndarray,
1462
+ sine: np.ndarray,
1463
+ length: np.ndarray,
1464
+ ) -> np.ndarray:
1465
+ operator = np.zeros((3, 9), dtype=np.float64)
1466
+ for edge, (first, second) in enumerate(((0, 1), (1, 2), (2, 0))):
1467
+ first_base = 3 * first
1468
+ second_base = 3 * second
1469
+ operator[edge, first_base] = -1.0 / length[edge]
1470
+ operator[edge, second_base] = 1.0 / length[edge]
1471
+ operator[edge, first_base + 1] = 0.5 * cosine[edge]
1472
+ operator[edge, first_base + 2] = 0.5 * sine[edge]
1473
+ operator[edge, second_base + 1] = 0.5 * cosine[edge]
1474
+ operator[edge, second_base + 2] = 0.5 * sine[edge]
1475
+ return operator
1476
+
1477
+ @staticmethod
1478
+ def _side_shear_projection(
1479
+ shape: np.ndarray,
1480
+ cosine: np.ndarray,
1481
+ sine: np.ndarray,
1482
+ ) -> np.ndarray:
1483
+ c12, c23, c31 = cosine
1484
+ s12, s23, s31 = sine
1485
+ a1 = c12 * s31 - c31 * s12
1486
+ a2 = c23 * s12 - c12 * s23
1487
+ a3 = c31 * s23 - c23 * s31
1488
+ scale = max(abs(a1), abs(a2), abs(a3), 1.0)
1489
+ if min(abs(a1), abs(a2), abs(a3)) <= _DEGENERACY_FACTOR * scale:
1490
+ raise ValueError(
1491
+ "strict-flat S3 V2 side-shear projection is singular"
1492
+ )
1493
+ n1, n2, n3 = shape
1494
+ return np.asarray(
1495
+ (
1496
+ (
1497
+ s31 * n1 / a1 - s23 * n2 / a2,
1498
+ s12 * n2 / a2 - s31 * n3 / a3,
1499
+ s23 * n3 / a3 - s12 * n1 / a1,
1500
+ ),
1501
+ (
1502
+ -(c31 * n1 / a1 - c23 * n2 / a2),
1503
+ -(c12 * n2 / a2 - c31 * n3 / a3),
1504
+ -(c23 * n3 / a3 - c12 * n1 / a1),
1505
+ ),
1506
+ ),
1507
+ dtype=np.float64,
1508
+ )
1509
+
1510
+ @staticmethod
1511
+ def _bending_beta_operator(gradients: np.ndarray) -> np.ndarray:
1512
+ operator = np.zeros((3, 9), dtype=np.float64)
1513
+ for node, (derivative_x, derivative_y) in enumerate(gradients):
1514
+ base = 3 * node
1515
+ operator[0, base + 1] = derivative_x
1516
+ operator[1, base + 2] = derivative_y
1517
+ operator[2, base + 1] = derivative_y
1518
+ operator[2, base + 2] = derivative_x
1519
+ return operator
1520
+
1521
+ @staticmethod
1522
+ def _hierarchical_gradients(
1523
+ shape: np.ndarray,
1524
+ gradients: np.ndarray,
1525
+ ) -> np.ndarray:
1526
+ pairs = ((0, 1), (1, 2), (2, 0))
1527
+ made = np.empty((3, 2), dtype=np.float64)
1528
+ for edge, (first, second) in enumerate(pairs):
1529
+ made[edge] = 4.0 * (
1530
+ shape[first] * gradients[second]
1531
+ + shape[second] * gradients[first]
1532
+ )
1533
+ return made
1534
+
1535
+ @staticmethod
1536
+ def _bending_delta_operator(
1537
+ hierarchical_gradients: np.ndarray,
1538
+ cosine: np.ndarray,
1539
+ sine: np.ndarray,
1540
+ ) -> np.ndarray:
1541
+ operator = np.empty((3, 3), dtype=np.float64)
1542
+ for edge, (derivative_x, derivative_y) in enumerate(
1543
+ hierarchical_gradients
1544
+ ):
1545
+ operator[:, edge] = (
1546
+ derivative_x * cosine[edge],
1547
+ derivative_y * sine[edge],
1548
+ derivative_y * cosine[edge] + derivative_x * sine[edge],
1549
+ )
1550
+ return operator
1551
+
1552
+ def _operators(
1553
+ self,
1554
+ geometry: Mapping[str, Any],
1555
+ constitutive: Mapping[str, Any],
1556
+ ) -> Dict[str, Any]:
1557
+ del constitutive
1558
+ local = np.asarray(geometry["local_coordinates"], dtype=np.float64)
1559
+ gradients = np.asarray(geometry["shape_gradients"], dtype=np.float64)
1560
+ membrane = self._membrane_operator(gradients)
1561
+ bending_all = []
1562
+ shear_all = []
1563
+ shapes = []
1564
+ # UHM/CE/02-02 equations 2.23 and NASA A.1--A.4. This is the
1565
+ # source-authorized MIN3 operator that was independently accepted by
1566
+ # V5A/V5B; it deliberately replaces the historical V2A DKMT
1567
+ # elimination rather than modifying that preserved implementation.
1568
+ a = np.empty(3, dtype=np.float64)
1569
+ b = np.empty(3, dtype=np.float64)
1570
+ for node, first, second in ((0, 1, 2), (1, 2, 0), (2, 0, 1)):
1571
+ a[node] = local[second, 0] - local[first, 0]
1572
+ b[node] = local[first, 1] - local[second, 1]
1573
+ for xi, eta in HAMMER_POINTS:
1574
+ shape = np.asarray((1.0 - xi - eta, xi, eta), dtype=np.float64)
1575
+ dl = np.empty((2, 3), dtype=np.float64)
1576
+ dm = np.empty((2, 3), dtype=np.float64)
1577
+ for node, first, second in ((0, 1, 2), (1, 2, 0), (2, 0, 1)):
1578
+ for axis in range(2):
1579
+ derivative = gradients[:, axis]
1580
+ dl[axis, node] = 0.5 * (
1581
+ derivative[node]
1582
+ * (b[second] * shape[first] - b[first] * shape[second])
1583
+ + shape[node]
1584
+ * (
1585
+ b[second] * derivative[first]
1586
+ - b[first] * derivative[second]
1587
+ )
1588
+ )
1589
+ dm[axis, node] = 0.5 * (
1590
+ derivative[node]
1591
+ * (a[first] * shape[second] - a[second] * shape[first])
1592
+ + shape[node]
1593
+ * (
1594
+ a[first] * derivative[second]
1595
+ - a[second] * derivative[first]
1596
+ )
1597
+ )
1598
+ bending = np.zeros((3, 18), dtype=np.float64)
1599
+ shear = np.zeros((2, 18), dtype=np.float64)
1600
+ for node, (derivative_x, derivative_y) in enumerate(gradients):
1601
+ base = 6 * node
1602
+ bending[0, base + 4] = derivative_x
1603
+ bending[1, base + 3] = -derivative_y
1604
+ bending[2, base + 3] = -derivative_x
1605
+ bending[2, base + 4] = derivative_y
1606
+ shear[0, base + 2] = derivative_x
1607
+ shear[0, base + 3] = -dl[0, node]
1608
+ shear[0, base + 4] = dm[0, node] + shape[node]
1609
+ shear[1, base + 2] = derivative_y
1610
+ shear[1, base + 3] = -dl[1, node] - shape[node]
1611
+ shear[1, base + 4] = dm[1, node]
1612
+ bending_all.append(bending)
1613
+ shear_all.append(shear)
1614
+ shapes.append(shape)
1615
+ return {
1616
+ "B_m": membrane,
1617
+ "B_b": np.asarray(bending_all, dtype=np.float64),
1618
+ "B_s": np.asarray(shear_all, dtype=np.float64),
1619
+ "shape": np.asarray(shapes, dtype=np.float64),
1620
+ "C": self._pl_constraint(gradients),
1621
+ "phi": np.zeros(3, dtype=np.float64),
1622
+ }
1623
+
1624
+ compute_stiffness_components = _make_exact_component_compute_wrapper()
1625
+
1626
+ def compute_stiffness_matrix(
1627
+ self,
1628
+ mesh: FEMesh,
1629
+ material: Material,
1630
+ ) -> np.ndarray:
1631
+ return np.asarray(
1632
+ self.compute_stiffness_components(mesh, material)["total"],
1633
+ dtype=np.float64,
1634
+ ).copy()
1635
+
1636
+ def compute_internal_forces(
1637
+ self,
1638
+ mesh: FEMesh,
1639
+ displacements: np.ndarray,
1640
+ material: Material,
1641
+ ) -> np.ndarray:
1642
+ vector = self._get_element_displacements(mesh, displacements)
1643
+ if vector.shape != (18,) or not np.all(np.isfinite(vector)):
1644
+ raise ValueError(
1645
+ "strict-flat S3 V2 displacements must resolve to a finite 18-vector"
1646
+ )
1647
+ return self.compute_stiffness_matrix(mesh, material) @ vector
1648
+
1649
+ def compute_variational_resultants(
1650
+ self,
1651
+ mesh: FEMesh,
1652
+ displacements: np.ndarray,
1653
+ material: Material,
1654
+ ) -> Dict[str, Any]:
1655
+ geometry = self._geometry(mesh)
1656
+ constitutive = self._constitutive(material)
1657
+ operators = self._operators(geometry, constitutive)
1658
+ phi_squared = float(
1659
+ self.compute_stiffness_components(mesh, material)["phi_squared"]
1660
+ )
1661
+ vector = self._get_element_displacements(mesh, displacements)
1662
+ if vector.shape != (18,) or not np.all(np.isfinite(vector)):
1663
+ raise ValueError(
1664
+ "strict-flat S3 V2 displacements must resolve to a finite 18-vector"
1665
+ )
1666
+ local_vector = geometry["local_from_external"] @ vector
1667
+ membrane_strain = np.broadcast_to(
1668
+ operators["B_m"] @ local_vector,
1669
+ (3, 3),
1670
+ ).copy()
1671
+ curvature = np.einsum("gij,j->gi", operators["B_b"], local_vector)
1672
+ transverse_shear = np.einsum(
1673
+ "gij,j->gi",
1674
+ operators["B_s"],
1675
+ local_vector,
1676
+ )
1677
+ membrane_resultants = membrane_strain @ constitutive["A"].T
1678
+ bending_resultants = curvature @ constitutive["D"].T
1679
+ shear_resultants = (
1680
+ phi_squared * transverse_shear @ constitutive["H"].T
1681
+ )
1682
+ # Operators are evaluated in the positive internal D3 chart. Restore
1683
+ # station rows to the external connectivity order so the canonical
1684
+ # Hammer coordinates below always describe the returned row. The
1685
+ # component frame remains the explicitly reported physical frame.
1686
+ order = tuple(int(value) for value in geometry["internal_order"])
1687
+
1688
+ def external_station_order(values: np.ndarray) -> np.ndarray:
1689
+ made = np.empty_like(values)
1690
+ for internal_index, external_index in enumerate(order):
1691
+ made[external_index] = values[internal_index]
1692
+ return made
1693
+
1694
+ membrane_strain = external_station_order(membrane_strain)
1695
+ curvature = external_station_order(curvature)
1696
+ transverse_shear = external_station_order(transverse_shear)
1697
+ membrane_resultants = external_station_order(membrane_resultants)
1698
+ bending_resultants = external_station_order(bending_resultants)
1699
+ shear_resultants = external_station_order(shear_resultants)
1700
+ barycentric = np.column_stack(
1701
+ (
1702
+ 1.0 - HAMMER_POINTS[:, 0] - HAMMER_POINTS[:, 1],
1703
+ HAMMER_POINTS[:, 0],
1704
+ HAMMER_POINTS[:, 1],
1705
+ )
1706
+ )
1707
+ physical_stations = barycentric @ np.asarray(
1708
+ geometry["external_coordinates"], dtype=np.float64
1709
+ )
1710
+ area = float(geometry["area"])
1711
+ return {
1712
+ "recovery_scope": RESULTANT_POLICY_ID,
1713
+ "qualified_recovery": False,
1714
+ "physical_stress_available": False,
1715
+ "numerical_fields_excluded": True,
1716
+ "membrane_strain": membrane_strain,
1717
+ "curvature": curvature,
1718
+ "transverse_shear_strain": transverse_shear,
1719
+ "membrane_resultants": membrane_resultants,
1720
+ "bending_resultants": bending_resultants,
1721
+ "transverse_shear_resultants": shear_resultants,
1722
+ "min3_relaxation_phi_squared": phi_squared,
1723
+ "relaxation_authority_sha256": RELAXATION_AUTHORITY_SHA256,
1724
+ "hammer_points": np.asarray(HAMMER_POINTS, dtype=np.float64).copy(),
1725
+ "external_barycentric_coordinates": barycentric,
1726
+ "physical_station_coordinates": physical_stations,
1727
+ "internal_order": order,
1728
+ "physical_weights": np.full(3, area / 3.0, dtype=np.float64),
1729
+ "frame": np.asarray(geometry["frame"], dtype=np.float64).copy(),
1730
+ "resultant_policy_id": RESULTANT_POLICY_ID,
1731
+ }
1732
+
1733
+ def compute_dead_transverse_pressure_load(
1734
+ self,
1735
+ mesh: FEMesh,
1736
+ pressure: Any,
1737
+ ) -> np.ndarray:
1738
+ geometry = self._geometry(mesh)
1739
+ area = float(geometry["area"])
1740
+ if isinstance(pressure, (bool, np.bool_)):
1741
+ raise TypeError("strict-flat S3 V2 pressure must be real")
1742
+ if isinstance(pressure, (int, float, np.integer, np.floating)):
1743
+ value = _real_scalar(pressure, "pressure")
1744
+ else:
1745
+ raise StrictFlatLinearCapabilityError(
1746
+ "strict-flat S3 V2B source authority admits uniform pressure only"
1747
+ )
1748
+ local = np.asarray(geometry["local_coordinates"], dtype=np.float64)
1749
+ a = np.empty(3, dtype=np.float64)
1750
+ b = np.empty(3, dtype=np.float64)
1751
+ for node, first, second in ((0, 1, 2), (1, 2, 0), (2, 0, 1)):
1752
+ a[node] = local[second, 0] - local[first, 0]
1753
+ b[node] = local[first, 1] - local[second, 1]
1754
+ load_local = np.zeros(18, dtype=np.float64)
1755
+ for xi, eta in HAMMER_POINTS:
1756
+ shape = np.asarray((1.0 - xi - eta, xi, eta), dtype=np.float64)
1757
+ for node, first, second in ((0, 1, 2), (1, 2, 0), (2, 0, 1)):
1758
+ l_value = 0.5 * shape[node] * (
1759
+ b[second] * shape[first] - b[first] * shape[second]
1760
+ )
1761
+ m_value = 0.5 * shape[node] * (
1762
+ a[first] * shape[second] - a[second] * shape[first]
1763
+ )
1764
+ base = 6 * node
1765
+ weight = value * area / 3.0
1766
+ load_local[base + 2] += weight * shape[node]
1767
+ load_local[base + 3] -= weight * l_value
1768
+ load_local[base + 4] += weight * m_value
1769
+ transform = np.asarray(geometry["local_from_external"], dtype=np.float64)
1770
+ return transform.T @ load_local
1771
+
1772
+ # Explicitly seal every inherited mechanics or persistence route not
1773
+ # authorized by the Stage-1 equation map.
1774
+ def compute_mass_matrix(self, mesh: FEMesh, material: Material, **kwargs: Any) -> np.ndarray:
1775
+ self._unsupported("consistent_mass")
1776
+
1777
+ def compute_geometric_stiffness_matrix(
1778
+ self,
1779
+ mesh: FEMesh,
1780
+ material: Material,
1781
+ state: Optional[Any] = None,
1782
+ ) -> np.ndarray:
1783
+ self._unsupported("geometric_stiffness")
1784
+
1785
+ def init_nonlinear_state(self, num_layers: int) -> Dict[str, Any]:
1786
+ self._unsupported("nonlinear_state")
1787
+
1788
+ def compute_nonlinear_response(
1789
+ self,
1790
+ mesh: FEMesh,
1791
+ material: Material,
1792
+ u_elem: np.ndarray,
1793
+ state: Optional[Any] = None,
1794
+ num_layers: int = 5,
1795
+ tangent: bool = True,
1796
+ ) -> Tuple[np.ndarray, Optional[np.ndarray], Optional[Any]]:
1797
+ self._unsupported("nonlinear_geometry")
1798
+
1799
+ def compute_stresses(
1800
+ self,
1801
+ mesh: FEMesh,
1802
+ displacements: np.ndarray,
1803
+ material: Material,
1804
+ return_global: bool = False,
1805
+ ) -> Dict[str, Any]:
1806
+ self._unsupported("qualified_recovery")
1807
+
1808
+ def to_dict(self) -> Dict[str, Any]:
1809
+ self._unsupported("serialization")
1810
+
1811
+ @classmethod
1812
+ def from_dict(
1813
+ cls,
1814
+ payload: Mapping[str, Any],
1815
+ ) -> "StrictFlatLinearE4PLS3V2BShellElement":
1816
+ cls._unsupported("serialization")
1817
+
1818
+ def __getstate__(self) -> Dict[str, Any]:
1819
+ self._unsupported("restart")
1820
+
1821
+ def __setstate__(self, state: Mapping[str, Any]) -> None:
1822
+ self._unsupported("restart")
1823
+
1824
+ def __reduce_ex__(self, protocol: int) -> Any:
1825
+ self._unsupported("restart")
1826
+
1827
+ def __copy__(self) -> "StrictFlatLinearE4PLS3V2BShellElement":
1828
+ self._unsupported("restart")
1829
+
1830
+ def __deepcopy__(
1831
+ self, memo: Dict[int, Any]
1832
+ ) -> "StrictFlatLinearE4PLS3V2BShellElement":
1833
+ del memo
1834
+ self._unsupported("restart")
1835
+
1836
+
1837
+ # The live cache can be reached only through the reviewed public compute
1838
+ # wrapper installed above; its construction primitive is not a module surface.
1839
+ del _make_exact_component_compute_wrapper
1840
+
1841
+
1842
+ _ALLOWED_INHERITED_CALLABLES = frozenset(
1843
+ {
1844
+ "_get_element_displacements",
1845
+ "get_dof_mapping",
1846
+ "get_node_coordinates",
1847
+ }
1848
+ )
1849
+ _SEALED_INHERITED_CALLABLES = frozenset(
1850
+ {
1851
+ "_bending_compression_samples",
1852
+ "_build_drilling_b_matrix",
1853
+ "_build_shell_b_matrices",
1854
+ "_center_frame",
1855
+ "_compute_3node_shape_functions",
1856
+ "_compute_4node_shape_functions",
1857
+ "_compute_6node_shape_functions",
1858
+ "_compute_8node_shape_functions",
1859
+ "_compute_generalized_section_results",
1860
+ "_fallback_edge_direction",
1861
+ "_generalized_section_in_frame",
1862
+ "_generalized_section_nonlinear_response",
1863
+ "_hourglass_stabilization_matrix",
1864
+ "_local_dof_transform",
1865
+ "_local_frame_and_derivatives",
1866
+ "_material_angle",
1867
+ "_membrane_compression_from_state",
1868
+ "_membrane_compression_samples",
1869
+ "_mitc4_shear_b_matrix",
1870
+ "_mitc4_shear_samples",
1871
+ "_nonlinear_geometry",
1872
+ "_normalize",
1873
+ "_reference_center",
1874
+ "_resultant_samples",
1875
+ "_rigid_body_mode_matrix",
1876
+ "_stress_second_moment_samples",
1877
+ "_tri3_assumed_shear_b_matrix",
1878
+ "compute_jacobian",
1879
+ "compute_shape_functions",
1880
+ }
1881
+ )
1882
+
1883
+
1884
+ def _sealed_inherited_operator(name: str) -> Any:
1885
+ def sealed(self: StrictFlatLinearE4PLS3V2BShellElement, *args: Any, **kwargs: Any) -> Any:
1886
+ del args, kwargs
1887
+ self._unsupported(f"legacy_inherited_operator:{name}")
1888
+
1889
+ sealed.__name__ = name
1890
+ sealed.__qualname__ = f"StrictFlatLinearE4PLS3V2BShellElement.{name}"
1891
+ return sealed
1892
+
1893
+
1894
+ for _sealed_name in _SEALED_INHERITED_CALLABLES:
1895
+ setattr(
1896
+ StrictFlatLinearE4PLS3V2BShellElement,
1897
+ _sealed_name,
1898
+ _sealed_inherited_operator(_sealed_name),
1899
+ )
1900
+
1901
+
1902
+ type.__setattr__(
1903
+ StrictFlatLinearE4PLS3V2BShellElement,
1904
+ "_strict_flat_v2_class_frozen",
1905
+ True,
1906
+ )
1907
+ _initialize_final_class_authority(StrictFlatLinearE4PLS3V2BShellElement)
1908
+
1909
+
1910
+ __all__ = [
1911
+ "BLOCKED_OPERATIONS",
1912
+ "CBMIN3",
1913
+ "CAPABILITY_MATRIX",
1914
+ "DIRECTOR_POLICY_ID",
1915
+ "EQUATION_MAP_SHA256",
1916
+ "FORMULATION_ID",
1917
+ "FORMULATION_SCHEMA",
1918
+ "HAMMER_POINTS",
1919
+ "HAMMER_REFERENCE_WEIGHTS",
1920
+ "IMPLEMENTATION_ID",
1921
+ "PL_COMPLETION_POLICY_ID",
1922
+ "PRIMARY_SOURCE_SHA256",
1923
+ "QUADRATURE_AUTHORITY_ID",
1924
+ "RELAXATION_AUTHORITY_SHA256",
1925
+ "RESULTANT_POLICY_ID",
1926
+ "SECTION_POLICY_ID",
1927
+ "SELECTOR",
1928
+ "_ALLOWED_INHERITED_CALLABLES",
1929
+ "_SEALED_INHERITED_CALLABLES",
1930
+ "SHEAR_CORRECTION",
1931
+ "SOURCE_CONTRACT_SCHEMA",
1932
+ "SOURCE_CONTRACT_SHA256",
1933
+ "SUPPORTED_OPERATIONS",
1934
+ "StrictFlatLinearCapabilityError",
1935
+ "StrictFlatLinearE4PLS3V2BShellElement",
1936
+ ]