diff --git a/.github/workflows/reusable-scheduled.yml b/.github/workflows/reusable-scheduled.yml index e4652bd23..68f7f8f82 100644 --- a/.github/workflows/reusable-scheduled.yml +++ b/.github/workflows/reusable-scheduled.yml @@ -107,7 +107,7 @@ jobs: TEST_FILES="bsplines/tests/ console/tests/ fields_background/tests/ geometry/tests/ initial/tests/ kinetic_background/tests/ linear_algebra/tests/" ;; shard-2) - TEST_FILES="propagators/tests/ ode/tests/ polar/tests/ post_processing/tests/ dispersion_relations/tests/ io/tests/ simulation/tests/ models/tests/test_gpu_LinearVlasovAmpereOneSpecies.py models/tests/test_gpu_VlasovAmpereOneSpecies.py" + TEST_FILES="api/tests/ propagators/tests/ ode/tests/ polar/tests/ post_processing/tests/ dispersion_relations/tests/ io/tests/ simulation/tests/ models/tests/test_gpu_LinearVlasovAmpereOneSpecies.py models/tests/test_gpu_VlasovAmpereOneSpecies.py" ;; shard-3) TEST_FILES="feec/tests/" diff --git a/.github/workflows/reusable-unit-testing.yml b/.github/workflows/reusable-unit-testing.yml index 33c3b7a35..3864101f6 100644 --- a/.github/workflows/reusable-unit-testing.yml +++ b/.github/workflows/reusable-unit-testing.yml @@ -39,7 +39,7 @@ jobs: - shard: shard-1 test_files: bsplines/tests/ console/tests/ fields_background/tests/ geometry/tests/ initial/tests/ kinetic_background/tests/ linear_algebra/tests/ - shard: shard-2 - test_files: propagators/tests/ ode/tests/ polar/tests/ post_processing/tests/ dispersion_relations/tests/ io/tests/ simulation/tests/ models/tests/test_gpu_LinearVlasovAmpereOneSpecies.py models/tests/test_gpu_VlasovAmpereOneSpecies.py + test_files: api/tests/ propagators/tests/ ode/tests/ polar/tests/ post_processing/tests/ dispersion_relations/tests/ io/tests/ simulation/tests/ models/tests/test_gpu_LinearVlasovAmpereOneSpecies.py models/tests/test_gpu_VlasovAmpereOneSpecies.py - shard: shard-3 test_files: feec/tests/ - shard: shard-4 diff --git a/src/struphy/api/models/__init__.py b/src/struphy/api/models/__init__.py index 966384b90..9a120106c 100644 --- a/src/struphy/api/models/__init__.py +++ b/src/struphy/api/models/__init__.py @@ -1,5 +1,6 @@ from struphy.models.cold_plasma import ColdPlasma from struphy.models.cold_plasma_vlasov import ColdPlasmaVlasov +from struphy.models.curl_curl import CurlCurl from struphy.models.deterministic_particle_diffusion import ( DeterministicParticleDiffusion, ) @@ -9,6 +10,7 @@ from struphy.models.guiding_center import GuidingCenter from struphy.models.gyrokinetic_poisson import GyrokineticPoisson from struphy.models.hasegawa_wakatani import HasegawaWakatani +from struphy.models.incompressible_navier_stokes_sph import IncompressibleNavierStokesSPH from struphy.models.linear_extended_mh_duniform import LinearExtendedMHDuniform from struphy.models.linear_mhd import LinearMHD from struphy.models.linear_mhd_driftkinetic_cc import LinearMHDDriftkineticCC @@ -25,6 +27,7 @@ from struphy.models.shear_alfven import ShearAlfven from struphy.models.shear_alfven_curl_curl import ShearAlfvenCurlCurl from struphy.models.shear_alfven_curl_curl_with_proj import ShearAlfvenCurlCurlwithProj +from struphy.models.toy_drift import ToyDrift from struphy.models.two_fluid_quasi_neutral_toy import TwoFluidQuasiNeutralToy from struphy.models.variational_barotropic_fluid import VariationalBarotropicFluid from struphy.models.variational_compressible_fluid import VariationalCompressibleFluid @@ -49,11 +52,13 @@ __all__ = [ "ColdPlasma", "ColdPlasmaVlasov", + "CurlCurl", "DeterministicParticleDiffusion", "DriftKineticElectrostaticAdiabatic", "GuidingCenter", "GyrokineticPoisson", "HasegawaWakatani", + "IncompressibleNavierStokesSPH", "LinearExtendedMHDuniform", "LinearMHD", "LinearMHDDriftkineticCC", @@ -68,6 +73,7 @@ "ShearAlfven", "ShearAlfvenCurlCurl", "ShearAlfvenCurlCurlwithProj", + "ToyDrift", "TwoFluidQuasiNeutralToy", "VariationalBarotropicFluid", "VariationalCompressibleFluid", diff --git a/src/struphy/api/tests/__init__.py b/src/struphy/api/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/struphy/api/tests/test_public_api.py b/src/struphy/api/tests/test_public_api.py index e9211ac27..33bbe7e39 100644 --- a/src/struphy/api/tests/test_public_api.py +++ b/src/struphy/api/tests/test_public_api.py @@ -1,7 +1,13 @@ """Regression coverage for the public lazy imports.""" +import ast import subprocess import sys +from pathlib import Path + +import pytest + +pytestmark = pytest.mark.mpi_skip def test_post_processing_exports(): @@ -31,3 +37,23 @@ def test_post_processing_exports(): capture_output=True, text=True, ) + + +def test_api_models_match_models(): + # Parse instead of import: importing struphy.api.models loads every model. + import struphy.models + + api_init = Path(struphy.models.__file__).parents[1] / "api" / "models" / "__init__.py" + tree = ast.parse(api_init.read_text()) + (api_all,) = [ + ast.literal_eval(node.value) + for node in tree.body + if isinstance(node, ast.Assign) and any(getattr(t, "id", None) == "__all__" for t in node.targets) + ] + api_imports = { + alias.name: node.module for node in tree.body if isinstance(node, ast.ImportFrom) for alias in node.names + } + assert sorted(api_all) == sorted(struphy.models.__all__) + assert sorted(struphy.models.__all__) == sorted(struphy.models._LAZY_IMPORTS) + # every exported name is imported from the module that defines it + assert api_imports == struphy.models._LAZY_IMPORTS diff --git a/src/struphy/console/test.py b/src/struphy/console/test.py index 0af89df1f..264373cf3 100644 --- a/src/struphy/console/test.py +++ b/src/struphy/console/test.py @@ -44,6 +44,7 @@ def struphy_test( if "unit" in group: list_of_tests = [ + f"{LIBPATH}/api/tests/", f"{LIBPATH}/bsplines/tests/", f"{LIBPATH}/console/tests/", f"{LIBPATH}/dispersion_relations/tests/", diff --git a/src/struphy/models/base.py b/src/struphy/models/base.py index 0abc45730..7d969f23d 100644 --- a/src/struphy/models/base.py +++ b/src/struphy/models/base.py @@ -81,8 +81,10 @@ class StruphyModel(metaclass=StruphyModelMeta): Notes ----- - All Struphy models must be subclasses of ``StruphyModel`` and should be added to ``struphy/models/`` - in one of the modules: ``fluid.py``, ``kinetic.py``, ``hybrid.py``, or ``toy.py``. + All Struphy models must be subclasses of ``StruphyModel``. Each model lives in its own module + ``struphy/models/.py`` (snake case of the class name). After adding a model, regenerate + ``struphy/models/__init__.py`` with ``struphy build-init-files`` and add the model by hand to + ``struphy/api/models/__init__.py``. Time integration is performed by calling the ``integrate()`` method with a time step and splitting algorithm (Lie-Trotter or Strang). The model manages the execution of all propagators diff --git a/src/struphy/propagators/base.py b/src/struphy/propagators/base.py index 4353c0b08..aa7e399d7 100644 --- a/src/struphy/propagators/base.py +++ b/src/struphy/propagators/base.py @@ -66,7 +66,7 @@ class Options(OptionsBase): # specific literals OptsTemplate = Literal["implicit", "explicit"] # propagator options - opt1: str = ("implicit",) + opt1: OptsTemplate = "implicit" def __post_init__(self): # checks