Decides which elements to refine after a solve, how small to make them, refines the mesh and stops when the estimated error meets the target.
How the precision is kept
Coordinates are Float64Array and all sizes are 64-bit. The loop is driven by the estimated error percentage of each solve, which is an estimate and not a bound, so the final accuracy is set by the estimate, the target and the pass and element limits. The per-element indicators it ranks by are 32-bit copies made in tetfea.js and tet-elements.js.
Calculations under this policy
5 calculations in 1 source file. The code is read from the released app when this page loads. It is the calculation people run, not a copy kept for this page.
Elements are sorted by their indicator and their squares added until the sum reaches half the total or 30 % of the elements are marked. The ratio is guarded by a 1e-300 floor on ē; the size factor is clamped, so an indicator's exact value matters only for its rank. The indicators read here are 32-bit for a single field.
tetadapt.js
lines 98 to 114
PartCraft 0.8.1
/**
* Which elements to refine and to what size → { target: Float64Array (Infinity = leave), marked, share (of Σe² marked) }.
* err: e_K per element; energy U; errSq Σe²; tm: the linear mesh (element sizes); opts { target %, theta, maxFraction }.
*/
export function markForRefinement(tm, err, energy, errSq, { target = 5, theta = 0.5, maxFraction = 0.3, p = 2 } = {}) {
const m = err.length, order = Array.from({ length: m }, (_, e) => e).sort((a, b) => err[b] - err[a]);
const goal = theta * errSq, cap = Math.max(1, Math.floor(maxFraction * m)), out = new Float64Array(m).fill(Infinity);
const ebar = target / 100 * Math.sqrt((energy + errSq) / m);
let sum = 0, marked = 0;
for (const e of order) {
if (sum >= goal || marked >= cap) break;
sum += err[e] * err[e]; marked++;
const xi = err[e] / Math.max(ebar, 1e-300), f = Math.max(0.5, Math.min(0.7, xi ** (-1 / p)));
out[e] = f * longestEdge(tm.nodes, tm.tets, e);
}
return { target: out, marked, share: errSq > 0 ? sum / errSq : 0 };
}
New boundary vertices onto the exact faces
64-bit
Moves a vertex created on the boundary onto the true surface of its faces, unless that would damage the elements around it.
accept when every tet keeps volume > 0 and min dihedral ≥ min(10°, before)
A move shorter than 1e-14 × the bounding-box diagonal is skipped. The vertex is moved, the tets around it are tested with tetVolume and tetQuality, and it is put back on the chord when any test fails; both outcomes are counted.
The volume of the refined linear mesh, kept in its statistics.
V = Σₑ volume of tet e
A running 64-bit sum of signed tet volumes in element order over a Float64Array copy of the coordinates.
tetadapt.js
line 91
PartCraft 0.8.1
let vol = 0; for (let e = 0; e < m; e++) vol += tetVolume(nodes, tets[4 * e], tets[4 * e + 1], tets[4 * e + 2], tets[4 * e + 3]);
When the refinement stops
64-bit
Compares each pass's estimated error with the target and decides whether to refine again.
stop when η ≤ target, or passes used, or elements > limit
The comparison uses the solver's 64-bit error percentage directly. The percentage written in the message is formatted with two decimals; the table row keeps the unrounded value.
Dörfler marking: the elements with the largest indicators until their squares add up to θ = 0.5 of the total, at most 30 % of the elements. New size h × (ē ÷ e_K)^(1/2) clamped to 0.5 to 0.7 of the longest edge, with ē = target × √((U + Σe²) ÷ m). Conforming longest-edge bisection from tetmesh.js; new boundary vertices projected onto the exact faces when no tet around them inverts or drops below the smaller of 10° and its angle before.
Number types
64-bit numbers; Float64Array for coordinates and target sizes; Int32Array for elements.
Tolerances
An element is bisected while its longest edge exceeds 1.0001 × its target. A projection shorter than 1e-14 × the part's bounding-box diagonal is skipped. Default target 5 %, 1 to 10 passes (default 5), 150,000 elements; up to 9 bisection rounds per pass.
Limits
Every pass is a full re-solve. The loop ends on the target, the pass limit, the element limit or a failed pass, and reports which.
Approach: 64-bit, stated limit
The arithmetic is 64-bit, but the method or the data sets the accuracy: a solver tolerance, a mesh, a step size, a datum shift, a table. The limit is stated where the result is shown.