Metadata-Version: 2.1
Name: sdf-xarray
Version: 0.1.2
Summary: Provides a backend for xarray to read SDF files as created by the EPOCH plasma PIC code.
Author-Email: Peter Hill <peter.hill@york.ac.uk>, Joel Adams <joel.adams@york.ac.uk>
License: Copyright 2024, Peter Hill, Joel Adams, PlasmaFAIR team
        
        Redistribution and use in source and binary forms, with or without
        modification, are permitted provided that the following conditions are
        met:
        
        1. Redistributions of source code must retain the above copyright
        notice, this list of conditions and the following disclaimer.
        
        2. Redistributions in binary form must reproduce the above copyright
        notice, this list of conditions and the following disclaimer in the
        documentation and/or other materials provided with the distribution.
        
        3. Neither the name of the copyright holder nor the names of its
        contributors may be used to endorse or promote products derived from
        this software without specific prior written permission.
        
        THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
        “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
        LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
        A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
        HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
        SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
        LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
        DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
        THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
        (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
        OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Requires-Python: >=3.10
Requires-Dist: numpy>=2.0.0
Requires-Dist: xarray>=2024.1.0
Requires-Dist: dask>=2024.7.1
Requires-Dist: cython>=3.0
Requires-Dist: sphinx>=5.3; extra == "docs"
Requires-Dist: sphinx_autodoc_typehints>=1.19; extra == "docs"
Requires-Dist: sphinx-book-theme>=0.4.0rc1; extra == "docs"
Requires-Dist: sphinx-argparse-cli>=1.10.0; extra == "docs"
Requires-Dist: sphinx-inline-tabs; extra == "docs"
Requires-Dist: pytest>=3.3.0; extra == "test"
Requires-Dist: dask[complete]; extra == "test"
Requires-Dist: ruff; extra == "lint"
Requires-Dist: cibuildwheel[uv]; extra == "build"
Provides-Extra: docs
Provides-Extra: test
Provides-Extra: lint
Provides-Extra: build
Description-Content-Type: text/markdown

# sdf-xarray

`sdf-xarray` provides a backend for [xarray](https://xarray.dev) to
read SDF files as created by the [EPOCH](https://epochpic.github.io)
plasma PIC code.

`sdf-xarray` uses the [SDF-C](https://github.com/Warwick-Plasma/SDF_C) library.

> [!IMPORTANT]
> All variable names now use snake_case to align with Epoch’s `sdf_helper`
> conventions. For example, `Electric Field/Ex` has been updated to
> `Electric_Field_Ex`.

## Installation

Install from PyPI with:

```bash
pip install sdf-xarray
```

or from a local checkout:

```bash
git clone https://github.com/PlasmaFAIR/sdf-xarray.git
cd sdf-xarray
pip install .
```

We recommend switching to [uv](https://docs.astral.sh/uv/) to manage packages.

## Usage

`sdf-xarray` is a backend for xarray, and so is usable directly from
xarray:

### Single file loading

```python
import xarray as xr

df = xr.open_dataset("0010.sdf")

print(df["Electric_Field_Ex"])

# <xarray.DataArray 'Electric_Field_Ex' (X_x_px_deltaf_electron_beam: 16)> Size: 128B
# [16 values with dtype=float64]
# Coordinates:
#   * X_x_px_deltaf_electron_beam  (X_x_px_deltaf_electron_beam) float64 128B 1...
# Attributes:
#     units:    V/m
#     full_name: "Electric Field/Ex"
```

### Multi file loading

To open a whole simulation at once, pass `preprocess=sdf_xarray.SDFPreprocess()`
to `xarray.open_mfdataset`:

```python
import xarray as xr
from sdf_xarray import SDFPreprocess

with xr.open_mfdataset("*.sdf", preprocess=SDFPreprocess()) as ds:
    print(ds)

# Dimensions:
# time: 301, X_Grid_mid: 128, ...
# Coordinates: (9) ...
# Data variables: (18) ...
# Indexes: (9) ...
# Attributes: (22) ...
```

`SDFPreprocess` checks that all the files are from the same simulation, as
ensures there's a `time` dimension so the files are correctly concatenated.

If your simulation has multiple `output` blocks so that not all variables are
output at every time step, then those variables will have `NaN` values at the
corresponding time points.

Alternatively, we can create a separate time dimensions for each `output` block
(essentially) using `sdf_xarray.open_mfdataset` with `separate_times=True`:

```python
from sdf_xarray import open_mfdataset

with open_mfdataset("*.sdf", separate_times=True) as ds:
    print(ds)

# Dimensions:
# time0: 301, time1: 31, time2: 61, X_Grid_mid: 128, ...
# Coordinates: (12) ...
# Data variables: (18) ...
# Indexes: (9) ...
# Attributes: (22) ...
```

This is better for memory consumption, at the cost of perhaps slightly less
friendly comparisons between variables on different time coordinates.

### Reading particle data

By default, particle data isn't kept as it takes up a lot of space. Pass
`keep_particles=True` as a keyword argument to `open_dataset` (for single files)
or `open_mfdataset` (for multiple files):

```python
df = xr.open_dataset("0010.sdf", keep_particles=True)
```

### Loading SDF files directly

For debugging, sometimes it's useful to see the raw SDF files:

```python
from sdf_xarray import SDFFile

with SDFFile("0010.sdf") as sdf_file:
    print(sdf_file.variables["Electric Field/Ex"])

    # Variable(_id='ex', name='Electric Field/Ex', dtype=dtype('float64'), ...

    print(sdf_file.variables["Electric Field/Ex"].data)

    # [ 0.00000000e+00  0.00000000e+00  0.00000000e+00 ... -4.44992788e+12  1.91704994e+13  0.00000000e+00]
```
