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 = PetscMalloc(osm->n_local_true*sizeof(IS),&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 = PetscMalloc(osm->n_local*sizeof(VecScatter),&osm->restriction);CHKERRQ(ierr); 266 if (osm->is_local) {ierr = PetscMalloc(osm->n_local*sizeof(VecScatter),&osm->localization);CHKERRQ(ierr);} 267 ierr = PetscMalloc(osm->n_local*sizeof(VecScatter),&osm->prolongation);CHKERRQ(ierr); 268 ierr = PetscMalloc(osm->n_local*sizeof(Vec),&osm->x);CHKERRQ(ierr); 269 ierr = PetscMalloc(osm->n_local*sizeof(Vec),&osm->y);CHKERRQ(ierr); 270 ierr = PetscMalloc(osm->n_local*sizeof(Vec),&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 = PetscMalloc(m_local*sizeof(PetscInt),&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 = PetscMalloc(osm->n_local_true*sizeof(KSP*),&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(pc,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(pc,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 = PetscMalloc(n*sizeof(IS),&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 = PetscMalloc(n*sizeof(IS),&osm->is_local);CHKERRQ(ierr); 641 for (i=0; i<n; i++) osm->is_local[i] = is_local[i]; 642 if (!is) { 643 ierr = PetscMalloc(osm->n_local_true*sizeof(IS),&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_truelocal - Activates PCASMSetUseTrueLocal() 1012 . -pc_asm_blocks <blks> - Sets total blocks 1013 . -pc_asm_overlap <ovl> - Sets overlap 1014 - -pc_asm_type [basic,restrict,interpolate,none] - Sets ASM type 1015 1016 IMPORTANT: If you run with, for example, 3 blocks on 1 processor or 3 blocks on 3 processors you 1017 will get a different convergence rate due to the default option of -pc_asm_type restrict. Use 1018 -pc_asm_type basic to use the standard ASM. 1019 1020 Notes: Each processor can have one or more blocks, but a block cannot be shared by more 1021 than one processor. Defaults to one block per processor. 1022 1023 To set options on the solvers for each block append -sub_ to all the KSP, and PC 1024 options database keys. For example, -sub_pc_type ilu -sub_pc_factor_levels 1 -sub_ksp_type preonly 1025 1026 To set the options on the solvers separate for each block call PCASMGetSubKSP() 1027 and set the options directly on the resulting KSP object (you can access its PC 1028 with KSPGetPC()) 1029 1030 1031 Level: beginner 1032 1033 Concepts: additive Schwarz method 1034 1035 References: 1036 An additive variant of the Schwarz alternating method for the case of many subregions 1037 M Dryja, OB Widlund - Courant Institute, New York University Technical report 1038 1039 Domain Decompositions: Parallel Multilevel Methods for Elliptic Partial Differential Equations, 1040 Barry Smith, Petter Bjorstad, and William Gropp, Cambridge University Press, ISBN 0-521-49589-X. 1041 1042 .seealso: PCCreate(), PCSetType(), PCType (for list of available types), PC, 1043 PCBJACOBI, PCASMSetUseTrueLocal(), PCASMGetSubKSP(), PCASMSetLocalSubdomains(), 1044 PCASMSetTotalSubdomains(), PCSetModifySubmatrices(), PCASMSetOverlap(), PCASMSetType() 1045 1046 M*/ 1047 1048 EXTERN_C_BEGIN 1049 #undef __FUNCT__ 1050 #define __FUNCT__ "PCCreate_ASM" 1051 PetscErrorCode PCCreate_ASM(PC pc) 1052 { 1053 PetscErrorCode ierr; 1054 PC_ASM *osm; 1055 1056 PetscFunctionBegin; 1057 ierr = PetscNewLog(pc,PC_ASM,&osm);CHKERRQ(ierr); 1058 1059 osm->n = PETSC_DECIDE; 1060 osm->n_local = 0; 1061 osm->n_local_true = PETSC_DECIDE; 1062 osm->overlap = 1; 1063 osm->ksp = 0; 1064 osm->restriction = 0; 1065 osm->localization = 0; 1066 osm->prolongation = 0; 1067 osm->x = 0; 1068 osm->y = 0; 1069 osm->y_local = 0; 1070 osm->is = 0; 1071 osm->is_local = 0; 1072 osm->mat = 0; 1073 osm->pmat = 0; 1074 osm->type = PC_ASM_RESTRICT; 1075 osm->same_local_solves = PETSC_TRUE; 1076 osm->sort_indices = PETSC_TRUE; 1077 osm->dm_subdomains = PETSC_FALSE; 1078 1079 pc->data = (void*)osm; 1080 pc->ops->apply = PCApply_ASM; 1081 pc->ops->applytranspose = PCApplyTranspose_ASM; 1082 pc->ops->setup = PCSetUp_ASM; 1083 pc->ops->reset = PCReset_ASM; 1084 pc->ops->destroy = PCDestroy_ASM; 1085 pc->ops->setfromoptions = PCSetFromOptions_ASM; 1086 pc->ops->setuponblocks = PCSetUpOnBlocks_ASM; 1087 pc->ops->view = PCView_ASM; 1088 pc->ops->applyrichardson = 0; 1089 1090 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCASMSetLocalSubdomains_C","PCASMSetLocalSubdomains_ASM",PCASMSetLocalSubdomains_ASM);CHKERRQ(ierr); 1091 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCASMSetTotalSubdomains_C","PCASMSetTotalSubdomains_ASM",PCASMSetTotalSubdomains_ASM);CHKERRQ(ierr); 1092 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCASMSetOverlap_C","PCASMSetOverlap_ASM",PCASMSetOverlap_ASM);CHKERRQ(ierr); 1093 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCASMSetType_C","PCASMSetType_ASM",PCASMSetType_ASM);CHKERRQ(ierr); 1094 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCASMSetSortIndices_C","PCASMSetSortIndices_ASM",PCASMSetSortIndices_ASM);CHKERRQ(ierr); 1095 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCASMGetSubKSP_C","PCASMGetSubKSP_ASM",PCASMGetSubKSP_ASM);CHKERRQ(ierr); 1096 PetscFunctionReturn(0); 1097 } 1098 EXTERN_C_END 1099 1100 1101 #undef __FUNCT__ 1102 #define __FUNCT__ "PCASMCreateSubdomains" 1103 /*@C 1104 PCASMCreateSubdomains - Creates the index sets for the overlapping Schwarz 1105 preconditioner for a any problem on a general grid. 1106 1107 Collective 1108 1109 Input Parameters: 1110 + A - The global matrix operator 1111 - n - the number of local blocks 1112 1113 Output Parameters: 1114 . outis - the array of index sets defining the subdomains 1115 1116 Level: advanced 1117 1118 Note: this generates nonoverlapping subdomains; the PCASM will generate the overlap 1119 from these if you use PCASMSetLocalSubdomains() 1120 1121 In the Fortran version you must provide the array outis[] already allocated of length n. 1122 1123 .keywords: PC, ASM, additive Schwarz, create, subdomains, unstructured grid 1124 1125 .seealso: PCASMSetLocalSubdomains(), PCASMDestroySubdomains() 1126 @*/ 1127 PetscErrorCode PCASMCreateSubdomains(Mat A, PetscInt n, IS* outis[]) 1128 { 1129 MatPartitioning mpart; 1130 const char *prefix; 1131 PetscErrorCode (*f)(Mat,Mat*); 1132 PetscMPIInt size; 1133 PetscInt i,j,rstart,rend,bs; 1134 PetscBool isbaij = PETSC_FALSE,foundpart = PETSC_FALSE; 1135 Mat Ad = NULL, adj; 1136 IS ispart,isnumb,*is; 1137 PetscErrorCode ierr; 1138 1139 PetscFunctionBegin; 1140 PetscValidHeaderSpecific(A,MAT_CLASSID,1); 1141 PetscValidPointer(outis,3); 1142 if (n < 1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"number of local blocks must be > 0, n = %D",n); 1143 1144 /* Get prefix, row distribution, and block size */ 1145 ierr = MatGetOptionsPrefix(A,&prefix);CHKERRQ(ierr); 1146 ierr = MatGetOwnershipRange(A,&rstart,&rend);CHKERRQ(ierr); 1147 ierr = MatGetBlockSize(A,&bs);CHKERRQ(ierr); 1148 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); 1149 1150 /* Get diagonal block from matrix if possible */ 1151 ierr = MPI_Comm_size(PetscObjectComm((PetscObject)A),&size);CHKERRQ(ierr); 1152 ierr = PetscObjectQueryFunction((PetscObject)A,"MatGetDiagonalBlock_C",(void (**) (void))&f);CHKERRQ(ierr); 1153 if (f) { 1154 ierr = MatGetDiagonalBlock(A,&Ad);CHKERRQ(ierr); 1155 } else if (size == 1) { 1156 Ad = A; 1157 } 1158 if (Ad) { 1159 ierr = PetscObjectTypeCompare((PetscObject)Ad,MATSEQBAIJ,&isbaij);CHKERRQ(ierr); 1160 if (!isbaij) {ierr = PetscObjectTypeCompare((PetscObject)Ad,MATSEQSBAIJ,&isbaij);CHKERRQ(ierr);} 1161 } 1162 if (Ad && n > 1) { 1163 PetscBool match,done; 1164 /* Try to setup a good matrix partitioning if available */ 1165 ierr = MatPartitioningCreate(PETSC_COMM_SELF,&mpart);CHKERRQ(ierr); 1166 ierr = PetscObjectSetOptionsPrefix((PetscObject)mpart,prefix);CHKERRQ(ierr); 1167 ierr = MatPartitioningSetFromOptions(mpart);CHKERRQ(ierr); 1168 ierr = PetscObjectTypeCompare((PetscObject)mpart,MATPARTITIONINGCURRENT,&match);CHKERRQ(ierr); 1169 if (!match) { 1170 ierr = PetscObjectTypeCompare((PetscObject)mpart,MATPARTITIONINGSQUARE,&match);CHKERRQ(ierr); 1171 } 1172 if (!match) { /* assume a "good" partitioner is available */ 1173 PetscInt na; 1174 const PetscInt *ia,*ja; 1175 ierr = MatGetRowIJ(Ad,0,PETSC_TRUE,isbaij,&na,&ia,&ja,&done);CHKERRQ(ierr); 1176 if (done) { 1177 /* Build adjacency matrix by hand. Unfortunately a call to 1178 MatConvert(Ad,MATMPIADJ,MAT_INITIAL_MATRIX,&adj) will 1179 remove the block-aij structure and we cannot expect 1180 MatPartitioning to split vertices as we need */ 1181 PetscInt i,j,len,nnz,cnt,*iia=0,*jja=0; 1182 const PetscInt *row; 1183 nnz = 0; 1184 for (i=0; i<na; i++) { /* count number of nonzeros */ 1185 len = ia[i+1] - ia[i]; 1186 row = ja + ia[i]; 1187 for (j=0; j<len; j++) { 1188 if (row[j] == i) { /* don't count diagonal */ 1189 len--; break; 1190 } 1191 } 1192 nnz += len; 1193 } 1194 ierr = PetscMalloc((na+1)*sizeof(PetscInt),&iia);CHKERRQ(ierr); 1195 ierr = PetscMalloc((nnz)*sizeof(PetscInt),&jja);CHKERRQ(ierr); 1196 nnz = 0; 1197 iia[0] = 0; 1198 for (i=0; i<na; i++) { /* fill adjacency */ 1199 cnt = 0; 1200 len = ia[i+1] - ia[i]; 1201 row = ja + ia[i]; 1202 for (j=0; j<len; j++) { 1203 if (row[j] != i) { /* if not diagonal */ 1204 jja[nnz+cnt++] = row[j]; 1205 } 1206 } 1207 nnz += cnt; 1208 iia[i+1] = nnz; 1209 } 1210 /* Partitioning of the adjacency matrix */ 1211 ierr = MatCreateMPIAdj(PETSC_COMM_SELF,na,na,iia,jja,NULL,&adj);CHKERRQ(ierr); 1212 ierr = MatPartitioningSetAdjacency(mpart,adj);CHKERRQ(ierr); 1213 ierr = MatPartitioningSetNParts(mpart,n);CHKERRQ(ierr); 1214 ierr = MatPartitioningApply(mpart,&ispart);CHKERRQ(ierr); 1215 ierr = ISPartitioningToNumbering(ispart,&isnumb);CHKERRQ(ierr); 1216 ierr = MatDestroy(&adj);CHKERRQ(ierr); 1217 foundpart = PETSC_TRUE; 1218 } 1219 ierr = MatRestoreRowIJ(Ad,0,PETSC_TRUE,isbaij,&na,&ia,&ja,&done);CHKERRQ(ierr); 1220 } 1221 ierr = MatPartitioningDestroy(&mpart);CHKERRQ(ierr); 1222 } 1223 1224 ierr = PetscMalloc(n*sizeof(IS),&is);CHKERRQ(ierr); 1225 *outis = is; 1226 1227 if (!foundpart) { 1228 1229 /* Partitioning by contiguous chunks of rows */ 1230 1231 PetscInt mbs = (rend-rstart)/bs; 1232 PetscInt start = rstart; 1233 for (i=0; i<n; i++) { 1234 PetscInt count = (mbs/n + ((mbs % n) > i)) * bs; 1235 ierr = ISCreateStride(PETSC_COMM_SELF,count,start,1,&is[i]);CHKERRQ(ierr); 1236 start += count; 1237 } 1238 1239 } else { 1240 1241 /* Partitioning by adjacency of diagonal block */ 1242 1243 const PetscInt *numbering; 1244 PetscInt *count,nidx,*indices,*newidx,start=0; 1245 /* Get node count in each partition */ 1246 ierr = PetscMalloc(n*sizeof(PetscInt),&count);CHKERRQ(ierr); 1247 ierr = ISPartitioningCount(ispart,n,count);CHKERRQ(ierr); 1248 if (isbaij && bs > 1) { /* adjust for the block-aij case */ 1249 for (i=0; i<n; i++) count[i] *= bs; 1250 } 1251 /* Build indices from node numbering */ 1252 ierr = ISGetLocalSize(isnumb,&nidx);CHKERRQ(ierr); 1253 ierr = PetscMalloc(nidx*sizeof(PetscInt),&indices);CHKERRQ(ierr); 1254 for (i=0; i<nidx; i++) indices[i] = i; /* needs to be initialized */ 1255 ierr = ISGetIndices(isnumb,&numbering);CHKERRQ(ierr); 1256 ierr = PetscSortIntWithPermutation(nidx,numbering,indices);CHKERRQ(ierr); 1257 ierr = ISRestoreIndices(isnumb,&numbering);CHKERRQ(ierr); 1258 if (isbaij && bs > 1) { /* adjust for the block-aij case */ 1259 ierr = PetscMalloc(nidx*bs*sizeof(PetscInt),&newidx);CHKERRQ(ierr); 1260 for (i=0; i<nidx; i++) { 1261 for (j=0; j<bs; j++) newidx[i*bs+j] = indices[i]*bs + j; 1262 } 1263 ierr = PetscFree(indices);CHKERRQ(ierr); 1264 nidx *= bs; 1265 indices = newidx; 1266 } 1267 /* Shift to get global indices */ 1268 for (i=0; i<nidx; i++) indices[i] += rstart; 1269 1270 /* Build the index sets for each block */ 1271 for (i=0; i<n; i++) { 1272 ierr = ISCreateGeneral(PETSC_COMM_SELF,count[i],&indices[start],PETSC_COPY_VALUES,&is[i]);CHKERRQ(ierr); 1273 ierr = ISSort(is[i]);CHKERRQ(ierr); 1274 start += count[i]; 1275 } 1276 1277 ierr = PetscFree(count);CHKERRQ(ierr); 1278 ierr = PetscFree(indices);CHKERRQ(ierr); 1279 ierr = ISDestroy(&isnumb);CHKERRQ(ierr); 1280 ierr = ISDestroy(&ispart);CHKERRQ(ierr); 1281 1282 } 1283 PetscFunctionReturn(0); 1284 } 1285 1286 #undef __FUNCT__ 1287 #define __FUNCT__ "PCASMDestroySubdomains" 1288 /*@C 1289 PCASMDestroySubdomains - Destroys the index sets created with 1290 PCASMCreateSubdomains(). Should be called after setting subdomains 1291 with PCASMSetLocalSubdomains(). 1292 1293 Collective 1294 1295 Input Parameters: 1296 + n - the number of index sets 1297 . is - the array of index sets 1298 - is_local - the array of local index sets, can be NULL 1299 1300 Level: advanced 1301 1302 .keywords: PC, ASM, additive Schwarz, create, subdomains, unstructured grid 1303 1304 .seealso: PCASMCreateSubdomains(), PCASMSetLocalSubdomains() 1305 @*/ 1306 PetscErrorCode PCASMDestroySubdomains(PetscInt n, IS is[], IS is_local[]) 1307 { 1308 PetscInt i; 1309 PetscErrorCode ierr; 1310 1311 PetscFunctionBegin; 1312 if (n <= 0) PetscFunctionReturn(0); 1313 if (is) { 1314 PetscValidPointer(is,2); 1315 for (i=0; i<n; i++) { ierr = ISDestroy(&is[i]);CHKERRQ(ierr); } 1316 ierr = PetscFree(is);CHKERRQ(ierr); 1317 } 1318 if (is_local) { 1319 PetscValidPointer(is_local,3); 1320 for (i=0; i<n; i++) { ierr = ISDestroy(&is_local[i]);CHKERRQ(ierr); } 1321 ierr = PetscFree(is_local);CHKERRQ(ierr); 1322 } 1323 PetscFunctionReturn(0); 1324 } 1325 1326 #undef __FUNCT__ 1327 #define __FUNCT__ "PCASMCreateSubdomains2D" 1328 /*@ 1329 PCASMCreateSubdomains2D - Creates the index sets for the overlapping Schwarz 1330 preconditioner for a two-dimensional problem on a regular grid. 1331 1332 Not Collective 1333 1334 Input Parameters: 1335 + m, n - the number of mesh points in the x and y directions 1336 . M, N - the number of subdomains in the x and y directions 1337 . dof - degrees of freedom per node 1338 - overlap - overlap in mesh lines 1339 1340 Output Parameters: 1341 + Nsub - the number of subdomains created 1342 . is - array of index sets defining overlapping (if overlap > 0) subdomains 1343 - is_local - array of index sets defining non-overlapping subdomains 1344 1345 Note: 1346 Presently PCAMSCreateSubdomains2d() is valid only for sequential 1347 preconditioners. More general related routines are 1348 PCASMSetTotalSubdomains() and PCASMSetLocalSubdomains(). 1349 1350 Level: advanced 1351 1352 .keywords: PC, ASM, additive Schwarz, create, subdomains, 2D, regular grid 1353 1354 .seealso: PCASMSetTotalSubdomains(), PCASMSetLocalSubdomains(), PCASMGetSubKSP(), 1355 PCASMSetOverlap() 1356 @*/ 1357 PetscErrorCode PCASMCreateSubdomains2D(PetscInt m,PetscInt n,PetscInt M,PetscInt N,PetscInt dof,PetscInt overlap,PetscInt *Nsub,IS **is,IS **is_local) 1358 { 1359 PetscInt i,j,height,width,ystart,xstart,yleft,yright,xleft,xright,loc_outer; 1360 PetscErrorCode ierr; 1361 PetscInt nidx,*idx,loc,ii,jj,count; 1362 1363 PetscFunctionBegin; 1364 if (dof != 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP," "); 1365 1366 *Nsub = N*M; 1367 ierr = PetscMalloc((*Nsub)*sizeof(IS*),is);CHKERRQ(ierr); 1368 ierr = PetscMalloc((*Nsub)*sizeof(IS*),is_local);CHKERRQ(ierr); 1369 ystart = 0; 1370 loc_outer = 0; 1371 for (i=0; i<N; i++) { 1372 height = n/N + ((n % N) > i); /* height of subdomain */ 1373 if (height < 2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Too many N subdomains for mesh dimension n"); 1374 yleft = ystart - overlap; if (yleft < 0) yleft = 0; 1375 yright = ystart + height + overlap; if (yright > n) yright = n; 1376 xstart = 0; 1377 for (j=0; j<M; j++) { 1378 width = m/M + ((m % M) > j); /* width of subdomain */ 1379 if (width < 2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Too many M subdomains for mesh dimension m"); 1380 xleft = xstart - overlap; if (xleft < 0) xleft = 0; 1381 xright = xstart + width + overlap; if (xright > m) xright = m; 1382 nidx = (xright - xleft)*(yright - yleft); 1383 ierr = PetscMalloc(nidx*sizeof(PetscInt),&idx);CHKERRQ(ierr); 1384 loc = 0; 1385 for (ii=yleft; ii<yright; ii++) { 1386 count = m*ii + xleft; 1387 for (jj=xleft; jj<xright; jj++) idx[loc++] = count++; 1388 } 1389 ierr = ISCreateGeneral(PETSC_COMM_SELF,nidx,idx,PETSC_COPY_VALUES,(*is)+loc_outer);CHKERRQ(ierr); 1390 if (overlap == 0) { 1391 ierr = PetscObjectReference((PetscObject)(*is)[loc_outer]);CHKERRQ(ierr); 1392 1393 (*is_local)[loc_outer] = (*is)[loc_outer]; 1394 } else { 1395 for (loc=0,ii=ystart; ii<ystart+height; ii++) { 1396 for (jj=xstart; jj<xstart+width; jj++) { 1397 idx[loc++] = m*ii + jj; 1398 } 1399 } 1400 ierr = ISCreateGeneral(PETSC_COMM_SELF,loc,idx,PETSC_COPY_VALUES,*is_local+loc_outer);CHKERRQ(ierr); 1401 } 1402 ierr = PetscFree(idx);CHKERRQ(ierr); 1403 xstart += width; 1404 loc_outer++; 1405 } 1406 ystart += height; 1407 } 1408 for (i=0; i<*Nsub; i++) { ierr = ISSort((*is)[i]);CHKERRQ(ierr); } 1409 PetscFunctionReturn(0); 1410 } 1411 1412 #undef __FUNCT__ 1413 #define __FUNCT__ "PCASMGetLocalSubdomains" 1414 /*@C 1415 PCASMGetLocalSubdomains - Gets the local subdomains (for this processor 1416 only) for the additive Schwarz preconditioner. 1417 1418 Not Collective 1419 1420 Input Parameter: 1421 . pc - the preconditioner context 1422 1423 Output Parameters: 1424 + n - the number of subdomains for this processor (default value = 1) 1425 . is - the index sets that define the subdomains for this processor 1426 - is_local - the index sets that define the local part of the subdomains for this processor (can be NULL) 1427 1428 1429 Notes: 1430 The IS numbering is in the parallel, global numbering of the vector. 1431 1432 Level: advanced 1433 1434 .keywords: PC, ASM, set, local, subdomains, additive Schwarz 1435 1436 .seealso: PCASMSetTotalSubdomains(), PCASMSetOverlap(), PCASMGetSubKSP(), 1437 PCASMCreateSubdomains2D(), PCASMSetLocalSubdomains(), PCASMGetLocalSubmatrices() 1438 @*/ 1439 PetscErrorCode PCASMGetLocalSubdomains(PC pc,PetscInt *n,IS *is[],IS *is_local[]) 1440 { 1441 PC_ASM *osm; 1442 PetscErrorCode ierr; 1443 PetscBool match; 1444 1445 PetscFunctionBegin; 1446 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1447 PetscValidIntPointer(n,2); 1448 if (is) PetscValidPointer(is,3); 1449 ierr = PetscObjectTypeCompare((PetscObject)pc,PCASM,&match);CHKERRQ(ierr); 1450 if (!match) { 1451 if (n) *n = 0; 1452 if (is) *is = NULL; 1453 } else { 1454 osm = (PC_ASM*)pc->data; 1455 if (n) *n = osm->n_local_true; 1456 if (is) *is = osm->is; 1457 if (is_local) *is_local = osm->is_local; 1458 } 1459 PetscFunctionReturn(0); 1460 } 1461 1462 #undef __FUNCT__ 1463 #define __FUNCT__ "PCASMGetLocalSubmatrices" 1464 /*@C 1465 PCASMGetLocalSubmatrices - Gets the local submatrices (for this processor 1466 only) for the additive Schwarz preconditioner. 1467 1468 Not Collective 1469 1470 Input Parameter: 1471 . pc - the preconditioner context 1472 1473 Output Parameters: 1474 + n - the number of matrices for this processor (default value = 1) 1475 - mat - the matrices 1476 1477 1478 Level: advanced 1479 1480 Notes: Call after PCSetUp() (or KSPSetUp()) but before PCApply() (or KSPApply()) and before PCSetUpOnBlocks()) 1481 1482 Usually one would use PCSetModifySubmatrices() to change the submatrices in building the preconditioner. 1483 1484 .keywords: PC, ASM, set, local, subdomains, additive Schwarz, block Jacobi 1485 1486 .seealso: PCASMSetTotalSubdomains(), PCASMSetOverlap(), PCASMGetSubKSP(), 1487 PCASMCreateSubdomains2D(), PCASMSetLocalSubdomains(), PCASMGetLocalSubdomains(), PCSetModifySubmatrices() 1488 @*/ 1489 PetscErrorCode PCASMGetLocalSubmatrices(PC pc,PetscInt *n,Mat *mat[]) 1490 { 1491 PC_ASM *osm; 1492 PetscErrorCode ierr; 1493 PetscBool match; 1494 1495 PetscFunctionBegin; 1496 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1497 PetscValidIntPointer(n,2); 1498 if (mat) PetscValidPointer(mat,3); 1499 if (!pc->setupcalled) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must call after KSPSetUP() or PCSetUp()."); 1500 ierr = PetscObjectTypeCompare((PetscObject)pc,PCASM,&match);CHKERRQ(ierr); 1501 if (!match) { 1502 if (n) *n = 0; 1503 if (mat) *mat = NULL; 1504 } else { 1505 osm = (PC_ASM*)pc->data; 1506 if (n) *n = osm->n_local_true; 1507 if (mat) *mat = osm->pmat; 1508 } 1509 PetscFunctionReturn(0); 1510 } 1511 1512 #undef __FUNCT__ 1513 #define __FUNCT__ "PCASMSetDMSubdomains" 1514 /*@ 1515 PCASMSetDMSubdomains - Indicates whether to use DMCreateDomainDecomposition() to define the subdomains, whenever possible. 1516 Logically Collective 1517 1518 Input Parameter: 1519 + pc - the preconditioner 1520 - flg - boolean indicating whether to use subdomains defined by the DM 1521 1522 Options Database Key: 1523 . -pc_asm_dm_subdomains 1524 1525 Level: intermediate 1526 1527 Notes: 1528 PCASMSetTotalSubdomains() and PCASMSetOverlap() take precedence over PCASMSetDMSubdomains(), 1529 so setting either of the first two effectively turns the latter off. 1530 1531 .keywords: PC, ASM, DM, set, subdomains, additive Schwarz 1532 1533 .seealso: PCASMGetDMSubdomains(), PCASMSetTotalSubdomains(), PCASMSetOverlap() 1534 PCASMCreateSubdomains2D(), PCASMSetLocalSubdomains(), PCASMGetLocalSubdomains() 1535 @*/ 1536 PetscErrorCode PCASMSetDMSubdomains(PC pc,PetscBool flg) 1537 { 1538 PC_ASM *osm = (PC_ASM*)pc->data; 1539 PetscErrorCode ierr; 1540 PetscBool match; 1541 1542 PetscFunctionBegin; 1543 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1544 PetscValidLogicalCollectiveBool(pc,flg,2); 1545 if (pc->setupcalled) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONGSTATE,"Not for a setup PC."); 1546 ierr = PetscObjectTypeCompare((PetscObject)pc,PCASM,&match);CHKERRQ(ierr); 1547 if (match) { 1548 osm->dm_subdomains = flg; 1549 } 1550 PetscFunctionReturn(0); 1551 } 1552 1553 #undef __FUNCT__ 1554 #define __FUNCT__ "PCASMGetDMSubdomains" 1555 /*@ 1556 PCASMGetDMSubdomains - Returns flag indicating whether to use DMCreateDomainDecomposition() to define the subdomains, whenever possible. 1557 Not Collective 1558 1559 Input Parameter: 1560 . pc - the preconditioner 1561 1562 Output Parameter: 1563 . flg - boolean indicating whether to use subdomains defined by the DM 1564 1565 Level: intermediate 1566 1567 .keywords: PC, ASM, DM, set, subdomains, additive Schwarz 1568 1569 .seealso: PCASMSetDMSubdomains(), PCASMSetTotalSubdomains(), PCASMSetOverlap() 1570 PCASMCreateSubdomains2D(), PCASMSetLocalSubdomains(), PCASMGetLocalSubdomains() 1571 @*/ 1572 PetscErrorCode PCASMGetDMSubdomains(PC pc,PetscBool* flg) 1573 { 1574 PC_ASM *osm = (PC_ASM*)pc->data; 1575 PetscErrorCode ierr; 1576 PetscBool match; 1577 1578 PetscFunctionBegin; 1579 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1580 PetscValidPointer(flg,2); 1581 ierr = PetscObjectTypeCompare((PetscObject)pc,PCASM,&match);CHKERRQ(ierr); 1582 if (match) { 1583 if (flg) *flg = osm->dm_subdomains; 1584 } 1585 PetscFunctionReturn(0); 1586 } 1587