Actual source code: lmebasic.c

slepc-3.23.3 2025-09-08
Report Typos and Errors
  1: /*
  2:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  3:    SLEPc - Scalable Library for Eigenvalue Problem Computations
  4:    Copyright (c) 2002-, Universitat Politecnica de Valencia, Spain

  6:    This file is part of SLEPc.
  7:    SLEPc is distributed under a 2-clause BSD license (see LICENSE).
  8:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  9: */
 10: /*
 11:    Basic LME routines
 12: */

 14: #include <slepc/private/lmeimpl.h>

 16: /* Logging support */
 17: PetscClassId      LME_CLASSID = 0;
 18: PetscLogEvent     LME_SetUp = 0,LME_Solve = 0,LME_ComputeError = 0;

 20: /* List of registered LME routines */
 21: PetscFunctionList LMEList = NULL;
 22: PetscBool         LMERegisterAllCalled = PETSC_FALSE;

 24: /* List of registered LME monitors */
 25: PetscFunctionList LMEMonitorList              = NULL;
 26: PetscFunctionList LMEMonitorCreateList        = NULL;
 27: PetscFunctionList LMEMonitorDestroyList       = NULL;
 28: PetscBool         LMEMonitorRegisterAllCalled = PETSC_FALSE;

 30: /*@
 31:    LMEView - Prints the LME data structure.

 33:    Collective

 35:    Input Parameters:
 36: +  lme - the linear matrix equation solver context
 37: -  viewer - optional visualization context

 39:    Options Database Key:
 40: .  -lme_view -  Calls LMEView() at end of LMESolve()

 42:    Note:
 43:    The available visualization contexts include
 44: +     PETSC_VIEWER_STDOUT_SELF - standard output (default)
 45: -     PETSC_VIEWER_STDOUT_WORLD - synchronized standard
 46:          output where only the first processor opens
 47:          the file.  All other processors send their
 48:          data to the first processor to print.

 50:    The user can open an alternative visualization context with
 51:    PetscViewerASCIIOpen() - output to a specified file.

 53:    Level: beginner

 55: .seealso: LMECreate()
 56: @*/
 57: PetscErrorCode LMEView(LME lme,PetscViewer viewer)
 58: {
 59:   PetscBool      isascii;

 61:   PetscFunctionBegin;
 63:   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)lme),&viewer));
 65:   PetscCheckSameComm(lme,1,viewer,2);

 67:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii));
 68:   if (isascii) {
 69:     PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)lme,viewer));
 70:     PetscCall(PetscViewerASCIIPushTab(viewer));
 71:     PetscTryTypeMethod(lme,view,viewer);
 72:     PetscCall(PetscViewerASCIIPopTab(viewer));
 73:     PetscCall(PetscViewerASCIIPrintf(viewer,"  equation type: %s\n",LMEProblemTypes[lme->problem_type]));
 74:     PetscCall(PetscViewerASCIIPrintf(viewer,"  number of column vectors (ncv): %" PetscInt_FMT "\n",lme->ncv));
 75:     PetscCall(PetscViewerASCIIPrintf(viewer,"  maximum number of iterations: %" PetscInt_FMT "\n",lme->max_it));
 76:     PetscCall(PetscViewerASCIIPrintf(viewer,"  tolerance: %g\n",(double)lme->tol));
 77:   } else PetscTryTypeMethod(lme,view,viewer);
 78:   PetscCall(PetscViewerPushFormat(viewer,PETSC_VIEWER_ASCII_INFO));
 79:   if (!lme->V) PetscCall(LMEGetBV(lme,&lme->V));
 80:   PetscCall(BVView(lme->V,viewer));
 81:   PetscCall(PetscViewerPopFormat(viewer));
 82:   PetscFunctionReturn(PETSC_SUCCESS);
 83: }

 85: /*@
 86:    LMEViewFromOptions - View from options

 88:    Collective

 90:    Input Parameters:
 91: +  lme  - the linear matrix equation context
 92: .  obj  - optional object
 93: -  name - command line option

 95:    Level: intermediate

 97: .seealso: LMEView(), LMECreate()
 98: @*/
 99: PetscErrorCode LMEViewFromOptions(LME lme,PetscObject obj,const char name[])
100: {
101:   PetscFunctionBegin;
103:   PetscCall(PetscObjectViewFromOptions((PetscObject)lme,obj,name));
104:   PetscFunctionReturn(PETSC_SUCCESS);
105: }
106: /*@
107:    LMEConvergedReasonView - Displays the reason an LME solve converged or diverged.

109:    Collective

111:    Input Parameters:
112: +  lme - the linear matrix equation context
113: -  viewer - the viewer to display the reason

115:    Options Database Keys:
116: .  -lme_converged_reason - print reason for convergence, and number of iterations

118:    Note:
119:    To change the format of the output call PetscViewerPushFormat(viewer,format) before
120:    this call. Use PETSC_VIEWER_DEFAULT for the default, use PETSC_VIEWER_FAILED to only
121:    display a reason if it fails. The latter can be set in the command line with
122:    -lme_converged_reason ::failed

124:    Level: intermediate

126: .seealso: LMESetTolerances(), LMEGetIterationNumber(), LMEConvergedReasonViewFromOptions()
127: @*/
128: PetscErrorCode LMEConvergedReasonView(LME lme,PetscViewer viewer)
129: {
130:   PetscBool         isAscii;
131:   PetscViewerFormat format;

133:   PetscFunctionBegin;
134:   if (!viewer) viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)lme));
135:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isAscii));
136:   if (isAscii) {
137:     PetscCall(PetscViewerGetFormat(viewer,&format));
138:     PetscCall(PetscViewerASCIIAddTab(viewer,((PetscObject)lme)->tablevel));
139:     if (lme->reason > 0 && format != PETSC_VIEWER_FAILED) PetscCall(PetscViewerASCIIPrintf(viewer,"%s Linear matrix equation solve converged due to %s; iterations %" PetscInt_FMT "\n",((PetscObject)lme)->prefix?((PetscObject)lme)->prefix:"",LMEConvergedReasons[lme->reason],lme->its));
140:     else if (lme->reason <= 0) PetscCall(PetscViewerASCIIPrintf(viewer,"%s Linear matrix equation solve did not converge due to %s; iterations %" PetscInt_FMT "\n",((PetscObject)lme)->prefix?((PetscObject)lme)->prefix:"",LMEConvergedReasons[lme->reason],lme->its));
141:     PetscCall(PetscViewerASCIISubtractTab(viewer,((PetscObject)lme)->tablevel));
142:   }
143:   PetscFunctionReturn(PETSC_SUCCESS);
144: }

146: /*@
147:    LMEConvergedReasonViewFromOptions - Processes command line options to determine if/how
148:    the LME converged reason is to be viewed.

150:    Collective

152:    Input Parameter:
153: .  lme - the linear matrix equation context

155:    Level: developer

157: .seealso: LMEConvergedReasonView()
158: @*/
159: PetscErrorCode LMEConvergedReasonViewFromOptions(LME lme)
160: {
161:   PetscViewer       viewer;
162:   PetscBool         flg;
163:   static PetscBool  incall = PETSC_FALSE;
164:   PetscViewerFormat format;

166:   PetscFunctionBegin;
167:   if (incall) PetscFunctionReturn(PETSC_SUCCESS);
168:   incall = PETSC_TRUE;
169:   PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)lme),((PetscObject)lme)->options,((PetscObject)lme)->prefix,"-lme_converged_reason",&viewer,&format,&flg));
170:   if (flg) {
171:     PetscCall(PetscViewerPushFormat(viewer,format));
172:     PetscCall(LMEConvergedReasonView(lme,viewer));
173:     PetscCall(PetscViewerPopFormat(viewer));
174:     PetscCall(PetscViewerDestroy(&viewer));
175:   }
176:   incall = PETSC_FALSE;
177:   PetscFunctionReturn(PETSC_SUCCESS);
178: }

180: /*@
181:    LMECreate - Creates the default LME context.

183:    Collective

185:    Input Parameter:
186: .  comm - MPI communicator

188:    Output Parameter:
189: .  outlme - location to put the LME context

191:    Note:
192:    The default LME type is LMEKRYLOV

194:    Level: beginner

196: .seealso: LMESetUp(), LMESolve(), LMEDestroy(), LME
197: @*/
198: PetscErrorCode LMECreate(MPI_Comm comm,LME *outlme)
199: {
200:   LME            lme;

202:   PetscFunctionBegin;
203:   PetscAssertPointer(outlme,2);
204:   PetscCall(LMEInitializePackage());
205:   PetscCall(SlepcHeaderCreate(lme,LME_CLASSID,"LME","Linear Matrix Equation","LME",comm,LMEDestroy,LMEView));

207:   lme->A               = NULL;
208:   lme->B               = NULL;
209:   lme->D               = NULL;
210:   lme->E               = NULL;
211:   lme->C               = NULL;
212:   lme->X               = NULL;
213:   lme->problem_type    = LME_LYAPUNOV;
214:   lme->max_it          = PETSC_DETERMINE;
215:   lme->ncv             = PETSC_DETERMINE;
216:   lme->tol             = PETSC_DETERMINE;
217:   lme->errorifnotconverged = PETSC_FALSE;

219:   lme->numbermonitors  = 0;

221:   lme->V               = NULL;
222:   lme->nwork           = 0;
223:   lme->work            = NULL;
224:   lme->data            = NULL;

226:   lme->its             = 0;
227:   lme->errest          = 0;
228:   lme->setupcalled     = 0;
229:   lme->reason          = LME_CONVERGED_ITERATING;

231:   *outlme = lme;
232:   PetscFunctionReturn(PETSC_SUCCESS);
233: }

235: /*@
236:    LMESetType - Selects the particular solver to be used in the LME object.

238:    Logically Collective

240:    Input Parameters:
241: +  lme  - the linear matrix equation context
242: -  type - a known method

244:    Options Database Key:
245: .  -lme_type <method> - Sets the method; use -help for a list
246:     of available methods

248:    Notes:
249:    See "slepc/include/slepclme.h" for available methods. The default
250:    is LMEKRYLOV

252:    Normally, it is best to use the LMESetFromOptions() command and
253:    then set the LME type from the options database rather than by using
254:    this routine.  Using the options database provides the user with
255:    maximum flexibility in evaluating the different available methods.
256:    The LMESetType() routine is provided for those situations where it
257:    is necessary to set the iterative solver independently of the command
258:    line or options database.

260:    Level: intermediate

262: .seealso: LMEType
263: @*/
264: PetscErrorCode LMESetType(LME lme,LMEType type)
265: {
266:   PetscErrorCode (*r)(LME);
267:   PetscBool      match;

269:   PetscFunctionBegin;
271:   PetscAssertPointer(type,2);

273:   PetscCall(PetscObjectTypeCompare((PetscObject)lme,type,&match));
274:   if (match) PetscFunctionReturn(PETSC_SUCCESS);

276:   PetscCall(PetscFunctionListFind(LMEList,type,&r));
277:   PetscCheck(r,PetscObjectComm((PetscObject)lme),PETSC_ERR_ARG_UNKNOWN_TYPE,"Unknown LME type given: %s",type);

279:   PetscTryTypeMethod(lme,destroy);
280:   PetscCall(PetscMemzero(lme->ops,sizeof(struct _LMEOps)));

282:   lme->setupcalled = 0;
283:   PetscCall(PetscObjectChangeTypeName((PetscObject)lme,type));
284:   PetscCall((*r)(lme));
285:   PetscFunctionReturn(PETSC_SUCCESS);
286: }

288: /*@
289:    LMEGetType - Gets the LME type as a string from the LME object.

291:    Not Collective

293:    Input Parameter:
294: .  lme - the linear matrix equation context

296:    Output Parameter:
297: .  type - name of LME method

299:    Level: intermediate

301: .seealso: LMESetType()
302: @*/
303: PetscErrorCode LMEGetType(LME lme,LMEType *type)
304: {
305:   PetscFunctionBegin;
307:   PetscAssertPointer(type,2);
308:   *type = ((PetscObject)lme)->type_name;
309:   PetscFunctionReturn(PETSC_SUCCESS);
310: }

312: /*@C
313:    LMERegister - Adds a method to the linear matrix equation solver package.

315:    Not Collective

317:    Input Parameters:
318: +  name - name of a new user-defined solver
319: -  function - routine to create the solver context

321:    Notes:
322:    LMERegister() may be called multiple times to add several user-defined solvers.

324:    Example Usage:
325: .vb
326:     LMERegister("my_solver",MySolverCreate);
327: .ve

329:    Then, your solver can be chosen with the procedural interface via
330: $     LMESetType(lme,"my_solver")
331:    or at runtime via the option
332: $     -lme_type my_solver

334:    Level: advanced

336: .seealso: LMERegisterAll()
337: @*/
338: PetscErrorCode LMERegister(const char *name,PetscErrorCode (*function)(LME))
339: {
340:   PetscFunctionBegin;
341:   PetscCall(LMEInitializePackage());
342:   PetscCall(PetscFunctionListAdd(&LMEList,name,function));
343:   PetscFunctionReturn(PETSC_SUCCESS);
344: }

346: /*@C
347:    LMEMonitorRegister - Adds LME monitor routine.

349:    Not Collective

351:    Input Parameters:
352: +  name    - name of a new monitor routine
353: .  vtype   - a PetscViewerType for the output
354: .  format  - a PetscViewerFormat for the output
355: .  monitor - monitor routine
356: .  create  - creation routine, or NULL
357: -  destroy - destruction routine, or NULL

359:    Notes:
360:    LMEMonitorRegister() may be called multiple times to add several user-defined monitors.

362:    Example Usage:
363: .vb
364:    LMEMonitorRegister("my_monitor",PETSCVIEWERASCII,PETSC_VIEWER_ASCII_INFO_DETAIL,MyMonitor,NULL,NULL);
365: .ve

367:    Then, your monitor can be chosen with the procedural interface via
368: $      LMEMonitorSetFromOptions(lme,"-lme_monitor_my_monitor","my_monitor",NULL)
369:    or at runtime via the option
370: $      -lme_monitor_my_monitor

372:    Level: advanced

374: .seealso: LMEMonitorRegisterAll()
375: @*/
376: PetscErrorCode LMEMonitorRegister(const char name[],PetscViewerType vtype,PetscViewerFormat format,PetscErrorCode (*monitor)(LME,PetscInt,PetscReal,PetscViewerAndFormat*),PetscErrorCode (*create)(PetscViewer,PetscViewerFormat,void*,PetscViewerAndFormat**),PetscErrorCode (*destroy)(PetscViewerAndFormat**))
377: {
378:   char           key[PETSC_MAX_PATH_LEN];

380:   PetscFunctionBegin;
381:   PetscCall(LMEInitializePackage());
382:   PetscCall(SlepcMonitorMakeKey_Internal(name,vtype,format,key));
383:   PetscCall(PetscFunctionListAdd(&LMEMonitorList,key,monitor));
384:   if (create)  PetscCall(PetscFunctionListAdd(&LMEMonitorCreateList,key,create));
385:   if (destroy) PetscCall(PetscFunctionListAdd(&LMEMonitorDestroyList,key,destroy));
386:   PetscFunctionReturn(PETSC_SUCCESS);
387: }

389: /*@
390:    LMEReset - Resets the LME context to the initial state (prior to setup)
391:    and destroys any allocated Vecs and Mats.

393:    Collective

395:    Input Parameter:
396: .  lme - linear matrix equation context obtained from LMECreate()

398:    Level: advanced

400: .seealso: LMEDestroy()
401: @*/
402: PetscErrorCode LMEReset(LME lme)
403: {
404:   PetscFunctionBegin;
406:   if (!lme) PetscFunctionReturn(PETSC_SUCCESS);
407:   PetscTryTypeMethod(lme,reset);
408:   PetscCall(MatDestroy(&lme->A));
409:   PetscCall(MatDestroy(&lme->B));
410:   PetscCall(MatDestroy(&lme->D));
411:   PetscCall(MatDestroy(&lme->E));
412:   PetscCall(MatDestroy(&lme->C));
413:   PetscCall(MatDestroy(&lme->X));
414:   PetscCall(BVDestroy(&lme->V));
415:   PetscCall(VecDestroyVecs(lme->nwork,&lme->work));
416:   lme->nwork = 0;
417:   lme->setupcalled = 0;
418:   PetscFunctionReturn(PETSC_SUCCESS);
419: }

421: /*@
422:    LMEDestroy - Destroys the LME context.

424:    Collective

426:    Input Parameter:
427: .  lme - linear matrix equation context obtained from LMECreate()

429:    Level: beginner

431: .seealso: LMECreate(), LMESetUp(), LMESolve()
432: @*/
433: PetscErrorCode LMEDestroy(LME *lme)
434: {
435:   PetscFunctionBegin;
436:   if (!*lme) PetscFunctionReturn(PETSC_SUCCESS);
438:   if (--((PetscObject)*lme)->refct > 0) { *lme = NULL; PetscFunctionReturn(PETSC_SUCCESS); }
439:   PetscCall(LMEReset(*lme));
440:   PetscTryTypeMethod(*lme,destroy);
441:   PetscCall(LMEMonitorCancel(*lme));
442:   PetscCall(PetscHeaderDestroy(lme));
443:   PetscFunctionReturn(PETSC_SUCCESS);
444: }

446: /*@
447:    LMESetBV - Associates a basis vectors object to the linear matrix equation solver.

449:    Collective

451:    Input Parameters:
452: +  lme - linear matrix equation context obtained from LMECreate()
453: -  bv  - the basis vectors object

455:    Note:
456:    Use LMEGetBV() to retrieve the basis vectors context (for example,
457:    to free it at the end of the computations).

459:    Level: advanced

461: .seealso: LMEGetBV()
462: @*/
463: PetscErrorCode LMESetBV(LME lme,BV bv)
464: {
465:   PetscFunctionBegin;
468:   PetscCheckSameComm(lme,1,bv,2);
469:   PetscCall(PetscObjectReference((PetscObject)bv));
470:   PetscCall(BVDestroy(&lme->V));
471:   lme->V = bv;
472:   PetscFunctionReturn(PETSC_SUCCESS);
473: }

475: /*@
476:    LMEGetBV - Obtain the basis vectors object associated to the matrix
477:    function solver.

479:    Not Collective

481:    Input Parameters:
482: .  lme - linear matrix equation context obtained from LMECreate()

484:    Output Parameter:
485: .  bv - basis vectors context

487:    Level: advanced

489: .seealso: LMESetBV()
490: @*/
491: PetscErrorCode LMEGetBV(LME lme,BV *bv)
492: {
493:   PetscFunctionBegin;
495:   PetscAssertPointer(bv,2);
496:   if (!lme->V) {
497:     PetscCall(BVCreate(PetscObjectComm((PetscObject)lme),&lme->V));
498:     PetscCall(PetscObjectIncrementTabLevel((PetscObject)lme->V,(PetscObject)lme,0));
499:     PetscCall(PetscObjectSetOptions((PetscObject)lme->V,((PetscObject)lme)->options));
500:   }
501:   *bv = lme->V;
502:   PetscFunctionReturn(PETSC_SUCCESS);
503: }