Actual source code: lmvmutils.c

      1: #include <../src/ksp/ksp/utils/lmvm/lmvm.h>

      3: /*@
      4:    MatLMVMUpdate - Adds (X-Xprev) and (F-Fprev) updates to an LMVM matrix.
      5:    The first time the function is called for an LMVM matrix, no update is
      6:    applied, but the given X and F vectors are stored for use as Xprev and
      7:    Fprev in the next update.

      9:    If the user has provided another LMVM matrix in place of J0, the J0
     10:    matrix is also updated recursively.

     12:    Input Parameters:
     13: +  B - An LMVM-type matrix
     14: .  X - Solution vector
     15: -  F - Function vector

     17:    Level: intermediate

     19: .seealso: MatLMVMReset(), MatLMVMAllocate()
     20: @*/
     21: PetscErrorCode MatLMVMUpdate(Mat B, Vec X, Vec F)
     22: {
     23:   Mat_LMVM          *lmvm = (Mat_LMVM*)B->data;
     24:   PetscErrorCode    ierr;
     25:   PetscBool         same;

     31:   PetscObjectBaseTypeCompare((PetscObject)B, MATLMVM, &same);
     32:   if (!same) SETERRQ(PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONG, "Matrix must be an LMVM-type.");
     33:   if (!lmvm->allocated) {
     34:     MatLMVMAllocate(B, X, F);
     35:   } else {
     36:     VecCheckMatCompatible(B, X, 2, F, 3);
     37:   }
     38:   if (lmvm->J0) {
     39:     /* If the user provided an LMVM-type matrix as J0, then trigger its update as well */
     40:     PetscObjectBaseTypeCompare((PetscObject)lmvm->J0, MATLMVM, &same);
     41:     if (same) {
     42:       MatLMVMUpdate(lmvm->J0, X, F);
     43:     }
     44:   }
     45:   (*lmvm->ops->update)(B, X, F);
     46:   return(0);
     47: }

     49: /*------------------------------------------------------------*/

     51: /*@
     52:    MatLMVMClearJ0 - Removes all definitions of J0 and reverts to
     53:    an identity matrix (scale = 1.0).

     55:    Input Parameters:
     56: .  B - An LMVM-type matrix

     58:    Level: advanced

     60: .seealso: MatLMVMSetJ0()
     61: @*/
     62: PetscErrorCode MatLMVMClearJ0(Mat B)
     63: {
     64:   Mat_LMVM          *lmvm = (Mat_LMVM*)B->data;
     65:   PetscErrorCode    ierr;
     66:   PetscBool         same;
     67:   MPI_Comm          comm = PetscObjectComm((PetscObject)B);

     71:   PetscObjectBaseTypeCompare((PetscObject)B, MATLMVM, &same);
     72:   if (!same) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Matrix must be an LMVM-type.");
     73:   lmvm->user_pc = PETSC_FALSE;
     74:   lmvm->user_ksp = PETSC_FALSE;
     75:   lmvm->user_scale = PETSC_FALSE;
     76:   lmvm->J0scalar = 1.0;
     77:   VecDestroy(&lmvm->J0diag);
     78:   MatDestroy(&lmvm->J0);
     79:   PCDestroy(&lmvm->J0pc);
     80:   return(0);
     81: }

     83: /*------------------------------------------------------------*/

     85: /*@
     86:    MatLMVMSetJ0Scale - Allows the user to define a scalar value
     87:    mu such that J0 = mu*I.

     89:    Input Parameters:
     90: +  B - An LMVM-type matrix
     91: -  scale - Scalar value mu that defines the initial Jacobian

     93:    Level: advanced

     95: .seealso: MatLMVMSetDiagScale(), MatLMVMSetJ0()
     96: @*/
     97: PetscErrorCode MatLMVMSetJ0Scale(Mat B, PetscReal scale)
     98: {
     99:   Mat_LMVM          *lmvm = (Mat_LMVM*)B->data;
    100:   PetscErrorCode    ierr;
    101:   PetscBool         same;
    102:   MPI_Comm          comm = PetscObjectComm((PetscObject)B);

    106:   PetscObjectBaseTypeCompare((PetscObject)B, MATLMVM, &same);
    107:   if (!same) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Matrix must be an LMVM-type.");
    108:   if (!lmvm->square) SETERRQ(comm, PETSC_ERR_SUP, "Scaling is available only for square LMVM matrices");
    109:   MatLMVMClearJ0(B);
    110:   lmvm->J0scalar = scale;
    111:   lmvm->user_scale = PETSC_TRUE;
    112:   return(0);
    113: }

    115: /*------------------------------------------------------------*/

    117: /*@
    118:    MatLMVMSetJ0Diag - Allows the user to define a vector
    119:    V such that J0 = diag(V).

    121:    Input Parameters:
    122: +  B - An LMVM-type matrix
    123: -  V - Vector that defines the diagonal of the initial Jacobian

    125:    Level: advanced

    127: .seealso: MatLMVMSetScale(), MatLMVMSetJ0()
    128: @*/
    129: PetscErrorCode MatLMVMSetJ0Diag(Mat B, Vec V)
    130: {
    131:   Mat_LMVM          *lmvm = (Mat_LMVM*)B->data;
    132:   PetscErrorCode    ierr;
    133:   PetscBool         same;
    134:   MPI_Comm          comm = PetscObjectComm((PetscObject)B);

    139:   PetscObjectBaseTypeCompare((PetscObject)B, MATLMVM, &same);
    140:   if (!same) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Matrix must be an LMVM-type.");
    141:   if (!lmvm->allocated) SETERRQ(comm, PETSC_ERR_ORDER, "Matrix must be allocated before setting diagonal scaling");
    142:   if (!lmvm->square) SETERRQ(comm, PETSC_ERR_SUP, "Diagonal scaling is available only for square LMVM matrices");
    143:   VecCheckSameSize(V, 2, lmvm->Fprev, 3);
    144:   MatLMVMClearJ0(B);
    145:   if (!lmvm->J0diag) {
    146:     VecDuplicate(V, &lmvm->J0diag);
    147:   }
    148:   VecCopy(V, lmvm->J0diag);
    149:   lmvm->user_scale = PETSC_TRUE;
    150:   return(0);
    151: }

    153: /*------------------------------------------------------------*/

    155: /*@
    156:    MatLMVMSetJ0 - Allows the user to define the initial
    157:    Jacobian matrix from which the LMVM approximation is
    158:    built up. Inverse of this initial Jacobian is applied
    159:    using an internal KSP solver, which defaults to GMRES.
    160:    This internal KSP solver has the "mat_lmvm_" option
    161:    prefix.

    163:    Note that another LMVM matrix can be used in place of
    164:    J0, in which case updating the outer LMVM matrix will
    165:    also trigger the update for the inner LMVM matrix. This
    166:    is useful in cases where a full-memory diagonal approximation
    167:    such as MATLMVMDIAGBRDN is used in place of J0.

    169:    Input Parameters:
    170: +  B - An LMVM-type matrix
    171: -  J0 - The initial Jacobian matrix

    173:    Level: advanced

    175: .seealso: MatLMVMSetJ0PC(), MatLMVMSetJ0KSP()
    176: @*/
    177: PetscErrorCode MatLMVMSetJ0(Mat B, Mat J0)
    178: {
    179:   Mat_LMVM          *lmvm = (Mat_LMVM*)B->data;
    180:   PetscErrorCode    ierr;
    181:   PetscBool         same;
    182:   MPI_Comm          comm = PetscObjectComm((PetscObject)B);

    187:   PetscObjectBaseTypeCompare((PetscObject)B, MATLMVM, &same);
    188:   if (!same) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Matrix must be an LMVM-type.");
    189:   MatLMVMClearJ0(B);
    190:   MatDestroy(&lmvm->J0);
    191:   PetscObjectReference((PetscObject)J0);
    192:   lmvm->J0 = J0;
    193:   PetscObjectBaseTypeCompare((PetscObject)lmvm->J0, MATLMVM, &same);
    194:   if (!same && lmvm->square) {
    195:     KSPSetOperators(lmvm->J0ksp, lmvm->J0, lmvm->J0);
    196:   }
    197:   return(0);
    198: }

    200: /*------------------------------------------------------------*/

    202: /*@
    203:    MatLMVMSetJ0PC - Allows the user to define a PC object that
    204:    acts as the initial inverse-Jacobian matrix. This PC should
    205:    already contain all the operators necessary for its application.
    206:    The LMVM matrix only calls PCApply() without changing any other
    207:    options.

    209:    Input Parameters:
    210: +  B - An LMVM-type matrix
    211: -  J0pc - PC object where PCApply defines an inverse application for J0

    213:    Level: advanced

    215: .seealso: MatLMVMGetJ0PC()
    216: @*/
    217: PetscErrorCode MatLMVMSetJ0PC(Mat B, PC J0pc)
    218: {
    219:   Mat_LMVM          *lmvm = (Mat_LMVM*)B->data;
    220:   PetscErrorCode    ierr;
    221:   PetscBool         same;
    222:   MPI_Comm          comm = PetscObjectComm((PetscObject)B);

    227:   PetscObjectBaseTypeCompare((PetscObject)B, MATLMVM, &same);
    228:   if (!same) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Matrix must be an LMVM-type.");
    229:   if (!lmvm->square) SETERRQ(comm, PETSC_ERR_SUP, "Inverse J0 can be defined only for square LMVM matrices");
    230:   MatLMVMClearJ0(B);
    231:   PetscObjectReference((PetscObject)J0pc);
    232:   lmvm->J0pc = J0pc;
    233:   lmvm->user_pc = PETSC_TRUE;
    234:   return(0);
    235: }

    237: /*------------------------------------------------------------*/

    239: /*@
    240:    MatLMVMSetJ0KSP - Allows the user to provide a pre-configured
    241:    KSP solver for the initial inverse-Jacobian approximation.
    242:    This KSP solver should already contain all the operators
    243:    necessary to perform the inversion. The LMVM matrix only
    244:    calls KSPSolve() without changing any other options.

    246:    Input Parameters:
    247: +  B - An LMVM-type matrix
    248: -  J0ksp - KSP solver for the initial inverse-Jacobian application

    250:    Level: advanced

    252: .seealso: MatLMVMGetJ0KSP()
    253: @*/
    254: PetscErrorCode MatLMVMSetJ0KSP(Mat B, KSP J0ksp)
    255: {
    256:   Mat_LMVM          *lmvm = (Mat_LMVM*)B->data;
    257:   PetscErrorCode    ierr;
    258:   PetscBool         same;
    259:   MPI_Comm          comm = PetscObjectComm((PetscObject)B);

    264:   PetscObjectBaseTypeCompare((PetscObject)B, MATLMVM, &same);
    265:   if (!same) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Matrix must be an LMVM-type.");
    266:   if (!lmvm->square) SETERRQ(comm, PETSC_ERR_SUP, "Inverse J0 can be defined only for square LMVM matrices");
    267:   MatLMVMClearJ0(B);
    268:   KSPDestroy(&lmvm->J0ksp);
    269:   PetscObjectReference((PetscObject)J0ksp);
    270:   lmvm->J0ksp = J0ksp;
    271:   lmvm->user_ksp = PETSC_TRUE;
    272:   return(0);
    273: }

    275: /*------------------------------------------------------------*/

    277: /*@
    278:    MatLMVMGetJ0 - Returns a pointer to the internal J0 matrix.

    280:    Input Parameters:
    281: .  B - An LMVM-type matrix

    283:    Output Parameter:
    284: .  J0 - Mat object for defining the initial Jacobian

    286:    Level: advanced

    288: .seealso: MatLMVMSetJ0()
    289: @*/
    290: PetscErrorCode MatLMVMGetJ0(Mat B, Mat *J0)
    291: {
    292:   Mat_LMVM          *lmvm = (Mat_LMVM*)B->data;
    293:   PetscErrorCode    ierr;
    294:   PetscBool         same;

    298:   PetscObjectBaseTypeCompare((PetscObject)B, MATLMVM, &same);
    299:   if (!same) SETERRQ(PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONG, "Matrix must be an LMVM-type.");
    300:   *J0 = lmvm->J0;
    301:   return(0);
    302: }

    304: /*------------------------------------------------------------*/

    306: /*@
    307:    MatLMVMGetJ0PC - Returns a pointer to the internal PC object
    308:    associated with the initial Jacobian.

    310:    Input Parameters:
    311: .  B - An LMVM-type matrix

    313:    Output Parameter:
    314: .  J0pc - PC object for defining the initial inverse-Jacobian

    316:    Level: advanced

    318: .seealso: MatLMVMSetJ0PC()
    319: @*/
    320: PetscErrorCode MatLMVMGetJ0PC(Mat B, PC *J0pc)
    321: {
    322:   Mat_LMVM          *lmvm = (Mat_LMVM*)B->data;
    323:   PetscErrorCode    ierr;
    324:   PetscBool         same;

    328:   PetscObjectBaseTypeCompare((PetscObject)B, MATLMVM, &same);
    329:   if (!same) SETERRQ(PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONG, "Matrix must be an LMVM-type.");
    330:   if (lmvm->J0pc) {
    331:     *J0pc = lmvm->J0pc;
    332:   } else {
    333:     KSPGetPC(lmvm->J0ksp, J0pc);
    334:   }
    335:   return(0);
    336: }

    338: /*------------------------------------------------------------*/

    340: /*@
    341:    MatLMVMGetJ0KSP - Returns a pointer to the internal KSP solver
    342:    associated with the initial Jacobian.

    344:    Input Parameters:
    345: .  B - An LMVM-type matrix

    347:    Output Parameter:
    348: .  J0ksp - KSP solver for defining the initial inverse-Jacobian

    350:    Level: advanced

    352: .seealso: MatLMVMSetJ0KSP()
    353: @*/
    354: PetscErrorCode MatLMVMGetJ0KSP(Mat B, KSP *J0ksp)
    355: {
    356:   Mat_LMVM          *lmvm = (Mat_LMVM*)B->data;
    357:   PetscErrorCode    ierr;
    358:   PetscBool         same;

    362:   PetscObjectBaseTypeCompare((PetscObject)B, MATLMVM, &same);
    363:   if (!same) SETERRQ(PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONG, "Matrix must be an LMVM-type.");
    364:   *J0ksp = lmvm->J0ksp;
    365:   return(0);
    366: }

    368: /*------------------------------------------------------------*/

    370: /*@
    371:    MatLMVMApplyJ0Fwd - Applies an approximation of the forward
    372:    matrix-vector product with the initial Jacobian.

    374:    Input Parameters:
    375: +  B - An LMVM-type matrix
    376: -  X - vector to multiply with J0

    378:    Output Parameter:
    379: .  Y - resulting vector for the operation

    381:    Level: advanced

    383: .seealso: MatLMVMSetJ0(), MatLMVMSetJ0Scale(), MatLMVMSetJ0ScaleDiag(),
    384:           MatLMVMSetJ0PC(), MatLMVMSetJ0KSP(), MatLMVMApplyJ0Inv()
    385: @*/
    386: PetscErrorCode MatLMVMApplyJ0Fwd(Mat B, Vec X, Vec Y)
    387: {
    388:   Mat_LMVM          *lmvm = (Mat_LMVM*)B->data;
    389:   PetscErrorCode    ierr;
    390:   PetscBool         same, hasMult;
    391:   MPI_Comm          comm = PetscObjectComm((PetscObject)B);
    392:   Mat               Amat, Pmat;

    398:   PetscObjectBaseTypeCompare((PetscObject)B, MATLMVM, &same);
    399:   if (!same) SETERRQ(PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONG, "Matrix must be an LMVM-type.");
    400:   if (!lmvm->allocated) SETERRQ(comm, PETSC_ERR_ORDER, "LMVM matrix must be allocated first");
    401:   VecCheckMatCompatible(B, X, 2, Y, 3);
    402:   if (lmvm->user_pc || lmvm->user_ksp || lmvm->J0) {
    403:     /* User may have defined a PC or KSP for J0^{-1} so let's try to use its operators. */
    404:     if (lmvm->user_pc){
    405:       PCGetOperators(lmvm->J0pc, &Amat, &Pmat);
    406:     } else if (lmvm->user_ksp) {
    407:       KSPGetOperators(lmvm->J0ksp, &Amat, &Pmat);
    408:     } else {
    409:       Amat = lmvm->J0;
    410:     }
    411:     MatHasOperation(Amat, MATOP_MULT, &hasMult);
    412:     if (hasMult) {
    413:       /* product is available, use it */
    414:       MatMult(Amat, X, Y);
    415:     } else {
    416:       /* there's no product, so treat J0 as identity */
    417:       VecCopy(X, Y);
    418:     }
    419:   } else if (lmvm->user_scale) {
    420:     if (lmvm->J0diag) {
    421:       /* User has defined a diagonal vector for J0 */
    422:       VecPointwiseMult(X, lmvm->J0diag, Y);
    423:     } else {
    424:       /* User has defined a scalar value for J0 */
    425:       VecCopy(X, Y);
    426:       VecScale(Y, lmvm->J0scalar);
    427:     }
    428:   } else {
    429:     /* There is no J0 representation so just apply an identity matrix */
    430:     VecCopy(X, Y);
    431:   }
    432:   return(0);
    433: }

    435: /*------------------------------------------------------------*/

    437: /*@
    438:    MatLMVMApplyJ0Inv - Applies some estimation of the initial Jacobian
    439:    inverse to the given vector. The specific form of the application
    440:    depends on whether the user provided a scaling factor, a J0 matrix,
    441:    a J0 PC, or a J0 KSP object. If no form of the initial Jacobian is
    442:    provided, the function simply does an identity matrix application
    443:    (vector copy).

    445:    Input Parameters:
    446: +  B - An LMVM-type matrix
    447: -  X - vector to "multiply" with J0^{-1}

    449:    Output Parameter:
    450: .  Y - resulting vector for the operation

    452:    Level: advanced

    454: .seealso: MatLMVMSetJ0(), MatLMVMSetJ0Scale(), MatLMVMSetJ0ScaleDiag(),
    455:           MatLMVMSetJ0PC(), MatLMVMSetJ0KSP(), MatLMVMApplyJ0Fwd()
    456: @*/
    457: PetscErrorCode MatLMVMApplyJ0Inv(Mat B, Vec X, Vec Y)
    458: {
    459:   Mat_LMVM          *lmvm = (Mat_LMVM*)B->data;
    460:   PetscErrorCode    ierr;
    461:   PetscBool         same, hasSolve;
    462:   MPI_Comm          comm = PetscObjectComm((PetscObject)B);

    468:   PetscObjectBaseTypeCompare((PetscObject)B, MATLMVM, &same);
    469:   if (!same) SETERRQ(PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONG, "Matrix must be an LMVM-type.");
    470:   if (!lmvm->allocated) SETERRQ(comm, PETSC_ERR_ORDER, "LMVM matrix must be allocated first");
    471:   VecCheckMatCompatible(B, X, 2, Y, 3);
    472:   /* Invert the initial Jacobian onto q (or apply scaling) */
    473:   if (lmvm->user_pc) {
    474:     /* User has defined a J0 inverse so we can directly apply it as a preconditioner */
    475:     PCApply(lmvm->J0pc, X, Y);
    476:   } else if (lmvm->user_ksp) {
    477:     /* User has defined a J0 or a custom KSP so just perform a solution */
    478:     KSPSolve(lmvm->J0ksp, X, Y);
    479:   } else if (lmvm->J0) {
    480:     MatHasOperation(lmvm->J0, MATOP_SOLVE, &hasSolve);
    481:     if (hasSolve) {
    482:       MatSolve(lmvm->J0, X, Y);
    483:     } else {
    484:       KSPSolve(lmvm->J0ksp, X, Y);
    485:     }
    486:   } else if (lmvm->user_scale) {
    487:     if (lmvm->J0diag) {
    488:       VecPointwiseDivide(X, Y, lmvm->J0diag);
    489:     } else {
    490:       VecCopy(X, Y);
    491:       VecScale(Y, 1.0/lmvm->J0scalar);
    492:     }
    493:   } else {
    494:     /* There is no J0 representation so just apply an identity matrix */
    495:     VecCopy(X, Y);
    496:   }
    497:   return(0);
    498: }

    500: /*------------------------------------------------------------*/

    502: /*@
    503:    MatLMVMIsAllocated - Returns a boolean flag that shows whether
    504:    the necessary data structures for the underlying matrix is allocated.

    506:    Input Parameters:
    507: .  B - An LMVM-type matrix

    509:    Output Parameter:
    510: .  flg - PETSC_TRUE if allocated, PETSC_FALSE otherwise

    512:    Level: intermediate

    514: .seealso: MatLMVMAllocate(), MatLMVMReset()
    515: @*/

    517: PetscErrorCode MatLMVMIsAllocated(Mat B, PetscBool *flg)
    518: {
    519:   Mat_LMVM          *lmvm = (Mat_LMVM*)B->data;
    520:   PetscErrorCode    ierr;
    521:   PetscBool         same;

    525:   PetscObjectBaseTypeCompare((PetscObject)B, MATLMVM, &same);
    526:   if (!same) SETERRQ(PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONG, "Matrix must be an LMVM-type.");
    527:   *flg = PETSC_FALSE;
    528:   if (lmvm->allocated && B->preallocated && B->assembled) *flg = PETSC_TRUE;
    529:   return(0);
    530: }

    532: /*------------------------------------------------------------*/

    534: /*@
    535:    MatLMVMAllocate - Produces all necessary common memory for
    536:    LMVM approximations based on the solution and function vectors
    537:    provided. If MatSetSizes() and MatSetUp() have not been called
    538:    before MatLMVMAllocate(), the allocation will read sizes from
    539:    the provided vectors and update the matrix.

    541:    Input Parameters:
    542: +  B - An LMVM-type matrix
    543: .  X - Solution vector
    544: -  F - Function vector

    546:    Level: intermediate

    548: .seealso: MatLMVMReset(), MatLMVMUpdate()
    549: @*/
    550: PetscErrorCode MatLMVMAllocate(Mat B, Vec X, Vec F)
    551: {
    552:   Mat_LMVM          *lmvm = (Mat_LMVM*)B->data;
    553:   PetscErrorCode    ierr;
    554:   PetscBool         same;

    560:   PetscObjectBaseTypeCompare((PetscObject)B, MATLMVM, &same);
    561:   if (!same) SETERRQ(PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONG, "Matrix must be an LMVM-type.");
    562:   (*lmvm->ops->allocate)(B, X, F);
    563:   if (lmvm->J0) {
    564:     PetscObjectBaseTypeCompare((PetscObject)lmvm->J0, MATLMVM, &same);
    565:     if (same) {
    566:       MatLMVMAllocate(lmvm->J0, X, F);
    567:     }
    568:   }
    569:   return(0);
    570: }

    572: /*------------------------------------------------------------*/

    574: /*@
    575:    MatLMVMResetShift - Zero the shift factor.

    577:    Input Parameters:
    578: .  B - An LMVM-type matrix

    580:    Level: intermediate

    582: .seealso: MatLMVMAllocate(), MatLMVMUpdate()
    583: @*/
    584: PetscErrorCode MatLMVMResetShift(Mat B)
    585: {
    586:   Mat_LMVM          *lmvm = (Mat_LMVM*)B->data;
    587:   PetscErrorCode    ierr;
    588:   PetscBool         same;

    592:   PetscObjectBaseTypeCompare((PetscObject)B, MATLMVM, &same);
    593:   if (!same) SETERRQ(PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONG, "Matrix must be an LMVM-type.");
    594:   lmvm->shift = 0.0;
    595:   return(0);
    596: }

    598: /*------------------------------------------------------------*/

    600: /*@
    601:    MatLMVMReset - Flushes all of the accumulated updates out of
    602:    the LMVM approximation. In practice, this will not actually
    603:    destroy the data associated with the updates. It simply resets
    604:    counters, which leads to existing data being overwritten, and
    605:    MatSolve() being applied as if there are no updates. A boolean
    606:    flag is available to force destruction of the update vectors.

    608:    If the user has provided another LMVM matrix as J0, the J0
    609:    matrix is also reset in this function.

    611:    Input Parameters:
    612: +  B - An LMVM-type matrix
    613: -  destructive - flag for enabling destruction of data structures

    615:    Level: intermediate

    617: .seealso: MatLMVMAllocate(), MatLMVMUpdate()
    618: @*/
    619: PetscErrorCode MatLMVMReset(Mat B, PetscBool destructive)
    620: {
    621:   Mat_LMVM          *lmvm = (Mat_LMVM*)B->data;
    622:   PetscErrorCode    ierr;
    623:   PetscBool         same;

    627:   PetscObjectBaseTypeCompare((PetscObject)B, MATLMVM, &same);
    628:   if (!same) SETERRQ(PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONG, "Matrix must be an LMVM-type.");
    629:   (*lmvm->ops->reset)(B, destructive);
    630:   if (lmvm->J0) {
    631:     PetscObjectBaseTypeCompare((PetscObject)lmvm->J0, MATLMVM, &same);
    632:     if (same) {
    633:       MatLMVMReset(lmvm->J0, destructive);
    634:     }
    635:   }
    636:   return(0);
    637: }

    639: /*------------------------------------------------------------*/

    641: /*@
    642:    MatLMVMSetHistorySize - Set the number of past iterates to be
    643:    stored for the construction of the limited-memory QN update.

    645:    Input Parameters:
    646: +  B - An LMVM-type matrix
    647: -  hist_size - number of past iterates (default 5)

    649:    Options Database:
    650: .  -mat_lmvm_hist_size <m>

    652:    Level: beginner

    654: .seealso: MatLMVMGetUpdateCount()
    655: @*/

    657: PetscErrorCode MatLMVMSetHistorySize(Mat B, PetscInt hist_size)
    658: {
    659:   Mat_LMVM          *lmvm = (Mat_LMVM*)B->data;
    660:   PetscErrorCode    ierr;
    661:   PetscBool         same;
    662:   Vec               X, F;

    666:   PetscObjectBaseTypeCompare((PetscObject)B, MATLMVM, &same);
    667:   if (!same) SETERRQ(PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONG, "Matrix must be an LMVM-type.");
    668:   if (hist_size > 0) {
    669:     lmvm->m = hist_size;
    670:     if (lmvm->allocated && lmvm->m != lmvm->m_old) {
    671:       VecDuplicate(lmvm->Xprev, &X);
    672:       VecDuplicate(lmvm->Fprev, &F);
    673:       MatLMVMReset(B, PETSC_TRUE);
    674:       MatLMVMAllocate(B, X, F);
    675:       VecDestroy(&X);
    676:       VecDestroy(&F);
    677:     }
    678:   } else if (hist_size < 0) SETERRQ(PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONG, "QN history size must be a non-negative integer.");
    679:   return(0);
    680: }

    682: /*------------------------------------------------------------*/

    684: /*@
    685:    MatLMVMGetUpdateCount - Returns the number of accepted updates.
    686:    This number may be greater than the total number of update vectors
    687:    stored in the matrix. The counters are reset when MatLMVMReset()
    688:    is called.

    690:    Input Parameters:
    691: .  B - An LMVM-type matrix

    693:    Output Parameter:
    694: .  nupdates - number of accepted updates

    696:    Level: intermediate

    698: .seealso: MatLMVMGetRejectCount(), MatLMVMReset()
    699: @*/
    700: PetscErrorCode MatLMVMGetUpdateCount(Mat B, PetscInt *nupdates)
    701: {
    702:   Mat_LMVM          *lmvm = (Mat_LMVM*)B->data;
    703:   PetscErrorCode    ierr;
    704:   PetscBool         same;

    708:   PetscObjectBaseTypeCompare((PetscObject)B, MATLMVM, &same);
    709:   if (!same) SETERRQ(PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONG, "Matrix must be an LMVM-type.");
    710:   *nupdates = lmvm->nupdates;
    711:   return(0);
    712: }

    714: /*------------------------------------------------------------*/

    716: /*@
    717:    MatLMVMGetRejectCount - Returns the number of rejected updates.
    718:    The counters are reset when MatLMVMReset() is called.

    720:    Input Parameters:
    721: .  B - An LMVM-type matrix

    723:    Output Parameter:
    724: .  nrejects - number of rejected updates

    726:    Level: intermediate

    728: .seealso: MatLMVMGetRejectCount(), MatLMVMReset()
    729: @*/
    730: PetscErrorCode MatLMVMGetRejectCount(Mat B, PetscInt *nrejects)
    731: {
    732:   Mat_LMVM          *lmvm = (Mat_LMVM*)B->data;
    733:   PetscErrorCode    ierr;
    734:   PetscBool         same;

    738:   PetscObjectBaseTypeCompare((PetscObject)B, MATLMVM, &same);
    739:   if (!same) SETERRQ(PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONG, "Matrix must be an LMVM-type.");
    740:   *nrejects = lmvm->nrejects;
    741:   return(0);
    742: }