forked from 1b-agent/fieldcraft-upstream
verification: series-resistance heat flow across a tie (#358)
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
This commit is contained in:
1 parent
836513ddfe
commit
febcffefd6
5 files changed
+195
-7
No files matched your search
+22
-6
@@ -109,7 +109,9 @@ A heat conduction element carries one temperature per node (`heat::HEAT_DOFS`, k
|
||||
and a source ∫ N Q dV (mass rule), and the heat flux −k∇T at the integration points;
|
||||
`heat::face_weights` and `face_film` integrate surface flux and convection on tri3/tri6/quad4/quad8
|
||||
faces. The solver (`fieldcraft_solver::heat`) numbers the temperatures with
|
||||
`DofLayout::uniform(…, DofSet::TEMPERATURE)` and assembles with the same `sparse::add_block`.
|
||||
`DofLayout::uniform(…, DofSet::TEMPERATURE)`, assembles with the same `sparse::add_block`, and
|
||||
eliminates prescribed temperatures and ties (see Ties) with the structural solver's
|
||||
`constraints::Reduction`.
|
||||
|
||||
Thermal strain ε_th = α (T − T_ref) along the material axes enters a solid as the load
|
||||
`Solid::thermal_load(d, &ThermalStrain { alpha, delta })` = ∫ Bᵀ D ε_th dV and its stress as
|
||||
@@ -586,12 +588,26 @@ frequency, buckling and nonlinear steps (small-displacement constraints). Dividi
|
||||
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.
|
||||
warning. Explicit dynamics refuses 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⁻⁹.
|
||||
**Heat** (`fieldcraft_solver::heat`): the same weights tie temperatures, T_A = Σ_J w_AJ T_J (one row
|
||||
per secondary node, `tie::rows_of` with the temperature kind), in steady and transient heat
|
||||
transfer and in the heat solution of coupled temperature–displacement steps. The heat solver
|
||||
eliminates them with the prescribed temperatures through the same transformation
|
||||
(`constraints::Reduction`), so the interface has no resistance, the heat leaving one side enters
|
||||
the other, and the reactions at prescribed temperatures (T_pᵀ (K T + C Ṫ − f)) balance the heat
|
||||
supplied.
|
||||
|
||||
**Verification** (`crates/solver/tests/contact.rs`, `tests/oracle/tie-patch`,
|
||||
`tests/oracle/tie-heat-series`): 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⁻⁹. Heat: steady conduction between held ends through tied hex8/tet4 blocks
|
||||
(matching, graded and mixed meshes), the linear profile, the flux and the heat flow k A ΔT / L to
|
||||
10⁻⁹; with conductivities k₁ ≠ k₂ the series-resistance interface temperature
|
||||
(k₁ T₀ + k₂ T₁)/(k₁ + k₂) and heat flow ΔT/(L₁/k₁ + L₂/k₂); a transient tied bar equal to the
|
||||
single-body bar; a coupled step with a tie at a uniform ΔT expands freely (u = α ΔT x, no stress).
|
||||
Ties take linear faces only (tet4, wedge6, hex8), for heat as for displacement.
|
||||
|
||||
## Hyperelastic materials in explicit dynamics
|
||||
|
||||
|
||||
+7
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
Generated by `cargo xtask oracle` from [`tests/oracle/`](../tests/oracle/); the policy is [verification.md](verification.md). Every case is our own model, built with FieldCraft commands from the problem's published description, and compared with the reference value its `expected.json` cites, within the stated tolerance and for the stated reason. Accepted results are frozen in each case's `fixture.json`: a later change that moves one beyond its band (10⁻⁹ of its size) fails CI even while the reference still passes. No reference value was produced with a commercial product.
|
||||
|
||||
**270 of 276 quantities pass** (6 known failure(s)) in 70 active cases: 61 theory, 9 published benchmark, 0 experiment; 10 pending cases wait for capabilities still being built.
|
||||
**275 of 281 quantities pass** (6 known failure(s)) in 71 active cases: 62 theory, 9 published benchmark, 0 experiment; 10 pending cases wait for capabilities still being built.
|
||||
|
||||
## Theory: closed-form solutions, patch tests and mesh invariants
|
||||
|
||||
@@ -249,6 +249,11 @@ 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-heat-series](../tests/oracle/tie-heat-series/) | T at the tied secondary node (0.5, 0.5, 1) | 84 | 84 | < 1e-7% | 1e-9 rel. | pass | matches |
|
||||
| [tie-heat-series](../tests/oracle/tie-heat-series/) | T in the lower block at (0, 0, 0.5) | 52 | 52 | < 1e-7% | 1e-9 rel. | pass | matches |
|
||||
| [tie-heat-series](../tests/oracle/tie-heat-series/) | T in the upper block at (1, 1, 1.5) | 92 | 92 | < 1e-7% | 1e-9 rel. | pass | matches |
|
||||
| [tie-heat-series](../tests/oracle/tie-heat-series/) | heat flux q_z at (0, 0, 0.5) | -640 | -640 | < 1e-7% | 1e-9 rel. | pass | matches |
|
||||
| [tie-heat-series](../tests/oracle/tie-heat-series/) | heat flux q_z at (1, 1, 1.5) | -640 | -640 | < 1e-7% | 1e-9 rel. | 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 |
|
||||
@@ -360,6 +365,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-heat-series](../tests/oracle/tie-heat-series/)** (theory): Heat through a tie: two blocks of conductivities 10 and 40 with non-matching meshes, 20 and 100 at the ends. Source: Series thermal resistances: steady one-dimensional conduction through two layers in perfect contact, T_i = (k1 T0 + k2 T1)/(k1 + k2) and q = ΔT/(L1/k1 + L2/k2) (F. P. Incropera, D. P. DeWitt, Fundamentals of Heat and Mass Transfer, §3.1, the composite wall). A linear field in each layer is the exact discrete solution, and the dual mortar tie reproduces a linear temperature across non-matching meshes. Tolerances — t_interface: exact discrete solution: linear in each block, and the tie holds the interface temperature for non-matching meshes; t_lower: exact discrete solution: linear in each block, and the tie holds the interface temperature for non-matching meshes; t_upper: exact discrete solution: linear in each block, and the tie holds the interface temperature for non-matching meshes; q_lower: the heat flow ΔT/(1/k1 + 1/k2) = 640 per unit area, −k ∂T/∂z uniform in each block; q_upper: the same heat flow crosses the tie: nothing is lost at the interface
|
||||
- **[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%)
|
||||
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
{
|
||||
"title": "Heat through a tie: two blocks of conductivities 10 and 40 with non-matching meshes, 20 and 100 at the ends",
|
||||
"kind": "theory",
|
||||
"source": "Series thermal resistances: steady one-dimensional conduction through two layers in perfect contact, T_i = (k1 T0 + k2 T1)/(k1 + k2) and q = ΔT/(L1/k1 + L2/k2) (F. P. Incropera, D. P. DeWitt, Fundamentals of Heat and Mass Transfer, §3.1, the composite wall). A linear field in each layer is the exact discrete solution, and the dual mortar tie reproduces a linear temperature across non-matching meshes",
|
||||
"quantities": [
|
||||
{
|
||||
"id": "t_interface",
|
||||
"quantity": "T at the tied secondary node (0.5, 0.5, 1)",
|
||||
"measure": {
|
||||
"command": "solve.probe",
|
||||
"params": {
|
||||
"step": "Heat",
|
||||
"at": [
|
||||
[
|
||||
0.5,
|
||||
0.5,
|
||||
1.0
|
||||
]
|
||||
]
|
||||
},
|
||||
"pointer": "/nodes/0/temperature"
|
||||
},
|
||||
"value": 84.0,
|
||||
"tolerance": {
|
||||
"relative": 1e-09
|
||||
},
|
||||
"reason": "exact discrete solution: linear in each block, and the tie holds the interface temperature for non-matching meshes"
|
||||
},
|
||||
{
|
||||
"id": "t_lower",
|
||||
"quantity": "T in the lower block at (0, 0, 0.5)",
|
||||
"measure": {
|
||||
"command": "solve.probe",
|
||||
"params": {
|
||||
"step": "Heat",
|
||||
"at": [
|
||||
[
|
||||
0.0,
|
||||
0.0,
|
||||
0.5
|
||||
]
|
||||
]
|
||||
},
|
||||
"pointer": "/nodes/0/temperature"
|
||||
},
|
||||
"value": 52.0,
|
||||
"tolerance": {
|
||||
"relative": 1e-09
|
||||
},
|
||||
"reason": "exact discrete solution: linear in each block, and the tie holds the interface temperature for non-matching meshes"
|
||||
},
|
||||
{
|
||||
"id": "t_upper",
|
||||
"quantity": "T in the upper block at (1, 1, 1.5)",
|
||||
"measure": {
|
||||
"command": "solve.probe",
|
||||
"params": {
|
||||
"step": "Heat",
|
||||
"at": [
|
||||
[
|
||||
1.0,
|
||||
1.0,
|
||||
1.5
|
||||
]
|
||||
]
|
||||
},
|
||||
"pointer": "/nodes/0/temperature"
|
||||
},
|
||||
"value": 92.0,
|
||||
"tolerance": {
|
||||
"relative": 1e-09
|
||||
},
|
||||
"reason": "exact discrete solution: linear in each block, and the tie holds the interface temperature for non-matching meshes"
|
||||
},
|
||||
{
|
||||
"id": "q_lower",
|
||||
"quantity": "heat flux q_z at (0, 0, 0.5)",
|
||||
"measure": {
|
||||
"command": "solve.probe",
|
||||
"params": {
|
||||
"step": "Heat",
|
||||
"at": [
|
||||
[
|
||||
0.0,
|
||||
0.0,
|
||||
0.5
|
||||
]
|
||||
]
|
||||
},
|
||||
"pointer": "/nodes/0/heat_flux/2"
|
||||
},
|
||||
"value": -640.0,
|
||||
"tolerance": {
|
||||
"relative": 1e-09
|
||||
},
|
||||
"reason": "the heat flow ΔT/(1/k1 + 1/k2) = 640 per unit area, −k ∂T/∂z uniform in each block"
|
||||
},
|
||||
{
|
||||
"id": "q_upper",
|
||||
"quantity": "heat flux q_z at (1, 1, 1.5)",
|
||||
"measure": {
|
||||
"command": "solve.probe",
|
||||
"params": {
|
||||
"step": "Heat",
|
||||
"at": [
|
||||
[
|
||||
1.0,
|
||||
1.0,
|
||||
1.5
|
||||
]
|
||||
]
|
||||
},
|
||||
"pointer": "/nodes/0/heat_flux/2"
|
||||
},
|
||||
"value": -640.0,
|
||||
"tolerance": {
|
||||
"relative": 1e-09
|
||||
},
|
||||
"reason": "the same heat flow crosses the tie: nothing is lost at the interface"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"note": "FieldCraft's accepted results for this case, written by `cargo xtask oracle --bless`. A result outside its band fails CI.",
|
||||
"values": {
|
||||
"q_lower": {
|
||||
"band": 6.400000000000002e-7,
|
||||
"value": -640.0000000000002
|
||||
},
|
||||
"q_upper": {
|
||||
"band": 6.400000000000015e-7,
|
||||
"value": -640.0000000000015
|
||||
},
|
||||
"t_interface": {
|
||||
"band": 8.400000000000002e-8,
|
||||
"value": 84.00000000000001
|
||||
},
|
||||
"t_lower": {
|
||||
"band": 5.2000000000000035e-8,
|
||||
"value": 52.000000000000036
|
||||
},
|
||||
"t_upper": {
|
||||
"band": 9.200000000000008e-8,
|
||||
"value": 92.00000000000007
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
[
|
||||
{"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"}, "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"}, "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": "cold", "geometry": [{"body": "Lower", "face": "bottom"}]}},
|
||||
{"command": "model.set.create", "params": {"name": "hot", "geometry": [{"body": "Upper", "face": "top"}]}},
|
||||
{"command": "model.material.create", "params": {"name": "Low", "elastic": {"type": "isotropic", "young": 1000.0, "poisson": 0.3}, "thermal": {"conductivity": 10.0}}},
|
||||
{"command": "model.material.create", "params": {"name": "High", "elastic": {"type": "isotropic", "young": 1000.0, "poisson": 0.3}, "thermal": {"conductivity": 40.0}}},
|
||||
{"command": "model.section.create", "params": {"name": "lower", "set": "lower", "material": "Low", "kind": {"type": "solid"}}},
|
||||
{"command": "model.section.create", "params": {"name": "upper", "set": "upper", "material": "High", "kind": {"type": "solid"}}},
|
||||
{"command": "interaction.tie", "params": {"name": "glue", "main": "lower_top", "secondary": "upper_bottom"}},
|
||||
{"command": "model.boundary_condition.create", "params": {"name": "cold", "type": "temperature", "target": {"set": "cold"}, "value": 20.0}},
|
||||
{"command": "model.boundary_condition.create", "params": {"name": "hot", "type": "temperature", "target": {"set": "hot"}, "value": 100.0}},
|
||||
{"command": "model.step.create", "params": {"name": "Heat", "procedure": {"type": "heat_transfer"}, "boundary_conditions": ["cold", "hot"], "loads": []}},
|
||||
{"command": "solve.heat", "params": {"step": "Heat"}, "id": "heat"}
|
||||
]
|
||||
Reference in new issue
Block a user