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