1 #include <petsc/private/snesimpl.h> /*I "petscsnes.h" I*/ 2 #include <petscdm.h> 3 4 typedef struct { 5 PetscInt n; /* local subdomains */ 6 SNES *subsnes; /* nonlinear solvers for each subdomain */ 7 Vec *x; /* solution vectors */ 8 Vec *xl; /* solution local vectors */ 9 Vec *y; /* step vectors */ 10 Vec *b; /* rhs vectors */ 11 Vec weight; /* weighting for adding updates on overlaps, in global space */ 12 VecScatter *oscatter; /* scatter from global space to the subdomain global space */ 13 VecScatter *oscatter_copy; /* copy of the above */ 14 VecScatter *iscatter; /* scatter from global space to the nonoverlapping subdomain space */ 15 VecScatter *gscatter; /* scatter from global space to the subdomain local space */ 16 PCASMType type; /* ASM type */ 17 PetscBool usesdm; /* use the DM for setting up the subproblems */ 18 PetscBool finaljacobian; /* compute the jacobian of the converged solution */ 19 PetscReal damping; /* damping parameter for updates from the blocks */ 20 PetscBool weight_set; /* use a weight in the overlap updates */ 21 22 /* logging events */ 23 PetscLogEvent eventrestrictinterp; 24 PetscLogEvent eventsubsolve; 25 26 PetscInt fjtype; /* type of computed jacobian */ 27 Vec xinit; /* initial solution in case the final jacobian type is computed as first */ 28 } SNES_NASM; 29 30 const char *const SNESNASMTypes[] = {"NONE", "RESTRICT", "INTERPOLATE", "BASIC", "PCASMType", "PC_ASM_", NULL}; 31 const char *const SNESNASMFJTypes[] = {"FINALOUTER", "FINALINNER", "INITIAL"}; 32 33 static PetscErrorCode SNESReset_NASM(SNES snes) { 34 SNES_NASM *nasm = (SNES_NASM *)snes->data; 35 PetscInt i; 36 37 PetscFunctionBegin; 38 for (i = 0; i < nasm->n; i++) { 39 if (nasm->xl) PetscCall(VecDestroy(&nasm->xl[i])); 40 if (nasm->x) PetscCall(VecDestroy(&nasm->x[i])); 41 if (nasm->y) PetscCall(VecDestroy(&nasm->y[i])); 42 if (nasm->b) PetscCall(VecDestroy(&nasm->b[i])); 43 44 if (nasm->subsnes) PetscCall(SNESDestroy(&nasm->subsnes[i])); 45 if (nasm->oscatter) PetscCall(VecScatterDestroy(&nasm->oscatter[i])); 46 if (nasm->oscatter_copy) PetscCall(VecScatterDestroy(&nasm->oscatter_copy[i])); 47 if (nasm->iscatter) PetscCall(VecScatterDestroy(&nasm->iscatter[i])); 48 if (nasm->gscatter) PetscCall(VecScatterDestroy(&nasm->gscatter[i])); 49 } 50 51 PetscCall(PetscFree(nasm->x)); 52 PetscCall(PetscFree(nasm->xl)); 53 PetscCall(PetscFree(nasm->y)); 54 PetscCall(PetscFree(nasm->b)); 55 56 if (nasm->xinit) PetscCall(VecDestroy(&nasm->xinit)); 57 58 PetscCall(PetscFree(nasm->subsnes)); 59 PetscCall(PetscFree(nasm->oscatter)); 60 PetscCall(PetscFree(nasm->oscatter_copy)); 61 PetscCall(PetscFree(nasm->iscatter)); 62 PetscCall(PetscFree(nasm->gscatter)); 63 64 if (nasm->weight_set) PetscCall(VecDestroy(&nasm->weight)); 65 66 nasm->eventrestrictinterp = 0; 67 nasm->eventsubsolve = 0; 68 PetscFunctionReturn(0); 69 } 70 71 static PetscErrorCode SNESDestroy_NASM(SNES snes) { 72 PetscFunctionBegin; 73 PetscCall(SNESReset_NASM(snes)); 74 PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNASMSetType_C", NULL)); 75 PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNASMGetType_C", NULL)); 76 PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNASMSetSubdomains_C", NULL)); 77 PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNASMGetSubdomains_C", NULL)); 78 PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNASMSetDamping_C", NULL)); 79 PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNASMGetDamping_C", NULL)); 80 PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNASMGetSubdomainVecs_C", NULL)); 81 PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNASMSetComputeFinalJacobian_C", NULL)); 82 PetscCall(PetscFree(snes->data)); 83 PetscFunctionReturn(0); 84 } 85 86 static PetscErrorCode DMGlobalToLocalSubDomainDirichletHook_Private(DM dm, Vec g, InsertMode mode, Vec l, void *ctx) { 87 Vec bcs = (Vec)ctx; 88 89 PetscFunctionBegin; 90 PetscCall(VecCopy(bcs, l)); 91 PetscFunctionReturn(0); 92 } 93 94 static PetscErrorCode SNESSetUp_NASM(SNES snes) { 95 SNES_NASM *nasm = (SNES_NASM *)snes->data; 96 DM dm, subdm; 97 DM *subdms; 98 PetscInt i; 99 const char *optionsprefix; 100 Vec F; 101 PetscMPIInt size; 102 KSP ksp; 103 PC pc; 104 105 PetscFunctionBegin; 106 if (!nasm->subsnes) { 107 PetscCall(SNESGetDM(snes, &dm)); 108 if (dm) { 109 nasm->usesdm = PETSC_TRUE; 110 PetscCall(DMCreateDomainDecomposition(dm, &nasm->n, NULL, NULL, NULL, &subdms)); 111 PetscCheck(subdms, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM has no default decomposition defined. Set subsolves manually with SNESNASMSetSubdomains()."); 112 PetscCall(DMCreateDomainDecompositionScatters(dm, nasm->n, subdms, &nasm->iscatter, &nasm->oscatter, &nasm->gscatter)); 113 PetscCall(PetscMalloc1(nasm->n, &nasm->oscatter_copy)); 114 for (i = 0; i < nasm->n; i++) PetscCall(VecScatterCopy(nasm->oscatter[i], &nasm->oscatter_copy[i])); 115 116 PetscCall(SNESGetOptionsPrefix(snes, &optionsprefix)); 117 PetscCall(PetscMalloc1(nasm->n, &nasm->subsnes)); 118 for (i = 0; i < nasm->n; i++) { 119 PetscCall(SNESCreate(PETSC_COMM_SELF, &nasm->subsnes[i])); 120 PetscCall(PetscObjectIncrementTabLevel((PetscObject)nasm->subsnes[i], (PetscObject)snes, 1)); 121 PetscCall(SNESAppendOptionsPrefix(nasm->subsnes[i], optionsprefix)); 122 PetscCall(SNESAppendOptionsPrefix(nasm->subsnes[i], "sub_")); 123 PetscCall(SNESSetDM(nasm->subsnes[i], subdms[i])); 124 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)nasm->subsnes[i]), &size)); 125 if (size == 1) { 126 PetscCall(SNESGetKSP(nasm->subsnes[i], &ksp)); 127 PetscCall(KSPGetPC(ksp, &pc)); 128 PetscCall(KSPSetType(ksp, KSPPREONLY)); 129 PetscCall(PCSetType(pc, PCLU)); 130 } 131 PetscCall(SNESSetFromOptions(nasm->subsnes[i])); 132 PetscCall(DMDestroy(&subdms[i])); 133 } 134 PetscCall(PetscFree(subdms)); 135 } else SETERRQ(PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_WRONGSTATE, "Cannot construct local problems automatically without a DM!"); 136 } else SETERRQ(PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_WRONGSTATE, "Must set subproblems manually if there is no DM!"); 137 /* allocate the global vectors */ 138 if (!nasm->x) PetscCall(PetscCalloc1(nasm->n, &nasm->x)); 139 if (!nasm->xl) PetscCall(PetscCalloc1(nasm->n, &nasm->xl)); 140 if (!nasm->y) PetscCall(PetscCalloc1(nasm->n, &nasm->y)); 141 if (!nasm->b) PetscCall(PetscCalloc1(nasm->n, &nasm->b)); 142 143 for (i = 0; i < nasm->n; i++) { 144 PetscCall(SNESGetFunction(nasm->subsnes[i], &F, NULL, NULL)); 145 if (!nasm->x[i]) PetscCall(VecDuplicate(F, &nasm->x[i])); 146 if (!nasm->y[i]) PetscCall(VecDuplicate(F, &nasm->y[i])); 147 if (!nasm->b[i]) PetscCall(VecDuplicate(F, &nasm->b[i])); 148 if (!nasm->xl[i]) { 149 PetscCall(SNESGetDM(nasm->subsnes[i], &subdm)); 150 PetscCall(DMCreateLocalVector(subdm, &nasm->xl[i])); 151 PetscCall(DMGlobalToLocalHookAdd(subdm, DMGlobalToLocalSubDomainDirichletHook_Private, NULL, nasm->xl[i])); 152 } 153 } 154 if (nasm->finaljacobian) { 155 PetscCall(SNESSetUpMatrices(snes)); 156 if (nasm->fjtype == 2) PetscCall(VecDuplicate(snes->vec_sol, &nasm->xinit)); 157 for (i = 0; i < nasm->n; i++) PetscCall(SNESSetUpMatrices(nasm->subsnes[i])); 158 } 159 PetscFunctionReturn(0); 160 } 161 162 static PetscErrorCode SNESSetFromOptions_NASM(SNES snes, PetscOptionItems *PetscOptionsObject) { 163 PCASMType asmtype; 164 PetscBool flg, monflg; 165 SNES_NASM *nasm = (SNES_NASM *)snes->data; 166 167 PetscFunctionBegin; 168 PetscOptionsHeadBegin(PetscOptionsObject, "Nonlinear Additive Schwarz options"); 169 PetscCall(PetscOptionsEnum("-snes_nasm_type", "Type of restriction/extension", "", SNESNASMTypes, (PetscEnum)nasm->type, (PetscEnum *)&asmtype, &flg)); 170 if (flg) PetscCall(SNESNASMSetType(snes, asmtype)); 171 flg = PETSC_FALSE; 172 monflg = PETSC_TRUE; 173 PetscCall(PetscOptionsReal("-snes_nasm_damping", "The new solution is obtained as old solution plus dmp times (sum of the solutions on the subdomains)", "SNESNASMSetDamping", nasm->damping, &nasm->damping, &flg)); 174 if (flg) PetscCall(SNESNASMSetDamping(snes, nasm->damping)); 175 PetscCall(PetscOptionsDeprecated("-snes_nasm_sub_view", NULL, "3.15", "Use -snes_view ::ascii_info_detail")); 176 PetscCall(PetscOptionsBool("-snes_nasm_finaljacobian", "Compute the global jacobian of the final iterate (for ASPIN)", "", nasm->finaljacobian, &nasm->finaljacobian, NULL)); 177 PetscCall(PetscOptionsEList("-snes_nasm_finaljacobian_type", "The type of the final jacobian computed.", "", SNESNASMFJTypes, 3, SNESNASMFJTypes[0], &nasm->fjtype, NULL)); 178 PetscCall(PetscOptionsBool("-snes_nasm_log", "Log times for subSNES solves and restriction", "", monflg, &monflg, &flg)); 179 if (flg) { 180 PetscCall(PetscLogEventRegister("SNESNASMSubSolve", ((PetscObject)snes)->classid, &nasm->eventsubsolve)); 181 PetscCall(PetscLogEventRegister("SNESNASMRestrict", ((PetscObject)snes)->classid, &nasm->eventrestrictinterp)); 182 } 183 PetscOptionsHeadEnd(); 184 PetscFunctionReturn(0); 185 } 186 187 static PetscErrorCode SNESView_NASM(SNES snes, PetscViewer viewer) { 188 SNES_NASM *nasm = (SNES_NASM *)snes->data; 189 PetscMPIInt rank, size; 190 PetscInt i, N, bsz; 191 PetscBool iascii, isstring; 192 PetscViewer sviewer; 193 MPI_Comm comm; 194 PetscViewerFormat format; 195 const char *prefix; 196 197 PetscFunctionBegin; 198 PetscCall(PetscObjectGetComm((PetscObject)snes, &comm)); 199 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 200 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSTRING, &isstring)); 201 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 202 PetscCallMPI(MPI_Comm_size(comm, &size)); 203 PetscCall(MPIU_Allreduce(&nasm->n, &N, 1, MPIU_INT, MPI_SUM, comm)); 204 if (iascii) { 205 PetscCall(PetscViewerASCIIPrintf(viewer, " total subdomain blocks = %" PetscInt_FMT "\n", N)); 206 PetscCall(PetscViewerGetFormat(viewer, &format)); 207 if (format != PETSC_VIEWER_ASCII_INFO_DETAIL) { 208 if (nasm->subsnes) { 209 PetscCall(PetscViewerASCIIPrintf(viewer, " Local solver information for first block on rank 0:\n")); 210 PetscCall(SNESGetOptionsPrefix(snes, &prefix)); 211 PetscCall(PetscViewerASCIIPrintf(viewer, " Use -%ssnes_view ::ascii_info_detail to display information for all blocks\n", prefix ? prefix : "")); 212 PetscCall(PetscViewerASCIIPushTab(viewer)); 213 PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sviewer)); 214 if (rank == 0) { 215 PetscCall(PetscViewerASCIIPushTab(viewer)); 216 PetscCall(SNESView(nasm->subsnes[0], sviewer)); 217 PetscCall(PetscViewerASCIIPopTab(viewer)); 218 } 219 PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sviewer)); 220 PetscCall(PetscViewerASCIIPopTab(viewer)); 221 } 222 } else { 223 /* print the solver on each block */ 224 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 225 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " [%d] number of local blocks = %" PetscInt_FMT "\n", (int)rank, nasm->n)); 226 PetscCall(PetscViewerFlush(viewer)); 227 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 228 PetscCall(PetscViewerASCIIPrintf(viewer, " Local solver information for each block is in the following SNES objects:\n")); 229 PetscCall(PetscViewerASCIIPushTab(viewer)); 230 PetscCall(PetscViewerASCIIPrintf(viewer, "- - - - - - - - - - - - - - - - - -\n")); 231 PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sviewer)); 232 for (i = 0; i < nasm->n; i++) { 233 PetscCall(VecGetLocalSize(nasm->x[i], &bsz)); 234 PetscCall(PetscViewerASCIIPrintf(sviewer, "[%d] local block number %" PetscInt_FMT ", size = %" PetscInt_FMT "\n", (int)rank, i, bsz)); 235 PetscCall(SNESView(nasm->subsnes[i], sviewer)); 236 PetscCall(PetscViewerASCIIPrintf(sviewer, "- - - - - - - - - - - - - - - - - -\n")); 237 } 238 PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sviewer)); 239 PetscCall(PetscViewerFlush(viewer)); 240 PetscCall(PetscViewerASCIIPopTab(viewer)); 241 } 242 } else if (isstring) { 243 PetscCall(PetscViewerStringSPrintf(viewer, " blocks=%" PetscInt_FMT ",type=%s", N, SNESNASMTypes[nasm->type])); 244 PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sviewer)); 245 if (nasm->subsnes && rank == 0) PetscCall(SNESView(nasm->subsnes[0], sviewer)); 246 PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sviewer)); 247 } 248 PetscFunctionReturn(0); 249 } 250 251 /*@ 252 SNESNASMSetType - Set the type of subdomain update used 253 254 Logically Collective on SNES 255 256 Input Parameters: 257 + SNES - the SNES context 258 - type - the type of update, PC_ASM_BASIC or PC_ASM_RESTRICT 259 260 Level: intermediate 261 262 .seealso: `SNESNASM`, `SNESNASMGetType()`, `PCASMSetType()` 263 @*/ 264 PetscErrorCode SNESNASMSetType(SNES snes, PCASMType type) { 265 PetscErrorCode (*f)(SNES, PCASMType); 266 267 PetscFunctionBegin; 268 PetscCall(PetscObjectQueryFunction((PetscObject)snes, "SNESNASMSetType_C", &f)); 269 if (f) PetscCall((f)(snes, type)); 270 PetscFunctionReturn(0); 271 } 272 273 static PetscErrorCode SNESNASMSetType_NASM(SNES snes, PCASMType type) { 274 SNES_NASM *nasm = (SNES_NASM *)snes->data; 275 276 PetscFunctionBegin; 277 PetscCheck(type == PC_ASM_BASIC || type == PC_ASM_RESTRICT, PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_OUTOFRANGE, "SNESNASM only supports basic and restrict types"); 278 nasm->type = type; 279 PetscFunctionReturn(0); 280 } 281 282 /*@ 283 SNESNASMGetType - Get the type of subdomain update used 284 285 Logically Collective on SNES 286 287 Input Parameters: 288 . SNES - the SNES context 289 290 Output Parameters: 291 . type - the type of update 292 293 Level: intermediate 294 295 .seealso: `SNESNASM`, `SNESNASMSetType()`, `PCASMGetType()` 296 @*/ 297 PetscErrorCode SNESNASMGetType(SNES snes, PCASMType *type) { 298 PetscFunctionBegin; 299 PetscUseMethod(snes, "SNESNASMGetType_C", (SNES, PCASMType *), (snes, type)); 300 PetscFunctionReturn(0); 301 } 302 303 static PetscErrorCode SNESNASMGetType_NASM(SNES snes, PCASMType *type) { 304 SNES_NASM *nasm = (SNES_NASM *)snes->data; 305 306 PetscFunctionBegin; 307 *type = nasm->type; 308 PetscFunctionReturn(0); 309 } 310 311 /*@ 312 SNESNASMSetSubdomains - Manually Set the context required to restrict and solve subdomain problems. 313 314 Not Collective 315 316 Input Parameters: 317 + SNES - the SNES context 318 . n - the number of local subdomains 319 . subsnes - solvers defined on the local subdomains 320 . iscatter - scatters into the nonoverlapping portions of the local subdomains 321 . oscatter - scatters into the overlapping portions of the local subdomains 322 - gscatter - scatters into the (ghosted) local vector of the local subdomain 323 324 Level: intermediate 325 326 .seealso: `SNESNASM`, `SNESNASMGetSubdomains()` 327 @*/ 328 PetscErrorCode SNESNASMSetSubdomains(SNES snes, PetscInt n, SNES subsnes[], VecScatter iscatter[], VecScatter oscatter[], VecScatter gscatter[]) { 329 PetscErrorCode (*f)(SNES, PetscInt, SNES *, VecScatter *, VecScatter *, VecScatter *); 330 331 PetscFunctionBegin; 332 PetscCall(PetscObjectQueryFunction((PetscObject)snes, "SNESNASMSetSubdomains_C", &f)); 333 if (f) PetscCall((f)(snes, n, subsnes, iscatter, oscatter, gscatter)); 334 PetscFunctionReturn(0); 335 } 336 337 static PetscErrorCode SNESNASMSetSubdomains_NASM(SNES snes, PetscInt n, SNES subsnes[], VecScatter iscatter[], VecScatter oscatter[], VecScatter gscatter[]) { 338 PetscInt i; 339 SNES_NASM *nasm = (SNES_NASM *)snes->data; 340 341 PetscFunctionBegin; 342 PetscCheck(!snes->setupcalled, PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_WRONGSTATE, "SNESNASMSetSubdomains() should be called before calling SNESSetUp()."); 343 344 /* tear down the previously set things */ 345 PetscCall(SNESReset(snes)); 346 347 nasm->n = n; 348 if (oscatter) { 349 for (i = 0; i < n; i++) PetscCall(PetscObjectReference((PetscObject)oscatter[i])); 350 } 351 if (iscatter) { 352 for (i = 0; i < n; i++) PetscCall(PetscObjectReference((PetscObject)iscatter[i])); 353 } 354 if (gscatter) { 355 for (i = 0; i < n; i++) PetscCall(PetscObjectReference((PetscObject)gscatter[i])); 356 } 357 if (oscatter) { 358 PetscCall(PetscMalloc1(n, &nasm->oscatter)); 359 PetscCall(PetscMalloc1(n, &nasm->oscatter_copy)); 360 for (i = 0; i < n; i++) { 361 nasm->oscatter[i] = oscatter[i]; 362 PetscCall(VecScatterCopy(oscatter[i], &nasm->oscatter_copy[i])); 363 } 364 } 365 if (iscatter) { 366 PetscCall(PetscMalloc1(n, &nasm->iscatter)); 367 for (i = 0; i < n; i++) nasm->iscatter[i] = iscatter[i]; 368 } 369 if (gscatter) { 370 PetscCall(PetscMalloc1(n, &nasm->gscatter)); 371 for (i = 0; i < n; i++) nasm->gscatter[i] = gscatter[i]; 372 } 373 374 if (subsnes) { 375 PetscCall(PetscMalloc1(n, &nasm->subsnes)); 376 for (i = 0; i < n; i++) nasm->subsnes[i] = subsnes[i]; 377 } 378 PetscFunctionReturn(0); 379 } 380 381 /*@ 382 SNESNASMGetSubdomains - Get the local subdomain context. 383 384 Not Collective 385 386 Input Parameter: 387 . SNES - the SNES context 388 389 Output Parameters: 390 + n - the number of local subdomains 391 . subsnes - solvers defined on the local subdomains 392 . iscatter - scatters into the nonoverlapping portions of the local subdomains 393 . oscatter - scatters into the overlapping portions of the local subdomains 394 - gscatter - scatters into the (ghosted) local vector of the local subdomain 395 396 Level: intermediate 397 398 .seealso: `SNESNASM`, `SNESNASMSetSubdomains()` 399 @*/ 400 PetscErrorCode SNESNASMGetSubdomains(SNES snes, PetscInt *n, SNES *subsnes[], VecScatter *iscatter[], VecScatter *oscatter[], VecScatter *gscatter[]) { 401 PetscErrorCode (*f)(SNES, PetscInt *, SNES **, VecScatter **, VecScatter **, VecScatter **); 402 403 PetscFunctionBegin; 404 PetscCall(PetscObjectQueryFunction((PetscObject)snes, "SNESNASMGetSubdomains_C", &f)); 405 if (f) PetscCall((f)(snes, n, subsnes, iscatter, oscatter, gscatter)); 406 PetscFunctionReturn(0); 407 } 408 409 static PetscErrorCode SNESNASMGetSubdomains_NASM(SNES snes, PetscInt *n, SNES *subsnes[], VecScatter *iscatter[], VecScatter *oscatter[], VecScatter *gscatter[]) { 410 SNES_NASM *nasm = (SNES_NASM *)snes->data; 411 412 PetscFunctionBegin; 413 if (n) *n = nasm->n; 414 if (oscatter) *oscatter = nasm->oscatter; 415 if (iscatter) *iscatter = nasm->iscatter; 416 if (gscatter) *gscatter = nasm->gscatter; 417 if (subsnes) *subsnes = nasm->subsnes; 418 PetscFunctionReturn(0); 419 } 420 421 /*@ 422 SNESNASMGetSubdomainVecs - Get the processor-local subdomain vectors 423 424 Not Collective 425 426 Input Parameter: 427 . SNES - the SNES context 428 429 Output Parameters: 430 + n - the number of local subdomains 431 . x - The subdomain solution vector 432 . y - The subdomain step vector 433 . b - The subdomain RHS vector 434 - xl - The subdomain local vectors (ghosted) 435 436 Level: developer 437 438 .seealso: `SNESNASM`, `SNESNASMGetSubdomains()` 439 @*/ 440 PetscErrorCode SNESNASMGetSubdomainVecs(SNES snes, PetscInt *n, Vec **x, Vec **y, Vec **b, Vec **xl) { 441 PetscErrorCode (*f)(SNES, PetscInt *, Vec **, Vec **, Vec **, Vec **); 442 443 PetscFunctionBegin; 444 PetscCall(PetscObjectQueryFunction((PetscObject)snes, "SNESNASMGetSubdomainVecs_C", &f)); 445 if (f) PetscCall((f)(snes, n, x, y, b, xl)); 446 PetscFunctionReturn(0); 447 } 448 449 static PetscErrorCode SNESNASMGetSubdomainVecs_NASM(SNES snes, PetscInt *n, Vec **x, Vec **y, Vec **b, Vec **xl) { 450 SNES_NASM *nasm = (SNES_NASM *)snes->data; 451 452 PetscFunctionBegin; 453 if (n) *n = nasm->n; 454 if (x) *x = nasm->x; 455 if (y) *y = nasm->y; 456 if (b) *b = nasm->b; 457 if (xl) *xl = nasm->xl; 458 PetscFunctionReturn(0); 459 } 460 461 /*@ 462 SNESNASMSetComputeFinalJacobian - Schedules the computation of the global and subdomain Jacobians upon convergence 463 464 Collective on SNES 465 466 Input Parameters: 467 + SNES - the SNES context 468 - flg - indication of whether to compute the Jacobians or not 469 470 Level: developer 471 472 Notes: 473 This is used almost exclusively in the implementation of ASPIN, where the converged subdomain and global Jacobian 474 is needed at each linear iteration. 475 476 .seealso: `SNESNASM`, `SNESNASMGetSubdomains()` 477 @*/ 478 PetscErrorCode SNESNASMSetComputeFinalJacobian(SNES snes, PetscBool flg) { 479 PetscErrorCode (*f)(SNES, PetscBool); 480 481 PetscFunctionBegin; 482 PetscCall(PetscObjectQueryFunction((PetscObject)snes, "SNESNASMSetComputeFinalJacobian_C", &f)); 483 if (f) PetscCall((f)(snes, flg)); 484 PetscFunctionReturn(0); 485 } 486 487 static PetscErrorCode SNESNASMSetComputeFinalJacobian_NASM(SNES snes, PetscBool flg) { 488 SNES_NASM *nasm = (SNES_NASM *)snes->data; 489 490 PetscFunctionBegin; 491 nasm->finaljacobian = flg; 492 PetscFunctionReturn(0); 493 } 494 495 /*@ 496 SNESNASMSetDamping - Sets the update damping for NASM 497 498 Logically collective on SNES 499 500 Input Parameters: 501 + SNES - the SNES context 502 - dmp - damping 503 504 Level: intermediate 505 506 Notes: 507 The new solution is obtained as old solution plus dmp times (sum of the solutions on the subdomains) 508 509 .seealso: `SNESNASM`, `SNESNASMGetDamping()` 510 @*/ 511 PetscErrorCode SNESNASMSetDamping(SNES snes, PetscReal dmp) { 512 PetscErrorCode (*f)(SNES, PetscReal); 513 514 PetscFunctionBegin; 515 PetscCall(PetscObjectQueryFunction((PetscObject)snes, "SNESNASMSetDamping_C", (void (**)(void)) & f)); 516 if (f) PetscCall((f)(snes, dmp)); 517 PetscFunctionReturn(0); 518 } 519 520 static PetscErrorCode SNESNASMSetDamping_NASM(SNES snes, PetscReal dmp) { 521 SNES_NASM *nasm = (SNES_NASM *)snes->data; 522 523 PetscFunctionBegin; 524 nasm->damping = dmp; 525 PetscFunctionReturn(0); 526 } 527 528 /*@ 529 SNESNASMGetDamping - Gets the update damping for NASM 530 531 Not Collective 532 533 Input Parameters: 534 + SNES - the SNES context 535 - dmp - damping 536 537 Level: intermediate 538 539 .seealso: `SNESNASM`, `SNESNASMSetDamping()` 540 @*/ 541 PetscErrorCode SNESNASMGetDamping(SNES snes, PetscReal *dmp) { 542 PetscFunctionBegin; 543 PetscUseMethod(snes, "SNESNASMGetDamping_C", (SNES, PetscReal *), (snes, dmp)); 544 PetscFunctionReturn(0); 545 } 546 547 static PetscErrorCode SNESNASMGetDamping_NASM(SNES snes, PetscReal *dmp) { 548 SNES_NASM *nasm = (SNES_NASM *)snes->data; 549 550 PetscFunctionBegin; 551 *dmp = nasm->damping; 552 PetscFunctionReturn(0); 553 } 554 555 /* 556 Input Parameters: 557 + snes - The solver 558 . B - The RHS vector 559 - X - The initial guess 560 561 Output Parameters: 562 . Y - The solution update 563 564 TODO: All scatters should be packed into one 565 */ 566 PetscErrorCode SNESNASMSolveLocal_Private(SNES snes, Vec B, Vec Y, Vec X) { 567 SNES_NASM *nasm = (SNES_NASM *)snes->data; 568 SNES subsnes; 569 PetscInt i; 570 PetscReal dmp; 571 Vec Xl, Bl, Yl, Xlloc; 572 VecScatter iscat, oscat, gscat, oscat_copy; 573 DM dm, subdm; 574 PCASMType type; 575 576 PetscFunctionBegin; 577 PetscCall(SNESNASMGetType(snes, &type)); 578 PetscCall(SNESGetDM(snes, &dm)); 579 PetscCall(VecSet(Y, 0)); 580 if (nasm->eventrestrictinterp) PetscCall(PetscLogEventBegin(nasm->eventrestrictinterp, snes, 0, 0, 0)); 581 for (i = 0; i < nasm->n; i++) { 582 /* scatter the solution to the global solution and the local solution */ 583 Xl = nasm->x[i]; 584 Xlloc = nasm->xl[i]; 585 oscat = nasm->oscatter[i]; 586 oscat_copy = nasm->oscatter_copy[i]; 587 gscat = nasm->gscatter[i]; 588 PetscCall(VecScatterBegin(oscat, X, Xl, INSERT_VALUES, SCATTER_FORWARD)); 589 PetscCall(VecScatterBegin(gscat, X, Xlloc, INSERT_VALUES, SCATTER_FORWARD)); 590 if (B) { 591 /* scatter the RHS to the local RHS */ 592 Bl = nasm->b[i]; 593 PetscCall(VecScatterBegin(oscat_copy, B, Bl, INSERT_VALUES, SCATTER_FORWARD)); 594 } 595 } 596 if (nasm->eventrestrictinterp) PetscCall(PetscLogEventEnd(nasm->eventrestrictinterp, snes, 0, 0, 0)); 597 598 if (nasm->eventsubsolve) PetscCall(PetscLogEventBegin(nasm->eventsubsolve, snes, 0, 0, 0)); 599 for (i = 0; i < nasm->n; i++) { 600 Xl = nasm->x[i]; 601 Xlloc = nasm->xl[i]; 602 Yl = nasm->y[i]; 603 subsnes = nasm->subsnes[i]; 604 PetscCall(SNESGetDM(subsnes, &subdm)); 605 iscat = nasm->iscatter[i]; 606 oscat = nasm->oscatter[i]; 607 oscat_copy = nasm->oscatter_copy[i]; 608 gscat = nasm->gscatter[i]; 609 PetscCall(VecScatterEnd(oscat, X, Xl, INSERT_VALUES, SCATTER_FORWARD)); 610 PetscCall(VecScatterEnd(gscat, X, Xlloc, INSERT_VALUES, SCATTER_FORWARD)); 611 if (B) { 612 Bl = nasm->b[i]; 613 PetscCall(VecScatterEnd(oscat_copy, B, Bl, INSERT_VALUES, SCATTER_FORWARD)); 614 } else Bl = NULL; 615 616 PetscCall(DMSubDomainRestrict(dm, oscat, gscat, subdm)); 617 PetscCall(VecCopy(Xl, Yl)); 618 PetscCall(SNESSolve(subsnes, Bl, Xl)); 619 PetscCall(VecAYPX(Yl, -1.0, Xl)); 620 PetscCall(VecScale(Yl, nasm->damping)); 621 if (type == PC_ASM_BASIC) { 622 PetscCall(VecScatterBegin(oscat, Yl, Y, ADD_VALUES, SCATTER_REVERSE)); 623 PetscCall(VecScatterEnd(oscat, Yl, Y, ADD_VALUES, SCATTER_REVERSE)); 624 } else if (type == PC_ASM_RESTRICT) { 625 PetscCall(VecScatterBegin(iscat, Yl, Y, ADD_VALUES, SCATTER_REVERSE)); 626 PetscCall(VecScatterEnd(iscat, Yl, Y, ADD_VALUES, SCATTER_REVERSE)); 627 } else SETERRQ(PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_WRONGSTATE, "Only basic and restrict types are supported for SNESNASM"); 628 } 629 if (nasm->eventsubsolve) PetscCall(PetscLogEventEnd(nasm->eventsubsolve, snes, 0, 0, 0)); 630 if (nasm->eventrestrictinterp) PetscCall(PetscLogEventBegin(nasm->eventrestrictinterp, snes, 0, 0, 0)); 631 if (nasm->weight_set) PetscCall(VecPointwiseMult(Y, Y, nasm->weight)); 632 if (nasm->eventrestrictinterp) PetscCall(PetscLogEventEnd(nasm->eventrestrictinterp, snes, 0, 0, 0)); 633 PetscCall(SNESNASMGetDamping(snes, &dmp)); 634 PetscCall(VecAXPY(X, dmp, Y)); 635 PetscFunctionReturn(0); 636 } 637 638 static PetscErrorCode SNESNASMComputeFinalJacobian_Private(SNES snes, Vec Xfinal) { 639 Vec X = Xfinal; 640 SNES_NASM *nasm = (SNES_NASM *)snes->data; 641 SNES subsnes; 642 PetscInt i, lag = 1; 643 Vec Xlloc, Xl, Fl, F; 644 VecScatter oscat, gscat; 645 DM dm, subdm; 646 647 PetscFunctionBegin; 648 if (nasm->fjtype == 2) X = nasm->xinit; 649 F = snes->vec_func; 650 if (snes->normschedule == SNES_NORM_NONE) PetscCall(SNESComputeFunction(snes, X, F)); 651 PetscCall(SNESComputeJacobian(snes, X, snes->jacobian, snes->jacobian_pre)); 652 PetscCall(SNESGetDM(snes, &dm)); 653 if (nasm->eventrestrictinterp) PetscCall(PetscLogEventBegin(nasm->eventrestrictinterp, snes, 0, 0, 0)); 654 if (nasm->fjtype != 1) { 655 for (i = 0; i < nasm->n; i++) { 656 Xlloc = nasm->xl[i]; 657 gscat = nasm->gscatter[i]; 658 PetscCall(VecScatterBegin(gscat, X, Xlloc, INSERT_VALUES, SCATTER_FORWARD)); 659 } 660 } 661 if (nasm->eventrestrictinterp) PetscCall(PetscLogEventEnd(nasm->eventrestrictinterp, snes, 0, 0, 0)); 662 for (i = 0; i < nasm->n; i++) { 663 Fl = nasm->subsnes[i]->vec_func; 664 Xl = nasm->x[i]; 665 Xlloc = nasm->xl[i]; 666 subsnes = nasm->subsnes[i]; 667 oscat = nasm->oscatter[i]; 668 gscat = nasm->gscatter[i]; 669 if (nasm->fjtype != 1) PetscCall(VecScatterEnd(gscat, X, Xlloc, INSERT_VALUES, SCATTER_FORWARD)); 670 PetscCall(SNESGetDM(subsnes, &subdm)); 671 PetscCall(DMSubDomainRestrict(dm, oscat, gscat, subdm)); 672 if (nasm->fjtype != 1) { 673 PetscCall(DMLocalToGlobalBegin(subdm, Xlloc, INSERT_VALUES, Xl)); 674 PetscCall(DMLocalToGlobalEnd(subdm, Xlloc, INSERT_VALUES, Xl)); 675 } 676 if (subsnes->lagjacobian == -1) subsnes->lagjacobian = -2; 677 else if (subsnes->lagjacobian > 1) lag = subsnes->lagjacobian; 678 PetscCall(SNESComputeFunction(subsnes, Xl, Fl)); 679 PetscCall(SNESComputeJacobian(subsnes, Xl, subsnes->jacobian, subsnes->jacobian_pre)); 680 if (lag > 1) subsnes->lagjacobian = lag; 681 } 682 PetscFunctionReturn(0); 683 } 684 685 static PetscErrorCode SNESSolve_NASM(SNES snes) { 686 Vec F; 687 Vec X; 688 Vec B; 689 Vec Y; 690 PetscInt i; 691 PetscReal fnorm = 0.0; 692 SNESNormSchedule normschedule; 693 SNES_NASM *nasm = (SNES_NASM *)snes->data; 694 695 PetscFunctionBegin; 696 697 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); 698 699 PetscCall(PetscCitationsRegister(SNESCitation, &SNEScite)); 700 X = snes->vec_sol; 701 Y = snes->vec_sol_update; 702 F = snes->vec_func; 703 B = snes->vec_rhs; 704 705 PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes)); 706 snes->iter = 0; 707 snes->norm = 0.; 708 PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes)); 709 snes->reason = SNES_CONVERGED_ITERATING; 710 PetscCall(SNESGetNormSchedule(snes, &normschedule)); 711 if (normschedule == SNES_NORM_ALWAYS || normschedule == SNES_NORM_INITIAL_ONLY || normschedule == SNES_NORM_INITIAL_FINAL_ONLY) { 712 /* compute the initial function and preconditioned update delX */ 713 if (!snes->vec_func_init_set) { 714 PetscCall(SNESComputeFunction(snes, X, F)); 715 } else snes->vec_func_init_set = PETSC_FALSE; 716 717 PetscCall(VecNorm(F, NORM_2, &fnorm)); /* fnorm <- ||F|| */ 718 SNESCheckFunctionNorm(snes, fnorm); 719 PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes)); 720 snes->iter = 0; 721 snes->norm = fnorm; 722 PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes)); 723 PetscCall(SNESLogConvergenceHistory(snes, snes->norm, 0)); 724 PetscCall(SNESMonitor(snes, 0, snes->norm)); 725 726 /* test convergence */ 727 PetscUseTypeMethod(snes, converged, 0, 0.0, 0.0, fnorm, &snes->reason, snes->cnvP); 728 if (snes->reason) PetscFunctionReturn(0); 729 } else { 730 PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes)); 731 PetscCall(SNESLogConvergenceHistory(snes, snes->norm, 0)); 732 PetscCall(SNESMonitor(snes, 0, snes->norm)); 733 } 734 735 /* Call general purpose update function */ 736 PetscTryTypeMethod(snes, update, snes->iter); 737 /* copy the initial solution over for later */ 738 if (nasm->fjtype == 2) PetscCall(VecCopy(X, nasm->xinit)); 739 740 for (i = 0; i < snes->max_its; i++) { 741 PetscCall(SNESNASMSolveLocal_Private(snes, B, Y, X)); 742 if (normschedule == SNES_NORM_ALWAYS || ((i == snes->max_its - 1) && (normschedule == SNES_NORM_INITIAL_FINAL_ONLY || normschedule == SNES_NORM_FINAL_ONLY))) { 743 PetscCall(SNESComputeFunction(snes, X, F)); 744 PetscCall(VecNorm(F, NORM_2, &fnorm)); /* fnorm <- ||F|| */ 745 SNESCheckFunctionNorm(snes, fnorm); 746 } 747 /* Monitor convergence */ 748 PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes)); 749 snes->iter = i + 1; 750 snes->norm = fnorm; 751 PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes)); 752 PetscCall(SNESLogConvergenceHistory(snes, snes->norm, 0)); 753 PetscCall(SNESMonitor(snes, snes->iter, snes->norm)); 754 /* Test for convergence */ 755 if (normschedule == SNES_NORM_ALWAYS) PetscUseTypeMethod(snes, converged, snes->iter, 0.0, 0.0, fnorm, &snes->reason, snes->cnvP); 756 if (snes->reason) break; 757 /* Call general purpose update function */ 758 PetscTryTypeMethod(snes, update, snes->iter); 759 } 760 if (nasm->finaljacobian) { 761 PetscCall(SNESNASMComputeFinalJacobian_Private(snes, X)); 762 SNESCheckJacobianDomainerror(snes); 763 } 764 if (normschedule == SNES_NORM_ALWAYS) { 765 if (i == snes->max_its) { 766 PetscCall(PetscInfo(snes, "Maximum number of iterations has been reached: %" PetscInt_FMT "\n", snes->max_its)); 767 if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT; 768 } 769 } else if (!snes->reason) snes->reason = SNES_CONVERGED_ITS; /* NASM is meant to be used as a preconditioner */ 770 PetscFunctionReturn(0); 771 } 772 773 /*MC 774 SNESNASM - Nonlinear Additive Schwarz 775 776 Options Database: 777 + -snes_nasm_log - enable logging events for the communication and solve stages 778 . -snes_nasm_type <basic,restrict> - type of subdomain update used 779 . -snes_asm_damping <dmp> - the new solution is obtained as old solution plus dmp times (sum of the solutions on the subdomains) 780 . -snes_nasm_finaljacobian - compute the local and global jacobians of the final iterate 781 . -snes_nasm_finaljacobian_type <finalinner,finalouter,initial> - pick state the jacobian is calculated at 782 . -sub_snes_ - options prefix of the subdomain nonlinear solves 783 . -sub_ksp_ - options prefix of the subdomain Krylov solver 784 - -sub_pc_ - options prefix of the subdomain preconditioner 785 786 Level: advanced 787 788 Developer Note: This is a non-Newton based nonlinear solver that does not directly require a Jacobian; hence the flag snes->usesksp is set to 789 false and SNESView() and -snes_view do not display a KSP object. However, if the flag nasm->finaljacobian is set (for example, if 790 NASM is used as a nonlinear preconditioner for KSPASPIN) then SNESSetUpMatrices() is called to generate the Jacobian (needed by KSPASPIN) 791 and this utilizes the KSP for storing the matrices, but the KSP is never used for solving a linear system. Note that when SNESNASM is 792 used by SNESASPIN they share the same Jacobian matrices because SNESSetUp() (called on the outer SNES KSPASPIN) causes the inner SNES 793 object (in this case SNESNASM) to inherit the outer Jacobian matrices. 794 795 References: 796 . * - Peter R. Brune, Matthew G. Knepley, Barry F. Smith, and Xuemin Tu, "Composing Scalable Nonlinear Algebraic Solvers", 797 SIAM Review, 57(4), 2015 798 799 .seealso: `SNESCreate()`, `SNES`, `SNESSetType()`, `SNESType`, `SNESNASMSetType()`, `SNESNASMGetType()`, `SNESNASMSetSubdomains()`, `SNESNASMGetSubdomains()`, `SNESNASMGetSubdomainVecs()`, `SNESNASMSetComputeFinalJacobian()`, `SNESNASMSetDamping()`, `SNESNASMGetDamping()` 800 M*/ 801 802 PETSC_EXTERN PetscErrorCode SNESCreate_NASM(SNES snes) { 803 SNES_NASM *nasm; 804 805 PetscFunctionBegin; 806 PetscCall(PetscNewLog(snes, &nasm)); 807 snes->data = (void *)nasm; 808 809 nasm->n = PETSC_DECIDE; 810 nasm->subsnes = NULL; 811 nasm->x = NULL; 812 nasm->xl = NULL; 813 nasm->y = NULL; 814 nasm->b = NULL; 815 nasm->oscatter = NULL; 816 nasm->oscatter_copy = NULL; 817 nasm->iscatter = NULL; 818 nasm->gscatter = NULL; 819 nasm->damping = 1.; 820 821 nasm->type = PC_ASM_BASIC; 822 nasm->finaljacobian = PETSC_FALSE; 823 nasm->weight_set = PETSC_FALSE; 824 825 snes->ops->destroy = SNESDestroy_NASM; 826 snes->ops->setup = SNESSetUp_NASM; 827 snes->ops->setfromoptions = SNESSetFromOptions_NASM; 828 snes->ops->view = SNESView_NASM; 829 snes->ops->solve = SNESSolve_NASM; 830 snes->ops->reset = SNESReset_NASM; 831 832 snes->usesksp = PETSC_FALSE; 833 snes->usesnpc = PETSC_FALSE; 834 835 snes->alwayscomputesfinalresidual = PETSC_FALSE; 836 837 nasm->fjtype = 0; 838 nasm->xinit = NULL; 839 nasm->eventrestrictinterp = 0; 840 nasm->eventsubsolve = 0; 841 842 if (!snes->tolerancesset) { 843 snes->max_its = 10000; 844 snes->max_funcs = 10000; 845 } 846 847 PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNASMSetType_C", SNESNASMSetType_NASM)); 848 PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNASMGetType_C", SNESNASMGetType_NASM)); 849 PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNASMSetSubdomains_C", SNESNASMSetSubdomains_NASM)); 850 PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNASMGetSubdomains_C", SNESNASMGetSubdomains_NASM)); 851 PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNASMSetDamping_C", SNESNASMSetDamping_NASM)); 852 PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNASMGetDamping_C", SNESNASMGetDamping_NASM)); 853 PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNASMGetSubdomainVecs_C", SNESNASMGetSubdomainVecs_NASM)); 854 PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNASMSetComputeFinalJacobian_C", SNESNASMSetComputeFinalJacobian_NASM)); 855 PetscFunctionReturn(0); 856 } 857 858 /*@ 859 SNESNASMGetSNES - Gets a subsolver 860 861 Not collective 862 863 Input Parameters: 864 + snes - the SNES context 865 - i - the number of the subsnes to get 866 867 Output Parameters: 868 . subsnes - the subsolver context 869 870 Level: intermediate 871 872 .seealso: `SNESNASM`, `SNESNASMGetNumber()` 873 @*/ 874 PetscErrorCode SNESNASMGetSNES(SNES snes, PetscInt i, SNES *subsnes) { 875 SNES_NASM *nasm = (SNES_NASM *)snes->data; 876 877 PetscFunctionBegin; 878 PetscCheck(i >= 0 && i < nasm->n, PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_OUTOFRANGE, "No such subsolver"); 879 *subsnes = nasm->subsnes[i]; 880 PetscFunctionReturn(0); 881 } 882 883 /*@ 884 SNESNASMGetNumber - Gets number of subsolvers 885 886 Not collective 887 888 Input Parameters: 889 . snes - the SNES context 890 891 Output Parameters: 892 . n - the number of subsolvers 893 894 Level: intermediate 895 896 .seealso: `SNESNASM`, `SNESNASMGetSNES()` 897 @*/ 898 PetscErrorCode SNESNASMGetNumber(SNES snes, PetscInt *n) { 899 SNES_NASM *nasm = (SNES_NASM *)snes->data; 900 901 PetscFunctionBegin; 902 *n = nasm->n; 903 PetscFunctionReturn(0); 904 } 905 906 /*@ 907 SNESNASMSetWeight - Sets weight to use when adding overlapping updates 908 909 Collective 910 911 Input Parameters: 912 + snes - the SNES context 913 - weight - the weights to use (typically 1/N for each dof, where N is the number of patches it appears in) 914 915 Level: intermediate 916 917 .seealso: `SNESNASM` 918 @*/ 919 PetscErrorCode SNESNASMSetWeight(SNES snes, Vec weight) { 920 SNES_NASM *nasm = (SNES_NASM *)snes->data; 921 922 PetscFunctionBegin; 923 924 PetscCall(VecDestroy(&nasm->weight)); 925 nasm->weight_set = PETSC_TRUE; 926 nasm->weight = weight; 927 PetscCall(PetscObjectReference((PetscObject)nasm->weight)); 928 929 PetscFunctionReturn(0); 930 } 931