# Rupture disc assembly

Bursting disc assembly. An insert-type stainless holder (inlet and outlet halves with cap screws and seal) is centred inside the bolt circle between two weld-neck flanges. It holds a reverse-acting domed disc, convex towards the process. A stamped disc tag sticks up between the flanges with the tag number, burst pressure and flow direction. A burst-indicator sensor has an Ex connector, gland and field cable tail. Port A (holder inlet) is process and port B (holder outlet) is relief.

**Standards:** ISO 4126-2, ASME VIII UG-127, API 520 Part I, ASME B16.5

## Installation

```bash
npx -y https://decktwin.com/cli/deck-twin-0.2.2.tgz add rupture-disc
```

Copies `piping/rupture-disc.tsx`, any helper files it imports and the shared `lib/` into `src/components/deck-twin/`. Needs `three`, `@react-three/fiber` and `@react-three/drei`.

## Usage

```tsx
import { Canvas } from '@react-three/fiber'
import { OrbitControls } from '@react-three/drei'
import { Stage } from './components/deck-twin/lib/stage'
import { RuptureDisc } from './components/deck-twin/piping/rupture-disc'

export default function Scene() {
  return (
    <Canvas shadows camera={{ position: [8, 5, 9], fov: 35 }}>
      <Stage>
        <RuptureDisc />
      </Stage>
      <OrbitControls makeDefault />
    </Canvas>
  )
}
```

## Props

| Prop | Type | Default | Range |
| --- | --- | --- | --- |
| `nps` | `number (NPS, in)` | `3` |  |
| `rating` | `150 \| 300 \| 600 \| 900 \| 1500 \| 2500` | `300` |  |
| `burst` | `number (barg)` | `42` | 1 – 400 |
| `flanges` | `boolean` | `true` |  |
| `indicator` | `boolean` | `true` |  |
| `tag` | `string` | `"PSE-1101"` |  |
| `...group` | position, rotation, scale… |  |  |

## Ports

Flange faces in the component's local frame, metres. Origin: pipe centreline, flow along X.

| Id | Label | Position | Direction | Size | Class |
| --- | --- | --- | --- | --- | --- |
| `A` | Inlet (process side) | -0.021, 0.000, 0.000 | -1, 0, 0 | 3" | 300 |
| `B` | Outlet (vent side) | 0.021, 0.000, 0.000 | 1, 0, 0 | 3" | 300 |

## P&ID

A curved disc (arc) between two flange bars across the relief line, usually vertical with the inlet below, tagged PSE with the burst pressure; often fitted under a PSV with a pressure gauge or switch between them.

tag RD · tag BD · ISA PSE · ISA PI · ISA PSH · ISO 10628-2 / PIP PIC001 / ISA 5.1 (PSE)

An arc between flange bars with no spring = rupture disc; a spring zig-zag = PSV. A disc under a PSV forms a combination device; the PI / PSH in the space between detects a leak or burst.

Rupture disc datasheet (ISO 4126-2 / API 520 Part I) fields and the props they set:

| Field | Prop |
| --- | --- |
| Nominal size | `nps` |
| Flange rating | `rating` |
| Burst pressure | `burst` |
| Holder with flanges | `flanges` |
| Burst indicator | `indicator` |
| Tag number | `tag` |

## Typical suppliers

Fike · Continental Disc. The geometry is generic and sized from public standards. It is not vendor CAD.

## Source

`piping/rupture-disc.tsx`. This is the component file only: it imports shared code, so install it with the command above rather than pasting it alone. https://decktwin.com/r/rupture-disc.json has every file.

```tsx
// Rupture (bursting) disc assembly: insert-type holder between ASME B16.5 flanges with a reverse-acting domed disc, stamped disc tag and burst-indicator sensor.
import * as THREE from 'three'
import type { Kit } from '../lib/kit'
import { KitMesh, useKit, type GroupProps } from '../lib/mesh'
import { port, type Port } from '../lib/ports'
import { tagMaterial } from '../lib/textures'
import { flange as flangeDims, pipeOD, pipeWall, type Rating } from '../lib/standards'
import { boltHole, seg, waferFlanges } from './_flanges'

export interface RuptureDiscProps {
  /** nominal size, inches */
  nps?: number
  rating?: Rating
  /** marked burst pressure, barg */
  burst?: number
  /** draw the companion weld-neck flanges and through studs */
  flanges?: boolean
  /** burst indicator sensor with Ex connector and cable tail */
  indicator?: boolean
  tag?: string
}

export const defaults = { nps: 3, rating: 300 as Rating, burst: 42, flanges: true, indicator: true, tag: 'PSE-1101' }

/** typical insert holder: OD inside the bolts, total thickness from the bore. */
function holder(nps: number, rating: Rating) {
  const f = flangeDims(nps, rating)
  const od = f.boltCircle - boltHole(f.boltDia) - 0.004
  const w = Math.max(0.03, pipeOD(nps) * 0.28 + 0.018)
  return { f, od, w }
}

// Ports are the holder faces: A inlet (process), B outlet (relief); the line flanges bolt straight onto them.
export function ports(p: RuptureDiscProps = {}): Port[] {
  const { nps, rating } = { ...defaults, ...p }
  const { w } = holder(nps, rating)
  return [port('A', 'Inlet (process side)', [-w / 2, 0, 0], [-1, 0, 0], nps, rating), port('B', 'Outlet (vent side)', [w / 2, 0, 0], [1, 0, 0], nps, rating, 'relief')]
}

export function RuptureDisc({ nps = defaults.nps, rating = defaults.rating, burst = defaults.burst, flanges = defaults.flanges, indicator = defaults.indicator, tag = defaults.tag, ...group }: RuptureDiscProps & GroupProps) {
  const data = useKit((k) => build(k, nps, rating, burst, flanges, indicator, tag), [nps, rating, burst, flanges, indicator, tag])
  return (
    <group {...group}>
      <KitMesh data={data} />
    </group>
  )
}

export default RuptureDisc

function build(k: Kit, nps: number, rating: Rating, burst: number, flanges: boolean, indicator: boolean, tag: string) {
  const { od, w } = holder(nps, rating)
  const ri = pipeOD(nps) / 2 - pipeWall(nps, '40')
  const R = od / 2
  const n = seg(od)
  const xi = -w * 0.12 // disc seat between inlet and outlet holder
  // inlet holder (bevelled seat) and outlet holder, with the parting line and cap screws
  k.lathe('stainless', [[ri, -w / 2], [R - 0.002, -w / 2], [R, -w / 2 + 0.002], [R, xi - 0.0008], [R - 0.0015, xi]], [0, 0, 0], 'x', n)
  k.lathe('stainless', [[R - 0.0015, xi + 0.0012], [R, xi + 0.002], [R, w / 2 - 0.002], [R - 0.002, w / 2], [ri, w / 2]], [0, 0, 0], 'x', n)
  k.lathe('pipeBore', [[ri, w / 2], [ri, xi + 0.0012], [ri, xi - 0.0008], [ri, -w / 2]], [0, 0, 0], 'x', n)
  k.lathe('rubberBlack', [[R - 0.0015, xi], [R - 0.0015, xi + 0.0012]], [0, 0, 0], 'x', n)
  const ns = nps <= 2 ? 4 : 6
  for (let i = 0; i < ns; i++) {
    const a = (i / ns) * Math.PI * 2 + 0.3
    const r = R - Math.max(0.008, (R - ri) * 0.35)
    k.cyl('nut', 0.0045, 0.004, [w / 2 + 0.001, Math.sin(a) * r, Math.cos(a) * r], 'x', 10)
  }
  // reverse-acting disc: dome convex towards the inlet, with its flat seat ring
  const dh = ri * 0.32
  const rs = (ri * ri + dh * dh) / (2 * dh)
  const th = Math.asin(ri / rs)
  const dome = new THREE.SphereGeometry(rs, n, 12, 0, Math.PI * 2, 0, th)
  k.add('machined', dome, new THREE.Matrix4().compose(new THREE.Vector3(xi + rs - dh, 0, 0), new THREE.Quaternion().setFromUnitVectors(new THREE.Vector3(0, 1, 0), new THREE.Vector3(-1, 0, 0)), new THREE.Vector3(1, 1, 1)))
  k.add('machined', dome.clone(), new THREE.Matrix4().compose(new THREE.Vector3(xi + rs - dh + 0.0006, 0, 0), new THREE.Quaternion().setFromUnitVectors(new THREE.Vector3(0, -1, 0), new THREE.Vector3(1, 0, 0)).multiply(new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1, 0, 0), Math.PI)), new THREE.Vector3(1, 1, 1)))
  // stamped disc tag projecting above the flanges between the holder halves
  const f = flangeDims(nps, rating)
  const tagH = Math.max(0.05, f.od / 2 - R + 0.05)
  const tw = Math.min(0.08, Math.max(0.05, od * 0.4))
  k.box('stainless', [0.0012, tagH, tw * 0.35], [xi + 0.0006, R + tagH / 2 - 0.004, 0])
  const plate = Math.min(0.09, tw * 1.4)
  const yT = R + tagH + plate * 0.16
  k.box('stainless', [0.0015, plate * 0.34, plate], [xi + 0.0006, yT, 0])
  const label = `${tag} ${burst} BARG ↑FLOW→`
  for (const s of [-1, 1]) k.plane(tagMaterial(label), plate * 0.92, plate * 0.29, [xi + 0.0006 + s * 0.0009, yT, 0], new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), (s * Math.PI) / 2))
  if (indicator) {
    // burst sensor: Ex connector on the outlet holder rim with its gland and field cable tail
    const y0 = -R
    k.cyl('stainless', 0.009, 0.022, [w * 0.25, y0 - 0.011, 0], 'y', 16)
    k.hex('brass', 0.022, 0.012, [w * 0.25, y0 - 0.028, 0], 'y')
    k.spline('cable', [[w * 0.25, y0 - 0.034, 0], [w * 0.25, y0 - 0.09, 0.01], [w * 0.25 + 0.03, y0 - 0.16, 0.06], [w * 0.25 + 0.05, y0 - 0.2, 0.14]], 0.0035, 6, 24)
  }
  if (flanges) waferFlanges(k, nps, rating, w, '40', 0.1)
}
```
