Repository navigation
v3.4.0
Changelog
Struphy 3.4.0 - 2026-10-01
Headlines
- New lazy, xarray-based post-processing API:
OutputreplacesPostProcessor,PlottingData,sim.pproc()andsim.load_plotting_data().Simulation.run()now returns anOutput, andOutput("path/to/run")oropen_output()opens a finished run; post-processed fields, binned distributions, SPH densities and orbits are materialized on demand and returned asxarrayobjects with named dimensions, coordinates and units. #370 - Parallel kernel compilation:
struphy compile -j N(andCompiler(jobs=...)) compiles the pyccel kernels in parallel while preserving their dependency order; kernel dependencies are now detected by static AST parsing instead of importing the kernels. #382 - More efficient MPI sorting of markers: new
Pusherkeywordspushes_eta(required) andlocal_eval_onlycallmpi_sort_markersonly when markers have actually moved, cutting the number of sorts by 2x to 10x depending on the model with unchanged results, and giving good strong scaling for e.g.VlasovAmpereOneSpeciesandColdPlasmaVlasov. #415 - One folder per mapping: each of the 14 domains now lives in its own folder under
struphy/geometry/domains/, together with its own<name>_kernels.pyfor the mapping and Jacobian kernels; this prepares the translation to other backends such as CUDA. Imports likefrom struphy.geometry.domains import Cuboidstill work. #418 (merged via #417)
API changes
Outputandopen_outputreplacePostProcessorandPlottingDatainstruphy.__all__. OnSimulation,load_plotting_data()andplotting_dataare removed, andSimulation.outputandSimulation.from_output(path_out)are new.Domaingainsouter_boundary_mesh(), and theVariableclasses gainto_dict(). #370Compiler.__init__()andCompiler.compile()take a newjobsargument (default 1, serial) for parallel kernel compilation. #382- New option
HasegawaWakataniStep.Options.coupling(default1.0) sets the coupling coefficientCforc_fun="const", which was previously hard-coded to zero. #388 - The default of
parallelinOutput.pproc()andOutput.evaluate()changed fromFalsetoNone: post-processing now runs on all ranks when the MPI job has as many ranks as the saved run, and serially on rank 0 otherwise. #410 - New option
fast(defaultFalse) inVariationalViscosity.OptionsandVariationalResistivity.Options, replacing the leftoverfastkey of the old dict-based solver parameters. #454 - The misspelled field
LoadingParameters.dir_exrernalis renamed todir_external, as documented. #479 Simulation.spawn_sister()takes a newcommargument, so a sister simulation runs on the same communicator as its parent instead ofMPI.COMM_WORLD. #556- The
moment_factorssetters ofMaxwellian3D,GyroMaxwellian2D,GyroMaxwellian2DvperpandCanonicalMaxwellian2Dnow take a dict that is merged into the existing factors, e.g.f0.moment_factors = {"n": 3.0}; before, every assignment failed with aTypeError. #627 CanonicalMaxwellian2D.eval_psic()takes a new keyworduse_cbufs(defaultTrue) to bypass the result buffers. #637
Physics models
- None.
Bug fixes
- Fix
create_vtkin post-processing crashing onlog10(0)when no time steps were saved. #381 - Fix stale values in nested scalar sums (
a + b + c) inScalars.update(), which caused apparent drifts in derived quantities such as the total energy. #385 KineticEnergyPICandKineticEnergySPHno longer divide byN_ptwice, which made the kinetic energy of every PIC and SPH modelN_ptimes too small. #387- Fix
GyroMaxwellian2D.velocity_jacobian_detfor a callableB0, which now returns one value per marker. #394 - Zero-initialise
norm_b_prodin the pusher kernelpush_gc_cc_J2_stage_H1vec; its diagonal held uninitialised memory, corruptingCurrentCoupling5DGradBwithu_space="H1vec". #459 - Fix
PushRandomDiffusionadding the full Wiener increment at every Runge-Kutta stage, which made the effective diffusion coefficient 16 D withrk4. Each stage now adds itsb[i]fraction, and the default scheme isforward_euler(Euler-Maruyama). #458 - Fix the neutralising background in full-f
ImplicitDiffusion/PoissonSolvebeing multiplied by the mass matrixM0twice, which gave a large spurious initial potential inVlasovAmpereOneSpecies,ToyDriftandDriftKineticElectrostaticAdiabatic. #460 - Fix the missing charge source in the initial Poisson solve of
LinearVlasovMaxwellOneSpecies, which left the initial electric field at zero. #457 - Fix
dot_inner_tp_ringsinPolarLinearOperatorwriting the first tensor-product ring on every rank, which silently corrupted coefficients wheneta1is split across MPI ranks. #462 - Fix the missing barotropic pressure term in
VariationalDensityEvolvewithmodel="barotropic", which madeVariationalBarotropicFluidbehave like a pressureless fluid. #463 - Fix crashes of
VariationalViscosityandVariationalResistivityfor any non-zeromu/eta, caused by dict-style access to the solver dataclass, a wrong argument toeval_3formand an in-place update on aFEECVariable. #454 - Fix the missing
/pocin the eta1-derivatives of theHollowCylinderJacobian, which was wrong for anypoc != 1. #455 - Fix the missing factor
sin the eta1-derivatives of thePoweredEllipticCylinderJacobian, a 100% error for the defaults = 0.5. #464 Magnetosonic.allocateno longer re-allocates ab_fieldpassed in by the model, which dropped the initial conditions of the shared magnetic field in the linear MHD models. #461- Fix the missing toroidal-field term in
AxisymmMHDequilibrium.gradB_xyz; the gradient of |B| forEQDSKequilibriumwas off by about 4%. #465 EQDSKequilibriumnow rescales the boundary fluxpsi1to Struphy units likepsi0, fixing runs with non-defaultbase_units. #466- Fix a copy-paste error in the
G[0,2]metric entry of thehybrid_weightkernel, wrong for any mapping withdf[2,2] != 0such asCuboidorColella. #468 - Fix an
AttributeError(undefined_extracted_q2) inVariationalQBEvolvewithlinearize=True, which made every linearized run fail on its first step. #469 - Post-processing now tracks the saved markers,
fandn_sphper kinetic species, fixing aKeyErrorwhen only some species save particle data. #470 - Fix corner neighbour ranks left as
NoneinParticles._get_neighbouring_procfor mixed periodic/non-periodic boundaries, which broke SPH ghost-box communication. #471 ButcherTableau.a_stagenow raisesNotImplementedErrorfor the"3/8 rule"instead of silently dropping coefficients and degrading particle pushes to first order. #472- Fix
StencilMatrixFreeMassOperator.transposepassing coefficient spaces instead of FEM spaces, which crashed.Tandtransposed=Truefor matrix-free weighted mass operators. #473 - Fix the argument order in
AverageOperator.transpose, which made.Talways crash. #478 KineticEnergyPICno longer counts the magnetic momentmuas a velocity forParticles5D, removing a spurious energy term in all drift-kinetic models. #474- Add the missing equilibrium gradient
grad_PBeqin theH1vecbranch of the accumulation kernelcc_lin_mhd_5d_gradB, so bothu_spacechoices ofCurrentCoupling5DGradBgive the same physics. #476 - The SPH linear smoothing-kernel gradients now vanish at zero separation, so particles no longer push on themselves. #475
- Fix
loading="external"for particles, which failed with aTypeErrorinParticles.draw_markers; the parameter field is renamed todir_external. #479 - Fix
BasisProjectionOperatorLocal.update_weightsfor transposed operators, which kept applying the construction-time weights (e.g. inBracketOperator). #480 - The Uzawa path of
TwoFluidQuasiNeutralFullnow includesM2/dtin itsA11block, so it solves the time step instead of the steady problem. #483 BasisProjectionOperatorLocalnow treatsNoneweights as zero, fixing crashes ofBracketOperatorwithderham.with_local_projectors. #481- ... and 67 more bug fixes, see the closed PRs.
Internals
test_pprocgets ashow_plotsafeguard so the test doesn't open plot windows. #372- Update the managed dependency bounds in
pyproject.toml. #374 - Lazy imports:
import struphyand the public API objects, models and propagators are resolved on first access, and expensive imports are moved into the operations that need them, reducing Python startup time. #383 M2Bnnow uses the equilibrium field componentseq_mhd.b2_*instead of the curl of a projected vector potential, so the Hall operator keeps uniform background fields in periodic domains. #384LinearMHDandLinearExtendedMHDuniformget a new scalaren_thermal(quadratic compressional energy) that replaces the linear pressure diagnosticen_pinen_tot, removing the spurious drift of the total energy. #386- Replace Python lists by scalars in
surface_kernel_3d_matofmass_kernels.py, removing the kernels' only dependency on gFTL and with it the need forcmake >= 3.28instruphy compile. #389 - New features for quickly plotting the kinetic initial condition with the show-distribution-function utilities. #390
- New
ProjectorNoBCclass that wraps projectors to prevent applying Dirichlet boundary conditions. #395 - Rename the post-processing dimensions
e1,e2,e3toeta1,eta2,eta3, and pass slices directly toevaluate()instead ofisel(). #406 Outputintegrates the optional plasma-plots package: when it is installed,out.plot,out.analysisand the.plasmaaccessor on every product are available, e.g.out.plot.energies(). Install it withpip install "struphy[pproc]". #408- Kinetic boundary conditions are applied per marker inside the pusher kernels by the new kernel
apply_kinetic_bc_marker, speeding up position updates 2x-4x. #412 - Particle kernel setup is refactored into explicit
KernelSetupobjects (struphy/pic/pushing/kernel_setup.py). #413 - Bump the
feectoolsdependency to 0.1.11, which was missed in #410. #453 - CUDA strategy, part 1: proof of concept for running Struphy kernels on NVIDIA GPUs via CuPy next to the pyccel kernels (
CudaKernelinstruphy/utils/kernel_backends.py). #643 - CUDA strategy, part 2:
CudaKernel.from_file()loads CUDA kernels from<name>_cuda.cufiles next to the pyccel module. #644 - CUDA strategy, part 3:
KernelCatalogdiscovers kernels from the file layout, and a missing CUDA kernel raises a clear error on the GPU backend instead of silently falling back to the CPU. #645 - CUDA strategy, part 4:
Pusheraccepts aKernel(pyccel/CUDA pair) and chooses the kernel for the active backend once at setup; CPU behaviour is unchanged. #646 - CUDA strategy, part 5:
Domain.cuda_args_domainbuilds the CUDA kernel arguments of a domain on the device, andDomaindeep-copies correctly on the CuPy backend. #649
Struphy 3.3.0 - 2026-09-11
Headlines
- Enable automated scaling test workflow: running a profiling case across multiple MPI ranks, emitting per-run JSON metadata, packaging results into a publishable folder structure, and optionally uploading them to the struphy-hub/profiling-data repository. #266
- New tutorials and verification tests for SPH: #261
- tutorials/tutorial_viscous_euler_sph.ipynb
- tutorials/tutorial_velocity_diffusion_sph.ipynb
- tutorials/tutorial_hagen_poiseuille_sph.ipynb
- tutorials/tutorial_dam_break_sph.ipynb
- New guiding-center 5D phase-space conventions: switching from
(v_\parallel, v_\perp)to(v_\parallel, \mu)as the standard coordinates inParticles5D. Use consistentmu_idxhandling across particle kernels and PIC utilities. Introduced newCanonicalMaxwellian2Dwith caching capabilities. #275 - New surface (boundary) integral operators in the FEEC layer: enable assembly/application of boundary mass operators needed for non-homogeneous derivative boundary conditions. #303
- Enable parallel post processing on each rank. The default is still serial post-processing, which means that
parallel_pproc=Trueneeds to be passed for parallel work. #309 - Added memory estimates in struphy and feectools: Adds per-rank memory footprint reporting for particles and key linear-operator types, including a dry_run construction mode for StencilMatrix to estimate allocation size without actually allocating. #363
API changes
Variableshave been entirely removed fromPropagator'sOptionsclasses. Such "Options"-variables were not updated by thePropagator, but nevertheless needed in the sub-step. From now on, such variables have to be passed to thePropagatorconstructor, which is done internally in the model file. The user cannot pass these variables anymore in the launch file throughOptions(). #262- Added a switch in
EnvironmentOptionsthat lets you turn off writing of restart checkpoint data, this is convenient for benchmarking. #345
Physics models
- New propagator
PoissonAdiabaticGyrokineticfor the electric potential in gyrokinetic simulations with adiabatic electrons. #260 - New examples for model
DriftKineticElectrostaticAdiabatic: ITG in cylinderical geometry and cyclone base case (still issues due to noise). #260 - New model for TAE energetic particle simulations: The new API now supports TAE energetic particle simulations with the model
LinearMHDDriftkineticCC. #275 - New model
IncompressibleNavierStokesSPH: Incompressible Navier-Stokes equations solved using SPH with the Chorin projection scheme. The Poisson equation is solved on a grid with pressure in H1. This is a PIC scheme, not meshless anymore. #284 - Three new verification tests for
IncompressibleNavierStokesSPH(Chorin projection). #308 - Added
Poissonsolver case to the profiling examples. #302
Bug fixes
- Fix bug in
mpi_sort_markers: add missingself.update_ghost_particles()to get the correct number of valid_mks. #261 - Fix bug in matrix-matrix multiplication during weights assembling in
WeightedMassOperators.create_weighted_mass(). #267 - Fix incorrect accumulation kernels for
basis_u == 1andbasis_u == vin drift-kinetic-MHD hybrid scheme. #352
User news and internals
- For PIC, moved the factor
1/Npinto the definition of the weights. #261 - New files for sph kernels:
eval_kernels_sph.pyandpusher_kernels_sph.py. #261 - Added a new
Compilerclass wrapping the existingstruphy_compileCLI logic for API use. #281 - Added a
to_json()method to the Simulation class. #282 - Added workflow to build a docs preview for existing PRs. #283
- Added a new
to_json()method to theSimulationclass. #282 - Added a new workflow to build a docs preview for existing PRs. #283
- New accumulation kernel
div_u_weak_1formfor accumulating the divergence of the velocity field; new classParticlesToGridfor passing the accumulation parameters to a propagator in the model init; and new logic inImplicitDiffusionfor passing accumulation and filter parameters, respectively. #284 - Renamed propagator
PushVinEfield->PushVinForceField. #308 - Use config.json instead of files in postprocessing. Instead of exporting all the classes as pickled binary objects, export the main information about the simulation as a json file called
config.json. #314 - Nightly automatic check of dependency bounds. #318
- Enforce that feectools submodule should be pointing to the last commit. #320
- Only allocate the full eval grid on rank 0. Grids are now rank local,
_create_eval_gridsreturns global grids plus per-rank slices fromderham.domain_array, so each rank holds onlygrids_log_loc. The physical grid is built on rank 0 only. #322 - Added
setup/modules.jsonfor loading modules on known HPC systems. #326 - Added setters to all properties of the
Simulationclass. #336 - Added more profiling regions. #344
- Fixed the
xp.all(axis=1)bottleneck (10x speedup). #347 - Column major fix of apply markers bc. Added a pre-allocated
self._eta_bc_buf = xp.zeros((self.n_rows, 3))buffer (1.3x speedup). #348 _sendrecv_get_destinationsnow checks neighbor ranks first, and only falls back to checking the rest if some markers remain unmatched (up to 1.5x speedup). #350- Updated profiling setup (
scoper-profilerset to 0.5.0). Big improvements for GPU profiling and also line-by-line profiling for the regions we already defined using the tool without having to useline_profilerdirectly. #354 and #357 - Enable setting log file with environment variable. #358
- Improve docstring helpers. Added
_html,_markdown,_latexmethods to the model/domain/equilibria/perturbation baseclasses. Theinfo(),pde(), ... methods remain the same, they just use the_htmlmethods and display the code. #361 - Split up docstrings for the
Domain,Perturbation, andFluidEquilibriaclasses, mirroring the pattern already used byStruphyModel. #362
Struphy 3.2.0 - 2026-06-09
Headlines
- New Quickstart, Userguide, Tutorials and Developer's guide in the documentation: #252
- Each
Propagatornow sits in his own .py file: #236 - New propagator
CurlCurlSolve()for curl-curl problems: #245 - New classmethods to inspect the model docstring (in a jupyter notebook for example): #229
API changes
- Change in the signature of
ParticleSpecies.set_markers(), which is used in parameter files featuring particles. The new classesSortingParametersandSavingParametersreplace the methodsset_sorting_boxesandset_save_data. Instances of the new classes are passed toset_markers(): #247
User news
- Clean-up logging levels for simulation output: #247
- New plotting functionality for kinetic backgrounds: #239
- Addition of a matrix-free averaging operator for distributed FEEC data: #246
- New default for
boxes_per_dimistuple = (1, 1, 1): #247
Bug fixes
- Adaptation to general equilibria and new tests of the gyrokinetic Poisson solve: #238
Struphy 3.1.0 - 2026-04-24
Headlines
- Refactoring of the
Derhamclass: #212- Renamed
Nel -> num_elements,p -> degree,nq_pr -> nquads_proj,polar_ck -> polar_splines - The type of spline basis functions is now set via the argument
bcs, which is a tuple of length three. It holds the type for each direction:Nonefor periodic, or a tuple of length two with eitherfreeordirichletto indicate the type of clamped splines.bcsreplaces the two argumentsspl_kindanddirichlet_bc - The lifting is defined for each
FEECVariableseparately through the new attributelifting_function
- Renamed
- Refactoring of
WeightedMassOperators.create_weighted_massmethod: #227- The signature remains largely the same, except that list input for weights has been replaced by tuple input. Moreover, within the tuple, one can now pass a
SplineFunctionobject, either from H1 or L2 space, which will be multiplied to the constant weights during.assemble(). This allows for time dependent mass operators in nonlinear simulations (formerly treated with workarounds). - In the constructor of
create_weighted_mass, we now evaluate all callables derived fromweights: tuple[str]on the integration grid, multiply them together and then pass them as xp.arrays toWeightedMassOperatorfor building the object. This leads to much simpler code than in the previous version, where we built composed functions and passed them as weights. - In
MassMatrixPreconditioner, to build the Kronecker matrices from 1D matrices without domain decomposition, the values of the weights are now retrieved via an MPI sub-communicator, because the weights in M0, M1 etc. are now given as local xp.arrays, not as callables anymore.
- The signature remains largely the same, except that list input for weights has been replaced by tuple input. Moreover, within the tuple, one can now pass a
- Use
logginginstead of print statements; use functionset_logging_levelfrom the API to set the logging level of all handlers. With pytest you can usepytest --logging-level DEBUG src/struphyto set the loggong level: #199 and #219 - New user guide: #200
- Remove two submodules
struphy-parameter-filesandstruphy-tutorialsin favor of the new foldersexamples/ortutorials/: #206
API changes
base_unitsis removed from theStruphyModelconstructor; all equation parameters that can be seen in the model docstring can be passed to the model constructor: #222
User news
- Add
to_dictandfrom_dictmethods to theSimulationclass: #186 - Add
__repr__and__repr_no_defaults__methods to most classes in the API: #193 - Using
pyvista; dddshow_3dandcreate_geometry_meshmethods toDomainclass: #195 - Add iterators to models and domains: #196
- Added export and from_file methods to
SimulationBaseclass: #197 - Added name and description to the Simulation class: #198
- New model
ToyGyrokineticto simulate the diocotron instability: #201 - New classes for scalar quantities tracked during simulation (via new type
Scalar): #220 - The components of a model docstring are now available as class methods: #229
Bug fixes
- Weights in initial Poisson solves of kinetic models without control variate fixed: #192
Struphy 3.0.4 - 2026-02-27
Bug fixes
- New lower bound on pyccel is set to 2.2.0, due to this pyccel bug fix: pyccel/pyccel#2567
Struphy 3.0.3 - 2026-02-23
Headlines
- New class
Simulationinherits the genericSimulationBase, both are in the new folderstruphy/simulations/. The most important methods are:Simulation.run()Simulation.pproc()Simulation.load_plotting_data()Simulation.spawn_sister()(my new favorite!)
These are tested in the new tutorials: https://github.com/struphy-hub/struphy-tutorials/tree/use-species-properties
The file main.py has been deleted.
The Simulation takes a model as input. Other API classes are passed as well (see tutorials).
The model is viewed as everything related to the PDE, i.e. its variables, initial conditions etc. The simulation deals with the rest (geometry, derham, environment etc.)
Some important changes to the logic: The model does not have access to derham, mass_ops etc. anymore, these can be called from Propagator when needed. Solves that need to happen before the time stepping (like initial Poisson solves) are moved to model.allocate_helpers().
-
The default launch file has been improved. See Tutorial 2 or test with
struphy params MODEL. The files in the submodulestruphy-parameter-fileshave been adapted. -
Several new classes have been introduced for post processing and plotting data, see
post_processing_tools.py. The most important ones arePostProcessorandPlottingData. Dictionaries in the plotting data have been replaced by classes. Many classes now feature the__repr__dunder for customized printing.
API changes
New classes exposed: Simulation, PostProcessor and PlottingData.
User news
- Add
set_zero_velocityargument intoLoadingParameters, enforcing velocities of all particles along specified axis to always be zero: #176 - New model
ViscousEulerSPHreplacesEulerSPH. The evaluation of the viscosity tensor has been implemented and tested for SPH methods. Unit tests for evaluation of the fluid velocity and its gradients (needed in the viscosity tensor) have been improved: #160
Struphy 3.0.2 - 2026-02-06
Headlines
- Added a public API. This allows imports like
from struphy import equils: #168 - New default compile language is Fortran: #158
- Moved each model to its own file. Calling sub-processes must be avoided in the future because of incompatibility with MPI: #152
User news
- Added binning of higher order moments (current density, energy tensor) of f and delta f: #162
Developer news
- Use
pyccel 2.1: #153 - Added three submodules:
struphy-parameter-files,struphy-tutorialsandfeectools. The Struphy repo should be cloned withgit clone --recurse-submodules https://github.com/struphy-hub/struphy.gitto init and update the submodules. Also, rungit submodule updateregularly to get updates from the submodules. See #154 - Introduced class
options.LiteralOptionsfor parsing literals. MovedUnitstophysics.py: #167
Bug fixes
- Use
struphy.io.options.Unitsin equils. This enables the use of GVEC, EQDSK and DESC in the new framework: #158
Struphy 3.0.1 - 2025-12-11
Headlines
Psydac is now installed via pip from our fork renamed to feectools, which is published on PyPI. This avoids installing from a .whl file.
Functionality remains unchanged, but future releases of Struphy are much easier and quicker. We have kept the option to install the upstream psydac, once it is also on PyPI.
See #147.
User news
None
Developer news
- Removed legacy code (eigenvalue solver): #129
- Add context manager to h5py.File() calls: #135
- Fix undefined variables: #141
Bug fixes
- Fix setter in DESCequilibirum, update quickstart guide: #132
- Set defaults for given_in_basis: "0" for scalar and "v" for vector-valued: #136
- Fix the restart function: #143
Struphy 3.0.0 - 2025-11-13
Headlines
Struphy 3 represents a major refactoring with breaking changes with respect to Struphy 2, in particular:
- The
.ymlparameter files cannot be used anymore. Simulation parameters have to be transferred to the new.pylaunch files that are generated fromstruphy params MODEL. See the Struphy README for a quick introduction. - The console command
struphy run ...has been deprecated. The new way to launch simulations is by executing the.pylaunch file, for instance withpython params_MODEL.py. - Other deprecated console commands are
struphy pprocandstruphy units. Post-processing is now done through the API viamain.pproc(). - The Struphy repo has moved to Github. The old Gitlab repo will persist but not be maintained any longer. Issues, discussion and PRs will solely take place on the new Github repo.
User news
- Please consult the Struphy README and links therein to get familiar with the new workflows.
- New tutorials can be found on mybinder.
Developer news
Struphy has been refactored with the following principles in mind:
- get rid of console commands and increase the use of the Struphy API wherever possible
- become even more object-oriented
- use
Classesinstead ofdictswherever possible - use
Literalsto show options for string arguments
In Struphy 3, models feature the following important objects:
ParticleSpecies,FieldSpecies,FluidSpecies
Each species is a collection of Variables:
PICVariable,FEECVariable,SPHVariable
These variables are updated by Propagators. All options for a simluation can be set in the new .py launch file.
Bug fixes
- Incorporate psydac updates: #109
- Auto install Psydac on first Struphy import: #118
- Remove MPI Barrier responsible for deadlock: #121
Struphy 2.6.0 - 2025-11-12
Headlines
- This is a test run for the relaease of Struphy 3.0 from the new Github repo
Struphy 2.5.0 and prior releases
- See Gitlab