ANYsolver 0.1.2__tar.gz → 0.1.3__tar.gz

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 (158) hide show
  1. {anysolver-0.1.2 → anysolver-0.1.3}/CHANGELOG.md +19 -2
  2. {anysolver-0.1.2 → anysolver-0.1.3}/PKG-INFO +28 -3
  3. {anysolver-0.1.2 → anysolver-0.1.3}/README.md +35 -10
  4. {anysolver-0.1.2 → anysolver-0.1.3}/docs/ARCHITECTURE.md +41 -15
  5. {anysolver-0.1.2 → anysolver-0.1.3}/docs/QUALITY_CONTROL.md +11 -4
  6. {anysolver-0.1.2 → anysolver-0.1.3}/docs/THEORY.md +33 -13
  7. {anysolver-0.1.2 → anysolver-0.1.3}/pyproject.toml +1 -1
  8. {anysolver-0.1.2 → anysolver-0.1.3}/src/ANYsolver.egg-info/PKG-INFO +28 -3
  9. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/__init__.py +1 -1
  10. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/anystructure_fem_mode.py +72 -19
  11. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/recovery.py +137 -52
  12. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/runtime.py +219 -84
  13. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_fe_solver_anystructure_fem_mode.py +76 -1
  14. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_material_history_recovery.py +68 -1
  15. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_nonlinear_performance_batch_b.py +2 -1
  16. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_recovery_qualification.py +16 -0
  17. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_runtime_api.py +176 -1
  18. {anysolver-0.1.2 → anysolver-0.1.3}/LICENSE +0 -0
  19. {anysolver-0.1.2 → anysolver-0.1.3}/MANIFEST.in +0 -0
  20. {anysolver-0.1.2 → anysolver-0.1.3}/MIGRATION.md +0 -0
  21. {anysolver-0.1.2 → anysolver-0.1.3}/docs/ARC_LENGTH.md +0 -0
  22. {anysolver-0.1.2 → anysolver-0.1.3}/docs/NONLINEAR_PERFORMANCE.md +0 -0
  23. {anysolver-0.1.2 → anysolver-0.1.3}/docs/reference_cases/README.md +0 -0
  24. {anysolver-0.1.2 → anysolver-0.1.3}/scripts/benchmark_nonlinear_assembly.py +0 -0
  25. {anysolver-0.1.2 → anysolver-0.1.3}/scripts/compare_fe_baselines.py +0 -0
  26. {anysolver-0.1.2 → anysolver-0.1.3}/scripts/fetch_calculix_shell_reference.py +0 -0
  27. {anysolver-0.1.2 → anysolver-0.1.3}/scripts/generate_fe_baselines.py +0 -0
  28. {anysolver-0.1.2 → anysolver-0.1.3}/scripts/run_beam_shell_verification.py +0 -0
  29. {anysolver-0.1.2 → anysolver-0.1.3}/scripts/run_beam_validity.py +0 -0
  30. {anysolver-0.1.2 → anysolver-0.1.3}/scripts/run_buckling_validity.py +0 -0
  31. {anysolver-0.1.2 → anysolver-0.1.3}/scripts/run_capacity_workflow.py +0 -0
  32. {anysolver-0.1.2 → anysolver-0.1.3}/scripts/run_cylinder_benchmark.py +0 -0
  33. {anysolver-0.1.2 → anysolver-0.1.3}/scripts/run_element_qualification.py +0 -0
  34. {anysolver-0.1.2 → anysolver-0.1.3}/scripts/run_external_references.py +0 -0
  35. {anysolver-0.1.2 → anysolver-0.1.3}/scripts/run_fe_benchmarks.py +0 -0
  36. {anysolver-0.1.2 → anysolver-0.1.3}/scripts/run_fe_verification.py +0 -0
  37. {anysolver-0.1.2 → anysolver-0.1.3}/scripts/run_internal_shell_benchmark.py +0 -0
  38. {anysolver-0.1.2 → anysolver-0.1.3}/scripts/run_mass_modal_validity.py +0 -0
  39. {anysolver-0.1.2 → anysolver-0.1.3}/scripts/run_mesh_load_bc_verification.py +0 -0
  40. {anysolver-0.1.2 → anysolver-0.1.3}/scripts/run_plasticity_qualification.py +0 -0
  41. {anysolver-0.1.2 → anysolver-0.1.3}/scripts/run_recovery_policy.py +0 -0
  42. {anysolver-0.1.2 → anysolver-0.1.3}/scripts/run_s4_validity.py +0 -0
  43. {anysolver-0.1.2 → anysolver-0.1.3}/scripts/write_production_readiness.py +0 -0
  44. {anysolver-0.1.2 → anysolver-0.1.3}/setup.cfg +0 -0
  45. {anysolver-0.1.2 → anysolver-0.1.3}/src/ANYsolver.egg-info/SOURCES.txt +0 -0
  46. {anysolver-0.1.2 → anysolver-0.1.3}/src/ANYsolver.egg-info/dependency_links.txt +0 -0
  47. {anysolver-0.1.2 → anysolver-0.1.3}/src/ANYsolver.egg-info/requires.txt +0 -0
  48. {anysolver-0.1.2 → anysolver-0.1.3}/src/ANYsolver.egg-info/top_level.txt +0 -0
  49. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/arc_length.py +0 -0
  50. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/assembly.py +0 -0
  51. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/baselines.py +0 -0
  52. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/beam_shell_verification.py +0 -0
  53. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/beam_validity.py +0 -0
  54. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/benchmarks.py +0 -0
  55. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/boundary.py +0 -0
  56. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/buckling.py +0 -0
  57. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/buckling_validity.py +0 -0
  58. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/capacity_workflow.py +0 -0
  59. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/cases.py +0 -0
  60. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/composite_strip_verification.py +0 -0
  61. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/contact.py +0 -0
  62. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/corotational.py +0 -0
  63. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/cylinder_benchmarks.py +0 -0
  64. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/dynamics.py +0 -0
  65. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/element_qualification.py +0 -0
  66. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/elements.py +0 -0
  67. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/external_references.py +0 -0
  68. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/fe_core.py +0 -0
  69. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/fracture.py +0 -0
  70. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/imperfections.py +0 -0
  71. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/jit_compiler.py +0 -0
  72. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/kernel_warmup.py +0 -0
  73. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/linalg.py +0 -0
  74. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/mass_properties.py +0 -0
  75. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/material_curves.py +0 -0
  76. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/matrix_assembly.py +0 -0
  77. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/mesh_gen.py +0 -0
  78. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/mesh_load_bc_verification.py +0 -0
  79. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/modal.py +0 -0
  80. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/nonlinear.py +0 -0
  81. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/nonlinear_performance.py +0 -0
  82. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/nonlinear_performance_batch_b.py +0 -0
  83. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/nonlinear_performance_batch_c.py +0 -0
  84. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/nonlinear_performance_bootstrap.py +0 -0
  85. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/nonlinear_reduced_assembly.py +0 -0
  86. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/nonlinear_static.py +0 -0
  87. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/plasticity.py +0 -0
  88. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/plasticity_qualification.py +0 -0
  89. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/production_readiness.py +0 -0
  90. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/quality_control.py +0 -0
  91. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/recovery_policy.py +0 -0
  92. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/reference_cases.py +0 -0
  93. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/results.py +0 -0
  94. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/s4_validity.py +0 -0
  95. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/sesam_fem/__init__.py +0 -0
  96. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/sesam_fem/__main__.py +0 -0
  97. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/sesam_fem/diagnostics.py +0 -0
  98. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/sesam_fem/document.py +0 -0
  99. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/sesam_fem/exporter.py +0 -0
  100. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/sesam_fem/importer.py +0 -0
  101. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/sesam_fem/records.py +0 -0
  102. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/sesam_fem/schema.py +0 -0
  103. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/sesam_fem/sif_importer.py +0 -0
  104. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/sesam_fem/validation.py +0 -0
  105. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/shell_benchmarks.py +0 -0
  106. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/test_cases.py +0 -0
  107. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/validation.py +0 -0
  108. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/vectorized_nonlinear.py +0 -0
  109. {anysolver-0.1.2 → anysolver-0.1.3}/src/anysolver/vectorized_stiffness.py +0 -0
  110. {anysolver-0.1.2 → anysolver-0.1.3}/tests/conftest.py +0 -0
  111. {anysolver-0.1.2 → anysolver-0.1.3}/tests/fixtures/fe_baselines/baseline.json +0 -0
  112. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_arc_length.py +0 -0
  113. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_batch_b_activation.py +0 -0
  114. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_beam_axis_conventions.py +0 -0
  115. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_beam_shell_verification.py +0 -0
  116. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_corotational.py +0 -0
  117. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_external_references.py +0 -0
  118. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_fe_solver_architecture.py +0 -0
  119. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_fe_solver_buckling.py +0 -0
  120. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_fe_solver_capacity_workflow.py +0 -0
  121. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_fe_solver_contact.py +0 -0
  122. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_fe_solver_corotational_beam.py +0 -0
  123. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_fe_solver_cylinder_benchmarks.py +0 -0
  124. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_fe_solver_dynamics.py +0 -0
  125. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_fe_solver_element_qualification.py +0 -0
  126. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_fe_solver_element_quality.py +0 -0
  127. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_fe_solver_fracture.py +0 -0
  128. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_fe_solver_infrastructure.py +0 -0
  129. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_fe_solver_mass_modal.py +0 -0
  130. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_fe_solver_nonlinear_dnv.py +0 -0
  131. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_fe_solver_nonlinear_limit_point.py +0 -0
  132. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_fe_solver_nonlinear_static.py +0 -0
  133. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_fe_solver_plasticity_qualification.py +0 -0
  134. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_fe_solver_recovery_policy.py +0 -0
  135. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_fe_solver_reference_cases.py +0 -0
  136. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_fe_solver_s4_validity.py +0 -0
  137. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_fe_solver_shell_verification.py +0 -0
  138. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_fe_solver_theory.py +0 -0
  139. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_fe_solver_triangular_shell.py +0 -0
  140. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_fe_solver_triangular_shell_backend.py +0 -0
  141. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_follower_pressure.py +0 -0
  142. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_geometry_panel.py +0 -0
  143. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_hht_alpha.py +0 -0
  144. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_initial_fields_and_staged_history.py +0 -0
  145. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_local_patch_transition.py +0 -0
  146. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_mesh_load_bc_verification.py +0 -0
  147. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_mesher_improvements.py +0 -0
  148. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_nodal_stress_recovery.py +0 -0
  149. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_nonlinear_impact_plasticity.py +0 -0
  150. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_nonlinear_performance.py +0 -0
  151. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_nonlinear_performance_batch_c.py +0 -0
  152. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_performance_improvements.py +0 -0
  153. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_phase2.py +0 -0
  154. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_plane_stress_analytical_tangent.py +0 -0
  155. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_production_readiness.py +0 -0
  156. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_production_validation.py +0 -0
  157. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_quadratic_beam_nonlinear.py +0 -0
  158. {anysolver-0.1.2 → anysolver-0.1.3}/tests/test_sesam_fem.py +0 -0
@@ -2,6 +2,24 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.1.3 - 2026-07-28
6
+
7
+ - Complete the generated-geometry runtime bridge: apply configured shear force
8
+ and torsional moment, pass current-area follower pressure only to supported
9
+ nonlinear static/arc-length paths, retain the selected corotational
10
+ kinematics in arc length, and fail closed for incompatible follower paths.
11
+ Runtime prestress recovery now consumes matching committed nonlinear
12
+ histories and exposes Gauss-point membrane/bending resultants plus recovery
13
+ provenance.
14
+ - Correct nonlinear display recovery so plastic-history von Mises values use
15
+ only the return-mapped shell in-plane or beam-fiber components, while purely
16
+ elastic nonlinear states retain their full equivalent stress. Preserve
17
+ combinations with elastically reconstructed transverse shear/torsion as a
18
+ separately labelled model-scope diagnostic.
19
+ - Add the public `resolve_runtime_analysis()` contract so application GUIs can
20
+ reflect normalized nonlinear/material/control/kinematics selections without
21
+ importing private runtime helpers.
22
+
5
23
  ## 0.1.2 - 2026-07-28
6
24
 
7
25
  - Add opt-in executable CalculiX reference validation with isolated case runs,
@@ -34,8 +52,7 @@
34
52
  invalid-row fallback, add a safeguarded local consistency solve with
35
53
  fail-closed residual checks, and add constitutive and full-Newton
36
54
  parity/performance evidence.
37
-
38
- ## 0.1.1 - 2026-07-25
55
+ ## 0.1.1 - 2026-07-25
39
56
 
40
57
  - Correct the layered-shell membrane/bending coupling tangent and keep the
41
58
  accelerated plastic shell path consistent with the scalar return mapping.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ANYsolver
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Summary: Qualified beam and shell finite-element solver
5
5
  Author-email: Audun Arnesen Nyhus <audunarn@gmail.com>
6
6
  License-Expression: GPL-3.0-or-later
@@ -64,9 +64,27 @@ from anysolver import (
64
64
  run_generated_geometry_fem,
65
65
  solve_linear,
66
66
  )
67
- from anysolver.runtime import LightweightFEMConfig, run_production_fem
67
+ from anysolver.runtime import (
68
+ LightweightFEMConfig,
69
+ resolve_runtime_analysis,
70
+ run_production_fem,
71
+ )
68
72
  ```
69
73
 
74
+ The runtime facade applies its normalized axial force, bending moment, shear
75
+ force, torsional moment, and pressure inputs to the generated model. Set
76
+ `LightweightFEMConfig.follower_pressure=True` only for nonlinear static or
77
+ arc-length analysis using the `static only` or `nonlinear static` runtime
78
+ path; incompatible linear, stepwise eigenvalue-buckling, transient, collision,
79
+ and structured-capacity paths return an explicit `invalid_follower_pressure`
80
+ status. Arc length retains the requested von Karman or corotational
81
+ kinematics. Production runtime failures remain failures rather than being
82
+ replaced by an estimator.
83
+
84
+ Application integrations should use `resolve_runtime_analysis(config)` to
85
+ reflect the solver's effective nonlinear/material/control/kinematics choices;
86
+ the normalization helpers with leading underscores are implementation details.
87
+
70
88
  The generic `GeneratedGeometryFEM*` names are the preferred workflow API.
71
89
  Historical `AnyStructureFEM*` aliases remain available only for downstream
72
90
  compatibility. Material selection is centralized in
@@ -97,7 +115,7 @@ changes before making release claims.
97
115
  | Initial fields | Element-local shell membrane/bending stress or membrane/curvature prestrain, arbitrary configured beam-fiber stress/prestrain distributions, zero-external-load equilibration, admissibility checks, and provenance kept separate from geometric imperfections. |
98
116
  | Workflows | Normalized generated geometry to static/prestress/buckling; traceable static-to-buckling-to-imperfect nonlinear-capacity workflow. |
99
117
  | Interchange | Pure-Python SESAM formatted FEM record/document parsing, guarded round-trip writing, supported semantic import to `FEModel`, coordinate transforms, beam orientation, and SIF shell-stress reading by load case. |
100
- | Results | Result provenance; unified elastic or committed shell-layer/beam-fiber stress recovery; guarded Zienkiewicz-Zhu-style patch recovery for qualified shell neighborhoods; selected recovery; reaction filtering; validation diagnostics; deterministic baselines; benchmarks; and generated qualification reports. |
118
+ | Results | Result provenance; unified elastic or committed shell-layer/beam-fiber stress recovery; Gauss-point membrane-force and bending-moment resultants for generated-geometry prestress; guarded Zienkiewicz-Zhu-style patch recovery for qualified shell neighborhoods; selected recovery; reaction filtering; validation diagnostics; deterministic baselines; benchmarks; and generated qualification reports. |
101
119
  | External verification | Reproducible CalculiX input generation plus opt-in isolated execution, FRD/DAT parsing, solver provenance, and tolerance-controlled analytical comparison. Deck-only reports remain explicitly `not_executed` and make no numerical-agreement claim. |
102
120
 
103
121
  Implemented does not automatically mean qualified for every geometry or load
@@ -139,6 +157,13 @@ Important limits:
139
157
  - material-history-aware recovery requires retained, matching committed
140
158
  nonlinear layer/fiber states; missing or invalid state is reported and the
141
159
  affected components fall back explicitly to elastic reconstruction;
160
+ - with an active plastic constitutive history, `von_mises` covers the
161
+ return-mapped shell in-plane or beam-fiber stress components. Transverse
162
+ shell shear and beam shear/torsion remain elastic reconstructions and are
163
+ exposed separately through `mixed_reconstruction_von_mises`, rather than
164
+ being presented as a hardening-curve-consistent equivalent stress. A purely
165
+ elastic nonlinear state keeps the full mixed elastic value as its primary
166
+ equivalent stress;
142
167
  - the guarded patch-recovery fit is qualified only for locally planar,
143
168
  consistently oriented, homogeneous, full-integration Q4 or Q8 shell
144
169
  neighborhoods. Discontinuities remain separate, and the optional normalized
@@ -29,12 +29,30 @@ from anysolver import (
29
29
  run_generated_geometry_fem,
30
30
  solve_linear,
31
31
  )
32
- from anysolver.runtime import LightweightFEMConfig, run_production_fem
33
- ```
34
-
35
- The generic `GeneratedGeometryFEM*` names are the preferred workflow API.
36
- Historical `AnyStructureFEM*` aliases remain available only for downstream
37
- compatibility. Material selection is centralized in
32
+ from anysolver.runtime import (
33
+ LightweightFEMConfig,
34
+ resolve_runtime_analysis,
35
+ run_production_fem,
36
+ )
37
+ ```
38
+
39
+ The runtime facade applies its normalized axial force, bending moment, shear
40
+ force, torsional moment, and pressure inputs to the generated model. Set
41
+ `LightweightFEMConfig.follower_pressure=True` only for nonlinear static or
42
+ arc-length analysis using the `static only` or `nonlinear static` runtime
43
+ path; incompatible linear, stepwise eigenvalue-buckling, transient, collision,
44
+ and structured-capacity paths return an explicit `invalid_follower_pressure`
45
+ status. Arc length retains the requested von Karman or corotational
46
+ kinematics. Production runtime failures remain failures rather than being
47
+ replaced by an estimator.
48
+
49
+ Application integrations should use `resolve_runtime_analysis(config)` to
50
+ reflect the solver's effective nonlinear/material/control/kinematics choices;
51
+ the normalization helpers with leading underscores are implementation details.
52
+
53
+ The generic `GeneratedGeometryFEM*` names are the preferred workflow API.
54
+ Historical `AnyStructureFEM*` aliases remain available only for downstream
55
+ compatibility. Material selection is centralized in
38
56
  `dnv_c208_steel_properties()` and `dnv_c208_steel_curve()`; the runtime facade
39
57
  uses the same canonical table and validation.
40
58
 
@@ -62,7 +80,7 @@ changes before making release claims.
62
80
  | Initial fields | Element-local shell membrane/bending stress or membrane/curvature prestrain, arbitrary configured beam-fiber stress/prestrain distributions, zero-external-load equilibration, admissibility checks, and provenance kept separate from geometric imperfections. |
63
81
  | Workflows | Normalized generated geometry to static/prestress/buckling; traceable static-to-buckling-to-imperfect nonlinear-capacity workflow. |
64
82
  | Interchange | Pure-Python SESAM formatted FEM record/document parsing, guarded round-trip writing, supported semantic import to `FEModel`, coordinate transforms, beam orientation, and SIF shell-stress reading by load case. |
65
- | Results | Result provenance; unified elastic or committed shell-layer/beam-fiber stress recovery; guarded Zienkiewicz-Zhu-style patch recovery for qualified shell neighborhoods; selected recovery; reaction filtering; validation diagnostics; deterministic baselines; benchmarks; and generated qualification reports. |
83
+ | Results | Result provenance; unified elastic or committed shell-layer/beam-fiber stress recovery; Gauss-point membrane-force and bending-moment resultants for generated-geometry prestress; guarded Zienkiewicz-Zhu-style patch recovery for qualified shell neighborhoods; selected recovery; reaction filtering; validation diagnostics; deterministic baselines; benchmarks; and generated qualification reports. |
66
84
  | External verification | Reproducible CalculiX input generation plus opt-in isolated execution, FRD/DAT parsing, solver provenance, and tolerance-controlled analytical comparison. Deck-only reports remain explicitly `not_executed` and make no numerical-agreement claim. |
67
85
 
68
86
  Implemented does not automatically mean qualified for every geometry or load
@@ -101,9 +119,16 @@ Important limits:
101
119
  selected automatically for follower pressure, but its numerical
102
120
  frame-sensitivity evaluation is costlier than the rotated tangent used by
103
121
  default for ordinary corotational solves;
104
- - material-history-aware recovery requires retained, matching committed
105
- nonlinear layer/fiber states; missing or invalid state is reported and the
106
- affected components fall back explicitly to elastic reconstruction;
122
+ - material-history-aware recovery requires retained, matching committed
123
+ nonlinear layer/fiber states; missing or invalid state is reported and the
124
+ affected components fall back explicitly to elastic reconstruction;
125
+ - with an active plastic constitutive history, `von_mises` covers the
126
+ return-mapped shell in-plane or beam-fiber stress components. Transverse
127
+ shell shear and beam shear/torsion remain elastic reconstructions and are
128
+ exposed separately through `mixed_reconstruction_von_mises`, rather than
129
+ being presented as a hardening-curve-consistent equivalent stress. A purely
130
+ elastic nonlinear state keeps the full mixed elastic value as its primary
131
+ equivalent stress;
107
132
  - the guarded patch-recovery fit is qualified only for locally planar,
108
133
  consistently oriented, homogeneous, full-integration Q4 or Q8 shell
109
134
  neighborhoods. Discontinuities remain separate, and the optional normalized
@@ -177,12 +177,19 @@ persistent shell batches transport only ordinary constitutive history. This
177
177
  keeps field state and recovery exact while leaving the accelerated path
178
178
  unchanged for ordinary elements.
179
179
 
180
- Committed layered-shell and beam-fiber states are the preferred recovery
181
- source for nonlinear results. The unified recovery API ties those states to
182
- the matching displacement vector, records a component-level source and
183
- explicitly labels any elastic displacement-reconstruction fallback. In
184
- corotational analyses it uses the same objective pull-back and current element
185
- frame as force assembly.
180
+ Committed layered-shell and beam-fiber states are the preferred recovery
181
+ source for nonlinear results. The unified recovery API ties those states to
182
+ the matching displacement vector, records a component-level source and
183
+ explicitly labels any elastic displacement-reconstruction fallback. In
184
+ corotational analyses it uses the same objective pull-back and current element
185
+ frame as force assembly. With an active plastic constitutive history, the
186
+ material-history `von_mises` field is formed only from components governed by
187
+ the corresponding return map: shell in-plane layers or axial beam fibers. A
188
+ separately labelled `mixed_reconstruction_von_mises` diagnostic combines those
189
+ stresses with the matching elastic transverse-shear/torsion reconstruction
190
+ without implying that the mixed value was return-mapped or bounded by the
191
+ hardening curve. Committed states from purely elastic nonlinear analyses retain
192
+ the full mixed elastic value as primary `von_mises`.
186
193
 
187
194
  The optional Zienkiewicz--Zhu-style shell patch fit is deliberately narrow. It
188
195
  is qualified only for locally planar, consistently oriented, materially and
@@ -199,7 +206,7 @@ substep. It does not remove nodes, DOFs, or MPCs and is not crack mechanics.
199
206
  | Module | Responsibility |
200
207
  | --- | --- |
201
208
  | `anystructure_fem_mode.py` | Solver-owned generated-geometry workflow: normalize geometry, idealize tagged members, build the FE model/load, solve static response, recover prestress, and solve buckling. The filename is retained for source compatibility. |
202
- | `runtime.py` | Headless lightweight facade for normalized flat-panel/cylinder geometry, meshing, production solves, kernel warm-up, and typed runtime contracts. |
209
+ | `runtime.py` | Headless facade for normalized flat-panel/cylinder geometry, meshing, balanced generated axial/bending/shear/torsional loading, pressure/follower-pressure routing, production solves, kernel warm-up, and typed runtime contracts. |
203
210
  | `capacity_workflow.py` | Static solve -> prestress -> buckling -> stress-free imperfection -> nonlinear capacity. |
204
211
  | `sesam_fem/records.py` | Loss-aware sequential formatted-record parsing/writing. |
205
212
  | `sesam_fem/document.py` | Typed FEM document model, sections, transforms, loads, and preserved unknown records. |
@@ -207,10 +214,26 @@ substep. It does not remove nodes, DOFs, or MPCs and is not crack mechanics.
207
214
  | `sesam_fem/exporter.py` | Guarded document round-trip output; arbitrary `FEModel` semantic export is rejected. |
208
215
  | `sesam_fem/sif_importer.py` | Supported SIF result summaries and shell stress tensors with explicit load-case selection. |
209
216
 
210
- The generated-geometry mode does not infer arbitrary untagged surfaces into beams.
211
- Explicit line members are retained, while tagged member plates can be collapsed
212
- to equivalent beams. Disabling that idealization causes tagged member plates
213
- without matching beam members to fail closed, preventing double counting.
217
+ The generated-geometry mode does not infer arbitrary untagged surfaces into beams.
218
+ Explicit line members are retained, while tagged member plates can be collapsed
219
+ to equivalent beams. Disabling that idealization causes tagged member plates
220
+ without matching beam members to fail closed, preventing double counting.
221
+
222
+ The runtime facade is a production adapter, not a substitute solver. It applies
223
+ configured shear and torsion as balanced edge or ring loading and forwards
224
+ current-area pressure only when the selected path is nonlinear static or arc
225
+ length without a subsequent stepwise eigenvalue solve. Linear, stepwise
226
+ eigenvalue-buckling, transient, collision, and structured-capacity follower
227
+ requests fail with an explicit status. Arc length preserves the selected von
228
+ Karman or corotational kinematics. Downstream clients must preserve a
229
+ non-success status; they must not relabel a compact estimate as a successful
230
+ production solve.
231
+
232
+ Generated-geometry prestress recovery uses matching committed nonlinear states
233
+ when they are available. Shell buckling states retain the legacy mean membrane
234
+ resultants for compatibility and additionally carry membrane forces and bending
235
+ moments at each Gauss point. Recovery source, history use, warnings, and any
236
+ explicit elastic fallback are retained in result provenance.
214
237
 
215
238
  ### Public API boundaries
216
239
 
@@ -220,10 +243,13 @@ generated-geometry names `GeneratedGeometryFEMConfig`,
220
243
  `AnyStructureFEM*` names are compatibility aliases, not the preferred
221
244
  solver-owned vocabulary.
222
245
 
223
- `anysolver.runtime` defines an explicit `__all__` and typed
224
- `NormalizedGeometry`, `GeneratedGeometry`, and `StatusCallback` contracts.
225
- Downstream applications own state extraction, option mapping, UI, and plotting;
226
- they pass normalized data into this headless facade.
246
+ `anysolver.runtime` defines an explicit `__all__` and typed
247
+ `NormalizedGeometry`, `GeneratedGeometry`, `StatusCallback`, and
248
+ `RuntimeAnalysisSelection` contracts. Downstream applications own state
249
+ extraction, option mapping, UI, and plotting; they pass normalized data into
250
+ this headless facade. They use `resolve_runtime_analysis()` to reflect effective
251
+ solver selections instead of importing normalization helpers with leading
252
+ underscores.
227
253
 
228
254
  `dnv_c208_steel_properties()` is the single property-table entry point used by
229
255
  both the root analysis APIs and the runtime facade. This prevents grade and
@@ -69,9 +69,16 @@ Checks on 2026-07-28 against the `0.1.2` release-candidate source:
69
69
  shell initial-field equilibration, and retained a maximum analytical/oracle
70
70
  tangent error of `1.34e-9`.
71
71
 
72
- This evidence qualifies the `0.1.2` source. Distribution metadata, archive
73
- contents, and isolated-wheel execution are checked separately when the release
74
- artifacts are built; publishing remains a distinct, manually approved action.
72
+ This evidence qualified the then-current `0.1.2` source snapshot. Distribution
73
+ metadata, archive contents, and isolated-wheel execution are checked separately
74
+ when the release artifacts are built; publishing remains a distinct, manually
75
+ approved action.
76
+
77
+ The later generated-geometry runtime bridge follow-up (shear/torsion routing,
78
+ follower-pressure guards, corotational arc length, and committed-history
79
+ prestress resultants) is not represented by the numbered snapshot above until
80
+ the release verification and distribution checks are rerun against the final
81
+ source.
75
82
 
76
83
  ## Recorded 0.1.1 release evidence
77
84
 
@@ -216,7 +223,7 @@ deck-only artifact.
216
223
  | Nonlinear capacity | DNV curves, layered shell plasticity, beam fibers, von Karman/corotational paths, rotated/consistent corotational tangents, follower-pressure Newton and arc-length paths, load programs, displacement control, and imperfections. |
217
224
  | Transient/contact | Newmark/HHT-alpha, pressure patches, energy/impulse checks, shell/beam sphere contact, event subdivision, nonlinear impact, damage/erosion. |
218
225
  | Recovery/resources | Committed shell-layer/beam-fiber recovery, explicitly labelled elastic fallback, corotational objectivity, component provenance, guarded Q4/Q8 patch fits, discontinuity regions, selected components, deterministic threading, memory estimation/limits, and provenance. |
219
- | Workflows/interchange | Normalized generated geometry, capacity workflow, SESAM FEM round trip/import, transforms/orientation, and SIF load-case stress isolation. |
226
+ | Workflows/interchange | Normalized generated geometry; balanced axial/bending/shear/torsional runtime loads; guarded follower-pressure routing; corotational arc length; committed-history prestress with Gauss-point resultants and provenance; capacity workflow; SESAM FEM round trip/import; transforms/orientation; and SIF load-case stress isolation. |
220
227
  | Release scope | Stable verification IDs, PASS/XFAIL separation, production capability matrix, limitations, and evidence manifest. |
221
228
 
222
229
  ## Interpreting results
@@ -656,17 +656,24 @@ reported per element and per component, so a caller can distinguish
656
656
  `committed_shell_layer_state`, `committed_beam_fiber_state`, and explicitly
657
657
  labelled elastic fallback.
658
658
 
659
- For shells, committed return-mapped layer stresses are integrated with the
660
- same Gauss-Lobatto layer positions and weights used by the nonlinear
661
- formulation. The output includes membrane and bending stress measures, exact
662
- top/bottom layer values, and von Mises stress including the elastic transverse
663
- shear from the same solution. For fiber beams, the stored fiber coordinates,
664
- weights, and stations give axial force and biaxial bending resultants; the
665
- reported von Mises envelope also includes elastic shear and torsion. In
666
- corotational analyses, recovery uses the objective deformational pull-back,
667
- current coordinates, and current corotated frame. Material history can only be
668
- used when compatible committed states were retained; missing or invalid state
669
- is a visible elastic fallback, never a silent plastic-stress reconstruction.
659
+ For shells, committed return-mapped layer stresses are integrated with the
660
+ same Gauss-Lobatto layer positions and weights used by the nonlinear
661
+ formulation. The output includes membrane and bending stress measures, exact
662
+ top/bottom layer values, and an in-plane von Mises stress governed by the shell
663
+ return map. For fiber beams, the stored fiber coordinates, weights, and
664
+ stations give axial force and biaxial bending resultants; the material-history
665
+ von Mises envelope is the uniaxial fiber-stress envelope when a plastic
666
+ constitutive history is active. Transverse shell shear and beam shear/torsion
667
+ are matching elastic reconstructions rather than return-mapped state variables.
668
+ They remain available as individual components and in the explicitly labelled
669
+ `mixed_reconstruction_von_mises` diagnostic, but are not folded into the
670
+ hardening-curve-consistent `von_mises` field. A purely elastic nonlinear state
671
+ instead retains the full mixed elastic equivalent stress as primary. In
672
+ corotational analyses, recovery uses the objective deformational pull-back,
673
+ current coordinates, and current corotated frame. Material history can only
674
+ be used when compatible committed states were retained; missing or invalid
675
+ state is a visible elastic fallback, never a silent plastic-stress
676
+ reconstruction.
670
677
 
671
678
  Passing `PatchRecoveryConfig` enables a guarded linear least-squares,
672
679
  [Zienkiewicz-Zhu-style](https://doi.org/10.1002/nme.1620330702) shell surface
@@ -765,8 +772,21 @@ explicit backlog items, not current capabilities:
765
772
  midpoint/beam-axis penalty models as engineering approximations.
766
773
  5. Develop an equilibrated or compliance-weighted recovery estimator for
767
774
  adaptive refinement. The current guarded patch result and normalized
768
- stress-L2 discrepancy intentionally make no energy-norm or guaranteed-error
769
- claim.
775
+ stress-L2 discrepancy intentionally make no energy-norm or guaranteed-error
776
+ claim.
777
+ 6. Extend shell plasticity to transverse shear and beam-section plasticity to
778
+ shear/torsion interaction. Until then, large
779
+ `mixed_reconstruction_von_mises` values are model-scope warnings: the
780
+ underlying equilibrium used elastic shear/torsion and those components must
781
+ not be capped or described as plastically redistributed.
782
+ 7. Split shell patch-recovered nodal equivalent stress into the same
783
+ constitutive in-plane and explicitly mixed invariants used by element
784
+ recovery. The current patch tensor retains transverse shear and therefore
785
+ represents the mixed elastic/plastic diagnostic.
786
+ 8. Recover quadratic-beam shear and torsion at the same Gauss stations as each
787
+ fiber block before forming a mixed diagnostic. The current B3 diagnostic
788
+ combines station-dependent fiber stress with one element-level elastic
789
+ shear/torsion envelope; the constant-response B2 case is unaffected.
770
790
 
771
791
  ## Verification anchors
772
792
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "ANYsolver"
7
- version = "0.1.2"
7
+ version = "0.1.3"
8
8
  description = "Qualified beam and shell finite-element solver"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ANYsolver
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Summary: Qualified beam and shell finite-element solver
5
5
  Author-email: Audun Arnesen Nyhus <audunarn@gmail.com>
6
6
  License-Expression: GPL-3.0-or-later
@@ -64,9 +64,27 @@ from anysolver import (
64
64
  run_generated_geometry_fem,
65
65
  solve_linear,
66
66
  )
67
- from anysolver.runtime import LightweightFEMConfig, run_production_fem
67
+ from anysolver.runtime import (
68
+ LightweightFEMConfig,
69
+ resolve_runtime_analysis,
70
+ run_production_fem,
71
+ )
68
72
  ```
69
73
 
74
+ The runtime facade applies its normalized axial force, bending moment, shear
75
+ force, torsional moment, and pressure inputs to the generated model. Set
76
+ `LightweightFEMConfig.follower_pressure=True` only for nonlinear static or
77
+ arc-length analysis using the `static only` or `nonlinear static` runtime
78
+ path; incompatible linear, stepwise eigenvalue-buckling, transient, collision,
79
+ and structured-capacity paths return an explicit `invalid_follower_pressure`
80
+ status. Arc length retains the requested von Karman or corotational
81
+ kinematics. Production runtime failures remain failures rather than being
82
+ replaced by an estimator.
83
+
84
+ Application integrations should use `resolve_runtime_analysis(config)` to
85
+ reflect the solver's effective nonlinear/material/control/kinematics choices;
86
+ the normalization helpers with leading underscores are implementation details.
87
+
70
88
  The generic `GeneratedGeometryFEM*` names are the preferred workflow API.
71
89
  Historical `AnyStructureFEM*` aliases remain available only for downstream
72
90
  compatibility. Material selection is centralized in
@@ -97,7 +115,7 @@ changes before making release claims.
97
115
  | Initial fields | Element-local shell membrane/bending stress or membrane/curvature prestrain, arbitrary configured beam-fiber stress/prestrain distributions, zero-external-load equilibration, admissibility checks, and provenance kept separate from geometric imperfections. |
98
116
  | Workflows | Normalized generated geometry to static/prestress/buckling; traceable static-to-buckling-to-imperfect nonlinear-capacity workflow. |
99
117
  | Interchange | Pure-Python SESAM formatted FEM record/document parsing, guarded round-trip writing, supported semantic import to `FEModel`, coordinate transforms, beam orientation, and SIF shell-stress reading by load case. |
100
- | Results | Result provenance; unified elastic or committed shell-layer/beam-fiber stress recovery; guarded Zienkiewicz-Zhu-style patch recovery for qualified shell neighborhoods; selected recovery; reaction filtering; validation diagnostics; deterministic baselines; benchmarks; and generated qualification reports. |
118
+ | Results | Result provenance; unified elastic or committed shell-layer/beam-fiber stress recovery; Gauss-point membrane-force and bending-moment resultants for generated-geometry prestress; guarded Zienkiewicz-Zhu-style patch recovery for qualified shell neighborhoods; selected recovery; reaction filtering; validation diagnostics; deterministic baselines; benchmarks; and generated qualification reports. |
101
119
  | External verification | Reproducible CalculiX input generation plus opt-in isolated execution, FRD/DAT parsing, solver provenance, and tolerance-controlled analytical comparison. Deck-only reports remain explicitly `not_executed` and make no numerical-agreement claim. |
102
120
 
103
121
  Implemented does not automatically mean qualified for every geometry or load
@@ -139,6 +157,13 @@ Important limits:
139
157
  - material-history-aware recovery requires retained, matching committed
140
158
  nonlinear layer/fiber states; missing or invalid state is reported and the
141
159
  affected components fall back explicitly to elastic reconstruction;
160
+ - with an active plastic constitutive history, `von_mises` covers the
161
+ return-mapped shell in-plane or beam-fiber stress components. Transverse
162
+ shell shear and beam shear/torsion remain elastic reconstructions and are
163
+ exposed separately through `mixed_reconstruction_von_mises`, rather than
164
+ being presented as a hardening-curve-consistent equivalent stress. A purely
165
+ elastic nonlinear state keeps the full mixed elastic value as its primary
166
+ equivalent stress;
142
167
  - the guarded patch-recovery fit is qualified only for locally planar,
143
168
  consistently oriented, homogeneous, full-integration Q4 or Q8 shell
144
169
  neighborhoods. Discontinuities remain separate, and the optional normalized
@@ -355,7 +355,7 @@ from .sesam_fem import (
355
355
  write_sesam_fem_document,
356
356
  )
357
357
 
358
- __version__ = "0.1.2"
358
+ __version__ = "0.1.3"
359
359
 
360
360
  __all__ = [
361
361
  # Core classes
@@ -767,40 +767,93 @@ def build_symmetric_load_case(
767
767
  return load_case
768
768
 
769
769
 
770
- def recover_prestress_from_static_result(model: FEModel, displacements: np.ndarray) -> Tuple[Dict[int, Dict[str, float]], Dict[str, Any]]:
771
- """Recover element prestress states for buckling from a static solution."""
772
- states: Dict[int, Dict[str, float]] = {}
773
- stresses = compute_stresses(model, displacements)
770
+ def recover_prestress_from_static_result(
771
+ model: FEModel,
772
+ displacements: np.ndarray,
773
+ *,
774
+ nonlinear_result: Any = None,
775
+ ) -> Tuple[Dict[int, Dict[str, Any]], Dict[str, Any]]:
776
+ """Recover buckling prestress, retaining Gauss-point and material history.
777
+
778
+ Linear calls use displacement-based stress recovery. When a matching
779
+ nonlinear result is supplied, the unified recovery path reconstructs
780
+ stresses from committed shell-layer and beam-fiber states and records its
781
+ provenance.
782
+ """
783
+
784
+ states: Dict[int, Dict[str, Any]] = {}
785
+ recovery_provenance: Dict[str, Any] | None = None
786
+ if nonlinear_result is None:
787
+ stresses = compute_stresses(model, displacements)
788
+ else:
789
+ from .recovery import recover_stress_result
790
+
791
+ recovery = recover_stress_result(
792
+ model,
793
+ displacements,
794
+ nonlinear_result=nonlinear_result,
795
+ copy_committed_states=False,
796
+ )
797
+ stresses = recovery.element_stresses
798
+ recovery_provenance = recovery.provenance.to_dict()
774
799
  shell_count = 0
775
800
  beam_count = 0
776
801
  shell_compression = []
777
802
  beam_compression = []
778
803
  for element_id, element in model.mesh.elements.items():
779
- stress = stresses.get(element_id)
780
- if isinstance(element, ShellElement) and stress:
781
- sx = float(np.mean(stress.get("membrane_xx", np.zeros(1))))
782
- sy = float(np.mean(stress.get("membrane_yy", np.zeros(1))))
783
- txy = float(np.mean(stress.get("membrane_xy", np.zeros(1))))
784
- states[int(element_id)] = {
785
- "membrane_force_x": sx * element.thickness,
786
- "membrane_force_y": sy * element.thickness,
787
- "membrane_force_xy": txy * element.thickness,
788
- }
789
- shell_compression.append(max(-sx * element.thickness, -sy * element.thickness, 0.0))
804
+ stress = stresses.get(element_id)
805
+ if isinstance(element, ShellElement) and stress:
806
+ sx_gp = np.asarray(stress.get("membrane_xx", np.zeros(1)), dtype=float).reshape(-1)
807
+ sy_gp = np.asarray(stress.get("membrane_yy", np.zeros_like(sx_gp)), dtype=float).reshape(-1)
808
+ txy_gp = np.asarray(stress.get("membrane_xy", np.zeros_like(sx_gp)), dtype=float).reshape(-1)
809
+ if sy_gp.size != sx_gp.size or txy_gp.size != sx_gp.size:
810
+ raise ValueError("inconsistent shell membrane stress recovery shape")
811
+ bx_gp = np.asarray(stress.get("bending_xx", np.zeros_like(sx_gp)), dtype=float).reshape(-1)
812
+ by_gp = np.asarray(stress.get("bending_yy", np.zeros_like(sx_gp)), dtype=float).reshape(-1)
813
+ bxy_gp = np.asarray(stress.get("bending_xy", np.zeros_like(sx_gp)), dtype=float).reshape(-1)
814
+ if bx_gp.size != sx_gp.size or by_gp.size != sx_gp.size or bxy_gp.size != sx_gp.size:
815
+ raise ValueError("inconsistent shell bending stress recovery shape")
816
+
817
+ thickness = float(element.thickness)
818
+ membrane_resultants = np.column_stack((sx_gp, sy_gp, txy_gp)) * thickness
819
+ bending_resultants = (
820
+ np.column_stack((bx_gp, by_gp, bxy_gp))
821
+ * thickness
822
+ * thickness
823
+ / 6.0
824
+ )
825
+ sx = float(np.mean(sx_gp))
826
+ sy = float(np.mean(sy_gp))
827
+ txy = float(np.mean(txy_gp))
828
+ states[int(element_id)] = {
829
+ # Legacy mean resultants remain for serialized/downstream
830
+ # compatibility; the enhanced Mindlin operator consumes the
831
+ # Gauss-point fields below.
832
+ "membrane_force_x": sx * thickness,
833
+ "membrane_force_y": sy * thickness,
834
+ "membrane_force_xy": txy * thickness,
835
+ "membrane_forces_at_gauss": membrane_resultants.tolist(),
836
+ "bending_moments_at_gauss": bending_resultants.tolist(),
837
+ }
838
+ shell_compression.append(
839
+ float(max(np.max(-membrane_resultants[:, :2]), 0.0))
840
+ )
790
841
  shell_count += 1
791
842
  elif isinstance(element, (BeamElement, QuadraticBeamElement)) and stress:
792
843
  axial_force = float(stress.get("axial_stress", 0.0)) * float(getattr(element, "_A", 0.0))
793
844
  states[int(element_id)] = {"axial_force": axial_force}
794
845
  beam_compression.append(max(-axial_force, 0.0))
795
846
  beam_count += 1
796
- summary = {
847
+ summary = {
797
848
  "shell_elements": shell_count,
798
849
  "beam_elements": beam_count,
799
850
  "state_count": len(states),
800
851
  "max_shell_compression_resultant": float(max(shell_compression) if shell_compression else 0.0),
801
- "max_beam_compression_force": float(max(beam_compression) if beam_compression else 0.0),
802
- }
803
- return states, summary
852
+ "max_beam_compression_force": float(max(beam_compression) if beam_compression else 0.0),
853
+ }
854
+ if recovery_provenance is not None:
855
+ summary["stress_recovery"] = recovery_provenance
856
+ return states, summary
804
857
 
805
858
 
806
859
  def _stress_statistics(model: FEModel, displacements: np.ndarray, percentile: float) -> Dict[str, float]: