Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
a59d6ea
BOUT-dev: Use branch with SNES solver updates
bendudson Feb 12, 2026
40cdfbd
BOUT-dev: More SNES changes
bendudson Feb 12, 2026
ffcb5c8
evolve_density and pressure: Added a functionality to initialize numb…
malamast Dec 29, 2025
a165e56
zero_current: Set species momentum and added momentum to outputVars
malamast Dec 30, 2025
1334bb6
anomalous_diffusion: make anomalous_D variable accessible to other co…
malamast Dec 30, 2025
904e071
neutral_mixed: Added the contribution of ion velocity to the neutral …
malamast Dec 30, 2025
ed2e210
neutral_mixed: I separated the way we calculate the flux limiters in …
malamast Dec 30, 2025
adfae6a
braginskii_collisions: added a user-defined density_floor
malamast Dec 30, 2025
8f2081f
Fix rebase
mikekryjak Feb 25, 2026
d90cf0d
Add new diagnostics
mikekryjak Feb 26, 2026
54c69c6
Improve Dnn logic flow
mikekryjak Feb 26, 2026
c5a582e
Add temporary debug variable
mikekryjak Feb 26, 2026
62cd8c7
Fix segfault/wasted allocation
mikekryjak Feb 26, 2026
f4b37f0
Add diagnostics to allow reproduction in test
mikekryjak Feb 26, 2026
b183c15
Refactor eta for consistency with kappa
mikekryjak Feb 26, 2026
4369ef3
Improve diagnostic naming
mikekryjak Feb 26, 2026
33088f9
[bot] Add last format changes commit to ignore file
mikekryjak Feb 26, 2026
4bc4a46
Formatting
mikekryjak Feb 26, 2026
79615af
[bot] Apply format changes
mikekryjak Feb 26, 2026
06e7358
Make double counting lmax a flag, refactor
mikekryjak Mar 2, 2026
846f334
Improve formulation of thermal speed
mikekryjak Mar 2, 2026
d6e6a09
Add catch for boolean flux_limit setting
mikekryjak Mar 2, 2026
90ae2e3
Separate neutral limiters
mikekryjak Mar 2, 2026
2620863
Formatting
mikekryjak Mar 2, 2026
23c7d7c
Remove spurious neutral_lmax re-definition
mikekryjak Mar 3, 2026
7c3b10b
Remove flux limit exception duplicate due to poor merge
mikekryjak Mar 3, 2026
b62906b
Implement AFN style limiter formulation
mikekryjak Mar 3, 2026
d75bac3
Add setting for perp ion velocity coupling
mikekryjak Mar 3, 2026
42085c8
Formatting
mikekryjak Mar 3, 2026
deecde5
Merge branch 'master' into neutrals-flux-limmiters
mikekryjak Mar 3, 2026
9497476
Merge remote-tracking branch 'origin/snes-controllers' into neutrals-…
mikekryjak Mar 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion external/BOUT-dev
Submodule BOUT-dev updated 51 files
+2 −0 .clang-format-ignore
+4 −0 .git-blame-ignore-revs
+62 −0 .github/workflows/auto-formatting.yml
+0 −46 .github/workflows/black-fix.yml
+0 −33 .github/workflows/clang-format.yml
+79 −75 examples/blob2d/blob_velocity.py
+3 −2 examples/boutpp/simulation.py
+16 −8 examples/conduction-snb/fit_temperature.py
+18 −12 examples/conduction-snb/sinusoid.py
+15 −16 examples/conduction-snb/step.py
+2 −2 examples/conduction/generate.py
+18 −17 examples/eigen-box/eigenvals.py
+51 −40 examples/elm-pb/Python/2dprofile.py
+8 −8 examples/elm-pb/Python/analysis.py
+109 −70 examples/elm-pb/Python/elm_size.py
+4 −5 examples/elm-pb/Python/fftall.py
+5 −5 examples/elm-pb/Python/fftall2.py
+4 −5 examples/elm-pb/Python/grate.py
+25 −20 examples/elm-pb/Python/grate2.py
+25 −22 examples/elm-pb/Python/plotcollapse.py
+45 −48 examples/elm-pb/Python/plotmode.py
+46 −48 examples/elm-pb/Python/plotmode2.py
+22 −23 examples/elm-pb/Python/plotphase.py
+14 −12 examples/elm-pb/Python/polslice.py
+93 −49 examples/elm-pb/Python/post.py
+23 −23 examples/elm-pb/Python/read_elmsize.py
+20 −16 examples/elm-pb/Python/showpolslice.py
+21 −20 examples/elm-pb/Python/sprofiles.py
+17 −11 examples/elm-pb/runexample.py
+22 −23 examples/fci-wave/compare-density.py
+7 −7 examples/finite-volume/diffusion/mms.py
+10 −10 examples/finite-volume/fluid/mms.py
+8 −8 examples/laplace-petsc3d/plotcheck.py
+63 −53 examples/orszag-tang/generate.py
+2 −3 examples/performance/bracket/scaling_parser.py
+16 −16 examples/performance/ddx/new_scaling_parser.py
+16 −16 examples/performance/ddy/new_scaling_parser.py
+16 −16 examples/performance/ddz/new_scaling_parser.py
+2 −3 examples/performance/iterator/scaling_parser.py
+3 −3 examples/staggered_grid/generate.py
+5 −5 examples/subsampling/show.py
+1 −1 examples/wave-slab/generate.py
+3 −6 manual/CMakeLists.txt
+133 −103 manual/sphinx/figs/figure_creators/LaplacianMatrices.ipynb
+51 −46 manual/sphinx/figs/figure_creators/bout_runners_folder_structure.py
+57 −13 manual/sphinx/user_docs/time_integration.rst
+4 −21 src/field/initialprofiles.cxx
+231 −136 src/solver/impls/snes/snes.cxx
+46 −12 src/solver/impls/snes/snes.hxx
+1 −1 tests/MMS/advection/runtest
+120 −75 tests/unit/mesh/parallel/test_shiftedmetric.cxx
1 change: 1 addition & 0 deletions include/braginskii_collisions.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ private:
neutral_neutral;

BoutReal ei_multiplier; // Arbitrary user-set multiplier on electron-ion collisions
BoutReal density_floor;

/// Calculated collision rates saved for post-processing and use by other components
/// Saved in options, the BOUT++ dictionary-like object
Expand Down
3 changes: 3 additions & 0 deletions include/evolve_density.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ private:
bool diagnose; ///< Output additional diagnostics?
Field3D flow_xlow, flow_ylow; ///< Particle flow diagnostics

bool initialize_from_mesh; ///< Initilize the Field3D N from 2D profiles stored in the
///< mesh file.

/// This sets in the state
/// - species
/// - <name>
Expand Down
2 changes: 2 additions & 0 deletions include/evolve_pressure.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ private:
bool fix_momentum_boundary_flux; ///< Fix momentum flux to boundary condition?
Field3D Sp_nvh; ///< Pressure source due to artificial viscosity
Field3D E_PdivV, E_VgradP; ///< Diagnostic energy source terms for p*Div(V) and V*Grad(P)
bool initialize_from_mesh; ///< Initilize the Field3D P from 2D profiles stored in the
///< mesh file.

/// Inputs
/// - species
Expand Down
18 changes: 18 additions & 0 deletions include/fixed_density.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

#include "component.hxx"

using bout::globals::mesh;

/// Set ion density to a fixed value
///
struct FixedDensity : public Component {
Expand All @@ -26,6 +28,19 @@ struct FixedDensity : public Component {

// Get the density and normalise
N = options["density"].as<Field3D>() / Nnorm;

// Initilize the Field3D N from 2D profiles stored in the mesh file.
initialize_from_mesh =
options["initialize_from_mesh"]
.doc("Initilize field from 2D profiles stored in the mesh file?")
.withDefault<bool>(false);

if (initialize_from_mesh) {
// Try to read the initial field from the mesh
mesh->get(N, std::string("N") + name + "_init"); // Units: [m^-3/s]
N /= Nnorm; // Normalization
}

substitutePermissions("name", {name});
substitutePermissions("vars", {"AA", "charge", "density"});
}
Expand All @@ -51,6 +66,9 @@ private:

Field3D N; ///< Species density (normalised)

bool initialize_from_mesh; ///< Initilize the Field3D N from 2D profiles stored in the
///< mesh file.

/// Sets in the state the density, mass and charge of the species
///
/// - species
Expand Down
3 changes: 3 additions & 0 deletions include/isothermal.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ private:
BoutReal T; ///< The normalised temperature
Field3D P; ///< The normalised pressure

bool initialize_from_mesh; ///< Initilize the Field3D T from 2D profiles stored in the
///< mesh file.

bool diagnose; ///< Output additional diagnostics?

/// Inputs
Expand Down
33 changes: 29 additions & 4 deletions include/neutral_mixed.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,30 @@ private:
Field3D Tn; ///< Neutral temperature
Field3D Nnlim, Pnlim, logPnlim; // Limited in regions of low density

Field3D NVn_err; ///< Difference from momentum as input from solver
Field3D NVn_solver; ///< Momentum as calculated in the solver

BoutReal AA; ///< Atomic mass (proton = 1)

std::vector<std::string> collision_names; ///< Collisions used for collisionality
std::string
diffusion_collisions_mode; ///< Collision selection, either afn or multispecies
Field3D nu; ///< Collisionality to use for diffusion
Field3D Dnn; ///< Diffusion coefficient
Field3D nu_pseudo_mfp; ///< Pseudo-collision frequency based on mean free path
Field3D nu_total; ///< Total collision frequency used for diffusion, including
///< pseudo-collisions
Field3D Dnn, Dnn_unlimited, Dmax; ///< Diffusion coefficient
Field3D DnnNn, DnnPn, DnnTn, DnnNVn; ///< Used for operators
BoutReal flux_limit; ///< Diffusive flux limit
BoutReal diffusion_limit; ///< Maximum diffusion coefficient
Field3D kappa_n_unlimited, kappa_n_max_par, kappa_n_max_perp;
BoutReal flux_limit_adv; ///< Diffusive flux limit
BoutReal flux_limit_cond_par; ///< Limit for parallel conductive flux
BoutReal flux_limit_cond_perp; ///< Limit for perpendicular conductive flux
BoutReal flux_limit_visc_par; ///< Limit for parallel viscous flux
BoutReal flux_limit_visc_perp; ///< Limit for perpendicular viscous flux

BoutReal diffusion_limit; ///< Maximum diffusion coefficient
BoutReal neutral_lmax;
BoutReal flux_limiter_sharpness; ///< Sharpness of flux limiter transition

bool sheath_ydown, sheath_yup;

Expand All @@ -64,8 +77,18 @@ private:
bool neutral_conduction; ///< Include heat conduction?
bool evolve_momentum; ///< Evolve parallel momentum?
bool normalise_sources; ///< Normalise input sources?
bool perp_ion_coupling; ///< Include coupling to ion perpendicular velocity?

// Temporary variables
Field3D debug; ///< Debug variable FIXME: remove
bool double_count_lmax; ///< Include neutral_lmax in Dmax and kappa_max as well as Dnn?
bool legacy_thermal_speed; ///< Use legacy definition of thermal speed in flux limiter?
bool legacy_limiter_form; ///< Use legacy form of flux limiter rather than SOLPS-style

Field3D kappa_n, eta_n; ///< Neutral conduction and viscosity
Field3D kappa_n, eta_n_unlimited; ///< Neutral conduction and viscosity
Field3D kappa_n_perp, eta_n_perp; ///< Neutral conduction and viscosity
Field3D kappa_n_par, eta_n_par; ///< Neutral conduction and viscosity
Field3D eta_n_max_par, eta_n_max_perp; ///< Viscosity reduction factor for flux-limiting

bool nonorthogonal_operators; ///< Use nonorthogonal operators for radial transport?
bool precondition{true}; ///< Enable preconditioner?
Expand All @@ -77,6 +100,8 @@ private:
Field3D Sn, Sp, Snv; ///< Particle, pressure and momentum source
Field3D sound_speed; ///< Sound speed for use with Lax flux

bool zero_timederivs; ///< Set the time derivatives to zero?

bool output_ddt; ///< Save time derivatives?
bool diagnose; ///< Save additional diagnostics?

Expand Down
4 changes: 3 additions & 1 deletion include/zero_current.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@ struct ZeroCurrent : public Component {
private:
std::string name; ///< Name of this species
BoutReal charge; ///< The charge of this species
BoutReal atomic_mass; // Atomic mass

Field3D velocity; ///< Species velocity (for writing to output)

Field3D momentum; ///< Species momentum (for writing to output)

/// Required inputs
/// - species
/// - <name>
Expand Down
2 changes: 2 additions & 0 deletions src/anomalous_diffusion.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ void AnomalousDiffusion::transform_impl(GuardedOptions& state) {
flow_xlow, flow_ylow));
add(species["energy_flow_xlow"], flow_xlow);
add(species["energy_flow_ylow"], flow_ylow);

set(species["anomalous_D"], anomalous_D);
}

if (include_chi) {
Expand Down
4 changes: 3 additions & 1 deletion src/braginskii_collisions.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ BraginskiiCollisions::BraginskiiCollisions(const std::string& name, Options& all
.doc("User-set arbitrary multiplier on electron-ion collision rate")
.withDefault<BoutReal>(1.0);

density_floor = options["density_floor"].doc("Minimum density floor").withDefault(1e-8);

diagnose =
options["diagnose"].doc("Output additional diagnostics?").withDefault<bool>(false);

Expand Down Expand Up @@ -144,7 +146,7 @@ void BraginskiiCollisions::collide(GuardedOptions& species1, GuardedOptions& spe
const Field3D density2 = GET_NOBOUNDARY(Field3D, species2["density"]);

const Field3D nu = filledFrom(nu_12, [&](auto& i) {
return nu_12[i] * (A1 / A2) * density1[i] / softFloor(density2[i], 1e-5);
return nu_12[i] * (A1 / A2) * density1[i] / softFloor(density2[i], density_floor);
});

add(species2["collision_frequency"], nu); // Total collision frequency
Expand Down
12 changes: 12 additions & 0 deletions src/evolve_density.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,18 @@ EvolveDensity::EvolveDensity(std::string name, Options& alloptions, Solver* solv
}
substitutePermissions("name", {name});
substitutePermissions("outputs", outputs);

// Initilize the Field3D N from 2D profiles stored in the mesh file.
initialize_from_mesh =
n_options["initialize_from_mesh"]
.doc("Initilize field from 2D profiles stored in the mesh file?")
.withDefault<bool>(false);

if (initialize_from_mesh) {
// Try to read the initial field from the mesh
mesh->get(N, std::string("N") + name + "_init"); // Units: [m^-3/s]
N /= Nnorm; // Normalization
}
}

void EvolveDensity::transform_impl(GuardedOptions& state) {
Expand Down
16 changes: 14 additions & 2 deletions src/evolve_pressure.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,10 @@ EvolvePressure::EvolvePressure(std::string name, Options& alloptions, Solver* so
const BoutReal Nnorm = units["inv_meters_cubed"];
const BoutReal Tnorm = units["eV"];
const BoutReal Omega_ci = 1. / units["seconds"].as<BoutReal>();
const BoutReal Pnorm = SI::qe * Tnorm * Nnorm; // Pressure normalisation

auto& p_options = alloptions[std::string("P") + name];
source_normalisation =
SI::qe * Nnorm * Tnorm * Omega_ci; // [Pa/s] or [W/m^3] if converted to energy
source_normalisation = Pnorm * Omega_ci; // [Pa/s] or [W/m^3] if converted to energy
time_normalisation = 1. / Omega_ci; // [s]

// Try to read the pressure source from the mesh
Expand Down Expand Up @@ -164,6 +164,18 @@ EvolvePressure::EvolvePressure(std::string name, Options& alloptions, Solver* so
.doc("Include parallel heat conduction?")
.withDefault<bool>(true);

// Initilize the Field3D P from 2D profiles stored in the mesh file.
initialize_from_mesh =
p_options["initialize_from_mesh"]
.doc("Initilize field from 2D profiles stored in the mesh file?")
.withDefault<bool>(false);

if (initialize_from_mesh) {
// Try to read the initial field from the mesh
mesh->get(P, std::string("P") + name + "_init"); // Units: Pascal [Pa]
P /= Pnorm; // Normalization
}

if (source_time_dependent) {
setPermissions(readOnly("time"));
}
Expand Down
18 changes: 17 additions & 1 deletion src/isothermal.cxx
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@

#include "../include/isothermal.hxx"
#include <bout/constants.hxx>
#include <bout/mesh.hxx>

#include "../include/isothermal.hxx"
using bout::globals::mesh;

using bout::globals::mesh;

Isothermal::Isothermal(std::string name, Options& alloptions, Solver* UNUSED(solver))
: Component({readIfSet(fmt::format("species:{}:density", name), Regions::Interior),
Expand All @@ -15,6 +19,18 @@ Isothermal::Isothermal(std::string name, Options& alloptions, Solver* UNUSED(sol
T = options["temperature"].doc("Constant temperature [eV]").as<BoutReal>()
/ Tnorm; // Normalise

// Initilize the Field3D T from 2D profiles stored in the mesh file.
initialize_from_mesh =
options["initialize_from_mesh"]
.doc("Initilize field from 2D profiles stored in the mesh file?")
.withDefault<bool>(false);

if (initialize_from_mesh) {
// Try to read the initial field from the mesh
mesh->get(T, std::string("T") + name + "_init"); // Units: [eV]
T /= Tnorm; // Normalization
}

diagnose = options["diagnose"]
.doc("Save additional output diagnostics")
.withDefault<bool>(false);
Expand Down
Loading
Loading