forked from 1b-agent/fieldcraft-upstream
tests: add the NAFEMS LE7 cylinder/sphere oracle case
The thin-walled cylinder with a hemispherical cap under internal pressure as four axisymmetric quad8 blocks: axial stress on the outer surface at D 25.283. The NAFEMS target, 25.86, is the axisymmetric thin-shell solution; our solid model converges to 25.27, the value ESRD reports for its converged axisymmetric solid. So the NAFEMS quantity keeps a 1% tolerance and is a known failure until there is an axisymmetric shell element, and a second quantity checks the model against the solid reference (pass, 0.05%). Part of #97.
This commit is contained in:
1 parent
65066b8451
commit
a8040063a6
6 files changed
+149
-2
No files matched your search
+1
-1
@@ -50,7 +50,7 @@ pressure) is a degree of freedom of the existing DOF framework, not a separate s
|
||||
| M21 Biomechanics and biomaterials | Soft tissue: Holzapfel–Gasser–Ogden fibre-reinforced hyperelasticity with dispersion, Fung, transversely isotropic models; biphasic and poro-hyperelastic cartilage (M19); active muscle (Hill-type); hydrogel swelling. Bone: density-dependent moduli from CT data, strain-energy-density remodelling (Huiskes, Beaupré). Growth and remodelling by kinematic growth (F = Fe·Fg). Implants and biomaterials (titanium, PEEK, UHMWPE) from the M17 library. Verified against published experiments with their tolerances | planned |
|
||||
| M22 Design studies | Parameters of the SolidCraft design driven from FieldCraft: parametric sweeps, design of experiments, response surfaces and sensitivities; topology optimisation (SIMP with filters, manufacturing constraints); size and shape optimisation; submodelling (driven boundaries from a global model); uncertainty quantification | planned |
|
||||
| M23 Wave propagation and ultrasound | Elastic, acoustic and coupled waves from the explicit solver's 1D bar today to guided and ultrasonic waves, by two methods. Finite differences first, for fast 2D (then 3D) ultrasound on regular grids: staggered-grid velocity–stress FDTD (Virieux) and the elastodynamic finite integration technique for solids, the rotated staggered grid for anisotropic media, a k-space pseudospectral scheme for weakly heterogeneous tissue and water, all on grids voxelised from the face-tagged geometry by the LBM's exact voxeliser, with heterogeneous, layered and fluid–solid media, CPML boundaries, threads and the GPU backend; staircased curved boundaries scatter spuriously, so the FD grid is checked against the finite elements on curved parts. Finite elements for curved geometry and coupling with structures: spectral elements (high-order Gauss–Lobatto–Legendre hexes with diagonal mass) on the hex meshes, and a mesh check in elements per wavelength with the dispersion error it implies; absorbing boundaries (convolutional PML, absorbing layers with increasing damping) and infinite media; tone-burst sources (Hann-windowed cycles), point, line and surface excitation, and piezoelectric transducers (M19); anisotropic media (composites, crystals) and viscoelastic, power-law-in-frequency attenuation; fluid–solid interfaces and fluid-loaded plates; ultrasound in water and tissue, nonlinear acoustics (Westervelt, KZK) for focused ultrasound. Guided waves: dispersion curves by semi-analytical finite elements (SAFE) for plates, pipes, rails and layered and anisotropic laminates — Lamb, Rayleigh, Love and SH modes — with phase and group velocities and mode shapes; mode-selective excitation. Output: A-scans and B-scans at sensors, wavefield snapshots, 2D FFT (frequency–wavenumber) for mode identification, and time–frequency diagrams of any signal — short-time Fourier spectrograms, continuous wavelet transforms (Morlet), reassigned spectrograms and smoothed pseudo Wigner–Ville — with the SAFE or Rayleigh–Lamb group-velocity curves overlaid as arrival times, and group velocities extracted from the ridges. GPU paths (M12's backend) for long runs. Verified by Lamb's problem (point load on a half-space), Rayleigh-wave speed, Rayleigh–Lamb dispersion, Love waves in a layer over a half-space, reflection and transmission at interfaces, and published guided-wave measurements | planned |
|
||||
| Continuous: verification and validation | Every capability checked against theory (closed forms), experiments (published measurements) and published benchmarks (NAFEMS, vendor benchmark and verification manuals such as Abaqus's), each case our own model in `tests/oracle/` with its cited reference and tolerance; `cargo xtask oracle` runs them and writes docs/oracle.md; once a case matches, our result is frozen as a fixture so fidelity cannot regress (docs/verification.md). Runner, fixtures and CI job: done; 62 theory cases (patch tests of every solid element, cantilevers, Lamé in 3D, plane strain and axisymmetric, Kirsch in 3D and plane stress, rotating disc and cylinder, beam frequencies, couplings, explicit waves, impact and J2 plasticity, CDT invariants), 11 published benchmarks (the MacNeal–Harder solid tests, the Scordelis–Lo roof with solids and with shells, the pinched cylinder, NAFEMS LE1 in 3D and 2D, LE10, FV32) and 8 pending cases with citations (the pinched hemisphere and twisted beam shell meshes, thermal, Cook's membrane, Taylor bar, CFD, explicit Hertz contact); `mesh.block` mapped blocks and 2D patches build their meshes, curved shell patches are written node by node | started |
|
||||
| Continuous: verification and validation | Every capability checked against theory (closed forms), experiments (published measurements) and published benchmarks (NAFEMS, vendor benchmark and verification manuals such as Abaqus's), each case our own model in `tests/oracle/` with its cited reference and tolerance; `cargo xtask oracle` runs them and writes docs/oracle.md; once a case matches, our result is frozen as a fixture so fidelity cannot regress (docs/verification.md). Runner, fixtures and CI job: done; 62 theory cases (patch tests of every solid element, cantilevers, Lamé in 3D, plane strain and axisymmetric, Kirsch in 3D and plane stress, rotating disc and cylinder, beam frequencies, couplings, explicit waves, impact and J2 plasticity, CDT invariants), 15 published benchmarks (the MacNeal–Harder solid tests, the Scordelis–Lo roof with solids and with shells, the pinched cylinder, NAFEMS LE1 in 3D and 2D, LE2, LE3, LE5, LE7, LE10, FV32) and 8 pending cases with citations (the pinched hemisphere and twisted beam shell meshes, thermal, Cook's membrane, Taylor bar, CFD, explicit Hertz contact); `mesh.block` mapped blocks and 2D patches build their meshes, curved shell patches are written node by node | started |
|
||||
| Continuous: performance | CPU first, deterministic: results never depend on the thread count (fixed partitions, sums in a fixed order; checked by hashing results on 1, 2 and 7 threads). Supernodal left-looking Cholesky (11–15× faster than the column solver on one thread), parallel element matrices, stresses and Lanczos products, explicit element updates and LBM cell blocks on rayon threads (done — `fieldcraft-parallel`, `threads` on the solve commands, `FIELDCRAFT_THREADS`); parallel forward/back substitution and explicit tet4 assembly; GPU paths later, within a stated tolerance of the CPU | started |
|
||||
| Continuous: desktop and agents | Desktop app (viewport, model tree, commands, control channel, the open design drawn, `ui.capture` of the whole window offscreen: done; toolbar of every capability from the catalogue, ready or coming soon with its milestone, icons drawn with VectorCraft, docs/features.md: done; the Craft-family shell — title bar, workspaces and ribbon drop-downs, browser, context panel, command search, journal timeline, light and dark themes — native file pickers with background opening, drag and drop and recent files, samples and one-click Solve, and an examples gallery of ready-to-solve samples, each checked by a test (docs/examples.md): done; MCP server over stdio, headless or bridged to the app, with read and write roots, docs/mcp.md: done; caps labels in Inter SemiBold; the README's analysis video recorded through MCP by `tools/demo-video`: done; support, load, reference-point and coupling symbols in the viewport and headless renders, with their browser toggles: done; symbols as wireframes, one mark per constrained degree of freedom, a constant size on screen with a size setting, highlighted with their selected definition, concentrated loads drawn over the part: done; selection by picking in the viewport — geometry faces, edges, vertices and bodies, mesh nodes, element faces and elements, box selection, hover, a Target row in command forms, `ui.select`/`ui.selection` and MCP `select`: done; a camera parameter for screenshots, a ribbon that follows the command being run: in progress; the browser build — the same app in a web page with browser file pickers, downloads, drops and autosave to browser storage, deployed to GitHub Pages from each release, docs/web.md: done; in-app updates — a daily check of GitHub Releases, Help › Check for Updates and Reinstall, downloads verified against the release key's signature of SHA256SUMS.txt and swapped in after closing, `app.update.check`, `fieldcraft-cli update`, Reload to update in the browser, docs/updates.md: done), command schema as the public API | started |
|
||||
|
||||
|
||||
+4
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
Generated by `cargo xtask oracle` from [`tests/oracle/`](../tests/oracle/); the policy is [verification.md](verification.md). Every case is our own model, built with FieldCraft commands from the problem's published description, and compared with the reference value its `expected.json` cites, within the stated tolerance and for the stated reason. Accepted results are frozen in each case's `fixture.json`: a later change that moves one beyond its band (10⁻⁹ of its size) fails CI even while the reference still passes. No reference value was produced with a commercial product.
|
||||
|
||||
**281 of 287 quantities pass** (6 known failure(s)) in 76 active cases: 62 theory, 14 published benchmark, 0 experiment; 8 pending cases wait for capabilities still being built.
|
||||
**282 of 289 quantities pass** (7 known failure(s)) in 77 active cases: 62 theory, 15 published benchmark, 0 experiment; 8 pending cases wait for capabilities still being built.
|
||||
|
||||
## Theory: closed-form solutions, patch tests and mesh invariants
|
||||
|
||||
@@ -297,6 +297,8 @@ Generated by `cargo xtask oracle` from [`tests/oracle/`](../tests/oracle/); the
|
||||
| [nafems-le2](../tests/oracle/nafems-le2/) | tangential stress at E, outer surface, load case 2 (pressure and edge traction) | 60 | 59.904 | -0.161% | 1% | pass | matches |
|
||||
| [nafems-le3](../tests/oracle/nafems-le3/) | radial displacement at A (10, 0, 0), m | 0.185 | 0.18418 | -0.446% | 2% | pass | matches |
|
||||
| [nafems-le5](../tests/oracle/nafems-le5/) | σ_xx at A (2.5, −1, −1), mid-surface of the lower flange at its free edge | -108 | -109.45 | -1.35% | 2% | pass | matches |
|
||||
| [nafems-le7](../tests/oracle/nafems-le7/) | axial stress σ_yy at D (1.0125, 1.4034), outer surface | 25.86 | 25.283 | -2.23% | 1% | known failure: the target is the axisymmetric thin-shell solution and FieldCraft has no axisymmetric shell element; our axisymmetric solid model converges to 25.27 (−2.3%), the value ESRD reports for its converged axisymmetric solid (quantity syy_D_solid) | — |
|
||||
| [nafems-le7](../tests/oracle/nafems-le7/) | axial stress σ_yy at D (1.0125, 1.4034), outer surface, against the converged solid model | 25.27 | 25.283 | 0.0496% | 1% | pass | matches |
|
||||
| [pinched-cylinder](../tests/oracle/pinched-cylinder/) | radial displacement under the load, mid-surface | -1.8248e-5 | -1.8038e-5 | 1.15% | 2% | pass | matches |
|
||||
| [scordelis-lo-roof-shell](../tests/oracle/scordelis-lo-roof-shell/) | vertical displacement at the midpoint of the free edge, mid-surface | -0.3024 | -0.29901 | 1.12% | 2% | pass | matches |
|
||||
| [scordelis-lo-roof-solid](../tests/oracle/scordelis-lo-roof-solid/) | vertical displacement at the midpoint of the free edge, mid-surface | -0.3024 | -0.3014 | 0.33% | 2% | pass | matches |
|
||||
@@ -342,6 +344,7 @@ Generated by `cargo xtask oracle` from [`tests/oracle/`](../tests/oracle/); the
|
||||
- **[nafems-le2](../tests/oracle/nafems-le2/)** (benchmark): NAFEMS LE2 cylindrical shell bending patch test (MITC4 shells). Source: NAFEMS, The Standard NAFEMS Benchmarks, TNSB Rev. 3, October 1990, test LE2 (target: tangential stress 60 MPa on the outer surface at E, both load cases); the problem and target as reproduced in the Abaqus 2016 Benchmarks Guide, section 4.2.2 'LE2: Cylindrical shell bending patch test', and in the ESRD StressCheck Benchmarks Guide 'The Standard NAFEMS Benchmarks: Linear Elastic Tests' (2018), p. 8. Tolerances — stt_E_moment: the target is the exact thin-shell value (6M/t²) and the stress is uniform over the patch; the 8 × 8 flat facets tilt the element axes by ±1.875° from the hoop direction, which moves 0.1% of it into σ_zz, and 16 × 16 is within 0.03% (see README); stt_E_pressure: the target is the exact membrane value (pR/t) and the stress is uniform over the patch; as in load case 1 the facets' tilt and the pressure on flat facets keep 8 × 8 within 0.2%, 16 × 16 within 0.05% (see README)
|
||||
- **[nafems-le3](../tests/oracle/nafems-le3/)** (benchmark): NAFEMS LE3 hemispherical shell with point loads (MITC4 shells). Source: NAFEMS, The Standard NAFEMS Benchmarks, TNSB Rev. 3, October 1990, test LE3 (target: radial displacement 0.185 m at A); the problem and target as reproduced in the Abaqus 2016 Benchmarks Guide, section 4.2.3 'LE3: Hemispherical shell with point loads', and in the ESRD StressCheck Benchmarks Guide 'The Standard NAFEMS Benchmarks: Linear Elastic Tests' (2018), p. 12. Tolerances — ur_A: the target is published to three figures; the displacement under a point load on a shear-deformable shell keeps growing slowly as the mesh is refined (32 × 32 is 0.44% low, 64 × 64 0.16%; see README)
|
||||
- **[nafems-le5](../tests/oracle/nafems-le5/)** (benchmark): NAFEMS LE5 Z-section cantilever (hex20). Source: NAFEMS, The Standard NAFEMS Benchmarks, TNSB Rev. 3, October 1990, test LE5 (target: axial stress −108 MPa at A, mid-surface); the problem and target as reproduced in the Abaqus 2016 Benchmarks Guide, section 4.2.5 'LE5: Z-section cantilever', and in the ESRD StressCheck Benchmarks Guide 'The Standard NAFEMS Benchmarks: Linear Elastic Tests' (2018), p. 15. Tolerances — sxx_A: the target is published to three figures and comes from a thin-walled idealisation; a 3D solid model of the section converges about 1.5% beyond it (ours: −109.46 here, −109.60 on the next mesh; ESRD's p-version solid: −109.5, see README)
|
||||
- **[nafems-le7](../tests/oracle/nafems-le7/)** (benchmark): NAFEMS LE7 axisymmetric cylinder/sphere under pressure (axisymmetric quad8). Source: NAFEMS, The Standard NAFEMS Benchmarks, TNSB Rev. 3, October 1990, test LE7 (target: axial stress 25.86 MPa on the outer surface at D, R = 1.0125, Z = 1.4034), as reproduced in the ESRD StressCheck Benchmarks Guide 'The Standard NAFEMS Benchmarks: Linear Elastic Tests' (2018), p. 23, which also gives its converged axisymmetric solid result, 25.27 MPa (p. 24); the Abaqus 2016 Benchmarks Guide, section 4.2.7 'LE7: Axisymmetric cylinder/sphere under pressure', gives the target rounded to 25.9 MPa. Tolerances — syy_D: the target is published to four figures for the thin-shell model of the vessel, and a model of the same theory converges well within 1%; syy_D_solid: the same model idealisation (axisymmetric solid) as the reference, which ESRD reports converged to under 1% on two meshes; ours moves by 0.05% on the next refinement (see README)
|
||||
- **[nl-contact-patch](../tests/oracle/nl-contact-patch/)** (theory): Contact patch test: two blocks with non-matching meshes in uniaxial compression (implicit mortar contact). Source: The contact patch test: a contact discretisation must transmit a uniform pressure across a non-matching interface exactly; Taylor & Papadopoulos, On a patch test for contact problems in two dimensions, Nonlinear Computational Mechanics, Springer 1991, 690–702; Crisfield, Re-visiting the contact patch test, IJNME 48:435–449, 2000; passed by mortar methods: Puso & Laursen, CMAME 193:601–629, 2004. Uniaxial stress between frictionless symmetry planes is uniform in both blocks. Tolerances — small_lower_corner: small sliding is linear and its mortar integrals exact on these rectangular faces: a uniform stress is the discrete solution up to the convergence tolerance (10⁻¹⁰); small_lower_centre: as for the corner element; small_lower_base: as for the corner element; small_upper_top: as for the corner element; small_lateral: frictionless symmetry planes and a frictionless interface leave the blocks free to expand sideways; the non-matching interface must not hold them; small_pressure: the mortar multipliers are the nodal values of the contact pressure, uniform and equal to the stress across the interface; small_force: the pressure carries the whole load across the interface; finite_lower_corner: finite sliding is exact up to the geometric terms of the gaps the augmentation leaves (10⁻⁵ of the element thickness) and the default convergence tolerances; finite_lower_centre: as for the corner element; finite_lower_base: as for the corner element; finite_upper_top: as for the corner element; finite_lateral: frictionless symmetry planes and a frictionless interface leave the blocks free to expand sideways; the non-matching interface must not hold them; finite_pressure: the mortar multipliers are the nodal values of the contact pressure, uniform and equal to the stress across the interface; finite_force: the pressure carries the whole load across the interface; small_stress: the squeeze less the penetration the augmented Lagrangian leaves (up to 10⁻⁵ of the element thickness, a few 10⁻⁵ of the squeeze)
|
||||
- **[nl-contact-patch-axisymmetric](../tests/oracle/nl-contact-patch-axisymmetric/)** (theory): Contact patch test, axisymmetric: two rings with non-matching edges in axial compression (implicit mortar contact). Source: The contact patch test: a contact discretisation must transmit a uniform pressure across a non-matching interface exactly; Taylor & Papadopoulos, On a patch test for contact problems in two dimensions, Nonlinear Computational Mechanics, Springer 1991, 690–702; passed by 2D mortar methods: Yang, Laursen & Meng, IJNME 62:1183–1225, 2005. Uniaxial stress between frictionless supports is uniform in both blocks. Tolerances — small_lower_corner: small sliding is linear and its edge mortar integrals exact (degree-3 Gauss on the overlaps): the uniform stress is the discrete solution up to the convergence tolerance; small_lower_far: as for the corner element; small_lower_base: as for the corner element; small_upper_top: as for the corner element; small_lateral: a frictionless interface (and symmetry plane) leaves the blocks free to expand sideways; the non-matching interface must not hold them; small_pressure: the mortar multipliers are the nodal values of the contact pressure, uniform and equal to the stress across the interface; small_force: the pressure carries the whole load across the interface (both are totals over the circumference); finite_lower_corner: finite sliding is exact up to the geometric terms of the gaps the augmentation leaves (10⁻⁵ of the element thickness) and the default convergence tolerances; finite_lower_far: as for the corner element; finite_lower_base: as for the corner element; finite_upper_top: as for the corner element; finite_lateral: a frictionless interface (and symmetry plane) leaves the blocks free to expand sideways; the non-matching interface must not hold them; finite_pressure: the mortar multipliers are the nodal values of the contact pressure, uniform and equal to the stress across the interface; finite_force: the pressure carries the whole load across the interface (both are totals over the circumference); small_stress: the squeeze less the penetration the augmented Lagrangian leaves (up to 10⁻⁵ of the element thickness)
|
||||
- **[nl-contact-patch-plane-strain](../tests/oracle/nl-contact-patch-plane-strain/)** (theory): Contact patch test in plane strain: two blocks with non-matching edges in uniaxial compression (implicit mortar contact). Source: The contact patch test: a contact discretisation must transmit a uniform pressure across a non-matching interface exactly; Taylor & Papadopoulos, On a patch test for contact problems in two dimensions, Nonlinear Computational Mechanics, Springer 1991, 690–702; passed by 2D mortar methods: Yang, Laursen & Meng, IJNME 62:1183–1225, 2005. Uniaxial stress between frictionless supports is uniform in both blocks. Tolerances — small_lower_corner: small sliding is linear and its edge mortar integrals exact (degree-3 Gauss on the overlaps): the uniform stress is the discrete solution up to the convergence tolerance; small_lower_far: as for the corner element; small_lower_base: as for the corner element; small_upper_top: as for the corner element; small_lateral: a frictionless interface (and symmetry plane) leaves the blocks free to expand sideways; the non-matching interface must not hold them; small_pressure: the mortar multipliers are the nodal values of the contact pressure, uniform and equal to the stress across the interface; small_force: the pressure carries the whole load across the interface (both are totals over the thickness); finite_lower_corner: finite sliding is exact up to the geometric terms of the gaps the augmentation leaves (10⁻⁵ of the element thickness) and the default convergence tolerances; finite_lower_far: as for the corner element; finite_lower_base: as for the corner element; finite_upper_top: as for the corner element; finite_lateral: a frictionless interface (and symmetry plane) leaves the blocks free to expand sideways; the non-matching interface must not hold them; finite_pressure: the mortar multipliers are the nodal values of the contact pressure, uniform and equal to the stress across the interface; finite_force: the pressure carries the whole load across the interface (both are totals over the thickness); small_stress: the squeeze less the penetration the augmented Lagrangian leaves (up to 10⁻⁵ of the element thickness)
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
# NAFEMS LE7 axisymmetric cylinder/sphere under pressure (axisymmetric quad8)
|
||||
|
||||
Our model of the published problem: a thin-walled vessel, a cylinder closed by a hemispherical
|
||||
cap, of mid-surface radius 1 m and wall thickness 0.025 m, E = 210 GPa, ν = 0.3 (m, MN, MPa),
|
||||
under an internal pressure of 1 MPa. In FieldCraft's axisymmetric models x is the radius and y the
|
||||
axis. The cylinder runs from F (y = 0) to the junction C (y = 1.5), the cap from C to the pole A
|
||||
(y = 2.5). The axial displacement is zero at F (the vessel's plane of symmetry: the whole bottom
|
||||
edge) and the radial one at A (the pole edge, on the axis). The target is the axial stress σ_yy
|
||||
on the outer surface at D (R = 1.0125, y = 1.4034), 0.0966 m below the junction, inside the
|
||||
bending boundary layer the cap's different stiffness causes.
|
||||
|
||||
## The mesh
|
||||
|
||||
Four `mesh.block` quad8 patches through the wall thickness: three cylinder blocks with E
|
||||
(y = 1.1136) and D as block corners, so D is a node, and the cap, a quarter ring whose two curved
|
||||
edges are arcs about (0, 1.5) and whose fourth edge lies on the axis. 2 elements through the
|
||||
wall, about 50 per metre along it (56, 14 and 5 in the cylinder blocks, 79 round the cap); the
|
||||
blocks share their edges, so `mesh.block` joins them. The pressure acts on the inner edges of all
|
||||
four blocks.
|
||||
|
||||
The recipe was generated with this script (`python3 le7.py 2 50 > recipe.json`):
|
||||
|
||||
```python
|
||||
import json, math, sys
|
||||
|
||||
def le7(nt, per_m):
|
||||
"""NAFEMS LE7 cylinder with a hemispherical cap, axisymmetric (m, MN, MPa): x is the radius,
|
||||
y the axis. Mid-surface radius 1, wall 0.025 thick; the cylinder runs from F (y = 0, the plane
|
||||
of symmetry) to C (y = 1.5), the cap from C to the pole A (y = 2.5). nt elements through the
|
||||
wall, about per_m elements per metre along it."""
|
||||
ri, ro = 1 - 0.0125, 1 + 0.0125
|
||||
cuts = [0.0, 1.1136, 1.4034, 1.5] # F, E, D, C: E and D are nodes
|
||||
along = lambda length: max(1, round(length * per_m))
|
||||
commands = []
|
||||
for k, (y0, y1) in enumerate(zip(cuts, cuts[1:])):
|
||||
commands.append({"command": "mesh.block", "params": {"body": f"cylinder_{k + 1}", "kind": "quad8",
|
||||
"corners": [[ri, y0, 0], [ro, y0, 0], [ro, y1, 0], [ri, y1, 0]], "divisions": [nt, along(y1 - y0)],
|
||||
"edges": [{"corners": [1, 4], "name": "inside"}, {"corners": [1, 2], "name": "bottom"}]}})
|
||||
commands.append({"command": "mesh.block", "params": {"body": "cap", "kind": "quad8",
|
||||
"corners": [[ri, 1.5, 0], [ro, 1.5, 0], [0, 1.5 + ro, 0], [0, 1.5 + ri, 0]], "divisions": [nt, along(math.pi / 2)],
|
||||
"edges": [{"corners": [2, 3], "arc": {"center": [0, 1.5, 0]}}, {"corners": [4, 1], "arc": {"center": [0, 1.5, 0]}, "name": "inside"},
|
||||
{"corners": [3, 4], "name": "pole"}]}})
|
||||
bodies = ["cylinder_1", "cylinder_2", "cylinder_3", "cap"]
|
||||
return commands + [
|
||||
{"command": "model.set.create", "params": {"name": "all", "geometry": [{"body": b, "face": "area"} for b in bodies]}},
|
||||
{"command": "model.set.create", "params": {"name": "inside", "geometry": [{"body": b, "edge": "inside"} for b in bodies]}},
|
||||
{"command": "model.set.create", "params": {"name": "F", "geometry": [{"body": "cylinder_1", "edge": "bottom"}]}},
|
||||
{"command": "model.set.create", "params": {"name": "A", "geometry": [{"body": "cap", "edge": "pole"}]}},
|
||||
{"command": "model.material.create", "params": {"name": "Steel", "elastic": {"type": "isotropic", "young": 210000.0, "poisson": 0.3}}},
|
||||
{"command": "model.section.create", "params": {"name": "vessel", "set": "all", "material": "Steel", "kind": {"type": "axisymmetric"}}},
|
||||
{"command": "model.boundary_condition.create", "params": {"name": "F", "type": "symmetry", "target": {"set": "F"}, "plane": "y"}},
|
||||
{"command": "model.boundary_condition.create", "params": {"name": "A", "type": "symmetry", "target": {"set": "A"}, "plane": "x"}},
|
||||
{"command": "model.load.create", "params": {"name": "pressure", "type": "pressure", "set": "inside", "magnitude": 1.0}},
|
||||
{"command": "model.step.create", "params": {"name": "Pressure", "procedure": {"type": "static"}, "boundary_conditions": ["F", "A"], "loads": ["pressure"]}},
|
||||
{"command": "solve.static", "params": {}, "id": "solve"},
|
||||
]
|
||||
|
||||
nt, per_m = (int(a) for a in sys.argv[1:3]) if len(sys.argv) > 2 else (2, 50)
|
||||
print("[\n " + ",\n ".join(json.dumps(c) for c in le7(nt, per_m)) + "\n]")
|
||||
```
|
||||
|
||||
## Refinement
|
||||
|
||||
Every row is the listing above with the row's divisions, solved and probed at D as the case does;
|
||||
the case mesh is 2 × 50:
|
||||
|
||||
| through the wall × per metre | σ_yy at D | against 25.86 | against 25.27 |
|
||||
|---|---|---|---|
|
||||
| 2 × 25 | 25.331 | −2.05% | +0.24% |
|
||||
| 2 × 50 (this case) | 25.283 | −2.23% | +0.05% |
|
||||
| 4 × 100 | 25.271 | −2.28% | +0.00% |
|
||||
| 8 × 200 | 25.269 | −2.29% | −0.00% |
|
||||
|
||||
Far from the junction the model is exact: at F the axial stress on the outer surface is 19.503
|
||||
(p r_i²/(r_o² − r_i²)) and the hoop stress 39.006 (Lamé).
|
||||
|
||||
## Two references, one known failure
|
||||
|
||||
The published target, 25.86, comes from axisymmetric thin-shell theory. The ESRD guide solves the
|
||||
same problem with axisymmetric solid elements and reports 25.27 on two meshes, 2.3% below the
|
||||
target, and our solid model converges to the same 25.27: the difference is the model, not the
|
||||
mesh. So the case keeps the NAFEMS target with the
|
||||
tolerance a shell model would earn, 1%, marked `known_failure` until FieldCraft has an
|
||||
axisymmetric shell element, and checks the solid model against the solid reference, also at 1%.
|
||||
|
||||
`fixture.json` holds the passing quantity's 2 × 50 value: the mesh is built by `mesh.block` from
|
||||
the recipe's corners, so it is the same on every platform.
|
||||
|
||||
## Running it
|
||||
|
||||
```sh
|
||||
cargo xtask oracle --case nafems-le7
|
||||
cargo xtask oracle --bless nafems-le7 # only after the case passes
|
||||
```
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"title": "NAFEMS LE7 axisymmetric cylinder/sphere under pressure (axisymmetric quad8)",
|
||||
"kind": "benchmark",
|
||||
"source": "NAFEMS, The Standard NAFEMS Benchmarks, TNSB Rev. 3, October 1990, test LE7 (target: axial stress 25.86 MPa on the outer surface at D, R = 1.0125, Z = 1.4034), as reproduced in the ESRD StressCheck Benchmarks Guide 'The Standard NAFEMS Benchmarks: Linear Elastic Tests' (2018), p. 23, which also gives its converged axisymmetric solid result, 25.27 MPa (p. 24); the Abaqus 2016 Benchmarks Guide, section 4.2.7 'LE7: Axisymmetric cylinder/sphere under pressure', gives the target rounded to 25.9 MPa",
|
||||
"quantities": [
|
||||
{
|
||||
"id": "syy_D",
|
||||
"quantity": "axial stress σ_yy at D (1.0125, 1.4034), outer surface",
|
||||
"measure": {"command": "solve.probe", "params": {"step": "Pressure", "at": [[1.0125, 1.4034, 0]]}, "pointer": "/nodes/0/stress/1"},
|
||||
"value": 25.86,
|
||||
"tolerance": {"relative": 0.01},
|
||||
"reason": "the target is published to four figures for the thin-shell model of the vessel, and a model of the same theory converges well within 1%",
|
||||
"known_failure": "the target is the axisymmetric thin-shell solution and FieldCraft has no axisymmetric shell element; our axisymmetric solid model converges to 25.27 (−2.3%), the value ESRD reports for its converged axisymmetric solid (quantity syy_D_solid)"
|
||||
},
|
||||
{
|
||||
"id": "syy_D_solid",
|
||||
"quantity": "axial stress σ_yy at D (1.0125, 1.4034), outer surface, against the converged solid model",
|
||||
"measure": {"command": "solve.probe", "params": {"step": "Pressure", "at": [[1.0125, 1.4034, 0]]}, "pointer": "/nodes/0/stress/1"},
|
||||
"value": 25.27,
|
||||
"tolerance": {"relative": 0.01},
|
||||
"reason": "the same model idealisation (axisymmetric solid) as the reference, which ESRD reports converged to under 1% on two meshes; ours moves by 0.05% on the next refinement (see README)"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"note": "FieldCraft's accepted results for this case, written by `cargo xtask oracle --bless`. A result outside its band fails CI.",
|
||||
"values": {
|
||||
"syy_D_solid": {
|
||||
"band": 2.5282545696283336e-8,
|
||||
"value": 25.282545696283336
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
[
|
||||
{"command": "mesh.block", "params": {"body": "cylinder_1", "kind": "quad8", "corners": [[0.9875, 0.0, 0], [1.0125, 0.0, 0], [1.0125, 1.1136, 0], [0.9875, 1.1136, 0]], "divisions": [2, 56], "edges": [{"corners": [1, 4], "name": "inside"}, {"corners": [1, 2], "name": "bottom"}]}},
|
||||
{"command": "mesh.block", "params": {"body": "cylinder_2", "kind": "quad8", "corners": [[0.9875, 1.1136, 0], [1.0125, 1.1136, 0], [1.0125, 1.4034, 0], [0.9875, 1.4034, 0]], "divisions": [2, 14], "edges": [{"corners": [1, 4], "name": "inside"}, {"corners": [1, 2], "name": "bottom"}]}},
|
||||
{"command": "mesh.block", "params": {"body": "cylinder_3", "kind": "quad8", "corners": [[0.9875, 1.4034, 0], [1.0125, 1.4034, 0], [1.0125, 1.5, 0], [0.9875, 1.5, 0]], "divisions": [2, 5], "edges": [{"corners": [1, 4], "name": "inside"}, {"corners": [1, 2], "name": "bottom"}]}},
|
||||
{"command": "mesh.block", "params": {"body": "cap", "kind": "quad8", "corners": [[0.9875, 1.5, 0], [1.0125, 1.5, 0], [0, 2.5125, 0], [0, 2.4875, 0]], "divisions": [2, 79], "edges": [{"corners": [2, 3], "arc": {"center": [0, 1.5, 0]}}, {"corners": [4, 1], "arc": {"center": [0, 1.5, 0]}, "name": "inside"}, {"corners": [3, 4], "name": "pole"}]}},
|
||||
{"command": "model.set.create", "params": {"name": "all", "geometry": [{"body": "cylinder_1", "face": "area"}, {"body": "cylinder_2", "face": "area"}, {"body": "cylinder_3", "face": "area"}, {"body": "cap", "face": "area"}]}},
|
||||
{"command": "model.set.create", "params": {"name": "inside", "geometry": [{"body": "cylinder_1", "edge": "inside"}, {"body": "cylinder_2", "edge": "inside"}, {"body": "cylinder_3", "edge": "inside"}, {"body": "cap", "edge": "inside"}]}},
|
||||
{"command": "model.set.create", "params": {"name": "F", "geometry": [{"body": "cylinder_1", "edge": "bottom"}]}},
|
||||
{"command": "model.set.create", "params": {"name": "A", "geometry": [{"body": "cap", "edge": "pole"}]}},
|
||||
{"command": "model.material.create", "params": {"name": "Steel", "elastic": {"type": "isotropic", "young": 210000.0, "poisson": 0.3}}},
|
||||
{"command": "model.section.create", "params": {"name": "vessel", "set": "all", "material": "Steel", "kind": {"type": "axisymmetric"}}},
|
||||
{"command": "model.boundary_condition.create", "params": {"name": "F", "type": "symmetry", "target": {"set": "F"}, "plane": "y"}},
|
||||
{"command": "model.boundary_condition.create", "params": {"name": "A", "type": "symmetry", "target": {"set": "A"}, "plane": "x"}},
|
||||
{"command": "model.load.create", "params": {"name": "pressure", "type": "pressure", "set": "inside", "magnitude": 1.0}},
|
||||
{"command": "model.step.create", "params": {"name": "Pressure", "procedure": {"type": "static"}, "boundary_conditions": ["F", "A"], "loads": ["pressure"]}},
|
||||
{"command": "solve.static", "params": {}, "id": "solve"}
|
||||
]
|
||||
Reference in new issue
Block a user