1 #define PETSCKSP_DLL 2 3 /* 4 This file defines an additive Schwarz preconditioner for any Mat implementation. 5 6 Note that each processor may have any number of subdomains. But in order to 7 deal easily with the VecScatter(), we treat each processor as if it has the 8 same number of subdomains. 9 10 n - total number of true subdomains on all processors 11 n_local_true - actual number of subdomains on this processor 12 n_local = maximum over all processors of n_local_true 13 */ 14 #include "private/pcimpl.h" /*I "petscpc.h" I*/ 15 16 typedef struct { 17 PetscInt n, n_local, n_local_true; 18 PetscInt overlap; /* overlap requested by user */ 19 KSP *ksp; /* linear solvers for each block */ 20 VecScatter *restriction; /* mapping from global to subregion */ 21 VecScatter *localization; /* mapping from overlapping to non-overlapping subregion */ 22 VecScatter *prolongation; /* mapping from subregion to global */ 23 Vec *x,*y,*y_local; /* work vectors */ 24 IS *is; /* index set that defines each overlapping subdomain */ 25 IS *is_local; /* index set that defines each non-overlapping subdomain, may be NULL */ 26 Mat *mat,*pmat; /* mat is not currently used */ 27 PCASMType type; /* use reduced interpolation, restriction or both */ 28 PetscTruth type_set; /* if user set this value (so won't change it for symmetric problems) */ 29 PetscTruth same_local_solves; /* flag indicating whether all local solvers are same */ 30 PetscTruth sort_indices; /* flag to sort subdomain indices */ 31 } PC_ASM; 32 33 #undef __FUNCT__ 34 #define __FUNCT__ "PCView_ASM" 35 static PetscErrorCode PCView_ASM(PC pc,PetscViewer viewer) 36 { 37 PC_ASM *osm = (PC_ASM*)pc->data; 38 PetscErrorCode ierr; 39 PetscMPIInt rank; 40 PetscInt i,bsz; 41 PetscTruth iascii,isstring; 42 PetscViewer sviewer; 43 44 45 PetscFunctionBegin; 46 ierr = PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr); 47 ierr = PetscTypeCompare((PetscObject)viewer,PETSCVIEWERSTRING,&isstring);CHKERRQ(ierr); 48 if (iascii) { 49 char overlaps[256] = "user-defined overlap",blocks[256] = "total subdomain blocks not yet set"; 50 if (osm->overlap >= 0) {ierr = PetscSNPrintf(overlaps,sizeof overlaps,"amount of overlap = %D",osm->overlap);CHKERRQ(ierr);} 51 if (osm->n > 0) {ierr = PetscSNPrintf(blocks,sizeof blocks,"total subdomain blocks = %D",osm->n);CHKERRQ(ierr);} 52 ierr = PetscViewerASCIIPrintf(viewer," Additive Schwarz: %s, %s\n",blocks,overlaps);CHKERRQ(ierr); 53 ierr = PetscViewerASCIIPrintf(viewer," Additive Schwarz: restriction/interpolation type - %s\n",PCASMTypes[osm->type]);CHKERRQ(ierr); 54 ierr = MPI_Comm_rank(((PetscObject)pc)->comm,&rank);CHKERRQ(ierr); 55 if (osm->same_local_solves) { 56 if (osm->ksp) { 57 ierr = PetscViewerASCIIPrintf(viewer," Local solve is same for all blocks, in the following KSP and PC objects:\n");CHKERRQ(ierr); 58 ierr = PetscViewerGetSingleton(viewer,&sviewer);CHKERRQ(ierr); 59 if (!rank) { 60 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 61 ierr = KSPView(osm->ksp[0],sviewer);CHKERRQ(ierr); 62 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 63 } 64 ierr = PetscViewerRestoreSingleton(viewer,&sviewer);CHKERRQ(ierr); 65 } 66 } else { 67 ierr = PetscViewerASCIISynchronizedPrintf(viewer," [%d] number of local blocks = %D\n",(int)rank,osm->n_local_true);CHKERRQ(ierr); 68 ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 69 ierr = PetscViewerASCIIPrintf(viewer," Local solve info for each block is in the following KSP and PC objects:\n");CHKERRQ(ierr); 70 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 71 ierr = PetscViewerASCIIPrintf(viewer,"- - - - - - - - - - - - - - - - - -\n");CHKERRQ(ierr); 72 for (i=0; i<osm->n_local; i++) { 73 ierr = PetscViewerGetSingleton(viewer,&sviewer);CHKERRQ(ierr); 74 if (i < osm->n_local_true) { 75 ierr = ISGetLocalSize(osm->is[i],&bsz);CHKERRQ(ierr); 76 ierr = PetscViewerASCIISynchronizedPrintf(sviewer,"[%d] local block number %D, size = %D\n",(int)rank,i,bsz);CHKERRQ(ierr); 77 ierr = KSPView(osm->ksp[i],sviewer);CHKERRQ(ierr); 78 ierr = PetscViewerASCIISynchronizedPrintf(sviewer,"- - - - - - - - - - - - - - - - - -\n");CHKERRQ(ierr); 79 } 80 ierr = PetscViewerRestoreSingleton(viewer,&sviewer);CHKERRQ(ierr); 81 } 82 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 83 ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 84 } 85 } else if (isstring) { 86 ierr = PetscViewerStringSPrintf(viewer," blocks=%D, overlap=%D, type=%s",osm->n,osm->overlap,PCASMTypes[osm->type]);CHKERRQ(ierr); 87 ierr = PetscViewerGetSingleton(viewer,&sviewer);CHKERRQ(ierr); 88 if (osm->ksp) {ierr = KSPView(osm->ksp[0],sviewer);CHKERRQ(ierr);} 89 ierr = PetscViewerRestoreSingleton(viewer,&sviewer);CHKERRQ(ierr); 90 } else { 91 SETERRQ1(((PetscObject)pc)->comm,PETSC_ERR_SUP,"Viewer type %s not supported for PCASM",((PetscObject)viewer)->type_name); 92 } 93 PetscFunctionReturn(0); 94 } 95 96 #undef __FUNCT__ 97 #define __FUNCT__ "PCASMPrintSubdomains" 98 static PetscErrorCode PCASMPrintSubdomains(PC pc) 99 { 100 PC_ASM *osm = (PC_ASM*)pc->data; 101 const char *prefix; 102 char fname[PETSC_MAX_PATH_LEN+1]; 103 PetscViewer viewer; 104 PetscInt i,j,nidx; 105 const PetscInt *idx; 106 PetscErrorCode ierr; 107 108 PetscFunctionBegin; 109 ierr = PCGetOptionsPrefix(pc,&prefix);CHKERRQ(ierr); 110 ierr = PetscOptionsGetString(prefix,"-pc_asm_print_subdomains",fname,PETSC_MAX_PATH_LEN,PETSC_NULL);CHKERRQ(ierr); 111 if (fname[0] == 0) { ierr = PetscStrcpy(fname,"stdout");CHKERRQ(ierr); }; 112 ierr = PetscViewerASCIIOpen(((PetscObject)pc)->comm,fname,&viewer);CHKERRQ(ierr); 113 for (i=0;i<osm->n_local_true;i++) { 114 ierr = ISGetLocalSize(osm->is[i],&nidx);CHKERRQ(ierr); 115 ierr = ISGetIndices(osm->is[i],&idx);CHKERRQ(ierr); 116 for (j=0; j<nidx; j++) { 117 ierr = PetscViewerASCIISynchronizedPrintf(viewer,"%D ",idx[j]);CHKERRQ(ierr); 118 } 119 ierr = ISRestoreIndices(osm->is[i],&idx);CHKERRQ(ierr); 120 ierr = PetscViewerASCIISynchronizedPrintf(viewer,"\n");CHKERRQ(ierr); 121 if (osm->is_local) { 122 ierr = ISGetLocalSize(osm->is_local[i],&nidx);CHKERRQ(ierr); 123 ierr = ISGetIndices(osm->is_local[i],&idx);CHKERRQ(ierr); 124 for (j=0; j<nidx; j++) { 125 ierr = PetscViewerASCIISynchronizedPrintf(viewer,"%D ",idx[j]);CHKERRQ(ierr); 126 } 127 ierr = ISRestoreIndices(osm->is_local[i],&idx);CHKERRQ(ierr); 128 ierr = PetscViewerASCIISynchronizedPrintf(viewer,"\n");CHKERRQ(ierr); 129 } 130 } 131 ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 132 ierr = PetscViewerDestroy(viewer);CHKERRQ(ierr); 133 PetscFunctionReturn(0); 134 } 135 136 #undef __FUNCT__ 137 #define __FUNCT__ "PCSetUp_ASM" 138 static PetscErrorCode PCSetUp_ASM(PC pc) 139 { 140 PC_ASM *osm = (PC_ASM*)pc->data; 141 PetscErrorCode ierr; 142 PetscTruth symset,flg; 143 PetscInt i,m,m_local,firstRow,lastRow; 144 PetscMPIInt size; 145 MatReuse scall = MAT_REUSE_MATRIX; 146 IS isl; 147 KSP ksp; 148 PC subpc; 149 const char *prefix,*pprefix; 150 Vec vec; 151 152 PetscFunctionBegin; 153 if (!pc->setupcalled) { 154 155 if (!osm->type_set) { 156 ierr = MatIsSymmetricKnown(pc->pmat,&symset,&flg);CHKERRQ(ierr); 157 if (symset && flg) { osm->type = PC_ASM_BASIC; } 158 } 159 160 if (osm->n == PETSC_DECIDE && osm->n_local_true < 1) { 161 /* no subdomains given, use one per processor */ 162 osm->n_local = osm->n_local_true = 1; 163 ierr = MPI_Comm_size(((PetscObject)pc)->comm,&size);CHKERRQ(ierr); 164 osm->n = size; 165 } else if (osm->n == PETSC_DECIDE) { 166 /* determine global number of subdomains */ 167 PetscInt inwork[2],outwork[2]; 168 inwork[0] = inwork[1] = osm->n_local_true; 169 ierr = MPI_Allreduce(inwork,outwork,1,MPIU_2INT,PetscMaxSum_Op,((PetscObject)pc)->comm);CHKERRQ(ierr); 170 osm->n_local = outwork[0]; 171 osm->n = outwork[1]; 172 } 173 174 if (!osm->is){ /* create the index sets */ 175 ierr = PCASMCreateSubdomains(pc->pmat,osm->n_local_true,&osm->is);CHKERRQ(ierr); 176 } 177 if (osm->n_local_true > 1 && !osm->is_local) { 178 ierr = PetscMalloc(osm->n_local_true*sizeof(IS),&osm->is_local);CHKERRQ(ierr); 179 for (i=0; i<osm->n_local_true; i++) { 180 if (osm->overlap > 0) { /* With positive overlap, osm->is[i] will be modified */ 181 ierr = ISDuplicate(osm->is[i],&osm->is_local[i]);CHKERRQ(ierr); 182 ierr = ISCopy(osm->is[i],osm->is_local[i]);CHKERRQ(ierr); 183 } else { 184 ierr = PetscObjectReference((PetscObject)osm->is[i]);CHKERRQ(ierr); 185 osm->is_local[i] = osm->is[i]; 186 } 187 } 188 } 189 ierr = PCGetOptionsPrefix(pc,&prefix);CHKERRQ(ierr); 190 flg = PETSC_FALSE; 191 ierr = PetscOptionsGetTruth(prefix,"-pc_asm_print_subdomains",&flg,PETSC_NULL);CHKERRQ(ierr); 192 if (flg) { ierr = PCASMPrintSubdomains(pc);CHKERRQ(ierr); } 193 194 if (osm->overlap > 0) { 195 /* Extend the "overlapping" regions by a number of steps */ 196 ierr = MatIncreaseOverlap(pc->pmat,osm->n_local_true,osm->is,osm->overlap);CHKERRQ(ierr); 197 } 198 if (osm->sort_indices) { 199 for (i=0; i<osm->n_local_true; i++) { 200 ierr = ISSort(osm->is[i]);CHKERRQ(ierr); 201 if (osm->is_local) { 202 ierr = ISSort(osm->is_local[i]);CHKERRQ(ierr); 203 } 204 } 205 } 206 207 /* Create the local work vectors and scatter contexts */ 208 ierr = MatGetVecs(pc->pmat,&vec,0);CHKERRQ(ierr); 209 ierr = PetscMalloc(osm->n_local*sizeof(VecScatter *),&osm->restriction);CHKERRQ(ierr); 210 if (osm->is_local) {ierr = PetscMalloc(osm->n_local*sizeof(VecScatter *),&osm->localization);CHKERRQ(ierr);} 211 ierr = PetscMalloc(osm->n_local*sizeof(VecScatter *),&osm->prolongation);CHKERRQ(ierr); 212 ierr = PetscMalloc(osm->n_local*sizeof(Vec *),&osm->x);CHKERRQ(ierr); 213 ierr = PetscMalloc(osm->n_local*sizeof(Vec *),&osm->y);CHKERRQ(ierr); 214 ierr = PetscMalloc(osm->n_local*sizeof(Vec *),&osm->y_local);CHKERRQ(ierr); 215 ierr = VecGetOwnershipRange(vec, &firstRow, &lastRow);CHKERRQ(ierr); 216 for (i=0; i<osm->n_local_true; ++i, firstRow += m_local) { 217 ierr = ISGetLocalSize(osm->is[i],&m);CHKERRQ(ierr); 218 ierr = VecCreateSeq(PETSC_COMM_SELF,m,&osm->x[i]);CHKERRQ(ierr); 219 ierr = ISCreateStride(PETSC_COMM_SELF,m,0,1,&isl);CHKERRQ(ierr); 220 ierr = VecScatterCreate(vec,osm->is[i],osm->x[i],isl,&osm->restriction[i]);CHKERRQ(ierr); 221 ierr = ISDestroy(isl);CHKERRQ(ierr); 222 ierr = VecDuplicate(osm->x[i],&osm->y[i]);CHKERRQ(ierr); 223 if (osm->is_local) { 224 ISLocalToGlobalMapping ltog; 225 IS isll; 226 const PetscInt *idx_local; 227 PetscInt *idx,nout; 228 229 ierr = ISLocalToGlobalMappingCreateIS(osm->is[i],<og);CHKERRQ(ierr); 230 ierr = ISGetLocalSize(osm->is_local[i],&m_local);CHKERRQ(ierr); 231 ierr = ISGetIndices(osm->is_local[i], &idx_local);CHKERRQ(ierr); 232 ierr = PetscMalloc(m_local*sizeof(PetscInt),&idx);CHKERRQ(ierr); 233 ierr = ISGlobalToLocalMappingApply(ltog,IS_GTOLM_DROP,m_local,idx_local,&nout,idx);CHKERRQ(ierr); 234 ierr = ISLocalToGlobalMappingDestroy(ltog);CHKERRQ(ierr); 235 if (nout != m_local) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"is_local not a subset of is"); 236 ierr = ISRestoreIndices(osm->is_local[i], &idx_local);CHKERRQ(ierr); 237 ierr = ISCreateGeneral(PETSC_COMM_SELF,m_local,idx,&isll);CHKERRQ(ierr); 238 ierr = PetscFree(idx);CHKERRQ(ierr); 239 ierr = ISCreateStride(PETSC_COMM_SELF,m_local,0,1,&isl);CHKERRQ(ierr); 240 ierr = VecCreateSeq(PETSC_COMM_SELF,m_local,&osm->y_local[i]);CHKERRQ(ierr); 241 ierr = VecScatterCreate(osm->y[i],isll,osm->y_local[i],isl,&osm->localization[i]);CHKERRQ(ierr); 242 ierr = ISDestroy(isll);CHKERRQ(ierr); 243 244 ierr = VecScatterCreate(vec,osm->is_local[i],osm->y_local[i],isl,&osm->prolongation[i]);CHKERRQ(ierr); 245 ierr = ISDestroy(isl);CHKERRQ(ierr); 246 } else { 247 ierr = VecGetLocalSize(vec,&m_local);CHKERRQ(ierr); 248 osm->y_local[i] = osm->y[i]; 249 ierr = PetscObjectReference((PetscObject) osm->y[i]);CHKERRQ(ierr); 250 osm->prolongation[i] = osm->restriction[i]; 251 ierr = PetscObjectReference((PetscObject) osm->restriction[i]);CHKERRQ(ierr); 252 } 253 } 254 if (firstRow != lastRow) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB, "Specified ASM subdomain sizes were invalid: %d != %d", firstRow, lastRow); 255 for (i=osm->n_local_true; i<osm->n_local; i++) { 256 ierr = VecCreateSeq(PETSC_COMM_SELF,0,&osm->x[i]);CHKERRQ(ierr); 257 ierr = VecDuplicate(osm->x[i],&osm->y[i]);CHKERRQ(ierr); 258 ierr = VecDuplicate(osm->x[i],&osm->y_local[i]);CHKERRQ(ierr); 259 ierr = ISCreateStride(PETSC_COMM_SELF,0,0,1,&isl);CHKERRQ(ierr); 260 ierr = VecScatterCreate(vec,isl,osm->x[i],isl,&osm->restriction[i]);CHKERRQ(ierr); 261 if (osm->is_local) { 262 ierr = VecScatterCreate(osm->y[i],isl,osm->y_local[i],isl,&osm->localization[i]);CHKERRQ(ierr); 263 ierr = VecScatterCreate(vec,isl,osm->x[i],isl,&osm->prolongation[i]);CHKERRQ(ierr); 264 } else { 265 osm->prolongation[i] = osm->restriction[i]; 266 ierr = PetscObjectReference((PetscObject) osm->restriction[i]);CHKERRQ(ierr); 267 } 268 ierr = ISDestroy(isl);CHKERRQ(ierr); 269 } 270 ierr = VecDestroy(vec);CHKERRQ(ierr); 271 272 /* Create the local solvers */ 273 ierr = PetscMalloc(osm->n_local_true*sizeof(KSP *),&osm->ksp);CHKERRQ(ierr); 274 for (i=0; i<osm->n_local_true; i++) { 275 ierr = KSPCreate(PETSC_COMM_SELF,&ksp);CHKERRQ(ierr); 276 ierr = PetscLogObjectParent(pc,ksp);CHKERRQ(ierr); 277 ierr = PetscObjectIncrementTabLevel((PetscObject)ksp,(PetscObject)pc,1);CHKERRQ(ierr); 278 ierr = KSPSetType(ksp,KSPPREONLY);CHKERRQ(ierr); 279 ierr = KSPGetPC(ksp,&subpc);CHKERRQ(ierr); 280 ierr = PCGetOptionsPrefix(pc,&prefix);CHKERRQ(ierr); 281 ierr = KSPSetOptionsPrefix(ksp,prefix);CHKERRQ(ierr); 282 ierr = KSPAppendOptionsPrefix(ksp,"sub_");CHKERRQ(ierr); 283 osm->ksp[i] = ksp; 284 } 285 scall = MAT_INITIAL_MATRIX; 286 287 } else { 288 /* 289 Destroy the blocks from the previous iteration 290 */ 291 if (pc->flag == DIFFERENT_NONZERO_PATTERN) { 292 ierr = MatDestroyMatrices(osm->n_local_true,&osm->pmat);CHKERRQ(ierr); 293 scall = MAT_INITIAL_MATRIX; 294 } 295 } 296 297 /* 298 Extract out the submatrices 299 */ 300 ierr = MatGetSubMatrices(pc->pmat,osm->n_local_true,osm->is,osm->is,scall,&osm->pmat);CHKERRQ(ierr); 301 if (scall == MAT_INITIAL_MATRIX) { 302 ierr = PetscObjectGetOptionsPrefix((PetscObject)pc->pmat,&pprefix);CHKERRQ(ierr); 303 for (i=0; i<osm->n_local_true; i++) { 304 ierr = PetscLogObjectParent(pc,osm->pmat[i]);CHKERRQ(ierr); 305 ierr = PetscObjectSetOptionsPrefix((PetscObject)osm->pmat[i],pprefix);CHKERRQ(ierr); 306 } 307 } 308 309 /* Return control to the user so that the submatrices can be modified (e.g., to apply 310 different boundary conditions for the submatrices than for the global problem) */ 311 ierr = PCModifySubMatrices(pc,osm->n_local_true,osm->is,osm->is,osm->pmat,pc->modifysubmatricesP);CHKERRQ(ierr); 312 313 /* 314 Loop over subdomains putting them into local ksp 315 */ 316 for (i=0; i<osm->n_local_true; i++) { 317 ierr = KSPSetOperators(osm->ksp[i],osm->pmat[i],osm->pmat[i],pc->flag);CHKERRQ(ierr); 318 if (!pc->setupcalled) { 319 ierr = KSPSetFromOptions(osm->ksp[i]);CHKERRQ(ierr); 320 } 321 } 322 323 PetscFunctionReturn(0); 324 } 325 326 #undef __FUNCT__ 327 #define __FUNCT__ "PCSetUpOnBlocks_ASM" 328 static PetscErrorCode PCSetUpOnBlocks_ASM(PC pc) 329 { 330 PC_ASM *osm = (PC_ASM*)pc->data; 331 PetscErrorCode ierr; 332 PetscInt i; 333 334 PetscFunctionBegin; 335 for (i=0; i<osm->n_local_true; i++) { 336 ierr = KSPSetUp(osm->ksp[i]);CHKERRQ(ierr); 337 } 338 PetscFunctionReturn(0); 339 } 340 341 #undef __FUNCT__ 342 #define __FUNCT__ "PCApply_ASM" 343 static PetscErrorCode PCApply_ASM(PC pc,Vec x,Vec y) 344 { 345 PC_ASM *osm = (PC_ASM*)pc->data; 346 PetscErrorCode ierr; 347 PetscInt i,n_local = osm->n_local,n_local_true = osm->n_local_true; 348 ScatterMode forward = SCATTER_FORWARD,reverse = SCATTER_REVERSE; 349 350 PetscFunctionBegin; 351 /* 352 Support for limiting the restriction or interpolation to only local 353 subdomain values (leaving the other values 0). 354 */ 355 if (!(osm->type & PC_ASM_RESTRICT)) { 356 forward = SCATTER_FORWARD_LOCAL; 357 /* have to zero the work RHS since scatter may leave some slots empty */ 358 for (i=0; i<n_local_true; i++) { 359 ierr = VecZeroEntries(osm->x[i]);CHKERRQ(ierr); 360 } 361 } 362 if (!(osm->type & PC_ASM_INTERPOLATE)) { 363 reverse = SCATTER_REVERSE_LOCAL; 364 } 365 366 for (i=0; i<n_local; i++) { 367 ierr = VecScatterBegin(osm->restriction[i],x,osm->x[i],INSERT_VALUES,forward);CHKERRQ(ierr); 368 } 369 ierr = VecZeroEntries(y);CHKERRQ(ierr); 370 /* do the local solves */ 371 for (i=0; i<n_local_true; i++) { 372 ierr = VecScatterEnd(osm->restriction[i],x,osm->x[i],INSERT_VALUES,forward);CHKERRQ(ierr); 373 ierr = KSPSolve(osm->ksp[i],osm->x[i],osm->y[i]);CHKERRQ(ierr); 374 if (osm->localization) { 375 ierr = VecScatterBegin(osm->localization[i],osm->y[i],osm->y_local[i],INSERT_VALUES,forward);CHKERRQ(ierr); 376 ierr = VecScatterEnd(osm->localization[i],osm->y[i],osm->y_local[i],INSERT_VALUES,forward);CHKERRQ(ierr); 377 } 378 ierr = VecScatterBegin(osm->prolongation[i],osm->y_local[i],y,ADD_VALUES,reverse);CHKERRQ(ierr); 379 } 380 /* handle the rest of the scatters that do not have local solves */ 381 for (i=n_local_true; i<n_local; i++) { 382 ierr = VecScatterEnd(osm->restriction[i],x,osm->x[i],INSERT_VALUES,forward);CHKERRQ(ierr); 383 ierr = VecScatterBegin(osm->prolongation[i],osm->y_local[i],y,ADD_VALUES,reverse);CHKERRQ(ierr); 384 } 385 for (i=0; i<n_local; i++) { 386 ierr = VecScatterEnd(osm->prolongation[i],osm->y_local[i],y,ADD_VALUES,reverse);CHKERRQ(ierr); 387 } 388 PetscFunctionReturn(0); 389 } 390 391 #undef __FUNCT__ 392 #define __FUNCT__ "PCApplyTranspose_ASM" 393 static PetscErrorCode PCApplyTranspose_ASM(PC pc,Vec x,Vec y) 394 { 395 PC_ASM *osm = (PC_ASM*)pc->data; 396 PetscErrorCode ierr; 397 PetscInt i,n_local = osm->n_local,n_local_true = osm->n_local_true; 398 ScatterMode forward = SCATTER_FORWARD,reverse = SCATTER_REVERSE; 399 400 PetscFunctionBegin; 401 /* 402 Support for limiting the restriction or interpolation to only local 403 subdomain values (leaving the other values 0). 404 405 Note: these are reversed from the PCApply_ASM() because we are applying the 406 transpose of the three terms 407 */ 408 if (!(osm->type & PC_ASM_INTERPOLATE)) { 409 forward = SCATTER_FORWARD_LOCAL; 410 /* have to zero the work RHS since scatter may leave some slots empty */ 411 for (i=0; i<n_local_true; i++) { 412 ierr = VecZeroEntries(osm->x[i]);CHKERRQ(ierr); 413 } 414 } 415 if (!(osm->type & PC_ASM_RESTRICT)) { 416 reverse = SCATTER_REVERSE_LOCAL; 417 } 418 419 for (i=0; i<n_local; i++) { 420 ierr = VecScatterBegin(osm->restriction[i],x,osm->x[i],INSERT_VALUES,forward);CHKERRQ(ierr); 421 } 422 ierr = VecZeroEntries(y);CHKERRQ(ierr); 423 /* do the local solves */ 424 for (i=0; i<n_local_true; i++) { 425 ierr = VecScatterEnd(osm->restriction[i],x,osm->x[i],INSERT_VALUES,forward);CHKERRQ(ierr); 426 ierr = KSPSolveTranspose(osm->ksp[i],osm->x[i],osm->y[i]);CHKERRQ(ierr); 427 if (osm->localization) { 428 ierr = VecScatterBegin(osm->localization[i],osm->y[i],osm->y_local[i],INSERT_VALUES,forward);CHKERRQ(ierr); 429 ierr = VecScatterEnd(osm->localization[i],osm->y[i],osm->y_local[i],INSERT_VALUES,forward);CHKERRQ(ierr); 430 } 431 ierr = VecScatterBegin(osm->prolongation[i],osm->y_local[i],y,ADD_VALUES,reverse);CHKERRQ(ierr); 432 } 433 /* handle the rest of the scatters that do not have local solves */ 434 for (i=n_local_true; i<n_local; i++) { 435 ierr = VecScatterEnd(osm->restriction[i],x,osm->x[i],INSERT_VALUES,forward);CHKERRQ(ierr); 436 ierr = VecScatterBegin(osm->prolongation[i],osm->y_local[i],y,ADD_VALUES,reverse);CHKERRQ(ierr); 437 } 438 for (i=0; i<n_local; i++) { 439 ierr = VecScatterEnd(osm->prolongation[i],osm->y_local[i],y,ADD_VALUES,reverse);CHKERRQ(ierr); 440 } 441 PetscFunctionReturn(0); 442 } 443 444 #undef __FUNCT__ 445 #define __FUNCT__ "PCDestroy_ASM" 446 static PetscErrorCode PCDestroy_ASM(PC pc) 447 { 448 PC_ASM *osm = (PC_ASM*)pc->data; 449 PetscErrorCode ierr; 450 PetscInt i; 451 452 PetscFunctionBegin; 453 if (osm->ksp) { 454 for (i=0; i<osm->n_local_true; i++) { 455 ierr = KSPDestroy(osm->ksp[i]);CHKERRQ(ierr); 456 } 457 ierr = PetscFree(osm->ksp);CHKERRQ(ierr); 458 } 459 if (osm->pmat) { 460 if (osm->n_local_true > 0) { 461 ierr = MatDestroyMatrices(osm->n_local_true,&osm->pmat);CHKERRQ(ierr); 462 } 463 } 464 if (osm->restriction) { 465 for (i=0; i<osm->n_local; i++) { 466 ierr = VecScatterDestroy(osm->restriction[i]);CHKERRQ(ierr); 467 if (osm->localization) {ierr = VecScatterDestroy(osm->localization[i]);CHKERRQ(ierr);} 468 ierr = VecScatterDestroy(osm->prolongation[i]);CHKERRQ(ierr); 469 ierr = VecDestroy(osm->x[i]);CHKERRQ(ierr); 470 ierr = VecDestroy(osm->y[i]);CHKERRQ(ierr); 471 ierr = VecDestroy(osm->y_local[i]);CHKERRQ(ierr); 472 } 473 ierr = PetscFree(osm->restriction);CHKERRQ(ierr); 474 if (osm->localization) {ierr = PetscFree(osm->localization);CHKERRQ(ierr);} 475 ierr = PetscFree(osm->prolongation);CHKERRQ(ierr); 476 ierr = PetscFree(osm->x);CHKERRQ(ierr); 477 ierr = PetscFree(osm->y);CHKERRQ(ierr); 478 ierr = PetscFree(osm->y_local);CHKERRQ(ierr); 479 } 480 if (osm->is) { 481 ierr = PCASMDestroySubdomains(osm->n_local_true,osm->is,osm->is_local);CHKERRQ(ierr); 482 } 483 ierr = PetscFree(osm);CHKERRQ(ierr); 484 PetscFunctionReturn(0); 485 } 486 487 #undef __FUNCT__ 488 #define __FUNCT__ "PCSetFromOptions_ASM" 489 static PetscErrorCode PCSetFromOptions_ASM(PC pc) 490 { 491 PC_ASM *osm = (PC_ASM*)pc->data; 492 PetscErrorCode ierr; 493 PetscInt blocks,ovl; 494 PetscTruth symset,flg; 495 PCASMType asmtype; 496 497 PetscFunctionBegin; 498 /* set the type to symmetric if matrix is symmetric */ 499 if (!osm->type_set && pc->pmat) { 500 ierr = MatIsSymmetricKnown(pc->pmat,&symset,&flg);CHKERRQ(ierr); 501 if (symset && flg) { osm->type = PC_ASM_BASIC; } 502 } 503 ierr = PetscOptionsHead("Additive Schwarz options");CHKERRQ(ierr); 504 ierr = PetscOptionsInt("-pc_asm_blocks","Number of subdomains","PCASMSetTotalSubdomains",osm->n,&blocks,&flg);CHKERRQ(ierr); 505 if (flg) {ierr = PCASMSetTotalSubdomains(pc,blocks,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr); } 506 ierr = PetscOptionsInt("-pc_asm_overlap","Number of grid points overlap","PCASMSetOverlap",osm->overlap,&ovl,&flg);CHKERRQ(ierr); 507 if (flg) {ierr = PCASMSetOverlap(pc,ovl);CHKERRQ(ierr); } 508 flg = PETSC_FALSE; 509 ierr = PetscOptionsEnum("-pc_asm_type","Type of restriction/extension","PCASMSetType",PCASMTypes,(PetscEnum)osm->type,(PetscEnum*)&asmtype,&flg);CHKERRQ(ierr); 510 if (flg) {ierr = PCASMSetType(pc,asmtype);CHKERRQ(ierr); } 511 ierr = PetscOptionsTail();CHKERRQ(ierr); 512 PetscFunctionReturn(0); 513 } 514 515 /*------------------------------------------------------------------------------------*/ 516 517 EXTERN_C_BEGIN 518 #undef __FUNCT__ 519 #define __FUNCT__ "PCASMSetLocalSubdomains_ASM" 520 PetscErrorCode PETSCKSP_DLLEXPORT PCASMSetLocalSubdomains_ASM(PC pc,PetscInt n,IS is[],IS is_local[]) 521 { 522 PC_ASM *osm = (PC_ASM*)pc->data; 523 PetscErrorCode ierr; 524 PetscInt i; 525 526 PetscFunctionBegin; 527 if (n < 1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Each process must have 1 or more blocks, n = %D",n); 528 if (pc->setupcalled && (n != osm->n_local_true || is)) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONGSTATE,"PCASMSetLocalSubdomains() should be called before calling PCSetUp()."); 529 530 if (!pc->setupcalled) { 531 if (is) { 532 for (i=0; i<n; i++) {ierr = PetscObjectReference((PetscObject)is[i]);CHKERRQ(ierr);} 533 } 534 if (is_local) { 535 for (i=0; i<n; i++) {ierr = PetscObjectReference((PetscObject)is_local[i]);CHKERRQ(ierr);} 536 } 537 if (osm->is) { 538 ierr = PCASMDestroySubdomains(osm->n_local_true,osm->is,osm->is_local);CHKERRQ(ierr); 539 } 540 osm->n_local_true = n; 541 osm->is = 0; 542 osm->is_local = 0; 543 if (is) { 544 ierr = PetscMalloc(n*sizeof(IS *),&osm->is);CHKERRQ(ierr); 545 for (i=0; i<n; i++) { osm->is[i] = is[i]; } 546 /* Flag indicating that the user has set overlapping subdomains so PCASM should not increase their size. */ 547 osm->overlap = -1; 548 } 549 if (is_local) { 550 ierr = PetscMalloc(n*sizeof(IS *),&osm->is_local);CHKERRQ(ierr); 551 for (i=0; i<n; i++) { osm->is_local[i] = is_local[i]; } 552 } 553 } 554 PetscFunctionReturn(0); 555 } 556 EXTERN_C_END 557 558 EXTERN_C_BEGIN 559 #undef __FUNCT__ 560 #define __FUNCT__ "PCASMSetTotalSubdomains_ASM" 561 PetscErrorCode PETSCKSP_DLLEXPORT PCASMSetTotalSubdomains_ASM(PC pc,PetscInt N,IS *is,IS *is_local) 562 { 563 PC_ASM *osm = (PC_ASM*)pc->data; 564 PetscErrorCode ierr; 565 PetscMPIInt rank,size; 566 PetscInt n; 567 568 PetscFunctionBegin; 569 if (N < 1) SETERRQ1(((PetscObject)pc)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Number of total blocks must be > 0, N = %D",N); 570 if (is || is_local) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_SUP,"Use PCASMSetLocalSubdomains() to set specific index sets\n\they cannot be set globally yet."); 571 572 /* 573 Split the subdomains equally among all processors 574 */ 575 ierr = MPI_Comm_rank(((PetscObject)pc)->comm,&rank);CHKERRQ(ierr); 576 ierr = MPI_Comm_size(((PetscObject)pc)->comm,&size);CHKERRQ(ierr); 577 n = N/size + ((N % size) > rank); 578 if (!n) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Process %d must have at least one block: total processors %d total blocks %D",(int)rank,(int)size,N); 579 if (pc->setupcalled && n != osm->n_local_true) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"PCASMSetTotalSubdomains() should be called before PCSetUp()."); 580 if (!pc->setupcalled) { 581 if (osm->is) { 582 ierr = PCASMDestroySubdomains(osm->n_local_true,osm->is,osm->is_local);CHKERRQ(ierr); 583 } 584 osm->n_local_true = n; 585 osm->is = 0; 586 osm->is_local = 0; 587 } 588 PetscFunctionReturn(0); 589 } 590 EXTERN_C_END 591 592 EXTERN_C_BEGIN 593 #undef __FUNCT__ 594 #define __FUNCT__ "PCASMSetOverlap_ASM" 595 PetscErrorCode PETSCKSP_DLLEXPORT PCASMSetOverlap_ASM(PC pc,PetscInt ovl) 596 { 597 PC_ASM *osm = (PC_ASM*)pc->data; 598 599 PetscFunctionBegin; 600 if (ovl < 0) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Negative overlap value requested"); 601 if (pc->setupcalled && ovl != osm->overlap) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONGSTATE,"PCASMSetOverlap() should be called before PCSetUp()."); 602 if (!pc->setupcalled) { 603 osm->overlap = ovl; 604 } 605 PetscFunctionReturn(0); 606 } 607 EXTERN_C_END 608 609 EXTERN_C_BEGIN 610 #undef __FUNCT__ 611 #define __FUNCT__ "PCASMSetType_ASM" 612 PetscErrorCode PETSCKSP_DLLEXPORT PCASMSetType_ASM(PC pc,PCASMType type) 613 { 614 PC_ASM *osm = (PC_ASM*)pc->data; 615 616 PetscFunctionBegin; 617 osm->type = type; 618 osm->type_set = PETSC_TRUE; 619 PetscFunctionReturn(0); 620 } 621 EXTERN_C_END 622 623 EXTERN_C_BEGIN 624 #undef __FUNCT__ 625 #define __FUNCT__ "PCASMSetSortIndices_ASM" 626 PetscErrorCode PETSCKSP_DLLEXPORT PCASMSetSortIndices_ASM(PC pc,PetscTruth doSort) 627 { 628 PC_ASM *osm = (PC_ASM*)pc->data; 629 630 PetscFunctionBegin; 631 osm->sort_indices = doSort; 632 PetscFunctionReturn(0); 633 } 634 EXTERN_C_END 635 636 EXTERN_C_BEGIN 637 #undef __FUNCT__ 638 #define __FUNCT__ "PCASMGetSubKSP_ASM" 639 PetscErrorCode PETSCKSP_DLLEXPORT PCASMGetSubKSP_ASM(PC pc,PetscInt *n_local,PetscInt *first_local,KSP **ksp) 640 { 641 PC_ASM *osm = (PC_ASM*)pc->data; 642 PetscErrorCode ierr; 643 644 PetscFunctionBegin; 645 if (osm->n_local_true < 1) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ORDER,"Need to call PCSetUP() on PC (or KSPSetUp() on the outer KSP object) before calling here"); 646 647 if (n_local) { 648 *n_local = osm->n_local_true; 649 } 650 if (first_local) { 651 ierr = MPI_Scan(&osm->n_local_true,first_local,1,MPIU_INT,MPI_SUM,((PetscObject)pc)->comm);CHKERRQ(ierr); 652 *first_local -= osm->n_local_true; 653 } 654 if (ksp) { 655 /* Assume that local solves are now different; not necessarily 656 true though! This flag is used only for PCView_ASM() */ 657 *ksp = osm->ksp; 658 osm->same_local_solves = PETSC_FALSE; 659 } 660 PetscFunctionReturn(0); 661 } 662 EXTERN_C_END 663 664 665 #undef __FUNCT__ 666 #define __FUNCT__ "PCASMSetLocalSubdomains" 667 /*@C 668 PCASMSetLocalSubdomains - Sets the local subdomains (for this processor 669 only) for the additive Schwarz preconditioner. 670 671 Collective on PC 672 673 Input Parameters: 674 + pc - the preconditioner context 675 . n - the number of subdomains for this processor (default value = 1) 676 . is - the index sets that define the subdomains for this processor 677 (or PETSC_NULL for PETSc to determine subdomains) 678 - is_local - the index sets that define the local part of the subdomains for this processor 679 (or PETSC_NULL to use the default of 1 subdomain per process) 680 681 Notes: 682 The IS numbering is in the parallel, global numbering of the vector. 683 684 By default the ASM preconditioner uses 1 block per processor. 685 686 Use PCASMSetTotalSubdomains() to set the subdomains for all processors. 687 688 Level: advanced 689 690 .keywords: PC, ASM, set, local, subdomains, additive Schwarz 691 692 .seealso: PCASMSetTotalSubdomains(), PCASMSetOverlap(), PCASMGetSubKSP(), 693 PCASMCreateSubdomains2D(), PCASMGetLocalSubdomains() 694 @*/ 695 PetscErrorCode PETSCKSP_DLLEXPORT PCASMSetLocalSubdomains(PC pc,PetscInt n,IS is[],IS is_local[]) 696 { 697 PetscErrorCode ierr,(*f)(PC,PetscInt,IS[],IS[]); 698 699 PetscFunctionBegin; 700 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 701 ierr = PetscObjectQueryFunction((PetscObject)pc,"PCASMSetLocalSubdomains_C",(void (**)(void))&f);CHKERRQ(ierr); 702 if (f) { 703 ierr = (*f)(pc,n,is,is_local);CHKERRQ(ierr); 704 } 705 PetscFunctionReturn(0); 706 } 707 708 #undef __FUNCT__ 709 #define __FUNCT__ "PCASMSetTotalSubdomains" 710 /*@C 711 PCASMSetTotalSubdomains - Sets the subdomains for all processor for the 712 additive Schwarz preconditioner. Either all or no processors in the 713 PC communicator must call this routine, with the same index sets. 714 715 Collective on PC 716 717 Input Parameters: 718 + pc - the preconditioner context 719 . n - the number of subdomains for all processors 720 . is - the index sets that define the subdomains for all processor 721 (or PETSC_NULL for PETSc to determine subdomains) 722 - is_local - the index sets that define the local part of the subdomains for this processor 723 (or PETSC_NULL to use the default of 1 subdomain per process) 724 725 Options Database Key: 726 To set the total number of subdomain blocks rather than specify the 727 index sets, use the option 728 . -pc_asm_blocks <blks> - Sets total blocks 729 730 Notes: 731 Currently you cannot use this to set the actual subdomains with the argument is. 732 733 By default the ASM preconditioner uses 1 block per processor. 734 735 These index sets cannot be destroyed until after completion of the 736 linear solves for which the ASM preconditioner is being used. 737 738 Use PCASMSetLocalSubdomains() to set local subdomains. 739 740 Level: advanced 741 742 .keywords: PC, ASM, set, total, global, subdomains, additive Schwarz 743 744 .seealso: PCASMSetLocalSubdomains(), PCASMSetOverlap(), PCASMGetSubKSP(), 745 PCASMCreateSubdomains2D() 746 @*/ 747 PetscErrorCode PETSCKSP_DLLEXPORT PCASMSetTotalSubdomains(PC pc,PetscInt N,IS is[],IS is_local[]) 748 { 749 PetscErrorCode ierr,(*f)(PC,PetscInt,IS[],IS[]); 750 751 PetscFunctionBegin; 752 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 753 ierr = PetscObjectQueryFunction((PetscObject)pc,"PCASMSetTotalSubdomains_C",(void (**)(void))&f);CHKERRQ(ierr); 754 if (f) { 755 ierr = (*f)(pc,N,is,is_local);CHKERRQ(ierr); 756 } 757 PetscFunctionReturn(0); 758 } 759 760 #undef __FUNCT__ 761 #define __FUNCT__ "PCASMSetOverlap" 762 /*@ 763 PCASMSetOverlap - Sets the overlap between a pair of subdomains for the 764 additive Schwarz preconditioner. Either all or no processors in the 765 PC communicator must call this routine. 766 767 Logically Collective on PC 768 769 Input Parameters: 770 + pc - the preconditioner context 771 - ovl - the amount of overlap between subdomains (ovl >= 0, default value = 1) 772 773 Options Database Key: 774 . -pc_asm_overlap <ovl> - Sets overlap 775 776 Notes: 777 By default the ASM preconditioner uses 1 block per processor. To use 778 multiple blocks per perocessor, see PCASMSetTotalSubdomains() and 779 PCASMSetLocalSubdomains() (and the option -pc_asm_blocks <blks>). 780 781 The overlap defaults to 1, so if one desires that no additional 782 overlap be computed beyond what may have been set with a call to 783 PCASMSetTotalSubdomains() or PCASMSetLocalSubdomains(), then ovl 784 must be set to be 0. In particular, if one does not explicitly set 785 the subdomains an application code, then all overlap would be computed 786 internally by PETSc, and using an overlap of 0 would result in an ASM 787 variant that is equivalent to the block Jacobi preconditioner. 788 789 Note that one can define initial index sets with any overlap via 790 PCASMSetTotalSubdomains() or PCASMSetLocalSubdomains(); the routine 791 PCASMSetOverlap() merely allows PETSc to extend that overlap further 792 if desired. 793 794 Level: intermediate 795 796 .keywords: PC, ASM, set, overlap 797 798 .seealso: PCASMSetTotalSubdomains(), PCASMSetLocalSubdomains(), PCASMGetSubKSP(), 799 PCASMCreateSubdomains2D(), PCASMGetLocalSubdomains() 800 @*/ 801 PetscErrorCode PETSCKSP_DLLEXPORT PCASMSetOverlap(PC pc,PetscInt ovl) 802 { 803 PetscErrorCode ierr,(*f)(PC,PetscInt); 804 805 PetscFunctionBegin; 806 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 807 PetscValidLogicalCollectiveInt(pc,ovl,2); 808 ierr = PetscObjectQueryFunction((PetscObject)pc,"PCASMSetOverlap_C",(void (**)(void))&f);CHKERRQ(ierr); 809 if (f) { 810 ierr = (*f)(pc,ovl);CHKERRQ(ierr); 811 } 812 PetscFunctionReturn(0); 813 } 814 815 #undef __FUNCT__ 816 #define __FUNCT__ "PCASMSetType" 817 /*@ 818 PCASMSetType - Sets the type of restriction and interpolation used 819 for local problems in the additive Schwarz method. 820 821 Logically Collective on PC 822 823 Input Parameters: 824 + pc - the preconditioner context 825 - type - variant of ASM, one of 826 .vb 827 PC_ASM_BASIC - full interpolation and restriction 828 PC_ASM_RESTRICT - full restriction, local processor interpolation 829 PC_ASM_INTERPOLATE - full interpolation, local processor restriction 830 PC_ASM_NONE - local processor restriction and interpolation 831 .ve 832 833 Options Database Key: 834 . -pc_asm_type [basic,restrict,interpolate,none] - Sets ASM type 835 836 Level: intermediate 837 838 .keywords: PC, ASM, set, type 839 840 .seealso: PCASMSetTotalSubdomains(), PCASMSetTotalSubdomains(), PCASMGetSubKSP(), 841 PCASMCreateSubdomains2D() 842 @*/ 843 PetscErrorCode PETSCKSP_DLLEXPORT PCASMSetType(PC pc,PCASMType type) 844 { 845 PetscErrorCode ierr,(*f)(PC,PCASMType); 846 847 PetscFunctionBegin; 848 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 849 PetscValidLogicalCollectiveEnum(pc,type,2); 850 ierr = PetscObjectQueryFunction((PetscObject)pc,"PCASMSetType_C",(void (**)(void))&f);CHKERRQ(ierr); 851 if (f) { 852 ierr = (*f)(pc,type);CHKERRQ(ierr); 853 } 854 PetscFunctionReturn(0); 855 } 856 857 #undef __FUNCT__ 858 #define __FUNCT__ "PCASMSetSortIndices" 859 /*@ 860 PCASMSetSortIndices - Determines whether subdomain indices are sorted. 861 862 Logically Collective on PC 863 864 Input Parameters: 865 + pc - the preconditioner context 866 - doSort - sort the subdomain indices 867 868 Level: intermediate 869 870 .keywords: PC, ASM, set, type 871 872 .seealso: PCASMSetLocalSubdomains(), PCASMSetTotalSubdomains(), PCASMGetSubKSP(), 873 PCASMCreateSubdomains2D() 874 @*/ 875 PetscErrorCode PETSCKSP_DLLEXPORT PCASMSetSortIndices(PC pc,PetscTruth doSort) 876 { 877 PetscErrorCode ierr,(*f)(PC,PetscTruth); 878 879 PetscFunctionBegin; 880 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 881 PetscValidLogicalCollectiveTruth(pc,doSort,2); 882 ierr = PetscObjectQueryFunction((PetscObject)pc,"PCASMSetSortIndices_C",(void (**)(void))&f);CHKERRQ(ierr); 883 if (f) { 884 ierr = (*f)(pc,doSort);CHKERRQ(ierr); 885 } 886 PetscFunctionReturn(0); 887 } 888 889 #undef __FUNCT__ 890 #define __FUNCT__ "PCASMGetSubKSP" 891 /*@C 892 PCASMGetSubKSP - Gets the local KSP contexts for all blocks on 893 this processor. 894 895 Collective on PC iff first_local is requested 896 897 Input Parameter: 898 . pc - the preconditioner context 899 900 Output Parameters: 901 + n_local - the number of blocks on this processor or PETSC_NULL 902 . first_local - the global number of the first block on this processor or PETSC_NULL, 903 all processors must request or all must pass PETSC_NULL 904 - ksp - the array of KSP contexts 905 906 Note: 907 After PCASMGetSubKSP() the array of KSPes is not to be freed 908 909 Currently for some matrix implementations only 1 block per processor 910 is supported. 911 912 You must call KSPSetUp() before calling PCASMGetSubKSP(). 913 914 Level: advanced 915 916 .keywords: PC, ASM, additive Schwarz, get, sub, KSP, context 917 918 .seealso: PCASMSetTotalSubdomains(), PCASMSetTotalSubdomains(), PCASMSetOverlap(), 919 PCASMCreateSubdomains2D(), 920 @*/ 921 PetscErrorCode PETSCKSP_DLLEXPORT PCASMGetSubKSP(PC pc,PetscInt *n_local,PetscInt *first_local,KSP *ksp[]) 922 { 923 PetscErrorCode ierr,(*f)(PC,PetscInt*,PetscInt*,KSP **); 924 925 PetscFunctionBegin; 926 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 927 ierr = PetscObjectQueryFunction((PetscObject)pc,"PCASMGetSubKSP_C",(void (**)(void))&f);CHKERRQ(ierr); 928 if (f) { 929 ierr = (*f)(pc,n_local,first_local,ksp);CHKERRQ(ierr); 930 } else SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONG,"Cannot get subksp for this type of PC"); 931 PetscFunctionReturn(0); 932 } 933 934 /* -------------------------------------------------------------------------------------*/ 935 /*MC 936 PCASM - Use the (restricted) additive Schwarz method, each block is (approximately) solved with 937 its own KSP object. 938 939 Options Database Keys: 940 + -pc_asm_truelocal - Activates PCASMSetUseTrueLocal() 941 . -pc_asm_blocks <blks> - Sets total blocks 942 . -pc_asm_overlap <ovl> - Sets overlap 943 - -pc_asm_type [basic,restrict,interpolate,none] - Sets ASM type 944 945 IMPORTANT: If you run with, for example, 3 blocks on 1 processor or 3 blocks on 3 processors you 946 will get a different convergence rate due to the default option of -pc_asm_type restrict. Use 947 -pc_asm_type basic to use the standard ASM. 948 949 Notes: Each processor can have one or more blocks, but a block cannot be shared by more 950 than one processor. Defaults to one block per processor. 951 952 To set options on the solvers for each block append -sub_ to all the KSP, and PC 953 options database keys. For example, -sub_pc_type ilu -sub_pc_factor_levels 1 -sub_ksp_type preonly 954 955 To set the options on the solvers separate for each block call PCASMGetSubKSP() 956 and set the options directly on the resulting KSP object (you can access its PC 957 with KSPGetPC()) 958 959 960 Level: beginner 961 962 Concepts: additive Schwarz method 963 964 References: 965 An additive variant of the Schwarz alternating method for the case of many subregions 966 M Dryja, OB Widlund - Courant Institute, New York University Technical report 967 968 Domain Decompositions: Parallel Multilevel Methods for Elliptic Partial Differential Equations, 969 Barry Smith, Petter Bjorstad, and William Gropp, Cambridge University Press, ISBN 0-521-49589-X. 970 971 .seealso: PCCreate(), PCSetType(), PCType (for list of available types), PC, 972 PCBJACOBI, PCASMSetUseTrueLocal(), PCASMGetSubKSP(), PCASMSetLocalSubdomains(), 973 PCASMSetTotalSubdomains(), PCSetModifySubmatrices(), PCASMSetOverlap(), PCASMSetType() 974 975 M*/ 976 977 EXTERN_C_BEGIN 978 #undef __FUNCT__ 979 #define __FUNCT__ "PCCreate_ASM" 980 PetscErrorCode PETSCKSP_DLLEXPORT PCCreate_ASM(PC pc) 981 { 982 PetscErrorCode ierr; 983 PC_ASM *osm; 984 985 PetscFunctionBegin; 986 ierr = PetscNewLog(pc,PC_ASM,&osm);CHKERRQ(ierr); 987 osm->n = PETSC_DECIDE; 988 osm->n_local = 0; 989 osm->n_local_true = 0; 990 osm->overlap = 1; 991 osm->ksp = 0; 992 osm->restriction = 0; 993 osm->localization = 0; 994 osm->prolongation = 0; 995 osm->x = 0; 996 osm->y = 0; 997 osm->y_local = 0; 998 osm->is = 0; 999 osm->is_local = 0; 1000 osm->mat = 0; 1001 osm->pmat = 0; 1002 osm->type = PC_ASM_RESTRICT; 1003 osm->same_local_solves = PETSC_TRUE; 1004 osm->sort_indices = PETSC_TRUE; 1005 1006 pc->data = (void*)osm; 1007 pc->ops->apply = PCApply_ASM; 1008 pc->ops->applytranspose = PCApplyTranspose_ASM; 1009 pc->ops->setup = PCSetUp_ASM; 1010 pc->ops->destroy = PCDestroy_ASM; 1011 pc->ops->setfromoptions = PCSetFromOptions_ASM; 1012 pc->ops->setuponblocks = PCSetUpOnBlocks_ASM; 1013 pc->ops->view = PCView_ASM; 1014 pc->ops->applyrichardson = 0; 1015 1016 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCASMSetLocalSubdomains_C","PCASMSetLocalSubdomains_ASM", 1017 PCASMSetLocalSubdomains_ASM);CHKERRQ(ierr); 1018 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCASMSetTotalSubdomains_C","PCASMSetTotalSubdomains_ASM", 1019 PCASMSetTotalSubdomains_ASM);CHKERRQ(ierr); 1020 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCASMSetOverlap_C","PCASMSetOverlap_ASM", 1021 PCASMSetOverlap_ASM);CHKERRQ(ierr); 1022 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCASMSetType_C","PCASMSetType_ASM", 1023 PCASMSetType_ASM);CHKERRQ(ierr); 1024 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCASMSetSortIndices_C","PCASMSetSortIndices_ASM", 1025 PCASMSetSortIndices_ASM);CHKERRQ(ierr); 1026 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCASMGetSubKSP_C","PCASMGetSubKSP_ASM", 1027 PCASMGetSubKSP_ASM);CHKERRQ(ierr); 1028 PetscFunctionReturn(0); 1029 } 1030 EXTERN_C_END 1031 1032 1033 #undef __FUNCT__ 1034 #define __FUNCT__ "PCASMCreateSubdomains" 1035 /*@C 1036 PCASMCreateSubdomains - Creates the index sets for the overlapping Schwarz 1037 preconditioner for a any problem on a general grid. 1038 1039 Collective 1040 1041 Input Parameters: 1042 + A - The global matrix operator 1043 - n - the number of local blocks 1044 1045 Output Parameters: 1046 . outis - the array of index sets defining the subdomains 1047 1048 Level: advanced 1049 1050 Note: this generates nonoverlapping subdomains; the PCASM will generate the overlap 1051 from these if you use PCASMSetLocalSubdomains() 1052 1053 In the Fortran version you must provide the array outis[] already allocated of length n. 1054 1055 .keywords: PC, ASM, additive Schwarz, create, subdomains, unstructured grid 1056 1057 .seealso: PCASMSetLocalSubdomains(), PCASMDestroySubdomains() 1058 @*/ 1059 PetscErrorCode PETSCKSP_DLLEXPORT PCASMCreateSubdomains(Mat A, PetscInt n, IS* outis[]) 1060 { 1061 MatPartitioning mpart; 1062 const char *prefix; 1063 PetscErrorCode (*f)(Mat,PetscTruth*,MatReuse,Mat*); 1064 PetscMPIInt size; 1065 PetscInt i,j,rstart,rend,bs; 1066 PetscTruth iscopy = PETSC_FALSE,isbaij = PETSC_FALSE,foundpart = PETSC_FALSE; 1067 Mat Ad = PETSC_NULL, adj; 1068 IS ispart,isnumb,*is; 1069 PetscErrorCode ierr; 1070 1071 PetscFunctionBegin; 1072 PetscValidHeaderSpecific(A,MAT_CLASSID,1); 1073 PetscValidPointer(outis,3); 1074 if (n < 1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"number of local blocks must be > 0, n = %D",n); 1075 1076 /* Get prefix, row distribution, and block size */ 1077 ierr = MatGetOptionsPrefix(A,&prefix);CHKERRQ(ierr); 1078 ierr = MatGetOwnershipRange(A,&rstart,&rend);CHKERRQ(ierr); 1079 ierr = MatGetBlockSize(A,&bs);CHKERRQ(ierr); 1080 if (rstart/bs*bs != rstart || rend/bs*bs != rend) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"bad row distribution [%D,%D) for matrix block size %D",rstart,rend,bs); 1081 1082 /* Get diagonal block from matrix if possible */ 1083 ierr = MPI_Comm_size(((PetscObject)A)->comm,&size);CHKERRQ(ierr); 1084 ierr = PetscObjectQueryFunction((PetscObject)A,"MatGetDiagonalBlock_C",(void (**)(void))&f);CHKERRQ(ierr); 1085 if (f) { 1086 ierr = (*f)(A,&iscopy,MAT_INITIAL_MATRIX,&Ad);CHKERRQ(ierr); 1087 } else if (size == 1) { 1088 iscopy = PETSC_FALSE; Ad = A; 1089 } else { 1090 iscopy = PETSC_FALSE; Ad = PETSC_NULL; 1091 } 1092 if (Ad) { 1093 ierr = PetscTypeCompare((PetscObject)Ad,MATSEQBAIJ,&isbaij);CHKERRQ(ierr); 1094 if (!isbaij) {ierr = PetscTypeCompare((PetscObject)Ad,MATSEQSBAIJ,&isbaij);CHKERRQ(ierr);} 1095 } 1096 if (Ad && n > 1) { 1097 PetscTruth match,done; 1098 /* Try to setup a good matrix partitioning if available */ 1099 ierr = MatPartitioningCreate(PETSC_COMM_SELF,&mpart);CHKERRQ(ierr); 1100 ierr = PetscObjectSetOptionsPrefix((PetscObject)mpart,prefix);CHKERRQ(ierr); 1101 ierr = MatPartitioningSetFromOptions(mpart);CHKERRQ(ierr); 1102 ierr = PetscTypeCompare((PetscObject)mpart,MATPARTITIONINGCURRENT,&match);CHKERRQ(ierr); 1103 if (!match) { 1104 ierr = PetscTypeCompare((PetscObject)mpart,MATPARTITIONINGSQUARE,&match);CHKERRQ(ierr); 1105 } 1106 if (!match) { /* assume a "good" partitioner is available */ 1107 PetscInt na,*ia,*ja; 1108 ierr = MatGetRowIJ(Ad,0,PETSC_TRUE,isbaij,&na,&ia,&ja,&done);CHKERRQ(ierr); 1109 if (done) { 1110 /* Build adjacency matrix by hand. Unfortunately a call to 1111 MatConvert(Ad,MATMPIADJ,MAT_INITIAL_MATRIX,&adj) will 1112 remove the block-aij structure and we cannot expect 1113 MatPartitioning to split vertices as we need */ 1114 PetscInt i,j,*row,len,nnz,cnt,*iia=0,*jja=0; 1115 nnz = 0; 1116 for (i=0; i<na; i++) { /* count number of nonzeros */ 1117 len = ia[i+1] - ia[i]; 1118 row = ja + ia[i]; 1119 for (j=0; j<len; j++) { 1120 if (row[j] == i) { /* don't count diagonal */ 1121 len--; break; 1122 } 1123 } 1124 nnz += len; 1125 } 1126 ierr = PetscMalloc((na+1)*sizeof(PetscInt),&iia);CHKERRQ(ierr); 1127 ierr = PetscMalloc((nnz)*sizeof(PetscInt),&jja);CHKERRQ(ierr); 1128 nnz = 0; 1129 iia[0] = 0; 1130 for (i=0; i<na; i++) { /* fill adjacency */ 1131 cnt = 0; 1132 len = ia[i+1] - ia[i]; 1133 row = ja + ia[i]; 1134 for (j=0; j<len; j++) { 1135 if (row[j] != i) { /* if not diagonal */ 1136 jja[nnz+cnt++] = row[j]; 1137 } 1138 } 1139 nnz += cnt; 1140 iia[i+1] = nnz; 1141 } 1142 /* Partitioning of the adjacency matrix */ 1143 ierr = MatCreateMPIAdj(PETSC_COMM_SELF,na,na,iia,jja,PETSC_NULL,&adj);CHKERRQ(ierr); 1144 ierr = MatPartitioningSetAdjacency(mpart,adj);CHKERRQ(ierr); 1145 ierr = MatPartitioningSetNParts(mpart,n);CHKERRQ(ierr); 1146 ierr = MatPartitioningApply(mpart,&ispart);CHKERRQ(ierr); 1147 ierr = ISPartitioningToNumbering(ispart,&isnumb);CHKERRQ(ierr); 1148 ierr = MatDestroy(adj);CHKERRQ(ierr); 1149 foundpart = PETSC_TRUE; 1150 } 1151 ierr = MatRestoreRowIJ(Ad,0,PETSC_TRUE,isbaij,&na,&ia,&ja,&done);CHKERRQ(ierr); 1152 } 1153 ierr = MatPartitioningDestroy(mpart);CHKERRQ(ierr); 1154 } 1155 if (iscopy) {ierr = MatDestroy(Ad);CHKERRQ(ierr);} 1156 1157 ierr = PetscMalloc(n*sizeof(IS),&is);CHKERRQ(ierr); 1158 *outis = is; 1159 1160 if (!foundpart) { 1161 1162 /* Partitioning by contiguous chunks of rows */ 1163 1164 PetscInt mbs = (rend-rstart)/bs; 1165 PetscInt start = rstart; 1166 for (i=0; i<n; i++) { 1167 PetscInt count = (mbs/n + ((mbs % n) > i)) * bs; 1168 ierr = ISCreateStride(PETSC_COMM_SELF,count,start,1,&is[i]);CHKERRQ(ierr); 1169 start += count; 1170 } 1171 1172 } else { 1173 1174 /* Partitioning by adjacency of diagonal block */ 1175 1176 const PetscInt *numbering; 1177 PetscInt *count,nidx,*indices,*newidx,start=0; 1178 /* Get node count in each partition */ 1179 ierr = PetscMalloc(n*sizeof(PetscInt),&count);CHKERRQ(ierr); 1180 ierr = ISPartitioningCount(ispart,n,count);CHKERRQ(ierr); 1181 if (isbaij && bs > 1) { /* adjust for the block-aij case */ 1182 for (i=0; i<n; i++) count[i] *= bs; 1183 } 1184 /* Build indices from node numbering */ 1185 ierr = ISGetLocalSize(isnumb,&nidx);CHKERRQ(ierr); 1186 ierr = PetscMalloc(nidx*sizeof(PetscInt),&indices);CHKERRQ(ierr); 1187 for (i=0; i<nidx; i++) indices[i] = i; /* needs to be initialized */ 1188 ierr = ISGetIndices(isnumb,&numbering);CHKERRQ(ierr); 1189 ierr = PetscSortIntWithPermutation(nidx,numbering,indices);CHKERRQ(ierr); 1190 ierr = ISRestoreIndices(isnumb,&numbering);CHKERRQ(ierr); 1191 if (isbaij && bs > 1) { /* adjust for the block-aij case */ 1192 ierr = PetscMalloc(nidx*bs*sizeof(PetscInt),&newidx);CHKERRQ(ierr); 1193 for (i=0; i<nidx; i++) 1194 for (j=0; j<bs; j++) 1195 newidx[i*bs+j] = indices[i]*bs + j; 1196 ierr = PetscFree(indices);CHKERRQ(ierr); 1197 nidx *= bs; 1198 indices = newidx; 1199 } 1200 /* Shift to get global indices */ 1201 for (i=0; i<nidx; i++) indices[i] += rstart; 1202 1203 /* Build the index sets for each block */ 1204 for (i=0; i<n; i++) { 1205 ierr = ISCreateGeneral(PETSC_COMM_SELF,count[i],&indices[start],&is[i]);CHKERRQ(ierr); 1206 ierr = ISSort(is[i]);CHKERRQ(ierr); 1207 start += count[i]; 1208 } 1209 1210 ierr = PetscFree(count); 1211 ierr = PetscFree(indices); 1212 ierr = ISDestroy(isnumb);CHKERRQ(ierr); 1213 ierr = ISDestroy(ispart);CHKERRQ(ierr); 1214 1215 } 1216 1217 PetscFunctionReturn(0); 1218 } 1219 1220 #undef __FUNCT__ 1221 #define __FUNCT__ "PCASMDestroySubdomains" 1222 /*@C 1223 PCASMDestroySubdomains - Destroys the index sets created with 1224 PCASMCreateSubdomains(). Should be called after setting subdomains 1225 with PCASMSetLocalSubdomains(). 1226 1227 Collective 1228 1229 Input Parameters: 1230 + n - the number of index sets 1231 . is - the array of index sets 1232 - is_local - the array of local index sets, can be PETSC_NULL 1233 1234 Level: advanced 1235 1236 .keywords: PC, ASM, additive Schwarz, create, subdomains, unstructured grid 1237 1238 .seealso: PCASMCreateSubdomains(), PCASMSetLocalSubdomains() 1239 @*/ 1240 PetscErrorCode PETSCKSP_DLLEXPORT PCASMDestroySubdomains(PetscInt n, IS is[], IS is_local[]) 1241 { 1242 PetscInt i; 1243 PetscErrorCode ierr; 1244 PetscFunctionBegin; 1245 if (n <= 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"n must be > 0: n = %D",n); 1246 PetscValidPointer(is,2); 1247 for (i=0; i<n; i++) { ierr = ISDestroy(is[i]);CHKERRQ(ierr); } 1248 ierr = PetscFree(is);CHKERRQ(ierr); 1249 if (is_local) { 1250 PetscValidPointer(is_local,3); 1251 for (i=0; i<n; i++) { ierr = ISDestroy(is_local[i]);CHKERRQ(ierr); } 1252 ierr = PetscFree(is_local);CHKERRQ(ierr); 1253 } 1254 PetscFunctionReturn(0); 1255 } 1256 1257 #undef __FUNCT__ 1258 #define __FUNCT__ "PCASMCreateSubdomains2D" 1259 /*@ 1260 PCASMCreateSubdomains2D - Creates the index sets for the overlapping Schwarz 1261 preconditioner for a two-dimensional problem on a regular grid. 1262 1263 Not Collective 1264 1265 Input Parameters: 1266 + m, n - the number of mesh points in the x and y directions 1267 . M, N - the number of subdomains in the x and y directions 1268 . dof - degrees of freedom per node 1269 - overlap - overlap in mesh lines 1270 1271 Output Parameters: 1272 + Nsub - the number of subdomains created 1273 . is - array of index sets defining overlapping (if overlap > 0) subdomains 1274 - is_local - array of index sets defining non-overlapping subdomains 1275 1276 Note: 1277 Presently PCAMSCreateSubdomains2d() is valid only for sequential 1278 preconditioners. More general related routines are 1279 PCASMSetTotalSubdomains() and PCASMSetLocalSubdomains(). 1280 1281 Level: advanced 1282 1283 .keywords: PC, ASM, additive Schwarz, create, subdomains, 2D, regular grid 1284 1285 .seealso: PCASMSetTotalSubdomains(), PCASMSetLocalSubdomains(), PCASMGetSubKSP(), 1286 PCASMSetOverlap() 1287 @*/ 1288 PetscErrorCode PETSCKSP_DLLEXPORT PCASMCreateSubdomains2D(PetscInt m,PetscInt n,PetscInt M,PetscInt N,PetscInt dof,PetscInt overlap,PetscInt *Nsub,IS **is,IS **is_local) 1289 { 1290 PetscInt i,j,height,width,ystart,xstart,yleft,yright,xleft,xright,loc_outer; 1291 PetscErrorCode ierr; 1292 PetscInt nidx,*idx,loc,ii,jj,count; 1293 1294 PetscFunctionBegin; 1295 if (dof != 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP," "); 1296 1297 *Nsub = N*M; 1298 ierr = PetscMalloc((*Nsub)*sizeof(IS*),is);CHKERRQ(ierr); 1299 ierr = PetscMalloc((*Nsub)*sizeof(IS*),is_local);CHKERRQ(ierr); 1300 ystart = 0; 1301 loc_outer = 0; 1302 for (i=0; i<N; i++) { 1303 height = n/N + ((n % N) > i); /* height of subdomain */ 1304 if (height < 2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Too many N subdomains for mesh dimension n"); 1305 yleft = ystart - overlap; if (yleft < 0) yleft = 0; 1306 yright = ystart + height + overlap; if (yright > n) yright = n; 1307 xstart = 0; 1308 for (j=0; j<M; j++) { 1309 width = m/M + ((m % M) > j); /* width of subdomain */ 1310 if (width < 2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Too many M subdomains for mesh dimension m"); 1311 xleft = xstart - overlap; if (xleft < 0) xleft = 0; 1312 xright = xstart + width + overlap; if (xright > m) xright = m; 1313 nidx = (xright - xleft)*(yright - yleft); 1314 ierr = PetscMalloc(nidx*sizeof(PetscInt),&idx);CHKERRQ(ierr); 1315 loc = 0; 1316 for (ii=yleft; ii<yright; ii++) { 1317 count = m*ii + xleft; 1318 for (jj=xleft; jj<xright; jj++) { 1319 idx[loc++] = count++; 1320 } 1321 } 1322 ierr = ISCreateGeneral(PETSC_COMM_SELF,nidx,idx,(*is)+loc_outer);CHKERRQ(ierr); 1323 if (overlap == 0) { 1324 ierr = PetscObjectReference((PetscObject)(*is)[loc_outer]);CHKERRQ(ierr); 1325 (*is_local)[loc_outer] = (*is)[loc_outer]; 1326 } else { 1327 for (loc=0,ii=ystart; ii<ystart+height; ii++) { 1328 for (jj=xstart; jj<xstart+width; jj++) { 1329 idx[loc++] = m*ii + jj; 1330 } 1331 } 1332 ierr = ISCreateGeneral(PETSC_COMM_SELF,loc,idx,*is_local+loc_outer);CHKERRQ(ierr); 1333 } 1334 ierr = PetscFree(idx);CHKERRQ(ierr); 1335 xstart += width; 1336 loc_outer++; 1337 } 1338 ystart += height; 1339 } 1340 for (i=0; i<*Nsub; i++) { ierr = ISSort((*is)[i]);CHKERRQ(ierr); } 1341 PetscFunctionReturn(0); 1342 } 1343 1344 #undef __FUNCT__ 1345 #define __FUNCT__ "PCASMGetLocalSubdomains" 1346 /*@C 1347 PCASMGetLocalSubdomains - Gets the local subdomains (for this processor 1348 only) for the additive Schwarz preconditioner. 1349 1350 Not Collective 1351 1352 Input Parameter: 1353 . pc - the preconditioner context 1354 1355 Output Parameters: 1356 + n - the number of subdomains for this processor (default value = 1) 1357 . is - the index sets that define the subdomains for this processor 1358 - is_local - the index sets that define the local part of the subdomains for this processor (can be PETSC_NULL) 1359 1360 1361 Notes: 1362 The IS numbering is in the parallel, global numbering of the vector. 1363 1364 Level: advanced 1365 1366 .keywords: PC, ASM, set, local, subdomains, additive Schwarz 1367 1368 .seealso: PCASMSetTotalSubdomains(), PCASMSetOverlap(), PCASMGetSubKSP(), 1369 PCASMCreateSubdomains2D(), PCASMSetLocalSubdomains(), PCASMGetLocalSubmatrices() 1370 @*/ 1371 PetscErrorCode PETSCKSP_DLLEXPORT PCASMGetLocalSubdomains(PC pc,PetscInt *n,IS *is[],IS *is_local[]) 1372 { 1373 PC_ASM *osm; 1374 PetscErrorCode ierr; 1375 PetscTruth match; 1376 1377 PetscFunctionBegin; 1378 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1379 PetscValidIntPointer(n,2); 1380 if (is) PetscValidPointer(is,3); 1381 ierr = PetscTypeCompare((PetscObject)pc,PCASM,&match);CHKERRQ(ierr); 1382 if (!match) { 1383 if (n) *n = 0; 1384 if (is) *is = PETSC_NULL; 1385 } else { 1386 osm = (PC_ASM*)pc->data; 1387 if (n) *n = osm->n_local_true; 1388 if (is) *is = osm->is; 1389 if (is_local) *is_local = osm->is_local; 1390 } 1391 PetscFunctionReturn(0); 1392 } 1393 1394 #undef __FUNCT__ 1395 #define __FUNCT__ "PCASMGetLocalSubmatrices" 1396 /*@C 1397 PCASMGetLocalSubmatrices - Gets the local submatrices (for this processor 1398 only) for the additive Schwarz preconditioner. 1399 1400 Not Collective 1401 1402 Input Parameter: 1403 . pc - the preconditioner context 1404 1405 Output Parameters: 1406 + n - the number of matrices for this processor (default value = 1) 1407 - mat - the matrices 1408 1409 1410 Level: advanced 1411 1412 .keywords: PC, ASM, set, local, subdomains, additive Schwarz, block Jacobi 1413 1414 .seealso: PCASMSetTotalSubdomains(), PCASMSetOverlap(), PCASMGetSubKSP(), 1415 PCASMCreateSubdomains2D(), PCASMSetLocalSubdomains(), PCASMGetLocalSubdomains() 1416 @*/ 1417 PetscErrorCode PETSCKSP_DLLEXPORT PCASMGetLocalSubmatrices(PC pc,PetscInt *n,Mat *mat[]) 1418 { 1419 PC_ASM *osm; 1420 PetscErrorCode ierr; 1421 PetscTruth match; 1422 1423 PetscFunctionBegin; 1424 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1425 PetscValidIntPointer(n,2); 1426 if (mat) PetscValidPointer(mat,3); 1427 if (!pc->setupcalled) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONGSTATE,"Must call after KSPSetUP() or PCSetUp()."); 1428 ierr = PetscTypeCompare((PetscObject)pc,PCASM,&match);CHKERRQ(ierr); 1429 if (!match) { 1430 if (n) *n = 0; 1431 if (mat) *mat = PETSC_NULL; 1432 } else { 1433 osm = (PC_ASM*)pc->data; 1434 if (n) *n = osm->n_local_true; 1435 if (mat) *mat = osm->pmat; 1436 } 1437 PetscFunctionReturn(0); 1438 } 1439