Resources Numerical accuracy Calculation policy

Vessel outline and inside volume

Works out the revolved outline of a vessel with its two heads, its height and inside volume, and where a nozzle sits on it.

How the precision is kept

64-bit arithmetic. Each head is a polyline of points that lie on the head curve, and the volume is the exact volume of that polyline revolved. The number of segments therefore sets how close the volume is to the curved head.

Open item. Add the closed-form head volumes to the reported volume, or state the segment count next to it.

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.

process/equip/vessel2.js CadCraft 0.8.2 64-bit 4 calculations Reviewed

Tests tools/process-test/test-chem4.mjs

Head outline

64-bit

The outline of a hemispherical, ellipsoidal or torispherical head from the axis to the tangent line.

ellipsoidal: (R·cos a, (R ÷ ratio)·sin a), a from π ÷ 2 to 0 in n steps

Each point is computed from its own angle (index ÷ n), not from the previous point, so nothing accumulates. 24 segments by default.

  • process/equip/vessel2.js
  • lines 39 to 49
  • CadCraft 0.8.2
/** Head outline from the axis out to the tangent line, z measured from the tangent line outward (mm). type: 'hemispherical' | 'ellipsoidal' (ratio, default 2) | 'torispherical' (crownR, knuckleR). */
export function headOutline({ type = 'ellipsoidal', D, ratio = 2, crownR = null, knuckleR = null, n = 24 }) {
  const R = D / 2;
  if (type === 'hemispherical') return arc(0, 0, R, Math.PI / 2, 0, n);
  if (type === 'ellipsoidal') { const h = R / ratio; return Array.from({ length: n + 1 }, (_, i) => { const a = Math.PI / 2 * (1 - i / n); return [R * Math.cos(a), h * Math.sin(a)]; }); }
  if (type === 'torispherical') {
    if (!(crownR > 0 && knuckleR > 0)) throw new Error('a torispherical head needs the crown radius and the knuckle radius');
    return torisph(R, crownR, knuckleR, n);
  }
  throw new Error('unknown head type ' + type);
}

Torispherical head outline

64-bit

The crown and knuckle arcs of a torispherical head and where they join.

c = R − r_k; dz = √((R_c − r_k)² − c²); junction angle = atan2(dz, c)

The crown center depth is a square root of a difference of squares, floored at 0. The junction is found with Math.atan2, and both arcs are sampled by angle with n segments each.

  • process/equip/vessel2.js
  • lines 50 to 60
  • CadCraft 0.8.2
function torisph(R, Rc, rk, n) {                                   // z = 0 at the tangent line, the crown apex is the top
  const c = R - rk, zk = 0, dz = Math.sqrt(Math.max((Rc - rk) ** 2 - c * c, 0));
  if (!(Rc > rk && Rc >= R)) throw new Error('torispherical head: the crown radius must exceed the knuckle radius and the shell radius');
  const Cz = -dz;                                                    // crown centre; knuckle centre K = (c, 0)
  const ang = Math.atan2(dz, c);                                     // direction C -> K, also the junction angle at K
  const aj = Math.atan2(zk - Cz + rk * Math.sin(ang), c + rk * Math.cos(ang));
  const out = [];
  for (let i = 0; i <= n; i++) { const a = Math.PI / 2 - (Math.PI / 2 - aj) * (i / n); out.push([Rc * Math.cos(a), Cz + Rc * Math.sin(a)]); }
  for (let i = 1; i <= n; i++) { const a = ang - ang * (i / n); out.push([c + rk * Math.cos(a), rk * Math.sin(a)]); }
  return out;
}

Vessel outline, height and volume

64-bit

The full inside outline with both heads, the overall height and the inside volume.

V = Σ π·(r₁² + r₁·r₂ + r₂²) ÷ 3 × (z₂ − z₁); m³ = mm³ × 10⁻⁹

The sum is the conical-frustum formula, which is exact for the straight segments of the outline (the comment calls it a trapezoid rule). The outline points lie on the head curve, so the volume is that of the inscribed polyline. The total is multiplied by 1e-9 to give m³.

  • process/equip/vessel2.js
  • lines 61 to 70
  • CadCraft 0.8.2
/** Revolved outline: spec { D (inside, mm), t (shell thickness), Ltt (tangent-to-tangent), head: { type, ratio, crownR, knuckleR }, orientation } → { profile: [[r, z], …] (inside surface, z from the bottom head apex), tangents: [z1, z2], height, volume (m3, inside) }. */
export function bodyProfile(spec) {
  const { D, Ltt } = spec, hd = spec.head || { type: 'ellipsoidal' }, out = headOutline({ ...hd, D });
  const depth = Math.max(...out.map((p) => p[1])), z1 = depth, z2 = depth + Ltt, prof = [];
  for (const [r, z] of out) prof.push([r, z1 - z]);                                          // bottom head: apex at z = 0, tangent at z1
    for (const [r, z] of out.slice().reverse()) prof.push([r, z2 + z]);                       // top head: tangent to apex
  // volume of the revolved outline by the trapezoid rule on pi r² dz
  let V = 0; for (let i = 0; i + 1 < prof.length; i++) { const [r1, za] = prof[i], [r2, zb] = prof[i + 1]; V += Math.PI * (r1 * r1 + r1 * r2 + r2 * r2) / 3 * (zb - za); }
  return { profile: prof, tangents: [z1, z2], height: z2 + depth, headDepth: depth, volume: Math.abs(V) * 1e-9, notes: ['inside surface only; thickness is added by the host'] };
}

Nozzle position on the body

64-bit

The position and axis of a nozzle on the shell or on a head.

position = (R·cos φ, R·sin φ, z_tangent + at)

R is the largest radius in the outline. The angle is converted with Math.PI ÷ 180 and the same cosine and sine give the axis.

  • process/equip/vessel2.js
  • lines 71 to 75
  • CadCraft 0.8.2
export function nozzleOnBody(body, { at, angle = 0, onHead = null, D }) {
  const R = Math.max(...body.profile.map((p) => p[0]));
  if (!onHead) { const z = body.tangents[0] + at; return { position: [R * Math.cos(angle * Math.PI / 180), R * Math.sin(angle * Math.PI / 180), z], axis: [Math.cos(angle * Math.PI / 180), Math.sin(angle * Math.PI / 180), 0], D }; }
  const z = onHead === 'top' ? body.height : 0; return { position: [0, 0, z], axis: [0, 0, onHead === 'top' ? 1 : -1], D };
}

In detail

Method
Points on a circle, an ellipse or the crown and knuckle arcs of a torispherical head; volume as a sum of conical frustums between successive points.
Number types
64-bit numbers; outline as arrays of [r, z] in mm; volume in m³.
Tolerances
24 segments per arc by default. The square root that places the torispherical crown center is floored at 0.
Limits
The outline is inscribed in the curved head, so the reported volume is slightly below the volume of the true curve. Inside surface only.

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