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