diff --git a/ROADMAP.md b/ROADMAP.md index 038c8d3..cf5f833 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -33,7 +33,7 @@ pressure) is a degree of freedom of the existing DOF framework, not a separate s | M4 Own solver and first results | Element library per docs/elements.md (1D and 2D first); Linear static and modal solver (tet4/10, wedge6, hex8, hex20; sparse direct, Lanczos), verified against analytic solutions (solver: done — `fieldcraft-fem` kernels, `fieldcraft-solver` with nested dissection, sparse Cholesky and block Lanczos, `solve.static`/`solve.frequency`/`solve.probe`, patch, cantilever, Lamé, Kirsch and beam-frequency tests; reference points with kinematic and distributing couplings and moments by master–slave constraint elimination, verified by rigid motion, clamping, Saint-Venant tension, bending and tube torsion; 1D elements I: rod2/rod3 trusses, point masses, rotary inertia, springs and dashpots in both solvers and all three decks, verified by the method of joints, the three-bar truss, spring–mass, two-mass chain and torsional pendulum frequencies, and damped decay; 2D elements: plane stress, plane strain and axisymmetric tri3, tri6, quad4 (incompatible modes QM6), quad8 with two degrees of freedom per node, centrifugal loads, `mesh.planar` 2D meshes of polygons and planar faces, verified by patch tests, Kirsch, Lamé (plane strain and axisymmetric), rotating discs and cylinders, and a plane stress cantilever; deck mapping to Abaqus CPS/CPE/CAX, Nastran membranes, LS-DYNA ELFORM 12/13); shells and beams (done: quad4 MITC4 and tri3 MITC3 flat shells with a Hughes–Brezzi drilling rotation, two-node Timoshenko beams with profile properties and orientations, six degrees of freedom at shell and beam nodes shared with solids and trusses, section forces and surface stresses, verified by shell patch tests, Navier's plate, cantilever and portal-frame beams, and the Scordelis–Lo and pinched-cylinder benchmarks); results display (done: `results.*` commands, deformed shape to scale, banded contours of displacement, von Mises, principal and component stresses with a legend, mode shapes with their frequencies and animation, probing a node by clicking it, reaction force and moment sums per set, stale results marked after an edit; explicit steps: field frames by slider or animation with contours per frame, energy histories plotted) | started | | M5 Structured hex | 2D quad meshing of faces (`fieldcraft-mesh::quad`: transfinite mapped meshes, free all-quad meshes of polygons with holes on prescribed boundary nodes, exact planar quad validity, shared `SizeField` and even edge divisions; done for planar faces); mapped hex of six-sided regions (trivariate TFI, curved faces) and sweep meshing (multi-level extrusions with imprinted cross-sections, revolutions, one-to-one sweeps through linking faces; interval assignment, hex8/hex20 on the geometry, B-rep face tags, `mesh.hex.generate`/`sweep`/`mapped`: done, 16 of 21 corpus parts all-hex); conforming interfaces between cells (done: `mesh.hex.blocks` meshes a part split with SolidCraft's Split Body into mapped blocks as one conforming mesh — composite faces for seams and tangent faces, interval assignment over all cells, shared faces meshed once, grading off holes and fillets, free-internal-face check; the filleted bracket in 30 cells, hex20 within 0.1 % of a fine tet10 tip deflection); sweepable cells in a conforming mesh and tet–hex transition; automatic decomposition into sweepable and mappable regions, proposed as SolidCraft splits | started | | M6 Automatic hex | Octree/grid all-hex for any part (first version: done — `fieldcraft-mesh::octree`, `mesh.hex.octree`: 3-refinement grid with conforming templates refined by curvature, thickness and narrow faces, a core cleared to a manifold boundary, feature map onto it, padding and a pillow per patch capturing every sharp curve, foldover-free fitting, certified validity, B-rep face tags; the corpus hex column and the filleted-bracket oracle case; next: transitions for concave refined regions so thin and curved parts stop over-refining); hex-dominant by tet recombination; polycube for blocky parts; layers through thin walls; mesh editing and orphan-mesh import | started | -| M7 Assemblies, contact and friction | Needs M15. Part instances from SolidCraft occurrences; tie between non-matching meshes (mortar); implicit contact: surface-to-surface mortar and node-to-surface, penalty and augmented Lagrange, self-contact, automatic pair detection (mortar contact pairs with Coulomb friction in nonlinear static steps: done — segment-to-segment mortar with the consistent tangent by automatic differentiation of the segmentation, augmented Lagrangian with Uzawa updates to a gap tolerance, semismooth active set with a chattering cutback, small sliding without nonlinear geometry and finite sliding with it, overclosure adjusted or refused, Coulomb friction (stick/slip return map, static and kinetic coefficients, symmetrised tangent), pressure, gap, status, shear and slip output; verified by the contact patch test, Hertz cylinder and sphere, Newton's quadratic rate and sliding blocks; the linear analyses refuse contact by name); friction: Coulomb with stick–slip, static/kinetic, anisotropic, pressure-, rate- and temperature-dependent coefficients; contact output (pressure, slip, status); thermal contact conductance and frictional heating; wear (Archard); bolt pretension, connectors with behaviour (elastic, damped, stops, locks); amplitudes, multiple steps, restart; nonlinear steps in all three decks. Verified by Hertz (sphere and cylinder), the Cattaneo–Mindlin partial-slip problem, the sliding block, NAFEMS contact benchmarks | started | +| M7 Assemblies, contact and friction | Needs M15. Part instances from SolidCraft occurrences; tie between non-matching meshes (mortar: done — `interaction.tie`, dual mortar constraints in the implicit analyses, Abaqus `*TIE` and LS-DYNA tied contact, the tie patch test); implicit contact: surface-to-surface mortar and node-to-surface, penalty and augmented Lagrange, self-contact, automatic pair detection (mortar contact pairs with Coulomb friction in nonlinear static steps: done — segment-to-segment mortar with the consistent tangent by automatic differentiation of the segmentation, augmented Lagrangian with Uzawa updates to a gap tolerance, semismooth active set with a chattering cutback, small sliding without nonlinear geometry and finite sliding with it, overclosure adjusted or refused, Coulomb friction (stick/slip return map, static and kinetic coefficients, symmetrised tangent), pressure, gap, status, shear and slip output; verified by the contact patch test, Hertz cylinder and sphere, Newton's quadratic rate and sliding blocks; the linear analyses refuse contact by name); friction: Coulomb with stick–slip, static/kinetic, anisotropic, pressure-, rate- and temperature-dependent coefficients; contact output (pressure, slip, status); thermal contact conductance and frictional heating; wear (Archard); bolt pretension, connectors with behaviour (elastic, damped, stops, locks); amplitudes, multiple steps, restart; nonlinear steps in all three decks. Verified by Hertz (sphere and cylinder), the Cattaneo–Mindlin partial-slip problem, the sliding block, NAFEMS contact benchmarks | started | | M8 Materials, explicit, shells, composites | Plasticity, hyperelasticity, damage data per solver; explicit dynamics decks (Abaqus/Explicit, LS-DYNA); midsurface shells; composite layups and material orientations, continuum shells on swept hex; hybrid (mixed u–p) hex8/hex20/tet10 for nearly incompressible materials (done); heat transfer (solids done: steady and θ-method transient conduction with flux, convection and sources, thermal strain in static steps (solids and 2D) and explicit dynamics (with plasticity), coupled temperature–displacement, `solve.heat`; deck output, 2D/shell/beam conduction planned) | started | | M9 Post-processing and deck readers | Results readers for public formats (Nastran OP2, LS-DYNA d3plot, Abaqus `.fil`); XY and path plots, cuts, display groups, free-body forces; deck readers that keep unknown keywords; mesh convergence studies | planned | | M10 Explicit dynamics | Shared element and material kernels with the implicit solver (`fem`); central-difference solver with lumped mass, stable time step, one-point hex8 with hourglass control and nodal-pressure tet4, bulk viscosity, energy accounting (X1 core: done — `fieldcraft-explicit`, `explicit_dynamic` steps with initial velocities, prescribed motion and planar rigid walls, `solve.explicit`/`solve.history`, small-strain linear elastic; bar wave, rigid-wall impact, energy balance and cantilever-period tests); large-deformation materials (X2: done — updated Lagrangian elements, Jaumann/Hughes–Winget and Green–Naghdi/Flanagan–Taylor rates, J2 bilinear/table plasticity, Johnson–Cook strength with heating and damage, erosion; materials gain `plastic`, `damage`, `erosion` with `model.material.plasticity`/`damage`; Dienes shear, rigid rotation, J2 uniaxial and Taylor-bar tests); contact (X3: done — `interaction.contact.pair`/`general`/`find`, segment-to-segment penalty contact both ways with polygon clipping (passes the contact patch test on non-matching meshes), pairs, general (all exterior faces) and self contact, bucket-grid search, deterministic on any thread count, a penalty from the masses and the stable increment that never shortens it, Coulomb friction with exponential decay by a return map, friction on rigid walls, contact energy and friction dissipation in the balance, initial penetrations adjusted or refused; Abaqus `*CONTACT PAIR`/`*CONTACT`/`*FRICTION` and LS-DYNA automatic contacts in the decks; verified by colliding bars, sliding blocks, the patch test and Hertz's sphere impact); hyperelastic materials (neo-Hookean, Mooney–Rivlin, Yeoh) on the shared material point with average nodal pressure tets, and opt-in mass scaling with the added mass reported: done; runs on hex and tet meshes | started | @@ -77,7 +77,7 @@ What exists and what is missing, by area; each gap is in a milestone above. | Area | Today | Missing | |---|---|---| | Solution procedures | Linear static, nonlinear static (solids with geometric and material nonlinearity: hyperelasticity, J2 plasticity), frequency (Lanczos), steady and transient heat, coupled temperature–displacement, explicit dynamics, LBM flow | Nonlinear shells and beams, arc-length, buckling (M15); implicit, harmonic, random and spectrum dynamics (M16) | -| Contact, friction, adhesion | Explicit deformable contact (pairs, general, self; segment to segment, penalty) with Coulomb friction and exponential decay; rigid walls with friction; implicit mortar contact pairs (augmented Lagrangian, Coulomb friction) in nonlinear static steps; couplings, springs, dashpots | Implicit self contact, tie, anisotropic and pressure- or temperature-dependent friction, thermal contact, wear, eroding contact (M7, M10); cohesive adhesion and debonding (M20) | +| Contact, friction, adhesion | Explicit deformable contact (pairs, general, self; segment to segment, penalty) with Coulomb friction and exponential decay; rigid walls with friction; implicit mortar contact pairs (augmented Lagrangian, Coulomb friction) in nonlinear static steps; ties between non-matching meshes (dual mortar); couplings, springs, dashpots | Implicit self contact, anisotropic and pressure- or temperature-dependent friction, thermal contact, wear, eroding contact (M7, M10); cohesive adhesion and debonding (M20) | | Materials | Isotropic and orthotropic elasticity, density, thermal, J2 plasticity (bilinear, table, Johnson–Cook), Johnson–Cook damage and erosion, compressible neo-Hookean, Mooney–Rivlin and Yeoh hyperelasticity, Newtonian fluids | Elastomers beyond Yeoh (Ogden, Arruda–Boyce 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) | diff --git a/docs/fem.md b/docs/fem.md index 38b85fb..c48fd44 100644 --- a/docs/fem.md +++ b/docs/fem.md @@ -544,6 +544,30 @@ with small sliding and 3% with finite sliding, where the block turns a little, a slipping; `tests/oracle/nl-friction-sliding-blocks`); initial overclosure adjusted and refused; bit-for-bit results on one and four threads; the refusals. +## Ties (non-matching meshes) + +**Model** (`fieldcraft_model::tie`): a tie names a `main` and a `secondary` surface (sets of +element faces) and an optional position tolerance; commands `interaction.tie|tie.edit|tie.delete`. +Abaqus writes `*TIE, ADJUST=NO` (secondary surface first, `POSITION TOLERANCE` when given), +LS-DYNA `*CONTACT_TIED_SURFACE_TO_SURFACE` between segment sets; Nastran refuses ties by name. + +**Constraints** (`fieldcraft_solver::tie`): dual mortar. Each secondary face's dual shape +functions ψ_a = Σ_b A_ab N_b, A = D M⁻¹ (M_ab = ∫ N_a N_b, D = diag ∫ N_a), are biorthogonal to its +own, so the secondary mortar matrix is diagonal and each secondary node becomes the weighted +average of the main nodes under it, u_A = Σ_J (M_AJ/Σ_K M_AK) u_J with M_AJ = ∫ ψ_A N_J over the +overlaps of the reference configuration (`fieldcraft_fem::mortar`). The rows go to the constraint +elimination like a coupling's, the secondary node the intended dependent, in linear static, +frequency, buckling and nonlinear steps (small-displacement constraints). Dividing by the sum +keeps rigid motions exact at a surface's edge where a face is only partly covered. Main faces +count when the secondary face overlaps them along its normal with a mean gap within the position +tolerance (default half the main element's thickness); uncovered secondary nodes stay free with a +warning. Heat transfer and explicit dynamics refuse ties by name. + +**Verification** (`crates/solver/tests/contact.rs`, `tests/oracle/tie-patch`): a linear field +across non-matching hex8/tet4 meshes reproduced to round-off (to 10⁻⁶ on distorted quadrilateral +faces, where the overlap integration is accurate to its degree) in linear and nonlinear static +steps; uniaxial tension across a tie, σ_zz = Eε in every element to 10⁻⁹. + ## Hyperelastic materials in explicit dynamics Hyperelastic materials (neo-Hookean, Mooney–Rivlin, Yeoh) use the shared finite-strain material diff --git a/docs/oracle.md b/docs/oracle.md index 6fdf25c..601f90b 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. -**225 of 231 quantities pass** (6 known failure(s)) in 65 active cases: 56 theory, 9 published benchmark, 0 experiment; 10 pending cases wait for capabilities still being built. +**232 of 238 quantities pass** (6 known failure(s)) in 66 active cases: 57 theory, 9 published benchmark, 0 experiment; 10 pending cases wait for capabilities still being built. ## Theory: closed-form solutions, patch tests and mesh invariants @@ -211,6 +211,13 @@ Generated by `cargo xtask oracle` from [`tests/oracle/`](../tests/oracle/); the | [rotating-disc-plane-stress](../tests/oracle/rotating-disc-plane-stress/) | hoop stress σ_θ = σ_yy at the bore (20, 0) | 65.312 | 65.188 | -0.19% | 1% | pass | matches | | [rotating-disc-plane-stress](../tests/oracle/rotating-disc-plane-stress/) | radial stress σ_r = σ_xx at r = √(ab), its maximum | 20.724 | 20.683 | -0.2% | 1% | pass | matches | | [rotating-disc-plane-stress](../tests/oracle/rotating-disc-plane-stress/) | hoop stress σ_θ = σ_yy at the rim (100, 0) | 16.328 | 16.352 | 0.149% | 1% | pass | matches | +| [tie-patch](../tests/oracle/tie-patch/) | σ_zz of the lower block's corner element under the tie (element 10) | 10 | 10 | < 1e-7% | 1e-9 rel. | pass | matches | +| [tie-patch](../tests/oracle/tie-patch/) | σ_zz of the lower block's centre element under the tie (element 14) | 10 | 10 | < 1e-7% | 1e-9 rel. | pass | matches | +| [tie-patch](../tests/oracle/tie-patch/) | σ_zz of the lower block's bottom corner element (element 1) | 10 | 10 | < 1e-7% | 1e-9 rel. | pass | matches | +| [tie-patch](../tests/oracle/tie-patch/) | σ_zz of the upper block's corner element over the tie (element 19) | 10 | 10 | < 1e-7% | 1e-9 rel. | pass | matches | +| [tie-patch](../tests/oracle/tie-patch/) | σ_zz of the upper block's top far corner element (element 26) | 10 | 10 | < 1e-7% | 1e-9 rel. | pass | matches | +| [tie-patch](../tests/oracle/tie-patch/) | σ_xx of element 14 (uniaxial stress: 0) | 0 | ≈ 0 | ≈ 0 | ± 1.0000e-9 | pass | matches | +| [tie-patch](../tests/oracle/tie-patch/) | u_z at the tied secondary node (0.5, 0.5, 1) | 0.01 | 0.01 | < 1e-7% | 1e-9 rel. | pass | matches | | [tube-torsion-coupling](../tests/oracle/tube-torsion-coupling/) | rotation of the reference point about z | 0.056071 | 0.056071 | 0.000619% | 0.5% | pass | matches | | [tube-torsion-coupling](../tests/oracle/tube-torsion-coupling/) | surface shear stress τ_θz = σ_yz at (10, 0, 20) | 1078.3 | 1081.4 | 0.288% | 1% | pass | matches | @@ -311,6 +318,7 @@ Generated by `cargo xtask oracle` from [`tests/oracle/`](../tests/oracle/); the - **[rotating-cylinder-axisymmetric](../tests/oracle/rotating-cylinder-axisymmetric/)** (theory): Long rotating solid cylinder, axisymmetric. Source: Timoshenko and Goodier, Theory of Elasticity, 3rd ed., McGraw-Hill 1970, §32 (long rotating cylinder, ε_z = 0). Tolerances — radial_axis: stress extrapolated to the axis, where σ_r = σ_θ: under 1% with sixteen quadratic elements across; hoop_rim: stress extrapolated to the surface: under 1% - **[rotating-disc-plane-stress](../tests/oracle/rotating-disc-plane-stress/)** (theory): Rotating disc with a central hole, plane stress. Source: Timoshenko and Goodier, Theory of Elasticity, 3rd ed., McGraw-Hill 1970, §32 (rotating disc of uniform thickness with a hole). Tolerances — hoop_bore: stress extrapolated to the bore surface, where the a²b²/r² term is steepest: 16 radial quadratic elements graded towards the bore leave about 0.2% (8 uniform: −2.4%; 32 graded: −0.05%); radial_max: the nearest node to √(ab) is within half an element of it, where σ_r is stationary (an error of order (h/r)², under 0.5%), and nodal averaging adds a few tenths of a percent; hoop_rim: as at the bore - **[scordelis-lo-roof-solid](../tests/oracle/scordelis-lo-roof-solid/)** (benchmark): Scordelis–Lo roof with one layer of hex20 reduced-integration solids. Source: 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. 8 (p. 8) geometry, material and load; Table 5(a) (p. 11) reference displacement 0.3024; Belytschko et al., Computer Methods in Applied Mechanics and Engineering 51 (1985) 221–258 (shell obstacle course). Tolerances — uz: MacNeal and Harder grade an element A within 2% of the theoretical value on this prescribed coarse mesh (p. 14); MacNeal and Harder normalise by 0.3024 (the deep-shell value quoted in their [5] is 0.3086), and a solid model of R/t = 100 differs from shell theory by O(t/R) +- **[tie-patch](../tests/oracle/tie-patch/)** (theory): Tie patch test: two blocks with non-matching meshes tied together in uniaxial tension. Source: The patch test for mesh tying: a tie across non-matching meshes must transmit a constant stress exactly; B. I. Wohlmuth, A mortar finite element method using dual spaces for the Lagrange multiplier, SIAM J. Numer. Anal. 38(3):989–1012, 2000; M. A. Puso, A 3D mortar method for solid mechanics, IJNME 59:315–336, 2004. Uniaxial stress between frictionless symmetry planes is uniform in both blocks. Tolerances — szz_10: uniaxial stress E ε = 1000 × 0.01 is the exact discrete solution: the dual mortar conditions hold for the linear field on both meshes; szz_14: uniaxial stress E ε = 1000 × 0.01 is the exact discrete solution: the dual mortar conditions hold for the linear field on both meshes; szz_1: uniaxial stress E ε = 1000 × 0.01 is the exact discrete solution: the dual mortar conditions hold for the linear field on both meshes; szz_19: uniaxial stress E ε = 1000 × 0.01 is the exact discrete solution: the dual mortar conditions hold for the linear field on both meshes; szz_26: uniaxial stress E ε = 1000 × 0.01 is the exact discrete solution: the dual mortar conditions hold for the linear field on both meshes; sxx_14: the tie must not hold the lateral contraction of either mesh; uz_interface: the tied node follows the uniform strain field - **[tube-torsion-coupling](../tests/oracle/tube-torsion-coupling/)** (theory): Torsion of a tube through a kinematically coupled reference point. Source: Saint-Venant torsion of a circular tube, φ = TL/(GJ), τ = Tr/J with J = π(b⁴ − a⁴)/2; Timoshenko and Goodier, Theory of Elasticity, 3rd ed., 1970, §104. Tolerances — twist: Saint-Venant torsion of a circular tube is exact in elasticity; the rigid end coupling only stiffens a short zone near the tip; quadratic elements with 16 divisions around are within 0.1%; shear: stress extrapolated to the outer surface and averaged where two blocks meet: about 0.3% with four radial quadratic elements (two gave 1.1%) ## Pending cases diff --git a/docs/parity.md b/docs/parity.md index 7ddd34b..cbcabc2 100644 --- a/docs/parity.md +++ b/docs/parity.md @@ -54,7 +54,7 @@ products are run, no documentation text is copied). Status: **done**, **started* | 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, M15 | | started (nonlinear static with or without nonlinear geometry, increments, tolerances and a load path (cyclic loading), written to Abaqus `*STEP, NLGEOM` and LS-DYNA implicit (the load path as LS-DYNA's curve; refused by Abaqus for now), refused by Nastran; explicit dynamics; heat transfer; amplitudes per load planned) | -| Interaction | Tie between non-matching meshes | M7 | | planned | +| Interaction | Tie between non-matching meshes | M7 | | done (`interaction.tie`: dual mortar constraints in the implicit analyses, the tie patch test; Abaqus `*TIE`, LS-DYNA tied contact) | | Interaction | Contact (general and pairs), friction, automatic pair detection | M7, M10 | | started (explicit: pairs, general and self contact, segment to segment with a penalty that keeps the time increment, Coulomb friction with exponential decay, friction on rigid walls, `interaction.contact.find`, Abaqus and LS-DYNA contact keywords; implicit: mortar contact pairs in nonlinear static steps by an augmented Lagrangian with Coulomb friction, self contact next) | | 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) | | Interaction | Bolt pretension, connectors | M7 | | planned | diff --git a/docs/solvers/literature.md b/docs/solvers/literature.md index eefb52c..3793505 100644 --- a/docs/solvers/literature.md +++ b/docs/solvers/literature.md @@ -1329,6 +1329,11 @@ written from (cited again in the module docs); docs/fem.md describes the formula deformations*, CMAME 193:4891–4913, 2004; C. A. Coulomb's law, *Théorie des machines simples*, 1785. The tangent is symmetrised like the follower pressure's (the non-symmetric coupling to the pressure is left out; the residual is exact). +- Ties by dual mortar constraints: B. I. Wohlmuth, *A mortar finite element method using dual + spaces for the Lagrange multiplier*, SIAM J. Numer. Anal. 38(3):989–1012, 2000; A. Popp, B. I. + Wohlmuth, M. W. Gee, W. A. Wall, *Dual quadratic mortar finite element methods for 3D finite + deformation contact*, SIAM J. Sci. Comput. 34(4):B421–B446, 2012; mesh tying in solid + mechanics, M. A. Puso, *A 3D mortar method for solid mechanics*, IJNME 59:315–336, 2004. - The active set inside Newton (the max() of the regularised pressure, a semismooth Newton method): P. Alart, A. Curnier, *A mixed formulation for frictional contact problems prone to Newton like solution methods*, CMAME 92:353–375, 1991; Popp et al. 2009. diff --git a/tests/oracle/tie-patch/README.md b/tests/oracle/tie-patch/README.md new file mode 100644 index 0000000..cf8019d --- /dev/null +++ b/tests/oracle/tie-patch/README.md @@ -0,0 +1,7 @@ +# Tie patch test (non-matching meshes) + +Two unit cubes stacked along z, meshed independently: 3 × 3 × 2 hex8 below (graded in x and y), +2 × 2 × 2 above, so the nodes at z = 1 do not match. A tie bonds the upper block's bottom +(secondary) to the lower block's top (main). The faces x = 0 and y = 0 are symmetry planes, the +base z = 0 is held in z, and the top z = 2 is pulled up by 0.02 (E = 1000, ν = 0.3) in a linear +static step. The exact state is the uniaxial stress σ_zz = 10, uniform in both blocks. diff --git a/tests/oracle/tie-patch/expected.json b/tests/oracle/tie-patch/expected.json new file mode 100644 index 0000000..579ad63 --- /dev/null +++ b/tests/oracle/tie-patch/expected.json @@ -0,0 +1,144 @@ +{ + "title": "Tie patch test: two blocks with non-matching meshes tied together in uniaxial tension", + "kind": "theory", + "source": "The patch test for mesh tying: a tie across non-matching meshes must transmit a constant stress exactly; B. I. Wohlmuth, A mortar finite element method using dual spaces for the Lagrange multiplier, SIAM J. Numer. Anal. 38(3):989–1012, 2000; M. A. Puso, A 3D mortar method for solid mechanics, IJNME 59:315–336, 2004. Uniaxial stress between frictionless symmetry planes is uniform in both blocks", + "quantities": [ + { + "id": "szz_10", + "quantity": "σ_zz of the lower block's corner element under the tie (element 10)", + "measure": { + "command": "solve.probe", + "params": { + "step": "Pull", + "elements": [ + 10 + ] + }, + "pointer": "/elements/0/stress/0/2" + }, + "value": 10.0, + "tolerance": { + "relative": 1e-09 + }, + "reason": "uniaxial stress E ε = 1000 × 0.01 is the exact discrete solution: the dual mortar conditions hold for the linear field on both meshes" + }, + { + "id": "szz_14", + "quantity": "σ_zz of the lower block's centre element under the tie (element 14)", + "measure": { + "command": "solve.probe", + "params": { + "step": "Pull", + "elements": [ + 14 + ] + }, + "pointer": "/elements/0/stress/0/2" + }, + "value": 10.0, + "tolerance": { + "relative": 1e-09 + }, + "reason": "uniaxial stress E ε = 1000 × 0.01 is the exact discrete solution: the dual mortar conditions hold for the linear field on both meshes" + }, + { + "id": "szz_1", + "quantity": "σ_zz of the lower block's bottom corner element (element 1)", + "measure": { + "command": "solve.probe", + "params": { + "step": "Pull", + "elements": [ + 1 + ] + }, + "pointer": "/elements/0/stress/0/2" + }, + "value": 10.0, + "tolerance": { + "relative": 1e-09 + }, + "reason": "uniaxial stress E ε = 1000 × 0.01 is the exact discrete solution: the dual mortar conditions hold for the linear field on both meshes" + }, + { + "id": "szz_19", + "quantity": "σ_zz of the upper block's corner element over the tie (element 19)", + "measure": { + "command": "solve.probe", + "params": { + "step": "Pull", + "elements": [ + 19 + ] + }, + "pointer": "/elements/0/stress/0/2" + }, + "value": 10.0, + "tolerance": { + "relative": 1e-09 + }, + "reason": "uniaxial stress E ε = 1000 × 0.01 is the exact discrete solution: the dual mortar conditions hold for the linear field on both meshes" + }, + { + "id": "szz_26", + "quantity": "σ_zz of the upper block's top far corner element (element 26)", + "measure": { + "command": "solve.probe", + "params": { + "step": "Pull", + "elements": [ + 26 + ] + }, + "pointer": "/elements/0/stress/0/2" + }, + "value": 10.0, + "tolerance": { + "relative": 1e-09 + }, + "reason": "uniaxial stress E ε = 1000 × 0.01 is the exact discrete solution: the dual mortar conditions hold for the linear field on both meshes" + }, + { + "id": "sxx_14", + "quantity": "σ_xx of element 14 (uniaxial stress: 0)", + "measure": { + "command": "solve.probe", + "params": { + "step": "Pull", + "elements": [ + 14 + ] + }, + "pointer": "/elements/0/stress/0/0" + }, + "value": 0.0, + "tolerance": { + "absolute": 1e-09 + }, + "reason": "the tie must not hold the lateral contraction of either mesh" + }, + { + "id": "uz_interface", + "quantity": "u_z at the tied secondary node (0.5, 0.5, 1)", + "measure": { + "command": "solve.probe", + "params": { + "step": "Pull", + "at": [ + [ + 0.5, + 0.5, + 1.0 + ] + ] + }, + "pointer": "/nodes/0/displacement/2" + }, + "value": 0.01, + "tolerance": { + "relative": 1e-09 + }, + "reason": "the tied node follows the uniform strain field" + } + ] +} \ No newline at end of file diff --git a/tests/oracle/tie-patch/fixture.json b/tests/oracle/tie-patch/fixture.json new file mode 100644 index 0000000..7a2f02a --- /dev/null +++ b/tests/oracle/tie-patch/fixture.json @@ -0,0 +1,33 @@ +{ + "note": "FieldCraft's accepted results for this case, written by `cargo xtask oracle --bless`. A result outside its band fails CI.", + "values": { + "sxx_14": { + "band": 1e-9, + "value": -5.317400101732486e-15 + }, + "szz_1": { + "band": 1.0000000000000018e-8, + "value": 10.000000000000018 + }, + "szz_10": { + "band": 1e-8, + "value": 9.999999999999993 + }, + "szz_14": { + "band": 1.0000000000000002e-8, + "value": 10.000000000000002 + }, + "szz_19": { + "band": 1.0000000000000017e-8, + "value": 10.000000000000016 + }, + "szz_26": { + "band": 1.000000000000001e-8, + "value": 10.000000000000009 + }, + "uz_interface": { + "band": 1.0000000000000001e-11, + "value": 0.009999999999999997 + } + } +} diff --git a/tests/oracle/tie-patch/recipe.json b/tests/oracle/tie-patch/recipe.json new file mode 100644 index 0000000..ac6f28f --- /dev/null +++ b/tests/oracle/tie-patch/recipe.json @@ -0,0 +1,22 @@ +[ + {"command": "mesh.block", "params": {"body": "Lower", "kind": "hex8", "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": [3, 3, 2], "faces": {"1": "bottom", "2": "top", "3": "y0", "6": "x0"}, "bias": [2.0, 0.6, 1.0]}}, + {"command": "mesh.block", "params": {"body": "Upper", "kind": "hex8", "corners": [[0, 0, 1], [1, 0, 1], [1, 1, 1], [0, 1, 1], [0, 0, 2], [1, 0, 2], [1, 1, 2], [0, 1, 2]], "divisions": [2, 2, 2], "faces": {"1": "bottom", "2": "top", "3": "y0", "6": "x0"}, "merge": 0}}, + {"command": "model.set.create", "params": {"name": "lower", "geometry": [{"body": "Lower"}]}}, + {"command": "model.set.create", "params": {"name": "upper", "geometry": [{"body": "Upper"}]}}, + {"command": "model.set.create", "params": {"name": "lower_top", "geometry": [{"body": "Lower", "face": "top"}]}}, + {"command": "model.set.create", "params": {"name": "upper_bottom", "geometry": [{"body": "Upper", "face": "bottom"}]}}, + {"command": "model.set.create", "params": {"name": "x0", "geometry": [{"body": "Lower", "face": "x0"}, {"body": "Upper", "face": "x0"}]}}, + {"command": "model.set.create", "params": {"name": "y0", "geometry": [{"body": "Lower", "face": "y0"}, {"body": "Upper", "face": "y0"}]}}, + {"command": "model.set.create", "params": {"name": "z0", "geometry": [{"body": "Lower", "face": "bottom"}]}}, + {"command": "model.set.create", "params": {"name": "top", "geometry": [{"body": "Upper", "face": "top"}]}}, + {"command": "model.material.create", "params": {"name": "Mat", "elastic": {"type": "isotropic", "young": 1000.0, "poisson": 0.3}}}, + {"command": "model.section.create", "params": {"name": "lower", "set": "lower", "material": "Mat", "kind": {"type": "solid"}}}, + {"command": "model.section.create", "params": {"name": "upper", "set": "upper", "material": "Mat", "kind": {"type": "solid"}}}, + {"command": "interaction.tie", "params": {"name": "glue", "main": "lower_top", "secondary": "upper_bottom"}}, + {"command": "model.boundary_condition.create", "params": {"name": "x0", "type": "displacement", "target": {"set": "x0"}, "values": [0, null, null, null, null, null]}}, + {"command": "model.boundary_condition.create", "params": {"name": "y0", "type": "displacement", "target": {"set": "y0"}, "values": [null, 0, null, null, null, null]}}, + {"command": "model.boundary_condition.create", "params": {"name": "z0", "type": "displacement", "target": {"set": "z0"}, "values": [null, null, 0, null, null, null]}}, + {"command": "model.boundary_condition.create", "params": {"name": "push", "type": "displacement", "target": {"set": "top"}, "values": [null, null, 0.02, null, null, null]}}, + {"command": "model.step.create", "params": {"name": "Pull", "procedure": {"type": "static"}, "boundary_conditions": ["x0", "y0", "z0", "push"], "loads": []}}, + {"command": "solve.static", "params": {"step": "Pull"}, "id": "pull"} +]