Metadata-Version: 2.4
Name: statescale
Version: 0.3.0
Summary: snapshot-driven state upscaling
Author-email: Andreas Dutzler <a.dutzler@gmail.com>
License-Expression: MIT
Project-URL: Homepage, https://statescale.readthedocs.io/en/latest
Project-URL: Documentation, https://statescale.readthedocs.io/en/latest
Project-URL: Repository, https://github.com/adtzlr/statescale
Project-URL: Issues, https://github.com/adtzlr/statescale/issues
Project-URL: Changelog, https://github.com/adtzlr/statescale/blob/main/CHANGELOG.md
Keywords: computational-mechanics,interpolation,surrogate-model,python,scientific-computing,solid-mechanics-codes
Classifier: Development Status :: 5 - Production/Stable
Classifier: Programming Language :: Python
Classifier: Intended Audience :: Science/Research
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Scientific/Engineering
Classifier: Topic :: Scientific/Engineering :: Mathematics
Classifier: Topic :: Utilities
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy
Requires-Dist: scipy
Requires-Dist: joblib
Provides-Extra: docs
Requires-Dist: pydata-sphinx-theme; extra == "docs"
Requires-Dist: sphinx-autoapi; extra == "docs"
Requires-Dist: sphinx-inline-tabs; extra == "docs"
Requires-Dist: sphinx-copybutton; extra == "docs"
Requires-Dist: sphinx-design; extra == "docs"
Requires-Dist: sphinx-gallery; extra == "docs"
Requires-Dist: pypandoc; extra == "docs"
Provides-Extra: examples
Requires-Dist: felupe; extra == "examples"
Requires-Dist: pyvista[jupyter]; extra == "examples"
Requires-Dist: matplotlib; extra == "examples"
Requires-Dist: meshio; extra == "examples"
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Requires-Dist: tox; extra == "dev"
Dynamic: license-file

<p align="center">
  <a href="https://felupe.readthedocs.io/en/latest/?badge=latest"><img src="https://github.com/user-attachments/assets/d1bc153c-b597-4961-839f-ed24de096747" height="160"></a>
  <p align="center"><i>statescale - Snapshot-driven state upscaling</i></p>
</p>

[![PyPI - Version](https://img.shields.io/pypi/v/statescale)](https://pypi.org/project/statescale/)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://mit-license.org/)
[![codecov](https://codecov.io/gh/adtzlr/statescale/graph/badge.svg?token=doCYWavVbp)](https://codecov.io/gh/adtzlr/statescale)
[![readthedocs](https://app.readthedocs.org/projects/statescale/badge/?version=latest&style=flat)](https://statescale.readthedocs.io/en/latest/)
[![DOI](https://zenodo.org/badge/1139657723.svg)](https://doi.org/10.5281/zenodo.18377264)
![Codestyle black](https://img.shields.io/badge/code%20style-black-black)

`statescale` is a Python package for **snapshot-driven upscaling of high-dimensional
simulation states** along arbitrary parameter or signal paths.

## ✨ Overview
`statescale` provides a lightweight API to manage time-dependent point- and cell-data
and time-independent field-data across snapshots and to interpolate that data on new
signals. The central class is
[`SnapshotModel`](https://statescale.readthedocs.io/en/latest/statescale.html#statescale.SnapshotModel).

**Highlights**

- ✅ Snapshot-driven state upscaling
- ✅ Upscale simulation data to continuous signals from sparse snapshots
- ✅ Efficient handling of high-dimensional data
- ✅ Easy-to-use API

<p align="center">
  <img width="371" height="256" alt="Image" src="https://github.com/user-attachments/assets/0ab590ab-4c91-4093-a36c-22662a604401" />
</p>

## 📦 Installation
Install from PyPI:

```
pip install statescale
```

Development install (from source):

1. Clone the repository:

```
git clone https://github.com/adtzlr/statescale.git
cd statescale
```

2. Install in editable mode:

```
pip install --editable .
```

Dependencies: `numpy` and `scipy` (and `pytest` for running tests).

## 🚀 Quickstart
A minimal example. Snapshots must have shapes `(n_snapshots, n_dim)`, point- and cell-
data `(n_snapshots, ...)` and the dimension of the signal must be compatible with
snapshots, i.e. `(n_steps, n_dim)`. The second dimension of snapshots and the signal
are optional, 1d-arrays are also supported. The model result will be of shape
`(n_steps, ...)`.

### Array-based input data
```python
import numpy as np
import statescale

snapshots = np.linspace(0, 1, num=3).reshape(-1, 1)  # 3 snapshots, 1 parameter
point_data = {"displacement": np.random.rand(3, 9, 3)}  # 3 snapshots, 9 points, 3 dim
cell_data = {"strain": np.random.rand(3, 4, 6)}  # 3 snapshots, 4 cells, 6 dim
field_data = {"id": 1001}  # time-independent data

model = statescale.SnapshotModel(
    snapshots=snapshots,
    point_data=point_data,
    cell_data=cell_data,
    field_data=field_data,
    # kernel="surrogate",  # use a POD "surrogate" model or simple "griddata"
    # modes=(2, 10),  # min- and max no. of modes for surrogate model
)

signal = np.linspace(0, 1, num=20).reshape(-1, 1)  # 20 items, 1 parameter

# a `ModelResult` object with `point_data`, `cell_data` and `field_data`.
res = model.evaluate(signal, method="griddata")  # method "griddata" or "rbf"
```

### List-based input data
If the data is list-based, the model can also import lists of dicts, with per-snapshot
list items. Model results also support indexing and a conversion to lists of dicts.

```python
import numpy as np
import statescale

point_data = [
    {"displacement": np.random.rand(6, 2)},  # 1. snapshot, 6 points, 2 dim
    {"displacement": np.random.rand(6, 2)},  # 2. snapshot, 6 points, 2 dim
    {"displacement": np.random.rand(6, 2)},  # 3. snapshot, 6 points, 2 dim
]
cell_data = [
    {"strain": np.random.rand(4, 2, 2)},  # 1. snapshot, 4 cells, (2, 2) dim
    {"strain": np.random.rand(4, 2, 2)},  # 2. snapshot, 4 cells, (2, 2) dim
    {"strain": np.random.rand(4, 2, 2)},  # 3. snapshot, 4 cells, (2, 2) dim
]

model = statescale.SnapshotModel(
    snapshots=snapshots,
    point_data=point_data,
    cell_data=cell_data,
    field_data=field_data,
)

# `point_data`, `cell_data` and `field_data` for step 5 of the signal.
res_5 = model.evaluate(signal)[5]
```

Any NumPy-function may be applied to the model result data on all time-dependent arrays.
E.g., the mean over all cells (here, the first axis) of the cell-data is evaluated by:

```python
res_5_mean = res_5.apply(np.mean, on_point_data=False, on_cell_data=True)(axis=0)
```

More details can be found in the [documentation](https://statescale.readthedocs.io/).

## 🛠️ Tests
The tests are located in `tests`. Run them locally with:

```
tox
```

## ➕ Contributing
Bug reports and pull requests are welcome. Please open an issue or PR in
the repository. The package is in early development, expect breaking API changes until
version 1.0.0.

## 📄 Changelog
All notable changes to this project will be documented in [this file](CHANGELOG.md).
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and
this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## 🔓 License
See the [`LICENSE`](LICENSE) file.
