Skip to content

New approach to normalising variables in SNES#3395

Merged
bendudson merged 13 commits into
nextfrom
cmacmackin/snes-scale-residual
Jun 20, 2026
Merged

New approach to normalising variables in SNES#3395
bendudson merged 13 commits into
nextfrom
cmacmackin/snes-scale-residual

Conversation

@cmacmackin

@cmacmackin cmacmackin commented Jun 19, 2026

Copy link
Copy Markdown
Collaborator

The rescale_vars option in SNESSolver has been rewritten. Previously it was meant to perform Jacobian column scaling. It now changes the nonlinear equation being solved from

$$ F(x_{n+1}) = \frac{x_{n} - x_{n+1}}{\Delta t} + f({x}_{n+1}) = 0 $$

to

$$ \tilde{F}(\tilde{x}_{n+1}) = \frac{\tilde{x}_{n} - \tilde{x}_{n+1}}{\Delta t} + Sf(S^{-1}\tilde{x}_{n+1}) = 0, $$

where $f$ is the function for the time-derivative of $x$, $\tilde x = Sx$, and $S$ is a diagonal matrix with each entry set to the inverse of the corresponding value of $x$ in a previous time-step.

A new, dynamic scheme has been adopted for deciding when to rescale $x$, to ensure rescaling will happen promptly when $x$ has changed significantly.

With this PR, the SNES solver will also output the residual from the last nonlinear solve (i.e., the value of $F(x)$, not the value of $f(x)$) when diagnose = true. This was used to help understand what areas of the domain were controlling the convergence of the solve and whether rescaling changed this. In order to output this information, some refactoring was done to the base Solver class to generalise its functions for transferring data between arrays and Field objects.

Has involved refactoring Solver to allow loading/saving from/to
arbitrary sets of fields. Have also changed how scale_vars works,
although I'll probably want to name a different setting for this. What
I've made it done doesn't appear to be what it was intended for
originally.
@cmacmackin cmacmackin requested a review from bendudson June 19, 2026 17:10
@cmacmackin cmacmackin assigned cmacmackin and unassigned cmacmackin Jun 19, 2026
@cmacmackin cmacmackin requested a review from mikekryjak June 19, 2026 17:11

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

clang-tidy made some suggestions

Comment thread include/bout/solver.hxx Outdated
Comment thread include/bout/solver.hxx Outdated
Comment thread include/bout/solver.hxx
Comment thread include/bout/solver.hxx
Comment thread include/bout/solver.hxx Outdated
Comment thread src/solver/impls/snes/snes.cxx Outdated
Comment thread src/solver/impls/snes/snes.cxx Outdated
Comment thread src/solver/impls/snes/snes.cxx Outdated
Comment thread src/solver/impls/snes/snes.cxx Outdated
Comment thread src/solver/impls/snes/snes.hxx

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

clang-tidy made some suggestions

Comment thread include/bout/solver.hxx Outdated
Comment thread include/bout/solver.hxx
Comment thread include/bout/solver.hxx
Comment thread include/bout/solver.hxx Outdated
Comment thread include/bout/solver.hxx Outdated
Comment thread src/solver/impls/snes/snes.cxx Outdated
// Copy derivatives back
{
if (diagnose) {
BoutReal* fdata = nullptr;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: pointee of variable 'fdata' of type 'BoutReal *' (aka 'double *') can be declared 'const' [misc-const-correctness]

Suggested change
BoutReal* fdata = nullptr;
{ const

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

No it can't, because the argument of save_derivs must be non-const.

}

if (diagnose) {
BoutReal* resid_data = nullptr;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: pointee of variable 'resid_data' of type 'BoutReal *' (aka 'double *') can be declared 'const' [misc-const-correctness]

Suggested change
BoutReal* resid_data = nullptr;
{ const

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

No it can't, because the argument of save_derivs must be non-const.

class SNESSolver;

#include <vector>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: included header vector is not used directly [misc-include-cleaner]

Suggested change

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Yes it is, see lines 281 and 283.

Comment thread src/solver/solver.cxx
}

void Solver::set_id(BoutReal* udata) { loop_vars(udata, SOLVER_VAR_OP::SET_ID); }
void Solver::set_id(BoutReal* udata) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: method 'set_id' can be made static [readability-convert-member-functions-to-static]

include/bout/solver.hxx:602:

-   void set_id(BoutReal* udata);
+   static void set_id(BoutReal* udata);

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

No it can't. This calls loop_vars which isn't static (and can't be made static).

Comment thread src/solver/solver.cxx
}

void Solver::set_id(BoutReal* udata) { loop_vars(udata, SOLVER_VAR_OP::SET_ID); }
void Solver::set_id(BoutReal* udata) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: pointer parameter 'udata' can be pointer to const [readability-non-const-parameter]

include/bout/solver.hxx:602:

-   void set_id(BoutReal* udata);
+   void set_id(const BoutReal* udata);
Suggested change
void Solver::set_id(BoutReal* udata) {
void Solver::set_id(const BoutReal* udata) {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Again, no it can't. It gets passed into a function that needs it to be non-const.

@cmacmackin

Copy link
Copy Markdown
Collaborator Author

clang-tidy made some suggestions

Many of these suggestions were just wrong. I'm not sure what's going on there.

@malamast

Copy link
Copy Markdown
Contributor

Nice work, Chris! Thank you for doing this. I will check it more carefully next week.

One thing I was wondering about is how this behaves for sign-changing variables. For example, the ion parallel velocity, Vd+, can be positive, negative, or very close to zero. So, the scale based on abs(x) could potentially become very small. Is there a way to treat sign-changing variables differently?

@cmacmackin

Copy link
Copy Markdown
Collaborator Author

Variables are always normalised by their absolute value, so negative variables will stay negative. We also clamp the normalisation, limiting it to rtol, so variables can still approach zero.

C is a template parameter so can be determined at compile time.
The x1 vector is only allocated if predictor is enabled.
Previously metadata_it only advanced on the non-continue path. If one
field had evolve_bndry == false, every later field in that boundary
loop would be checked against the same stale metadata entry and
skipped too.
When SNES takes zero iterations (nl_its == 0) a simple Euler
step is taken. If scale_vars is true then the derivatives
should be scaled to be consistent with rhs_function.

@bendudson bendudson left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks @cmacmackin !

@bendudson bendudson merged commit 57348db into next Jun 20, 2026
23 checks passed
@bendudson bendudson deleted the cmacmackin/snes-scale-residual branch June 20, 2026 21:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants