xref: /petsc/src/snes/impls/al/al.c (revision d7c1f4409a34685d8dcd545a97d161d483d89f66)
197276fddSZach Atkins #include <../src/snes/impls/al/alimpl.h> /*I "petscsnes.h" I*/
297276fddSZach Atkins 
397276fddSZach Atkins /*
497276fddSZach Atkins      This file implements a truncated Newton method with arc length continuation,
597276fddSZach Atkins      for solving a system of nonlinear equations, using the KSP, Vec,
697276fddSZach Atkins      and Mat interfaces for linear solvers, vectors, and matrices,
797276fddSZach Atkins      respectively.
897276fddSZach Atkins */
997276fddSZach Atkins 
1097276fddSZach Atkins const char NewtonALExactCitation[]   = "@article{Ritto-CorreaCamotim2008,\n"
1197276fddSZach Atkins                                        "  title={On the arc-length and other quadratic control methods: Established, less known and new implementation procedures},\n"
1297276fddSZach Atkins                                        "  volume={86},\n"
1397276fddSZach Atkins                                        "  ISSN={0045-7949},\n"
1497276fddSZach Atkins                                        "  DOI={10.1016/j.compstruc.2007.08.003},\n"
1597276fddSZach Atkins                                        "  number={11},\n"
1697276fddSZach Atkins                                        "  journal={Computers & Structures},\n"
1797276fddSZach Atkins                                        "  author={Ritto-Corr{\\^{e}}a, Manuel and Camotim, Dinar},\n"
1897276fddSZach Atkins                                        "  year={2008},\n"
1997276fddSZach Atkins                                        "  month=jun,\n"
2097276fddSZach Atkins                                        "  pages={1353-1368},\n"
2197276fddSZach Atkins                                        "}\n";
2297276fddSZach Atkins PetscBool  NewtonALExactCitationSet  = PETSC_FALSE;
2397276fddSZach Atkins const char NewtonALNormalCitation[]  = "@article{LeonPaulinoPereiraMenezesLages_2011,\n"
2497276fddSZach Atkins                                        "  title={A Unified Library of Nonlinear Solution Schemes},\n"
2597276fddSZach Atkins                                        "  volume={64},\n"
2697276fddSZach Atkins                                        "  ISSN={0003-6900, 2379-0407},\n"
2797276fddSZach Atkins                                        "  DOI={10.1115/1.4006992},\n"
2897276fddSZach Atkins                                        "  number={4},\n"
2997276fddSZach Atkins                                        "  journal={Applied Mechanics Reviews},\n"
3097276fddSZach Atkins                                        "  author={Leon, Sofie E. and Paulino, Glaucio H. and Pereira, Anderson and Menezes, Ivan F. M. and Lages, Eduardo N.},\n"
3197276fddSZach Atkins                                        "  year={2011},\n"
3297276fddSZach Atkins                                        "  month=jul,\n"
3397276fddSZach Atkins                                        "  pages={040803},\n"
3497276fddSZach Atkins                                        "  language={en}\n"
3597276fddSZach Atkins                                        "}\n";
3697276fddSZach Atkins PetscBool  NewtonALNormalCitationSet = PETSC_FALSE;
3797276fddSZach Atkins 
3897276fddSZach Atkins const char *const SNESNewtonALCorrectionTypes[] = {"EXACT", "NORMAL", "SNESNewtonALCorrectionType", "SNES_NEWTONAL_CORRECTION_", NULL};
3997276fddSZach Atkins 
4097276fddSZach Atkins static PetscErrorCode SNESNewtonALCheckArcLength(SNES snes, Vec XStep, PetscReal lambdaStep, PetscReal stepSize)
4197276fddSZach Atkins {
4297276fddSZach Atkins   PetscReal      arcLength, arcLengthError;
4397276fddSZach Atkins   SNES_NEWTONAL *al = (SNES_NEWTONAL *)snes->data;
4497276fddSZach Atkins 
4597276fddSZach Atkins   PetscFunctionBegin;
4697276fddSZach Atkins   PetscCall(VecNorm(XStep, NORM_2, &arcLength));
4797276fddSZach Atkins   arcLength      = PetscSqrtReal(PetscSqr(arcLength) + al->psisq * lambdaStep * lambdaStep);
4897276fddSZach Atkins   arcLengthError = PetscAbsReal(arcLength - stepSize);
4997276fddSZach Atkins 
5097276fddSZach Atkins   if (arcLengthError > PETSC_SQRT_MACHINE_EPSILON) PetscCall(PetscInfo(snes, "Arc length differs from specified step size: computed=%18.16e, expected=%18.16e, error=%18.16e \n", (double)arcLength, (double)stepSize, (double)arcLengthError));
5197276fddSZach Atkins   PetscFunctionReturn(PETSC_SUCCESS);
5297276fddSZach Atkins }
5397276fddSZach Atkins 
5497276fddSZach Atkins /* stable implementation of roots of a*x^2 + b*x + c = 0 */
5597276fddSZach Atkins static inline void PetscQuadraticRoots(PetscReal a, PetscReal b, PetscReal c, PetscReal *xm, PetscReal *xp)
5697276fddSZach Atkins {
5797276fddSZach Atkins   PetscReal temp = -0.5 * (b + PetscCopysignReal(1.0, b) * PetscSqrtReal(b * b - 4 * a * c));
5897276fddSZach Atkins   PetscReal x1   = temp / a;
5997276fddSZach Atkins   PetscReal x2   = c / temp;
6097276fddSZach Atkins   *xm            = PetscMin(x1, x2);
6197276fddSZach Atkins   *xp            = PetscMax(x1, x2);
6297276fddSZach Atkins }
6397276fddSZach Atkins 
6497276fddSZach Atkins static PetscErrorCode SNESNewtonALSetCorrectionType_NEWTONAL(SNES snes, SNESNewtonALCorrectionType ctype)
6597276fddSZach Atkins {
6697276fddSZach Atkins   SNES_NEWTONAL *al = (SNES_NEWTONAL *)snes->data;
6797276fddSZach Atkins 
6897276fddSZach Atkins   PetscFunctionBegin;
6997276fddSZach Atkins   al->correction_type = ctype;
7097276fddSZach Atkins   PetscFunctionReturn(PETSC_SUCCESS);
7197276fddSZach Atkins }
7297276fddSZach Atkins 
7397276fddSZach Atkins /*@
7497276fddSZach Atkins   SNESNewtonALSetCorrectionType - Set the type of correction to use in the arc-length continuation method.
7597276fddSZach Atkins 
7697276fddSZach Atkins   Logically Collective
7797276fddSZach Atkins 
7897276fddSZach Atkins   Input Parameters:
7997276fddSZach Atkins + snes  - the nonlinear solver object
8097276fddSZach Atkins - ctype - the type of correction to use
8197276fddSZach Atkins 
8297276fddSZach Atkins   Options Database Key:
8397276fddSZach Atkins . -snes_newtonal_correction_type <type> - Set the type of correction to use; use -help for a list of available types
8497276fddSZach Atkins 
8597276fddSZach Atkins   Level: intermediate
8697276fddSZach Atkins 
8797276fddSZach Atkins .seealso: [](ch_snes), `SNES`, `SNESNEWTONAL`, `SNESNewtonALCorrectionType`
8897276fddSZach Atkins @*/
8997276fddSZach Atkins PetscErrorCode SNESNewtonALSetCorrectionType(SNES snes, SNESNewtonALCorrectionType ctype)
9097276fddSZach Atkins {
9197276fddSZach Atkins   PetscFunctionBegin;
9297276fddSZach Atkins   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
9397276fddSZach Atkins   PetscValidLogicalCollectiveEnum(snes, ctype, 2);
9497276fddSZach Atkins   PetscTryMethod(snes, "SNESNewtonALSetCorrectionType_C", (SNES, SNESNewtonALCorrectionType), (snes, ctype));
9597276fddSZach Atkins   PetscFunctionReturn(PETSC_SUCCESS);
9697276fddSZach Atkins }
9797276fddSZach Atkins 
9897276fddSZach Atkins static PetscErrorCode SNESNewtonALSetFunction_NEWTONAL(SNES snes, SNESFunctionFn *func, void *ctx)
9997276fddSZach Atkins {
10097276fddSZach Atkins   SNES_NEWTONAL *al = (SNES_NEWTONAL *)snes->data;
10197276fddSZach Atkins 
10297276fddSZach Atkins   PetscFunctionBegin;
10397276fddSZach Atkins   al->computealfunction = func;
10497276fddSZach Atkins   al->alctx             = ctx;
10597276fddSZach Atkins   PetscFunctionReturn(PETSC_SUCCESS);
10697276fddSZach Atkins }
10797276fddSZach Atkins 
10897276fddSZach Atkins /*@C
10997276fddSZach Atkins   SNESNewtonALSetFunction - Sets a user function that is called at each function evaluation to
11097276fddSZach Atkins   compute the tangent load vector for the arc-length continuation method.
11197276fddSZach Atkins 
11297276fddSZach Atkins   Logically Collective
11397276fddSZach Atkins 
11497276fddSZach Atkins   Input Parameters:
11597276fddSZach Atkins + snes - the nonlinear solver object
11697276fddSZach Atkins . func - [optional] tangent load function evaluation routine, see `SNESFunctionFn` for the calling sequence. `U` is the current solution vector, `Q` is the output tangent load vector
11797276fddSZach Atkins - ctx  - [optional] user-defined context for private data for the function evaluation routine (may be `NULL`)
11897276fddSZach Atkins 
11997276fddSZach Atkins   Level: intermediate
12097276fddSZach Atkins 
12197276fddSZach Atkins   Notes:
12297276fddSZach Atkins   If the current value of the load parameter is needed in `func`, it can be obtained with `SNESNewtonALGetLoadParameter()`.
12397276fddSZach Atkins 
12497276fddSZach Atkins   The tangent load vector is the partial derivative of external load with respect to the load parameter.
12597276fddSZach Atkins   In the case of proportional loading, the tangent load vector is the full external load vector at the end of the load step.
12697276fddSZach Atkins 
12797276fddSZach Atkins .seealso: [](ch_snes), `SNES`, `SNESNEWTONAL`, `SNESNewtonALGetFunction()`, `SNESNewtonALGetLoadParameter()`
12897276fddSZach Atkins @*/
12997276fddSZach Atkins PetscErrorCode SNESNewtonALSetFunction(SNES snes, SNESFunctionFn *func, void *ctx)
13097276fddSZach Atkins {
13197276fddSZach Atkins   PetscFunctionBegin;
13297276fddSZach Atkins   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
13397276fddSZach Atkins   PetscTryMethod(snes, "SNESNewtonALSetFunction_C", (SNES, SNESFunctionFn *, void *), (snes, func, ctx));
13497276fddSZach Atkins   PetscFunctionReturn(PETSC_SUCCESS);
13597276fddSZach Atkins }
13697276fddSZach Atkins 
13797276fddSZach Atkins static PetscErrorCode SNESNewtonALGetFunction_NEWTONAL(SNES snes, SNESFunctionFn **func, void **ctx)
13897276fddSZach Atkins {
13997276fddSZach Atkins   SNES_NEWTONAL *al = (SNES_NEWTONAL *)snes->data;
14097276fddSZach Atkins 
14197276fddSZach Atkins   PetscFunctionBegin;
14297276fddSZach Atkins   if (func) *func = al->computealfunction;
14397276fddSZach Atkins   if (ctx) *ctx = al->alctx;
14497276fddSZach Atkins   PetscFunctionReturn(PETSC_SUCCESS);
14597276fddSZach Atkins }
14697276fddSZach Atkins 
14797276fddSZach Atkins /*@C
14897276fddSZach Atkins   SNESNewtonALGetFunction - Get the user function and context set with `SNESNewtonALSetFunction`
14997276fddSZach Atkins 
15097276fddSZach Atkins   Logically Collective
15197276fddSZach Atkins 
15297276fddSZach Atkins   Input Parameters:
15397276fddSZach Atkins + snes - the nonlinear solver object
15497276fddSZach Atkins . func - [optional] tangent load function evaluation routine, see `SNESNewtonALSetFunction()` for the call sequence
15597276fddSZach Atkins - ctx  - [optional] user-defined context for private data for the function evaluation routine (may be `NULL`)
15697276fddSZach Atkins 
15797276fddSZach Atkins   Level: intermediate
15897276fddSZach Atkins 
15997276fddSZach Atkins .seealso: [](ch_snes), `SNES`, `SNESNEWTONAL`, `SNESNewtonALSetFunction()`
16097276fddSZach Atkins @*/
16197276fddSZach Atkins PetscErrorCode SNESNewtonALGetFunction(SNES snes, SNESFunctionFn **func, void **ctx)
16297276fddSZach Atkins {
16397276fddSZach Atkins   PetscFunctionBegin;
16497276fddSZach Atkins   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
16597276fddSZach Atkins   PetscUseMethod(snes, "SNESNewtonALGetFunction_C", (SNES, SNESFunctionFn **, void **), (snes, func, ctx));
16697276fddSZach Atkins   PetscFunctionReturn(PETSC_SUCCESS);
16797276fddSZach Atkins }
16897276fddSZach Atkins 
16997276fddSZach Atkins static PetscErrorCode SNESNewtonALGetLoadParameter_NEWTONAL(SNES snes, PetscReal *lambda)
17097276fddSZach Atkins {
17197276fddSZach Atkins   SNES_NEWTONAL *al;
17297276fddSZach Atkins 
17397276fddSZach Atkins   PetscFunctionBeginHot;
17497276fddSZach Atkins   al      = (SNES_NEWTONAL *)snes->data;
17597276fddSZach Atkins   *lambda = al->lambda;
17697276fddSZach Atkins   PetscFunctionReturn(PETSC_SUCCESS);
17797276fddSZach Atkins }
17897276fddSZach Atkins 
17997276fddSZach Atkins /*@C
18097276fddSZach Atkins   SNESNewtonALGetLoadParameter - Get the value of the load parameter `lambda` for the arc-length continuation method.
18197276fddSZach Atkins 
18297276fddSZach Atkins   Logically Collective
18397276fddSZach Atkins 
18497276fddSZach Atkins   Input Parameter:
18597276fddSZach Atkins . snes - the nonlinear solver object
18697276fddSZach Atkins 
18797276fddSZach Atkins   Output Parameter:
18897276fddSZach Atkins . lambda - the arc-length parameter
18997276fddSZach Atkins 
19097276fddSZach Atkins   Level: intermediate
19197276fddSZach Atkins 
19297276fddSZach Atkins   Notes:
19397276fddSZach Atkins   This function should be used in the functions provided to `SNESSetFunction()` and `SNESNewtonALSetFunction()`
19497276fddSZach Atkins   to compute the residual and tangent load vectors for a given value of `lambda` (0 <= lambda <= 1).
19597276fddSZach Atkins 
19697276fddSZach Atkins   Usually, `lambda` is used to scale the external force vector in the residual function, i.e. proportional loading,
19797276fddSZach Atkins   in which case the tangent load vector is the full external force vector.
19897276fddSZach Atkins 
19997276fddSZach Atkins .seealso: [](ch_snes), `SNES`, `SNESNEWTONAL`, `SNESNewtonALSetFunction()`
20097276fddSZach Atkins @*/
20197276fddSZach Atkins PetscErrorCode SNESNewtonALGetLoadParameter(SNES snes, PetscReal *lambda)
20297276fddSZach Atkins {
20397276fddSZach Atkins   PetscFunctionBeginHot;
20497276fddSZach Atkins   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
20597276fddSZach Atkins   PetscAssertPointer(lambda, 2);
20697276fddSZach Atkins   PetscUseMethod(snes, "SNESNewtonALGetLoadParameter_C", (SNES, PetscReal *), (snes, lambda));
20797276fddSZach Atkins   PetscFunctionReturn(PETSC_SUCCESS);
20897276fddSZach Atkins }
20997276fddSZach Atkins 
21097276fddSZach Atkins static PetscErrorCode SNESNewtonALComputeFunction_NEWTONAL(SNES snes, Vec X, Vec Q)
21197276fddSZach Atkins {
21297276fddSZach Atkins   void           *ctx               = NULL;
21397276fddSZach Atkins   SNESFunctionFn *computealfunction = NULL;
21497276fddSZach Atkins   SNES_NEWTONAL  *al;
21597276fddSZach Atkins 
21697276fddSZach Atkins   PetscFunctionBegin;
21797276fddSZach Atkins   al = (SNES_NEWTONAL *)snes->data;
21897276fddSZach Atkins   PetscCall(SNESNewtonALGetFunction(snes, &computealfunction, &ctx));
21997276fddSZach Atkins 
22097276fddSZach Atkins   PetscCall(VecZeroEntries(Q));
22197276fddSZach Atkins   PetscCheck(computealfunction || (snes->vec_rhs && al->scale_rhs), PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "No tangent load function or rhs vector has been set");
22297276fddSZach Atkins   if (computealfunction) {
22397276fddSZach Atkins     PetscCall(VecLockReadPush(X));
22497276fddSZach Atkins     PetscCallBack("SNES callback NewtonAL tangent load function", (*computealfunction)(snes, X, Q, ctx));
22597276fddSZach Atkins     PetscCall(VecLockReadPop(X));
22697276fddSZach Atkins   }
22797276fddSZach Atkins   if (al->scale_rhs && snes->vec_rhs) {
22897276fddSZach Atkins     /* Save original RHS vector values, then scale `snes->vec_rhs` by load parameter */
22997276fddSZach Atkins     if (!al->vec_rhs_orig) { PetscCall(VecDuplicate(snes->vec_rhs, &al->vec_rhs_orig)); }
23097276fddSZach Atkins     if (!al->copied_rhs) {
23197276fddSZach Atkins       PetscCall(VecCopy(snes->vec_rhs, al->vec_rhs_orig));
23297276fddSZach Atkins       al->copied_rhs = PETSC_TRUE;
23397276fddSZach Atkins     }
23497276fddSZach Atkins     PetscCall(VecAXPBY(snes->vec_rhs, al->lambda, 0.0, al->vec_rhs_orig));
23597276fddSZach Atkins     PetscCall(VecAXPY(Q, 1, al->vec_rhs_orig));
23697276fddSZach Atkins   }
23797276fddSZach Atkins   PetscFunctionReturn(PETSC_SUCCESS);
23897276fddSZach Atkins }
23997276fddSZach Atkins 
24097276fddSZach Atkins /*@C
24197276fddSZach Atkins   SNESNewtonALComputeFunction - Calls the function that has been set with `SNESNewtonALSetFunction()`.
24297276fddSZach Atkins 
24397276fddSZach Atkins   Collective
24497276fddSZach Atkins 
24597276fddSZach Atkins   Input Parameters:
24697276fddSZach Atkins + snes - the `SNES` context
24797276fddSZach Atkins - X    - input vector
24897276fddSZach Atkins 
24997276fddSZach Atkins   Output Parameter:
25097276fddSZach Atkins . Q - tangent load vector, as set by `SNESNewtonALSetFunction()`
25197276fddSZach Atkins 
25297276fddSZach Atkins   Level: developer
25397276fddSZach Atkins 
25497276fddSZach Atkins   Note:
25597276fddSZach Atkins   `SNESNewtonALComputeFunction()` is typically used within nonlinear solvers
25697276fddSZach Atkins   implementations, so users would not generally call this routine themselves.
25797276fddSZach Atkins 
25897276fddSZach Atkins .seealso: [](ch_snes), `SNES`, `SNESNewtonALSetFunction()`, `SNESNewtonALGetFunction()`
25997276fddSZach Atkins @*/
26097276fddSZach Atkins PetscErrorCode SNESNewtonALComputeFunction(SNES snes, Vec X, Vec Q)
26197276fddSZach Atkins {
26297276fddSZach Atkins   PetscFunctionBegin;
26397276fddSZach Atkins   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
26497276fddSZach Atkins   PetscValidHeaderSpecific(X, VEC_CLASSID, 2);
26597276fddSZach Atkins   PetscValidHeaderSpecific(Q, VEC_CLASSID, 3);
26697276fddSZach Atkins   PetscCheckSameComm(snes, 1, X, 2);
26797276fddSZach Atkins   PetscCheckSameComm(snes, 1, Q, 3);
26897276fddSZach Atkins   PetscCall(VecValidValues_Internal(X, 2, PETSC_TRUE));
26997276fddSZach Atkins   PetscCall(PetscLogEventBegin(SNES_NewtonALEval, snes, X, Q, 0));
27097276fddSZach Atkins   PetscTryMethod(snes, "SNESNewtonALComputeFunction_C", (SNES, Vec, Vec), (snes, X, Q));
27197276fddSZach Atkins   PetscCall(PetscLogEventEnd(SNES_NewtonALEval, snes, X, Q, 0));
27297276fddSZach Atkins   PetscFunctionReturn(PETSC_SUCCESS);
27397276fddSZach Atkins }
27497276fddSZach Atkins 
27597276fddSZach Atkins /*
27697276fddSZach Atkins   SNESSolve_NEWTONAL - Solves a nonlinear system with Newton's method with arc length continuation.
27797276fddSZach Atkins 
27897276fddSZach Atkins   Input Parameter:
27997276fddSZach Atkins . snes - the `SNES` context
28097276fddSZach Atkins 
28197276fddSZach Atkins   Application Interface Routine: SNESSolve()
28297276fddSZach Atkins */
28397276fddSZach Atkins static PetscErrorCode SNESSolve_NEWTONAL(SNES snes)
28497276fddSZach Atkins {
28597276fddSZach Atkins   SNES_NEWTONAL *data = (SNES_NEWTONAL *)snes->data;
28697276fddSZach Atkins   PetscInt       maxits, maxincs, lits;
28797276fddSZach Atkins   PetscReal      fnorm, xnorm, ynorm, stepSize;
28897276fddSZach Atkins   Vec            DeltaX, deltaX, X, R, Q, deltaX_Q, deltaX_R;
28997276fddSZach Atkins 
29097276fddSZach Atkins   PetscFunctionBegin;
29197276fddSZach Atkins   PetscCheck(!snes->xl && !snes->xu && !snes->ops->computevariablebounds, PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_WRONGSTATE, "SNES solver %s does not support bounds", ((PetscObject)snes)->type_name);
29297276fddSZach Atkins 
29397276fddSZach Atkins   /* Register citations */
29497276fddSZach Atkins   PetscCall(PetscCitationsRegister(SNESCitation, &SNEScite));
29597276fddSZach Atkins   if (data->correction_type == SNES_NEWTONAL_CORRECTION_EXACT) {
29697276fddSZach Atkins     PetscCall(PetscCitationsRegister(NewtonALExactCitation, &NewtonALExactCitationSet));
29797276fddSZach Atkins   } else if (data->correction_type == SNES_NEWTONAL_CORRECTION_NORMAL) {
29897276fddSZach Atkins     PetscCall(PetscCitationsRegister(NewtonALNormalCitation, &NewtonALNormalCitationSet));
29997276fddSZach Atkins   }
30097276fddSZach Atkins 
30197276fddSZach Atkins   data->copied_rhs             = PETSC_FALSE;
30297276fddSZach Atkins   data->lambda_update          = 0.0;
30397276fddSZach Atkins   data->lambda                 = 0.0;
30497276fddSZach Atkins   snes->numFailures            = 0;
30597276fddSZach Atkins   snes->numLinearSolveFailures = 0;
30697276fddSZach Atkins   snes->reason                 = SNES_CONVERGED_ITERATING;
30797276fddSZach Atkins 
30897276fddSZach Atkins   maxits   = snes->max_its;                /* maximum number of iterations */
30997276fddSZach Atkins   maxincs  = data->max_continuation_steps; /* maximum number of increments */
31097276fddSZach Atkins   X        = snes->vec_sol;                /* solution vector */
31197276fddSZach Atkins   R        = snes->vec_func;               /* residual vector */
31297276fddSZach Atkins   Q        = snes->work[0];                /* tangent load vector */
31397276fddSZach Atkins   deltaX_Q = snes->work[1];                /* variation of X with respect to lambda */
31497276fddSZach Atkins   deltaX_R = snes->work[2];                /* linearized error correction */
31597276fddSZach Atkins   DeltaX   = snes->work[3];                /* step from equilibrium */
31697276fddSZach Atkins   deltaX   = snes->vec_sol_update;         /* full newton step */
31797276fddSZach Atkins   stepSize = data->step_size;              /* initial step size */
31897276fddSZach Atkins 
31997276fddSZach Atkins   PetscCall(VecZeroEntries(DeltaX));
32097276fddSZach Atkins 
32197276fddSZach Atkins   /* set snes->max_its for convergence test */
32297276fddSZach Atkins   snes->max_its = maxits * maxincs;
32397276fddSZach Atkins 
32497276fddSZach Atkins   /* main incremental-iterative loop */
32597276fddSZach Atkins   for (PetscInt i = 0; i < maxincs || maxincs < 0; i++) {
32697276fddSZach Atkins     PetscReal deltaLambda;
32797276fddSZach Atkins 
32897276fddSZach Atkins     PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes));
32997276fddSZach Atkins     snes->norm = 0.0;
33097276fddSZach Atkins     PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes));
33197276fddSZach Atkins     PetscCall(SNESNewtonALComputeFunction(snes, X, Q));
33297276fddSZach Atkins     PetscCall(SNESComputeFunction(snes, X, R));
33397276fddSZach Atkins     PetscCall(VecAXPY(R, 1, Q));           /* R <- R + Q */
33497276fddSZach Atkins     PetscCall(VecNorm(R, NORM_2, &fnorm)); /* fnorm <- ||R|| */
33597276fddSZach Atkins     SNESCheckFunctionNorm(snes, fnorm);
33697276fddSZach Atkins 
33797276fddSZach Atkins     /* Monitor convergence */
33897276fddSZach Atkins     PetscCall(SNESConverged(snes, snes->iter, 0.0, 0.0, fnorm));
33997276fddSZach Atkins     PetscCall(SNESMonitor(snes, snes->iter, fnorm));
34097276fddSZach Atkins     if (i == 0 && snes->reason) break;
34197276fddSZach Atkins     for (PetscInt j = 0; j < maxits; j++) {
34297276fddSZach Atkins       PetscReal normsqX_Q, deltaS = 1;
34397276fddSZach Atkins 
34497276fddSZach Atkins       /* Call general purpose update function */
34597276fddSZach Atkins       PetscTryTypeMethod(snes, update, snes->iter);
34697276fddSZach Atkins 
34797276fddSZach Atkins       PetscCall(SNESComputeJacobian(snes, X, snes->jacobian, snes->jacobian_pre));
34897276fddSZach Atkins       SNESCheckJacobianDomainerror(snes);
34997276fddSZach Atkins       PetscCall(KSPSetOperators(snes->ksp, snes->jacobian, snes->jacobian_pre));
35097276fddSZach Atkins       /* Solve J deltaX_Q = Q, where J is Jacobian matrix */
35197276fddSZach Atkins       PetscCall(KSPSolve(snes->ksp, Q, deltaX_Q));
35297276fddSZach Atkins       SNESCheckKSPSolve(snes);
35397276fddSZach Atkins       PetscCall(KSPGetIterationNumber(snes->ksp, &lits));
35497276fddSZach Atkins       PetscCall(PetscInfo(snes, "iter=%" PetscInt_FMT ", tangent load linear solve iterations=%" PetscInt_FMT "\n", snes->iter, lits));
35597276fddSZach Atkins       /* Compute load parameter variation */
35697276fddSZach Atkins       PetscCall(VecNorm(deltaX_Q, NORM_2, &normsqX_Q));
35797276fddSZach Atkins       normsqX_Q *= normsqX_Q;
35897276fddSZach Atkins       /* On first iter, use predictor. This is the same regardless of corrector scheme. */
35997276fddSZach Atkins       if (j == 0) {
36097276fddSZach Atkins         PetscReal sign = 1.0;
36197276fddSZach Atkins         if (i > 0) {
36297276fddSZach Atkins           PetscCall(VecDotRealPart(DeltaX, deltaX_Q, &sign));
36397276fddSZach Atkins           sign += data->psisq * data->lambda_update;
36497276fddSZach Atkins           sign = sign >= 0 ? 1.0 : -1.0;
36597276fddSZach Atkins         }
36697276fddSZach Atkins         data->lambda_update = 0.0;
36797276fddSZach Atkins         PetscCall(VecZeroEntries(DeltaX));
36897276fddSZach Atkins         deltaLambda = sign * stepSize / PetscSqrtReal(normsqX_Q + data->psisq);
36997276fddSZach Atkins       } else {
37097276fddSZach Atkins         /* Solve J deltaX_R = -R */
37197276fddSZach Atkins         PetscCall(KSPSolve(snes->ksp, R, deltaX_R));
37297276fddSZach Atkins         SNESCheckKSPSolve(snes);
37397276fddSZach Atkins         PetscCall(KSPGetIterationNumber(snes->ksp, &lits));
37497276fddSZach Atkins         PetscCall(PetscInfo(snes, "iter=%" PetscInt_FMT ", residual linear solve iterations=%" PetscInt_FMT "\n", snes->iter, lits));
37597276fddSZach Atkins         PetscCall(VecScale(deltaX_R, -1));
37697276fddSZach Atkins 
37797276fddSZach Atkins         if (data->correction_type == SNES_NEWTONAL_CORRECTION_NORMAL) {
37897276fddSZach Atkins           /*
37997276fddSZach Atkins             Take a step orthogonal to the current incremental update DeltaX.
38097276fddSZach Atkins             Note, this approach is cheaper than the exact correction, but may exhibit convergence
381*d7c1f440SPierre Jolivet             issues due to the iterative trial points not being on the quadratic constraint surface.
38297276fddSZach Atkins             On the bright side, we always have a real and unique solution for deltaLambda.
38397276fddSZach Atkins           */
38497276fddSZach Atkins           PetscScalar coefs[2];
38597276fddSZach Atkins           Vec         rhs[] = {deltaX_R, deltaX_Q};
38697276fddSZach Atkins 
38797276fddSZach Atkins           PetscCall(VecMDot(DeltaX, 2, rhs, coefs));
38897276fddSZach Atkins           deltaLambda = -PetscRealPart(coefs[0]) / (PetscRealPart(coefs[1]) + data->psisq * data->lambda_update);
38997276fddSZach Atkins         } else {
39097276fddSZach Atkins           /*
39197276fddSZach Atkins             Solve
39297276fddSZach Atkins               a*deltaLambda^2 + b*deltaLambda + c = 0  (*)
39397276fddSZach Atkins             where
39497276fddSZach Atkins               a = a0
39597276fddSZach Atkins               b = b0 + b1*deltaS
39697276fddSZach Atkins               c = c0 + c1*deltaS + c2*deltaS^2
39797276fddSZach Atkins             and deltaS is either 1, or the largest value in (0, 1) that satisfies
39897276fddSZach Atkins               b^2 - 4*a*c = as*deltaS^2 + bs*deltaS + cs >= 0
39997276fddSZach Atkins             where
40097276fddSZach Atkins               as = b1^2 - 4*a0*c2
40197276fddSZach Atkins               bs = 2*b1*b0 - 4*a0*c1
40297276fddSZach Atkins               cs = b0^2 - 4*a0*c0
40397276fddSZach Atkins             These "partial corrections" prevent (*) from having complex roots.
40497276fddSZach Atkins           */
40597276fddSZach Atkins           PetscReal   psisqLambdaUpdate, discriminant;
40697276fddSZach Atkins           PetscReal   as, bs, cs;
40797276fddSZach Atkins           PetscReal   a0, b0, b1, c0, c1, c2;
40897276fddSZach Atkins           PetscScalar coefs1[3]; /* coefs[0] = deltaX_Q*DeltaX, coefs[1] = deltaX_R*DeltaX, coefs[2] = DeltaX*DeltaX */
40997276fddSZach Atkins           PetscScalar coefs2[2]; /* coefs[0] = deltaX_Q*deltaX_R, coefs[1] = deltaX_R*deltaX_R */
41097276fddSZach Atkins           const Vec   rhs1[3] = {deltaX_Q, deltaX_R, DeltaX};
41197276fddSZach Atkins           const Vec   rhs2[2] = {deltaX_Q, deltaX_R};
41297276fddSZach Atkins 
41397276fddSZach Atkins           psisqLambdaUpdate = data->psisq * data->lambda_update;
41497276fddSZach Atkins           PetscCall(VecMDotBegin(DeltaX, 3, rhs1, coefs1));
41597276fddSZach Atkins           PetscCall(VecMDotBegin(deltaX_R, 2, rhs2, coefs2));
41697276fddSZach Atkins           PetscCall(VecMDotEnd(DeltaX, 3, rhs1, coefs1));
41797276fddSZach Atkins           PetscCall(VecMDotEnd(deltaX_R, 2, rhs2, coefs2));
41897276fddSZach Atkins 
41997276fddSZach Atkins           a0 = normsqX_Q + data->psisq;
42097276fddSZach Atkins           b0 = 2 * (PetscRealPart(coefs1[0]) + psisqLambdaUpdate);
42197276fddSZach Atkins           b1 = 2 * PetscRealPart(coefs2[0]);
42297276fddSZach Atkins           c0 = PetscRealPart(coefs1[2]) + psisqLambdaUpdate * data->lambda_update - stepSize * stepSize;
42397276fddSZach Atkins           c1 = 2 * PetscRealPart(coefs1[1]);
42497276fddSZach Atkins           c2 = PetscRealPart(coefs2[1]);
42597276fddSZach Atkins 
42697276fddSZach Atkins           as = b1 * b1 - 4 * a0 * c2;
42797276fddSZach Atkins           bs = 2 * (b1 * b0 - 2 * a0 * c1);
42897276fddSZach Atkins           cs = b0 * b0 - 4 * a0 * c0;
42997276fddSZach Atkins 
43097276fddSZach Atkins           discriminant = cs + bs * deltaS + as * deltaS * deltaS;
43197276fddSZach Atkins 
43297276fddSZach Atkins           if (discriminant < 0) {
43397276fddSZach Atkins             /* Take deltaS < 1 with the unique root -b/(2*a) */
43497276fddSZach Atkins             PetscReal x1;
43597276fddSZach Atkins 
43697276fddSZach Atkins             /* Compute deltaS to be the largest root of (as * x^2 + bs * x + cs = 0) */
43797276fddSZach Atkins             PetscQuadraticRoots(as, bs, cs, &x1, &deltaS);
43897276fddSZach Atkins             PetscCall(PetscInfo(snes, "iter=%" PetscInt_FMT ", discriminant=%18.16e < 0, shrinking residual update size to deltaS = %18.16e\n", snes->iter, (double)discriminant, (double)deltaS));
43997276fddSZach Atkins             deltaLambda = -0.5 * (b0 + b1 * deltaS) / a0;
44097276fddSZach Atkins           } else {
44197276fddSZach Atkins             /* Use deltaS = 1, pick root that is closest to the last point to prevent doubling back */
44297276fddSZach Atkins             PetscReal dlambda1, dlambda2;
44397276fddSZach Atkins 
44497276fddSZach Atkins             PetscQuadraticRoots(a0, b0 + b1, c0 + c1 + c2, &dlambda1, &dlambda2);
44597276fddSZach Atkins             deltaLambda = (b0 * dlambda1) > (b0 * dlambda2) ? dlambda1 : dlambda2;
44697276fddSZach Atkins           }
44797276fddSZach Atkins         }
44897276fddSZach Atkins       }
44997276fddSZach Atkins       PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes));
45097276fddSZach Atkins       data->lambda = data->lambda + deltaLambda;
45197276fddSZach Atkins       if (data->lambda > data->lambda_max) {
45297276fddSZach Atkins         /* Ensure that lambda = lambda_max exactly at the end of incremental process. This ensures the final solution matches the problem we want to solve. */
45397276fddSZach Atkins         deltaLambda  = deltaLambda - (data->lambda - data->lambda_max);
45497276fddSZach Atkins         data->lambda = data->lambda_max;
45597276fddSZach Atkins       }
45697276fddSZach Atkins       if (data->lambda < data->lambda_min) {
45797276fddSZach Atkins         // LCOV_EXCL_START
45897276fddSZach Atkins         /* Ensure that lambda >= lambda_min. This prevents some potential oscillatory behavior. */
45997276fddSZach Atkins         deltaLambda  = deltaLambda - (data->lambda - data->lambda_min);
46097276fddSZach Atkins         data->lambda = data->lambda_min;
46197276fddSZach Atkins         // LCOV_EXCL_STOP
46297276fddSZach Atkins       }
46397276fddSZach Atkins       data->lambda_update = data->lambda_update + deltaLambda;
46497276fddSZach Atkins       PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes));
46597276fddSZach Atkins       PetscCall(PetscInfo(snes, "iter=%" PetscInt_FMT ", lambda=%18.16e, lambda_update=%18.16e\n", snes->iter, (double)data->lambda, (double)data->lambda_update));
46697276fddSZach Atkins       if (j == 0) {
46797276fddSZach Atkins         /* deltaX = deltaLambda*deltaX_Q */
46897276fddSZach Atkins         PetscCall(VecCopy(deltaX_Q, deltaX));
46997276fddSZach Atkins         PetscCall(VecScale(deltaX, deltaLambda));
47097276fddSZach Atkins       } else {
47197276fddSZach Atkins         /* deltaX = deltaS*deltaX_R + deltaLambda*deltaX_Q */
47297276fddSZach Atkins         PetscCall(VecAXPBYPCZ(deltaX, deltaS, deltaLambda, 0, deltaX_R, deltaX_Q));
47397276fddSZach Atkins       }
47497276fddSZach Atkins       PetscCall(VecAXPY(DeltaX, 1, deltaX));
47597276fddSZach Atkins       PetscCall(VecAXPY(X, 1, deltaX));
47697276fddSZach Atkins       /* Q = -dF/dlambda(X, lambda)*/
47797276fddSZach Atkins       PetscCall(SNESNewtonALComputeFunction(snes, X, Q));
47897276fddSZach Atkins       /* R = F(X, lambda) */
47997276fddSZach Atkins       PetscCall(SNESComputeFunction(snes, X, R));
48097276fddSZach Atkins       PetscCall(VecNormBegin(R, NORM_2, &fnorm));
48197276fddSZach Atkins       PetscCall(VecNormBegin(X, NORM_2, &xnorm));
48297276fddSZach Atkins       PetscCall(VecNormBegin(deltaX, NORM_2, &ynorm));
48397276fddSZach Atkins       PetscCall(VecNormEnd(R, NORM_2, &fnorm));
48497276fddSZach Atkins       PetscCall(VecNormEnd(X, NORM_2, &xnorm));
48597276fddSZach Atkins       PetscCall(VecNormEnd(deltaX, NORM_2, &ynorm));
48697276fddSZach Atkins 
48797276fddSZach Atkins       if (PetscLogPrintInfo) PetscCall(SNESNewtonALCheckArcLength(snes, DeltaX, data->lambda_update, stepSize));
48897276fddSZach Atkins 
48997276fddSZach Atkins       /* Monitor convergence */
49097276fddSZach Atkins       PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes));
49197276fddSZach Atkins       snes->iter++;
49297276fddSZach Atkins       snes->norm  = fnorm;
49397276fddSZach Atkins       snes->ynorm = ynorm;
49497276fddSZach Atkins       snes->xnorm = xnorm;
49597276fddSZach Atkins       PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes));
49697276fddSZach Atkins       PetscCall(SNESLogConvergenceHistory(snes, snes->norm, lits));
49797276fddSZach Atkins       PetscCall(SNESConverged(snes, snes->iter, xnorm, ynorm, fnorm));
49897276fddSZach Atkins       PetscCall(SNESMonitor(snes, snes->iter, snes->norm));
49997276fddSZach Atkins       if (snes->reason) break;
50097276fddSZach Atkins       if (j == maxits - 1) {
50197276fddSZach Atkins         snes->reason = SNES_DIVERGED_MAX_IT;
50297276fddSZach Atkins         break;
50397276fddSZach Atkins       }
50497276fddSZach Atkins     }
50597276fddSZach Atkins     if (snes->reason < 0) break;
50697276fddSZach Atkins     if (data->lambda >= data->lambda_max) {
50797276fddSZach Atkins       break;
50897276fddSZach Atkins     } else if (maxincs > 0 && i == maxincs - 1) {
50997276fddSZach Atkins       snes->reason = SNES_DIVERGED_MAX_IT;
51097276fddSZach Atkins       break;
51197276fddSZach Atkins     } else {
51297276fddSZach Atkins       snes->reason = SNES_CONVERGED_ITERATING;
51397276fddSZach Atkins     }
51497276fddSZach Atkins   }
51597276fddSZach Atkins   /* Reset RHS vector, if changed */
51697276fddSZach Atkins   if (data->copied_rhs) {
51797276fddSZach Atkins     PetscCall(VecCopy(data->vec_rhs_orig, snes->vec_rhs));
51897276fddSZach Atkins     data->copied_rhs = PETSC_FALSE;
51997276fddSZach Atkins   }
52097276fddSZach Atkins   snes->max_its = maxits; /* reset snes->max_its */
52197276fddSZach Atkins   PetscFunctionReturn(PETSC_SUCCESS);
52297276fddSZach Atkins }
52397276fddSZach Atkins 
52497276fddSZach Atkins /*
52597276fddSZach Atkins    SNESSetUp_NEWTONAL - Sets up the internal data structures for the later use
52697276fddSZach Atkins    of the SNESNEWTONAL nonlinear solver.
52797276fddSZach Atkins 
52897276fddSZach Atkins    Input Parameter:
52997276fddSZach Atkins .  snes - the SNES context
53097276fddSZach Atkins .  x - the solution vector
53197276fddSZach Atkins 
53297276fddSZach Atkins    Application Interface Routine: SNESSetUp()
53397276fddSZach Atkins  */
53497276fddSZach Atkins static PetscErrorCode SNESSetUp_NEWTONAL(SNES snes)
53597276fddSZach Atkins {
53697276fddSZach Atkins   PetscFunctionBegin;
53797276fddSZach Atkins   PetscCall(SNESSetWorkVecs(snes, 4));
53897276fddSZach Atkins   PetscCall(SNESSetUpMatrices(snes));
53997276fddSZach Atkins   PetscFunctionReturn(PETSC_SUCCESS);
54097276fddSZach Atkins }
54197276fddSZach Atkins 
54297276fddSZach Atkins /*
54397276fddSZach Atkins    SNESSetFromOptions_NEWTONAL - Sets various parameters for the SNESNEWTONAL method.
54497276fddSZach Atkins 
54597276fddSZach Atkins    Input Parameter:
54697276fddSZach Atkins .  snes - the SNES context
54797276fddSZach Atkins 
54897276fddSZach Atkins    Application Interface Routine: SNESSetFromOptions()
54997276fddSZach Atkins */
55097276fddSZach Atkins static PetscErrorCode SNESSetFromOptions_NEWTONAL(SNES snes, PetscOptionItems *PetscOptionsObject)
55197276fddSZach Atkins {
55297276fddSZach Atkins   SNES_NEWTONAL             *data            = (SNES_NEWTONAL *)snes->data;
55397276fddSZach Atkins   SNESNewtonALCorrectionType correction_type = data->correction_type;
55497276fddSZach Atkins 
55597276fddSZach Atkins   PetscFunctionBegin;
55697276fddSZach Atkins   PetscOptionsHeadBegin(PetscOptionsObject, "SNES Newton Arc Length options");
55797276fddSZach Atkins   PetscCall(PetscOptionsReal("-snes_newtonal_step_size", "Initial arc length increment step size", "SNESNewtonAL", data->step_size, &data->step_size, NULL));
55897276fddSZach Atkins   PetscCall(PetscOptionsInt("-snes_newtonal_max_continuation_steps", "Maximum number of increment steps", "SNESNewtonAL", data->max_continuation_steps, &data->max_continuation_steps, NULL));
55997276fddSZach Atkins   PetscCall(PetscOptionsReal("-snes_newtonal_psisq", "Regularization parameter for arc length continuation, 0 for cylindrical", "SNESNewtonAL", data->psisq, &data->psisq, NULL));
56097276fddSZach Atkins   PetscCall(PetscOptionsReal("-snes_newtonal_lambda_min", "Minimum value of the load parameter lambda", "SNESNewtonAL", data->lambda_min, &data->lambda_min, NULL));
56197276fddSZach Atkins   PetscCall(PetscOptionsReal("-snes_newtonal_lambda_max", "Maximum value of the load parameter lambda", "SNESNewtonAL", data->lambda_max, &data->lambda_max, NULL));
56297276fddSZach Atkins   PetscCall(PetscOptionsBool("-snes_newtonal_scale_rhs", "Scale the constant vector passed to `SNESSolve` by the load parameter lambda", "SNESNewtonAL", data->scale_rhs, &data->scale_rhs, NULL));
56397276fddSZach Atkins   PetscCall(PetscOptionsEnum("-snes_newtonal_correction_type", "Type of correction to use in the arc-length continuation method", "SNESNewtonALCorrectionType", SNESNewtonALCorrectionTypes, (PetscEnum)correction_type, (PetscEnum *)&correction_type, NULL));
56497276fddSZach Atkins   PetscCall(SNESNewtonALSetCorrectionType(snes, correction_type));
56597276fddSZach Atkins   PetscOptionsHeadEnd();
56697276fddSZach Atkins   PetscFunctionReturn(PETSC_SUCCESS);
56797276fddSZach Atkins }
56897276fddSZach Atkins 
56997276fddSZach Atkins static PetscErrorCode SNESReset_NEWTONAL(SNES snes)
57097276fddSZach Atkins {
57197276fddSZach Atkins   SNES_NEWTONAL *al = (SNES_NEWTONAL *)snes->data;
57297276fddSZach Atkins 
57397276fddSZach Atkins   PetscFunctionBegin;
57497276fddSZach Atkins   PetscCall(VecDestroy(&al->vec_rhs_orig));
57597276fddSZach Atkins   PetscFunctionReturn(PETSC_SUCCESS);
57697276fddSZach Atkins }
57797276fddSZach Atkins 
57897276fddSZach Atkins /*
57997276fddSZach Atkins    SNESDestroy_NEWTONAL - Destroys the private SNES_NEWTONAL context that was created
58097276fddSZach Atkins    with SNESCreate_NEWTONAL().
58197276fddSZach Atkins 
58297276fddSZach Atkins    Input Parameter:
58397276fddSZach Atkins .  snes - the SNES context
58497276fddSZach Atkins 
58597276fddSZach Atkins    Application Interface Routine: SNESDestroy()
58697276fddSZach Atkins  */
58797276fddSZach Atkins static PetscErrorCode SNESDestroy_NEWTONAL(SNES snes)
58897276fddSZach Atkins {
58997276fddSZach Atkins   PetscFunctionBegin;
59097276fddSZach Atkins   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNewtonALSetCorrectionType_C", NULL));
59197276fddSZach Atkins   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNewtonALGetLoadParameter_C", NULL));
59297276fddSZach Atkins   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNewtonALSetFunction_C", NULL));
59397276fddSZach Atkins   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNewtonALGetFunction_C", NULL));
59497276fddSZach Atkins   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNewtonALComputeFunction_C", NULL));
59597276fddSZach Atkins   PetscCall(PetscFree(snes->data));
59697276fddSZach Atkins   PetscFunctionReturn(PETSC_SUCCESS);
59797276fddSZach Atkins }
59897276fddSZach Atkins 
59997276fddSZach Atkins /*MC
60097276fddSZach Atkins   SNESNEWTONAL - Newton based nonlinear solver that uses a arc-length continuation method to solve the nonlinear system.
60197276fddSZach Atkins 
60297276fddSZach Atkins   Options Database Keys:
60397276fddSZach Atkins +   -snes_newtonal_step_size <1.0>              - Initial arc length increment step size
60497276fddSZach Atkins .   -snes_newtonal_max_continuation_steps <100> - Maximum number of continuation steps, or negative for no limit (not recommended)
60597276fddSZach Atkins .   -snes_newtonal_psisq <1.0>                  - Regularization parameter for arc length continuation, 0 for cylindrical. Larger values generally lead to more steps.
60697276fddSZach Atkins .   -snes_newtonal_lambda_min <0.0>             - Minimum value of the load parameter lambda
60797276fddSZach Atkins .   -snes_newtonal_lambda_max <1.0>             - Maximum value of the load parameter lambda
60897276fddSZach Atkins .   -snes_newtonal_scale_rhs <true>             - Scale the constant vector passed to `SNESSolve` by the load parameter lambda
60997276fddSZach Atkins -   -snes_newtonal_correction_type <exact>      - Type of correction to use in the arc-length continuation method, `exact` or `normal`
61097276fddSZach Atkins 
61197276fddSZach Atkins   Level: intermediate
61297276fddSZach Atkins 
61397276fddSZach Atkins   Note:
61497276fddSZach Atkins   The exact correction scheme with partial updates is detailed in {cite}`Ritto-CorreaCamotim2008` and the implementation of the
61597276fddSZach Atkins   normal correction scheme is based on {cite}`LeonPaulinoPereiraMenezesLages_2011`.
61697276fddSZach Atkins 
61797276fddSZach Atkins .seealso: [](ch_snes), `SNESCreate()`, `SNES`, `SNESSetType()`, `SNESNEWTONAL`, `SNESNewtonALSetFunction()`, `SNESNewtonALGetFunction()`, `SNESNewtonALGetLoadParameter()`
61897276fddSZach Atkins M*/
61997276fddSZach Atkins PETSC_EXTERN PetscErrorCode SNESCreate_NEWTONAL(SNES snes)
62097276fddSZach Atkins {
62197276fddSZach Atkins   SNES_NEWTONAL *arclengthParameters;
62297276fddSZach Atkins 
62397276fddSZach Atkins   PetscFunctionBegin;
62497276fddSZach Atkins   snes->ops->setup          = SNESSetUp_NEWTONAL;
62597276fddSZach Atkins   snes->ops->solve          = SNESSolve_NEWTONAL;
62697276fddSZach Atkins   snes->ops->destroy        = SNESDestroy_NEWTONAL;
62797276fddSZach Atkins   snes->ops->setfromoptions = SNESSetFromOptions_NEWTONAL;
62897276fddSZach Atkins   snes->ops->reset          = SNESReset_NEWTONAL;
62997276fddSZach Atkins 
63097276fddSZach Atkins   snes->usesksp = PETSC_TRUE;
63197276fddSZach Atkins   snes->usesnpc = PETSC_FALSE;
63297276fddSZach Atkins 
63397276fddSZach Atkins   PetscCall(SNESParametersInitialize(snes));
63497276fddSZach Atkins   PetscObjectParameterSetDefault(snes, max_funcs, 30000);
63597276fddSZach Atkins   PetscObjectParameterSetDefault(snes, max_its, 50);
63697276fddSZach Atkins 
63797276fddSZach Atkins   snes->alwayscomputesfinalresidual = PETSC_TRUE;
63897276fddSZach Atkins 
63997276fddSZach Atkins   PetscCall(PetscNew(&arclengthParameters));
64097276fddSZach Atkins   arclengthParameters->lambda                 = 0.0;
64197276fddSZach Atkins   arclengthParameters->lambda_update          = 0.0;
64297276fddSZach Atkins   arclengthParameters->step_size              = 1.0;
64397276fddSZach Atkins   arclengthParameters->max_continuation_steps = 100;
64497276fddSZach Atkins   arclengthParameters->psisq                  = 1.0;
64597276fddSZach Atkins   arclengthParameters->lambda_min             = 0.0;
64697276fddSZach Atkins   arclengthParameters->lambda_max             = 1.0;
64797276fddSZach Atkins   arclengthParameters->scale_rhs              = PETSC_TRUE;
64897276fddSZach Atkins   arclengthParameters->correction_type        = SNES_NEWTONAL_CORRECTION_EXACT;
64997276fddSZach Atkins   snes->data                                  = (void *)arclengthParameters;
65097276fddSZach Atkins 
65197276fddSZach Atkins   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNewtonALSetCorrectionType_C", SNESNewtonALSetCorrectionType_NEWTONAL));
65297276fddSZach Atkins   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNewtonALGetLoadParameter_C", SNESNewtonALGetLoadParameter_NEWTONAL));
65397276fddSZach Atkins   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNewtonALSetFunction_C", SNESNewtonALSetFunction_NEWTONAL));
65497276fddSZach Atkins   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNewtonALGetFunction_C", SNESNewtonALGetFunction_NEWTONAL));
65597276fddSZach Atkins   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNewtonALComputeFunction_C", SNESNewtonALComputeFunction_NEWTONAL));
65697276fddSZach Atkins   PetscFunctionReturn(PETSC_SUCCESS);
65797276fddSZach Atkins }
658