{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\n# Converting Between HDF4 and HDF5\n\nConvert PSI-style HDF files between HDF4 (.hdf) and HDF5 (.h5) formats.\n\nThis example demonstrates two conversion routines:\n\n- :func:`~psi_io.psi_io.convert` \u2013 a general-purpose bidirectional converter that\n  preserves all datasets and their attributes while keeping the original dataset\n  names intact.\n- :func:`~psi_io.psi_io.convert_psih4_to_psih5` \u2013 a PSI-convention-aware converter\n  that additionally remaps the standard HDF4 primary dataset name (``'Data-Set-2'``)\n  to its HDF5 equivalent (``'Data'``).\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "import tempfile\nfrom pathlib import Path\nfrom psi_io import convert, convert_psih4_to_psih5, read_hdf_meta, data"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Fetch a real PSI HDF4 data file (the radial magnetic field cube) to use as\nthe conversion source:\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "br_hdf4_filepath = data.get_3d_data(hdf=\".hdf\")\nprint(f\"Source file : {Path(br_hdf4_filepath).name}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Inspect the HDF4 metadata. Note the PSI-standard dataset name ``'Data-Set-2'``\nand scale names ``'fakeDim0'``, ``'fakeDim1'``, ``'fakeDim2'``:\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "source_meta = read_hdf_meta(br_hdf4_filepath)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "**Generic conversion** with :func:`~psi_io.psi_io.convert`\n\nThe generic converter reads every non-scale dataset in the source file and writes\nit to the output file under the **same name**. For a PSI HDF4 file, this means\nthe primary dataset is preserved as ``'Data-Set-2'`` in the resulting HDF5 file.\nAll associated scale datasets and attributes are also carried over:\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "with tempfile.TemporaryDirectory() as tmpdir:\n    out_generic = Path(tmpdir) / \"br_generic.h5\"\n    convert(br_hdf4_filepath, out_generic)\n\n    generic_meta = read_hdf_meta(out_generic)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "<div class=\"alert alert-info\"><h4>Note</h4><p>Because :func:`~psi_io.psi_io.convert` preserves dataset names verbatim, the\n   resulting HDF5 file has a ``'Data-Set-2'`` dataset rather than the ``'Data'``\n   dataset expected by :func:`~psi_io.psi_io.read_hdf_data` and other ``psi-io``\n   reading routines by default. Use :func:`~psi_io.psi_io.convert_psih4_to_psih5`\n   when PSI-convention HDF5 naming is required.</p></div>\n\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "**PSI-convention conversion** with :func:`~psi_io.psi_io.convert_psih4_to_psih5`\n\nThis converter is designed specifically for PSI-style HDF4 files. It reads the\n``'Data-Set-2'`` dataset and writes it as ``'Data'`` in the output HDF5 file,\nmatching the naming convention expected by all ``psi-io`` reading routines. Scale\nnames are also updated from ``'fakeDimN'`` to ``'dimN'``:\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "with tempfile.TemporaryDirectory() as tmpdir:\n    out_psi = Path(tmpdir) / \"br_psi.h5\"\n    convert_psih4_to_psih5(br_hdf4_filepath, out_psi)\n\n    psi_meta = read_hdf_meta(out_psi)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "**HDF5 \u2192 HDF4 conversion**\n\n:func:`~psi_io.psi_io.convert` is bidirectional. Passing an HDF5 file as input\nand an HDF4 path as output performs the reverse conversion. When ``ofile`` is\nomitted, the output file is placed alongside the input file with its extension\nswapped:\n\n<div class=\"alert alert-info\"><h4>Note</h4><p>Here the ``strict`` parameter is set to ``False``. It is **CRITICAL** to note\n   that HDF4 has a more restrictive attribute type system than HDF5.\n   HDF5 Datasets are typically written with ``DIMENSION_LABELS`` and ``DIMENSION_LIST``\n   attributes \u2013 arrays of coordinate-variable proxy objects (which HDF4 cannot represent).\n\n   Therefore, it is generally advised to set ``strict=False`` when converting from HDF5 to\n   HDF4 to avoid conversion failures due to unsupported attribute types. With ``strict=False``,\n   unsupported attributes are skipped with a warning rather than causing the entire\n   conversion to fail.</p></div>\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "with tempfile.TemporaryDirectory() as tmpdir:\n    br_h5_filepath = data.get_3d_data(hdf=\".h5\")\n    out_hdf = Path(tmpdir) / \"br_back.hdf\"\n    convert(br_h5_filepath, out_hdf, strict=False)\n\n    back_meta = read_hdf_meta(out_hdf)"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.13.9"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}