-
Notifications
You must be signed in to change notification settings - Fork 90
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add matrix coloring to beuler solver (and fix imexbdf2) #2454
Conversation
Solvers can pass a flag to say whether the function can be linearised (e.g. inside inner linear solve, or Jacobian calculation). Physics models don't have to use the argument: rhs functions with a single (time) argument continue to work.
Should use const reference to avoid copying index
Deprecated, flagged as warning by Apple Clang
Enables large reductions in the number of iterations needed to calculate the Jacobian elements. Having the Jacobian then enables good preconditioning. Simple conduction example, nout=5 and timestep=10: PVODE: ``` 1.000e+01 644 1.25e-01 74.9 0.0 0.7 13.4 10.9 2.000e+01 161 4.41e-02 50.9 0.0 0.4 29.4 19.2 ``` beuler, SNESType = anderson ``` 1.000e+01 962 2.13e-01 65.8 0.0 0.7 8.2 25.4 2.000e+01 347 8.20e-02 61.3 0.0 0.6 14.0 24.0 ``` beuler, SNESType = newtonls, matrix free (no Jacobian) ``` 1.000e+01 3389 5.68e-01 89.2 0.0 0.8 3.3 6.6 2.000e+01 2325 3.55e-01 89.1 0.0 0.8 3.3 6.8 ``` beuler, SNESType = newtonls, with Jacobian, no coloring ``` 1.000e+01 833 1.53e-01 78.8 0.0 0.7 12.1 8.4 2.000e+01 521 9.81e-02 76.6 0.0 0.8 12.3 10.4 ``` beuler, SNESType = newtonls, with Jacobian coloring ``` 1.000e+01 85 3.78e-02 33.3 0.0 0.3 46.5 19.9 2.000e+01 57 3.16e-02 26.4 0.0 0.2 48.9 24.6 ```
Was destroying the iscoloring object before setup, and then reverting to brute-force calculation of the Jacobian.
There was a problem hiding this comment.
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
There were too many comments to post at once. Showing the first 25 out of 151. Check the log or trigger a new build to see more.
|
||
// Redundent definition because < C++17 | ||
constexpr int IMEXBDF2::MAX_SUPPORTED_ORDER; | ||
|
||
IMEXBDF2::IMEXBDF2(Options *opt) | ||
IMEXBDF2::IMEXBDF2(Options* opt) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: constructor does not initialize these fields: maxOrder, out_timestep, nsteps, timestep, ninternal, mxstep, adaptive, nadapt, mxstepAdapt, scaleCushUp, scaleCushDown, adaptRtol, dtMin, dtMax, dtMinFatal, dtImp, nlocal, neq, implicit_gamma, implicit_curtime, predictor, diagnose, verbose, linear_fails, nonlinear_fails, have_constraints, fdcoloring [cppcoreguidelines-pro-type-member-init]
IMEXBDF2::IMEXBDF2(Options* opt)
^
o_nnz[localIndex+i] += (n3d + n2d); | ||
for (int i = 0; i < n3d; i++) { | ||
d_nnz[localIndex + i] -= (n3d + n2d); | ||
o_nnz[localIndex + i] += (n3d + n2d); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: do not use pointer arithmetic [cppcoreguidelines-pro-bounds-pointer-arithmetic]
o_nnz[localIndex + i] += (n3d + n2d);
^
o_nnz[localIndex+i] += (n3d + n2d); | ||
for (int i = 0; i < n2d + n3d; i++) { | ||
// d_nnz[localIndex+i] -= (n3d + n2d); | ||
o_nnz[localIndex + i] += (n3d + n2d); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: do not use pointer arithmetic [cppcoreguidelines-pro-bounds-pointer-arithmetic]
o_nnz[localIndex + i] += (n3d + n2d);
^
o_nnz[localIndex+i] += (n3d + n2d); | ||
for (int i = 0; i < n3d; i++) { | ||
// d_nnz[localIndex+i] -= (n3d + n2d); | ||
o_nnz[localIndex + i] += (n3d + n2d); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: do not use pointer arithmetic [cppcoreguidelines-pro-bounds-pointer-arithmetic]
o_nnz[localIndex + i] += (n3d + n2d);
^
o_nnz[localIndex+i] += (n3d + n2d); | ||
for (int i = 0; i < n2d + n3d; i++) { | ||
// d_nnz[localIndex+i] -= (n3d + n2d); | ||
o_nnz[localIndex + i] += (n3d + n2d); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: do not use pointer arithmetic [cppcoreguidelines-pro-bounds-pointer-arithmetic]
o_nnz[localIndex + i] += (n3d + n2d);
^
o_nnz[localIndex+i] += (n3d + n2d); | ||
for (int i = 0; i < n3d; i++) { | ||
// d_nnz[localIndex+i] -= (n3d + n2d); | ||
o_nnz[localIndex + i] += (n3d + n2d); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: do not use pointer arithmetic [cppcoreguidelines-pro-bounds-pointer-arithmetic]
o_nnz[localIndex + i] += (n3d + n2d);
^
Describe all the options, and how to use newtonls with Jacobian coloring.
[skip ci]
- Defaults to using coloring to calculate a Jacobian - Iterations and lag jacobian set to values that work for SD1D tests so far. - Diagnostic outputs now include number of linear iterations and number of failures.
Reflect changes in defaults, and some notes on when these are likely to fail.
There was a problem hiding this comment.
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
There were too many comments to post at once. Showing the first 25 out of 128. Check the log or trigger a new build to see more.
for(int i=0;i<n2d+n3d;i++) { | ||
o_nnz[localIndex+i] -= (n3d + n2d); | ||
for (int i = 0; i < n2d + n3d; i++) { | ||
o_nnz[localIndex + i] -= (n3d + n2d); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: do not use pointer arithmetic [cppcoreguidelines-pro-bounds-pointer-arithmetic]
o_nnz[localIndex + i] -= (n3d + n2d);
^
for(int i=0;i<n3d;i++) { | ||
o_nnz[localIndex+i] -= (n3d + n2d); | ||
for (int i = 0; i < n3d; i++) { | ||
o_nnz[localIndex + i] -= (n3d + n2d); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: do not use pointer arithmetic [cppcoreguidelines-pro-bounds-pointer-arithmetic]
o_nnz[localIndex + i] -= (n3d + n2d);
^
for(int i=0;i<n2d+n3d;i++) { | ||
o_nnz[localIndex+i] -= (n3d + n2d); | ||
for (int i = 0; i < n2d + n3d; i++) { | ||
o_nnz[localIndex + i] -= (n3d + n2d); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: do not use pointer arithmetic [cppcoreguidelines-pro-bounds-pointer-arithmetic]
o_nnz[localIndex + i] -= (n3d + n2d);
^
for(int i=0;i<n3d;i++) { | ||
o_nnz[localIndex+i] -= (n3d + n2d); | ||
for (int i = 0; i < n3d; i++) { | ||
o_nnz[localIndex + i] -= (n3d + n2d); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: do not use pointer arithmetic [cppcoreguidelines-pro-bounds-pointer-arithmetic]
o_nnz[localIndex + i] -= (n3d + n2d);
^
const int xoffset[5] = {0,-1, 1, 0, 0}; | ||
const int yoffset[5] = {0, 0, 0,-1, 1}; | ||
|
||
const int xoffset[5] = {0, -1, 1, 0, 0}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: do not declare C-style arrays, use std::array<> instead [cppcoreguidelines-avoid-c-arrays]
const int xoffset[5] = {0, -1, 1, 0, 0};
^
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not touched in this PR, but this is a good suggestion we should do at some point
// An error occurred. If adaptive, reduce timestep | ||
if(!adaptive) | ||
if (!adaptive) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: statement should be inside braces [readability-braces-around-statements]
if (!adaptive)
^
{
// Now we can calculate the error and decide what we want to do | ||
if (checkingErr) { | ||
// Now we want to find the actual (abs) error | ||
BoutReal errTot[3] = {0, 0, 0}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: do not declare C-style arrays, use std::array<> instead [cppcoreguidelines-avoid-c-arrays]
BoutReal errTot[3] = {0, 0, 0};
^
if (checkingErr) { | ||
// Now we want to find the actual (abs) error | ||
BoutReal errTot[3] = {0, 0, 0}; | ||
BoutReal errGlobTot[3] = {0, 0, 0}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: do not declare C-style arrays, use std::array<> instead [cppcoreguidelines-avoid-c-arrays]
BoutReal errGlobTot[3] = {0, 0, 0};
^
//Increment order if we're not at the maximum requested | ||
if(order<maxOrder) order++; | ||
// Increment order if we're not at the maximum requested | ||
if (order < maxOrder) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: statement should be inside braces [readability-braces-around-statements]
if (order < maxOrder)
^
{
|
||
iteration++; // Advance iteration number | ||
|
||
/// Call the monitor function | ||
|
||
if(call_monitors(simtime, s, nsteps)) { | ||
if (call_monitors(simtime, s, nsteps)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: implicit conversion int
-> bool [readability-implicit-bool-conversion]
if (call_monitors(simtime, s, nsteps)) {
^
!= 0
Clang tidy suggestions
If timestep falls below this threshold, reset the Jacobian and preconditioner, and try to take a large timestep. The idea is that sometimes the solver gets stuck in a local minimum, and the observation that sometimes stopping the simulation and restarting can help.
There was a problem hiding this comment.
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
There were too many comments to post at once. Showing the first 25 out of 103. Check the log or trigger a new build to see more.
@@ -1152,97 +1176,102 @@ PetscErrorCode IMEXBDF2::solve_implicit(BoutReal curtime, BoutReal gamma) { | |||
implicit_gamma = gamma; | |||
|
|||
// Set initial guess at the solution | |||
BoutReal *xdata; | |||
BoutReal* xdata; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: variable xdata
is not initialized [cppcoreguidelines-init-variables]
BoutReal* xdata;
^
= nullptr
for(int i=0;i<nlocal;i++) { | ||
xdata[i] = uV[0][i]; // Use previous solution | ||
for (int i = 0; i < nlocal; i++) { | ||
xdata[i] = uV[0][i]; // Use previous solution |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: do not use pointer arithmetic [cppcoreguidelines-pro-bounds-pointer-arithmetic]
xdata[i] = uV[0][i]; // Use previous solution
^
for(int i=0;i<nlocal;i++) { | ||
xdata[i] = 2.*uV[0][i] - uV[1][i]; | ||
for (int i = 0; i < nlocal; i++) { | ||
xdata[i] = 2. * uV[0][i] - uV[1][i]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: do not use pointer arithmetic [cppcoreguidelines-pro-bounds-pointer-arithmetic]
xdata[i] = 2. * uV[0][i] - uV[1][i];
^
for(int i=0;i<nlocal;i++) { | ||
xdata[i] = 3.*uV[0][i] - 3.*uV[1][i] + uV[2][i]; | ||
for (int i = 0; i < nlocal; i++) { | ||
xdata[i] = 3. * uV[0][i] - 3. * uV[1][i] + uV[2][i]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: do not use pointer arithmetic [cppcoreguidelines-pro-bounds-pointer-arithmetic]
xdata[i] = 3. * uV[0][i] - 3. * uV[1][i] + uV[2][i];
^
for(int i=0;i<nlocal;i++) { | ||
xdata[i] = rhs[i]; // If G = 0 | ||
for (int i = 0; i < nlocal; i++) { | ||
xdata[i] = rhs[i]; // If G = 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: do not use pointer arithmetic [cppcoreguidelines-pro-bounds-pointer-arithmetic]
xdata[i] = rhs[i]; // If G = 0
^
op.run(jx, jy, jz, u); ++u; | ||
if (mesh->firstX() && !mesh->periodicX) { | ||
for (int jx = 0; jx < mesh->xstart; ++jx) | ||
for (int jy = mesh->ystart; jy <= mesh->yend; ++jy) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: statement should be inside braces [readability-braces-around-statements]
for (int jy = mesh->ystart; jy <= mesh->yend; ++jy)
^
{
for(int jz=0; jz < mesh->LocalNz; ++jz) { | ||
op.run(jx, jy, jz, u); ++u; | ||
if (mesh->lastX() && !mesh->periodicX) { | ||
for (int jx = mesh->xend + 1; jx < mesh->LocalNx; ++jx) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: statement should be inside braces [readability-braces-around-statements]
for (int jx = mesh->xend + 1; jx < mesh->LocalNx; ++jx)
^
{
op.run(jx, jy, jz, u); ++u; | ||
if (mesh->lastX() && !mesh->periodicX) { | ||
for (int jx = mesh->xend + 1; jx < mesh->LocalNx; ++jx) | ||
for (int jy = mesh->ystart; jy <= mesh->yend; ++jy) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: statement should be inside braces [readability-braces-around-statements]
for (int jy = mesh->ystart; jy <= mesh->yend; ++jy)
^
{
- If resetting doesn't work once, quit rather than get stuck in an infinite loop - Turn off the predictor when resetting. The predictor seems to make convergence slower when nearly in steady state.
There was a problem hiding this comment.
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
There were too many comments to post at once. Showing the first 25 out of 78. Check the log or trigger a new build to see more.
for(int jz=0; jz < mesh->LocalNz; ++jz) { | ||
op.run(*xi, jy, jz, u); ++u; | ||
for (RangeIterator xi = mesh->iterateBndryLowerY(); !xi.isDone(); ++xi) { | ||
for (int jy = 0; jy < mesh->ystart; ++jy) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: statement should be inside braces [readability-braces-around-statements]
for (int jy = 0; jy < mesh->ystart; ++jy)
^
{
for(int jz=0; jz < mesh->LocalNz; ++jz) { | ||
op.run(*xi, jy, jz, u); ++u; | ||
for (RangeIterator xi = mesh->iterateBndryUpperY(); !xi.isDone(); ++xi) { | ||
for (int jy = mesh->yend + 1; jy < mesh->LocalNy; ++jy) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: statement should be inside braces [readability-braces-around-statements]
for (int jy = mesh->yend + 1; jy < mesh->LocalNy; ++jy)
^
{
for (int jy = mesh->yend + 1; jy < mesh->LocalNy; ++jy) | ||
for (int jz = 0; jz < mesh->LocalNz; ++jz) { | ||
op.run(*xi, jy, jz, u); | ||
++u; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: do not use pointer arithmetic [cppcoreguidelines-pro-bounds-pointer-arithmetic]
++u;
^
for(int jy=mesh->ystart; jy <= mesh->yend; ++jy) | ||
for(int jz=0; jz < mesh->LocalNz; ++jz) { | ||
op.run(jx, jy, jz, u); ++u; | ||
for (int jx = mesh->xstart; jx <= mesh->xend; ++jx) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: statement should be inside braces [readability-braces-around-statements]
for (int jx = mesh->xstart; jx <= mesh->xend; ++jx)
^
{
src/solver/impls/snes/snes.cxx
Outdated
MatSetFromOptions(Jmf); | ||
|
||
PetscInt *d_nnz, *o_nnz; | ||
PetscMalloc((localN) * sizeof(PetscInt), &d_nnz); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]
PetscMalloc((localN) * sizeof(PetscInt), &d_nnz);
^
/usr/lib/petsc/include/petscsys.h:453:99: note: expanded from macro 'PetscMalloc'
#define PetscMalloc(a,b) ((*PetscTrMalloc)((a),PETSC_FALSE,__LINE__,PETSC_FUNCTION_NAME,__FILE__,(void**)(b)))
^
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The docs suggest using PetscNew
or PetscMalloc1
instead.
Could we even use std::vector<PetscInt> d_nnz(localN)
here instead? I can't quite get my head around all the alignment business and if it's required, but I think this should be fine? This would eliminate the calls to PetscFree
, and should hopefully avoid all the warnings about pointer arithmetic
I think we probably need to turn off |
Missing on for loops in imex-bdf2 code
There was a problem hiding this comment.
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
There were too many comments to post at once. Showing the first 25 out of 53. Check the log or trigger a new build to see more.
Shouldn't `output.print("\r")` be the proper replacement?
|
Thanks to @dschworer suggestion. [skip ci]
For me the old defaults give better results 😞 |
There was a problem hiding this comment.
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
There were too many comments to post at once. Showing the first 25 out of 28. Check the log or trigger a new build to see more.
src/solver/impls/snes/snes.cxx
Outdated
// Mark non-zero entries | ||
|
||
// Offsets for a 5-point pattern | ||
const int xoffset[5] = {0, -1, 1, 0, 0}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: do not declare C-style arrays, use std::array<> instead [cppcoreguidelines-avoid-c-arrays]
const int xoffset[5] = {0, -1, 1, 0, 0};
^
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As this is new code, I think it's worth implementing this suggestion:
const int xoffset[5] = {0, -1, 1, 0, 0}; | |
constexpr std::array<int, 5> xoffset = {0, -1, 1, 0, 0}; |
src/solver/impls/snes/snes.cxx
Outdated
|
||
// Offsets for a 5-point pattern | ||
const int xoffset[5] = {0, -1, 1, 0, 0}; | ||
const int yoffset[5] = {0, 0, 0, -1, 1}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: do not declare C-style arrays, use std::array<> instead [cppcoreguidelines-avoid-c-arrays]
const int yoffset[5] = {0, 0, 0, -1, 1};
^
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const int yoffset[5] = {0, 0, 0, -1, 1}; | |
constexpr std::array<int, 5> yoffset = {0, 0, 0, -1, 1}; |
If a step which would have ended at an output time fails, the looping variable should be reset to true so that the retry occurs. Thanks to Mike Kryjak for the report
Sets the linear solver and preconditioner to use
There was a problem hiding this comment.
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
src/solver/solver.cxx
Outdated
@@ -1246,13 +1246,13 @@ int Solver::run_rhs(BoutReal t) { | |||
|
|||
save_vars(tmp.begin()); // Copy variables into tmp | |||
pre_rhs(t); | |||
status = model->runConvective(t); | |||
status = model->runConvective(t, linear); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: Value stored to status
is never read [clang-analyzer-deadcode.DeadStores]
status = model->runConvective(t, linear);
^
src/solver/solver.cxx:1249:5: note: Value stored to 'status' is never read
beuler sometimes appears to reach a steady state, with timesteps continuously increasing, and zero nonlinear iterations e.g. ``` Time: 2189781.780775979, timestep: 9781.780775979214, nl iter: 0, lin iter: 1 Time: 2190000.0, timestep: 10759.958853577136, nl iter: 0, lin iter: 1 2.190e+06 31 1.94e+00 94.9 0.0 0.0 3.0 2.0 Time: 2200000.0, timestep: 10759.958853577136, nl iter: 0, lin iter: 1 2.200e+06 16 1.05e+00 91.0 0.0 0.0 6.3 2.7 Time: 2210000.0, timestep: 10759.958853577136, nl iter: 0, lin iter: 1 2.210e+06 16 1.08e+00 91.9 0.0 0.0 5.5 2.6 Time: 2220000.0, timestep: 10759.958853577136, nl iter: 0, lin iter: 1 ``` Restarting from this state however shows that it is not in steady state and even doesn't converge. To try to prevent this, force SNES to take at least one iteration, add more checks and reporting.
Will sometimes hit a state where snes stops after zero iterations (due to stol tolerance), and continues "converging" until the end of the simulation. Taking a small Euler step seems to help.
Add ability to change line search type. When SNES fails to converge, print diagnostic information on the fields and their time derivatives.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. There's a few bits that could be polished perhaps. Lots of noise from clang-tidy because PETSc.
There's a fair bit of repeated code between IMEX-BDF2 and SNES for the colouring -- is it possible to pull this out into a shared helper function/class?
const int xoffset[5] = {0,-1, 1, 0, 0}; | ||
const int yoffset[5] = {0, 0, 0,-1, 1}; | ||
|
||
const int xoffset[5] = {0, -1, 1, 0, 0}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not touched in this PR, but this is a good suggestion we should do at some point
src/solver/impls/snes/snes.cxx
Outdated
MatSetFromOptions(Jmf); | ||
|
||
PetscInt *d_nnz, *o_nnz; | ||
PetscMalloc((localN) * sizeof(PetscInt), &d_nnz); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The docs suggest using PetscNew
or PetscMalloc1
instead.
Could we even use std::vector<PetscInt> d_nnz(localN)
here instead? I can't quite get my head around all the alignment business and if it's required, but I think this should be fine? This would eliminate the calls to PetscFree
, and should hopefully avoid all the warnings about pointer arithmetic
src/solver/impls/snes/snes.cxx
Outdated
} else { | ||
// Only 3D fields | ||
for (int i = 0; i < n3d; i++) { | ||
d_nnz[localIndex + i] -= (n3d + n2d); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just flagging this to be double-checked: is the rhs supposed to match the loop limit? i.e. should this be
d_nnz[localIndex + i] -= (n3d + n2d); | |
d_nnz[localIndex + i] -= n3d; |
src/solver/impls/snes/snes.cxx
Outdated
if (z == 0) { | ||
// All 2D and 3D fields | ||
for (int i = 0; i < n2d + n3d; i++) { | ||
d_nnz[localIndex + i] -= (n3d + n2d); | ||
} | ||
} else { | ||
// Only 3D fields | ||
for (int i = 0; i < n3d; i++) { | ||
d_nnz[localIndex + i] -= (n3d + n2d); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assuming the loop body is supposed to be identical between the branches, here's a more concise way of writing this that avoids the repetition in the loop body:
if (z == 0) { | |
// All 2D and 3D fields | |
for (int i = 0; i < n2d + n3d; i++) { | |
d_nnz[localIndex + i] -= (n3d + n2d); | |
} | |
} else { | |
// Only 3D fields | |
for (int i = 0; i < n3d; i++) { | |
d_nnz[localIndex + i] -= (n3d + n2d); | |
} | |
const auto num_fields = (z == 0) ? n2d + n3d : n3d; | |
for (int i = 0; i < num_fields; i++) { | |
d_nnz[localIndex + i] -= (n3d + n2d); | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also wonder if these loop bodies could be wrapped up into functions and reused? Might cut down on this section a fair bit
src/solver/impls/snes/snes.cxx
Outdated
// Mark non-zero entries | ||
|
||
// Offsets for a 5-point pattern | ||
const int xoffset[5] = {0, -1, 1, 0, 0}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As this is new code, I think it's worth implementing this suggestion:
const int xoffset[5] = {0, -1, 1, 0, 0}; | |
constexpr std::array<int, 5> xoffset = {0, -1, 1, 0, 0}; |
src/solver/impls/snes/snes.cxx
Outdated
|
||
// Offsets for a 5-point pattern | ||
const int xoffset[5] = {0, -1, 1, 0, 0}; | ||
const int yoffset[5] = {0, 0, 0, -1, 1}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const int yoffset[5] = {0, 0, 0, -1, 1}; | |
constexpr std::array<int, 5> yoffset = {0, 0, 0, -1, 1}; |
src/solver/impls/snes/snes.cxx
Outdated
PetscInt row = ind0 + i; | ||
|
||
// Loop through each point in the 5-point stencil | ||
for (int c = 0; c < 5; c++) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One day C++ will have zip
!
src/solver/impls/snes/snes.hxx
Outdated
/// @param[out] f The vector for the result f(x) | ||
/// @param[in] linear Specifies that the SNES solver is in a linear (KSP) inner loop, | ||
/// so the operator should be linearised if possible | ||
PetscErrorCode snes_function(Vec x, Vec f, bool linear); ///< Nonlinear function |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PetscErrorCode snes_function(Vec x, Vec f, bool linear); ///< Nonlinear function | |
PetscErrorCode snes_function(Vec x, Vec f, bool linear); |
Sorry, didn't have time to look through the code yet (will try to get to it). One thought though - this might be something for a separate PR, but I don't think these solvers are using the Petsclib features for setting options that were added in #1795 (like for example If this is a good thing to do, it might be good to add sooner rather than later, since it would change the input file structure - i.e. use a |
There was a problem hiding this comment.
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
Fails to compile on github due to using petsc 3.7.7
equation_form switches between: - Pseudo-transient (like UEDGE) - A rearranged backward Euler - The original backward Euler
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, but a couple of things to double check, and a small number of things to fix
src/solver/impls/snes/snes.cxx
Outdated
|
||
// Only 3D fields | ||
for (int i = 0; i < n3d; i++) { | ||
// d_nnz[localIndex+i] -= (n3d + n2d); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// d_nnz[localIndex+i] -= (n3d + n2d); |
src/solver/impls/snes/snes.cxx
Outdated
localIndex = ROUND(index(x, mesh->yend, 0)); | ||
// All 2D and 3D fields | ||
for (int i = 0; i < n2d + n3d; i++) { | ||
// d_nnz[localIndex+i] -= (n3d + n2d); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// d_nnz[localIndex+i] -= (n3d + n2d); |
src/solver/impls/snes/snes.cxx
Outdated
|
||
// Only 3D fields | ||
for (int i = 0; i < n3d; i++) { | ||
// d_nnz[localIndex+i] -= (n3d + n2d); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// d_nnz[localIndex+i] -= (n3d + n2d); |
src/solver/impls/snes/snes.cxx
Outdated
if (z == 0) { | ||
// All 2D and 3D fields | ||
for (int i = 0; i < n2d + n3d; i++) { | ||
d_nnz[localIndex + i] -= (n3d + n2d); | ||
} | ||
} else { | ||
// Only 3D fields | ||
for (int i = 0; i < n3d; i++) { | ||
d_nnz[localIndex + i] -= (n3d + n2d); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also wonder if these loop bodies could be wrapped up into functions and reused? Might cut down on this section a fair bit
src/solver/impls/snes/snes.cxx
Outdated
for (int j = 0; j < n2d; j++) { | ||
PetscInt col = ind2 + j; | ||
|
||
MatSetValues(Jmf, 1, &row, 1, &col, &val, INSERT_VALUES); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it worth looking at using our Petsc Matrix wrapper for this new code?
src/solver/impls/snes/snes.cxx
Outdated
|
||
equation_form = (*options)["equation_form"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could equation_form
be a BOUT_ENUM_CLASS
? Then users could use the names directly, rather than integers
In y boundaries the X index can be out of the domain, leading to negative indices. This caused out of bounds memory access, and a lot of slowdown in the Jacobian coloring setup. Also added some progress output
There was a problem hiding this comment.
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
Also add some notes on preconditioner options
…ev into beuler-jacobian-color
Co-authored-by: Peter Hill <zed.three@gmail.com>
Limits how large the timestep can be made, to try and prevent repeated increases and failures
beuler solver additions
* next: (37 commits) Merge in Solver and PhysicsModel changes from next SNES solver merges Fix contributor's name Update release date Update changelog Fix ambiguous visit call Revert SONAME/SOVERSION to 4.4.0 Fix test-bout-override-default-option for cmake Update DOI and release date for 4.4.1 Update changelog for 4.4.1 Update translation files for 4.4.1 Bump version to 4.4.1 Enable setting SNES solver PETSc options from input file Try to consolidate some loops/branches in SNESSolver Use `BOUT_ENUM_CLASS` for `SNESSolver::equation_form` Use `std::vector/array` instead of C style arrays Remove `__FUNCT__` macros for PETSc callbacks Update backport of beuler/snes solver Fix typo in docs Remove IDL section and recommend xBOUT for analysis ...
The |
Enables large reductions in the number of iterations needed to calculate the Jacobian elements. Having the Jacobian then enables good preconditioning.
Simple conduction example, nout=5 and timestep=10:
PVODE:
beuler, SNESType = anderson
beuler, SNESType = newtonls, matrix free (no Jacobian)
beuler, SNESType = newtonls, with Jacobian, no coloring
beuler, SNESType = newtonls, with Jacobian coloring
Also includes some reformatting and drive-by fixes for things flagged by Apple Clang. These are in separate commits (mostly) for reviewing.