Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
fee27c9
Dump field before and after rhs evaluation for debugging
dschwoerer Nov 3, 2023
96da2e9
Add setName function
dschwoerer Nov 3, 2023
e56981c
Set div_par and grad_par names
dschwoerer Jun 19, 2023
6b2c132
Dump debug file if PVODE fails
dschwoerer Jun 19, 2023
df2d661
Add tracking to Field3D
dschwoerer Jun 19, 2023
263f9fe
Add tracking to Field3D
dschwoerer Jun 19, 2023
bac4ca9
cvode: Add option to use Adams Moulton solver instead of BDF
dschwoerer Apr 25, 2023
708bdcb
Expose more pvode option to user
dschwoerer Mar 29, 2023
d88b454
Fix bad cherry-pick
dschwoerer Mar 19, 2024
023bc41
Update to new API
dschwoerer Mar 19, 2024
affc995
Fix documentation
dschwoerer Mar 19, 2024
71f5b6a
Apply clang-format changes
dschwoerer Mar 19, 2024
31fd461
Apply recomendations from code-review
dschwoerer Mar 20, 2024
17e46cf
Use more meaningful names
dschwoerer Mar 20, 2024
9c0ae16
Apply clang-format changes
dschwoerer Mar 20, 2024
4a17b49
Apply suggestions from code review
dschwoerer Mar 20, 2024
2f7c3c0
Workaround for gcc 9.4
dschwoerer Mar 20, 2024
d611758
Add option to debug on failure
dschwoerer Apr 9, 2024
db96b7e
Add option to euler solver to dump debug info
dschwoerer Apr 9, 2024
84bfcef
Disable tracking once we are done
dschwoerer Apr 15, 2024
73265df
Allow to dump every timestep with euler
dschwoerer Apr 15, 2024
8ff388a
Apply clang-format changes
dschwoerer Apr 15, 2024
6724e75
Dump also parallel fields by default
dschwoerer Aug 9, 2024
28212c2
Also dump parallel fields
dschwoerer Aug 9, 2024
9cf0fba
Clarify which div_par has been used
dschwoerer Aug 9, 2024
97b67e1
Expose tracking
dschwoerer Aug 9, 2024
77e08ec
Apply clang-format changes
dschwoerer Oct 22, 2024
ba6fc6c
Add simple interface to store parallel fields
dschwoerer Aug 9, 2024
3c0d6a8
Apply clang-format changes
dschwoerer Oct 22, 2024
8e578fc
Merge branch 'next' into pvcode-cvode-improvements
dschwoerer Oct 22, 2024
d0669cd
Do not use numberParallelSlices()
dschwoerer Oct 22, 2024
291e4af
Merge branch 'next' of https://github.com/boutproject/BOUT-dev into p…
dschwoerer Jan 16, 2025
42fc8ff
prefer const ref
dschwoerer Jan 16, 2025
c9c13d4
Update for move of bout/version.hxx
dschwoerer Jan 16, 2025
ff93406
Prefer auto
dschwoerer Jan 16, 2025
a096cc5
Avoid warning for 3d metrics
dschwoerer Jan 16, 2025
27db46d
Apply recommendations from code review
dschwoerer Jan 16, 2025
24610c3
Explain purpose of variables
dschwoerer Jan 16, 2025
f6db2df
Apply clang-format changes
dschwoerer Jan 16, 2025
d1c137f
Add option to disable tracking
dschwoerer Jul 2, 2024
ee8a9d6
Apply clang-format changes
dschwoerer Nov 18, 2025
00fbaac
Merge branch 'next' of https://github.com/boutproject/BOUT-dev into p…
dschwoerer Nov 20, 2025
12c6c00
Merge branch 'pvcode-cvode-improvements' of https://github.com/boutpr…
dschwoerer Nov 20, 2025
e684304
Forward f to avoid copy
dschwoerer Nov 20, 2025
b75d020
Add missing header from clang-tidy
dschwoerer Nov 24, 2025
b824cfc
Apply more clang-tidy suggestions
dschwoerer Nov 24, 2025
90815fa
Add more headers explicitly
dschwoerer Nov 24, 2025
69457b8
Apply clang-format changes
dschwoerer Nov 24, 2025
b265c90
Remove duplicate definition
dschwoerer Nov 24, 2025
9c47bb8
Add more headers explicitly
dschwoerer Nov 24, 2025
02cc7d1
Apply clang-format changes
dschwoerer Nov 24, 2025
9e4edd9
Merge branch 'next' of https://github.com/boutproject/BOUT-dev into p…
dschwoerer Jan 29, 2026
cb0d3f1
Add backtrace to tracked operations
dschwoerer Jan 21, 2026
07d130c
Merge branch 'pvcode-cvode-improvements' of https://github.com/boutpr…
dschwoerer Jan 29, 2026
f2ed814
Apply clang-format changes
dschwoerer Jan 29, 2026
e3f8923
Apply clang-format suggestions
dschwoerer Jan 29, 2026
873c94f
Apply clang-format suggestions
dschwoerer Jan 29, 2026
7e5c311
Apply clang-format changes
dschwoerer Jan 29, 2026
e5f2d37
do not TRACK names
dschwoerer Feb 2, 2026
751abc4
Remove setName again
dschwoerer Feb 2, 2026
3cc061b
Update generated source code
dschwoerer Feb 2, 2026
5230138
[bot] Apply format changes
dschwoerer Feb 2, 2026
03283f4
[bot] Add last format changes commit to ignore file
dschwoerer Feb 2, 2026
fc2e28f
Merge branch 'next' into pvcode-cvode-improvements
dschwoerer Feb 2, 2026
26651cc
Revert accidential typo
dschwoerer Feb 2, 2026
f319c61
Fix comment
dschwoerer Feb 3, 2026
1519bf2
Add simple method to write data in parallel
dschwoerer Feb 3, 2026
b61f815
Use new interface to write data
dschwoerer Feb 3, 2026
eab6b03
Add docs on using solver-dumping
dschwoerer Feb 3, 2026
508dcda
Improve docs
dschwoerer Feb 3, 2026
c9732b7
Add more docs
dschwoerer Feb 3, 2026
9b96dad
simplify to_load creation
dschwoerer Feb 3, 2026
94f9ea6
Fixup to_load
dschwoerer Feb 3, 2026
6ec3917
Take reference to avoid copy
dschwoerer Feb 3, 2026
6f19419
Cleanup included headers
dschwoerer Feb 13, 2026
b04a242
Switch to [[maybe_unused]]
dschwoerer Feb 13, 2026
7476e31
Merge branch 'next' of https://github.com/boutproject/BOUT-dev into p…
dschwoerer Feb 13, 2026
83cf779
[bot] Apply format changes
dschwoerer Feb 13, 2026
bc86a19
[bot] Add last format changes commit to ignore file
dschwoerer Feb 13, 2026
cdd911c
Merge branch 'next' into pvcode-cvode-improvements
ZedThree Feb 16, 2026
3f31ab6
Merge remote-tracking branch 'origin/next' into HEAD
dschwoerer Feb 25, 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: 2 additions & 0 deletions .git-blame-ignore-revs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ ed2117e6d6826a98b6988e2f18c0c34e408563b6
17ac13c28aa3b34a0e46dbe87bb3874f6b25e706
# Added by the bot
4b010b7634aee1045743be80c268d4644522cd29
52301380586fdbf890f620c04f689b08d89a6c34
a71cad2dd6ace5741a754e2ca7daacd4bb094e0e
83cf77923a4c72e44303354923021acf932b4fd2
2c2402ed59c91164eaff46dee0f79386b7347e9e
05b7c571544c3bcb153fce67d12b9ac48947fc2d
33 changes: 33 additions & 0 deletions include/bout/field3d.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,15 @@ class Field3D;
#include "bout/field2d.hxx"
#include "bout/fieldperp.hxx"
#include "bout/region.hxx"
#include "bout/traits.hxx"

#include <memory>
#include <optional>
#include <string>
#include <vector>

class Mesh;
class Options;

/// Class for 3D X-Y-Z scalar fields
/*!
Expand Down Expand Up @@ -291,6 +295,17 @@ public:
/// cuts on closed field lines?
bool requiresTwistShift(bool twist_shift_enabled);

/// Enable a special tracking mode for debugging
/// Save all changes that, are done to the field, to tracking
Field3D& enableTracking(const std::string& name, std::weak_ptr<Options> tracking);

/// Disable tracking
Field3D& disableTracking() {
tracking.reset();
tracking_state = 0;
return *this;
}

/////////////////////////////////////////////////////////
// Data access

Expand Down Expand Up @@ -493,6 +508,8 @@ public:

int size() const override { return nx * ny * nz; };

std::weak_ptr<Options> getTracking() { return tracking; };

private:
/// Array sizes (from fieldmesh). These are valid only if fieldmesh is not null
int nx{-1}, ny{-1}, nz{-1};
Expand All @@ -508,6 +525,22 @@ private:

/// RegionID over which the field is valid
std::optional<size_t> regionID;

/// counter for tracking, to assign unique names to the variable names
int tracking_state{0};
std::weak_ptr<Options> tracking;
// name is changed if we assign to the variable, while selfname is a
// non-changing copy that is used for the variable names in the dump files
std::string selfname;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this if we already have name?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added:

  // name is changed if we assign to the variable, while selfname is a
  // non-changing copy that is used for the variable names in the dump files

template <typename T>
void track(const T& change, const std::string& operation) {
if (tracking_state != 0) {
_track(change, operation);
}
}
template <typename T, typename = bout::utils::EnableIfField<T>>
void _track(const T& change, std::string operation);
void _track(const BoutReal& change, std::string operation);
};

// Non-member overloaded operators
Expand Down
3 changes: 3 additions & 0 deletions include/bout/options.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -1012,6 +1012,9 @@ auto Options::as(const Tensor<int>& similar_to) const -> Tensor<int>;
/// Convert \p value to string
std::string toString(const Options& value);

/// Save the parallel fields
void saveParallel(Options& opt, const std::string& name, const Field3D& tosave);

/// Output a stringified \p value to a stream
///
/// This is templated to avoid implict casting: anything is
Expand Down
29 changes: 21 additions & 8 deletions include/bout/options_io.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,36 @@
///
/// 1. Dump files, containing time history:
///
/// auto dump = OptionsIOFactory::getInstance().createOutput();
/// dump->write(data);
/// auto dump = OptionsIOFactory::getInstance().createOutput();
/// dump->write(data);
///
/// where data is an Options tree. By default dump files are configured
/// with the root `output` section, or an Option tree can be passed to
/// `createOutput`.
///
/// 2. Restart files:
///
/// auto restart = OptionsIOFactory::getInstance().createOutput();
/// restart->write(data);
/// auto restart = OptionsIOFactory::getInstance().createRestart();
/// restart->write(data);
///
/// where data is an Options tree. By default restart files are configured
/// with the root `restart_files` section, or an Option tree can be passed to
/// `createRestart`.
///
/// 3. Ad-hoc single files
/// Note: The caller should consider how multiple processors interact with the file.
/// Note: The caller should consider how multiple processors interact with the file.
///
/// auto file = OptionsIOFactory::getInstance().createFile("some_file.nc");
/// or
/// auto file = OptionsIO::create("some_file.nc");
/// auto file = OptionsIOFactory::getInstance().createFile("some_file.nc");
/// or
/// auto file = OptionsIO::create("some_file.nc");
///
/// 4. Ad-hoc parallel files
/// This adds also metric information, such that the file can be read with
/// boutdata or xBOUT
///
/// OptionIO::write("some_file", data, mesh);
///
/// if mesh is omitted, no grid information is added.
///

#pragma once
Expand All @@ -37,6 +44,7 @@

#include "bout/build_defines.hxx"
#include "bout/generic_factory.hxx"
#include "bout/mesh.hxx"
#include "bout/options.hxx"

#include <memory>
Expand Down Expand Up @@ -77,6 +85,11 @@ public:
/// This uses the default file type and default options.
static std::unique_ptr<OptionsIO> create(const std::string& file);

/// Write some data to a file with a given name prefix
/// This will be done in parallel. If Mesh is given, also mesh data will be
/// added, which is needed for xBOUT or boutdata to read the files.
static void write(const std::string& prefix, Options& data, Mesh* mesh = nullptr);

/// Create an OptionsIO for I/O to the given file.
/// The file will be configured using the given `config` options:
/// - "type" : string The file type e.g. "netcdf" or "adios"
Expand Down
27 changes: 27 additions & 0 deletions manual/sphinx/developer_docs/debugging.rst
Original file line number Diff line number Diff line change
Expand Up @@ -158,3 +158,30 @@ If you need to capture runtime information in the message, you can use
the ``fmt`` syntax also used by the loggers::

TRACE("Value of i={}, some arbitrary {}", i, "string");


Time evolution
==============

It can be useful to know what happened when the simulation failed. The pvode
solver can dump the state of the simulation, at the time the solver
failed. This information includes the individual terms in the derivative. This
allows to identify which term is causing the issue. Additionally, the
residuum is dumped. This identifies not only which term is causing the issue,
but also where in the domain the solver is struggling. This can be enabled
with::

solver:type=pvode solver:debug_on_failure=true

It can be also useful for understanding why the solver is slow. Forcing a
higher min_timestep, the solver will fail to evolve the system as it
encounters the situation, and provides information where it is happening.
This can be done with::

solver:type=pvode solver:debug_on_failure=true solver:min_timestep=1e2

It is also possible to dump at a specific time using the euler solver.
This can be useful for tracking down what is causing differences between two
different versions. It can be used with::

solver:type=euler solver:dump_at_time=0 input:error_on_unused_options=false
2 changes: 1 addition & 1 deletion manual/sphinx/user_docs/bout_options.rst
Original file line number Diff line number Diff line change
Expand Up @@ -889,7 +889,7 @@ Fields can also be stored and written::
Options fields;
fields["f2d"] = Field2D(1.0);
fields["f3d"] = Field3D(2.0);
bout::OptionsIO::create("fields.nc").write(fields);
bout::OptionsIO::create("fields.nc")->write(fields);

This allows the input settings and evolving variables to be
combined into a single tree (see above on joining trees) and written
Expand Down
70 changes: 70 additions & 0 deletions src/field/field3d.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
#include <bout/globals.hxx>

#include <cmath>
#include <cpptrace/cpptrace.hpp>
#include <memory>
#include <utility>

#include "bout/parallel_boundary_op.hxx"
#include "bout/parallel_boundary_region.hxx"
Expand All @@ -46,6 +49,8 @@
#include <bout/output.hxx>
#include <bout/utils.hxx>

#include "fmt/format.h"

/// Constructor
Field3D::Field3D(Mesh* localmesh, CELL_LOC location_in, DirectionTypes directions_in)
: Field(localmesh, location_in, directions_in) {
Expand Down Expand Up @@ -235,6 +240,8 @@ Field3D& Field3D::operator=(const Field3D& rhs) {
return (*this); // skip this assignment
}

track(rhs, "operator=");

// Copy base slice
Field::operator=(rhs);

Expand All @@ -254,6 +261,7 @@ Field3D& Field3D::operator=(const Field3D& rhs) {
}

Field3D& Field3D::operator=(Field3D&& rhs) {
track(rhs, "operator=");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really think this should be a macro that is only enabled at higher CHECK


// Move parallel slices or delete existing ones.
yup_fields = std::move(rhs.yup_fields);
Expand All @@ -274,6 +282,7 @@ Field3D& Field3D::operator=(Field3D&& rhs) {
}

Field3D& Field3D::operator=(const Field2D& rhs) {
track(rhs, "operator=");

/// Check that the data is allocated
ASSERT1(rhs.isAllocated());
Expand Down Expand Up @@ -318,6 +327,7 @@ void Field3D::operator=(const FieldPerp& rhs) {
}

Field3D& Field3D::operator=(const BoutReal val) {
track(val, "operator=");

// Delete existing parallel slices. We don't copy parallel slices, so any
// that currently exist will be incorrect.
Expand Down Expand Up @@ -831,3 +841,63 @@ Field3D::getValidRegionWithDefault(const std::string& region_name) const {
void Field3D::setRegion(const std::string& region_name) {
regionID = fieldmesh->getRegionID(region_name);
}

Field3D& Field3D::enableTracking(const std::string& name,
std::weak_ptr<Options> _tracking) {
tracking = std::move(_tracking);
tracking_state = 1;
selfname = name;
return *this;
}

template <typename T, typename>
void Field3D::_track(const T& change, std::string operation) {
if (tracking_state == 0) {
return;
}
auto locked = tracking.lock();
if (locked == nullptr) {
return;
}
const std::string outname{fmt::format("track_{:s}_{:d}", selfname, tracking_state++)};

locked->set(outname, change, "tracking");

const std::string trace = cpptrace::generate_trace().to_string();

// Workaround for bug in gcc9.4
#if BOUT_USE_TRACK
const std::string changename = change.name;
#endif
(*locked)[outname].setAttributes({
{"operation", operation},
#if BOUT_USE_TRACK
{"rhs.name", changename},
#endif
{"trace", trace},
});
}

template void
Field3D::_track<Field3D, bout::utils::EnableIfField<Field3D>>(const Field3D&,
std::string);
template void Field3D::_track<Field2D>(const Field2D&, std::string);
template void Field3D::_track<>(const FieldPerp&, std::string);

void Field3D::_track(const BoutReal& change, std::string operation) {
if (tracking_state == 0) {
return;
}
auto locked = tracking.lock();
if (locked == nullptr) {
return;
}
const std::string trace = cpptrace::generate_trace().to_string();
const std::string outname{fmt::format("track_{:s}_{:d}", selfname, tracking_state++)};
locked->set(outname, change, "tracking");
(*locked)[outname].setAttributes({
{"operation", operation},
{"rhs.name", "BoutReal"},
{"trace", trace},
});
}
7 changes: 7 additions & 0 deletions src/field/gen_fieldops.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,16 @@
}
{% endif %}

{% if lhs == "Field3D" %}
track(rhs, "operator{{operator}}=");
{% endif %}

checkData(*this);

} else {
{% if lhs == "Field3D" %}
track(rhs, "operator{{operator}}=");
{% endif %}
(*this) = (*this) {{operator}} {{rhs.name}};
}
return *this;
Expand Down
Loading
Loading