> ## Documentation Index
> Fetch the complete documentation index at: https://docs.activeviam.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Measures

> The common-layer infrastructure for registering and accessing cube measures, including the measure factory pattern and how to add custom measures.

Each solution defines its own measures, but the common layer provides the infrastructure for registering and accessing them.
Understanding this infrastructure is useful when adding custom measures or modifying existing ones.

**Prerequisites**: Familiarity with the Atoti Configuration API cube model and the Copper measure API.

## How are measures defined?

The Copper measure API is a fluent interface for defining measure calculations as `CopperMeasure` objects. The code examples on this page use Copper to construct and transform measures.

## How are measures organized?

The common layer exposes three constructs for working with measures.

**`IMeasuresConfigurator`** is the interface on the cube used to register new measures. Call `cubeManagerConfigurator.cube(name).measures()` to obtain an instance, then use `addMeasure()` to register a `CopperMeasure`.

**The measure factory pattern** allows solutions to define reusable, parameterized measure templates. A factory implements `IMeasureFactory<T>` where `T` is an `IMeasureFactoryInput` describing the inputs. Each factory is identified by a unique plugin key returned by its `key()` method. A factory registered under the same plugin key for the cube replaces the existing one, which allows overriding the default calculation logic of a built-in measure. For a full reference of all common factory plugin keys, see [Measures reference](/solutions/enterprise-risk-suite/1.0/common/reference/measures.md).

**`ISolutionCube.measures()`** is the accessor for retrieving a solution's measure collections programmatically. Use it inside an `IModelConfigurer` to obtain existing measures and build new ones on top of them.

## How to add or modify measures

### Via configuration properties

Some measure parameters can be adjusted using configuration properties without writing Java code. For example, confidence levels and display currencies affect how certain measures are computed and displayed.

See [Configuration properties](/solutions/enterprise-risk-suite/1.0/common/reference/configuration-properties.md) for supported options.

### Via the Java API

To add new measures programmatically, build a `CopperMeasure` and register it via `IMeasuresConfigurator` in an `IModelConfigurer`.

The pattern has three elements:

* Obtain an existing measure via `ISolutionCube.measures()`
* Transform it using the Copper API
* Register it via `IMeasuresConfigurator.addMeasure(name, measure)`, which names the measure through its first argument

The following example illustrates this pattern by adding a measure that computes the maximum value from an aggregated scenario vector. It uses `Copper.combine(...)` together with the `.map(BiConsumer, type)` operator: the mapper receives a reader for the combined inputs and a writer for the result. The reader exposes the underlying vector via `readVector(int)`, and the result is written with `writer.writeDouble(...)`. The output literal type is declared with `ILiteralType.DOUBLE`:

```java theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}}
// Compute the per-vector maximum of an aggregated scenario vector.
CopperMeasure pnlMax =
    Copper.combine(pnlVectorSum)
        .map(
            (reader, writer) -> {
              final var vector = reader.readVector(0);
              if (vector == null || vector.size() == 0) {
                writer.writeNull();
                return;
              }
              double max = Double.NEGATIVE_INFINITY;
              for (int i = 0; i < vector.size(); i++) {
                max = Math.max(max, vector.readDouble(i));
              }
              writer.writeDouble(max);
            },
            ILiteralType.DOUBLE)
        .as("PnL Max");
measuresConfigurator.addMeasure("PnL Max", pnlMax);
```

### How to register a custom measure factory

Register a custom measure factory by declaring a `MeasureFactoryRegistration` bean. Spring's component scanning discovers the bean and registers the factories it wraps. Because the factory is instantiated by Spring, it can depend on other Spring-managed beans:

```java theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}}
@Bean
public MeasureFactoryRegistration customMeasureFactories(MyDependency dependency) {
  return new MeasureFactoryRegistration(new MyMeasureFactory(dependency));
}
```

Factories can be registered globally (for all cubes) or per cube. Pass a `Map<String, Collection<IMeasureFactory<?>>>` keyed by cube name for the latter. Per-cube factories take precedence over globally registered ones. To replace a built-in factory, register the replacement for the cube. See [How to override a factory](/solutions/enterprise-risk-suite/1.0/common/reference/measures.md#how-to-override-a-factory). Multiple factories can be registered in a single `MeasureFactoryRegistration` bean.

## How to rename measures

Measures defined by a solution can be renamed without modifying Java code. Add name overrides to `application.yml`:

```yaml theme={"languages":{"custom":["/engine/python-sdk/6.2/languages/pycon.tmLanguage.json"]}}
semantic-model:
  name-overrides:
    cubes:
      CubeName:
        measures:
          Measure1: MeasureA
          '[Measure with spaces]': MeasureB
```

Use square brackets for measure names that contain spaces.

> For details on defining and customizing measures using the Atoti Configuration API, see the [measures reference](/solutions/enterprise-risk-suite/1.0/foundry/cube/measures.md).

## Related pages

* [Dimensions](/solutions/enterprise-risk-suite/1.0/common/developer-guide/cube/dimensions.md)
* [Configuration properties](/solutions/enterprise-risk-suite/1.0/common/reference/configuration-properties.md)
