1b1a0a8a3SJed Brown 2b1a0a8a3SJed Brown /* 3f746d493SDmitry Karpeev This file defines an "generalized" additive Schwarz preconditioner for any Mat implementation. 444fe18e5SDmitry Karpeev In this version each processor may have any number of subdomains and a subdomain may live on multiple 5f746d493SDmitry Karpeev processors. 6b1a0a8a3SJed Brown 7af538404SDmitry Karpeev N - total number of subdomains on all processors 8f746d493SDmitry Karpeev n - actual number of subdomains on this processor 9f746d493SDmitry Karpeev nmax - maximum number of subdomains per processor 10b1a0a8a3SJed Brown */ 11*c6db04a5SJed Brown #include <private/pcimpl.h> /*I "petscpc.h" I*/ 12b1a0a8a3SJed Brown 13b1a0a8a3SJed Brown typedef struct { 14f746d493SDmitry Karpeev PetscInt N,n,nmax; 15b1a0a8a3SJed Brown PetscInt overlap; /* overlap requested by user */ 16b1a0a8a3SJed Brown KSP *ksp; /* linear solvers for each block */ 17f746d493SDmitry Karpeev Vec gx,gy; /* Merged work vectors */ 18f746d493SDmitry Karpeev Vec *x,*y; /* Split work vectors; storage aliases pieces of storage of the above merged vectors. */ 19f746d493SDmitry Karpeev IS gis, gis_local; /* merged ISs */ 20f746d493SDmitry Karpeev VecScatter grestriction; /* merged restriction */ 21f746d493SDmitry Karpeev VecScatter gprolongation; /* merged prolongation */ 22b1a0a8a3SJed Brown IS *is; /* index set that defines each overlapping subdomain */ 23f746d493SDmitry Karpeev IS *is_local; /* index set that defines each local subdomain (same as subdomain with the overlap removed); may be NULL */ 24f746d493SDmitry Karpeev Mat *pmat; /* subdomain block matrices */ 25f746d493SDmitry Karpeev PCGASMType type; /* use reduced interpolation, restriction or both */ 26b1a0a8a3SJed Brown PetscBool type_set; /* if user set this value (so won't change it for symmetric problems) */ 27b1a0a8a3SJed Brown PetscBool same_local_solves; /* flag indicating whether all local solvers are same */ 28b1a0a8a3SJed Brown PetscBool sort_indices; /* flag to sort subdomain indices */ 29f746d493SDmitry Karpeev } PC_GASM; 30b1a0a8a3SJed Brown 31b1a0a8a3SJed Brown #undef __FUNCT__ 32af538404SDmitry Karpeev #define __FUNCT__ "PCGASMPrintSubdomains" 33af538404SDmitry Karpeev static PetscErrorCode PCGASMPrintSubdomains(PC pc) 34af538404SDmitry Karpeev { 35af538404SDmitry Karpeev PC_GASM *osm = (PC_GASM*)pc->data; 36af538404SDmitry Karpeev const char *prefix; 37af538404SDmitry Karpeev char fname[PETSC_MAX_PATH_LEN+1]; 38af538404SDmitry Karpeev PetscViewer viewer, sviewer; 39af538404SDmitry Karpeev PetscInt i,j,nidx; 40af538404SDmitry Karpeev const PetscInt *idx; 41af538404SDmitry Karpeev char *cidx; 42af538404SDmitry Karpeev PetscBool found; 43eec7e3faSDmitry Karpeev PetscMPIInt size, rank; 44af538404SDmitry Karpeev PetscErrorCode ierr; 45af538404SDmitry Karpeev 46af538404SDmitry Karpeev PetscFunctionBegin; 47eec7e3faSDmitry Karpeev ierr = MPI_Comm_size(((PetscObject)pc)->comm, &size); CHKERRQ(ierr); 48eec7e3faSDmitry Karpeev ierr = MPI_Comm_rank(((PetscObject)pc)->comm, &rank); CHKERRQ(ierr); 49af538404SDmitry Karpeev ierr = PCGetOptionsPrefix(pc,&prefix);CHKERRQ(ierr); 50af538404SDmitry Karpeev ierr = PetscOptionsGetString(prefix,"-pc_gasm_print_subdomains",fname,PETSC_MAX_PATH_LEN,&found);CHKERRQ(ierr); 51af538404SDmitry Karpeev if (!found) { ierr = PetscStrcpy(fname,"stdout");CHKERRQ(ierr); }; 52af538404SDmitry Karpeev for (i=0;i<osm->n;++i) { 53af538404SDmitry Karpeev ierr = PetscViewerASCIIOpen(((PetscObject)((osm->is)[i]))->comm,fname,&viewer);CHKERRQ(ierr); 54af538404SDmitry Karpeev ierr = ISGetLocalSize(osm->is[i], &nidx); CHKERRQ(ierr); 55eec7e3faSDmitry Karpeev /* 56eec7e3faSDmitry Karpeev No more than 15 characters per index plus a space. 57eec7e3faSDmitry Karpeev PetscViewerStringSPrintf requires a string of size at least 2, so use (nidx+1) instead of nidx, 58eec7e3faSDmitry Karpeev in case nidx == 0. That will take care of the space for the trailing '\0' as well. 59eec7e3faSDmitry Karpeev For nidx == 0, the whole string 16 '\0'. 60eec7e3faSDmitry Karpeev */ 61eec7e3faSDmitry Karpeev ierr = PetscMalloc(sizeof(char)*(16*(nidx+1)+1), &cidx); CHKERRQ(ierr); 62af538404SDmitry Karpeev ierr = ISGetIndices(osm->is[i], &idx); CHKERRQ(ierr); 63eec7e3faSDmitry Karpeev ierr = PetscViewerStringOpen(((PetscObject)(osm->is[i]))->comm, cidx, 16*(nidx+1), &sviewer); CHKERRQ(ierr); 64af538404SDmitry Karpeev for(j = 0; j < nidx; ++j) { 65af538404SDmitry Karpeev ierr = PetscViewerStringSPrintf(sviewer, "%D ", idx[j]); CHKERRQ(ierr); 66af538404SDmitry Karpeev } 67af538404SDmitry Karpeev ierr = PetscViewerDestroy(sviewer); CHKERRQ(ierr); 68af538404SDmitry Karpeev ierr = ISRestoreIndices(osm->is[i],&idx); CHKERRQ(ierr); 69eec7e3faSDmitry Karpeev 70af538404SDmitry Karpeev ierr = PetscViewerASCIIPrintf(viewer, "Subdomain with overlap\n"); CHKERRQ(ierr); 71af538404SDmitry Karpeev ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%s", cidx); CHKERRQ(ierr); 72af538404SDmitry Karpeev ierr = PetscViewerFlush(viewer); CHKERRQ(ierr); 73af538404SDmitry Karpeev ierr = PetscViewerASCIIPrintf(viewer, "\n"); CHKERRQ(ierr); 74af538404SDmitry Karpeev ierr = PetscFree(cidx); CHKERRQ(ierr); 75af538404SDmitry Karpeev ierr = PetscViewerDestroy(viewer); CHKERRQ(ierr); 76af538404SDmitry Karpeev if (osm->is_local) { 77af538404SDmitry Karpeev ierr = PetscViewerASCIIOpen(((PetscObject)((osm->is)[i]))->comm,fname,&viewer);CHKERRQ(ierr); 78af538404SDmitry Karpeev ierr = ISGetLocalSize(osm->is_local[i], &nidx); CHKERRQ(ierr); 79eec7e3faSDmitry Karpeev /* 80eec7e3faSDmitry Karpeev No more than 15 characters per index plus a space. 81eec7e3faSDmitry Karpeev PetscViewerStringSPrintf requires a string of size at least 2, so use (nidx+1) instead of nidx, 82eec7e3faSDmitry Karpeev in case nidx == 0. That will take care of the space for the trailing '\0' as well. 83eec7e3faSDmitry Karpeev For nidx == 0, the whole string 16 '\0'. 84eec7e3faSDmitry Karpeev */ 85eec7e3faSDmitry Karpeev ierr = PetscMalloc(sizeof(char)*(16*(nidx+1)+1), &cidx); CHKERRQ(ierr); 86af538404SDmitry Karpeev ierr = ISGetIndices(osm->is_local[i], &idx); CHKERRQ(ierr); 87eec7e3faSDmitry Karpeev ierr = PetscViewerStringOpen(((PetscObject)(osm->is_local[i]))->comm, cidx, 16*(nidx+1), &sviewer); CHKERRQ(ierr); 88af538404SDmitry Karpeev for(j = 0; j < nidx; ++j) { 89af538404SDmitry Karpeev ierr = PetscViewerStringSPrintf(sviewer, "%D ", idx[j]); CHKERRQ(ierr); 90af538404SDmitry Karpeev } 91af538404SDmitry Karpeev ierr = PetscViewerDestroy(sviewer); CHKERRQ(ierr); 92af538404SDmitry Karpeev ierr = ISRestoreIndices(osm->is_local[i],&idx); CHKERRQ(ierr); 93eec7e3faSDmitry Karpeev 94af538404SDmitry Karpeev ierr = PetscViewerASCIIPrintf(viewer, "Subdomain without overlap\n"); CHKERRQ(ierr); 95af538404SDmitry Karpeev ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%s", cidx); CHKERRQ(ierr); 96af538404SDmitry Karpeev ierr = PetscViewerFlush(viewer); CHKERRQ(ierr); 97af538404SDmitry Karpeev ierr = PetscViewerASCIIPrintf(viewer, "\n"); CHKERRQ(ierr); 98af538404SDmitry Karpeev ierr = PetscFree(cidx); CHKERRQ(ierr); 99af538404SDmitry Karpeev ierr = PetscViewerDestroy(viewer); CHKERRQ(ierr); 100af538404SDmitry Karpeev } 101af538404SDmitry Karpeev } 102af538404SDmitry Karpeev PetscFunctionReturn(0); 103af538404SDmitry Karpeev } 104af538404SDmitry Karpeev 105af538404SDmitry Karpeev 106af538404SDmitry Karpeev #undef __FUNCT__ 107f746d493SDmitry Karpeev #define __FUNCT__ "PCView_GASM" 108f746d493SDmitry Karpeev static PetscErrorCode PCView_GASM(PC pc,PetscViewer viewer) 109b1a0a8a3SJed Brown { 110f746d493SDmitry Karpeev PC_GASM *osm = (PC_GASM*)pc->data; 111af538404SDmitry Karpeev const char *prefix; 112b1a0a8a3SJed Brown PetscErrorCode ierr; 113af538404SDmitry Karpeev PetscMPIInt rank, size; 114b1a0a8a3SJed Brown PetscInt i,bsz; 115af538404SDmitry Karpeev PetscBool iascii,isstring, print_subdomains; 116b1a0a8a3SJed Brown PetscViewer sviewer; 117b1a0a8a3SJed Brown 118b1a0a8a3SJed Brown 119b1a0a8a3SJed Brown PetscFunctionBegin; 120af538404SDmitry Karpeev ierr = MPI_Comm_size(((PetscObject)pc)->comm, &size); CHKERRQ(ierr); 121af538404SDmitry Karpeev ierr = MPI_Comm_rank(((PetscObject)pc)->comm, &rank); CHKERRQ(ierr); 122b1a0a8a3SJed Brown ierr = PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr); 123b1a0a8a3SJed Brown ierr = PetscTypeCompare((PetscObject)viewer,PETSCVIEWERSTRING,&isstring);CHKERRQ(ierr); 124af538404SDmitry Karpeev ierr = PCGetOptionsPrefix(pc,&prefix);CHKERRQ(ierr); 125af538404SDmitry Karpeev ierr = PetscOptionsGetBool(prefix,"-pc_gasm_print_subdomains",&print_subdomains,PETSC_NULL);CHKERRQ(ierr); 126b1a0a8a3SJed Brown if (iascii) { 127af538404SDmitry Karpeev char overlaps[256] = "user-defined overlap",subdomains[256] = "total subdomains set"; 128b1a0a8a3SJed Brown if (osm->overlap >= 0) {ierr = PetscSNPrintf(overlaps,sizeof overlaps,"amount of overlap = %D",osm->overlap);CHKERRQ(ierr);} 129af538404SDmitry Karpeev if (osm->nmax > 0) {ierr = PetscSNPrintf(subdomains,sizeof subdomains,"max number of local subdomains = %D",osm->nmax);CHKERRQ(ierr);} 130eec7e3faSDmitry Karpeev ierr = PetscViewerASCIISynchronizedPrintf(viewer," [%d:%d] number of locally-supported subdomains = %D\n",(int)rank,(int)size,osm->n);CHKERRQ(ierr); 131af538404SDmitry Karpeev ierr = PetscViewerFlush(viewer); CHKERRQ(ierr); 132af538404SDmitry Karpeev ierr = PetscViewerASCIIPrintf(viewer," Generalized additive Schwarz: %s, %s\n",subdomains,overlaps);CHKERRQ(ierr); 133f746d493SDmitry Karpeev ierr = PetscViewerASCIIPrintf(viewer," Generalized additive Schwarz: restriction/interpolation type - %s\n",PCGASMTypes[osm->type]);CHKERRQ(ierr); 134b1a0a8a3SJed Brown ierr = MPI_Comm_rank(((PetscObject)pc)->comm,&rank);CHKERRQ(ierr); 135b1a0a8a3SJed Brown if (osm->same_local_solves) { 136b1a0a8a3SJed Brown if (osm->ksp) { 137af538404SDmitry Karpeev ierr = PetscViewerASCIIPrintf(viewer," Local solve is same for all subdomains, in the following KSP and PC objects:\n");CHKERRQ(ierr); 138b1a0a8a3SJed Brown ierr = PetscViewerGetSingleton(viewer,&sviewer);CHKERRQ(ierr); 139b1a0a8a3SJed Brown if (!rank) { 140b1a0a8a3SJed Brown ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 141b1a0a8a3SJed Brown ierr = KSPView(osm->ksp[0],sviewer);CHKERRQ(ierr); 142b1a0a8a3SJed Brown ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 143b1a0a8a3SJed Brown } 144b1a0a8a3SJed Brown ierr = PetscViewerRestoreSingleton(viewer,&sviewer);CHKERRQ(ierr); 145b1a0a8a3SJed Brown } 146b1a0a8a3SJed Brown } else { 147b1a0a8a3SJed Brown ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 148af538404SDmitry Karpeev ierr = PetscViewerASCIIPrintf(viewer," Local solve info for each subdomain is in the following KSP and PC objects:\n");CHKERRQ(ierr); 149b1a0a8a3SJed Brown ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 150b1a0a8a3SJed Brown ierr = PetscViewerASCIIPrintf(viewer,"- - - - - - - - - - - - - - - - - -\n");CHKERRQ(ierr); 151f746d493SDmitry Karpeev for (i=0; i<osm->nmax; i++) { 152b1a0a8a3SJed Brown ierr = PetscViewerGetSingleton(viewer,&sviewer);CHKERRQ(ierr); 153f746d493SDmitry Karpeev if (i < osm->n) { 154b1a0a8a3SJed Brown ierr = ISGetLocalSize(osm->is[i],&bsz);CHKERRQ(ierr); 155af538404SDmitry Karpeev ierr = PetscViewerASCIISynchronizedPrintf(sviewer,"[%d:%d] local subdomain number %D, size = %D\n",(int)rank,(int)size,i,bsz);CHKERRQ(ierr); 156b1a0a8a3SJed Brown ierr = KSPView(osm->ksp[i],sviewer);CHKERRQ(ierr); 157b1a0a8a3SJed Brown ierr = PetscViewerASCIISynchronizedPrintf(sviewer,"- - - - - - - - - - - - - - - - - -\n");CHKERRQ(ierr); 158b1a0a8a3SJed Brown } 159b1a0a8a3SJed Brown ierr = PetscViewerRestoreSingleton(viewer,&sviewer);CHKERRQ(ierr); 160b1a0a8a3SJed Brown } 161b1a0a8a3SJed Brown ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 162b1a0a8a3SJed Brown ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 163b1a0a8a3SJed Brown } 164b1a0a8a3SJed Brown } else if (isstring) { 165af538404SDmitry Karpeev ierr = PetscViewerStringSPrintf(viewer," subdomains=%D, overlap=%D, type=%s",osm->n,osm->overlap,PCGASMTypes[osm->type]);CHKERRQ(ierr); 166b1a0a8a3SJed Brown ierr = PetscViewerGetSingleton(viewer,&sviewer);CHKERRQ(ierr); 167b1a0a8a3SJed Brown if (osm->ksp) {ierr = KSPView(osm->ksp[0],sviewer);CHKERRQ(ierr);} 168b1a0a8a3SJed Brown ierr = PetscViewerRestoreSingleton(viewer,&sviewer);CHKERRQ(ierr); 169b1a0a8a3SJed Brown } else { 170f746d493SDmitry Karpeev SETERRQ1(((PetscObject)pc)->comm,PETSC_ERR_SUP,"Viewer type %s not supported for PCGASM",((PetscObject)viewer)->type_name); 171b1a0a8a3SJed Brown } 172b1a0a8a3SJed Brown ierr = PetscViewerFlush(viewer); CHKERRQ(ierr); 173af538404SDmitry Karpeev if(print_subdomains) { 174af538404SDmitry Karpeev ierr = PCGASMPrintSubdomains(pc); CHKERRQ(ierr); 175af538404SDmitry Karpeev } 176b1a0a8a3SJed Brown PetscFunctionReturn(0); 177b1a0a8a3SJed Brown } 178b1a0a8a3SJed Brown 179af538404SDmitry Karpeev 180af538404SDmitry Karpeev 181af538404SDmitry Karpeev 182af538404SDmitry Karpeev 183b1a0a8a3SJed Brown #undef __FUNCT__ 184f746d493SDmitry Karpeev #define __FUNCT__ "PCSetUp_GASM" 185f746d493SDmitry Karpeev static PetscErrorCode PCSetUp_GASM(PC pc) 186b1a0a8a3SJed Brown { 187f746d493SDmitry Karpeev PC_GASM *osm = (PC_GASM*)pc->data; 188b1a0a8a3SJed Brown PetscErrorCode ierr; 189b1a0a8a3SJed Brown PetscBool symset,flg; 19088389755SJed Brown PetscInt i; 191c10bc1a1SDmitry Karpeev PetscMPIInt rank, size; 192b1a0a8a3SJed Brown MatReuse scall = MAT_REUSE_MATRIX; 193b1a0a8a3SJed Brown KSP ksp; 194b1a0a8a3SJed Brown PC subpc; 195b1a0a8a3SJed Brown const char *prefix,*pprefix; 196f746d493SDmitry Karpeev PetscInt dn; /* Number of indices in a single subdomain assigned to this processor. */ 197f746d493SDmitry Karpeev const PetscInt *didx; /* Indices from a single subdomain assigned to this processor. */ 198f746d493SDmitry Karpeev PetscInt ddn; /* Number of indices in all subdomains assigned to this processor. */ 199f746d493SDmitry Karpeev PetscInt *ddidx; /* Indices of all subdomains assigned to this processor. */ 200f746d493SDmitry Karpeev IS gid; /* Identity IS of the size of all subdomains assigned to this processor. */ 201f746d493SDmitry Karpeev Vec x,y; 202f746d493SDmitry Karpeev PetscScalar *gxarray, *gyarray; 2036d98aee9SDmitry Karpeev PetscInt gfirst, glast; 204b1a0a8a3SJed Brown 205b1a0a8a3SJed Brown PetscFunctionBegin; 206c10bc1a1SDmitry Karpeev ierr = MPI_Comm_size(((PetscObject)pc)->comm,&size);CHKERRQ(ierr); 207c10bc1a1SDmitry Karpeev ierr = MPI_Comm_rank(((PetscObject)pc)->comm,&rank);CHKERRQ(ierr); 208b1a0a8a3SJed Brown if (!pc->setupcalled) { 209b1a0a8a3SJed Brown 210b1a0a8a3SJed Brown if (!osm->type_set) { 211b1a0a8a3SJed Brown ierr = MatIsSymmetricKnown(pc->pmat,&symset,&flg);CHKERRQ(ierr); 212f746d493SDmitry Karpeev if (symset && flg) { osm->type = PC_GASM_BASIC; } 213b1a0a8a3SJed Brown } 214b1a0a8a3SJed Brown 21544fe18e5SDmitry Karpeev if (osm->N == PETSC_DECIDE && osm->n < 1) { 216b1a0a8a3SJed Brown /* no subdomains given, use one per processor */ 21744fe18e5SDmitry Karpeev osm->nmax = osm->n = 1; 218b1a0a8a3SJed Brown ierr = MPI_Comm_size(((PetscObject)pc)->comm,&size);CHKERRQ(ierr); 219f746d493SDmitry Karpeev osm->N = size; 220f746d493SDmitry Karpeev } else if (osm->N == PETSC_DECIDE) { 221b1a0a8a3SJed Brown PetscInt inwork[2], outwork[2]; 222f746d493SDmitry Karpeev /* determine global number of subdomains and the max number of local subdomains */ 223f746d493SDmitry Karpeev inwork[0] = inwork[1] = osm->n; 224b1a0a8a3SJed Brown ierr = MPI_Allreduce(inwork,outwork,1,MPIU_2INT,PetscMaxSum_Op,((PetscObject)pc)->comm);CHKERRQ(ierr); 225f746d493SDmitry Karpeev osm->nmax = outwork[0]; 226f746d493SDmitry Karpeev osm->N = outwork[1]; 227b1a0a8a3SJed Brown } 228b1a0a8a3SJed Brown if (!osm->is){ /* create the index sets */ 229f746d493SDmitry Karpeev ierr = PCGASMCreateSubdomains(pc->pmat,osm->n,&osm->is);CHKERRQ(ierr); 230b1a0a8a3SJed Brown } 23193c1ec32SDmitry Karpeev if (!osm->is_local) { 23293c1ec32SDmitry Karpeev /* 23393c1ec32SDmitry Karpeev This indicates that osm->is should define a nonoverlapping decomposition 23493c1ec32SDmitry Karpeev (there is no way to really guarantee that if subdomains are set by the user through PCGASMSetLocalSubdomains, 23593c1ec32SDmitry Karpeev but the assumption is that either the user does the right thing, or subdomains in ossm->is have been created 23693c1ec32SDmitry Karpeev via PCGASMCreateSubdomains, which guarantees a nonoverlapping decomposition). 23793c1ec32SDmitry Karpeev Therefore, osm->is will be used to define osm->is_local. 23893c1ec32SDmitry Karpeev If a nonzero overlap has been requested by the user, then osm->is will be expanded and will overlap, 23993c1ec32SDmitry Karpeev so osm->is_local should obtain a copy of osm->is while they are still (presumably) nonoverlapping. 24093c1ec32SDmitry Karpeev Otherwise (no overlap has been requested), osm->is_local are simply aliases for osm->is. 24193c1ec32SDmitry Karpeev */ 242f746d493SDmitry Karpeev ierr = PetscMalloc(osm->n*sizeof(IS),&osm->is_local);CHKERRQ(ierr); 243f746d493SDmitry Karpeev for (i=0; i<osm->n; i++) { 244b1a0a8a3SJed Brown if (osm->overlap > 0) { /* With positive overlap, osm->is[i] will be modified */ 245b1a0a8a3SJed Brown ierr = ISDuplicate(osm->is[i],&osm->is_local[i]);CHKERRQ(ierr); 246b1a0a8a3SJed Brown ierr = ISCopy(osm->is[i],osm->is_local[i]);CHKERRQ(ierr); 247b1a0a8a3SJed Brown } else { 248b1a0a8a3SJed Brown ierr = PetscObjectReference((PetscObject)osm->is[i]);CHKERRQ(ierr); 249b1a0a8a3SJed Brown osm->is_local[i] = osm->is[i]; 250b1a0a8a3SJed Brown } 251b1a0a8a3SJed Brown } 252b1a0a8a3SJed Brown } 25393c1ec32SDmitry Karpeev /* Beyond this point osm->is_local is not null. */ 25493c1ec32SDmitry Karpeev if (osm->overlap > 0) { 25593c1ec32SDmitry Karpeev /* Extend the "overlapping" regions by a number of steps */ 25693c1ec32SDmitry Karpeev ierr = MatIncreaseOverlap(pc->pmat,osm->n,osm->is,osm->overlap);CHKERRQ(ierr); 25793c1ec32SDmitry Karpeev } 258b1a0a8a3SJed Brown ierr = PCGetOptionsPrefix(pc,&prefix);CHKERRQ(ierr); 259b1a0a8a3SJed Brown flg = PETSC_FALSE; 260f746d493SDmitry Karpeev ierr = PetscOptionsGetBool(prefix,"-pc_gasm_print_subdomains",&flg,PETSC_NULL);CHKERRQ(ierr); 261f746d493SDmitry Karpeev if (flg) { ierr = PCGASMPrintSubdomains(pc);CHKERRQ(ierr); } 262b1a0a8a3SJed Brown 263b1a0a8a3SJed Brown if (osm->sort_indices) { 264f746d493SDmitry Karpeev for (i=0; i<osm->n; i++) { 265b1a0a8a3SJed Brown ierr = ISSort(osm->is[i]);CHKERRQ(ierr); 266b1a0a8a3SJed Brown ierr = ISSort(osm->is_local[i]);CHKERRQ(ierr); 267b1a0a8a3SJed Brown } 268b1a0a8a3SJed Brown } 269f746d493SDmitry Karpeev /* Merge the ISs, create merged vectors and scatter contexts. */ 27093c1ec32SDmitry Karpeev /* Restriction ISs. */ 271f746d493SDmitry Karpeev ddn = 0; 272f746d493SDmitry Karpeev for (i=0; i<osm->n; i++) { 273f746d493SDmitry Karpeev ierr = ISGetLocalSize(osm->is[i],&dn); CHKERRQ(ierr); 274f746d493SDmitry Karpeev ddn += dn; 275f746d493SDmitry Karpeev } 276f746d493SDmitry Karpeev ierr = PetscMalloc(ddn*sizeof(PetscInt), &ddidx); CHKERRQ(ierr); 277f746d493SDmitry Karpeev ddn = 0; 278f746d493SDmitry Karpeev for (i=0; i<osm->n; i++) { 279f746d493SDmitry Karpeev ierr = ISGetLocalSize(osm->is[i],&dn); CHKERRQ(ierr); 280f746d493SDmitry Karpeev ierr = ISGetIndices(osm->is[i],&didx); CHKERRQ(ierr); 281f746d493SDmitry Karpeev ierr = PetscMemcpy(ddidx+ddn, didx, sizeof(PetscInt)*dn); CHKERRQ(ierr); 282f746d493SDmitry Karpeev ierr = ISRestoreIndices(osm->is[i], &didx); CHKERRQ(ierr); 28393c1ec32SDmitry Karpeev ddn += dn; 284f746d493SDmitry Karpeev } 285f746d493SDmitry Karpeev ierr = ISCreateGeneral(((PetscObject)(pc))->comm, ddn, ddidx, PETSC_OWN_POINTER, &osm->gis); CHKERRQ(ierr); 286f746d493SDmitry Karpeev ierr = MatGetVecs(pc->pmat,&x,&y);CHKERRQ(ierr); 287f746d493SDmitry Karpeev ierr = VecCreateMPI(((PetscObject)pc)->comm, ddn, PETSC_DECIDE, &osm->gx); CHKERRQ(ierr); 288f746d493SDmitry Karpeev ierr = VecDuplicate(osm->gx,&osm->gy); CHKERRQ(ierr); 2896d98aee9SDmitry Karpeev ierr = VecGetOwnershipRange(osm->gx, &gfirst, &glast); CHKERRQ(ierr); 2906d98aee9SDmitry Karpeev ierr = ISCreateStride(((PetscObject)pc)->comm,ddn,gfirst,1, &gid); CHKERRQ(ierr); 291f746d493SDmitry Karpeev ierr = VecScatterCreate(x,osm->gis,osm->gx,gid, &(osm->grestriction)); CHKERRQ(ierr); 292f746d493SDmitry Karpeev ierr = ISDestroy(gid); CHKERRQ(ierr); 29393c1ec32SDmitry Karpeev /* Prolongation ISs */ 29481a5c4aaSDmitry Karpeev { PetscInt dn_local; /* Number of indices in the local part of a single domain assigned to this processor. */ 295f746d493SDmitry Karpeev const PetscInt *didx_local; /* Global indices from the local part of a single domain assigned to this processor. */ 296f746d493SDmitry Karpeev PetscInt ddn_local; /* Number of indices in the local part of the disjoint union all domains assigned to this processor. */ 297f746d493SDmitry Karpeev PetscInt *ddidx_local; /* Global indices of the local part of the disjoint union of all domains assigned to this processor. */ 298f746d493SDmitry Karpeev /**/ 29993c1ec32SDmitry Karpeev ISLocalToGlobalMapping ltog; /* Map from global to local indices on the disjoint union of subdomains: "local" ind's run from 0 to ddn-1. */ 30093c1ec32SDmitry Karpeev PetscInt *ddidx_llocal; /* Mapped local indices of the disjoint union of local parts of subdomains. */ 301f746d493SDmitry Karpeev PetscInt ddn_llocal; /* Number of indices in ddidx_llocal; must equal ddn_local, or else gis_local is not a sub-IS of gis. */ 302f746d493SDmitry Karpeev IS gis_llocal; /* IS with ddidx_llocal indices. */ 303f746d493SDmitry Karpeev PetscInt j; 304f746d493SDmitry Karpeev ddn_local = 0; 305f746d493SDmitry Karpeev for (i=0; i<osm->n; i++) { 306f746d493SDmitry Karpeev ierr = ISGetLocalSize(osm->is_local[i],&dn_local); CHKERRQ(ierr); 307f746d493SDmitry Karpeev ddn_local += dn_local; 308f746d493SDmitry Karpeev } 309f746d493SDmitry Karpeev ierr = PetscMalloc(ddn_local*sizeof(PetscInt), &ddidx_local); CHKERRQ(ierr); 310f746d493SDmitry Karpeev ddn_local = 0; 311f746d493SDmitry Karpeev for (i=0; i<osm->n; i++) { 312f746d493SDmitry Karpeev ierr = ISGetLocalSize(osm->is_local[i],&dn_local); CHKERRQ(ierr); 313f746d493SDmitry Karpeev ierr = ISGetIndices(osm->is_local[i],&didx_local); CHKERRQ(ierr); 314f746d493SDmitry Karpeev ierr = PetscMemcpy(ddidx_local+ddn_local, didx_local, sizeof(PetscInt)*dn_local); CHKERRQ(ierr); 315f746d493SDmitry Karpeev ierr = ISRestoreIndices(osm->is_local[i], &didx_local); CHKERRQ(ierr); 316f746d493SDmitry Karpeev ddn_local += dn_local; 317f746d493SDmitry Karpeev } 318ab3e923fSDmitry Karpeev ierr = PetscMalloc(sizeof(PetscInt)*ddn_local, &ddidx_llocal); CHKERRQ(ierr); 319f746d493SDmitry Karpeev ierr = ISCreateGeneral(((PetscObject)pc)->comm, ddn_local, ddidx_local, PETSC_OWN_POINTER, &(osm->gis_local)); CHKERRQ(ierr); 320f746d493SDmitry Karpeev ierr = ISLocalToGlobalMappingCreateIS(osm->gis,<og);CHKERRQ(ierr); 32181a5c4aaSDmitry Karpeev ierr = ISGlobalToLocalMappingApply(ltog,IS_GTOLM_DROP,ddn_local,ddidx_local,&ddn_llocal,ddidx_llocal);CHKERRQ(ierr); 322b1a0a8a3SJed Brown ierr = ISLocalToGlobalMappingDestroy(ltog);CHKERRQ(ierr); 32393c1ec32SDmitry Karpeev if (ddn_llocal != ddn_local) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"gis_local contains %D indices outside of gis", ddn_llocal - ddn_local); 324f746d493SDmitry Karpeev /* Now convert these localized indices into the global indices into the merged output vector. */ 3256d98aee9SDmitry Karpeev ierr = VecGetOwnershipRange(osm->gy, &gfirst, &glast); CHKERRQ(ierr); 326f746d493SDmitry Karpeev for(j=0; j < ddn_llocal; ++j) { 3276d98aee9SDmitry Karpeev ddidx_llocal[j] += gfirst; 328f746d493SDmitry Karpeev } 329f746d493SDmitry Karpeev ierr = ISCreateGeneral(PETSC_COMM_SELF,ddn_llocal,ddidx_llocal,PETSC_OWN_POINTER,&gis_llocal); CHKERRQ(ierr); 330f746d493SDmitry Karpeev ierr = VecScatterCreate(y,osm->gis_local,osm->gy,gis_llocal,&osm->gprolongation); CHKERRQ(ierr); 331f746d493SDmitry Karpeev ierr = ISDestroy(gis_llocal);CHKERRQ(ierr); 332b1a0a8a3SJed Brown } 333f746d493SDmitry Karpeev /* Create the subdomain work vectors. */ 334f746d493SDmitry Karpeev ierr = PetscMalloc(osm->n*sizeof(Vec),&osm->x);CHKERRQ(ierr); 335f746d493SDmitry Karpeev ierr = PetscMalloc(osm->n*sizeof(Vec),&osm->y);CHKERRQ(ierr); 3366d98aee9SDmitry Karpeev ierr = VecGetOwnershipRange(osm->gx, &gfirst, &glast);CHKERRQ(ierr); 337f746d493SDmitry Karpeev ierr = VecGetArray(osm->gx, &gxarray); CHKERRQ(ierr); 338f746d493SDmitry Karpeev ierr = VecGetArray(osm->gy, &gyarray); CHKERRQ(ierr); 339f746d493SDmitry Karpeev for (i=0, ddn=0; i<osm->n; ++i, ddn += dn) { 34086b96d36SDmitry Karpeev PetscInt dN; 341f746d493SDmitry Karpeev ierr = ISGetLocalSize(osm->is[i],&dn);CHKERRQ(ierr); 34286b96d36SDmitry Karpeev ierr = ISGetSize(osm->is[i],&dN);CHKERRQ(ierr); 34386b96d36SDmitry Karpeev ierr = VecCreateMPIWithArray(((PetscObject)(osm->is[i]))->comm,dn,dN,gxarray+ddn,&osm->x[i]);CHKERRQ(ierr); 34486b96d36SDmitry Karpeev ierr = VecCreateMPIWithArray(((PetscObject)(osm->is[i]))->comm,dn,dN,gyarray+ddn,&osm->y[i]);CHKERRQ(ierr); 345b1a0a8a3SJed Brown } 346f746d493SDmitry Karpeev ierr = VecRestoreArray(osm->gx, &gxarray); CHKERRQ(ierr); 347f746d493SDmitry Karpeev ierr = VecRestoreArray(osm->gy, &gyarray); CHKERRQ(ierr); 348f746d493SDmitry Karpeev ierr = VecDestroy(x); CHKERRQ(ierr); 349f746d493SDmitry Karpeev ierr = VecDestroy(y); CHKERRQ(ierr); 350b1a0a8a3SJed Brown /* Create the local solvers */ 351f746d493SDmitry Karpeev ierr = PetscMalloc(osm->n*sizeof(KSP *),&osm->ksp);CHKERRQ(ierr); 35244fe18e5SDmitry Karpeev for (i=0; i<osm->n; i++) { /* KSPs are local */ 35386b96d36SDmitry Karpeev ierr = KSPCreate(((PetscObject)(osm->is[i]))->comm,&ksp);CHKERRQ(ierr); 354b1a0a8a3SJed Brown ierr = PetscLogObjectParent(pc,ksp);CHKERRQ(ierr); 355b1a0a8a3SJed Brown ierr = PetscObjectIncrementTabLevel((PetscObject)ksp,(PetscObject)pc,1);CHKERRQ(ierr); 356b1a0a8a3SJed Brown ierr = KSPSetType(ksp,KSPPREONLY);CHKERRQ(ierr); 357b1a0a8a3SJed Brown ierr = KSPGetPC(ksp,&subpc);CHKERRQ(ierr); 358b1a0a8a3SJed Brown ierr = PCGetOptionsPrefix(pc,&prefix);CHKERRQ(ierr); 359b1a0a8a3SJed Brown ierr = KSPSetOptionsPrefix(ksp,prefix);CHKERRQ(ierr); 360b1a0a8a3SJed Brown ierr = KSPAppendOptionsPrefix(ksp,"sub_");CHKERRQ(ierr); 361b1a0a8a3SJed Brown osm->ksp[i] = ksp; 362b1a0a8a3SJed Brown } 363b1a0a8a3SJed Brown scall = MAT_INITIAL_MATRIX; 364b1a0a8a3SJed Brown 365b1a0a8a3SJed Brown } else { 366b1a0a8a3SJed Brown /* 367b1a0a8a3SJed Brown Destroy the blocks from the previous iteration 368b1a0a8a3SJed Brown */ 369b1a0a8a3SJed Brown if (pc->flag == DIFFERENT_NONZERO_PATTERN) { 370f746d493SDmitry Karpeev ierr = MatDestroyMatrices(osm->n,&osm->pmat);CHKERRQ(ierr); 371b1a0a8a3SJed Brown scall = MAT_INITIAL_MATRIX; 372b1a0a8a3SJed Brown } 373b1a0a8a3SJed Brown } 374b1a0a8a3SJed Brown 375b1a0a8a3SJed Brown /* 376f746d493SDmitry Karpeev Extract out the submatrices. 377b1a0a8a3SJed Brown */ 37881a5c4aaSDmitry Karpeev if(size > 1) { 3796d42056aSDmitry Karpeev ierr = MatGetSubMatricesParallel(pc->pmat,osm->n,osm->is, osm->is,scall,&osm->pmat);CHKERRQ(ierr); 38081a5c4aaSDmitry Karpeev } 38181a5c4aaSDmitry Karpeev else { 38281a5c4aaSDmitry Karpeev ierr = MatGetSubMatrices(pc->pmat,osm->n,osm->is, osm->is,scall,&osm->pmat);CHKERRQ(ierr); 38381a5c4aaSDmitry Karpeev } 384b1a0a8a3SJed Brown if (scall == MAT_INITIAL_MATRIX) { 385b1a0a8a3SJed Brown ierr = PetscObjectGetOptionsPrefix((PetscObject)pc->pmat,&pprefix);CHKERRQ(ierr); 386f746d493SDmitry Karpeev for (i=0; i<osm->n; i++) { 387b1a0a8a3SJed Brown ierr = PetscLogObjectParent(pc,osm->pmat[i]);CHKERRQ(ierr); 388b1a0a8a3SJed Brown ierr = PetscObjectSetOptionsPrefix((PetscObject)osm->pmat[i],pprefix);CHKERRQ(ierr); 389b1a0a8a3SJed Brown } 390b1a0a8a3SJed Brown } 391b1a0a8a3SJed Brown 392b1a0a8a3SJed Brown /* Return control to the user so that the submatrices can be modified (e.g., to apply 393b1a0a8a3SJed Brown different boundary conditions for the submatrices than for the global problem) */ 394c10bc1a1SDmitry Karpeev ierr = PCModifySubMatrices(pc,osm->n,osm->is,osm->is,osm->pmat,pc->modifysubmatricesP);CHKERRQ(ierr); 395b1a0a8a3SJed Brown 396b1a0a8a3SJed Brown /* 397f746d493SDmitry Karpeev Loop over submatrices putting them into local ksp 398b1a0a8a3SJed Brown */ 399f746d493SDmitry Karpeev for (i=0; i<osm->n; i++) { 400b1a0a8a3SJed Brown ierr = KSPSetOperators(osm->ksp[i],osm->pmat[i],osm->pmat[i],pc->flag);CHKERRQ(ierr); 401b1a0a8a3SJed Brown if (!pc->setupcalled) { 402b1a0a8a3SJed Brown ierr = KSPSetFromOptions(osm->ksp[i]);CHKERRQ(ierr); 403b1a0a8a3SJed Brown } 404b1a0a8a3SJed Brown } 405b1a0a8a3SJed Brown 406b1a0a8a3SJed Brown PetscFunctionReturn(0); 407b1a0a8a3SJed Brown } 408b1a0a8a3SJed Brown 409b1a0a8a3SJed Brown #undef __FUNCT__ 410f746d493SDmitry Karpeev #define __FUNCT__ "PCSetUpOnBlocks_GASM" 411f746d493SDmitry Karpeev static PetscErrorCode PCSetUpOnBlocks_GASM(PC pc) 412b1a0a8a3SJed Brown { 413f746d493SDmitry Karpeev PC_GASM *osm = (PC_GASM*)pc->data; 414b1a0a8a3SJed Brown PetscErrorCode ierr; 415b1a0a8a3SJed Brown PetscInt i; 416b1a0a8a3SJed Brown 417b1a0a8a3SJed Brown PetscFunctionBegin; 418f746d493SDmitry Karpeev for (i=0; i<osm->n; i++) { 419b1a0a8a3SJed Brown ierr = KSPSetUp(osm->ksp[i]);CHKERRQ(ierr); 420b1a0a8a3SJed Brown } 421b1a0a8a3SJed Brown PetscFunctionReturn(0); 422b1a0a8a3SJed Brown } 423b1a0a8a3SJed Brown 424b1a0a8a3SJed Brown #undef __FUNCT__ 425f746d493SDmitry Karpeev #define __FUNCT__ "PCApply_GASM" 426f746d493SDmitry Karpeev static PetscErrorCode PCApply_GASM(PC pc,Vec x,Vec y) 427b1a0a8a3SJed Brown { 428f746d493SDmitry Karpeev PC_GASM *osm = (PC_GASM*)pc->data; 429b1a0a8a3SJed Brown PetscErrorCode ierr; 430f746d493SDmitry Karpeev PetscInt i; 431b1a0a8a3SJed Brown ScatterMode forward = SCATTER_FORWARD,reverse = SCATTER_REVERSE; 432b1a0a8a3SJed Brown 433b1a0a8a3SJed Brown PetscFunctionBegin; 434b1a0a8a3SJed Brown /* 435b1a0a8a3SJed Brown Support for limiting the restriction or interpolation to only local 436b1a0a8a3SJed Brown subdomain values (leaving the other values 0). 437b1a0a8a3SJed Brown */ 438f746d493SDmitry Karpeev if (!(osm->type & PC_GASM_RESTRICT)) { 439b1a0a8a3SJed Brown forward = SCATTER_FORWARD_LOCAL; 440b1a0a8a3SJed Brown /* have to zero the work RHS since scatter may leave some slots empty */ 441f746d493SDmitry Karpeev ierr = VecZeroEntries(osm->gx); CHKERRQ(ierr); 442b1a0a8a3SJed Brown } 443f746d493SDmitry Karpeev if (!(osm->type & PC_GASM_INTERPOLATE)) { 444b1a0a8a3SJed Brown reverse = SCATTER_REVERSE_LOCAL; 445b1a0a8a3SJed Brown } 446b1a0a8a3SJed Brown 447f746d493SDmitry Karpeev ierr = VecScatterBegin(osm->grestriction,x,osm->gx,INSERT_VALUES,forward);CHKERRQ(ierr); 448b1a0a8a3SJed Brown ierr = VecZeroEntries(y);CHKERRQ(ierr); 449f746d493SDmitry Karpeev ierr = VecScatterEnd(osm->grestriction,x,osm->gx,INSERT_VALUES,forward);CHKERRQ(ierr); 45086b96d36SDmitry Karpeev /* do the subdomain solves */ 45186b96d36SDmitry Karpeev for (i=0; i<osm->n; ++i) { 452b1a0a8a3SJed Brown ierr = KSPSolve(osm->ksp[i],osm->x[i],osm->y[i]);CHKERRQ(ierr); 453b1a0a8a3SJed Brown } 454f746d493SDmitry Karpeev ierr = VecScatterBegin(osm->gprolongation,osm->gy,y,ADD_VALUES,reverse);CHKERRQ(ierr); 455f746d493SDmitry Karpeev ierr = VecScatterEnd(osm->gprolongation,osm->gy,y,ADD_VALUES,reverse);CHKERRQ(ierr); 456b1a0a8a3SJed Brown PetscFunctionReturn(0); 457b1a0a8a3SJed Brown } 458b1a0a8a3SJed Brown 459b1a0a8a3SJed Brown #undef __FUNCT__ 460f746d493SDmitry Karpeev #define __FUNCT__ "PCApplyTranspose_GASM" 461f746d493SDmitry Karpeev static PetscErrorCode PCApplyTranspose_GASM(PC pc,Vec x,Vec y) 462b1a0a8a3SJed Brown { 463f746d493SDmitry Karpeev PC_GASM *osm = (PC_GASM*)pc->data; 464b1a0a8a3SJed Brown PetscErrorCode ierr; 465f746d493SDmitry Karpeev PetscInt i; 466b1a0a8a3SJed Brown ScatterMode forward = SCATTER_FORWARD,reverse = SCATTER_REVERSE; 467b1a0a8a3SJed Brown 468b1a0a8a3SJed Brown PetscFunctionBegin; 469b1a0a8a3SJed Brown /* 470b1a0a8a3SJed Brown Support for limiting the restriction or interpolation to only local 471b1a0a8a3SJed Brown subdomain values (leaving the other values 0). 472b1a0a8a3SJed Brown 473f746d493SDmitry Karpeev Note: these are reversed from the PCApply_GASM() because we are applying the 474b1a0a8a3SJed Brown transpose of the three terms 475b1a0a8a3SJed Brown */ 476f746d493SDmitry Karpeev if (!(osm->type & PC_GASM_INTERPOLATE)) { 477b1a0a8a3SJed Brown forward = SCATTER_FORWARD_LOCAL; 478b1a0a8a3SJed Brown /* have to zero the work RHS since scatter may leave some slots empty */ 479f746d493SDmitry Karpeev ierr = VecZeroEntries(osm->gx);CHKERRQ(ierr); 480b1a0a8a3SJed Brown } 481f746d493SDmitry Karpeev if (!(osm->type & PC_GASM_RESTRICT)) { 482b1a0a8a3SJed Brown reverse = SCATTER_REVERSE_LOCAL; 483b1a0a8a3SJed Brown } 484b1a0a8a3SJed Brown 485ab3e923fSDmitry Karpeev ierr = VecScatterBegin(osm->grestriction,x,osm->gx,INSERT_VALUES,forward);CHKERRQ(ierr); 486b1a0a8a3SJed Brown ierr = VecZeroEntries(y);CHKERRQ(ierr); 487ab3e923fSDmitry Karpeev ierr = VecScatterEnd(osm->grestriction,x,osm->gx,INSERT_VALUES,forward);CHKERRQ(ierr); 488b1a0a8a3SJed Brown /* do the local solves */ 489ab3e923fSDmitry Karpeev for (i=0; i<osm->n; ++i) { /* Note that the solves are local, so we can go to osm->n, rather than osm->nmax. */ 490b1a0a8a3SJed Brown ierr = KSPSolveTranspose(osm->ksp[i],osm->x[i],osm->y[i]);CHKERRQ(ierr); 491b1a0a8a3SJed Brown } 492ab3e923fSDmitry Karpeev ierr = VecScatterBegin(osm->gprolongation,osm->gy,y,ADD_VALUES,reverse);CHKERRQ(ierr); 493ab3e923fSDmitry Karpeev ierr = VecScatterEnd(osm->gprolongation,osm->gy,y,ADD_VALUES,reverse);CHKERRQ(ierr); 494b1a0a8a3SJed Brown PetscFunctionReturn(0); 495b1a0a8a3SJed Brown } 496b1a0a8a3SJed Brown 497b1a0a8a3SJed Brown #undef __FUNCT__ 498f746d493SDmitry Karpeev #define __FUNCT__ "PCDestroy_GASM" 499f746d493SDmitry Karpeev static PetscErrorCode PCDestroy_GASM(PC pc) 500b1a0a8a3SJed Brown { 501f746d493SDmitry Karpeev PC_GASM *osm = (PC_GASM*)pc->data; 502b1a0a8a3SJed Brown PetscErrorCode ierr; 503b1a0a8a3SJed Brown PetscInt i; 504b1a0a8a3SJed Brown 505b1a0a8a3SJed Brown PetscFunctionBegin; 506b1a0a8a3SJed Brown if (osm->ksp) { 507f746d493SDmitry Karpeev for (i=0; i<osm->n; i++) { 508b1a0a8a3SJed Brown ierr = KSPDestroy(osm->ksp[i]);CHKERRQ(ierr); 509b1a0a8a3SJed Brown } 510b1a0a8a3SJed Brown ierr = PetscFree(osm->ksp);CHKERRQ(ierr); 511b1a0a8a3SJed Brown } 512b1a0a8a3SJed Brown if (osm->pmat) { 513f746d493SDmitry Karpeev if (osm->n > 0) { 514ab3e923fSDmitry Karpeev ierr = MatDestroyMatrices(osm->n,&osm->pmat);CHKERRQ(ierr); 515b1a0a8a3SJed Brown } 516b1a0a8a3SJed Brown } 517f746d493SDmitry Karpeev for (i=0; i<osm->n; i++) { 518b1a0a8a3SJed Brown ierr = VecDestroy(osm->x[i]);CHKERRQ(ierr); 519b1a0a8a3SJed Brown ierr = VecDestroy(osm->y[i]);CHKERRQ(ierr); 520b1a0a8a3SJed Brown } 521b1a0a8a3SJed Brown ierr = PetscFree(osm->x);CHKERRQ(ierr); 522b1a0a8a3SJed Brown ierr = PetscFree(osm->y);CHKERRQ(ierr); 523f746d493SDmitry Karpeev ierr = VecDestroy(osm->gx); CHKERRQ(ierr); 524ab3e923fSDmitry Karpeev ierr = VecDestroy(osm->gy); CHKERRQ(ierr); 525ab3e923fSDmitry Karpeev 526ab3e923fSDmitry Karpeev ierr = VecScatterDestroy(osm->grestriction); CHKERRQ(ierr); 527ab3e923fSDmitry Karpeev ierr = VecScatterDestroy(osm->gprolongation); CHKERRQ(ierr); 528f746d493SDmitry Karpeev 529b1a0a8a3SJed Brown if (osm->is) { 530ab3e923fSDmitry Karpeev ierr = PCGASMDestroySubdomains(osm->n,osm->is,osm->is_local);CHKERRQ(ierr); 531b1a0a8a3SJed Brown } 532167188bfSDmitry Karpeev 533167188bfSDmitry Karpeev if(osm->gis) { 534167188bfSDmitry Karpeev ierr = ISDestroy(osm->gis); CHKERRQ(ierr); 535167188bfSDmitry Karpeev } 536167188bfSDmitry Karpeev if(osm->gis_local) { 537167188bfSDmitry Karpeev ierr = ISDestroy(osm->gis_local); CHKERRQ(ierr); 538167188bfSDmitry Karpeev } 539c31cb41cSBarry Smith ierr = PetscFree(pc->data);CHKERRQ(ierr); 540b1a0a8a3SJed Brown PetscFunctionReturn(0); 541b1a0a8a3SJed Brown } 542b1a0a8a3SJed Brown 543b1a0a8a3SJed Brown #undef __FUNCT__ 544f746d493SDmitry Karpeev #define __FUNCT__ "PCSetFromOptions_GASM" 545ab3e923fSDmitry Karpeev static PetscErrorCode PCSetFromOptions_GASM(PC pc) { 546f746d493SDmitry Karpeev PC_GASM *osm = (PC_GASM*)pc->data; 547b1a0a8a3SJed Brown PetscErrorCode ierr; 548b1a0a8a3SJed Brown PetscInt blocks,ovl; 549b1a0a8a3SJed Brown PetscBool symset,flg; 550f746d493SDmitry Karpeev PCGASMType gasmtype; 551b1a0a8a3SJed Brown 552b1a0a8a3SJed Brown PetscFunctionBegin; 553b1a0a8a3SJed Brown /* set the type to symmetric if matrix is symmetric */ 554b1a0a8a3SJed Brown if (!osm->type_set && pc->pmat) { 555b1a0a8a3SJed Brown ierr = MatIsSymmetricKnown(pc->pmat,&symset,&flg);CHKERRQ(ierr); 556f746d493SDmitry Karpeev if (symset && flg) { osm->type = PC_GASM_BASIC; } 557b1a0a8a3SJed Brown } 55844fe18e5SDmitry Karpeev ierr = PetscOptionsHead("Generalized additive Schwarz options");CHKERRQ(ierr); 559f746d493SDmitry Karpeev ierr = PetscOptionsInt("-pc_gasm_blocks","Number of subdomains","PCGASMSetTotalSubdomains",osm->n,&blocks,&flg);CHKERRQ(ierr); 560ab3e923fSDmitry Karpeev if (flg) {ierr = PCGASMSetTotalSubdomains(pc,blocks);CHKERRQ(ierr); } 561f746d493SDmitry Karpeev ierr = PetscOptionsInt("-pc_gasm_overlap","Number of grid points overlap","PCGASMSetOverlap",osm->overlap,&ovl,&flg);CHKERRQ(ierr); 562f746d493SDmitry Karpeev if (flg) {ierr = PCGASMSetOverlap(pc,ovl);CHKERRQ(ierr); } 563b1a0a8a3SJed Brown flg = PETSC_FALSE; 564f746d493SDmitry Karpeev ierr = PetscOptionsEnum("-pc_gasm_type","Type of restriction/extension","PCGASMSetType",PCGASMTypes,(PetscEnum)osm->type,(PetscEnum*)&gasmtype,&flg);CHKERRQ(ierr); 565f746d493SDmitry Karpeev if (flg) {ierr = PCGASMSetType(pc,gasmtype);CHKERRQ(ierr); } 566b1a0a8a3SJed Brown ierr = PetscOptionsTail();CHKERRQ(ierr); 567b1a0a8a3SJed Brown PetscFunctionReturn(0); 568b1a0a8a3SJed Brown } 569b1a0a8a3SJed Brown 570b1a0a8a3SJed Brown /*------------------------------------------------------------------------------------*/ 571b1a0a8a3SJed Brown 572b1a0a8a3SJed Brown EXTERN_C_BEGIN 573b1a0a8a3SJed Brown #undef __FUNCT__ 574f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMSetLocalSubdomains_GASM" 5757087cfbeSBarry Smith PetscErrorCode PCGASMSetLocalSubdomains_GASM(PC pc,PetscInt n,IS is[],IS is_local[]) 576b1a0a8a3SJed Brown { 577f746d493SDmitry Karpeev PC_GASM *osm = (PC_GASM*)pc->data; 578b1a0a8a3SJed Brown PetscErrorCode ierr; 579b1a0a8a3SJed Brown PetscInt i; 580b1a0a8a3SJed Brown 581b1a0a8a3SJed Brown PetscFunctionBegin; 582b1a0a8a3SJed Brown if (n < 1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Each process must have 1 or more blocks, n = %D",n); 583f746d493SDmitry Karpeev if (pc->setupcalled && (n != osm->n || is)) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONGSTATE,"PCGASMSetLocalSubdomains() should be called before calling PCSetUp()."); 584b1a0a8a3SJed Brown 585b1a0a8a3SJed Brown if (!pc->setupcalled) { 58693c1ec32SDmitry Karpeev osm->n = n; 58793c1ec32SDmitry Karpeev osm->is = 0; 58893c1ec32SDmitry Karpeev osm->is_local = 0; 589b1a0a8a3SJed Brown if (is) { 590b1a0a8a3SJed Brown for (i=0; i<n; i++) {ierr = PetscObjectReference((PetscObject)is[i]);CHKERRQ(ierr);} 591b1a0a8a3SJed Brown } 592b1a0a8a3SJed Brown if (is_local) { 593b1a0a8a3SJed Brown for (i=0; i<n; i++) {ierr = PetscObjectReference((PetscObject)is_local[i]);CHKERRQ(ierr);} 594b1a0a8a3SJed Brown } 595b1a0a8a3SJed Brown if (osm->is) { 596ab3e923fSDmitry Karpeev ierr = PCGASMDestroySubdomains(osm->n,osm->is,osm->is_local);CHKERRQ(ierr); 597b1a0a8a3SJed Brown } 598b1a0a8a3SJed Brown if (is) { 599b1a0a8a3SJed Brown ierr = PetscMalloc(n*sizeof(IS),&osm->is);CHKERRQ(ierr); 600b1a0a8a3SJed Brown for (i=0; i<n; i++) { osm->is[i] = is[i]; } 601f746d493SDmitry Karpeev /* Flag indicating that the user has set overlapping subdomains so PCGASM should not increase their size. */ 602b1a0a8a3SJed Brown osm->overlap = -1; 603b1a0a8a3SJed Brown } 604b1a0a8a3SJed Brown if (is_local) { 605b1a0a8a3SJed Brown ierr = PetscMalloc(n*sizeof(IS),&osm->is_local);CHKERRQ(ierr); 606b1a0a8a3SJed Brown for (i=0; i<n; i++) { osm->is_local[i] = is_local[i]; } 607b1a0a8a3SJed Brown } 608b1a0a8a3SJed Brown } 609b1a0a8a3SJed Brown PetscFunctionReturn(0); 610b1a0a8a3SJed Brown } 611b1a0a8a3SJed Brown EXTERN_C_END 612b1a0a8a3SJed Brown 613b1a0a8a3SJed Brown EXTERN_C_BEGIN 614b1a0a8a3SJed Brown #undef __FUNCT__ 615f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMSetTotalSubdomains_GASM" 6167087cfbeSBarry Smith PetscErrorCode PCGASMSetTotalSubdomains_GASM(PC pc,PetscInt N) { 617f746d493SDmitry Karpeev PC_GASM *osm = (PC_GASM*)pc->data; 618b1a0a8a3SJed Brown PetscErrorCode ierr; 619b1a0a8a3SJed Brown PetscMPIInt rank,size; 620b1a0a8a3SJed Brown PetscInt n; 621b1a0a8a3SJed Brown 622b1a0a8a3SJed Brown PetscFunctionBegin; 623b1a0a8a3SJed Brown if (N < 1) SETERRQ1(((PetscObject)pc)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Number of total blocks must be > 0, N = %D",N); 624b1a0a8a3SJed Brown 625b1a0a8a3SJed Brown /* 626b1a0a8a3SJed Brown Split the subdomains equally among all processors 627b1a0a8a3SJed Brown */ 628b1a0a8a3SJed Brown ierr = MPI_Comm_rank(((PetscObject)pc)->comm,&rank);CHKERRQ(ierr); 629b1a0a8a3SJed Brown ierr = MPI_Comm_size(((PetscObject)pc)->comm,&size);CHKERRQ(ierr); 630b1a0a8a3SJed Brown n = N/size + ((N % size) > rank); 631b1a0a8a3SJed Brown 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); 632f746d493SDmitry Karpeev if (pc->setupcalled && n != osm->n) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"PCGASMSetTotalSubdomains() should be called before PCSetUp()."); 633b1a0a8a3SJed Brown if (!pc->setupcalled) { 634b1a0a8a3SJed Brown if (osm->is) { 635ab3e923fSDmitry Karpeev ierr = PCGASMDestroySubdomains(osm->n,osm->is,osm->is_local);CHKERRQ(ierr); 636b1a0a8a3SJed Brown } 63793c1ec32SDmitry Karpeev osm->N = N; 638f746d493SDmitry Karpeev osm->n = n; 639b1a0a8a3SJed Brown osm->is = 0; 640b1a0a8a3SJed Brown osm->is_local = 0; 641b1a0a8a3SJed Brown } 642b1a0a8a3SJed Brown PetscFunctionReturn(0); 643ab3e923fSDmitry Karpeev }/* PCGASMSetTotalSubdomains_GASM() */ 644b1a0a8a3SJed Brown EXTERN_C_END 645b1a0a8a3SJed Brown 646b1a0a8a3SJed Brown EXTERN_C_BEGIN 647b1a0a8a3SJed Brown #undef __FUNCT__ 648f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMSetOverlap_GASM" 6497087cfbeSBarry Smith PetscErrorCode PCGASMSetOverlap_GASM(PC pc,PetscInt ovl) 650b1a0a8a3SJed Brown { 651f746d493SDmitry Karpeev PC_GASM *osm = (PC_GASM*)pc->data; 652b1a0a8a3SJed Brown 653b1a0a8a3SJed Brown PetscFunctionBegin; 654b1a0a8a3SJed Brown if (ovl < 0) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Negative overlap value requested"); 655f746d493SDmitry Karpeev if (pc->setupcalled && ovl != osm->overlap) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONGSTATE,"PCGASMSetOverlap() should be called before PCSetUp()."); 656b1a0a8a3SJed Brown if (!pc->setupcalled) { 657b1a0a8a3SJed Brown osm->overlap = ovl; 658b1a0a8a3SJed Brown } 659b1a0a8a3SJed Brown PetscFunctionReturn(0); 660b1a0a8a3SJed Brown } 661b1a0a8a3SJed Brown EXTERN_C_END 662b1a0a8a3SJed Brown 663b1a0a8a3SJed Brown EXTERN_C_BEGIN 664b1a0a8a3SJed Brown #undef __FUNCT__ 665f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMSetType_GASM" 6667087cfbeSBarry Smith PetscErrorCode PCGASMSetType_GASM(PC pc,PCGASMType type) 667b1a0a8a3SJed Brown { 668f746d493SDmitry Karpeev PC_GASM *osm = (PC_GASM*)pc->data; 669b1a0a8a3SJed Brown 670b1a0a8a3SJed Brown PetscFunctionBegin; 671b1a0a8a3SJed Brown osm->type = type; 672b1a0a8a3SJed Brown osm->type_set = PETSC_TRUE; 673b1a0a8a3SJed Brown PetscFunctionReturn(0); 674b1a0a8a3SJed Brown } 675b1a0a8a3SJed Brown EXTERN_C_END 676b1a0a8a3SJed Brown 677b1a0a8a3SJed Brown EXTERN_C_BEGIN 678b1a0a8a3SJed Brown #undef __FUNCT__ 679f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMSetSortIndices_GASM" 6807087cfbeSBarry Smith PetscErrorCode PCGASMSetSortIndices_GASM(PC pc,PetscBool doSort) 681b1a0a8a3SJed Brown { 682f746d493SDmitry Karpeev PC_GASM *osm = (PC_GASM*)pc->data; 683b1a0a8a3SJed Brown 684b1a0a8a3SJed Brown PetscFunctionBegin; 685b1a0a8a3SJed Brown osm->sort_indices = doSort; 686b1a0a8a3SJed Brown PetscFunctionReturn(0); 687b1a0a8a3SJed Brown } 688b1a0a8a3SJed Brown EXTERN_C_END 689b1a0a8a3SJed Brown 690b1a0a8a3SJed Brown EXTERN_C_BEGIN 691b1a0a8a3SJed Brown #undef __FUNCT__ 692f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMGetSubKSP_GASM" 69344fe18e5SDmitry Karpeev /* 69444fe18e5SDmitry Karpeev FIX: This routine might need to be modified once multiple ranks per subdomain are allowed. 69544fe18e5SDmitry Karpeev In particular, it would upset the global subdomain number calculation. 69644fe18e5SDmitry Karpeev */ 6977087cfbeSBarry Smith PetscErrorCode PCGASMGetSubKSP_GASM(PC pc,PetscInt *n,PetscInt *first,KSP **ksp) 698b1a0a8a3SJed Brown { 699f746d493SDmitry Karpeev PC_GASM *osm = (PC_GASM*)pc->data; 700b1a0a8a3SJed Brown PetscErrorCode ierr; 701b1a0a8a3SJed Brown 702b1a0a8a3SJed Brown PetscFunctionBegin; 703ab3e923fSDmitry Karpeev if (osm->n < 1) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ORDER,"Need to call PCSetUP() on PC (or KSPSetUp() on the outer KSP object) before calling here"); 704b1a0a8a3SJed Brown 705ab3e923fSDmitry Karpeev if (n) { 706ab3e923fSDmitry Karpeev *n = osm->n; 707b1a0a8a3SJed Brown } 708ab3e923fSDmitry Karpeev if (first) { 709ab3e923fSDmitry Karpeev ierr = MPI_Scan(&osm->n,first,1,MPIU_INT,MPI_SUM,((PetscObject)pc)->comm);CHKERRQ(ierr); 710ab3e923fSDmitry Karpeev *first -= osm->n; 711b1a0a8a3SJed Brown } 712b1a0a8a3SJed Brown if (ksp) { 713b1a0a8a3SJed Brown /* Assume that local solves are now different; not necessarily 714f746d493SDmitry Karpeev true though! This flag is used only for PCView_GASM() */ 715b1a0a8a3SJed Brown *ksp = osm->ksp; 716b1a0a8a3SJed Brown osm->same_local_solves = PETSC_FALSE; 717b1a0a8a3SJed Brown } 718b1a0a8a3SJed Brown PetscFunctionReturn(0); 719ab3e923fSDmitry Karpeev }/* PCGASMGetSubKSP_GASM() */ 720b1a0a8a3SJed Brown EXTERN_C_END 721b1a0a8a3SJed Brown 722b1a0a8a3SJed Brown 723b1a0a8a3SJed Brown #undef __FUNCT__ 724f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMSetLocalSubdomains" 725b1a0a8a3SJed Brown /*@C 726f746d493SDmitry Karpeev PCGASMSetLocalSubdomains - Sets the local subdomains (for this processor 727b1a0a8a3SJed Brown only) for the additive Schwarz preconditioner. 728b1a0a8a3SJed Brown 729b1a0a8a3SJed Brown Collective on PC 730b1a0a8a3SJed Brown 731b1a0a8a3SJed Brown Input Parameters: 732b1a0a8a3SJed Brown + pc - the preconditioner context 733b1a0a8a3SJed Brown . n - the number of subdomains for this processor (default value = 1) 734b1a0a8a3SJed Brown . is - the index set that defines the subdomains for this processor 735b1a0a8a3SJed Brown (or PETSC_NULL for PETSc to determine subdomains) 736b1a0a8a3SJed Brown - is_local - the index sets that define the local part of the subdomains for this processor 737b1a0a8a3SJed Brown (or PETSC_NULL to use the default of 1 subdomain per process) 738b1a0a8a3SJed Brown 739b1a0a8a3SJed Brown Notes: 740b1a0a8a3SJed Brown The IS numbering is in the parallel, global numbering of the vector. 741b1a0a8a3SJed Brown 742f746d493SDmitry Karpeev By default the GASM preconditioner uses 1 block per processor. 743b1a0a8a3SJed Brown 744f746d493SDmitry Karpeev Use PCGASMSetTotalSubdomains() to set the subdomains for all processors. 745b1a0a8a3SJed Brown 746b1a0a8a3SJed Brown Level: advanced 747b1a0a8a3SJed Brown 748f746d493SDmitry Karpeev .keywords: PC, GASM, set, local, subdomains, additive Schwarz 749b1a0a8a3SJed Brown 750f746d493SDmitry Karpeev .seealso: PCGASMSetTotalSubdomains(), PCGASMSetOverlap(), PCGASMGetSubKSP(), 751f746d493SDmitry Karpeev PCGASMCreateSubdomains2D(), PCGASMGetLocalSubdomains() 752b1a0a8a3SJed Brown @*/ 7537087cfbeSBarry Smith PetscErrorCode PCGASMSetLocalSubdomains(PC pc,PetscInt n,IS is[],IS is_local[]) 754b1a0a8a3SJed Brown { 755b1a0a8a3SJed Brown PetscErrorCode ierr; 756b1a0a8a3SJed Brown 757b1a0a8a3SJed Brown PetscFunctionBegin; 758b1a0a8a3SJed Brown PetscValidHeaderSpecific(pc,PC_CLASSID,1); 759f746d493SDmitry Karpeev ierr = PetscTryMethod(pc,"PCGASMSetLocalSubdomains_C",(PC,PetscInt,IS[],IS[]),(pc,n,is,is_local));CHKERRQ(ierr); 760b1a0a8a3SJed Brown PetscFunctionReturn(0); 761b1a0a8a3SJed Brown } 762b1a0a8a3SJed Brown 763b1a0a8a3SJed Brown #undef __FUNCT__ 764f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMSetTotalSubdomains" 765b1a0a8a3SJed Brown /*@C 766f746d493SDmitry Karpeev PCGASMSetTotalSubdomains - Sets the subdomains for all processor for the 767b1a0a8a3SJed Brown additive Schwarz preconditioner. Either all or no processors in the 768b1a0a8a3SJed Brown PC communicator must call this routine, with the same index sets. 769b1a0a8a3SJed Brown 770b1a0a8a3SJed Brown Collective on PC 771b1a0a8a3SJed Brown 772b1a0a8a3SJed Brown Input Parameters: 773b1a0a8a3SJed Brown + pc - the preconditioner context 774b1a0a8a3SJed Brown . n - the number of subdomains for all processors 775b1a0a8a3SJed Brown . is - the index sets that define the subdomains for all processor 776b1a0a8a3SJed Brown (or PETSC_NULL for PETSc to determine subdomains) 777b1a0a8a3SJed Brown - is_local - the index sets that define the local part of the subdomains for this processor 778b1a0a8a3SJed Brown (or PETSC_NULL to use the default of 1 subdomain per process) 779b1a0a8a3SJed Brown 780b1a0a8a3SJed Brown Options Database Key: 781b1a0a8a3SJed Brown To set the total number of subdomain blocks rather than specify the 782b1a0a8a3SJed Brown index sets, use the option 783f746d493SDmitry Karpeev . -pc_gasm_blocks <blks> - Sets total blocks 784b1a0a8a3SJed Brown 785b1a0a8a3SJed Brown Notes: 786b1a0a8a3SJed Brown Currently you cannot use this to set the actual subdomains with the argument is. 787b1a0a8a3SJed Brown 788f746d493SDmitry Karpeev By default the GASM preconditioner uses 1 block per processor. 789b1a0a8a3SJed Brown 790b1a0a8a3SJed Brown These index sets cannot be destroyed until after completion of the 791f746d493SDmitry Karpeev linear solves for which the GASM preconditioner is being used. 792b1a0a8a3SJed Brown 793f746d493SDmitry Karpeev Use PCGASMSetLocalSubdomains() to set local subdomains. 794b1a0a8a3SJed Brown 795b1a0a8a3SJed Brown Level: advanced 796b1a0a8a3SJed Brown 797f746d493SDmitry Karpeev .keywords: PC, GASM, set, total, global, subdomains, additive Schwarz 798b1a0a8a3SJed Brown 799f746d493SDmitry Karpeev .seealso: PCGASMSetLocalSubdomains(), PCGASMSetOverlap(), PCGASMGetSubKSP(), 800f746d493SDmitry Karpeev PCGASMCreateSubdomains2D() 801b1a0a8a3SJed Brown @*/ 8027087cfbeSBarry Smith PetscErrorCode PCGASMSetTotalSubdomains(PC pc,PetscInt N) 803b1a0a8a3SJed Brown { 804b1a0a8a3SJed Brown PetscErrorCode ierr; 805b1a0a8a3SJed Brown 806b1a0a8a3SJed Brown PetscFunctionBegin; 807b1a0a8a3SJed Brown PetscValidHeaderSpecific(pc,PC_CLASSID,1); 808f746d493SDmitry Karpeev ierr = PetscTryMethod(pc,"PCGASMSetTotalSubdomains_C",(PC,PetscInt),(pc,N));CHKERRQ(ierr); 809b1a0a8a3SJed Brown PetscFunctionReturn(0); 810b1a0a8a3SJed Brown } 811b1a0a8a3SJed Brown 812b1a0a8a3SJed Brown #undef __FUNCT__ 813f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMSetOverlap" 814b1a0a8a3SJed Brown /*@ 815f746d493SDmitry Karpeev PCGASMSetOverlap - Sets the overlap between a pair of subdomains for the 816b1a0a8a3SJed Brown additive Schwarz preconditioner. Either all or no processors in the 817b1a0a8a3SJed Brown PC communicator must call this routine. 818b1a0a8a3SJed Brown 819b1a0a8a3SJed Brown Logically Collective on PC 820b1a0a8a3SJed Brown 821b1a0a8a3SJed Brown Input Parameters: 822b1a0a8a3SJed Brown + pc - the preconditioner context 823b1a0a8a3SJed Brown - ovl - the amount of overlap between subdomains (ovl >= 0, default value = 1) 824b1a0a8a3SJed Brown 825b1a0a8a3SJed Brown Options Database Key: 826f746d493SDmitry Karpeev . -pc_gasm_overlap <ovl> - Sets overlap 827b1a0a8a3SJed Brown 828b1a0a8a3SJed Brown Notes: 829f746d493SDmitry Karpeev By default the GASM preconditioner uses 1 block per processor. To use 830f746d493SDmitry Karpeev multiple blocks per perocessor, see PCGASMSetTotalSubdomains() and 831f746d493SDmitry Karpeev PCGASMSetLocalSubdomains() (and the option -pc_gasm_blocks <blks>). 832b1a0a8a3SJed Brown 833b1a0a8a3SJed Brown The overlap defaults to 1, so if one desires that no additional 834b1a0a8a3SJed Brown overlap be computed beyond what may have been set with a call to 835f746d493SDmitry Karpeev PCGASMSetTotalSubdomains() or PCGASMSetLocalSubdomains(), then ovl 836b1a0a8a3SJed Brown must be set to be 0. In particular, if one does not explicitly set 837b1a0a8a3SJed Brown the subdomains an application code, then all overlap would be computed 838f746d493SDmitry Karpeev internally by PETSc, and using an overlap of 0 would result in an GASM 839b1a0a8a3SJed Brown variant that is equivalent to the block Jacobi preconditioner. 840b1a0a8a3SJed Brown 841b1a0a8a3SJed Brown Note that one can define initial index sets with any overlap via 842f746d493SDmitry Karpeev PCGASMSetTotalSubdomains() or PCGASMSetLocalSubdomains(); the routine 843f746d493SDmitry Karpeev PCGASMSetOverlap() merely allows PETSc to extend that overlap further 844b1a0a8a3SJed Brown if desired. 845b1a0a8a3SJed Brown 846b1a0a8a3SJed Brown Level: intermediate 847b1a0a8a3SJed Brown 848f746d493SDmitry Karpeev .keywords: PC, GASM, set, overlap 849b1a0a8a3SJed Brown 850f746d493SDmitry Karpeev .seealso: PCGASMSetTotalSubdomains(), PCGASMSetLocalSubdomains(), PCGASMGetSubKSP(), 851f746d493SDmitry Karpeev PCGASMCreateSubdomains2D(), PCGASMGetLocalSubdomains() 852b1a0a8a3SJed Brown @*/ 8537087cfbeSBarry Smith PetscErrorCode PCGASMSetOverlap(PC pc,PetscInt ovl) 854b1a0a8a3SJed Brown { 855b1a0a8a3SJed Brown PetscErrorCode ierr; 856b1a0a8a3SJed Brown 857b1a0a8a3SJed Brown PetscFunctionBegin; 858b1a0a8a3SJed Brown PetscValidHeaderSpecific(pc,PC_CLASSID,1); 859b1a0a8a3SJed Brown PetscValidLogicalCollectiveInt(pc,ovl,2); 860f746d493SDmitry Karpeev ierr = PetscTryMethod(pc,"PCGASMSetOverlap_C",(PC,PetscInt),(pc,ovl));CHKERRQ(ierr); 861b1a0a8a3SJed Brown PetscFunctionReturn(0); 862b1a0a8a3SJed Brown } 863b1a0a8a3SJed Brown 864b1a0a8a3SJed Brown #undef __FUNCT__ 865f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMSetType" 866b1a0a8a3SJed Brown /*@ 867f746d493SDmitry Karpeev PCGASMSetType - Sets the type of restriction and interpolation used 868b1a0a8a3SJed Brown for local problems in the additive Schwarz method. 869b1a0a8a3SJed Brown 870b1a0a8a3SJed Brown Logically Collective on PC 871b1a0a8a3SJed Brown 872b1a0a8a3SJed Brown Input Parameters: 873b1a0a8a3SJed Brown + pc - the preconditioner context 874f746d493SDmitry Karpeev - type - variant of GASM, one of 875b1a0a8a3SJed Brown .vb 876f746d493SDmitry Karpeev PC_GASM_BASIC - full interpolation and restriction 877f746d493SDmitry Karpeev PC_GASM_RESTRICT - full restriction, local processor interpolation 878f746d493SDmitry Karpeev PC_GASM_INTERPOLATE - full interpolation, local processor restriction 879f746d493SDmitry Karpeev PC_GASM_NONE - local processor restriction and interpolation 880b1a0a8a3SJed Brown .ve 881b1a0a8a3SJed Brown 882b1a0a8a3SJed Brown Options Database Key: 883f746d493SDmitry Karpeev . -pc_gasm_type [basic,restrict,interpolate,none] - Sets GASM type 884b1a0a8a3SJed Brown 885b1a0a8a3SJed Brown Level: intermediate 886b1a0a8a3SJed Brown 887f746d493SDmitry Karpeev .keywords: PC, GASM, set, type 888b1a0a8a3SJed Brown 889f746d493SDmitry Karpeev .seealso: PCGASMSetTotalSubdomains(), PCGASMSetTotalSubdomains(), PCGASMGetSubKSP(), 890f746d493SDmitry Karpeev PCGASMCreateSubdomains2D() 891b1a0a8a3SJed Brown @*/ 8927087cfbeSBarry Smith PetscErrorCode PCGASMSetType(PC pc,PCGASMType type) 893b1a0a8a3SJed Brown { 894b1a0a8a3SJed Brown PetscErrorCode ierr; 895b1a0a8a3SJed Brown 896b1a0a8a3SJed Brown PetscFunctionBegin; 897b1a0a8a3SJed Brown PetscValidHeaderSpecific(pc,PC_CLASSID,1); 898b1a0a8a3SJed Brown PetscValidLogicalCollectiveEnum(pc,type,2); 899f746d493SDmitry Karpeev ierr = PetscTryMethod(pc,"PCGASMSetType_C",(PC,PCGASMType),(pc,type));CHKERRQ(ierr); 900b1a0a8a3SJed Brown PetscFunctionReturn(0); 901b1a0a8a3SJed Brown } 902b1a0a8a3SJed Brown 903b1a0a8a3SJed Brown #undef __FUNCT__ 904f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMSetSortIndices" 905b1a0a8a3SJed Brown /*@ 906f746d493SDmitry Karpeev PCGASMSetSortIndices - Determines whether subdomain indices are sorted. 907b1a0a8a3SJed Brown 908b1a0a8a3SJed Brown Logically Collective on PC 909b1a0a8a3SJed Brown 910b1a0a8a3SJed Brown Input Parameters: 911b1a0a8a3SJed Brown + pc - the preconditioner context 912b1a0a8a3SJed Brown - doSort - sort the subdomain indices 913b1a0a8a3SJed Brown 914b1a0a8a3SJed Brown Level: intermediate 915b1a0a8a3SJed Brown 916f746d493SDmitry Karpeev .keywords: PC, GASM, set, type 917b1a0a8a3SJed Brown 918f746d493SDmitry Karpeev .seealso: PCGASMSetLocalSubdomains(), PCGASMSetTotalSubdomains(), PCGASMGetSubKSP(), 919f746d493SDmitry Karpeev PCGASMCreateSubdomains2D() 920b1a0a8a3SJed Brown @*/ 9217087cfbeSBarry Smith PetscErrorCode PCGASMSetSortIndices(PC pc,PetscBool doSort) 922b1a0a8a3SJed Brown { 923b1a0a8a3SJed Brown PetscErrorCode ierr; 924b1a0a8a3SJed Brown 925b1a0a8a3SJed Brown PetscFunctionBegin; 926b1a0a8a3SJed Brown PetscValidHeaderSpecific(pc,PC_CLASSID,1); 927b1a0a8a3SJed Brown PetscValidLogicalCollectiveBool(pc,doSort,2); 928f746d493SDmitry Karpeev ierr = PetscTryMethod(pc,"PCGASMSetSortIndices_C",(PC,PetscBool),(pc,doSort));CHKERRQ(ierr); 929b1a0a8a3SJed Brown PetscFunctionReturn(0); 930b1a0a8a3SJed Brown } 931b1a0a8a3SJed Brown 932b1a0a8a3SJed Brown #undef __FUNCT__ 933f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMGetSubKSP" 934b1a0a8a3SJed Brown /*@C 935f746d493SDmitry Karpeev PCGASMGetSubKSP - Gets the local KSP contexts for all blocks on 936b1a0a8a3SJed Brown this processor. 937b1a0a8a3SJed Brown 938b1a0a8a3SJed Brown Collective on PC iff first_local is requested 939b1a0a8a3SJed Brown 940b1a0a8a3SJed Brown Input Parameter: 941b1a0a8a3SJed Brown . pc - the preconditioner context 942b1a0a8a3SJed Brown 943b1a0a8a3SJed Brown Output Parameters: 944b1a0a8a3SJed Brown + n_local - the number of blocks on this processor or PETSC_NULL 945b1a0a8a3SJed Brown . first_local - the global number of the first block on this processor or PETSC_NULL, 946b1a0a8a3SJed Brown all processors must request or all must pass PETSC_NULL 947b1a0a8a3SJed Brown - ksp - the array of KSP contexts 948b1a0a8a3SJed Brown 949b1a0a8a3SJed Brown Note: 950f746d493SDmitry Karpeev After PCGASMGetSubKSP() the array of KSPes is not to be freed 951b1a0a8a3SJed Brown 952b1a0a8a3SJed Brown Currently for some matrix implementations only 1 block per processor 953b1a0a8a3SJed Brown is supported. 954b1a0a8a3SJed Brown 955f746d493SDmitry Karpeev You must call KSPSetUp() before calling PCGASMGetSubKSP(). 956b1a0a8a3SJed Brown 957b1a0a8a3SJed Brown Level: advanced 958b1a0a8a3SJed Brown 959f746d493SDmitry Karpeev .keywords: PC, GASM, additive Schwarz, get, sub, KSP, context 960b1a0a8a3SJed Brown 961f746d493SDmitry Karpeev .seealso: PCGASMSetTotalSubdomains(), PCGASMSetTotalSubdomains(), PCGASMSetOverlap(), 962f746d493SDmitry Karpeev PCGASMCreateSubdomains2D(), 963b1a0a8a3SJed Brown @*/ 9647087cfbeSBarry Smith PetscErrorCode PCGASMGetSubKSP(PC pc,PetscInt *n_local,PetscInt *first_local,KSP *ksp[]) 965b1a0a8a3SJed Brown { 966b1a0a8a3SJed Brown PetscErrorCode ierr; 967b1a0a8a3SJed Brown 968b1a0a8a3SJed Brown PetscFunctionBegin; 969b1a0a8a3SJed Brown PetscValidHeaderSpecific(pc,PC_CLASSID,1); 970f746d493SDmitry Karpeev ierr = PetscUseMethod(pc,"PCGASMGetSubKSP_C",(PC,PetscInt*,PetscInt*,KSP **),(pc,n_local,first_local,ksp));CHKERRQ(ierr); 971b1a0a8a3SJed Brown PetscFunctionReturn(0); 972b1a0a8a3SJed Brown } 973b1a0a8a3SJed Brown 974b1a0a8a3SJed Brown /* -------------------------------------------------------------------------------------*/ 975b1a0a8a3SJed Brown /*MC 976f746d493SDmitry Karpeev PCGASM - Use the (restricted) additive Schwarz method, each block is (approximately) solved with 977b1a0a8a3SJed Brown its own KSP object. 978b1a0a8a3SJed Brown 979b1a0a8a3SJed Brown Options Database Keys: 980f746d493SDmitry Karpeev + -pc_gasm_truelocal - Activates PCGGASMSetUseTrueLocal() 981f746d493SDmitry Karpeev . -pc_gasm_blocks <blks> - Sets total blocks 982f746d493SDmitry Karpeev . -pc_gasm_overlap <ovl> - Sets overlap 983f746d493SDmitry Karpeev - -pc_gasm_type [basic,restrict,interpolate,none] - Sets GASM type 984b1a0a8a3SJed Brown 985b1a0a8a3SJed Brown IMPORTANT: If you run with, for example, 3 blocks on 1 processor or 3 blocks on 3 processors you 986f746d493SDmitry Karpeev will get a different convergence rate due to the default option of -pc_gasm_type restrict. Use 987f746d493SDmitry Karpeev -pc_gasm_type basic to use the standard GASM. 988b1a0a8a3SJed Brown 989b1a0a8a3SJed Brown Notes: Each processor can have one or more blocks, but a block cannot be shared by more 990b1a0a8a3SJed Brown than one processor. Defaults to one block per processor. 991b1a0a8a3SJed Brown 992b1a0a8a3SJed Brown To set options on the solvers for each block append -sub_ to all the KSP, and PC 993b1a0a8a3SJed Brown options database keys. For example, -sub_pc_type ilu -sub_pc_factor_levels 1 -sub_ksp_type preonly 994b1a0a8a3SJed Brown 995f746d493SDmitry Karpeev To set the options on the solvers separate for each block call PCGASMGetSubKSP() 996b1a0a8a3SJed Brown and set the options directly on the resulting KSP object (you can access its PC 997b1a0a8a3SJed Brown with KSPGetPC()) 998b1a0a8a3SJed Brown 999b1a0a8a3SJed Brown 1000b1a0a8a3SJed Brown Level: beginner 1001b1a0a8a3SJed Brown 1002b1a0a8a3SJed Brown Concepts: additive Schwarz method 1003b1a0a8a3SJed Brown 1004b1a0a8a3SJed Brown References: 1005b1a0a8a3SJed Brown An additive variant of the Schwarz alternating method for the case of many subregions 1006b1a0a8a3SJed Brown M Dryja, OB Widlund - Courant Institute, New York University Technical report 1007b1a0a8a3SJed Brown 1008b1a0a8a3SJed Brown Domain Decompositions: Parallel Multilevel Methods for Elliptic Partial Differential Equations, 1009b1a0a8a3SJed Brown Barry Smith, Petter Bjorstad, and William Gropp, Cambridge University Press, ISBN 0-521-49589-X. 1010b1a0a8a3SJed Brown 1011b1a0a8a3SJed Brown .seealso: PCCreate(), PCSetType(), PCType (for list of available types), PC, 1012f746d493SDmitry Karpeev PCBJACOBI, PCGASMSetUseTrueLocal(), PCGASMGetSubKSP(), PCGASMSetLocalSubdomains(), 1013f746d493SDmitry Karpeev PCGASMSetTotalSubdomains(), PCSetModifySubmatrices(), PCGASMSetOverlap(), PCGASMSetType() 1014b1a0a8a3SJed Brown 1015b1a0a8a3SJed Brown M*/ 1016b1a0a8a3SJed Brown 1017b1a0a8a3SJed Brown EXTERN_C_BEGIN 1018b1a0a8a3SJed Brown #undef __FUNCT__ 1019f746d493SDmitry Karpeev #define __FUNCT__ "PCCreate_GASM" 10207087cfbeSBarry Smith PetscErrorCode PCCreate_GASM(PC pc) 1021b1a0a8a3SJed Brown { 1022b1a0a8a3SJed Brown PetscErrorCode ierr; 1023f746d493SDmitry Karpeev PC_GASM *osm; 1024b1a0a8a3SJed Brown 1025b1a0a8a3SJed Brown PetscFunctionBegin; 1026f746d493SDmitry Karpeev ierr = PetscNewLog(pc,PC_GASM,&osm);CHKERRQ(ierr); 1027ab3e923fSDmitry Karpeev osm->N = PETSC_DECIDE; 1028ab3e923fSDmitry Karpeev osm->n = 0; 1029ab3e923fSDmitry Karpeev osm->nmax = 0; 1030b1a0a8a3SJed Brown osm->overlap = 1; 1031b1a0a8a3SJed Brown osm->ksp = 0; 1032ab3e923fSDmitry Karpeev osm->grestriction = 0; 1033ab3e923fSDmitry Karpeev osm->gprolongation = 0; 1034ab3e923fSDmitry Karpeev osm->gx = 0; 1035ab3e923fSDmitry Karpeev osm->gy = 0; 1036b1a0a8a3SJed Brown osm->x = 0; 1037b1a0a8a3SJed Brown osm->y = 0; 1038b1a0a8a3SJed Brown osm->is = 0; 1039b1a0a8a3SJed Brown osm->is_local = 0; 1040b1a0a8a3SJed Brown osm->pmat = 0; 1041f746d493SDmitry Karpeev osm->type = PC_GASM_RESTRICT; 1042b1a0a8a3SJed Brown osm->same_local_solves = PETSC_TRUE; 1043b1a0a8a3SJed Brown osm->sort_indices = PETSC_TRUE; 1044b1a0a8a3SJed Brown 1045b1a0a8a3SJed Brown pc->data = (void*)osm; 1046f746d493SDmitry Karpeev pc->ops->apply = PCApply_GASM; 1047f746d493SDmitry Karpeev pc->ops->applytranspose = PCApplyTranspose_GASM; 1048f746d493SDmitry Karpeev pc->ops->setup = PCSetUp_GASM; 1049f746d493SDmitry Karpeev pc->ops->destroy = PCDestroy_GASM; 1050f746d493SDmitry Karpeev pc->ops->setfromoptions = PCSetFromOptions_GASM; 1051f746d493SDmitry Karpeev pc->ops->setuponblocks = PCSetUpOnBlocks_GASM; 1052f746d493SDmitry Karpeev pc->ops->view = PCView_GASM; 1053b1a0a8a3SJed Brown pc->ops->applyrichardson = 0; 1054b1a0a8a3SJed Brown 1055f746d493SDmitry Karpeev ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCGASMSetLocalSubdomains_C","PCGASMSetLocalSubdomains_GASM", 1056f746d493SDmitry Karpeev PCGASMSetLocalSubdomains_GASM);CHKERRQ(ierr); 1057f746d493SDmitry Karpeev ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCGASMSetTotalSubdomains_C","PCGASMSetTotalSubdomains_GASM", 1058f746d493SDmitry Karpeev PCGASMSetTotalSubdomains_GASM);CHKERRQ(ierr); 1059f746d493SDmitry Karpeev ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCGASMSetOverlap_C","PCGASMSetOverlap_GASM", 1060f746d493SDmitry Karpeev PCGASMSetOverlap_GASM);CHKERRQ(ierr); 1061f746d493SDmitry Karpeev ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCGASMSetType_C","PCGASMSetType_GASM", 1062f746d493SDmitry Karpeev PCGASMSetType_GASM);CHKERRQ(ierr); 1063f746d493SDmitry Karpeev ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCGASMSetSortIndices_C","PCGASMSetSortIndices_GASM", 1064f746d493SDmitry Karpeev PCGASMSetSortIndices_GASM);CHKERRQ(ierr); 1065f746d493SDmitry Karpeev ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCGASMGetSubKSP_C","PCGASMGetSubKSP_GASM", 1066f746d493SDmitry Karpeev PCGASMGetSubKSP_GASM);CHKERRQ(ierr); 1067b1a0a8a3SJed Brown PetscFunctionReturn(0); 1068b1a0a8a3SJed Brown } 1069b1a0a8a3SJed Brown EXTERN_C_END 1070b1a0a8a3SJed Brown 1071b1a0a8a3SJed Brown 1072b1a0a8a3SJed Brown #undef __FUNCT__ 1073f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMCreateSubdomains" 1074b1a0a8a3SJed Brown /*@C 1075f746d493SDmitry Karpeev PCGASMCreateSubdomains - Creates the index sets for the overlapping Schwarz 1076b1a0a8a3SJed Brown preconditioner for a any problem on a general grid. 1077b1a0a8a3SJed Brown 1078b1a0a8a3SJed Brown Collective 1079b1a0a8a3SJed Brown 1080b1a0a8a3SJed Brown Input Parameters: 1081b1a0a8a3SJed Brown + A - The global matrix operator 1082b1a0a8a3SJed Brown - n - the number of local blocks 1083b1a0a8a3SJed Brown 1084b1a0a8a3SJed Brown Output Parameters: 1085b1a0a8a3SJed Brown . outis - the array of index sets defining the subdomains 1086b1a0a8a3SJed Brown 1087b1a0a8a3SJed Brown Level: advanced 1088b1a0a8a3SJed Brown 1089f746d493SDmitry Karpeev Note: this generates nonoverlapping subdomains; the PCGASM will generate the overlap 1090f746d493SDmitry Karpeev from these if you use PCGASMSetLocalSubdomains() 1091b1a0a8a3SJed Brown 1092b1a0a8a3SJed Brown In the Fortran version you must provide the array outis[] already allocated of length n. 1093b1a0a8a3SJed Brown 1094f746d493SDmitry Karpeev .keywords: PC, GASM, additive Schwarz, create, subdomains, unstructured grid 1095b1a0a8a3SJed Brown 1096f746d493SDmitry Karpeev .seealso: PCGASMSetLocalSubdomains(), PCGASMDestroySubdomains() 1097b1a0a8a3SJed Brown @*/ 10987087cfbeSBarry Smith PetscErrorCode PCGASMCreateSubdomains(Mat A, PetscInt n, IS* outis[]) 1099b1a0a8a3SJed Brown { 1100b1a0a8a3SJed Brown MatPartitioning mpart; 1101b1a0a8a3SJed Brown const char *prefix; 1102b1a0a8a3SJed Brown PetscErrorCode (*f)(Mat,PetscBool *,MatReuse,Mat*); 1103b1a0a8a3SJed Brown PetscMPIInt size; 1104b1a0a8a3SJed Brown PetscInt i,j,rstart,rend,bs; 1105b1a0a8a3SJed Brown PetscBool iscopy = PETSC_FALSE,isbaij = PETSC_FALSE,foundpart = PETSC_FALSE; 1106b1a0a8a3SJed Brown Mat Ad = PETSC_NULL, adj; 1107b1a0a8a3SJed Brown IS ispart,isnumb,*is; 1108b1a0a8a3SJed Brown PetscErrorCode ierr; 1109b1a0a8a3SJed Brown 1110b1a0a8a3SJed Brown PetscFunctionBegin; 1111b1a0a8a3SJed Brown PetscValidHeaderSpecific(A,MAT_CLASSID,1); 1112b1a0a8a3SJed Brown PetscValidPointer(outis,3); 1113b1a0a8a3SJed Brown if (n < 1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"number of local blocks must be > 0, n = %D",n); 1114b1a0a8a3SJed Brown 1115b1a0a8a3SJed Brown /* Get prefix, row distribution, and block size */ 1116b1a0a8a3SJed Brown ierr = MatGetOptionsPrefix(A,&prefix);CHKERRQ(ierr); 1117b1a0a8a3SJed Brown ierr = MatGetOwnershipRange(A,&rstart,&rend);CHKERRQ(ierr); 1118b1a0a8a3SJed Brown ierr = MatGetBlockSize(A,&bs);CHKERRQ(ierr); 1119b1a0a8a3SJed Brown 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); 1120b1a0a8a3SJed Brown 1121b1a0a8a3SJed Brown /* Get diagonal block from matrix if possible */ 1122b1a0a8a3SJed Brown ierr = MPI_Comm_size(((PetscObject)A)->comm,&size);CHKERRQ(ierr); 1123b1a0a8a3SJed Brown ierr = PetscObjectQueryFunction((PetscObject)A,"MatGetDiagonalBlock_C",(void (**)(void))&f);CHKERRQ(ierr); 1124b1a0a8a3SJed Brown if (f) { 1125b1a0a8a3SJed Brown ierr = (*f)(A,&iscopy,MAT_INITIAL_MATRIX,&Ad);CHKERRQ(ierr); 1126b1a0a8a3SJed Brown } else if (size == 1) { 1127b1a0a8a3SJed Brown iscopy = PETSC_FALSE; Ad = A; 1128b1a0a8a3SJed Brown } else { 1129b1a0a8a3SJed Brown iscopy = PETSC_FALSE; Ad = PETSC_NULL; 1130b1a0a8a3SJed Brown } 1131b1a0a8a3SJed Brown if (Ad) { 1132b1a0a8a3SJed Brown ierr = PetscTypeCompare((PetscObject)Ad,MATSEQBAIJ,&isbaij);CHKERRQ(ierr); 1133b1a0a8a3SJed Brown if (!isbaij) {ierr = PetscTypeCompare((PetscObject)Ad,MATSEQSBAIJ,&isbaij);CHKERRQ(ierr);} 1134b1a0a8a3SJed Brown } 1135b1a0a8a3SJed Brown if (Ad && n > 1) { 1136b1a0a8a3SJed Brown PetscBool match,done; 1137b1a0a8a3SJed Brown /* Try to setup a good matrix partitioning if available */ 1138b1a0a8a3SJed Brown ierr = MatPartitioningCreate(PETSC_COMM_SELF,&mpart);CHKERRQ(ierr); 1139b1a0a8a3SJed Brown ierr = PetscObjectSetOptionsPrefix((PetscObject)mpart,prefix);CHKERRQ(ierr); 1140b1a0a8a3SJed Brown ierr = MatPartitioningSetFromOptions(mpart);CHKERRQ(ierr); 1141b1a0a8a3SJed Brown ierr = PetscTypeCompare((PetscObject)mpart,MATPARTITIONINGCURRENT,&match);CHKERRQ(ierr); 1142b1a0a8a3SJed Brown if (!match) { 1143b1a0a8a3SJed Brown ierr = PetscTypeCompare((PetscObject)mpart,MATPARTITIONINGSQUARE,&match);CHKERRQ(ierr); 1144b1a0a8a3SJed Brown } 1145b1a0a8a3SJed Brown if (!match) { /* assume a "good" partitioner is available */ 1146b1a0a8a3SJed Brown PetscInt na,*ia,*ja; 1147b1a0a8a3SJed Brown ierr = MatGetRowIJ(Ad,0,PETSC_TRUE,isbaij,&na,&ia,&ja,&done);CHKERRQ(ierr); 1148b1a0a8a3SJed Brown if (done) { 1149b1a0a8a3SJed Brown /* Build adjacency matrix by hand. Unfortunately a call to 1150b1a0a8a3SJed Brown MatConvert(Ad,MATMPIADJ,MAT_INITIAL_MATRIX,&adj) will 1151b1a0a8a3SJed Brown remove the block-aij structure and we cannot expect 1152b1a0a8a3SJed Brown MatPartitioning to split vertices as we need */ 1153b1a0a8a3SJed Brown PetscInt i,j,*row,len,nnz,cnt,*iia=0,*jja=0; 1154b1a0a8a3SJed Brown nnz = 0; 1155b1a0a8a3SJed Brown for (i=0; i<na; i++) { /* count number of nonzeros */ 1156b1a0a8a3SJed Brown len = ia[i+1] - ia[i]; 1157b1a0a8a3SJed Brown row = ja + ia[i]; 1158b1a0a8a3SJed Brown for (j=0; j<len; j++) { 1159b1a0a8a3SJed Brown if (row[j] == i) { /* don't count diagonal */ 1160b1a0a8a3SJed Brown len--; break; 1161b1a0a8a3SJed Brown } 1162b1a0a8a3SJed Brown } 1163b1a0a8a3SJed Brown nnz += len; 1164b1a0a8a3SJed Brown } 1165b1a0a8a3SJed Brown ierr = PetscMalloc((na+1)*sizeof(PetscInt),&iia);CHKERRQ(ierr); 1166b1a0a8a3SJed Brown ierr = PetscMalloc((nnz)*sizeof(PetscInt),&jja);CHKERRQ(ierr); 1167b1a0a8a3SJed Brown nnz = 0; 1168b1a0a8a3SJed Brown iia[0] = 0; 1169b1a0a8a3SJed Brown for (i=0; i<na; i++) { /* fill adjacency */ 1170b1a0a8a3SJed Brown cnt = 0; 1171b1a0a8a3SJed Brown len = ia[i+1] - ia[i]; 1172b1a0a8a3SJed Brown row = ja + ia[i]; 1173b1a0a8a3SJed Brown for (j=0; j<len; j++) { 1174b1a0a8a3SJed Brown if (row[j] != i) { /* if not diagonal */ 1175b1a0a8a3SJed Brown jja[nnz+cnt++] = row[j]; 1176b1a0a8a3SJed Brown } 1177b1a0a8a3SJed Brown } 1178b1a0a8a3SJed Brown nnz += cnt; 1179b1a0a8a3SJed Brown iia[i+1] = nnz; 1180b1a0a8a3SJed Brown } 1181b1a0a8a3SJed Brown /* Partitioning of the adjacency matrix */ 1182b1a0a8a3SJed Brown ierr = MatCreateMPIAdj(PETSC_COMM_SELF,na,na,iia,jja,PETSC_NULL,&adj);CHKERRQ(ierr); 1183b1a0a8a3SJed Brown ierr = MatPartitioningSetAdjacency(mpart,adj);CHKERRQ(ierr); 1184b1a0a8a3SJed Brown ierr = MatPartitioningSetNParts(mpart,n);CHKERRQ(ierr); 1185b1a0a8a3SJed Brown ierr = MatPartitioningApply(mpart,&ispart);CHKERRQ(ierr); 1186b1a0a8a3SJed Brown ierr = ISPartitioningToNumbering(ispart,&isnumb);CHKERRQ(ierr); 1187b1a0a8a3SJed Brown ierr = MatDestroy(adj);CHKERRQ(ierr); 1188b1a0a8a3SJed Brown foundpart = PETSC_TRUE; 1189b1a0a8a3SJed Brown } 1190b1a0a8a3SJed Brown ierr = MatRestoreRowIJ(Ad,0,PETSC_TRUE,isbaij,&na,&ia,&ja,&done);CHKERRQ(ierr); 1191b1a0a8a3SJed Brown } 1192b1a0a8a3SJed Brown ierr = MatPartitioningDestroy(mpart);CHKERRQ(ierr); 1193b1a0a8a3SJed Brown } 1194b1a0a8a3SJed Brown if (iscopy) {ierr = MatDestroy(Ad);CHKERRQ(ierr);} 1195b1a0a8a3SJed Brown 1196b1a0a8a3SJed Brown ierr = PetscMalloc(n*sizeof(IS),&is);CHKERRQ(ierr); 1197b1a0a8a3SJed Brown *outis = is; 1198b1a0a8a3SJed Brown 1199b1a0a8a3SJed Brown if (!foundpart) { 1200b1a0a8a3SJed Brown 1201b1a0a8a3SJed Brown /* Partitioning by contiguous chunks of rows */ 1202b1a0a8a3SJed Brown 1203b1a0a8a3SJed Brown PetscInt mbs = (rend-rstart)/bs; 1204b1a0a8a3SJed Brown PetscInt start = rstart; 1205b1a0a8a3SJed Brown for (i=0; i<n; i++) { 1206b1a0a8a3SJed Brown PetscInt count = (mbs/n + ((mbs % n) > i)) * bs; 1207b1a0a8a3SJed Brown ierr = ISCreateStride(PETSC_COMM_SELF,count,start,1,&is[i]);CHKERRQ(ierr); 1208b1a0a8a3SJed Brown start += count; 1209b1a0a8a3SJed Brown } 1210b1a0a8a3SJed Brown 1211b1a0a8a3SJed Brown } else { 1212b1a0a8a3SJed Brown 1213b1a0a8a3SJed Brown /* Partitioning by adjacency of diagonal block */ 1214b1a0a8a3SJed Brown 1215b1a0a8a3SJed Brown const PetscInt *numbering; 1216b1a0a8a3SJed Brown PetscInt *count,nidx,*indices,*newidx,start=0; 1217b1a0a8a3SJed Brown /* Get node count in each partition */ 1218b1a0a8a3SJed Brown ierr = PetscMalloc(n*sizeof(PetscInt),&count);CHKERRQ(ierr); 1219b1a0a8a3SJed Brown ierr = ISPartitioningCount(ispart,n,count);CHKERRQ(ierr); 1220b1a0a8a3SJed Brown if (isbaij && bs > 1) { /* adjust for the block-aij case */ 1221b1a0a8a3SJed Brown for (i=0; i<n; i++) count[i] *= bs; 1222b1a0a8a3SJed Brown } 1223b1a0a8a3SJed Brown /* Build indices from node numbering */ 1224b1a0a8a3SJed Brown ierr = ISGetLocalSize(isnumb,&nidx);CHKERRQ(ierr); 1225b1a0a8a3SJed Brown ierr = PetscMalloc(nidx*sizeof(PetscInt),&indices);CHKERRQ(ierr); 1226b1a0a8a3SJed Brown for (i=0; i<nidx; i++) indices[i] = i; /* needs to be initialized */ 1227b1a0a8a3SJed Brown ierr = ISGetIndices(isnumb,&numbering);CHKERRQ(ierr); 1228b1a0a8a3SJed Brown ierr = PetscSortIntWithPermutation(nidx,numbering,indices);CHKERRQ(ierr); 1229b1a0a8a3SJed Brown ierr = ISRestoreIndices(isnumb,&numbering);CHKERRQ(ierr); 1230b1a0a8a3SJed Brown if (isbaij && bs > 1) { /* adjust for the block-aij case */ 1231b1a0a8a3SJed Brown ierr = PetscMalloc(nidx*bs*sizeof(PetscInt),&newidx);CHKERRQ(ierr); 1232b1a0a8a3SJed Brown for (i=0; i<nidx; i++) 1233b1a0a8a3SJed Brown for (j=0; j<bs; j++) 1234b1a0a8a3SJed Brown newidx[i*bs+j] = indices[i]*bs + j; 1235b1a0a8a3SJed Brown ierr = PetscFree(indices);CHKERRQ(ierr); 1236b1a0a8a3SJed Brown nidx *= bs; 1237b1a0a8a3SJed Brown indices = newidx; 1238b1a0a8a3SJed Brown } 1239b1a0a8a3SJed Brown /* Shift to get global indices */ 1240b1a0a8a3SJed Brown for (i=0; i<nidx; i++) indices[i] += rstart; 1241b1a0a8a3SJed Brown 1242b1a0a8a3SJed Brown /* Build the index sets for each block */ 1243b1a0a8a3SJed Brown for (i=0; i<n; i++) { 1244b1a0a8a3SJed Brown ierr = ISCreateGeneral(PETSC_COMM_SELF,count[i],&indices[start],PETSC_COPY_VALUES,&is[i]);CHKERRQ(ierr); 1245b1a0a8a3SJed Brown ierr = ISSort(is[i]);CHKERRQ(ierr); 1246b1a0a8a3SJed Brown start += count[i]; 1247b1a0a8a3SJed Brown } 1248b1a0a8a3SJed Brown 1249b1a0a8a3SJed Brown ierr = PetscFree(count); 1250b1a0a8a3SJed Brown ierr = PetscFree(indices); 1251b1a0a8a3SJed Brown ierr = ISDestroy(isnumb);CHKERRQ(ierr); 1252b1a0a8a3SJed Brown ierr = ISDestroy(ispart);CHKERRQ(ierr); 1253b1a0a8a3SJed Brown } 1254b1a0a8a3SJed Brown 1255b1a0a8a3SJed Brown PetscFunctionReturn(0); 1256b1a0a8a3SJed Brown } 1257b1a0a8a3SJed Brown 1258b1a0a8a3SJed Brown #undef __FUNCT__ 1259f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMDestroySubdomains" 1260b1a0a8a3SJed Brown /*@C 1261f746d493SDmitry Karpeev PCGASMDestroySubdomains - Destroys the index sets created with 1262f746d493SDmitry Karpeev PCGASMCreateSubdomains(). Should be called after setting subdomains 1263f746d493SDmitry Karpeev with PCGASMSetLocalSubdomains(). 1264b1a0a8a3SJed Brown 1265b1a0a8a3SJed Brown Collective 1266b1a0a8a3SJed Brown 1267b1a0a8a3SJed Brown Input Parameters: 1268b1a0a8a3SJed Brown + n - the number of index sets 1269b1a0a8a3SJed Brown . is - the array of index sets 1270b1a0a8a3SJed Brown - is_local - the array of local index sets, can be PETSC_NULL 1271b1a0a8a3SJed Brown 1272b1a0a8a3SJed Brown Level: advanced 1273b1a0a8a3SJed Brown 1274f746d493SDmitry Karpeev .keywords: PC, GASM, additive Schwarz, create, subdomains, unstructured grid 1275b1a0a8a3SJed Brown 1276f746d493SDmitry Karpeev .seealso: PCGASMCreateSubdomains(), PCGASMSetLocalSubdomains() 1277b1a0a8a3SJed Brown @*/ 12787087cfbeSBarry Smith PetscErrorCode PCGASMDestroySubdomains(PetscInt n, IS is[], IS is_local[]) 1279b1a0a8a3SJed Brown { 1280b1a0a8a3SJed Brown PetscInt i; 1281b1a0a8a3SJed Brown PetscErrorCode ierr; 1282b1a0a8a3SJed Brown PetscFunctionBegin; 1283b1a0a8a3SJed Brown if (n <= 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"n must be > 0: n = %D",n); 1284b1a0a8a3SJed Brown PetscValidPointer(is,2); 1285b1a0a8a3SJed Brown for (i=0; i<n; i++) { ierr = ISDestroy(is[i]);CHKERRQ(ierr); } 1286b1a0a8a3SJed Brown ierr = PetscFree(is);CHKERRQ(ierr); 1287b1a0a8a3SJed Brown if (is_local) { 1288b1a0a8a3SJed Brown PetscValidPointer(is_local,3); 1289b1a0a8a3SJed Brown for (i=0; i<n; i++) { ierr = ISDestroy(is_local[i]);CHKERRQ(ierr); } 1290b1a0a8a3SJed Brown ierr = PetscFree(is_local);CHKERRQ(ierr); 1291b1a0a8a3SJed Brown } 1292b1a0a8a3SJed Brown PetscFunctionReturn(0); 1293b1a0a8a3SJed Brown } 1294b1a0a8a3SJed Brown 1295af538404SDmitry Karpeev 1296af538404SDmitry Karpeev #define PCGASMLocalSubdomainBounds2D(M,N,xleft,ylow,xright,yhigh,first,last,xleft_loc,ylow_loc,xright_loc,yhigh_loc,n) \ 1297af538404SDmitry Karpeev { \ 1298af538404SDmitry Karpeev PetscInt first_row = first/M, last_row = last/M+1; \ 1299af538404SDmitry Karpeev /* \ 1300af538404SDmitry Karpeev Compute ylow_loc and yhigh_loc so that (ylow_loc,xleft) and (yhigh_loc,xright) are the corners \ 1301af538404SDmitry Karpeev of the bounding box of the intersection of the subdomain with the local ownership range (local \ 1302af538404SDmitry Karpeev subdomain). \ 1303af538404SDmitry Karpeev Also compute xleft_loc and xright_loc as the lower and upper bounds on the first and last rows \ 1304af538404SDmitry Karpeev of the intersection. \ 1305af538404SDmitry Karpeev */ \ 1306af538404SDmitry Karpeev /* ylow_loc is the grid row containing the first element of the local sumbdomain */ \ 1307eec7e3faSDmitry Karpeev *ylow_loc = PetscMax(first_row,ylow); \ 1308af538404SDmitry Karpeev /* xleft_loc is the offset of first element of the local subdomain within its grid row (might actually be outside the local subdomain) */ \ 1309eec7e3faSDmitry Karpeev *xleft_loc = *ylow_loc==first_row?PetscMax(first%M,xleft):xleft; \ 1310af538404SDmitry Karpeev /* yhigh_loc is the grid row above the last local subdomain element */ \ 1311eec7e3faSDmitry Karpeev *yhigh_loc = PetscMin(last_row,yhigh); \ 1312af538404SDmitry Karpeev /* xright is the offset of the end of the local subdomain within its grid row (might actually be outside the local subdomain) */ \ 1313eec7e3faSDmitry Karpeev *xright_loc = *yhigh_loc==last_row?PetscMin(xright,last%M):xright; \ 1314af538404SDmitry Karpeev /* Now compute the size of the local subdomain n. */ \ 1315c3518bceSDmitry Karpeev *n = 0; \ 1316eec7e3faSDmitry Karpeev if(*ylow_loc < *yhigh_loc) { \ 1317af538404SDmitry Karpeev PetscInt width = xright-xleft; \ 1318eec7e3faSDmitry Karpeev *n += width*(*yhigh_loc-*ylow_loc-1); \ 1319eec7e3faSDmitry Karpeev *n += PetscMin(PetscMax(*xright_loc-xleft,0),width); \ 1320eec7e3faSDmitry Karpeev *n -= PetscMin(PetscMax(*xleft_loc-xleft,0), width); \ 1321af538404SDmitry Karpeev }\ 1322af538404SDmitry Karpeev } 1323af538404SDmitry Karpeev 1324c3518bceSDmitry Karpeev 1325eec7e3faSDmitry Karpeev 1326eec7e3faSDmitry Karpeev #undef __FUNCT__ 1327f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMCreateSubdomains2D" 1328b1a0a8a3SJed Brown /*@ 1329f746d493SDmitry Karpeev PCGASMCreateSubdomains2D - Creates the index sets for the overlapping Schwarz 1330b1a0a8a3SJed Brown preconditioner for a two-dimensional problem on a regular grid. 1331b1a0a8a3SJed Brown 1332af538404SDmitry Karpeev Collective 1333b1a0a8a3SJed Brown 1334b1a0a8a3SJed Brown Input Parameters: 1335af538404SDmitry Karpeev + M, N - the global number of mesh points in the x and y directions 1336af538404SDmitry Karpeev . Mdomains, Ndomains - the global number of subdomains in the x and y directions 1337b1a0a8a3SJed Brown . dof - degrees of freedom per node 1338b1a0a8a3SJed Brown - overlap - overlap in mesh lines 1339b1a0a8a3SJed Brown 1340b1a0a8a3SJed Brown Output Parameters: 1341af538404SDmitry Karpeev + Nsub - the number of local subdomains created 1342b1a0a8a3SJed Brown . is - array of index sets defining overlapping (if overlap > 0) subdomains 1343b1a0a8a3SJed Brown - is_local - array of index sets defining non-overlapping subdomains 1344b1a0a8a3SJed Brown 1345b1a0a8a3SJed Brown Note: 1346b1a0a8a3SJed Brown Presently PCAMSCreateSubdomains2d() is valid only for sequential 1347b1a0a8a3SJed Brown preconditioners. More general related routines are 1348f746d493SDmitry Karpeev PCGASMSetTotalSubdomains() and PCGASMSetLocalSubdomains(). 1349b1a0a8a3SJed Brown 1350b1a0a8a3SJed Brown Level: advanced 1351b1a0a8a3SJed Brown 1352f746d493SDmitry Karpeev .keywords: PC, GASM, additive Schwarz, create, subdomains, 2D, regular grid 1353b1a0a8a3SJed Brown 1354f746d493SDmitry Karpeev .seealso: PCGASMSetTotalSubdomains(), PCGASMSetLocalSubdomains(), PCGASMGetSubKSP(), 1355f746d493SDmitry Karpeev PCGASMSetOverlap() 1356b1a0a8a3SJed Brown @*/ 13577087cfbeSBarry Smith PetscErrorCode PCGASMCreateSubdomains2D(PC pc, PetscInt M,PetscInt N,PetscInt Mdomains,PetscInt Ndomains,PetscInt dof,PetscInt overlap, PetscInt *nsub,IS **is,IS **is_local) 1358b1a0a8a3SJed Brown { 1359b1a0a8a3SJed Brown PetscErrorCode ierr; 13602bbb417fSDmitry Karpeev PetscMPIInt size, rank; 13612bbb417fSDmitry Karpeev PetscInt i, j; 13622bbb417fSDmitry Karpeev PetscInt maxheight, maxwidth; 13632bbb417fSDmitry Karpeev PetscInt xstart, xleft, xright, xleft_loc, xright_loc; 13642bbb417fSDmitry Karpeev PetscInt ystart, ylow, yhigh, ylow_loc, yhigh_loc; 1365eec7e3faSDmitry Karpeev PetscInt x[2][2], y[2][2], n[2]; 13662bbb417fSDmitry Karpeev PetscInt first, last; 13672bbb417fSDmitry Karpeev PetscInt nidx, *idx; 13682bbb417fSDmitry Karpeev PetscInt ii,jj,s,q,d; 1369af538404SDmitry Karpeev PetscInt k,kk; 13702bbb417fSDmitry Karpeev PetscMPIInt color; 13712bbb417fSDmitry Karpeev MPI_Comm comm, subcomm; 1372af538404SDmitry Karpeev 13732bbb417fSDmitry Karpeev IS **iis; 1374b1a0a8a3SJed Brown PetscFunctionBegin; 13752bbb417fSDmitry Karpeev ierr = PetscObjectGetComm((PetscObject)pc, &comm); CHKERRQ(ierr); 13762bbb417fSDmitry Karpeev ierr = MPI_Comm_size(comm, &size); CHKERRQ(ierr); 13772bbb417fSDmitry Karpeev ierr = MPI_Comm_rank(comm, &rank); CHKERRQ(ierr); 13782bbb417fSDmitry Karpeev ierr = MatGetOwnershipRange(pc->pmat, &first, &last); CHKERRQ(ierr); 13792bbb417fSDmitry Karpeev if(first%dof || last%dof) { 13802bbb417fSDmitry Karpeev SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Matrix row partitioning unsuitable for domain decomposition: local row range (%D,%D) " 13812bbb417fSDmitry Karpeev "does not respect the number of degrees of freedom per grid point %D", first, last, dof); 13822bbb417fSDmitry Karpeev } 1383af538404SDmitry Karpeev /* Determine the number of domains with nonzero intersections with the local ownership range. */ 13842bbb417fSDmitry Karpeev s = 0; 1385af538404SDmitry Karpeev ystart = 0; 1386af538404SDmitry Karpeev for (j=0; j<Ndomains; ++j) { 1387af538404SDmitry Karpeev maxheight = N/Ndomains + ((N % Ndomains) > j); /* Maximal height of subdomain */ 1388af538404SDmitry Karpeev if (maxheight < 2) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Too many %D subdomains in the vertical directon for mesh height %D", Ndomains, N); 1389eec7e3faSDmitry Karpeev /* Vertical domain limits with an overlap. */ 1390eec7e3faSDmitry Karpeev ylow = PetscMax(ystart - overlap,0); 1391eec7e3faSDmitry Karpeev yhigh = PetscMin(ystart + maxheight + overlap,N); 1392b1a0a8a3SJed Brown xstart = 0; 1393af538404SDmitry Karpeev for (i=0; i<Mdomains; ++i) { 1394af538404SDmitry Karpeev maxwidth = M/Mdomains + ((M % Mdomains) > i); /* Maximal width of subdomain */ 1395af538404SDmitry Karpeev if (maxwidth < 2) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Too many %D subdomains in the horizontal direction for mesh width %D", Mdomains, M); 1396eec7e3faSDmitry Karpeev /* Horizontal domain limits with an overlap. */ 1397eec7e3faSDmitry Karpeev xleft = PetscMax(xstart - overlap,0); 1398eec7e3faSDmitry Karpeev xright = PetscMin(xstart + maxwidth + overlap,M); 1399af538404SDmitry Karpeev /* 1400af538404SDmitry Karpeev Determine whether this subdomain intersects this processor's ownership range of pc->pmat. 1401af538404SDmitry Karpeev */ 1402c3518bceSDmitry Karpeev PCGASMLocalSubdomainBounds2D(M,N,xleft,ylow,xright,yhigh,first,last,(&xleft_loc),(&ylow_loc),(&xright_loc),(&yhigh_loc),(&nidx)); 1403af538404SDmitry Karpeev if(nidx) { 1404af538404SDmitry Karpeev ++s; 1405af538404SDmitry Karpeev } 1406af538404SDmitry Karpeev xstart += maxwidth; 1407af538404SDmitry Karpeev }/* for(i = 0; i < Mdomains; ++i) */ 1408af538404SDmitry Karpeev ystart += maxheight; 1409af538404SDmitry Karpeev }/* for(j = 0; j < Ndomains; ++j) */ 1410af538404SDmitry Karpeev /* Now we can allocate the necessary number of ISs. */ 1411af538404SDmitry Karpeev *nsub = s; 1412af538404SDmitry Karpeev ierr = PetscMalloc((*nsub)*sizeof(IS*),is); CHKERRQ(ierr); 1413af538404SDmitry Karpeev ierr = PetscMalloc((*nsub)*sizeof(IS*),is_local); CHKERRQ(ierr); 1414af538404SDmitry Karpeev s = 0; 1415af538404SDmitry Karpeev ystart = 0; 1416af538404SDmitry Karpeev for (j=0; j<Ndomains; ++j) { 1417af538404SDmitry Karpeev maxheight = N/Ndomains + ((N % Ndomains) > j); /* Maximal height of subdomain */ 1418af538404SDmitry Karpeev if (maxheight < 2) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Too many %D subdomains in the vertical directon for mesh height %D", Ndomains, N); 1419af538404SDmitry Karpeev /* Vertical domain limits with an overlap. */ 1420eec7e3faSDmitry Karpeev y[0][0] = PetscMax(ystart - overlap,0); 1421eec7e3faSDmitry Karpeev y[0][1] = PetscMin(ystart + maxheight + overlap,N); 1422eec7e3faSDmitry Karpeev /* Vertical domain limits without an overlap. */ 1423eec7e3faSDmitry Karpeev y[1][0] = ystart; 1424eec7e3faSDmitry Karpeev y[1][1] = PetscMin(ystart + maxheight,N); 1425eec7e3faSDmitry Karpeev xstart = 0; 1426af538404SDmitry Karpeev for (i=0; i<Mdomains; ++i) { 1427af538404SDmitry Karpeev maxwidth = M/Mdomains + ((M % Mdomains) > i); /* Maximal width of subdomain */ 1428af538404SDmitry Karpeev if (maxwidth < 2) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Too many %D subdomains in the horizontal direction for mesh width %D", Mdomains, M); 1429af538404SDmitry Karpeev /* Horizontal domain limits with an overlap. */ 1430eec7e3faSDmitry Karpeev x[0][0] = PetscMax(xstart - overlap,0); 1431eec7e3faSDmitry Karpeev x[0][1] = PetscMin(xstart + maxwidth + overlap,M); 1432eec7e3faSDmitry Karpeev /* Horizontal domain limits without an overlap. */ 1433eec7e3faSDmitry Karpeev x[1][0] = xstart; 1434eec7e3faSDmitry Karpeev x[1][1] = PetscMin(xstart+maxwidth,M); 14352bbb417fSDmitry Karpeev /* 14362bbb417fSDmitry Karpeev Determine whether this domain intersects this processor's ownership range of pc->pmat. 14372bbb417fSDmitry Karpeev Do this twice: first for the domains with overlaps, and once without. 14382bbb417fSDmitry Karpeev During the first pass create the subcommunicators, and use them on the second pass as well. 14392bbb417fSDmitry Karpeev */ 14402bbb417fSDmitry Karpeev for(q = 0; q < 2; ++q) { 14412bbb417fSDmitry Karpeev /* 14422bbb417fSDmitry Karpeev domain limits, (xleft, xright) and (ylow, yheigh) are adjusted 14432bbb417fSDmitry Karpeev according to whether the domain with an overlap or without is considered. 14442bbb417fSDmitry Karpeev */ 14452bbb417fSDmitry Karpeev xleft = x[q][0]; xright = x[q][1]; 14462bbb417fSDmitry Karpeev ylow = y[q][0]; yhigh = y[q][1]; 1447c3518bceSDmitry Karpeev PCGASMLocalSubdomainBounds2D(M,N,xleft,ylow,xright,yhigh,first,last,(&xleft_loc),(&ylow_loc),(&xright_loc),(&yhigh_loc),(&nidx)); 1448af538404SDmitry Karpeev nidx *= dof; 1449eec7e3faSDmitry Karpeev n[q] = nidx; 14502bbb417fSDmitry Karpeev /* 1451eec7e3faSDmitry Karpeev Based on the counted number of indices in the local domain *with an overlap*, 1452af538404SDmitry Karpeev construct a subcommunicator of all the processors supporting this domain. 1453eec7e3faSDmitry Karpeev Observe that a domain with an overlap might have nontrivial local support, 1454eec7e3faSDmitry Karpeev while the domain without an overlap might not. Hence, the decision to participate 1455eec7e3faSDmitry Karpeev in the subcommunicator must be based on the domain with an overlap. 14562bbb417fSDmitry Karpeev */ 14572bbb417fSDmitry Karpeev if(q == 0) { 14582bbb417fSDmitry Karpeev if(nidx) { 14592bbb417fSDmitry Karpeev color = 1; 1460b1a0a8a3SJed Brown } 14612bbb417fSDmitry Karpeev else { 14622bbb417fSDmitry Karpeev color = MPI_UNDEFINED; 14632bbb417fSDmitry Karpeev } 14642bbb417fSDmitry Karpeev ierr = MPI_Comm_split(comm, color, rank, &subcomm); CHKERRQ(ierr); 14652bbb417fSDmitry Karpeev } 1466af538404SDmitry Karpeev /* 1467eec7e3faSDmitry Karpeev Proceed only if the number of local indices *with an overlap* is nonzero. 1468af538404SDmitry Karpeev */ 1469eec7e3faSDmitry Karpeev if(n[0]) { 1470af538404SDmitry Karpeev if(q == 0) { 1471eec7e3faSDmitry Karpeev iis = is; 1472af538404SDmitry Karpeev } 1473af538404SDmitry Karpeev if(q == 1) { 1474af538404SDmitry Karpeev /* 1475eec7e3faSDmitry Karpeev The IS for the no-overlap subdomain shares a communicator with the overlapping domain. 1476af538404SDmitry Karpeev Moreover, if the overlap is zero, the two ISs are identical. 1477af538404SDmitry Karpeev */ 1478b1a0a8a3SJed Brown if(overlap == 0) { 1479eec7e3faSDmitry Karpeev (*is_local)[s] = (*is)[s]; 14802bbb417fSDmitry Karpeev ierr = PetscObjectReference((PetscObject)(*is)[s]);CHKERRQ(ierr); 14812bbb417fSDmitry Karpeev continue; 14822bbb417fSDmitry Karpeev } 1483af538404SDmitry Karpeev else { 1484eec7e3faSDmitry Karpeev iis = is_local; 1485eec7e3faSDmitry Karpeev subcomm = ((PetscObject)(*is)[s])->comm; 14862bbb417fSDmitry Karpeev } 1487af538404SDmitry Karpeev }/* if(q == 1) */ 1488eec7e3faSDmitry Karpeev idx = PETSC_NULL; 14892bbb417fSDmitry Karpeev ierr = PetscMalloc(nidx*sizeof(PetscInt),&idx);CHKERRQ(ierr); 1490eec7e3faSDmitry Karpeev if(nidx) { 14912bbb417fSDmitry Karpeev k = 0; 14922bbb417fSDmitry Karpeev for (jj=ylow_loc; jj<yhigh_loc; ++jj) { 1493af538404SDmitry Karpeev PetscInt x0 = (jj==ylow_loc)?xleft_loc:xleft; 1494af538404SDmitry Karpeev PetscInt x1 = (jj==yhigh_loc-1)?xright_loc:xright; 1495af538404SDmitry Karpeev kk = dof*(M*jj + x0); 14962bbb417fSDmitry Karpeev for (ii=x0; ii<x1; ++ii) { 14972bbb417fSDmitry Karpeev for(d = 0; d < dof; ++d) { 14982bbb417fSDmitry Karpeev idx[k++] = kk++; 1499b1a0a8a3SJed Brown } 1500b1a0a8a3SJed Brown } 1501b1a0a8a3SJed Brown } 1502eec7e3faSDmitry Karpeev } 15032bbb417fSDmitry Karpeev ierr = ISCreateGeneral(subcomm,nidx,idx,PETSC_OWN_POINTER,(*iis)+s);CHKERRQ(ierr); 1504eec7e3faSDmitry Karpeev }/* if(n[0]) */ 15052bbb417fSDmitry Karpeev }/* for(q = 0; q < 2; ++q) */ 1506eec7e3faSDmitry Karpeev if(n[0]) { 15072bbb417fSDmitry Karpeev ++s; 1508b1a0a8a3SJed Brown } 1509af538404SDmitry Karpeev xstart += maxwidth; 1510af538404SDmitry Karpeev }/* for(i = 0; i < Mdomains; ++i) */ 15112bbb417fSDmitry Karpeev ystart += maxheight; 1512af538404SDmitry Karpeev }/* for(j = 0; j < Ndomains; ++j) */ 1513b1a0a8a3SJed Brown PetscFunctionReturn(0); 1514b1a0a8a3SJed Brown } 1515b1a0a8a3SJed Brown 1516b1a0a8a3SJed Brown #undef __FUNCT__ 1517f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMGetLocalSubdomains" 1518b1a0a8a3SJed Brown /*@C 1519f746d493SDmitry Karpeev PCGASMGetLocalSubdomains - Gets the local subdomains (for this processor 1520b1a0a8a3SJed Brown only) for the additive Schwarz preconditioner. 1521b1a0a8a3SJed Brown 1522b1a0a8a3SJed Brown Not Collective 1523b1a0a8a3SJed Brown 1524b1a0a8a3SJed Brown Input Parameter: 1525b1a0a8a3SJed Brown . pc - the preconditioner context 1526b1a0a8a3SJed Brown 1527b1a0a8a3SJed Brown Output Parameters: 1528b1a0a8a3SJed Brown + n - the number of subdomains for this processor (default value = 1) 1529b1a0a8a3SJed Brown . is - the index sets that define the subdomains for this processor 1530b1a0a8a3SJed Brown - is_local - the index sets that define the local part of the subdomains for this processor (can be PETSC_NULL) 1531b1a0a8a3SJed Brown 1532b1a0a8a3SJed Brown 1533b1a0a8a3SJed Brown Notes: 1534b1a0a8a3SJed Brown The IS numbering is in the parallel, global numbering of the vector. 1535b1a0a8a3SJed Brown 1536b1a0a8a3SJed Brown Level: advanced 1537b1a0a8a3SJed Brown 1538f746d493SDmitry Karpeev .keywords: PC, GASM, set, local, subdomains, additive Schwarz 1539b1a0a8a3SJed Brown 1540f746d493SDmitry Karpeev .seealso: PCGASMSetTotalSubdomains(), PCGASMSetOverlap(), PCGASMGetSubKSP(), 1541f746d493SDmitry Karpeev PCGASMCreateSubdomains2D(), PCGASMSetLocalSubdomains(), PCGASMGetLocalSubmatrices() 1542b1a0a8a3SJed Brown @*/ 15437087cfbeSBarry Smith PetscErrorCode PCGASMGetLocalSubdomains(PC pc,PetscInt *n,IS *is[],IS *is_local[]) 1544b1a0a8a3SJed Brown { 1545f746d493SDmitry Karpeev PC_GASM *osm; 1546b1a0a8a3SJed Brown PetscErrorCode ierr; 1547b1a0a8a3SJed Brown PetscBool match; 1548b1a0a8a3SJed Brown 1549b1a0a8a3SJed Brown PetscFunctionBegin; 1550b1a0a8a3SJed Brown PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1551b1a0a8a3SJed Brown PetscValidIntPointer(n,2); 1552b1a0a8a3SJed Brown if (is) PetscValidPointer(is,3); 1553f746d493SDmitry Karpeev ierr = PetscTypeCompare((PetscObject)pc,PCGASM,&match);CHKERRQ(ierr); 1554b1a0a8a3SJed Brown if (!match) { 1555b1a0a8a3SJed Brown if (n) *n = 0; 1556b1a0a8a3SJed Brown if (is) *is = PETSC_NULL; 1557b1a0a8a3SJed Brown } else { 1558f746d493SDmitry Karpeev osm = (PC_GASM*)pc->data; 1559ab3e923fSDmitry Karpeev if (n) *n = osm->n; 1560b1a0a8a3SJed Brown if (is) *is = osm->is; 1561b1a0a8a3SJed Brown if (is_local) *is_local = osm->is_local; 1562b1a0a8a3SJed Brown } 1563b1a0a8a3SJed Brown PetscFunctionReturn(0); 1564b1a0a8a3SJed Brown } 1565b1a0a8a3SJed Brown 1566b1a0a8a3SJed Brown #undef __FUNCT__ 1567f746d493SDmitry Karpeev #define __FUNCT__ "PCGASMGetLocalSubmatrices" 1568b1a0a8a3SJed Brown /*@C 1569f746d493SDmitry Karpeev PCGASMGetLocalSubmatrices - Gets the local submatrices (for this processor 1570b1a0a8a3SJed Brown only) for the additive Schwarz preconditioner. 1571b1a0a8a3SJed Brown 1572b1a0a8a3SJed Brown Not Collective 1573b1a0a8a3SJed Brown 1574b1a0a8a3SJed Brown Input Parameter: 1575b1a0a8a3SJed Brown . pc - the preconditioner context 1576b1a0a8a3SJed Brown 1577b1a0a8a3SJed Brown Output Parameters: 1578b1a0a8a3SJed Brown + n - the number of matrices for this processor (default value = 1) 1579b1a0a8a3SJed Brown - mat - the matrices 1580b1a0a8a3SJed Brown 1581b1a0a8a3SJed Brown 1582b1a0a8a3SJed Brown Level: advanced 1583b1a0a8a3SJed Brown 1584f746d493SDmitry Karpeev .keywords: PC, GASM, set, local, subdomains, additive Schwarz, block Jacobi 1585b1a0a8a3SJed Brown 1586f746d493SDmitry Karpeev .seealso: PCGASMSetTotalSubdomains(), PCGASMSetOverlap(), PCGASMGetSubKSP(), 1587f746d493SDmitry Karpeev PCGASMCreateSubdomains2D(), PCGASMSetLocalSubdomains(), PCGASMGetLocalSubdomains() 1588b1a0a8a3SJed Brown @*/ 15897087cfbeSBarry Smith PetscErrorCode PCGASMGetLocalSubmatrices(PC pc,PetscInt *n,Mat *mat[]) 1590b1a0a8a3SJed Brown { 1591f746d493SDmitry Karpeev PC_GASM *osm; 1592b1a0a8a3SJed Brown PetscErrorCode ierr; 1593b1a0a8a3SJed Brown PetscBool match; 1594b1a0a8a3SJed Brown 1595b1a0a8a3SJed Brown PetscFunctionBegin; 1596b1a0a8a3SJed Brown PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1597b1a0a8a3SJed Brown PetscValidIntPointer(n,2); 1598b1a0a8a3SJed Brown if (mat) PetscValidPointer(mat,3); 1599b1a0a8a3SJed Brown if (!pc->setupcalled) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONGSTATE,"Must call after KSPSetUP() or PCSetUp()."); 1600f746d493SDmitry Karpeev ierr = PetscTypeCompare((PetscObject)pc,PCGASM,&match);CHKERRQ(ierr); 1601b1a0a8a3SJed Brown if (!match) { 1602b1a0a8a3SJed Brown if (n) *n = 0; 1603b1a0a8a3SJed Brown if (mat) *mat = PETSC_NULL; 1604b1a0a8a3SJed Brown } else { 1605f746d493SDmitry Karpeev osm = (PC_GASM*)pc->data; 1606ab3e923fSDmitry Karpeev if (n) *n = osm->n; 1607b1a0a8a3SJed Brown if (mat) *mat = osm->pmat; 1608b1a0a8a3SJed Brown } 1609b1a0a8a3SJed Brown PetscFunctionReturn(0); 1610b1a0a8a3SJed Brown } 1611