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 VecScatter *oscatter; /* scatter from global space to the subdomain global space */ 12 VecScatter *iscatter; /* scatter from global space to the nonoverlapping subdomain space */ 13 VecScatter *gscatter; /* scatter from global space to the subdomain local space */ 14 PCASMType type; /* ASM type */ 15 PetscBool usesdm; /* use the DM for setting up the subproblems */ 16 PetscBool finaljacobian; /* compute the jacobian of the converged solution */ 17 PetscReal damping; /* damping parameter for updates from the blocks */ 18 PetscBool same_local_solves; /* flag to determine if the solvers have been individually modified */ 19 20 /* logging events */ 21 PetscLogEvent eventrestrictinterp; 22 PetscLogEvent eventsubsolve; 23 24 PetscInt fjtype; /* type of computed jacobian */ 25 Vec xinit; /* initial solution in case the final jacobian type is computed as first */ 26 } SNES_NASM; 27 28 const char *const SNESNASMTypes[] = {"NONE","RESTRICT","INTERPOLATE","BASIC","PCASMType","PC_ASM_",0}; 29 const char *const SNESNASMFJTypes[] = {"FINALOUTER","FINALINNER","INITIAL"}; 30 31 static PetscErrorCode SNESReset_NASM(SNES snes) 32 { 33 SNES_NASM *nasm = (SNES_NASM*)snes->data; 34 PetscErrorCode ierr; 35 PetscInt i; 36 37 PetscFunctionBegin; 38 for (i=0; i<nasm->n; i++) { 39 if (nasm->xl) { ierr = VecDestroy(&nasm->xl[i]);CHKERRQ(ierr); } 40 if (nasm->x) { ierr = VecDestroy(&nasm->x[i]);CHKERRQ(ierr); } 41 if (nasm->y) { ierr = VecDestroy(&nasm->y[i]);CHKERRQ(ierr); } 42 if (nasm->b) { ierr = VecDestroy(&nasm->b[i]);CHKERRQ(ierr); } 43 44 if (nasm->subsnes) { ierr = SNESDestroy(&nasm->subsnes[i]);CHKERRQ(ierr); } 45 if (nasm->oscatter) { ierr = VecScatterDestroy(&nasm->oscatter[i]);CHKERRQ(ierr); } 46 if (nasm->iscatter) { ierr = VecScatterDestroy(&nasm->iscatter[i]);CHKERRQ(ierr); } 47 if (nasm->gscatter) { ierr = VecScatterDestroy(&nasm->gscatter[i]);CHKERRQ(ierr); } 48 } 49 50 ierr = PetscFree(nasm->x);CHKERRQ(ierr); 51 ierr = PetscFree(nasm->xl);CHKERRQ(ierr); 52 ierr = PetscFree(nasm->y);CHKERRQ(ierr); 53 ierr = PetscFree(nasm->b);CHKERRQ(ierr); 54 55 if (nasm->xinit) {ierr = VecDestroy(&nasm->xinit);CHKERRQ(ierr);} 56 57 ierr = PetscFree(nasm->subsnes);CHKERRQ(ierr); 58 ierr = PetscFree(nasm->oscatter);CHKERRQ(ierr); 59 ierr = PetscFree(nasm->iscatter);CHKERRQ(ierr); 60 ierr = PetscFree(nasm->gscatter);CHKERRQ(ierr); 61 62 nasm->eventrestrictinterp = 0; 63 nasm->eventsubsolve = 0; 64 PetscFunctionReturn(0); 65 } 66 67 static PetscErrorCode SNESDestroy_NASM(SNES snes) 68 { 69 PetscErrorCode ierr; 70 71 PetscFunctionBegin; 72 ierr = SNESReset_NASM(snes);CHKERRQ(ierr); 73 ierr = PetscFree(snes->data);CHKERRQ(ierr); 74 PetscFunctionReturn(0); 75 } 76 77 static PetscErrorCode DMGlobalToLocalSubDomainDirichletHook_Private(DM dm,Vec g,InsertMode mode,Vec l,void *ctx) 78 { 79 PetscErrorCode ierr; 80 Vec bcs = (Vec)ctx; 81 82 PetscFunctionBegin; 83 ierr = VecCopy(bcs,l);CHKERRQ(ierr); 84 PetscFunctionReturn(0); 85 } 86 87 static PetscErrorCode SNESSetUp_NASM(SNES snes) 88 { 89 SNES_NASM *nasm = (SNES_NASM*)snes->data; 90 PetscErrorCode ierr; 91 DM dm,subdm; 92 DM *subdms; 93 PetscInt i; 94 const char *optionsprefix; 95 Vec F; 96 PetscMPIInt size; 97 KSP ksp; 98 PC pc; 99 100 PetscFunctionBegin; 101 if (!nasm->subsnes) { 102 ierr = SNESGetDM(snes,&dm);CHKERRQ(ierr); 103 if (dm) { 104 nasm->usesdm = PETSC_TRUE; 105 ierr = DMCreateDomainDecomposition(dm,&nasm->n,NULL,NULL,NULL,&subdms);CHKERRQ(ierr); 106 if (!subdms) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE,"DM has no default decomposition defined. Set subsolves manually with SNESNASMSetSubdomains()."); 107 ierr = DMCreateDomainDecompositionScatters(dm,nasm->n,subdms,&nasm->iscatter,&nasm->oscatter,&nasm->gscatter);CHKERRQ(ierr); 108 109 ierr = SNESGetOptionsPrefix(snes, &optionsprefix);CHKERRQ(ierr); 110 ierr = PetscMalloc1(nasm->n,&nasm->subsnes);CHKERRQ(ierr); 111 for (i=0; i<nasm->n; i++) { 112 ierr = SNESCreate(PETSC_COMM_SELF,&nasm->subsnes[i]);CHKERRQ(ierr); 113 ierr = SNESAppendOptionsPrefix(nasm->subsnes[i],optionsprefix);CHKERRQ(ierr); 114 ierr = SNESAppendOptionsPrefix(nasm->subsnes[i],"sub_");CHKERRQ(ierr); 115 ierr = SNESSetDM(nasm->subsnes[i],subdms[i]);CHKERRQ(ierr); 116 ierr = MPI_Comm_size(PetscObjectComm((PetscObject)nasm->subsnes[i]),&size);CHKERRQ(ierr); 117 if (size == 1) { 118 ierr = SNESGetKSP(nasm->subsnes[i],&ksp);CHKERRQ(ierr); 119 ierr = KSPGetPC(ksp,&pc);CHKERRQ(ierr); 120 ierr = KSPSetType(ksp,KSPPREONLY);CHKERRQ(ierr); 121 ierr = PCSetType(pc,PCLU);CHKERRQ(ierr); 122 } 123 ierr = SNESSetFromOptions(nasm->subsnes[i]);CHKERRQ(ierr); 124 ierr = DMDestroy(&subdms[i]);CHKERRQ(ierr); 125 } 126 ierr = PetscFree(subdms);CHKERRQ(ierr); 127 } else SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE,"Cannot construct local problems automatically without a DM!"); 128 } else SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE,"Must set subproblems manually if there is no DM!"); 129 /* allocate the global vectors */ 130 if (!nasm->x) { 131 ierr = PetscCalloc1(nasm->n,&nasm->x);CHKERRQ(ierr); 132 } 133 if (!nasm->xl) { 134 ierr = PetscCalloc1(nasm->n,&nasm->xl);CHKERRQ(ierr); 135 } 136 if (!nasm->y) { 137 ierr = PetscCalloc1(nasm->n,&nasm->y);CHKERRQ(ierr); 138 } 139 if (!nasm->b) { 140 ierr = PetscCalloc1(nasm->n,&nasm->b);CHKERRQ(ierr); 141 } 142 143 for (i=0; i<nasm->n; i++) { 144 ierr = SNESGetFunction(nasm->subsnes[i],&F,NULL,NULL);CHKERRQ(ierr); 145 if (!nasm->x[i]) {ierr = VecDuplicate(F,&nasm->x[i]);CHKERRQ(ierr);} 146 if (!nasm->y[i]) {ierr = VecDuplicate(F,&nasm->y[i]);CHKERRQ(ierr);} 147 if (!nasm->b[i]) {ierr = VecDuplicate(F,&nasm->b[i]);CHKERRQ(ierr);} 148 if (!nasm->xl[i]) { 149 ierr = SNESGetDM(nasm->subsnes[i],&subdm);CHKERRQ(ierr); 150 ierr = DMCreateLocalVector(subdm,&nasm->xl[i]);CHKERRQ(ierr); 151 ierr = DMGlobalToLocalHookAdd(subdm,DMGlobalToLocalSubDomainDirichletHook_Private,NULL,nasm->xl[i]);CHKERRQ(ierr); 152 } 153 } 154 if (nasm->finaljacobian) { 155 ierr = SNESSetUpMatrices(snes);CHKERRQ(ierr); 156 if (nasm->fjtype == 2) { 157 ierr = VecDuplicate(snes->vec_sol,&nasm->xinit);CHKERRQ(ierr); 158 } 159 for (i=0; i<nasm->n;i++) { 160 ierr = SNESSetUpMatrices(nasm->subsnes[i]);CHKERRQ(ierr); 161 } 162 } 163 PetscFunctionReturn(0); 164 } 165 166 static PetscErrorCode SNESSetFromOptions_NASM(PetscOptionItems *PetscOptionsObject,SNES snes) 167 { 168 PetscErrorCode ierr; 169 PCASMType asmtype; 170 PetscBool flg,monflg,subviewflg; 171 SNES_NASM *nasm = (SNES_NASM*)snes->data; 172 173 PetscFunctionBegin; 174 ierr = PetscOptionsHead(PetscOptionsObject,"Nonlinear Additive Schwartz options");CHKERRQ(ierr); 175 ierr = PetscOptionsEnum("-snes_nasm_type","Type of restriction/extension","",SNESNASMTypes,(PetscEnum)nasm->type,(PetscEnum*)&asmtype,&flg);CHKERRQ(ierr); 176 if (flg) {ierr = SNESNASMSetType(snes,asmtype);CHKERRQ(ierr);} 177 flg = PETSC_FALSE; 178 monflg = PETSC_TRUE; 179 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); 180 if (flg) {ierr = SNESNASMSetDamping(snes,nasm->damping);CHKERRQ(ierr);} 181 subviewflg = PETSC_FALSE; 182 ierr = PetscOptionsBool("-snes_nasm_sub_view","Print detailed information for every processor when using -snes_view","",subviewflg,&subviewflg,&flg);CHKERRQ(ierr); 183 if (flg) { 184 nasm->same_local_solves = PETSC_FALSE; 185 if (!subviewflg) { 186 nasm->same_local_solves = PETSC_TRUE; 187 } 188 } 189 ierr = PetscOptionsBool("-snes_nasm_finaljacobian","Compute the global jacobian of the final iterate (for ASPIN)","",nasm->finaljacobian,&nasm->finaljacobian,NULL);CHKERRQ(ierr); 190 ierr = PetscOptionsEList("-snes_nasm_finaljacobian_type","The type of the final jacobian computed.","",SNESNASMFJTypes,3,SNESNASMFJTypes[0],&nasm->fjtype,NULL);CHKERRQ(ierr); 191 ierr = PetscOptionsBool("-snes_nasm_log","Log times for subSNES solves and restriction","",monflg,&monflg,&flg);CHKERRQ(ierr); 192 if (flg) { 193 ierr = PetscLogEventRegister("SNESNASMSubSolve",((PetscObject)snes)->classid,&nasm->eventsubsolve);CHKERRQ(ierr); 194 ierr = PetscLogEventRegister("SNESNASMRestrict",((PetscObject)snes)->classid,&nasm->eventrestrictinterp);CHKERRQ(ierr); 195 } 196 ierr = PetscOptionsTail();CHKERRQ(ierr); 197 PetscFunctionReturn(0); 198 } 199 200 static PetscErrorCode SNESView_NASM(SNES snes, PetscViewer viewer) 201 { 202 SNES_NASM *nasm = (SNES_NASM*)snes->data; 203 PetscErrorCode ierr; 204 PetscMPIInt rank,size; 205 PetscInt i,N,bsz; 206 PetscBool iascii,isstring; 207 PetscViewer sviewer; 208 MPI_Comm comm; 209 210 PetscFunctionBegin; 211 ierr = PetscObjectGetComm((PetscObject)snes,&comm);CHKERRQ(ierr); 212 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr); 213 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERSTRING,&isstring);CHKERRQ(ierr); 214 ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr); 215 ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr); 216 ierr = MPIU_Allreduce(&nasm->n,&N,1,MPIU_INT,MPI_SUM,comm);CHKERRQ(ierr); 217 if (iascii) { 218 ierr = PetscViewerASCIIPrintf(viewer, " Nonlinear Additive Schwarz: total subdomain blocks = %D\n",N);CHKERRQ(ierr); 219 if (nasm->same_local_solves) { 220 if (nasm->subsnes) { 221 ierr = PetscViewerASCIIPrintf(viewer," Local solve is the same for all blocks:\n");CHKERRQ(ierr); 222 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 223 ierr = PetscViewerGetSubViewer(viewer,PETSC_COMM_SELF,&sviewer);CHKERRQ(ierr); 224 if (!rank) { 225 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 226 ierr = SNESView(nasm->subsnes[0],sviewer);CHKERRQ(ierr); 227 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 228 } 229 ierr = PetscViewerRestoreSubViewer(viewer,PETSC_COMM_SELF,&sviewer);CHKERRQ(ierr); 230 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 231 } 232 } else { 233 /* print the solver on each block */ 234 ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr); 235 ierr = PetscViewerASCIISynchronizedPrintf(viewer," [%d] number of local blocks = %D\n",(int)rank,nasm->n);CHKERRQ(ierr); 236 ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 237 ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr); 238 ierr = PetscViewerASCIIPrintf(viewer," Local solve info for each block is in the following SNES objects:\n");CHKERRQ(ierr); 239 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 240 ierr = PetscViewerASCIIPrintf(viewer,"- - - - - - - - - - - - - - - - - -\n");CHKERRQ(ierr); 241 ierr = PetscViewerGetSubViewer(viewer,PETSC_COMM_SELF,&sviewer);CHKERRQ(ierr); 242 for (i=0; i<nasm->n; i++) { 243 ierr = VecGetLocalSize(nasm->x[i],&bsz);CHKERRQ(ierr); 244 ierr = PetscViewerASCIIPrintf(sviewer,"[%d] local block number %D, size = %D\n",(int)rank,i,bsz);CHKERRQ(ierr); 245 ierr = SNESView(nasm->subsnes[i],sviewer);CHKERRQ(ierr); 246 ierr = PetscViewerASCIIPrintf(sviewer,"- - - - - - - - - - - - - - - - - -\n");CHKERRQ(ierr); 247 } 248 ierr = PetscViewerRestoreSubViewer(viewer,PETSC_COMM_SELF,&sviewer);CHKERRQ(ierr); 249 ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 250 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 251 } 252 } else if (isstring) { 253 ierr = PetscViewerStringSPrintf(viewer," blocks=%D,type=%s",N,SNESNASMTypes[nasm->type]);CHKERRQ(ierr); 254 ierr = PetscViewerGetSubViewer(viewer,PETSC_COMM_SELF,&sviewer);CHKERRQ(ierr); 255 if (nasm->subsnes && !rank) {ierr = SNESView(nasm->subsnes[0],sviewer);CHKERRQ(ierr);} 256 ierr = PetscViewerRestoreSubViewer(viewer,PETSC_COMM_SELF,&sviewer);CHKERRQ(ierr); 257 } 258 PetscFunctionReturn(0); 259 } 260 261 /*@ 262 SNESNASMSetType - Set the type of subdomain update used 263 264 Logically Collective on SNES 265 266 Input Parameters: 267 + SNES - the SNES context 268 - type - the type of update, PC_ASM_BASIC or PC_ASM_RESTRICT 269 270 Level: intermediate 271 272 .keywords: SNES, NASM 273 274 .seealso: SNESNASM, SNESNASMGetType(), PCASMSetType() 275 @*/ 276 PetscErrorCode SNESNASMSetType(SNES snes,PCASMType type) 277 { 278 PetscErrorCode ierr; 279 PetscErrorCode (*f)(SNES,PCASMType); 280 281 PetscFunctionBegin; 282 ierr = PetscObjectQueryFunction((PetscObject)snes,"SNESNASMSetType_C",&f);CHKERRQ(ierr); 283 if (f) {ierr = (f)(snes,type);CHKERRQ(ierr);} 284 PetscFunctionReturn(0); 285 } 286 287 static PetscErrorCode SNESNASMSetType_NASM(SNES snes,PCASMType type) 288 { 289 SNES_NASM *nasm = (SNES_NASM*)snes->data; 290 291 PetscFunctionBegin; 292 if (type != PC_ASM_BASIC && type != PC_ASM_RESTRICT) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_OUTOFRANGE,"SNESNASM only supports basic and restrict types"); 293 nasm->type = type; 294 PetscFunctionReturn(0); 295 } 296 297 /*@ 298 SNESNASMGetType - Get the type of subdomain update used 299 300 Logically Collective on SNES 301 302 Input Parameters: 303 . SNES - the SNES context 304 305 Output Parameters: 306 . type - the type of update 307 308 Level: intermediate 309 310 .keywords: SNES, NASM 311 312 .seealso: SNESNASM, SNESNASMSetType(), PCASMGetType() 313 @*/ 314 PetscErrorCode SNESNASMGetType(SNES snes,PCASMType *type) 315 { 316 PetscErrorCode ierr; 317 318 PetscFunctionBegin; 319 ierr = PetscUseMethod(snes,"SNESNASMGetType_C",(SNES,PCASMType*),(snes,type));CHKERRQ(ierr); 320 PetscFunctionReturn(0); 321 } 322 323 static PetscErrorCode SNESNASMGetType_NASM(SNES snes,PCASMType *type) 324 { 325 SNES_NASM *nasm = (SNES_NASM*)snes->data; 326 327 PetscFunctionBegin; 328 *type = nasm->type; 329 PetscFunctionReturn(0); 330 } 331 332 /*@ 333 SNESNASMSetSubdomains - Manually Set the context required to restrict and solve subdomain problems. 334 335 Not Collective 336 337 Input Parameters: 338 + SNES - the SNES context 339 . n - the number of local subdomains 340 . subsnes - solvers defined on the local subdomains 341 . iscatter - scatters into the nonoverlapping portions of the local subdomains 342 . oscatter - scatters into the overlapping portions of the local subdomains 343 - gscatter - scatters into the (ghosted) local vector of the local subdomain 344 345 Level: intermediate 346 347 .keywords: SNES, NASM 348 349 .seealso: SNESNASM, SNESNASMGetSubdomains() 350 @*/ 351 PetscErrorCode SNESNASMSetSubdomains(SNES snes,PetscInt n,SNES subsnes[],VecScatter iscatter[],VecScatter oscatter[],VecScatter gscatter[]) 352 { 353 PetscErrorCode ierr; 354 PetscErrorCode (*f)(SNES,PetscInt,SNES*,VecScatter*,VecScatter*,VecScatter*); 355 356 PetscFunctionBegin; 357 ierr = PetscObjectQueryFunction((PetscObject)snes,"SNESNASMSetSubdomains_C",&f);CHKERRQ(ierr); 358 if (f) {ierr = (f)(snes,n,subsnes,iscatter,oscatter,gscatter);CHKERRQ(ierr);} 359 PetscFunctionReturn(0); 360 } 361 362 static PetscErrorCode SNESNASMSetSubdomains_NASM(SNES snes,PetscInt n,SNES subsnes[],VecScatter iscatter[],VecScatter oscatter[],VecScatter gscatter[]) 363 { 364 PetscInt i; 365 PetscErrorCode ierr; 366 SNES_NASM *nasm = (SNES_NASM*)snes->data; 367 368 PetscFunctionBegin; 369 if (snes->setupcalled) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE,"SNESNASMSetSubdomains() should be called before calling SNESSetUp()."); 370 371 /* tear down the previously set things */ 372 ierr = SNESReset(snes);CHKERRQ(ierr); 373 374 nasm->n = n; 375 if (oscatter) { 376 for (i=0; i<n; i++) {ierr = PetscObjectReference((PetscObject)oscatter[i]);CHKERRQ(ierr);} 377 } 378 if (iscatter) { 379 for (i=0; i<n; i++) {ierr = PetscObjectReference((PetscObject)iscatter[i]);CHKERRQ(ierr);} 380 } 381 if (gscatter) { 382 for (i=0; i<n; i++) {ierr = PetscObjectReference((PetscObject)gscatter[i]);CHKERRQ(ierr);} 383 } 384 if (oscatter) { 385 ierr = PetscMalloc1(n,&nasm->oscatter);CHKERRQ(ierr); 386 for (i=0; i<n; i++) { 387 nasm->oscatter[i] = oscatter[i]; 388 } 389 } 390 if (iscatter) { 391 ierr = PetscMalloc1(n,&nasm->iscatter);CHKERRQ(ierr); 392 for (i=0; i<n; i++) { 393 nasm->iscatter[i] = iscatter[i]; 394 } 395 } 396 if (gscatter) { 397 ierr = PetscMalloc1(n,&nasm->gscatter);CHKERRQ(ierr); 398 for (i=0; i<n; i++) { 399 nasm->gscatter[i] = gscatter[i]; 400 } 401 } 402 403 if (subsnes) { 404 ierr = PetscMalloc1(n,&nasm->subsnes);CHKERRQ(ierr); 405 for (i=0; i<n; i++) { 406 nasm->subsnes[i] = subsnes[i]; 407 } 408 nasm->same_local_solves = PETSC_FALSE; 409 } 410 PetscFunctionReturn(0); 411 } 412 413 /*@ 414 SNESNASMGetSubdomains - Get the local subdomain context. 415 416 Not Collective 417 418 Input Parameters: 419 . SNES - the SNES context 420 421 Output Parameters: 422 + n - the number of local subdomains 423 . subsnes - solvers defined on the local subdomains 424 . iscatter - scatters into the nonoverlapping portions of the local subdomains 425 . oscatter - scatters into the overlapping portions of the local subdomains 426 - gscatter - scatters into the (ghosted) local vector of the local subdomain 427 428 Level: intermediate 429 430 .keywords: SNES, NASM 431 432 .seealso: SNESNASM, SNESNASMSetSubdomains() 433 @*/ 434 PetscErrorCode SNESNASMGetSubdomains(SNES snes,PetscInt *n,SNES *subsnes[],VecScatter *iscatter[],VecScatter *oscatter[],VecScatter *gscatter[]) 435 { 436 PetscErrorCode ierr; 437 PetscErrorCode (*f)(SNES,PetscInt*,SNES**,VecScatter**,VecScatter**,VecScatter**); 438 439 PetscFunctionBegin; 440 ierr = PetscObjectQueryFunction((PetscObject)snes,"SNESNASMGetSubdomains_C",&f);CHKERRQ(ierr); 441 if (f) {ierr = (f)(snes,n,subsnes,iscatter,oscatter,gscatter);CHKERRQ(ierr);} 442 PetscFunctionReturn(0); 443 } 444 445 static PetscErrorCode SNESNASMGetSubdomains_NASM(SNES snes,PetscInt *n,SNES *subsnes[],VecScatter *iscatter[],VecScatter *oscatter[],VecScatter *gscatter[]) 446 { 447 SNES_NASM *nasm = (SNES_NASM*)snes->data; 448 449 PetscFunctionBegin; 450 if (n) *n = nasm->n; 451 if (oscatter) *oscatter = nasm->oscatter; 452 if (iscatter) *iscatter = nasm->iscatter; 453 if (gscatter) *gscatter = nasm->gscatter; 454 if (subsnes) { 455 *subsnes = nasm->subsnes; 456 nasm->same_local_solves = PETSC_FALSE; 457 } 458 PetscFunctionReturn(0); 459 } 460 461 /*@ 462 SNESNASMGetSubdomainVecs - Get the processor-local subdomain vectors 463 464 Not Collective 465 466 Input Parameters: 467 . SNES - the SNES context 468 469 Output Parameters: 470 + n - the number of local subdomains 471 . x - The subdomain solution vector 472 . y - The subdomain step vector 473 . b - The subdomain RHS vector 474 - xl - The subdomain local vectors (ghosted) 475 476 Level: developer 477 478 .keywords: SNES, NASM 479 480 .seealso: SNESNASM, SNESNASMGetSubdomains() 481 @*/ 482 PetscErrorCode SNESNASMGetSubdomainVecs(SNES snes,PetscInt *n,Vec **x,Vec **y,Vec **b, Vec **xl) 483 { 484 PetscErrorCode ierr; 485 PetscErrorCode (*f)(SNES,PetscInt*,Vec**,Vec**,Vec**,Vec**); 486 487 PetscFunctionBegin; 488 ierr = PetscObjectQueryFunction((PetscObject)snes,"SNESNASMGetSubdomainVecs_C",&f);CHKERRQ(ierr); 489 if (f) {ierr = (f)(snes,n,x,y,b,xl);CHKERRQ(ierr);} 490 PetscFunctionReturn(0); 491 } 492 493 static PetscErrorCode SNESNASMGetSubdomainVecs_NASM(SNES snes,PetscInt *n,Vec **x,Vec **y,Vec **b,Vec **xl) 494 { 495 SNES_NASM *nasm = (SNES_NASM*)snes->data; 496 497 PetscFunctionBegin; 498 if (n) *n = nasm->n; 499 if (x) *x = nasm->x; 500 if (y) *y = nasm->y; 501 if (b) *b = nasm->b; 502 if (xl) *xl = nasm->xl; 503 PetscFunctionReturn(0); 504 } 505 506 /*@ 507 SNESNASMSetComputeFinalJacobian - Schedules the computation of the global and subdomain jacobians upon convergence 508 509 Collective on SNES 510 511 Input Parameters: 512 + SNES - the SNES context 513 - flg - indication of whether to compute the jacobians or not 514 515 Level: developer 516 517 Notes: This is used almost exclusively in the implementation of ASPIN, where the converged subdomain and global jacobian 518 is needed at each linear iteration. 519 520 .keywords: SNES, NASM, ASPIN 521 522 .seealso: SNESNASM, SNESNASMGetSubdomains() 523 @*/ 524 PetscErrorCode SNESNASMSetComputeFinalJacobian(SNES snes,PetscBool flg) 525 { 526 PetscErrorCode (*f)(SNES,PetscBool); 527 PetscErrorCode ierr; 528 529 PetscFunctionBegin; 530 ierr = PetscObjectQueryFunction((PetscObject)snes,"SNESNASMSetComputeFinalJacobian_C",&f);CHKERRQ(ierr); 531 if (f) {ierr = (f)(snes,flg);CHKERRQ(ierr);} 532 PetscFunctionReturn(0); 533 } 534 535 static PetscErrorCode SNESNASMSetComputeFinalJacobian_NASM(SNES snes,PetscBool flg) 536 { 537 SNES_NASM *nasm = (SNES_NASM*)snes->data; 538 539 PetscFunctionBegin; 540 nasm->finaljacobian = flg; 541 if (flg) snes->usesksp = PETSC_TRUE; 542 PetscFunctionReturn(0); 543 } 544 545 /*@ 546 SNESNASMSetDamping - Sets the update damping for NASM 547 548 Logically collective on SNES 549 550 Input Parameters: 551 + SNES - the SNES context 552 - dmp - damping 553 554 Level: intermediate 555 556 Notes: The new solution is obtained as old solution plus dmp times (sum of the solutions on the subdomains) 557 558 .keywords: SNES, NASM, damping 559 560 .seealso: SNESNASM, SNESNASMGetDamping() 561 @*/ 562 PetscErrorCode SNESNASMSetDamping(SNES snes,PetscReal dmp) 563 { 564 PetscErrorCode (*f)(SNES,PetscReal); 565 PetscErrorCode ierr; 566 567 PetscFunctionBegin; 568 ierr = PetscObjectQueryFunction((PetscObject)snes,"SNESNASMSetDamping_C",(void (**)(void))&f);CHKERRQ(ierr); 569 if (f) {ierr = (f)(snes,dmp);CHKERRQ(ierr);} 570 PetscFunctionReturn(0); 571 } 572 573 static PetscErrorCode SNESNASMSetDamping_NASM(SNES snes,PetscReal dmp) 574 { 575 SNES_NASM *nasm = (SNES_NASM*)snes->data; 576 577 PetscFunctionBegin; 578 nasm->damping = dmp; 579 PetscFunctionReturn(0); 580 } 581 582 /*@ 583 SNESNASMGetDamping - Gets the update damping for NASM 584 585 Not Collective 586 587 Input Parameters: 588 + SNES - the SNES context 589 - dmp - damping 590 591 Level: intermediate 592 593 .keywords: SNES, NASM, damping 594 595 .seealso: SNESNASM, SNESNASMSetDamping() 596 @*/ 597 PetscErrorCode SNESNASMGetDamping(SNES snes,PetscReal *dmp) 598 { 599 PetscErrorCode ierr; 600 601 PetscFunctionBegin; 602 ierr = PetscUseMethod(snes,"SNESNASMGetDamping_C",(SNES,PetscReal*),(snes,dmp));CHKERRQ(ierr); 603 PetscFunctionReturn(0); 604 } 605 606 static PetscErrorCode SNESNASMGetDamping_NASM(SNES snes,PetscReal *dmp) 607 { 608 SNES_NASM *nasm = (SNES_NASM*)snes->data; 609 610 PetscFunctionBegin; 611 *dmp = nasm->damping; 612 PetscFunctionReturn(0); 613 } 614 615 616 /* 617 Input Parameters: 618 + snes - The solver 619 . B - The RHS vector 620 - X - The initial guess 621 622 Output Parameters: 623 . Y - The solution update 624 625 TODO: All scatters should be packed into one 626 */ 627 PetscErrorCode SNESNASMSolveLocal_Private(SNES snes,Vec B,Vec Y,Vec X) 628 { 629 SNES_NASM *nasm = (SNES_NASM*)snes->data; 630 SNES subsnes; 631 PetscInt i; 632 PetscReal dmp; 633 PetscErrorCode ierr; 634 Vec Xlloc,Xl,Bl,Yl; 635 VecScatter iscat,oscat,gscat; 636 DM dm,subdm; 637 PCASMType type; 638 639 PetscFunctionBegin; 640 ierr = SNESNASMGetType(snes,&type);CHKERRQ(ierr); 641 ierr = SNESGetDM(snes,&dm);CHKERRQ(ierr); 642 ierr = VecSet(Y,0);CHKERRQ(ierr); 643 if (nasm->eventrestrictinterp) {ierr = PetscLogEventBegin(nasm->eventrestrictinterp,snes,0,0,0);CHKERRQ(ierr);} 644 for (i=0; i<nasm->n; i++) { 645 /* scatter the solution to the local solution */ 646 Xlloc = nasm->xl[i]; 647 gscat = nasm->gscatter[i]; 648 oscat = nasm->oscatter[i]; 649 ierr = VecScatterBegin(gscat,X,Xlloc,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 650 if (B) { 651 /* scatter the RHS to the local RHS */ 652 Bl = nasm->b[i]; 653 ierr = VecScatterBegin(oscat,B,Bl,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 654 } 655 } 656 if (nasm->eventrestrictinterp) {ierr = PetscLogEventEnd(nasm->eventrestrictinterp,snes,0,0,0);CHKERRQ(ierr);} 657 658 659 if (nasm->eventsubsolve) {ierr = PetscLogEventBegin(nasm->eventsubsolve,snes,0,0,0);CHKERRQ(ierr);} 660 for (i=0; i<nasm->n; i++) { 661 Xl = nasm->x[i]; 662 Xlloc = nasm->xl[i]; 663 Yl = nasm->y[i]; 664 subsnes = nasm->subsnes[i]; 665 ierr = SNESGetDM(subsnes,&subdm);CHKERRQ(ierr); 666 iscat = nasm->iscatter[i]; 667 oscat = nasm->oscatter[i]; 668 gscat = nasm->gscatter[i]; 669 ierr = VecScatterEnd(gscat,X,Xlloc,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 670 if (B) { 671 Bl = nasm->b[i]; 672 ierr = VecScatterEnd(oscat,B,Bl,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 673 } else Bl = NULL; 674 ierr = DMSubDomainRestrict(dm,oscat,gscat,subdm);CHKERRQ(ierr); 675 /* Could scatter directly from X */ 676 ierr = DMLocalToGlobalBegin(subdm,Xlloc,INSERT_VALUES,Xl);CHKERRQ(ierr); 677 ierr = DMLocalToGlobalEnd(subdm,Xlloc,INSERT_VALUES,Xl);CHKERRQ(ierr); 678 ierr = VecCopy(Xl,Yl);CHKERRQ(ierr); 679 ierr = SNESSolve(subsnes,Bl,Xl);CHKERRQ(ierr); 680 ierr = VecAYPX(Yl,-1.0,Xl);CHKERRQ(ierr); 681 if (type == PC_ASM_BASIC) { 682 ierr = VecScatterBegin(oscat,Yl,Y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 683 } else if (type == PC_ASM_RESTRICT) { 684 ierr = VecScatterBegin(iscat,Yl,Y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 685 } else SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE,"Only basic and restrict types are supported for SNESNASM"); 686 } 687 if (nasm->eventsubsolve) {ierr = PetscLogEventEnd(nasm->eventsubsolve,snes,0,0,0);CHKERRQ(ierr);} 688 if (nasm->eventrestrictinterp) {ierr = PetscLogEventBegin(nasm->eventrestrictinterp,snes,0,0,0);CHKERRQ(ierr);} 689 for (i=0; i<nasm->n; i++) { 690 Yl = nasm->y[i]; 691 iscat = nasm->iscatter[i]; 692 oscat = nasm->oscatter[i]; 693 if (type == PC_ASM_BASIC) { 694 ierr = VecScatterEnd(oscat,Yl,Y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 695 } else if (type == PC_ASM_RESTRICT) { 696 ierr = VecScatterEnd(iscat,Yl,Y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 697 } else SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE,"Only basic and restrict types are supported for SNESNASM"); 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) {ierr = SNESNASMComputeFinalJacobian_Private(snes,X);CHKERRQ(ierr);} 834 if (normschedule == SNES_NORM_ALWAYS) { 835 if (i == snes->max_its) { 836 ierr = PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",snes->max_its);CHKERRQ(ierr); 837 if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT; 838 } 839 } else if (!snes->reason) snes->reason = SNES_CONVERGED_ITS; /* NASM is meant to be used as a preconditioner */ 840 PetscFunctionReturn(0); 841 } 842 843 /*MC 844 SNESNASM - Nonlinear Additive Schwartz 845 846 Options Database: 847 + -snes_nasm_log - enable logging events for the communication and solve stages 848 . -snes_nasm_type <basic,restrict> - type of subdomain update used 849 . -snes_asm_damping <dmp> - the new solution is obtained as old solution plus dmp times (sum of the solutions on the subdomains) 850 . -snes_nasm_finaljacobian - compute the local and global jacobians of the final iterate 851 . -snes_nasm_finaljacobian_type <finalinner,finalouter,initial> - pick state the jacobian is calculated at 852 . -sub_snes_ - options prefix of the subdomain nonlinear solves 853 . -sub_ksp_ - options prefix of the subdomain Krylov solver 854 - -sub_pc_ - options prefix of the subdomain preconditioner 855 856 Level: advanced 857 858 References: 859 . 1. - Peter R. Brune, Matthew G. Knepley, Barry F. Smith, and Xuemin Tu, "Composing Scalable Nonlinear Algebraic Solvers", 860 SIAM Review, 57(4), 2015 861 862 .seealso: SNESCreate(), SNES, SNESSetType(), SNESType (for list of available types), SNESNASMSetType(), SNESNASMGetType(), SNESNASMSetSubdomains(), SNESNASMGetSubdomains(), SNESNASMGetSubdomainVecs(), SNESNASMSetComputeFinalJacobian(), SNESNASMSetDamping(), SNESNASMGetDamping() 863 M*/ 864 865 PETSC_EXTERN PetscErrorCode SNESCreate_NASM(SNES snes) 866 { 867 SNES_NASM *nasm; 868 PetscErrorCode ierr; 869 870 PetscFunctionBegin; 871 ierr = PetscNewLog(snes,&nasm);CHKERRQ(ierr); 872 snes->data = (void*)nasm; 873 874 nasm->n = PETSC_DECIDE; 875 nasm->subsnes = 0; 876 nasm->x = 0; 877 nasm->xl = 0; 878 nasm->y = 0; 879 nasm->b = 0; 880 nasm->oscatter = 0; 881 nasm->iscatter = 0; 882 nasm->gscatter = 0; 883 nasm->damping = 1.; 884 885 nasm->type = PC_ASM_BASIC; 886 nasm->finaljacobian = PETSC_FALSE; 887 nasm->same_local_solves = PETSC_TRUE; 888 889 snes->ops->destroy = SNESDestroy_NASM; 890 snes->ops->setup = SNESSetUp_NASM; 891 snes->ops->setfromoptions = SNESSetFromOptions_NASM; 892 snes->ops->view = SNESView_NASM; 893 snes->ops->solve = SNESSolve_NASM; 894 snes->ops->reset = SNESReset_NASM; 895 896 snes->usesksp = PETSC_FALSE; 897 snes->usespc = PETSC_FALSE; 898 899 snes->alwayscomputesfinalresidual = PETSC_FALSE; 900 901 nasm->fjtype = 0; 902 nasm->xinit = NULL; 903 nasm->eventrestrictinterp = 0; 904 nasm->eventsubsolve = 0; 905 906 if (!snes->tolerancesset) { 907 snes->max_its = 10000; 908 snes->max_funcs = 10000; 909 } 910 911 ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESNASMSetType_C",SNESNASMSetType_NASM);CHKERRQ(ierr); 912 ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESNASMGetType_C",SNESNASMGetType_NASM);CHKERRQ(ierr); 913 ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESNASMSetSubdomains_C",SNESNASMSetSubdomains_NASM);CHKERRQ(ierr); 914 ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESNASMGetSubdomains_C",SNESNASMGetSubdomains_NASM);CHKERRQ(ierr); 915 ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESNASMSetDamping_C",SNESNASMSetDamping_NASM);CHKERRQ(ierr); 916 ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESNASMGetDamping_C",SNESNASMGetDamping_NASM);CHKERRQ(ierr); 917 ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESNASMGetSubdomainVecs_C",SNESNASMGetSubdomainVecs_NASM);CHKERRQ(ierr); 918 ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESNASMSetComputeFinalJacobian_C",SNESNASMSetComputeFinalJacobian_NASM);CHKERRQ(ierr); 919 PetscFunctionReturn(0); 920 } 921 922