# Geometry and volumes

> Estimate gravel pack and seal volumes, compute cylindrical and annular volumes, and read depths and diameters from a well's construction with @welldot/utils.

Construction intervals give everything needed to estimate materials: how much gravel to order, how much grout to mix, how wide the drawing must be. These functions read the construction blocks of a `Well` in the format's units, meters for depth and millimeters for diameter, and return cubic meters.

## Gravel pack and seal

```ts
import { calculateHoleFillVolume, formatNumber } from '@welldot/utils';

const gravel = calculateHoleFillVolume('gravel_pack', well);
const seal = calculateHoleFillVolume('seal', well);

formatNumber(gravel, { fractionDigits: 2, suffix: 'm³' }); // '1.88 m³'
formatNumber(seal, { fractionDigits: 2, suffix: 'm³' }); // '0.39 m³'
```

`calculateHoleFillVolume(type, well)` adds up every `hole_fill` interval of that type (`'gravel_pack'` or `'seal'`, the two values of the closed vocabulary in [HoleFill](/format/spec/v2/object-schemas#holefill--hole_fill)). For each interval it takes the annulus at the fill's `diameter` and subtracts any casing or screen that overlaps it, so the result is the net volume of material.

For one interval, use `calculateHoleFillSegmentVolume(holeFill, well)`:

```ts
import { calculateHoleFillSegmentVolume } from '@welldot/utils';

for (const fill of well.hole_fill) {
  console.log(
    fill.type,
    fill.from,
    fill.to,
    calculateHoleFillSegmentVolume(fill, well),
  );
}
```

::note
These are geometric volumes of a perfect cylinder. Real holes are wider than the bit, and drillers add a margin (often 20 to 50 %) for washouts and losses. Apply your own factor; the library does not guess one.
::

## Cylinders

`calculateCylindricVolume(diameter, height)` is the volume in m³ of a cylinder with a diameter in millimeters and a height in meters:

```ts
import { calculateCylindricVolume } from '@welldot/utils';

calculateCylindricVolume(254, 60); // 3.04 m³: a 10 in hole, 60 m deep
calculateCylindricVolume(168.3, 1); // 0.022 m³ per meter of 6 in casing
```

Useful for drilling fluid volumes, well disinfection doses or the water stored in the casing.

## Depths

`getProfileLastItemsDepths(well)` returns the deepest point of each block, in a fixed order: lithology, fractures, caves, bore hole, hole fill, reduction, surface case, well case, well screen. An empty block gives `0`.

```ts
import { getProfileLastItemsDepths } from '@welldot/utils';

Math.max(...getProfileLastItemsDepths(well)); // the deepest recorded point, geology included
```

For the drilled depth from construction only, use `calculatedWellDepth` from [`@welldot/core`](/core/api/functions/calculatedWellDepth). The difference matters when a lithology log goes deeper than the finished well. [Depths and intervals](/format/concepts/depths-and-intervals) explains `well_depth`.

## Diameters

```ts
import { getProfileDiamValues } from '@welldot/utils';

const diameters = getProfileDiamValues(well); // every diameter in mm, both ends of each reduction
const widest = Math.max(...diameters); // to scale a cross-section
```

`getProfileDiamValues` accepts any object with the construction arrays (the `Constructive` type), and a `Well` is one. `getConstructivePropertySummary(well, property)` is the general form: one named property pulled from every construction component, `undefined` where a component has no such field.

## Centralizers

The spec stores centralizers as an interval and a spacing, and forbids storing their count ([Centralizer](/format/spec/v2/object-schemas#centralizer--centralizers-since-v21)). `getCentralizerDepths` derives the positions:

```ts
import { getCentralizerDepths } from '@welldot/utils';

getCentralizerDepths({ from: 10, to: 58, spacing: 12, type: 'spring_bow' });
// [10, 22, 34, 46, 58]
```

Without a spacing it returns only the two ends.
