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