# Reading Legacy DOLFIN Data

`io4dolfinx` provides functionality to read meshes and functions created with the
legacy version of DOLFIN (often referred to as "Old FEniCS"). This allows users to
migrate data from older simulations to DOLFINx.

## Supported Formats

The library supports reading data stored in the **HDF5** format used by legacy DOLFIN.
This includes:
* Meshes stored using `dolfin.HDF5File`.
* Functions stored using `dolfin.HDF5File`.
* Checkpoints stored using `dolfin.XDMFFile` (which produces an `.h5` file alongside the `.xdmf` file).

**Note:** The `.xml` or `.xml.gz` formats are not supported. You must convert these to
HDF5 using legacy DOLFIN before reading them with `io4dolfinx`.

## Reading Meshes

To read a mesh, you must know the **group name** where the mesh is stored within the HDF5 file.
In legacy DOLFIN, this was often `/mesh` or the name you provided to the write function.

```python
from mpi4py import MPI
import io4dolfinx
```

```python
comm = MPI.COMM_WORLD
filename = "legacy_mesh.h5"
```

### Read the mesh
Here 'group' is the path to the mesh inside the HDF5 file (e.g., "/mesh")
```python
mesh = io4dolfinx.read_mesh_from_legacy_h5(
    filename=filename,
    comm=comm,
    group="/mesh",
)
```

```python
print(f"Read mesh with topology dimension: {mesh.topology.dim}")
```

## Reading Functions

Reading a function requires you to first create a compatible **FunctionSpace** and **Function** in DOLFINx.
The data is then read from the file and loaded into this function.

### Simple Function Read

If the function was saved directly using `HDF5File.write(u, "name")`:

```python
import dolfinx
import io4dolfinx
from mpi4py import MPI
```

#### Read the mesh first
```python
comm = MPI.COMM_WORLD
filename = "legacy_data.h5"
mesh = io4dolfinx.read_mesh_from_legacy_h5(filename, comm, group="/mesh")
```

#### Create the appropriate FunctionSpace 
You must know the element family and degree used in the legacy simulation
```python
V = dolfinx.fem.functionspace(mesh, ("Lagrange", 1))
```


#### Create the function to hold the data
```python
u = dolfinx.fem.Function(V)
```

#### Read the data

Here 'group' corresponds to the name given when writing in legacy DOLFIN
```python
io4dolfinx.read_function_from_legacy_h5(filename=filename, comm=comm, u=u, group="v")
```

### Reading from XDMF Checkpoints

If the data was saved using `XDMFFile.write_checkpoint`, the HDF5 structure is slightly different (often containing time steps). You can specify the `step` argument to read a specific snapshot.


Assuming mesh and function space V are already created as above

```python
u_checkpoint = dolfinx.fem.Function(V)
```

Read the first time step (step=0). Note that the filename should be the .h5 file generated by the XDMFFile

```python
io4dolfinx.read_function_from_legacy_h5(
    filename="checkpoint.h5",
    comm=comm,
    u=u_checkpoint,
    group="v",  # The name of the function in the checkpoint
    step=0,
)
```

## Reading Vector Functions

Vector functions are read in the same way, provided the `FunctionSpace` is initialized correctly with the vector shape.

```python
W = dolfinx.fem.functionspace(mesh, ("Lagrange", 1, (mesh.geometry.dim,)))
w = dolfinx.fem.Function(W)
```

```python
io4dolfinx.read_function_from_legacy_h5(
    filename="legacy_vector.h5", comm=comm, u=w, group="velocity_function"
)
```

## Limitations

* **Function Types:** Only `Lagrange` (Continuous Galerkin) and `DG` (Discontinuous Galerkin)
    functions are supported.
* **One Checkpoint per File:** The legacy reader generally expects one checkpoint series per file
    structure for XDMF checkpoints.
* **Backends:** The default backend is `adios2`. Ensure you have an MPI-enabled build of HDF5
    if using the `h5py` backend explicitly.
