# Hammer union (Fig 1502)

Wing (hammer) union for well testing, frac and temporary flowlines. The male sub has a three-lug wing nut stamped with its figure number. The female sub has an exposed ACME thread and an elastomer lip seal at the joint. Butt-weld subs taper to bevelled Sch 160 weld ends, with optional pup joints. The nut is painted red, the colour commonly used for Fig 1502. Proportions are typical, not a particular maker's drawing.

**Standards:** API 6A (service, typical), NACE MR0175 (sour, optional), ASME B16.25

## Installation

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

Copies `piping/hammer-union.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 { HammerUnion } from './components/deck-twin/piping/hammer-union'

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

## Props

| Prop | Type | Default | Range |
| --- | --- | --- | --- |
| `nps` | `1 \| 1.5 \| 2 \| 3 \| 4` | `2` |  |
| `stub` | `number (m)` | `0` | 0 – 0.6 |
| `figure` | `"1502" \| "602" \| "2002"` | `"1502"` |  |
| `...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` | Male end | -0.123, 0.000, 0.000 | -1, 0, 0 | 2" | – |
| `B` | Female end | 0.123, 0.000, 0.000 | 1, 0, 0 | 2" | – |

## P&ID

A union symbol (two short bars with a third bar between them) in the line, with the figure number (e.g. Fig 1502) noted; well-test and frac schematics show one at every temporary flowline joint.

tag UN · ISO 10628-2 / PIP PIC001 (union) / well-testing temporary flowline convention

A flanged joint has two bars only. Figure numbers are not interchangeable (1502 vs 602 vs 2002 pressure ratings), so read the note.

Temporary flowline equipment list (union figure number, API 6A service) fields and the props they set:

| Field | Prop |
| --- | --- |
| Nominal size | `nps` |
| Figure number | `figure` |

## Typical suppliers

Abdex · Kuriyama. The geometry is generic and sized from public standards. It is not vendor CAD.

## Source

`piping/hammer-union.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/hammer-union.json has every file.

```tsx
// Hammer union: Fig 1502 wing union for well testing and temporary flowlines; male sub with three-lug wing nut, female sub with ACME thread and lip seal, butt-weld ends.
import type { Kit } from '../lib/kit'
import { KitMesh, useKit, type GroupProps } from '../lib/mesh'
import { port, type Port } from '../lib/ports'
import { pipeOD, pipeWall } from '../lib/standards'
import { BEVEL_TAN, LAND, buttWeld, hammerSpan, hammerUnion, pipeStub, seg } from './_flanges'

export interface HammerUnionProps {
  /** nominal size, inches (1–6) */
  nps?: number
  /** butt-welded pup joints each side, m */
  stub?: number
  /** figure stamped on the nut */
  figure?: '1502' | '602' | '2002'
}

export const defaults = { nps: 2, stub: 0, figure: '1502' as const }

/** typical: weld-end taper from the sub body to the pipe OD. */
const taper = (nps: number) => pipeOD(nps) * 0.5

function span(nps: number, stub: number) {
  const { xm, xf } = hammerSpan(nps)
  const c = (xm + xf) / 2
  const t = taper(nps) + Math.max(0, stub)
  return { jx: -c, xa: xm - c - t, xb: xf - c + t }
}

export function ports(p: HammerUnionProps = {}): Port[] {
  const { nps, stub } = { ...defaults, ...p }
  const s = span(nps, stub)
  return [port('A', 'Male end', [s.xa, 0, 0], [-1, 0, 0], nps), port('B', 'Female end', [s.xb, 0, 0], [1, 0, 0], nps)]
}

export function HammerUnion({ nps = defaults.nps, stub = defaults.stub, figure = defaults.figure, ...group }: HammerUnionProps & GroupProps) {
  const data = useKit((k) => build(k, Math.min(Math.max(nps, 1), 6), Math.max(0, stub), figure), [nps, stub, figure])
  return (
    <group {...group}>
      <KitMesh data={data} />
    </group>
  )
}

export default HammerUnion

function build(k: Kit, nps: number, stub: number, figure: string) {
  const s = span(nps, stub)
  const u = hammerUnion(k, s.jx, nps, 'valveBody', `FIG ${figure}`)
  const ro = pipeOD(nps) / 2
  const ri = ro - pipeWall(nps, '160')
  const t = taper(nps)
  const bev = Math.max(0, ro - ri - LAND) * BEVEL_TAN
  const n = seg(u.rBody * 2)
  // weld-end tapers with B16.25 bevels
  for (const [x, d] of [[u.xm, -1], [u.xf, 1]] as const) {
    const e = x + d * t
    k.lathe('valveBody', d < 0 ? [[ro, e + bev], [ro, e + t * 0.3], [u.rBody, x]] : [[u.rBody, x], [ro, e - t * 0.3], [ro, e - bev]], [0, 0, 0], 'x', n)
    k.lathe('machined', d < 0 ? [[ri, e], [ri + LAND, e], [ro, e + bev]] : [[ro, e - bev], [ri + LAND, e], [ri, e]], [0, 0, 0], 'x', n)
    k.lathe('pipeBore', d < 0 ? [[ri, x], [ri, e]] : [[ri, e], [ri, x]], [0, 0, 0], 'x', n)
    if (stub > 0) {
      pipeStub(k, [e, 0, 0], [d, 0, 0], stub, nps, '160', 'open', 'bevel')
      buttWeld(k, [e, 0, 0], [1, 0, 0], ro, ro - ri)
    }
  }
}
```
