Skip to content

odys.parameters.vectorize

Internal implementation detail. Most users do not need this page directly.

vectorize builds a typed collection of arrays from the same-named fields of a sequence of entities, so a quantity carries the same name in the domain and in the model.

Generic vectorization of entity fields into typed arrays.

EntityArrays

Bases: BaseModel

Base of the typed array collections: frozen, holding xr.DataArray fields.

Source code in src/odys/parameters/vectorize.py
14
15
16
17
class EntityArrays(BaseModel):
    """Base of the typed array collections: frozen, holding `xr.DataArray` fields."""

    model_config = ConfigDict(frozen=True, extra="forbid", arbitrary_types_allowed=True)

vectorize(arrays_type, models, coordinates)

Build one array per field of arrays_type from the same-named field of every model.

Each field of arrays_type is an xr.DataArray named exactly like a field of the models, so a quantity carries the same name in the domain and in the model. The models are labelled by coordinates, in order. An unset optional field (None) becomes NaN, so optional numeric fields give float arrays.

Parameters:

Name Type Description Default
arrays_type type[ArraysT]

The typed collection of arrays to build, such as GeneratorArrays.

required
models Sequence[BaseModel]

The entities (or value objects such as batteries) to read, one per label.

required
coordinates Coordinates

The labels of the models along their dimension.

required

Returns:

Type Description
ArraysT

An instance of arrays_type with one array per field, along coordinates.dimension.

Raises:

Type Description
OdysError

If there are no models, a model lacks a field of arrays_type, or the number of models differs from the number of labels.

Source code in src/odys/parameters/vectorize.py
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
def vectorize(arrays_type: type[ArraysT], models: Sequence[BaseModel], coordinates: Coordinates) -> ArraysT:
    """Build one array per field of `arrays_type` from the same-named field of every model.

    Each field of `arrays_type` is an `xr.DataArray` named exactly like a field
    of the models, so a quantity carries the same name in the domain and in the
    model. The models are labelled by `coordinates`, in order. An unset optional
    field (`None`) becomes `NaN`, so optional numeric fields give float arrays.

    Args:
        arrays_type: The typed collection of arrays to build, such as `GeneratorArrays`.
        models: The entities (or value objects such as batteries) to read, one per label.
        coordinates: The labels of the models along their dimension.

    Returns:
        An instance of `arrays_type` with one array per field, along `coordinates.dimension`.

    Raises:
        OdysError: If there are no models, a model lacks a field of `arrays_type`,
            or the number of models differs from the number of labels.

    """
    if not models:
        msg = f"{arrays_type.__name__} requires at least one model to vectorize."
        raise OdysError(msg)
    if len(models) != len(coordinates.labels):
        msg = (
            f"Cannot vectorize {len(models)} models along "
            f"{len(coordinates.labels)} labels of '{coordinates.dimension}'."
        )
        raise OdysError(msg)
    missing = sorted({
        field for model in models for field in arrays_type.model_fields if field not in type(model).model_fields
    })
    if missing:
        msg = f"{arrays_type.__name__} reads fields the models do not have: {missing}."
        raise OdysError(msg)
    arrays = {
        field: xr.DataArray(
            [np.nan if (value := getattr(model, field)) is None else value for model in models],
            dims=coordinates.dimension,
            coords=coordinates.dimension_coordinates_map,
        )
        for field in arrays_type.model_fields
    }
    return arrays_type.model_validate(arrays)