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