Resources Numerical accuracy Calculation policy

Script result fields and meshes shown in the window

The scalar a script's field plot colors by, its range, and the outer surface of a result mesh.

How the precision is kept

A field value is turned into one 64-bit number per node or element (a component, a magnitude or von Mises). The range comes from those numbers. The surface positions handed to the view are 32-bit.

Calculations under this policy

4 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.

cs-ui.js PartCraft 0.8.1 32-bit, display only 4 calculations Reviewed

Tests None found by the review

Scalar from a field

64-bit

One number per node or element from a vector or stress field.

|u| = √(ux² + uy² + uz²); σvm as above

The result array is a Float64Array and the formula runs in 64-bit arithmetic. Math.hypot is used for the vector magnitude. The 6-component case squares the differences and shears in the order written.

  • cs-ui.js
  • lines 305 to 318
  • PartCraft 0.8.1
/** One number per node or element: { values: Float64Array, label }. */
export function fieldScalar(field, comp) {
  const c = field.comps || 1, d = field.data, n = Math.floor(d.length / c), out = new Float64Array(n);
  if (!(c === 1 || c === 3 || c === 6) || d.length % c) throw new Error(t('script.ui.field.comps'));
  if (c === 1) { out.set(d.subarray ? d.subarray(0, n) : d.slice(0, n)); return { values: out, label: '' }; }
  const comps = componentsOf(field), key = comps.some(([k]) => k === comp) ? comp : comps[0][0], k = comps.findIndex(([q]) => q === key) - 1;
  for (let i = 0; i < n; i++) {
    const o = i * c;
    if (c === 3) out[i] = key === 'mag' ? Math.hypot(d[o], d[o + 1], d[o + 2]) : d[o + k];
    else if (key === 'vm') { const [sx, sy, sz, txy, tyz, tzx] = [d[o], d[o + 1], d[o + 2], d[o + 3], d[o + 4], d[o + 5]]; out[i] = Math.sqrt(0.5 * ((sx - sy) ** 2 + (sy - sz) ** 2 + (sz - sx) ** 2) + 3 * (txy * txy + tyz * tyz + tzx * tzx)); }
    else out[i] = d[o + k];
  }
  return { values: out, label: comps.find(([q]) => q === key)[1] };
}

Range of the plotted values

64-bit

The lowest and highest value that set the color scale.

hi ≤ lo → hi = lo + max(|lo|, 1) × 1e-6

A plain loop over the values; a flat field is widened by a relative 1e-6 so the scale is not zero wide.

  • cs-ui.js
  • lines 319 to 325
  • PartCraft 0.8.1
export function rangeOf(values) {
  let lo = Infinity, hi = -Infinity;
  for (let i = 0; i < values.length; i++) { const x = values[i]; if (x < lo) lo = x; if (x > hi) hi = x; }
  if (!Number.isFinite(lo)) return { lo: 0, hi: 1 };
  if (!(hi > lo)) hi = lo + (Math.abs(lo) || 1) * 1e-6;
  return { lo, hi };
}

Deformation scale

32-bit, display only

A round scale that makes the largest displacement about 8 percent of the model size.

raw = 0.08 × diagonal ÷ max |u|, rounded up to 1, 2, 5 or 10 × 10ᵉ

The model size is taken from the surface positions, which are 32-bit. The result is only the exaggeration applied when drawing, not a reported number.

  • cs-ui.js
  • lines 326 to 336
  • PartCraft 0.8.1
/** A round deformation scale making the largest displacement about 8 % of the model's size. */
export function autoScale(positions, u, vertNode) {
  let lo = [Infinity, Infinity, Infinity], hi = [-Infinity, -Infinity, -Infinity];
  for (let i = 0; i < positions.length; i += 3) for (let a = 0; a < 3; a++) { lo[a] = Math.min(lo[a], positions[i + a]); hi[a] = Math.max(hi[a], positions[i + a]); }
  const diag = Math.hypot(hi[0] - lo[0], hi[1] - lo[1], hi[2] - lo[2]) || 1;
  let m = 0;
  for (let v = 0; v < vertNode.length; v++) { const n = vertNode[v]; m = Math.max(m, Math.hypot(u[3 * n], u[3 * n + 1], u[3 * n + 2])); }
  if (!(m > 0)) return 1;
  const raw = 0.08 * diag / m, e = Math.floor(Math.log10(raw)), b = raw / 10 ** e;
  return +(([1, 2, 5, 10].find((s) => s >= b) || 10) * 10 ** e).toPrecision(2);
}

Outer surface of a mesh

32-bit, display only

The outer surface of a solid or surface mesh as triangles for the view.

Positions are copied with Float32Array.from for the view; the node coordinates in the source mesh are not changed. Tetrahedron faces are oriented by the sign of a 64-bit triple product.

  • cs-ui.js
  • lines 248 to 249
  • PartCraft 0.8.1
  return build((n) => [N[3 * n], N[3 * n + 1], N[3 * n + 2]], polys, maxLines, m);
}

In detail

Method
Magnitude = hypot of the components; von Mises = √(½((σx−σy)² + (σy−σz)² + (σz−σx)²) + 3(τxy² + τyz² + τzx²)).
Number types
Output Float64Array. The input field data keeps whatever type the script gave it. surfaceOf returns positions as a Float32Array.
Tolerances
A range with no width is widened by 1e-6 of its size (or of 1 if the value is 0). The deformation scale is rounded to 2 significant digits of 1, 2, 5 or 10 times a power of ten.
Limits
The surface positions are 32-bit copies of the mesh nodes and are for drawing.

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.

Every policy that takes this approach