# Check mass properties

Claim volume, surface area, centre of mass and mass, and read which evidence the engine measured.

Canonical page: https://www.geospec.xyz/docs/guides/check-mass-properties

A STEP subject is measured from its exact BRep and a mesh from its triangles; the claim is the same either way, and the result names the source it used.

### 1. Claim volume, area and centre [#1-claim-volume-area-and-centre]

```ts
expectGeo(part)
  .toHaveVolume({ value: 30429.2 });
expectGeo(part)
  .toHaveSurfaceArea({ value: 6871.24 });
expectGeo(part)
  .toHaveCenterOfMass({ point: [0, 0, 10] });
```

The plate is 40 × 40 × 20 mm with a 10 mm bore: 32,000 mm³ less the bore's 1,570.8 mm³. Set the volume's `value` to 32000 and it fails by that much: `Volume is 30429.20367320504 (brep evidence), which does not satisfy 32000 within 0.02.`

### 2. Give mass a density [#2-give-mass-a-density]

```ts
expectGeo(part)
  .toHaveMass({ value: 82.16 });
expectGeo(part)
  .toHaveMass({ value: 82.16, density: 0.0027 });
```

No admitted subject carries a material, so a mass claim without `density` is refused with `GEOSPEC_UNSUPPORTED_EVIDENCE`, and its suggestion asks for one; in a script the refusal throws or raises `GeoSpecAssertionError`, as a failure does. The mass unit follows the density: grams per mm³ gives grams, so the plate in aluminium at 0.0027 g/mm³ weighs 82.16 g.

### 3. Read the evidence [#3-read-the-evidence]

A passed or failed claim reports the measured value, the expectation the engine applied and the source.

**TypeScript**

The assertion holds it under `report.evidence`; on a thrown `GeoSpecAssertionError` it is `error.report.evidence`, and `error.diagnostics[0].code` names the reason.

**Python**

The report holds it under `report.result["evidence"]`; on a raised `GeoSpecAssertionError` it is `error.result["evidence"]`, and `error.code` names the reason.

The mass claim on the plate measures as:

```json
{
  "measured": 82.15884991765361,
  "normalizedExpected": { "density": 0.0027, "tolerance": 0.02, "value": 82.16 },
  "witnesses": { "density": 0.0027, "source": "brep", "tolerance": 0.02, "volume": 30429.20367320504 }
}
```

A failed claim carries `GEOSPEC_MEASUREMENT_MISMATCH` and says what it measured: `Mass is 82.15884991765361 (brep evidence), which does not satisfy 82 within 0.02.`

### 4. Switch to the mesh [#4-switch-to-the-mesh]

Switch the model in step 1 to the gear and every number fails: the mesh measures 911.53 mm³ from its 624 triangles, its surface area of 910.80 mm² is the sum of the triangle areas, and the evidence `source` is `mesh`. A mesh approximates curved faces, so its numbers differ from the BRep of the same part; claim the numbers of the export you admitted. An open mesh still yields a volume and a centroid, so pair these claims with `toBeWatertight` from [Check meshes](https://www.geospec.xyz/docs/guides/check-meshes.mdx).

## Variations [#variations]

**A range instead of a value.** `value: { greaterThan: 30000, lessThan: 31000 }` passes on the plate; tolerance applies to `value` only. [Set tolerances and budgets](https://www.geospec.xyz/docs/guides/set-tolerances-and-budgets.mdx) has the comparison rules.

**Centre of mass on chosen axes.** `point: { z: 10 }` constrains z and leaves x and y free. A failed claim lists each axis that missed under `failures`, with the actual and expected values.

**A nominal volume.** `tolerance: 0` on `value: 30429.2` fails, because the plate measures 30429.20367 mm³. State the value you computed and a tolerance that covers your rounding, not the engine's.

**The reference.** The [measurement reference](https://www.geospec.xyz/docs/reference/measurement.mdx#tohavemass) lists every field and the admitted geometry of each claim; [Check dimensions](https://www.geospec.xyz/docs/guides/check-dimensions.mdx) covers the bounds the same evidence yields.