xpypact


Namexpypact JSON
Version 0.12.5 PyPI version JSON
download
home_pagehttps://github.com/MC-kit/xpypact
Summary"Python workflow framework for FISPACT."
upload_time2025-02-03 11:42:18
maintainerNone
docs_urlNone
authordvp2015
requires_python<3.14,>=3.10
licenseMIT
keywords element nuclide isotope abundance fispact activation duckdb polars
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            ==============================================================================
*xpypact*: FISPACT output to Polars or DuckDB datasets converter
==============================================================================

Aggregate results of `FISPACT <https://fispact.ukaea.uk/>`_ runs to efficient datasets.


|Maintained| |License| |Versions| |PyPI| |Docs|

.. contents::


.. note::

    This document is in progress.

Description
-----------

The module loads FISPACT JSON output files and converts to `Polars <https://pola.rs/>`_ dataframes
with minor data normalization. The dataframes can be stored either to `parquet <https://parquet.apache.org>`_
files or `DuckDb <https://duckdb.org/>`_ database.
This allows efficient data aggregation and analysis.
**Multiple** JSON files for different
FISPACT runs can be combined using simple additional identification.
So far, we use just two-dimensional identification by material
and *case*. The *case* usually identifies certain neutron flux energy distribution.


Implemented functionality
-------------------------

- export to DuckDB
- export to parquet files
- neutron flux presentation conversion


Installation
------------

From PyPI

.. code-block::

    pip install xpypact


As dependency

.. code-block::

    poetry add xpypact


From source

.. code-block::

    pip install htpps://github.com/MC-kit/xpypact.git


Examples
--------

.. code-block::

    from xpypact import FullDataCollector, Inventory

    def get_material_id(p: Path) -> int:
        ...

    def get_case_id(p: Path) -> int:
        ...

    jsons = [path1, path2, ...]
    material_ids = {p: get_material_id(p) for p in jsons }
    case_ids = {c: get_case_id(p) for p in jsons }

    collector = FullDataCollector()

    if sequential_load:
        for json in jsons:
            inventory = Inventory.from_json(json)
            collector.append(inventory, material_id=material_ids[json], case_id=case_ids[json])

    else:  # multithreading is allowed for collector as well

        task_list = ...  # list of tuples[directory, case_id, tasks_sequence]
        threads = 16  # whatever

        def _find_path(arg) -> tuple[int, int, Path]:
            _case, path, inventory = arg
            json_path: Path = (Path(path) / inventory).with_suffix(".json")
            if not json_path.exists():
                msg = f"Cannot find file {json_path}"
                raise FindPathError(msg)
            try:
                material_id = int(inventory[_LEN_INVENTORY:])
                case_str = json_path.parent.parts[-1]
                case_id = int(case_str[_LEN_CASE:])
            except (ValueError, IndexError) as x:
                msg = f"Cannot define material_id and case_id from {json_path}"
                raise FindPathError(msg) from x
            if case_id != _case:
                msg = f"Contradicting values of case_id in case path and database: {case_id} != {_case}"
                raise FindPathError(msg)
            return material_id, case_id, json_path

        with futures.ThreadPoolExecutor(max_workers=threads) as executor:
            mcp_futures = [
                executor.submit(_find_path, arg)
                for arg in (
                    (task_case[0], task_case[1], task)
                    for task_case in task_list
                    for task in task_case[2].split(",")
                    if task.startswith("inventory-")
                )
            ]

        mips = [x.result() for x in futures.as_completed(mcp_futures)]
        mips.sort(key=lambda x: x[0:2])  # sort by material_id, case_id

        def _load_json(arg) -> None:
            collector, material_id, case_id, json_path = arg
            collector.append(from_json(json_path.read_text(encoding="utf8")), material_id, case_id)

        with futures.ThreadPoolExecutor(max_workers=threads) as executor:
            executor.map(_load_json, ((collector, *mip) for mip in mips))


    collected = collector.get_result()

    # save to parquet files

    collected.save_to_parquets(Path.cwd() / "parquets")

    # or use DuckDB database

    import from xpypact.dao save
    import duckdb as db

    con = db.connect()
    save(con, collected)

    gamma_from_db = con.sql(
        """
        select
        g, rate
        from timestep_gamma
        where material_id = 1 and case_id = 54 and time_step_number = 7
        order by g
        """,
    ).fetchall()


Contributing
------------

.. image:: https://github.com/MC-kit/xpypact/workflows/Tests/badge.svg
   :target: https://github.com/MC-kit/xpypact/actions?query=workflow%3ATests
   :alt: Tests
.. image:: https://codecov.io/gh/MC-kit/xpypact/branch/master/graph/badge.svg?token=P6DPGSWM94
   :target: https://codecov.io/gh/MC-kit/xpypact
   :alt: Coverage
.. image:: https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white
   :target: https://github.com/pre-commit/pre-commit
   :alt: pre-commit
.. image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/charliermarsh/ruff/main/assets/badge/v2.json
   :target: https://github.com/astral-sh/ruff
   :alt: linter & style


Just follow ordinary practice:

    - `Commit message <https://github.com/angular/angular/blob/22b96b9/CONTRIBUTING.md#-commit-message-guidelines>`_
    - `Conventional commits <https://www.conventionalcommits.org/en/v1.0.0/#summary>`_


References
----------

    - `FISPACT <https://fispact.ukaea.uk/>`_
    - `FISPACT-II tools (including pypact) repositories <https://github.com/fispact>`_
    - `FISPACT at NEA/OECD <https://oecd-nea.org/tools/abstract/detail/NEA-1890>`_
    - `FISPACT introduction <https://indico.ictp.it/event/7994/session/5/contribution/24/material/slides/0.pdf>`_


.. Substitutions


.. |Maintained| image:: https://img.shields.io/badge/Maintained%3F-yes-green.svg
   :target: https://github.com/MC-kit/xpypact/graphs/commit-activity
.. |Tests| image:: https://github.com/MC-kit/xpypact/workflows/Tests/badge.svg
   :target: https://github.com/MC-kit/xpypact/actions?workflow=Tests
   :alt: Tests
.. |License| image:: https://img.shields.io/github/license/MC-kit/xpypact
   :target: https://github.com/MC-kit/xpypact
.. |Versions| image:: https://img.shields.io/pypi/pyversions/xpypact
   :alt: PyPI - Python Version
.. |PyPI| image:: https://img.shields.io/pypi/v/xpypact
   :target: https://pypi.org/project/xpypact/
   :alt: PyPI
.. |Docs| image:: https://readthedocs.org/projects/xpypact/badge/?version=latest
   :target: https://xpypact.readthedocs.io/en/latest/?badge=latest
   :alt: Documentation Status

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/MC-kit/xpypact",
    "name": "xpypact",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<3.14,>=3.10",
    "maintainer_email": null,
    "keywords": "element, nuclide, isotope, abundance, FISPACT, activation, duckdb, polars",
    "author": "dvp2015",
    "author_email": "dmitri_portnov@yahoo.com",
    "download_url": "https://files.pythonhosted.org/packages/68/b0/716344a2eb0a72f33ab50bdf19a14cd2e9aeb63afd2cb89bf7fee5c5c697/xpypact-0.12.5.tar.gz",
    "platform": null,
    "description": "==============================================================================\n*xpypact*: FISPACT output to Polars or DuckDB datasets converter\n==============================================================================\n\nAggregate results of `FISPACT <https://fispact.ukaea.uk/>`_ runs to efficient datasets.\n\n\n|Maintained| |License| |Versions| |PyPI| |Docs|\n\n.. contents::\n\n\n.. note::\n\n    This document is in progress.\n\nDescription\n-----------\n\nThe module loads FISPACT JSON output files and converts to `Polars <https://pola.rs/>`_ dataframes\nwith minor data normalization. The dataframes can be stored either to `parquet <https://parquet.apache.org>`_\nfiles or `DuckDb <https://duckdb.org/>`_ database.\nThis allows efficient data aggregation and analysis.\n**Multiple** JSON files for different\nFISPACT runs can be combined using simple additional identification.\nSo far, we use just two-dimensional identification by material\nand *case*. The *case* usually identifies certain neutron flux energy distribution.\n\n\nImplemented functionality\n-------------------------\n\n- export to DuckDB\n- export to parquet files\n- neutron flux presentation conversion\n\n\nInstallation\n------------\n\nFrom PyPI\n\n.. code-block::\n\n    pip install xpypact\n\n\nAs dependency\n\n.. code-block::\n\n    poetry add xpypact\n\n\nFrom source\n\n.. code-block::\n\n    pip install htpps://github.com/MC-kit/xpypact.git\n\n\nExamples\n--------\n\n.. code-block::\n\n    from xpypact import FullDataCollector, Inventory\n\n    def get_material_id(p: Path) -> int:\n        ...\n\n    def get_case_id(p: Path) -> int:\n        ...\n\n    jsons = [path1, path2, ...]\n    material_ids = {p: get_material_id(p) for p in jsons }\n    case_ids = {c: get_case_id(p) for p in jsons }\n\n    collector = FullDataCollector()\n\n    if sequential_load:\n        for json in jsons:\n            inventory = Inventory.from_json(json)\n            collector.append(inventory, material_id=material_ids[json], case_id=case_ids[json])\n\n    else:  # multithreading is allowed for collector as well\n\n        task_list = ...  # list of tuples[directory, case_id, tasks_sequence]\n        threads = 16  # whatever\n\n        def _find_path(arg) -> tuple[int, int, Path]:\n            _case, path, inventory = arg\n            json_path: Path = (Path(path) / inventory).with_suffix(\".json\")\n            if not json_path.exists():\n                msg = f\"Cannot find file {json_path}\"\n                raise FindPathError(msg)\n            try:\n                material_id = int(inventory[_LEN_INVENTORY:])\n                case_str = json_path.parent.parts[-1]\n                case_id = int(case_str[_LEN_CASE:])\n            except (ValueError, IndexError) as x:\n                msg = f\"Cannot define material_id and case_id from {json_path}\"\n                raise FindPathError(msg) from x\n            if case_id != _case:\n                msg = f\"Contradicting values of case_id in case path and database: {case_id} != {_case}\"\n                raise FindPathError(msg)\n            return material_id, case_id, json_path\n\n        with futures.ThreadPoolExecutor(max_workers=threads) as executor:\n            mcp_futures = [\n                executor.submit(_find_path, arg)\n                for arg in (\n                    (task_case[0], task_case[1], task)\n                    for task_case in task_list\n                    for task in task_case[2].split(\",\")\n                    if task.startswith(\"inventory-\")\n                )\n            ]\n\n        mips = [x.result() for x in futures.as_completed(mcp_futures)]\n        mips.sort(key=lambda x: x[0:2])  # sort by material_id, case_id\n\n        def _load_json(arg) -> None:\n            collector, material_id, case_id, json_path = arg\n            collector.append(from_json(json_path.read_text(encoding=\"utf8\")), material_id, case_id)\n\n        with futures.ThreadPoolExecutor(max_workers=threads) as executor:\n            executor.map(_load_json, ((collector, *mip) for mip in mips))\n\n\n    collected = collector.get_result()\n\n    # save to parquet files\n\n    collected.save_to_parquets(Path.cwd() / \"parquets\")\n\n    # or use DuckDB database\n\n    import from xpypact.dao save\n    import duckdb as db\n\n    con = db.connect()\n    save(con, collected)\n\n    gamma_from_db = con.sql(\n        \"\"\"\n        select\n        g, rate\n        from timestep_gamma\n        where material_id = 1 and case_id = 54 and time_step_number = 7\n        order by g\n        \"\"\",\n    ).fetchall()\n\n\nContributing\n------------\n\n.. image:: https://github.com/MC-kit/xpypact/workflows/Tests/badge.svg\n   :target: https://github.com/MC-kit/xpypact/actions?query=workflow%3ATests\n   :alt: Tests\n.. image:: https://codecov.io/gh/MC-kit/xpypact/branch/master/graph/badge.svg?token=P6DPGSWM94\n   :target: https://codecov.io/gh/MC-kit/xpypact\n   :alt: Coverage\n.. image:: https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white\n   :target: https://github.com/pre-commit/pre-commit\n   :alt: pre-commit\n.. image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/charliermarsh/ruff/main/assets/badge/v2.json\n   :target: https://github.com/astral-sh/ruff\n   :alt: linter & style\n\n\nJust follow ordinary practice:\n\n    - `Commit message <https://github.com/angular/angular/blob/22b96b9/CONTRIBUTING.md#-commit-message-guidelines>`_\n    - `Conventional commits <https://www.conventionalcommits.org/en/v1.0.0/#summary>`_\n\n\nReferences\n----------\n\n    - `FISPACT <https://fispact.ukaea.uk/>`_\n    - `FISPACT-II tools (including pypact) repositories <https://github.com/fispact>`_\n    - `FISPACT at NEA/OECD <https://oecd-nea.org/tools/abstract/detail/NEA-1890>`_\n    - `FISPACT introduction <https://indico.ictp.it/event/7994/session/5/contribution/24/material/slides/0.pdf>`_\n\n\n.. Substitutions\n\n\n.. |Maintained| image:: https://img.shields.io/badge/Maintained%3F-yes-green.svg\n   :target: https://github.com/MC-kit/xpypact/graphs/commit-activity\n.. |Tests| image:: https://github.com/MC-kit/xpypact/workflows/Tests/badge.svg\n   :target: https://github.com/MC-kit/xpypact/actions?workflow=Tests\n   :alt: Tests\n.. |License| image:: https://img.shields.io/github/license/MC-kit/xpypact\n   :target: https://github.com/MC-kit/xpypact\n.. |Versions| image:: https://img.shields.io/pypi/pyversions/xpypact\n   :alt: PyPI - Python Version\n.. |PyPI| image:: https://img.shields.io/pypi/v/xpypact\n   :target: https://pypi.org/project/xpypact/\n   :alt: PyPI\n.. |Docs| image:: https://readthedocs.org/projects/xpypact/badge/?version=latest\n   :target: https://xpypact.readthedocs.io/en/latest/?badge=latest\n   :alt: Documentation Status\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "\"Python workflow framework for FISPACT.\"",
    "version": "0.12.5",
    "project_urls": {
        "Changelog": "https://github.com/MC-kit/xpypact/releases",
        "Documentation": "https://xpypact.readthedocs.io",
        "Homepage": "https://github.com/MC-kit/xpypact",
        "Repository": "https://github.com/MC-kit/xpypact"
    },
    "split_keywords": [
        "element",
        " nuclide",
        " isotope",
        " abundance",
        " fispact",
        " activation",
        " duckdb",
        " polars"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "a01e882bc9f7abee489ec30c680bedbc25e7eade918fe9582e58d9343609ba16",
                "md5": "8065163ddabe7ce38452d8d9e450348b",
                "sha256": "56f39dfd4f0103fcac96703f554ed02a382316067450c4b211b2a323553df0ab"
            },
            "downloads": -1,
            "filename": "xpypact-0.12.5-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "8065163ddabe7ce38452d8d9e450348b",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<3.14,>=3.10",
            "size": 22237,
            "upload_time": "2025-02-03T11:42:16",
            "upload_time_iso_8601": "2025-02-03T11:42:16.425716Z",
            "url": "https://files.pythonhosted.org/packages/a0/1e/882bc9f7abee489ec30c680bedbc25e7eade918fe9582e58d9343609ba16/xpypact-0.12.5-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "68b0716344a2eb0a72f33ab50bdf19a14cd2e9aeb63afd2cb89bf7fee5c5c697",
                "md5": "5e835dccbafce4de7cc59b9e9dd25cd0",
                "sha256": "89b9fa9809672bfd6763bbfcb78e240127806c480b01473e45acc7a32493dcd0"
            },
            "downloads": -1,
            "filename": "xpypact-0.12.5.tar.gz",
            "has_sig": false,
            "md5_digest": "5e835dccbafce4de7cc59b9e9dd25cd0",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<3.14,>=3.10",
            "size": 61289,
            "upload_time": "2025-02-03T11:42:18",
            "upload_time_iso_8601": "2025-02-03T11:42:18.235576Z",
            "url": "https://files.pythonhosted.org/packages/68/b0/716344a2eb0a72f33ab50bdf19a14cd2e9aeb63afd2cb89bf7fee5c5c697/xpypact-0.12.5.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-02-03 11:42:18",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "MC-kit",
    "github_project": "xpypact",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "xpypact"
}
        
Elapsed time: 1.62132s