Actual source code: dmksp.c

  1: #include <petsc/private/dmimpl.h>
  2: #include <petsc/private/kspimpl.h>
  3: #include <petscdm.h>

  5: static PetscErrorCode DMKSPDestroy(DMKSP *kdm)
  6: {
  7:   PetscFunctionBegin;
  8:   if (!*kdm) PetscFunctionReturn(PETSC_SUCCESS);
 10:   if (--((PetscObject)*kdm)->refct > 0) {
 11:     *kdm = NULL;
 12:     PetscFunctionReturn(PETSC_SUCCESS);
 13:   }
 14:   if ((*kdm)->ops->destroy) PetscCall(((*kdm)->ops->destroy)(kdm));
 15:   PetscCall(PetscHeaderDestroy(kdm));
 16:   PetscFunctionReturn(PETSC_SUCCESS);
 17: }

 19: static PetscErrorCode DMKSPCreate(MPI_Comm comm, DMKSP *kdm)
 20: {
 21:   PetscFunctionBegin;
 22:   PetscCall(KSPInitializePackage());
 23:   PetscCall(PetscHeaderCreate(*kdm, DMKSP_CLASSID, "DMKSP", "DMKSP", "DMKSP", comm, DMKSPDestroy, NULL));
 24:   PetscFunctionReturn(PETSC_SUCCESS);
 25: }

 27: /* Attaches the DMKSP to the coarse level.
 28:  * Under what conditions should we copy versus duplicate?
 29:  */
 30: static PetscErrorCode DMCoarsenHook_DMKSP(DM dm, DM dmc, PetscCtx ctx)
 31: {
 32:   PetscFunctionBegin;
 33:   PetscCall(DMCopyDMKSP(dm, dmc));
 34:   PetscFunctionReturn(PETSC_SUCCESS);
 35: }

 37: /* Attaches the DMKSP to the coarse level.
 38:  * Under what conditions should we copy versus duplicate?
 39:  */
 40: static PetscErrorCode DMRefineHook_DMKSP(DM dm, DM dmc, PetscCtx ctx)
 41: {
 42:   PetscFunctionBegin;
 43:   PetscCall(DMCopyDMKSP(dm, dmc));
 44:   PetscFunctionReturn(PETSC_SUCCESS);
 45: }

 47: /*
 48:   DMKSPCopy - copies the information in a `DMKSP` to another `DMKSP`

 50:   Not Collective

 52:   Input Parameters:
 53: + kdm  - Original `DMKSP`
 54: - nkdm - `DMKSP` to receive the data, created with `DMKSPCreate()`

 56:   Level: developer

 58: .seealso: [](ch_ksp), `DMKSP`, `DMKSPCreate()`, `DMKSPDestroy()`
 59: */
 60: static PetscErrorCode DMKSPCopy(DMKSP kdm, DMKSP nkdm)
 61: {
 62:   PetscFunctionBegin;
 65:   nkdm->ops->createoperators     = kdm->ops->createoperators;
 66:   nkdm->ops->computeoperators    = kdm->ops->computeoperators;
 67:   nkdm->ops->computerhs          = kdm->ops->computerhs;
 68:   nkdm->ops->computeinitialguess = kdm->ops->computeinitialguess;
 69:   nkdm->ops->destroy             = kdm->ops->destroy;
 70:   nkdm->ops->duplicate           = kdm->ops->duplicate;

 72:   nkdm->createoperatorsctx = kdm->createoperatorsctx;
 73:   nkdm->operatorsctx       = kdm->operatorsctx;
 74:   nkdm->rhsctx             = kdm->rhsctx;
 75:   nkdm->initialguessctx    = kdm->initialguessctx;
 76:   nkdm->data               = kdm->data;
 77:   /* nkdm->originaldm   = kdm->originaldm; */ /* No need since nkdm->originaldm will be immediately updated in caller DMGetDMKSPWrite */

 79:   nkdm->fortran_func_pointers[0] = kdm->fortran_func_pointers[0];
 80:   nkdm->fortran_func_pointers[1] = kdm->fortran_func_pointers[1];
 81:   nkdm->fortran_func_pointers[2] = kdm->fortran_func_pointers[2];

 83:   /* implementation specific copy hooks */
 84:   PetscTryTypeMethod(kdm, duplicate, nkdm);
 85:   PetscFunctionReturn(PETSC_SUCCESS);
 86: }

 88: /*@
 89:   DMGetDMKSP - get the read-only private `DMKSP` context from a `DM`

 91:   Logically Collective

 93:   Input Parameter:
 94: . dm - `DM` used with a `KSP`

 96:   Output Parameter:
 97: . kspdm - private `DMKSP` context

 99:   Level: developer

101:   Note:
102:   Use `DMGetDMKSPWrite()` if write access is needed. The DMKSPSetXXX API should be used wherever possible.

104: .seealso: [](ch_ksp), `DMKSP`, `DM`, `KSP`, `DMGetDMKSPWrite()`
105: @*/
106: PetscErrorCode DMGetDMKSP(DM dm, DMKSP *kspdm)
107: {
108:   PetscFunctionBegin;
110:   *kspdm = (DMKSP)dm->dmksp;
111:   if (!*kspdm) {
112:     PetscCall(PetscInfo(dm, "Creating new DMKSP\n"));
113:     PetscCall(DMKSPCreate(PetscObjectComm((PetscObject)dm), kspdm));
114:     dm->dmksp            = (PetscObject)*kspdm;
115:     (*kspdm)->originaldm = dm;
116:     PetscCall(DMCoarsenHookAdd(dm, DMCoarsenHook_DMKSP, NULL, NULL));
117:     PetscCall(DMRefineHookAdd(dm, DMRefineHook_DMKSP, NULL, NULL));
118:   }
119:   PetscFunctionReturn(PETSC_SUCCESS);
120: }

122: /*@
123:   DMGetDMKSPWrite - get write access to private `DMKSP` context from a `DM`

125:   Logically Collective

127:   Input Parameter:
128: . dm - `DM` used with a `KSP`

130:   Output Parameter:
131: . kspdm - private `DMKSP` context

133:   Level: developer

135: .seealso: [](ch_ksp), `DMKSP`, `DM`, `KSP`, `DMGetDMKSP()`
136: @*/
137: PetscErrorCode DMGetDMKSPWrite(DM dm, DMKSP *kspdm)
138: {
139:   DMKSP kdm;

141:   PetscFunctionBegin;
143:   PetscCall(DMGetDMKSP(dm, &kdm));
144:   PetscCheck(kdm->originaldm, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DMKSP has a NULL originaldm");
145:   if (kdm->originaldm != dm) { /* Copy on write */
146:     DMKSP oldkdm = kdm;
147:     PetscCall(PetscInfo(dm, "Copying DMKSP due to write\n"));
148:     PetscCall(DMKSPCreate(PetscObjectComm((PetscObject)dm), &kdm));
149:     PetscCall(DMKSPCopy(oldkdm, kdm));
150:     PetscCall(DMKSPDestroy((DMKSP *)&dm->dmksp));
151:     dm->dmksp       = (PetscObject)kdm;
152:     kdm->originaldm = dm;
153:   }
154:   *kspdm = kdm;
155:   PetscFunctionReturn(PETSC_SUCCESS);
156: }

158: /*@
159:   DMCopyDMKSP - copies a `DM` `DMKSP` context to a new `DM`

161:   Logically Collective

163:   Input Parameters:
164: + dmsrc  - `DM` to obtain context from
165: - dmdest - `DM` to add context to

167:   Level: developer

169:   Note:
170:   The context is copied by reference. This function does not ensure that a context exists.

172: .seealso: [](ch_ksp), `DMKSP`, `DM`, `KSP`, `DMGetDMKSP()`, `KSPSetDM()`
173: @*/
174: PetscErrorCode DMCopyDMKSP(DM dmsrc, DM dmdest)
175: {
176:   PetscFunctionBegin;
179:   PetscCall(DMKSPDestroy((DMKSP *)&dmdest->dmksp));
180:   dmdest->dmksp = dmsrc->dmksp;
181:   PetscCall(PetscObjectReference(dmdest->dmksp));
182:   PetscCall(DMCoarsenHookAdd(dmdest, DMCoarsenHook_DMKSP, NULL, NULL));
183:   PetscCall(DMRefineHookAdd(dmdest, DMRefineHook_DMKSP, NULL, NULL));
184:   PetscFunctionReturn(PETSC_SUCCESS);
185: }

187: /*@
188:   DMKSPSetCreateOperators - set the `KSP` matrix creation function used in `KSPSetUp()`

190:   Logically Collective

192:   Input Parameters:
193: + dm   - `DM` to be used with `KSP`
194: . func - matrix creation function, for calling sequence see `KSPCreateOperatorsFn`
195: - ctx  - context for matrix creation

197:   Level: developer

199:   Notes:
200:   `func` is called by `KSPSetUp()` when `KSPSetDMActive()` has enabled the `KSP_DMACTIVE_OPERATOR` flag.
201:   It is used to create once the matrices before the matrix evaluation function set with `DMKSPSetComputeOperators()` is called.
202:   Pass `NULL` for both `func` and `ctx` to remove the callback.

204:   If this matrix creation function is not provided, `KSPSetUp()` will create a single matrix `A` (also used for `P`) using `DMCreateMatrix()`.

206: .seealso: [](ch_ksp), `DMKSP`, `DM`, `KSP`, `DMKSPGetCreateOperators()`, `DMKSPSetComputeOperators()`, `KSPCreateOperatorsFn`, `KSPSetDMActive()`, `KSPSetOperators()`, `DMCreateMatrix()`
207: @*/
208: PetscErrorCode DMKSPSetCreateOperators(DM dm, KSPCreateOperatorsFn *func, PetscCtx ctx)
209: {
210:   DMKSP kdm;

212:   PetscFunctionBegin;
214:   PetscCall(DMGetDMKSPWrite(dm, &kdm));
215:   if (func) kdm->ops->createoperators = func;
216:   if (ctx) kdm->createoperatorsctx = ctx;
217:   if (!func && !ctx) {
218:     kdm->ops->createoperators = NULL;
219:     kdm->createoperatorsctx   = NULL;
220:   }
221:   PetscFunctionReturn(PETSC_SUCCESS);
222: }

224: /*@
225:   DMKSPGetCreateOperators - get `KSP` matrix creation function

227:   Not Collective

229:   Input Parameter:
230: . dm - `DM` used with a `KSP`

232:   Output Parameters:
233: + func - matrix creation function, for calling sequence see `KSPCreateOperatorsFn`
234: - ctx  - context for matrix creation

236:   Level: developer

238: .seealso: [](ch_ksp), `DMKSP`, `DM`, `KSP`, `DMKSPSetCreateOperators()`, `DMKSPSetComputeOperators()`, `KSPCreateOperatorsFn`
239: @*/
240: PetscErrorCode DMKSPGetCreateOperators(DM dm, KSPCreateOperatorsFn **func, PetscCtx ctx)
241: {
242:   DMKSP kdm;

244:   PetscFunctionBegin;
246:   PetscCall(DMGetDMKSP(dm, &kdm));
247:   if (func) *func = kdm->ops->createoperators;
248:   if (ctx) *(void **)ctx = kdm->createoperatorsctx;
249:   PetscFunctionReturn(PETSC_SUCCESS);
250: }

252: /*@
253:   DMKSPSetComputeOperators - set `KSP` matrix evaluation function

255:   Logically Collective

257:   Input Parameters:
258: + dm   - `DM` to be used with `KSP`
259: . func - matrix evaluation function,  for calling sequence see `KSPComputeOperatorsFn`
260: - ctx  - context for matrix evaluation

262:   Level: developer

264:   Note:
265:   `KSPSetComputeOperators()` is normally used, but it calls this function internally because the application context is actually
266:   associated with the `DM`.  This makes the interface consistent regardless of whether the user interacts with a `DM` or
267:   not.

269:   Developer Note:
270:   If `DM` took a more central role at some later date, this could become the primary method of setting the matrix.

272:   Pass `NULL` for both `func` and `ctx` to remove the callback.

274: .seealso: [](ch_ksp), `DMKSP`, `DM`, `KSP`, `DMKSPSetContext()`, `DMKSPGetComputeOperators()`, `KSPSetOperators()`, `KSPComputeOperatorsFn`
275: @*/
276: PetscErrorCode DMKSPSetComputeOperators(DM dm, KSPComputeOperatorsFn *func, PetscCtx ctx)
277: {
278:   DMKSP kdm;

280:   PetscFunctionBegin;
282:   PetscCall(DMGetDMKSPWrite(dm, &kdm));
283:   if (func) kdm->ops->computeoperators = func;
284:   if (ctx) kdm->operatorsctx = ctx;
285:   if (!func && !ctx) {
286:     kdm->ops->computeoperators = NULL;
287:     kdm->operatorsctx          = NULL;
288:   }
289:   PetscFunctionReturn(PETSC_SUCCESS);
290: }

292: /*@
293:   DMKSPGetComputeOperators - get `KSP` matrix evaluation function

295:   Not Collective

297:   Input Parameter:
298: . dm - `DM` used with a `KSP`

300:   Output Parameters:
301: + func - matrix evaluation function,  for calling sequence see `KSPComputeOperatorsFn`
302: - ctx  - context for matrix evaluation

304:   Level: developer

306: .seealso: [](ch_ksp), `DMKSP`, `DM`, `KSP`, `DMKSPSetContext()`, `KSPSetComputeOperators()`, `DMKSPSetComputeOperators()`, `KSPComputeOperatorsFn`
307: @*/
308: PetscErrorCode DMKSPGetComputeOperators(DM dm, KSPComputeOperatorsFn **func, PetscCtx ctx)
309: {
310:   DMKSP kdm;

312:   PetscFunctionBegin;
314:   PetscCall(DMGetDMKSP(dm, &kdm));
315:   if (func) *func = kdm->ops->computeoperators;
316:   if (ctx) *(void **)ctx = kdm->operatorsctx;
317:   PetscFunctionReturn(PETSC_SUCCESS);
318: }

320: /*@
321:   DMKSPSetComputeRHS - set `KSP` right-hand side evaluation function

323:   Not Collective

325:   Input Parameters:
326: + dm   - `DM` used with a `KSP`
327: . func - right-hand side evaluation function,  for calling sequence see `KSPComputeRHSFn`
328: - ctx  - context for right-hand side evaluation

330:   Level: developer

332:   Note:
333:   `KSPSetComputeRHS()` is normally used, but it calls this function internally because the application context is actually
334:   associated with the `DM`.  This makes the interface consistent regardless of whether the user interacts with a `DM` or
335:   not.

337:   Developer Note:
338:   If `DM` took a more central role at some later date, this could become the primary method of setting the matrix.

340: .seealso: [](ch_ksp), `DMKSP`, `DM`, `KSP`, `DMKSPSetContext()`, `DMKSPGetComputeRHS()`
341: @*/
342: PetscErrorCode DMKSPSetComputeRHS(DM dm, KSPComputeRHSFn *func, PetscCtx ctx)
343: {
344:   DMKSP kdm;

346:   PetscFunctionBegin;
348:   PetscCall(DMGetDMKSPWrite(dm, &kdm));
349:   if (func) kdm->ops->computerhs = func;
350:   if (ctx) kdm->rhsctx = ctx;
351:   PetscFunctionReturn(PETSC_SUCCESS);
352: }

354: /*@
355:   DMKSPSetComputeInitialGuess - set `KSP` initial guess evaluation function

357:   Not Collective

359:   Input Parameters:
360: + dm   - `DM` to be used with `KSP`
361: . func - initial guess evaluation function, for calling sequence see `KSPComputeInitialGuessFn`
362: - ctx  - context for initial guess evaluation

364:   Level: developer

366:   Note:
367:   `KSPSetComputeInitialGuess()` is normally used, but it calls this function internally because the application context is actually
368:   associated with the `DM`.

370: .seealso: [](ch_ksp), `DMKSP`, `DM`, `KSP`, `DMKSPSetContext()`, `DMKSPGetComputeRHS()`, `KSPComputeInitialGuessFn`
371: @*/
372: PetscErrorCode DMKSPSetComputeInitialGuess(DM dm, KSPComputeInitialGuessFn *func, PetscCtx ctx)
373: {
374:   DMKSP kdm;

376:   PetscFunctionBegin;
378:   PetscCall(DMGetDMKSPWrite(dm, &kdm));
379:   if (func) kdm->ops->computeinitialguess = func;
380:   if (ctx) kdm->initialguessctx = ctx;
381:   PetscFunctionReturn(PETSC_SUCCESS);
382: }

384: /*@
385:   DMKSPGetComputeRHS - get `KSP` right-hand side evaluation function

387:   Not Collective

389:   Input Parameter:
390: . dm - `DM` to be used with `KSP`

392:   Output Parameters:
393: + func - right-hand side evaluation function,  for calling sequence see `KSPComputeRHSFn`
394: - ctx  - context for right-hand side evaluation

396:   Level: advanced

398: .seealso: [](ch_ksp), `DMKSP`, `DM`, `KSP`, `DMKSPSetContext()`, `KSPSetComputeRHS()`, `DMKSPSetComputeRHS()`, `KSPComputeRHSFn`
399: @*/
400: PetscErrorCode DMKSPGetComputeRHS(DM dm, KSPComputeRHSFn **func, PetscCtx ctx)
401: {
402:   DMKSP kdm;

404:   PetscFunctionBegin;
406:   PetscCall(DMGetDMKSP(dm, &kdm));
407:   if (func) *func = kdm->ops->computerhs;
408:   if (ctx) *(void **)ctx = kdm->rhsctx;
409:   PetscFunctionReturn(PETSC_SUCCESS);
410: }

412: /*@
413:   DMKSPGetComputeInitialGuess - get `KSP` initial guess evaluation function

415:   Not Collective

417:   Input Parameter:
418: . dm - `DM` used with a `KSP`

420:   Output Parameters:
421: + func - initial guess evaluation function, for calling sequence see `KSPComputeInitialGuessFn`
422: - ctx  - context for right-hand side evaluation

424:   Level: advanced

426: .seealso: [](ch_ksp), `DMKSP`, `DM`, `KSP`, `DMKSPSetContext()`, `KSPSetComputeRHS()`, `DMKSPSetComputeRHS()`, `KSPComputeInitialGuessFn`
427: @*/
428: PetscErrorCode DMKSPGetComputeInitialGuess(DM dm, KSPComputeInitialGuessFn **func, PetscCtx ctx)
429: {
430:   DMKSP kdm;

432:   PetscFunctionBegin;
434:   PetscCall(DMGetDMKSP(dm, &kdm));
435:   if (func) *func = kdm->ops->computeinitialguess;
436:   if (ctx) *(void **)ctx = kdm->initialguessctx;
437:   PetscFunctionReturn(PETSC_SUCCESS);
438: }