diff --git a/ROADMAP.md b/ROADMAP.md index 78cec25..78fa652 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -41,7 +41,7 @@ pressure) is a degree of freedom of the existing DOF framework, not a separate s | M12 CFD: lattice Boltzmann | D3Q19/D3Q27 on grids voxelised from the face-tagged surface; TRT, regularised and cumulant collision; interpolated walls, inlets and outlets; LES (Smagorinsky, WALE) with wall models; thermal LBM and conjugate heat transfer with the structure's thermal solver; non-Newtonian viscosity (power-law, Carreau–Yasuda, Cross, Herschel–Bulkley, Bingham) and temperature-dependent viscosity; porous media (Brinkman, Darcy–Forchheimer); multiphase and free surface (M13); validation by the lid-driven cavity, backward-facing step, cylinder wake (Strouhal) and turbulent channel; octree refinement shared with the hex mesher; wgpu backend (deterministic per device, checked against the CPU) (CPU core: done — `fieldcraft-lbm` with D3Q19 TRT and Guo forcing, halfway bounce-back and moving walls, slip and periodic faces, Zou–He velocity and pressure faces, exact voxelisation of obstacle bodies, momentum-exchange forces per face; fluid materials, fluid domains and fluid steps in the model; `model.fluid_domain.*`, `solve.fluid`; verified by Poiseuille channel and pipe, Couette, Taylor–Green decay, sphere-array Stokes drag and mass conservation; Schäfer–Turek 2D-1 as a benchmark) | started | | M13 Fluid–structure interaction | Immersed-boundary coupling of the lattice Boltzmann fluid with the explicit or implicit structure; interface force transfer; sub-cycling; Aitken then interface quasi-Newton coupling; free-surface flow | planned | | M14 Blast and impact fluids | EOS-driven fluids in the explicit solver: ALE multi-material or SPH, with fluid–structure contact | planned | -| M15 Nonlinear implicit core | Newton–Raphson with line search, automatic increments and cutbacks, convergence on force, displacement and energy; geometric nonlinearity (total and updated Lagrangian, large rotations for shells and beams, follower pressure); every `fem` material behind one interface with its consistent tangent (plasticity, damage and thermal strain from the explicit solver reused implicitly); arc-length (Riks) for snap-through; linear buckling (eigen) with preload stress stiffening, and imperfections from buckling modes; nonlinear stabilisation; restart. Verified by the elastica, Lee's frame, the snap-through arch, the hinged cylindrical shell and plastic collapse loads | planned | +| M15 Nonlinear implicit core | Newton–Raphson with line search, automatic increments and cutbacks, convergence on force, displacement and energy; geometric nonlinearity (total and updated Lagrangian, large rotations for shells and beams, follower pressure); every `fem` material behind one interface with its consistent tangent (plasticity, damage and thermal strain from the explicit solver reused implicitly); arc-length (Riks) for snap-through; linear buckling (eigen) with preload stress stiffening, and imperfections from buckling modes; nonlinear stabilisation; restart. Verified by the elastica, Lee's frame, the snap-through arch, the hinged cylindrical shell and plastic collapse loads (solids core: done — `nonlinear_static` steps with automatic increments and cutbacks, Newton–Raphson with the consistent tangent, force, displacement and energy convergence and an optional line search; a material point interface (Kirchhoff stress and spatial tangent from F, with history) with St Venant–Kirchhoff and compressible neo-Hookean; total Lagrangian tet4, tet10, wedge6, hex8, hex20 (full and reduced), hybrid hex8/hex20/tet10 by the three-field mixed form, plane strain and axisymmetric elements; follower pressure with its symmetrised load stiffness; Cauchy stress and logarithmic strain, increment history and frames, `solve.nonlinear`; Abaqus and LS-DYNA decks; verified by the patch and objectivity tests, uniaxial stretch, the elastica and tube inflation by a follower pressure (finite-strain Cook's membrane pending its transcribed reference). Next: J2 plasticity and Mooney–Rivlin on the interface, thermal strain, incompatible modes (EAS), shells and beams, arc-length) | started | | M16 Structural dynamics | Implicit transient (Newmark, HHT-α, generalised-α); modal superposition transient; steady-state harmonic (direct and modal), with Rayleigh, modal, structural and material damping; random vibration from PSDs and response spectrum (SRSS, CQC); complex eigenvalues with damping; rotating machinery (Campbell diagrams, gyroscopic terms); substructures (Craig–Bampton) | planned | | M17 Constitutive library and material library | Elastic: transversely isotropic, fully anisotropic (21 constants), temperature-dependent. Elastomers: hyperelastic neo-Hookean, Mooney–Rivlin, Yeoh, Ogden, Arruda–Boyce, Gent, Marlow, with Mullins softening and finite-strain viscoelasticity (Prony series; parallel networks after Bergström–Boyce), foams. Viscoelasticity: small- and finite-strain Prony series, time–temperature superposition (WLF, Arrhenius), storage and loss moduli for harmonic steps. Viscoplasticity and creep: Norton power law, time and strain hardening, Perzyna, Anand, Chaboche combined hardening. Plasticity: Hill anisotropic, Drucker–Prager, Mohr–Coulomb, Cam-clay, crushable foam, concrete damaged plasticity, Gurson. Fluids: Newtonian and non-Newtonian viscosity shared with M12. Material library: curated, cited data sets (steels, aluminium and titanium alloys, polymers, elastomers, composites, tissues) with units and temperature dependence; calibration from test data (uniaxial, biaxial, shear, relaxation, DMA) by least squares with Drucker stability checks; user materials as a safe Rust trait | planned | | M18 Composites and anisotropy | Material orientations (rectangular, cylindrical, spherical, from geometry edges and faces, per-element fields, draping of fibres over curved parts); layups on shells and continuum shells, ply stacks on swept hex; classical lamination theory checks; ply stresses and strains through the thickness; failure indices (Tsai–Wu, Tsai–Hill, Hashin, Puck, LaRC) and progressive damage; homogenisation (rule of mixtures, Mori–Tanaka, RVEs with periodic boundary conditions); delamination through M20's cohesive zones. Verified by laminate closed forms and the NAFEMS composite benchmarks | planned | @@ -67,7 +67,8 @@ In progress, in this order of landing: 4. A Scordelis–Lo refinement study (32×32×2, 64×64×4, hex20 full and reduced) separating discretisation error from the solid-versus-shell model difference (−0.33 % today). 5. The nonlinear implicit core (M15), the gate for contact (M7), elastomers and viscoelasticity - (M17), composite failure (M18), adhesion (M20) and tissues (M21). + (M17), composite failure (M18), adhesion (M20) and tissues (M21): solids, hyperelasticity and + follower pressure done; J2 plasticity and Mooney–Rivlin on the material point interface next. ## Gap review (2026-10-14) @@ -75,9 +76,9 @@ What exists and what is missing, by area; each gap is in a milestone above. | Area | Today | Missing | |---|---|---| -| Solution procedures | Linear static, frequency (Lanczos), steady and transient heat, coupled temperature–displacement, explicit dynamics, LBM flow | Nonlinear static and geometric nonlinearity, arc-length, buckling (M15); implicit, harmonic, random and spectrum dynamics (M16) | +| Solution procedures | Linear static, nonlinear static (solids with geometric nonlinearity), frequency (Lanczos), steady and transient heat, coupled temperature–displacement, explicit dynamics, LBM flow | Nonlinear shells and beams, plasticity in implicit steps, arc-length, buckling (M15); implicit, harmonic, random and spectrum dynamics (M16) | | Contact, friction, adhesion | Explicit planar rigid walls (frictionless); couplings, springs, dashpots | Implicit and explicit deformable contact, tie, friction laws, thermal contact, wear (M7); cohesive adhesion and debonding (M20) | -| Materials | Isotropic and orthotropic elasticity, density, thermal, J2 plasticity (bilinear, table, Johnson–Cook), Johnson–Cook damage and erosion, Newtonian fluids | Hyperelastic and elastomers, viscoelasticity, viscoplasticity and creep, anisotropic and pressure-dependent plasticity, non-Newtonian viscosity, a cited material library and calibration (M17) | +| Materials | Isotropic and orthotropic elasticity, density, thermal, J2 plasticity (bilinear, table, Johnson–Cook), Johnson–Cook damage and erosion, compressible neo-Hookean hyperelasticity, Newtonian fluids | Elastomers beyond neo-Hookean (Mooney–Rivlin and the rest), viscoelasticity, viscoplasticity and creep, anisotropic and pressure-dependent plasticity, non-Newtonian viscosity, a cited material library and calibration (M17) | | Composites and anisotropy | Orthotropic constants | Orientations, layups, ply results, failure criteria, homogenisation (M18) | | Coupled fields | Thermal–structural (one way and coupled) | Piezoelectric, poroelastic, electro-thermal, acoustics (M19) | | Failure | Johnson–Cook damage and element erosion (explicit) | Fracture mechanics, fatigue, cohesive zones, composite progressive damage (M18, M20) | diff --git a/docs/fem.md b/docs/fem.md index ff24d24..4295d5a 100644 --- a/docs/fem.md +++ b/docs/fem.md @@ -149,3 +149,97 @@ K G M⁻¹ ∫ N_p tr ε_th, so a heated nearly incompressible solid takes its b when confined. A continuous nodal pressure (`DofKind::P`, Taylor–Hood) needs a symmetric indefinite factorization and is planned. + +## Nonlinear static analysis (finite strain) + +A step `{"type": "nonlinear_static", …}` (`Procedure::NonlinearStatic`, solved by +`solve.nonlinear`, `fieldcraft_solver::nonlinear`) follows equilibrium in load increments with +Newton–Raphson iterations. The step's load factor λ runs from 0 to 1: dead loads are λ times +their values, a pressure follows the deformed faces with λ times its magnitude, and prescribed +displacements are λ times theirs (a linear ramp). + +**Material point** (`fieldcraft_fem::constitutive`). Given the deformation gradient F and the +history committed at the end of the last converged increment, a material returns the +**Kirchhoff stress** τ = J σ and the **spatial tangent** c of its Lie derivative (L_v τ = c : d), +in Voigt order with engineering-shear columns, so c = D at F = I. This is the push-forward of +the second Piola–Kirchhoff stress and its tangent: τ = F S Fᵀ, c_ijkl = F_iI F_jJ F_kK F_lL +C_IJKL. History variables (`MaterialModel::history_len` per integration point) are read from the +committed slice and written to a separate one, which the solver commits when the increment +converges, so a cut-back increment leaves no trace. The materials: + +| Material in a nonlinear step | Model | +|---|---| +| Elastic (isotropic or orthotropic), no option | St Venant–Kirchhoff: S = D E, E = ½(FᵀF − I). Right for large rotations with small strains; it softens without bound in large compression. | +| Isotropic elastic with `"hyperelastic": {"type": "neo_hookean"}` | Compressible neo-Hookean with the isochoric–volumetric split, W = μ/2 (Ī₁ − 3) + κ/2 (J − 1)², μ and κ from E and ν (C₁₀ = μ/2, D₁ = 2/κ). Its small-strain limit is the linear material, which linear steps use. | + +"Isotropic elastic" keeps meaning the same thing everywhere: the neo-Hookean model is chosen +only by the explicit option, and explicit dynamics refuses a hyperelastic material by name. + +**Elements** (`fieldcraft_fem::finite`), total Lagrangian over the reference element with its +own quadrature: f_a = ∫ Bₓ,aᵀ τ dV₀ and K_ab = ∫ (Bₓ,aᵀ c Bₓ,b + ∇ₓN_a·τ∇ₓN_b I) dV₀ with the +current gradients ∇ₓN = F⁻ᵀ∇₀N (material plus geometric stiffness), identical term by term to +∫ B₀ᵀ S dV₀ and its linearisation. Every element's tangent is checked against central +differences of its forces. + +| Element | Nonlinear steps | +|---|---| +| tet4, tet10, wedge6, hex8, hex20 (full), hex20 (reduced) | total Lagrangian | +| hybrid hex8, hex20, tet10 | Simo–Taylor–Pister three-field form on the linear hybrid elements' pressure fields (θ the projection of J, p the projection of U′(θ)); needs the neo-Hookean option (St Venant–Kirchhoff has no volumetric split) | +| hex8 and quad4 incompatible modes | refused: their finite-strain form (enhanced assumed strain, Simo–Armero 1992) needs the modes as unknowns carried between iterations and hourglasses in large compression; use full integration, hybrid or quadratic elements | +| plane strain, axisymmetric (tri3, tri6, quad4, quad8) | total Lagrangian with F₃₃ = 1 or r/R (hoop column N/r, geometric term τ_θθ N_a N_b/r²) | +| plane stress | refused (σ_zz = 0 needs a local iteration for the thickness) | +| trusses, shells, beams | refused (large rotations of structural elements come later in M15) | + +Without nonlinear geometry (`"nonlinear_geometry": false`) the elements are the linear ones: +every material is elastic today, so such a step is the linear solution reached by Newton (the +path the next materials, plasticity first, take with small strains). + +**Follower pressure** (`fieldcraft_fem::face::follower_pressure`, `follower_edge_pressure`): +fᵢ = −p ∫ Nᵢ (x,ξ × x,η) dξ dη on the current face, with its load stiffness +K = p ∫ N_a (N_b,η [x,ξ]× − N_b,ξ [x,η]×). The load stiffness is not symmetric. The solver keeps +its symmetric part and leaves the skew part out, so the tangent stays symmetric for the +supernodal Cholesky factorization: the residual is exact (the converged answer does not +change), and over a closed surface or one whose boundary is held the skew parts of neighbouring +faces cancel (Schweizerhof & Ramm 1984), so nothing is lost there; elsewhere Newton may converge +linearly instead of quadratically, and the result says how large the left-out part is. An LU +factorization would double the factor's memory and lose the symmetric solver for a gain only in +the rate of convergence of open loaded surfaces; it is revisited with the symmetric indefinite +(LDLᵀ) factorization that arc-length and Taylor–Hood need. Without nonlinear geometry a pressure +is a dead load. + +**Newton–Raphson** with the consistent tangent refactored every iteration, an optional line +search (off by default: on large elastic rotations the full step converges in fewer +iterations), and convergence when the force residual (∞-norm over the largest force seen), the +displacement correction (over the increment's largest displacement) and the energy (over the +first iteration's) are all below their tolerances, or the residual is round-off. Each increment +starts from the linear extrapolation of the last one. Automatic incrementation grows an +increment by half after two fast ones (≤ 4 iterations), shrinks it after a slow one (> 8), and +cuts it to a quarter when an element inverts, the residual is not finite or grows twice, the +tangent is not positive definite, or the iterations run out; the step stops with the load factor +and the reason at the minimum increment, the increment cap, or `Limits::max_newton_iterations`. + +**Results**: the final displacements and reactions, the **Cauchy stress** and the +**logarithmic strain** (ln V, engineering shears) at the integration points and averaged at the +nodes, every increment's load factor, iterations and residuals, and a displacement frame per +converged increment (`results.frame`, the slider in the results panel). + +**Couplings** stay the linear constraints of the linear solver (small rotations of the +reference points), with a warning; springs act along their fixed directions. Temperature and +centrifugal loads are refused by name in nonlinear steps. + +**Decks**: Abaqus `*STEP, NLGEOM=YES|NO, INC=` with `*STATIC` (initial, period 1, minimum, +maximum) and `*CONTROLS, PARAMETERS=LINE SEARCH`; the neo-Hookean option as `*HYPERELASTIC, NEO +HOOKE`. LS-DYNA: the ramped implicit run with full Newton (`ilimit` 1, `maxref`) and +`*CONTROL_IMPLICIT_AUTO`; hyperelastic materials in nonlinear steps and steps without nonlinear +geometry are refused. Nastran refuses nonlinear steps (SOL 400) by name. Iteration caps and +tolerances are left to each solver's own controls, whose norms differ from ours. + +**Verification** (`crates/solver/tests/nonlinear.rs`, `crates/fem/src/{constitutive,finite,face}.rs`, +and `tests/oracle/nl-*`): consistent tangents of both materials and of every element (central +differences); uniaxial stretch to λ = 2 of a neo-Hookean block in every element kind, plane +strain and axisymmetric (closed form); St Venant–Kirchhoff uniaxial stretch; the nonlinear patch +test on a distorted mesh (all solids, hybrid ones included); a 90° rigid rotation (zero stress); +the elastica (Bisshopp–Drucker) at P L²/(E I) = 1, 2, 5, 10 with hex20 (0.2–0.5 %); the inflation of a thick neo-Hookean tube by a follower pressure (Rivlin's closed form); +Newton's quadratic convergence; the linear limit; a finite-strain Cook's membrane is pending +its transcribed reference; and the failures (an element inverted by +crushing stops at the minimum increment, naming it; the caps; what is refused). diff --git a/docs/oracle.md b/docs/oracle.md index 1970110..79288f9 100644 --- a/docs/oracle.md +++ b/docs/oracle.md @@ -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. -**117 of 123 quantities pass** (6 known failure(s)) in 35 active cases: 26 theory, 9 published benchmark, 0 experiment; 9 pending cases wait for capabilities still being built. +**142 of 148 quantities pass** (6 known failure(s)) in 40 active cases: 31 theory, 9 published benchmark, 0 experiment; 10 pending cases wait for capabilities still being built. ## Theory: closed-form solutions, patch tests and mesh invariants @@ -47,6 +47,31 @@ Generated by `cargo xtask oracle` from [`tests/oracle/`](../tests/oracle/); the | [lame-cylinder-plane-strain](../tests/oracle/lame-cylinder-plane-strain/) | radial displacement at the bore (10, 0) | 0.0090794 | 0.0090793 | -0.000267% | 0.1% | pass | matches | | [lame-cylinder-plane-strain](../tests/oracle/lame-cylinder-plane-strain/) | hoop stress σ_θ = σ_yy at the bore (10, 0) | 166.67 | 166.36 | -0.183% | 1% | pass | matches | | [lame-cylinder-plane-strain](../tests/oracle/lame-cylinder-plane-strain/) | axial stress σ_zz = 2νA at the bore (plane strain) | 20 | 20.083 | 0.415% | 1% | pass | matches | +| [nl-cylinder-inflation](../tests/oracle/nl-cylinder-inflation/) | radial displacement of the bore (10, 0, 0) at the pressure that inflates it to a = 15 | 5 | 5.004 | 0.0793% | 0.5% | pass | matches | +| [nl-cylinder-inflation](../tests/oracle/nl-cylinder-inflation/) | radial displacement of the outer wall (20, 0, 0) | 2.9129 | 2.9173 | 0.152% | 0.5% | pass | matches | +| [nl-elastica-cantilever](../tests/oracle/nl-elastica-cantilever/) | tip deflection δ_v/L at P L²/(E I) = 1 | 0.30172 | 0.30226 | 0.179% | 1% | pass | matches | +| [nl-elastica-cantilever](../tests/oracle/nl-elastica-cantilever/) | tip shortening δ_h/L at P L²/(E I) = 1 | 0.056433 | 0.056633 | 0.354% | 2% | pass | matches | +| [nl-elastica-cantilever](../tests/oracle/nl-elastica-cantilever/) | tip deflection δ_v/L at P L²/(E I) = 2 | 0.49346 | 0.49455 | 0.221% | 1% | pass | matches | +| [nl-elastica-cantilever](../tests/oracle/nl-elastica-cantilever/) | tip shortening δ_h/L at P L²/(E I) = 2 | 0.16064 | 0.16132 | 0.422% | 2% | pass | matches | +| [nl-elastica-cantilever](../tests/oracle/nl-elastica-cantilever/) | tip deflection δ_v/L at P L²/(E I) = 5 | 0.71379 | 0.71598 | 0.306% | 1% | pass | matches | +| [nl-elastica-cantilever](../tests/oracle/nl-elastica-cantilever/) | tip shortening δ_h/L at P L²/(E I) = 5 | 0.38763 | 0.38955 | 0.495% | 2% | pass | matches | +| [nl-elastica-cantilever](../tests/oracle/nl-elastica-cantilever/) | tip deflection δ_v/L at P L²/(E I) = 10 | 0.81061 | 0.81421 | 0.444% | 1% | pass | matches | +| [nl-elastica-cantilever](../tests/oracle/nl-elastica-cantilever/) | tip shortening δ_h/L at P L²/(E I) = 10 | 0.555 | 0.558 | 0.541% | 2% | pass | matches | +| [nl-neo-hookean-uniaxial](../tests/oracle/nl-neo-hookean-uniaxial/) | axial Cauchy stress at the corner (1, 1, 1), stretch λ = 2 | 8.0601 | 8.0601 | < 1e-7% | 1e-6 rel. | pass | matches | +| [nl-neo-hookean-uniaxial](../tests/oracle/nl-neo-hookean-uniaxial/) | lateral displacement u_y at the corner (1, 1, 1), l − 1 | -0.18686 | -0.18686 | < 1e-7% | 1e-6 rel. | pass | matches | +| [nl-patch-hex8](../tests/oracle/nl-patch-hex8/) | u_x at inner node 22 | 0.13583 | 0.13583 | < 1e-7% | 1e-8 rel. | pass | matches | +| [nl-patch-hex8](../tests/oracle/nl-patch-hex8/) | u_y at inner node 22 | 3.4875e-4 | 3.4875e-4 | -0.000000665% | 1e-8 rel. | pass | matches | +| [nl-patch-hex8](../tests/oracle/nl-patch-hex8/) | u_z at inner node 22 | -0.0023985 | -0.0023985 | -0.000000102% | 1e-8 rel. | pass | matches | +| [nl-patch-hex8](../tests/oracle/nl-patch-hex8/) | Cauchy σ_xx at inner node 22 | 42.296 | 42.296 | < 1e-7% | 1e-7 rel. | pass | matches | +| [nl-patch-hex8](../tests/oracle/nl-patch-hex8/) | Cauchy σ_yy at inner node 22 | 23.501 | 23.501 | < 1e-7% | 1e-7 rel. | pass | matches | +| [nl-patch-hex8](../tests/oracle/nl-patch-hex8/) | Cauchy σ_zz at inner node 22 | 31.453 | 31.453 | < 1e-7% | 1e-7 rel. | pass | matches | +| [nl-patch-hex8](../tests/oracle/nl-patch-hex8/) | Cauchy σ_xy at inner node 22 | -0.88971 | -0.88971 | < 1e-7% | 1e-7 rel. | pass | matches | +| [nl-patch-hex8](../tests/oracle/nl-patch-hex8/) | Cauchy σ_xz at inner node 22 | -1.8906 | -1.8906 | < 1e-7% | 1e-7 rel. | pass | matches | +| [nl-patch-hex8](../tests/oracle/nl-patch-hex8/) | Cauchy σ_yz at inner node 22 | 1.9462 | 1.9462 | < 1e-7% | 1e-7 rel. | pass | matches | +| [nl-rigid-rotation](../tests/oracle/nl-rigid-rotation/) | u_x at inner node 22: the rotation's | -0.011149 | -0.011149 | -1.2e-16 | ± 1.0000e-9 | pass | matches | +| [nl-rigid-rotation](../tests/oracle/nl-rigid-rotation/) | u_y at inner node 22: the rotation's | 0.078591 | 0.078591 | -5.6e-17 | ± 1.0000e-9 | pass | matches | +| [nl-rigid-rotation](../tests/oracle/nl-rigid-rotation/) | u_z at inner node 22: the rotation's | -0.067441 | -0.067441 | -1.2e-16 | ± 1.0000e-9 | pass | matches | +| [nl-rigid-rotation](../tests/oracle/nl-rigid-rotation/) | von Mises stress at inner node 22 | 0 | ≈ 0 | ≈ 0 | ± 1.0000e-8 | pass | matches | | [patch-hex20](../tests/oracle/patch-hex20/) | u_x at the corner (1, 1, 1) | -2.5000e-4 | -2.5000e-4 | < 1e-7% | 1e-9 rel. | pass | matches | | [patch-hex20](../tests/oracle/patch-hex20/) | u_y at the corner (1, 1, 1) | 0.001 | 0.001 | < 1e-7% | 1e-9 rel. | pass | matches | | [patch-hex20](../tests/oracle/patch-hex20/) | u_z at the corner (1, 1, 1) | 0.00225 | 0.00225 | < 1e-7% | 1e-9 rel. | pass | matches | @@ -162,6 +187,11 @@ Generated by `cargo xtask oracle` from [`tests/oracle/`](../tests/oracle/); the - **[nafems-le1](../tests/oracle/nafems-le1/)** (benchmark): NAFEMS LE1 elliptic membrane (hex20 plane stress layer). Source: NAFEMS, The Standard NAFEMS Benchmarks, TNSB Rev. 3, October 1990, test LE1 (target σ_yy = 92.7 MPa at D); as reproduced in the Abaqus 2017 Benchmarks Guide, 'LE1: Plane stress elements—elliptic membrane'. Tolerances — syy_D: the target is published to three figures; plane stress modelled by a thin solid layer and the stress extrapolated to the edge add a few tenths of a percent - **[nafems-le1-plane-stress](../tests/oracle/nafems-le1-plane-stress/)** (benchmark): NAFEMS LE1 elliptic membrane with 2D plane stress elements (quad8). Source: NAFEMS, The Standard NAFEMS Benchmarks, TNSB Rev. 3, October 1990, test LE1 (target σ_yy = 92.7 MPa at D); as reproduced in the Abaqus 2017 Benchmarks Guide, 'LE1: Plane stress elements—elliptic membrane'. Tolerances — syy_D: the target is published to three figures; the stress extrapolated to the edge on a converged mesh adds a few tenths of a percent - **[nafems-le10](../tests/oracle/nafems-le10/)** (benchmark): NAFEMS LE10 thick plate under pressure (hex20). Source: NAFEMS, The Standard NAFEMS Benchmarks, TNSB Rev. 3, October 1990, test LE10 (target σ_yy = −5.38 MPa at D); as reproduced in the Abaqus 2017 Benchmarks Guide, 'LE10: Thick plate under pressure'. Tolerances — syy_D: the target is published to three figures; at D the stress is extrapolated to a corner where the hole edge meets the loaded face, and published converged solutions scatter by 1–2% (Abaqus Benchmarks Guide fine meshes: −5.51 to −5.89) +- **[nl-cylinder-inflation](../tests/oracle/nl-cylinder-inflation/)** (theory): Inflation of a thick neo-Hookean cylinder by a follower pressure (plane strain). Source: Finite inflation of an incompressible neo-Hookean thick-walled tube in plane strain: r² = R² + a² − A², σ_θ − σ_r = μ (λ² − λ⁻²) with λ = r/R, integrated through the wall: p = (μ/2)[(ln λ_a² − λ_a⁻²) − (ln λ_b² − λ_b⁻²)] (R. S. Rivlin, Large elastic deformations of isotropic materials VI, Phil. Trans. R. Soc. A 242:173–195, 1949; R. W. Ogden, Non-Linear Elastic Deformations, Dover 1997, §5.3.2). Tolerances — ua: the closed form is incompressible and our material nearly so (κ/μ = 1000, a volume change of order p/κ ≈ 4·10⁻⁴); hybrid hex20, 6 × 16, follow the wall's strain gradient well inside; ub: as at the bore +- **[nl-elastica-cantilever](../tests/oracle/nl-elastica-cantilever/)** (theory): Large-deflection cantilever under a dead tip load against the elastica (solids). Source: The elastica of a cantilever under a vertical end load: K. E. Bisshopp, D. C. Drucker, Large deflection of cantilever beams, Quarterly of Applied Mathematics 3(3):272–275, 1945 (elliptic-integral solution); values computed by integrating θ″ = −(P/EI) cos θ by shooting (our own RK4, 20000 steps), agreeing with the table of K. Mattiasson, Numerical results from large deflection beam and frame problems analysed by means of elliptic integrals, IJNME 17(1):145–153, 1981, to all six digits. Tolerances — v1: hex20, 40 × 2 through the depth, L/h = 20: shear deformation (0.6 (h/L)² ≈ 0.15 % of the deflection) and the clamp's local restraint, both absent from the elastica; u1: as δ_v; the shortening is the smaller, second-order quantity, so its relative error is about twice the deflection's; v2: hex20, 40 × 2 through the depth, L/h = 20: shear deformation (0.6 (h/L)² ≈ 0.15 % of the deflection) and the clamp's local restraint, both absent from the elastica; u2: as δ_v; the shortening is the smaller, second-order quantity, so its relative error is about twice the deflection's; v5: hex20, 40 × 2 through the depth, L/h = 20: shear deformation (0.6 (h/L)² ≈ 0.15 % of the deflection) and the clamp's local restraint, both absent from the elastica; u5: as δ_v; the shortening is the smaller, second-order quantity, so its relative error is about twice the deflection's; v10: hex20, 40 × 2 through the depth, L/h = 20: shear deformation (0.6 (h/L)² ≈ 0.15 % of the deflection) and the clamp's local restraint, both absent from the elastica; u10: as δ_v; the shortening is the smaller, second-order quantity, so its relative error is about twice the deflection's +- **[nl-neo-hookean-uniaxial](../tests/oracle/nl-neo-hookean-uniaxial/)** (theory): Uniaxial stretch of a neo-Hookean block to twice its length. Source: Closed form of the compressible neo-Hookean model W = μ/2 (Ī₁ − 3) + κ/2 (J − 1)² in uniaxial stress (G. A. Holzapfel, Nonlinear Solid Mechanics, Wiley 2000, §6.5, eq. 6.148 with the volumetric term of §6.4): σ_yy = μ J^(−5/3)(l² − Ī/3) + κ(J − 1) = 0 fixes the lateral stretch l, then σ_xx = μ J^(−5/3)(λ² − l²). Tolerances — sigma: a homogeneous deformation every element represents exactly: the tolerance only admits rounding and the Newton tolerance; lateral: a homogeneous deformation every element represents exactly: the tolerance only admits rounding and the Newton tolerance +- **[nl-patch-hex8](../tests/oracle/nl-patch-hex8/)** (theory): Nonlinear patch test, hex8: a homogeneous finite deformation of a distorted mesh. Source: The patch test (B. M. Irons, A. Razzaque, in A. K. Aziz (ed.), The Mathematical Foundations of the Finite Element Method, Academic Press 1972, 557–587) at finite strain: a boundary moved by x = F X makes F the solution everywhere (J. Bonet, R. D. Wood, Nonlinear Continuum Mechanics for Finite Element Analysis, 2nd ed., Cambridge 2008, §8); the neo-Hookean Cauchy stress σ = μ J^(−5/3) dev b + κ (J − 1) I of that F. Tolerances — ux: a patch test is passed exactly: the tolerance admits rounding and the Newton tolerance; uy: a patch test is passed exactly: the tolerance admits rounding and the Newton tolerance; uz: a patch test is passed exactly: the tolerance admits rounding and the Newton tolerance; sxx: a patch test is passed exactly: the tolerance admits rounding and the Newton tolerance; syy: a patch test is passed exactly: the tolerance admits rounding and the Newton tolerance; szz: a patch test is passed exactly: the tolerance admits rounding and the Newton tolerance; sxy: a patch test is passed exactly: the tolerance admits rounding and the Newton tolerance; sxz: a patch test is passed exactly: the tolerance admits rounding and the Newton tolerance; syz: a patch test is passed exactly: the tolerance admits rounding and the Newton tolerance +- **[nl-rigid-rotation](../tests/oracle/nl-rigid-rotation/)** (theory): A quarter turn strains and stresses nothing (objectivity). Source: Objectivity of the total Lagrangian formulation and of the hyperelastic stress: a rigid motion x = R X + c gives C = I and σ = 0 whatever the rotation (Bonet & Wood 2008, §3.4 and §5.2; T. Belytschko, W. K. Liu, B. Moran, Nonlinear Finite Elements for Continua and Structures, 2nd ed., Wiley 2014, §5.5). Tolerances — ux: the inner nodes follow the rigid rotation exactly; uy: the inner nodes follow the rigid rotation exactly; uz: the inner nodes follow the rigid rotation exactly; von_mises: zero up to rounding of stresses of order E = 1000: a 90° turn leaves no strain - **[patch-hex20](../tests/oracle/patch-hex20/)** (theory): Constant-stress patch test, hex20. Source: Irons and Razzaque, 'Experience with the patch test for convergence of finite elements', in Aziz (ed.), The Mathematical Foundations of the Finite Element Method, Academic Press 1972, pp. 557–587; MacNeal and Harder, Finite Elements in Analysis and Design 1 (1985) 3–20, constant-stress loading, p. 14 Table 7. Tolerances — ux: a patch test is passed exactly: the tolerance only admits rounding; uy: a patch test is passed exactly: the tolerance only admits rounding; uz: a patch test is passed exactly: the tolerance only admits rounding; sxx: a patch test is passed exactly: the tolerance only admits rounding; syy: a patch test is passed exactly: the tolerance only admits rounding; szz: a patch test is passed exactly: the tolerance only admits rounding; sxy: a patch test is passed exactly: the tolerance only admits rounding (stresses of order 1) - **[patch-hex20-reduced](../tests/oracle/patch-hex20-reduced/)** (theory): Constant-stress patch test, hex20-reduced. Source: Irons and Razzaque, 'Experience with the patch test for convergence of finite elements', in Aziz (ed.), The Mathematical Foundations of the Finite Element Method, Academic Press 1972, pp. 557–587; MacNeal and Harder, Finite Elements in Analysis and Design 1 (1985) 3–20, constant-stress loading, p. 14 Table 7. Tolerances — ux: a patch test is passed exactly: the tolerance only admits rounding; uy: a patch test is passed exactly: the tolerance only admits rounding; uz: a patch test is passed exactly: the tolerance only admits rounding; sxx: a patch test is passed exactly: the tolerance only admits rounding; syy: a patch test is passed exactly: the tolerance only admits rounding; szz: a patch test is passed exactly: the tolerance only admits rounding; sxy: a patch test is passed exactly: the tolerance only admits rounding (stresses of order 1) - **[patch-hex8](../tests/oracle/patch-hex8/)** (theory): Constant-stress patch test, hex8. Source: Irons and Razzaque, 'Experience with the patch test for convergence of finite elements', in Aziz (ed.), The Mathematical Foundations of the Finite Element Method, Academic Press 1972, pp. 557–587; MacNeal and Harder, Finite Elements in Analysis and Design 1 (1985) 3–20, constant-stress loading, p. 14 Table 7. Tolerances — ux: a patch test is passed exactly: the tolerance only admits rounding; uy: a patch test is passed exactly: the tolerance only admits rounding; uz: a patch test is passed exactly: the tolerance only admits rounding; sxx: a patch test is passed exactly: the tolerance only admits rounding; syy: a patch test is passed exactly: the tolerance only admits rounding; szz: a patch test is passed exactly: the tolerance only admits rounding; sxy: a patch test is passed exactly: the tolerance only admits rounding (stresses of order 1) @@ -185,6 +215,7 @@ Reference values already cited; each case gets its recipe when the capability it | [lid-driven-cavity-re100](../tests/oracle/lid-driven-cavity-re100/) | benchmark | Lid-driven cavity, Re = 100 | lattice Boltzmann CFD (M12) | u/U at y = 0.4531 on the vertical centreline = -0.2109 | Ghia, Ghia and Shin, Journal of Computational Physics 48 (1982) 387–411, Table I (u along the vertical centreline) | | [mh-twisted-beam](../tests/oracle/mh-twisted-beam/) | benchmark | MacNeal–Harder twisted beam | shell elements (M8) or mapped blocks with helical edges | tip displacement along the in-plane load = 0.005424; tip displacement along the out-of-plane load = 0.001754 | MacNeal and Harder, 'A proposed standard set of problems to test finite element accuracy', Finite Elements in Analysis and Design 1 (1985) 3–20, Fig. 6 (p. 8), Table 3 (p. 10) | | [nafems-le11](../tests/oracle/nafems-le11/) | benchmark | NAFEMS LE11 solid cylinder/taper/sphere under a temperature field | thermal loads (M8 heat transfer) | σ_zz at A = -105 | NAFEMS, The Standard NAFEMS Benchmarks, TNSB Rev. 3, October 1990, test LE11 (target σ_zz = −105 MPa at A) | +| [nl-cook-membrane](../tests/oracle/nl-cook-membrane/) | benchmark | Cook's membrane, nearly incompressible neo-Hookean, large load (plane strain) | the published finite-strain reference value, transcribed from the paper with its load and material constants | vertical displacement of the top corner C (48, 60) = to be transcribed | R. D. Cook, Improved two-dimensional finite element, J. Struct. Div. ASCE 100(ST9):1851–1863, 1974 (the tapered panel (0, 0), (48, 44), (48, 60), (0, 44), clamped on x = 0, shear on x = 48); finite-strain versions with a neo-Hookean material are published by J. C. Simo, F. Armero, IJNME 33:1413–1449, 1992; the values to compare with are to be transcribed from the paper | | [pinched-cylinder](../tests/oracle/pinched-cylinder/) | benchmark | Pinched cylinder with rigid diaphragms | shell elements (M8) | radial displacement under the load = -1.8248e-5 | Belytschko, Stolarski, Liu, Carpenter and Ong, 'Stress projection for membrane and shear locking in shell finite elements', Computer Methods in Applied Mechanics and Engineering 51 (1985) 221–258 (the shell obstacle course); reference 1.8248 × 10⁻⁵ under the load | | [pinched-hemisphere](../tests/oracle/pinched-hemisphere/) | benchmark | Hemispherical shell with an 18° hole under alternating point loads | shell elements (M8), or mapped blocks that follow doubly curved faces | displacement under the load along the load = 0.094 | MacNeal and Harder, 'A proposed standard set of problems to test finite element accuracy', Finite Elements in Analysis and Design 1 (1985) 3–20, Fig. 9 (p. 9), Table 5(b) (p. 11): 0.0940 (lower bound 0.0924 from their [7]) | | [plastic-thick-cylinder](../tests/oracle/plastic-thick-cylinder/) | theory | Elastic–perfectly plastic thick cylinder: collapse pressure | implicit (static) J2 plasticity: explicit J2 is in, a collapse load needs the static solver | collapse pressure for a = 10, b = 20, σ_y = 250 = 200.09 | Hill, The Mathematical Theory of Plasticity, Oxford 1950, ch. V §2: plane strain von Mises collapse pressure p = (2/√3)σ_y ln(b/a) | diff --git a/docs/parity.md b/docs/parity.md index 49ac1c9..e90ea57 100644 --- a/docs/parity.md +++ b/docs/parity.md @@ -44,7 +44,7 @@ products are run, no documentation text is copied). Status: **done**, **started* | Mesh | Mesh editing (move, merge, split, collapse, remesh region), imported orphan meshes | M6 | yes | started (node/element add/remove) | | Model | Sets and surfaces bound to geometry names | M3 | yes | done | | Model | Materials: elastic (isotropic, orthotropic), density, unit-system check | M3 | | done | -| Model | Materials: plasticity, hyperelasticity, damage, thermal | M8 | | started (von Mises plasticity: bilinear, table, Johnson–Cook; Johnson–Cook damage, erosion; written to Abaqus `*PLASTIC`, Nastran `MATS1`, LS-DYNA plastic materials where expressible) | +| Model | Materials: plasticity, hyperelasticity, damage, thermal | M8 | | started (von Mises plasticity: bilinear, table, Johnson–Cook; Johnson–Cook damage, erosion; written to Abaqus `*PLASTIC`, Nastran `MATS1`, LS-DYNA plastic materials where expressible; compressible neo-Hookean for nonlinear steps, Abaqus `*HYPERELASTIC, NEO HOOKE`) | | Model | Sections: solid, shell, beam profiles; assignment by set | M3 | | done | | Model | 2D sections: plane stress, plane strain, axisymmetric (XY plane, Y the axis); element edges in sets; centrifugal load | M4 | | done | | Model | Composite layups, material orientations, continuum shells | M8 | yes | planned | @@ -53,7 +53,7 @@ products are run, no documentation text is copied). Status: **done**, **started* | Model | Loads: force and moment, pressure, gravity, body force | M3 | | done | | Model | Reference points, kinematic and distributing coupling | M3 | | done | | Model | Steps: linear static, frequency; output presets | M3 | | done | -| Model | Steps: nonlinear static, explicit dynamics, heat transfer; amplitudes | M7–M8 | | planned | +| Model | Steps: nonlinear static, explicit dynamics, heat transfer; amplitudes | M7–M8, M15 | | started (nonlinear static with nonlinear geometry, increments and tolerances, written to Abaqus `*STEP, NLGEOM` and LS-DYNA implicit, refused by Nastran; explicit dynamics; heat transfer; amplitudes planned) | | Interaction | Tie between non-matching meshes | M7 | | planned | | Interaction | Contact (general and pairs), friction, automatic pair detection | M7 | | planned | | Interaction | Springs and dashpots (ground or two-point; DOF, vector or line), point masses with rotary inertia | M4 | | done (implicit; explicit translational; all three decks with what each cannot take reported) | @@ -63,6 +63,7 @@ products are run, no documentation text is copied). Status: **done**, **started* | Decks | LS-DYNA keyword writer (implicit; explicit in M8) | M3 | | done (implicit static and eigenvalue; beam sections planned) | | Decks | Readers keeping unknown keywords | M9 | | planned | | Solve | Own linear static and modal solver, verified against analytic solutions | M4 | yes | started (solid elements: tet4, tet10, wedge6, hex8, hex20; 2D plane stress, plane strain and axisymmetric tri3, tri6, quad4 (full, incompatible modes), quad8 (full, reduced); quad4/tri3 MITC shells and Timoshenko beams with profiles, mixed with solids; reference points, kinematic and distributing couplings, moments; centrifugal loads) | +| Solve | Own nonlinear implicit solver: Newton–Raphson with line search and automatic increments, total Lagrangian solids and 2D elements, mixed u–p at finite strain, follower pressure | M15 | yes | started (solids, plane strain, axisymmetric; St Venant–Kirchhoff and neo-Hookean; verified by the elastica, tube inflation, patch and objectivity tests; plasticity, shells, contact, arc-length next) | | Solve | Own explicit dynamics solver (central differences, one-point hex8 with hourglass control, nodal-pressure tet4, bulk viscosity, energy balance), verified against analytic wave and impact solutions | M10 | yes | started (X1 core and X2: large deformation, objective rates, J2 and Johnson–Cook plasticity, damage, erosion; contact planned) | | Results | Deformed shape, contours, mode shapes, probes, reaction sums | M4 | | started (results in the session, `solve.probe`, reaction sums; display planned) | | Results | XY and path plots, cuts, display groups, free-body forces, animation | M9 | | planned | diff --git a/docs/solvers/literature.md b/docs/solvers/literature.md index 852d060..6e494e8 100644 --- a/docs/solvers/literature.md +++ b/docs/solvers/literature.md @@ -1158,3 +1158,31 @@ update are written from (cited again in the module docs): ν = 0.4999 (exact), Lamé's thick cylinder in plane strain at ν = 0.4999 (hex20 1e-5, tet10 1e-3, hex8 3e-3 relative error in the bore displacement, where the displacement hex8 is 80 % too stiff). Cook's membrane is a published benchmark, not part of the analytic gate. + +## Part M: Nonlinear static analysis (finite strain), as implemented + +- Total Lagrangian formulation written with spatial quantities (Kirchhoff stress, spatial + tangent, current gradients): J. Bonet, R. D. Wood, *Nonlinear Continuum Mechanics for Finite + Element Analysis*, 2nd ed., Cambridge 2008, ch. 5–9; G. A. Holzapfel, *Nonlinear Solid + Mechanics*, Wiley 2000, §6.6 (the isochoric–volumetric split and its tangents); K.-J. Bathe, + *Finite Element Procedures*, 2nd ed., 2014, §6.3; T. Belytschko, W. K. Liu, B. Moran, + K. Elkhodary, *Nonlinear Finite Elements for Continua and Structures*, 2nd ed., Wiley 2014, + ch. 4–6. +- Decoupled neo-Hookean energy: P. J. Flory, Trans. Faraday Soc. 57:829–838, 1961. +- Mixed u–p at finite strain: J. C. Simo, R. L. Taylor, K. S. Pister, CMAME 51:177–208, 1985; + mean dilatation: J. C. Nagtegaal, D. M. Parks, J. R. Rice, CMAME 4:153–177, 1974. +- Enhanced assumed strain at finite strain (why incompatible modes are refused for now): J. C. + Simo, F. Armero, IJNME 33:1413–1449, 1992; their hourglassing in compression: P. Wriggers, + S. Reese, CMAME 135:201–209, 1996. +- Follower pressure and its load stiffness: K. Schweizerhof, E. Ramm, Comput. Struct. + 18(6):1099–1114, 1984. +- Newton–Raphson, line search and convergence criteria: M. A. Crisfield, *Non-linear Finite + Element Analysis of Solids and Structures*, vol. 1, Wiley 1991, ch. 9; K.-J. Bathe, + A. P. Cimento, CMAME 22:59–85, 1980. +- Symmetric eigen-decomposition for the logarithmic strain: G. H. Golub, C. F. Van Loan, + *Matrix Computations*, 4th ed., Johns Hopkins 2013, §8.5 (cyclic Jacobi). +- Verification references: the elastica, K. E. Bisshopp, D. C. Drucker, Q. Appl. Math. + 3(3):272–275, 1945, with K. Mattiasson, IJNME 17(1):145–153, 1981; Cook's membrane (pending its + transcribed finite-strain values), R. D. Cook, J. Struct. Div. ASCE 100(ST9):1851–1863, 1974, + and J. C. Simo, F. Armero, IJNME 33:1413–1449, 1992; tube inflation, R. S. Rivlin, Phil. Trans. R. Soc. A + 242:173–195, 1949, and R. W. Ogden, *Non-Linear Elastic Deformations*, Dover 1997. diff --git a/tests/oracle/nl-cook-membrane/README.md b/tests/oracle/nl-cook-membrane/README.md new file mode 100644 index 0000000..4b549e7 --- /dev/null +++ b/tests/oracle/nl-cook-membrane/README.md @@ -0,0 +1,7 @@ +# Cook's membrane at finite strain (pending) + +Waits for its reference value: the finite-strain Cook's membrane is defined (load, μ, κ) and +answered in papers we have not transcribed, and no value is entered from memory. FieldCraft +solves the model today (hybrid hex20 one element thick in plane strain, or plane strain quad8 for +compressible materials); the case becomes active when the published numbers are copied in with +their table. diff --git a/tests/oracle/nl-cook-membrane/expected.json b/tests/oracle/nl-cook-membrane/expected.json new file mode 100644 index 0000000..c79e82c --- /dev/null +++ b/tests/oracle/nl-cook-membrane/expected.json @@ -0,0 +1,14 @@ +{ + "title": "Cook's membrane, nearly incompressible neo-Hookean, large load (plane strain)", + "kind": "benchmark", + "source": "R. D. Cook, Improved two-dimensional finite element, J. Struct. Div. ASCE 100(ST9):1851–1863, 1974 (the tapered panel (0, 0), (48, 44), (48, 60), (0, 44), clamped on x = 0, shear on x = 48); finite-strain versions with a neo-Hookean material are published by J. C. Simo, F. Armero, IJNME 33:1413–1449, 1992; the values to compare with are to be transcribed from the paper", + "status": "pending", + "requires": "the published finite-strain reference value, transcribed from the paper with its load and material constants", + "quantities": [ + { + "id": "vC", + "quantity": "vertical displacement of the top corner C (48, 60)", + "value": null + } + ] +} diff --git a/tests/oracle/nl-cylinder-inflation/README.md b/tests/oracle/nl-cylinder-inflation/README.md new file mode 100644 index 0000000..286043a --- /dev/null +++ b/tests/oracle/nl-cylinder-inflation/README.md @@ -0,0 +1,7 @@ +# Inflation of a thick neo-Hookean cylinder (follower pressure) + +A quarter of a tube A = 10, B = 20, one unit long, in plane strain (symmetry planes x = 0, +y = 0 and both ends), 6 × 16 hybrid hex20 elements, neo-Hookean with E = 3, ν = 0.4995 +(μ = 1.00033, κ = 1000). The bore pressure p = 0.428371199 follows the deforming bore; the incompressible +closed form puts the bore at a = 15 and the outer wall at b = 22.912878475. This is the follower-pressure +case: the pressure turns with the bore and grows with its area. diff --git a/tests/oracle/nl-cylinder-inflation/expected.json b/tests/oracle/nl-cylinder-inflation/expected.json new file mode 100644 index 0000000..3208f7b --- /dev/null +++ b/tests/oracle/nl-cylinder-inflation/expected.json @@ -0,0 +1,53 @@ +{ + "title": "Inflation of a thick neo-Hookean cylinder by a follower pressure (plane strain)", + "kind": "theory", + "source": "Finite inflation of an incompressible neo-Hookean thick-walled tube in plane strain: r² = R² + a² − A², σ_θ − σ_r = μ (λ² − λ⁻²) with λ = r/R, integrated through the wall: p = (μ/2)[(ln λ_a² − λ_a⁻²) − (ln λ_b² − λ_b⁻²)] (R. S. Rivlin, Large elastic deformations of isotropic materials VI, Phil. Trans. R. Soc. A 242:173–195, 1949; R. W. Ogden, Non-Linear Elastic Deformations, Dover 1997, §5.3.2)", + "quantities": [ + { + "id": "ua", + "quantity": "radial displacement of the bore (10, 0, 0) at the pressure that inflates it to a = 15", + "measure": { + "command": "solve.probe", + "params": { + "step": "Inflate", + "at": [ + [ + 10.0, + 0, + 0 + ] + ] + }, + "pointer": "/nodes/0/displacement/0" + }, + "value": 5.0, + "tolerance": { + "relative": 0.005 + }, + "reason": "the closed form is incompressible and our material nearly so (κ/μ = 1000, a volume change of order p/κ ≈ 4·10⁻⁴); hybrid hex20, 6 × 16, follow the wall's strain gradient well inside" + }, + { + "id": "ub", + "quantity": "radial displacement of the outer wall (20, 0, 0)", + "measure": { + "command": "solve.probe", + "params": { + "step": "Inflate", + "at": [ + [ + 20.0, + 0, + 0 + ] + ] + }, + "pointer": "/nodes/0/displacement/0" + }, + "value": 2.9128784747791983, + "tolerance": { + "relative": 0.005 + }, + "reason": "as at the bore" + } + ] +} diff --git a/tests/oracle/nl-cylinder-inflation/fixture.json b/tests/oracle/nl-cylinder-inflation/fixture.json new file mode 100644 index 0000000..20adefd --- /dev/null +++ b/tests/oracle/nl-cylinder-inflation/fixture.json @@ -0,0 +1,13 @@ +{ + "note": "FieldCraft's accepted results for this case, written by `cargo xtask oracle --bless`. A result outside its band fails CI.", + "values": { + "ua": { + "band": 5.003966508393597e-9, + "value": 5.003966508393597 + }, + "ub": { + "band": 2.917320022569369e-9, + "value": 2.9173200225693687 + } + } +} diff --git a/tests/oracle/nl-cylinder-inflation/recipe.json b/tests/oracle/nl-cylinder-inflation/recipe.json new file mode 100644 index 0000000..2c69136 --- /dev/null +++ b/tests/oracle/nl-cylinder-inflation/recipe.json @@ -0,0 +1,18 @@ +[ + {"command": "mesh.block", "params": {"body": "Pipe", "kind": "hex20", "corners": [[10.0, 0, 0], [20.0, 0, 0], [0, 20.0, 0], [0, 10.0, 0], [10.0, 0, 1], [20.0, 0, 1], [0, 20.0, 1], [0, 10.0, 1]], "divisions": [6, 16, 1], "edges": [{"corners": [2, 3], "arc": {"center": [0, 0, 0]}}, {"corners": [1, 4], "arc": {"center": [0, 0, 0]}}, {"corners": [6, 7], "arc": {"center": [0, 0, 1]}}, {"corners": [5, 8], "arc": {"center": [0, 0, 1]}}], "faces": {"6": "bore", "3": "y0", "5": "x0", "1": "z0", "2": "z1"}}}, + {"command": "model.set.create", "params": {"name": "all", "geometry": [{"body": "Pipe"}]}}, + {"command": "model.set.create", "params": {"name": "bore", "geometry": [{"body": "Pipe", "face": "bore"}]}}, + {"command": "model.set.create", "params": {"name": "x0", "geometry": [{"body": "Pipe", "face": "x0"}]}}, + {"command": "model.set.create", "params": {"name": "y0", "geometry": [{"body": "Pipe", "face": "y0"}]}}, + {"command": "model.set.create", "params": {"name": "z0", "geometry": [{"body": "Pipe", "face": "z0"}]}}, + {"command": "model.set.create", "params": {"name": "z1", "geometry": [{"body": "Pipe", "face": "z1"}]}}, + {"command": "model.material.create", "params": {"name": "Rubber", "elastic": {"type": "isotropic", "young": 3.0, "poisson": 0.4995}, "hyperelastic": {"type": "neo_hookean"}}}, + {"command": "model.section.create", "params": {"name": "pipe", "set": "all", "material": "Rubber", "kind": {"type": "solid"}, "formulation": {"hybrid": true}}}, + {"command": "model.boundary_condition.create", "params": {"name": "sx", "type": "symmetry", "target": {"set": "x0"}, "plane": "x"}}, + {"command": "model.boundary_condition.create", "params": {"name": "sy", "type": "symmetry", "target": {"set": "y0"}, "plane": "y"}}, + {"command": "model.boundary_condition.create", "params": {"name": "sz0", "type": "symmetry", "target": {"set": "z0"}, "plane": "z"}}, + {"command": "model.boundary_condition.create", "params": {"name": "sz1", "type": "symmetry", "target": {"set": "z1"}, "plane": "z"}}, + {"command": "model.load.create", "params": {"name": "p", "type": "pressure", "set": "bore", "magnitude": 0.42837119949633445}}, + {"command": "model.step.create", "params": {"name": "Inflate", "procedure": {"type": "nonlinear_static"}, "boundary_conditions": ["sx", "sy", "sz0", "sz1"], "loads": ["p"]}}, + {"command": "solve.nonlinear", "params": {"step": "Inflate"}, "id": "solve"} +] diff --git a/tests/oracle/nl-elastica-cantilever/README.md b/tests/oracle/nl-elastica-cantilever/README.md new file mode 100644 index 0000000..d6eca03 --- /dev/null +++ b/tests/oracle/nl-elastica-cantilever/README.md @@ -0,0 +1,8 @@ +# Large-deflection cantilever (elastica) + +A cantilever L = 10, b = 1, h = 0.5 (L/h = 20) of 40 × 1 × 2 hex20 elements, clamped at x = 0, +E = 10⁴, ν = 0 (an elastic material in a nonlinear step: St Venant–Kirchhoff, exact for large +rotations with these small strains), under a dead vertical tip force P spread over the end face. +Four steps at P L²/(E I) = 1, 2, 5 and 10 (rotations of the tip 0.46 to 1.43 rad). The tip's +neutral-axis node (10, 0, 0.25) is compared with the elastica (Bisshopp–Drucker), whose values +were computed by shooting and agree with Mattiasson's table. diff --git a/tests/oracle/nl-elastica-cantilever/expected.json b/tests/oracle/nl-elastica-cantilever/expected.json new file mode 100644 index 0000000..6be8676 --- /dev/null +++ b/tests/oracle/nl-elastica-cantilever/expected.json @@ -0,0 +1,199 @@ +{ + "title": "Large-deflection cantilever under a dead tip load against the elastica (solids)", + "kind": "theory", + "source": "The elastica of a cantilever under a vertical end load: K. E. Bisshopp, D. C. Drucker, Large deflection of cantilever beams, Quarterly of Applied Mathematics 3(3):272–275, 1945 (elliptic-integral solution); values computed by integrating θ″ = −(P/EI) cos θ by shooting (our own RK4, 20000 steps), agreeing with the table of K. Mattiasson, Numerical results from large deflection beam and frame problems analysed by means of elliptic integrals, IJNME 17(1):145–153, 1981, to all six digits", + "quantities": [ + { + "id": "v1", + "quantity": "tip deflection δ_v/L at P L²/(E I) = 1", + "measure": { + "command": "solve.probe", + "params": { + "step": "K1", + "at": [ + [ + 10.0, + 0, + 0.25 + ] + ] + }, + "pointer": "/nodes/0/displacement/2", + "scale": -0.1 + }, + "value": 0.301721, + "tolerance": { + "relative": 0.01 + }, + "reason": "hex20, 40 × 2 through the depth, L/h = 20: shear deformation (0.6 (h/L)² ≈ 0.15 % of the deflection) and the clamp's local restraint, both absent from the elastica" + }, + { + "id": "u1", + "quantity": "tip shortening δ_h/L at P L²/(E I) = 1", + "measure": { + "command": "solve.probe", + "params": { + "step": "K1", + "at": [ + [ + 10.0, + 0, + 0.25 + ] + ] + }, + "pointer": "/nodes/0/displacement/0", + "scale": -0.1 + }, + "value": 0.056433, + "tolerance": { + "relative": 0.02 + }, + "reason": "as δ_v; the shortening is the smaller, second-order quantity, so its relative error is about twice the deflection's" + }, + { + "id": "v2", + "quantity": "tip deflection δ_v/L at P L²/(E I) = 2", + "measure": { + "command": "solve.probe", + "params": { + "step": "K2", + "at": [ + [ + 10.0, + 0, + 0.25 + ] + ] + }, + "pointer": "/nodes/0/displacement/2", + "scale": -0.1 + }, + "value": 0.493457, + "tolerance": { + "relative": 0.01 + }, + "reason": "hex20, 40 × 2 through the depth, L/h = 20: shear deformation (0.6 (h/L)² ≈ 0.15 % of the deflection) and the clamp's local restraint, both absent from the elastica" + }, + { + "id": "u2", + "quantity": "tip shortening δ_h/L at P L²/(E I) = 2", + "measure": { + "command": "solve.probe", + "params": { + "step": "K2", + "at": [ + [ + 10.0, + 0, + 0.25 + ] + ] + }, + "pointer": "/nodes/0/displacement/0", + "scale": -0.1 + }, + "value": 0.160642, + "tolerance": { + "relative": 0.02 + }, + "reason": "as δ_v; the shortening is the smaller, second-order quantity, so its relative error is about twice the deflection's" + }, + { + "id": "v5", + "quantity": "tip deflection δ_v/L at P L²/(E I) = 5", + "measure": { + "command": "solve.probe", + "params": { + "step": "K5", + "at": [ + [ + 10.0, + 0, + 0.25 + ] + ] + }, + "pointer": "/nodes/0/displacement/2", + "scale": -0.1 + }, + "value": 0.713792, + "tolerance": { + "relative": 0.01 + }, + "reason": "hex20, 40 × 2 through the depth, L/h = 20: shear deformation (0.6 (h/L)² ≈ 0.15 % of the deflection) and the clamp's local restraint, both absent from the elastica" + }, + { + "id": "u5", + "quantity": "tip shortening δ_h/L at P L²/(E I) = 5", + "measure": { + "command": "solve.probe", + "params": { + "step": "K5", + "at": [ + [ + 10.0, + 0, + 0.25 + ] + ] + }, + "pointer": "/nodes/0/displacement/0", + "scale": -0.1 + }, + "value": 0.387628, + "tolerance": { + "relative": 0.02 + }, + "reason": "as δ_v; the shortening is the smaller, second-order quantity, so its relative error is about twice the deflection's" + }, + { + "id": "v10", + "quantity": "tip deflection δ_v/L at P L²/(E I) = 10", + "measure": { + "command": "solve.probe", + "params": { + "step": "K10", + "at": [ + [ + 10.0, + 0, + 0.25 + ] + ] + }, + "pointer": "/nodes/0/displacement/2", + "scale": -0.1 + }, + "value": 0.810609, + "tolerance": { + "relative": 0.01 + }, + "reason": "hex20, 40 × 2 through the depth, L/h = 20: shear deformation (0.6 (h/L)² ≈ 0.15 % of the deflection) and the clamp's local restraint, both absent from the elastica" + }, + { + "id": "u10", + "quantity": "tip shortening δ_h/L at P L²/(E I) = 10", + "measure": { + "command": "solve.probe", + "params": { + "step": "K10", + "at": [ + [ + 10.0, + 0, + 0.25 + ] + ] + }, + "pointer": "/nodes/0/displacement/0", + "scale": -0.1 + }, + "value": 0.554996, + "tolerance": { + "relative": 0.02 + }, + "reason": "as δ_v; the shortening is the smaller, second-order quantity, so its relative error is about twice the deflection's" + } + ] +} diff --git a/tests/oracle/nl-elastica-cantilever/fixture.json b/tests/oracle/nl-elastica-cantilever/fixture.json new file mode 100644 index 0000000..32b468b --- /dev/null +++ b/tests/oracle/nl-elastica-cantilever/fixture.json @@ -0,0 +1,37 @@ +{ + "note": "FieldCraft's accepted results for this case, written by `cargo xtask oracle --bless`. A result outside its band fails CI.", + "values": { + "u1": { + "band": 5.6632559447764666e-11, + "value": 0.056632559447764665 + }, + "u10": { + "band": 5.579973985797526e-10, + "value": 0.5579973985797526 + }, + "u2": { + "band": 1.6132061646961728e-10, + "value": 0.16132061646961726 + }, + "u5": { + "band": 3.895481979257076e-10, + "value": 0.3895481979257076 + }, + "v1": { + "band": 3.02260079032045e-10, + "value": 0.30226007903204494 + }, + "v10": { + "band": 8.142088468220408e-10, + "value": 0.8142088468220408 + }, + "v2": { + "band": 4.945495713426414e-10, + "value": 0.4945495713426413 + }, + "v5": { + "band": 7.159758984663589e-10, + "value": 0.7159758984663589 + } + } +} diff --git a/tests/oracle/nl-elastica-cantilever/recipe.json b/tests/oracle/nl-elastica-cantilever/recipe.json new file mode 100644 index 0000000..ae4661a --- /dev/null +++ b/tests/oracle/nl-elastica-cantilever/recipe.json @@ -0,0 +1,21 @@ +[ + {"command": "mesh.block", "params": {"body": "Beam", "kind": "hex20", "corners": [[0, 0, 0], [10.0, 0, 0], [10.0, 1.0, 0], [0, 1.0, 0], [0, 0, 0.5], [10.0, 0, 0.5], [10.0, 1.0, 0.5], [0, 1.0, 0.5]], "divisions": [40, 1, 2], "faces": {"6": "root", "4": "tip"}}}, + {"command": "model.set.create", "params": {"name": "all", "geometry": [{"body": "Beam"}]}}, + {"command": "model.set.create", "params": {"name": "root", "geometry": [{"body": "Beam", "face": "root"}]}}, + {"command": "model.set.create", "params": {"name": "tip", "geometry": [{"body": "Beam", "face": "tip"}]}}, + {"command": "model.material.create", "params": {"name": "Steel", "elastic": {"type": "isotropic", "young": 10000.0, "poisson": 0.0}}}, + {"command": "model.section.create", "params": {"name": "beam", "set": "all", "material": "Steel", "kind": {"type": "solid"}}}, + {"command": "model.boundary_condition.create", "params": {"name": "clamp", "type": "fixed", "target": {"set": "root"}}}, + {"command": "model.load.create", "params": {"name": "P1", "type": "force", "target": {"set": "tip"}, "vector": [0, 0, -1.0416666666666667]}}, + {"command": "model.step.create", "params": {"name": "K1", "procedure": {"type": "nonlinear_static"}, "boundary_conditions": ["clamp"], "loads": ["P1"]}}, + {"command": "model.load.create", "params": {"name": "P2", "type": "force", "target": {"set": "tip"}, "vector": [0, 0, -2.0833333333333335]}}, + {"command": "model.step.create", "params": {"name": "K2", "procedure": {"type": "nonlinear_static"}, "boundary_conditions": ["clamp"], "loads": ["P2"]}}, + {"command": "model.load.create", "params": {"name": "P5", "type": "force", "target": {"set": "tip"}, "vector": [0, 0, -5.208333333333334]}}, + {"command": "model.step.create", "params": {"name": "K5", "procedure": {"type": "nonlinear_static"}, "boundary_conditions": ["clamp"], "loads": ["P5"]}}, + {"command": "model.load.create", "params": {"name": "P10", "type": "force", "target": {"set": "tip"}, "vector": [0, 0, -10.416666666666668]}}, + {"command": "model.step.create", "params": {"name": "K10", "procedure": {"type": "nonlinear_static"}, "boundary_conditions": ["clamp"], "loads": ["P10"]}}, + {"command": "solve.nonlinear", "params": {"step": "K1"}, "id": "solve1"}, + {"command": "solve.nonlinear", "params": {"step": "K2"}, "id": "solve2"}, + {"command": "solve.nonlinear", "params": {"step": "K5"}, "id": "solve5"}, + {"command": "solve.nonlinear", "params": {"step": "K10"}, "id": "solve10"} +] diff --git a/tests/oracle/nl-neo-hookean-uniaxial/README.md b/tests/oracle/nl-neo-hookean-uniaxial/README.md new file mode 100644 index 0000000..8fdc2a2 --- /dev/null +++ b/tests/oracle/nl-neo-hookean-uniaxial/README.md @@ -0,0 +1,7 @@ +# Uniaxial stretch of a neo-Hookean block + +A unit cube of 2 × 2 × 2 hex20 elements, symmetry planes x = 0, y = 0, z = 0, the face x = 1 +pulled to x = 2 (λ = 2) in a nonlinear static step; E = 10, ν = 0.3 with the neo-Hookean +option (μ = 3.84615, κ = 8.33333). The lateral stretch l = 0.813143719 solves σ_yy = 0 (bisection +on the closed form), and σ_xx = 8.060135422. The deformation is homogeneous, so every element +reproduces it exactly. diff --git a/tests/oracle/nl-neo-hookean-uniaxial/expected.json b/tests/oracle/nl-neo-hookean-uniaxial/expected.json new file mode 100644 index 0000000..f52498b --- /dev/null +++ b/tests/oracle/nl-neo-hookean-uniaxial/expected.json @@ -0,0 +1,53 @@ +{ + "title": "Uniaxial stretch of a neo-Hookean block to twice its length", + "kind": "theory", + "source": "Closed form of the compressible neo-Hookean model W = μ/2 (Ī₁ − 3) + κ/2 (J − 1)² in uniaxial stress (G. A. Holzapfel, Nonlinear Solid Mechanics, Wiley 2000, §6.5, eq. 6.148 with the volumetric term of §6.4): σ_yy = μ J^(−5/3)(l² − Ī/3) + κ(J − 1) = 0 fixes the lateral stretch l, then σ_xx = μ J^(−5/3)(λ² − l²)", + "quantities": [ + { + "id": "sigma", + "quantity": "axial Cauchy stress at the corner (1, 1, 1), stretch λ = 2", + "measure": { + "command": "solve.probe", + "params": { + "step": "Stretch", + "at": [ + [ + 1, + 1, + 1 + ] + ] + }, + "pointer": "/nodes/0/stress/0" + }, + "value": 8.060135422196785, + "tolerance": { + "relative": 1e-06 + }, + "reason": "a homogeneous deformation every element represents exactly: the tolerance only admits rounding and the Newton tolerance" + }, + { + "id": "lateral", + "quantity": "lateral displacement u_y at the corner (1, 1, 1), l − 1", + "measure": { + "command": "solve.probe", + "params": { + "step": "Stretch", + "at": [ + [ + 1, + 1, + 1 + ] + ] + }, + "pointer": "/nodes/0/displacement/1" + }, + "value": -0.1868562805727787, + "tolerance": { + "relative": 1e-06 + }, + "reason": "a homogeneous deformation every element represents exactly: the tolerance only admits rounding and the Newton tolerance" + } + ] +} diff --git a/tests/oracle/nl-neo-hookean-uniaxial/fixture.json b/tests/oracle/nl-neo-hookean-uniaxial/fixture.json new file mode 100644 index 0000000..701d99b --- /dev/null +++ b/tests/oracle/nl-neo-hookean-uniaxial/fixture.json @@ -0,0 +1,13 @@ +{ + "note": "FieldCraft's accepted results for this case, written by `cargo xtask oracle --bless`. A result outside its band fails CI.", + "values": { + "lateral": { + "band": 1.8685628057277872e-10, + "value": -0.18685628056417355 + }, + "sigma": { + "band": 8.060135422217968e-9, + "value": 8.060135422217968 + } + } +} diff --git a/tests/oracle/nl-neo-hookean-uniaxial/recipe.json b/tests/oracle/nl-neo-hookean-uniaxial/recipe.json new file mode 100644 index 0000000..fafa572 --- /dev/null +++ b/tests/oracle/nl-neo-hookean-uniaxial/recipe.json @@ -0,0 +1,16 @@ +[ + {"command": "mesh.block", "params": {"body": "Cube", "kind": "hex20", "corners": [[0, 0, 0], [1, 0, 0], [1, 1, 0], [0, 1, 0], [0, 0, 1], [1, 0, 1], [1, 1, 1], [0, 1, 1]], "divisions": [2, 2, 2], "faces": {"6": "x0", "3": "y0", "1": "z0", "4": "x1"}}}, + {"command": "model.set.create", "params": {"name": "all", "geometry": [{"body": "Cube"}]}}, + {"command": "model.set.create", "params": {"name": "x0", "geometry": [{"body": "Cube", "face": "x0"}]}}, + {"command": "model.set.create", "params": {"name": "y0", "geometry": [{"body": "Cube", "face": "y0"}]}}, + {"command": "model.set.create", "params": {"name": "z0", "geometry": [{"body": "Cube", "face": "z0"}]}}, + {"command": "model.set.create", "params": {"name": "x1", "geometry": [{"body": "Cube", "face": "x1"}]}}, + {"command": "model.material.create", "params": {"name": "Rubber", "elastic": {"type": "isotropic", "young": 10.0, "poisson": 0.3}, "hyperelastic": {"type": "neo_hookean"}}}, + {"command": "model.section.create", "params": {"name": "cube", "set": "all", "material": "Rubber", "kind": {"type": "solid"}}}, + {"command": "model.boundary_condition.create", "params": {"name": "sx", "type": "symmetry", "target": {"set": "x0"}, "plane": "x"}}, + {"command": "model.boundary_condition.create", "params": {"name": "sy", "type": "symmetry", "target": {"set": "y0"}, "plane": "y"}}, + {"command": "model.boundary_condition.create", "params": {"name": "sz", "type": "symmetry", "target": {"set": "z0"}, "plane": "z"}}, + {"command": "model.boundary_condition.create", "params": {"name": "pull", "type": "displacement", "target": {"set": "x1"}, "values": [1.0, null, null, null, null, null]}}, + {"command": "model.step.create", "params": {"name": "Stretch", "procedure": {"type": "nonlinear_static"}, "boundary_conditions": ["sx", "sy", "sz", "pull"], "loads": []}}, + {"command": "solve.nonlinear", "params": {"step": "Stretch"}, "id": "solve"} +] diff --git a/tests/oracle/nl-patch-hex8/README.md b/tests/oracle/nl-patch-hex8/README.md new file mode 100644 index 0000000..384cffb --- /dev/null +++ b/tests/oracle/nl-patch-hex8/README.md @@ -0,0 +1,7 @@ +# Nonlinear patch test, hex8 + +A unit cube of 3 × 3 × 3 hex8 elements whose non-corner nodes are moved off the lattice, so no +element is a parallelepiped. Every boundary node is prescribed u = (F − I) X with +F = [[1.3, 0.2, -0.1], [-0.15, 0.9, 0.25], [0.05, -0.2, 1.1]] (stretch, shear and rotation, J = 1.389000); the eight inner nodes are free. The neo-Hookean +material (E = 100, ν = 0.3) must take the homogeneous deformation: the inner node 22 moves by +(F − I) X and the Cauchy stress is uniform. diff --git a/tests/oracle/nl-patch-hex8/expected.json b/tests/oracle/nl-patch-hex8/expected.json new file mode 100644 index 0000000..3cea86b --- /dev/null +++ b/tests/oracle/nl-patch-hex8/expected.json @@ -0,0 +1,178 @@ +{ + "title": "Nonlinear patch test, hex8: a homogeneous finite deformation of a distorted mesh", + "kind": "theory", + "source": "The patch test (B. M. Irons, A. Razzaque, in A. K. Aziz (ed.), The Mathematical Foundations of the Finite Element Method, Academic Press 1972, 557–587) at finite strain: a boundary moved by x = F X makes F the solution everywhere (J. Bonet, R. D. Wood, Nonlinear Continuum Mechanics for Finite Element Analysis, 2nd ed., Cambridge 2008, §8); the neo-Hookean Cauchy stress σ = μ J^(−5/3) dev b + κ (J − 1) I of that F", + "quantities": [ + { + "id": "ux", + "quantity": "u_x at inner node 22", + "measure": { + "command": "solve.probe", + "params": { + "step": "Deform", + "nodes": [ + 22 + ] + }, + "pointer": "/nodes/0/displacement/0" + }, + "value": 0.13583340405268285, + "tolerance": { + "relative": 1e-08 + }, + "reason": "a patch test is passed exactly: the tolerance admits rounding and the Newton tolerance" + }, + { + "id": "uy", + "quantity": "u_y at inner node 22", + "measure": { + "command": "solve.probe", + "params": { + "step": "Deform", + "nodes": [ + 22 + ] + }, + "pointer": "/nodes/0/displacement/1" + }, + "value": 0.0003487491373645457, + "tolerance": { + "relative": 1e-08 + }, + "reason": "a patch test is passed exactly: the tolerance admits rounding and the Newton tolerance" + }, + { + "id": "uz", + "quantity": "u_z at inner node 22", + "measure": { + "command": "solve.probe", + "params": { + "step": "Deform", + "nodes": [ + 22 + ] + }, + "pointer": "/nodes/0/displacement/2" + }, + "value": -0.002398508020922785, + "tolerance": { + "relative": 1e-08 + }, + "reason": "a patch test is passed exactly: the tolerance admits rounding and the Newton tolerance" + }, + { + "id": "sxx", + "quantity": "Cauchy σ_xx at inner node 22", + "measure": { + "command": "solve.probe", + "params": { + "step": "Deform", + "nodes": [ + 22 + ] + }, + "pointer": "/nodes/0/stress/0" + }, + "value": 42.29617970634737, + "tolerance": { + "relative": 1e-07 + }, + "reason": "a patch test is passed exactly: the tolerance admits rounding and the Newton tolerance" + }, + { + "id": "syy", + "quantity": "Cauchy σ_yy at inner node 22", + "measure": { + "command": "solve.probe", + "params": { + "step": "Deform", + "nodes": [ + 22 + ] + }, + "pointer": "/nodes/0/stress/1" + }, + "value": 23.501008557686546, + "tolerance": { + "relative": 1e-07 + }, + "reason": "a patch test is passed exactly: the tolerance admits rounding and the Newton tolerance" + }, + { + "id": "szz", + "quantity": "Cauchy σ_zz at inner node 22", + "measure": { + "command": "solve.probe", + "params": { + "step": "Deform", + "nodes": [ + 22 + ] + }, + "pointer": "/nodes/0/stress/2" + }, + "value": 31.452811735966126, + "tolerance": { + "relative": 1e-07 + }, + "reason": "a patch test is passed exactly: the tolerance admits rounding and the Newton tolerance" + }, + { + "id": "sxy", + "quantity": "Cauchy σ_xy at inner node 22", + "measure": { + "command": "solve.probe", + "params": { + "step": "Deform", + "nodes": [ + 22 + ] + }, + "pointer": "/nodes/0/stress/3" + }, + "value": -0.8897122437235885, + "tolerance": { + "relative": 1e-07 + }, + "reason": "a patch test is passed exactly: the tolerance admits rounding and the Newton tolerance" + }, + { + "id": "sxz", + "quantity": "Cauchy σ_xz at inner node 22", + "measure": { + "command": "solve.probe", + "params": { + "step": "Deform", + "nodes": [ + 22 + ] + }, + "pointer": "/nodes/0/stress/4" + }, + "value": -1.8906385179126266, + "tolerance": { + "relative": 1e-07 + }, + "reason": "a patch test is passed exactly: the tolerance admits rounding and the Newton tolerance" + }, + { + "id": "syz", + "quantity": "Cauchy σ_yz at inner node 22", + "measure": { + "command": "solve.probe", + "params": { + "step": "Deform", + "nodes": [ + 22 + ] + }, + "pointer": "/nodes/0/stress/5" + }, + "value": 1.9462455331453503, + "tolerance": { + "relative": 1e-07 + }, + "reason": "a patch test is passed exactly: the tolerance admits rounding and the Newton tolerance" + } + ] +} diff --git a/tests/oracle/nl-patch-hex8/fixture.json b/tests/oracle/nl-patch-hex8/fixture.json new file mode 100644 index 0000000..372753d --- /dev/null +++ b/tests/oracle/nl-patch-hex8/fixture.json @@ -0,0 +1,41 @@ +{ + "note": "FieldCraft's accepted results for this case, written by `cargo xtask oracle --bless`. A result outside its band fails CI.", + "values": { + "sxx": { + "band": 4.2296179707574264e-8, + "value": 42.29617970757426 + }, + "sxy": { + "band": 8.89712243927903e-10, + "value": -0.8897122439279029 + }, + "sxz": { + "band": 1.8906385180297377e-9, + "value": -1.8906385180297376 + }, + "syy": { + "band": 2.3501008558807953e-8, + "value": 23.501008558807953 + }, + "syz": { + "band": 1.9462455331453503e-9, + "value": 1.9462455329577204 + }, + "szz": { + "band": 3.14528117370872e-8, + "value": 31.452811737087195 + }, + "ux": { + "band": 1.3583340405308903e-10, + "value": 0.13583340405308902 + }, + "uy": { + "band": 3.4874913736454575e-13, + "value": 0.0003487491350470007 + }, + "uz": { + "band": 2.3985080233668645e-12, + "value": -0.002398508023366864 + } + } +} diff --git a/tests/oracle/nl-patch-hex8/recipe.json b/tests/oracle/nl-patch-hex8/recipe.json new file mode 100644 index 0000000..fea87e6 --- /dev/null +++ b/tests/oracle/nl-patch-hex8/recipe.json @@ -0,0 +1,210 @@ +[ + {"command": "mesh.node.add", "params": {"label": 1, "xyz": [0.0, 0.0, 0.0]}}, + {"command": "mesh.node.add", "params": {"label": 2, "xyz": [0.2962451065991113, 0.0, 0.0]}}, + {"command": "mesh.node.add", "params": {"label": 3, "xyz": [0.6111177857270027, 0.0, 0.0]}}, + {"command": "mesh.node.add", "params": {"label": 4, "xyz": [1.0, 0.0, 0.0]}}, + {"command": "mesh.node.add", "params": {"label": 5, "xyz": [0.0, 0.2910009137991098, 0.0]}}, + {"command": "mesh.node.add", "params": {"label": 6, "xyz": [0.3571377677211701, 0.2737737705050953, 0.0]}}, + {"command": "mesh.node.add", "params": {"label": 7, "xyz": [0.714575893424076, 0.2779668080365649, 0.0]}}, + {"command": "mesh.node.add", "params": {"label": 8, "xyz": [1.0, 0.2966218598767702, 0.0]}}, + {"command": "mesh.node.add", "params": {"label": 9, "xyz": [0.0, 0.6967279180541397, 0.0]}}, + {"command": "mesh.node.add", "params": {"label": 10, "xyz": [0.3333333333333333, 0.7184592286655991, 0.0]}}, + {"command": "mesh.node.add", "params": {"label": 11, "xyz": [0.6295784399324447, 0.7261031080083589, 0.0]}}, + {"command": "mesh.node.add", "params": {"label": 12, "xyz": [1.0, 0.7142867384976158, 0.0]}}, + {"command": "mesh.node.add", "params": {"label": 13, "xyz": [0.0, 1.0, 0.0]}}, + {"command": "mesh.node.add", "params": {"label": 14, "xyz": [0.31800086721172344, 1.0, 0.0]}}, + {"command": "mesh.node.add", "params": {"label": 15, "xyz": [0.6904711010545035, 1.0, 0.0]}}, + {"command": "mesh.node.add", "params": {"label": 16, "xyz": [1.0, 1.0, 0.0]}}, + {"command": "mesh.node.add", "params": {"label": 17, "xyz": [0.0, 0.0, 0.31040904830229277]}}, + {"command": "mesh.node.add", "params": {"label": 18, "xyz": [0.2777844523936694, 0.0, 0.340800598743757]}}, + {"command": "mesh.node.add", "params": {"label": 19, "xyz": [0.6089828171538932, 0.0, 0.37600300670769227]}}, + {"command": "mesh.node.add", "params": {"label": 20, "xyz": [1.0, 0.0, 0.39127279992629]}}, + {"command": "mesh.node.add", "params": {"label": 21, "xyz": [0.0, 0.2737737705050953, 0.3696657255165094]}}, + {"command": "mesh.node.add", "params": {"label": 22, "xyz": [0.38124256009074275, 0.2779668080365649, 0.34132725581852985]}}, + {"command": "mesh.node.add", "params": {"label": 23, "xyz": [0.7261665552938148, 0.2966218598767702, 0.31090073344351915]}}, + {"command": "mesh.node.add", "params": {"label": 24, "xyz": [1.0, 0.33381112436048954, 0.28130120256419844]}}, + {"command": "mesh.node.add", "params": {"label": 25, "xyz": [0.0, 0.7184592286655991, 0.28103878698851803]}}, + {"command": "mesh.node.add", "params": {"label": 26, "xyz": [0.2962451065991113, 0.7261031080083589, 0.31040904830229277]}}, + {"command": "mesh.node.add", "params": {"label": 27, "xyz": [0.6111177857270027, 0.7142867384976158, 0.340800598743757]}}, + {"command": "mesh.node.add", "params": {"label": 28, "xyz": [1.0, 0.6815367191456442, 0.37600300670769227]}}, + {"command": "mesh.node.add", "params": {"label": 29, "xyz": [0.0, 1.0, 0.3914085136552225]}}, + {"command": "mesh.node.add", "params": {"label": 30, "xyz": [0.3571377677211701, 1.0, 0.3696657255165094]}}, + {"command": "mesh.node.add", "params": {"label": 31, "xyz": [0.714575893424076, 1.0, 0.34132725581852985]}}, + {"command": "mesh.node.add", "params": {"label": 32, "xyz": [1.0, 1.0, 0.31090073344351915]}}, + {"command": "mesh.node.add", "params": {"label": 33, "xyz": [0.0, 0.0, 0.6741339320770904]}}, + {"command": "mesh.node.add", "params": {"label": 34, "xyz": [0.2756494838205599, 0.0, 0.7093363400410255]}}, + {"command": "mesh.node.add", "params": {"label": 35, "xyz": [0.6246741854110541, 0.0, 0.7246061332596233]}}, + {"command": "mesh.node.add", "params": {"label": 36, "xyz": [1.0, 0.0, 0.7247418469885558]}}, + {"command": "mesh.node.add", "params": {"label": 37, "xyz": [0.0, 0.2779668080365649, 0.6746605891518631]}}, + {"command": "mesh.node.add", "params": {"label": 38, "xyz": [0.3928332219604814, 0.2966218598767702, 0.6442340667768525]}}, + {"command": "mesh.node.add", "params": {"label": 39, "xyz": [0.7182163755580564, 0.33381112436048954, 0.6146345358975318]}}, + {"command": "mesh.node.add", "params": {"label": 40, "xyz": [1.0, 0.3633945847208064, 0.6066672542736244]}}, + {"command": "mesh.node.add", "params": {"label": 41, "xyz": [0.0, 0.7261031080083589, 0.6437423816356261]}}, + {"command": "mesh.node.add", "params": {"label": 42, "xyz": [0.2777844523936694, 0.7142867384976158, 0.6741339320770904]}}, + {"command": "mesh.node.add", "params": {"label": 43, "xyz": [0.6089828171538932, 0.6815367191456442, 0.7093363400410255]}}, + {"command": "mesh.node.add", "params": {"label": 44, "xyz": [1.0, 0.6508727591847184, 0.7246061332596233]}}, + {"command": "mesh.node.add", "params": {"label": 45, "xyz": [0.0, 1.0, 0.7029990588498427]}}, + {"command": "mesh.node.add", "params": {"label": 46, "xyz": [0.38124256009074275, 1.0, 0.6746605891518631]}}, + {"command": "mesh.node.add", "params": {"label": 47, "xyz": [0.7261665552938148, 1.0, 0.6442340667768525]}}, + {"command": "mesh.node.add", "params": {"label": 48, "xyz": [1.0, 1.0, 0.6146345358975318]}}, + {"command": "mesh.node.add", "params": {"label": 49, "xyz": [0.0, 0.0, 1.0]}}, + {"command": "mesh.node.add", "params": {"label": 50, "xyz": [0.29134085207772076, 0.0, 1.0]}}, + {"command": "mesh.node.add", "params": {"label": 51, "xyz": [0.6513342005450568, 0.0, 1.0]}}, + {"command": "mesh.node.add", "params": {"label": 52, "xyz": [1.0, 0.0, 1.0]}}, + {"command": "mesh.node.add", "params": {"label": 53, "xyz": [0.0, 0.2966218598767702, 1.0]}}, + {"command": "mesh.node.add", "params": {"label": 54, "xyz": [0.3848830422247231, 0.33381112436048954, 1.0]}}, + {"command": "mesh.node.add", "params": {"label": 55, "xyz": [0.6963134677349831, 0.3633945847208064, 1.0]}}, + {"command": "mesh.node.add", "params": {"label": 56, "xyz": [1.0, 0.3851258953322657, 1.0]}}, + {"command": "mesh.node.add", "params": {"label": 57, "xyz": [0.0, 0.7142867384976158, 1.0]}}, + {"command": "mesh.node.add", "params": {"label": 58, "xyz": [0.2756494838205599, 0.6815367191456442, 1.0]}}, + {"command": "mesh.node.add", "params": {"label": 59, "xyz": [0.6246741854110541, 0.6508727591847184, 1.0]}}, + {"command": "mesh.node.add", "params": {"label": 60, "xyz": [1.0, 0.6243342471324431, 1.0]}}, + {"command": "mesh.node.add", "params": {"label": 61, "xyz": [0.0, 1.0, 1.0]}}, + {"command": "mesh.node.add", "params": {"label": 62, "xyz": [0.3928332219604814, 1.0, 1.0]}}, + {"command": "mesh.node.add", "params": {"label": 63, "xyz": [0.7182163755580564, 1.0, 1.0]}}, + {"command": "mesh.node.add", "params": {"label": 64, "xyz": [1.0, 1.0, 1.0]}}, + {"command": "mesh.element.add", "params": {"label": 1, "kind": "hex8", "nodes": [1, 2, 6, 5, 17, 18, 22, 21]}}, + {"command": "mesh.element.add", "params": {"label": 2, "kind": "hex8", "nodes": [2, 3, 7, 6, 18, 19, 23, 22]}}, + {"command": "mesh.element.add", "params": {"label": 3, "kind": "hex8", "nodes": [3, 4, 8, 7, 19, 20, 24, 23]}}, + {"command": "mesh.element.add", "params": {"label": 4, "kind": "hex8", "nodes": [5, 6, 10, 9, 21, 22, 26, 25]}}, + {"command": "mesh.element.add", "params": {"label": 5, "kind": "hex8", "nodes": [6, 7, 11, 10, 22, 23, 27, 26]}}, + {"command": "mesh.element.add", "params": {"label": 6, "kind": "hex8", "nodes": [7, 8, 12, 11, 23, 24, 28, 27]}}, + {"command": "mesh.element.add", "params": {"label": 7, "kind": "hex8", "nodes": [9, 10, 14, 13, 25, 26, 30, 29]}}, + {"command": "mesh.element.add", "params": {"label": 8, "kind": "hex8", "nodes": [10, 11, 15, 14, 26, 27, 31, 30]}}, + {"command": "mesh.element.add", "params": {"label": 9, "kind": "hex8", "nodes": [11, 12, 16, 15, 27, 28, 32, 31]}}, + {"command": "mesh.element.add", "params": {"label": 10, "kind": "hex8", "nodes": [17, 18, 22, 21, 33, 34, 38, 37]}}, + {"command": "mesh.element.add", "params": {"label": 11, "kind": "hex8", "nodes": [18, 19, 23, 22, 34, 35, 39, 38]}}, + {"command": "mesh.element.add", "params": {"label": 12, "kind": "hex8", "nodes": [19, 20, 24, 23, 35, 36, 40, 39]}}, + {"command": "mesh.element.add", "params": {"label": 13, "kind": "hex8", "nodes": [21, 22, 26, 25, 37, 38, 42, 41]}}, + {"command": "mesh.element.add", "params": {"label": 14, "kind": "hex8", "nodes": [22, 23, 27, 26, 38, 39, 43, 42]}}, + {"command": "mesh.element.add", "params": {"label": 15, "kind": "hex8", "nodes": [23, 24, 28, 27, 39, 40, 44, 43]}}, + {"command": "mesh.element.add", "params": {"label": 16, "kind": "hex8", "nodes": [25, 26, 30, 29, 41, 42, 46, 45]}}, + {"command": "mesh.element.add", "params": {"label": 17, "kind": "hex8", "nodes": [26, 27, 31, 30, 42, 43, 47, 46]}}, + {"command": "mesh.element.add", "params": {"label": 18, "kind": "hex8", "nodes": [27, 28, 32, 31, 43, 44, 48, 47]}}, + {"command": "mesh.element.add", "params": {"label": 19, "kind": "hex8", "nodes": [33, 34, 38, 37, 49, 50, 54, 53]}}, + {"command": "mesh.element.add", "params": {"label": 20, "kind": "hex8", "nodes": [34, 35, 39, 38, 50, 51, 55, 54]}}, + {"command": "mesh.element.add", "params": {"label": 21, "kind": "hex8", "nodes": [35, 36, 40, 39, 51, 52, 56, 55]}}, + {"command": "mesh.element.add", "params": {"label": 22, "kind": "hex8", "nodes": [37, 38, 42, 41, 53, 54, 58, 57]}}, + {"command": "mesh.element.add", "params": {"label": 23, "kind": "hex8", "nodes": [38, 39, 43, 42, 54, 55, 59, 58]}}, + {"command": "mesh.element.add", "params": {"label": 24, "kind": "hex8", "nodes": [39, 40, 44, 43, 55, 56, 60, 59]}}, + {"command": "mesh.element.add", "params": {"label": 25, "kind": "hex8", "nodes": [41, 42, 46, 45, 57, 58, 62, 61]}}, + {"command": "mesh.element.add", "params": {"label": 26, "kind": "hex8", "nodes": [42, 43, 47, 46, 58, 59, 63, 62]}}, + {"command": "mesh.element.add", "params": {"label": 27, "kind": "hex8", "nodes": [43, 44, 48, 47, 59, 60, 64, 63]}}, + {"command": "model.set.create", "params": {"name": "all", "elements": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27]}}, + {"command": "model.material.create", "params": {"name": "Rubber", "elastic": {"type": "isotropic", "young": 100.0, "poisson": 0.3}, "hyperelastic": {"type": "neo_hookean"}}}, + {"command": "model.section.create", "params": {"name": "s", "set": "all", "material": "Rubber", "kind": {"type": "solid"}}}, + {"command": "model.set.create", "params": {"name": "n1", "nodes": [1]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n1", "type": "displacement", "target": {"set": "n1"}, "values": [0.0, 0.0, 0.0, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n2", "nodes": [2]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n2", "type": "displacement", "target": {"set": "n2"}, "values": [0.08887353197973341, -0.04443676598986669, 0.014812255329955566, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n3", "nodes": [3]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n3", "type": "displacement", "target": {"set": "n3"}, "values": [0.1833353357181008, -0.09166766785905041, 0.030555889286350137, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n4", "nodes": [4]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n4", "type": "displacement", "target": {"set": "n4"}, "values": [0.30000000000000004, -0.15, 0.05, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n5", "nodes": [5]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n5", "type": "displacement", "target": {"set": "n5"}, "values": [0.058200182759821965, -0.029100091379910986, -0.058200182759821965, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n6", "nodes": [6]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n6", "type": "displacement", "target": {"set": "n6"}, "values": [0.16189608441737013, -0.08094804220868504, -0.036897865714960565, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n7", "nodes": [7]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n7", "type": "displacement", "target": {"set": "n7"}, "values": [0.2699661296345358, -0.1349830648172679, -0.019864566936109183, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n8", "nodes": [8]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n8", "type": "displacement", "target": {"set": "n8"}, "values": [0.35932437197535405, -0.179662185987677, -0.009324371975354039, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n9", "nodes": [9]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n9", "type": "displacement", "target": {"set": "n9"}, "values": [0.13934558361082794, -0.06967279180541397, -0.13934558361082794, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n10", "nodes": [10]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n10", "type": "displacement", "target": {"set": "n10"}, "values": [0.2436918457331198, -0.12184592286655993, -0.12702517906645316, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n11", "nodes": [11]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n11", "type": "displacement", "target": {"set": "n11"}, "values": [0.33409415358140526, -0.16704707679070263, -0.11374169960504955, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n12", "nodes": [12]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n12", "type": "displacement", "target": {"set": "n12"}, "values": [0.44285734769952323, -0.22142867384976161, -0.09285734769952315, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n13", "nodes": [13]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n13", "type": "displacement", "target": {"set": "n13"}, "values": [0.2, -0.09999999999999998, -0.2, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n14", "nodes": [14]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n14", "type": "displacement", "target": {"set": "n14"}, "values": [0.295400260163517, -0.14770013008175853, -0.18409995663941384, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n15", "nodes": [15]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n15", "type": "displacement", "target": {"set": "n15"}, "values": [0.40714133031635114, -0.20357066515817546, -0.16547644494727484, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n16", "nodes": [16]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n16", "type": "displacement", "target": {"set": "n16"}, "values": [0.5, -0.25, -0.15000000000000002, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n17", "nodes": [17]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n17", "type": "displacement", "target": {"set": "n17"}, "values": [-0.03104090483022928, 0.07760226207557319, 0.03104090483022931, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n18", "nodes": [18]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n18", "type": "displacement", "target": {"set": "n18"}, "values": [0.04925527584372513, 0.04353248182688885, 0.047969282494059184, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n19", "nodes": [19]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n19", "type": "displacement", "target": {"set": "n19"}, "values": [0.1450945444753987, 0.002653329103839086, 0.06804944152846393, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n20", "nodes": [20]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n20", "type": "displacement", "target": {"set": "n20"}, "values": [0.26087272000737105, -0.052181800018427496, 0.08912727999262904, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n21", "nodes": [21]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n21", "type": "displacement", "target": {"set": "n21"}, "values": [0.017788181549368128, 0.06503905432861784, -0.017788181549368065, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n24", "nodes": [24]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n24", "type": "displacement", "target": {"set": "n24"}, "values": [0.33863210461567816, -0.11305581179499935, 0.011367895384321924, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n25", "nodes": [25]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n25", "type": "displacement", "target": {"set": "n25"}, "values": [0.11558796703426802, -0.0015862261194303784, -0.11558796703426799, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n28", "nodes": [28]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n28", "type": "displacement", "target": {"set": "n28"}, "values": [0.3987070431583597, -0.12415292023764135, -0.04870704315835961, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n29", "nodes": [29]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n29", "type": "displacement", "target": {"set": "n29"}, "values": [0.16085914863447776, -0.0021478715861943387, -0.1608591486344777, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n30", "nodes": [30]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n30", "type": "displacement", "target": {"set": "n30"}, "values": [0.2701747577647001, -0.06115423377904816, -0.14517653906229053, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n31", "nodes": [31]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n31", "type": "displacement", "target": {"set": "n31"}, "values": [0.3802400424453698, -0.12185457005897893, -0.13013847974694318, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n32", "nodes": [32]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n32", "type": "displacement", "target": {"set": "n32"}, "values": [0.46890992665564823, -0.17227481663912014, -0.11890992665564809, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n33", "nodes": [33]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n33", "type": "displacement", "target": {"set": "n33"}, "values": [-0.06741339320770905, 0.1685334830192726, 0.06741339320770912, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n34", "nodes": [34]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n34", "type": "displacement", "target": {"set": "n34"}, "values": [0.011761211142065409, 0.1359866624371724, 0.08471610819513054, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n35", "nodes": [35]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n35", "type": "displacement", "target": {"set": "n35"}, "values": [0.11494164229735393, 0.08745040550324772, 0.10369432259651512, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n36", "nodes": [36]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n36", "type": "displacement", "target": {"set": "n36"}, "values": [0.22752581530114435, 0.03118546174713896, 0.12247418469885574, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n37", "nodes": [37]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n37", "type": "displacement", "target": {"set": "n37"}, "values": [-0.011872697307873326, 0.14086846648430928, 0.011872697307873437, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n40", "nodes": [40]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n40", "type": "displacement", "target": {"set": "n40"}, "values": [0.3120121915167988, -0.034672644903674554, 0.03798780848320127, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n41", "nodes": [41]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n41", "type": "displacement", "target": {"set": "n41"}, "values": [0.08084638343810917, 0.08832528460807065, -0.08084638343810913, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n44", "nodes": [44]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n44", "type": "displacement", "target": {"set": "n44"}, "values": [0.3577139385109813, -0.03393574260356602, -0.007713938510981233, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n45", "nodes": [45]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n45", "type": "displacement", "target": {"set": "n45"}, "values": [0.12970009411501573, 0.07574976471246075, -0.1297000941150157, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n46", "nodes": [46]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n46", "type": "displacement", "target": {"set": "n46"}, "values": [0.2469067091120365, 0.011478763274354487, -0.11347181308027643, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n47", "nodes": [47]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n47", "type": "displacement", "target": {"set": "n47"}, "values": [0.35342655991045935, -0.04786646659985905, -0.09926826555762391, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n48", "nodes": [48]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n48", "type": "displacement", "target": {"set": "n48"}, "values": [0.43853654641024686, -0.09634136602561705, -0.08853654641024677, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n49", "nodes": [49]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n49", "type": "displacement", "target": {"set": "n49"}, "values": [-0.1, 0.25, 0.10000000000000009, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n50", "nodes": [50]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n50", "type": "displacement", "target": {"set": "n50"}, "values": [-0.012597744376683817, 0.2062988721883419, 0.11456704260388606, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n51", "nodes": [51]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n51", "type": "displacement", "target": {"set": "n51"}, "values": [0.0954002601635171, 0.1522998699182415, 0.13256671002725295, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n52", "nodes": [52]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n52", "type": "displacement", "target": {"set": "n52"}, "values": [0.19999999999999996, 0.1, 0.15000000000000013, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n53", "nodes": [53]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n53", "type": "displacement", "target": {"set": "n53"}, "values": [-0.040675628024645964, 0.22033781401232294, 0.04067562802464608, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n54", "nodes": [54]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n54", "type": "displacement", "target": {"set": "n54"}, "values": [0.08222713753951483, 0.1588864312302426, 0.05248192723913836, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n55", "nodes": [55]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n55", "type": "displacement", "target": {"set": "n55"}, "values": [0.18157295726465628, 0.10921352136767187, 0.06213675644258787, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n56", "nodes": [56]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n56", "type": "displacement", "target": {"set": "n56"}, "values": [0.2770251790664533, 0.06148741046677342, 0.07297482093354701, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n57", "nodes": [57]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n57", "type": "displacement", "target": {"set": "n57"}, "values": [0.04285734769952315, 0.1785713261502384, -0.042857347699523096, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n58", "nodes": [58]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n58", "type": "displacement", "target": {"set": "n58"}, "values": [0.11900218897529685, 0.14049890551235156, -0.022524869638100742, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n59", "nodes": [59]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n59", "type": "displacement", "target": {"set": "n59"}, "values": [0.21757680746025987, 0.09121159626987008, 0.0010591574336091814, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n60", "nodes": [60]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n60", "type": "displacement", "target": {"set": "n60"}, "values": [0.3248668494264886, 0.037566575286755666, 0.02513315057351151, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n61", "nodes": [61]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n61", "type": "displacement", "target": {"set": "n61"}, "values": [0.1, 0.1499999999999999, -0.09999999999999987, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n62", "nodes": [62]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n62", "type": "displacement", "target": {"set": "n62"}, "values": [0.21784996658814437, 0.09107501670592777, -0.08035833890197586, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n63", "nodes": [63]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n63", "type": "displacement", "target": {"set": "n63"}, "values": [0.31546491266741694, 0.042267543666291596, -0.06408918122209706, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n64", "nodes": [64]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n64", "type": "displacement", "target": {"set": "n64"}, "values": [0.40000000000000013, 0.0, -0.04999999999999993, null, null, null]}}, + {"command": "model.step.create", "params": {"name": "Deform", "procedure": {"type": "nonlinear_static"}, "boundary_conditions": ["n1", "n2", "n3", "n4", "n5", "n6", "n7", "n8", "n9", "n10", "n11", "n12", "n13", "n14", "n15", "n16", "n17", "n18", "n19", "n20", "n21", "n24", "n25", "n28", "n29", "n30", "n31", "n32", "n33", "n34", "n35", "n36", "n37", "n40", "n41", "n44", "n45", "n46", "n47", "n48", "n49", "n50", "n51", "n52", "n53", "n54", "n55", "n56", "n57", "n58", "n59", "n60", "n61", "n62", "n63", "n64"], "loads": []}}, + {"command": "solve.nonlinear", "params": {"step": "Deform"}, "id": "solve"} +] diff --git a/tests/oracle/nl-rigid-rotation/README.md b/tests/oracle/nl-rigid-rotation/README.md new file mode 100644 index 0000000..c874e38 --- /dev/null +++ b/tests/oracle/nl-rigid-rotation/README.md @@ -0,0 +1,6 @@ +# Rigid rotation: objectivity + +The distorted 3 × 3 × 3 hex8 cube of nl-patch-hex8 (neo-Hookean, E = 1000, ν = 0.3) with every +boundary node prescribed the motion of a 90° rotation about the axis (1, 1, 1)/√3, applied in +one ramp (the intermediate states are not rigid; the end state is). The inner nodes must follow +the rotation and the stress must vanish. diff --git a/tests/oracle/nl-rigid-rotation/expected.json b/tests/oracle/nl-rigid-rotation/expected.json new file mode 100644 index 0000000..2993b58 --- /dev/null +++ b/tests/oracle/nl-rigid-rotation/expected.json @@ -0,0 +1,83 @@ +{ + "title": "A quarter turn strains and stresses nothing (objectivity)", + "kind": "theory", + "source": "Objectivity of the total Lagrangian formulation and of the hyperelastic stress: a rigid motion x = R X + c gives C = I and σ = 0 whatever the rotation (Bonet & Wood 2008, §3.4 and §5.2; T. Belytschko, W. K. Liu, B. Moran, Nonlinear Finite Elements for Continua and Structures, 2nd ed., Wiley 2014, §5.5)", + "quantities": [ + { + "id": "ux", + "quantity": "u_x at inner node 22: the rotation's", + "measure": { + "command": "solve.probe", + "params": { + "step": "Turn", + "nodes": [ + 22 + ] + }, + "pointer": "/nodes/0/displacement/0" + }, + "value": -0.011149180525904245, + "tolerance": { + "absolute": 1e-09 + }, + "reason": "the inner nodes follow the rigid rotation exactly" + }, + { + "id": "uy", + "quantity": "u_y at inner node 22: the rotation's", + "measure": { + "command": "solve.probe", + "params": { + "step": "Turn", + "nodes": [ + 22 + ] + }, + "pointer": "/nodes/0/displacement/1" + }, + "value": 0.07859051161172886, + "tolerance": { + "absolute": 1e-09 + }, + "reason": "the inner nodes follow the rigid rotation exactly" + }, + { + "id": "uz", + "quantity": "u_z at inner node 22: the rotation's", + "measure": { + "command": "solve.probe", + "params": { + "step": "Turn", + "nodes": [ + 22 + ] + }, + "pointer": "/nodes/0/displacement/2" + }, + "value": -0.06744133108582467, + "tolerance": { + "absolute": 1e-09 + }, + "reason": "the inner nodes follow the rigid rotation exactly" + }, + { + "id": "von_mises", + "quantity": "von Mises stress at inner node 22", + "measure": { + "command": "solve.probe", + "params": { + "step": "Turn", + "nodes": [ + 22 + ] + }, + "pointer": "/nodes/0/von_mises" + }, + "value": 0.0, + "tolerance": { + "absolute": 1e-08 + }, + "reason": "zero up to rounding of stresses of order E = 1000: a 90° turn leaves no strain" + } + ] +} diff --git a/tests/oracle/nl-rigid-rotation/fixture.json b/tests/oracle/nl-rigid-rotation/fixture.json new file mode 100644 index 0000000..98d76ad --- /dev/null +++ b/tests/oracle/nl-rigid-rotation/fixture.json @@ -0,0 +1,21 @@ +{ + "note": "FieldCraft's accepted results for this case, written by `cargo xtask oracle --bless`. A result outside its band fails CI.", + "values": { + "ux": { + "band": 1.2149180525904365e-11, + "value": -0.011149180525904363 + }, + "uy": { + "band": 7.959051161172887e-11, + "value": 0.07859051161172881 + }, + "uz": { + "band": 6.84413310858248e-11, + "value": -0.0674413310858248 + }, + "von_mises": { + "band": 1e-8, + "value": 4.868377314671631e-13 + } + } +} diff --git a/tests/oracle/nl-rigid-rotation/recipe.json b/tests/oracle/nl-rigid-rotation/recipe.json new file mode 100644 index 0000000..163c16d --- /dev/null +++ b/tests/oracle/nl-rigid-rotation/recipe.json @@ -0,0 +1,210 @@ +[ + {"command": "mesh.node.add", "params": {"label": 1, "xyz": [0.0, 0.0, 0.0]}}, + {"command": "mesh.node.add", "params": {"label": 2, "xyz": [0.2962451065991113, 0.0, 0.0]}}, + {"command": "mesh.node.add", "params": {"label": 3, "xyz": [0.6111177857270027, 0.0, 0.0]}}, + {"command": "mesh.node.add", "params": {"label": 4, "xyz": [1.0, 0.0, 0.0]}}, + {"command": "mesh.node.add", "params": {"label": 5, "xyz": [0.0, 0.2910009137991098, 0.0]}}, + {"command": "mesh.node.add", "params": {"label": 6, "xyz": [0.3571377677211701, 0.2737737705050953, 0.0]}}, + {"command": "mesh.node.add", "params": {"label": 7, "xyz": [0.714575893424076, 0.2779668080365649, 0.0]}}, + {"command": "mesh.node.add", "params": {"label": 8, "xyz": [1.0, 0.2966218598767702, 0.0]}}, + {"command": "mesh.node.add", "params": {"label": 9, "xyz": [0.0, 0.6967279180541397, 0.0]}}, + {"command": "mesh.node.add", "params": {"label": 10, "xyz": [0.3333333333333333, 0.7184592286655991, 0.0]}}, + {"command": "mesh.node.add", "params": {"label": 11, "xyz": [0.6295784399324447, 0.7261031080083589, 0.0]}}, + {"command": "mesh.node.add", "params": {"label": 12, "xyz": [1.0, 0.7142867384976158, 0.0]}}, + {"command": "mesh.node.add", "params": {"label": 13, "xyz": [0.0, 1.0, 0.0]}}, + {"command": "mesh.node.add", "params": {"label": 14, "xyz": [0.31800086721172344, 1.0, 0.0]}}, + {"command": "mesh.node.add", "params": {"label": 15, "xyz": [0.6904711010545035, 1.0, 0.0]}}, + {"command": "mesh.node.add", "params": {"label": 16, "xyz": [1.0, 1.0, 0.0]}}, + {"command": "mesh.node.add", "params": {"label": 17, "xyz": [0.0, 0.0, 0.31040904830229277]}}, + {"command": "mesh.node.add", "params": {"label": 18, "xyz": [0.2777844523936694, 0.0, 0.340800598743757]}}, + {"command": "mesh.node.add", "params": {"label": 19, "xyz": [0.6089828171538932, 0.0, 0.37600300670769227]}}, + {"command": "mesh.node.add", "params": {"label": 20, "xyz": [1.0, 0.0, 0.39127279992629]}}, + {"command": "mesh.node.add", "params": {"label": 21, "xyz": [0.0, 0.2737737705050953, 0.3696657255165094]}}, + {"command": "mesh.node.add", "params": {"label": 22, "xyz": [0.38124256009074275, 0.2779668080365649, 0.34132725581852985]}}, + {"command": "mesh.node.add", "params": {"label": 23, "xyz": [0.7261665552938148, 0.2966218598767702, 0.31090073344351915]}}, + {"command": "mesh.node.add", "params": {"label": 24, "xyz": [1.0, 0.33381112436048954, 0.28130120256419844]}}, + {"command": "mesh.node.add", "params": {"label": 25, "xyz": [0.0, 0.7184592286655991, 0.28103878698851803]}}, + {"command": "mesh.node.add", "params": {"label": 26, "xyz": [0.2962451065991113, 0.7261031080083589, 0.31040904830229277]}}, + {"command": "mesh.node.add", "params": {"label": 27, "xyz": [0.6111177857270027, 0.7142867384976158, 0.340800598743757]}}, + {"command": "mesh.node.add", "params": {"label": 28, "xyz": [1.0, 0.6815367191456442, 0.37600300670769227]}}, + {"command": "mesh.node.add", "params": {"label": 29, "xyz": [0.0, 1.0, 0.3914085136552225]}}, + {"command": "mesh.node.add", "params": {"label": 30, "xyz": [0.3571377677211701, 1.0, 0.3696657255165094]}}, + {"command": "mesh.node.add", "params": {"label": 31, "xyz": [0.714575893424076, 1.0, 0.34132725581852985]}}, + {"command": "mesh.node.add", "params": {"label": 32, "xyz": [1.0, 1.0, 0.31090073344351915]}}, + {"command": "mesh.node.add", "params": {"label": 33, "xyz": [0.0, 0.0, 0.6741339320770904]}}, + {"command": "mesh.node.add", "params": {"label": 34, "xyz": [0.2756494838205599, 0.0, 0.7093363400410255]}}, + {"command": "mesh.node.add", "params": {"label": 35, "xyz": [0.6246741854110541, 0.0, 0.7246061332596233]}}, + {"command": "mesh.node.add", "params": {"label": 36, "xyz": [1.0, 0.0, 0.7247418469885558]}}, + {"command": "mesh.node.add", "params": {"label": 37, "xyz": [0.0, 0.2779668080365649, 0.6746605891518631]}}, + {"command": "mesh.node.add", "params": {"label": 38, "xyz": [0.3928332219604814, 0.2966218598767702, 0.6442340667768525]}}, + {"command": "mesh.node.add", "params": {"label": 39, "xyz": [0.7182163755580564, 0.33381112436048954, 0.6146345358975318]}}, + {"command": "mesh.node.add", "params": {"label": 40, "xyz": [1.0, 0.3633945847208064, 0.6066672542736244]}}, + {"command": "mesh.node.add", "params": {"label": 41, "xyz": [0.0, 0.7261031080083589, 0.6437423816356261]}}, + {"command": "mesh.node.add", "params": {"label": 42, "xyz": [0.2777844523936694, 0.7142867384976158, 0.6741339320770904]}}, + {"command": "mesh.node.add", "params": {"label": 43, "xyz": [0.6089828171538932, 0.6815367191456442, 0.7093363400410255]}}, + {"command": "mesh.node.add", "params": {"label": 44, "xyz": [1.0, 0.6508727591847184, 0.7246061332596233]}}, + {"command": "mesh.node.add", "params": {"label": 45, "xyz": [0.0, 1.0, 0.7029990588498427]}}, + {"command": "mesh.node.add", "params": {"label": 46, "xyz": [0.38124256009074275, 1.0, 0.6746605891518631]}}, + {"command": "mesh.node.add", "params": {"label": 47, "xyz": [0.7261665552938148, 1.0, 0.6442340667768525]}}, + {"command": "mesh.node.add", "params": {"label": 48, "xyz": [1.0, 1.0, 0.6146345358975318]}}, + {"command": "mesh.node.add", "params": {"label": 49, "xyz": [0.0, 0.0, 1.0]}}, + {"command": "mesh.node.add", "params": {"label": 50, "xyz": [0.29134085207772076, 0.0, 1.0]}}, + {"command": "mesh.node.add", "params": {"label": 51, "xyz": [0.6513342005450568, 0.0, 1.0]}}, + {"command": "mesh.node.add", "params": {"label": 52, "xyz": [1.0, 0.0, 1.0]}}, + {"command": "mesh.node.add", "params": {"label": 53, "xyz": [0.0, 0.2966218598767702, 1.0]}}, + {"command": "mesh.node.add", "params": {"label": 54, "xyz": [0.3848830422247231, 0.33381112436048954, 1.0]}}, + {"command": "mesh.node.add", "params": {"label": 55, "xyz": [0.6963134677349831, 0.3633945847208064, 1.0]}}, + {"command": "mesh.node.add", "params": {"label": 56, "xyz": [1.0, 0.3851258953322657, 1.0]}}, + {"command": "mesh.node.add", "params": {"label": 57, "xyz": [0.0, 0.7142867384976158, 1.0]}}, + {"command": "mesh.node.add", "params": {"label": 58, "xyz": [0.2756494838205599, 0.6815367191456442, 1.0]}}, + {"command": "mesh.node.add", "params": {"label": 59, "xyz": [0.6246741854110541, 0.6508727591847184, 1.0]}}, + {"command": "mesh.node.add", "params": {"label": 60, "xyz": [1.0, 0.6243342471324431, 1.0]}}, + {"command": "mesh.node.add", "params": {"label": 61, "xyz": [0.0, 1.0, 1.0]}}, + {"command": "mesh.node.add", "params": {"label": 62, "xyz": [0.3928332219604814, 1.0, 1.0]}}, + {"command": "mesh.node.add", "params": {"label": 63, "xyz": [0.7182163755580564, 1.0, 1.0]}}, + {"command": "mesh.node.add", "params": {"label": 64, "xyz": [1.0, 1.0, 1.0]}}, + {"command": "mesh.element.add", "params": {"label": 1, "kind": "hex8", "nodes": [1, 2, 6, 5, 17, 18, 22, 21]}}, + {"command": "mesh.element.add", "params": {"label": 2, "kind": "hex8", "nodes": [2, 3, 7, 6, 18, 19, 23, 22]}}, + {"command": "mesh.element.add", "params": {"label": 3, "kind": "hex8", "nodes": [3, 4, 8, 7, 19, 20, 24, 23]}}, + {"command": "mesh.element.add", "params": {"label": 4, "kind": "hex8", "nodes": [5, 6, 10, 9, 21, 22, 26, 25]}}, + {"command": "mesh.element.add", "params": {"label": 5, "kind": "hex8", "nodes": [6, 7, 11, 10, 22, 23, 27, 26]}}, + {"command": "mesh.element.add", "params": {"label": 6, "kind": "hex8", "nodes": [7, 8, 12, 11, 23, 24, 28, 27]}}, + {"command": "mesh.element.add", "params": {"label": 7, "kind": "hex8", "nodes": [9, 10, 14, 13, 25, 26, 30, 29]}}, + {"command": "mesh.element.add", "params": {"label": 8, "kind": "hex8", "nodes": [10, 11, 15, 14, 26, 27, 31, 30]}}, + {"command": "mesh.element.add", "params": {"label": 9, "kind": "hex8", "nodes": [11, 12, 16, 15, 27, 28, 32, 31]}}, + {"command": "mesh.element.add", "params": {"label": 10, "kind": "hex8", "nodes": [17, 18, 22, 21, 33, 34, 38, 37]}}, + {"command": "mesh.element.add", "params": {"label": 11, "kind": "hex8", "nodes": [18, 19, 23, 22, 34, 35, 39, 38]}}, + {"command": "mesh.element.add", "params": {"label": 12, "kind": "hex8", "nodes": [19, 20, 24, 23, 35, 36, 40, 39]}}, + {"command": "mesh.element.add", "params": {"label": 13, "kind": "hex8", "nodes": [21, 22, 26, 25, 37, 38, 42, 41]}}, + {"command": "mesh.element.add", "params": {"label": 14, "kind": "hex8", "nodes": [22, 23, 27, 26, 38, 39, 43, 42]}}, + {"command": "mesh.element.add", "params": {"label": 15, "kind": "hex8", "nodes": [23, 24, 28, 27, 39, 40, 44, 43]}}, + {"command": "mesh.element.add", "params": {"label": 16, "kind": "hex8", "nodes": [25, 26, 30, 29, 41, 42, 46, 45]}}, + {"command": "mesh.element.add", "params": {"label": 17, "kind": "hex8", "nodes": [26, 27, 31, 30, 42, 43, 47, 46]}}, + {"command": "mesh.element.add", "params": {"label": 18, "kind": "hex8", "nodes": [27, 28, 32, 31, 43, 44, 48, 47]}}, + {"command": "mesh.element.add", "params": {"label": 19, "kind": "hex8", "nodes": [33, 34, 38, 37, 49, 50, 54, 53]}}, + {"command": "mesh.element.add", "params": {"label": 20, "kind": "hex8", "nodes": [34, 35, 39, 38, 50, 51, 55, 54]}}, + {"command": "mesh.element.add", "params": {"label": 21, "kind": "hex8", "nodes": [35, 36, 40, 39, 51, 52, 56, 55]}}, + {"command": "mesh.element.add", "params": {"label": 22, "kind": "hex8", "nodes": [37, 38, 42, 41, 53, 54, 58, 57]}}, + {"command": "mesh.element.add", "params": {"label": 23, "kind": "hex8", "nodes": [38, 39, 43, 42, 54, 55, 59, 58]}}, + {"command": "mesh.element.add", "params": {"label": 24, "kind": "hex8", "nodes": [39, 40, 44, 43, 55, 56, 60, 59]}}, + {"command": "mesh.element.add", "params": {"label": 25, "kind": "hex8", "nodes": [41, 42, 46, 45, 57, 58, 62, 61]}}, + {"command": "mesh.element.add", "params": {"label": 26, "kind": "hex8", "nodes": [42, 43, 47, 46, 58, 59, 63, 62]}}, + {"command": "mesh.element.add", "params": {"label": 27, "kind": "hex8", "nodes": [43, 44, 48, 47, 59, 60, 64, 63]}}, + {"command": "model.set.create", "params": {"name": "all", "elements": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27]}}, + {"command": "model.material.create", "params": {"name": "Rubber", "elastic": {"type": "isotropic", "young": 1000.0, "poisson": 0.3}, "hyperelastic": {"type": "neo_hookean"}}}, + {"command": "model.section.create", "params": {"name": "s", "set": "all", "material": "Rubber", "kind": {"type": "solid"}}}, + {"command": "model.set.create", "params": {"name": "n1", "nodes": [1]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n1", "type": "displacement", "target": {"set": "n1"}, "values": [0.0, 0.0, 0.0, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n2", "nodes": [2]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n2", "type": "displacement", "target": {"set": "n2"}, "values": [-0.1974967377327409, 0.26978556090747674, -0.07228882317473585, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n3", "nodes": [3]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n3", "type": "displacement", "target": {"set": "n3"}, "values": [-0.4074118571513352, 0.5565349466717207, -0.14912308952038547, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n4", "nodes": [4]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n4", "type": "displacement", "target": {"set": "n4"}, "values": [-0.6666666666666669, 0.9106836025229592, -0.24401693585629242, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n5", "nodes": [5]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n5", "type": "displacement", "target": {"set": "n5"}, "values": [-0.07100915131663986, -0.1940006091994066, 0.2650097605160464, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n6", "nodes": [6]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n6", "type": "displacement", "target": {"set": "n6"}, "values": [-0.304897281743924, 0.1427236619019261, 0.16217361984199785, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n7", "nodes": [7]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n7", "type": "displacement", "target": {"set": "n7"}, "values": [-0.544212537716221, 0.4654413435417897, 0.07877119417443118, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n8", "nodes": [8]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n8", "type": "displacement", "target": {"set": "n8"}, "values": [-0.7390474240217908, 0.7129356959384456, 0.026111728083345054, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n9", "nodes": [9]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n9", "type": "displacement", "target": {"set": "n9"}, "values": [-0.17001341168910516, -0.4644852787027599, 0.634498690391865, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n10", "nodes": [10]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n10", "type": "displacement", "target": {"set": "n10"}, "values": [-0.3975384417388771, -0.1754116182694132, 0.5729500600082902, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n11", "nodes": [11]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n11", "type": "displacement", "target": {"set": "n11"}, "values": [-0.5969004154868935, 0.08927802307622379, 0.5076223924106696, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n12", "nodes": [12]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n12", "type": "displacement", "target": {"set": "n12"}, "values": [-0.8409647279176399, 0.43449244352454863, 0.4064722843930913, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n13", "nodes": [13]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n13", "type": "displacement", "target": {"set": "n13"}, "values": [-0.24401693585629242, -0.6666666666666669, 0.9106836025229592, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n14", "nodes": [14]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n14", "type": "displacement", "target": {"set": "n14"}, "values": [-0.45601751399744145, -0.3770684913088693, 0.8330860053063107, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n15", "nodes": [15]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n15", "type": "displacement", "target": {"set": "n15"}, "values": [-0.7043310032259615, -0.037865956920357435, 0.7421969601463189, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n16", "nodes": [16]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n16", "type": "displacement", "target": {"set": "n16"}, "values": [-0.9106836025229592, 0.24401693585629225, 0.6666666666666667, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n17", "nodes": [17]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n17", "type": "displacement", "target": {"set": "n17"}, "values": [0.28268443036365526, -0.07574506482879335, -0.20693936553486192, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n18", "nodes": [18]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n18", "type": "displacement", "target": {"set": "n18"}, "values": [0.1251718820768331, 0.16981262798729288, -0.29498451006412607, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n19", "nodes": [19]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n19", "type": "displacement", "target": {"set": "n19"}, "values": [-0.06356877206123668, 0.46283956423072403, -0.3992707921694874, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n20", "nodes": [20]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n20", "type": "displacement", "target": {"set": "n20"}, "values": [-0.310340943660548, 0.8152064128010338, -0.5048654691404858, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n21", "nodes": [21]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n21", "type": "displacement", "target": {"set": "n21"}, "values": [0.26984307804616103, -0.2727205446350288, 0.002877466588867783, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n24", "nodes": [24]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n24", "type": "displacement", "target": {"set": "n24"}, "values": [-0.49194584184265233, 0.6195005954468935, -0.12755475360424126, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n25", "nodes": [25]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n25", "type": "displacement", "target": {"set": "n25"}, "values": [0.08062119546673135, -0.547551042768107, 0.46692984730137566, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n28", "nodes": [28]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n28", "type": "displacement", "target": {"set": "n28"}, "values": [-0.49055339583811186, 0.36457468818963223, 0.12597870764847952, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n29", "nodes": [29]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n29", "type": "displacement", "target": {"set": "n29"}, "values": [0.11243237941740247, -0.76217697283688, 0.6497445934194774, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n30", "nodes": [30]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n30", "type": "displacement", "target": {"set": "n30"}, "values": [-0.14546026636110104, -0.43163185539297577, 0.5770921217540765, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n31", "nodes": [31]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n31", "type": "displacement", "target": {"set": "n31"}, "values": [-0.4095597298375821, -0.09920374885624161, 0.5087634786938237, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n32", "nodes": [32]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n32", "type": "displacement", "target": {"set": "n32"}, "values": [-0.627551402563585, 0.1681518915259308, 0.4593995110376539, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n33", "nodes": [33]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n33", "type": "displacement", "target": {"set": "n33"}, "values": [0.6139227178469325, -0.16450009646220556, -0.44942262138472705, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n34", "nodes": [34]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n34", "type": "displacement", "target": {"set": "n34"}, "values": [0.46221465100197195, 0.07793938477097354, -0.5401540357729455, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n35", "nodes": [35]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n35", "type": "displacement", "target": {"set": "n35"}, "values": [0.24343746690640233, 0.3920643692325442, -0.6355018361389466, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n36", "nodes": [36]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n36", "type": "displacement", "target": {"set": "n36"}, "values": [-0.00665615055198554, 0.7338343177339819, -0.7271781671819965, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n37", "nodes": [37]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n37", "type": "displacement", "target": {"set": "n37"}, "values": [0.5465737270422439, -0.3499398150655486, -0.19663391197669544, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n40", "nodes": [40]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n40", "type": "displacement", "target": {"set": "n40"}, "values": [-0.20285917908239148, 0.5203834615702214, -0.31752428248783016, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n41", "nodes": [41]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n41", "type": "displacement", "target": {"set": "n41"}, "values": [0.4090641756727114, -0.6411527821197969, 0.2320886064470854, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n44", "nodes": [44]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n44", "type": "displacement", "target": {"set": "n44"}, "values": [-0.1656037191481471, 0.29995226139245723, -0.13434854224431025, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n45", "nodes": [45]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n45", "type": "displacement", "target": {"set": "n45"}, "values": [0.3961927796273322, -0.8382103429170629, 0.4420175632897305, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n46", "nodes": [46]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n46", "type": "displacement", "target": {"set": "n46"}, "values": [0.11622369322562642, -0.48410392831599214, 0.3678802350903656, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n47", "nodes": [47]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n47", "type": "displacement", "target": {"set": "n47"}, "values": [-0.14143457191847508, -0.16256271500913355, 0.3039972869276085, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n48", "nodes": [48]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n48", "type": "displacement", "target": {"set": "n48"}, "values": [-0.350946009136768, 0.09403569973512238, 0.2569103094016455, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n49", "nodes": [49]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n49", "type": "displacement", "target": {"set": "n49"}, "values": [0.9106836025229592, -0.24401693585629242, -0.6666666666666669, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n50", "nodes": [50]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n50", "type": "displacement", "target": {"set": "n50"}, "values": [0.7164563678044786, 0.021302400875954863, -0.7377587686804337, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n51", "nodes": [51]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n51", "type": "displacement", "target": {"set": "n51"}, "values": [0.47646080215958786, 0.3491424403424915, -0.8256032425020795, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n52", "nodes": [52]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n52", "type": "displacement", "target": {"set": "n52"}, "values": [0.24401693585629225, 0.6666666666666667, -0.9106836025229592, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n53", "nodes": [53]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n53", "type": "displacement", "target": {"set": "n53"}, "values": [0.8383028451678353, -0.44176484244080594, -0.3965380027270293, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n54", "nodes": [54]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n54", "type": "displacement", "target": {"set": "n54"}, "values": [0.5726393399852867, -0.11605100998674517, -0.4565883299985416, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n55", "nodes": [55]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n55", "type": "displacement", "target": {"set": "n55"}, "values": [0.3578001909626294, 0.14784126494531863, -0.5056414559079481, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n56", "nodes": [56]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n56", "type": "displacement", "target": {"set": "n56"}, "values": [0.15003969495840175, 0.4099160697784896, -0.5599557647368913, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n57", "nodes": [57]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n57", "type": "displacement", "target": {"set": "n57"}, "values": [0.7363855412719862, -0.720208094854703, -0.016177446417283137, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n58", "nodes": [58]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n58", "type": "displacement", "target": {"set": "n58"}, "values": [0.5606107780964487, -0.44734528366075366, -0.11326549443569511, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n59", "nodes": [59]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n59", "type": "displacement", "target": {"set": "n59"}, "values": [0.33541016925367084, -0.10905157107287111, -0.22635859818079984, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n60", "nodes": [60]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n60", "type": "displacement", "target": {"set": "n60"}, "values": [0.09166880592088833, 0.250443835245038, -0.34211264116592655, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n61", "nodes": [61]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n61", "type": "displacement", "target": {"set": "n61"}, "values": [0.6666666666666667, -0.9106836025229592, 0.24401693585629225, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n62", "nodes": [62]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n62", "type": "displacement", "target": {"set": "n62"}, "values": [0.40477785202634575, -0.5529368287572868, 0.1481589767309408, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n63", "nodes": [63]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n63", "type": "displacement", "target": {"set": "n63"}, "values": [0.18785574962796237, -0.25661572623876583, 0.06875997661080335, null, null, null]}}, + {"command": "model.set.create", "params": {"name": "n64", "nodes": [64]}}, + {"command": "model.boundary_condition.create", "params": {"name": "n64", "type": "displacement", "target": {"set": "n64"}, "values": [0.0, 0.0, 0.0, null, null, null]}}, + {"command": "model.step.create", "params": {"name": "Turn", "procedure": {"type": "nonlinear_static"}, "boundary_conditions": ["n1", "n2", "n3", "n4", "n5", "n6", "n7", "n8", "n9", "n10", "n11", "n12", "n13", "n14", "n15", "n16", "n17", "n18", "n19", "n20", "n21", "n24", "n25", "n28", "n29", "n30", "n31", "n32", "n33", "n34", "n35", "n36", "n37", "n40", "n41", "n44", "n45", "n46", "n47", "n48", "n49", "n50", "n51", "n52", "n53", "n54", "n55", "n56", "n57", "n58", "n59", "n60", "n61", "n62", "n63", "n64"], "loads": []}}, + {"command": "solve.nonlinear", "params": {"step": "Turn"}, "id": "solve"} +]