Codebase Structure#

TorX is organized as a set of largely independent sub-packages, each covering a specific purpose (equilibria, grids, analysis, and so on). Before writing new code, find the sub-package that fits the code’s purpose and put it there, reusing or extending what already exists rather than adding a parallel copy elsewhere. A merge request that adds a new top-level file or a new sub-package should be properly discussed before it is merged (see Development Guide for an overview of the review process).

Sub-packages (torx/)#

See the API reference for the full, always-up-to-date list of sub-packages and what each one contains, generated directly from the code and its docstrings. specializations/ is covered separately below.

Specializations (torx/specializations/)#

Anything specific to how a single simulation code lays out its data on disk, names its parameters, or otherwise differs from the others belongs in specializations/, not in a generic sub-package. Examples include reading snap files, grids, and parameter files for GRILLIX and GENE-X.

which_code() at the top of specializations/ auto-detects which code produced a given simulation directory. If a routine can be written to accept plain arrays or a generic grid/equilibrium instead of reading files itself, prefer that over adding another code-specific reader (see Design Principles, point 6).

Companion libraries#

  • storx/ is a separate package for organized storage of datasets produced by TorX analysis. Code that saves or loads processed results (as opposed to processing them) belongs here, not in torx/.

  • flare/ and moose/ are external Fortran libraries used for 3D simulations and post-processing. torx.equilibrium.FlareEquilibrium is the TorX interface to use the FLARE equilibrium relevant functions. See FLARE.

  • notebooks/ holds example notebooks. A .py file is picked up as a notebook automatically by the presence of a jupytext header near the top of the file; nothing needs to be registered by hand. Prefer a notebook here over a new file in scripts/ for one-off or interactive analysis work (see Design Principles, point 5).

  • scripts/ holds standalone CLI tools, such as ncpydiff.py for diffing NetCDF/HDF5 files. This is for tooling that needs to run from the command line, not for analysis. If the code interprets simulation output rather than operating on files generically, it belongs in a notebook instead.

Fitting a merge request into the structure#

Before adding a new function or class:

  1. Find the owning sub-package. Use the list from the API reference to try and find an existing sub-package to fit a change into.

  2. Search for something to extend. Check the sub-package’s public API (from torx.<sub-package> import ..., or browse its __init__.py) for a function that already does this or something close. Prefer adding a parameter or a small extension to an existing function over writing a new one that duplicates most of its logic (see Code Guidelines, Readability).

  3. Export it. A new public name is only usable by others once it is re-exported from the sub-package’s __init__.py; see Packages and Imports.

  4. Test it alongside the existing tests for that sub-package (tests/test_<sub-package>/), rather than in a new top-level test file.

  5. If nothing fits, that is a signal to raise the question in the merge request or with a senior developer before adding a new sub-package, rather than deciding unilaterally where the new code should live.